* [RFC 00/22] Bluetooth: change tasklets to workqueue @ 2011-12-17 21:29 Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 01/22] Bluetooth: Process recv path in a workqueue instead of a tasklet Gustavo F. Padovan ` (2 more replies) 0 siblings, 3 replies; 34+ messages in thread From: Gustavo F. Padovan @ 2011-12-17 21:29 UTC (permalink / raw) To: linux-bluetooth; +Cc: Gustavo F. Padovan From: "Gustavo F. Padovan" <padovan@profusion.mobi> Here are the patches to run the receive path in workqueue. With these patches l2cap and rfcomm seems to be working fine, but some more work still needs to be done. Please review. Gustavo F. Padovan (21): Bluetooth: Replace spin_lock by mutex in hci_dev Bluetooth: Use delayed_work for connection timeout Bluetooth: Use delayed work for advertisiment cache timeout Bluetooth: hci_conn_auto_accept() doesn't need locking Bluetooth: Move L2CAP timers to workqueue Bluetooth: Don't use spin_lock socket lock anymore Bluetooth: Remove sk_backlog usage from L2CAP Bluetooth: move hci_task_lock to mutex Bluetooth: convert chan_lock to mutex Bluetooth: Use RCU to manipulate chan_list Bluetooth: convert conn hash to RCU Bluetooth: Don't disable tasklets to call hdev->notify() Bluetooth: Move command task to workqueue Bluetooth: convert tx_task to workqueue Bluetooth: convert info timer to delayed_work Bluetooth: remove power_on work_struct Bluetooth: invert locking order in connect path Bluetooth: Change l2cap chan_list to use RCU Bluetooth: move power_off to system workqueue Bluetooth: Use new alloc_workqueue() Bluetooth: Remove work_add and work_del from hci_sysfs Marcel Holtmann (1): Bluetooth: Process recv path in a workqueue instead of a tasklet include/net/bluetooth/hci_core.h | 75 +++++---- include/net/bluetooth/l2cap.h | 24 ++-- net/bluetooth/hci_conn.c | 48 ++---- net/bluetooth/hci_core.c | 165 ++++++++++-------- net/bluetooth/hci_event.c | 26 +-- net/bluetooth/hci_sock.c | 14 +- net/bluetooth/hci_sysfs.c | 91 ++++------ net/bluetooth/hidp/core.c | 4 +- net/bluetooth/l2cap_core.c | 345 +++++++++++++++++++------------------- net/bluetooth/l2cap_sock.c | 61 +------- net/bluetooth/mgmt.c | 108 ++++++------ net/bluetooth/sco.c | 4 +- 12 files changed, 456 insertions(+), 509 deletions(-) -- 1.7.6.4 ^ permalink raw reply [flat|nested] 34+ messages in thread
* [RFC 01/22] Bluetooth: Process recv path in a workqueue instead of a tasklet 2011-12-17 21:29 [RFC 00/22] Bluetooth: change tasklets to workqueue Gustavo F. Padovan @ 2011-12-17 21:29 ` Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 02/22] Bluetooth: Replace spin_lock by mutex in hci_dev Gustavo F. Padovan 2011-12-17 21:34 ` [RFC 00/22] Bluetooth: change tasklets " Gustavo Padovan 2011-12-17 22:17 ` Marcel Holtmann 2 siblings, 1 reply; 34+ messages in thread From: Gustavo F. Padovan @ 2011-12-17 21:29 UTC (permalink / raw) To: linux-bluetooth; +Cc: Marcel Holtmann From: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> --- include/net/bluetooth/hci_core.h | 3 ++- net/bluetooth/hci_core.c | 22 ++++++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 6a1ac2c..1e28be4 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -194,8 +194,9 @@ struct hci_dev { struct delayed_work discov_off; struct timer_list cmd_timer; + + struct work_struct rx_work; struct tasklet_struct cmd_task; - struct tasklet_struct rx_task; struct tasklet_struct tx_task; struct sk_buff_head rx_q; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 700d0ab..223809f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -56,8 +56,8 @@ int enable_hs; +static void hci_rx_work(struct work_struct *work); static void hci_cmd_task(unsigned long arg); -static void hci_rx_task(unsigned long arg); static void hci_tx_task(unsigned long arg); static DEFINE_RWLOCK(hci_task_lock); @@ -547,9 +547,9 @@ int hci_dev_open(__u16 dev) } } else { /* Init failed, cleanup */ - tasklet_kill(&hdev->rx_task); tasklet_kill(&hdev->tx_task); tasklet_kill(&hdev->cmd_task); + flush_work(&hdev->rx_work); skb_queue_purge(&hdev->cmd_q); skb_queue_purge(&hdev->rx_q); @@ -586,7 +586,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) } /* Kill RX and TX tasks */ - tasklet_kill(&hdev->rx_task); + cancel_work_sync(&hdev->rx_work); tasklet_kill(&hdev->tx_task); if (hdev->discov_timeout > 0) { @@ -617,8 +617,9 @@ static int hci_dev_do_close(struct hci_dev *hdev) clear_bit(HCI_INIT, &hdev->flags); } - /* Kill cmd task */ + /* Kill cmd task and evt work */ tasklet_kill(&hdev->cmd_task); + flush_work(&hdev->rx_work); /* Drop queues */ skb_queue_purge(&hdev->rx_q); @@ -1456,8 +1457,9 @@ int hci_register_dev(struct hci_dev *hdev) hdev->sniff_max_interval = 800; hdev->sniff_min_interval = 80; - tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev); - tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev); + INIT_WORK(&hdev->rx_work, hci_rx_work); + + tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev); tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev); skb_queue_head_init(&hdev->rx_q); @@ -1623,9 +1625,8 @@ int hci_recv_frame(struct sk_buff *skb) /* Time stamp */ __net_timestamp(skb); - /* Queue frame for rx task */ skb_queue_tail(&hdev->rx_q, skb); - tasklet_schedule(&hdev->rx_task); + queue_work(hdev->workqueue, &hdev->rx_work); return 0; } @@ -2486,9 +2487,9 @@ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb) kfree_skb(skb); } -static void hci_rx_task(unsigned long arg) +static void hci_rx_work(struct work_struct *work) { - struct hci_dev *hdev = (struct hci_dev *) arg; + struct hci_dev *hdev = container_of(work, struct hci_dev, rx_work); struct sk_buff *skb; BT_DBG("%s", hdev->name); @@ -2519,6 +2520,7 @@ static void hci_rx_task(unsigned long arg) /* Process frame */ switch (bt_cb(skb)->pkt_type) { case HCI_EVENT_PKT: + BT_DBG("%s Event packet", hdev->name); hci_event_packet(hdev, skb); break; -- 1.7.6.4 ^ permalink raw reply related [flat|nested] 34+ messages in thread
* [RFC 02/22] Bluetooth: Replace spin_lock by mutex in hci_dev 2011-12-17 21:29 ` [RFC 01/22] Bluetooth: Process recv path in a workqueue instead of a tasklet Gustavo F. Padovan @ 2011-12-17 21:29 ` Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 03/22] Bluetooth: Use delayed_work for connection timeout Gustavo F. Padovan 0 siblings, 1 reply; 34+ messages in thread From: Gustavo F. Padovan @ 2011-12-17 21:29 UTC (permalink / raw) To: linux-bluetooth; +Cc: Gustavo F. Padovan From: "Gustavo F. Padovan" <padovan@profusion.mobi> Now we run everything in HCI in process context, so it's a better idea use mutex instead spin_lock. The macro remains hci_dev_lock() (and I got rid of hci_dev_lock_bh()), of course. Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> --- include/net/bluetooth/hci_core.h | 8 +-- net/bluetooth/hci_conn.c | 12 ++-- net/bluetooth/hci_core.c | 38 +++++++------- net/bluetooth/hci_sock.c | 8 ++-- net/bluetooth/hci_sysfs.c | 20 ++++---- net/bluetooth/hidp/core.c | 4 +- net/bluetooth/l2cap_core.c | 4 +- net/bluetooth/mgmt.c | 104 +++++++++++++++++++------------------- net/bluetooth/sco.c | 4 +- 9 files changed, 100 insertions(+), 102 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 1e28be4..e7dbe59 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -117,7 +117,7 @@ struct adv_entry { #define NUM_REASSEMBLY 4 struct hci_dev { struct list_head list; - spinlock_t lock; + struct mutex lock; atomic_t refcnt; char name[8]; @@ -566,10 +566,8 @@ static inline struct hci_dev *hci_dev_hold(struct hci_dev *d) return NULL; } -#define hci_dev_lock(d) spin_lock(&d->lock) -#define hci_dev_unlock(d) spin_unlock(&d->lock) -#define hci_dev_lock_bh(d) spin_lock_bh(&d->lock) -#define hci_dev_unlock_bh(d) spin_unlock_bh(&d->lock) +#define hci_dev_lock(d) mutex_lock(&d->lock) +#define hci_dev_unlock(d) mutex_unlock(&d->lock) struct hci_dev *hci_dev_get(int index); struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 3131a99..d45783d 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -876,7 +876,7 @@ int hci_get_conn_list(void __user *arg) ci = cl->conn_info; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); list_for_each_entry(c, &hdev->conn_hash.list, list) { bacpy(&(ci + n)->bdaddr, &c->dst); (ci + n)->handle = c->handle; @@ -887,7 +887,7 @@ int hci_get_conn_list(void __user *arg) if (++n >= req.conn_num) break; } - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); cl->dev_id = hdev->id; cl->conn_num = n; @@ -911,7 +911,7 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg) if (copy_from_user(&req, arg, sizeof(req))) return -EFAULT; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); conn = hci_conn_hash_lookup_ba(hdev, req.type, &req.bdaddr); if (conn) { bacpy(&ci.bdaddr, &conn->dst); @@ -921,7 +921,7 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg) ci.state = conn->state; ci.link_mode = conn->link_mode; } - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); if (!conn) return -ENOENT; @@ -937,11 +937,11 @@ int hci_get_auth_info(struct hci_dev *hdev, void __user *arg) if (copy_from_user(&req, arg, sizeof(req))) return -EFAULT; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &req.bdaddr); if (conn) req.type = conn->auth_type; - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); if (!conn) return -ENOENT; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 223809f..279074c 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -433,14 +433,14 @@ int hci_inquiry(void __user *arg) if (!hdev) return -ENODEV; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX || inquiry_cache_empty(hdev) || ir.flags & IREQ_CACHE_FLUSH) { inquiry_cache_flush(hdev); do_inquiry = 1; } - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); timeo = ir.length * msecs_to_jiffies(2000); @@ -462,9 +462,9 @@ int hci_inquiry(void __user *arg) goto done; } - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); ir.num_rsp = inquiry_cache_dump(hdev, max_rsp, buf); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); BT_DBG("num_rsp %d", ir.num_rsp); @@ -541,9 +541,9 @@ int hci_dev_open(__u16 dev) set_bit(HCI_UP, &hdev->flags); hci_notify(hdev, HCI_DEV_UP); if (!test_bit(HCI_SETUP, &hdev->flags)) { - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); mgmt_powered(hdev, 1); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); } } else { /* Init failed, cleanup */ @@ -597,10 +597,10 @@ static int hci_dev_do_close(struct hci_dev *hdev) if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags)) cancel_delayed_work(&hdev->power_off); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); inquiry_cache_flush(hdev); hci_conn_hash_flush(hdev); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_notify(hdev, HCI_DEV_DOWN); @@ -637,9 +637,9 @@ static int hci_dev_do_close(struct hci_dev *hdev) * and no tasks are scheduled. */ hdev->close(hdev); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); mgmt_powered(hdev, 0); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); /* Clear flags */ hdev->flags = 0; @@ -682,10 +682,10 @@ int hci_dev_reset(__u16 dev) skb_queue_purge(&hdev->rx_q); skb_queue_purge(&hdev->cmd_q); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); inquiry_cache_flush(hdev); hci_conn_hash_flush(hdev); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); if (hdev->flush) hdev->flush(hdev); @@ -968,13 +968,13 @@ static void hci_discov_off(struct work_struct *work) BT_DBG("%s", hdev->name); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan); hdev->discov_timeout = 0; - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); } int hci_uuids_clear(struct hci_dev *hdev) @@ -1444,7 +1444,7 @@ int hci_register_dev(struct hci_dev *hdev) list_add_tail(&hdev->list, head); atomic_set(&hdev->refcnt, 1); - spin_lock_init(&hdev->lock); + mutex_init(&hdev->lock); hdev->flags = 0; hdev->dev_flags = 0; @@ -1559,9 +1559,9 @@ void hci_unregister_dev(struct hci_dev *hdev) if (!test_bit(HCI_INIT, &hdev->flags) && !test_bit(HCI_SETUP, &hdev->flags)) { - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); mgmt_index_removed(hdev); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); } /* mgmt_index_removed should take care of emptying the @@ -1581,13 +1581,13 @@ void hci_unregister_dev(struct hci_dev *hdev) destroy_workqueue(hdev->workqueue); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); hci_blacklist_clear(hdev); hci_uuids_clear(hdev); hci_link_keys_clear(hdev); hci_remote_oob_data_clear(hdev); hci_adv_entries_clear(hdev); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); __hci_dev_put(hdev); } diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index f6afe3d..399be34 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -188,11 +188,11 @@ static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg) if (copy_from_user(&bdaddr, arg, sizeof(bdaddr))) return -EFAULT; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); err = hci_blacklist_add(hdev, &bdaddr); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); return err; } @@ -205,11 +205,11 @@ static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg) if (copy_from_user(&bdaddr, arg, sizeof(bdaddr))) return -EFAULT; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); err = hci_blacklist_del(hdev, &bdaddr); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); return err; } diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index f8e6aa3..c3c1ec8 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -402,7 +402,7 @@ static int inquiry_cache_show(struct seq_file *f, void *p) struct inquiry_cache *cache = &hdev->inq_cache; struct inquiry_entry *e; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); for (e = cache->list; e; e = e->next) { struct inquiry_data *data = &e->data; @@ -415,7 +415,7 @@ static int inquiry_cache_show(struct seq_file *f, void *p) data->rssi, data->ssp_mode, e->timestamp); } - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); return 0; } @@ -437,12 +437,12 @@ static int blacklist_show(struct seq_file *f, void *p) struct hci_dev *hdev = f->private; struct bdaddr_list *b; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); list_for_each_entry(b, &hdev->blacklist, list) seq_printf(f, "%s\n", batostr(&b->bdaddr)); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); return 0; } @@ -481,12 +481,12 @@ static int uuids_show(struct seq_file *f, void *p) struct hci_dev *hdev = f->private; struct bt_uuid *uuid; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); list_for_each_entry(uuid, &hdev->uuids, list) print_bt_uuid(f, uuid->uuid); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); return 0; } @@ -507,11 +507,11 @@ static int auto_accept_delay_set(void *data, u64 val) { struct hci_dev *hdev = data; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); hdev->auto_accept_delay = val; - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); return 0; } @@ -520,11 +520,11 @@ static int auto_accept_delay_get(void *data, u64 *val) { struct hci_dev *hdev = data; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); *val = hdev->auto_accept_delay; - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); return 0; } diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 3c2d888..d478be1 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -795,11 +795,11 @@ static struct hci_conn *hidp_get_connection(struct hidp_session *session) if (!hdev) return NULL; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); if (conn) hci_conn_hold_device(conn); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 014fdec..0369a9b 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1171,7 +1171,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan) if (!hdev) return -EHOSTUNREACH; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); auth_type = l2cap_get_auth_type(chan); @@ -1214,7 +1214,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan) err = 0; done: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 7a23f21..ad4817c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -257,7 +257,7 @@ static int read_controller_info(struct sock *sk, u16 index) if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags)) cancel_delayed_work_sync(&hdev->power_off); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); set_bit(HCI_MGMT, &hdev->flags); @@ -286,7 +286,7 @@ static int read_controller_info(struct sock *sk, u16 index) memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name)); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp)); @@ -394,7 +394,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) return cmd_status(sk, index, MGMT_OP_SET_POWERED, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); up = test_bit(HCI_UP, &hdev->flags); if ((cp->val && up) || (!cp->val && !up)) { @@ -422,7 +422,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) err = 0; failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; } @@ -449,7 +449,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, @@ -492,7 +492,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data, hdev->discov_timeout = get_unaligned_le16(&cp->timeout); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -520,7 +520,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, @@ -557,7 +557,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -612,7 +612,7 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (cp->val) set_bit(HCI_PAIRABLE, &hdev->flags); @@ -628,7 +628,7 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data, err = mgmt_event(MGMT_EV_PAIRABLE, hdev, &ev, sizeof(ev), sk); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -827,7 +827,7 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) return cmd_status(sk, index, MGMT_OP_ADD_UUID, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC); if (!uuid) { @@ -851,7 +851,7 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -878,7 +878,7 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) { err = hci_uuids_clear(hdev); @@ -914,7 +914,7 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0); unlock: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -940,7 +940,7 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); hdev->major_class = cp->major; hdev->minor_class = cp->minor; @@ -950,7 +950,7 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, if (err == 0) err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -974,7 +974,7 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); BT_DBG("hci%u enable %d", index, cp->enable); @@ -995,7 +995,7 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data, cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, -err); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1034,7 +1034,7 @@ static int load_link_keys(struct sock *sk, u16 index, unsigned char *data, BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys, key_count); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); hci_link_keys_clear(hdev); @@ -1054,7 +1054,7 @@ static int load_link_keys(struct sock *sk, u16 index, unsigned char *data, cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return 0; @@ -1082,7 +1082,7 @@ static int remove_keys(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); memset(&rp, 0, sizeof(rp)); bacpy(&rp.bdaddr, &cp->bdaddr); @@ -1123,7 +1123,7 @@ unlock: if (err < 0) err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp, sizeof(rp)); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1151,7 +1151,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) return cmd_status(sk, index, MGMT_OP_DISCONNECT, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_DISCONNECT, @@ -1189,7 +1189,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1231,7 +1231,7 @@ static int get_connections(struct sock *sk, u16 index) return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); count = 0; list_for_each(p, &hdev->conn_hash.list) { @@ -1263,7 +1263,7 @@ static int get_connections(struct sock *sk, u16 index) unlock: kfree(rp); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; } @@ -1311,7 +1311,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, @@ -1354,7 +1354,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1380,7 +1380,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, @@ -1391,7 +1391,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data, err = send_pin_code_neg_reply(sk, index, hdev, cp); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1416,14 +1416,14 @@ static int set_io_capability(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); hdev->io_capability = cp->io_capability; BT_DBG("%s IO capability set to 0x%02x", hdev->name, hdev->io_capability); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0); @@ -1504,7 +1504,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); sec_level = BT_SECURITY_MEDIUM; if (cp->io_cap == 0x03) @@ -1561,7 +1561,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) err = 0; unlock: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1580,7 +1580,7 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr, return cmd_status(sk, index, mgmt_op, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED); @@ -1631,7 +1631,7 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr, mgmt_pending_remove(cmd); done: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1719,7 +1719,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len); if (!cmd) { @@ -1734,7 +1734,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1753,7 +1753,7 @@ static int read_local_oob_data(struct sock *sk, u16 index) return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, @@ -1784,7 +1784,7 @@ static int read_local_oob_data(struct sock *sk, u16 index) mgmt_pending_remove(cmd); unlock: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1808,7 +1808,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash, cp->randomizer); @@ -1819,7 +1819,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data, err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL, 0); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1843,7 +1843,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); err = hci_remove_remote_oob_data(hdev, &cp->bdaddr); if (err < 0) @@ -1853,7 +1853,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, NULL, 0); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1878,7 +1878,7 @@ static int start_discovery(struct sock *sk, u16 index, return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, @@ -1897,7 +1897,7 @@ static int start_discovery(struct sock *sk, u16 index, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1916,7 +1916,7 @@ static int stop_discovery(struct sock *sk, u16 index) return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0); if (!cmd) { @@ -1929,7 +1929,7 @@ static int stop_discovery(struct sock *sk, u16 index) mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1953,7 +1953,7 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); err = hci_blacklist_add(hdev, &cp->bdaddr); if (err < 0) @@ -1963,7 +1963,7 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data, err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, NULL, 0); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1987,7 +1987,7 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); err = hci_blacklist_del(hdev, &cp->bdaddr); @@ -1998,7 +1998,7 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data, err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, NULL, 0); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index a324b00..725e10d 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -189,7 +189,7 @@ static int sco_connect(struct sock *sk) if (!hdev) return -EHOSTUNREACH; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (lmp_esco_capable(hdev) && !disable_esco) type = ESCO_LINK; @@ -225,7 +225,7 @@ static int sco_connect(struct sock *sk) } done: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; } -- 1.7.6.4 ^ permalink raw reply related [flat|nested] 34+ messages in thread
* [RFC 03/22] Bluetooth: Use delayed_work for connection timeout 2011-12-17 21:29 ` [RFC 02/22] Bluetooth: Replace spin_lock by mutex in hci_dev Gustavo F. Padovan @ 2011-12-17 21:29 ` Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 04/22] Bluetooth: Use delayed work for advertisiment cache timeout Gustavo F. Padovan 0 siblings, 1 reply; 34+ messages in thread From: Gustavo F. Padovan @ 2011-12-17 21:29 UTC (permalink / raw) To: linux-bluetooth; +Cc: Gustavo F. Padovan From: "Gustavo F. Padovan" <padovan@profusion.mobi> Bluetooth rx task runs now in a workqueue, so it a good approach run any timer that share locking with process context code also in a workqueue. Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> --- include/net/bluetooth/hci_core.h | 8 +++++--- net/bluetooth/hci_conn.c | 9 +++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index e7dbe59..d915908 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -297,7 +297,7 @@ struct hci_conn { struct sk_buff_head data_q; struct list_head chan_list; - struct timer_list disc_timer; + struct delayed_work disc_work; struct timer_list idle_timer; struct timer_list auto_accept_timer; @@ -517,7 +517,7 @@ void hci_conn_put_device(struct hci_conn *conn); static inline void hci_conn_hold(struct hci_conn *conn) { atomic_inc(&conn->refcnt); - del_timer(&conn->disc_timer); + cancel_delayed_work_sync(&conn->disc_work); } static inline void hci_conn_put(struct hci_conn *conn) @@ -536,7 +536,9 @@ static inline void hci_conn_put(struct hci_conn *conn) } else { timeo = msecs_to_jiffies(10); } - mod_timer(&conn->disc_timer, jiffies + timeo); + cancel_delayed_work_sync(&conn->disc_work); + queue_delayed_work(conn->hdev->workqueue, + &conn->disc_work, jiffies + timeo); } } diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index d45783d..7d88a61 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -275,9 +275,10 @@ void hci_sco_setup(struct hci_conn *conn, __u8 status) } } -static void hci_conn_timeout(unsigned long arg) +static void hci_conn_timeout(struct work_struct *work) { - struct hci_conn *conn = (void *) arg; + struct hci_conn *conn = container_of(work, struct hci_conn, + disc_work.work); struct hci_dev *hdev = conn->hdev; __u8 reason; @@ -412,7 +413,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) INIT_LIST_HEAD(&conn->chan_list);; - setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn); + INIT_DELAYED_WORK(&conn->disc_work, hci_conn_timeout); setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn); setup_timer(&conn->auto_accept_timer, hci_conn_auto_accept, (unsigned long) conn); @@ -444,7 +445,7 @@ int hci_conn_del(struct hci_conn *conn) del_timer(&conn->idle_timer); - del_timer(&conn->disc_timer); + cancel_delayed_work_sync(&conn->disc_work); del_timer(&conn->auto_accept_timer); -- 1.7.6.4 ^ permalink raw reply related [flat|nested] 34+ messages in thread
* [RFC 04/22] Bluetooth: Use delayed work for advertisiment cache timeout 2011-12-17 21:29 ` [RFC 03/22] Bluetooth: Use delayed_work for connection timeout Gustavo F. Padovan @ 2011-12-17 21:29 ` Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 05/22] Bluetooth: hci_conn_auto_accept() doesn't need locking Gustavo F. Padovan 0 siblings, 1 reply; 34+ messages in thread From: Gustavo F. Padovan @ 2011-12-17 21:29 UTC (permalink / raw) To: linux-bluetooth; +Cc: Gustavo F. Padovan From: "Gustavo F. Padovan" <padovan@profusion.mobi> As HCI rx path is now done in process context it makes sense to do all the timer in process context as well. Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_core.c | 10 +++++----- net/bluetooth/hci_event.c | 6 ++++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index d915908..14b200b 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -226,7 +226,7 @@ struct hci_dev { struct list_head remote_oob_data; struct list_head adv_entries; - struct timer_list adv_timer; + struct delayed_work adv_work; struct hci_dev_stats stat; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 279074c..1605fe7 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1341,9 +1341,10 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr) return mgmt_device_unblocked(hdev, bdaddr); } -static void hci_clear_adv_cache(unsigned long arg) +static void hci_clear_adv_cache(struct work_struct *work) { - struct hci_dev *hdev = (void *) arg; + struct hci_dev *hdev = container_of(work, struct hci_dev, + adv_work.work); hci_dev_lock(hdev); @@ -1489,9 +1490,8 @@ int hci_register_dev(struct hci_dev *hdev) INIT_LIST_HEAD(&hdev->remote_oob_data); INIT_LIST_HEAD(&hdev->adv_entries); - setup_timer(&hdev->adv_timer, hci_clear_adv_cache, - (unsigned long) hdev); + INIT_DELAYED_WORK(&hdev->adv_work, hci_clear_adv_cache); INIT_WORK(&hdev->power_on, hci_power_on); INIT_DELAYED_WORK(&hdev->power_off, hci_power_off); @@ -1577,7 +1577,7 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_del_sysfs(hdev); - del_timer(&hdev->adv_timer); + cancel_delayed_work_sync(&hdev->adv_work); destroy_workqueue(hdev->workqueue); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 35cb56e..0a9501f 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1017,7 +1017,7 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, if (cp->enable == 0x01) { set_bit(HCI_LE_SCAN, &hdev->dev_flags); - del_timer(&hdev->adv_timer); + cancel_delayed_work_sync(&hdev->adv_work); hci_dev_lock(hdev); hci_adv_entries_clear(hdev); @@ -1025,7 +1025,9 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, } else if (cp->enable == 0x00) { clear_bit(HCI_LE_SCAN, &hdev->dev_flags); - mod_timer(&hdev->adv_timer, jiffies + ADV_CLEAR_TIMEOUT); + cancel_delayed_work_sync(&hdev->adv_work); + queue_delayed_work(hdev->workqueue, &hdev->adv_work, + jiffies + ADV_CLEAR_TIMEOUT); } } -- 1.7.6.4 ^ permalink raw reply related [flat|nested] 34+ messages in thread
* [RFC 05/22] Bluetooth: hci_conn_auto_accept() doesn't need locking 2011-12-17 21:29 ` [RFC 04/22] Bluetooth: Use delayed work for advertisiment cache timeout Gustavo F. Padovan @ 2011-12-17 21:29 ` Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 06/22] Bluetooth: Move L2CAP timers to workqueue Gustavo F. Padovan 0 siblings, 1 reply; 34+ messages in thread From: Gustavo F. Padovan @ 2011-12-17 21:29 UTC (permalink / raw) To: linux-bluetooth; +Cc: Gustavo F. Padovan From: "Gustavo F. Padovan" <padovan@profusion.mobi> It doesn't really touch any sensitive information about hdev. So no need to lock here. Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> --- net/bluetooth/hci_conn.c | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7d88a61..e6d8a22 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -362,12 +362,8 @@ static void hci_conn_auto_accept(unsigned long arg) struct hci_conn *conn = (void *) arg; struct hci_dev *hdev = conn->hdev; - hci_dev_lock(hdev); - hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, sizeof(conn->dst), &conn->dst); - - hci_dev_unlock(hdev); } struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) -- 1.7.6.4 ^ permalink raw reply related [flat|nested] 34+ messages in thread
* [RFC 06/22] Bluetooth: Move L2CAP timers to workqueue 2011-12-17 21:29 ` [RFC 05/22] Bluetooth: hci_conn_auto_accept() doesn't need locking Gustavo F. Padovan @ 2011-12-17 21:29 ` Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 07/22] Bluetooth: Don't use spin_lock socket lock anymore Gustavo F. Padovan 2011-12-19 11:05 ` [RFC 06/22] Bluetooth: Move L2CAP timers to workqueue Andrei Emeltchenko 0 siblings, 2 replies; 34+ messages in thread From: Gustavo F. Padovan @ 2011-12-17 21:29 UTC (permalink / raw) To: linux-bluetooth; +Cc: Gustavo F. Padovan From: "Gustavo F. Padovan" <padovan@profusion.mobi> L2CAP timers also need to run in process context. As the works in l2cap are small we are using the system worqueue. Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> --- include/net/bluetooth/l2cap.h | 17 +++++----- net/bluetooth/l2cap_core.c | 70 ++++++++++++++++++----------------------- 2 files changed, 40 insertions(+), 47 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 30719eb..03be911 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -482,10 +482,11 @@ struct l2cap_chan { __u32 remote_acc_lat; __u32 remote_flush_to; - struct timer_list chan_timer; - struct timer_list retrans_timer; - struct timer_list monitor_timer; - struct timer_list ack_timer; + struct delayed_work chan_timer; + struct delayed_work retrans_timer; + struct delayed_work monitor_timer; + struct delayed_work ack_timer; + struct sk_buff *tx_send_head; struct sk_buff_head tx_q; struct sk_buff_head srej_q; @@ -595,16 +596,16 @@ enum { }; #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t)) -#define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer) +#define __clear_chan_timer(c) l2cap_clear_timer(&c->chan_timer) #define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \ L2CAP_DEFAULT_RETRANS_TO); -#define __clear_retrans_timer(c) l2cap_clear_timer(c, &c->retrans_timer) +#define __clear_retrans_timer(c) l2cap_clear_timer(&c->retrans_timer) #define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \ L2CAP_DEFAULT_MONITOR_TO); -#define __clear_monitor_timer(c) l2cap_clear_timer(c, &c->monitor_timer) +#define __clear_monitor_timer(c) l2cap_clear_timer(&c->monitor_timer) #define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \ L2CAP_DEFAULT_ACK_TO); -#define __clear_ack_timer(c) l2cap_clear_timer(c, &c->ack_timer) +#define __clear_ack_timer(c) l2cap_clear_timer(&c->ack_timer) static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2) { diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 0369a9b..89cda6d 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -213,20 +213,18 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn) return 0; } -static void l2cap_set_timer(struct l2cap_chan *chan, struct timer_list *timer, long timeout) +static void l2cap_set_timer(struct l2cap_chan *chan, struct delayed_work *work, long timeout) { BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout); - if (!mod_timer(timer, jiffies + msecs_to_jiffies(timeout))) - chan_hold(chan); + cancel_delayed_work_sync(work); + + schedule_delayed_work(work, timeout); } -static void l2cap_clear_timer(struct l2cap_chan *chan, struct timer_list *timer) +static void l2cap_clear_timer(struct delayed_work *work) { - BT_DBG("chan %p state %d", chan, chan->state); - - if (timer_pending(timer) && del_timer(timer)) - chan_put(chan); + cancel_delayed_work_sync(work); } static char *state_to_string(int state) @@ -264,23 +262,16 @@ static void l2cap_state_change(struct l2cap_chan *chan, int state) chan->ops->state_change(chan->data, state); } -static void l2cap_chan_timeout(unsigned long arg) +static void l2cap_chan_timeout(struct work_struct *work) { - struct l2cap_chan *chan = (struct l2cap_chan *) arg; + struct l2cap_chan *chan = container_of(work, struct l2cap_chan, + chan_timer.work); struct sock *sk = chan->sk; int reason; BT_DBG("chan %p state %d", chan, chan->state); - bh_lock_sock(sk); - - if (sock_owned_by_user(sk)) { - /* sk is owned by user. Try again later */ - __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); - bh_unlock_sock(sk); - chan_put(chan); - return; - } + lock_sock(sk); if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG) reason = ECONNREFUSED; @@ -292,7 +283,7 @@ static void l2cap_chan_timeout(unsigned long arg) l2cap_chan_close(chan, reason); - bh_unlock_sock(sk); + release_sock(sk); chan->ops->close(chan->data); chan_put(chan); @@ -312,7 +303,7 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk) list_add(&chan->global_l, &chan_list); write_unlock_bh(&chan_list_lock); - setup_timer(&chan->chan_timer, l2cap_chan_timeout, (unsigned long) chan); + INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout); chan->state = BT_OPEN; @@ -1251,17 +1242,18 @@ int __l2cap_wait_ack(struct sock *sk) return err; } -static void l2cap_monitor_timeout(unsigned long arg) +static void l2cap_monitor_timeout(struct work_struct *work) { - struct l2cap_chan *chan = (void *) arg; + struct l2cap_chan *chan = container_of(work, struct l2cap_chan, + monitor_timer.work); struct sock *sk = chan->sk; BT_DBG("chan %p", chan); - bh_lock_sock(sk); + lock_sock(sk); if (chan->retry_count >= chan->remote_max_tx) { l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); - bh_unlock_sock(sk); + release_sock(sk); return; } @@ -1269,24 +1261,25 @@ static void l2cap_monitor_timeout(unsigned long arg) __set_monitor_timer(chan); l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); - bh_unlock_sock(sk); + release_sock(sk); } -static void l2cap_retrans_timeout(unsigned long arg) +static void l2cap_retrans_timeout(struct work_struct *work) { - struct l2cap_chan *chan = (void *) arg; + struct l2cap_chan *chan = container_of(work, struct l2cap_chan, + retrans_timer.work); struct sock *sk = chan->sk; BT_DBG("chan %p", chan); - bh_lock_sock(sk); + lock_sock(sk); chan->retry_count = 1; __set_monitor_timer(chan); set_bit(CONN_WAIT_F, &chan->conn_state); l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); - bh_unlock_sock(sk); + release_sock(sk); } static void l2cap_drop_acked_frames(struct l2cap_chan *chan) @@ -1955,13 +1948,14 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan) (unsigned long) &efs); } -static void l2cap_ack_timeout(unsigned long arg) +static void l2cap_ack_timeout(struct work_struct *work) { - struct l2cap_chan *chan = (void *) arg; + struct l2cap_chan *chan = container_of(work, struct l2cap_chan, + ack_timer.work); - bh_lock_sock(chan->sk); + lock_sock(chan->sk); l2cap_send_ack(chan); - bh_unlock_sock(chan->sk); + release_sock(chan->sk); } static inline void l2cap_ertm_init(struct l2cap_chan *chan) @@ -1974,11 +1968,9 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan) chan->num_acked = 0; chan->frames_sent = 0; - setup_timer(&chan->retrans_timer, l2cap_retrans_timeout, - (unsigned long) chan); - setup_timer(&chan->monitor_timer, l2cap_monitor_timeout, - (unsigned long) chan); - setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan); + INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout); + INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout); + INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout); skb_queue_head_init(&chan->srej_q); -- 1.7.6.4 ^ permalink raw reply related [flat|nested] 34+ messages in thread
* [RFC 07/22] Bluetooth: Don't use spin_lock socket lock anymore 2011-12-17 21:29 ` [RFC 06/22] Bluetooth: Move L2CAP timers to workqueue Gustavo F. Padovan @ 2011-12-17 21:29 ` Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 08/22] Bluetooth: Remove sk_backlog usage from L2CAP Gustavo F. Padovan 2011-12-19 9:53 ` [RFC 07/22] Bluetooth: Don't use spin_lock socket lock anymore Andrei Emeltchenko 2011-12-19 11:05 ` [RFC 06/22] Bluetooth: Move L2CAP timers to workqueue Andrei Emeltchenko 1 sibling, 2 replies; 34+ messages in thread From: Gustavo F. Padovan @ 2011-12-17 21:29 UTC (permalink / raw) To: linux-bluetooth; +Cc: Gustavo F. Padovan From: "Gustavo F. Padovan" <padovan@profusion.mobi> We now run everything in process context, so the mutex lock is the best option. But in some places we still need the bh_lock_sock() Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> --- net/bluetooth/l2cap_core.c | 66 +++++++++++++------------------------------ 1 files changed, 20 insertions(+), 46 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 89cda6d..ed67ac0 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -118,7 +118,7 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 ci read_lock(&conn->chan_lock); c = __l2cap_get_chan_by_scid(conn, cid); if (c) - bh_lock_sock(c->sk); + lock_sock(c->sk); read_unlock(&conn->chan_lock); return c; } @@ -141,7 +141,7 @@ static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn read_lock(&conn->chan_lock); c = __l2cap_get_chan_by_ident(conn, ident); if (c) - bh_lock_sock(c->sk); + lock_sock(c->sk); read_unlock(&conn->chan_lock); return c; } @@ -889,7 +889,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) parent = pchan->sk; - bh_lock_sock(parent); + lock_sock(parent); /* Check for backlog size */ if (sk_acceptq_is_full(parent)) { @@ -922,7 +922,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) write_unlock_bh(&conn->chan_lock); clean: - bh_unlock_sock(parent); + release_sock(parent); } static void l2cap_chan_ready(struct sock *sk) @@ -1024,9 +1024,9 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) /* Kill channels */ list_for_each_entry_safe(chan, l, &conn->chan_l, list) { sk = chan->sk; - bh_lock_sock(sk); + lock_sock(sk); l2cap_chan_del(chan, err); - bh_unlock_sock(sk); + release_sock(sk); chan->ops->close(chan->data); } @@ -2568,7 +2568,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd parent = pchan->sk; - bh_lock_sock(parent); + lock_sock(parent); /* Check if the ACL is secure enough (if not SDP) */ if (psm != cpu_to_le16(0x0001) && @@ -2645,7 +2645,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd write_unlock_bh(&conn->chan_lock); response: - bh_unlock_sock(parent); + release_sock(parent); sendresp: rsp.scid = cpu_to_le16(scid); @@ -2727,19 +2727,11 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd break; default: - /* don't delete l2cap channel if sk is owned by user */ - if (sock_owned_by_user(sk)) { - l2cap_state_change(chan, BT_DISCONN); - __clear_chan_timer(chan); - __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); - break; - } - l2cap_chan_del(chan, ECONNREFUSED); break; } - bh_unlock_sock(sk); + release_sock(sk); return 0; } @@ -2861,7 +2853,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr } unlock: - bh_unlock_sock(sk); + release_sock(sk); return 0; } @@ -2968,7 +2960,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr } done: - bh_unlock_sock(sk); + release_sock(sk); return 0; } @@ -2997,17 +2989,8 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd sk->sk_shutdown = SHUTDOWN_MASK; - /* don't delete l2cap channel if sk is owned by user */ - if (sock_owned_by_user(sk)) { - l2cap_state_change(chan, BT_DISCONN); - __clear_chan_timer(chan); - __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); - bh_unlock_sock(sk); - return 0; - } - l2cap_chan_del(chan, ECONNRESET); - bh_unlock_sock(sk); + release_sock(sk); chan->ops->close(chan->data); return 0; @@ -3031,17 +3014,8 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd sk = chan->sk; - /* don't delete l2cap channel if sk is owned by user */ - if (sock_owned_by_user(sk)) { - l2cap_state_change(chan, BT_DISCONN); - __clear_chan_timer(chan); - __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); - bh_unlock_sock(sk); - return 0; - } - l2cap_chan_del(chan, 0); - bh_unlock_sock(sk); + release_sock(sk); chan->ops->close(chan->data); return 0; @@ -4284,7 +4258,7 @@ drop: done: if (sk) - bh_unlock_sock(sk); + release_sock(sk); return 0; } @@ -4300,7 +4274,7 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str sk = chan->sk; - bh_lock_sock(sk); + lock_sock(sk); BT_DBG("sk %p, len %d", sk, skb->len); @@ -4318,7 +4292,7 @@ drop: done: if (sk) - bh_unlock_sock(sk); + release_sock(sk); return 0; } @@ -4333,7 +4307,7 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk = chan->sk; - bh_lock_sock(sk); + lock_sock(sk); BT_DBG("sk %p, len %d", sk, skb->len); @@ -4351,7 +4325,7 @@ drop: done: if (sk) - bh_unlock_sock(sk); + release_sock(sk); return 0; } @@ -4656,11 +4630,11 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl BT_ERR("Frame exceeding recv MTU (len %d, " "MTU %d)", len, chan->imtu); - bh_unlock_sock(sk); + release_sock(sk); l2cap_conn_unreliable(conn, ECOMM); goto drop; } - bh_unlock_sock(sk); + release_sock(sk); } /* Allocate skb for the complete frame (with header) */ -- 1.7.6.4 ^ permalink raw reply related [flat|nested] 34+ messages in thread
* [RFC 08/22] Bluetooth: Remove sk_backlog usage from L2CAP 2011-12-17 21:29 ` [RFC 07/22] Bluetooth: Don't use spin_lock socket lock anymore Gustavo F. Padovan @ 2011-12-17 21:29 ` Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 09/22] Bluetooth: move hci_task_lock to mutex Gustavo F. Padovan 2011-12-19 9:53 ` [RFC 07/22] Bluetooth: Don't use spin_lock socket lock anymore Andrei Emeltchenko 1 sibling, 1 reply; 34+ messages in thread From: Gustavo F. Padovan @ 2011-12-17 21:29 UTC (permalink / raw) To: linux-bluetooth; +Cc: Gustavo F. Padovan From: "Gustavo F. Padovan" <padovan@profusion.mobi> We run everything in the same lock now. The backlog queue is useless now Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> --- net/bluetooth/l2cap_core.c | 12 +----------- 1 files changed, 1 insertions(+), 11 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index ed67ac0..31c94fd 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1960,8 +1960,6 @@ static void l2cap_ack_timeout(struct work_struct *work) static inline void l2cap_ertm_init(struct l2cap_chan *chan) { - struct sock *sk = chan->sk; - chan->expected_ack_seq = 0; chan->unacked_frames = 0; chan->buffer_seq = 0; @@ -1975,9 +1973,6 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan) skb_queue_head_init(&chan->srej_q); INIT_LIST_HEAD(&chan->srej_l); - - - sk->sk_backlog_rcv = l2cap_ertm_data_rcv; } static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) @@ -4203,12 +4198,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk break; case L2CAP_MODE_ERTM: - if (!sock_owned_by_user(sk)) { - l2cap_ertm_data_rcv(sk, skb); - } else { - if (sk_add_backlog(sk, skb)) - goto drop; - } + l2cap_ertm_data_rcv(sk, skb); goto done; -- 1.7.6.4 ^ permalink raw reply related [flat|nested] 34+ messages in thread
* [RFC 09/22] Bluetooth: move hci_task_lock to mutex 2011-12-17 21:29 ` [RFC 08/22] Bluetooth: Remove sk_backlog usage from L2CAP Gustavo F. Padovan @ 2011-12-17 21:29 ` Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 10/22] Bluetooth: convert chan_lock " Gustavo F. Padovan 0 siblings, 1 reply; 34+ messages in thread From: Gustavo F. Padovan @ 2011-12-17 21:29 UTC (permalink / raw) To: linux-bluetooth; +Cc: Gustavo F. Padovan From: "Gustavo F. Padovan" <padovan@profusion.mobi> Now we can sleep in any path inside Bluetooth core, so mutex can make sense here. Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> --- net/bluetooth/hci_core.c | 18 +++++++++--------- 1 files changed, 9 insertions(+), 9 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 1605fe7..1f0198b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -60,7 +60,7 @@ static void hci_rx_work(struct work_struct *work); static void hci_cmd_task(unsigned long arg); static void hci_tx_task(unsigned long arg); -static DEFINE_RWLOCK(hci_task_lock); +static DEFINE_MUTEX(hci_task_lock); /* HCI device list */ LIST_HEAD(hci_dev_list); @@ -1809,14 +1809,14 @@ int hci_register_proto(struct hci_proto *hp) if (hp->id >= HCI_MAX_PROTO) return -EINVAL; - write_lock_bh(&hci_task_lock); + mutex_lock(&hci_task_lock); if (!hci_proto[hp->id]) hci_proto[hp->id] = hp; else err = -EEXIST; - write_unlock_bh(&hci_task_lock); + mutex_unlock(&hci_task_lock); return err; } @@ -1831,14 +1831,14 @@ int hci_unregister_proto(struct hci_proto *hp) if (hp->id >= HCI_MAX_PROTO) return -EINVAL; - write_lock_bh(&hci_task_lock); + mutex_lock(&hci_task_lock); if (hci_proto[hp->id]) hci_proto[hp->id] = NULL; else err = -ENOENT; - write_unlock_bh(&hci_task_lock); + mutex_unlock(&hci_task_lock); return err; } @@ -2387,7 +2387,7 @@ static void hci_tx_task(unsigned long arg) struct hci_dev *hdev = (struct hci_dev *) arg; struct sk_buff *skb; - read_lock(&hci_task_lock); + mutex_lock(&hci_task_lock); BT_DBG("%s acl %d sco %d le %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt, hdev->le_cnt); @@ -2406,7 +2406,7 @@ static void hci_tx_task(unsigned long arg) while ((skb = skb_dequeue(&hdev->raw_q))) hci_send_frame(skb); - read_unlock(&hci_task_lock); + mutex_unlock(&hci_task_lock); } /* ----- HCI RX task (incoming data processing) ----- */ @@ -2494,7 +2494,7 @@ static void hci_rx_work(struct work_struct *work) BT_DBG("%s", hdev->name); - read_lock(&hci_task_lock); + mutex_lock(&hci_task_lock); while ((skb = skb_dequeue(&hdev->rx_q))) { if (atomic_read(&hdev->promisc)) { @@ -2540,7 +2540,7 @@ static void hci_rx_work(struct work_struct *work) } } - read_unlock(&hci_task_lock); + mutex_unlock(&hci_task_lock); } static void hci_cmd_task(unsigned long arg) -- 1.7.6.4 ^ permalink raw reply related [flat|nested] 34+ messages in thread
* [RFC 10/22] Bluetooth: convert chan_lock to mutex 2011-12-17 21:29 ` [RFC 09/22] Bluetooth: move hci_task_lock to mutex Gustavo F. Padovan @ 2011-12-17 21:29 ` Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 11/22] Bluetooth: Use RCU to manipulate chan_list Gustavo F. Padovan 2011-12-19 9:58 ` [RFC 10/22] Bluetooth: convert chan_lock to mutex Andrei Emeltchenko 0 siblings, 2 replies; 34+ messages in thread From: Gustavo F. Padovan @ 2011-12-17 21:29 UTC (permalink / raw) To: linux-bluetooth; +Cc: Gustavo F. Padovan From: "Gustavo F. Padovan" <padovan@profusion.mobi> spin lock doesn't fit ok anymore on the new code based on workqueues. Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> --- include/net/bluetooth/l2cap.h | 2 +- net/bluetooth/l2cap_core.c | 52 ++++++++++++++++++++-------------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 03be911..a175091 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -536,7 +536,7 @@ struct l2cap_conn { struct smp_chan *smp_chan; struct list_head chan_l; - rwlock_t chan_lock; + struct mutex chan_lock; }; #define L2CAP_INFO_CL_MTU_REQ_SENT 0x01 diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 31c94fd..5c5948f 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -115,11 +115,11 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 ci { struct l2cap_chan *c; - read_lock(&conn->chan_lock); + mutex_lock(&conn->chan_lock); c = __l2cap_get_chan_by_scid(conn, cid); if (c) lock_sock(c->sk); - read_unlock(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); return c; } @@ -138,11 +138,11 @@ static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn { struct l2cap_chan *c; - read_lock(&conn->chan_lock); + mutex_lock(&conn->chan_lock); c = __l2cap_get_chan_by_ident(conn, ident); if (c) lock_sock(c->sk); - read_unlock(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); return c; } @@ -381,9 +381,9 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) if (conn) { /* Delete from channel list */ - write_lock_bh(&conn->chan_lock); + mutex_lock(&conn->chan_lock); list_del(&chan->list); - write_unlock_bh(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); chan_put(chan); chan->conn = NULL; @@ -754,7 +754,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) BT_DBG("conn %p", conn); - read_lock(&conn->chan_lock); + mutex_lock(&conn->chan_lock); list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { struct sock *sk = chan->sk; @@ -780,9 +780,9 @@ static void l2cap_conn_start(struct l2cap_conn *conn) &chan->conf_state)) { /* l2cap_chan_close() calls list_del(chan) * so release the lock */ - read_unlock(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); l2cap_chan_close(chan, ECONNRESET); - read_lock(&conn->chan_lock); + utex_lock(&conn->chan_lock); bh_unlock_sock(sk); continue; } @@ -838,7 +838,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) bh_unlock_sock(sk); } - read_unlock(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); } /* Find socket with cid and source bdaddr. @@ -903,7 +903,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) sk = chan->sk; - write_lock_bh(&conn->chan_lock); + mutex_lock(&conn->chan_lock); hci_conn_hold(conn->hcon); @@ -919,7 +919,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) l2cap_state_change(chan, BT_CONNECTED); parent->sk_data_ready(parent, 0); - write_unlock_bh(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); clean: release_sock(parent); @@ -954,7 +954,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) if (conn->hcon->out && conn->hcon->type == LE_LINK) smp_conn_security(conn, conn->hcon->pending_sec_level); - read_lock(&conn->chan_lock); + mutex_lock(&conn->chan_lock); list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; @@ -976,7 +976,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) bh_unlock_sock(sk); } - read_unlock(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); } /* Notify sockets that we cannot guaranty reliability anymore */ @@ -986,7 +986,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) BT_DBG("conn %p", conn); - read_lock(&conn->chan_lock); + mutex_lock(&conn->chan_lock); list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; @@ -995,7 +995,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) sk->sk_err = err; } - read_unlock(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); } static void l2cap_info_timeout(unsigned long arg) @@ -1086,7 +1086,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) conn->feat_mask = 0; spin_lock_init(&conn->lock); - rwlock_init(&conn->chan_lock); + mutex_init(&conn->chan_lock); INIT_LIST_HEAD(&conn->chan_l); @@ -1104,9 +1104,9 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { - write_lock_bh(&conn->chan_lock); + mutex_lock(&conn->chan_lock); __l2cap_chan_add(conn, chan); - write_unlock_bh(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); } /* ---- Socket interface ---- */ @@ -1771,7 +1771,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p", conn); - read_lock(&conn->chan_lock); + mutex_lock(&conn->chan_lock); list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; if (chan->chan_type != L2CAP_CHAN_RAW) @@ -1787,7 +1787,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) if (chan->ops->recv(chan->data, nskb)) kfree_skb(nskb); } - read_unlock(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); } /* ---- L2CAP signalling commands ---- */ @@ -2587,11 +2587,11 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd sk = chan->sk; - write_lock_bh(&conn->chan_lock); + mutex_lock(&conn->chan_lock); /* Check if we already have channel with that dcid */ if (__l2cap_get_chan_by_dcid(conn, scid)) { - write_unlock_bh(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); sock_set_flag(sk, SOCK_ZAPPED); chan->ops->close(chan->data); goto response; @@ -2637,7 +2637,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd status = L2CAP_CS_NO_INFO; } - write_unlock_bh(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); response: release_sock(parent); @@ -4474,7 +4474,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) del_timer(&conn->security_timer); } - read_lock(&conn->chan_lock); + mutex_lock(&conn->chan_lock); list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; @@ -4554,7 +4554,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) bh_unlock_sock(sk); } - read_unlock(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); return 0; } -- 1.7.6.4 ^ permalink raw reply related [flat|nested] 34+ messages in thread
* [RFC 11/22] Bluetooth: Use RCU to manipulate chan_list 2011-12-17 21:29 ` [RFC 10/22] Bluetooth: convert chan_lock " Gustavo F. Padovan @ 2011-12-17 21:29 ` Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 12/22] Bluetooth: convert conn hash to RCU Gustavo F. Padovan 2012-01-26 13:20 ` [RFC 11/22] Bluetooth: Use RCU to manipulate chan_list Andrei Emeltchenko 2011-12-19 9:58 ` [RFC 10/22] Bluetooth: convert chan_lock to mutex Andrei Emeltchenko 1 sibling, 2 replies; 34+ messages in thread From: Gustavo F. Padovan @ 2011-12-17 21:29 UTC (permalink / raw) To: linux-bluetooth; +Cc: Gustavo F. Padovan From: "Gustavo F. Padovan" <padovan@profusion.mobi> Instead of using tasklet_disable() to prevent acess to the channel use, we can use RCU and improve the performance of our code. Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> --- net/bluetooth/hci_conn.c | 14 ++++++-------- net/bluetooth/hci_core.c | 12 ++++++++++-- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index e6d8a22..b044676 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -960,9 +960,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn) chan->conn = conn; skb_queue_head_init(&chan->data_q); - tasklet_disable(&hdev->tx_task); - list_add(&conn->chan_list, &chan->list); - tasklet_enable(&hdev->tx_task); + list_add_rcu(&chan->list, &conn->chan_list); return chan; } @@ -974,9 +972,9 @@ int hci_chan_del(struct hci_chan *chan) BT_DBG("%s conn %p chan %p", hdev->name, conn, chan); - tasklet_disable(&hdev->tx_task); - list_del(&chan->list); - tasklet_enable(&hdev->tx_task); + list_del_rcu(&chan->list); + + synchronize_rcu(); skb_queue_purge(&chan->data_q); kfree(chan); @@ -986,10 +984,10 @@ int hci_chan_del(struct hci_chan *chan) void hci_chan_list_flush(struct hci_conn *conn) { - struct hci_chan *chan, *tmp; + struct hci_chan *chan; BT_DBG("conn %p", conn); - list_for_each_entry_safe(chan, tmp, &conn->chan_list, list) + list_for_each_entry_rcu(chan, &conn->chan_list, list) hci_chan_del(chan); } diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 1f0198b..f016a40 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2136,7 +2136,9 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, conn_num++; - list_for_each_entry(tmp, &conn->chan_list, list) { + rcu_read_lock(); + + list_for_each_entry_rcu(tmp, &conn->chan_list, list) { struct sk_buff *skb; if (skb_queue_empty(&tmp->data_q)) @@ -2160,6 +2162,8 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, } } + rcu_read_unlock(); + if (hci_conn_num(hdev, type) == conn_num) break; } @@ -2208,7 +2212,9 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type) num++; - list_for_each_entry(chan, &conn->chan_list, list) { + rcu_read_lock(); + + list_for_each_entry_rcu(chan, &conn->chan_list, list) { struct sk_buff *skb; if (chan->sent) { @@ -2229,6 +2235,8 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type) skb->priority); } + rcu_read_unlock(); + if (hci_conn_num(hdev, type) == num) break; } -- 1.7.6.4 ^ permalink raw reply related [flat|nested] 34+ messages in thread
* [RFC 12/22] Bluetooth: convert conn hash to RCU 2011-12-17 21:29 ` [RFC 11/22] Bluetooth: Use RCU to manipulate chan_list Gustavo F. Padovan @ 2011-12-17 21:29 ` Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 13/22] Bluetooth: Don't disable tasklets to call hdev->notify() Gustavo F. Padovan 2012-01-26 13:20 ` [RFC 11/22] Bluetooth: Use RCU to manipulate chan_list Andrei Emeltchenko 1 sibling, 1 reply; 34+ messages in thread From: Gustavo F. Padovan @ 2011-12-17 21:29 UTC (permalink / raw) To: linux-bluetooth; +Cc: Gustavo F. Padovan From: "Gustavo F. Padovan" <padovan@profusion.mobi> Handling hci_conn_hash with RCU make us avoid some locking and disable tasklets. Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> --- include/net/bluetooth/hci_core.h | 45 ++++++++++++++++++++++++++----------- net/bluetooth/hci_conn.c | 19 +++++++-------- net/bluetooth/hci_core.c | 34 ++++++++++++++++++---------- 3 files changed, 62 insertions(+), 36 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 14b200b..e832433 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -392,7 +392,7 @@ static inline void hci_conn_hash_init(struct hci_dev *hdev) static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) { struct hci_conn_hash *h = &hdev->conn_hash; - list_add(&c->list, &h->list); + list_add_rcu(&c->list, &h->list); switch (c->type) { case ACL_LINK: h->acl_num++; @@ -410,7 +410,10 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c) { struct hci_conn_hash *h = &hdev->conn_hash; - list_del(&c->list); + + list_del_rcu(&c->list); + synchronize_rcu(); + switch (c->type) { case ACL_LINK: h->acl_num--; @@ -445,14 +448,18 @@ static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev, __u16 handle) { struct hci_conn_hash *h = &hdev->conn_hash; - struct list_head *p; struct hci_conn *c; - list_for_each(p, &h->list) { - c = list_entry(p, struct hci_conn, list); - if (c->handle == handle) + rcu_read_lock(); + + list_for_each_entry_rcu(c, &h->list, list) { + if (c->handle == handle) { + rcu_read_unlock(); return c; + } } + rcu_read_unlock(); + return NULL; } @@ -460,14 +467,19 @@ static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev, __u8 type, bdaddr_t *ba) { struct hci_conn_hash *h = &hdev->conn_hash; - struct list_head *p; struct hci_conn *c; - list_for_each(p, &h->list) { - c = list_entry(p, struct hci_conn, list); - if (c->type == type && !bacmp(&c->dst, ba)) + rcu_read_lock(); + + list_for_each_entry_rcu(c, &h->list, list) { + if (c->type == type && !bacmp(&c->dst, ba)) { + rcu_read_unlock(); return c; + } } + + rcu_read_unlock(); + return NULL; } @@ -475,14 +487,19 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev, __u8 type, __u16 state) { struct hci_conn_hash *h = &hdev->conn_hash; - struct list_head *p; struct hci_conn *c; - list_for_each(p, &h->list) { - c = list_entry(p, struct hci_conn, list); - if (c->type == type && c->state == state) + rcu_read_lock(); + + list_for_each_entry_rcu(c, &h->list, list) { + if (c->type == type && c->state == state) { + rcu_read_unlock(); return c; + } } + + rcu_read_unlock(); + return NULL; } diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index b044676..5e9e193 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -418,18 +418,17 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) hci_dev_hold(hdev); - tasklet_disable(&hdev->tx_task); - hci_conn_hash_add(hdev, conn); - if (hdev->notify) + if (hdev->notify) { + tasklet_disable(&hdev->tx_task); hdev->notify(hdev, HCI_NOTIFY_CONN_ADD); + tasklet_enable(&hdev->tx_task); + } atomic_set(&conn->devref, 0); hci_conn_init_sysfs(conn); - tasklet_enable(&hdev->tx_task); - return conn; } @@ -465,15 +464,15 @@ int hci_conn_del(struct hci_conn *conn) } } - tasklet_disable(&hdev->tx_task); hci_chan_list_flush(conn); hci_conn_hash_del(hdev, conn); - if (hdev->notify) + if (hdev->notify) { + tasklet_disable(&hdev->tx_task); hdev->notify(hdev, HCI_NOTIFY_CONN_DEL); - - tasklet_enable(&hdev->tx_task); + tasklet_enable(&hdev->tx_task); + } skb_queue_purge(&conn->data_q); @@ -808,7 +807,7 @@ void hci_conn_hash_flush(struct hci_dev *hdev) BT_DBG("hdev %s", hdev->name); - list_for_each_entry(c, &h->list, list) { + list_for_each_entry_rcu(c, &h->list, list) { c->state = BT_CLOSED; hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f016a40..7654777 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2051,7 +2051,10 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int /* We don't have to lock device here. Connections are always * added and removed with TX task disabled. */ - list_for_each_entry(c, &h->list, list) { + + rcu_read_lock(); + + list_for_each_entry_rcu(c, &h->list, list) { if (c->type != type || skb_queue_empty(&c->data_q)) continue; @@ -2069,6 +2072,8 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int break; } + rcu_read_unlock(); + if (conn) { int cnt, q; @@ -2104,14 +2109,18 @@ static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type) BT_ERR("%s link tx timeout", hdev->name); + rcu_read_lock(); + /* Kill stalled connections */ - list_for_each_entry(c, &h->list, list) { + list_for_each_entry_rcu(c, &h->list, list) { if (c->type == type && c->sent) { BT_ERR("%s killing stalled connection %s", hdev->name, batostr(&c->dst)); hci_acl_disconn(c, 0x13); } } + + rcu_read_unlock(); } static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, @@ -2125,7 +2134,9 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, BT_DBG("%s", hdev->name); - list_for_each_entry(conn, &h->list, list) { + rcu_read_lock(); + + list_for_each_entry_rcu(conn, &h->list, list) { struct hci_chan *tmp; if (conn->type != type) @@ -2136,8 +2147,6 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, conn_num++; - rcu_read_lock(); - list_for_each_entry_rcu(tmp, &conn->chan_list, list) { struct sk_buff *skb; @@ -2162,12 +2171,12 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, } } - rcu_read_unlock(); - if (hci_conn_num(hdev, type) == conn_num) break; } + rcu_read_unlock(); + if (!chan) return NULL; @@ -2201,7 +2210,9 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type) BT_DBG("%s", hdev->name); - list_for_each_entry(conn, &h->list, list) { + rcu_read_lock(); + + list_for_each_entry_rcu(conn, &h->list, list) { struct hci_chan *chan; if (conn->type != type) @@ -2212,8 +2223,6 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type) num++; - rcu_read_lock(); - list_for_each_entry_rcu(chan, &conn->chan_list, list) { struct sk_buff *skb; @@ -2235,11 +2244,12 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type) skb->priority); } - rcu_read_unlock(); - if (hci_conn_num(hdev, type) == num) break; } + + rcu_read_unlock(); + } static inline void hci_sched_acl(struct hci_dev *hdev) -- 1.7.6.4 ^ permalink raw reply related [flat|nested] 34+ messages in thread
* [RFC 13/22] Bluetooth: Don't disable tasklets to call hdev->notify() 2011-12-17 21:29 ` [RFC 12/22] Bluetooth: convert conn hash to RCU Gustavo F. Padovan @ 2011-12-17 21:29 ` Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 14/22] Bluetooth: Move command task to workqueue Gustavo F. Padovan 0 siblings, 1 reply; 34+ messages in thread From: Gustavo F. Padovan @ 2011-12-17 21:29 UTC (permalink / raw) To: linux-bluetooth; +Cc: Gustavo F. Padovan From: "Gustavo F. Padovan" <padovan@profusion.mobi> It's pointless, we aren't protecting anything since btusb_notify() schedules a work to run, then all it operation happens without protection. If protection is really needed here, we will fix it further. Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> --- net/bluetooth/hci_conn.c | 10 ++-------- net/bluetooth/hci_event.c | 10 ++-------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 5e9e193..385cccb 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -419,11 +419,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) hci_dev_hold(hdev); hci_conn_hash_add(hdev, conn); - if (hdev->notify) { - tasklet_disable(&hdev->tx_task); + if (hdev->notify) hdev->notify(hdev, HCI_NOTIFY_CONN_ADD); - tasklet_enable(&hdev->tx_task); - } atomic_set(&conn->devref, 0); @@ -468,11 +465,8 @@ int hci_conn_del(struct hci_conn *conn) hci_chan_list_flush(conn); hci_conn_hash_del(hdev, conn); - if (hdev->notify) { - tasklet_disable(&hdev->tx_task); + if (hdev->notify) hdev->notify(hdev, HCI_NOTIFY_CONN_DEL); - tasklet_enable(&hdev->tx_task); - } skb_queue_purge(&conn->data_q); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 0a9501f..93ecb2d 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -378,11 +378,8 @@ static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s voice setting 0x%04x", hdev->name, setting); - if (hdev->notify) { - tasklet_disable(&hdev->tx_task); + if (hdev->notify) hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING); - tasklet_enable(&hdev->tx_task); - } } static void hci_cc_write_voice_setting(struct hci_dev *hdev, struct sk_buff *skb) @@ -409,11 +406,8 @@ static void hci_cc_write_voice_setting(struct hci_dev *hdev, struct sk_buff *skb BT_DBG("%s voice setting 0x%04x", hdev->name, setting); - if (hdev->notify) { - tasklet_disable(&hdev->tx_task); + if (hdev->notify) hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING); - tasklet_enable(&hdev->tx_task); - } } static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb) -- 1.7.6.4 ^ permalink raw reply related [flat|nested] 34+ messages in thread
* [RFC 14/22] Bluetooth: Move command task to workqueue 2011-12-17 21:29 ` [RFC 13/22] Bluetooth: Don't disable tasklets to call hdev->notify() Gustavo F. Padovan @ 2011-12-17 21:29 ` Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 15/22] Bluetooth: convert tx_task " Gustavo F. Padovan 0 siblings, 1 reply; 34+ messages in thread From: Gustavo F. Padovan @ 2011-12-17 21:29 UTC (permalink / raw) To: linux-bluetooth; +Cc: Gustavo F. Padovan From: "Gustavo F. Padovan" <padovan@profusion.mobi> As part of the moving on all the Bluetooth processing to Process context. Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_core.c | 22 +++++++++++----------- net/bluetooth/hci_event.c | 4 ++-- net/bluetooth/hci_sock.c | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index e832433..051fd7f 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -196,7 +196,7 @@ struct hci_dev { struct timer_list cmd_timer; struct work_struct rx_work; - struct tasklet_struct cmd_task; + struct work_struct cmd_work; struct tasklet_struct tx_task; struct sk_buff_head rx_q; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 7654777..405319e 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -57,7 +57,7 @@ int enable_hs; static void hci_rx_work(struct work_struct *work); -static void hci_cmd_task(unsigned long arg); +static void hci_cmd_work(struct work_struct *work); static void hci_tx_task(unsigned long arg); static DEFINE_MUTEX(hci_task_lock); @@ -209,7 +209,7 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) skb->dev = (void *) hdev; skb_queue_tail(&hdev->cmd_q, skb); - tasklet_schedule(&hdev->cmd_task); + queue_work(hdev->workqueue, &hdev->cmd_work); } skb_queue_purge(&hdev->driver_init); @@ -548,7 +548,7 @@ int hci_dev_open(__u16 dev) } else { /* Init failed, cleanup */ tasklet_kill(&hdev->tx_task); - tasklet_kill(&hdev->cmd_task); + flush_work(&hdev->cmd_work); flush_work(&hdev->rx_work); skb_queue_purge(&hdev->cmd_q); @@ -617,8 +617,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) clear_bit(HCI_INIT, &hdev->flags); } - /* Kill cmd task and evt work */ - tasklet_kill(&hdev->cmd_task); + /* flush cmd and rx work */ + flush_work(&hdev->cmd_work); flush_work(&hdev->rx_work); /* Drop queues */ @@ -1208,7 +1208,7 @@ static void hci_cmd_timer(unsigned long arg) BT_ERR("%s command tx timeout", hdev->name); atomic_set(&hdev->cmd_cnt, 1); - tasklet_schedule(&hdev->cmd_task); + queue_work(hdev->workqueue, &hdev->cmd_work); } struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev, @@ -1459,8 +1459,8 @@ int hci_register_dev(struct hci_dev *hdev) hdev->sniff_min_interval = 80; INIT_WORK(&hdev->rx_work, hci_rx_work); + INIT_WORK(&hdev->cmd_work, hci_cmd_work); - tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev); tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev); skb_queue_head_init(&hdev->rx_q); @@ -1923,7 +1923,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param) hdev->init_last_cmd = opcode; skb_queue_tail(&hdev->cmd_q, skb); - tasklet_schedule(&hdev->cmd_task); + queue_work(hdev->workqueue, &hdev->cmd_work); return 0; } @@ -2561,9 +2561,9 @@ static void hci_rx_work(struct work_struct *work) mutex_unlock(&hci_task_lock); } -static void hci_cmd_task(unsigned long arg) +static void hci_cmd_work(struct work_struct *work) { - struct hci_dev *hdev = (struct hci_dev *) arg; + struct hci_dev *hdev = container_of(work, struct hci_dev, cmd_work); struct sk_buff *skb; BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt)); @@ -2587,7 +2587,7 @@ static void hci_cmd_task(unsigned long arg) jiffies + msecs_to_jiffies(HCI_CMD_TIMEOUT)); } else { skb_queue_head(&hdev->cmd_q, skb); - tasklet_schedule(&hdev->cmd_task); + queue_work(hdev->workqueue, &hdev->cmd_work); } } } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 93ecb2d..23466bb 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2112,7 +2112,7 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk if (ev->ncmd) { atomic_set(&hdev->cmd_cnt, 1); if (!skb_queue_empty(&hdev->cmd_q)) - tasklet_schedule(&hdev->cmd_task); + queue_work(hdev->workqueue, &hdev->cmd_work); } } @@ -2194,7 +2194,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) { atomic_set(&hdev->cmd_cnt, 1); if (!skb_queue_empty(&hdev->cmd_q)) - tasklet_schedule(&hdev->cmd_task); + queue_work(hdev->workqueue, &hdev->cmd_work); } } diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 399be34..d10a724 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -538,7 +538,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, tasklet_schedule(&hdev->tx_task); } else { skb_queue_tail(&hdev->cmd_q, skb); - tasklet_schedule(&hdev->cmd_task); + queue_work(hdev->workqueue, &hdev->cmd_work); } } else { if (!capable(CAP_NET_RAW)) { -- 1.7.6.4 ^ permalink raw reply related [flat|nested] 34+ messages in thread
* [RFC 15/22] Bluetooth: convert tx_task to workqueue 2011-12-17 21:29 ` [RFC 14/22] Bluetooth: Move command task to workqueue Gustavo F. Padovan @ 2011-12-17 21:29 ` Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 16/22] Bluetooth: convert info timer to delayed_work Gustavo F. Padovan 0 siblings, 1 reply; 34+ messages in thread From: Gustavo F. Padovan @ 2011-12-17 21:29 UTC (permalink / raw) To: linux-bluetooth; +Cc: Gustavo F. Padovan From: "Gustavo F. Padovan" <padovan@profusion.mobi> This should simplify Bluetooth core processing a lot. Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_core.c | 18 ++++++++---------- net/bluetooth/hci_event.c | 6 +----- net/bluetooth/hci_sock.c | 4 ++-- 4 files changed, 12 insertions(+), 18 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 051fd7f..5d1bb51 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -197,7 +197,7 @@ struct hci_dev { struct work_struct rx_work; struct work_struct cmd_work; - struct tasklet_struct tx_task; + struct work_struct tx_work; struct sk_buff_head rx_q; struct sk_buff_head raw_q; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 405319e..fbc7968 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -58,7 +58,7 @@ int enable_hs; static void hci_rx_work(struct work_struct *work); static void hci_cmd_work(struct work_struct *work); -static void hci_tx_task(unsigned long arg); +static void hci_tx_work(struct work_struct *work); static DEFINE_MUTEX(hci_task_lock); @@ -547,7 +547,7 @@ int hci_dev_open(__u16 dev) } } else { /* Init failed, cleanup */ - tasklet_kill(&hdev->tx_task); + flush_work(&hdev->tx_work); flush_work(&hdev->cmd_work); flush_work(&hdev->rx_work); @@ -587,7 +587,6 @@ static int hci_dev_do_close(struct hci_dev *hdev) /* Kill RX and TX tasks */ cancel_work_sync(&hdev->rx_work); - tasklet_kill(&hdev->tx_task); if (hdev->discov_timeout > 0) { cancel_delayed_work(&hdev->discov_off); @@ -620,6 +619,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) /* flush cmd and rx work */ flush_work(&hdev->cmd_work); flush_work(&hdev->rx_work); + flush_work(&hdev->tx_work); /* Drop queues */ skb_queue_purge(&hdev->rx_q); @@ -673,7 +673,6 @@ int hci_dev_reset(__u16 dev) return -ENODEV; hci_req_lock(hdev); - tasklet_disable(&hdev->tx_task); if (!test_bit(HCI_UP, &hdev->flags)) goto done; @@ -698,7 +697,6 @@ int hci_dev_reset(__u16 dev) msecs_to_jiffies(HCI_INIT_TIMEOUT)); done: - tasklet_enable(&hdev->tx_task); hci_req_unlock(hdev); hci_dev_put(hdev); return ret; @@ -1460,8 +1458,8 @@ int hci_register_dev(struct hci_dev *hdev) INIT_WORK(&hdev->rx_work, hci_rx_work); INIT_WORK(&hdev->cmd_work, hci_cmd_work); + INIT_WORK(&hdev->tx_work, hci_tx_work); - tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev); skb_queue_head_init(&hdev->rx_q); skb_queue_head_init(&hdev->cmd_q); @@ -2013,7 +2011,7 @@ void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags) hci_queue_acl(conn, &chan->data_q, skb, flags); - tasklet_schedule(&hdev->tx_task); + queue_work(hdev->workqueue, &hdev->tx_work); } EXPORT_SYMBOL(hci_send_acl); @@ -2036,7 +2034,7 @@ void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb) bt_cb(skb)->pkt_type = HCI_SCODATA_PKT; skb_queue_tail(&conn->data_q, skb); - tasklet_schedule(&hdev->tx_task); + queue_work(hdev->workqueue, &hdev->tx_work); } EXPORT_SYMBOL(hci_send_sco); @@ -2400,9 +2398,9 @@ static inline void hci_sched_le(struct hci_dev *hdev) hci_prio_recalculate(hdev, LE_LINK); } -static void hci_tx_task(unsigned long arg) +static void hci_tx_work(struct work_struct *work) { - struct hci_dev *hdev = (struct hci_dev *) arg; + struct hci_dev *hdev = container_of(work, struct hci_dev, tx_work); struct sk_buff *skb; mutex_lock(&hci_task_lock); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 23466bb..74f7583 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2239,8 +2239,6 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s return; } - tasklet_disable(&hdev->tx_task); - for (i = 0, ptr = (__le16 *) skb->data; i < ev->num_hndl; i++) { struct hci_conn *conn; __u16 handle, count; @@ -2274,9 +2272,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s } } - tasklet_schedule(&hdev->tx_task); - - tasklet_enable(&hdev->tx_task); + queue_work(hdev->workqueue, &hdev->tx_work); } static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb) diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index d10a724..cd06406 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -535,7 +535,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, if (test_bit(HCI_RAW, &hdev->flags) || (ogf == 0x3f)) { skb_queue_tail(&hdev->raw_q, skb); - tasklet_schedule(&hdev->tx_task); + queue_work(hdev->workqueue, &hdev->tx_work); } else { skb_queue_tail(&hdev->cmd_q, skb); queue_work(hdev->workqueue, &hdev->cmd_work); @@ -547,7 +547,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, } skb_queue_tail(&hdev->raw_q, skb); - tasklet_schedule(&hdev->tx_task); + queue_work(hdev->workqueue, &hdev->tx_work); } err = len; -- 1.7.6.4 ^ permalink raw reply related [flat|nested] 34+ messages in thread
* [RFC 16/22] Bluetooth: convert info timer to delayed_work 2011-12-17 21:29 ` [RFC 15/22] Bluetooth: convert tx_task " Gustavo F. Padovan @ 2011-12-17 21:29 ` Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 17/22] Bluetooth: remove power_on work_struct Gustavo F. Padovan 0 siblings, 1 reply; 34+ messages in thread From: Gustavo F. Padovan @ 2011-12-17 21:29 UTC (permalink / raw) To: linux-bluetooth; +Cc: Gustavo F. Padovan From: "Gustavo F. Padovan" <padovan@profusion.mobi> Another step of remove interrupt context from Bluetooth Core. Use the system workqueue. Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> --- include/net/bluetooth/l2cap.h | 2 +- net/bluetooth/l2cap_core.c | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index a175091..f791374 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -522,7 +522,7 @@ struct l2cap_conn { __u8 info_state; __u8 info_ident; - struct timer_list info_timer; + struct delayed_work info_work; spinlock_t lock; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 5c5948f..a78cdf7 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -698,7 +698,7 @@ static void l2cap_do_start(struct l2cap_chan *chan) conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; conn->info_ident = l2cap_get_ident(conn); - mod_timer(&conn->info_timer, jiffies + + schedule_delayed_work(&conn->info_work, msecs_to_jiffies(L2CAP_INFO_TIMEOUT)); l2cap_send_cmd(conn, conn->info_ident, @@ -998,9 +998,10 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) mutex_unlock(&conn->chan_lock); } -static void l2cap_info_timeout(unsigned long arg) +static void l2cap_info_timeout(struct work_struct *work) { - struct l2cap_conn *conn = (void *) arg; + struct l2cap_conn *conn = container_of(work, struct l2cap_conn, + info_work.work); conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; conn->info_ident = 0; @@ -1033,7 +1034,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) hci_chan_del(conn->hchan); if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) - del_timer_sync(&conn->info_timer); + cancel_delayed_work_sync(&conn->info_work); if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) { del_timer(&conn->security_timer); @@ -1094,8 +1095,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) setup_timer(&conn->security_timer, security_timeout, (unsigned long) conn); else - setup_timer(&conn->info_timer, l2cap_info_timeout, - (unsigned long) conn); + INIT_DELAYED_WORK(&conn->info_work, l2cap_info_timeout); conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM; @@ -2530,7 +2530,7 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) && cmd->ident == conn->info_ident) { - del_timer(&conn->info_timer); + cancel_delayed_work_sync(&conn->info_work); conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; conn->info_ident = 0; @@ -2656,7 +2656,7 @@ sendresp: conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; conn->info_ident = l2cap_get_ident(conn); - mod_timer(&conn->info_timer, jiffies + + schedule_delayed_work(&conn->info_work, msecs_to_jiffies(L2CAP_INFO_TIMEOUT)); l2cap_send_cmd(conn, conn->info_ident, @@ -3081,7 +3081,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) return 0; - del_timer(&conn->info_timer); + cancel_delayed_work_sync(&conn->info_work); if (result != L2CAP_IR_SUCCESS) { conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; -- 1.7.6.4 ^ permalink raw reply related [flat|nested] 34+ messages in thread
* [RFC 17/22] Bluetooth: remove power_on work_struct 2011-12-17 21:29 ` [RFC 16/22] Bluetooth: convert info timer to delayed_work Gustavo F. Padovan @ 2011-12-17 21:29 ` Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 18/22] Bluetooth: invert locking order in connect path Gustavo F. Padovan 2011-12-17 22:13 ` [RFC 17/22] Bluetooth: remove power_on work_struct Marcel Holtmann 0 siblings, 2 replies; 34+ messages in thread From: Gustavo F. Padovan @ 2011-12-17 21:29 UTC (permalink / raw) To: linux-bluetooth; +Cc: Gustavo F. Padovan From: "Gustavo F. Padovan" <padovan@profusion.mobi> Since now we run in process context, we can now call hci_power_on directly. Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_core.c | 7 ++----- net/bluetooth/mgmt.c | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 5d1bb51..662877a 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -187,7 +187,6 @@ struct hci_dev { struct workqueue_struct *workqueue; - struct work_struct power_on; struct delayed_work power_off; __u16 discov_timeout; @@ -597,6 +596,7 @@ int hci_register_dev(struct hci_dev *hdev); void hci_unregister_dev(struct hci_dev *hdev); int hci_suspend_dev(struct hci_dev *hdev); int hci_resume_dev(struct hci_dev *hdev); +void hci_power_on(struct hci_dev *hdev); int hci_dev_open(__u16 dev); int hci_dev_close(__u16 dev); int hci_dev_reset(__u16 dev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index fbc7968..5c7fec8 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -928,10 +928,8 @@ void hci_free_dev(struct hci_dev *hdev) } EXPORT_SYMBOL(hci_free_dev); -static void hci_power_on(struct work_struct *work) +void hci_power_on(struct hci_dev *hdev) { - struct hci_dev *hdev = container_of(work, struct hci_dev, power_on); - BT_DBG("%s", hdev->name); if (hci_dev_open(hdev->id) < 0) @@ -1490,7 +1488,6 @@ int hci_register_dev(struct hci_dev *hdev) INIT_LIST_HEAD(&hdev->adv_entries); INIT_DELAYED_WORK(&hdev->adv_work, hci_clear_adv_cache); - INIT_WORK(&hdev->power_on, hci_power_on); INIT_DELAYED_WORK(&hdev->power_off, hci_power_off); INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off); @@ -1522,7 +1519,7 @@ int hci_register_dev(struct hci_dev *hdev) set_bit(HCI_AUTO_OFF, &hdev->flags); set_bit(HCI_SETUP, &hdev->flags); - queue_work(hdev->workqueue, &hdev->power_on); + hci_power_on(hdev); hci_notify(hdev, HCI_DEV_REG); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ad4817c..30cbdd7 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -415,7 +415,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) } if (cp->val) - queue_work(hdev->workqueue, &hdev->power_on); + hci_power_on(hdev); else queue_work(hdev->workqueue, &hdev->power_off.work); -- 1.7.6.4 ^ permalink raw reply related [flat|nested] 34+ messages in thread
* [RFC 18/22] Bluetooth: invert locking order in connect path 2011-12-17 21:29 ` [RFC 17/22] Bluetooth: remove power_on work_struct Gustavo F. Padovan @ 2011-12-17 21:29 ` Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 19/22] Bluetooth: Change l2cap chan_list to use RCU Gustavo F. Padovan 2011-12-17 22:13 ` [RFC 17/22] Bluetooth: remove power_on work_struct Marcel Holtmann 1 sibling, 1 reply; 34+ messages in thread From: Gustavo F. Padovan @ 2011-12-17 21:29 UTC (permalink / raw) To: linux-bluetooth; +Cc: Gustavo F. Padovan From: "Gustavo F. Padovan" <padovan@profusion.mobi> This move some checking code that was in l2cap_sock_connect() to l2cap_chan_connect(). Thus we can invert the lock calls, i.e., call lock_sock() before hci_dev_lock() to avoid a deadlock scenario. Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> --- include/net/bluetooth/l2cap.h | 3 +- net/bluetooth/l2cap_core.c | 58 +++++++++++++++++++++++++++++++++++++- net/bluetooth/l2cap_sock.c | 61 ++--------------------------------------- 3 files changed, 61 insertions(+), 61 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index f791374..c0d168a 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -806,7 +806,8 @@ int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid); struct l2cap_chan *l2cap_chan_create(struct sock *sk); void l2cap_chan_close(struct l2cap_chan *chan, int reason); void l2cap_chan_destroy(struct l2cap_chan *chan); -int l2cap_chan_connect(struct l2cap_chan *chan); +inline int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, + bdaddr_t *dst); int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 priority); void l2cap_chan_busy(struct l2cap_chan *chan, int busy); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a78cdf7..d616519 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1144,11 +1144,10 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr return c1; } -int l2cap_chan_connect(struct l2cap_chan *chan) +inline int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst) { struct sock *sk = chan->sk; bdaddr_t *src = &bt_sk(sk)->src; - bdaddr_t *dst = &bt_sk(sk)->dst; struct l2cap_conn *conn; struct hci_conn *hcon; struct hci_dev *hdev; @@ -1164,6 +1163,61 @@ int l2cap_chan_connect(struct l2cap_chan *chan) hci_dev_lock(hdev); + lock_sock(sk); + + /* PSM must be odd and lsb of upper byte must be 0 */ + if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid && + chan->chan_type != L2CAP_CHAN_RAW) { + err = -EINVAL; + goto done; + } + + if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) { + err = -EINVAL; + goto done; + } + + switch (chan->mode) { + case L2CAP_MODE_BASIC: + break; + case L2CAP_MODE_ERTM: + case L2CAP_MODE_STREAMING: + if (!disable_ertm) + break; + /* fall through */ + default: + err = -ENOTSUPP; + goto done; + } + + switch (sk->sk_state) { + case BT_CONNECT: + case BT_CONNECT2: + case BT_CONFIG: + /* Already connecting */ + err = 0; + goto done; + + case BT_CONNECTED: + /* Already connected */ + err = -EISCONN; + goto done; + + case BT_OPEN: + case BT_BOUND: + /* Can connect */ + break; + + default: + err = -EBADFD; + goto done; + } + + /* Set destination address and psm */ + bacpy(&bt_sk(sk)->dst, src); + chan->psm = psm; + chan->dcid = cid; + auth_type = l2cap_get_auth_type(chan); if (chan->dcid == L2CAP_CID_LE_DATA) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index fbdc8b3..6c7d432 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -121,70 +121,15 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al if (la.l2_cid && la.l2_psm) return -EINVAL; - lock_sock(sk); - - if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED - && !(la.l2_psm || la.l2_cid)) { - err = -EINVAL; - goto done; - } - - switch (chan->mode) { - case L2CAP_MODE_BASIC: - break; - case L2CAP_MODE_ERTM: - case L2CAP_MODE_STREAMING: - if (!disable_ertm) - break; - /* fall through */ - default: - err = -ENOTSUPP; - goto done; - } - - switch (sk->sk_state) { - case BT_CONNECT: - case BT_CONNECT2: - case BT_CONFIG: - /* Already connecting */ - goto wait; - - case BT_CONNECTED: - /* Already connected */ - err = -EISCONN; - goto done; - - case BT_OPEN: - case BT_BOUND: - /* Can connect */ - break; - - default: - err = -EBADFD; - goto done; - } - - /* PSM must be odd and lsb of upper byte must be 0 */ - if ((__le16_to_cpu(la.l2_psm) & 0x0101) != 0x0001 && !la.l2_cid && - chan->chan_type != L2CAP_CHAN_RAW) { - err = -EINVAL; - goto done; - } - - /* Set destination address and psm */ - bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr); - chan->psm = la.l2_psm; - chan->dcid = la.l2_cid; - - err = l2cap_chan_connect(chan); + err = l2cap_chan_connect(chan, la.l2_psm, la.l2_cid, &la.l2_bdaddr); if (err) goto done; -wait: err = bt_sock_wait_state(sk, BT_CONNECTED, sock_sndtimeo(sk, flags & O_NONBLOCK)); done: - release_sock(sk); + if (sock_owned_by_user(sk)) + release_sock(sk); return err; } -- 1.7.6.4 ^ permalink raw reply related [flat|nested] 34+ messages in thread
* [RFC 19/22] Bluetooth: Change l2cap chan_list to use RCU 2011-12-17 21:29 ` [RFC 18/22] Bluetooth: invert locking order in connect path Gustavo F. Padovan @ 2011-12-17 21:29 ` Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 20/22] Bluetooth: move power_off to system workqueue Gustavo F. Padovan ` (2 more replies) 0 siblings, 3 replies; 34+ messages in thread From: Gustavo F. Padovan @ 2011-12-17 21:29 UTC (permalink / raw) To: linux-bluetooth; +Cc: Gustavo F. Padovan From: "Gustavo F. Padovan" <padovan@profusion.mobi> This list has much more reads than writes, so RCU makes senses here, also it avoid deadlock against the socket lock. Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> --- net/bluetooth/l2cap_core.c | 117 +++++++++++++++++++++---------------------- 1 files changed, 57 insertions(+), 60 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d616519..a212295 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -89,24 +89,36 @@ static inline void chan_put(struct l2cap_chan *c) static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) { - struct l2cap_chan *c; + struct l2cap_chan *c, *r = NULL; - list_for_each_entry(c, &conn->chan_l, list) { - if (c->dcid == cid) - return c; + rcu_read_lock(); + + list_for_each_entry_rcu(c, &conn->chan_l, list) { + if (c->dcid == cid) { + r = c; + break; + } } + + rcu_read_unlock(); return NULL; } static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) { - struct l2cap_chan *c; + struct l2cap_chan *c, *r = NULL; - list_for_each_entry(c, &conn->chan_l, list) { - if (c->scid == cid) - return c; + rcu_read_lock(); + + list_for_each_entry_rcu(c, &conn->chan_l, list) { + if (c->scid == cid) { + r = c; + break; + } } - return NULL; + + rcu_read_unlock(); + return r; } /* Find channel with given SCID. @@ -115,34 +127,36 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 ci { struct l2cap_chan *c; - mutex_lock(&conn->chan_lock); c = __l2cap_get_chan_by_scid(conn, cid); if (c) lock_sock(c->sk); - mutex_unlock(&conn->chan_lock); return c; } static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) { - struct l2cap_chan *c; + struct l2cap_chan *c, *r = NULL; - list_for_each_entry(c, &conn->chan_l, list) { - if (c->ident == ident) - return c; + rcu_read_lock(); + + list_for_each_entry_rcu(c, &conn->chan_l, list) { + if (c->ident == ident) { + r = c; + break; + } } - return NULL; + + rcu_read_unlock(); + return r; } static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) { struct l2cap_chan *c; - mutex_lock(&conn->chan_lock); c = __l2cap_get_chan_by_ident(conn, ident); if (c) lock_sock(c->sk); - mutex_unlock(&conn->chan_lock); return c; } @@ -323,7 +337,7 @@ void l2cap_chan_destroy(struct l2cap_chan *chan) chan_put(chan); } -static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) +static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, chan->psm, chan->dcid); @@ -364,7 +378,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) chan_hold(chan); - list_add(&chan->list, &conn->chan_l); + list_add_rcu(&chan->list, &conn->chan_l); } /* Delete channel. @@ -381,9 +395,9 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) if (conn) { /* Delete from channel list */ - mutex_lock(&conn->chan_lock); - list_del(&chan->list); - mutex_unlock(&conn->chan_lock); + list_del_rcu(&chan->list); + synchronize_rcu(); + chan_put(chan); chan->conn = NULL; @@ -750,13 +764,13 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c /* ---- L2CAP connections ---- */ static void l2cap_conn_start(struct l2cap_conn *conn) { - struct l2cap_chan *chan, *tmp; + struct l2cap_chan *chan; BT_DBG("conn %p", conn); - mutex_lock(&conn->chan_lock); + rcu_read_lock(); - list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { + list_for_each_entry_rcu(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; bh_lock_sock(sk); @@ -780,9 +794,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) &chan->conf_state)) { /* l2cap_chan_close() calls list_del(chan) * so release the lock */ - mutex_unlock(&conn->chan_lock); l2cap_chan_close(chan, ECONNRESET); - utex_lock(&conn->chan_lock); bh_unlock_sock(sk); continue; } @@ -838,7 +850,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) bh_unlock_sock(sk); } - mutex_unlock(&conn->chan_lock); + rcu_read_unlock(); } /* Find socket with cid and source bdaddr. @@ -903,8 +915,6 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) sk = chan->sk; - mutex_lock(&conn->chan_lock); - hci_conn_hold(conn->hcon); bacpy(&bt_sk(sk)->src, conn->src); @@ -912,15 +922,13 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) bt_accept_enqueue(parent, sk); - __l2cap_chan_add(conn, chan); + l2cap_chan_add(conn, chan); __set_chan_timer(chan, sk->sk_sndtimeo); l2cap_state_change(chan, BT_CONNECTED); parent->sk_data_ready(parent, 0); - mutex_unlock(&conn->chan_lock); - clean: release_sock(parent); } @@ -954,9 +962,9 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) if (conn->hcon->out && conn->hcon->type == LE_LINK) smp_conn_security(conn, conn->hcon->pending_sec_level); - mutex_lock(&conn->chan_lock); + rcu_read_lock(); - list_for_each_entry(chan, &conn->chan_l, list) { + list_for_each_entry_rcu(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; bh_lock_sock(sk); @@ -976,7 +984,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) bh_unlock_sock(sk); } - mutex_unlock(&conn->chan_lock); + rcu_read_unlock(); } /* Notify sockets that we cannot guaranty reliability anymore */ @@ -986,16 +994,16 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) BT_DBG("conn %p", conn); - mutex_lock(&conn->chan_lock); + rcu_read_lock(); - list_for_each_entry(chan, &conn->chan_l, list) { + list_for_each_entry_rcu(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags)) sk->sk_err = err; } - mutex_unlock(&conn->chan_lock); + rcu_read_unlock(); } static void l2cap_info_timeout(struct work_struct *work) @@ -1087,7 +1095,6 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) conn->feat_mask = 0; spin_lock_init(&conn->lock); - mutex_init(&conn->chan_lock); INIT_LIST_HEAD(&conn->chan_l); @@ -1102,13 +1109,6 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) return conn; } -static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) -{ - mutex_lock(&conn->chan_lock); - __l2cap_chan_add(conn, chan); - mutex_unlock(&conn->chan_lock); -} - /* ---- Socket interface ---- */ /* Find socket with psm and source bdaddr. @@ -1825,8 +1825,9 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p", conn); - mutex_lock(&conn->chan_lock); - list_for_each_entry(chan, &conn->chan_l, list) { + rcu_read_lock(); + + list_for_each_entry_rcu(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; if (chan->chan_type != L2CAP_CHAN_RAW) continue; @@ -1841,7 +1842,8 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) if (chan->ops->recv(chan->data, nskb)) kfree_skb(nskb); } - mutex_unlock(&conn->chan_lock); + + rcu_read_unlock(); } /* ---- L2CAP signalling commands ---- */ @@ -2641,11 +2643,8 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd sk = chan->sk; - mutex_lock(&conn->chan_lock); - /* Check if we already have channel with that dcid */ if (__l2cap_get_chan_by_dcid(conn, scid)) { - mutex_unlock(&conn->chan_lock); sock_set_flag(sk, SOCK_ZAPPED); chan->ops->close(chan->data); goto response; @@ -2660,7 +2659,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd bt_accept_enqueue(parent, sk); - __l2cap_chan_add(conn, chan); + l2cap_chan_add(conn, chan); dcid = chan->scid; @@ -2691,8 +2690,6 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd status = L2CAP_CS_NO_INFO; } - mutex_unlock(&conn->chan_lock); - response: release_sock(parent); @@ -4528,9 +4525,9 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) del_timer(&conn->security_timer); } - mutex_lock(&conn->chan_lock); + rcu_read_lock(); - list_for_each_entry(chan, &conn->chan_l, list) { + list_for_each_entry_rcu(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; bh_lock_sock(sk); @@ -4608,7 +4605,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) bh_unlock_sock(sk); } - mutex_unlock(&conn->chan_lock); + rcu_read_unlock(); return 0; } -- 1.7.6.4 ^ permalink raw reply related [flat|nested] 34+ messages in thread
* [RFC 20/22] Bluetooth: move power_off to system workqueue 2011-12-17 21:29 ` [RFC 19/22] Bluetooth: Change l2cap chan_list to use RCU Gustavo F. Padovan @ 2011-12-17 21:29 ` Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 21/22] Bluetooth: Use new alloc_workqueue() Gustavo F. Padovan 2011-12-17 22:15 ` [RFC 19/22] Bluetooth: Change l2cap chan_list to use RCU Marcel Holtmann 2011-12-19 10:42 ` Andrei Emeltchenko 2 siblings, 1 reply; 34+ messages in thread From: Gustavo F. Padovan @ 2011-12-17 21:29 UTC (permalink / raw) To: linux-bluetooth; +Cc: Gustavo F. Padovan From: "Gustavo F. Padovan" <padovan@profusion.mobi> hdev->workqueue will be only for for rx/tx/cmd processing, all other small works should go to the system workqueue for now. Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> --- net/bluetooth/hci_core.c | 2 +- net/bluetooth/mgmt.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 5c7fec8..e4ff7b6 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -936,7 +936,7 @@ void hci_power_on(struct hci_dev *hdev) return; if (test_bit(HCI_AUTO_OFF, &hdev->flags)) - queue_delayed_work(hdev->workqueue, &hdev->power_off, + schedule_delayed_work(&hdev->power_off, msecs_to_jiffies(AUTO_OFF_TIMEOUT)); if (test_and_clear_bit(HCI_SETUP, &hdev->flags)) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 30cbdd7..4402c4d 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -417,7 +417,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) if (cp->val) hci_power_on(hdev); else - queue_work(hdev->workqueue, &hdev->power_off.work); + schedule_work(&hdev->power_off.work); err = 0; -- 1.7.6.4 ^ permalink raw reply related [flat|nested] 34+ messages in thread
* [RFC 21/22] Bluetooth: Use new alloc_workqueue() 2011-12-17 21:29 ` [RFC 20/22] Bluetooth: move power_off to system workqueue Gustavo F. Padovan @ 2011-12-17 21:29 ` Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 22/22] Bluetooth: Remove work_add and work_del from hci_sysfs Gustavo F. Padovan 0 siblings, 1 reply; 34+ messages in thread From: Gustavo F. Padovan @ 2011-12-17 21:29 UTC (permalink / raw) To: linux-bluetooth; +Cc: Gustavo F. Padovan From: "Gustavo F. Padovan" <padovan@profusion.mobi> Update hdev workqueue API usage to use the new interface, this new interface also allow us to mark this workqueue as WQ_HIGHPRI, so now rx and tx work gets higher priority when running. Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> --- net/bluetooth/hci_core.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e4ff7b6..21816dd 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1498,7 +1498,7 @@ int hci_register_dev(struct hci_dev *hdev) write_unlock_bh(&hci_dev_list_lock); - hdev->workqueue = create_singlethread_workqueue(hdev->name); + hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI, 1); if (!hdev->workqueue) { error = -ENOMEM; goto err; -- 1.7.6.4 ^ permalink raw reply related [flat|nested] 34+ messages in thread
* [RFC 22/22] Bluetooth: Remove work_add and work_del from hci_sysfs 2011-12-17 21:29 ` [RFC 21/22] Bluetooth: Use new alloc_workqueue() Gustavo F. Padovan @ 2011-12-17 21:29 ` Gustavo F. Padovan 0 siblings, 0 replies; 34+ messages in thread From: Gustavo F. Padovan @ 2011-12-17 21:29 UTC (permalink / raw) To: linux-bluetooth; +Cc: Gustavo F. Padovan From: "Gustavo F. Padovan" <padovan@profusion.mobi> As we run in process context now we don't need worqueue to add e del from sysfs. Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> --- include/net/bluetooth/hci_core.h | 3 -- net/bluetooth/hci_sysfs.c | 71 ++++++++++++++----------------------- 2 files changed, 27 insertions(+), 47 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 662877a..d10d2ba 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -300,9 +300,6 @@ struct hci_conn { struct timer_list idle_timer; struct timer_list auto_accept_timer; - struct work_struct work_add; - struct work_struct work_del; - struct device dev; atomic_t devref; diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index c3c1ec8..db6af70 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -88,11 +88,35 @@ static struct device_type bt_link = { .release = bt_link_release, }; -static void add_conn(struct work_struct *work) +/* + * The rfcomm tty device will possibly retain even when conn + * is down, and sysfs doesn't support move zombie device, + * so we should move the device before conn device is destroyed. + */ +static int __match_tty(struct device *dev, void *data) +{ + return !strncmp(dev_name(dev), "rfcomm", 6); +} + +void hci_conn_init_sysfs(struct hci_conn *conn) +{ + struct hci_dev *hdev = conn->hdev; + + BT_DBG("conn %p", conn); + + conn->dev.type = &bt_link; + conn->dev.class = bt_class; + conn->dev.parent = &hdev->dev; + + device_initialize(&conn->dev); +} + +void hci_conn_add_sysfs(struct hci_conn *conn) { - struct hci_conn *conn = container_of(work, struct hci_conn, work_add); struct hci_dev *hdev = conn->hdev; + BT_DBG("conn %p", conn); + dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle); dev_set_drvdata(&conn->dev, conn); @@ -105,19 +129,8 @@ static void add_conn(struct work_struct *work) hci_dev_hold(hdev); } -/* - * The rfcomm tty device will possibly retain even when conn - * is down, and sysfs doesn't support move zombie device, - * so we should move the device before conn device is destroyed. - */ -static int __match_tty(struct device *dev, void *data) -{ - return !strncmp(dev_name(dev), "rfcomm", 6); -} - -static void del_conn(struct work_struct *work) +void hci_conn_del_sysfs(struct hci_conn *conn) { - struct hci_conn *conn = container_of(work, struct hci_conn, work_del); struct hci_dev *hdev = conn->hdev; if (!device_is_registered(&conn->dev)) @@ -139,36 +152,6 @@ static void del_conn(struct work_struct *work) hci_dev_put(hdev); } -void hci_conn_init_sysfs(struct hci_conn *conn) -{ - struct hci_dev *hdev = conn->hdev; - - BT_DBG("conn %p", conn); - - conn->dev.type = &bt_link; - conn->dev.class = bt_class; - conn->dev.parent = &hdev->dev; - - device_initialize(&conn->dev); - - INIT_WORK(&conn->work_add, add_conn); - INIT_WORK(&conn->work_del, del_conn); -} - -void hci_conn_add_sysfs(struct hci_conn *conn) -{ - BT_DBG("conn %p", conn); - - queue_work(conn->hdev->workqueue, &conn->work_add); -} - -void hci_conn_del_sysfs(struct hci_conn *conn) -{ - BT_DBG("conn %p", conn); - - queue_work(conn->hdev->workqueue, &conn->work_del); -} - static inline char *host_bustostr(int bus) { switch (bus) { -- 1.7.6.4 ^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [RFC 19/22] Bluetooth: Change l2cap chan_list to use RCU 2011-12-17 21:29 ` [RFC 19/22] Bluetooth: Change l2cap chan_list to use RCU Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 20/22] Bluetooth: move power_off to system workqueue Gustavo F. Padovan @ 2011-12-17 22:15 ` Marcel Holtmann 2011-12-19 10:42 ` Andrei Emeltchenko 2 siblings, 0 replies; 34+ messages in thread From: Marcel Holtmann @ 2011-12-17 22:15 UTC (permalink / raw) To: Gustavo F. Padovan; +Cc: linux-bluetooth Hi Gustavo, > This list has much more reads than writes, so RCU makes senses here, also > it avoid deadlock against the socket lock. > > Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> > --- > net/bluetooth/l2cap_core.c | 117 +++++++++++++++++++++---------------------- > 1 files changed, 57 insertions(+), 60 deletions(-) > > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c > index d616519..a212295 100644 > --- a/net/bluetooth/l2cap_core.c > +++ b/net/bluetooth/l2cap_core.c > @@ -89,24 +89,36 @@ static inline void chan_put(struct l2cap_chan *c) > > static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) > { > - struct l2cap_chan *c; > + struct l2cap_chan *c, *r = NULL; > > - list_for_each_entry(c, &conn->chan_l, list) { > - if (c->dcid == cid) > - return c; > + rcu_read_lock(); > + > + list_for_each_entry_rcu(c, &conn->chan_l, list) { > + if (c->dcid == cid) { > + r = c; > + break; > + } > } > + > + rcu_read_unlock(); > return NULL; > } shouldn't this say return r; Regards Marcel ^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFC 19/22] Bluetooth: Change l2cap chan_list to use RCU 2011-12-17 21:29 ` [RFC 19/22] Bluetooth: Change l2cap chan_list to use RCU Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 20/22] Bluetooth: move power_off to system workqueue Gustavo F. Padovan 2011-12-17 22:15 ` [RFC 19/22] Bluetooth: Change l2cap chan_list to use RCU Marcel Holtmann @ 2011-12-19 10:42 ` Andrei Emeltchenko 2011-12-19 13:53 ` Gustavo Padovan 2 siblings, 1 reply; 34+ messages in thread From: Andrei Emeltchenko @ 2011-12-19 10:42 UTC (permalink / raw) To: Gustavo F. Padovan; +Cc: linux-bluetooth Hi Gustavo, On Sat, Dec 17, 2011 at 07:29:39PM -0200, Gustavo F. Padovan wrote: > From: "Gustavo F. Padovan" <padovan@profusion.mobi> > > This list has much more reads than writes, so RCU makes senses here, also > it avoid deadlock against the socket lock. > > Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> > --- > net/bluetooth/l2cap_core.c | 117 +++++++++++++++++++++---------------------- > 1 files changed, 57 insertions(+), 60 deletions(-) > > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c > index d616519..a212295 100644 > --- a/net/bluetooth/l2cap_core.c > +++ b/net/bluetooth/l2cap_core.c > @@ -89,24 +89,36 @@ static inline void chan_put(struct l2cap_chan *c) > > static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) > { > - struct l2cap_chan *c; > + struct l2cap_chan *c, *r = NULL; > > - list_for_each_entry(c, &conn->chan_l, list) { > - if (c->dcid == cid) > - return c; > + rcu_read_lock(); > + > + list_for_each_entry_rcu(c, &conn->chan_l, list) { > + if (c->dcid == cid) { > + r = c; > + break; > + } > } > + > + rcu_read_unlock(); > return NULL; > } > > static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) > { > - struct l2cap_chan *c; > + struct l2cap_chan *c, *r = NULL; > > - list_for_each_entry(c, &conn->chan_l, list) { > - if (c->scid == cid) > - return c; > + rcu_read_lock(); > + > + list_for_each_entry_rcu(c, &conn->chan_l, list) { > + if (c->scid == cid) { > + r = c; > + break; > + } > } > - return NULL; > + > + rcu_read_unlock(); > + return r; > } > > /* Find channel with given SCID. > @@ -115,34 +127,36 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 ci > { > struct l2cap_chan *c; > > - mutex_lock(&conn->chan_lock); > c = __l2cap_get_chan_by_scid(conn, cid); > if (c) > lock_sock(c->sk); > - mutex_unlock(&conn->chan_lock); > return c; > } > > static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) > { > - struct l2cap_chan *c; > + struct l2cap_chan *c, *r = NULL; > > - list_for_each_entry(c, &conn->chan_l, list) { > - if (c->ident == ident) > - return c; > + rcu_read_lock(); > + > + list_for_each_entry_rcu(c, &conn->chan_l, list) { > + if (c->ident == ident) { > + r = c; > + break; > + } > } > - return NULL; > + > + rcu_read_unlock(); > + return r; > } > > static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) > { > struct l2cap_chan *c; > > - mutex_lock(&conn->chan_lock); > c = __l2cap_get_chan_by_ident(conn, ident); > if (c) > lock_sock(c->sk); > - mutex_unlock(&conn->chan_lock); > return c; > } > > @@ -323,7 +337,7 @@ void l2cap_chan_destroy(struct l2cap_chan *chan) > chan_put(chan); > } > > -static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) > +static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) > { > BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, > chan->psm, chan->dcid); > @@ -364,7 +378,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) > > chan_hold(chan); > > - list_add(&chan->list, &conn->chan_l); > + list_add_rcu(&chan->list, &conn->chan_l); > } > > /* Delete channel. > @@ -381,9 +395,9 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) > > if (conn) { > /* Delete from channel list */ > - mutex_lock(&conn->chan_lock); > - list_del(&chan->list); > - mutex_unlock(&conn->chan_lock); > + list_del_rcu(&chan->list); > + synchronize_rcu(); > + > chan_put(chan); > > chan->conn = NULL; > @@ -750,13 +764,13 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c > /* ---- L2CAP connections ---- */ > static void l2cap_conn_start(struct l2cap_conn *conn) > { > - struct l2cap_chan *chan, *tmp; > + struct l2cap_chan *chan; > > BT_DBG("conn %p", conn); > > - mutex_lock(&conn->chan_lock); > + rcu_read_lock(); > > - list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { > + list_for_each_entry_rcu(chan, &conn->chan_l, list) { > struct sock *sk = chan->sk; > > bh_lock_sock(sk); > @@ -780,9 +794,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) > &chan->conf_state)) { > /* l2cap_chan_close() calls list_del(chan) > * so release the lock */ > - mutex_unlock(&conn->chan_lock); > l2cap_chan_close(chan, ECONNRESET); > - utex_lock(&conn->chan_lock); OK, I see why this works. BTW: IMO the mutex and rcu patches shall be amended, otherwise we do unneeded work of implementing mutexes and then changing them to RCU. Best regards Andrei Emeltchenko > bh_unlock_sock(sk); > continue; > } > @@ -838,7 +850,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) > bh_unlock_sock(sk); > } > > - mutex_unlock(&conn->chan_lock); > + rcu_read_unlock(); > } > > /* Find socket with cid and source bdaddr. > @@ -903,8 +915,6 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) > > sk = chan->sk; > > - mutex_lock(&conn->chan_lock); > - > hci_conn_hold(conn->hcon); > > bacpy(&bt_sk(sk)->src, conn->src); > @@ -912,15 +922,13 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) > > bt_accept_enqueue(parent, sk); > > - __l2cap_chan_add(conn, chan); > + l2cap_chan_add(conn, chan); > > __set_chan_timer(chan, sk->sk_sndtimeo); > > l2cap_state_change(chan, BT_CONNECTED); > parent->sk_data_ready(parent, 0); > > - mutex_unlock(&conn->chan_lock); > - > clean: > release_sock(parent); > } > @@ -954,9 +962,9 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) > if (conn->hcon->out && conn->hcon->type == LE_LINK) > smp_conn_security(conn, conn->hcon->pending_sec_level); > > - mutex_lock(&conn->chan_lock); > + rcu_read_lock(); > > - list_for_each_entry(chan, &conn->chan_l, list) { > + list_for_each_entry_rcu(chan, &conn->chan_l, list) { > struct sock *sk = chan->sk; > > bh_lock_sock(sk); > @@ -976,7 +984,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) > bh_unlock_sock(sk); > } > > - mutex_unlock(&conn->chan_lock); > + rcu_read_unlock(); > } > > /* Notify sockets that we cannot guaranty reliability anymore */ > @@ -986,16 +994,16 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) > > BT_DBG("conn %p", conn); > > - mutex_lock(&conn->chan_lock); > + rcu_read_lock(); > > - list_for_each_entry(chan, &conn->chan_l, list) { > + list_for_each_entry_rcu(chan, &conn->chan_l, list) { > struct sock *sk = chan->sk; > > if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags)) > sk->sk_err = err; > } > > - mutex_unlock(&conn->chan_lock); > + rcu_read_unlock(); > } > > static void l2cap_info_timeout(struct work_struct *work) > @@ -1087,7 +1095,6 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) > conn->feat_mask = 0; > > spin_lock_init(&conn->lock); > - mutex_init(&conn->chan_lock); > > INIT_LIST_HEAD(&conn->chan_l); > > @@ -1102,13 +1109,6 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) > return conn; > } > > -static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) > -{ > - mutex_lock(&conn->chan_lock); > - __l2cap_chan_add(conn, chan); > - mutex_unlock(&conn->chan_lock); > -} > - > /* ---- Socket interface ---- */ > > /* Find socket with psm and source bdaddr. > @@ -1825,8 +1825,9 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) > > BT_DBG("conn %p", conn); > > - mutex_lock(&conn->chan_lock); > - list_for_each_entry(chan, &conn->chan_l, list) { > + rcu_read_lock(); > + > + list_for_each_entry_rcu(chan, &conn->chan_l, list) { > struct sock *sk = chan->sk; > if (chan->chan_type != L2CAP_CHAN_RAW) > continue; > @@ -1841,7 +1842,8 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) > if (chan->ops->recv(chan->data, nskb)) > kfree_skb(nskb); > } > - mutex_unlock(&conn->chan_lock); > + > + rcu_read_unlock(); > } > > /* ---- L2CAP signalling commands ---- */ > @@ -2641,11 +2643,8 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd > > sk = chan->sk; > > - mutex_lock(&conn->chan_lock); > - > /* Check if we already have channel with that dcid */ > if (__l2cap_get_chan_by_dcid(conn, scid)) { > - mutex_unlock(&conn->chan_lock); > sock_set_flag(sk, SOCK_ZAPPED); > chan->ops->close(chan->data); > goto response; > @@ -2660,7 +2659,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd > > bt_accept_enqueue(parent, sk); > > - __l2cap_chan_add(conn, chan); > + l2cap_chan_add(conn, chan); > > dcid = chan->scid; > > @@ -2691,8 +2690,6 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd > status = L2CAP_CS_NO_INFO; > } > > - mutex_unlock(&conn->chan_lock); > - > response: > release_sock(parent); > > @@ -4528,9 +4525,9 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) > del_timer(&conn->security_timer); > } > > - mutex_lock(&conn->chan_lock); > + rcu_read_lock(); > > - list_for_each_entry(chan, &conn->chan_l, list) { > + list_for_each_entry_rcu(chan, &conn->chan_l, list) { > struct sock *sk = chan->sk; > > bh_lock_sock(sk); > @@ -4608,7 +4605,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) > bh_unlock_sock(sk); > } > > - mutex_unlock(&conn->chan_lock); > + rcu_read_unlock(); > > return 0; > } > -- > 1.7.6.4 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFC 19/22] Bluetooth: Change l2cap chan_list to use RCU 2011-12-19 10:42 ` Andrei Emeltchenko @ 2011-12-19 13:53 ` Gustavo Padovan 0 siblings, 0 replies; 34+ messages in thread From: Gustavo Padovan @ 2011-12-19 13:53 UTC (permalink / raw) To: Andrei Emeltchenko, linux-bluetooth Hi Andrei, * Andrei Emeltchenko <andrei.emeltchenko.news@gmail.com> [2011-12-19 12:42:57 +0200]: > Hi Gustavo, > > On Sat, Dec 17, 2011 at 07:29:39PM -0200, Gustavo F. Padovan wrote: > > From: "Gustavo F. Padovan" <padovan@profusion.mobi> > > > > This list has much more reads than writes, so RCU makes senses here, also > > it avoid deadlock against the socket lock. > > > > Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> > > --- > > net/bluetooth/l2cap_core.c | 117 +++++++++++++++++++++---------------------- > > 1 files changed, 57 insertions(+), 60 deletions(-) > > > > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c > > index d616519..a212295 100644 > > --- a/net/bluetooth/l2cap_core.c > > +++ b/net/bluetooth/l2cap_core.c > > @@ -89,24 +89,36 @@ static inline void chan_put(struct l2cap_chan *c) > > > > static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) > > { > > - struct l2cap_chan *c; > > + struct l2cap_chan *c, *r = NULL; > > > > - list_for_each_entry(c, &conn->chan_l, list) { > > - if (c->dcid == cid) > > - return c; > > + rcu_read_lock(); > > + > > + list_for_each_entry_rcu(c, &conn->chan_l, list) { > > + if (c->dcid == cid) { > > + r = c; > > + break; > > + } > > } > > + > > + rcu_read_unlock(); > > return NULL; > > } > > > > static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) > > { > > - struct l2cap_chan *c; > > + struct l2cap_chan *c, *r = NULL; > > > > - list_for_each_entry(c, &conn->chan_l, list) { > > - if (c->scid == cid) > > - return c; > > + rcu_read_lock(); > > + > > + list_for_each_entry_rcu(c, &conn->chan_l, list) { > > + if (c->scid == cid) { > > + r = c; > > + break; > > + } > > } > > - return NULL; > > + > > + rcu_read_unlock(); > > + return r; > > } > > > > /* Find channel with given SCID. > > @@ -115,34 +127,36 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 ci > > { > > struct l2cap_chan *c; > > > > - mutex_lock(&conn->chan_lock); > > c = __l2cap_get_chan_by_scid(conn, cid); > > if (c) > > lock_sock(c->sk); > > - mutex_unlock(&conn->chan_lock); > > return c; > > } > > > > static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) > > { > > - struct l2cap_chan *c; > > + struct l2cap_chan *c, *r = NULL; > > > > - list_for_each_entry(c, &conn->chan_l, list) { > > - if (c->ident == ident) > > - return c; > > + rcu_read_lock(); > > + > > + list_for_each_entry_rcu(c, &conn->chan_l, list) { > > + if (c->ident == ident) { > > + r = c; > > + break; > > + } > > } > > - return NULL; > > + > > + rcu_read_unlock(); > > + return r; > > } > > > > static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) > > { > > struct l2cap_chan *c; > > > > - mutex_lock(&conn->chan_lock); > > c = __l2cap_get_chan_by_ident(conn, ident); > > if (c) > > lock_sock(c->sk); > > - mutex_unlock(&conn->chan_lock); > > return c; > > } > > > > @@ -323,7 +337,7 @@ void l2cap_chan_destroy(struct l2cap_chan *chan) > > chan_put(chan); > > } > > > > -static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) > > +static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) > > { > > BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, > > chan->psm, chan->dcid); > > @@ -364,7 +378,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) > > > > chan_hold(chan); > > > > - list_add(&chan->list, &conn->chan_l); > > + list_add_rcu(&chan->list, &conn->chan_l); > > } > > > > /* Delete channel. > > @@ -381,9 +395,9 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) > > > > if (conn) { > > /* Delete from channel list */ > > - mutex_lock(&conn->chan_lock); > > - list_del(&chan->list); > > - mutex_unlock(&conn->chan_lock); > > + list_del_rcu(&chan->list); > > + synchronize_rcu(); > > + > > chan_put(chan); > > > > chan->conn = NULL; > > @@ -750,13 +764,13 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c > > /* ---- L2CAP connections ---- */ > > static void l2cap_conn_start(struct l2cap_conn *conn) > > { > > - struct l2cap_chan *chan, *tmp; > > + struct l2cap_chan *chan; > > > > BT_DBG("conn %p", conn); > > > > - mutex_lock(&conn->chan_lock); > > + rcu_read_lock(); > > > > - list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { > > + list_for_each_entry_rcu(chan, &conn->chan_l, list) { > > struct sock *sk = chan->sk; > > > > bh_lock_sock(sk); > > @@ -780,9 +794,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) > > &chan->conf_state)) { > > /* l2cap_chan_close() calls list_del(chan) > > * so release the lock */ > > - mutex_unlock(&conn->chan_lock); > > l2cap_chan_close(chan, ECONNRESET); > > - utex_lock(&conn->chan_lock); > > OK, I see why this works. BTW: IMO the mutex and rcu patches shall be > amended, otherwise we do unneeded work of implementing mutexes and then > changing them to RCU. Indeed, but unfortunately I pushed the patches already and forgot to ammend both path patches. I was trying to push this ASAP so you guys could rebase your work on top of it. Gustavo ^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFC 17/22] Bluetooth: remove power_on work_struct 2011-12-17 21:29 ` [RFC 17/22] Bluetooth: remove power_on work_struct Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 18/22] Bluetooth: invert locking order in connect path Gustavo F. Padovan @ 2011-12-17 22:13 ` Marcel Holtmann 1 sibling, 0 replies; 34+ messages in thread From: Marcel Holtmann @ 2011-12-17 22:13 UTC (permalink / raw) To: Gustavo F. Padovan; +Cc: linux-bluetooth Hi Gustavo, > Since now we run in process context, we can now call hci_power_on > directly. > > Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> > --- > include/net/bluetooth/hci_core.h | 2 +- > net/bluetooth/hci_core.c | 7 ++----- > net/bluetooth/mgmt.c | 2 +- > 3 files changed, 4 insertions(+), 7 deletions(-) > > diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h > index 5d1bb51..662877a 100644 > --- a/include/net/bluetooth/hci_core.h > +++ b/include/net/bluetooth/hci_core.h > @@ -187,7 +187,6 @@ struct hci_dev { > > struct workqueue_struct *workqueue; > > - struct work_struct power_on; > struct delayed_work power_off; > > __u16 discov_timeout; > @@ -597,6 +596,7 @@ int hci_register_dev(struct hci_dev *hdev); > void hci_unregister_dev(struct hci_dev *hdev); > int hci_suspend_dev(struct hci_dev *hdev); > int hci_resume_dev(struct hci_dev *hdev); > +void hci_power_on(struct hci_dev *hdev); > int hci_dev_open(__u16 dev); > int hci_dev_close(__u16 dev); > int hci_dev_reset(__u16 dev); > diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c > index fbc7968..5c7fec8 100644 > --- a/net/bluetooth/hci_core.c > +++ b/net/bluetooth/hci_core.c > @@ -928,10 +928,8 @@ void hci_free_dev(struct hci_dev *hdev) > } > EXPORT_SYMBOL(hci_free_dev); > > -static void hci_power_on(struct work_struct *work) > +void hci_power_on(struct hci_dev *hdev) > { > - struct hci_dev *hdev = container_of(work, struct hci_dev, power_on); > - > BT_DBG("%s", hdev->name); > > if (hci_dev_open(hdev->id) < 0) > @@ -1490,7 +1488,6 @@ int hci_register_dev(struct hci_dev *hdev) > INIT_LIST_HEAD(&hdev->adv_entries); > > INIT_DELAYED_WORK(&hdev->adv_work, hci_clear_adv_cache); > - INIT_WORK(&hdev->power_on, hci_power_on); > INIT_DELAYED_WORK(&hdev->power_off, hci_power_off); > > INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off); > @@ -1522,7 +1519,7 @@ int hci_register_dev(struct hci_dev *hdev) > > set_bit(HCI_AUTO_OFF, &hdev->flags); > set_bit(HCI_SETUP, &hdev->flags); > - queue_work(hdev->workqueue, &hdev->power_on); > + hci_power_on(hdev); > > hci_notify(hdev, HCI_DEV_REG); > > diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c > index ad4817c..30cbdd7 100644 > --- a/net/bluetooth/mgmt.c > +++ b/net/bluetooth/mgmt.c > @@ -415,7 +415,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) > } > > if (cp->val) > - queue_work(hdev->workqueue, &hdev->power_on); > + hci_power_on(hdev); > else > queue_work(hdev->workqueue, &hdev->power_off.work); this is a bad idea. We are running with the hdev->workqueue now here we do not wanna interrupt this. So I would rather leave this one out for now. At least until we figured out on what is the best solution. Obviously we should push it onto the system workqueue instead of hdev->workqueue. Regards Marcel ^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFC 11/22] Bluetooth: Use RCU to manipulate chan_list 2011-12-17 21:29 ` [RFC 11/22] Bluetooth: Use RCU to manipulate chan_list Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 12/22] Bluetooth: convert conn hash to RCU Gustavo F. Padovan @ 2012-01-26 13:20 ` Andrei Emeltchenko 1 sibling, 0 replies; 34+ messages in thread From: Andrei Emeltchenko @ 2012-01-26 13:20 UTC (permalink / raw) To: Gustavo F. Padovan; +Cc: linux-bluetooth, marcel Hi Gustavo, On Sat, Dec 17, 2011 at 07:29:31PM -0200, Gustavo F. Padovan wrote: > From: "Gustavo F. Padovan" <padovan@profusion.mobi> > > Instead of using tasklet_disable() to prevent acess to the channel use, we > can use RCU and improve the performance of our code. > > Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> ... > @@ -986,10 +984,10 @@ int hci_chan_del(struct hci_chan *chan) > > void hci_chan_list_flush(struct hci_conn *conn) > { > - struct hci_chan *chan, *tmp; > + struct hci_chan *chan; > > BT_DBG("conn %p", conn); > > - list_for_each_entry_safe(chan, tmp, &conn->chan_list, list) > + list_for_each_entry_rcu(chan, &conn->chan_list, list) > hci_chan_del(chan); > } I feel that this code is not exactly correct. hci_chan_del frees chan: <------8<-------------------------------------------------------- | int hci_chan_del(struct hci_chan *chan) | { | struct hci_conn *conn = chan->conn; | struct hci_dev *hdev = conn->hdev; | | BT_DBG("%s conn %p chan %p", hdev->name, conn, chan); | | list_del_rcu(&chan->list); | | synchronize_rcu(); | | skb_queue_purge(&chan->data_q); | kfree(chan); | | return 0; | } <------8<-------------------------------------------------------- and then list_for_each_entry_rcu references chan->member.next which is not safe ;) I've sent patch reverting this change. Best regards Andrei Emeltchenko ^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFC 10/22] Bluetooth: convert chan_lock to mutex 2011-12-17 21:29 ` [RFC 10/22] Bluetooth: convert chan_lock " Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 11/22] Bluetooth: Use RCU to manipulate chan_list Gustavo F. Padovan @ 2011-12-19 9:58 ` Andrei Emeltchenko 1 sibling, 0 replies; 34+ messages in thread From: Andrei Emeltchenko @ 2011-12-19 9:58 UTC (permalink / raw) To: Gustavo F. Padovan; +Cc: linux-bluetooth Hi Gustavo, On Sat, Dec 17, 2011 at 07:29:30PM -0200, Gustavo F. Padovan wrote: > From: "Gustavo F. Padovan" <padovan@profusion.mobi> > > spin lock doesn't fit ok anymore on the new code based on workqueues. > > Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> > --- > include/net/bluetooth/l2cap.h | 2 +- > net/bluetooth/l2cap_core.c | 52 ++++++++++++++++++++-------------------- > 2 files changed, 27 insertions(+), 27 deletions(-) > > diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h > index 03be911..a175091 100644 > --- a/include/net/bluetooth/l2cap.h > +++ b/include/net/bluetooth/l2cap.h > @@ -536,7 +536,7 @@ struct l2cap_conn { > struct smp_chan *smp_chan; > > struct list_head chan_l; > - rwlock_t chan_lock; > + struct mutex chan_lock; > }; > > #define L2CAP_INFO_CL_MTU_REQ_SENT 0x01 > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c > index 31c94fd..5c5948f 100644 > --- a/net/bluetooth/l2cap_core.c > +++ b/net/bluetooth/l2cap_core.c > @@ -115,11 +115,11 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 ci > { > struct l2cap_chan *c; > > - read_lock(&conn->chan_lock); > + mutex_lock(&conn->chan_lock); > c = __l2cap_get_chan_by_scid(conn, cid); > if (c) > lock_sock(c->sk); > - read_unlock(&conn->chan_lock); > + mutex_unlock(&conn->chan_lock); > return c; > } > > @@ -138,11 +138,11 @@ static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn > { > struct l2cap_chan *c; > > - read_lock(&conn->chan_lock); > + mutex_lock(&conn->chan_lock); > c = __l2cap_get_chan_by_ident(conn, ident); > if (c) > lock_sock(c->sk); > - read_unlock(&conn->chan_lock); > + mutex_unlock(&conn->chan_lock); > return c; > } > > @@ -381,9 +381,9 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) > > if (conn) { > /* Delete from channel list */ > - write_lock_bh(&conn->chan_lock); > + mutex_lock(&conn->chan_lock); > list_del(&chan->list); > - write_unlock_bh(&conn->chan_lock); > + mutex_unlock(&conn->chan_lock); > chan_put(chan); > > chan->conn = NULL; > @@ -754,7 +754,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) > > BT_DBG("conn %p", conn); > > - read_lock(&conn->chan_lock); > + mutex_lock(&conn->chan_lock); > > list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { > struct sock *sk = chan->sk; > @@ -780,9 +780,9 @@ static void l2cap_conn_start(struct l2cap_conn *conn) > &chan->conf_state)) { > /* l2cap_chan_close() calls list_del(chan) > * so release the lock */ > - read_unlock(&conn->chan_lock); > + mutex_unlock(&conn->chan_lock); > l2cap_chan_close(chan, ECONNRESET); > - read_lock(&conn->chan_lock); > + utex_lock(&conn->chan_lock); Something corrupted here? Best regards Andrei Emeltchenko > bh_unlock_sock(sk); > continue; > } > @@ -838,7 +838,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) > bh_unlock_sock(sk); > } > > - read_unlock(&conn->chan_lock); > + mutex_unlock(&conn->chan_lock); > } > > /* Find socket with cid and source bdaddr. > @@ -903,7 +903,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) > > sk = chan->sk; > > - write_lock_bh(&conn->chan_lock); > + mutex_lock(&conn->chan_lock); > > hci_conn_hold(conn->hcon); > > @@ -919,7 +919,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) > l2cap_state_change(chan, BT_CONNECTED); > parent->sk_data_ready(parent, 0); > > - write_unlock_bh(&conn->chan_lock); > + mutex_unlock(&conn->chan_lock); > > clean: > release_sock(parent); > @@ -954,7 +954,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) > if (conn->hcon->out && conn->hcon->type == LE_LINK) > smp_conn_security(conn, conn->hcon->pending_sec_level); > > - read_lock(&conn->chan_lock); > + mutex_lock(&conn->chan_lock); > > list_for_each_entry(chan, &conn->chan_l, list) { > struct sock *sk = chan->sk; > @@ -976,7 +976,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) > bh_unlock_sock(sk); > } > > - read_unlock(&conn->chan_lock); > + mutex_unlock(&conn->chan_lock); > } > > /* Notify sockets that we cannot guaranty reliability anymore */ > @@ -986,7 +986,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) > > BT_DBG("conn %p", conn); > > - read_lock(&conn->chan_lock); > + mutex_lock(&conn->chan_lock); > > list_for_each_entry(chan, &conn->chan_l, list) { > struct sock *sk = chan->sk; > @@ -995,7 +995,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) > sk->sk_err = err; > } > > - read_unlock(&conn->chan_lock); > + mutex_unlock(&conn->chan_lock); > } > > static void l2cap_info_timeout(unsigned long arg) > @@ -1086,7 +1086,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) > conn->feat_mask = 0; > > spin_lock_init(&conn->lock); > - rwlock_init(&conn->chan_lock); > + mutex_init(&conn->chan_lock); > > INIT_LIST_HEAD(&conn->chan_l); > > @@ -1104,9 +1104,9 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) > > static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) > { > - write_lock_bh(&conn->chan_lock); > + mutex_lock(&conn->chan_lock); > __l2cap_chan_add(conn, chan); > - write_unlock_bh(&conn->chan_lock); > + mutex_unlock(&conn->chan_lock); > } > > /* ---- Socket interface ---- */ > @@ -1771,7 +1771,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) > > BT_DBG("conn %p", conn); > > - read_lock(&conn->chan_lock); > + mutex_lock(&conn->chan_lock); > list_for_each_entry(chan, &conn->chan_l, list) { > struct sock *sk = chan->sk; > if (chan->chan_type != L2CAP_CHAN_RAW) > @@ -1787,7 +1787,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) > if (chan->ops->recv(chan->data, nskb)) > kfree_skb(nskb); > } > - read_unlock(&conn->chan_lock); > + mutex_unlock(&conn->chan_lock); > } > > /* ---- L2CAP signalling commands ---- */ > @@ -2587,11 +2587,11 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd > > sk = chan->sk; > > - write_lock_bh(&conn->chan_lock); > + mutex_lock(&conn->chan_lock); > > /* Check if we already have channel with that dcid */ > if (__l2cap_get_chan_by_dcid(conn, scid)) { > - write_unlock_bh(&conn->chan_lock); > + mutex_unlock(&conn->chan_lock); > sock_set_flag(sk, SOCK_ZAPPED); > chan->ops->close(chan->data); > goto response; > @@ -2637,7 +2637,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd > status = L2CAP_CS_NO_INFO; > } > > - write_unlock_bh(&conn->chan_lock); > + mutex_unlock(&conn->chan_lock); > > response: > release_sock(parent); > @@ -4474,7 +4474,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) > del_timer(&conn->security_timer); > } > > - read_lock(&conn->chan_lock); > + mutex_lock(&conn->chan_lock); > > list_for_each_entry(chan, &conn->chan_l, list) { > struct sock *sk = chan->sk; > @@ -4554,7 +4554,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) > bh_unlock_sock(sk); > } > > - read_unlock(&conn->chan_lock); > + mutex_unlock(&conn->chan_lock); > > return 0; > } > -- > 1.7.6.4 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFC 07/22] Bluetooth: Don't use spin_lock socket lock anymore 2011-12-17 21:29 ` [RFC 07/22] Bluetooth: Don't use spin_lock socket lock anymore Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 08/22] Bluetooth: Remove sk_backlog usage from L2CAP Gustavo F. Padovan @ 2011-12-19 9:53 ` Andrei Emeltchenko 1 sibling, 0 replies; 34+ messages in thread From: Andrei Emeltchenko @ 2011-12-19 9:53 UTC (permalink / raw) To: Gustavo F. Padovan; +Cc: linux-bluetooth Hi Gustavo, On Sat, Dec 17, 2011 at 07:29:27PM -0200, Gustavo F. Padovan wrote: > From: "Gustavo F. Padovan" <padovan@profusion.mobi> > > We now run everything in process context, so the mutex lock is the best > option. But in some places we still need the bh_lock_sock() minor comment: {lock,release}_sock Best regards Andrei Emeltchenko > > Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> > --- > net/bluetooth/l2cap_core.c | 66 +++++++++++++------------------------------ > 1 files changed, 20 insertions(+), 46 deletions(-) > > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c > index 89cda6d..ed67ac0 100644 > --- a/net/bluetooth/l2cap_core.c > +++ b/net/bluetooth/l2cap_core.c > @@ -118,7 +118,7 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 ci > read_lock(&conn->chan_lock); > c = __l2cap_get_chan_by_scid(conn, cid); > if (c) > - bh_lock_sock(c->sk); > + lock_sock(c->sk); > read_unlock(&conn->chan_lock); > return c; > } > @@ -141,7 +141,7 @@ static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn > read_lock(&conn->chan_lock); > c = __l2cap_get_chan_by_ident(conn, ident); > if (c) > - bh_lock_sock(c->sk); > + lock_sock(c->sk); > read_unlock(&conn->chan_lock); > return c; > } > @@ -889,7 +889,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) > > parent = pchan->sk; > > - bh_lock_sock(parent); > + lock_sock(parent); > > /* Check for backlog size */ > if (sk_acceptq_is_full(parent)) { > @@ -922,7 +922,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) > write_unlock_bh(&conn->chan_lock); > > clean: > - bh_unlock_sock(parent); > + release_sock(parent); > } > > static void l2cap_chan_ready(struct sock *sk) > @@ -1024,9 +1024,9 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) > /* Kill channels */ > list_for_each_entry_safe(chan, l, &conn->chan_l, list) { > sk = chan->sk; > - bh_lock_sock(sk); > + lock_sock(sk); > l2cap_chan_del(chan, err); > - bh_unlock_sock(sk); > + release_sock(sk); > chan->ops->close(chan->data); > } > > @@ -2568,7 +2568,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd > > parent = pchan->sk; > > - bh_lock_sock(parent); > + lock_sock(parent); > > /* Check if the ACL is secure enough (if not SDP) */ > if (psm != cpu_to_le16(0x0001) && > @@ -2645,7 +2645,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd > write_unlock_bh(&conn->chan_lock); > > response: > - bh_unlock_sock(parent); > + release_sock(parent); > > sendresp: > rsp.scid = cpu_to_le16(scid); > @@ -2727,19 +2727,11 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd > break; > > default: > - /* don't delete l2cap channel if sk is owned by user */ > - if (sock_owned_by_user(sk)) { > - l2cap_state_change(chan, BT_DISCONN); > - __clear_chan_timer(chan); > - __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); > - break; > - } > - > l2cap_chan_del(chan, ECONNREFUSED); > break; > } > > - bh_unlock_sock(sk); > + release_sock(sk); > return 0; > } > > @@ -2861,7 +2853,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr > } > > unlock: > - bh_unlock_sock(sk); > + release_sock(sk); > return 0; > } > > @@ -2968,7 +2960,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr > } > > done: > - bh_unlock_sock(sk); > + release_sock(sk); > return 0; > } > > @@ -2997,17 +2989,8 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd > > sk->sk_shutdown = SHUTDOWN_MASK; > > - /* don't delete l2cap channel if sk is owned by user */ > - if (sock_owned_by_user(sk)) { > - l2cap_state_change(chan, BT_DISCONN); > - __clear_chan_timer(chan); > - __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); > - bh_unlock_sock(sk); > - return 0; > - } > - > l2cap_chan_del(chan, ECONNRESET); > - bh_unlock_sock(sk); > + release_sock(sk); > > chan->ops->close(chan->data); > return 0; > @@ -3031,17 +3014,8 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd > > sk = chan->sk; > > - /* don't delete l2cap channel if sk is owned by user */ > - if (sock_owned_by_user(sk)) { > - l2cap_state_change(chan, BT_DISCONN); > - __clear_chan_timer(chan); > - __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); > - bh_unlock_sock(sk); > - return 0; > - } > - > l2cap_chan_del(chan, 0); > - bh_unlock_sock(sk); > + release_sock(sk); > > chan->ops->close(chan->data); > return 0; > @@ -4284,7 +4258,7 @@ drop: > > done: > if (sk) > - bh_unlock_sock(sk); > + release_sock(sk); > > return 0; > } > @@ -4300,7 +4274,7 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str > > sk = chan->sk; > > - bh_lock_sock(sk); > + lock_sock(sk); > > BT_DBG("sk %p, len %d", sk, skb->len); > > @@ -4318,7 +4292,7 @@ drop: > > done: > if (sk) > - bh_unlock_sock(sk); > + release_sock(sk); > return 0; > } > > @@ -4333,7 +4307,7 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct > > sk = chan->sk; > > - bh_lock_sock(sk); > + lock_sock(sk); > > BT_DBG("sk %p, len %d", sk, skb->len); > > @@ -4351,7 +4325,7 @@ drop: > > done: > if (sk) > - bh_unlock_sock(sk); > + release_sock(sk); > return 0; > } > > @@ -4656,11 +4630,11 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl > BT_ERR("Frame exceeding recv MTU (len %d, " > "MTU %d)", len, > chan->imtu); > - bh_unlock_sock(sk); > + release_sock(sk); > l2cap_conn_unreliable(conn, ECOMM); > goto drop; > } > - bh_unlock_sock(sk); > + release_sock(sk); > } > > /* Allocate skb for the complete frame (with header) */ > -- > 1.7.6.4 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFC 06/22] Bluetooth: Move L2CAP timers to workqueue 2011-12-17 21:29 ` [RFC 06/22] Bluetooth: Move L2CAP timers to workqueue Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 07/22] Bluetooth: Don't use spin_lock socket lock anymore Gustavo F. Padovan @ 2011-12-19 11:05 ` Andrei Emeltchenko 2011-12-19 12:59 ` Ulisses Furquim 1 sibling, 1 reply; 34+ messages in thread From: Andrei Emeltchenko @ 2011-12-19 11:05 UTC (permalink / raw) To: Gustavo F. Padovan; +Cc: linux-bluetooth Hi Gustavo, On Sat, Dec 17, 2011 at 07:29:26PM -0200, Gustavo F. Padovan wrote: > From: "Gustavo F. Padovan" <padovan@profusion.mobi> > > L2CAP timers also need to run in process context. As the works in l2cap > are small we are using the system worqueue. > > Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> > --- > include/net/bluetooth/l2cap.h | 17 +++++----- > net/bluetooth/l2cap_core.c | 70 ++++++++++++++++++----------------------- > 2 files changed, 40 insertions(+), 47 deletions(-) ... > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c > index 0369a9b..89cda6d 100644 > --- a/net/bluetooth/l2cap_core.c > +++ b/net/bluetooth/l2cap_core.c > @@ -213,20 +213,18 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn) > return 0; > } > > -static void l2cap_set_timer(struct l2cap_chan *chan, struct timer_list *timer, long timeout) > +static void l2cap_set_timer(struct l2cap_chan *chan, struct delayed_work *work, long timeout) > { > BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout); > > - if (!mod_timer(timer, jiffies + msecs_to_jiffies(timeout))) > - chan_hold(chan); > + cancel_delayed_work_sync(work); > + > + schedule_delayed_work(work, timeout); > } > > -static void l2cap_clear_timer(struct l2cap_chan *chan, struct timer_list *timer) > +static void l2cap_clear_timer(struct delayed_work *work) > { > - BT_DBG("chan %p state %d", chan, chan->state); > - > - if (timer_pending(timer) && del_timer(timer)) > - chan_put(chan); > + cancel_delayed_work_sync(work); > } Do you think we do not need to use chan_hold / chan_put? Best regards Andrei Emeltchenko ^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFC 06/22] Bluetooth: Move L2CAP timers to workqueue 2011-12-19 11:05 ` [RFC 06/22] Bluetooth: Move L2CAP timers to workqueue Andrei Emeltchenko @ 2011-12-19 12:59 ` Ulisses Furquim 0 siblings, 0 replies; 34+ messages in thread From: Ulisses Furquim @ 2011-12-19 12:59 UTC (permalink / raw) To: Andrei Emeltchenko, Gustavo F. Padovan, linux-bluetooth Hi Andrei, On Mon, Dec 19, 2011 at 9:05 AM, Andrei Emeltchenko <andrei.emeltchenko.news@gmail.com> wrote: > Hi Gustavo, > > On Sat, Dec 17, 2011 at 07:29:26PM -0200, Gustavo F. Padovan wrote: >> From: "Gustavo F. Padovan" <padovan@profusion.mobi> >> >> L2CAP timers also need to run in process context. As the works in l2cap >> are small we are using the system worqueue. >> >> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi> >> --- >> include/net/bluetooth/l2cap.h | 17 +++++----- >> net/bluetooth/l2cap_core.c | 70 ++++++++++++++++++----------------------- >> 2 files changed, 40 insertions(+), 47 deletions(-) > > ... > >> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c >> index 0369a9b..89cda6d 100644 >> --- a/net/bluetooth/l2cap_core.c >> +++ b/net/bluetooth/l2cap_core.c >> @@ -213,20 +213,18 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn) >> return 0; >> } >> >> -static void l2cap_set_timer(struct l2cap_chan *chan, struct timer_list *timer, long timeout) >> +static void l2cap_set_timer(struct l2cap_chan *chan, struct delayed_work *work, long timeout) >> { >> BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout); >> >> - if (!mod_timer(timer, jiffies + msecs_to_jiffies(timeout))) >> - chan_hold(chan); >> + cancel_delayed_work_sync(work); >> + >> + schedule_delayed_work(work, timeout); >> } >> >> -static void l2cap_clear_timer(struct l2cap_chan *chan, struct timer_list *timer) >> +static void l2cap_clear_timer(struct delayed_work *work) >> { >> - BT_DBG("chan %p state %d", chan, chan->state); >> - >> - if (timer_pending(timer) && del_timer(timer)) >> - chan_put(chan); >> + cancel_delayed_work_sync(work); >> } > > > Do you think we do not need to use chan_hold / chan_put? It's good you spotted it too. It's a known issue Padovan is looking at. Thanks. Best regards, -- Ulisses Furquim ProFUSION embedded systems http://profusion.mobi Mobile: +55 19 9250 0942 Skype: ulissesffs ^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFC 00/22] Bluetooth: change tasklets to workqueue 2011-12-17 21:29 [RFC 00/22] Bluetooth: change tasklets to workqueue Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 01/22] Bluetooth: Process recv path in a workqueue instead of a tasklet Gustavo F. Padovan @ 2011-12-17 21:34 ` Gustavo Padovan 2011-12-17 22:17 ` Marcel Holtmann 2 siblings, 0 replies; 34+ messages in thread From: Gustavo Padovan @ 2011-12-17 21:34 UTC (permalink / raw) To: linux-bluetooth * Gustavo F. Padovan <padovan@profusion.mobi> [2011-12-17 19:29:20 -0200]: > From: "Gustavo F. Padovan" <padovan@profusion.mobi> > > Here are the patches to run the receive path in workqueue. With these patches > l2cap and rfcomm seems to be working fine, but some more work still needs to be > done. You can also check the ongoing work at http://git.kernel.org/?p=linux/kernel/git/padovan/bluetooth-testing.git Gustavo ^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFC 00/22] Bluetooth: change tasklets to workqueue 2011-12-17 21:29 [RFC 00/22] Bluetooth: change tasklets to workqueue Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 01/22] Bluetooth: Process recv path in a workqueue instead of a tasklet Gustavo F. Padovan 2011-12-17 21:34 ` [RFC 00/22] Bluetooth: change tasklets " Gustavo Padovan @ 2011-12-17 22:17 ` Marcel Holtmann 2 siblings, 0 replies; 34+ messages in thread From: Marcel Holtmann @ 2011-12-17 22:17 UTC (permalink / raw) To: Gustavo F. Padovan; +Cc: linux-bluetooth Hi Gustavo, > Here are the patches to run the receive path in workqueue. With these patches > l2cap and rfcomm seems to be working fine, but some more work still needs to be > done. so besides my two comments, this looks fine to me. Acked-by: Marcel Holtmann <marcel@holtmann.org> Regards Marcel ^ permalink raw reply [flat|nested] 34+ messages in thread
end of thread, other threads:[~2012-01-26 13:20 UTC | newest] Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2011-12-17 21:29 [RFC 00/22] Bluetooth: change tasklets to workqueue Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 01/22] Bluetooth: Process recv path in a workqueue instead of a tasklet Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 02/22] Bluetooth: Replace spin_lock by mutex in hci_dev Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 03/22] Bluetooth: Use delayed_work for connection timeout Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 04/22] Bluetooth: Use delayed work for advertisiment cache timeout Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 05/22] Bluetooth: hci_conn_auto_accept() doesn't need locking Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 06/22] Bluetooth: Move L2CAP timers to workqueue Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 07/22] Bluetooth: Don't use spin_lock socket lock anymore Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 08/22] Bluetooth: Remove sk_backlog usage from L2CAP Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 09/22] Bluetooth: move hci_task_lock to mutex Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 10/22] Bluetooth: convert chan_lock " Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 11/22] Bluetooth: Use RCU to manipulate chan_list Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 12/22] Bluetooth: convert conn hash to RCU Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 13/22] Bluetooth: Don't disable tasklets to call hdev->notify() Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 14/22] Bluetooth: Move command task to workqueue Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 15/22] Bluetooth: convert tx_task " Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 16/22] Bluetooth: convert info timer to delayed_work Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 17/22] Bluetooth: remove power_on work_struct Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 18/22] Bluetooth: invert locking order in connect path Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 19/22] Bluetooth: Change l2cap chan_list to use RCU Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 20/22] Bluetooth: move power_off to system workqueue Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 21/22] Bluetooth: Use new alloc_workqueue() Gustavo F. Padovan 2011-12-17 21:29 ` [RFC 22/22] Bluetooth: Remove work_add and work_del from hci_sysfs Gustavo F. Padovan 2011-12-17 22:15 ` [RFC 19/22] Bluetooth: Change l2cap chan_list to use RCU Marcel Holtmann 2011-12-19 10:42 ` Andrei Emeltchenko 2011-12-19 13:53 ` Gustavo Padovan 2011-12-17 22:13 ` [RFC 17/22] Bluetooth: remove power_on work_struct Marcel Holtmann 2012-01-26 13:20 ` [RFC 11/22] Bluetooth: Use RCU to manipulate chan_list Andrei Emeltchenko 2011-12-19 9:58 ` [RFC 10/22] Bluetooth: convert chan_lock to mutex Andrei Emeltchenko 2011-12-19 9:53 ` [RFC 07/22] Bluetooth: Don't use spin_lock socket lock anymore Andrei Emeltchenko 2011-12-19 11:05 ` [RFC 06/22] Bluetooth: Move L2CAP timers to workqueue Andrei Emeltchenko 2011-12-19 12:59 ` Ulisses Furquim 2011-12-17 21:34 ` [RFC 00/22] Bluetooth: change tasklets " Gustavo Padovan 2011-12-17 22:17 ` Marcel Holtmann
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.