Line 0
Link Here
|
|
|
1 |
#ifdef CONFIG_SCHED_AUTOGROUP |
2 |
|
3 |
unsigned int __read_mostly sysctl_sched_autogroup_enabled = 1; |
4 |
|
5 |
struct autogroup { |
6 |
struct task_group *tg; |
7 |
struct kref kref; |
8 |
unsigned long id; |
9 |
}; |
10 |
|
11 |
static struct autogroup autogroup_default; |
12 |
static atomic_t autogroup_seq_nr; |
13 |
|
14 |
static void autogroup_init(struct task_struct *init_task) |
15 |
{ |
16 |
autogroup_default.tg = &init_task_group; |
17 |
autogroup_default.id = 0; |
18 |
atomic_set(&autogroup_seq_nr, 1); |
19 |
kref_init(&autogroup_default.kref); |
20 |
init_task->signal->autogroup = &autogroup_default; |
21 |
} |
22 |
|
23 |
static inline void autogroup_destroy(struct kref *kref) |
24 |
{ |
25 |
struct autogroup *ag = container_of(kref, struct autogroup, kref); |
26 |
struct task_group *tg = ag->tg; |
27 |
|
28 |
kfree(ag); |
29 |
sched_destroy_group(tg); |
30 |
} |
31 |
|
32 |
static inline void autogroup_kref_put(struct autogroup *ag) |
33 |
{ |
34 |
kref_put(&ag->kref, autogroup_destroy); |
35 |
} |
36 |
|
37 |
static inline struct autogroup *autogroup_kref_get(struct autogroup *ag) |
38 |
{ |
39 |
kref_get(&ag->kref); |
40 |
return ag; |
41 |
} |
42 |
|
43 |
static inline struct autogroup *autogroup_create(void) |
44 |
{ |
45 |
struct autogroup *ag = kmalloc(sizeof(*ag), GFP_KERNEL); |
46 |
|
47 |
if (!ag) |
48 |
goto out_fail; |
49 |
|
50 |
ag->tg = sched_create_group(&init_task_group); |
51 |
|
52 |
if (IS_ERR(ag->tg)) |
53 |
goto out_fail; |
54 |
|
55 |
kref_init(&ag->kref); |
56 |
ag->tg->autogroup = ag; |
57 |
ag->id = atomic_inc_return(&autogroup_seq_nr); |
58 |
|
59 |
return ag; |
60 |
|
61 |
out_fail: |
62 |
if (ag) { |
63 |
kfree(ag); |
64 |
WARN_ON(1); |
65 |
} else |
66 |
WARN_ON(1); |
67 |
|
68 |
return autogroup_kref_get(&autogroup_default); |
69 |
} |
70 |
|
71 |
static inline bool |
72 |
task_wants_autogroup(struct task_struct *p, struct task_group *tg) |
73 |
{ |
74 |
if (tg != &root_task_group) |
75 |
return false; |
76 |
|
77 |
if (p->sched_class != &fair_sched_class) |
78 |
return false; |
79 |
|
80 |
if (p->flags & PF_EXITING) |
81 |
return false; |
82 |
|
83 |
return true; |
84 |
} |
85 |
|
86 |
static inline struct task_group * |
87 |
autogroup_task_group(struct task_struct *p, struct task_group *tg) |
88 |
{ |
89 |
int enabled = ACCESS_ONCE(sysctl_sched_autogroup_enabled); |
90 |
|
91 |
if (enabled && task_wants_autogroup(p, tg)) |
92 |
return p->signal->autogroup->tg; |
93 |
|
94 |
return tg; |
95 |
} |
96 |
|
97 |
static void |
98 |
autogroup_move_group(struct task_struct *p, struct autogroup *ag) |
99 |
{ |
100 |
struct autogroup *prev; |
101 |
struct task_struct *t; |
102 |
|
103 |
spin_lock(&p->sighand->siglock); |
104 |
|
105 |
prev = p->signal->autogroup; |
106 |
if (prev == ag) { |
107 |
spin_unlock(&p->sighand->siglock); |
108 |
return; |
109 |
} |
110 |
|
111 |
p->signal->autogroup = autogroup_kref_get(ag); |
112 |
t = p; |
113 |
|
114 |
do { |
115 |
sched_move_task(p); |
116 |
} while_each_thread(p, t); |
117 |
|
118 |
spin_unlock(&p->sighand->siglock); |
119 |
|
120 |
autogroup_kref_put(prev); |
121 |
} |
122 |
|
123 |
/* Allocates GFP_KERNEL, cannot be called under any spinlock */ |
124 |
void sched_autogroup_create_attach(struct task_struct *p) |
125 |
{ |
126 |
struct autogroup *ag = autogroup_create(); |
127 |
|
128 |
autogroup_move_group(p, ag); |
129 |
/* drop extra refrence added by autogroup_create() */ |
130 |
autogroup_kref_put(ag); |
131 |
} |
132 |
EXPORT_SYMBOL(sched_autogroup_create_attach); |
133 |
|
134 |
/* Cannot be called under siglock. Currently has no users */ |
135 |
void sched_autogroup_detach(struct task_struct *p) |
136 |
{ |
137 |
autogroup_move_group(p, &autogroup_default); |
138 |
} |
139 |
EXPORT_SYMBOL(sched_autogroup_detach); |
140 |
|
141 |
void sched_autogroup_fork(struct signal_struct *sig) |
142 |
{ |
143 |
struct sighand_struct *sighand = current->sighand; |
144 |
|
145 |
spin_lock(&sighand->siglock); |
146 |
sig->autogroup = autogroup_kref_get(current->signal->autogroup); |
147 |
spin_unlock(&sighand->siglock); |
148 |
} |
149 |
|
150 |
void sched_autogroup_exit(struct signal_struct *sig) |
151 |
{ |
152 |
autogroup_kref_put(sig->autogroup); |
153 |
} |
154 |
|
155 |
static int __init setup_autogroup(char *str) |
156 |
{ |
157 |
sysctl_sched_autogroup_enabled = 0; |
158 |
|
159 |
return 1; |
160 |
} |
161 |
|
162 |
__setup("noautogroup", setup_autogroup); |
163 |
|
164 |
#ifdef CONFIG_SCHED_DEBUG |
165 |
static inline int autogroup_path(struct task_group *tg, char *buf, int buflen) |
166 |
{ |
167 |
return snprintf(buf, buflen, "%s-%ld", "autogroup", tg->autogroup->id); |
168 |
} |
169 |
#endif |
170 |
#endif /* CONFIG_SCHED_AUTOGROUP */ |