Blame view

kernel/taskstats.c 15.8 KB
c942fddf8   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
c757249af   Shailabh Nagar   [PATCH] per-task-...
2
3
4
5
6
  /*
   * taskstats.c - Export per-task statistics to userland
   *
   * Copyright (C) Shailabh Nagar, IBM Corp. 2006
   *           (C) Balbir Singh,   IBM Corp. 2006
c757249af   Shailabh Nagar   [PATCH] per-task-...
7
8
9
10
   */
  
  #include <linux/kernel.h>
  #include <linux/taskstats_kern.h>
f3cef7a99   Jay Lan   [PATCH] csa: basi...
11
  #include <linux/tsacct_kern.h>
6f44993fe   Shailabh Nagar   [PATCH] per-task-...
12
  #include <linux/delayacct.h>
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
13
14
  #include <linux/cpumask.h>
  #include <linux/percpu.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
15
  #include <linux/slab.h>
846c7bb05   Balbir Singh   Add cgroupstats
16
17
18
19
  #include <linux/cgroupstats.h>
  #include <linux/cgroup.h>
  #include <linux/fs.h>
  #include <linux/file.h>
4bd6e32ac   Eric W. Biederman   userns: Convert t...
20
  #include <linux/pid_namespace.h>
c757249af   Shailabh Nagar   [PATCH] per-task-...
21
  #include <net/genetlink.h>
60063497a   Arun Sharma   atomic: use <linu...
22
  #include <linux/atomic.h>
8c733420b   Zhang Xiao   taskstats: add e/...
23
  #include <linux/sched/cputime.h>
c757249af   Shailabh Nagar   [PATCH] per-task-...
24

f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
25
26
27
28
29
  /*
   * Maximum length of a cpumask that can be specified in
   * the TASKSTATS_CMD_ATTR_REGISTER/DEREGISTER_CPUMASK attribute
   */
  #define TASKSTATS_CPUMASK_MAXLEN	(100+6*NR_CPUS)
b81f3ea92   Vegard Nossum   taskstats: remove...
30
  static DEFINE_PER_CPU(__u32, taskstats_seqnum);
c757249af   Shailabh Nagar   [PATCH] per-task-...
31
  static int family_registered;
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
32
  struct kmem_cache *taskstats_cache;
c757249af   Shailabh Nagar   [PATCH] per-task-...
33

489111e5c   Johannes Berg   genetlink: static...
34
  static struct genl_family family;
c757249af   Shailabh Nagar   [PATCH] per-task-...
35

b54452b07   Alexey Dobriyan   const: struct nla...
36
  static const struct nla_policy taskstats_cmd_get_policy[TASKSTATS_CMD_ATTR_MAX+1] = {
c757249af   Shailabh Nagar   [PATCH] per-task-...
37
38
  	[TASKSTATS_CMD_ATTR_PID]  = { .type = NLA_U32 },
  	[TASKSTATS_CMD_ATTR_TGID] = { .type = NLA_U32 },
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
39
40
  	[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK] = { .type = NLA_STRING },
  	[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK] = { .type = NLA_STRING },};
243d52126   WANG Cong   taskstats: fix th...
41
42
43
44
45
  /*
   * We have to use TASKSTATS_CMD_ATTR_MAX here, it is the maxattr in the family.
   * Make sure they are always aligned.
   */
  static const struct nla_policy cgroupstats_cmd_get_policy[TASKSTATS_CMD_ATTR_MAX+1] = {
846c7bb05   Balbir Singh   Add cgroupstats
46
47
  	[CGROUPSTATS_CMD_ATTR_FD] = { .type = NLA_U32 },
  };
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
48
49
50
  struct listener {
  	struct list_head list;
  	pid_t pid;
bb129994c   Shailabh Nagar   [PATCH] Remove do...
51
  	char valid;
c757249af   Shailabh Nagar   [PATCH] per-task-...
52
  };
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
53
54
55
56
57
58
59
60
61
62
63
  struct listener_list {
  	struct rw_semaphore sem;
  	struct list_head list;
  };
  static DEFINE_PER_CPU(struct listener_list, listener_array);
  
  enum actions {
  	REGISTER,
  	DEREGISTER,
  	CPU_DONT_CARE
  };
c757249af   Shailabh Nagar   [PATCH] per-task-...
64
65
  
  static int prepare_reply(struct genl_info *info, u8 cmd, struct sk_buff **skbp,
371674853   Oleg Nesterov   [PATCH] taskstats...
66
  				size_t size)
c757249af   Shailabh Nagar   [PATCH] per-task-...
67
68
69
70
71
72
73
  {
  	struct sk_buff *skb;
  	void *reply;
  
  	/*
  	 * If new attributes are added, please revisit this allocation
  	 */
3dabc7157   Thomas Graf   [GENL]: Add genlm...
74
  	skb = genlmsg_new(size, GFP_KERNEL);
c757249af   Shailabh Nagar   [PATCH] per-task-...
75
76
77
78
  	if (!skb)
  		return -ENOMEM;
  
  	if (!info) {
cd85fc58c   Christoph Lameter   taskstats: Use th...
79
  		int seq = this_cpu_inc_return(taskstats_seqnum) - 1;
c757249af   Shailabh Nagar   [PATCH] per-task-...
80

17c157c88   Thomas Graf   [GENL]: Add genlm...
81
  		reply = genlmsg_put(skb, 0, seq, &family, 0, cmd);
c757249af   Shailabh Nagar   [PATCH] per-task-...
82
  	} else
17c157c88   Thomas Graf   [GENL]: Add genlm...
83
  		reply = genlmsg_put_reply(skb, info, &family, 0, cmd);
c757249af   Shailabh Nagar   [PATCH] per-task-...
84
85
86
87
88
89
  	if (reply == NULL) {
  		nlmsg_free(skb);
  		return -EINVAL;
  	}
  
  	*skbp = skb;
c757249af   Shailabh Nagar   [PATCH] per-task-...
90
91
  	return 0;
  }
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
92
93
94
  /*
   * Send taskstats data in @skb to listener with nl_pid @pid
   */
