|
@@ -3821,6 +3821,23 @@ static int cgroup_write_notify_on_release(struct cgroup *cgrp,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * When dput() is called asynchronously, if umount has been done and
|
|
|
+ * then deactivate_super() in cgroup_free_fn() kills the superblock,
|
|
|
+ * there's a small window that vfs will see the root dentry with non-zero
|
|
|
+ * refcnt and trigger BUG().
|
|
|
+ *
|
|
|
+ * That's why we hold a reference before dput() and drop it right after.
|
|
|
+ */
|
|
|
+static void cgroup_dput(struct cgroup *cgrp)
|
|
|
+{
|
|
|
+ struct super_block *sb = cgrp->root->sb;
|
|
|
+
|
|
|
+ atomic_inc(&sb->s_active);
|
|
|
+ dput(cgrp->dentry);
|
|
|
+ deactivate_super(sb);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Unregister event and free resources.
|
|
|
*
|
|
@@ -3841,7 +3858,7 @@ static void cgroup_event_remove(struct work_struct *work)
|
|
|
|
|
|
eventfd_ctx_put(event->eventfd);
|
|
|
kfree(event);
|
|
|
- dput(cgrp->dentry);
|
|
|
+ cgroup_dput(cgrp);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -4129,12 +4146,8 @@ static void css_dput_fn(struct work_struct *work)
|
|
|
{
|
|
|
struct cgroup_subsys_state *css =
|
|
|
container_of(work, struct cgroup_subsys_state, dput_work);
|
|
|
- struct dentry *dentry = css->cgroup->dentry;
|
|
|
- struct super_block *sb = dentry->d_sb;
|
|
|
|
|
|
- atomic_inc(&sb->s_active);
|
|
|
- dput(dentry);
|
|
|
- deactivate_super(sb);
|
|
|
+ cgroup_dput(css->cgroup);
|
|
|
}
|
|
|
|
|
|
static void css_release(struct percpu_ref *ref)
|