NFC: Fixed nfc core and hci unregistration and cleanup
When an adapter is removed, it will unregister itself from hci and/or nfc core. In order to do that safely, work tasks must first be canceled and prevented to be scheduled again, before the hci or nfc device can be destroyed. Signed-off-by: Eric Lapuyade <eric.lapuyade@intel.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
parent
5f4d6214ef
commit
f0c9103813
@ -87,6 +87,8 @@ struct nfc_hci_dev {
|
||||
|
||||
u32 max_data_link_payload;
|
||||
|
||||
bool shutting_down;
|
||||
|
||||
struct mutex msg_tx_mutex;
|
||||
|
||||
struct list_head msg_tx_queue;
|
||||
|
@ -115,6 +115,8 @@ struct nfc_dev {
|
||||
struct timer_list check_pres_timer;
|
||||
struct work_struct check_pres_work;
|
||||
|
||||
bool shutting_down;
|
||||
|
||||
struct nfc_ops *ops;
|
||||
};
|
||||
#define to_nfc_dev(_dev) container_of(_dev, struct nfc_dev, dev)
|
||||
|
@ -338,7 +338,7 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol)
|
||||
dev->active_target = target;
|
||||
dev->rf_mode = NFC_RF_INITIATOR;
|
||||
|
||||
if (dev->ops->check_presence)
|
||||
if (dev->ops->check_presence && !dev->shutting_down)
|
||||
mod_timer(&dev->check_pres_timer, jiffies +
|
||||
msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
|
||||
}
|
||||
@ -429,7 +429,7 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb,
|
||||
rc = dev->ops->im_transceive(dev, dev->active_target, skb, cb,
|
||||
cb_context);
|
||||
|
||||
if (!rc && dev->ops->check_presence)
|
||||
if (!rc && dev->ops->check_presence && !dev->shutting_down)
|
||||
mod_timer(&dev->check_pres_timer, jiffies +
|
||||
msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
|
||||
} else if (dev->rf_mode == NFC_RF_TARGET && dev->ops->tm_send != NULL) {
|
||||
@ -684,11 +684,6 @@ static void nfc_release(struct device *d)
|
||||
|
||||
pr_debug("dev_name=%s\n", dev_name(&dev->dev));
|
||||
|
||||
if (dev->ops->check_presence) {
|
||||
del_timer_sync(&dev->check_pres_timer);
|
||||
cancel_work_sync(&dev->check_pres_work);
|
||||
}
|
||||
|
||||
nfc_genl_data_exit(&dev->genl_data);
|
||||
kfree(dev->targets);
|
||||
kfree(dev);
|
||||
@ -706,15 +701,16 @@ static void nfc_check_pres_work(struct work_struct *work)
|
||||
rc = dev->ops->check_presence(dev, dev->active_target);
|
||||
if (rc == -EOPNOTSUPP)
|
||||
goto exit;
|
||||
if (!rc) {
|
||||
mod_timer(&dev->check_pres_timer, jiffies +
|
||||
msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
|
||||
} else {
|
||||
if (rc) {
|
||||
u32 active_target_idx = dev->active_target->idx;
|
||||
device_unlock(&dev->dev);
|
||||
nfc_target_lost(dev, active_target_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dev->shutting_down)
|
||||
mod_timer(&dev->check_pres_timer, jiffies +
|
||||
msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
|
||||
}
|
||||
|
||||
exit:
|
||||
@ -853,26 +849,27 @@ void nfc_unregister_device(struct nfc_dev *dev)
|
||||
|
||||
id = dev->idx;
|
||||
|
||||
mutex_lock(&nfc_devlist_mutex);
|
||||
nfc_devlist_generation++;
|
||||
|
||||
/* lock to avoid unregistering a device while an operation
|
||||
is in progress */
|
||||
device_lock(&dev->dev);
|
||||
device_del(&dev->dev);
|
||||
device_unlock(&dev->dev);
|
||||
|
||||
mutex_unlock(&nfc_devlist_mutex);
|
||||
|
||||
nfc_llcp_unregister_device(dev);
|
||||
if (dev->ops->check_presence) {
|
||||
device_lock(&dev->dev);
|
||||
dev->shutting_down = true;
|
||||
device_unlock(&dev->dev);
|
||||
del_timer_sync(&dev->check_pres_timer);
|
||||
cancel_work_sync(&dev->check_pres_work);
|
||||
}
|
||||
|
||||
rc = nfc_genl_device_removed(dev);
|
||||
if (rc)
|
||||
pr_debug("The userspace won't be notified that the device %s was removed\n",
|
||||
dev_name(&dev->dev));
|
||||
pr_debug("The userspace won't be notified that the device %s "
|
||||
"was removed\n", dev_name(&dev->dev));
|
||||
|
||||
nfc_llcp_unregister_device(dev);
|
||||
|
||||
mutex_lock(&nfc_devlist_mutex);
|
||||
nfc_devlist_generation++;
|
||||
device_del(&dev->dev);
|
||||
mutex_unlock(&nfc_devlist_mutex);
|
||||
|
||||
ida_simple_remove(&nfc_index_ida, id);
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL(nfc_unregister_device);
|
||||
|
||||
|
@ -57,6 +57,8 @@ static void nfc_hci_msg_tx_work(struct work_struct *work)
|
||||
int r = 0;
|
||||
|
||||
mutex_lock(&hdev->msg_tx_mutex);
|
||||
if (hdev->shutting_down)
|
||||
goto exit;
|
||||
|
||||
if (hdev->cmd_pending_msg) {
|
||||
if (timer_pending(&hdev->cmd_timer) == 0) {
|
||||
@ -868,6 +870,28 @@ void nfc_hci_unregister_device(struct nfc_hci_dev *hdev)
|
||||
{
|
||||
struct hci_msg *msg, *n;
|
||||
|
||||
mutex_lock(&hdev->msg_tx_mutex);
|
||||
|
||||
if (hdev->cmd_pending_msg) {
|
||||
if (hdev->cmd_pending_msg->cb)
|
||||
hdev->cmd_pending_msg->cb(
|
||||
hdev->cmd_pending_msg->cb_context,
|
||||
NULL, -ESHUTDOWN);
|
||||
kfree(hdev->cmd_pending_msg);
|
||||
hdev->cmd_pending_msg = NULL;
|
||||
}
|
||||
|
||||
hdev->shutting_down = true;
|
||||
|
||||
mutex_unlock(&hdev->msg_tx_mutex);
|
||||
|
||||
del_timer_sync(&hdev->cmd_timer);
|
||||
cancel_work_sync(&hdev->msg_tx_work);
|
||||
|
||||
cancel_work_sync(&hdev->msg_rx_work);
|
||||
|
||||
nfc_unregister_device(hdev->ndev);
|
||||
|
||||
skb_queue_purge(&hdev->rx_hcp_frags);
|
||||
skb_queue_purge(&hdev->msg_rx_queue);
|
||||
|
||||
@ -876,13 +900,6 @@ void nfc_hci_unregister_device(struct nfc_hci_dev *hdev)
|
||||
skb_queue_purge(&msg->msg_frags);
|
||||
kfree(msg);
|
||||
}
|
||||
|
||||
del_timer_sync(&hdev->cmd_timer);
|
||||
|
||||
nfc_unregister_device(hdev->ndev);
|
||||
|
||||
cancel_work_sync(&hdev->msg_tx_work);
|
||||
cancel_work_sync(&hdev->msg_rx_work);
|
||||
}
|
||||
EXPORT_SYMBOL(nfc_hci_unregister_device);
|
||||
|
||||
|
@ -105,6 +105,13 @@ int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe,
|
||||
}
|
||||
|
||||
mutex_lock(&hdev->msg_tx_mutex);
|
||||
|
||||
if (hdev->shutting_down) {
|
||||
err = -ESHUTDOWN;
|
||||
mutex_unlock(&hdev->msg_tx_mutex);
|
||||
goto out_skb_err;
|
||||
}
|
||||
|
||||
list_add_tail(&cmd->msg_l, &hdev->msg_tx_queue);
|
||||
mutex_unlock(&hdev->msg_tx_mutex);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user