Blame view

kernel/taskstats.c 13.8 KB
c757249af   Shailabh Nagar   [PATCH] per-task-...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  /*
   * taskstats.c - Export per-task statistics to userland
   *
   * Copyright (C) Shailabh Nagar, IBM Corp. 2006
   *           (C) Balbir Singh,   IBM Corp. 2006
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   */
  
  #include <linux/kernel.h>
  #include <linux/taskstats_kern.h>
f3cef7a99   Jay Lan   [PATCH] csa: basi...
21
  #include <linux/tsacct_kern.h>
6f44993fe   Shailabh Nagar   [PATCH] per-task-...
22
  #include <linux/delayacct.h>
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
23
24
  #include <linux/cpumask.h>
  #include <linux/percpu.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
25
  #include <linux/slab.h>
846c7bb05   Balbir Singh   Add cgroupstats
26
27
28
29
  #include <linux/cgroupstats.h>
  #include <linux/cgroup.h>
  #include <linux/fs.h>
  #include <linux/file.h>
c757249af   Shailabh Nagar   [PATCH] per-task-...
30
31
  #include <net/genetlink.h>
  #include <asm/atomic.h>
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
32
33
34
35
36
  /*
   * 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...
37
  static DEFINE_PER_CPU(__u32, taskstats_seqnum);
c757249af   Shailabh Nagar   [PATCH] per-task-...
38
  static int family_registered;
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
39
  struct kmem_cache *taskstats_cache;
c757249af   Shailabh Nagar   [PATCH] per-task-...
40
41
42
43
44
45
46
  
  static struct genl_family family = {
  	.id		= GENL_ID_GENERATE,
  	.name		= TASKSTATS_GENL_NAME,
  	.version	= TASKSTATS_GENL_VERSION,
  	.maxattr	= TASKSTATS_CMD_ATTR_MAX,
  };
b54452b07   Alexey Dobriyan   const: struct nla...
47
  static const struct nla_policy taskstats_cmd_get_policy[TASKSTATS_CMD_ATTR_MAX+1] = {
c757249af   Shailabh Nagar   [PATCH] per-task-...
48
49
  	[TASKSTATS_CMD_ATTR_PID]  = { .type = NLA_U32 },
  	[TASKSTATS_CMD_ATTR_TGID] = { .type = NLA_U32 },
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
50
51
  	[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK] = { .type = NLA_STRING },
  	[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK] = { .type = NLA_STRING },};
b54452b07   Alexey Dobriyan   const: struct nla...
52
  static const struct nla_policy cgroupstats_cmd_get_policy[CGROUPSTATS_CMD_ATTR_MAX+1] = {
846c7bb05   Balbir Singh   Add cgroupstats
53
54
  	[CGROUPSTATS_CMD_ATTR_FD] = { .type = NLA_U32 },
  };
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
55
56
57
  struct listener {
  	struct list_head list;
  	pid_t pid;
bb129994c   Shailabh Nagar   [PATCH] Remove do...
58
  	char valid;
c757249af   Shailabh Nagar   [PATCH] per-task-...
59
  };
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
60
61
62
63
64
65
66
67
68
69
70
  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-...
71
72
  
  static int prepare_reply(struct genl_info *info, u8 cmd, struct sk_buff **skbp,
371674853   Oleg Nesterov   [PATCH] taskstats...
73
  				size_t size)
c757249af   Shailabh Nagar   [PATCH] per-task-...
74
75
76
77
78
79
80
  {
  	struct sk_buff *skb;
  	void *reply;
  
  	/*
  	 * If new attributes are added, please revisit this allocation
  	 */
3dabc7157   Thomas Graf   [GENL]: Add genlm...
81
  	skb = genlmsg_new(size, GFP_KERNEL);
c757249af   Shailabh Nagar   [PATCH] per-task-...
82
83
84
85
86
87
  	if (!skb)
  		return -ENOMEM;
  
  	if (!info) {
  		int seq = get_cpu_var(taskstats_seqnum)++;
  		put_cpu_var(taskstats_seqnum);
17c157c88   Thomas Graf   [GENL]: Add genlm...
88
  		reply = genlmsg_put(skb, 0, seq, &family, 0, cmd);
c757249af   Shailabh Nagar   [PATCH] per-task-...
89
  	} else
