aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGustavo F. Padovan <padovan@profusion.mobi>2011-05-17 13:34:52 -0400
committerGustavo F. Padovan <padovan@profusion.mobi>2011-06-13 13:55:33 -0400
commit71ba0e569bb43ab99a07ccbb514f8b0f732140c3 (patch)
tree30133049da8d58a97e7231d61af2f56647ff120e
parent89bc500e41fc5b48e0573e6b0d927fc97b8951dc (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.h2
-rw-r--r--net/bluetooth/l2cap_core.c30
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,
78static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); 78static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
79 79
80/* ---- L2CAP channels ---- */ 80/* ---- L2CAP channels ---- */
81
82static inline void chan_hold(struct l2cap_chan *c)
83{
84 atomic_inc(&c->refcnt);
85}
86
87static inline void chan_put(struct l2cap_chan *c)
88{
89 if (atomic_dec_and_test(&c->refcnt))
90 kfree(c);
91}
92
81static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) 93static 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
219static void l2cap_chan_clear_timer(struct l2cap_chan *chan) 231static 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
227static void l2cap_state_change(struct l2cap_chan *chan, int state) 239static 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
267struct l2cap_chan *l2cap_chan_create(struct sock *sk) 279struct 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
297static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) 311static 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);