diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/cgroup.c | 95 |
1 files changed, 24 insertions, 71 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 14efffed72c8..22db0a7cf1fa 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
| @@ -1121,7 +1121,6 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp) | |||
| 1121 | INIT_LIST_HEAD(&cgrp->children); | 1121 | INIT_LIST_HEAD(&cgrp->children); |
| 1122 | INIT_LIST_HEAD(&cgrp->css_sets); | 1122 | INIT_LIST_HEAD(&cgrp->css_sets); |
| 1123 | INIT_LIST_HEAD(&cgrp->release_list); | 1123 | INIT_LIST_HEAD(&cgrp->release_list); |
| 1124 | INIT_LIST_HEAD(&cgrp->pids_list); | ||
| 1125 | init_rwsem(&cgrp->pids_mutex); | 1124 | init_rwsem(&cgrp->pids_mutex); |
| 1126 | } | 1125 | } |
| 1127 | 1126 | ||
| @@ -2431,30 +2430,12 @@ err: | |||
| 2431 | return ret; | 2430 | return ret; |
| 2432 | } | 2431 | } |
| 2433 | 2432 | ||
| 2434 | /* | ||
| 2435 | * Cache pids for all threads in the same pid namespace that are | ||
| 2436 | * opening the same "tasks" file. | ||
| 2437 | */ | ||
| 2438 | struct cgroup_pids { | ||
| 2439 | /* The node in cgrp->pids_list */ | ||
| 2440 | struct list_head list; | ||
| 2441 | /* The cgroup those pids belong to */ | ||
| 2442 | struct cgroup *cgrp; | ||
| 2443 | /* The namepsace those pids belong to */ | ||
| 2444 | struct pid_namespace *ns; | ||
| 2445 | /* Array of process ids in the cgroup */ | ||
| 2446 | pid_t *tasks_pids; | ||
| 2447 | /* How many files are using the this tasks_pids array */ | ||
| 2448 | int use_count; | ||
| 2449 | /* Length of the current tasks_pids array */ | ||
| 2450 | int length; | ||
| 2451 | }; | ||
| 2452 | |||
| 2453 | static int cmppid(const void *a, const void *b) | 2433 | static int cmppid(const void *a, const void *b) |
| 2454 | { | 2434 | { |
| 2455 | return *(pid_t *)a - *(pid_t *)b; | 2435 | return *(pid_t *)a - *(pid_t *)b; |
| 2456 | } | 2436 | } |
| 2457 | 2437 | ||
| 2438 | |||
| 2458 | /* | 2439 | /* |
| 2459 | * seq_file methods for the "tasks" file. The seq_file position is the | 2440 | * seq_file methods for the "tasks" file. The seq_file position is the |
| 2460 | * next pid to display; the seq_file iterator is a pointer to the pid | 2441 | * next pid to display; the seq_file iterator is a pointer to the pid |
| @@ -2469,47 +2450,45 @@ static void *cgroup_tasks_start(struct seq_file *s, loff_t *pos) | |||
| 2469 | * after a seek to the start). Use a binary-search to find the | 2450 | * after a seek to the start). Use a binary-search to find the |
| 2470 | * next pid to display, if any | 2451 | * next pid to display, if any |
| 2471 | */ | 2452 | */ |
| 2472 | struct cgroup_pids *cp = s->private; | 2453 | struct cgroup *cgrp = s->private; |
| 2473 | struct cgroup *cgrp = cp->cgrp; | ||
| 2474 | int index = 0, pid = *pos; | 2454 | int index = 0, pid = *pos; |
| 2475 | int *iter; | 2455 | int *iter; |
| 2476 | 2456 | ||
| 2477 | down_read(&cgrp->pids_mutex); | 2457 | down_read(&cgrp->pids_mutex); |
| 2478 | if (pid) { | 2458 | if (pid) { |
| 2479 | int end = cp->length; | 2459 | int end = cgrp->pids_length; |
| 2480 | 2460 | ||
| 2481 | while (index < end) { | 2461 | while (index < end) { |
| 2482 | int mid = (index + end) / 2; | 2462 | int mid = (index + end) / 2; |
| 2483 | if (cp->tasks_pids[mid] == pid) { | 2463 | if (cgrp->tasks_pids[mid] == pid) { |
| 2484 | index = mid; | 2464 | index = mid; |
| 2485 | break; | 2465 | break; |
| 2486 | } else if (cp->tasks_pids[mid] <= pid) | 2466 | } else if (cgrp->tasks_pids[mid] <= pid) |
| 2487 | index = mid + 1; | 2467 | index = mid + 1; |
| 2488 | else | 2468 | else |
| 2489 | end = mid; | 2469 | end = mid; |
| 2490 | } | 2470 | } |
| 2491 | } | 2471 | } |
| 2492 | /* If we're off the end of the array, we're done */ | 2472 | /* If we're off the end of the array, we're done */ |
| 2493 | if (index >= cp->length) | 2473 | if (index >= cgrp->pids_length) |
| 2494 | return NULL; | 2474 | return NULL; |
| 2495 | /* Update the abstract position to be the actual pid that we found */ | 2475 | /* Update the abstract position to be the actual pid that we found */ |
| 2496 | iter = cp->tasks_pids + index; | 2476 | iter = cgrp->tasks_pids + index; |
| 2497 | *pos = *iter; | 2477 | *pos = *iter; |
| 2498 | return iter; | 2478 | return iter; |
| 2499 | } | 2479 | } |
| 2500 | 2480 | ||
| 2501 | static void cgroup_tasks_stop(struct seq_file *s, void *v) | 2481 | static void cgroup_tasks_stop(struct seq_file *s, void *v) |
| 2502 | { | 2482 | { |
| 2503 | struct cgroup_pids *cp = s->private; | 2483 | struct cgroup *cgrp = s->private; |
| 2504 | struct cgroup *cgrp = cp->cgrp; | ||
| 2505 | up_read(&cgrp->pids_mutex); | 2484 | up_read(&cgrp->pids_mutex); |
| 2506 | } | 2485 | } |
| 2507 | 2486 | ||
| 2508 | static void *cgroup_tasks_next(struct seq_file *s, void *v, loff_t *pos) | 2487 | static void *cgroup_tasks_next(struct seq_file *s, void *v, loff_t *pos) |
| 2509 | { | 2488 | { |
| 2510 | struct cgroup_pids *cp = s->private; | 2489 | struct cgroup *cgrp = s->private; |
| 2511 | int *p = v; | 2490 | int *p = v; |
| 2512 | int *end = cp->tasks_pids + cp->length; | 2491 | int *end = cgrp->tasks_pids + cgrp->pids_length; |
| 2513 | 2492 | ||
| 2514 | /* | 2493 | /* |
| 2515 | * Advance to the next pid in the array. If this goes off the | 2494 | * Advance to the next pid in the array. If this goes off the |
| @@ -2536,33 +2515,26 @@ static const struct seq_operations cgroup_tasks_seq_operations = { | |||
| 2536 | .show = cgroup_tasks_show, | 2515 | .show = cgroup_tasks_show, |
| 2537 | }; | 2516 | }; |
| 2538 | 2517 | ||
| 2539 | static void release_cgroup_pid_array(struct cgroup_pids *cp) | 2518 | static void release_cgroup_pid_array(struct cgroup *cgrp) |
| 2540 | { | 2519 | { |
| 2541 | struct cgroup *cgrp = cp->cgrp; | ||
| 2542 | |||
| 2543 | down_write(&cgrp->pids_mutex); | 2520 | down_write(&cgrp->pids_mutex); |
| 2544 | BUG_ON(!cp->use_count); | 2521 | BUG_ON(!cgrp->pids_use_count); |
| 2545 | if (!--cp->use_count) { | 2522 | if (!--cgrp->pids_use_count) { |
| 2546 | list_del(&cp->list); | 2523 | kfree(cgrp->tasks_pids); |
| 2547 | put_pid_ns(cp->ns); | 2524 | cgrp->tasks_pids = NULL; |
| 2548 | kfree(cp->tasks_pids); | 2525 | cgrp->pids_length = 0; |
| 2549 | kfree(cp); | ||
| 2550 | } | 2526 | } |
| 2551 | up_write(&cgrp->pids_mutex); | 2527 | up_write(&cgrp->pids_mutex); |
| 2552 | } | 2528 | } |
| 2553 | 2529 | ||
| 2554 | static int cgroup_tasks_release(struct inode *inode, struct file *file) | 2530 | static int cgroup_tasks_release(struct inode *inode, struct file *file) |
| 2555 | { | 2531 | { |
| 2556 | struct seq_file *seq; | 2532 | struct cgroup *cgrp = __d_cgrp(file->f_dentry->d_parent); |
| 2557 | struct cgroup_pids *cp; | ||
| 2558 | 2533 | ||
| 2559 | if (!(file->f_mode & FMODE_READ)) | 2534 | if (!(file->f_mode & FMODE_READ)) |
| 2560 | return 0; | 2535 | return 0; |
| 2561 | 2536 | ||
| 2562 | seq = file->private_data; | 2537 | release_cgroup_pid_array(cgrp); |
| 2563 | cp = seq->private; | ||
| 2564 | |||
| 2565 | release_cgroup_pid_array(cp); | ||
| 2566 | return seq_release(inode, file); | 2538 | return seq_release(inode, file); |
| 2567 | } | 2539 | } |
| 2568 | 2540 | ||
| @@ -2581,8 +2553,6 @@ static struct file_operations cgroup_tasks_operations = { | |||
| 2581 | static int cgroup_tasks_open(struct inode *unused, struct file *file) | 2553 | static int cgroup_tasks_open(struct inode *unused, struct file *file) |
| 2582 | { | 2554 | { |
| 2583 | struct cgroup *cgrp = __d_cgrp(file->f_dentry->d_parent); | 2555 | struct cgroup *cgrp = __d_cgrp(file->f_dentry->d_parent); |
| 2584 | struct pid_namespace *ns = current->nsproxy->pid_ns; | ||
| 2585 | struct cgroup_pids *cp; | ||
| 2586 | pid_t *pidarray; | 2556 | pid_t *pidarray; |
| 2587 | int npids; | 2557 | int npids; |
| 2588 | int retval; | 2558 | int retval; |
| @@ -2609,37 +2579,20 @@ static int cgroup_tasks_open(struct inode *unused, struct file *file) | |||
| 2609 | * array if necessary | 2579 | * array if necessary |
| 2610 | */ | 2580 | */ |
| 2611 | down_write(&cgrp->pids_mutex); | 2581 | down_write(&cgrp->pids_mutex); |
| 2612 | 2582 | kfree(cgrp->tasks_pids); | |
| 2613 | list_for_each_entry(cp, &cgrp->pids_list, list) { | 2583 | cgrp->tasks_pids = pidarray; |
| 2614 | if (ns == cp->ns) | 2584 | cgrp->pids_length = npids; |
| 2615 | goto found; | 2585 | cgrp->pids_use_count++; |
| 2616 | } | ||
| 2617 | |||
| 2618 | cp = kzalloc(sizeof(*cp), GFP_KERNEL); | ||
| 2619 | if (!cp) { | ||
| 2620 | up_write(&cgrp->pids_mutex); | ||
| 2621 | kfree(pidarray); | ||
| 2622 | return -ENOMEM; | ||
| 2623 | } | ||
| 2624 | cp->cgrp = cgrp; | ||
| 2625 | cp->ns = ns; | ||
| 2626 | get_pid_ns(ns); | ||
| 2627 | list_add(&cp->list, &cgrp->pids_list); | ||
| 2628 | found: | ||
| 2629 | kfree(cp->tasks_pids); | ||
| 2630 | cp->tasks_pids = pidarray; | ||
| 2631 | cp->length = npids; | ||
| 2632 | cp->use_count++; | ||
| 2633 | up_write(&cgrp->pids_mutex); | 2586 | up_write(&cgrp->pids_mutex); |
| 2634 | 2587 | ||
| 2635 | file->f_op = &cgroup_tasks_operations; | 2588 | file->f_op = &cgroup_tasks_operations; |
| 2636 | 2589 | ||
| 2637 | retval = seq_open(file, &cgroup_tasks_seq_operations); | 2590 | retval = seq_open(file, &cgroup_tasks_seq_operations); |
| 2638 | if (retval) { | 2591 | if (retval) { |
| 2639 | release_cgroup_pid_array(cp); | 2592 | release_cgroup_pid_array(cgrp); |
| 2640 | return retval; | 2593 | return retval; |
| 2641 | } | 2594 | } |
| 2642 | ((struct seq_file *)file->private_data)->private = cp; | 2595 | ((struct seq_file *)file->private_data)->private = cgrp; |
| 2643 | return 0; | 2596 | return 0; |
| 2644 | } | 2597 | } |
| 2645 | 2598 | ||