17c157c88   Thomas Graf   [GENL]: Add genlm...
90
  		reply = genlmsg_put_reply(skb, info, &family, 0, cmd);
c757249af   Shailabh Nagar   [PATCH] per-task-...
91
92
93
94
95
96
  	if (reply == NULL) {
  		nlmsg_free(skb);
  		return -EINVAL;
  	}
  
  	*skbp = skb;
c757249af   Shailabh Nagar   [PATCH] per-task-...
97
98
  	return 0;
  }
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
99
100
101
  /*
   * Send taskstats data in @skb to listener with nl_pid @pid
   */
134e63756   Johannes Berg   genetlink: make n...
102
  static int send_reply(struct sk_buff *skb, struct genl_info *info)
c757249af   Shailabh Nagar   [PATCH] per-task-...
103
  {
b529ccf27   Arnaldo Carvalho de Melo   [NETLINK]: Introd...
104
  	struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
105
  	void *reply = genlmsg_data(genlhdr);
c757249af   Shailabh Nagar   [PATCH] per-task-...
106
  	int rc;
c757249af   Shailabh Nagar   [PATCH] per-task-...
107
108
109
110
111
  	rc = genlmsg_end(skb, reply);
  	if (rc < 0) {
  		nlmsg_free(skb);
  		return rc;
  	}
134e63756   Johannes Berg   genetlink: make n...
112
  	return genlmsg_reply(skb, info);
c757249af   Shailabh Nagar   [PATCH] per-task-...
113
  }
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
114
115
116
  /*
   * Send taskstats data in @skb to listeners registered for @cpu's exit data
   */
