Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754351AbbGFIu5 (ORCPT ); Mon, 6 Jul 2015 04:50:57 -0400 Received: from mailhub.sw.ru ([195.214.232.25]:43022 "EHLO relay.sw.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754168AbbGFIuq (ORCPT ); Mon, 6 Jul 2015 04:50:46 -0400 From: Andrey Vagin To: linux-kernel@vger.kernel.org Cc: linux-api@vger.kernel.org, Andrey Vagin , Oleg Nesterov , Andrew Morton , Cyrill Gorcunov , Pavel Emelyanov , Roger Luethi , Arnd Bergmann , Arnaldo Carvalho de Melo , David Ahern , Andy Lutomirski , Pavel Odintsov Subject: [PATCH 06/24] task_diag: add ability to split per-task data on a few netlink messages Date: Mon, 6 Jul 2015 11:47:07 +0300 Message-Id: <1436172445-6979-7-git-send-email-avagin@openvz.org> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1436172445-6979-1-git-send-email-avagin@openvz.org> References: <1436172445-6979-1-git-send-email-avagin@openvz.org> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 3784 Lines: 156 The size of requested per-task data can be bigger that the size of one netlink skb. Currently we are able to split data into a few netlink messages. v2: set NLM_F_MULTI for multipart packets Signed-off-by: Andrey Vagin --- kernel/taskdiag.c | 76 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 25 deletions(-) diff --git a/kernel/taskdiag.c b/kernel/taskdiag.c index 3497304..5771baf 100644 --- a/kernel/taskdiag.c +++ b/kernel/taskdiag.c @@ -84,13 +84,21 @@ static int fill_task_base(struct task_struct *p, struct sk_buff *skb) } static int task_diag_fill(struct task_struct *tsk, struct sk_buff *skb, - u64 show_flags, u32 portid, u32 seq) + u64 show_flags, u32 portid, u32 seq, + struct netlink_callback *cb) { void *reply; - int err; + int err = 0, i = 0, n = 0; + int flags = 0; u32 pid; - reply = genlmsg_put(skb, portid, seq, &taskstats_family, 0, TASK_DIAG_CMD_GET); + if (cb) { + n = cb->args[2]; + flags |= NLM_F_MULTI; + } + + reply = genlmsg_put(skb, portid, seq, &taskstats_family, + flags, TASK_DIAG_CMD_GET); if (reply == NULL) return -EMSGSIZE; @@ -100,15 +108,26 @@ static int task_diag_fill(struct task_struct *tsk, struct sk_buff *skb, goto err; if (show_flags & TASK_DIAG_SHOW_BASE) { - err = fill_task_base(tsk, skb); + if (i >= n) + err = fill_task_base(tsk, skb); if (err) goto err; + i++; } genlmsg_end(skb, reply); + if (cb) + cb->args[2] = 0; + return 0; err: - genlmsg_cancel(skb, reply); + if (err == -EMSGSIZE && i != 0) { + if (cb) + cb->args[2] = i; + genlmsg_end(skb, reply); + } else + genlmsg_cancel(skb, reply); + return err; } @@ -138,7 +157,7 @@ int taskdiag_dumpit(struct sk_buff *skb, struct netlink_callback *cb) continue; rc = task_diag_fill(iter.task, skb, req.show_flags, - NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq); + NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, cb); if (rc < 0) { put_task_struct(iter.task); if (rc != -EMSGSIZE) @@ -157,7 +176,7 @@ int taskdiag_doit(struct sk_buff *skb, struct genl_info *info) struct nlattr *nla = info->attrs[TASK_DIAG_CMD_ATTR_GET]; struct task_struct *tsk = NULL; struct task_diag_pid req; - struct sk_buff *msg; + struct sk_buff *msg = NULL; size_t size; int rc; @@ -174,35 +193,42 @@ int taskdiag_doit(struct sk_buff *skb, struct genl_info *info) */ memcpy(&req, nla_data(nla), sizeof(req)); - size = taskdiag_packet_size(req.show_flags); - msg = genlmsg_new(size, GFP_KERNEL); - if (!msg) - return -ENOMEM; - rcu_read_lock(); tsk = find_task_by_vpid(req.pid); if (tsk) get_task_struct(tsk); rcu_read_unlock(); - if (!tsk) { - rc = -ESRCH; - goto err; - }; + if (!tsk) + return -ESRCH; if (!ptrace_may_access(tsk, PTRACE_MODE_READ)) { put_task_struct(tsk); - rc = -EPERM; - goto err; + return -EPERM; + } + + size = taskdiag_packet_size(req.show_flags); + + while (1) { + msg = genlmsg_new(size, GFP_KERNEL); + if (!msg) { + put_task_struct(tsk); + return -EMSGSIZE; + } + + rc = task_diag_fill(tsk, msg, req.show_flags, + info->snd_portid, info->snd_seq, NULL); + if (rc != -EMSGSIZE) + break; + + nlmsg_free(msg); + size += 128; } - rc = task_diag_fill(tsk, msg, req.show_flags, - info->snd_portid, info->snd_seq); put_task_struct(tsk); - if (rc < 0) - goto err; + if (rc < 0) { + nlmsg_free(msg); + return rc; + } return genlmsg_reply(msg, info); -err: - nlmsg_free(msg); - return rc; } -- 2.1.0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/