Skip to content

Commit

Permalink
btrfs: add a btrfs_get_dev_args_from_path helper
Browse files Browse the repository at this point in the history
We are going to want to populate our device lookup args outside of any
locks and then do the actual device lookup later, so add a helper to do
this work and make btrfs_find_device_by_devspec() use this helper for
now.

Reviewed-by: Nikolay Borisov <nborisov@suse.com>
Reviewed-by: Anand Jain <anand.jain@oracle.com>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: David Sterba <dsterba@suse.com>
  • Loading branch information
josefbacik authored and kdave committed Oct 26, 2021
1 parent 562d7b1 commit faa775c
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 32 deletions.
96 changes: 64 additions & 32 deletions fs/btrfs/volumes.c
Original file line number Diff line number Diff line change
Expand Up @@ -2325,45 +2325,81 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_device *tgtdev)
btrfs_free_device(tgtdev);
}

static struct btrfs_device *btrfs_find_device_by_path(
struct btrfs_fs_info *fs_info, const char *device_path)
/**
* Populate args from device at path
*
* @fs_info: the filesystem
* @args: the args to populate
* @path: the path to the device
*
* This will read the super block of the device at @path and populate @args with
* the devid, fsid, and uuid. This is meant to be used for ioctls that need to
* lookup a device to operate on, but need to do it before we take any locks.
* This properly handles the special case of "missing" that a user may pass in,
* and does some basic sanity checks. The caller must make sure that @path is
* properly NUL terminated before calling in, and must call
* btrfs_put_dev_args_from_path() in order to free up the temporary fsid and
* uuid buffers.
*
* Return: 0 for success, -errno for failure
*/
int btrfs_get_dev_args_from_path(struct btrfs_fs_info *fs_info,
struct btrfs_dev_lookup_args *args,
const char *path)
{
BTRFS_DEV_LOOKUP_ARGS(args);
int ret = 0;
struct btrfs_super_block *disk_super;
struct block_device *bdev;
struct btrfs_device *device;
int ret;

ret = btrfs_get_bdev_and_sb(device_path, FMODE_READ,
fs_info->bdev_holder, 0, &bdev, &disk_super);
if (ret)
return ERR_PTR(ret);
if (!path || !path[0])
return -EINVAL;
if (!strcmp(path, "missing")) {
args->missing = true;
return 0;
}

args->uuid = kzalloc(BTRFS_UUID_SIZE, GFP_KERNEL);
args->fsid = kzalloc(BTRFS_FSID_SIZE, GFP_KERNEL);
if (!args->uuid || !args->fsid) {
btrfs_put_dev_args_from_path(args);
return -ENOMEM;
}

args.devid = btrfs_stack_device_id(&disk_super->dev_item);
args.uuid = disk_super->dev_item.uuid;
ret = btrfs_get_bdev_and_sb(path, FMODE_READ, fs_info->bdev_holder, 0,
&bdev, &disk_super);
if (ret)
return ret;
args->devid = btrfs_stack_device_id(&disk_super->dev_item);
memcpy(args->uuid, disk_super->dev_item.uuid, BTRFS_UUID_SIZE);
if (btrfs_fs_incompat(fs_info, METADATA_UUID))
args.fsid = disk_super->metadata_uuid;
memcpy(args->fsid, disk_super->metadata_uuid, BTRFS_FSID_SIZE);
else
args.fsid = disk_super->fsid;

device = btrfs_find_device(fs_info->fs_devices, &args);

memcpy(args->fsid, disk_super->fsid, BTRFS_FSID_SIZE);
btrfs_release_disk_super(disk_super);
if (!device)
device = ERR_PTR(-ENOENT);
blkdev_put(bdev, FMODE_READ);
return device;
return 0;
}

/*
* Lookup a device given by device id, or the path if the id is 0.
* Only use this jointly with btrfs_get_dev_args_from_path() because we will
* allocate our ->uuid and ->fsid pointers, everybody else uses local variables
* that don't need to be freed.
*/
void btrfs_put_dev_args_from_path(struct btrfs_dev_lookup_args *args)
{
kfree(args->uuid);
kfree(args->fsid);
args->uuid = NULL;
args->fsid = NULL;
}

struct btrfs_device *btrfs_find_device_by_devspec(
struct btrfs_fs_info *fs_info, u64 devid,
const char *device_path)
{
BTRFS_DEV_LOOKUP_ARGS(args);
struct btrfs_device *device;
int ret;

if (devid) {
args.devid = devid;
Expand All @@ -2373,18 +2409,14 @@ struct btrfs_device *btrfs_find_device_by_devspec(
return device;
}

if (!device_path || !device_path[0])
return ERR_PTR(-EINVAL);

if (strcmp(device_path, "missing") == 0) {
args.missing = true;
device = btrfs_find_device(fs_info->fs_devices, &args);
if (!device)
return ERR_PTR(-ENOENT);
return device;
}

return btrfs_find_device_by_path(fs_info, device_path);
ret = btrfs_get_dev_args_from_path(fs_info, &args, device_path);
if (ret)
return ERR_PTR(ret);
device = btrfs_find_device(fs_info->fs_devices, &args);
btrfs_put_dev_args_from_path(&args);
if (!device)
return ERR_PTR(-ENOENT);
return device;
}

/*
Expand Down
4 changes: 4 additions & 0 deletions fs/btrfs/volumes.h
Original file line number Diff line number Diff line change
Expand Up @@ -520,9 +520,13 @@ void btrfs_assign_next_active_device(struct btrfs_device *device,
struct btrfs_device *btrfs_find_device_by_devspec(struct btrfs_fs_info *fs_info,
u64 devid,
const char *devpath);
int btrfs_get_dev_args_from_path(struct btrfs_fs_info *fs_info,
struct btrfs_dev_lookup_args *args,
const char *path);
struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
const u64 *devid,
const u8 *uuid);
void btrfs_put_dev_args_from_path(struct btrfs_dev_lookup_args *args);
void btrfs_free_device(struct btrfs_device *device);
int btrfs_rm_device(struct btrfs_fs_info *fs_info,
const char *device_path, u64 devid,
Expand Down

0 comments on commit faa775c

Please sign in to comment.