Messages in this thread Patch in this message | | | Date | Thu, 28 Apr 2022 12:03:45 +0800 (GMT+08:00) | From | duoming@zju ... | Subject | Re: Re: [PATCH net v4] nfc: nfcmrvl: main: reorder destructive operations in nfcmrvl_nci_unregister_dev to avoid bugs |
| |
Hello,
On Wed, 27 Apr 2022 17:45:48 -0700 Jakub Kicinski wrote:
> > diff --git a/net/nfc/core.c b/net/nfc/core.c > > index dc7a2404efd..1d91334ee86 100644 > > --- a/net/nfc/core.c > > +++ b/net/nfc/core.c > > @@ -25,6 +25,8 @@ > > #define NFC_CHECK_PRES_FREQ_MS 2000 > > > > int nfc_devlist_generation; > > +/* nfc_download: used to judge whether nfc firmware download could start */ > > +static bool nfc_download; > > DEFINE_MUTEX(nfc_devlist_mutex); > > > > /* NFC device ID bitmap */ > > @@ -38,7 +40,7 @@ int nfc_fw_download(struct nfc_dev *dev, const char *firmware_name) > > > > device_lock(&dev->dev); > > > > - if (!device_is_registered(&dev->dev)) { > > + if (!device_is_registered(&dev->dev) || !nfc_download) { > > rc = -ENODEV; > > goto error; > > } > > @@ -1134,6 +1136,7 @@ int nfc_register_device(struct nfc_dev *dev) > > dev->rfkill = NULL; > > } > > } > > + nfc_download = true; > > device_unlock(&dev->dev); > > > > rc = nfc_genl_device_added(dev); > > @@ -1166,6 +1169,7 @@ void nfc_unregister_device(struct nfc_dev *dev) > > rfkill_unregister(dev->rfkill); > > rfkill_destroy(dev->rfkill); > > } > > + nfc_download = false; > > device_unlock(&dev->dev); > > > > if (dev->ops->check_presence) { > > You can't use a single global variable, there can be many devices > each with their own lock. > > Paolo suggested adding a lock, if spin lock doesn't fit the bill > why not add a mutex?
We could not use mutex either, because the release_firmware() is also called by fw_dnld_timeout() which is a timer handler. If we use mutex lock in a timer handler, it will cause sleep in atomic bug. The process is shown below:
nfcmrvl_fw_dnld_start ... mod_timer (wait a time) fw_dnld_timeout fw_dnld_over release_firmware
I will change the single global variable to dev->dev_up flag, which is shown below:
diff --git a/drivers/nfc/nfcmrvl/main.c b/drivers/nfc/nfcmrvl/main.c index 2fcf545012b..1a5284de434 100644 --- a/drivers/nfc/nfcmrvl/main.c +++ b/drivers/nfc/nfcmrvl/main.c @@ -183,6 +183,7 @@ void nfcmrvl_nci_unregister_dev(struct nfcmrvl_private *priv) { struct nci_dev *ndev = priv->ndev;
+ nci_unregister_device(ndev); if (priv->ndev->nfc_dev->fw_download_in_progress) nfcmrvl_fw_dnld_abort(priv);
@@ -191,7 +192,6 @@ void nfcmrvl_nci_unregister_dev(struct nfcmrvl_private *priv) if (gpio_is_valid(priv->config.reset_n_io)) gpio_free(priv->config.reset_n_io);
- nci_unregister_device(ndev); nci_free_device(ndev); kfree(priv); } diff --git a/net/nfc/core.c b/net/nfc/core.c index dc7a2404efd..09f54c599fe 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -1166,6 +1166,7 @@ void nfc_unregister_device(struct nfc_dev *dev) rfkill_unregister(dev->rfkill); rfkill_destroy(dev->rfkill); } + dev->dev_up = false; device_unlock(&dev->dev);
if (dev->ops->check_presence) { The above solution has been tested, it is well synchronized.
Best regards, Duoming Zhou | |