lkml.org 
[lkml]   [2009]   [Sep]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    SubjectRe: [PATCH] net: Fix sock_wfree() race
    Jarek Poplawski a écrit :
    > Eric Dumazet wrote, On 09/23/2009 03:44 PM:
    >
    > ...
    >> Here is the patch for reference :
    >>
    >> [PATCH] net: Fix sock_wfree() race
    >>
    >> Commit 2b85a34e911bf483c27cfdd124aeb1605145dc80
    >> (net: No more expensive sock_hold()/sock_put() on each tx)
    >> opens a window in sock_wfree() where another cpu
    >> might free the socket we are working on.
    >>
    >> A fix is to call sk->sk_write_space(sk) while still
    >> holding a reference on sk.
    >>
    >>
    >> Reported-by: Jike Song <albcamus@gmail.com>
    >> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
    >> ---
    >> net/core/sock.c | 19 ++++++++++++-------
    >> 1 files changed, 12 insertions(+), 7 deletions(-)
    >>
    >> diff --git a/net/core/sock.c b/net/core/sock.c
    >> index 30d5446..e1f034e 100644
    >> --- a/net/core/sock.c
    >> +++ b/net/core/sock.c
    >> @@ -1228,17 +1228,22 @@ void __init sk_init(void)
    >> void sock_wfree(struct sk_buff *skb)
    >> {
    >> struct sock *sk = skb->sk;
    >> - int res;
    >> + unsigned int len = skb->truesize;
    >>
    >> - /* In case it might be waiting for more memory. */
    >> - res = atomic_sub_return(skb->truesize, &sk->sk_wmem_alloc);
    >> - if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE))
    >> + if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE)) {
    >> + /*
    >> + * Keep a reference on sk_wmem_alloc, this will be released
    >> + * after sk_write_space() call
    >> + */
    >> + atomic_sub(len - 1, &sk->sk_wmem_alloc);
    >> sk->sk_write_space(sk);
    >> + len = 1;
    >> + }
    >> /*
    >> - * if sk_wmem_alloc reached 0, we are last user and should
    >> - * free this sock, as sk_free() call could not do it.
    >> + * if sk_wmem_alloc reaches 0, we must finish what sk_free()
    >> + * could not do because of in-flight packets
    >> */
    >> - if (res == 0)
    >> + if (atomic_sub_return(len, &sk->sk_wmem_alloc) == 0)
    >> __sk_free(sk);
    >
    >
    > Probably atomic_sub_and_test() is more popular for this.

    Indeed, as x86 can generate faster code (no need of xadd instruction)

    Thanks Jarek

    [PATCH] net: Fix sock_wfree() race

    Commit 2b85a34e911bf483c27cfdd124aeb1605145dc80
    (net: No more expensive sock_hold()/sock_put() on each tx)
    opens a window in sock_wfree() where another cpu
    might free the socket we are working on.

    A fix is to call sk->sk_write_space(sk) while still
    holding a reference on sk.


    Reported-by: Jike Song <albcamus@gmail.com>
    Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
    ---
    net/core/sock.c | 19 ++++++++++++-------
    1 files changed, 12 insertions(+), 7 deletions(-)

    diff --git a/net/core/sock.c b/net/core/sock.c
    index 30d5446..e1f034e 100644
    --- a/net/core/sock.c
    +++ b/net/core/sock.c
    @@ -1228,17 +1228,22 @@ void __init sk_init(void)
    void sock_wfree(struct sk_buff *skb)
    {
    struct sock *sk = skb->sk;
    - int res;
    + unsigned int len = skb->truesize;

    - /* In case it might be waiting for more memory. */
    - res = atomic_sub_return(skb->truesize, &sk->sk_wmem_alloc);
    - if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE))
    + if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE)) {
    + /*
    + * Keep a reference on sk_wmem_alloc, this will be released
    + * after sk_write_space() call
    + */
    + atomic_sub(len - 1, &sk->sk_wmem_alloc);
    sk->sk_write_space(sk);
    + len = 1;
    + }
    /*
    - * if sk_wmem_alloc reached 0, we are last user and should
    - * free this sock, as sk_free() call could not do it.
    + * if sk_wmem_alloc reaches 0, we must finish what sk_free()
    + * could not do because of in-flight packets
    */
    - if (res == 0)
    + if (atomic_sub_and_test(len, &sk->sk_wmem_alloc))
    __sk_free(sk);
    }
    EXPORT_SYMBOL(sock_wfree);
    --
    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/

    \
     
     \ /
      Last update: 2009-09-24 22:51    [W:0.028 / U:2.164 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site