134e63756   Johannes Berg   genetlink: make n...
95
  static int send_reply(struct sk_buff *skb, struct genl_info *info)
c757249af   Shailabh Nagar   [PATCH] per-task-...
96
  {
b529ccf27   Arnaldo Carvalho de Melo   [NETLINK]: Introd...
97
  	struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
98
  	void *reply = genlmsg_data(genlhdr);
c757249af   Shailabh Nagar   [PATCH] per-task-...
99

053c095a8   Johannes Berg   netlink: make nlm...
100
  	genlmsg_end(skb, reply);
c757249af   Shailabh Nagar   [PATCH] per-task-...
101

134e63756   Johannes Berg   genetlink: make n...
102
  	return genlmsg_reply(skb, info);
c757249af   Shailabh Nagar   [PATCH] per-task-...
103
  }
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
104
105
106
  /*
   * Send taskstats data in @skb to listeners registered for @cpu's exit data
   */
115085ea0   Oleg Nesterov   [PATCH] taskstats...
107
108
  static void send_cpu_listeners(struct sk_buff *skb,
  					struct listener_list *listeners)
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
109
  {
b529ccf27   Arnaldo Carvalho de Melo   [NETLINK]: Introd...
110
  	struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
111
112
113
  	struct listener *s, *tmp;
  	struct sk_buff *skb_next, *skb_cur = skb;
  	void *reply = genlmsg_data(genlhdr);
d94a04151   Shailabh Nagar   [PATCH] taskstats...
114
  	int rc, delcount = 0;
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
115

053c095a8   Johannes Berg   netlink: make nlm...
116
  	genlmsg_end(skb, reply);
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
117
118
  
  	rc = 0;
bb129994c   Shailabh Nagar   [PATCH] Remove do...
119
  	down_read(&listeners->sem);
d94a04151   Shailabh Nagar   [PATCH] taskstats...
120
  	list_for_each_entry(s, &listeners->list, list) {
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
121
122
123
  		skb_next = NULL;
  		if (!list_is_last(&s->list, &listeners->list)) {
  			skb_next = skb_clone(skb_cur, GFP_KERNEL);
d94a04151   Shailabh Nagar   [PATCH] taskstats...
124
  			if (!skb_next)
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
125
  				break;
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
126
  		}
134e63756   Johannes Berg   genetlink: make n...
127
  		rc = genlmsg_unicast(&init_net, skb_cur, s->pid);
d94a04151   Shailabh Nagar   [PATCH] taskstats...
128
  		if (rc == -ECONNREFUSED) {
bb129994c   Shailabh Nagar   [PATCH] Remove do...
129
130
  			s->valid = 0;
  			delcount++;
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
131
132
133
  		}
  		skb_cur = skb_next;
  	}
bb129994c   Shailabh Nagar   [PATCH] Remove do...
134
  	up_read(&listeners->sem);
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
135

d94a04151   Shailabh Nagar   [PATCH] taskstats...
136
137
  	if (skb_cur)
  		nlmsg_free(skb_cur);
bb129994c   Shailabh Nagar   [PATCH] Remove do...
138
  	if (!delcount)
d94a04151   Shailabh Nagar   [PATCH] taskstats...
139
  		return;
bb129994c   Shailabh Nagar   [PATCH] Remove do...
140
141
142
143
144
145
146
147
148
149
  
  	/* Delete invalidated entries */
  	down_write(&listeners->sem);
  	list_for_each_entry_safe(s, tmp, &listeners->list, list) {
  		if (!s->valid) {
  			list_del(&s->list);
  			kfree(s);
  		}
  	}
  	up_write(&listeners->sem);
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
150
  }
4bd6e32ac   Eric W. Biederman   userns: Convert t...
151
152
153
  static void fill_stats(struct user_namespace *user_ns,
  		       struct pid_namespace *pid_ns,
  		       struct task_struct *tsk, struct taskstats *stats)
c757249af   Shailabh Nagar   [PATCH] per-task-...
154
  {
51de4d908   Oleg Nesterov   [PATCH] taskstats...
155
  	memset(stats, 0, sizeof(*stats));
c757249af   Shailabh Nagar   [PATCH] per-task-...
156
157
158
159
  	/*
  	 * Each accounting subsystem adds calls to its functions to
  	 * fill in relevant parts of struct taskstsats as follows
  	 *
7d94dddd4   Shailabh Nagar   [PATCH] make task...
160
  	 *	per-task-foo(stats, tsk);
c757249af   Shailabh Nagar   [PATCH] per-task-...
161
  	 */
7d94dddd4   Shailabh Nagar   [PATCH] make task...
162
  	delayacct_add_tsk(stats, tsk);
f3cef7a99   Jay Lan   [PATCH] csa: basi...
163
164
  
  	/* fill in basic acct fields */
6f44993fe   Shailabh Nagar   [PATCH] per-task-...
165
  	stats->version = TASKSTATS_VERSION;
b663a79c1   Maxim Uvarov   taskstats: add co...
166
167
  	stats->nvcsw = tsk->nvcsw;
  	stats->nivcsw = tsk->nivcsw;
4bd6e32ac   Eric W. Biederman   userns: Convert t...
168
  	bacct_add_tsk(user_ns, pid_ns, stats, tsk);
6f44993fe   Shailabh Nagar   [PATCH] per-task-...
169

9acc18535   Jay Lan   [PATCH] csa: Exte...
170
171
  	/* fill in extended acct fields */
  	xacct_add_tsk(stats, tsk);
3d9e0cf1f   Michael Holzheu   taskstats: split ...
172
  }