115085ea0   Oleg Nesterov   [PATCH] taskstats...
117
118
  static void send_cpu_listeners(struct sk_buff *skb,
  					struct listener_list *listeners)
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
119
  {
b529ccf27   Arnaldo Carvalho de Melo   [NETLINK]: Introd...
120
  	struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
121
122
123
  	struct listener *s, *tmp;
  	struct sk_buff *skb_next, *skb_cur = skb;
  	void *reply = genlmsg_data(genlhdr);
d94a04151   Shailabh Nagar   [PATCH] taskstats...
124
  	int rc, delcount = 0;
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
125
126
127
128
  
  	rc = genlmsg_end(skb, reply);
  	if (rc < 0) {
  		nlmsg_free(skb);
d94a04151   Shailabh Nagar   [PATCH] taskstats...
129
  		return;
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
130
131
132
  	}
  
  	rc = 0;
bb129994c   Shailabh Nagar   [PATCH] Remove do...
133
  	down_read(&listeners->sem);
d94a04151   Shailabh Nagar   [PATCH] taskstats...
134
  	list_for_each_entry(s, &listeners->list, list) {
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
135
136
137
  		skb_next = NULL;
  		if (!list_is_last(&s->list, &listeners->list)) {
  			skb_next = skb_clone(skb_cur, GFP_KERNEL);
d94a04151   Shailabh Nagar   [PATCH] taskstats...
138
  			if (!skb_next)
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
139
  				break;
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
140
  		}
134e63756   Johannes Berg   genetlink: make n...
141
  		rc = genlmsg_unicast(&init_net, skb_cur, s->pid);
d94a04151   Shailabh Nagar   [PATCH] taskstats...
142
  		if (rc == -ECONNREFUSED) {
bb129994c   Shailabh Nagar   [PATCH] Remove do...
143
144
  			s->valid = 0;
  			delcount++;
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
145
146
147
  		}
  		skb_cur = skb_next;
  	}
bb129994c   Shailabh Nagar   [PATCH] Remove do...
148
  	up_read(&listeners->sem);
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
149

d94a04151   Shailabh Nagar   [PATCH] taskstats...
150
151
  	if (skb_cur)
  		nlmsg_free(skb_cur);
bb129994c   Shailabh Nagar   [PATCH] Remove do...
152
  	if (!delcount)
d94a04151   Shailabh Nagar   [PATCH] taskstats...
153
  		return;
bb129994c   Shailabh Nagar   [PATCH] Remove do...
154
155
156
157
158
159
160
161
162
163
  
  	/* 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 ...
164
  }
a98b60942   Oleg Nesterov   [PATCH] taskstats...
165
  static int fill_pid(pid_t pid, struct task_struct *tsk,
c757249af   Shailabh Nagar   [PATCH] per-task-...
166
167
  		struct taskstats *stats)
  {
7d94dddd4   Shailabh Nagar   [PATCH] make task...
168
  	int rc = 0;
c757249af   Shailabh Nagar   [PATCH] per-task-...
169

a98b60942   Oleg Nesterov   [PATCH] taskstats...
170
171
  	if (!tsk) {
  		rcu_read_lock();
cb41d6d06   Pavel Emelyanov   Use find_task_by_...
172
  		tsk = find_task_by_vpid(pid);
a98b60942   Oleg Nesterov   [PATCH] taskstats...
173
174
175
176
  		if (tsk)
  			get_task_struct(tsk);
  		rcu_read_unlock();
  		if (!tsk)
c757249af   Shailabh Nagar   [PATCH] per-task-...
177
  			return -ESRCH;
c757249af   Shailabh Nagar   [PATCH] per-task-...
178
179
  	} else
  		get_task_struct(tsk);
51de4d908   Oleg Nesterov   [PATCH] taskstats...
180
  	memset(stats, 0, sizeof(*stats));
c757249af   Shailabh Nagar   [PATCH] per-task-...
181
182
183
184
  	/*
  	 * Each accounting subsystem adds calls to its functions to
  	 * fill in relevant parts of struct taskstsats as follows
  	 *
7d94dddd4   Shailabh Nagar   [PATCH] make task...
185
  	 *	per-task-foo(stats, tsk);
c757249af   Shailabh Nagar   [PATCH] per-task-...
186
  	 */
7d94dddd4   Shailabh Nagar   [PATCH] make task...
187
  	delayacct_add_tsk(stats, tsk);
f3cef7a99   Jay Lan   [PATCH] csa: basi...
188
189
  
  	/* fill in basic acct fields */
6f44993fe   Shailabh Nagar   [PATCH] per-task-...
190
  	stats->version = TASKSTATS_VERSION;
b663a79c1   Maxim Uvarov   taskstats: add co...
191
192
  	stats->nvcsw = tsk->nvcsw;
  	stats->nivcsw = tsk->nivcsw;
f3cef7a99   Jay Lan   [PATCH] csa: basi...
193
  	bacct_add_tsk(stats, tsk);
6f44993fe   Shailabh Nagar   [PATCH] per-task-...
194

9acc18535   Jay Lan   [PATCH] csa: Exte...
195
196
  	/* fill in extended acct fields */
  	xacct_add_tsk(stats, tsk);
6f44993fe   Shailabh Nagar   [PATCH] per-task-...
197
  	/* Define err: label here if needed */
c757249af   Shailabh Nagar   [PATCH] per-task-...
198
199
200
201
  	put_task_struct(tsk);
  	return rc;
  
  }
