|
@@ -50,7 +50,6 @@ static struct tty_driver *rfcomm_tty_driver;
|
|
struct rfcomm_dev {
|
|
struct rfcomm_dev {
|
|
struct tty_port port;
|
|
struct tty_port port;
|
|
struct list_head list;
|
|
struct list_head list;
|
|
- atomic_t refcnt;
|
|
|
|
|
|
|
|
char name[12];
|
|
char name[12];
|
|
int id;
|
|
int id;
|
|
@@ -85,8 +84,17 @@ static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig);
|
|
static void rfcomm_tty_wakeup(struct work_struct *work);
|
|
static void rfcomm_tty_wakeup(struct work_struct *work);
|
|
|
|
|
|
/* ---- Device functions ---- */
|
|
/* ---- Device functions ---- */
|
|
-static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
|
|
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * The reason this isn't actually a race, as you no doubt have a little voice
|
|
|
|
+ * screaming at you in your head, is that the refcount should never actually
|
|
|
|
+ * reach zero unless the device has already been taken off the list, in
|
|
|
|
+ * rfcomm_dev_del(). And if that's not true, we'll hit the BUG() in
|
|
|
|
+ * rfcomm_dev_destruct() anyway.
|
|
|
|
+ */
|
|
|
|
+static void rfcomm_dev_destruct(struct tty_port *port)
|
|
{
|
|
{
|
|
|
|
+ struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port);
|
|
struct rfcomm_dlc *dlc = dev->dlc;
|
|
struct rfcomm_dlc *dlc = dev->dlc;
|
|
|
|
|
|
BT_DBG("dev %p dlc %p", dev, dlc);
|
|
BT_DBG("dev %p dlc %p", dev, dlc);
|
|
@@ -113,23 +121,9 @@ static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
|
|
module_put(THIS_MODULE);
|
|
module_put(THIS_MODULE);
|
|
}
|
|
}
|
|
|
|
|
|
-static inline void rfcomm_dev_hold(struct rfcomm_dev *dev)
|
|
|
|
-{
|
|
|
|
- atomic_inc(&dev->refcnt);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static inline void rfcomm_dev_put(struct rfcomm_dev *dev)
|
|
|
|
-{
|
|
|
|
- /* The reason this isn't actually a race, as you no
|
|
|
|
- doubt have a little voice screaming at you in your
|
|
|
|
- head, is that the refcount should never actually
|
|
|
|
- reach zero unless the device has already been taken
|
|
|
|
- off the list, in rfcomm_dev_del(). And if that's not
|
|
|
|
- true, we'll hit the BUG() in rfcomm_dev_destruct()
|
|
|
|
- anyway. */
|
|
|
|
- if (atomic_dec_and_test(&dev->refcnt))
|
|
|
|
- rfcomm_dev_destruct(dev);
|
|
|
|
-}
|
|
|
|
|
|
+static const struct tty_port_operations rfcomm_port_ops = {
|
|
|
|
+ .destruct = rfcomm_dev_destruct,
|
|
|
|
+};
|
|
|
|
|
|
static struct rfcomm_dev *__rfcomm_dev_get(int id)
|
|
static struct rfcomm_dev *__rfcomm_dev_get(int id)
|
|
{
|
|
{
|
|
@@ -154,7 +148,7 @@ static inline struct rfcomm_dev *rfcomm_dev_get(int id)
|
|
if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
|
|
if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
|
|
dev = NULL;
|
|
dev = NULL;
|
|
else
|
|
else
|
|
- rfcomm_dev_hold(dev);
|
|
|
|
|
|
+ tty_port_get(&dev->port);
|
|
}
|
|
}
|
|
|
|
|
|
spin_unlock(&rfcomm_dev_lock);
|
|
spin_unlock(&rfcomm_dev_lock);
|
|
@@ -241,7 +235,6 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
|
|
sprintf(dev->name, "rfcomm%d", dev->id);
|
|
sprintf(dev->name, "rfcomm%d", dev->id);
|
|
|
|
|
|
list_add(&dev->list, head);
|
|
list_add(&dev->list, head);
|
|
- atomic_set(&dev->refcnt, 1);
|
|
|
|
|
|
|
|
bacpy(&dev->src, &req->src);
|
|
bacpy(&dev->src, &req->src);
|
|
bacpy(&dev->dst, &req->dst);
|
|
bacpy(&dev->dst, &req->dst);
|
|
@@ -253,6 +246,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
|
|
atomic_set(&dev->opened, 0);
|
|
atomic_set(&dev->opened, 0);
|
|
|
|
|
|
tty_port_init(&dev->port);
|
|
tty_port_init(&dev->port);
|
|
|
|
+ dev->port.ops = &rfcomm_port_ops;
|
|
init_waitqueue_head(&dev->wait);
|
|
init_waitqueue_head(&dev->wait);
|
|
INIT_WORK(&dev->wakeup_task, rfcomm_tty_wakeup);
|
|
INIT_WORK(&dev->wakeup_task, rfcomm_tty_wakeup);
|
|
|
|
|
|
@@ -332,7 +326,7 @@ static void rfcomm_dev_del(struct rfcomm_dev *dev)
|
|
list_del_init(&dev->list);
|
|
list_del_init(&dev->list);
|
|
spin_unlock(&rfcomm_dev_lock);
|
|
spin_unlock(&rfcomm_dev_lock);
|
|
|
|
|
|
- rfcomm_dev_put(dev);
|
|
|
|
|
|
+ tty_port_put(&dev->port);
|
|
}
|
|
}
|
|
|
|
|
|
/* ---- Send buffer ---- */
|
|
/* ---- Send buffer ---- */
|
|
@@ -349,12 +343,12 @@ static void rfcomm_wfree(struct sk_buff *skb)
|
|
atomic_sub(skb->truesize, &dev->wmem_alloc);
|
|
atomic_sub(skb->truesize, &dev->wmem_alloc);
|
|
if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags))
|
|
if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags))
|
|
queue_work(system_nrt_wq, &dev->wakeup_task);
|
|
queue_work(system_nrt_wq, &dev->wakeup_task);
|
|
- rfcomm_dev_put(dev);
|
|
|
|
|
|
+ tty_port_put(&dev->port);
|
|
}
|
|
}
|
|
|
|
|
|
static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
|
|
static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
|
|
{
|
|
{
|
|
- rfcomm_dev_hold(dev);
|
|
|
|
|
|
+ tty_port_get(&dev->port);
|
|
atomic_add(skb->truesize, &dev->wmem_alloc);
|
|
atomic_add(skb->truesize, &dev->wmem_alloc);
|
|
skb->sk = (void *) dev;
|
|
skb->sk = (void *) dev;
|
|
skb->destructor = rfcomm_wfree;
|
|
skb->destructor = rfcomm_wfree;
|
|
@@ -433,7 +427,7 @@ static int rfcomm_release_dev(void __user *arg)
|
|
return -ENODEV;
|
|
return -ENODEV;
|
|
|
|
|
|
if (dev->flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN)) {
|
|
if (dev->flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN)) {
|
|
- rfcomm_dev_put(dev);
|
|
|
|
|
|
+ tty_port_put(&dev->port);
|
|
return -EPERM;
|
|
return -EPERM;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -446,7 +440,7 @@ static int rfcomm_release_dev(void __user *arg)
|
|
|
|
|
|
if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
|
|
if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
|
|
rfcomm_dev_del(dev);
|
|
rfcomm_dev_del(dev);
|
|
- rfcomm_dev_put(dev);
|
|
|
|
|
|
+ tty_port_put(&dev->port);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -524,7 +518,7 @@ static int rfcomm_get_dev_info(void __user *arg)
|
|
if (copy_to_user(arg, &di, sizeof(di)))
|
|
if (copy_to_user(arg, &di, sizeof(di)))
|
|
err = -EFAULT;
|
|
err = -EFAULT;
|
|
|
|
|
|
- rfcomm_dev_put(dev);
|
|
|
|
|
|
+ tty_port_put(&dev->port);
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -592,7 +586,7 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
|
|
* 1. rfcomm_dev_get will take rfcomm_dev_lock
|
|
* 1. rfcomm_dev_get will take rfcomm_dev_lock
|
|
* but in rfcomm_dev_add there's lock order:
|
|
* but in rfcomm_dev_add there's lock order:
|
|
* rfcomm_dev_lock -> dlc lock
|
|
* rfcomm_dev_lock -> dlc lock
|
|
- * 2. rfcomm_dev_put will deadlock if it's
|
|
|
|
|
|
+ * 2. tty_port_put will deadlock if it's
|
|
* the last reference
|
|
* the last reference
|
|
*/
|
|
*/
|
|
rfcomm_dlc_unlock(dlc);
|
|
rfcomm_dlc_unlock(dlc);
|
|
@@ -602,7 +596,7 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
|
|
}
|
|
}
|
|
|
|
|
|
rfcomm_dev_del(dev);
|
|
rfcomm_dev_del(dev);
|
|
- rfcomm_dev_put(dev);
|
|
|
|
|
|
+ tty_port_put(&dev->port);
|
|
rfcomm_dlc_lock(dlc);
|
|
rfcomm_dlc_lock(dlc);
|
|
}
|
|
}
|
|
} else
|
|
} else
|
|
@@ -771,11 +765,11 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
|
|
list_del_init(&dev->list);
|
|
list_del_init(&dev->list);
|
|
spin_unlock(&rfcomm_dev_lock);
|
|
spin_unlock(&rfcomm_dev_lock);
|
|
|
|
|
|
- rfcomm_dev_put(dev);
|
|
|
|
|
|
+ tty_port_put(&dev->port);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- rfcomm_dev_put(dev);
|
|
|
|
|
|
+ tty_port_put(&dev->port);
|
|
}
|
|
}
|
|
|
|
|
|
static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
|
|
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)
|
|
if (rfcomm_dev_get(dev->id) == NULL)
|
|
if (rfcomm_dev_get(dev->id) == NULL)
|
|
return;
|
|
return;
|
|
rfcomm_dev_del(dev);
|
|
rfcomm_dev_del(dev);
|
|
- rfcomm_dev_put(dev);
|
|
|
|
|
|
+ tty_port_put(&dev->port);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|