mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-13 08:07:32 -04:00
Merge "taskstats: handle NULL nla case in taskstats2"
This commit is contained in:
commit
514fa165a3
2 changed files with 209 additions and 1 deletions
|
|
@ -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 */
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
|
|
@ -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,
|
||||
|
|
@ -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;
|
||||
|
|
@ -683,6 +752,120 @@ err:
|
|||
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])
|
||||
|
|
@ -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,
|
||||
|
|
@ -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…
Reference in a new issue