From: Eldad Zinger Date: Wed, 6 Oct 2010 09:52:10 +0000 (+0200) Subject: sdp: BUG2141 - fix refcnt bug X-Git-Tag: v4.1.12-92~264^2~5^2~94 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=9c4bca694a1be60f114de4e175de00a42b24b79a;p=users%2Fjedix%2Flinux-maple.git sdp: BUG2141 - fix refcnt bug This bug is reproducable when sdpnetstat(1) is run while a socket is being destructed. sdp_proc utilities might try to hold a refcnt for a socket that its destruction already began. This is possible because sdp_proc utilities uses sock_list to scan for sockets, but a socket is removed from that list only after all its resourcs are freed. Signed-off-by: Eldad Zinger --- diff --git a/drivers/infiniband/ulp/sdp/sdp_proc.c b/drivers/infiniband/ulp/sdp/sdp_proc.c index 99006dd7e7278..c00093b8b8279 100644 --- a/drivers/infiniband/ulp/sdp/sdp_proc.c +++ b/drivers/infiniband/ulp/sdp/sdp_proc.c @@ -69,6 +69,14 @@ static void *sdp_get_idx(struct seq_file *seq, loff_t pos) return NULL; } +#define sdp_sock_hold_return(sk, msg) \ + ({ \ + _sdp_add_to_history(sk, #msg, __func__, __LINE__, HOLD_REF, msg); \ + sdp_dbg(sk, "%s:%d - %s (%s) ref = %d.\n", __func__, __LINE__, \ + "sock_hold", #msg, atomic_read(&(sk)->sk_refcnt)); \ + atomic_inc_return(&(sk)->sk_refcnt); \ + }) + static void *sdp_seq_start(struct seq_file *seq, loff_t *pos) { void *start = NULL; @@ -81,8 +89,12 @@ static void *sdp_seq_start(struct seq_file *seq, loff_t *pos) spin_lock_irq(&sock_list_lock); start = sdp_get_idx(seq, *pos - 1); - if (start) - sock_hold((struct sock *)start, SOCK_REF_SEQ); + if (!start) + goto out; + + if (sdp_sock_hold_return((struct sock *)start, SOCK_REF_SEQ) < 2) + start = NULL; +out: spin_unlock_irq(&sock_list_lock); return start; @@ -98,10 +110,13 @@ static void *sdp_seq_next(struct seq_file *seq, void *v, loff_t *pos) next = sdp_get_idx(seq, 0); else next = sdp_get_idx(seq, *pos); - if (next) - sock_hold((struct sock *)next, SOCK_REF_SEQ); - spin_unlock_irq(&sock_list_lock); + if (!next) + goto out; + if (sdp_sock_hold_return((struct sock *)next, SOCK_REF_SEQ) < 2) + next = NULL; +out: + spin_unlock_irq(&sock_list_lock); *pos += 1; st->num++;