9acc18535   Jay Lan   [PATCH] csa: Exte...
173

3d9e0cf1f   Michael Holzheu   taskstats: split ...
174
175
176
  static int fill_stats_for_pid(pid_t pid, struct taskstats *stats)
  {
  	struct task_struct *tsk;
c757249af   Shailabh Nagar   [PATCH] per-task-...
177

2ee082608   Mike Rapoport   pids: introduce f...
178
  	tsk = find_get_task_by_vpid(pid);
3d9e0cf1f   Michael Holzheu   taskstats: split ...
179
180
  	if (!tsk)
  		return -ESRCH;
4bd6e32ac   Eric W. Biederman   userns: Convert t...
181
  	fill_stats(current_user_ns(), task_active_pid_ns(current), tsk, stats);
3d9e0cf1f   Michael Holzheu   taskstats: split ...
182
183
  	put_task_struct(tsk);
  	return 0;
c757249af   Shailabh Nagar   [PATCH] per-task-...
184
  }
3d9e0cf1f   Michael Holzheu   taskstats: split ...
185
  static int fill_stats_for_tgid(pid_t tgid, struct taskstats *stats)
c757249af   Shailabh Nagar   [PATCH] per-task-...
186
  {
3d9e0cf1f   Michael Holzheu   taskstats: split ...
187
  	struct task_struct *tsk, *first;
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
188
  	unsigned long flags;
a98b60942   Oleg Nesterov   [PATCH] taskstats...
189
  	int rc = -ESRCH;
8c733420b   Zhang Xiao   taskstats: add e/...
190
191
  	u64 delta, utime, stime;
  	u64 start_time;
c757249af   Shailabh Nagar   [PATCH] per-task-...
192

ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
193
194
195
196
  	/*
  	 * Add additional stats from live tasks except zombie thread group
  	 * leaders who are already counted with the dead tasks
  	 */
a98b60942   Oleg Nesterov   [PATCH] taskstats...
197
  	rcu_read_lock();
3d9e0cf1f   Michael Holzheu   taskstats: split ...
198
  	first = find_task_by_vpid(tgid);
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
199

a98b60942   Oleg Nesterov   [PATCH] taskstats...
200
201
  	if (!first || !lock_task_sighand(first, &flags))
  		goto out;
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
202

a98b60942   Oleg Nesterov   [PATCH] taskstats...
203
204
  	if (first->signal->stats)
  		memcpy(stats, first->signal->stats, sizeof(*stats));
51de4d908   Oleg Nesterov   [PATCH] taskstats...
205
206
  	else
  		memset(stats, 0, sizeof(*stats));
fca178c0c   Oleg Nesterov   [PATCH] fill_tgid...
207

a98b60942   Oleg Nesterov   [PATCH] taskstats...
208
  	tsk = first;
8c733420b   Zhang Xiao   taskstats: add e/...
209
  	start_time = ktime_get_ns();
c757249af   Shailabh Nagar   [PATCH] per-task-...
210
  	do {
d7c3f5f23   Oleg Nesterov   [PATCH] fill_tgid...
211
  		if (tsk->exit_state)
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
212
  			continue;
c757249af   Shailabh Nagar   [PATCH] per-task-...
213
  		/*
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
214
  		 * Accounting subsystem can call its functions here to
c757249af   Shailabh Nagar   [PATCH] per-task-...
215
216
  		 * fill in relevant parts of struct taskstsats as follows
  		 *
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
217
  		 *	per-task-foo(stats, tsk);
c757249af   Shailabh Nagar   [PATCH] per-task-...
218
  		 */
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
219
  		delayacct_add_tsk(stats, tsk);
6f44993fe   Shailabh Nagar   [PATCH] per-task-...
220

8c733420b   Zhang Xiao   taskstats: add e/...
221
222
223
224
225
226
227
228
229
  		/* calculate task elapsed time in nsec */
  		delta = start_time - tsk->start_time;
  		/* Convert to micro seconds */
  		do_div(delta, NSEC_PER_USEC);
  		stats->ac_etime += delta;
  
  		task_cputime(tsk, &utime, &stime);
  		stats->ac_utime += div_u64(utime, NSEC_PER_USEC);
  		stats->ac_stime += div_u64(stime, NSEC_PER_USEC);
b663a79c1   Maxim Uvarov   taskstats: add co...
230
231
  		stats->nvcsw += tsk->nvcsw;
  		stats->nivcsw += tsk->nivcsw;
c757249af   Shailabh Nagar   [PATCH] per-task-...
232
  	} while_each_thread(first, tsk);
6f44993fe   Shailabh Nagar   [PATCH] per-task-...
233

a98b60942   Oleg Nesterov   [PATCH] taskstats...
234
235
236
237
238
239
  	unlock_task_sighand(first, &flags);
  	rc = 0;
  out:
  	rcu_read_unlock();
  
  	stats->version = TASKSTATS_VERSION;
c757249af   Shailabh Nagar   [PATCH] per-task-...
240
  	/*
3a4fa0a25   Robert P. J. Day   Fix misspellings ...
241
  	 * Accounting subsystems can also add calls here to modify
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
242
  	 * fields of taskstats.
c757249af   Shailabh Nagar   [PATCH] per-task-...
243
  	 */
a98b60942   Oleg Nesterov   [PATCH] taskstats...
244
  	return rc;
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
245
  }
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
246
247
248
  static void fill_tgid_exit(struct task_struct *tsk)
  {
  	unsigned long flags;
b8534d7bd   Oleg Nesterov   [PATCH] taskstats...
249
  	spin_lock_irqsave(&tsk->sighand->siglock, flags);
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
250
251
252
253
254
255
256
257
258
259
260
  	if (!tsk->signal->stats)
  		goto ret;
  
  	/*
  	 * Each accounting subsystem calls its functions here to
  	 * accumalate its per-task stats for tsk, into the per-tgid structure
  	 *
  	 *	per-task-foo(tsk->signal->stats, tsk);
  	 */
  	delayacct_add_tsk(tsk->signal->stats, tsk);
  ret:
b8534d7bd   Oleg Nesterov   [PATCH] taskstats...
261
  	spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
262
  	return;
c757249af   Shailabh Nagar   [PATCH] per-task-...
263
  }
