Commit f0c9103813b3045bd5b43220b6a78c9908a45d24

Authored by Eric Lapuyade
Committed by Samuel Ortiz
1 parent 5f4d6214ef

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>

Showing 5 changed files with 57 additions and 32 deletions Side-by-side Diff

include/net/nfc/hci.h
... ... @@ -87,6 +87,8 @@
87 87  
88 88 u32 max_data_link_payload;
89 89  
  90 + bool shutting_down;
  91 +
90 92 struct mutex msg_tx_mutex;
91 93  
92 94 struct list_head msg_tx_queue;
include/net/nfc/nfc.h
... ... @@ -115,6 +115,8 @@
115 115 struct timer_list check_pres_timer;
116 116 struct work_struct check_pres_work;
117 117  
  118 + bool shutting_down;
  119 +
118 120 struct nfc_ops *ops;
119 121 };
120 122 #define to_nfc_dev(_dev) container_of(_dev, struct nfc_dev, dev)
... ... @@ -338,7 +338,7 @@
338 338 dev->active_target = target;
339 339 dev->rf_mode = NFC_RF_INITIATOR;
340 340  
341   - if (dev->ops->check_presence)
  341 + if (dev->ops->check_presence && !dev->shutting_down)
342 342 mod_timer(&dev->check_pres_timer, jiffies +
343 343 msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
344 344 }
... ... @@ -429,7 +429,7 @@
429 429 rc = dev->ops->im_transceive(dev, dev->active_target, skb, cb,
430 430 cb_context);
431 431  
432   - if (!rc && dev->ops->check_presence)
  432 + if (!rc && dev->ops->check_presence && !dev->shutting_down)
433 433 mod_timer(&dev->check_pres_timer, jiffies +
434 434 msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
435 435 } else if (dev->rf_mode == NFC_RF_TARGET && dev->ops->tm_send != NULL) {
... ... @@ -684,11 +684,6 @@
684 684  
685 685 pr_debug("dev_name=%s\n", dev_name(&dev->dev));
686 686  
687   - if (dev->ops->check_presence) {
688   - del_timer_sync(&dev->check_pres_timer);
689   - cancel_work_sync(&dev->check_pres_work);
690   - }
691   -
692 687 nfc_genl_data_exit(&dev->genl_data);
693 688 kfree(dev->targets);
694 689 kfree(dev);
695 690  
... ... @@ -706,15 +701,16 @@
706 701 rc = dev->ops->check_presence(dev, dev->active_target);
707 702 if (rc == -EOPNOTSUPP)
708 703 goto exit;
709   - if (!rc) {
710   - mod_timer(&dev->check_pres_timer, jiffies +
711   - msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
712   - } else {
  704 + if (rc) {
713 705 u32 active_target_idx = dev->active_target->idx;
714 706 device_unlock(&dev->dev);
715 707 nfc_target_lost(dev, active_target_idx);
716 708 return;
717 709 }
  710 +
  711 + if (!dev->shutting_down)
  712 + mod_timer(&dev->check_pres_timer, jiffies +
  713 + msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
718 714 }
719 715  
720 716 exit:
721 717  
722 718  
723 719  
724 720  
... ... @@ -853,26 +849,27 @@
853 849  
854 850 id = dev->idx;
855 851  
  852 + if (dev->ops->check_presence) {
  853 + device_lock(&dev->dev);
  854 + dev->shutting_down = true;
  855 + device_unlock(&dev->dev);
  856 + del_timer_sync(&dev->check_pres_timer);
  857 + cancel_work_sync(&dev->check_pres_work);
  858 + }
  859 +
  860 + rc = nfc_genl_device_removed(dev);
  861 + if (rc)
  862 + pr_debug("The userspace won't be notified that the device %s "
  863 + "was removed\n", dev_name(&dev->dev));
  864 +
  865 + nfc_llcp_unregister_device(dev);
  866 +
856 867 mutex_lock(&nfc_devlist_mutex);
857 868 nfc_devlist_generation++;
858   -
859   - /* lock to avoid unregistering a device while an operation
860   - is in progress */
861   - device_lock(&dev->dev);
862 869 device_del(&dev->dev);
863   - device_unlock(&dev->dev);
864   -
865 870 mutex_unlock(&nfc_devlist_mutex);
866 871  
867   - nfc_llcp_unregister_device(dev);
868   -
869   - rc = nfc_genl_device_removed(dev);
870   - if (rc)
871   - pr_debug("The userspace won't be notified that the device %s was removed\n",
872   - dev_name(&dev->dev));
873   -
874 872 ida_simple_remove(&nfc_index_ida, id);
875   -
876 873 }
877 874 EXPORT_SYMBOL(nfc_unregister_device);
878 875  
... ... @@ -57,6 +57,8 @@
57 57 int r = 0;
58 58  
59 59 mutex_lock(&hdev->msg_tx_mutex);
  60 + if (hdev->shutting_down)
  61 + goto exit;
60 62  
61 63 if (hdev->cmd_pending_msg) {
62 64 if (timer_pending(&hdev->cmd_timer) == 0) {
... ... @@ -868,6 +870,28 @@
868 870 {
869 871 struct hci_msg *msg, *n;
870 872  
  873 + mutex_lock(&hdev->msg_tx_mutex);
  874 +
  875 + if (hdev->cmd_pending_msg) {
  876 + if (hdev->cmd_pending_msg->cb)
  877 + hdev->cmd_pending_msg->cb(
  878 + hdev->cmd_pending_msg->cb_context,
  879 + NULL, -ESHUTDOWN);
  880 + kfree(hdev->cmd_pending_msg);
  881 + hdev->cmd_pending_msg = NULL;
  882 + }
  883 +
  884 + hdev->shutting_down = true;
  885 +
  886 + mutex_unlock(&hdev->msg_tx_mutex);
  887 +
  888 + del_timer_sync(&hdev->cmd_timer);
  889 + cancel_work_sync(&hdev->msg_tx_work);
  890 +
  891 + cancel_work_sync(&hdev->msg_rx_work);
  892 +
  893 + nfc_unregister_device(hdev->ndev);
  894 +
871 895 skb_queue_purge(&hdev->rx_hcp_frags);
872 896 skb_queue_purge(&hdev->msg_rx_queue);
873 897  
... ... @@ -876,13 +900,6 @@
876 900 skb_queue_purge(&msg->msg_frags);
877 901 kfree(msg);
878 902 }
879   -
880   - del_timer_sync(&hdev->cmd_timer);
881   -
882   - nfc_unregister_device(hdev->ndev);
883   -
884   - cancel_work_sync(&hdev->msg_tx_work);
885   - cancel_work_sync(&hdev->msg_rx_work);
886 903 }
887 904 EXPORT_SYMBOL(nfc_hci_unregister_device);
888 905  
... ... @@ -105,6 +105,13 @@
105 105 }
106 106  
107 107 mutex_lock(&hdev->msg_tx_mutex);
  108 +
  109 + if (hdev->shutting_down) {
  110 + err = -ESHUTDOWN;
  111 + mutex_unlock(&hdev->msg_tx_mutex);
  112 + goto out_skb_err;
  113 + }
  114 +
108 115 list_add_tail(&cmd->msg_l, &hdev->msg_tx_queue);
109 116 mutex_unlock(&hdev->msg_tx_mutex);
110 117