diff options
author | Jiri Slaby <jslaby@suse.cz> | 2012-04-02 07:54:51 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-04-09 15:04:31 -0400 |
commit | 67054019289ff11a7ffbc1a5d3c95aeb36e2f03e (patch) | |
tree | aaae7634460e55683c1688732acbeefa2064c1f6 /net | |
parent | f60db8c4246ac7c33448fad173bed85354b7d75e (diff) |
TTY: rfcomm/tty, use tty_port refcounting
Switch the refcounting from manual atomic plays with refcounter to the
one offered by tty_port.
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/rfcomm/tty.c | 58 |
1 files changed, 26 insertions, 32 deletions
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 97c2a087a9f1..da4f54515775 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c | |||
@@ -50,7 +50,6 @@ static struct tty_driver *rfcomm_tty_driver; | |||
50 | struct rfcomm_dev { | 50 | struct rfcomm_dev { |
51 | struct tty_port port; | 51 | struct tty_port port; |
52 | struct list_head list; | 52 | struct list_head list; |
53 | atomic_t refcnt; | ||
54 | 53 | ||
55 | char name[12]; | 54 | char name[12]; |
56 | int id; | 55 | int id; |
@@ -85,8 +84,17 @@ static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig); | |||
85 | static void rfcomm_tty_wakeup(struct work_struct *work); | 84 | static void rfcomm_tty_wakeup(struct work_struct *work); |
86 | 85 | ||
87 | /* ---- Device functions ---- */ | 86 | /* ---- Device functions ---- */ |
88 | static void rfcomm_dev_destruct(struct rfcomm_dev *dev) | 87 | |
88 | /* | ||
89 | * The reason this isn't actually a race, as you no doubt have a little voice | ||
90 | * screaming at you in your head, is that the refcount should never actually | ||
91 | * reach zero unless the device has already been taken off the list, in | ||
92 | * rfcomm_dev_del(). And if that's not true, we'll hit the BUG() in | ||
93 | * rfcomm_dev_destruct() anyway. | ||
94 | */ | ||
95 | static void rfcomm_dev_destruct(struct tty_port *port) | ||
89 | { | 96 | { |
97 | struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port); | ||
90 | struct rfcomm_dlc *dlc = dev->dlc; | 98 | struct rfcomm_dlc *dlc = dev->dlc; |
91 | 99 | ||
92 | BT_DBG("dev %p dlc %p", dev, dlc); | 100 | BT_DBG("dev %p dlc %p", dev, dlc); |
@@ -113,23 +121,9 @@ static void rfcomm_dev_destruct(struct rfcomm_dev *dev) | |||
113 | module_put(THIS_MODULE); | 121 | module_put(THIS_MODULE); |
114 | } | 122 | } |
115 | 123 | ||
116 | static inline void rfcomm_dev_hold(struct rfcomm_dev *dev) | 124 | static const struct tty_port_operations rfcomm_port_ops = { |
117 | { | 125 | .destruct = rfcomm_dev_destruct, |
118 | atomic_inc(&dev->refcnt); | 126 | }; |
119 | } | ||
120 | |||
121 | static inline void rfcomm_dev_put(struct rfcomm_dev *dev) | ||
122 | { | ||
123 | /* The reason this isn't actually a race, as you no | ||
124 | doubt have a little voice screaming at you in your | ||
125 | head, is that the refcount should never actually | ||
126 | reach zero unless the device has already been taken | ||
127 | off the list, in rfcomm_dev_del(). And if that's not | ||
128 | true, we'll hit the BUG() in rfcomm_dev_destruct() | ||
129 | anyway. */ | ||
130 | if (atomic_dec_and_test(&dev->refcnt)) | ||
131 | rfcomm_dev_destruct(dev); | ||
132 | } | ||
133 | 127 | ||
134 | static struct rfcomm_dev *__rfcomm_dev_get(int id) | 128 | static struct rfcomm_dev *__rfcomm_dev_get(int id) |
135 | { | 129 | { |
@@ -154,7 +148,7 @@ static inline struct rfcomm_dev *rfcomm_dev_get(int id) | |||
154 | if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) | 148 | if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) |
155 | dev = NULL; | 149 | dev = NULL; |
156 | else | 150 | else |
157 | rfcomm_dev_hold(dev); | 151 | tty_port_get(&dev->port); |
158 | } | 152 | } |
159 | 153 | ||
160 | spin_unlock(&rfcomm_dev_lock); | 154 | spin_unlock(&rfcomm_dev_lock); |
@@ -241,7 +235,6 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) | |||
241 | sprintf(dev->name, "rfcomm%d", dev->id); | 235 | sprintf(dev->name, "rfcomm%d", dev->id); |
242 | 236 | ||
243 | list_add(&dev->list, head); | 237 | list_add(&dev->list, head); |
244 | atomic_set(&dev->refcnt, 1); | ||
245 | 238 | ||
246 | bacpy(&dev->src, &req->src); | 239 | bacpy(&dev->src, &req->src); |
247 | bacpy(&dev->dst, &req->dst); | 240 | bacpy(&dev->dst, &req->dst); |
@@ -253,6 +246,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) | |||
253 | atomic_set(&dev->opened, 0); | 246 | atomic_set(&dev->opened, 0); |
254 | 247 | ||
255 | tty_port_init(&dev->port); | 248 | tty_port_init(&dev->port); |
249 | dev->port.ops = &rfcomm_port_ops; | ||
256 | init_waitqueue_head(&dev->wait); | 250 | init_waitqueue_head(&dev->wait); |
257 | INIT_WORK(&dev->wakeup_task, rfcomm_tty_wakeup); | 251 | INIT_WORK(&dev->wakeup_task, rfcomm_tty_wakeup); |
258 | 252 | ||
@@ -332,7 +326,7 @@ static void rfcomm_dev_del(struct rfcomm_dev *dev) | |||
332 | list_del_init(&dev->list); | 326 | list_del_init(&dev->list); |
333 | spin_unlock(&rfcomm_dev_lock); | 327 | spin_unlock(&rfcomm_dev_lock); |
334 | 328 | ||
335 | rfcomm_dev_put(dev); | 329 | tty_port_put(&dev->port); |
336 | } | 330 | } |
337 | 331 | ||
338 | /* ---- Send buffer ---- */ | 332 | /* ---- Send buffer ---- */ |
@@ -349,12 +343,12 @@ static void rfcomm_wfree(struct sk_buff *skb) | |||
349 | atomic_sub(skb->truesize, &dev->wmem_alloc); | 343 | atomic_sub(skb->truesize, &dev->wmem_alloc); |
350 | if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags)) | 344 | if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags)) |
351 | queue_work(system_nrt_wq, &dev->wakeup_task); | 345 | queue_work(system_nrt_wq, &dev->wakeup_task); |
352 | rfcomm_dev_put(dev); | 346 | tty_port_put(&dev->port); |
353 | } | 347 | } |
354 | 348 | ||
355 | static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev) | 349 | static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev) |
356 | { | 350 | { |
357 | rfcomm_dev_hold(dev); | 351 | tty_port_get(&dev->port); |
358 | atomic_add(skb->truesize, &dev->wmem_alloc); | 352 | atomic_add(skb->truesize, &dev->wmem_alloc); |
359 | skb->sk = (void *) dev; | 353 | skb->sk = (void *) dev; |
360 | skb->destructor = rfcomm_wfree; | 354 | skb->destructor = rfcomm_wfree; |
@@ -433,7 +427,7 @@ static int rfcomm_release_dev(void __user *arg) | |||
433 | return -ENODEV; | 427 | return -ENODEV; |
434 | 428 | ||
435 | if (dev->flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN)) { | 429 | if (dev->flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN)) { |
436 | rfcomm_dev_put(dev); | 430 | tty_port_put(&dev->port); |
437 | return -EPERM; | 431 | return -EPERM; |
438 | } | 432 | } |
439 | 433 | ||
@@ -446,7 +440,7 @@ static int rfcomm_release_dev(void __user *arg) | |||
446 | 440 | ||
447 | if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) | 441 | if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) |
448 | rfcomm_dev_del(dev); | 442 | rfcomm_dev_del(dev); |
449 | rfcomm_dev_put(dev); | 443 | tty_port_put(&dev->port); |
450 | return 0; | 444 | return 0; |
451 | } | 445 | } |
452 | 446 | ||
@@ -524,7 +518,7 @@ static int rfcomm_get_dev_info(void __user *arg) | |||
524 | if (copy_to_user(arg, &di, sizeof(di))) | 518 | if (copy_to_user(arg, &di, sizeof(di))) |
525 | err = -EFAULT; | 519 | err = -EFAULT; |
526 | 520 | ||
527 | rfcomm_dev_put(dev); | 521 | tty_port_put(&dev->port); |
528 | return err; | 522 | return err; |
529 | } | 523 | } |
530 | 524 | ||
@@ -592,7 +586,7 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err) | |||
592 | * 1. rfcomm_dev_get will take rfcomm_dev_lock | 586 | * 1. rfcomm_dev_get will take rfcomm_dev_lock |
593 | * but in rfcomm_dev_add there's lock order: | 587 | * but in rfcomm_dev_add there's lock order: |
594 | * rfcomm_dev_lock -> dlc lock | 588 | * rfcomm_dev_lock -> dlc lock |
595 | * 2. rfcomm_dev_put will deadlock if it's | 589 | * 2. tty_port_put will deadlock if it's |
596 | * the last reference | 590 | * the last reference |
597 | */ | 591 | */ |
598 | rfcomm_dlc_unlock(dlc); | 592 | rfcomm_dlc_unlock(dlc); |
@@ -602,7 +596,7 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err) | |||
602 | } | 596 | } |
603 | 597 | ||
604 | rfcomm_dev_del(dev); | 598 | rfcomm_dev_del(dev); |
605 | rfcomm_dev_put(dev); | 599 | tty_port_put(&dev->port); |
606 | rfcomm_dlc_lock(dlc); | 600 | rfcomm_dlc_lock(dlc); |
607 | } | 601 | } |
608 | } else | 602 | } else |
@@ -771,11 +765,11 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp) | |||
771 | list_del_init(&dev->list); | 765 | list_del_init(&dev->list); |
772 | spin_unlock(&rfcomm_dev_lock); | 766 | spin_unlock(&rfcomm_dev_lock); |
773 | 767 | ||
774 | rfcomm_dev_put(dev); | 768 | tty_port_put(&dev->port); |
775 | } | 769 | } |
776 | } | 770 | } |
777 | 771 | ||
778 | rfcomm_dev_put(dev); | 772 | tty_port_put(&dev->port); |
779 | } | 773 | } |
780 | 774 | ||
781 | static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) | 775 | static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) |
@@ -1084,7 +1078,7 @@ static void rfcomm_tty_hangup(struct tty_struct *tty) | |||
1084 | if (rfcomm_dev_get(dev->id) == NULL) | 1078 | if (rfcomm_dev_get(dev->id) == NULL) |
1085 | return; | 1079 | return; |
1086 | rfcomm_dev_del(dev); | 1080 | rfcomm_dev_del(dev); |
1087 | rfcomm_dev_put(dev); | 1081 | tty_port_put(&dev->port); |
1088 | } | 1082 | } |
1089 | } | 1083 | } |
1090 | 1084 | ||