41c7bb958   Rusty Russell   cpumask: convert ...
264
  static int add_del_listener(pid_t pid, const struct cpumask *mask, int isadd)
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
265
266
  {
  	struct listener_list *listeners;
26c4caea9   Vasiliy Kulikov   taskstats: don't ...
267
  	struct listener *s, *tmp, *s2;
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
268
  	unsigned int cpu;
0d20633b0   Chen Gang   kernel/taskstats....
269
  	int ret = 0;
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
270

41c7bb958   Rusty Russell   cpumask: convert ...
271
  	if (!cpumask_subset(mask, cpu_possible_mask))
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
272
  		return -EINVAL;
4bd6e32ac   Eric W. Biederman   userns: Convert t...
273
274
275
276
277
  	if (current_user_ns() != &init_user_ns)
  		return -EINVAL;
  
  	if (task_active_pid_ns(current) != &init_pid_ns)
  		return -EINVAL;
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
278
  	if (isadd == REGISTER) {
41c7bb958   Rusty Russell   cpumask: convert ...
279
  		for_each_cpu(cpu, mask) {
dfc428b65   Oleg Nesterov   taskstats: add_de...
280
281
  			s = kmalloc_node(sizeof(struct listener),
  					GFP_KERNEL, cpu_to_node(cpu));
0d20633b0   Chen Gang   kernel/taskstats....
282
283
  			if (!s) {
  				ret = -ENOMEM;
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
284
  				goto cleanup;
0d20633b0   Chen Gang   kernel/taskstats....
285
  			}
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
286
  			s->pid = pid;
bb129994c   Shailabh Nagar   [PATCH] Remove do...
287
  			s->valid = 1;
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
288
289
290
  
  			listeners = &per_cpu(listener_array, cpu);
  			down_write(&listeners->sem);
dfc428b65   Oleg Nesterov   taskstats: add_de...
291
  			list_for_each_entry(s2, &listeners->list, list) {
a7295898a   Oleg Nesterov   taskstats: add_de...
292
  				if (s2->pid == pid && s2->valid)
dfc428b65   Oleg Nesterov   taskstats: add_de...
293
  					goto exists;
26c4caea9   Vasiliy Kulikov   taskstats: don't ...
294
  			}
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
295
  			list_add(&s->list, &listeners->list);
26c4caea9   Vasiliy Kulikov   taskstats: don't ...
296
  			s = NULL;
dfc428b65   Oleg Nesterov   taskstats: add_de...
297
  exists:
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
298
  			up_write(&listeners->sem);
dfc428b65   Oleg Nesterov   taskstats: add_de...
299
  			kfree(s); /* nop if NULL */
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
300
301
302
303
304
305
  		}
  		return 0;
  	}
  
  	/* Deregister or cleanup */
  cleanup:
41c7bb958   Rusty Russell   cpumask: convert ...
306
  	for_each_cpu(cpu, mask) {
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
307
308
309
310
311
312
313
314
315
316
317
  		listeners = &per_cpu(listener_array, cpu);
  		down_write(&listeners->sem);
  		list_for_each_entry_safe(s, tmp, &listeners->list, list) {
  			if (s->pid == pid) {
  				list_del(&s->list);
  				kfree(s);
  				break;
  			}
  		}
  		up_write(&listeners->sem);
  	}
0d20633b0   Chen Gang   kernel/taskstats....
318
  	return ret;
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
319
  }
41c7bb958   Rusty Russell   cpumask: convert ...
320
  static int parse(struct nlattr *na, struct cpumask *mask)
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
  {
  	char *data;
  	int len;
  	int ret;
  
  	if (na == NULL)
  		return 1;
  	len = nla_len(na);
  	if (len > TASKSTATS_CPUMASK_MAXLEN)
  		return -E2BIG;
  	if (len < 1)
  		return -EINVAL;
  	data = kmalloc(len, GFP_KERNEL);
  	if (!data)
  		return -ENOMEM;
  	nla_strlcpy(data, na, len);
29c0177e6   Rusty Russell   cpumask: change c...
337
  	ret = cpulist_parse(data, mask);
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
338
339
340
  	kfree(data);
  	return ret;
  }
51de4d908   Oleg Nesterov   [PATCH] taskstats...
341
  static struct taskstats *mk_reply(struct sk_buff *skb, int type, u32 pid)