a98b60942   Oleg Nesterov   [PATCH] taskstats...
202
  static int fill_tgid(pid_t tgid, struct task_struct *first,
c757249af   Shailabh Nagar   [PATCH] per-task-...
203
204
  		struct taskstats *stats)
  {
a98b60942   Oleg Nesterov   [PATCH] taskstats...
205
  	struct task_struct *tsk;
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
206
  	unsigned long flags;
a98b60942   Oleg Nesterov   [PATCH] taskstats...
207
  	int rc = -ESRCH;
c757249af   Shailabh Nagar   [PATCH] per-task-...
208

ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
209
210
211
212
  	/*
  	 * Add additional stats from live tasks except zombie thread group
  	 * leaders who are already counted with the dead tasks
  	 */
a98b60942   Oleg Nesterov   [PATCH] taskstats...
213
214
  	rcu_read_lock();
  	if (!first)
cb41d6d06   Pavel Emelyanov   Use find_task_by_...
215
  		first = find_task_by_vpid(tgid);
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
216

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

a98b60942   Oleg Nesterov   [PATCH] taskstats...
220
221
  	if (first->signal->stats)
  		memcpy(stats, first->signal->stats, sizeof(*stats));
51de4d908   Oleg Nesterov   [PATCH] taskstats...
222
223
  	else
  		memset(stats, 0, sizeof(*stats));
fca178c0c   Oleg Nesterov   [PATCH] fill_tgid...
224

a98b60942   Oleg Nesterov   [PATCH] taskstats...
225
  	tsk = first;
c757249af   Shailabh Nagar   [PATCH] per-task-...
226
  	do {
d7c3f5f23   Oleg Nesterov   [PATCH] fill_tgid...
227
  		if (tsk->exit_state)
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
228
  			continue;
c757249af   Shailabh Nagar   [PATCH] per-task-...
229
  		/*
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
230
  		 * Accounting subsystem can call its functions here to
c757249af   Shailabh Nagar   [PATCH] per-task-...
231
232
  		 * fill in relevant parts of struct taskstsats as follows
  		 *
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
233
  		 *	per-task-foo(stats, tsk);
c757249af   Shailabh Nagar   [PATCH] per-task-...
234
  		 */
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
235
  		delayacct_add_tsk(stats, tsk);
6f44993fe   Shailabh Nagar   [PATCH] per-task-...
236

b663a79c1   Maxim Uvarov   taskstats: add co...
237
238
  		stats->nvcsw += tsk->nvcsw;
  		stats->nivcsw += tsk->nivcsw;
c757249af   Shailabh Nagar   [PATCH] per-task-...
239
  	} while_each_thread(first, tsk);
6f44993fe   Shailabh Nagar   [PATCH] per-task-...
240

a98b60942   Oleg Nesterov   [PATCH] taskstats...
241
242
243
244
245
246
  	unlock_task_sighand(first, &flags);
  	rc = 0;
  out:
  	rcu_read_unlock();
  
  	stats->version = TASKSTATS_VERSION;
c757249af   Shailabh Nagar   [PATCH] per-task-...
247
  	/*
3a4fa0a25   Robert P. J. Day   Fix misspellings ...
248
  	 * Accounting subsystems can also add calls here to modify
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
249
  	 * fields of taskstats.
c757249af   Shailabh Nagar   [PATCH] per-task-...
250
  	 */
a98b60942   Oleg Nesterov   [PATCH] taskstats...
251
  	return rc;
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
252
253
254
255
256
257
  }
  
  
  static void fill_tgid_exit(struct task_struct *tsk)
  {
  	unsigned long flags;
b8534d7bd   Oleg Nesterov   [PATCH] taskstats...
258
  	spin_lock_irqsave(&tsk->sighand->siglock, flags);
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
259
260
261
262
263
264
265
266
267
268
269
  	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...
270
  	spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
271
  	return;
c757249af   Shailabh Nagar   [PATCH] per-task-...
272
  }
41c7bb958   Rusty Russell   cpumask: convert ...
273
  static int add_del_listener(pid_t pid, const struct cpumask *mask, int isadd)
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
274
275
276
277
  {
  	struct listener_list *listeners;
  	struct listener *s, *tmp;
  	unsigned int cpu;
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
278

41c7bb958   Rusty Russell   cpumask: convert ...
279
  	if (!cpumask_subset(mask, cpu_possible_mask))
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
280
281
282
  		return -EINVAL;
  
  	if (isadd == REGISTER) {
41c7bb958   Rusty Russell   cpumask: convert ...
283
  		for_each_cpu(cpu, mask) {
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
284
285
286
287
288
289
  			s = kmalloc_node(sizeof(struct listener), GFP_KERNEL,
  					 cpu_to_node(cpu));
  			if (!s)
  				goto cleanup;
  			s->pid = pid;
  			INIT_LIST_HEAD(&s->list);
bb129994c   Shailabh Nagar   [PATCH] Remove do...
290
  			s->valid = 1;
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
291
292
293
294
295
296
297
298
299
300
301
  
  			listeners = &per_cpu(listener_array, cpu);
  			down_write(&listeners->sem);
  			list_add(&s->list, &listeners->list);
  			up_write(&listeners->sem);
  		}
  		return 0;
  	}
  
  	/* Deregister or cleanup */
  cleanup:
41c7bb958   Rusty Russell   cpumask: convert ...
302
  	for_each_cpu(cpu, mask) {
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
303
304
305
306
307
308
309
310
311
312
313
314
315
  		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);
  	}
  	return 0;
  }
