lkml.org 
[lkml]   [2022]   [Sep]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.10 74/80] btrfs: harden identification of a stale device
    Date
    From: Anand Jain <anand.jain@oracle.com>

    commit 770c79fb65506fc7c16459855c3839429f46cb32 upstream.

    Identifying and removing the stale device from the fs_uuids list is done
    by btrfs_free_stale_devices(). btrfs_free_stale_devices() in turn
    depends on device_path_matched() to check if the device appears in more
    than one btrfs_device structure.

    The matching of the device happens by its path, the device path. However,
    when device mapper is in use, the dm device paths are nothing but a link
    to the actual block device, which leads to the device_path_matched()
    failing to match.

    Fix this by matching the dev_t as provided by lookup_bdev() instead of
    plain string compare of the device paths.

    Reported-by: Josef Bacik <josef@toxicpanda.com>
    Signed-off-by: Anand Jain <anand.jain@oracle.com>
    Signed-off-by: David Sterba <dsterba@suse.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    fs/btrfs/volumes.c | 44 +++++++++++++++++++++++++++++++++++++-------
    1 file changed, 37 insertions(+), 7 deletions(-)

    --- a/fs/btrfs/volumes.c
    +++ b/fs/btrfs/volumes.c
    @@ -540,15 +540,47 @@ error:
    return ret;
    }

    -static bool device_path_matched(const char *path, struct btrfs_device *device)
    +/*
    + * Check if the device in the path matches the device in the given struct device.
    + *
    + * Returns:
    + * true If it is the same device.
    + * false If it is not the same device or on error.
    + */
    +static bool device_matched(const struct btrfs_device *device, const char *path)
    {
    - int found;
    + char *device_name;
    + struct block_device *bdev_old;
    + struct block_device *bdev_new;
    +
    + /*
    + * If we are looking for a device with the matching dev_t, then skip
    + * device without a name (a missing device).
    + */
    + if (!device->name)
    + return false;
    +
    + device_name = kzalloc(BTRFS_PATH_NAME_MAX, GFP_KERNEL);
    + if (!device_name)
    + return false;

    rcu_read_lock();
    - found = strcmp(rcu_str_deref(device->name), path);
    + scnprintf(device_name, BTRFS_PATH_NAME_MAX, "%s", rcu_str_deref(device->name));
    rcu_read_unlock();

    - return found == 0;
    + bdev_old = lookup_bdev(device_name);
    + kfree(device_name);
    + if (IS_ERR(bdev_old))
    + return false;
    +
    + bdev_new = lookup_bdev(path);
    + if (IS_ERR(bdev_new))
    + return false;
    +
    + if (bdev_old == bdev_new)
    + return true;
    +
    + return false;
    }

    /*
    @@ -581,9 +613,7 @@ static int btrfs_free_stale_devices(cons
    &fs_devices->devices, dev_list) {
    if (skip_device && skip_device == device)
    continue;
    - if (path && !device->name)
    - continue;
    - if (path && !device_path_matched(path, device))
    + if (path && !device_matched(device, path))
    continue;
    if (fs_devices->opened) {
    /* for an already deleted device return 0 */

    \
     
     \ /
      Last update: 2022-09-06 15:43    [W:4.265 / U:1.004 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site