diff options
author | Ville Tervo <ville.tervo@nokia.com> | 2007-07-11 03:23:41 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2007-07-11 01:06:51 -0400 |
commit | 8de0a15483b357d0f0b821330ec84d1660cadc4e (patch) | |
tree | b53fe490c95066dfc95f58d52b26e3f1f75ecdba | |
parent | 84950cf0ba02fd6a5defe2511bc41f9aa2237632 (diff) |
[Bluetooth] Keep rfcomm_dev on the list until it is freed
This patch changes the RFCOMM TTY release process so that the TTY is kept
on the list until it is really freed. A new device flag is used to keep
track of released TTYs.
Signed-off-by: Ville Tervo <ville.tervo@nokia.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r-- | include/net/bluetooth/rfcomm.h | 1 | ||||
-rw-r--r-- | net/bluetooth/rfcomm/tty.c | 30 |
2 files changed, 23 insertions, 8 deletions
diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h index 3c563f02907c..25aa575db807 100644 --- a/include/net/bluetooth/rfcomm.h +++ b/include/net/bluetooth/rfcomm.h | |||
@@ -323,6 +323,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc | |||
323 | #define RFCOMM_RELEASE_ONHUP 1 | 323 | #define RFCOMM_RELEASE_ONHUP 1 |
324 | #define RFCOMM_HANGUP_NOW 2 | 324 | #define RFCOMM_HANGUP_NOW 2 |
325 | #define RFCOMM_TTY_ATTACHED 3 | 325 | #define RFCOMM_TTY_ATTACHED 3 |
326 | #define RFCOMM_TTY_RELEASED 4 | ||
326 | 327 | ||
327 | struct rfcomm_dev_req { | 328 | struct rfcomm_dev_req { |
328 | s16 dev_id; | 329 | s16 dev_id; |
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index ba469b038ea0..23ba61a13bdd 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c | |||
@@ -95,6 +95,10 @@ static void rfcomm_dev_destruct(struct rfcomm_dev *dev) | |||
95 | 95 | ||
96 | BT_DBG("dev %p dlc %p", dev, dlc); | 96 | BT_DBG("dev %p dlc %p", dev, dlc); |
97 | 97 | ||
98 | write_lock_bh(&rfcomm_dev_lock); | ||
99 | list_del_init(&dev->list); | ||
100 | write_unlock_bh(&rfcomm_dev_lock); | ||
101 | |||
98 | rfcomm_dlc_lock(dlc); | 102 | rfcomm_dlc_lock(dlc); |
99 | /* Detach DLC if it's owned by this dev */ | 103 | /* Detach DLC if it's owned by this dev */ |
100 | if (dlc->owner == dev) | 104 | if (dlc->owner == dev) |
@@ -156,8 +160,13 @@ static inline struct rfcomm_dev *rfcomm_dev_get(int id) | |||
156 | read_lock(&rfcomm_dev_lock); | 160 | read_lock(&rfcomm_dev_lock); |
157 | 161 | ||
158 | dev = __rfcomm_dev_get(id); | 162 | dev = __rfcomm_dev_get(id); |
159 | if (dev) | 163 | |
160 | rfcomm_dev_hold(dev); | 164 | if (dev) { |
165 | if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) | ||
166 | dev = NULL; | ||
167 | else | ||
168 | rfcomm_dev_hold(dev); | ||
169 | } | ||
161 | 170 | ||
162 | read_unlock(&rfcomm_dev_lock); | 171 | read_unlock(&rfcomm_dev_lock); |
163 | 172 | ||
@@ -265,6 +274,12 @@ out: | |||
265 | 274 | ||
266 | dev->tty_dev = tty_register_device(rfcomm_tty_driver, dev->id, NULL); | 275 | dev->tty_dev = tty_register_device(rfcomm_tty_driver, dev->id, NULL); |
267 | 276 | ||
277 | if (IS_ERR(dev->tty_dev)) { | ||
278 | list_del(&dev->list); | ||
279 | kfree(dev); | ||
280 | return PTR_ERR(dev->tty_dev); | ||
281 | } | ||
282 | |||
268 | return dev->id; | 283 | return dev->id; |
269 | } | 284 | } |
270 | 285 | ||
@@ -272,10 +287,7 @@ static void rfcomm_dev_del(struct rfcomm_dev *dev) | |||
272 | { | 287 | { |
273 | BT_DBG("dev %p", dev); | 288 | BT_DBG("dev %p", dev); |
274 | 289 | ||
275 | write_lock_bh(&rfcomm_dev_lock); | 290 | set_bit(RFCOMM_TTY_RELEASED, &dev->flags); |
276 | list_del_init(&dev->list); | ||
277 | write_unlock_bh(&rfcomm_dev_lock); | ||
278 | |||
279 | rfcomm_dev_put(dev); | 291 | rfcomm_dev_put(dev); |
280 | } | 292 | } |
281 | 293 | ||
@@ -329,7 +341,7 @@ static int rfcomm_create_dev(struct sock *sk, void __user *arg) | |||
329 | if (copy_from_user(&req, arg, sizeof(req))) | 341 | if (copy_from_user(&req, arg, sizeof(req))) |
330 | return -EFAULT; | 342 | return -EFAULT; |
331 | 343 | ||
332 | BT_DBG("sk %p dev_id %id flags 0x%x", sk, req.dev_id, req.flags); | 344 | BT_DBG("sk %p dev_id %d flags 0x%x", sk, req.dev_id, req.flags); |
333 | 345 | ||
334 | if (req.flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN)) | 346 | if (req.flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN)) |
335 | return -EPERM; | 347 | return -EPERM; |
@@ -370,7 +382,7 @@ static int rfcomm_release_dev(void __user *arg) | |||
370 | if (copy_from_user(&req, arg, sizeof(req))) | 382 | if (copy_from_user(&req, arg, sizeof(req))) |
371 | return -EFAULT; | 383 | return -EFAULT; |
372 | 384 | ||
373 | BT_DBG("dev_id %id flags 0x%x", req.dev_id, req.flags); | 385 | BT_DBG("dev_id %d flags 0x%x", req.dev_id, req.flags); |
374 | 386 | ||
375 | if (!(dev = rfcomm_dev_get(req.dev_id))) | 387 | if (!(dev = rfcomm_dev_get(req.dev_id))) |
376 | return -ENODEV; | 388 | return -ENODEV; |
@@ -419,6 +431,8 @@ static int rfcomm_get_dev_list(void __user *arg) | |||
419 | 431 | ||
420 | list_for_each(p, &rfcomm_dev_list) { | 432 | list_for_each(p, &rfcomm_dev_list) { |
421 | struct rfcomm_dev *dev = list_entry(p, struct rfcomm_dev, list); | 433 | struct rfcomm_dev *dev = list_entry(p, struct rfcomm_dev, list); |
434 | if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) | ||
435 | continue; | ||
422 | (di + n)->id = dev->id; | 436 | (di + n)->id = dev->id; |
423 | (di + n)->flags = dev->flags; | 437 | (di + n)->flags = dev->flags; |
424 | (di + n)->state = dev->dlc->state; | 438 | (di + n)->state = dev->dlc->state; |