|
@@ -865,11 +865,8 @@ static int cgroup_call_pre_destroy(struct cgroup *cgrp)
|
|
|
continue;
|
|
|
|
|
|
ret = ss->pre_destroy(cgrp);
|
|
|
- if (ret) {
|
|
|
- /* ->pre_destroy() failure is being deprecated */
|
|
|
- WARN_ON_ONCE(!ss->__DEPRECATED_clear_css_refs);
|
|
|
+ if (WARN_ON_ONCE(ret))
|
|
|
break;
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
return ret;
|
|
@@ -3901,14 +3898,12 @@ static void init_cgroup_css(struct cgroup_subsys_state *css,
|
|
|
cgrp->subsys[ss->subsys_id] = css;
|
|
|
|
|
|
/*
|
|
|
- * If !clear_css_refs, css holds an extra ref to @cgrp->dentry
|
|
|
- * which is put on the last css_put(). dput() requires process
|
|
|
- * context, which css_put() may be called without. @css->dput_work
|
|
|
- * will be used to invoke dput() asynchronously from css_put().
|
|
|
+ * css holds an extra ref to @cgrp->dentry which is put on the last
|
|
|
+ * css_put(). dput() requires process context, which css_put() may
|
|
|
+ * be called without. @css->dput_work will be used to invoke
|
|
|
+ * dput() asynchronously from css_put().
|
|
|
*/
|
|
|
INIT_WORK(&css->dput_work, css_dput_fn);
|
|
|
- if (ss->__DEPRECATED_clear_css_refs)
|
|
|
- set_bit(CSS_CLEAR_CSS_REFS, &css->flags);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -3978,10 +3973,9 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
|
|
|
if (err < 0)
|
|
|
goto err_remove;
|
|
|
|
|
|
- /* If !clear_css_refs, each css holds a ref to the cgroup's dentry */
|
|
|
+ /* each css holds a ref to the cgroup's dentry */
|
|
|
for_each_subsys(root, ss)
|
|
|
- if (!ss->__DEPRECATED_clear_css_refs)
|
|
|
- dget(dentry);
|
|
|
+ dget(dentry);
|
|
|
|
|
|
/* The cgroup directory was pre-locked for us */
|
|
|
BUG_ON(!mutex_is_locked(&cgrp->dentry->d_inode->i_mutex));
|
|
@@ -4066,71 +4060,6 @@ static int cgroup_has_css_refs(struct cgroup *cgrp)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * Atomically mark all (or else none) of the cgroup's CSS objects as
|
|
|
- * CSS_REMOVED. Return true on success, or false if the cgroup has
|
|
|
- * busy subsystems. Call with cgroup_mutex held
|
|
|
- *
|
|
|
- * Depending on whether a subsys has __DEPRECATED_clear_css_refs set or
|
|
|
- * not, cgroup removal behaves differently.
|
|
|
- *
|
|
|
- * If clear is set, css refcnt for the subsystem should be zero before
|
|
|
- * cgroup removal can be committed. This is implemented by
|
|
|
- * CGRP_WAIT_ON_RMDIR and retry logic around ->pre_destroy(), which may be
|
|
|
- * called multiple times until all css refcnts reach zero and is allowed to
|
|
|
- * veto removal on any invocation. This behavior is deprecated and will be
|
|
|
- * removed as soon as the existing user (memcg) is updated.
|
|
|
- *
|
|
|
- * If clear is not set, each css holds an extra reference to the cgroup's
|
|
|
- * dentry and cgroup removal proceeds regardless of css refs.
|
|
|
- * ->pre_destroy() will be called at least once and is not allowed to fail.
|
|
|
- * On the last put of each css, whenever that may be, the extra dentry ref
|
|
|
- * is put so that dentry destruction happens only after all css's are
|
|
|
- * released.
|
|
|
- */
|
|
|
-static int cgroup_clear_css_refs(struct cgroup *cgrp)
|
|
|
-{
|
|
|
- struct cgroup_subsys *ss;
|
|
|
- unsigned long flags;
|
|
|
- bool failed = false;
|
|
|
-
|
|
|
- local_irq_save(flags);
|
|
|
-
|
|
|
- /*
|
|
|
- * Block new css_tryget() by deactivating refcnt. If all refcnts
|
|
|
- * for subsystems w/ clear_css_refs set were 1 at the moment of
|
|
|
- * deactivation, we succeeded.
|
|
|
- */
|
|
|
- for_each_subsys(cgrp->root, ss) {
|
|
|
- struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
|
|
|
-
|
|
|
- WARN_ON(atomic_read(&css->refcnt) < 0);
|
|
|
- atomic_add(CSS_DEACT_BIAS, &css->refcnt);
|
|
|
-
|
|
|
- if (ss->__DEPRECATED_clear_css_refs)
|
|
|
- failed |= css_refcnt(css) != 1;
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- * If succeeded, set REMOVED and put all the base refs; otherwise,
|
|
|
- * restore refcnts to positive values. Either way, all in-progress
|
|
|
- * css_tryget() will be released.
|
|
|
- */
|
|
|
- for_each_subsys(cgrp->root, ss) {
|
|
|
- struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
|
|
|
-
|
|
|
- if (!failed) {
|
|
|
- set_bit(CSS_REMOVED, &css->flags);
|
|
|
- css_put(css);
|
|
|
- } else {
|
|
|
- atomic_sub(CSS_DEACT_BIAS, &css->refcnt);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- local_irq_restore(flags);
|
|
|
- return !failed;
|
|
|
-}
|
|
|
-
|
|
|
static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
|
|
|
{
|
|
|
struct cgroup *cgrp = dentry->d_fsdata;
|
|
@@ -4138,10 +4067,10 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
|
|
|
struct cgroup *parent;
|
|
|
DEFINE_WAIT(wait);
|
|
|
struct cgroup_event *event, *tmp;
|
|
|
+ struct cgroup_subsys *ss;
|
|
|
int ret;
|
|
|
|
|
|
/* the vfs holds both inode->i_mutex already */
|
|
|
-again:
|
|
|
mutex_lock(&cgroup_mutex);
|
|
|
if (atomic_read(&cgrp->count) != 0) {
|
|
|
mutex_unlock(&cgroup_mutex);
|
|
@@ -4182,21 +4111,34 @@ again:
|
|
|
return -EBUSY;
|
|
|
}
|
|
|
prepare_to_wait(&cgroup_rmdir_waitq, &wait, TASK_INTERRUPTIBLE);
|
|
|
- if (!cgroup_clear_css_refs(cgrp)) {
|
|
|
- mutex_unlock(&cgroup_mutex);
|
|
|
- /*
|
|
|
- * Because someone may call cgroup_wakeup_rmdir_waiter() before
|
|
|
- * prepare_to_wait(), we need to check this flag.
|
|
|
- */
|
|
|
- if (test_bit(CGRP_WAIT_ON_RMDIR, &cgrp->flags))
|
|
|
- schedule();
|
|
|
- finish_wait(&cgroup_rmdir_waitq, &wait);
|
|
|
- clear_bit(CGRP_WAIT_ON_RMDIR, &cgrp->flags);
|
|
|
- if (signal_pending(current))
|
|
|
- return -EINTR;
|
|
|
- goto again;
|
|
|
+
|
|
|
+ local_irq_disable();
|
|
|
+
|
|
|
+ /* block new css_tryget() by deactivating refcnt */
|
|
|
+ for_each_subsys(cgrp->root, ss) {
|
|
|
+ struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
|
|
|
+
|
|
|
+ WARN_ON(atomic_read(&css->refcnt) < 0);
|
|
|
+ atomic_add(CSS_DEACT_BIAS, &css->refcnt);
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Set REMOVED. All in-progress css_tryget() will be released.
|
|
|
+ * Put all the base refs. Each css holds an extra reference to the
|
|
|
+ * cgroup's dentry and cgroup removal proceeds regardless of css
|
|
|
+ * refs. On the last put of each css, whenever that may be, the
|
|
|
+ * extra dentry ref is put so that dentry destruction happens only
|
|
|
+ * after all css's are released.
|
|
|
+ */
|
|
|
+ for_each_subsys(cgrp->root, ss) {
|
|
|
+ struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
|
|
|
+
|
|
|
+ set_bit(CSS_REMOVED, &css->flags);
|
|
|
+ css_put(css);
|
|
|
}
|
|
|
- /* NO css_tryget() can success after here. */
|
|
|
+
|
|
|
+ local_irq_enable();
|
|
|
+
|
|
|
finish_wait(&cgroup_rmdir_waitq, &wait);
|
|
|
clear_bit(CGRP_WAIT_ON_RMDIR, &cgrp->flags);
|
|
|
|
|
@@ -4949,8 +4891,7 @@ void __css_put(struct cgroup_subsys_state *css)
|
|
|
cgroup_wakeup_rmdir_waiter(cgrp);
|
|
|
break;
|
|
|
case 0:
|
|
|
- if (!test_bit(CSS_CLEAR_CSS_REFS, &css->flags))
|
|
|
- schedule_work(&css->dput_work);
|
|
|
+ schedule_work(&css->dput_work);
|
|
|
break;
|
|
|
}
|
|
|
rcu_read_unlock();
|