Use a cloned sk_buff for each netlink message sent to multiple listeners. Earlier, the same skb, representing a netlink message, was being erroneously reused for doing genetlink_unicast()'s (effectively netlink_unicast()) to each listener on the per-cpu list of listeners. Since netlink_unicast() frees up the skb passed to it, regardless of status of the send, reuse is bad.
Thanks to Chandra Seetharaman for discovering this bug. Signed-Off-By: Shailabh Nagar <[EMAIL PROTECTED]> Signed-Off-By: Chandra Seetharaman <[EMAIL PROTECTED]> kernel/taskstats.c | 13 ++++++++++++- 1 files changed, 12 insertions(+), 1 deletion(-) Index: linux-2.6.18-rc1/kernel/taskstats.c =================================================================== --- linux-2.6.18-rc1.orig/kernel/taskstats.c 2006-07-10 23:44:56.000000000 -0400 +++ linux-2.6.18-rc1/kernel/taskstats.c 2006-07-10 23:45:15.000000000 -0400 @@ -125,6 +125,7 @@ static int send_cpu_listeners(struct sk_ struct genlmsghdr *genlhdr = nlmsg_data((struct nlmsghdr *)skb->data); struct listener_list *listeners; struct listener *s, *tmp; + struct sk_buff *skb_next, *skb_cur = skb; void *reply = genlmsg_data(genlhdr); int rc, ret; @@ -138,12 +139,22 @@ static int send_cpu_listeners(struct sk_ listeners = &per_cpu(listener_array, cpu); down_write(&listeners->sem); list_for_each_entry_safe(s, tmp, &listeners->list, list) { - ret = genlmsg_unicast(skb, s->pid); + skb_next = NULL; + if (!list_islast(&s->list, &listeners->list)) { + skb_next = skb_clone(skb_cur, GFP_KERNEL); + if (!skb_next) { + nlmsg_free(skb_cur); + rc = -ENOMEM; + break; + } + } + ret = genlmsg_unicast(skb_cur, s->pid); if (ret == -ECONNREFUSED) { list_del(&s->list); kfree(s); rc = ret; } + skb_cur = skb_next; } up_write(&listeners->sem); - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html