diff options
author | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-05-17 13:34:52 -0400 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-06-13 13:55:33 -0400 |
commit | 71ba0e569bb43ab99a07ccbb514f8b0f732140c3 (patch) | |
tree | 30133049da8d58a97e7231d61af2f56647ff120e | |
parent | 89bc500e41fc5b48e0573e6b0d927fc97b8951dc (diff) |
Bluetooth: Add refcnt to struct l2cap_chan
struct l2cap_chan has now its own refcnt that is compatible with the
socket refcnt, i.e., we won't see sk_refcnt = 0 and chan->refcnt > 0.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
-rw-r--r-- | include/net/bluetooth/l2cap.h | 2 | ||||
-rw-r--r-- | net/bluetooth/l2cap_core.c | 30 |
2 files changed, 23 insertions, 9 deletions
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 68c87244eafc..b3d953b5f399 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h | |||
@@ -289,6 +289,8 @@ struct l2cap_chan { | |||
289 | 289 | ||
290 | __u8 state; | 290 | __u8 state; |
291 | 291 | ||
292 | atomic_t refcnt; | ||
293 | |||
292 | __le16 psm; | 294 | __le16 psm; |
293 | __u16 dcid; | 295 | __u16 dcid; |
294 | __u16 scid; | 296 | __u16 scid; |
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 58fe03abee66..f24022c39869 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
@@ -78,6 +78,18 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, | |||
78 | static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); | 78 | static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); |
79 | 79 | ||
80 | /* ---- L2CAP channels ---- */ | 80 | /* ---- L2CAP channels ---- */ |
81 | |||
82 | static inline void chan_hold(struct l2cap_chan *c) | ||
83 | { | ||
84 | atomic_inc(&c->refcnt); | ||
85 | } | ||
86 | |||
87 | static inline void chan_put(struct l2cap_chan *c) | ||
88 | { | ||
89 | if (atomic_dec_and_test(&c->refcnt)) | ||
90 | kfree(c); | ||
91 | } | ||
92 | |||
81 | static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) | 93 | static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) |
82 | { | 94 | { |
83 | struct l2cap_chan *c; | 95 | struct l2cap_chan *c; |
@@ -213,7 +225,7 @@ static void l2cap_chan_set_timer(struct l2cap_chan *chan, long timeout) | |||
213 | BT_DBG("chan %p state %d timeout %ld", chan->sk, chan->state, timeout); | 225 | BT_DBG("chan %p state %d timeout %ld", chan->sk, chan->state, timeout); |
214 | 226 | ||
215 | if (!mod_timer(&chan->chan_timer, jiffies + timeout)) | 227 | if (!mod_timer(&chan->chan_timer, jiffies + timeout)) |
216 | sock_hold(chan->sk); | 228 | chan_hold(chan); |
217 | } | 229 | } |
218 | 230 | ||
219 | static void l2cap_chan_clear_timer(struct l2cap_chan *chan) | 231 | static void l2cap_chan_clear_timer(struct l2cap_chan *chan) |
@@ -221,7 +233,7 @@ static void l2cap_chan_clear_timer(struct l2cap_chan *chan) | |||
221 | BT_DBG("chan %p state %d", chan, chan->state); | 233 | BT_DBG("chan %p state %d", chan, chan->state); |
222 | 234 | ||
223 | if (timer_pending(&chan->chan_timer) && del_timer(&chan->chan_timer)) | 235 | if (timer_pending(&chan->chan_timer) && del_timer(&chan->chan_timer)) |
224 | __sock_put(chan->sk); | 236 | chan_put(chan); |
225 | } | 237 | } |
226 | 238 | ||
227 | static void l2cap_state_change(struct l2cap_chan *chan, int state) | 239 | static void l2cap_state_change(struct l2cap_chan *chan, int state) |
@@ -244,7 +256,7 @@ static void l2cap_chan_timeout(unsigned long arg) | |||
244 | /* sk is owned by user. Try again later */ | 256 | /* sk is owned by user. Try again later */ |
245 | l2cap_chan_set_timer(chan, HZ / 5); | 257 | l2cap_chan_set_timer(chan, HZ / 5); |
246 | bh_unlock_sock(sk); | 258 | bh_unlock_sock(sk); |
247 | sock_put(sk); | 259 | chan_put(chan); |
248 | return; | 260 | return; |
249 | } | 261 | } |
250 | 262 | ||
@@ -261,7 +273,7 @@ static void l2cap_chan_timeout(unsigned long arg) | |||
261 | bh_unlock_sock(sk); | 273 | bh_unlock_sock(sk); |
262 | 274 | ||
263 | chan->ops->close(chan->data); | 275 | chan->ops->close(chan->data); |
264 | sock_put(sk); | 276 | chan_put(chan); |
265 | } | 277 | } |
266 | 278 | ||
267 | struct l2cap_chan *l2cap_chan_create(struct sock *sk) | 279 | struct l2cap_chan *l2cap_chan_create(struct sock *sk) |
@@ -282,6 +294,8 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk) | |||
282 | 294 | ||
283 | chan->state = BT_OPEN; | 295 | chan->state = BT_OPEN; |
284 | 296 | ||
297 | atomic_set(&chan->refcnt, 1); | ||
298 | |||
285 | return chan; | 299 | return chan; |
286 | } | 300 | } |
287 | 301 | ||
@@ -291,13 +305,11 @@ void l2cap_chan_destroy(struct l2cap_chan *chan) | |||
291 | list_del(&chan->global_l); | 305 | list_del(&chan->global_l); |
292 | write_unlock_bh(&chan_list_lock); | 306 | write_unlock_bh(&chan_list_lock); |
293 | 307 | ||
294 | kfree(chan); | 308 | chan_put(chan); |
295 | } | 309 | } |
296 | 310 | ||
297 | static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) | 311 | static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) |
298 | { | 312 | { |
299 | struct sock *sk = chan->sk; | ||
300 | |||
301 | BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, | 313 | BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, |
302 | chan->psm, chan->dcid); | 314 | chan->psm, chan->dcid); |
303 | 315 | ||
@@ -328,7 +340,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) | |||
328 | chan->omtu = L2CAP_DEFAULT_MTU; | 340 | chan->omtu = L2CAP_DEFAULT_MTU; |
329 | } | 341 | } |
330 | 342 | ||
331 | sock_hold(sk); | 343 | chan_hold(chan); |
332 | 344 | ||
333 | list_add(&chan->list, &conn->chan_l); | 345 | list_add(&chan->list, &conn->chan_l); |
334 | } | 346 | } |
@@ -350,7 +362,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) | |||
350 | write_lock_bh(&conn->chan_lock); | 362 | write_lock_bh(&conn->chan_lock); |
351 | list_del(&chan->list); | 363 | list_del(&chan->list); |
352 | write_unlock_bh(&conn->chan_lock); | 364 | write_unlock_bh(&conn->chan_lock); |
353 | __sock_put(sk); | 365 | chan_put(chan); |
354 | 366 | ||
355 | chan->conn = NULL; | 367 | chan->conn = NULL; |
356 | hci_conn_put(conn->hcon); | 368 | hci_conn_put(conn->hcon); |