68062b86f   Oleg Nesterov   [PATCH] taskstats...
342
  {
51de4d908   Oleg Nesterov   [PATCH] taskstats...
343
  	struct nlattr *na, *ret;
68062b86f   Oleg Nesterov   [PATCH] taskstats...
344
  	int aggr;
371674853   Oleg Nesterov   [PATCH] taskstats...
345
346
347
  	aggr = (type == TASKSTATS_TYPE_PID)
  			? TASKSTATS_TYPE_AGGR_PID
  			: TASKSTATS_TYPE_AGGR_TGID;
68062b86f   Oleg Nesterov   [PATCH] taskstats...
348

ae0be8de9   Michal Kubecek   netlink: make nla...
349
  	na = nla_nest_start_noflag(skb, aggr);
371674853   Oleg Nesterov   [PATCH] taskstats...
350
351
  	if (!na)
  		goto err;
4be2c95d1   Jeff Mahoney   taskstats: pad ta...
352

3fa582663   Chen Gang   kernel/taskstats....
353
354
  	if (nla_put(skb, type, sizeof(pid), &pid) < 0) {
  		nla_nest_cancel(skb, na);
51de4d908   Oleg Nesterov   [PATCH] taskstats...
355
  		goto err;
3fa582663   Chen Gang   kernel/taskstats....
356
  	}
80df55427   Nicolas Dichtel   taskstats: use th...
357
358
  	ret = nla_reserve_64bit(skb, TASKSTATS_TYPE_STATS,
  				sizeof(struct taskstats), TASKSTATS_TYPE_NULL);
3fa582663   Chen Gang   kernel/taskstats....
359
360
  	if (!ret) {
  		nla_nest_cancel(skb, na);
51de4d908   Oleg Nesterov   [PATCH] taskstats...
361
  		goto err;
3fa582663   Chen Gang   kernel/taskstats....
362
  	}
68062b86f   Oleg Nesterov   [PATCH] taskstats...
363
  	nla_nest_end(skb, na);
51de4d908   Oleg Nesterov   [PATCH] taskstats...
364
365
366
  	return nla_data(ret);
  err:
  	return NULL;
68062b86f   Oleg Nesterov   [PATCH] taskstats...
367
  }
846c7bb05   Balbir Singh   Add cgroupstats
368
369
370
371
372
373
374
375
  static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
  {
  	int rc = 0;
  	struct sk_buff *rep_skb;
  	struct cgroupstats *stats;
  	struct nlattr *na;
  	size_t size;
  	u32 fd;
2903ff019   Al Viro   switch simple cas...
376
  	struct fd f;
846c7bb05   Balbir Singh   Add cgroupstats
377
378
379
380
381
382
  
  	na = info->attrs[CGROUPSTATS_CMD_ATTR_FD];
  	if (!na)
  		return -EINVAL;
  
  	fd = nla_get_u32(info->attrs[CGROUPSTATS_CMD_ATTR_FD]);
2903ff019   Al Viro   switch simple cas...
383
384
  	f = fdget(fd);
  	if (!f.file)
f96159840   Adrian Bunk   kernel/taskstats....
385
  		return 0;
846c7bb05   Balbir Singh   Add cgroupstats
386

f96159840   Adrian Bunk   kernel/taskstats....
387
  	size = nla_total_size(sizeof(struct cgroupstats));
846c7bb05   Balbir Singh   Add cgroupstats
388

f96159840   Adrian Bunk   kernel/taskstats....
389
390
391
392
  	rc = prepare_reply(info, CGROUPSTATS_CMD_NEW, &rep_skb,
  				size);
  	if (rc < 0)
  		goto err;
846c7bb05   Balbir Singh   Add cgroupstats
393

f96159840   Adrian Bunk   kernel/taskstats....
394
395
  	na = nla_reserve(rep_skb, CGROUPSTATS_TYPE_CGROUP_STATS,
  				sizeof(struct cgroupstats));
25353b337   Alan Cox   taskstats: check ...
396
  	if (na == NULL) {
0324b5a45   Jesper Juhl   taskstats: cgroup...
397
  		nlmsg_free(rep_skb);
25353b337   Alan Cox   taskstats: check ...
398
399
400
  		rc = -EMSGSIZE;
  		goto err;
  	}
f96159840   Adrian Bunk   kernel/taskstats....
401
402
  	stats = nla_data(na);
  	memset(stats, 0, sizeof(*stats));
846c7bb05   Balbir Singh   Add cgroupstats
403

b583043e9   Al Viro   kill f_dentry uses
404
  	rc = cgroupstats_build(stats, f.file->f_path.dentry);
f96159840   Adrian Bunk   kernel/taskstats....
405
406
407
  	if (rc < 0) {
  		nlmsg_free(rep_skb);
  		goto err;
846c7bb05   Balbir Singh   Add cgroupstats
408
  	}
134e63756   Johannes Berg   genetlink: make n...
409
  	rc = send_reply(rep_skb, info);
f96159840   Adrian Bunk   kernel/taskstats....
410

846c7bb05   Balbir Singh   Add cgroupstats
411
  err:
2903ff019   Al Viro   switch simple cas...
412
  	fdput(f);
846c7bb05   Balbir Singh   Add cgroupstats
413
414
  	return rc;
  }
932331259   Michael Holzheu   taskstats: separa...
415
  static int cmd_attr_register_cpumask(struct genl_info *info)
