aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/taskstats.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/taskstats.c')
-rw-r--r--kernel/taskstats.c205
1 files changed, 136 insertions, 69 deletions
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index 11281d5792bd..3308fd7f1b52 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -175,22 +175,8 @@ static void send_cpu_listeners(struct sk_buff *skb,
175 up_write(&listeners->sem); 175 up_write(&listeners->sem);
176} 176}
177 177
178static int fill_pid(pid_t pid, struct task_struct *tsk, 178static void fill_stats(struct task_struct *tsk, struct taskstats *stats)
179 struct taskstats *stats)
180{ 179{
181 int rc = 0;
182
183 if (!tsk) {
184 rcu_read_lock();
185 tsk = find_task_by_vpid(pid);
186 if (tsk)
187 get_task_struct(tsk);
188 rcu_read_unlock();
189 if (!tsk)
190 return -ESRCH;
191 } else
192 get_task_struct(tsk);
193
194 memset(stats, 0, sizeof(*stats)); 180 memset(stats, 0, sizeof(*stats));
195 /* 181 /*
196 * Each accounting subsystem adds calls to its functions to 182 * Each accounting subsystem adds calls to its functions to
@@ -209,17 +195,27 @@ static int fill_pid(pid_t pid, struct task_struct *tsk,
209 195
210 /* fill in extended acct fields */ 196 /* fill in extended acct fields */
211 xacct_add_tsk(stats, tsk); 197 xacct_add_tsk(stats, tsk);
198}
212 199
213 /* Define err: label here if needed */ 200static int fill_stats_for_pid(pid_t pid, struct taskstats *stats)
214 put_task_struct(tsk); 201{
215 return rc; 202 struct task_struct *tsk;
216 203
204 rcu_read_lock();
205 tsk = find_task_by_vpid(pid);
206 if (tsk)
207 get_task_struct(tsk);
208 rcu_read_unlock();
209 if (!tsk)
210 return -ESRCH;
211 fill_stats(tsk, stats);
212 put_task_struct(tsk);
213 return 0;
217} 214}
218 215
219static int fill_tgid(pid_t tgid, struct task_struct *first, 216static int fill_stats_for_tgid(pid_t tgid, struct taskstats *stats)
220 struct taskstats *stats)
221{ 217{
222 struct task_struct *tsk; 218 struct task_struct *tsk, *first;
223 unsigned long flags; 219 unsigned long flags;
224 int rc = -ESRCH; 220 int rc = -ESRCH;
225 221
@@ -228,8 +224,7 @@ static int fill_tgid(pid_t tgid, struct task_struct *first,
228 * leaders who are already counted with the dead tasks 224 * leaders who are already counted with the dead tasks
229 */ 225 */
230 rcu_read_lock(); 226 rcu_read_lock();
231 if (!first) 227 first = find_task_by_vpid(tgid);
232 first = find_task_by_vpid(tgid);
233 228
234 if (!first || !lock_task_sighand(first, &flags)) 229 if (!first || !lock_task_sighand(first, &flags))
235 goto out; 230 goto out;
@@ -268,7 +263,6 @@ out:
268 return rc; 263 return rc;
269} 264}
270 265
271
272static void fill_tgid_exit(struct task_struct *tsk) 266static void fill_tgid_exit(struct task_struct *tsk)
273{ 267{
274 unsigned long flags; 268 unsigned long flags;
@@ -355,6 +349,10 @@ static int parse(struct nlattr *na, struct cpumask *mask)
355 return ret; 349 return ret;
356} 350}
357 351
352#ifdef CONFIG_IA64
353#define TASKSTATS_NEEDS_PADDING 1
354#endif
355
358static struct taskstats *mk_reply(struct sk_buff *skb, int type, u32 pid) 356static struct taskstats *mk_reply(struct sk_buff *skb, int type, u32 pid)
359{ 357{
360 struct nlattr *na, *ret; 358 struct nlattr *na, *ret;
@@ -364,9 +362,33 @@ static struct taskstats *mk_reply(struct sk_buff *skb, int type, u32 pid)
364 ? TASKSTATS_TYPE_AGGR_PID 362 ? TASKSTATS_TYPE_AGGR_PID
365 : TASKSTATS_TYPE_AGGR_TGID; 363 : TASKSTATS_TYPE_AGGR_TGID;
366 364
365 /*
366 * The taskstats structure is internally aligned on 8 byte
367 * boundaries but the layout of the aggregrate reply, with
368 * two NLA headers and the pid (each 4 bytes), actually
369 * force the entire structure to be unaligned. This causes
370 * the kernel to issue unaligned access warnings on some
371 * architectures like ia64. Unfortunately, some software out there
372 * doesn't properly unroll the NLA packet and assumes that the start
373 * of the taskstats structure will always be 20 bytes from the start
374 * of the netlink payload. Aligning the start of the taskstats
375 * structure breaks this software, which we don't want. So, for now
376 * the alignment only happens on architectures that require it
377 * and those users will have to update to fixed versions of those
378 * packages. Space is reserved in the packet only when needed.
379 * This ifdef should be removed in several years e.g. 2012 once
380 * we can be confident that fixed versions are installed on most
381 * systems. We add the padding before the aggregate since the
382 * aggregate is already a defined type.
383 */
384#ifdef TASKSTATS_NEEDS_PADDING
385 if (nla_put(skb, TASKSTATS_TYPE_NULL, 0, NULL) < 0)
386 goto err;
387#endif
367 na = nla_nest_start(skb, aggr); 388 na = nla_nest_start(skb, aggr);
368 if (!na) 389 if (!na)
369 goto err; 390 goto err;
391
370 if (nla_put(skb, type, sizeof(pid), &pid) < 0) 392 if (nla_put(skb, type, sizeof(pid), &pid) < 0)
371 goto err; 393 goto err;
372 ret = nla_reserve(skb, TASKSTATS_TYPE_STATS, sizeof(struct taskstats)); 394 ret = nla_reserve(skb, TASKSTATS_TYPE_STATS, sizeof(struct taskstats));
@@ -424,74 +446,122 @@ err:
424 return rc; 446 return rc;
425} 447}
426 448
427static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info) 449static int cmd_attr_register_cpumask(struct genl_info *info)
428{ 450{
429 int rc;
430 struct sk_buff *rep_skb;
431 struct taskstats *stats;
432 size_t size;
433 cpumask_var_t mask; 451 cpumask_var_t mask;
452 int rc;
434 453
435 if (!alloc_cpumask_var(&mask, GFP_KERNEL)) 454 if (!alloc_cpumask_var(&mask, GFP_KERNEL))
436 return -ENOMEM; 455 return -ENOMEM;
437
438 rc = parse(info->attrs[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK], mask); 456 rc = parse(info->attrs[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK], mask);
439 if (rc < 0) 457 if (rc < 0)
440 goto free_return_rc; 458 goto out;
441 if (rc == 0) { 459 rc = add_del_listener(info->snd_pid, mask, REGISTER);
442 rc = add_del_listener(info->snd_pid, mask, REGISTER); 460out:
443 goto free_return_rc; 461 free_cpumask_var(mask);
444 } 462 return rc;
463}
464
465static int cmd_attr_deregister_cpumask(struct genl_info *info)
466{
467 cpumask_var_t mask;
468 int rc;
445 469
470 if (!alloc_cpumask_var(&mask, GFP_KERNEL))
471 return -ENOMEM;
446 rc = parse(info->attrs[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK], mask); 472 rc = parse(info->attrs[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK], mask);
447 if (rc < 0) 473 if (rc < 0)
448 goto free_return_rc; 474 goto out;
449 if (rc == 0) { 475 rc = add_del_listener(info->snd_pid, mask, DEREGISTER);
450 rc = add_del_listener(info->snd_pid, mask, DEREGISTER); 476out:
451free_return_rc:
452 free_cpumask_var(mask);
453 return rc;
454 }
455 free_cpumask_var(mask); 477 free_cpumask_var(mask);
478 return rc;
479}
480
481static size_t taskstats_packet_size(void)
482{
483 size_t size;
456 484
457 /*
458 * Size includes space for nested attributes
459 */
460 size = nla_total_size(sizeof(u32)) + 485 size = nla_total_size(sizeof(u32)) +
461 nla_total_size(sizeof(struct taskstats)) + nla_total_size(0); 486 nla_total_size(sizeof(struct taskstats)) + nla_total_size(0);
487#ifdef TASKSTATS_NEEDS_PADDING
488 size += nla_total_size(0); /* Padding for alignment */
489#endif
490 return size;
491}
492
493static int cmd_attr_pid(struct genl_info *info)
494{
495 struct taskstats *stats;
496 struct sk_buff *rep_skb;
497 size_t size;
498 u32 pid;
499 int rc;
500
501 size = taskstats_packet_size();
462 502
463 rc = prepare_reply(info, TASKSTATS_CMD_NEW, &rep_skb, size); 503 rc = prepare_reply(info, TASKSTATS_CMD_NEW, &rep_skb, size);
464 if (rc < 0) 504 if (rc < 0)
465 return rc; 505 return rc;
466 506
467 rc = -EINVAL; 507 rc = -EINVAL;
468 if (info->attrs[TASKSTATS_CMD_ATTR_PID]) { 508 pid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_PID]);
469 u32 pid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_PID]); 509 stats = mk_reply(rep_skb, TASKSTATS_TYPE_PID, pid);
470 stats = mk_reply(rep_skb, TASKSTATS_TYPE_PID, pid); 510 if (!stats)
471 if (!stats)
472 goto err;
473
474 rc = fill_pid(pid, NULL, stats);
475 if (rc < 0)
476 goto err;
477 } else if (info->attrs[TASKSTATS_CMD_ATTR_TGID]) {
478 u32 tgid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_TGID]);
479 stats = mk_reply(rep_skb, TASKSTATS_TYPE_TGID, tgid);
480 if (!stats)
481 goto err;
482
483 rc = fill_tgid(tgid, NULL, stats);
484 if (rc < 0)
485 goto err;
486 } else
487 goto err; 511 goto err;
488 512
513 rc = fill_stats_for_pid(pid, stats);
514 if (rc < 0)
515 goto err;
489 return send_reply(rep_skb, info); 516 return send_reply(rep_skb, info);
490err: 517err:
491 nlmsg_free(rep_skb); 518 nlmsg_free(rep_skb);
492 return rc; 519 return rc;
493} 520}
494 521
522static int cmd_attr_tgid(struct genl_info *info)
523{
524 struct taskstats *stats;
525 struct sk_buff *rep_skb;
526 size_t size;
527 u32 tgid;
528 int rc;
529
530 size = taskstats_packet_size();
531
532 rc = prepare_reply(info, TASKSTATS_CMD_NEW, &rep_skb, size);
533 if (rc < 0)
534 return rc;
535
536 rc = -EINVAL;
537 tgid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_TGID]);
538 stats = mk_reply(rep_skb, TASKSTATS_TYPE_TGID, tgid);
539 if (!stats)
540 goto err;
541
542 rc = fill_stats_for_tgid(tgid, stats);
543 if (rc < 0)
544 goto err;
545 return send_reply(rep_skb, info);
546err:
547 nlmsg_free(rep_skb);
548 return rc;
549}
550
551static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
552{
553 if (info->attrs[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK])
554 return cmd_attr_register_cpumask(info);
555 else if (info->attrs[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK])
556 return cmd_attr_deregister_cpumask(info);
557 else if (info->attrs[TASKSTATS_CMD_ATTR_PID])
558 return cmd_attr_pid(info);
559 else if (info->attrs[TASKSTATS_CMD_ATTR_TGID])
560 return cmd_attr_tgid(info);
561 else
562 return -EINVAL;
563}
564
495static struct taskstats *taskstats_tgid_alloc(struct task_struct *tsk) 565static struct taskstats *taskstats_tgid_alloc(struct task_struct *tsk)
496{ 566{
497 struct signal_struct *sig = tsk->signal; 567 struct signal_struct *sig = tsk->signal;
@@ -532,8 +602,7 @@ void taskstats_exit(struct task_struct *tsk, int group_dead)
532 /* 602 /*
533 * Size includes space for nested attributes 603 * Size includes space for nested attributes
534 */ 604 */
535 size = nla_total_size(sizeof(u32)) + 605 size = taskstats_packet_size();
536 nla_total_size(sizeof(struct taskstats)) + nla_total_size(0);
537 606
538 is_thread_group = !!taskstats_tgid_alloc(tsk); 607 is_thread_group = !!taskstats_tgid_alloc(tsk);
539 if (is_thread_group) { 608 if (is_thread_group) {
@@ -555,9 +624,7 @@ void taskstats_exit(struct task_struct *tsk, int group_dead)
555 if (!stats) 624 if (!stats)
556 goto err; 625 goto err;
557 626
558 rc = fill_pid(-1, tsk, stats); 627 fill_stats(tsk, stats);
559 if (rc < 0)
560 goto err;
561 628
562 /* 629 /*
563 * Doesn't matter if tsk is the leader or the last group member leaving 630 * Doesn't matter if tsk is the leader or the last group member leaving