lkml.org 
[lkml]   [2011]   [Apr]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH 2/2] block: rescan partitions on invalidated devices on -ENOMEDIA too
    __blkdev_get() doesn't rescan partitions if disk->fops->open() fails,
    which leads to ghost partition devices lingering after medimum removal
    is known to both the kernel and userland. The behavior also creates a
    subtle inconsistency where O_NONBLOCK open, which doesn't fail even if
    there's no medium, clears the ghots partitions, which is exploited to
    work around the problem from userland.

    Fix it by updating __blkdev_get() to issue partition rescan after
    -ENOMEDIA too.

    This was reported in the following bz.

    https://bugzilla.kernel.org/show_bug.cgi?id=13029

    Signed-off-by: Tejun Heo <tj@kernel.org>
    Reported-by: David Zeuthen <zeuthen@gmail.com>
    Reported-by: Martin Pitt <martin.pitt@ubuntu.com>
    Reported-by: Kay Sievers <kay.sievers@vrfy.org>
    Tested-by: Kay Sievers <kay.sievers@vrfy.org>
    Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
    ---
    fs/block_dev.c | 27 ++++++++++++++++++---------
    1 file changed, 18 insertions(+), 9 deletions(-)

    diff --git a/fs/block_dev.c b/fs/block_dev.c
    index c1511c6..a926ad4 100644
    --- a/fs/block_dev.c
    +++ b/fs/block_dev.c
    @@ -1102,6 +1102,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
    if (!bdev->bd_part)
    goto out_clear;

    + ret = 0;
    if (disk->fops->open) {
    ret = disk->fops->open(bdev, mode);
    if (ret == -ERESTARTSYS) {
    @@ -1118,9 +1119,18 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
    put_disk(disk);
    goto restart;
    }
    - if (ret)
    - goto out_clear;
    }
    + /*
    + * If the device is invalidated, rescan partition
    + * if open succeeded or failed with -ENOMEDIUM.
    + * The latter is necessary to prevent ghost
    + * partitions on a removed medium.
    + */
    + if (bdev->bd_invalidated && (!ret || ret == -ENOMEDIUM))
    + rescan_partitions(disk, bdev);
    + if (ret)
    + goto out_clear;
    +
    if (!bdev->bd_openers) {
    bd_set_size(bdev,(loff_t)get_capacity(disk)<<9);
    bdi = blk_get_backing_dev_info(bdev);
    @@ -1128,8 +1138,6 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
    bdi = &default_backing_dev_info;
    bdev_inode_switch_bdi(bdev->bd_inode, bdi);
    }
    - if (bdev->bd_invalidated)
    - rescan_partitions(disk, bdev);
    } else {
    struct block_device *whole;
    whole = bdget_disk(disk, 0);
    @@ -1153,13 +1161,14 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
    }
    } else {
    if (bdev->bd_contains == bdev) {
    - if (bdev->bd_disk->fops->open) {
    + ret = 0;
    + if (bdev->bd_disk->fops->open)
    ret = bdev->bd_disk->fops->open(bdev, mode);
    - if (ret)
    - goto out_unlock_bdev;
    - }
    - if (bdev->bd_invalidated)
    + /* the same as first opener case, read comment there */
    + if (bdev->bd_invalidated && (!ret || ret == -ENOMEDIUM))
    rescan_partitions(bdev->bd_disk, bdev);
    + if (ret)
    + goto out_unlock_bdev;
    }
    /* only one opener holds refs to the module and disk */
    module_put(disk->fops->owner);

    \
     
     \ /
      Last update: 2011-04-06 14:25    [W:0.027 / U:0.372 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site