diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-07-26 11:48:49 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-07-26 11:48:49 -0400 |
commit | c3cc99ff5d24e2eeaf7ec2032e720681916990e3 (patch) | |
tree | c3e74171bbbd2adde9d60b9db1c440415c8d2831 /kernel/cgroup.c | |
parent | 38ffbe66d59051fd9cfcfc8545f164700e2fa3bc (diff) | |
parent | 024e8ac04453b3525448c31ef39848cf675ba6db (diff) |
Merge branch 'linus' into x86/xen
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r-- | kernel/cgroup.c | 309 |
1 files changed, 143 insertions, 166 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 15ac0e1e4f4d..66ec9fd21e0c 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 | ||
@@ -118,7 +114,7 @@ static int root_count; | |||
118 | * extra work in the fork/exit path if none of the subsystems need to | 114 | * extra work in the fork/exit path if none of the subsystems need to |
119 | * be called. | 115 | * be called. |
120 | */ | 116 | */ |
121 | static int need_forkexit_callback; | 117 | static int need_forkexit_callback __read_mostly; |
122 | static int need_mm_owner_callback __read_mostly; | 118 | static int need_mm_owner_callback __read_mostly; |
123 | 119 | ||
124 | /* convenient tests for these bits */ | 120 | /* convenient tests for these bits */ |
@@ -220,7 +216,7 @@ static struct hlist_head *css_set_hash(struct cgroup_subsys_state *css[]) | |||
220 | * task until after the first call to cgroup_iter_start(). This | 216 | * task until after the first call to cgroup_iter_start(). This |
221 | * reduces the fork()/exit() overhead for people who have cgroups | 217 | * reduces the fork()/exit() overhead for people who have cgroups |
222 | * compiled into their kernel but not actually in use */ | 218 | * compiled into their kernel but not actually in use */ |
223 | static int use_task_css_set_links; | 219 | static int use_task_css_set_links __read_mostly; |
224 | 220 | ||
225 | /* When we create or destroy a css_set, the operation simply | 221 | /* When we create or destroy a css_set, the operation simply |
226 | * takes/releases a reference count on all the cgroups referenced | 222 | * takes/releases a reference count on all the cgroups referenced |
@@ -241,17 +237,20 @@ static int use_task_css_set_links; | |||
241 | */ | 237 | */ |
242 | static void unlink_css_set(struct css_set *cg) | 238 | static void unlink_css_set(struct css_set *cg) |
243 | { | 239 | { |
240 | struct cg_cgroup_link *link; | ||
241 | struct cg_cgroup_link *saved_link; | ||
242 | |||
244 | write_lock(&css_set_lock); | 243 | write_lock(&css_set_lock); |
245 | hlist_del(&cg->hlist); | 244 | hlist_del(&cg->hlist); |
246 | css_set_count--; | 245 | css_set_count--; |
247 | while (!list_empty(&cg->cg_links)) { | 246 | |
248 | struct cg_cgroup_link *link; | 247 | list_for_each_entry_safe(link, saved_link, &cg->cg_links, |
249 | link = list_entry(cg->cg_links.next, | 248 | cg_link_list) { |
250 | struct cg_cgroup_link, cg_link_list); | ||
251 | list_del(&link->cg_link_list); | 249 | list_del(&link->cg_link_list); |
252 | list_del(&link->cgrp_link_list); | 250 | list_del(&link->cgrp_link_list); |
253 | kfree(link); | 251 | kfree(link); |
254 | } | 252 | } |
253 | |||
255 | write_unlock(&css_set_lock); | 254 | write_unlock(&css_set_lock); |
256 | } | 255 | } |
257 | 256 | ||
@@ -363,15 +362,14 @@ static struct css_set *find_existing_css_set( | |||
363 | static int allocate_cg_links(int count, struct list_head *tmp) | 362 | static int allocate_cg_links(int count, struct list_head *tmp) |
364 | { | 363 | { |
365 | struct cg_cgroup_link *link; | 364 | struct cg_cgroup_link *link; |
365 | struct cg_cgroup_link *saved_link; | ||
366 | int i; | 366 | int i; |
367 | INIT_LIST_HEAD(tmp); | 367 | INIT_LIST_HEAD(tmp); |
368 | for (i = 0; i < count; i++) { | 368 | for (i = 0; i < count; i++) { |
369 | link = kmalloc(sizeof(*link), GFP_KERNEL); | 369 | link = kmalloc(sizeof(*link), GFP_KERNEL); |
370 | if (!link) { | 370 | if (!link) { |
371 | while (!list_empty(tmp)) { | 371 | list_for_each_entry_safe(link, saved_link, tmp, |
372 | link = list_entry(tmp->next, | 372 | cgrp_link_list) { |
373 | struct cg_cgroup_link, | ||
374 | cgrp_link_list); | ||
375 | list_del(&link->cgrp_link_list); | 373 | list_del(&link->cgrp_link_list); |
376 | kfree(link); | 374 | kfree(link); |
377 | } | 375 | } |
@@ -384,11 +382,10 @@ static int allocate_cg_links(int count, struct list_head *tmp) | |||
384 | 382 | ||
385 | static void free_cg_links(struct list_head *tmp) | 383 | static void free_cg_links(struct list_head *tmp) |
386 | { | 384 | { |
387 | while (!list_empty(tmp)) { | 385 | struct cg_cgroup_link *link; |
388 | struct cg_cgroup_link *link; | 386 | struct cg_cgroup_link *saved_link; |
389 | link = list_entry(tmp->next, | 387 | |
390 | struct cg_cgroup_link, | 388 | list_for_each_entry_safe(link, saved_link, tmp, cgrp_link_list) { |
391 | cgrp_link_list); | ||
392 | list_del(&link->cgrp_link_list); | 389 | list_del(&link->cgrp_link_list); |
393 | kfree(link); | 390 | kfree(link); |
394 | } | 391 | } |
@@ -415,11 +412,11 @@ static struct css_set *find_css_set( | |||
415 | 412 | ||
416 | /* First see if we already have a cgroup group that matches | 413 | /* First see if we already have a cgroup group that matches |
417 | * the desired set */ | 414 | * the desired set */ |
418 | write_lock(&css_set_lock); | 415 | read_lock(&css_set_lock); |
419 | res = find_existing_css_set(oldcg, cgrp, template); | 416 | res = find_existing_css_set(oldcg, cgrp, template); |
420 | if (res) | 417 | if (res) |
421 | get_css_set(res); | 418 | get_css_set(res); |
422 | write_unlock(&css_set_lock); | 419 | read_unlock(&css_set_lock); |
423 | 420 | ||
424 | if (res) | 421 | if (res) |
425 | return res; | 422 | return res; |
@@ -507,10 +504,6 @@ static struct css_set *find_css_set( | |||
507 | * knows that the cgroup won't be removed, as cgroup_rmdir() | 504 | * knows that the cgroup won't be removed, as cgroup_rmdir() |
508 | * needs that mutex. | 505 | * needs that mutex. |
509 | * | 506 | * |
510 | * The cgroup_common_file_write handler for operations that modify | ||
511 | * the cgroup hierarchy holds cgroup_mutex across the entire operation, | ||
512 | * single threading all such cgroup modifications across the system. | ||
513 | * | ||
514 | * The fork and exit callbacks cgroup_fork() and cgroup_exit(), don't | 507 | * The fork and exit callbacks cgroup_fork() and cgroup_exit(), don't |
515 | * (usually) take cgroup_mutex. These are the two most performance | 508 | * (usually) take cgroup_mutex. These are the two most performance |
516 | * critical pieces of code here. The exception occurs on cgroup_exit(), | 509 | * critical pieces of code here. The exception occurs on cgroup_exit(), |
@@ -1093,6 +1086,8 @@ static void cgroup_kill_sb(struct super_block *sb) { | |||
1093 | struct cgroupfs_root *root = sb->s_fs_info; | 1086 | struct cgroupfs_root *root = sb->s_fs_info; |
1094 | struct cgroup *cgrp = &root->top_cgroup; | 1087 | struct cgroup *cgrp = &root->top_cgroup; |
1095 | int ret; | 1088 | int ret; |
1089 | struct cg_cgroup_link *link; | ||
1090 | struct cg_cgroup_link *saved_link; | ||
1096 | 1091 | ||
1097 | BUG_ON(!root); | 1092 | BUG_ON(!root); |
1098 | 1093 | ||
@@ -1112,10 +1107,9 @@ static void cgroup_kill_sb(struct super_block *sb) { | |||
1112 | * root cgroup | 1107 | * root cgroup |
1113 | */ | 1108 | */ |
1114 | write_lock(&css_set_lock); | 1109 | write_lock(&css_set_lock); |
1115 | while (!list_empty(&cgrp->css_sets)) { | 1110 | |
1116 | struct cg_cgroup_link *link; | 1111 | list_for_each_entry_safe(link, saved_link, &cgrp->css_sets, |
1117 | link = list_entry(cgrp->css_sets.next, | 1112 | cgrp_link_list) { |
1118 | struct cg_cgroup_link, cgrp_link_list); | ||
1119 | list_del(&link->cg_link_list); | 1113 | list_del(&link->cg_link_list); |
1120 | list_del(&link->cgrp_link_list); | 1114 | list_del(&link->cgrp_link_list); |
1121 | kfree(link); | 1115 | kfree(link); |
@@ -1281,18 +1275,14 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk) | |||
1281 | } | 1275 | } |
1282 | 1276 | ||
1283 | /* | 1277 | /* |
1284 | * Attach task with pid 'pid' to cgroup 'cgrp'. Call with | 1278 | * Attach task with pid 'pid' to cgroup 'cgrp'. Call with cgroup_mutex |
1285 | * cgroup_mutex, may take task_lock of task | 1279 | * held. May take task_lock of task |
1286 | */ | 1280 | */ |
1287 | static int attach_task_by_pid(struct cgroup *cgrp, char *pidbuf) | 1281 | static int attach_task_by_pid(struct cgroup *cgrp, u64 pid) |
1288 | { | 1282 | { |
1289 | pid_t pid; | ||
1290 | struct task_struct *tsk; | 1283 | struct task_struct *tsk; |
1291 | int ret; | 1284 | int ret; |
1292 | 1285 | ||
1293 | if (sscanf(pidbuf, "%d", &pid) != 1) | ||
1294 | return -EIO; | ||
1295 | |||
1296 | if (pid) { | 1286 | if (pid) { |
1297 | rcu_read_lock(); | 1287 | rcu_read_lock(); |
1298 | tsk = find_task_by_vpid(pid); | 1288 | tsk = find_task_by_vpid(pid); |
@@ -1318,6 +1308,16 @@ static int attach_task_by_pid(struct cgroup *cgrp, char *pidbuf) | |||
1318 | return ret; | 1308 | return ret; |
1319 | } | 1309 | } |
1320 | 1310 | ||
1311 | static int cgroup_tasks_write(struct cgroup *cgrp, struct cftype *cft, u64 pid) | ||
1312 | { | ||
1313 | int ret; | ||
1314 | if (!cgroup_lock_live_group(cgrp)) | ||
1315 | return -ENODEV; | ||
1316 | ret = attach_task_by_pid(cgrp, pid); | ||
1317 | cgroup_unlock(); | ||
1318 | return ret; | ||
1319 | } | ||
1320 | |||
1321 | /* The various types of files and directories in a cgroup file system */ | 1321 | /* The various types of files and directories in a cgroup file system */ |
1322 | enum cgroup_filetype { | 1322 | enum cgroup_filetype { |
1323 | FILE_ROOT, | 1323 | FILE_ROOT, |
@@ -1327,12 +1327,54 @@ enum cgroup_filetype { | |||
1327 | FILE_RELEASE_AGENT, | 1327 | FILE_RELEASE_AGENT, |
1328 | }; | 1328 | }; |
1329 | 1329 | ||
1330 | /** | ||
1331 | * cgroup_lock_live_group - take cgroup_mutex and check that cgrp is alive. | ||
1332 | * @cgrp: the cgroup to be checked for liveness | ||
1333 | * | ||
1334 | * On success, returns true; the lock should be later released with | ||
1335 | * cgroup_unlock(). On failure returns false with no lock held. | ||
1336 | */ | ||
1337 | bool cgroup_lock_live_group(struct cgroup *cgrp) | ||
1338 | { | ||
1339 | mutex_lock(&cgroup_mutex); | ||
1340 | if (cgroup_is_removed(cgrp)) { | ||
1341 | mutex_unlock(&cgroup_mutex); | ||
1342 | return false; | ||
1343 | } | ||
1344 | return true; | ||
1345 | } | ||
1346 | |||
1347 | static int cgroup_release_agent_write(struct cgroup *cgrp, struct cftype *cft, | ||
1348 | const char *buffer) | ||
1349 | { | ||
1350 | BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX); | ||
1351 | if (!cgroup_lock_live_group(cgrp)) | ||
1352 | return -ENODEV; | ||
1353 | strcpy(cgrp->root->release_agent_path, buffer); | ||
1354 | cgroup_unlock(); | ||
1355 | return 0; | ||
1356 | } | ||
1357 | |||
1358 | static int cgroup_release_agent_show(struct cgroup *cgrp, struct cftype *cft, | ||
1359 | struct seq_file *seq) | ||
1360 | { | ||
1361 | if (!cgroup_lock_live_group(cgrp)) | ||
1362 | return -ENODEV; | ||
1363 | seq_puts(seq, cgrp->root->release_agent_path); | ||
1364 | seq_putc(seq, '\n'); | ||
1365 | cgroup_unlock(); | ||
1366 | return 0; | ||
1367 | } | ||
1368 | |||
1369 | /* A buffer size big enough for numbers or short strings */ | ||
1370 | #define CGROUP_LOCAL_BUFFER_SIZE 64 | ||
1371 | |||
1330 | static ssize_t cgroup_write_X64(struct cgroup *cgrp, struct cftype *cft, | 1372 | static ssize_t cgroup_write_X64(struct cgroup *cgrp, struct cftype *cft, |
1331 | struct file *file, | 1373 | struct file *file, |
1332 | const char __user *userbuf, | 1374 | const char __user *userbuf, |
1333 | size_t nbytes, loff_t *unused_ppos) | 1375 | size_t nbytes, loff_t *unused_ppos) |
1334 | { | 1376 | { |
1335 | char buffer[64]; | 1377 | char buffer[CGROUP_LOCAL_BUFFER_SIZE]; |
1336 | int retval = 0; | 1378 | int retval = 0; |
1337 | char *end; | 1379 | char *end; |
1338 | 1380 | ||
@@ -1361,68 +1403,36 @@ static ssize_t cgroup_write_X64(struct cgroup *cgrp, struct cftype *cft, | |||
1361 | return retval; | 1403 | return retval; |
1362 | } | 1404 | } |
1363 | 1405 | ||
1364 | static ssize_t cgroup_common_file_write(struct cgroup *cgrp, | 1406 | static ssize_t cgroup_write_string(struct cgroup *cgrp, struct cftype *cft, |
1365 | struct cftype *cft, | 1407 | struct file *file, |
1366 | struct file *file, | 1408 | const char __user *userbuf, |
1367 | const char __user *userbuf, | 1409 | size_t nbytes, loff_t *unused_ppos) |
1368 | size_t nbytes, loff_t *unused_ppos) | ||
1369 | { | 1410 | { |
1370 | enum cgroup_filetype type = cft->private; | 1411 | char local_buffer[CGROUP_LOCAL_BUFFER_SIZE]; |
1371 | char *buffer; | ||
1372 | int retval = 0; | 1412 | int retval = 0; |
1413 | size_t max_bytes = cft->max_write_len; | ||
1414 | char *buffer = local_buffer; | ||
1373 | 1415 | ||
1374 | if (nbytes >= PATH_MAX) | 1416 | if (!max_bytes) |
1417 | max_bytes = sizeof(local_buffer) - 1; | ||
1418 | if (nbytes >= max_bytes) | ||
1375 | return -E2BIG; | 1419 | return -E2BIG; |
1376 | 1420 | /* Allocate a dynamic buffer if we need one */ | |
1377 | /* +1 for nul-terminator */ | 1421 | if (nbytes >= sizeof(local_buffer)) { |
1378 | buffer = kmalloc(nbytes + 1, GFP_KERNEL); | 1422 | buffer = kmalloc(nbytes + 1, GFP_KERNEL); |
1379 | if (buffer == NULL) | 1423 | if (buffer == NULL) |
1380 | return -ENOMEM; | 1424 | return -ENOMEM; |
1381 | |||
1382 | if (copy_from_user(buffer, userbuf, nbytes)) { | ||
1383 | retval = -EFAULT; | ||
1384 | goto out1; | ||
1385 | } | 1425 | } |
1386 | buffer[nbytes] = 0; /* nul-terminate */ | 1426 | if (nbytes && copy_from_user(buffer, userbuf, nbytes)) |
1387 | strstrip(buffer); /* strip -just- trailing whitespace */ | 1427 | return -EFAULT; |
1388 | |||
1389 | mutex_lock(&cgroup_mutex); | ||
1390 | 1428 | ||
1391 | /* | 1429 | buffer[nbytes] = 0; /* nul-terminate */ |
1392 | * This was already checked for in cgroup_file_write(), but | 1430 | strstrip(buffer); |
1393 | * check again now we're holding cgroup_mutex. | 1431 | retval = cft->write_string(cgrp, cft, buffer); |
1394 | */ | 1432 | if (!retval) |
1395 | if (cgroup_is_removed(cgrp)) { | ||
1396 | retval = -ENODEV; | ||
1397 | goto out2; | ||
1398 | } | ||
1399 | |||
1400 | switch (type) { | ||
1401 | case FILE_TASKLIST: | ||
1402 | retval = attach_task_by_pid(cgrp, buffer); | ||
1403 | break; | ||
1404 | case FILE_NOTIFY_ON_RELEASE: | ||
1405 | clear_bit(CGRP_RELEASABLE, &cgrp->flags); | ||
1406 | if (simple_strtoul(buffer, NULL, 10) != 0) | ||
1407 | set_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags); | ||
1408 | else | ||
1409 | clear_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags); | ||
1410 | break; | ||
1411 | case FILE_RELEASE_AGENT: | ||
1412 | BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX); | ||
1413 | strcpy(cgrp->root->release_agent_path, buffer); | ||
1414 | break; | ||
1415 | default: | ||
1416 | retval = -EINVAL; | ||
1417 | goto out2; | ||
1418 | } | ||
1419 | |||
1420 | if (retval == 0) | ||
1421 | retval = nbytes; | 1433 | retval = nbytes; |
1422 | out2: | 1434 | if (buffer != local_buffer) |
1423 | mutex_unlock(&cgroup_mutex); | 1435 | kfree(buffer); |
1424 | out1: | ||
1425 | kfree(buffer); | ||
1426 | return retval; | 1436 | return retval; |
1427 | } | 1437 | } |
1428 | 1438 | ||
@@ -1438,6 +1448,8 @@ static ssize_t cgroup_file_write(struct file *file, const char __user *buf, | |||
1438 | return cft->write(cgrp, cft, file, buf, nbytes, ppos); | 1448 | return cft->write(cgrp, cft, file, buf, nbytes, ppos); |
1439 | if (cft->write_u64 || cft->write_s64) | 1449 | if (cft->write_u64 || cft->write_s64) |
1440 | return cgroup_write_X64(cgrp, cft, file, buf, nbytes, ppos); | 1450 | return cgroup_write_X64(cgrp, cft, file, buf, nbytes, ppos); |
1451 | if (cft->write_string) | ||
1452 | return cgroup_write_string(cgrp, cft, file, buf, nbytes, ppos); | ||
1441 | if (cft->trigger) { | 1453 | if (cft->trigger) { |
1442 | int ret = cft->trigger(cgrp, (unsigned int)cft->private); | 1454 | int ret = cft->trigger(cgrp, (unsigned int)cft->private); |
1443 | return ret ? ret : nbytes; | 1455 | return ret ? ret : nbytes; |
@@ -1450,7 +1462,7 @@ static ssize_t cgroup_read_u64(struct cgroup *cgrp, struct cftype *cft, | |||
1450 | char __user *buf, size_t nbytes, | 1462 | char __user *buf, size_t nbytes, |
1451 | loff_t *ppos) | 1463 | loff_t *ppos) |
1452 | { | 1464 | { |
1453 | char tmp[64]; | 1465 | char tmp[CGROUP_LOCAL_BUFFER_SIZE]; |
1454 | u64 val = cft->read_u64(cgrp, cft); | 1466 | u64 val = cft->read_u64(cgrp, cft); |
1455 | int len = sprintf(tmp, "%llu\n", (unsigned long long) val); | 1467 | int len = sprintf(tmp, "%llu\n", (unsigned long long) val); |
1456 | 1468 | ||
@@ -1462,56 +1474,13 @@ static ssize_t cgroup_read_s64(struct cgroup *cgrp, struct cftype *cft, | |||
1462 | char __user *buf, size_t nbytes, | 1474 | char __user *buf, size_t nbytes, |
1463 | loff_t *ppos) | 1475 | loff_t *ppos) |
1464 | { | 1476 | { |
1465 | char tmp[64]; | 1477 | char tmp[CGROUP_LOCAL_BUFFER_SIZE]; |
1466 | s64 val = cft->read_s64(cgrp, cft); | 1478 | s64 val = cft->read_s64(cgrp, cft); |
1467 | int len = sprintf(tmp, "%lld\n", (long long) val); | 1479 | int len = sprintf(tmp, "%lld\n", (long long) val); |
1468 | 1480 | ||
1469 | return simple_read_from_buffer(buf, nbytes, ppos, tmp, len); | 1481 | return simple_read_from_buffer(buf, nbytes, ppos, tmp, len); |
1470 | } | 1482 | } |
1471 | 1483 | ||
1472 | static ssize_t cgroup_common_file_read(struct cgroup *cgrp, | ||
1473 | struct cftype *cft, | ||
1474 | struct file *file, | ||
1475 | char __user *buf, | ||
1476 | size_t nbytes, loff_t *ppos) | ||
1477 | { | ||
1478 | enum cgroup_filetype type = cft->private; | ||
1479 | char *page; | ||
1480 | ssize_t retval = 0; | ||
1481 | char *s; | ||
1482 | |||
1483 | if (!(page = (char *)__get_free_page(GFP_KERNEL))) | ||
1484 | return -ENOMEM; | ||
1485 | |||
1486 | s = page; | ||
1487 | |||
1488 | switch (type) { | ||
1489 | case FILE_RELEASE_AGENT: | ||
1490 | { | ||
1491 | struct cgroupfs_root *root; | ||
1492 | size_t n; | ||
1493 | mutex_lock(&cgroup_mutex); | ||
1494 | root = cgrp->root; | ||
1495 | n = strnlen(root->release_agent_path, | ||
1496 | sizeof(root->release_agent_path)); | ||
1497 | n = min(n, (size_t) PAGE_SIZE); | ||
1498 | strncpy(s, root->release_agent_path, n); | ||
1499 | mutex_unlock(&cgroup_mutex); | ||
1500 | s += n; | ||
1501 | break; | ||
1502 | } | ||
1503 | default: | ||
1504 | retval = -EINVAL; | ||
1505 | goto out; | ||
1506 | } | ||
1507 | *s++ = '\n'; | ||
1508 | |||
1509 | retval = simple_read_from_buffer(buf, nbytes, ppos, page, s - page); | ||
1510 | out: | ||
1511 | free_page((unsigned long)page); | ||
1512 | return retval; | ||
1513 | } | ||
1514 | |||
1515 | static ssize_t cgroup_file_read(struct file *file, char __user *buf, | 1484 | static ssize_t cgroup_file_read(struct file *file, char __user *buf, |
1516 | size_t nbytes, loff_t *ppos) | 1485 | size_t nbytes, loff_t *ppos) |
1517 | { | 1486 | { |
@@ -1569,6 +1538,7 @@ int cgroup_seqfile_release(struct inode *inode, struct file *file) | |||
1569 | 1538 | ||
1570 | static struct file_operations cgroup_seqfile_operations = { | 1539 | static struct file_operations cgroup_seqfile_operations = { |
1571 | .read = seq_read, | 1540 | .read = seq_read, |
1541 | .write = cgroup_file_write, | ||
1572 | .llseek = seq_lseek, | 1542 | .llseek = seq_lseek, |
1573 | .release = cgroup_seqfile_release, | 1543 | .release = cgroup_seqfile_release, |
1574 | }; | 1544 | }; |
@@ -1756,15 +1726,11 @@ int cgroup_add_files(struct cgroup *cgrp, | |||
1756 | int cgroup_task_count(const struct cgroup *cgrp) | 1726 | int cgroup_task_count(const struct cgroup *cgrp) |
1757 | { | 1727 | { |
1758 | int count = 0; | 1728 | int count = 0; |
1759 | struct list_head *l; | 1729 | struct cg_cgroup_link *link; |
1760 | 1730 | ||
1761 | read_lock(&css_set_lock); | 1731 | read_lock(&css_set_lock); |
1762 | l = cgrp->css_sets.next; | 1732 | list_for_each_entry(link, &cgrp->css_sets, cgrp_link_list) { |
1763 | while (l != &cgrp->css_sets) { | ||
1764 | struct cg_cgroup_link *link = | ||
1765 | list_entry(l, struct cg_cgroup_link, cgrp_link_list); | ||
1766 | count += atomic_read(&link->cg->ref.refcount); | 1733 | count += atomic_read(&link->cg->ref.refcount); |
1767 | l = l->next; | ||
1768 | } | 1734 | } |
1769 | read_unlock(&css_set_lock); | 1735 | read_unlock(&css_set_lock); |
1770 | return count; | 1736 | return count; |
@@ -2227,6 +2193,18 @@ static u64 cgroup_read_notify_on_release(struct cgroup *cgrp, | |||
2227 | return notify_on_release(cgrp); | 2193 | return notify_on_release(cgrp); |
2228 | } | 2194 | } |
2229 | 2195 | ||
2196 | static int cgroup_write_notify_on_release(struct cgroup *cgrp, | ||
2197 | struct cftype *cft, | ||
2198 | u64 val) | ||
2199 | { | ||
2200 | clear_bit(CGRP_RELEASABLE, &cgrp->flags); | ||
2201 | if (val) | ||
2202 | set_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags); | ||
2203 | else | ||
2204 | clear_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags); | ||
2205 | return 0; | ||
2206 | } | ||
2207 | |||
2230 | /* | 2208 | /* |
2231 | * for the common functions, 'private' gives the type of file | 2209 | * for the common functions, 'private' gives the type of file |
2232 | */ | 2210 | */ |
@@ -2235,7 +2213,7 @@ static struct cftype files[] = { | |||
2235 | .name = "tasks", | 2213 | .name = "tasks", |
2236 | .open = cgroup_tasks_open, | 2214 | .open = cgroup_tasks_open, |
2237 | .read = cgroup_tasks_read, | 2215 | .read = cgroup_tasks_read, |
2238 | .write = cgroup_common_file_write, | 2216 | .write_u64 = cgroup_tasks_write, |
2239 | .release = cgroup_tasks_release, | 2217 | .release = cgroup_tasks_release, |
2240 | .private = FILE_TASKLIST, | 2218 | .private = FILE_TASKLIST, |
2241 | }, | 2219 | }, |
@@ -2243,15 +2221,16 @@ static struct cftype files[] = { | |||
2243 | { | 2221 | { |
2244 | .name = "notify_on_release", | 2222 | .name = "notify_on_release", |
2245 | .read_u64 = cgroup_read_notify_on_release, | 2223 | .read_u64 = cgroup_read_notify_on_release, |
2246 | .write = cgroup_common_file_write, | 2224 | .write_u64 = cgroup_write_notify_on_release, |
2247 | .private = FILE_NOTIFY_ON_RELEASE, | 2225 | .private = FILE_NOTIFY_ON_RELEASE, |
2248 | }, | 2226 | }, |
2249 | }; | 2227 | }; |
2250 | 2228 | ||
2251 | static struct cftype cft_release_agent = { | 2229 | static struct cftype cft_release_agent = { |
2252 | .name = "release_agent", | 2230 | .name = "release_agent", |
2253 | .read = cgroup_common_file_read, | 2231 | .read_seq_string = cgroup_release_agent_show, |
2254 | .write = cgroup_common_file_write, | 2232 | .write_string = cgroup_release_agent_write, |
2233 | .max_write_len = PATH_MAX, | ||
2255 | .private = FILE_RELEASE_AGENT, | 2234 | .private = FILE_RELEASE_AGENT, |
2256 | }; | 2235 | }; |
2257 | 2236 | ||
@@ -2869,16 +2848,17 @@ void cgroup_exit(struct task_struct *tsk, int run_callbacks) | |||
2869 | * cgroup_clone - clone the cgroup the given subsystem is attached to | 2848 | * cgroup_clone - clone the cgroup the given subsystem is attached to |
2870 | * @tsk: the task to be moved | 2849 | * @tsk: the task to be moved |
2871 | * @subsys: the given subsystem | 2850 | * @subsys: the given subsystem |
2851 | * @nodename: the name for the new cgroup | ||
2872 | * | 2852 | * |
2873 | * Duplicate the current cgroup in the hierarchy that the given | 2853 | * Duplicate the current cgroup in the hierarchy that the given |
2874 | * subsystem is attached to, and move this task into the new | 2854 | * subsystem is attached to, and move this task into the new |
2875 | * child. | 2855 | * child. |
2876 | */ | 2856 | */ |
2877 | int cgroup_clone(struct task_struct *tsk, struct cgroup_subsys *subsys) | 2857 | int cgroup_clone(struct task_struct *tsk, struct cgroup_subsys *subsys, |
2858 | char *nodename) | ||
2878 | { | 2859 | { |
2879 | struct dentry *dentry; | 2860 | struct dentry *dentry; |
2880 | int ret = 0; | 2861 | int ret = 0; |
2881 | char nodename[MAX_CGROUP_TYPE_NAMELEN]; | ||
2882 | struct cgroup *parent, *child; | 2862 | struct cgroup *parent, *child; |
2883 | struct inode *inode; | 2863 | struct inode *inode; |
2884 | struct css_set *cg; | 2864 | struct css_set *cg; |
@@ -2903,8 +2883,6 @@ int cgroup_clone(struct task_struct *tsk, struct cgroup_subsys *subsys) | |||
2903 | cg = tsk->cgroups; | 2883 | cg = tsk->cgroups; |
2904 | parent = task_cgroup(tsk, subsys->subsys_id); | 2884 | parent = task_cgroup(tsk, subsys->subsys_id); |
2905 | 2885 | ||
2906 | snprintf(nodename, MAX_CGROUP_TYPE_NAMELEN, "%d", tsk->pid); | ||
2907 | |||
2908 | /* Pin the hierarchy */ | 2886 | /* Pin the hierarchy */ |
2909 | atomic_inc(&parent->root->sb->s_active); | 2887 | atomic_inc(&parent->root->sb->s_active); |
2910 | 2888 | ||
@@ -3078,27 +3056,24 @@ static void cgroup_release_agent(struct work_struct *work) | |||
3078 | while (!list_empty(&release_list)) { | 3056 | while (!list_empty(&release_list)) { |
3079 | char *argv[3], *envp[3]; | 3057 | char *argv[3], *envp[3]; |
3080 | int i; | 3058 | int i; |
3081 | char *pathbuf; | 3059 | char *pathbuf = NULL, *agentbuf = NULL; |
3082 | struct cgroup *cgrp = list_entry(release_list.next, | 3060 | struct cgroup *cgrp = list_entry(release_list.next, |
3083 | struct cgroup, | 3061 | struct cgroup, |
3084 | release_list); | 3062 | release_list); |
3085 | list_del_init(&cgrp->release_list); | 3063 | list_del_init(&cgrp->release_list); |
3086 | spin_unlock(&release_list_lock); | 3064 | spin_unlock(&release_list_lock); |
3087 | pathbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); | 3065 | pathbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); |
3088 | if (!pathbuf) { | 3066 | if (!pathbuf) |
3089 | spin_lock(&release_list_lock); | 3067 | goto continue_free; |
3090 | continue; | 3068 | if (cgroup_path(cgrp, pathbuf, PAGE_SIZE) < 0) |
3091 | } | 3069 | goto continue_free; |
3092 | 3070 | agentbuf = kstrdup(cgrp->root->release_agent_path, GFP_KERNEL); | |
3093 | if (cgroup_path(cgrp, pathbuf, PAGE_SIZE) < 0) { | 3071 | if (!agentbuf) |
3094 | kfree(pathbuf); | 3072 | goto continue_free; |
3095 | spin_lock(&release_list_lock); | ||
3096 | continue; | ||
3097 | } | ||
3098 | 3073 | ||
3099 | i = 0; | 3074 | i = 0; |
3100 | argv[i++] = cgrp->root->release_agent_path; | 3075 | argv[i++] = agentbuf; |
3101 | argv[i++] = (char *)pathbuf; | 3076 | argv[i++] = pathbuf; |
3102 | argv[i] = NULL; | 3077 | argv[i] = NULL; |
3103 | 3078 | ||
3104 | i = 0; | 3079 | i = 0; |
@@ -3112,8 +3087,10 @@ static void cgroup_release_agent(struct work_struct *work) | |||
3112 | * be a slow process */ | 3087 | * be a slow process */ |
3113 | mutex_unlock(&cgroup_mutex); | 3088 | mutex_unlock(&cgroup_mutex); |
3114 | call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC); | 3089 | call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC); |
3115 | kfree(pathbuf); | ||
3116 | mutex_lock(&cgroup_mutex); | 3090 | mutex_lock(&cgroup_mutex); |
3091 | continue_free: | ||
3092 | kfree(pathbuf); | ||
3093 | kfree(agentbuf); | ||
3117 | spin_lock(&release_list_lock); | 3094 | spin_lock(&release_list_lock); |
3118 | } | 3095 | } |
3119 | spin_unlock(&release_list_lock); | 3096 | spin_unlock(&release_list_lock); |