Blame view

kernel/taskstats.c 12.1 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>
9acc18535   Jay Lan   [PATCH] csa: Exte...
23
  #include <linux/tsacct_kern.h>
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
24
25
  #include <linux/cpumask.h>
  #include <linux/percpu.h>
c757249af   Shailabh Nagar   [PATCH] per-task-...
26
27
  #include <net/genetlink.h>
  #include <asm/atomic.h>
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
28
29
30
31
32
  /*
   * 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)
c757249af   Shailabh Nagar   [PATCH] per-task-...
33
34
  static DEFINE_PER_CPU(__u32, taskstats_seqnum) = { 0 };
  static int family_registered;
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
35
  struct kmem_cache *taskstats_cache;
c757249af   Shailabh Nagar   [PATCH] per-task-...
36
37
38
39
40
41
42
43
44
45
46
47
  
  static struct genl_family family = {
  	.id		= GENL_ID_GENERATE,
  	.name		= TASKSTATS_GENL_NAME,
  	.version	= TASKSTATS_GENL_VERSION,
  	.maxattr	= TASKSTATS_CMD_ATTR_MAX,
  };
  
  static struct nla_policy taskstats_cmd_get_policy[TASKSTATS_CMD_ATTR_MAX+1]
  __read_mostly = {
  	[TASKSTATS_CMD_ATTR_PID]  = { .type = NLA_U32 },
  	[TASKSTATS_CMD_ATTR_TGID] = { .type = NLA_U32 },
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
48
49
50
51
52
53
  	[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK] = { .type = NLA_STRING },
  	[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK] = { .type = NLA_STRING },};
  
  struct listener {
  	struct list_head list;
  	pid_t pid;
bb129994c   Shailabh Nagar   [PATCH] Remove do...
54
  	char valid;
c757249af   Shailabh Nagar   [PATCH] per-task-...
55
  };
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
56
57
58
59
60
61
62
63
64
65
66
  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-...
67
68
  
  static int prepare_reply(struct genl_info *info, u8 cmd, struct sk_buff **skbp,
371674853   Oleg Nesterov   [PATCH] taskstats...
69
  				size_t size)
c757249af   Shailabh Nagar   [PATCH] per-task-...
70
71
72
73
74
75
76
  {
  	struct sk_buff *skb;
  	void *reply;
  
  	/*
  	 * If new attributes are added, please revisit this allocation
  	 */
3dabc7157   Thomas Graf   [GENL]: Add genlm...
77
  	skb = genlmsg_new(size, GFP_KERNEL);
c757249af   Shailabh Nagar   [PATCH] per-task-...
78
79
80
81
82
83
  	if (!skb)
  		return -ENOMEM;
  
  	if (!info) {
  		int seq = get_cpu_var(taskstats_seqnum)++;
  		put_cpu_var(taskstats_seqnum);
17c157c88   Thomas Graf   [GENL]: Add genlm...
84
  		reply = genlmsg_put(skb, 0, seq, &family, 0, cmd);
c757249af   Shailabh Nagar   [PATCH] per-task-...
85
  	} else
17c157c88   Thomas Graf   [GENL]: Add genlm...
86
  		reply = genlmsg_put_reply(skb, info, &family, 0, cmd);
c757249af   Shailabh Nagar   [PATCH] per-task-...
87
88
89
90
91
92
  	if (reply == NULL) {
  		nlmsg_free(skb);
  		return -EINVAL;
  	}
  
  	*skbp = skb;
c757249af   Shailabh Nagar   [PATCH] per-task-...
93
94
  	return 0;
  }
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
95
96
97
98
  /*
   * Send taskstats data in @skb to listener with nl_pid @pid
   */
  static int send_reply(struct sk_buff *skb, pid_t pid)
c757249af   Shailabh Nagar   [PATCH] per-task-...
99
  {
b529ccf27   Arnaldo Carvalho de Melo   [NETLINK]: Introd...
100
  	struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
101
  	void *reply = genlmsg_data(genlhdr);
c757249af   Shailabh Nagar   [PATCH] per-task-...
102
  	int rc;
c757249af   Shailabh Nagar   [PATCH] per-task-...
103
104
105
106
107
  	rc = genlmsg_end(skb, reply);
  	if (rc < 0) {
  		nlmsg_free(skb);
  		return rc;
  	}
c757249af   Shailabh Nagar   [PATCH] per-task-...
108
109
  	return genlmsg_unicast(skb, pid);
  }
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
110
111
112
  /*
   * Send taskstats data in @skb to listeners registered for @cpu's exit data
   */
