btrfs: add a btrfs_get_dev_args_from_path helper
[ Upstream commit faa775c41d
]
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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Родитель
5578b681fb
Коммит
321a81835b
|
@ -2361,45 +2361,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 (!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;
|
||||
}
|
||||
|
||||
ret = btrfs_get_bdev_and_sb(path, FMODE_READ, fs_info->bdev_holder, 0,
|
||||
&bdev, &disk_super);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
args.devid = btrfs_stack_device_id(&disk_super->dev_item);
|
||||
args.uuid = disk_super->dev_item.uuid;
|
||||
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;
|
||||
|
@ -2409,18 +2445,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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -487,9 +487,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,
|
||||
|
|
Загрузка…
Ссылка в новой задаче