diff options
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r-- | kernel/cgroup.c | 162 |
1 files changed, 0 insertions, 162 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 89428b9d9933..05c0c23549f9 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -2697,168 +2697,6 @@ void css_task_iter_end(struct css_task_iter *it) | |||
2697 | up_read(&css_set_rwsem); | 2697 | up_read(&css_set_rwsem); |
2698 | } | 2698 | } |
2699 | 2699 | ||
2700 | static inline int started_after_time(struct task_struct *t1, | ||
2701 | struct timespec *time, | ||
2702 | struct task_struct *t2) | ||
2703 | { | ||
2704 | int start_diff = timespec_compare(&t1->start_time, time); | ||
2705 | if (start_diff > 0) { | ||
2706 | return 1; | ||
2707 | } else if (start_diff < 0) { | ||
2708 | return 0; | ||
2709 | } else { | ||
2710 | /* | ||
2711 | * Arbitrarily, if two processes started at the same | ||
2712 | * time, we'll say that the lower pointer value | ||
2713 | * started first. Note that t2 may have exited by now | ||
2714 | * so this may not be a valid pointer any longer, but | ||
2715 | * that's fine - it still serves to distinguish | ||
2716 | * between two tasks started (effectively) simultaneously. | ||
2717 | */ | ||
2718 | return t1 > t2; | ||
2719 | } | ||
2720 | } | ||
2721 | |||
2722 | /* | ||
2723 | * This function is a callback from heap_insert() and is used to order | ||
2724 | * the heap. | ||
2725 | * In this case we order the heap in descending task start time. | ||
2726 | */ | ||
2727 | static inline int started_after(void *p1, void *p2) | ||
2728 | { | ||
2729 | struct task_struct *t1 = p1; | ||
2730 | struct task_struct *t2 = p2; | ||
2731 | return started_after_time(t1, &t2->start_time, t2); | ||
2732 | } | ||
2733 | |||
2734 | /** | ||
2735 | * css_scan_tasks - iterate though all the tasks in a css | ||
2736 | * @css: the css to iterate tasks of | ||
2737 | * @test: optional test callback | ||
2738 | * @process: process callback | ||
2739 | * @data: data passed to @test and @process | ||
2740 | * @heap: optional pre-allocated heap used for task iteration | ||
2741 | * | ||
2742 | * Iterate through all the tasks in @css, calling @test for each, and if it | ||
2743 | * returns %true, call @process for it also. | ||
2744 | * | ||
2745 | * @test may be NULL, meaning always true (select all tasks), which | ||
2746 | * effectively duplicates css_task_iter_{start,next,end}() but does not | ||
2747 | * lock css_set_rwsem for the call to @process. | ||
2748 | * | ||
2749 | * It is guaranteed that @process will act on every task that is a member | ||
2750 | * of @css for the duration of this call. This function may or may not | ||
2751 | * call @process for tasks that exit or move to a different css during the | ||
2752 | * call, or are forked or move into the css during the call. | ||
2753 | * | ||
2754 | * Note that @test may be called with locks held, and may in some | ||
2755 | * situations be called multiple times for the same task, so it should be | ||
2756 | * cheap. | ||
2757 | * | ||
2758 | * If @heap is non-NULL, a heap has been pre-allocated and will be used for | ||
2759 | * heap operations (and its "gt" member will be overwritten), else a | ||
2760 | * temporary heap will be used (allocation of which may cause this function | ||
2761 | * to fail). | ||
2762 | */ | ||
2763 | int css_scan_tasks(struct cgroup_subsys_state *css, | ||
2764 | bool (*test)(struct task_struct *, void *), | ||
2765 | void (*process)(struct task_struct *, void *), | ||
2766 | void *data, struct ptr_heap *heap) | ||
2767 | { | ||
2768 | int retval, i; | ||
2769 | struct css_task_iter it; | ||
2770 | struct task_struct *p, *dropped; | ||
2771 | /* Never dereference latest_task, since it's not refcounted */ | ||
2772 | struct task_struct *latest_task = NULL; | ||
2773 | struct ptr_heap tmp_heap; | ||
2774 | struct timespec latest_time = { 0, 0 }; | ||
2775 | |||
2776 | if (heap) { | ||
2777 | /* The caller supplied our heap and pre-allocated its memory */ | ||
2778 | heap->gt = &started_after; | ||
2779 | } else { | ||
2780 | /* We need to allocate our own heap memory */ | ||
2781 | heap = &tmp_heap; | ||
2782 | retval = heap_init(heap, PAGE_SIZE, GFP_KERNEL, &started_after); | ||
2783 | if (retval) | ||
2784 | /* cannot allocate the heap */ | ||
2785 | return retval; | ||
2786 | } | ||
2787 | |||
2788 | again: | ||
2789 | /* | ||
2790 | * Scan tasks in the css, using the @test callback to determine | ||
2791 | * which are of interest, and invoking @process callback on the | ||
2792 | * ones which need an update. Since we don't want to hold any | ||
2793 | * locks during the task updates, gather tasks to be processed in a | ||
2794 | * heap structure. The heap is sorted by descending task start | ||
2795 | * time. If the statically-sized heap fills up, we overflow tasks | ||
2796 | * that started later, and in future iterations only consider tasks | ||
2797 | * that started after the latest task in the previous pass. This | ||
2798 | * guarantees forward progress and that we don't miss any tasks. | ||
2799 | */ | ||
2800 | heap->size = 0; | ||
2801 | css_task_iter_start(css, &it); | ||
2802 | while ((p = css_task_iter_next(&it))) { | ||
2803 | /* | ||
2804 | * Only affect tasks that qualify per the caller's callback, | ||
2805 | * if he provided one | ||
2806 | */ | ||
2807 | if (test && !test(p, data)) | ||
2808 | continue; | ||
2809 | /* | ||
2810 | * Only process tasks that started after the last task | ||
2811 | * we processed | ||
2812 | */ | ||
2813 | if (!started_after_time(p, &latest_time, latest_task)) | ||
2814 | continue; | ||
2815 | dropped = heap_insert(heap, p); | ||
2816 | if (dropped == NULL) { | ||
2817 | /* | ||
2818 | * The new task was inserted; the heap wasn't | ||
2819 | * previously full | ||
2820 | */ | ||
2821 | get_task_struct(p); | ||
2822 | } else if (dropped != p) { | ||
2823 | /* | ||
2824 | * The new task was inserted, and pushed out a | ||
2825 | * different task | ||
2826 | */ | ||
2827 | get_task_struct(p); | ||
2828 | put_task_struct(dropped); | ||
2829 | } | ||
2830 | /* | ||
2831 | * Else the new task was newer than anything already in | ||
2832 | * the heap and wasn't inserted | ||
2833 | */ | ||
2834 | } | ||
2835 | css_task_iter_end(&it); | ||
2836 | |||
2837 | if (heap->size) { | ||
2838 | for (i = 0; i < heap->size; i++) { | ||
2839 | struct task_struct *q = heap->ptrs[i]; | ||
2840 | if (i == 0) { | ||
2841 | latest_time = q->start_time; | ||
2842 | latest_task = q; | ||
2843 | } | ||
2844 | /* Process the task per the caller's callback */ | ||
2845 | process(q, data); | ||
2846 | put_task_struct(q); | ||
2847 | } | ||
2848 | /* | ||
2849 | * If we had to process any tasks at all, scan again | ||
2850 | * in case some of them were in the middle of forking | ||
2851 | * children that didn't get processed. | ||
2852 | * Not the most efficient way to do it, but it avoids | ||
2853 | * having to take callback_mutex in the fork path | ||
2854 | */ | ||
2855 | goto again; | ||
2856 | } | ||
2857 | if (heap == &tmp_heap) | ||
2858 | heap_free(&tmp_heap); | ||
2859 | return 0; | ||
2860 | } | ||
2861 | |||
2862 | /** | 2700 | /** |
2863 | * cgroup_trasnsfer_tasks - move tasks from one cgroup to another | 2701 | * cgroup_trasnsfer_tasks - move tasks from one cgroup to another |
2864 | * @to: cgroup to which the tasks will be moved | 2702 | * @to: cgroup to which the tasks will be moved |