c757249af   Shailabh Nagar   [PATCH] per-task-...
416
  {
41c7bb958   Rusty Russell   cpumask: convert ...
417
  	cpumask_var_t mask;
932331259   Michael Holzheu   taskstats: separa...
418
  	int rc;
41c7bb958   Rusty Russell   cpumask: convert ...
419
420
421
  
  	if (!alloc_cpumask_var(&mask, GFP_KERNEL))
  		return -ENOMEM;
41c7bb958   Rusty Russell   cpumask: convert ...
422
  	rc = parse(info->attrs[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK], mask);
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
423
  	if (rc < 0)
932331259   Michael Holzheu   taskstats: separa...
424
  		goto out;
15e473046   Eric W. Biederman   netlink: Rename p...
425
  	rc = add_del_listener(info->snd_portid, mask, REGISTER);
932331259   Michael Holzheu   taskstats: separa...
426
427
428
429
430
431
432
433
434
  out:
  	free_cpumask_var(mask);
  	return rc;
  }
  
  static int cmd_attr_deregister_cpumask(struct genl_info *info)
  {
  	cpumask_var_t mask;
  	int rc;
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
435

932331259   Michael Holzheu   taskstats: separa...
436
437
  	if (!alloc_cpumask_var(&mask, GFP_KERNEL))
  		return -ENOMEM;
41c7bb958   Rusty Russell   cpumask: convert ...
438
  	rc = parse(info->attrs[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK], mask);
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
439
  	if (rc < 0)
932331259   Michael Holzheu   taskstats: separa...
440
  		goto out;
15e473046   Eric W. Biederman   netlink: Rename p...
441
  	rc = add_del_listener(info->snd_portid, mask, DEREGISTER);
932331259   Michael Holzheu   taskstats: separa...
442
  out:
41c7bb958   Rusty Russell   cpumask: convert ...
443
  	free_cpumask_var(mask);
932331259   Michael Holzheu   taskstats: separa...
444
445
  	return rc;
  }
4be2c95d1   Jeff Mahoney   taskstats: pad ta...
446
447
448
449
450
  static size_t taskstats_packet_size(void)
  {
  	size_t size;
  
  	size = nla_total_size(sizeof(u32)) +
80df55427   Nicolas Dichtel   taskstats: use th...
451
452
  		nla_total_size_64bit(sizeof(struct taskstats)) +
  		nla_total_size(0);
4be2c95d1   Jeff Mahoney   taskstats: pad ta...
453
454
  	return size;
  }
932331259   Michael Holzheu   taskstats: separa...
455
456
457
458
459
460
461
  static int cmd_attr_pid(struct genl_info *info)
  {
  	struct taskstats *stats;
  	struct sk_buff *rep_skb;
  	size_t size;
  	u32 pid;
  	int rc;
c757249af   Shailabh Nagar   [PATCH] per-task-...
462

4be2c95d1   Jeff Mahoney   taskstats: pad ta...
463
  	size = taskstats_packet_size();
c757249af   Shailabh Nagar   [PATCH] per-task-...
464

371674853   Oleg Nesterov   [PATCH] taskstats...
465
  	rc = prepare_reply(info, TASKSTATS_CMD_NEW, &rep_skb, size);
c757249af   Shailabh Nagar   [PATCH] per-task-...
466
467
  	if (rc < 0)
  		return rc;
51de4d908   Oleg Nesterov   [PATCH] taskstats...
468
  	rc = -EINVAL;
932331259   Michael Holzheu   taskstats: separa...
469
470
471
  	pid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_PID]);
  	stats = mk_reply(rep_skb, TASKSTATS_TYPE_PID, pid);
  	if (!stats)
c757249af   Shailabh Nagar   [PATCH] per-task-...
472
  		goto err;
c757249af   Shailabh Nagar   [PATCH] per-task-...
473

3d9e0cf1f   Michael Holzheu   taskstats: split ...
474
  	rc = fill_stats_for_pid(pid, stats);
932331259   Michael Holzheu   taskstats: separa...
475
476
  	if (rc < 0)
  		goto err;
134e63756   Johannes Berg   genetlink: make n...
477
  	return send_reply(rep_skb, info);
c757249af   Shailabh Nagar   [PATCH] per-task-...
478
479
480
481
  err:
  	nlmsg_free(rep_skb);
  	return rc;
  }
932331259   Michael Holzheu   taskstats: separa...
482
483
484
485
486
487
488
  static int cmd_attr_tgid(struct genl_info *info)
  {
  	struct taskstats *stats;
  	struct sk_buff *rep_skb;
  	size_t size;
  	u32 tgid;
  	int rc;
4be2c95d1   Jeff Mahoney   taskstats: pad ta...
489
  	size = taskstats_packet_size();
932331259   Michael Holzheu   taskstats: separa...
490
491
492
493
494
495
496
497
498
499
  
  	rc = prepare_reply(info, TASKSTATS_CMD_NEW, &rep_skb, size);
  	if (rc < 0)
  		return rc;
  
  	rc = -EINVAL;
  	tgid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_TGID]);
  	stats = mk_reply(rep_skb, TASKSTATS_TYPE_TGID, tgid);
  	if (!stats)
  		goto err;
3d9e0cf1f   Michael Holzheu   taskstats: split ...
500
  	rc = fill_stats_for_tgid(tgid, stats);
932331259   Michael Holzheu   taskstats: separa...
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
  	if (rc < 0)
  		goto err;
  	return send_reply(rep_skb, info);
  err:
  	nlmsg_free(rep_skb);
  	return rc;
  }
  
  static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
  {
  	if (info->attrs[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK])
  		return cmd_attr_register_cpumask(info);
  	else if (info->attrs[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK])
  		return cmd_attr_deregister_cpumask(info);
  	else if (info->attrs[TASKSTATS_CMD_ATTR_PID])
  		return cmd_attr_pid(info);
  	else if (info->attrs[TASKSTATS_CMD_ATTR_TGID])
  		return cmd_attr_tgid(info);
  	else
  		return -EINVAL;
  }