41c7bb958   Rusty Russell   cpumask: convert ...
316
  static int parse(struct nlattr *na, struct cpumask *mask)
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
  {
  	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...
333
  	ret = cpulist_parse(data, mask);
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
334
335
336
  	kfree(data);
  	return ret;
  }
51de4d908   Oleg Nesterov   [PATCH] taskstats...
337
  static struct taskstats *mk_reply(struct sk_buff *skb, int type, u32 pid)
68062b86f   Oleg Nesterov   [PATCH] taskstats...
338
  {
51de4d908   Oleg Nesterov   [PATCH] taskstats...
339
  	struct nlattr *na, *ret;
68062b86f   Oleg Nesterov   [PATCH] taskstats...
340
  	int aggr;
371674853   Oleg Nesterov   [PATCH] taskstats...
341
342
343
  	aggr = (type == TASKSTATS_TYPE_PID)
  			? TASKSTATS_TYPE_AGGR_PID
  			: TASKSTATS_TYPE_AGGR_TGID;
68062b86f   Oleg Nesterov   [PATCH] taskstats...
344
345
  
  	na = nla_nest_start(skb, aggr);
371674853   Oleg Nesterov   [PATCH] taskstats...
346
347
  	if (!na)
  		goto err;
51de4d908   Oleg Nesterov   [PATCH] taskstats...
348
349
350
351
352
  	if (nla_put(skb, type, sizeof(pid), &pid) < 0)
  		goto err;
  	ret = nla_reserve(skb, TASKSTATS_TYPE_STATS, sizeof(struct taskstats));
  	if (!ret)
  		goto err;
68062b86f   Oleg Nesterov   [PATCH] taskstats...
353
  	nla_nest_end(skb, na);
51de4d908   Oleg Nesterov   [PATCH] taskstats...
354
355
356
  	return nla_data(ret);
  err:
  	return NULL;
68062b86f   Oleg Nesterov   [PATCH] taskstats...
357
  }
846c7bb05   Balbir Singh   Add cgroupstats
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
  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;
  	struct file *file;
  	int fput_needed;
  
  	na = info->attrs[CGROUPSTATS_CMD_ATTR_FD];
  	if (!na)
  		return -EINVAL;
  
  	fd = nla_get_u32(info->attrs[CGROUPSTATS_CMD_ATTR_FD]);
  	file = fget_light(fd, &fput_needed);
f96159840   Adrian Bunk   kernel/taskstats....
375
376
  	if (!file)
  		return 0;
846c7bb05   Balbir Singh   Add cgroupstats
377

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

f96159840   Adrian Bunk   kernel/taskstats....
380
381
382
383
  	rc = prepare_reply(info, CGROUPSTATS_CMD_NEW, &rep_skb,
  				size);
  	if (rc < 0)
  		goto err;
846c7bb05   Balbir Singh   Add cgroupstats
384

f96159840   Adrian Bunk   kernel/taskstats....
385
386
387
388
  	na = nla_reserve(rep_skb, CGROUPSTATS_TYPE_CGROUP_STATS,
  				sizeof(struct cgroupstats));
  	stats = nla_data(na);
  	memset(stats, 0, sizeof(*stats));
846c7bb05   Balbir Singh   Add cgroupstats
389

f96159840   Adrian Bunk   kernel/taskstats....
390
391
392
393
  	rc = cgroupstats_build(stats, file->f_dentry);
  	if (rc < 0) {
  		nlmsg_free(rep_skb);
  		goto err;
846c7bb05   Balbir Singh   Add cgroupstats
394
  	}
134e63756   Johannes Berg   genetlink: make n...
395
  	rc = send_reply(rep_skb, info);
f96159840   Adrian Bunk   kernel/taskstats....
396

846c7bb05   Balbir Singh   Add cgroupstats
397
  err:
f96159840   Adrian Bunk   kernel/taskstats....
398
  	fput_light(file, fput_needed);
846c7bb05   Balbir Singh   Add cgroupstats
399
400
  	return rc;
  }
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
401
  static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
