709 lines · 16.0 KB · C
RawDownload
	struct taskstats *stats;	struct sk_buff *rep_skb;	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; 	if (sig->stats || thread_group_empty(tsk))		goto ret; 	/* No problem if kmem_cache_zalloc() fails */	stats = kmem_cache_zalloc(taskstats_cache, GFP_KERNEL); 	spin_lock_irq(&tsk->sighand->siglock);	if (!sig->stats) {		sig->stats = stats;		stats = NULL;	}	spin_unlock_irq(&tsk->sighand->siglock); 	if (stats)		kmem_cache_free(taskstats_cache, stats);ret:	return sig->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 = __this_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, tsk->pid);	if (!stats)		goto err; 	fill_stats(tsk, stats); 	/*	 * 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, tsk->tgid);	if (!stats)		goto err; 	memcpy(stats, tsk->signal->stats, sizeof(*stats)); send:	send_cpu_listeners(rep_skb, listeners);	return;err:	nlmsg_free(rep_skb);} static struct genl_ops taskstats_ops = {	.cmd		= TASKSTATS_CMD_GET,	.doit		= taskstats_user_cmd,	.policy		= taskstats_cmd_get_policy,	.flags		= GENL_ADMIN_PERM,}; static struct genl_ops cgroupstats_ops = {	.cmd		= CGROUPSTATS_CMD_GET,	.doit		= cgroupstats_user_cmd,	.policy		= cgroupstats_cmd_get_policy,}; /* 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; 	rc = genl_register_ops(&family, &taskstats_ops);	if (rc < 0)		goto err; 	rc = genl_register_ops(&family, &cgroupstats_ops);	if (rc < 0)		goto err_cgroup_ops; 	family_registered = 1;	pr_info("registered taskstats version %d\n", TASKSTATS_GENL_VERSION);	return 0;err_cgroup_ops:	genl_unregister_ops(&family, &taskstats_ops);err:	genl_unregister_family(&family);	return rc;} /* * late initcall ensures initialization of statistics collection * mechanisms precedes initialization of the taskstats interface */late_initcall(taskstats_init);

Lines 501–709 of 709. Previous lines