From: Stephen Hemminger Date: Fri, 14 Sep 2018 15:30:19 +0000 (-0700) Subject: igb_uio: fix refcount if open returns error X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=ab856f2947ef0af523eb4d22f4aa8347bbf07391;p=dpdk.git igb_uio: fix refcount if open returns error This fixes the problem of reference count leak if igbuio_pci_enable_interrupts fails. Also, replace mutex and integer with a kernel atomic counter. This is standard pattern for kernel devices. Fixes: 19685d5aa79c ("igb_uio: allow multi-process access") Cc: stable@dpdk.org Signed-off-by: Stephen Hemminger Acked-by: Ferruh Yigit --- diff --git a/kernel/linux/igb_uio/igb_uio.c b/kernel/linux/igb_uio/igb_uio.c index 3398eacd3f..fede66cf27 100644 --- a/kernel/linux/igb_uio/igb_uio.c +++ b/kernel/linux/igb_uio/igb_uio.c @@ -26,8 +26,7 @@ struct rte_uio_pci_dev { struct uio_info info; struct pci_dev *pdev; enum rte_intr_mode mode; - struct mutex lock; - int refcnt; + atomic_t refcnt; }; static int wc_activate; @@ -320,23 +319,19 @@ igbuio_pci_open(struct uio_info *info, struct inode *inode) struct pci_dev *dev = udev->pdev; int err; - mutex_lock(&udev->lock); - if (++udev->refcnt > 1) { - mutex_unlock(&udev->lock); + if (atomic_inc_return(&udev->refcnt) != 1) return 0; - } /* set bus master, which was cleared by the reset function */ pci_set_master(dev); /* enable interrupts */ err = igbuio_pci_enable_interrupts(udev); - mutex_unlock(&udev->lock); if (err) { + atomic_dec(&udev->refcnt); dev_err(&dev->dev, "Enable interrupt fails\n"); - return err; } - return 0; + return err; } static int @@ -345,19 +340,14 @@ igbuio_pci_release(struct uio_info *info, struct inode *inode) struct rte_uio_pci_dev *udev = info->priv; struct pci_dev *dev = udev->pdev; - mutex_lock(&udev->lock); - if (--udev->refcnt > 0) { - mutex_unlock(&udev->lock); - return 0; - } - - /* disable interrupts */ - igbuio_pci_disable_interrupts(udev); + if (atomic_dec_and_test(&udev->refcnt)) { + /* disable interrupts */ + igbuio_pci_disable_interrupts(udev); - /* stop the device from further DMA */ - pci_clear_master(dev); + /* stop the device from further DMA */ + pci_clear_master(dev); + } - mutex_unlock(&udev->lock); return 0; } @@ -489,7 +479,6 @@ igbuio_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) if (!udev) return -ENOMEM; - mutex_init(&udev->lock); /* * enable device: ask low-level code to enable I/O and * memory @@ -529,6 +518,7 @@ igbuio_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) udev->info.release = igbuio_pci_release; udev->info.priv = udev; udev->pdev = dev; + atomic_set(&udev->refcnt, 0); err = sysfs_create_group(&dev->dev.kobj, &dev_attr_grp); if (err != 0) @@ -580,7 +570,6 @@ igbuio_pci_remove(struct pci_dev *dev) { struct rte_uio_pci_dev *udev = pci_get_drvdata(dev); - mutex_destroy(&udev->lock); sysfs_remove_group(&dev->dev.kobj, &dev_attr_grp); uio_unregister_device(&udev->info); igbuio_pci_release_iomem(&udev->info);