c757249af   Shailabh Nagar   [PATCH] per-task-...
402
  {
41c7bb958   Rusty Russell   cpumask: convert ...
403
  	int rc;
c757249af   Shailabh Nagar   [PATCH] per-task-...
404
  	struct sk_buff *rep_skb;
51de4d908   Oleg Nesterov   [PATCH] taskstats...
405
  	struct taskstats *stats;
c757249af   Shailabh Nagar   [PATCH] per-task-...
406
  	size_t size;
41c7bb958   Rusty Russell   cpumask: convert ...
407
408
409
410
  	cpumask_var_t mask;
  
  	if (!alloc_cpumask_var(&mask, GFP_KERNEL))
  		return -ENOMEM;
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
411

41c7bb958   Rusty Russell   cpumask: convert ...
412
  	rc = parse(info->attrs[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK], mask);
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
413
  	if (rc < 0)
41c7bb958   Rusty Russell   cpumask: convert ...
414
415
416
417
418
  		goto free_return_rc;
  	if (rc == 0) {
  		rc = add_del_listener(info->snd_pid, mask, REGISTER);
  		goto free_return_rc;
  	}
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
419

41c7bb958   Rusty Russell   cpumask: convert ...
420
  	rc = parse(info->attrs[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK], mask);
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
421
  	if (rc < 0)
41c7bb958   Rusty Russell   cpumask: convert ...
422
423
424
425
426
  		goto free_return_rc;
  	if (rc == 0) {
  		rc = add_del_listener(info->snd_pid, mask, DEREGISTER);
  free_return_rc:
  		free_cpumask_var(mask);
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
427
  		return rc;
41c7bb958   Rusty Russell   cpumask: convert ...
428
429
  	}
  	free_cpumask_var(mask);
c757249af   Shailabh Nagar   [PATCH] per-task-...
430
431
432
433
434
435
  
  	/*
  	 * Size includes space for nested attributes
  	 */
  	size = nla_total_size(sizeof(u32)) +
  		nla_total_size(sizeof(struct taskstats)) + nla_total_size(0);
371674853   Oleg Nesterov   [PATCH] taskstats...
436
  	rc = prepare_reply(info, TASKSTATS_CMD_NEW, &rep_skb, size);
c757249af   Shailabh Nagar   [PATCH] per-task-...
437
438
  	if (rc < 0)
  		return rc;
51de4d908   Oleg Nesterov   [PATCH] taskstats...
439
  	rc = -EINVAL;
c757249af   Shailabh Nagar   [PATCH] per-task-...
440
441
  	if (info->attrs[TASKSTATS_CMD_ATTR_PID]) {
  		u32 pid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_PID]);
51de4d908   Oleg Nesterov   [PATCH] taskstats...
442
443
  		stats = mk_reply(rep_skb, TASKSTATS_TYPE_PID, pid);
  		if (!stats)
371674853   Oleg Nesterov   [PATCH] taskstats...
444
  			goto err;
c757249af   Shailabh Nagar   [PATCH] per-task-...
445

51de4d908   Oleg Nesterov   [PATCH] taskstats...
446
447
  		rc = fill_pid(pid, NULL, stats);
  		if (rc < 0)
371674853   Oleg Nesterov   [PATCH] taskstats...
448
  			goto err;
c757249af   Shailabh Nagar   [PATCH] per-task-...
449
450
  	} else if (info->attrs[TASKSTATS_CMD_ATTR_TGID]) {
  		u32 tgid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_TGID]);
51de4d908   Oleg Nesterov   [PATCH] taskstats...
451
452
  		stats = mk_reply(rep_skb, TASKSTATS_TYPE_TGID, tgid);
  		if (!stats)
371674853   Oleg Nesterov   [PATCH] taskstats...
453
  			goto err;
c757249af   Shailabh Nagar   [PATCH] per-task-...
454

51de4d908   Oleg Nesterov   [PATCH] taskstats...
455
456
  		rc = fill_tgid(tgid, NULL, stats);
  		if (rc < 0)
371674853   Oleg Nesterov   [PATCH] taskstats...
457
  			goto err;
51de4d908   Oleg Nesterov   [PATCH] taskstats...
458
  	} else
c757249af   Shailabh Nagar   [PATCH] per-task-...
459
  		goto err;
