Merge tag 'for-5.18/drivers-2022-04-01' of git://git.kernel.dk/linux-block
[linux-2.6-microblaze.git] / drivers / block / loop.c
index 39e7650..a58595f 100644 (file)
@@ -79,6 +79,7 @@
 #include <linux/ioprio.h>
 #include <linux/blk-cgroup.h>
 #include <linux/sched/mm.h>
+#include <linux/statfs.h>
 
 #include "loop.h"
 
@@ -773,8 +774,13 @@ static void loop_config_discard(struct loop_device *lo)
                granularity = 0;
 
        } else {
+               struct kstatfs sbuf;
+
                max_discard_sectors = UINT_MAX >> 9;
-               granularity = inode->i_sb->s_blocksize;
+               if (!vfs_statfs(&file->f_path, &sbuf))
+                       granularity = sbuf.f_bsize;
+               else
+                       max_discard_sectors = 0;
        }
 
        if (max_discard_sectors) {
@@ -1081,7 +1087,7 @@ out_putf:
        return error;
 }
 
-static void __loop_clr_fd(struct loop_device *lo)
+static void __loop_clr_fd(struct loop_device *lo, bool release)
 {
        struct file *filp;
        gfp_t gfp = lo->old_gfp_mask;
@@ -1143,6 +1149,8 @@ static void __loop_clr_fd(struct loop_device *lo)
        /* let user-space know about this change */
        kobject_uevent(&disk_to_dev(lo->lo_disk)->kobj, KOBJ_CHANGE);
        mapping_set_gfp_mask(filp->f_mapping, gfp);
+       /* This is safe: open() is still holding a reference. */
+       module_put(THIS_MODULE);
        blk_mq_unfreeze_queue(lo->lo_queue);
 
        disk_force_media_change(lo->lo_disk, DISK_EVENT_MEDIA_CHANGE);
@@ -1150,52 +1158,44 @@ static void __loop_clr_fd(struct loop_device *lo)
        if (lo->lo_flags & LO_FLAGS_PARTSCAN) {
                int err;
 
-               mutex_lock(&lo->lo_disk->open_mutex);
+               /*
+                * open_mutex has been held already in release path, so don't
+                * acquire it if this function is called in such case.
+                *
+                * If the reread partition isn't from release path, lo_refcnt
+                * must be at least one and it can only become zero when the
+                * current holder is released.
+                */
+               if (!release)
+                       mutex_lock(&lo->lo_disk->open_mutex);
                err = bdev_disk_changed(lo->lo_disk, false);
-               mutex_unlock(&lo->lo_disk->open_mutex);
+               if (!release)
+                       mutex_unlock(&lo->lo_disk->open_mutex);
                if (err)
                        pr_warn("%s: partition scan of loop%d failed (rc=%d)\n",
                                __func__, lo->lo_number, err);
                /* Device is gone, no point in returning error */
        }
 
+       /*
+        * lo->lo_state is set to Lo_unbound here after above partscan has
+        * finished. There cannot be anybody else entering __loop_clr_fd() as
+        * Lo_rundown state protects us from all the other places trying to
+        * change the 'lo' device.
+        */
        lo->lo_flags = 0;
        if (!part_shift)
                lo->lo_disk->flags |= GENHD_FL_NO_PART;
-
-       fput(filp);
-}
-
-static void loop_rundown_completed(struct loop_device *lo)
-{
        mutex_lock(&lo->lo_mutex);
        lo->lo_state = Lo_unbound;
        mutex_unlock(&lo->lo_mutex);
-       module_put(THIS_MODULE);
-}
-
-static void loop_rundown_workfn(struct work_struct *work)
-{
-       struct loop_device *lo = container_of(work, struct loop_device,
-                                             rundown_work);
-       struct block_device *bdev = lo->lo_device;
-       struct gendisk *disk = lo->lo_disk;
-
-       __loop_clr_fd(lo);
-       kobject_put(&bdev->bd_device.kobj);
-       module_put(disk->fops->owner);
-       loop_rundown_completed(lo);
-}
-
-static void loop_schedule_rundown(struct loop_device *lo)
-{
-       struct block_device *bdev = lo->lo_device;
-       struct gendisk *disk = lo->lo_disk;
 
-       __module_get(disk->fops->owner);
-       kobject_get(&bdev->bd_device.kobj);
-       INIT_WORK(&lo->rundown_work, loop_rundown_workfn);
-       queue_work(system_long_wq, &lo->rundown_work);
+       /*
+        * Need not hold lo_mutex to fput backing file. Calling fput holding
+        * lo_mutex triggers a circular lock dependency possibility warning as
+        * fput can take open_mutex which is usually taken before lo_mutex.
+        */
+       fput(filp);
 }
 
 static int loop_clr_fd(struct loop_device *lo)
@@ -1227,8 +1227,7 @@ static int loop_clr_fd(struct loop_device *lo)
        lo->lo_state = Lo_rundown;
        mutex_unlock(&lo->lo_mutex);
 
-       __loop_clr_fd(lo);
-       loop_rundown_completed(lo);
+       __loop_clr_fd(lo, false);
        return 0;
 }
 
@@ -1754,7 +1753,7 @@ static void lo_release(struct gendisk *disk, fmode_t mode)
                 * In autoclear mode, stop the loop thread
                 * and remove configuration after last close.
                 */
-               loop_schedule_rundown(lo);
+               __loop_clr_fd(lo, true);
                return;
        } else if (lo->lo_state == Lo_bound) {
                /*