Rafael J. Wysocki a écrit :
> This message has been generated automatically as a part of a report
> of regressions introduced between 2.6.30 and 2.6.31.
> 
> The following bug entry is on the current list of known regressions
> introduced between 2.6.30 and 2.6.31.  Please verify if it still should
> be listed and let me know (either way).
> 
> 
> Bug-Entry     : http://bugzilla.kernel.org/show_bug.cgi?id=14301
> Subject               : WARNING: at net/ipv4/af_inet.c:154
> Submitter     : Ralf Hildebrandt <[email protected]>
> Date          : 2009-09-30 12:24 (2 days old)
> References    : http://marc.info/?l=linux-kernel&m=125431350218137&w=4
> 
> 

If commit d99927f4d93f36553699573b279e0ff98ad7dea6
(net: Fix sock_wfree() race) doesnt fix this problem, then
maybe we should take a look at an old patch.

< data mining... running... output results to lkml/netdev >

Random guesses

 1) : commit d55d87fdff8252d0e2f7c28c2d443aee17e9d70f
(net: Move rx skb_orphan call to where needed)

A similar problem on SCTP was fixed by commit 
1bc4ee4088c9a502db0e9c87f675e61e57fa1734
(sctp: fix warning at inet_sock_destruct() while release sctp socket)

2) CORK and UDP sockets
  It seems we can leave an UDP socket with a frame in sk_write_queue
  Purge of this queue is done by udp_flush_pending_frames()
   This calls ip_flush_pending_frames()
   But this function only calls kfree_skb(), not sk_wmem_free_skb()...


Could you try following patch ?

Thanks

[PATCH] net: UDP should not use ip_flush_pending_frames()

Now xmit UDP messages are charged, we must take care of calling right
skb freeing function.

In case a close() is performed on a socket where CORKED frame
is still queued in sk_write_queue, calling ip_flush_pending_frames()
leads to sk_forward_alloc leak.

Reported-by: Ralf Hildebrandt <[email protected]>
Signed-off-by: Eric Dumazet <[email protected]>
---
 include/net/sock.h  |   10 ++++++++++
 include/net/tcp.h   |   10 ----------
 net/ipv4/tcp.c      |    2 +-
 net/ipv4/tcp_ipv4.c |    2 +-
 net/ipv4/udp.c      |    2 +-
 5 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/include/net/sock.h b/include/net/sock.h
index 1621935..7c80fec 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -882,6 +882,16 @@ static inline void sk_wmem_free_skb(struct sock *sk, 
struct sk_buff *skb)
        __kfree_skb(skb);
 }
 
+/* write queue abstraction */
+static inline void sk_write_queue_purge(struct sock *sk)
+{
+       struct sk_buff *skb;
+
+       while ((skb = __skb_dequeue(&sk->sk_write_queue)) != NULL)
+               sk_wmem_free_skb(sk, skb);
+       sk_mem_reclaim(sk);
+}
+
 /* Used by processes to "lock" a socket state, so that
  * interrupts and bottom half handlers won't change it
  * from under us. It essentially blocks any incoming
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 03a49c7..4c7036a 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1220,16 +1220,6 @@ static inline void               
tcp_put_md5sig_pool(void)
        put_cpu();
 }
 
-/* write queue abstraction */
-static inline void tcp_write_queue_purge(struct sock *sk)
-{
-       struct sk_buff *skb;
-
-       while ((skb = __skb_dequeue(&sk->sk_write_queue)) != NULL)
-               sk_wmem_free_skb(sk, skb);
-       sk_mem_reclaim(sk);
-}
-
 static inline struct sk_buff *tcp_write_queue_head(struct sock *sk)
 {
        return skb_peek(&sk->sk_write_queue);
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 64d0af6..0124f5b 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1992,7 +1992,7 @@ int tcp_disconnect(struct sock *sk, int flags)
 
        tcp_clear_xmit_timers(sk);
        __skb_queue_purge(&sk->sk_receive_queue);
-       tcp_write_queue_purge(sk);
+       sk_write_queue_purge(sk);
        __skb_queue_purge(&tp->out_of_order_queue);
 #ifdef CONFIG_NET_DMA
        __skb_queue_purge(&sk->sk_async_wait_queue);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 7cda24b..76e59df 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1845,7 +1845,7 @@ void tcp_v4_destroy_sock(struct sock *sk)
        tcp_cleanup_congestion_control(sk);
 
        /* Cleanup up the write buffer. */
-       tcp_write_queue_purge(sk);
+       sk_write_queue_purge(sk);
 
        /* Cleans up our, hopefully empty, out_of_order_queue. */
        __skb_queue_purge(&tp->out_of_order_queue);
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 6ec6a8a..58007d1 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -464,7 +464,7 @@ void udp_flush_pending_frames(struct sock *sk)
        if (up->pending) {
                up->len = 0;
                up->pending = 0;
-               ip_flush_pending_frames(sk);
+               sk_write_queue_purge(sk);
        }
 }
 EXPORT_SYMBOL(udp_flush_pending_frames);
--
To unsubscribe from this list: send the line "unsubscribe kernel-testers" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to