c757249af   Shailabh Nagar   [PATCH] per-task-...
460

134e63756   Johannes Berg   genetlink: make n...
461
  	return send_reply(rep_skb, info);
c757249af   Shailabh Nagar   [PATCH] per-task-...
462
463
464
465
  err:
  	nlmsg_free(rep_skb);
  	return rc;
  }
34ec12349   Oleg Nesterov   [PATCH] taskstats...
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
  static struct taskstats *taskstats_tgid_alloc(struct task_struct *tsk)
  {
  	struct signal_struct *sig = tsk->signal;
  	struct taskstats *stats;
  
  	if (sig->stats || thread_group_empty(tsk))
  		goto ret;
  
  	/* No problem if kmem_cache_zalloc() fails */
  	stats = kmem_cache_zalloc(taskstats_cache, GFP_KERNEL);
  
  	spin_lock_irq(&tsk->sighand->siglock);
  	if (!sig->stats) {
  		sig->stats = stats;
  		stats = NULL;
  	}
  	spin_unlock_irq(&tsk->sighand->siglock);
  
  	if (stats)
  		kmem_cache_free(taskstats_cache, stats);
  ret:
  	return sig->stats;
  }
c757249af   Shailabh Nagar   [PATCH] per-task-...
489
  /* Send pid data out on exit */
115085ea0   Oleg Nesterov   [PATCH] taskstats...
490
  void taskstats_exit(struct task_struct *tsk, int group_dead)
c757249af   Shailabh Nagar   [PATCH] per-task-...
491
492
  {
  	int rc;
115085ea0   Oleg Nesterov   [PATCH] taskstats...
493
  	struct listener_list *listeners;
51de4d908   Oleg Nesterov   [PATCH] taskstats...
494
  	struct taskstats *stats;
c757249af   Shailabh Nagar   [PATCH] per-task-...
495
  	struct sk_buff *rep_skb;
c757249af   Shailabh Nagar   [PATCH] per-task-...
496
497
  	size_t size;
  	int is_thread_group;
c757249af   Shailabh Nagar   [PATCH] per-task-...
498

4a279ff1e   Oleg Nesterov   [PATCH] taskstats...
499
  	if (!family_registered)
c757249af   Shailabh Nagar   [PATCH] per-task-...
500
  		return;
c757249af   Shailabh Nagar   [PATCH] per-task-...
501
502
503
504
505
  	/*
  	 * Size includes space for nested attributes
  	 */
  	size = nla_total_size(sizeof(u32)) +
  		nla_total_size(sizeof(struct taskstats)) + nla_total_size(0);
34ec12349   Oleg Nesterov   [PATCH] taskstats...
506
  	is_thread_group = !!taskstats_tgid_alloc(tsk);
4a279ff1e   Oleg Nesterov   [PATCH] taskstats...
507
508
509
510
511
512
  	if (is_thread_group) {
  		/* PID + STATS + TGID + STATS */
  		size = 2 * size;
  		/* fill the tsk->signal->stats structure */
  		fill_tgid_exit(tsk);
  	}
115085ea0   Oleg Nesterov   [PATCH] taskstats...
513
514
515
  	listeners = &__raw_get_cpu_var(listener_array);
  	if (list_empty(&listeners->list))
  		return;
371674853   Oleg Nesterov   [PATCH] taskstats...
516
  	rc = prepare_reply(NULL, TASKSTATS_CMD_NEW, &rep_skb, size);
c757249af   Shailabh Nagar   [PATCH] per-task-...
517
  	if (rc < 0)
51de4d908   Oleg Nesterov   [PATCH] taskstats...
518
  		return;
c757249af   Shailabh Nagar   [PATCH] per-task-...
519

51de4d908   Oleg Nesterov   [PATCH] taskstats...
520
521
  	stats = mk_reply(rep_skb, TASKSTATS_TYPE_PID, tsk->pid);
  	if (!stats)
371674853   Oleg Nesterov   [PATCH] taskstats...
522
  		goto err;
c757249af   Shailabh Nagar   [PATCH] per-task-...
523

cb41d6d06   Pavel Emelyanov   Use find_task_by_...
524
  	rc = fill_pid(-1, tsk, stats);
51de4d908   Oleg Nesterov   [PATCH] taskstats...
525
  	if (rc < 0)
371674853   Oleg Nesterov   [PATCH] taskstats...
526
  		goto err;
c757249af   Shailabh Nagar   [PATCH] per-task-...
527

c757249af   Shailabh Nagar   [PATCH] per-task-...
528
  	/*
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
529
  	 * Doesn't matter if tsk is the leader or the last group member leaving
c757249af   Shailabh Nagar   [PATCH] per-task-...
530
  	 */
68062b86f   Oleg Nesterov   [PATCH] taskstats...
531
  	if (!is_thread_group || !group_dead)
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
532
  		goto send;
c757249af   Shailabh Nagar   [PATCH] per-task-...
533

51de4d908   Oleg Nesterov   [PATCH] taskstats...
534
535
  	stats = mk_reply(rep_skb, TASKSTATS_TYPE_TGID, tsk->tgid);
  	if (!stats)
371674853   Oleg Nesterov   [PATCH] taskstats...
536
  		goto err;
51de4d908   Oleg Nesterov   [PATCH] taskstats...
537
538
  
  	memcpy(stats, tsk->signal->stats, sizeof(*stats));
c757249af   Shailabh Nagar   [PATCH] per-task-...
539

ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
540
  send:
115085ea0   Oleg Nesterov   [PATCH] taskstats...
541
  	send_cpu_listeners(rep_skb, listeners);
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
542
  	return;
371674853   Oleg Nesterov   [PATCH] taskstats...
543
  err:
c757249af   Shailabh Nagar   [PATCH] per-task-...
544
  	nlmsg_free(rep_skb);
c757249af   Shailabh Nagar   [PATCH] per-task-...
545
546
547
548
  }
  
  static struct genl_ops taskstats_ops = {
  	.cmd		= TASKSTATS_CMD_GET,
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
549
  	.doit		= taskstats_user_cmd,
c757249af   Shailabh Nagar   [PATCH] per-task-...
550
551
  	.policy		= taskstats_cmd_get_policy,
  };
