Loading include/uapi/linux/taskstats.h +17 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ #define TASKSTATS_VERSION 9 #define TASKSTATS2_VERSION 1 #define TS_COMM_LEN 32 /* should be >= TASK_COMM_LEN * in linux/sched.h */ Loading Loading @@ -170,6 +171,19 @@ struct taskstats { __u64 thrashing_delay_total; }; struct taskstats2 { __u16 version; __s16 oom_score; __u32 pid; __u64 anon_rss; /* KB */ __u64 file_rss; /* KB */ __u64 swap_rss; /* KB */ __u64 shmem_rss; /* KB */ #ifdef CONFIG_MM_STAT_UNRECLAIMABLE_PAGES __u64 unreclaimable; /* KB */ #endif /* version 1 ends here */ }; /* * Commands sent from userspace Loading @@ -181,6 +195,7 @@ enum { TASKSTATS_CMD_UNSPEC = 0, /* Reserved */ TASKSTATS_CMD_GET, /* user->kernel request/get-response */ TASKSTATS_CMD_NEW, /* kernel->user event */ TASKSTATS2_CMD_GET, /* user->kernel request/get-response */ __TASKSTATS_CMD_MAX, }; Loading @@ -194,6 +209,7 @@ enum { TASKSTATS_TYPE_AGGR_PID, /* contains pid + stats */ TASKSTATS_TYPE_AGGR_TGID, /* contains tgid + stats */ TASKSTATS_TYPE_NULL, /* contains nothing */ TASKSTATS_TYPE_FOREACH, /* contains stats */ __TASKSTATS_TYPE_MAX, }; Loading @@ -205,6 +221,7 @@ enum { TASKSTATS_CMD_ATTR_TGID, TASKSTATS_CMD_ATTR_REGISTER_CPUMASK, TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK, TASKSTATS_CMD_ATTR_FOREACH, __TASKSTATS_CMD_ATTR_MAX, }; Loading kernel/taskstats.c +192 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <net/genetlink.h> #include <linux/atomic.h> #include <linux/sched/cputime.h> #include <linux/oom.h> /* * Maximum length of a cpumask that can be specified in Loading @@ -41,7 +42,8 @@ static const struct nla_policy taskstats_cmd_get_policy[TASKSTATS_CMD_ATTR_MAX+1 [TASKSTATS_CMD_ATTR_PID] = { .type = NLA_U32 }, [TASKSTATS_CMD_ATTR_TGID] = { .type = NLA_U32 }, [TASKSTATS_CMD_ATTR_REGISTER_CPUMASK] = { .type = NLA_STRING }, [TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK] = { .type = NLA_STRING },}; [TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK] = { .type = NLA_STRING }, [TASKSTATS_CMD_ATTR_FOREACH] = { .type = NLA_U32 },}; /* * We have to use TASKSTATS_CMD_ATTR_MAX here, it is the maxattr in the family. Loading @@ -68,6 +70,11 @@ struct listener_list { }; static DEFINE_PER_CPU(struct listener_list, listener_array); struct tgid_iter { unsigned int tgid; struct task_struct *task; }; enum actions { REGISTER, DEREGISTER, Loading Loading @@ -625,6 +632,68 @@ static size_t taskstats_packet_size(void) return size; } static int taskstats2_cmd_attr_pid(struct genl_info *info) { struct taskstats2 *stats; struct sk_buff *rep_skb; struct nlattr *ret; struct task_struct *tsk; struct task_struct *p; size_t size; u32 pid; int rc; size = nla_total_size_64bit(sizeof(struct taskstats2)); rc = prepare_reply(info, TASKSTATS_CMD_NEW, &rep_skb, size); if (rc < 0) return rc; rc = -EINVAL; pid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_PID]); ret = nla_reserve_64bit(rep_skb, TASKSTATS_TYPE_STATS, sizeof(struct taskstats2), TASKSTATS_TYPE_NULL); if (!ret) goto err; stats = nla_data(ret); rcu_read_lock(); tsk = find_task_by_vpid(pid); if (tsk) get_task_struct(tsk); rcu_read_unlock(); if (!tsk) { rc = -ESRCH; goto err; } memset(stats, 0, sizeof(*stats)); stats->version = TASKSTATS2_VERSION; stats->pid = task_pid_nr_ns(tsk, task_active_pid_ns(current)); p = find_lock_task_mm(tsk); if (p) { __acquire(p->alloc_lock); /* Fake it out ;) */ #define K(x) ((x) << (PAGE_SHIFT - 10)) stats->anon_rss = K(get_mm_counter(p->mm, MM_ANONPAGES)); stats->file_rss = K(get_mm_counter(p->mm, MM_FILEPAGES)); stats->shmem_rss = K(get_mm_counter(p->mm, MM_SHMEMPAGES)); stats->swap_rss = K(get_mm_counter(p->mm, MM_SWAPENTS)); #ifdef CONFIG_MM_STAT_UNRECLAIMABLE_PAGES stats->unreclaimable = K(get_mm_counter(p->mm, MM_UNRECLAIMABLE)); #endif #undef K task_unlock(p); } put_task_struct(tsk); return send_reply(rep_skb, info); err: nlmsg_free(rep_skb); return rc; } static int cmd_attr_pid(struct genl_info *info) { struct taskstats *stats; Loading Loading @@ -683,6 +752,120 @@ static int cmd_attr_tgid(struct genl_info *info) return rc; } static struct tgid_iter next_tgid(struct pid_namespace *ns, struct tgid_iter iter) { struct pid *pid; if (iter.task) put_task_struct(iter.task); rcu_read_lock(); retry: iter.task = NULL; pid = find_ge_pid(iter.tgid, ns); if (pid) { iter.tgid = pid_nr_ns(pid, ns); iter.task = pid_task(pid, PIDTYPE_PID); if (!iter.task || !has_group_leader_pid(iter.task)) { iter.tgid += 1; goto retry; } get_task_struct(iter.task); } rcu_read_unlock(); return iter; } static int taskstats2_foreach(struct sk_buff *skb, struct netlink_callback *cb) { struct pid_namespace *ns = task_active_pid_ns(current); struct tgid_iter iter; void *reply; struct nlattr *attr; struct nlattr *nla; struct taskstats2 *stats; struct task_struct *p; short oom_score; short oom_score_min; short oom_score_max; u32 buf; nla = nla_find(nlmsg_attrdata(cb->nlh, GENL_HDRLEN), nlmsg_attrlen(cb->nlh, GENL_HDRLEN), TASKSTATS_TYPE_FOREACH); if (!nla) goto out; buf = nla_get_u32(nla); oom_score_min = (short) (buf & 0xFFFF); oom_score_max = (short) ((buf >> 16) & 0xFFFF); iter.tgid = cb->args[0]; iter.task = NULL; for (iter = next_tgid(ns, iter); iter.task; iter.tgid += 1, iter = next_tgid(ns, iter)) { if (iter.task->flags & PF_KTHREAD) continue; oom_score = iter.task->signal->oom_score_adj; if ((oom_score < oom_score_min) || (oom_score > oom_score_max)) continue; reply = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, &family, 0, TASKSTATS2_CMD_GET); if (reply == NULL) { put_task_struct(iter.task); break; } attr = nla_reserve(skb, TASKSTATS_TYPE_FOREACH, sizeof(struct taskstats2)); if (!attr) { put_task_struct(iter.task); genlmsg_cancel(skb, reply); break; } stats = nla_data(attr); memset(stats, 0, sizeof(struct taskstats2)); stats->version = TASKSTATS2_VERSION; rcu_read_lock(); stats->pid = task_pid_nr_ns(iter.task, task_active_pid_ns(current)); stats->oom_score = iter.task->signal->oom_score_adj; rcu_read_unlock(); p = find_lock_task_mm(iter.task); if (p) { #define K(x) ((x) << (PAGE_SHIFT - 10)) __acquire(p->alloc_lock); /* Fake it out ;) */ stats->anon_rss = K(get_mm_counter(p->mm, MM_ANONPAGES)); stats->file_rss = K(get_mm_counter(p->mm, MM_FILEPAGES)); stats->shmem_rss = K(get_mm_counter(p->mm, MM_SHMEMPAGES)); stats->swap_rss = K(get_mm_counter(p->mm, MM_SWAPENTS)); task_unlock(p); #undef K } genlmsg_end(skb, reply); } cb->args[0] = iter.tgid; out: return skb->len; } static int taskstats2_user_cmd(struct sk_buff *skb, struct genl_info *info) { if (info->attrs[TASKSTATS_CMD_ATTR_PID]) return taskstats2_cmd_attr_pid(info); else return -EINVAL; } static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info) { if (info->attrs[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK]) Loading Loading @@ -798,6 +981,13 @@ static const struct genl_ops taskstats_ops[] = { /* policy enforced later */ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_HASPOL, }, { .cmd = TASKSTATS2_CMD_GET, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = taskstats2_user_cmd, .dumpit = taskstats2_foreach, /* policy enforced later */ }, { .cmd = CGROUPSTATS_CMD_GET, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, Loading @@ -820,6 +1010,7 @@ static int taskstats_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, switch (ops->cmd) { case TASKSTATS_CMD_GET: case TASKSTATS2_CMD_GET: policy = taskstats_cmd_get_policy; break; case CGROUPSTATS_CMD_GET: Loading Loading
include/uapi/linux/taskstats.h +17 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ #define TASKSTATS_VERSION 9 #define TASKSTATS2_VERSION 1 #define TS_COMM_LEN 32 /* should be >= TASK_COMM_LEN * in linux/sched.h */ Loading Loading @@ -170,6 +171,19 @@ struct taskstats { __u64 thrashing_delay_total; }; struct taskstats2 { __u16 version; __s16 oom_score; __u32 pid; __u64 anon_rss; /* KB */ __u64 file_rss; /* KB */ __u64 swap_rss; /* KB */ __u64 shmem_rss; /* KB */ #ifdef CONFIG_MM_STAT_UNRECLAIMABLE_PAGES __u64 unreclaimable; /* KB */ #endif /* version 1 ends here */ }; /* * Commands sent from userspace Loading @@ -181,6 +195,7 @@ enum { TASKSTATS_CMD_UNSPEC = 0, /* Reserved */ TASKSTATS_CMD_GET, /* user->kernel request/get-response */ TASKSTATS_CMD_NEW, /* kernel->user event */ TASKSTATS2_CMD_GET, /* user->kernel request/get-response */ __TASKSTATS_CMD_MAX, }; Loading @@ -194,6 +209,7 @@ enum { TASKSTATS_TYPE_AGGR_PID, /* contains pid + stats */ TASKSTATS_TYPE_AGGR_TGID, /* contains tgid + stats */ TASKSTATS_TYPE_NULL, /* contains nothing */ TASKSTATS_TYPE_FOREACH, /* contains stats */ __TASKSTATS_TYPE_MAX, }; Loading @@ -205,6 +221,7 @@ enum { TASKSTATS_CMD_ATTR_TGID, TASKSTATS_CMD_ATTR_REGISTER_CPUMASK, TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK, TASKSTATS_CMD_ATTR_FOREACH, __TASKSTATS_CMD_ATTR_MAX, }; Loading
kernel/taskstats.c +192 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <net/genetlink.h> #include <linux/atomic.h> #include <linux/sched/cputime.h> #include <linux/oom.h> /* * Maximum length of a cpumask that can be specified in Loading @@ -41,7 +42,8 @@ static const struct nla_policy taskstats_cmd_get_policy[TASKSTATS_CMD_ATTR_MAX+1 [TASKSTATS_CMD_ATTR_PID] = { .type = NLA_U32 }, [TASKSTATS_CMD_ATTR_TGID] = { .type = NLA_U32 }, [TASKSTATS_CMD_ATTR_REGISTER_CPUMASK] = { .type = NLA_STRING }, [TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK] = { .type = NLA_STRING },}; [TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK] = { .type = NLA_STRING }, [TASKSTATS_CMD_ATTR_FOREACH] = { .type = NLA_U32 },}; /* * We have to use TASKSTATS_CMD_ATTR_MAX here, it is the maxattr in the family. Loading @@ -68,6 +70,11 @@ struct listener_list { }; static DEFINE_PER_CPU(struct listener_list, listener_array); struct tgid_iter { unsigned int tgid; struct task_struct *task; }; enum actions { REGISTER, DEREGISTER, Loading Loading @@ -625,6 +632,68 @@ static size_t taskstats_packet_size(void) return size; } static int taskstats2_cmd_attr_pid(struct genl_info *info) { struct taskstats2 *stats; struct sk_buff *rep_skb; struct nlattr *ret; struct task_struct *tsk; struct task_struct *p; size_t size; u32 pid; int rc; size = nla_total_size_64bit(sizeof(struct taskstats2)); rc = prepare_reply(info, TASKSTATS_CMD_NEW, &rep_skb, size); if (rc < 0) return rc; rc = -EINVAL; pid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_PID]); ret = nla_reserve_64bit(rep_skb, TASKSTATS_TYPE_STATS, sizeof(struct taskstats2), TASKSTATS_TYPE_NULL); if (!ret) goto err; stats = nla_data(ret); rcu_read_lock(); tsk = find_task_by_vpid(pid); if (tsk) get_task_struct(tsk); rcu_read_unlock(); if (!tsk) { rc = -ESRCH; goto err; } memset(stats, 0, sizeof(*stats)); stats->version = TASKSTATS2_VERSION; stats->pid = task_pid_nr_ns(tsk, task_active_pid_ns(current)); p = find_lock_task_mm(tsk); if (p) { __acquire(p->alloc_lock); /* Fake it out ;) */ #define K(x) ((x) << (PAGE_SHIFT - 10)) stats->anon_rss = K(get_mm_counter(p->mm, MM_ANONPAGES)); stats->file_rss = K(get_mm_counter(p->mm, MM_FILEPAGES)); stats->shmem_rss = K(get_mm_counter(p->mm, MM_SHMEMPAGES)); stats->swap_rss = K(get_mm_counter(p->mm, MM_SWAPENTS)); #ifdef CONFIG_MM_STAT_UNRECLAIMABLE_PAGES stats->unreclaimable = K(get_mm_counter(p->mm, MM_UNRECLAIMABLE)); #endif #undef K task_unlock(p); } put_task_struct(tsk); return send_reply(rep_skb, info); err: nlmsg_free(rep_skb); return rc; } static int cmd_attr_pid(struct genl_info *info) { struct taskstats *stats; Loading Loading @@ -683,6 +752,120 @@ static int cmd_attr_tgid(struct genl_info *info) return rc; } static struct tgid_iter next_tgid(struct pid_namespace *ns, struct tgid_iter iter) { struct pid *pid; if (iter.task) put_task_struct(iter.task); rcu_read_lock(); retry: iter.task = NULL; pid = find_ge_pid(iter.tgid, ns); if (pid) { iter.tgid = pid_nr_ns(pid, ns); iter.task = pid_task(pid, PIDTYPE_PID); if (!iter.task || !has_group_leader_pid(iter.task)) { iter.tgid += 1; goto retry; } get_task_struct(iter.task); } rcu_read_unlock(); return iter; } static int taskstats2_foreach(struct sk_buff *skb, struct netlink_callback *cb) { struct pid_namespace *ns = task_active_pid_ns(current); struct tgid_iter iter; void *reply; struct nlattr *attr; struct nlattr *nla; struct taskstats2 *stats; struct task_struct *p; short oom_score; short oom_score_min; short oom_score_max; u32 buf; nla = nla_find(nlmsg_attrdata(cb->nlh, GENL_HDRLEN), nlmsg_attrlen(cb->nlh, GENL_HDRLEN), TASKSTATS_TYPE_FOREACH); if (!nla) goto out; buf = nla_get_u32(nla); oom_score_min = (short) (buf & 0xFFFF); oom_score_max = (short) ((buf >> 16) & 0xFFFF); iter.tgid = cb->args[0]; iter.task = NULL; for (iter = next_tgid(ns, iter); iter.task; iter.tgid += 1, iter = next_tgid(ns, iter)) { if (iter.task->flags & PF_KTHREAD) continue; oom_score = iter.task->signal->oom_score_adj; if ((oom_score < oom_score_min) || (oom_score > oom_score_max)) continue; reply = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, &family, 0, TASKSTATS2_CMD_GET); if (reply == NULL) { put_task_struct(iter.task); break; } attr = nla_reserve(skb, TASKSTATS_TYPE_FOREACH, sizeof(struct taskstats2)); if (!attr) { put_task_struct(iter.task); genlmsg_cancel(skb, reply); break; } stats = nla_data(attr); memset(stats, 0, sizeof(struct taskstats2)); stats->version = TASKSTATS2_VERSION; rcu_read_lock(); stats->pid = task_pid_nr_ns(iter.task, task_active_pid_ns(current)); stats->oom_score = iter.task->signal->oom_score_adj; rcu_read_unlock(); p = find_lock_task_mm(iter.task); if (p) { #define K(x) ((x) << (PAGE_SHIFT - 10)) __acquire(p->alloc_lock); /* Fake it out ;) */ stats->anon_rss = K(get_mm_counter(p->mm, MM_ANONPAGES)); stats->file_rss = K(get_mm_counter(p->mm, MM_FILEPAGES)); stats->shmem_rss = K(get_mm_counter(p->mm, MM_SHMEMPAGES)); stats->swap_rss = K(get_mm_counter(p->mm, MM_SWAPENTS)); task_unlock(p); #undef K } genlmsg_end(skb, reply); } cb->args[0] = iter.tgid; out: return skb->len; } static int taskstats2_user_cmd(struct sk_buff *skb, struct genl_info *info) { if (info->attrs[TASKSTATS_CMD_ATTR_PID]) return taskstats2_cmd_attr_pid(info); else return -EINVAL; } static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info) { if (info->attrs[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK]) Loading Loading @@ -798,6 +981,13 @@ static const struct genl_ops taskstats_ops[] = { /* policy enforced later */ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_HASPOL, }, { .cmd = TASKSTATS2_CMD_GET, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = taskstats2_user_cmd, .dumpit = taskstats2_foreach, /* policy enforced later */ }, { .cmd = CGROUPSTATS_CMD_GET, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, Loading @@ -820,6 +1010,7 @@ static int taskstats_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, switch (ops->cmd) { case TASKSTATS_CMD_GET: case TASKSTATS2_CMD_GET: policy = taskstats_cmd_get_policy; break; case CGROUPSTATS_CMD_GET: Loading