LCOV - code coverage report
Current view: top level - kernel - taskstats.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 58 349 16.6 %
Date: 2021-04-22 12:43:58 Functions: 5 20 25.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /*
       3             :  * taskstats.c - Export per-task statistics to userland
       4             :  *
       5             :  * Copyright (C) Shailabh Nagar, IBM Corp. 2006
       6             :  *           (C) Balbir Singh,   IBM Corp. 2006
       7             :  */
       8             : 
       9             : #include <linux/kernel.h>
      10             : #include <linux/taskstats_kern.h>
      11             : #include <linux/tsacct_kern.h>
      12             : #include <linux/delayacct.h>
      13             : #include <linux/cpumask.h>
      14             : #include <linux/percpu.h>
      15             : #include <linux/slab.h>
      16             : #include <linux/cgroupstats.h>
      17             : #include <linux/cgroup.h>
      18             : #include <linux/fs.h>
      19             : #include <linux/file.h>
      20             : #include <linux/pid_namespace.h>
      21             : #include <net/genetlink.h>
      22             : #include <linux/atomic.h>
      23             : #include <linux/sched/cputime.h>
      24             : 
      25             : /*
      26             :  * Maximum length of a cpumask that can be specified in
      27             :  * the TASKSTATS_CMD_ATTR_REGISTER/DEREGISTER_CPUMASK attribute
      28             :  */
      29             : #define TASKSTATS_CPUMASK_MAXLEN        (100+6*NR_CPUS)
      30             : 
      31             : static DEFINE_PER_CPU(__u32, taskstats_seqnum);
      32             : static int family_registered;
      33             : struct kmem_cache *taskstats_cache;
      34             : 
      35             : static struct genl_family family;
      36             : 
      37             : static const struct nla_policy taskstats_cmd_get_policy[] = {
      38             :         [TASKSTATS_CMD_ATTR_PID]  = { .type = NLA_U32 },
      39             :         [TASKSTATS_CMD_ATTR_TGID] = { .type = NLA_U32 },
      40             :         [TASKSTATS_CMD_ATTR_REGISTER_CPUMASK] = { .type = NLA_STRING },
      41             :         [TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK] = { .type = NLA_STRING },};
      42             : 
      43             : static const struct nla_policy cgroupstats_cmd_get_policy[] = {
      44             :         [CGROUPSTATS_CMD_ATTR_FD] = { .type = NLA_U32 },
      45             : };
      46             : 
      47             : struct listener {
      48             :         struct list_head list;
      49             :         pid_t pid;
      50             :         char valid;
      51             : };
      52             : 
      53             : struct listener_list {
      54             :         struct rw_semaphore sem;
      55             :         struct list_head list;
      56             : };
      57             : static DEFINE_PER_CPU(struct listener_list, listener_array);
      58             : 
      59             : enum actions {
      60             :         REGISTER,
      61             :         DEREGISTER,
      62             :         CPU_DONT_CARE
      63             : };
      64             : 
      65           0 : static int prepare_reply(struct genl_info *info, u8 cmd, struct sk_buff **skbp,
      66             :                                 size_t size)
      67             : {
      68           0 :         struct sk_buff *skb;
      69           0 :         void *reply;
      70             : 
      71             :         /*
      72             :          * If new attributes are added, please revisit this allocation
      73             :          */
      74           0 :         skb = genlmsg_new(size, GFP_KERNEL);
      75           0 :         if (!skb)
      76             :                 return -ENOMEM;
      77             : 
      78           0 :         if (!info) {
      79           0 :                 int seq = this_cpu_inc_return(taskstats_seqnum) - 1;
      80             : 
      81           0 :                 reply = genlmsg_put(skb, 0, seq, &family, 0, cmd);
      82             :         } else
      83           0 :                 reply = genlmsg_put_reply(skb, info, &family, 0, cmd);
      84           0 :         if (reply == NULL) {
      85           0 :                 nlmsg_free(skb);
      86           0 :                 return -EINVAL;
      87             :         }
      88             : 
      89           0 :         *skbp = skb;
      90           0 :         return 0;
      91             : }
      92             : 
      93             : /*
      94             :  * Send taskstats data in @skb to listener with nl_pid @pid
      95             :  */
      96           0 : static int send_reply(struct sk_buff *skb, struct genl_info *info)
      97             : {
      98           0 :         struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
      99           0 :         void *reply = genlmsg_data(genlhdr);
     100             : 
     101           0 :         genlmsg_end(skb, reply);
     102             : 
     103           0 :         return genlmsg_reply(skb, info);
     104             : }
     105             : 
     106             : /*
     107             :  * Send taskstats data in @skb to listeners registered for @cpu's exit data
     108             :  */
     109           0 : static void send_cpu_listeners(struct sk_buff *skb,
     110             :                                         struct listener_list *listeners)
     111             : {
     112           0 :         struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
     113           0 :         struct listener *s, *tmp;
     114           0 :         struct sk_buff *skb_next, *skb_cur = skb;
     115           0 :         void *reply = genlmsg_data(genlhdr);
     116           0 :         int rc, delcount = 0;
     117             : 
     118           0 :         genlmsg_end(skb, reply);
     119             : 
     120           0 :         rc = 0;
     121           0 :         down_read(&listeners->sem);
     122           0 :         list_for_each_entry(s, &listeners->list, list) {
     123           0 :                 skb_next = NULL;
     124           0 :                 if (!list_is_last(&s->list, &listeners->list)) {
     125           0 :                         skb_next = skb_clone(skb_cur, GFP_KERNEL);
     126           0 :                         if (!skb_next)
     127             :                                 break;
     128             :                 }
     129           0 :                 rc = genlmsg_unicast(&init_net, skb_cur, s->pid);
     130           0 :                 if (rc == -ECONNREFUSED) {
     131           0 :                         s->valid = 0;
     132           0 :                         delcount++;
     133             :                 }
     134           0 :                 skb_cur = skb_next;
     135             :         }
     136           0 :         up_read(&listeners->sem);
     137             : 
     138           0 :         if (skb_cur)
     139           0 :                 nlmsg_free(skb_cur);
     140             : 
     141           0 :         if (!delcount)
     142             :                 return;
     143             : 
     144             :         /* Delete invalidated entries */
     145           0 :         down_write(&listeners->sem);
     146           0 :         list_for_each_entry_safe(s, tmp, &listeners->list, list) {
     147           0 :                 if (!s->valid) {
     148           0 :                         list_del(&s->list);
     149           0 :                         kfree(s);
     150             :                 }
     151             :         }
     152           0 :         up_write(&listeners->sem);
     153             : }
     154             : 
     155           0 : static void fill_stats(struct user_namespace *user_ns,
     156             :                        struct pid_namespace *pid_ns,
     157             :                        struct task_struct *tsk, struct taskstats *stats)
     158             : {
     159           0 :         memset(stats, 0, sizeof(*stats));
     160             :         /*
     161             :          * Each accounting subsystem adds calls to its functions to
     162             :          * fill in relevant parts of struct taskstsats as follows
     163             :          *
     164             :          *      per-task-foo(stats, tsk);
     165             :          */
     166             : 
     167           0 :         delayacct_add_tsk(stats, tsk);
     168             : 
     169             :         /* fill in basic acct fields */
     170           0 :         stats->version = TASKSTATS_VERSION;
     171           0 :         stats->nvcsw = tsk->nvcsw;
     172           0 :         stats->nivcsw = tsk->nivcsw;
     173           0 :         bacct_add_tsk(user_ns, pid_ns, stats, tsk);
     174             : 
     175             :         /* fill in extended acct fields */
     176           0 :         xacct_add_tsk(stats, tsk);
     177           0 : }
     178             : 
     179           0 : static int fill_stats_for_pid(pid_t pid, struct taskstats *stats)
     180             : {
     181           0 :         struct task_struct *tsk;
     182             : 
     183           0 :         tsk = find_get_task_by_vpid(pid);
     184           0 :         if (!tsk)
     185             :                 return -ESRCH;
     186           0 :         fill_stats(current_user_ns(), task_active_pid_ns(current), tsk, stats);
     187           0 :         put_task_struct(tsk);
     188           0 :         return 0;
     189             : }
     190             : 
     191           0 : static int fill_stats_for_tgid(pid_t tgid, struct taskstats *stats)
     192             : {
     193           0 :         struct task_struct *tsk, *first;
     194           0 :         unsigned long flags;
     195           0 :         int rc = -ESRCH;
     196           0 :         u64 delta, utime, stime;
     197           0 :         u64 start_time;
     198             : 
     199             :         /*
     200             :          * Add additional stats from live tasks except zombie thread group
     201             :          * leaders who are already counted with the dead tasks
     202             :          */
     203           0 :         rcu_read_lock();
     204           0 :         first = find_task_by_vpid(tgid);
     205             : 
     206           0 :         if (!first || !lock_task_sighand(first, &flags))
     207           0 :                 goto out;
     208             : 
     209           0 :         if (first->signal->stats)
     210           0 :                 memcpy(stats, first->signal->stats, sizeof(*stats));
     211             :         else
     212           0 :                 memset(stats, 0, sizeof(*stats));
     213             : 
     214           0 :         tsk = first;
     215           0 :         start_time = ktime_get_ns();
     216           0 :         do {
     217           0 :                 if (tsk->exit_state)
     218           0 :                         continue;
     219             :                 /*
     220             :                  * Accounting subsystem can call its functions here to
     221             :                  * fill in relevant parts of struct taskstsats as follows
     222             :                  *
     223             :                  *      per-task-foo(stats, tsk);
     224             :                  */
     225           0 :                 delayacct_add_tsk(stats, tsk);
     226             : 
     227             :                 /* calculate task elapsed time in nsec */
     228           0 :                 delta = start_time - tsk->start_time;
     229             :                 /* Convert to micro seconds */
     230           0 :                 do_div(delta, NSEC_PER_USEC);
     231           0 :                 stats->ac_etime += delta;
     232             : 
     233           0 :                 task_cputime(tsk, &utime, &stime);
     234           0 :                 stats->ac_utime += div_u64(utime, NSEC_PER_USEC);
     235           0 :                 stats->ac_stime += div_u64(stime, NSEC_PER_USEC);
     236             : 
     237           0 :                 stats->nvcsw += tsk->nvcsw;
     238           0 :                 stats->nivcsw += tsk->nivcsw;
     239           0 :         } while_each_thread(first, tsk);
     240             : 
     241           0 :         unlock_task_sighand(first, &flags);
     242           0 :         rc = 0;
     243           0 : out:
     244           0 :         rcu_read_unlock();
     245             : 
     246           0 :         stats->version = TASKSTATS_VERSION;
     247             :         /*
     248             :          * Accounting subsystems can also add calls here to modify
     249             :          * fields of taskstats.
     250             :          */
     251           0 :         return rc;
     252             : }
     253             : 
     254           2 : static void fill_tgid_exit(struct task_struct *tsk)
     255             : {
     256           2 :         unsigned long flags;
     257             : 
     258           2 :         spin_lock_irqsave(&tsk->sighand->siglock, flags);
     259           2 :         if (!tsk->signal->stats)
     260           0 :                 goto ret;
     261             : 
     262             :         /*
     263             :          * Each accounting subsystem calls its functions here to
     264             :          * accumalate its per-task stats for tsk, into the per-tgid structure
     265             :          *
     266             :          *      per-task-foo(tsk->signal->stats, tsk);
     267             :          */
     268           2 :         delayacct_add_tsk(tsk->signal->stats, tsk);
     269           2 : ret:
     270           2 :         spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
     271           2 :         return;
     272             : }
     273             : 
     274           0 : static int add_del_listener(pid_t pid, const struct cpumask *mask, int isadd)
     275             : {
     276           0 :         struct listener_list *listeners;
     277           0 :         struct listener *s, *tmp, *s2;
     278           0 :         unsigned int cpu;
     279           0 :         int ret = 0;
     280             : 
     281           0 :         if (!cpumask_subset(mask, cpu_possible_mask))
     282             :                 return -EINVAL;
     283             : 
     284           0 :         if (current_user_ns() != &init_user_ns)
     285             :                 return -EINVAL;
     286             : 
     287           0 :         if (task_active_pid_ns(current) != &init_pid_ns)
     288             :                 return -EINVAL;
     289             : 
     290           0 :         if (isadd == REGISTER) {
     291           0 :                 for_each_cpu(cpu, mask) {
     292           0 :                         s = kmalloc_node(sizeof(struct listener),
     293             :                                         GFP_KERNEL, cpu_to_node(cpu));
     294           0 :                         if (!s) {
     295           0 :                                 ret = -ENOMEM;
     296           0 :                                 goto cleanup;
     297             :                         }
     298           0 :                         s->pid = pid;
     299           0 :                         s->valid = 1;
     300             : 
     301           0 :                         listeners = &per_cpu(listener_array, cpu);
     302           0 :                         down_write(&listeners->sem);
     303           0 :                         list_for_each_entry(s2, &listeners->list, list) {
     304           0 :                                 if (s2->pid == pid && s2->valid)
     305           0 :                                         goto exists;
     306             :                         }
     307           0 :                         list_add(&s->list, &listeners->list);
     308           0 :                         s = NULL;
     309           0 : exists:
     310           0 :                         up_write(&listeners->sem);
     311           0 :                         kfree(s); /* nop if NULL */
     312             :                 }
     313             :                 return 0;
     314             :         }
     315             : 
     316             :         /* Deregister or cleanup */
     317           0 : cleanup:
     318           0 :         for_each_cpu(cpu, mask) {
     319           0 :                 listeners = &per_cpu(listener_array, cpu);
     320           0 :                 down_write(&listeners->sem);
     321           0 :                 list_for_each_entry_safe(s, tmp, &listeners->list, list) {
     322           0 :                         if (s->pid == pid) {
     323           0 :                                 list_del(&s->list);
     324           0 :                                 kfree(s);
     325           0 :                                 break;
     326             :                         }
     327             :                 }
     328           0 :                 up_write(&listeners->sem);
     329             :         }
     330             :         return ret;
     331             : }
     332             : 
     333           0 : static int parse(struct nlattr *na, struct cpumask *mask)
     334             : {
     335           0 :         char *data;
     336           0 :         int len;
     337           0 :         int ret;
     338             : 
     339           0 :         if (na == NULL)
     340             :                 return 1;
     341           0 :         len = nla_len(na);
     342           0 :         if (len > TASKSTATS_CPUMASK_MAXLEN)
     343             :                 return -E2BIG;
     344           0 :         if (len < 1)
     345             :                 return -EINVAL;
     346           0 :         data = kmalloc(len, GFP_KERNEL);
     347           0 :         if (!data)
     348             :                 return -ENOMEM;
     349           0 :         nla_strscpy(data, na, len);
     350           0 :         ret = cpulist_parse(data, mask);
     351           0 :         kfree(data);
     352           0 :         return ret;
     353             : }
     354             : 
     355           0 : static struct taskstats *mk_reply(struct sk_buff *skb, int type, u32 pid)
     356             : {
     357           0 :         struct nlattr *na, *ret;
     358           0 :         int aggr;
     359             : 
     360           0 :         aggr = (type == TASKSTATS_TYPE_PID)
     361             :                         ? TASKSTATS_TYPE_AGGR_PID
     362           0 :                         : TASKSTATS_TYPE_AGGR_TGID;
     363             : 
     364           0 :         na = nla_nest_start_noflag(skb, aggr);
     365           0 :         if (!na)
     366           0 :                 goto err;
     367             : 
     368           0 :         if (nla_put(skb, type, sizeof(pid), &pid) < 0) {
     369           0 :                 nla_nest_cancel(skb, na);
     370           0 :                 goto err;
     371             :         }
     372           0 :         ret = nla_reserve_64bit(skb, TASKSTATS_TYPE_STATS,
     373             :                                 sizeof(struct taskstats), TASKSTATS_TYPE_NULL);
     374           0 :         if (!ret) {
     375           0 :                 nla_nest_cancel(skb, na);
     376           0 :                 goto err;
     377             :         }
     378           0 :         nla_nest_end(skb, na);
     379             : 
     380           0 :         return nla_data(ret);
     381             : err:
     382             :         return NULL;
     383             : }
     384             : 
     385           0 : static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
     386             : {
     387           0 :         int rc = 0;
     388           0 :         struct sk_buff *rep_skb;
     389           0 :         struct cgroupstats *stats;
     390           0 :         struct nlattr *na;
     391           0 :         size_t size;
     392           0 :         u32 fd;
     393           0 :         struct fd f;
     394             : 
     395           0 :         na = info->attrs[CGROUPSTATS_CMD_ATTR_FD];
     396           0 :         if (!na)
     397             :                 return -EINVAL;
     398             : 
     399           0 :         fd = nla_get_u32(info->attrs[CGROUPSTATS_CMD_ATTR_FD]);
     400           0 :         f = fdget(fd);
     401           0 :         if (!f.file)
     402             :                 return 0;
     403             : 
     404           0 :         size = nla_total_size(sizeof(struct cgroupstats));
     405             : 
     406           0 :         rc = prepare_reply(info, CGROUPSTATS_CMD_NEW, &rep_skb,
     407             :                                 size);
     408           0 :         if (rc < 0)
     409           0 :                 goto err;
     410             : 
     411           0 :         na = nla_reserve(rep_skb, CGROUPSTATS_TYPE_CGROUP_STATS,
     412             :                                 sizeof(struct cgroupstats));
     413           0 :         if (na == NULL) {
     414           0 :                 nlmsg_free(rep_skb);
     415           0 :                 rc = -EMSGSIZE;
     416           0 :                 goto err;
     417             :         }
     418             : 
     419           0 :         stats = nla_data(na);
     420           0 :         memset(stats, 0, sizeof(*stats));
     421             : 
     422           0 :         rc = cgroupstats_build(stats, f.file->f_path.dentry);
     423           0 :         if (rc < 0) {
     424           0 :                 nlmsg_free(rep_skb);
     425           0 :                 goto err;
     426             :         }
     427             : 
     428           0 :         rc = send_reply(rep_skb, info);
     429             : 
     430           0 : err:
     431           0 :         fdput(f);
     432           0 :         return rc;
     433             : }
     434             : 
     435           0 : static int cmd_attr_register_cpumask(struct genl_info *info)
     436             : {
     437           0 :         cpumask_var_t mask;
     438           0 :         int rc;
     439             : 
     440           0 :         if (!alloc_cpumask_var(&mask, GFP_KERNEL))
     441             :                 return -ENOMEM;
     442           0 :         rc = parse(info->attrs[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK], mask);
     443           0 :         if (rc < 0)
     444           0 :                 goto out;
     445           0 :         rc = add_del_listener(info->snd_portid, mask, REGISTER);
     446           0 : out:
     447           0 :         free_cpumask_var(mask);
     448           0 :         return rc;
     449             : }
     450             : 
     451           0 : static int cmd_attr_deregister_cpumask(struct genl_info *info)
     452             : {
     453           0 :         cpumask_var_t mask;
     454           0 :         int rc;
     455             : 
     456           0 :         if (!alloc_cpumask_var(&mask, GFP_KERNEL))
     457             :                 return -ENOMEM;
     458           0 :         rc = parse(info->attrs[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK], mask);
     459           0 :         if (rc < 0)
     460           0 :                 goto out;
     461           0 :         rc = add_del_listener(info->snd_portid, mask, DEREGISTER);
     462           0 : out:
     463           0 :         free_cpumask_var(mask);
     464           0 :         return rc;
     465             : }
     466             : 
     467        1107 : static size_t taskstats_packet_size(void)
     468             : {
     469        1107 :         size_t size;
     470             : 
     471        1107 :         size = nla_total_size(sizeof(u32)) +
     472        1107 :                 nla_total_size_64bit(sizeof(struct taskstats)) +
     473        1107 :                 nla_total_size(0);
     474             : 
     475        1107 :         return size;
     476             : }
     477             : 
     478           0 : static int cmd_attr_pid(struct genl_info *info)
     479             : {
     480           0 :         struct taskstats *stats;
     481           0 :         struct sk_buff *rep_skb;
     482           0 :         size_t size;
     483           0 :         u32 pid;
     484           0 :         int rc;
     485             : 
     486           0 :         size = taskstats_packet_size();
     487             : 
     488           0 :         rc = prepare_reply(info, TASKSTATS_CMD_NEW, &rep_skb, size);
     489           0 :         if (rc < 0)
     490             :                 return rc;
     491             : 
     492           0 :         rc = -EINVAL;
     493           0 :         pid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_PID]);
     494           0 :         stats = mk_reply(rep_skb, TASKSTATS_TYPE_PID, pid);
     495           0 :         if (!stats)
     496           0 :                 goto err;
     497             : 
     498           0 :         rc = fill_stats_for_pid(pid, stats);
     499           0 :         if (rc < 0)
     500           0 :                 goto err;
     501           0 :         return send_reply(rep_skb, info);
     502           0 : err:
     503           0 :         nlmsg_free(rep_skb);
     504           0 :         return rc;
     505             : }
     506             : 
     507           0 : static int cmd_attr_tgid(struct genl_info *info)
     508             : {
     509           0 :         struct taskstats *stats;
     510           0 :         struct sk_buff *rep_skb;
     511           0 :         size_t size;
     512           0 :         u32 tgid;
     513           0 :         int rc;
     514             : 
     515           0 :         size = taskstats_packet_size();
     516             : 
     517           0 :         rc = prepare_reply(info, TASKSTATS_CMD_NEW, &rep_skb, size);
     518           0 :         if (rc < 0)
     519             :                 return rc;
     520             : 
     521           0 :         rc = -EINVAL;
     522           0 :         tgid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_TGID]);
     523           0 :         stats = mk_reply(rep_skb, TASKSTATS_TYPE_TGID, tgid);
     524           0 :         if (!stats)
     525           0 :                 goto err;
     526             : 
     527           0 :         rc = fill_stats_for_tgid(tgid, stats);
     528           0 :         if (rc < 0)
     529           0 :                 goto err;
     530           0 :         return send_reply(rep_skb, info);
     531           0 : err:
     532           0 :         nlmsg_free(rep_skb);
     533           0 :         return rc;
     534             : }
     535             : 
     536           0 : static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
     537             : {
     538           0 :         if (info->attrs[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK])
     539           0 :                 return cmd_attr_register_cpumask(info);
     540           0 :         else if (info->attrs[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK])
     541           0 :                 return cmd_attr_deregister_cpumask(info);
     542           0 :         else if (info->attrs[TASKSTATS_CMD_ATTR_PID])
     543           0 :                 return cmd_attr_pid(info);
     544           0 :         else if (info->attrs[TASKSTATS_CMD_ATTR_TGID])
     545           0 :                 return cmd_attr_tgid(info);
     546             :         else
     547             :                 return -EINVAL;
     548             : }
     549             : 
     550        1107 : static struct taskstats *taskstats_tgid_alloc(struct task_struct *tsk)
     551             : {
     552        1107 :         struct signal_struct *sig = tsk->signal;
     553        1107 :         struct taskstats *stats_new, *stats;
     554             : 
     555             :         /* Pairs with smp_store_release() below. */
     556        1107 :         stats = smp_load_acquire(&sig->stats);
     557        1107 :         if (stats || thread_group_empty(tsk))
     558             :                 return stats;
     559             : 
     560             :         /* No problem if kmem_cache_zalloc() fails */
     561           1 :         stats_new = kmem_cache_zalloc(taskstats_cache, GFP_KERNEL);
     562             : 
     563           1 :         spin_lock_irq(&tsk->sighand->siglock);
     564           1 :         stats = sig->stats;
     565           1 :         if (!stats) {
     566             :                 /*
     567             :                  * Pairs with smp_store_release() above and order the
     568             :                  * kmem_cache_zalloc().
     569             :                  */
     570           1 :                 smp_store_release(&sig->stats, stats_new);
     571           1 :                 stats = stats_new;
     572           1 :                 stats_new = NULL;
     573             :         }
     574           1 :         spin_unlock_irq(&tsk->sighand->siglock);
     575             : 
     576           1 :         if (stats_new)
     577           0 :                 kmem_cache_free(taskstats_cache, stats_new);
     578             : 
     579             :         return stats;
     580             : }
     581             : 
     582             : /* Send pid data out on exit */
     583        1107 : void taskstats_exit(struct task_struct *tsk, int group_dead)
     584             : {
     585        1107 :         int rc;
     586        1107 :         struct listener_list *listeners;
     587        1107 :         struct taskstats *stats;
     588        1107 :         struct sk_buff *rep_skb;
     589        1107 :         size_t size;
     590        1107 :         int is_thread_group;
     591             : 
     592        1107 :         if (!family_registered)
     593        1107 :                 return;
     594             : 
     595             :         /*
     596             :          * Size includes space for nested attributes
     597             :          */
     598        1107 :         size = taskstats_packet_size();
     599             : 
     600        1107 :         is_thread_group = !!taskstats_tgid_alloc(tsk);
     601        1107 :         if (is_thread_group) {
     602             :                 /* PID + STATS + TGID + STATS */
     603           2 :                 size = 2 * size;
     604             :                 /* fill the tsk->signal->stats structure */
     605           2 :                 fill_tgid_exit(tsk);
     606             :         }
     607             : 
     608        1107 :         listeners = raw_cpu_ptr(&listener_array);
     609        1107 :         if (list_empty(&listeners->list))
     610             :                 return;
     611             : 
     612           0 :         rc = prepare_reply(NULL, TASKSTATS_CMD_NEW, &rep_skb, size);
     613           0 :         if (rc < 0)
     614             :                 return;
     615             : 
     616           0 :         stats = mk_reply(rep_skb, TASKSTATS_TYPE_PID,
     617           0 :                          task_pid_nr_ns(tsk, &init_pid_ns));
     618           0 :         if (!stats)
     619           0 :                 goto err;
     620             : 
     621           0 :         fill_stats(&init_user_ns, &init_pid_ns, tsk, stats);
     622             : 
     623             :         /*
     624             :          * Doesn't matter if tsk is the leader or the last group member leaving
     625             :          */
     626           0 :         if (!is_thread_group || !group_dead)
     627           0 :                 goto send;
     628             : 
     629           0 :         stats = mk_reply(rep_skb, TASKSTATS_TYPE_TGID,
     630           0 :                          task_tgid_nr_ns(tsk, &init_pid_ns));
     631           0 :         if (!stats)
     632           0 :                 goto err;
     633             : 
     634           0 :         memcpy(stats, tsk->signal->stats, sizeof(*stats));
     635             : 
     636           0 : send:
     637           0 :         send_cpu_listeners(rep_skb, listeners);
     638           0 :         return;
     639           0 : err:
     640           0 :         nlmsg_free(rep_skb);
     641             : }
     642             : 
     643             : static const struct genl_ops taskstats_ops[] = {
     644             :         {
     645             :                 .cmd            = TASKSTATS_CMD_GET,
     646             :                 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
     647             :                 .doit           = taskstats_user_cmd,
     648             :                 .policy         = taskstats_cmd_get_policy,
     649             :                 .maxattr        = ARRAY_SIZE(taskstats_cmd_get_policy) - 1,
     650             :                 .flags          = GENL_ADMIN_PERM,
     651             :         },
     652             :         {
     653             :                 .cmd            = CGROUPSTATS_CMD_GET,
     654             :                 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
     655             :                 .doit           = cgroupstats_user_cmd,
     656             :                 .policy         = cgroupstats_cmd_get_policy,
     657             :                 .maxattr        = ARRAY_SIZE(cgroupstats_cmd_get_policy) - 1,
     658             :         },
     659             : };
     660             : 
     661             : static struct genl_family family __ro_after_init = {
     662             :         .name           = TASKSTATS_GENL_NAME,
     663             :         .version        = TASKSTATS_GENL_VERSION,
     664             :         .module         = THIS_MODULE,
     665             :         .ops            = taskstats_ops,
     666             :         .n_ops          = ARRAY_SIZE(taskstats_ops),
     667             : };
     668             : 
     669             : /* Needed early in initialization */
     670           1 : void __init taskstats_init_early(void)
     671             : {
     672           1 :         unsigned int i;
     673             : 
     674           1 :         taskstats_cache = KMEM_CACHE(taskstats, SLAB_PANIC);
     675           6 :         for_each_possible_cpu(i) {
     676           4 :                 INIT_LIST_HEAD(&(per_cpu(listener_array, i).list));
     677           5 :                 init_rwsem(&(per_cpu(listener_array, i).sem));
     678             :         }
     679           1 : }
     680             : 
     681           1 : static int __init taskstats_init(void)
     682             : {
     683           1 :         int rc;
     684             : 
     685           1 :         rc = genl_register_family(&family);
     686           1 :         if (rc)
     687             :                 return rc;
     688             : 
     689           1 :         family_registered = 1;
     690           1 :         pr_info("registered taskstats version %d\n", TASKSTATS_GENL_VERSION);
     691           1 :         return 0;
     692             : }
     693             : 
     694             : /*
     695             :  * late initcall ensures initialization of statistics collection
     696             :  * mechanisms precedes initialization of the taskstats interface
     697             :  */
     698             : late_initcall(taskstats_init);

Generated by: LCOV version 1.14