From: Weifeng Su The /dev/uioX device has concurrent operations in a few scenarios. For example, when a process using the device exits abnormally, the management program starts the same process to operate the device. When the process exits and closes the /dev/uioX device, the master bit of the device is cleared. In this case, if the new process is issuing commands, I/Os are suspended and cannot be automatically recovered. Therefore, reference counting is added to clear the master bit only when the last process exits. Signed-off-by: Weifeng Su --- The difference between the first patch and the first patch is that the reference counting operation is performed using the atomic semantics, just like other drivers under UIO: cdfa835c6e5e87d145f("uio_hv_generic: defer opening vmbus until first use"). drivers/uio/uio_pci_generic.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/uio/uio_pci_generic.c b/drivers/uio/uio_pci_generic.c index e03f9b532..df436e3d9 100644 --- a/drivers/uio/uio_pci_generic.c +++ b/drivers/uio/uio_pci_generic.c @@ -31,6 +31,7 @@ struct uio_pci_generic_dev { struct uio_info info; struct pci_dev *pdev; + atomic_t refcnt; }; static inline struct uio_pci_generic_dev * @@ -39,10 +40,19 @@ to_uio_pci_generic_dev(struct uio_info *info) return container_of(info, struct uio_pci_generic_dev, info); } +static int open(struct uio_info *info, struct inode *inode) +{ + struct uio_pci_generic_dev *gdev = to_uio_pci_generic_dev(info); + + atomic_inc(&gdev->refcnt); + return 0; +} + static int release(struct uio_info *info, struct inode *inode) { struct uio_pci_generic_dev *gdev = to_uio_pci_generic_dev(info); + /* * This driver is insecure when used with devices doing DMA, but some  * people (mis)use it with such devices. @@ -51,7 +61,8 @@ static int release(struct uio_info *info, struct inode *inode)  * Note that there's a non-zero chance doing this will wedge the device  * at least until reset. */ - pci_clear_master(gdev->pdev); + if (atomic_dec_and_test(&gdev->refcnt)) + pci_clear_master(gdev->pdev); return 0; } @@ -93,7 +104,9 @@ static int probe(struct pci_dev *pdev, gdev->info.name = "uio_pci_generic"; gdev->info.version = DRIVER_VERSION; gdev->info.release = release; + gdev->info.open = open; gdev->pdev = pdev; + atomic_set(&gdev->refcnt, 0); if (pdev->irq && (pdev->irq != IRQ_NOTCONNECTED)) { gdev->info.irq = pdev->irq; gdev->info.irq_flags = IRQF_SHARED; -- 2.33.0