1c757249aSShailabh Nagar /* 2c757249aSShailabh Nagar * taskstats.c - Export per-task statistics to userland 3c757249aSShailabh Nagar * 4c757249aSShailabh Nagar * Copyright (C) Shailabh Nagar, IBM Corp. 2006 5c757249aSShailabh Nagar * (C) Balbir Singh, IBM Corp. 2006 6c757249aSShailabh Nagar * 7c757249aSShailabh Nagar * This program is free software; you can redistribute it and/or modify 8c757249aSShailabh Nagar * it under the terms of the GNU General Public License as published by 9c757249aSShailabh Nagar * the Free Software Foundation; either version 2 of the License, or 10c757249aSShailabh Nagar * (at your option) any later version. 11c757249aSShailabh Nagar * 12c757249aSShailabh Nagar * This program is distributed in the hope that it will be useful, 13c757249aSShailabh Nagar * but WITHOUT ANY WARRANTY; without even the implied warranty of 14c757249aSShailabh Nagar * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15c757249aSShailabh Nagar * GNU General Public License for more details. 16c757249aSShailabh Nagar * 17c757249aSShailabh Nagar */ 18c757249aSShailabh Nagar 19c757249aSShailabh Nagar #include <linux/kernel.h> 20c757249aSShailabh Nagar #include <linux/taskstats_kern.h> 216f44993fSShailabh Nagar #include <linux/delayacct.h> 22f9fd8914SShailabh Nagar #include <linux/cpumask.h> 23f9fd8914SShailabh Nagar #include <linux/percpu.h> 24c757249aSShailabh Nagar #include <net/genetlink.h> 25c757249aSShailabh Nagar #include <asm/atomic.h> 26c757249aSShailabh Nagar 27f9fd8914SShailabh Nagar /* 28f9fd8914SShailabh Nagar * Maximum length of a cpumask that can be specified in 29f9fd8914SShailabh Nagar * the TASKSTATS_CMD_ATTR_REGISTER/DEREGISTER_CPUMASK attribute 30f9fd8914SShailabh Nagar */ 31f9fd8914SShailabh Nagar #define TASKSTATS_CPUMASK_MAXLEN (100+6*NR_CPUS) 32f9fd8914SShailabh Nagar 33c757249aSShailabh Nagar static DEFINE_PER_CPU(__u32, taskstats_seqnum) = { 0 }; 34c757249aSShailabh Nagar static int family_registered; 35c757249aSShailabh Nagar kmem_cache_t *taskstats_cache; 36c757249aSShailabh Nagar 37c757249aSShailabh Nagar static struct genl_family family = { 38c757249aSShailabh Nagar .id = GENL_ID_GENERATE, 39c757249aSShailabh Nagar .name = TASKSTATS_GENL_NAME, 40c757249aSShailabh Nagar .version = TASKSTATS_GENL_VERSION, 41c757249aSShailabh Nagar .maxattr = TASKSTATS_CMD_ATTR_MAX, 42c757249aSShailabh Nagar }; 43c757249aSShailabh Nagar 44c757249aSShailabh Nagar static struct nla_policy taskstats_cmd_get_policy[TASKSTATS_CMD_ATTR_MAX+1] 45c757249aSShailabh Nagar __read_mostly = { 46c757249aSShailabh Nagar [TASKSTATS_CMD_ATTR_PID] = { .type = NLA_U32 }, 47c757249aSShailabh Nagar [TASKSTATS_CMD_ATTR_TGID] = { .type = NLA_U32 }, 48f9fd8914SShailabh Nagar [TASKSTATS_CMD_ATTR_REGISTER_CPUMASK] = { .type = NLA_STRING }, 49f9fd8914SShailabh Nagar [TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK] = { .type = NLA_STRING },}; 50f9fd8914SShailabh Nagar 51f9fd8914SShailabh Nagar struct listener { 52f9fd8914SShailabh Nagar struct list_head list; 53f9fd8914SShailabh Nagar pid_t pid; 54bb129994SShailabh Nagar char valid; 55c757249aSShailabh Nagar }; 56c757249aSShailabh Nagar 57f9fd8914SShailabh Nagar struct listener_list { 58f9fd8914SShailabh Nagar struct rw_semaphore sem; 59f9fd8914SShailabh Nagar struct list_head list; 60f9fd8914SShailabh Nagar }; 61f9fd8914SShailabh Nagar static DEFINE_PER_CPU(struct listener_list, listener_array); 62f9fd8914SShailabh Nagar 63f9fd8914SShailabh Nagar enum actions { 64f9fd8914SShailabh Nagar REGISTER, 65f9fd8914SShailabh Nagar DEREGISTER, 66f9fd8914SShailabh Nagar CPU_DONT_CARE 67f9fd8914SShailabh Nagar }; 68c757249aSShailabh Nagar 69c757249aSShailabh Nagar static int prepare_reply(struct genl_info *info, u8 cmd, struct sk_buff **skbp, 70c757249aSShailabh Nagar void **replyp, size_t size) 71c757249aSShailabh Nagar { 72c757249aSShailabh Nagar struct sk_buff *skb; 73c757249aSShailabh Nagar void *reply; 74c757249aSShailabh Nagar 75c757249aSShailabh Nagar /* 76c757249aSShailabh Nagar * If new attributes are added, please revisit this allocation 77c757249aSShailabh Nagar */ 78c757249aSShailabh Nagar skb = nlmsg_new(size); 79c757249aSShailabh Nagar if (!skb) 80c757249aSShailabh Nagar return -ENOMEM; 81c757249aSShailabh Nagar 82c757249aSShailabh Nagar if (!info) { 83c757249aSShailabh Nagar int seq = get_cpu_var(taskstats_seqnum)++; 84c757249aSShailabh Nagar put_cpu_var(taskstats_seqnum); 85c757249aSShailabh Nagar 86c757249aSShailabh Nagar reply = genlmsg_put(skb, 0, seq, 87c757249aSShailabh Nagar family.id, 0, 0, 88c757249aSShailabh Nagar cmd, family.version); 89c757249aSShailabh Nagar } else 90c757249aSShailabh Nagar reply = genlmsg_put(skb, info->snd_pid, info->snd_seq, 91c757249aSShailabh Nagar family.id, 0, 0, 92c757249aSShailabh Nagar cmd, family.version); 93c757249aSShailabh Nagar if (reply == NULL) { 94c757249aSShailabh Nagar nlmsg_free(skb); 95c757249aSShailabh Nagar return -EINVAL; 96c757249aSShailabh Nagar } 97c757249aSShailabh Nagar 98c757249aSShailabh Nagar *skbp = skb; 99c757249aSShailabh Nagar *replyp = reply; 100c757249aSShailabh Nagar return 0; 101c757249aSShailabh Nagar } 102c757249aSShailabh Nagar 103f9fd8914SShailabh Nagar /* 104f9fd8914SShailabh Nagar * Send taskstats data in @skb to listener with nl_pid @pid 105f9fd8914SShailabh Nagar */ 106f9fd8914SShailabh Nagar static int send_reply(struct sk_buff *skb, pid_t pid) 107c757249aSShailabh Nagar { 108c757249aSShailabh Nagar struct genlmsghdr *genlhdr = nlmsg_data((struct nlmsghdr *)skb->data); 109f9fd8914SShailabh Nagar void *reply = genlmsg_data(genlhdr); 110c757249aSShailabh Nagar int rc; 111c757249aSShailabh Nagar 112c757249aSShailabh Nagar rc = genlmsg_end(skb, reply); 113c757249aSShailabh Nagar if (rc < 0) { 114c757249aSShailabh Nagar nlmsg_free(skb); 115c757249aSShailabh Nagar return rc; 116c757249aSShailabh Nagar } 117c757249aSShailabh Nagar 118c757249aSShailabh Nagar return genlmsg_unicast(skb, pid); 119c757249aSShailabh Nagar } 120c757249aSShailabh Nagar 121f9fd8914SShailabh Nagar /* 122f9fd8914SShailabh Nagar * Send taskstats data in @skb to listeners registered for @cpu's exit data 123f9fd8914SShailabh Nagar */ 124f9fd8914SShailabh Nagar static int send_cpu_listeners(struct sk_buff *skb, unsigned int cpu) 125f9fd8914SShailabh Nagar { 126f9fd8914SShailabh Nagar struct genlmsghdr *genlhdr = nlmsg_data((struct nlmsghdr *)skb->data); 127f9fd8914SShailabh Nagar struct listener_list *listeners; 128f9fd8914SShailabh Nagar struct listener *s, *tmp; 129f9fd8914SShailabh Nagar struct sk_buff *skb_next, *skb_cur = skb; 130f9fd8914SShailabh Nagar void *reply = genlmsg_data(genlhdr); 131bb129994SShailabh Nagar int rc, ret, delcount = 0; 132f9fd8914SShailabh Nagar 133f9fd8914SShailabh Nagar rc = genlmsg_end(skb, reply); 134f9fd8914SShailabh Nagar if (rc < 0) { 135f9fd8914SShailabh Nagar nlmsg_free(skb); 136f9fd8914SShailabh Nagar return rc; 137f9fd8914SShailabh Nagar } 138f9fd8914SShailabh Nagar 139f9fd8914SShailabh Nagar rc = 0; 140f9fd8914SShailabh Nagar listeners = &per_cpu(listener_array, cpu); 141bb129994SShailabh Nagar down_read(&listeners->sem); 142f9fd8914SShailabh Nagar list_for_each_entry_safe(s, tmp, &listeners->list, list) { 143f9fd8914SShailabh Nagar skb_next = NULL; 144f9fd8914SShailabh Nagar if (!list_is_last(&s->list, &listeners->list)) { 145f9fd8914SShailabh Nagar skb_next = skb_clone(skb_cur, GFP_KERNEL); 146f9fd8914SShailabh Nagar if (!skb_next) { 147f9fd8914SShailabh Nagar nlmsg_free(skb_cur); 148f9fd8914SShailabh Nagar rc = -ENOMEM; 149f9fd8914SShailabh Nagar break; 150f9fd8914SShailabh Nagar } 151f9fd8914SShailabh Nagar } 152f9fd8914SShailabh Nagar ret = genlmsg_unicast(skb_cur, s->pid); 153f9fd8914SShailabh Nagar if (ret == -ECONNREFUSED) { 154bb129994SShailabh Nagar s->valid = 0; 155bb129994SShailabh Nagar delcount++; 156f9fd8914SShailabh Nagar rc = ret; 157f9fd8914SShailabh Nagar } 158f9fd8914SShailabh Nagar skb_cur = skb_next; 159f9fd8914SShailabh Nagar } 160bb129994SShailabh Nagar up_read(&listeners->sem); 161f9fd8914SShailabh Nagar 162bb129994SShailabh Nagar if (!delcount) 163bb129994SShailabh Nagar return rc; 164bb129994SShailabh Nagar 165bb129994SShailabh Nagar /* Delete invalidated entries */ 166bb129994SShailabh Nagar down_write(&listeners->sem); 167bb129994SShailabh Nagar list_for_each_entry_safe(s, tmp, &listeners->list, list) { 168bb129994SShailabh Nagar if (!s->valid) { 169bb129994SShailabh Nagar list_del(&s->list); 170bb129994SShailabh Nagar kfree(s); 171bb129994SShailabh Nagar } 172bb129994SShailabh Nagar } 173bb129994SShailabh Nagar up_write(&listeners->sem); 174f9fd8914SShailabh Nagar return rc; 175f9fd8914SShailabh Nagar } 176f9fd8914SShailabh Nagar 177c757249aSShailabh Nagar static int fill_pid(pid_t pid, struct task_struct *pidtsk, 178c757249aSShailabh Nagar struct taskstats *stats) 179c757249aSShailabh Nagar { 180*7d94ddddSShailabh Nagar int rc = 0; 181c757249aSShailabh Nagar struct task_struct *tsk = pidtsk; 182c757249aSShailabh Nagar 183c757249aSShailabh Nagar if (!pidtsk) { 184c757249aSShailabh Nagar read_lock(&tasklist_lock); 185c757249aSShailabh Nagar tsk = find_task_by_pid(pid); 186c757249aSShailabh Nagar if (!tsk) { 187c757249aSShailabh Nagar read_unlock(&tasklist_lock); 188c757249aSShailabh Nagar return -ESRCH; 189c757249aSShailabh Nagar } 190c757249aSShailabh Nagar get_task_struct(tsk); 191c757249aSShailabh Nagar read_unlock(&tasklist_lock); 192c757249aSShailabh Nagar } else 193c757249aSShailabh Nagar get_task_struct(tsk); 194c757249aSShailabh Nagar 195c757249aSShailabh Nagar /* 196c757249aSShailabh Nagar * Each accounting subsystem adds calls to its functions to 197c757249aSShailabh Nagar * fill in relevant parts of struct taskstsats as follows 198c757249aSShailabh Nagar * 199*7d94ddddSShailabh Nagar * per-task-foo(stats, tsk); 200c757249aSShailabh Nagar */ 201c757249aSShailabh Nagar 202*7d94ddddSShailabh Nagar delayacct_add_tsk(stats, tsk); 2036f44993fSShailabh Nagar stats->version = TASKSTATS_VERSION; 2046f44993fSShailabh Nagar 2056f44993fSShailabh Nagar /* Define err: label here if needed */ 206c757249aSShailabh Nagar put_task_struct(tsk); 207c757249aSShailabh Nagar return rc; 208c757249aSShailabh Nagar 209c757249aSShailabh Nagar } 210c757249aSShailabh Nagar 211c757249aSShailabh Nagar static int fill_tgid(pid_t tgid, struct task_struct *tgidtsk, 212c757249aSShailabh Nagar struct taskstats *stats) 213c757249aSShailabh Nagar { 214c757249aSShailabh Nagar struct task_struct *tsk, *first; 215ad4ecbcbSShailabh Nagar unsigned long flags; 216c757249aSShailabh Nagar 217ad4ecbcbSShailabh Nagar /* 218ad4ecbcbSShailabh Nagar * Add additional stats from live tasks except zombie thread group 219ad4ecbcbSShailabh Nagar * leaders who are already counted with the dead tasks 220ad4ecbcbSShailabh Nagar */ 221c757249aSShailabh Nagar first = tgidtsk; 222c757249aSShailabh Nagar if (!first) { 223ad4ecbcbSShailabh Nagar read_lock(&tasklist_lock); 224c757249aSShailabh Nagar first = find_task_by_pid(tgid); 225c757249aSShailabh Nagar if (!first) { 226c757249aSShailabh Nagar read_unlock(&tasklist_lock); 227c757249aSShailabh Nagar return -ESRCH; 228c757249aSShailabh Nagar } 229ad4ecbcbSShailabh Nagar get_task_struct(first); 230ad4ecbcbSShailabh Nagar read_unlock(&tasklist_lock); 231ad4ecbcbSShailabh Nagar } else 232ad4ecbcbSShailabh Nagar get_task_struct(first); 233ad4ecbcbSShailabh Nagar 234ad4ecbcbSShailabh Nagar /* Start with stats from dead tasks */ 235ad4ecbcbSShailabh Nagar spin_lock_irqsave(&first->signal->stats_lock, flags); 236ad4ecbcbSShailabh Nagar if (first->signal->stats) 237ad4ecbcbSShailabh Nagar memcpy(stats, first->signal->stats, sizeof(*stats)); 238ad4ecbcbSShailabh Nagar spin_unlock_irqrestore(&first->signal->stats_lock, flags); 239ad4ecbcbSShailabh Nagar 240c757249aSShailabh Nagar tsk = first; 241ad4ecbcbSShailabh Nagar read_lock(&tasklist_lock); 242c757249aSShailabh Nagar do { 243ad4ecbcbSShailabh Nagar if (tsk->exit_state == EXIT_ZOMBIE && thread_group_leader(tsk)) 244ad4ecbcbSShailabh Nagar continue; 245c757249aSShailabh Nagar /* 246ad4ecbcbSShailabh Nagar * Accounting subsystem can call its functions here to 247c757249aSShailabh Nagar * fill in relevant parts of struct taskstsats as follows 248c757249aSShailabh Nagar * 249ad4ecbcbSShailabh Nagar * per-task-foo(stats, tsk); 250c757249aSShailabh Nagar */ 251ad4ecbcbSShailabh Nagar delayacct_add_tsk(stats, tsk); 2526f44993fSShailabh Nagar 253c757249aSShailabh Nagar } while_each_thread(first, tsk); 254c757249aSShailabh Nagar read_unlock(&tasklist_lock); 2556f44993fSShailabh Nagar stats->version = TASKSTATS_VERSION; 2566f44993fSShailabh Nagar 257c757249aSShailabh Nagar /* 258ad4ecbcbSShailabh Nagar * Accounting subsytems can also add calls here to modify 259ad4ecbcbSShailabh Nagar * fields of taskstats. 260c757249aSShailabh Nagar */ 261c757249aSShailabh Nagar 262ad4ecbcbSShailabh Nagar return 0; 263c757249aSShailabh Nagar } 264c757249aSShailabh Nagar 265ad4ecbcbSShailabh Nagar 266ad4ecbcbSShailabh Nagar static void fill_tgid_exit(struct task_struct *tsk) 267ad4ecbcbSShailabh Nagar { 268ad4ecbcbSShailabh Nagar unsigned long flags; 269ad4ecbcbSShailabh Nagar 270ad4ecbcbSShailabh Nagar spin_lock_irqsave(&tsk->signal->stats_lock, flags); 271ad4ecbcbSShailabh Nagar if (!tsk->signal->stats) 272ad4ecbcbSShailabh Nagar goto ret; 273ad4ecbcbSShailabh Nagar 274ad4ecbcbSShailabh Nagar /* 275ad4ecbcbSShailabh Nagar * Each accounting subsystem calls its functions here to 276ad4ecbcbSShailabh Nagar * accumalate its per-task stats for tsk, into the per-tgid structure 277ad4ecbcbSShailabh Nagar * 278ad4ecbcbSShailabh Nagar * per-task-foo(tsk->signal->stats, tsk); 279ad4ecbcbSShailabh Nagar */ 280ad4ecbcbSShailabh Nagar delayacct_add_tsk(tsk->signal->stats, tsk); 281ad4ecbcbSShailabh Nagar ret: 282ad4ecbcbSShailabh Nagar spin_unlock_irqrestore(&tsk->signal->stats_lock, flags); 283ad4ecbcbSShailabh Nagar return; 284ad4ecbcbSShailabh Nagar } 285ad4ecbcbSShailabh Nagar 286f9fd8914SShailabh Nagar static int add_del_listener(pid_t pid, cpumask_t *maskp, int isadd) 287f9fd8914SShailabh Nagar { 288f9fd8914SShailabh Nagar struct listener_list *listeners; 289f9fd8914SShailabh Nagar struct listener *s, *tmp; 290f9fd8914SShailabh Nagar unsigned int cpu; 291f9fd8914SShailabh Nagar cpumask_t mask = *maskp; 292ad4ecbcbSShailabh Nagar 293f9fd8914SShailabh Nagar if (!cpus_subset(mask, cpu_possible_map)) 294f9fd8914SShailabh Nagar return -EINVAL; 295f9fd8914SShailabh Nagar 296f9fd8914SShailabh Nagar if (isadd == REGISTER) { 297f9fd8914SShailabh Nagar for_each_cpu_mask(cpu, mask) { 298f9fd8914SShailabh Nagar s = kmalloc_node(sizeof(struct listener), GFP_KERNEL, 299f9fd8914SShailabh Nagar cpu_to_node(cpu)); 300f9fd8914SShailabh Nagar if (!s) 301f9fd8914SShailabh Nagar goto cleanup; 302f9fd8914SShailabh Nagar s->pid = pid; 303f9fd8914SShailabh Nagar INIT_LIST_HEAD(&s->list); 304bb129994SShailabh Nagar s->valid = 1; 305f9fd8914SShailabh Nagar 306f9fd8914SShailabh Nagar listeners = &per_cpu(listener_array, cpu); 307f9fd8914SShailabh Nagar down_write(&listeners->sem); 308f9fd8914SShailabh Nagar list_add(&s->list, &listeners->list); 309f9fd8914SShailabh Nagar up_write(&listeners->sem); 310f9fd8914SShailabh Nagar } 311f9fd8914SShailabh Nagar return 0; 312f9fd8914SShailabh Nagar } 313f9fd8914SShailabh Nagar 314f9fd8914SShailabh Nagar /* Deregister or cleanup */ 315f9fd8914SShailabh Nagar cleanup: 316f9fd8914SShailabh Nagar for_each_cpu_mask(cpu, mask) { 317f9fd8914SShailabh Nagar listeners = &per_cpu(listener_array, cpu); 318f9fd8914SShailabh Nagar down_write(&listeners->sem); 319f9fd8914SShailabh Nagar list_for_each_entry_safe(s, tmp, &listeners->list, list) { 320f9fd8914SShailabh Nagar if (s->pid == pid) { 321f9fd8914SShailabh Nagar list_del(&s->list); 322f9fd8914SShailabh Nagar kfree(s); 323f9fd8914SShailabh Nagar break; 324f9fd8914SShailabh Nagar } 325f9fd8914SShailabh Nagar } 326f9fd8914SShailabh Nagar up_write(&listeners->sem); 327f9fd8914SShailabh Nagar } 328f9fd8914SShailabh Nagar return 0; 329f9fd8914SShailabh Nagar } 330f9fd8914SShailabh Nagar 331f9fd8914SShailabh Nagar static int parse(struct nlattr *na, cpumask_t *mask) 332f9fd8914SShailabh Nagar { 333f9fd8914SShailabh Nagar char *data; 334f9fd8914SShailabh Nagar int len; 335f9fd8914SShailabh Nagar int ret; 336f9fd8914SShailabh Nagar 337f9fd8914SShailabh Nagar if (na == NULL) 338f9fd8914SShailabh Nagar return 1; 339f9fd8914SShailabh Nagar len = nla_len(na); 340f9fd8914SShailabh Nagar if (len > TASKSTATS_CPUMASK_MAXLEN) 341f9fd8914SShailabh Nagar return -E2BIG; 342f9fd8914SShailabh Nagar if (len < 1) 343f9fd8914SShailabh Nagar return -EINVAL; 344f9fd8914SShailabh Nagar data = kmalloc(len, GFP_KERNEL); 345f9fd8914SShailabh Nagar if (!data) 346f9fd8914SShailabh Nagar return -ENOMEM; 347f9fd8914SShailabh Nagar nla_strlcpy(data, na, len); 348f9fd8914SShailabh Nagar ret = cpulist_parse(data, *mask); 349f9fd8914SShailabh Nagar kfree(data); 350f9fd8914SShailabh Nagar return ret; 351f9fd8914SShailabh Nagar } 352f9fd8914SShailabh Nagar 353f9fd8914SShailabh Nagar static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info) 354c757249aSShailabh Nagar { 355c757249aSShailabh Nagar int rc = 0; 356c757249aSShailabh Nagar struct sk_buff *rep_skb; 357c757249aSShailabh Nagar struct taskstats stats; 358c757249aSShailabh Nagar void *reply; 359c757249aSShailabh Nagar size_t size; 360c757249aSShailabh Nagar struct nlattr *na; 361f9fd8914SShailabh Nagar cpumask_t mask; 362f9fd8914SShailabh Nagar 363f9fd8914SShailabh Nagar rc = parse(info->attrs[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK], &mask); 364f9fd8914SShailabh Nagar if (rc < 0) 365f9fd8914SShailabh Nagar return rc; 366f9fd8914SShailabh Nagar if (rc == 0) 367f9fd8914SShailabh Nagar return add_del_listener(info->snd_pid, &mask, REGISTER); 368f9fd8914SShailabh Nagar 369f9fd8914SShailabh Nagar rc = parse(info->attrs[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK], &mask); 370f9fd8914SShailabh Nagar if (rc < 0) 371f9fd8914SShailabh Nagar return rc; 372f9fd8914SShailabh Nagar if (rc == 0) 373f9fd8914SShailabh Nagar return add_del_listener(info->snd_pid, &mask, DEREGISTER); 374c757249aSShailabh Nagar 375c757249aSShailabh Nagar /* 376c757249aSShailabh Nagar * Size includes space for nested attributes 377c757249aSShailabh Nagar */ 378c757249aSShailabh Nagar size = nla_total_size(sizeof(u32)) + 379c757249aSShailabh Nagar nla_total_size(sizeof(struct taskstats)) + nla_total_size(0); 380c757249aSShailabh Nagar 381c757249aSShailabh Nagar memset(&stats, 0, sizeof(stats)); 382c757249aSShailabh Nagar rc = prepare_reply(info, TASKSTATS_CMD_NEW, &rep_skb, &reply, size); 383c757249aSShailabh Nagar if (rc < 0) 384c757249aSShailabh Nagar return rc; 385c757249aSShailabh Nagar 386c757249aSShailabh Nagar if (info->attrs[TASKSTATS_CMD_ATTR_PID]) { 387c757249aSShailabh Nagar u32 pid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_PID]); 388c757249aSShailabh Nagar rc = fill_pid(pid, NULL, &stats); 389c757249aSShailabh Nagar if (rc < 0) 390c757249aSShailabh Nagar goto err; 391c757249aSShailabh Nagar 392c757249aSShailabh Nagar na = nla_nest_start(rep_skb, TASKSTATS_TYPE_AGGR_PID); 393c757249aSShailabh Nagar NLA_PUT_U32(rep_skb, TASKSTATS_TYPE_PID, pid); 394c757249aSShailabh Nagar NLA_PUT_TYPE(rep_skb, struct taskstats, TASKSTATS_TYPE_STATS, 395c757249aSShailabh Nagar stats); 396c757249aSShailabh Nagar } else if (info->attrs[TASKSTATS_CMD_ATTR_TGID]) { 397c757249aSShailabh Nagar u32 tgid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_TGID]); 398c757249aSShailabh Nagar rc = fill_tgid(tgid, NULL, &stats); 399c757249aSShailabh Nagar if (rc < 0) 400c757249aSShailabh Nagar goto err; 401c757249aSShailabh Nagar 402c757249aSShailabh Nagar na = nla_nest_start(rep_skb, TASKSTATS_TYPE_AGGR_TGID); 403c757249aSShailabh Nagar NLA_PUT_U32(rep_skb, TASKSTATS_TYPE_TGID, tgid); 404c757249aSShailabh Nagar NLA_PUT_TYPE(rep_skb, struct taskstats, TASKSTATS_TYPE_STATS, 405c757249aSShailabh Nagar stats); 406c757249aSShailabh Nagar } else { 407c757249aSShailabh Nagar rc = -EINVAL; 408c757249aSShailabh Nagar goto err; 409c757249aSShailabh Nagar } 410c757249aSShailabh Nagar 411c757249aSShailabh Nagar nla_nest_end(rep_skb, na); 412c757249aSShailabh Nagar 413f9fd8914SShailabh Nagar return send_reply(rep_skb, info->snd_pid); 414c757249aSShailabh Nagar 415c757249aSShailabh Nagar nla_put_failure: 416c757249aSShailabh Nagar return genlmsg_cancel(rep_skb, reply); 417c757249aSShailabh Nagar err: 418c757249aSShailabh Nagar nlmsg_free(rep_skb); 419c757249aSShailabh Nagar return rc; 420c757249aSShailabh Nagar } 421c757249aSShailabh Nagar 422f9fd8914SShailabh Nagar void taskstats_exit_alloc(struct taskstats **ptidstats, unsigned int *mycpu) 423f9fd8914SShailabh Nagar { 424f9fd8914SShailabh Nagar struct listener_list *listeners; 425f9fd8914SShailabh Nagar struct taskstats *tmp; 426f9fd8914SShailabh Nagar /* 427f9fd8914SShailabh Nagar * This is the cpu on which the task is exiting currently and will 428f9fd8914SShailabh Nagar * be the one for which the exit event is sent, even if the cpu 429f9fd8914SShailabh Nagar * on which this function is running changes later. 430f9fd8914SShailabh Nagar */ 431f9fd8914SShailabh Nagar *mycpu = raw_smp_processor_id(); 432f9fd8914SShailabh Nagar 433f9fd8914SShailabh Nagar *ptidstats = NULL; 434f9fd8914SShailabh Nagar tmp = kmem_cache_zalloc(taskstats_cache, SLAB_KERNEL); 435f9fd8914SShailabh Nagar if (!tmp) 436f9fd8914SShailabh Nagar return; 437f9fd8914SShailabh Nagar 438f9fd8914SShailabh Nagar listeners = &per_cpu(listener_array, *mycpu); 439f9fd8914SShailabh Nagar down_read(&listeners->sem); 440f9fd8914SShailabh Nagar if (!list_empty(&listeners->list)) { 441f9fd8914SShailabh Nagar *ptidstats = tmp; 442f9fd8914SShailabh Nagar tmp = NULL; 443f9fd8914SShailabh Nagar } 444f9fd8914SShailabh Nagar up_read(&listeners->sem); 445f9fd8914SShailabh Nagar kfree(tmp); 446f9fd8914SShailabh Nagar } 447f9fd8914SShailabh Nagar 448c757249aSShailabh Nagar /* Send pid data out on exit */ 449c757249aSShailabh Nagar void taskstats_exit_send(struct task_struct *tsk, struct taskstats *tidstats, 450f9fd8914SShailabh Nagar int group_dead, unsigned int mycpu) 451c757249aSShailabh Nagar { 452c757249aSShailabh Nagar int rc; 453c757249aSShailabh Nagar struct sk_buff *rep_skb; 454c757249aSShailabh Nagar void *reply; 455c757249aSShailabh Nagar size_t size; 456c757249aSShailabh Nagar int is_thread_group; 457c757249aSShailabh Nagar struct nlattr *na; 458ad4ecbcbSShailabh Nagar unsigned long flags; 459c757249aSShailabh Nagar 460c757249aSShailabh Nagar if (!family_registered || !tidstats) 461c757249aSShailabh Nagar return; 462c757249aSShailabh Nagar 463ad4ecbcbSShailabh Nagar spin_lock_irqsave(&tsk->signal->stats_lock, flags); 464ad4ecbcbSShailabh Nagar is_thread_group = tsk->signal->stats ? 1 : 0; 465ad4ecbcbSShailabh Nagar spin_unlock_irqrestore(&tsk->signal->stats_lock, flags); 466c757249aSShailabh Nagar 467ad4ecbcbSShailabh Nagar rc = 0; 468c757249aSShailabh Nagar /* 469c757249aSShailabh Nagar * Size includes space for nested attributes 470c757249aSShailabh Nagar */ 471c757249aSShailabh Nagar size = nla_total_size(sizeof(u32)) + 472c757249aSShailabh Nagar nla_total_size(sizeof(struct taskstats)) + nla_total_size(0); 473c757249aSShailabh Nagar 474c757249aSShailabh Nagar if (is_thread_group) 475c757249aSShailabh Nagar size = 2 * size; /* PID + STATS + TGID + STATS */ 476c757249aSShailabh Nagar 477c757249aSShailabh Nagar rc = prepare_reply(NULL, TASKSTATS_CMD_NEW, &rep_skb, &reply, size); 478c757249aSShailabh Nagar if (rc < 0) 479c757249aSShailabh Nagar goto ret; 480c757249aSShailabh Nagar 481c757249aSShailabh Nagar rc = fill_pid(tsk->pid, tsk, tidstats); 482c757249aSShailabh Nagar if (rc < 0) 483c757249aSShailabh Nagar goto err_skb; 484c757249aSShailabh Nagar 485c757249aSShailabh Nagar na = nla_nest_start(rep_skb, TASKSTATS_TYPE_AGGR_PID); 486c757249aSShailabh Nagar NLA_PUT_U32(rep_skb, TASKSTATS_TYPE_PID, (u32)tsk->pid); 487c757249aSShailabh Nagar NLA_PUT_TYPE(rep_skb, struct taskstats, TASKSTATS_TYPE_STATS, 488c757249aSShailabh Nagar *tidstats); 489c757249aSShailabh Nagar nla_nest_end(rep_skb, na); 490c757249aSShailabh Nagar 491ad4ecbcbSShailabh Nagar if (!is_thread_group) 492ad4ecbcbSShailabh Nagar goto send; 493c757249aSShailabh Nagar 494c757249aSShailabh Nagar /* 495ad4ecbcbSShailabh Nagar * tsk has/had a thread group so fill the tsk->signal->stats structure 496ad4ecbcbSShailabh Nagar * Doesn't matter if tsk is the leader or the last group member leaving 497c757249aSShailabh Nagar */ 498ad4ecbcbSShailabh Nagar 499ad4ecbcbSShailabh Nagar fill_tgid_exit(tsk); 500ad4ecbcbSShailabh Nagar if (!group_dead) 501ad4ecbcbSShailabh Nagar goto send; 502c757249aSShailabh Nagar 503c757249aSShailabh Nagar na = nla_nest_start(rep_skb, TASKSTATS_TYPE_AGGR_TGID); 504c757249aSShailabh Nagar NLA_PUT_U32(rep_skb, TASKSTATS_TYPE_TGID, (u32)tsk->tgid); 505ad4ecbcbSShailabh Nagar /* No locking needed for tsk->signal->stats since group is dead */ 506c757249aSShailabh Nagar NLA_PUT_TYPE(rep_skb, struct taskstats, TASKSTATS_TYPE_STATS, 507ad4ecbcbSShailabh Nagar *tsk->signal->stats); 508c757249aSShailabh Nagar nla_nest_end(rep_skb, na); 509c757249aSShailabh Nagar 510ad4ecbcbSShailabh Nagar send: 511f9fd8914SShailabh Nagar send_cpu_listeners(rep_skb, mycpu); 512ad4ecbcbSShailabh Nagar return; 513c757249aSShailabh Nagar 514c757249aSShailabh Nagar nla_put_failure: 515c757249aSShailabh Nagar genlmsg_cancel(rep_skb, reply); 516c757249aSShailabh Nagar goto ret; 517c757249aSShailabh Nagar err_skb: 518c757249aSShailabh Nagar nlmsg_free(rep_skb); 519c757249aSShailabh Nagar ret: 520c757249aSShailabh Nagar return; 521c757249aSShailabh Nagar } 522c757249aSShailabh Nagar 523c757249aSShailabh Nagar static struct genl_ops taskstats_ops = { 524c757249aSShailabh Nagar .cmd = TASKSTATS_CMD_GET, 525f9fd8914SShailabh Nagar .doit = taskstats_user_cmd, 526c757249aSShailabh Nagar .policy = taskstats_cmd_get_policy, 527c757249aSShailabh Nagar }; 528c757249aSShailabh Nagar 529c757249aSShailabh Nagar /* Needed early in initialization */ 530c757249aSShailabh Nagar void __init taskstats_init_early(void) 531c757249aSShailabh Nagar { 532f9fd8914SShailabh Nagar unsigned int i; 533f9fd8914SShailabh Nagar 534c757249aSShailabh Nagar taskstats_cache = kmem_cache_create("taskstats_cache", 535c757249aSShailabh Nagar sizeof(struct taskstats), 536c757249aSShailabh Nagar 0, SLAB_PANIC, NULL, NULL); 537f9fd8914SShailabh Nagar for_each_possible_cpu(i) { 538f9fd8914SShailabh Nagar INIT_LIST_HEAD(&(per_cpu(listener_array, i).list)); 539f9fd8914SShailabh Nagar init_rwsem(&(per_cpu(listener_array, i).sem)); 540f9fd8914SShailabh Nagar } 541c757249aSShailabh Nagar } 542c757249aSShailabh Nagar 543c757249aSShailabh Nagar static int __init taskstats_init(void) 544c757249aSShailabh Nagar { 545c757249aSShailabh Nagar int rc; 546c757249aSShailabh Nagar 547c757249aSShailabh Nagar rc = genl_register_family(&family); 548c757249aSShailabh Nagar if (rc) 549c757249aSShailabh Nagar return rc; 550c757249aSShailabh Nagar 551c757249aSShailabh Nagar rc = genl_register_ops(&family, &taskstats_ops); 552c757249aSShailabh Nagar if (rc < 0) 553c757249aSShailabh Nagar goto err; 554c757249aSShailabh Nagar 555c757249aSShailabh Nagar family_registered = 1; 556c757249aSShailabh Nagar return 0; 557c757249aSShailabh Nagar err: 558c757249aSShailabh Nagar genl_unregister_family(&family); 559c757249aSShailabh Nagar return rc; 560c757249aSShailabh Nagar } 561c757249aSShailabh Nagar 562c757249aSShailabh Nagar /* 563c757249aSShailabh Nagar * late initcall ensures initialization of statistics collection 564c757249aSShailabh Nagar * mechanisms precedes initialization of the taskstats interface 565c757249aSShailabh Nagar */ 566c757249aSShailabh Nagar late_initcall(taskstats_init); 567