btrfs: refactor btrfs_free_stale_devices() to get return value

Preparatory patch to add ioctl that allows to forget a device (ie.
reverse of scan).

Refactors btrfs_free_stale_devices() to obtain return status. As this
function can fail if it can't find the given path (returns -ENOENT) or
trying to delete a mounted device (returns -EBUSY).

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:
Anand Jain 2019-01-04 13:31:53 +08:00 коммит произвёл David Sterba
Родитель e4319cd9ca
Коммит 70bc7088aa
1 изменённых файлов: 31 добавлений и 15 удалений

Просмотреть файл

@ -734,6 +734,17 @@ static void pending_bios_fn(struct btrfs_work *work)
run_scheduled_bios(device); run_scheduled_bios(device);
} }
static bool device_path_matched(const char *path, struct btrfs_device *device)
{
int found;
rcu_read_lock();
found = strcmp(rcu_str_deref(device->name), path);
rcu_read_unlock();
return found == 0;
}
/* /*
* Search and remove all stale (devices which are not mounted) devices. * Search and remove all stale (devices which are not mounted) devices.
* When both inputs are NULL, it will search and release all stale devices. * When both inputs are NULL, it will search and release all stale devices.
@ -741,52 +752,57 @@ static void pending_bios_fn(struct btrfs_work *work)
* matching this path only. * matching this path only.
* skip_dev: Optional. Will skip this device when searching for the stale * skip_dev: Optional. Will skip this device when searching for the stale
* devices. * devices.
* Return: 0 for success or if @path is NULL.
* -EBUSY if @path is a mounted device.
* -ENOENT if @path does not match any device in the list.
*/ */
static void btrfs_free_stale_devices(const char *path, static int btrfs_free_stale_devices(const char *path,
struct btrfs_device *skip_device) struct btrfs_device *skip_device)
{ {
struct btrfs_fs_devices *fs_devices, *tmp_fs_devices; struct btrfs_fs_devices *fs_devices, *tmp_fs_devices;
struct btrfs_device *device, *tmp_device; struct btrfs_device *device, *tmp_device;
int ret = 0;
if (path)
ret = -ENOENT;
list_for_each_entry_safe(fs_devices, tmp_fs_devices, &fs_uuids, fs_list) { list_for_each_entry_safe(fs_devices, tmp_fs_devices, &fs_uuids, fs_list) {
mutex_lock(&fs_devices->device_list_mutex);
if (fs_devices->opened) {
mutex_unlock(&fs_devices->device_list_mutex);
continue;
}
mutex_lock(&fs_devices->device_list_mutex);
list_for_each_entry_safe(device, tmp_device, list_for_each_entry_safe(device, tmp_device,
&fs_devices->devices, dev_list) { &fs_devices->devices, dev_list) {
int not_found = 0;
if (skip_device && skip_device == device) if (skip_device && skip_device == device)
continue; continue;
if (path && !device->name) if (path && !device->name)
continue; continue;
if (path && !device_path_matched(path, device))
rcu_read_lock();
if (path)
not_found = strcmp(rcu_str_deref(device->name),
path);
rcu_read_unlock();
if (not_found)
continue; continue;
if (fs_devices->opened) {
/* for an already deleted device return 0 */
if (path && ret != 0)
ret = -EBUSY;
break;
}
/* delete the stale device */ /* delete the stale device */
fs_devices->num_devices--; fs_devices->num_devices--;
list_del(&device->dev_list); list_del(&device->dev_list);
btrfs_free_device(device); btrfs_free_device(device);
ret = 0;
if (fs_devices->num_devices == 0) if (fs_devices->num_devices == 0)
break; break;
} }
mutex_unlock(&fs_devices->device_list_mutex); mutex_unlock(&fs_devices->device_list_mutex);
if (fs_devices->num_devices == 0) { if (fs_devices->num_devices == 0) {
btrfs_sysfs_remove_fsid(fs_devices); btrfs_sysfs_remove_fsid(fs_devices);
list_del(&fs_devices->fs_list); list_del(&fs_devices->fs_list);
free_fs_devices(fs_devices); free_fs_devices(fs_devices);
} }
} }
return ret;
} }
static int btrfs_open_one_device(struct btrfs_fs_devices *fs_devices, static int btrfs_open_one_device(struct btrfs_fs_devices *fs_devices,