34ec12349   Oleg Nesterov   [PATCH] taskstats...
522
523
524
  static struct taskstats *taskstats_tgid_alloc(struct task_struct *tsk)
  {
  	struct signal_struct *sig = tsk->signal;
d25bf5a34   Christian Brauner   taskstats: fix da...
525
  	struct taskstats *stats_new, *stats;
34ec12349   Oleg Nesterov   [PATCH] taskstats...
526

d25bf5a34   Christian Brauner   taskstats: fix da...
527
528
529
530
  	/* Pairs with smp_store_release() below. */
  	stats = smp_load_acquire(&sig->stats);
  	if (stats || thread_group_empty(tsk))
  		return stats;
34ec12349   Oleg Nesterov   [PATCH] taskstats...
531
532
  
  	/* No problem if kmem_cache_zalloc() fails */
d25bf5a34   Christian Brauner   taskstats: fix da...
533
  	stats_new = kmem_cache_zalloc(taskstats_cache, GFP_KERNEL);
34ec12349   Oleg Nesterov   [PATCH] taskstats...
534
535
  
  	spin_lock_irq(&tsk->sighand->siglock);
d25bf5a34   Christian Brauner   taskstats: fix da...
536
537
538
539
540
541
542
543
544
  	stats = sig->stats;
  	if (!stats) {
  		/*
  		 * Pairs with smp_store_release() above and order the
  		 * kmem_cache_zalloc().
  		 */
  		smp_store_release(&sig->stats, stats_new);
  		stats = stats_new;
  		stats_new = NULL;
34ec12349   Oleg Nesterov   [PATCH] taskstats...
545
546
  	}
  	spin_unlock_irq(&tsk->sighand->siglock);
d25bf5a34   Christian Brauner   taskstats: fix da...
547
548
549
550
  	if (stats_new)
  		kmem_cache_free(taskstats_cache, stats_new);
  
  	return stats;
34ec12349   Oleg Nesterov   [PATCH] taskstats...
551
  }
c757249af   Shailabh Nagar   [PATCH] per-task-...
552
  /* Send pid data out on exit */
115085ea0   Oleg Nesterov   [PATCH] taskstats...
553
  void taskstats_exit(struct task_struct *tsk, int group_dead)
c757249af   Shailabh Nagar   [PATCH] per-task-...
554
555
  {
  	int rc;
115085ea0   Oleg Nesterov   [PATCH] taskstats...
556
  	struct listener_list *listeners;
51de4d908   Oleg Nesterov   [PATCH] taskstats...
557
  	struct taskstats *stats;
c757249af   Shailabh Nagar   [PATCH] per-task-...
558
  	struct sk_buff *rep_skb;
c757249af   Shailabh Nagar   [PATCH] per-task-...
559
560
  	size_t size;
  	int is_thread_group;
c757249af   Shailabh Nagar   [PATCH] per-task-...
561

4a279ff1e   Oleg Nesterov   [PATCH] taskstats...
562
  	if (!family_registered)
c757249af   Shailabh Nagar   [PATCH] per-task-...
563
  		return;
c757249af   Shailabh Nagar   [PATCH] per-task-...
564
565
566
  	/*
  	 * Size includes space for nested attributes
  	 */
4be2c95d1   Jeff Mahoney   taskstats: pad ta...
567
  	size = taskstats_packet_size();
c757249af   Shailabh Nagar   [PATCH] per-task-...
568

34ec12349   Oleg Nesterov   [PATCH] taskstats...
569
  	is_thread_group = !!taskstats_tgid_alloc(tsk);
4a279ff1e   Oleg Nesterov   [PATCH] taskstats...
570
571
572
573
574
575
  	if (is_thread_group) {
  		/* PID + STATS + TGID + STATS */
  		size = 2 * size;
  		/* fill the tsk->signal->stats structure */
  		fill_tgid_exit(tsk);
  	}
4a32fea9d   Christoph Lameter   scheduler: Replac...
576
  	listeners = raw_cpu_ptr(&listener_array);
115085ea0   Oleg Nesterov   [PATCH] taskstats...
577
578
  	if (list_empty(&listeners->list))
  		return;
371674853   Oleg Nesterov   [PATCH] taskstats...
579
  	rc = prepare_reply(NULL, TASKSTATS_CMD_NEW, &rep_skb, size);
c757249af   Shailabh Nagar   [PATCH] per-task-...
580
  	if (rc < 0)
51de4d908   Oleg Nesterov   [PATCH] taskstats...
581
  		return;
c757249af   Shailabh Nagar   [PATCH] per-task-...
582

4bd6e32ac   Eric W. Biederman   userns: Convert t...
583
584
  	stats = mk_reply(rep_skb, TASKSTATS_TYPE_PID,
  			 task_pid_nr_ns(tsk, &init_pid_ns));
51de4d908   Oleg Nesterov   [PATCH] taskstats...
585
  	if (!stats)
371674853   Oleg Nesterov   [PATCH] taskstats...
586
  		goto err;
c757249af   Shailabh Nagar   [PATCH] per-task-...
587

4bd6e32ac   Eric W. Biederman   userns: Convert t...
588
  	fill_stats(&init_user_ns, &init_pid_ns, tsk, stats);
c757249af   Shailabh Nagar   [PATCH] per-task-...
589

c757249af   Shailabh Nagar   [PATCH] per-task-...
590
  	/*
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
591
  	 * Doesn't matter if tsk is the leader or the last group member leaving
c757249af   Shailabh Nagar   [PATCH] per-task-...
592
  	 */
68062b86f   Oleg Nesterov   [PATCH] taskstats...
593
  	if (!is_thread_group || !group_dead)
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
594
  		goto send;
c757249af   Shailabh Nagar   [PATCH] per-task-...
595

4bd6e32ac   Eric W. Biederman   userns: Convert t...
596
597
  	stats = mk_reply(rep_skb, TASKSTATS_TYPE_TGID,
  			 task_tgid_nr_ns(tsk, &init_pid_ns));
51de4d908   Oleg Nesterov   [PATCH] taskstats...
598
  	if (!stats)
371674853   Oleg Nesterov   [PATCH] taskstats...
599
  		goto err;
51de4d908   Oleg Nesterov   [PATCH] taskstats...
600
601
  
  	memcpy(stats, tsk->signal->stats, sizeof(*stats));
c757249af   Shailabh Nagar   [PATCH] per-task-...
602

ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
603
  send:
115085ea0   Oleg Nesterov   [PATCH] taskstats...
604
  	send_cpu_listeners(rep_skb, listeners);
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
605
  	return;
371674853   Oleg Nesterov   [PATCH] taskstats...
606
  err:
c757249af   Shailabh Nagar   [PATCH] per-task-...
607
  	nlmsg_free(rep_skb);
c757249af   Shailabh Nagar   [PATCH] per-task-...
608
  }
