* Chris Wright (chrisw(a)osdl.org) wrote:
* Linda Knippers (linda.knippers(a)hp.com) wrote:
> I had the same problem when I booted it on my ia64 box, as soon
> as I started the auditd.
Odd. I had tested on 2.6.12-rc2 and the git tree and never saw that.
Just tried the .29 and got same as you. I'm digging into it.
OK, my current working theory is this is tickling a bug in the netlink core
which has since been fixed. Here's the patch in mainline, haven't
tested this theory yet...
Note how it clones when "shared" (we don't actually share, but we hold
an extra ref in case we have to requeue).
===== net/netlink/af_netlink.c 1.66 vs 1.68 =====
--- 1.66/net/netlink/af_netlink.c 2005-01-13 20:41:06 -08:00
+++ 1.68/net/netlink/af_netlink.c 2005-01-19 14:04:07 -08:00
@@ -629,7 +629,6 @@ int netlink_attachskb(struct sock *sk, s
}
return 1;
}
- skb_orphan(skb);
skb_set_owner_r(skb, sk);
return 0;
}
@@ -661,21 +660,28 @@ void netlink_detachskb(struct sock *sk,
sock_put(sk);
}
-static inline void netlink_trim(struct sk_buff *skb, int allocation)
+static inline struct sk_buff *netlink_trim(struct sk_buff *skb, int allocation)
{
- int delta = skb->end - skb->tail;
+ int delta;
- /* If the packet is charged to a socket, the modification
- * of truesize below is illegal and will corrupt socket
- * buffer accounting state.
- */
- BUG_ON(skb->list != NULL);
+ skb_orphan(skb);
+ delta = skb->end - skb->tail;
if (delta * 2 < skb->truesize)
- return;
- if (pskb_expand_head(skb, 0, -delta, allocation))
- return;
- skb->truesize -= delta;
+ return skb;
+
+ if (skb_shared(skb)) {
+ struct sk_buff *nskb = skb_clone(skb, allocation);
+ if (!nskb)
+ return skb;
+ kfree_skb(skb);
+ skb = nskb;
+ }
+
+ if (!pskb_expand_head(skb, 0, -delta, allocation))
+ skb->truesize -= delta;
+
+ return skb;
}
int netlink_unicast(struct sock *ssk, struct sk_buff *skb, u32 pid, int nonblock)
@@ -684,7 +690,7 @@ int netlink_unicast(struct sock *ssk, st
int err;
long timeo;
- netlink_trim(skb, gfp_any());
+ skb = netlink_trim(skb, gfp_any());
timeo = sock_sndtimeo(ssk, nonblock);
retry:
@@ -707,14 +713,12 @@ static __inline__ int netlink_broadcast_
struct netlink_opt *nlk = nlk_sk(sk);
#ifdef NL_EMULATE_DEV
if (nlk->handler) {
- skb_orphan(skb);
nlk->handler(sk->sk_protocol, skb);
return 0;
} else
#endif
if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf &&
!test_bit(0, &nlk->state)) {
- skb_orphan(skb);
skb_set_owner_r(skb, sk);
skb_queue_tail(&sk->sk_receive_queue, skb);
sk->sk_data_ready(sk, skb->len);
@@ -784,6 +788,8 @@ int netlink_broadcast(struct sock *ssk,
struct hlist_node *node;
struct sock *sk;
+ skb = netlink_trim(skb, allocation);
+
info.exclude_sk = ssk;
info.pid = pid;
info.group = group;
@@ -793,8 +799,6 @@ int netlink_broadcast(struct sock *ssk,
info.allocation = allocation;
info.skb = skb;
info.skb2 = NULL;
-
- netlink_trim(skb, allocation);
/* While we sleep in clone, do not allow to change socket list */