]> www.infradead.org Git - users/hch/block.git/commitdiff
loop: only take lo_mutex for the last reference in lo_release
authorChristoph Hellwig <hch@lst.de>
Wed, 26 Jan 2022 14:21:21 +0000 (15:21 +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_release
actually takes action for the final release.

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

index d3a7f281ce1b6394cba11b0086c77efaa931937e..b58dc95f80d96dac6a962e9359d78de8174bbd6c 100644 (file)
@@ -1740,10 +1740,14 @@ static void lo_release(struct gendisk *disk, fmode_t mode)
 {
        struct loop_device *lo = disk->private_data;
 
-       mutex_lock(&lo->lo_mutex);
-       if (atomic_dec_return(&lo->lo_refcnt))
-               goto out_unlock;
+       /*
+        * Note: this requires disk->open_mutex to protect against races
+        * with lo_open.
+        */
+       if (!atomic_dec_and_test(&lo->lo_refcnt))
+               return;
 
+       mutex_lock(&lo->lo_mutex);
        if (lo->lo_flags & LO_FLAGS_AUTOCLEAR) {
                if (lo->lo_state != Lo_bound)
                        goto out_unlock;