115085ea0   Oleg Nesterov   [PATCH] taskstats...
113
114
  static void send_cpu_listeners(struct sk_buff *skb,
  					struct listener_list *listeners)
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
115
  {
b529ccf27   Arnaldo Carvalho de Melo   [NETLINK]: Introd...
116
  	struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
117
118
119
  	struct listener *s, *tmp;
  	struct sk_buff *skb_next, *skb_cur = skb;
  	void *reply = genlmsg_data(genlhdr);
d94a04151   Shailabh Nagar   [PATCH] taskstats...
120
  	int rc, delcount = 0;
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
121
122
123
124
  
  	rc = genlmsg_end(skb, reply);
  	if (rc < 0) {
  		nlmsg_free(skb);
d94a04151   Shailabh Nagar   [PATCH] taskstats...
125
  		return;
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
126
127
128
  	}
  
  	rc = 0;
bb129994c   Shailabh Nagar   [PATCH] Remove do...
129
  	down_read(&listeners->sem);
d94a04151   Shailabh Nagar   [PATCH] taskstats...
130
  	list_for_each_entry(s, &listeners->list, list) {
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
131
132
133
  		skb_next = NULL;
  		if (!list_is_last(&s->list, &listeners->list)) {
  			skb_next = skb_clone(skb_cur, GFP_KERNEL);
d94a04151   Shailabh Nagar   [PATCH] taskstats...
134
  			if (!skb_next)
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
135
  				break;
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
136
  		}
d94a04151   Shailabh Nagar   [PATCH] taskstats...
137
138
  		rc = genlmsg_unicast(skb_cur, s->pid);
  		if (rc == -ECONNREFUSED) {
bb129994c   Shailabh Nagar   [PATCH] Remove do...
139
140
  			s->valid = 0;
  			delcount++;
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
141
142
143
  		}
  		skb_cur = skb_next;
  	}
bb129994c   Shailabh Nagar   [PATCH] Remove do...
144
  	up_read(&listeners->sem);
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
145

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

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

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

ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
205
206
207
208
  	/*
  	 * Add additional stats from live tasks except zombie thread group
  	 * leaders who are already counted with the dead tasks
  	 */
a98b60942   Oleg Nesterov   [PATCH] taskstats...
209
210
  	rcu_read_lock();
  	if (!first)
c757249af   Shailabh Nagar   [PATCH] per-task-...
211
  		first = find_task_by_pid(tgid);
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
212

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

a98b60942   Oleg Nesterov   [PATCH] taskstats...
216
217
  	if (first->signal->stats)
  		memcpy(stats, first->signal->stats, sizeof(*stats));
51de4d908   Oleg Nesterov   [PATCH] taskstats...
218
219
  	else
  		memset(stats, 0, sizeof(*stats));
fca178c0c   Oleg Nesterov   [PATCH] fill_tgid...
220

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

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

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

f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
276
277
278
279
280
281
282
283
284
285
286
  	if (!cpus_subset(mask, cpu_possible_map))
  		return -EINVAL;
  
  	if (isadd == REGISTER) {
  		for_each_cpu_mask(cpu, mask) {
  			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...
287
  			s->valid = 1;
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
  
  			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:
  	for_each_cpu_mask(cpu, mask) {
  		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;
  }
  
  static int parse(struct nlattr *na, cpumask_t *mask)
  {
  	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);
  	ret = cpulist_parse(data, *mask);
  	kfree(data);
  	return ret;
  }
51de4d908   Oleg Nesterov   [PATCH] taskstats...
335
  static struct taskstats *mk_reply(struct sk_buff *skb, int type, u32 pid)
68062b86f   Oleg Nesterov   [PATCH] taskstats...
336
  {
51de4d908   Oleg Nesterov   [PATCH] taskstats...
337
  	struct nlattr *na, *ret;
68062b86f   Oleg Nesterov   [PATCH] taskstats...
338
  	int aggr;
371674853   Oleg Nesterov   [PATCH] taskstats...
339
340
341
  	aggr = (type == TASKSTATS_TYPE_PID)
  			? TASKSTATS_TYPE_AGGR_PID
  			: TASKSTATS_TYPE_AGGR_TGID;
68062b86f   Oleg Nesterov   [PATCH] taskstats...
342
343
  
  	na = nla_nest_start(skb, aggr);
371674853   Oleg Nesterov   [PATCH] taskstats...
344
345
  	if (!na)
  		goto err;
51de4d908   Oleg Nesterov   [PATCH] taskstats...
346
347
348
349
350
  	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...
351
  	nla_nest_end(skb, na);
51de4d908   Oleg Nesterov   [PATCH] taskstats...
352
353
354
  	return nla_data(ret);
  err:
  	return NULL;
68062b86f   Oleg Nesterov   [PATCH] taskstats...
355
  }
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
356
  static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
c757249af   Shailabh Nagar   [PATCH] per-task-...
357
358
359
  {
  	int rc = 0;
  	struct sk_buff *rep_skb;
51de4d908   Oleg Nesterov   [PATCH] taskstats...
360
  	struct taskstats *stats;
c757249af   Shailabh Nagar   [PATCH] per-task-...
361
  	size_t size;
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
362
363
364
365
366
367
368
369
370
371
372
373
374
  	cpumask_t mask;
  
  	rc = parse(info->attrs[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK], &mask);
  	if (rc < 0)
  		return rc;
  	if (rc == 0)
  		return add_del_listener(info->snd_pid, &mask, REGISTER);
  
  	rc = parse(info->attrs[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK], &mask);
  	if (rc < 0)
  		return rc;
  	if (rc == 0)
  		return add_del_listener(info->snd_pid, &mask, DEREGISTER);
c757249af   Shailabh Nagar   [PATCH] per-task-...
375
376
377
378
379
380
  
  	/*
  	 * 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...
381
  	rc = prepare_reply(info, TASKSTATS_CMD_NEW, &rep_skb, size);
c757249af   Shailabh Nagar   [PATCH] per-task-...
382
383
  	if (rc < 0)
  		return rc;
51de4d908   Oleg Nesterov   [PATCH] taskstats...
384
  	rc = -EINVAL;
c757249af   Shailabh Nagar   [PATCH] per-task-...
385
386
  	if (info->attrs[TASKSTATS_CMD_ATTR_PID]) {
  		u32 pid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_PID]);
51de4d908   Oleg Nesterov   [PATCH] taskstats...
387
388
  		stats = mk_reply(rep_skb, TASKSTATS_TYPE_PID, pid);
  		if (!stats)
371674853   Oleg Nesterov   [PATCH] taskstats...
389
  			goto err;
c757249af   Shailabh Nagar   [PATCH] per-task-...
390

51de4d908   Oleg Nesterov   [PATCH] taskstats...
391
392
  		rc = fill_pid(pid, NULL, stats);
  		if (rc < 0)
371674853   Oleg Nesterov   [PATCH] taskstats...
393
  			goto err;
c757249af   Shailabh Nagar   [PATCH] per-task-...
394
395
  	} else if (info->attrs[TASKSTATS_CMD_ATTR_TGID]) {
  		u32 tgid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_TGID]);
51de4d908   Oleg Nesterov   [PATCH] taskstats...
396
397
  		stats = mk_reply(rep_skb, TASKSTATS_TYPE_TGID, tgid);
  		if (!stats)
371674853   Oleg Nesterov   [PATCH] taskstats...
398
  			goto err;
c757249af   Shailabh Nagar   [PATCH] per-task-...
399

51de4d908   Oleg Nesterov   [PATCH] taskstats...
400
401
  		rc = fill_tgid(tgid, NULL, stats);
  		if (rc < 0)
371674853   Oleg Nesterov   [PATCH] taskstats...
402
  			goto err;
51de4d908   Oleg Nesterov   [PATCH] taskstats...
403
  	} else
c757249af   Shailabh Nagar   [PATCH] per-task-...
404
  		goto err;
c757249af   Shailabh Nagar   [PATCH] per-task-...
405

f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
406
  	return send_reply(rep_skb, info->snd_pid);
c757249af   Shailabh Nagar   [PATCH] per-task-...
407
408
409
410
  err:
  	nlmsg_free(rep_skb);
  	return rc;
  }
34ec12349   Oleg Nesterov   [PATCH] taskstats...
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
  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-...
434
  /* Send pid data out on exit */
115085ea0   Oleg Nesterov   [PATCH] taskstats...
435
  void taskstats_exit(struct task_struct *tsk, int group_dead)
c757249af   Shailabh Nagar   [PATCH] per-task-...
436
437
  {
  	int rc;
115085ea0   Oleg Nesterov   [PATCH] taskstats...
438
  	struct listener_list *listeners;
51de4d908   Oleg Nesterov   [PATCH] taskstats...
439
  	struct taskstats *stats;
c757249af   Shailabh Nagar   [PATCH] per-task-...
440
  	struct sk_buff *rep_skb;
c757249af   Shailabh Nagar   [PATCH] per-task-...
441
442
  	size_t size;
  	int is_thread_group;
c757249af   Shailabh Nagar   [PATCH] per-task-...
443

4a279ff1e   Oleg Nesterov   [PATCH] taskstats...
444
  	if (!family_registered)
c757249af   Shailabh Nagar   [PATCH] per-task-...
445
  		return;
c757249af   Shailabh Nagar   [PATCH] per-task-...
446
447
448
449
450
  	/*
  	 * 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...
451
  	is_thread_group = !!taskstats_tgid_alloc(tsk);
4a279ff1e   Oleg Nesterov   [PATCH] taskstats...
452
453
454
455
456
457
  	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...
458
459
460
  	listeners = &__raw_get_cpu_var(listener_array);
  	if (list_empty(&listeners->list))
  		return;
371674853   Oleg Nesterov   [PATCH] taskstats...
461
  	rc = prepare_reply(NULL, TASKSTATS_CMD_NEW, &rep_skb, size);
c757249af   Shailabh Nagar   [PATCH] per-task-...
462
  	if (rc < 0)
51de4d908   Oleg Nesterov   [PATCH] taskstats...
463
  		return;
c757249af   Shailabh Nagar   [PATCH] per-task-...
464

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

51de4d908   Oleg Nesterov   [PATCH] taskstats...
469
470
  	rc = fill_pid(tsk->pid, tsk, stats);
  	if (rc < 0)
371674853   Oleg Nesterov   [PATCH] taskstats...
471
  		goto err;
c757249af   Shailabh Nagar   [PATCH] per-task-...
472

c757249af   Shailabh Nagar   [PATCH] per-task-...
473
  	/*
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
474
  	 * Doesn't matter if tsk is the leader or the last group member leaving
c757249af   Shailabh Nagar   [PATCH] per-task-...
475
  	 */
68062b86f   Oleg Nesterov   [PATCH] taskstats...
476
  	if (!is_thread_group || !group_dead)
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
477
  		goto send;
c757249af   Shailabh Nagar   [PATCH] per-task-...
478

51de4d908   Oleg Nesterov   [PATCH] taskstats...
479
480
  	stats = mk_reply(rep_skb, TASKSTATS_TYPE_TGID, tsk->tgid);
  	if (!stats)
371674853   Oleg Nesterov   [PATCH] taskstats...
481
  		goto err;
51de4d908   Oleg Nesterov   [PATCH] taskstats...
482
483
  
  	memcpy(stats, tsk->signal->stats, sizeof(*stats));
c757249af   Shailabh Nagar   [PATCH] per-task-...
484

ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
485
  send:
115085ea0   Oleg Nesterov   [PATCH] taskstats...
486
  	send_cpu_listeners(rep_skb, listeners);
ad4ecbcba   Shailabh Nagar   [PATCH] delay acc...
487
  	return;
371674853   Oleg Nesterov   [PATCH] taskstats...
488
  err:
c757249af   Shailabh Nagar   [PATCH] per-task-...
489
  	nlmsg_free(rep_skb);
c757249af   Shailabh Nagar   [PATCH] per-task-...
490
491
492
493
  }
  
  static struct genl_ops taskstats_ops = {
  	.cmd		= TASKSTATS_CMD_GET,
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
494
  	.doit		= taskstats_user_cmd,
c757249af   Shailabh Nagar   [PATCH] per-task-...
495
496
497
498
499
500
  	.policy		= taskstats_cmd_get_policy,
  };
  
  /* Needed early in initialization */
  void __init taskstats_init_early(void)
  {
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
501
  	unsigned int i;
0a31bd5f2   Christoph Lameter   KMEM_CACHE(): sim...
502
  	taskstats_cache = KMEM_CACHE(taskstats, SLAB_PANIC);
f9fd8914c   Shailabh Nagar   [PATCH] per-task ...
503
504
505
506
  	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-...
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
  }
  
  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;
  
  	family_registered = 1;
  	return 0;
  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);