722 lines · 15.8 KB · C
RawDownload
	size_t size;	u32 pid;	int rc; 	size = taskstats_packet_size(); 	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]);	stats = mk_reply(rep_skb, TASKSTATS_TYPE_PID, pid);	if (!stats)		goto err; 	rc = fill_stats_for_pid(pid, stats);	if (rc < 0)		goto err;	return send_reply(rep_skb, info);err:	nlmsg_free(rep_skb);	return rc;} static int cmd_attr_tgid(struct genl_info *info){	struct taskstats *stats;	struct sk_buff *rep_skb;	size_t size;	u32 tgid;	int rc; 	size = taskstats_packet_size(); 	rc = prepare_reply(info, TASKSTATS_CMD_NEW, &rep_skb, size);	if (rc < 0)		return rc; 	rc = -EINVAL;	tgid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_TGID]);	stats = mk_reply(rep_skb, TASKSTATS_TYPE_TGID, tgid);	if (!stats)		goto err; 	rc = fill_stats_for_tgid(tgid, stats);	if (rc < 0)		goto err;	return send_reply(rep_skb, info);err:	nlmsg_free(rep_skb);	return rc;} static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info){	if (info->attrs[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK])		return cmd_attr_register_cpumask(info);	else if (info->attrs[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK])		return cmd_attr_deregister_cpumask(info);	else if (info->attrs[TASKSTATS_CMD_ATTR_PID])		return cmd_attr_pid(info);	else if (info->attrs[TASKSTATS_CMD_ATTR_TGID])		return cmd_attr_tgid(info);	else		return -EINVAL;} static struct taskstats *taskstats_tgid_alloc(struct task_struct *tsk){	struct signal_struct *sig = tsk->signal;	struct taskstats *stats_new, *stats; 	/* Pairs with smp_store_release() below. */	stats = smp_load_acquire(&sig->stats);	if (stats || thread_group_empty(tsk))		return stats; 	/* No problem if kmem_cache_zalloc() fails */	stats_new = kmem_cache_zalloc(taskstats_cache, GFP_KERNEL); 	spin_lock_irq(&tsk->sighand->siglock);	stats = sig->stats;	if (!stats) {		/*		 * Pairs with smp_store_release() above and order the		 * kmem_cache_zalloc().		 */		smp_store_release(&sig->stats, stats_new);		stats = stats_new;		stats_new = NULL;	}	spin_unlock_irq(&tsk->sighand->siglock); 	if (stats_new)		kmem_cache_free(taskstats_cache, stats_new); 	return stats;} /* Send pid data out on exit */void taskstats_exit(struct task_struct *tsk, int group_dead){	int rc;	struct listener_list *listeners;	struct taskstats *stats;	struct sk_buff *rep_skb;	size_t size;	int is_thread_group; 	if (!family_registered)		return; 	/*	 * Size includes space for nested attributes	 */	size = taskstats_packet_size(); 	is_thread_group = !!taskstats_tgid_alloc(tsk);	if (is_thread_group) {		/* PID + STATS + TGID + STATS */		size = 2 * size;		/* fill the tsk->signal->stats structure */		fill_tgid_exit(tsk);	} 	listeners = raw_cpu_ptr(&listener_array);	if (list_empty(&listeners->list))		return; 	rc = prepare_reply(NULL, TASKSTATS_CMD_NEW, &rep_skb, size);	if (rc < 0)		return; 	stats = mk_reply(rep_skb, TASKSTATS_TYPE_PID,			 task_pid_nr_ns(tsk, &init_pid_ns));	if (!stats)		goto err; 	fill_stats(&init_user_ns, &init_pid_ns, tsk, stats);	if (group_dead)		stats->ac_flag |= AGROUP; 	/*	 * Doesn't matter if tsk is the leader or the last group member leaving	 */	if (!is_thread_group || !group_dead)		goto send; 	stats = mk_reply(rep_skb, TASKSTATS_TYPE_TGID,			 task_tgid_nr_ns(tsk, &init_pid_ns));	if (!stats)		goto err; 	memcpy(stats, tsk->signal->stats, sizeof(*stats));	stats->version = TASKSTATS_VERSION; send:	send_cpu_listeners(rep_skb, listeners);	return;err:	nlmsg_free(rep_skb);} static const struct genl_ops taskstats_ops[] = {	{		.cmd		= TASKSTATS_CMD_GET,		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,		.doit		= taskstats_user_cmd,		.policy		= taskstats_cmd_get_policy,		.maxattr	= ARRAY_SIZE(taskstats_cmd_get_policy) - 1,		.flags		= GENL_ADMIN_PERM,	},	{		.cmd		= CGROUPSTATS_CMD_GET,		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,		.doit		= cgroupstats_user_cmd,		.policy		= cgroupstats_cmd_get_policy,		.maxattr	= ARRAY_SIZE(cgroupstats_cmd_get_policy) - 1,	},}; static struct genl_family family __ro_after_init = {	.name		= TASKSTATS_GENL_NAME,	.version	= TASKSTATS_GENL_VERSION,	.module		= THIS_MODULE,	.ops		= taskstats_ops,	.n_ops		= ARRAY_SIZE(taskstats_ops),	.resv_start_op	= CGROUPSTATS_CMD_GET + 1,	.netnsok	= true,}; /* Needed early in initialization */void __init taskstats_init_early(void){	unsigned int i; 	taskstats_cache = KMEM_CACHE(taskstats, SLAB_PANIC);	for_each_possible_cpu(i) {		INIT_LIST_HEAD(&(per_cpu(listener_array, i).list));		init_rwsem(&(per_cpu(listener_array, i).sem));	}} static int __init taskstats_init(void){	int rc; 	rc = genl_register_family(&family);	if (rc)		return rc; 	family_registered = 1;	pr_info("registered taskstats version %d\n", TASKSTATS_GENL_VERSION);	return 0;} /* * late initcall ensures initialization of statistics collection * mechanisms precedes initialization of the taskstats interface */late_initcall(taskstats_init);

Lines 501–722 of 722. Previous lines