From: Patrick McHardy Date: Tue, 27 Feb 2007 17:56:42 +0000 (-0800) Subject: [NET]: Handle disabled preemption in gfp_any() X-Git-Tag: v2.6.21-rc3~149^2~3 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4498121ca3acbf928681b71261227d28dc29b6f6;p=linux-2.6 [NET]: Handle disabled preemption in gfp_any() ctnetlink uses netlink_unicast from an atomic_notifier_chain (which is called within a RCU read side critical section) without holding further locks. netlink_unicast calls netlink_trim with the result of gfp_any() for the gfp flags, which are passed down to pskb_expand_header. gfp_any() only checks for softirq context and returns GFP_KERNEL, resulting in this warning: BUG: sleeping function called from invalid context at mm/slab.c:3032 in_atomic():1, irqs_disabled():0 no locks held by rmmod/7010. Call Trace: [] debug_show_held_locks+0x9/0xb [] __might_sleep+0xd9/0xdb [] __kmalloc+0x68/0x110 [] pskb_expand_head+0x4d/0x13b [] netlink_broadcast+0xa5/0x2e0 [] :nfnetlink:nfnetlink_send+0x83/0x8a [] :nf_conntrack_netlink:ctnetlink_conntrack_event+0x94c/0x96a [] notifier_call_chain+0x29/0x3e [] atomic_notifier_call_chain+0x32/0x60 [] :nf_conntrack:destroy_conntrack+0xa5/0x1d3 [] :nf_conntrack:nf_ct_cleanup+0x8c/0x12c [] :nf_conntrack:kill_l3proto+0x0/0x13 [] :nf_conntrack:nf_conntrack_l3proto_unregister+0x90/0x94 [] :nf_conntrack_ipv4:nf_conntrack_l3proto_ipv4_fini+0x2b/0x5d [] sys_delete_module+0x1b5/0x1e6 [] trace_hardirqs_on_thunk+0x35/0x37 [] system_call+0x7e/0x83 Since netlink_unicast is supposed to be callable from within RCU read side critical sections, make gfp_any() check for in_atomic() instead of in_softirq(). Additionally nfnetlink_send needs to use gfp_any() as well for the call to netlink_broadcast). Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- diff --git a/include/net/sock.h b/include/net/sock.h index 03684e702d..2c7d60ca35 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1278,7 +1278,7 @@ static inline int sock_writeable(const struct sock *sk) static inline gfp_t gfp_any(void) { - return in_softirq() ? GFP_ATOMIC : GFP_KERNEL; + return in_atomic() ? GFP_ATOMIC : GFP_KERNEL; } static inline long sock_rcvtimeo(const struct sock *sk, int noblock) diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index 11d504d0ac..bf23e489e4 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -197,13 +197,12 @@ EXPORT_SYMBOL_GPL(nfnetlink_has_listeners); int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo) { - gfp_t allocation = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; int err = 0; NETLINK_CB(skb).dst_group = group; if (echo) atomic_inc(&skb->users); - netlink_broadcast(nfnl, skb, pid, group, allocation); + netlink_broadcast(nfnl, skb, pid, group, gfp_any()); if (echo) err = netlink_unicast(nfnl, skb, pid, MSG_DONTWAIT);