]> www.infradead.org Git - users/hch/block.git/commitdiff
loop: only take lo_mutex for the first reference in lo_open
authorChristoph Hellwig <hch@lst.de>
Wed, 26 Jan 2022 14:23:45 +0000 (15:23 +0100)
committerChristoph Hellwig <hch@lst.de>
Fri, 28 Jan 2022 12:58:53 +0000 (13:58 +0100)
lo_refcnt is only incremented in lo_open and decremented in lo_release,
and thus protected by open_mutex.  Only take lo_mutex when lo_open is
called the first time, as only for the first open there is any affect
on the driver state (incremental opens on partitions don't end up in
lo_open at all already).

Signed-off-by: Christoph Hellwig <hch@lst.de>
Tested-by: Darrick J. Wong <djwong@kernel.org>
drivers/block/loop.c

index b58dc95f80d96dac6a962e9359d78de8174bbd6c..f349ddfc0e84a53b7e2aaa88c42acc46fba28cb2 100644 (file)
@@ -1725,13 +1725,20 @@ static int lo_open(struct block_device *bdev, fmode_t mode)
        struct loop_device *lo = bdev->bd_disk->private_data;
        int err;
 
+       /*
+        * Note: this requires disk->open_mutex to protect against races
+        * with lo_release.
+        */
+       if (atomic_inc_return(&lo->lo_refcnt) > 1)
+               return 0;
+
        err = mutex_lock_killable(&lo->lo_mutex);
        if (err)
                return err;
-       if (lo->lo_state == Lo_deleting)
+       if (lo->lo_state == Lo_deleting) {
+               atomic_dec(&lo->lo_refcnt);
                err = -ENXIO;
-       else
-               atomic_inc(&lo->lo_refcnt);
+       }
        mutex_unlock(&lo->lo_mutex);
        return err;
 }