Skip to content

Commit e7b20d9

Browse files
committed
cgroup: Restructure release_agent_path handling
cgrp->root->release_agent_path is protected by both cgroup_mutex and release_agent_path_lock and readers can hold either one. The dual-locking scheme was introduced while breaking a locking dependency issue around cgroup_mutex but doesn't make sense anymore given that the only remaining reader which uses cgroup_mutex is cgroup1_releaes_agent(). This patch updates cgroup1_release_agent() to use release_agent_path_lock so that release_agent_path is always protected only by release_agent_path_lock. While at it, convert strlen() based empty string checks to direct tests on the first character as suggested by Linus. Signed-off-by: Tejun Heo <[email protected]> Cc: Linus Torvalds <[email protected]>
1 parent a09833f commit e7b20d9

File tree

1 file changed

+17
-17
lines changed

1 file changed

+17
-17
lines changed

kernel/cgroup/cgroup-v1.c

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,7 @@ static bool cgroup_no_v1_named;
3838
*/
3939
static struct workqueue_struct *cgroup_pidlist_destroy_wq;
4040

41-
/*
42-
* Protects cgroup_subsys->release_agent_path. Modifying it also requires
43-
* cgroup_mutex. Reading requires either cgroup_mutex or this spinlock.
44-
*/
41+
/* protects cgroup_subsys->release_agent_path */
4542
static DEFINE_SPINLOCK(release_agent_path_lock);
4643

4744
bool cgroup1_ssid_disabled(int ssid)
@@ -775,22 +772,29 @@ void cgroup1_release_agent(struct work_struct *work)
775772
{
776773
struct cgroup *cgrp =
777774
container_of(work, struct cgroup, release_agent_work);
778-
char *pathbuf = NULL, *agentbuf = NULL;
775+
char *pathbuf, *agentbuf;
779776
char *argv[3], *envp[3];
780777
int ret;
781778

782-
mutex_lock(&cgroup_mutex);
779+
/* snoop agent path and exit early if empty */
780+
if (!cgrp->root->release_agent_path[0])
781+
return;
783782

783+
/* prepare argument buffers */
784784
pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
785-
agentbuf = kstrdup(cgrp->root->release_agent_path, GFP_KERNEL);
786-
if (!pathbuf || !agentbuf || !strlen(agentbuf))
787-
goto out;
785+
agentbuf = kmalloc(PATH_MAX, GFP_KERNEL);
786+
if (!pathbuf || !agentbuf)
787+
goto out_free;
788788

789-
spin_lock_irq(&css_set_lock);
790-
ret = cgroup_path_ns_locked(cgrp, pathbuf, PATH_MAX, &init_cgroup_ns);
791-
spin_unlock_irq(&css_set_lock);
789+
spin_lock(&release_agent_path_lock);
790+
strlcpy(agentbuf, cgrp->root->release_agent_path, PATH_MAX);
791+
spin_unlock(&release_agent_path_lock);
792+
if (!agentbuf[0])
793+
goto out_free;
794+
795+
ret = cgroup_path_ns(cgrp, pathbuf, PATH_MAX, &init_cgroup_ns);
792796
if (ret < 0 || ret >= PATH_MAX)
793-
goto out;
797+
goto out_free;
794798

795799
argv[0] = agentbuf;
796800
argv[1] = pathbuf;
@@ -801,11 +805,7 @@ void cgroup1_release_agent(struct work_struct *work)
801805
envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
802806
envp[2] = NULL;
803807

804-
mutex_unlock(&cgroup_mutex);
805808
call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
806-
goto out_free;
807-
out:
808-
mutex_unlock(&cgroup_mutex);
809809
out_free:
810810
kfree(agentbuf);
811811
kfree(pathbuf);

0 commit comments

Comments
 (0)