4534de830   Johannes Berg   genetlink: make a...
609
  static const struct genl_ops taskstats_ops[] = {
88d36a994   Johannes Berg   taskstats: use ge...
610
611
  	{
  		.cmd		= TASKSTATS_CMD_GET,
ef6243acb   Johannes Berg   genetlink: option...
612
  		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
88d36a994   Johannes Berg   taskstats: use ge...
613
  		.doit		= taskstats_user_cmd,
3b0f31f2b   Johannes Berg   genetlink: make p...
614
615
  		/* policy enforced later */
  		.flags		= GENL_ADMIN_PERM | GENL_CMD_CAP_HASPOL,
88d36a994   Johannes Berg   taskstats: use ge...
616
617
618
  	},
  	{
  		.cmd		= CGROUPSTATS_CMD_GET,
ef6243acb   Johannes Berg   genetlink: option...
619
  		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
88d36a994   Johannes Berg   taskstats: use ge...
620
  		.doit		= cgroupstats_user_cmd,
3b0f31f2b   Johannes Berg   genetlink: make p...
621
622
  		/* policy enforced later */
  		.flags		= GENL_CMD_CAP_HASPOL,
88d36a994   Johannes Berg   taskstats: use ge...
623
  	},
846c7bb05   Balbir Singh   Add cgroupstats
624
  };
3b0f31f2b   Johannes Berg   genetlink: make p...
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
  static int taskstats_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
  			      struct genl_info *info)
  {
  	const struct nla_policy *policy = NULL;
  
  	switch (ops->cmd) {
  	case TASKSTATS_CMD_GET:
  		policy = taskstats_cmd_get_policy;
  		break;
  	case CGROUPSTATS_CMD_GET:
  		policy = cgroupstats_cmd_get_policy;
  		break;
  	default:
  		return -EINVAL;
  	}
8cb081746   Johannes Berg   netlink: make val...
640
641
642
  	return nlmsg_validate_deprecated(info->nlhdr, GENL_HDRLEN,
  					 TASKSTATS_CMD_ATTR_MAX, policy,
  					 info->extack);
3b0f31f2b   Johannes Berg   genetlink: make p...
643
  }
56989f6d8   Johannes Berg   genetlink: mark f...
644
  static struct genl_family family __ro_after_init = {
489111e5c   Johannes Berg   genetlink: static...
645
646
647
648
649
650
  	.name		= TASKSTATS_GENL_NAME,
  	.version	= TASKSTATS_GENL_VERSION,
  	.maxattr	= TASKSTATS_CMD_ATTR_MAX,
  	.module		= THIS_MODULE,
  	.ops		= taskstats_ops,
  	.n_ops		= ARRAY_SIZE(taskstats_ops),
3b0f31f2b   Johannes Berg   genetlink: make p...
651
  	.pre_doit	= taskstats_pre_doit,
489111e5c   Johannes Berg   genetlink: static...
652
  };
c757249af   Shailabh Nagar   [PATCH] per-task-...
653
654
655
  /* Needed early in initialization */
  void __init taskstats_init_early(void)
  {
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
656
  	unsigned int i;
0a31bd5f2   Christoph Lameter   KMEM_CACHE(): sim...
657
  	taskstats_cache = KMEM_CACHE(taskstats, SLAB_PANIC);
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
658
659
660
661
  	for_each_possible_cpu(i) {
  		INIT_LIST_HEAD(&(per_cpu(listener_array, i).list));
  		init_rwsem(&(per_cpu(listener_array, i).sem));
  	}
c757249af   Shailabh Nagar   [PATCH] per-task-...
662
663
664
665
666
  }
  
  static int __init taskstats_init(void)
  {
  	int rc;
489111e5c   Johannes Berg   genetlink: static...
667
  	rc = genl_register_family(&family);
c757249af   Shailabh Nagar   [PATCH] per-task-...
668
669
  	if (rc)
  		return rc;
c757249af   Shailabh Nagar   [PATCH] per-task-...
670
  	family_registered = 1;
f9b182e24   Mandeep Singh Baines   taskstats: use ap...
671
672
  	pr_info("registered taskstats version %d
  ", TASKSTATS_GENL_VERSION);
c757249af   Shailabh Nagar   [PATCH] per-task-...
673
  	return 0;
c757249af   Shailabh Nagar   [PATCH] per-task-...
674
675
676
677
678
679
680
  }
  
  /*
   * late initcall ensures initialization of statistics collection
   * mechanisms precedes initialization of the taskstats interface
   */
  late_initcall(taskstats_init);