From: David Zafman Date: Tue, 22 Oct 2019 22:24:05 +0000 (-0700) Subject: mgr: Release GIL before calling OSDMap::calc_pg_upmaps() X-Git-Tag: v13.2.9~112^2~21 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=5873a15bd683a7bd4231aa28f7a0bc7ccc3c769e;p=ceph.git mgr: Release GIL before calling OSDMap::calc_pg_upmaps() Prevent optimize and execute commands from running with active balancer Fixes: https://tracker.ceph.com/issues/42432 Signed-off-by: David Zafman (cherry picked from commit e2a35e8c8e9f381a635ad0ca01326a2c512590a9) Conflicts: src/pybind/mgr/balancer/module.py (trivial) src/test/cli-integration/balancer/misplaced.t (doesn't exist) --- diff --git a/src/mgr/PyOSDMap.cc b/src/mgr/PyOSDMap.cc index e4fdd8f5a1526..72fbad0249828 100644 --- a/src/mgr/PyOSDMap.cc +++ b/src/mgr/PyOSDMap.cc @@ -147,11 +147,13 @@ static PyObject *osdmap_calc_pg_upmaps(BasePyOSDMap* self, PyObject *args) << " max_iterations " << max_iterations << " pools " << pools << dendl; + PyThreadState *tstate = PyEval_SaveThread(); int r = self->osdmap->calc_pg_upmaps(g_ceph_context, max_deviation, max_iterations, pools, incobj->inc); + PyEval_RestoreThread(tstate); dout(10) << __func__ << " r = " << r << dendl; return PyInt_FromLong(r); } diff --git a/src/pybind/mgr/balancer/module.py b/src/pybind/mgr/balancer/module.py index 0eddb0011d810..b53831c61000b 100644 --- a/src/pybind/mgr/balancer/module.py +++ b/src/pybind/mgr/balancer/module.py @@ -290,6 +290,7 @@ class Module(MgrModule): run = True plans = {} mode = '' + optimizing = False def __init__(self, *args, **kwargs): super(Module, self).__init__(*args, **kwargs) @@ -350,6 +351,11 @@ class Module(MgrModule): 'current cluster') return (0, self.evaluate(ms, pools, verbose=verbose), '') elif command['prefix'] == 'balancer optimize': + # The GIL can be release by the active balancer, so disallow when active + if self.active: + return (-errno.EINVAL, '', 'Balancer enabled, disable to optimize manually') + if self.optimizing: + return (-errno.EINVAL, '', 'Balancer finishing up....try again') pools = [] if 'pools' in command: pools = command['pools'] @@ -363,10 +369,9 @@ class Module(MgrModule): return (-errno.EINVAL, '', 'pools %s not found' % invalid_pool_names) plan = self.plan_create(command['plan'], osdmap, pools) r, detail = self.optimize(plan) - # remove plan if we are currently unable to find an optimization - # or distribution is already perfect - if r: - self.plan_rm(command['plan']) + # Add plan if an optimization was created + if not r: + self.plans[command['plan']] = plan return (r, '', detail) elif command['prefix'] == 'balancer rm': self.plan_rm(command['plan']) @@ -387,6 +392,11 @@ class Module(MgrModule): return (-errno.ENOENT, '', 'plan %s not found' % command['plan']) return (0, plan.show(), '') elif command['prefix'] == 'balancer execute': + # The GIL can be release by the active balancer, so disallow when active + if self.active: + return (-errno.EINVAL, '', 'Balancer enabled, disable to execute a plan') + if self.optimizing: + return (-errno.EINVAL, '', 'Balancer finishing up....try again') plan = self.plans.get(command['plan']) if not plan: return (-errno.ENOENT, '', 'plan %s not found' % command['plan']) @@ -445,10 +455,11 @@ class Module(MgrModule): self.log.debug('Running') name = 'auto_%s' % time.strftime(TIME_FORMAT, time.gmtime()) plan = self.plan_create(name, self.get_osdmap(), []) + self.optimizing = True r, detail = self.optimize(plan) if r == 0: self.execute(plan) - self.plan_rm(name) + self.optimizing = False self.log.debug('Sleeping for %d', sleep_interval) self.event.wait(sleep_interval) self.event.clear() @@ -459,7 +470,6 @@ class Module(MgrModule): self.get("pg_dump"), 'plan %s initial' % name), pools) - self.plans[name] = plan return plan def plan_rm(self, name):