aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Menage <menage@google.com>2008-07-25 04:46:59 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-25 13:53:35 -0400
commite788e066c651b1bbf4a927dc95395c1aa13be436 (patch)
tree8ffb80dc5917ba5b77e17ab2b71afcea3aadfef8
parentdb3b14978abc02041046ed8353f0899cb58ffffc (diff)
cgroup files: move the release_agent file to use typed handlers
Adds cgroup_release_agent_write() and cgroup_release_agent_show() methods to handle writing/reading the path to a cgroup hierarchy's release agent. As a result, cgroup_common_file_read() is now unnecessary. As part of the change, a previously-tolerated race in cgroup_release_agent() is avoided by copying the current release_agent_path prior to calling call_usermode_helper(). Signed-off-by: Paul Menage <menage@google.com> Cc: Paul Jackson <pj@sgi.com> Cc: Pavel Emelyanov <xemul@openvz.org> Cc: Balbir Singh <balbir@in.ibm.com> Acked-by: Serge Hallyn <serue@us.ibm.com> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/cgroup.h2
-rw-r--r--kernel/cgroup.c125
2 files changed, 59 insertions, 68 deletions
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index f5379455bb59..e78377a91a74 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -295,6 +295,8 @@ int cgroup_add_files(struct cgroup *cgrp,
295 295
296int cgroup_is_removed(const struct cgroup *cgrp); 296int cgroup_is_removed(const struct cgroup *cgrp);
297 297
298int cgroup_lock_live_group(struct cgroup *cgrp);
299
298int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen); 300int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen);
299 301
300int cgroup_task_count(const struct cgroup *cgrp); 302int cgroup_task_count(const struct cgroup *cgrp);
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 3a99cc2df860..0120b5d67a73 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -89,11 +89,7 @@ struct cgroupfs_root {
89 /* Hierarchy-specific flags */ 89 /* Hierarchy-specific flags */
90 unsigned long flags; 90 unsigned long flags;
91 91
92 /* The path to use for release notifications. No locking 92 /* The path to use for release notifications. */
93 * between setting and use - so if userspace updates this
94 * while child cgroups exist, you could miss a
95 * notification. We ensure that it's always a valid
96 * NUL-terminated string */
97 char release_agent_path[PATH_MAX]; 93 char release_agent_path[PATH_MAX];
98}; 94};
99 95
@@ -1329,6 +1325,45 @@ enum cgroup_filetype {
1329 FILE_RELEASE_AGENT, 1325 FILE_RELEASE_AGENT,
1330}; 1326};
1331 1327
1328/**
1329 * cgroup_lock_live_group - take cgroup_mutex and check that cgrp is alive.
1330 * @cgrp: the cgroup to be checked for liveness
1331 *
1332 * Returns true (with lock held) on success, or false (with no lock
1333 * held) on failure.
1334 */
1335int cgroup_lock_live_group(struct cgroup *cgrp)
1336{
1337 mutex_lock(&cgroup_mutex);
1338 if (cgroup_is_removed(cgrp)) {
1339 mutex_unlock(&cgroup_mutex);
1340 return false;
1341 }
1342 return true;
1343}
1344
1345static int cgroup_release_agent_write(struct cgroup *cgrp, struct cftype *cft,
1346 const char *buffer)
1347{
1348 BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX);
1349 if (!cgroup_lock_live_group(cgrp))
1350 return -ENODEV;
1351 strcpy(cgrp->root->release_agent_path, buffer);
1352 mutex_unlock(&cgroup_mutex);
1353 return 0;
1354}
1355
1356static int cgroup_release_agent_show(struct cgroup *cgrp, struct cftype *cft,
1357 struct seq_file *seq)
1358{
1359 if (!cgroup_lock_live_group(cgrp))
1360 return -ENODEV;
1361 seq_puts(seq, cgrp->root->release_agent_path);
1362 seq_putc(seq, '\n');
1363 mutex_unlock(&cgroup_mutex);
1364 return 0;
1365}
1366
1332static ssize_t cgroup_write_X64(struct cgroup *cgrp, struct cftype *cft, 1367static ssize_t cgroup_write_X64(struct cgroup *cgrp, struct cftype *cft,
1333 struct file *file, 1368 struct file *file,
1334 const char __user *userbuf, 1369 const char __user *userbuf,
@@ -1443,10 +1478,6 @@ static ssize_t cgroup_common_file_write(struct cgroup *cgrp,
1443 else 1478 else
1444 clear_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags); 1479 clear_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);
1445 break; 1480 break;
1446 case FILE_RELEASE_AGENT:
1447 BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX);
1448 strcpy(cgrp->root->release_agent_path, buffer);
1449 break;
1450 default: 1481 default:
1451 retval = -EINVAL; 1482 retval = -EINVAL;
1452 goto out2; 1483 goto out2;
@@ -1506,49 +1537,6 @@ static ssize_t cgroup_read_s64(struct cgroup *cgrp, struct cftype *cft,
1506 return simple_read_from_buffer(buf, nbytes, ppos, tmp, len); 1537 return simple_read_from_buffer(buf, nbytes, ppos, tmp, len);
1507} 1538}
1508 1539
1509static ssize_t cgroup_common_file_read(struct cgroup *cgrp,
1510 struct cftype *cft,
1511 struct file *file,
1512 char __user *buf,
1513 size_t nbytes, loff_t *ppos)
1514{
1515 enum cgroup_filetype type = cft->private;
1516 char *page;
1517 ssize_t retval = 0;
1518 char *s;
1519
1520 if (!(page = (char *)__get_free_page(GFP_KERNEL)))
1521 return -ENOMEM;
1522
1523 s = page;
1524
1525 switch (type) {
1526 case FILE_RELEASE_AGENT:
1527 {
1528 struct cgroupfs_root *root;
1529 size_t n;
1530 mutex_lock(&cgroup_mutex);
1531 root = cgrp->root;
1532 n = strnlen(root->release_agent_path,
1533 sizeof(root->release_agent_path));
1534 n = min(n, (size_t) PAGE_SIZE);
1535 strncpy(s, root->release_agent_path, n);
1536 mutex_unlock(&cgroup_mutex);
1537 s += n;
1538 break;
1539 }
1540 default:
1541 retval = -EINVAL;
1542 goto out;
1543 }
1544 *s++ = '\n';
1545
1546 retval = simple_read_from_buffer(buf, nbytes, ppos, page, s - page);
1547out:
1548 free_page((unsigned long)page);
1549 return retval;
1550}
1551
1552static ssize_t cgroup_file_read(struct file *file, char __user *buf, 1540static ssize_t cgroup_file_read(struct file *file, char __user *buf,
1553 size_t nbytes, loff_t *ppos) 1541 size_t nbytes, loff_t *ppos)
1554{ 1542{
@@ -1606,6 +1594,7 @@ int cgroup_seqfile_release(struct inode *inode, struct file *file)
1606 1594
1607static struct file_operations cgroup_seqfile_operations = { 1595static struct file_operations cgroup_seqfile_operations = {
1608 .read = seq_read, 1596 .read = seq_read,
1597 .write = cgroup_file_write,
1609 .llseek = seq_lseek, 1598 .llseek = seq_lseek,
1610 .release = cgroup_seqfile_release, 1599 .release = cgroup_seqfile_release,
1611}; 1600};
@@ -2283,8 +2272,9 @@ static struct cftype files[] = {
2283 2272
2284static struct cftype cft_release_agent = { 2273static struct cftype cft_release_agent = {
2285 .name = "release_agent", 2274 .name = "release_agent",
2286 .read = cgroup_common_file_read, 2275 .read_seq_string = cgroup_release_agent_show,
2287 .write = cgroup_common_file_write, 2276 .write_string = cgroup_release_agent_write,
2277 .max_write_len = PATH_MAX,
2288 .private = FILE_RELEASE_AGENT, 2278 .private = FILE_RELEASE_AGENT,
2289}; 2279};
2290 2280
@@ -3111,27 +3101,24 @@ static void cgroup_release_agent(struct work_struct *work)
3111 while (!list_empty(&release_list)) { 3101 while (!list_empty(&release_list)) {
3112 char *argv[3], *envp[3]; 3102 char *argv[3], *envp[3];
3113 int i; 3103 int i;
3114 char *pathbuf; 3104 char *pathbuf = NULL, *agentbuf = NULL;
3115 struct cgroup *cgrp = list_entry(release_list.next, 3105 struct cgroup *cgrp = list_entry(release_list.next,
3116 struct cgroup, 3106 struct cgroup,
3117 release_list); 3107 release_list);
3118 list_del_init(&cgrp->release_list); 3108 list_del_init(&cgrp->release_list);
3119 spin_unlock(&release_list_lock); 3109 spin_unlock(&release_list_lock);
3120 pathbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); 3110 pathbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
3121 if (!pathbuf) { 3111 if (!pathbuf)
3122 spin_lock(&release_list_lock); 3112 goto continue_free;
3123 continue; 3113 if (cgroup_path(cgrp, pathbuf, PAGE_SIZE) < 0)
3124 } 3114 goto continue_free;
3125 3115 agentbuf = kstrdup(cgrp->root->release_agent_path, GFP_KERNEL);
3126 if (cgroup_path(cgrp, pathbuf, PAGE_SIZE) < 0) { 3116 if (!agentbuf)
3127 kfree(pathbuf); 3117 goto continue_free;
3128 spin_lock(&release_list_lock);
3129 continue;
3130 }
3131 3118
3132 i = 0; 3119 i = 0;
3133 argv[i++] = cgrp->root->release_agent_path; 3120 argv[i++] = agentbuf;
3134 argv[i++] = (char *)pathbuf; 3121 argv[i++] = pathbuf;
3135 argv[i] = NULL; 3122 argv[i] = NULL;
3136 3123
3137 i = 0; 3124 i = 0;
@@ -3145,8 +3132,10 @@ static void cgroup_release_agent(struct work_struct *work)
3145 * be a slow process */ 3132 * be a slow process */
3146 mutex_unlock(&cgroup_mutex); 3133 mutex_unlock(&cgroup_mutex);
3147 call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC); 3134 call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
3148 kfree(pathbuf);
3149 mutex_lock(&cgroup_mutex); 3135 mutex_lock(&cgroup_mutex);
3136 continue_free:
3137 kfree(pathbuf);
3138 kfree(agentbuf);
3150 spin_lock(&release_list_lock); 3139 spin_lock(&release_list_lock);
3151 } 3140 }
3152 spin_unlock(&release_list_lock); 3141 spin_unlock(&release_list_lock);