[PATCH v2 5/8] Bluetooth: hci_sync: make hci_cmd_sync_run* return -EEXIST if not run

Pauli Virtanen
2025-11-02T16:23:09Z

hci_cmd_sync_run_once() needs to indicate whether a queue item was
added, so caller can know if callbacks are called, so it can avoid
leaking resources.

Change the function to return -EEXIST if queue item already exists.

hci_cmd_sync_run() may run the work immediately. If so, make it behave
as if item was queued successfully. Change it to call also destroy() and
return 0.

Modify all callsites vs. the changes.

Signed-off-by: Pauli Virtanen <pav@iki.fi>
---

Notes:
v2:
- no change

net/bluetooth/hci_conn.c | 4 +++-
net/bluetooth/hci_sync.c | 13 ++++++++++---
2 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index d140e5740f92..214fa6ec832b 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -2959,6 +2959,7 @@ static int abort_conn_sync(struct hci_dev *hdev, void *data)
int hci_abort_conn(struct hci_conn *conn, u8 reason)
{
struct hci_dev *hdev = conn->hdev;
+ int err;

/* If abort_reason has already been set it means the connection is
* already being aborted so don't attempt to overwrite it.
@@ -2995,7 +2996,8 @@ int hci_abort_conn(struct hci_conn *conn, u8 reason)
* as a result to MGMT_OP_DISCONNECT/MGMT_OP_UNPAIR which does
* already queue its callback on cmd_sync_work.
*/
- return hci_cmd_sync_run_once(hdev, abort_conn_sync, conn, NULL);
+ err = hci_cmd_sync_run_once(hdev, abort_conn_sync, conn, NULL);
+ return (err == -EEXIST) ? 0 : err;
}

void hci_setup_tx_timestamp(struct sk_buff *skb, size_t key_offset,
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index a71a1b7b2541..6c4c736cf93a 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -801,8 +801,15 @@ int hci_cmd_sync_run(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
return -ENETDOWN;

/* If on cmd_sync_work then run immediately otherwise queue */
- if (current_work() == &hdev->cmd_sync_work)
- return func(hdev, data);
+ if (current_work() == &hdev->cmd_sync_work) {
+ int err;
+
+ err = func(hdev, data);
+ if (destroy)
+ destroy(hdev, data, err);
+
+ return 0;
+ }

return hci_cmd_sync_submit(hdev, func, data, destroy);
}
@@ -818,7 +825,7 @@ int hci_cmd_sync_run_once(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
void *data, hci_cmd_sync_work_destroy_t destroy)
{
if (hci_cmd_sync_lookup_entry(hdev, func, data, destroy))
- return 0;
+ return -EEXIST;

return hci_cmd_sync_run(hdev, func, data, destroy);
}
--
2.51.1