2012-01-18 12:48:03

by Ulisses Furquim

[permalink] [raw]
Subject: [PATCH 1/2] Bluetooth: Remove usage of __cancel_delayed_work()

__cancel_delayed_work() is being used in some paths where we cannot
sleep waiting for the delayed work to finish. However, that function
might return while the timer is running and the work will be queued
again. Replace the calls with safer cancel_delayed_work() version
which spins until the timer handler finishes in other CPUs and
cancels the delayed work.

Signed-off-by: Ulisses Furquim <[email protected]>
---
include/net/bluetooth/l2cap.h | 4 ++--
net/bluetooth/l2cap_core.c | 10 +++++-----
2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 18242ea..dd2dbe8 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -611,7 +611,7 @@ static inline void l2cap_set_timer(struct l2cap_chan *chan,
{
BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout);

- if (!__cancel_delayed_work(work))
+ if (!cancel_delayed_work(work))
l2cap_chan_hold(chan);
schedule_delayed_work(work, timeout);
}
@@ -621,7 +621,7 @@ static inline bool l2cap_clear_timer(struct l2cap_chan *chan,
{
bool ret;

- ret = __cancel_delayed_work(work);
+ ret = cancel_delayed_work(work);
if (ret)
l2cap_chan_put(chan);

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 0087db8..6ee7a2d 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1018,10 +1018,10 @@ 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)
- __cancel_delayed_work(&conn->info_timer);
+ cancel_delayed_work(&conn->info_timer);

if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) {
- __cancel_delayed_work(&conn->security_timer);
+ cancel_delayed_work(&conn->security_timer);
smp_chan_destroy(conn);
}

@@ -2583,7 +2583,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) {
- __cancel_delayed_work(&conn->info_timer);
+ cancel_delayed_work(&conn->info_timer);

conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
conn->info_ident = 0;
@@ -3130,7 +3130,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;

- __cancel_delayed_work(&conn->info_timer);
+ cancel_delayed_work(&conn->info_timer);

if (result != L2CAP_IR_SUCCESS) {
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
@@ -4504,7 +4504,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)

if (hcon->type == LE_LINK) {
smp_distribute_keys(conn, 0);
- __cancel_delayed_work(&conn->security_timer);
+ cancel_delayed_work(&conn->security_timer);
}

rcu_read_lock();
--
1.7.8.rc4



2012-01-18 19:40:15

by Ulisses Furquim

[permalink] [raw]
Subject: Re: [PATCH 2/2] Bluetooth: Remove wait for delayed work to finish

Hi Andre,

On Wed, Jan 18, 2012 at 5:34 PM, Andre Guedes
<[email protected]> wrote:
> Hi Ulisses,
>
> On Wed, Jan 18, 2012 at 9:48 AM, Ulisses Furquim <[email protected]> wrote:
>> Do not wait for delayed work to finish where it's not needed. In the
>> case of adv_work the handler is already protected by the hdev lock
>> and removing the wait we also avoid introducing deadlocks involving
>> the delayed work lock.
>>
>> Signed-off-by: Ulisses Furquim <[email protected]>
>> ---
>> ?net/bluetooth/hci_core.c ?| ? ?2 +-
>> ?net/bluetooth/hci_event.c | ? ?2 +-
>> ?2 files changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
>> index a7b7200..b4041be 100644
>> --- a/net/bluetooth/hci_core.c
>> +++ b/net/bluetooth/hci_core.c
>> @@ -1731,7 +1731,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
>>
>> ? ? ? ?hci_del_sysfs(hdev);
>>
>> - ? ? ? cancel_delayed_work_sync(&hdev->adv_work);
>> + ? ? ? cancel_delayed_work(&hdev->adv_work);
>
> I'm afraid we'll introduce a race condition if we don't use the
> _sync variant at hci_unregister_dev.
>
> If we don't wait adv_work finish it may be running after hdev
> object is freed.

Indeed, you're right. And I was going through the uses of _sync() and
skipped those in paths where we free the object but didn't see this
one.

Regards,

--
Ulisses Furquim
ProFUSION embedded systems
http://profusion.mobi
Mobile: +55 19 9250 0942
Skype: ulissesffs

2012-01-18 19:34:23

by Andre Guedes

[permalink] [raw]
Subject: Re: [PATCH 2/2] Bluetooth: Remove wait for delayed work to finish

Hi Ulisses,

On Wed, Jan 18, 2012 at 9:48 AM, Ulisses Furquim <[email protected]> wrote:
> Do not wait for delayed work to finish where it's not needed. In the
> case of adv_work the handler is already protected by the hdev lock
> and removing the wait we also avoid introducing deadlocks involving
> the delayed work lock.
>
> Signed-off-by: Ulisses Furquim <[email protected]>
> ---
> ?net/bluetooth/hci_core.c ?| ? ?2 +-
> ?net/bluetooth/hci_event.c | ? ?2 +-
> ?2 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
> index a7b7200..b4041be 100644
> --- a/net/bluetooth/hci_core.c
> +++ b/net/bluetooth/hci_core.c
> @@ -1731,7 +1731,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
>
> ? ? ? ?hci_del_sysfs(hdev);
>
> - ? ? ? cancel_delayed_work_sync(&hdev->adv_work);
> + ? ? ? cancel_delayed_work(&hdev->adv_work);

I'm afraid we'll introduce a race condition if we don't use the
_sync variant at hci_unregister_dev.

If we don't wait adv_work finish it may be running after hdev
object is freed.

>
> ? ? ? ?destroy_workqueue(hdev->workqueue);
>
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index c2fe964..f28cbae 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -1045,7 +1045,7 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
> ? ? ? ?case LE_SCANNING_ENABLED:
> ? ? ? ? ? ? ? ?set_bit(HCI_LE_SCAN, &hdev->dev_flags);
>
> - ? ? ? ? ? ? ? cancel_delayed_work_sync(&hdev->adv_work);
> + ? ? ? ? ? ? ? cancel_delayed_work(&hdev->adv_work);
>
> ? ? ? ? ? ? ? ?hci_dev_lock(hdev);
> ? ? ? ? ? ? ? ?hci_adv_entries_clear(hdev);

BR,

Andre

2012-01-18 12:48:04

by Ulisses Furquim

[permalink] [raw]
Subject: [PATCH 2/2] Bluetooth: Remove wait for delayed work to finish

Do not wait for delayed work to finish where it's not needed. In the
case of adv_work the handler is already protected by the hdev lock
and removing the wait we also avoid introducing deadlocks involving
the delayed work lock.

Signed-off-by: Ulisses Furquim <[email protected]>
---
net/bluetooth/hci_core.c | 2 +-
net/bluetooth/hci_event.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index a7b7200..b4041be 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1731,7 +1731,7 @@ void hci_unregister_dev(struct hci_dev *hdev)

hci_del_sysfs(hdev);

- cancel_delayed_work_sync(&hdev->adv_work);
+ cancel_delayed_work(&hdev->adv_work);

destroy_workqueue(hdev->workqueue);

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index c2fe964..f28cbae 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1045,7 +1045,7 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
case LE_SCANNING_ENABLED:
set_bit(HCI_LE_SCAN, &hdev->dev_flags);

- cancel_delayed_work_sync(&hdev->adv_work);
+ cancel_delayed_work(&hdev->adv_work);

hci_dev_lock(hdev);
hci_adv_entries_clear(hdev);
--
1.7.8.rc4