mirror of
https://gitee.com/bianbu-linux/linux-6.6
synced 2025-04-24 14:07:52 -04:00
btrfs: move device->name RCU allocation and assign to btrfs_alloc_device()
There is a repeating code section in the parent function after calling btrfs_alloc_device(), as below: name = rcu_string_strdup(path, GFP_...); if (!name) { btrfs_free_device(device); return ERR_PTR(-ENOMEM); } rcu_assign_pointer(device->name, name); Except in add_missing_dev() for obvious reasons. This patch consolidates that repeating code into the btrfs_alloc_device() itself so that the parent function doesn't have to duplicate code. This consolidation also helps to review issues regarding RCU lock violation with device->name. Parent function device_list_add() and add_missing_dev() use GFP_NOFS for the allocation, whereas the rest of the parent functions use GFP_KERNEL, so bring the NOFS allocation context using memalloc_nofs_save() in the function device_list_add() and add_missing_dev() is already doing it. Signed-off-by: Anand Jain <anand.jain@oracle.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
3e09b5b229
commit
bb21e30260
3 changed files with 34 additions and 48 deletions
|
@ -249,7 +249,6 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
|
||||||
struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
|
struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
|
||||||
struct btrfs_device *device;
|
struct btrfs_device *device;
|
||||||
struct block_device *bdev;
|
struct block_device *bdev;
|
||||||
struct rcu_string *name;
|
|
||||||
u64 devid = BTRFS_DEV_REPLACE_DEVID;
|
u64 devid = BTRFS_DEV_REPLACE_DEVID;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
@ -293,19 +292,12 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
device = btrfs_alloc_device(NULL, &devid, NULL);
|
device = btrfs_alloc_device(NULL, &devid, NULL, device_path);
|
||||||
if (IS_ERR(device)) {
|
if (IS_ERR(device)) {
|
||||||
ret = PTR_ERR(device);
|
ret = PTR_ERR(device);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
name = rcu_string_strdup(device_path, GFP_KERNEL);
|
|
||||||
if (!name) {
|
|
||||||
btrfs_free_device(device);
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
rcu_assign_pointer(device->name, name);
|
|
||||||
ret = lookup_bdev(device_path, &device->devt);
|
ret = lookup_bdev(device_path, &device->devt);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
|
@ -845,26 +845,23 @@ static noinline struct btrfs_device *device_list_add(const char *path,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!device) {
|
if (!device) {
|
||||||
|
unsigned int nofs_flag;
|
||||||
|
|
||||||
if (fs_devices->opened) {
|
if (fs_devices->opened) {
|
||||||
mutex_unlock(&fs_devices->device_list_mutex);
|
mutex_unlock(&fs_devices->device_list_mutex);
|
||||||
return ERR_PTR(-EBUSY);
|
return ERR_PTR(-EBUSY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nofs_flag = memalloc_nofs_save();
|
||||||
device = btrfs_alloc_device(NULL, &devid,
|
device = btrfs_alloc_device(NULL, &devid,
|
||||||
disk_super->dev_item.uuid);
|
disk_super->dev_item.uuid, path);
|
||||||
|
memalloc_nofs_restore(nofs_flag);
|
||||||
if (IS_ERR(device)) {
|
if (IS_ERR(device)) {
|
||||||
mutex_unlock(&fs_devices->device_list_mutex);
|
mutex_unlock(&fs_devices->device_list_mutex);
|
||||||
/* we can safely leave the fs_devices entry around */
|
/* we can safely leave the fs_devices entry around */
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
name = rcu_string_strdup(path, GFP_NOFS);
|
|
||||||
if (!name) {
|
|
||||||
btrfs_free_device(device);
|
|
||||||
mutex_unlock(&fs_devices->device_list_mutex);
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
}
|
|
||||||
rcu_assign_pointer(device->name, name);
|
|
||||||
device->devt = path_devt;
|
device->devt = path_devt;
|
||||||
|
|
||||||
list_add_rcu(&device->dev_list, &fs_devices->devices);
|
list_add_rcu(&device->dev_list, &fs_devices->devices);
|
||||||
|
@ -997,30 +994,22 @@ static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig)
|
||||||
fs_devices->total_devices = orig->total_devices;
|
fs_devices->total_devices = orig->total_devices;
|
||||||
|
|
||||||
list_for_each_entry(orig_dev, &orig->devices, dev_list) {
|
list_for_each_entry(orig_dev, &orig->devices, dev_list) {
|
||||||
struct rcu_string *name;
|
const char *dev_path = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is ok to do without RCU read locked because we hold the
|
||||||
|
* uuid mutex so nothing we touch in here is going to disappear.
|
||||||
|
*/
|
||||||
|
if (orig_dev->name)
|
||||||
|
dev_path = orig_dev->name->str;
|
||||||
|
|
||||||
device = btrfs_alloc_device(NULL, &orig_dev->devid,
|
device = btrfs_alloc_device(NULL, &orig_dev->devid,
|
||||||
orig_dev->uuid);
|
orig_dev->uuid, dev_path);
|
||||||
if (IS_ERR(device)) {
|
if (IS_ERR(device)) {
|
||||||
ret = PTR_ERR(device);
|
ret = PTR_ERR(device);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* This is ok to do without rcu read locked because we hold the
|
|
||||||
* uuid mutex so nothing we touch in here is going to disappear.
|
|
||||||
*/
|
|
||||||
if (orig_dev->name) {
|
|
||||||
name = rcu_string_strdup(orig_dev->name->str,
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!name) {
|
|
||||||
btrfs_free_device(device);
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
rcu_assign_pointer(device->name, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (orig_dev->zone_info) {
|
if (orig_dev->zone_info) {
|
||||||
struct btrfs_zoned_device_info *zone_info;
|
struct btrfs_zoned_device_info *zone_info;
|
||||||
|
|
||||||
|
@ -2604,7 +2593,6 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
|
||||||
struct btrfs_device *device;
|
struct btrfs_device *device;
|
||||||
struct block_device *bdev;
|
struct block_device *bdev;
|
||||||
struct super_block *sb = fs_info->sb;
|
struct super_block *sb = fs_info->sb;
|
||||||
struct rcu_string *name;
|
|
||||||
struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
|
struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
|
||||||
struct btrfs_fs_devices *seed_devices;
|
struct btrfs_fs_devices *seed_devices;
|
||||||
u64 orig_super_total_bytes;
|
u64 orig_super_total_bytes;
|
||||||
|
@ -2645,20 +2633,13 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
device = btrfs_alloc_device(fs_info, NULL, NULL);
|
device = btrfs_alloc_device(fs_info, NULL, NULL, device_path);
|
||||||
if (IS_ERR(device)) {
|
if (IS_ERR(device)) {
|
||||||
/* we can safely leave the fs_devices entry around */
|
/* we can safely leave the fs_devices entry around */
|
||||||
ret = PTR_ERR(device);
|
ret = PTR_ERR(device);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
name = rcu_string_strdup(device_path, GFP_KERNEL);
|
|
||||||
if (!name) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto error_free_device;
|
|
||||||
}
|
|
||||||
rcu_assign_pointer(device->name, name);
|
|
||||||
|
|
||||||
device->fs_info = fs_info;
|
device->fs_info = fs_info;
|
||||||
device->bdev = bdev;
|
device->bdev = bdev;
|
||||||
ret = lookup_bdev(device_path, &device->devt);
|
ret = lookup_bdev(device_path, &device->devt);
|
||||||
|
@ -6998,8 +6979,9 @@ static struct btrfs_device *add_missing_dev(struct btrfs_fs_devices *fs_devices,
|
||||||
* always do NOFS because we use it in a lot of other GFP_KERNEL safe
|
* always do NOFS because we use it in a lot of other GFP_KERNEL safe
|
||||||
* places.
|
* places.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
nofs_flag = memalloc_nofs_save();
|
nofs_flag = memalloc_nofs_save();
|
||||||
device = btrfs_alloc_device(NULL, &devid, dev_uuid);
|
device = btrfs_alloc_device(NULL, &devid, dev_uuid, NULL);
|
||||||
memalloc_nofs_restore(nofs_flag);
|
memalloc_nofs_restore(nofs_flag);
|
||||||
if (IS_ERR(device))
|
if (IS_ERR(device))
|
||||||
return device;
|
return device;
|
||||||
|
@ -7023,14 +7005,15 @@ static struct btrfs_device *add_missing_dev(struct btrfs_fs_devices *fs_devices,
|
||||||
* is generated.
|
* is generated.
|
||||||
* @uuid: a pointer to UUID for this device. If NULL a new UUID
|
* @uuid: a pointer to UUID for this device. If NULL a new UUID
|
||||||
* is generated.
|
* is generated.
|
||||||
|
* @path: a pointer to device path if available, NULL otherwise.
|
||||||
*
|
*
|
||||||
* Return: a pointer to a new &struct btrfs_device on success; ERR_PTR()
|
* Return: a pointer to a new &struct btrfs_device on success; ERR_PTR()
|
||||||
* on error. Returned struct is not linked onto any lists and must be
|
* on error. Returned struct is not linked onto any lists and must be
|
||||||
* destroyed with btrfs_free_device.
|
* destroyed with btrfs_free_device.
|
||||||
*/
|
*/
|
||||||
struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
|
struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
|
||||||
const u64 *devid,
|
const u64 *devid, const u8 *uuid,
|
||||||
const u8 *uuid)
|
const char *path)
|
||||||
{
|
{
|
||||||
struct btrfs_device *dev;
|
struct btrfs_device *dev;
|
||||||
u64 tmp;
|
u64 tmp;
|
||||||
|
@ -7068,6 +7051,17 @@ struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
|
||||||
else
|
else
|
||||||
generate_random_uuid(dev->uuid);
|
generate_random_uuid(dev->uuid);
|
||||||
|
|
||||||
|
if (path) {
|
||||||
|
struct rcu_string *name;
|
||||||
|
|
||||||
|
name = rcu_string_strdup(path, GFP_KERNEL);
|
||||||
|
if (!name) {
|
||||||
|
btrfs_free_device(dev);
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
}
|
||||||
|
rcu_assign_pointer(dev->name, name);
|
||||||
|
}
|
||||||
|
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -649,8 +649,8 @@ int btrfs_get_dev_args_from_path(struct btrfs_fs_info *fs_info,
|
||||||
struct btrfs_dev_lookup_args *args,
|
struct btrfs_dev_lookup_args *args,
|
||||||
const char *path);
|
const char *path);
|
||||||
struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
|
struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
|
||||||
const u64 *devid,
|
const u64 *devid, const u8 *uuid,
|
||||||
const u8 *uuid);
|
const char *path);
|
||||||
void btrfs_put_dev_args_from_path(struct btrfs_dev_lookup_args *args);
|
void btrfs_put_dev_args_from_path(struct btrfs_dev_lookup_args *args);
|
||||||
void btrfs_free_device(struct btrfs_device *device);
|
void btrfs_free_device(struct btrfs_device *device);
|
||||||
int btrfs_rm_device(struct btrfs_fs_info *fs_info,
|
int btrfs_rm_device(struct btrfs_fs_info *fs_info,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue