lkml.org 
[lkml]   [2019]   [Mar]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH AUTOSEL 4.19 068/192] loop: set GENHD_FL_NO_PART_SCAN after blkdev_reread_part()
    Date
    From: Dongli Zhang <dongli.zhang@oracle.com>

    [ Upstream commit 758a58d0bc67457f1215321a536226654a830eeb ]

    Commit 0da03cab87e6
    ("loop: Fix deadlock when calling blkdev_reread_part()") moves
    blkdev_reread_part() out of the loop_ctl_mutex. However,
    GENHD_FL_NO_PART_SCAN is set before __blkdev_reread_part(). As a result,
    __blkdev_reread_part() will fail the check of GENHD_FL_NO_PART_SCAN and
    will not rescan the loop device to delete all partitions.

    Below are steps to reproduce the issue:

    step1 # dd if=/dev/zero of=tmp.raw bs=1M count=100
    step2 # losetup -P /dev/loop0 tmp.raw
    step3 # parted /dev/loop0 mklabel gpt
    step4 # parted -a none -s /dev/loop0 mkpart primary 64s 1
    step5 # losetup -d /dev/loop0

    Step5 will not be able to delete /dev/loop0p1 (introduced by step4) and
    there is below kernel warning message:

    [ 464.414043] __loop_clr_fd: partition scan of loop0 failed (rc=-22)

    This patch sets GENHD_FL_NO_PART_SCAN after blkdev_reread_part().

    Fixes: 0da03cab87e6 ("loop: Fix deadlock when calling blkdev_reread_part()")
    Signed-off-by: Dongli Zhang <dongli.zhang@oracle.com>
    Reviewed-by: Jan Kara <jack@suse.cz>
    Signed-off-by: Jens Axboe <axboe@kernel.dk>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/block/loop.c | 21 +++++++++++++++++----
    1 file changed, 17 insertions(+), 4 deletions(-)

    diff --git a/drivers/block/loop.c b/drivers/block/loop.c
    index c9c2bcc36e26..fc83a8f21ce3 100644
    --- a/drivers/block/loop.c
    +++ b/drivers/block/loop.c
    @@ -1090,16 +1090,12 @@ static int __loop_clr_fd(struct loop_device *lo, bool release)
    kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE);
    }
    mapping_set_gfp_mask(filp->f_mapping, gfp);
    - lo->lo_state = Lo_unbound;
    /* This is safe: open() is still holding a reference. */
    module_put(THIS_MODULE);
    blk_mq_unfreeze_queue(lo->lo_queue);

    partscan = lo->lo_flags & LO_FLAGS_PARTSCAN && bdev;
    lo_number = lo->lo_number;
    - lo->lo_flags = 0;
    - if (!part_shift)
    - lo->lo_disk->flags |= GENHD_FL_NO_PART_SCAN;
    loop_unprepare_queue(lo);
    out_unlock:
    mutex_unlock(&loop_ctl_mutex);
    @@ -1121,6 +1117,23 @@ static int __loop_clr_fd(struct loop_device *lo, bool release)
    /* Device is gone, no point in returning error */
    err = 0;
    }
    +
    + /*
    + * 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->lo_backing_file is already cleared and Lo_rundown state
    + * protects us from all the other places trying to change the 'lo'
    + * device.
    + */
    + mutex_lock(&loop_ctl_mutex);
    + lo->lo_flags = 0;
    + if (!part_shift)
    + lo->lo_disk->flags |= GENHD_FL_NO_PART_SCAN;
    + lo->lo_state = Lo_unbound;
    + mutex_unlock(&loop_ctl_mutex);
    +
    /*
    * Need not hold loop_ctl_mutex to fput backing file.
    * Calling fput holding loop_ctl_mutex triggers a circular
    --
    2.19.1
    \
     
     \ /
      Last update: 2019-03-27 20:07    [W:6.730 / U:0.056 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site