Commit 008ee9eb authored by Luiz Augusto von Dentz's avatar Luiz Augusto von Dentz Committed by Marcel Holtmann
Browse files

Bluetooth: hci_sync: Fix not processing all entries on cmd_sync_work

hci_cmd_sync_queue can be called multiple times, each adding a
hci_cmd_sync_work_entry, before hci_cmd_sync_work is run so this makes
sure they are all dequeued properly otherwise it creates a backlog of
entries that are never run.

Link: https://lore.kernel.org/all/CAJCQCtSeUtHCgsHXLGrSTWKmyjaQDbDNpP4rb0i+RE+L2FTXSA@mail.gmail.com/T/


Fixes: 6a98e383 ("Bluetooth: Add helper for serialized HCI command execution")
Tested-by: default avatarChris Clayton <chris2553@googlemail.com>
Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 815d5121
Loading
Loading
Loading
Loading
+23 −26
Original line number Diff line number Diff line
@@ -276,41 +276,38 @@ EXPORT_SYMBOL(__hci_cmd_sync_status);
static void hci_cmd_sync_work(struct work_struct *work)
{
	struct hci_dev *hdev = container_of(work, struct hci_dev, cmd_sync_work);
	struct hci_cmd_sync_work_entry *entry;
	hci_cmd_sync_work_func_t func;
	hci_cmd_sync_work_destroy_t destroy;
	void *data;

	bt_dev_dbg(hdev, "");

	/* Dequeue all entries and run them */
	while (1) {
		struct hci_cmd_sync_work_entry *entry;

		mutex_lock(&hdev->cmd_sync_work_lock);
	entry = list_first_entry(&hdev->cmd_sync_work_list,
				 struct hci_cmd_sync_work_entry, list);
	if (entry) {
		entry = list_first_entry_or_null(&hdev->cmd_sync_work_list,
						 struct hci_cmd_sync_work_entry,
						 list);
		if (entry)
			list_del(&entry->list);
		func = entry->func;
		data = entry->data;
		destroy = entry->destroy;
		kfree(entry);
	} else {
		func = NULL;
		data = NULL;
		destroy = NULL;
	}
		mutex_unlock(&hdev->cmd_sync_work_lock);

	if (func) {
		int err;

		hci_req_sync_lock(hdev);
		if (!entry)
			break;

		err = func(hdev, data);
		bt_dev_dbg(hdev, "entry %p", entry);

		if (destroy)
			destroy(hdev, data, err);
		if (entry->func) {
			int err;

			hci_req_sync_lock(hdev);
			err = entry->func(hdev, entry->data);
			if (entry->destroy)
				entry->destroy(hdev, entry->data, err);
			hci_req_sync_unlock(hdev);
		}

		kfree(entry);
	}
}

static void hci_cmd_sync_cancel_work(struct work_struct *work)