846c7bb05   Balbir Singh   Add cgroupstats
552
553
554
555
556
  static struct genl_ops cgroupstats_ops = {
  	.cmd		= CGROUPSTATS_CMD_GET,
  	.doit		= cgroupstats_user_cmd,
  	.policy		= cgroupstats_cmd_get_policy,
  };
c757249af   Shailabh Nagar   [PATCH] per-task-...
557
558
559
  /* Needed early in initialization */
  void __init taskstats_init_early(void)
  {
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
560
  	unsigned int i;
0a31bd5f2   Christoph Lameter   KMEM_CACHE(): sim...
561
  	taskstats_cache = KMEM_CACHE(taskstats, SLAB_PANIC);
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
562
563
564
565
  	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-...
566
567
568
569
570
571
572
573
574
575
576
577
578
  }
  
  static int __init taskstats_init(void)
  {
  	int rc;
  
  	rc = genl_register_family(&family);
  	if (rc)
  		return rc;
  
  	rc = genl_register_ops(&family, &taskstats_ops);
  	if (rc < 0)
  		goto err;
846c7bb05   Balbir Singh   Add cgroupstats
579
580
581
  	rc = genl_register_ops(&family, &cgroupstats_ops);
  	if (rc < 0)
  		goto err_cgroup_ops;
c757249af   Shailabh Nagar   [PATCH] per-task-...
582
  	family_registered = 1;
846c7bb05   Balbir Singh   Add cgroupstats
583
584
  	printk("registered taskstats version %d
  ", TASKSTATS_GENL_VERSION);
c757249af   Shailabh Nagar   [PATCH] per-task-...
585
  	return 0;
846c7bb05   Balbir Singh   Add cgroupstats
586
587
  err_cgroup_ops:
  	genl_unregister_ops(&family, &taskstats_ops);
c757249af   Shailabh Nagar   [PATCH] per-task-...
588
589
590
591
592
593
594
595
596
597
  err:
  	genl_unregister_family(&family);
  	return rc;
  }
  
  /*
   * late initcall ensures initialization of statistics collection
   * mechanisms precedes initialization of the taskstats interface
   */
  late_initcall(taskstats_init);