diff options
author | Eric Dumazet <edumazet@google.com> | 2015-03-15 21:12:16 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-03-16 15:55:29 -0400 |
commit | 13854e5a60461daee08ce99842b7f4d37553d911 (patch) | |
tree | f7bf7650ead7d8af1e93d98114da5cd1bf658956 /include/net | |
parent | 2c13270b441054a9596bcd99c0f446603c9ad131 (diff) | |
download | linux-13854e5a60461daee08ce99842b7f4d37553d911.tar.bz2 |
inet: add proper refcounting to request sock
reqsk_put() is the generic function that should be used
to release a refcount (and automatically call reqsk_free())
reqsk_free() might be called if refcount is known to be 0
or undefined.
refcnt is set to one in inet_csk_reqsk_queue_add()
As request socks are not yet in global ehash table,
I added temporary debugging checks in reqsk_put() and reqsk_free()
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include/net')
-rw-r--r-- | include/net/inet_connection_sock.h | 5 | ||||
-rw-r--r-- | include/net/inet_sock.h | 5 | ||||
-rw-r--r-- | include/net/request_sock.h | 13 |
3 files changed, 17 insertions, 6 deletions
diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index b9a6b0a94cc6..191feec60205 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h @@ -275,6 +275,11 @@ static inline void inet_csk_reqsk_queue_add(struct sock *sk, struct sock *child) { reqsk_queue_add(&inet_csk(sk)->icsk_accept_queue, req, sk, child); + /* before letting lookups find us, make sure all req fields + * are committed to memory. + */ + smp_wmb(); + atomic_set(&req->rsk_refcnt, 1); } void inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req, diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index b3053fdd871e..3d8c09abb097 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -255,6 +255,11 @@ static inline struct request_sock *inet_reqsk_alloc(struct request_sock_ops *ops ireq->opt = NULL; atomic64_set(&ireq->ir_cookie, 0); ireq->ireq_state = TCP_NEW_SYN_RECV; + + /* Following is temporary. It is coupled with debugging + * helpers in reqsk_put() & reqsk_free() + */ + atomic_set(&ireq->ireq_refcnt, 0); } return req; diff --git a/include/net/request_sock.h b/include/net/request_sock.h index 3275cf31f731..56dc2faba47e 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -82,19 +82,20 @@ static inline struct request_sock *inet_reqsk(struct sock *sk) return (struct request_sock *)sk; } -static inline void __reqsk_free(struct request_sock *req) -{ - kmem_cache_free(req->rsk_ops->slab, req); -} - static inline void reqsk_free(struct request_sock *req) { + /* temporary debugging */ + WARN_ON_ONCE(atomic_read(&req->rsk_refcnt) != 0); + req->rsk_ops->destructor(req); - __reqsk_free(req); + kmem_cache_free(req->rsk_ops->slab, req); } static inline void reqsk_put(struct request_sock *req) { + /* temporary debugging, until req sock are put into ehash table */ + WARN_ON_ONCE(atomic_read(&req->rsk_refcnt) != 1); + if (atomic_dec_and_test(&req->rsk_refcnt)) reqsk_free(req); } |