Commit 36fac9e9 authored by David Sterba's avatar David Sterba

Merge branch 'foreign/anand/dev-del-by-id-ext' into for-chris-4.7-20160516

parents 5ef64a3e 88acff64
...@@ -44,9 +44,6 @@ static void btrfs_dev_replace_update_device_in_mapping_tree( ...@@ -44,9 +44,6 @@ static void btrfs_dev_replace_update_device_in_mapping_tree(
struct btrfs_fs_info *fs_info, struct btrfs_fs_info *fs_info,
struct btrfs_device *srcdev, struct btrfs_device *srcdev,
struct btrfs_device *tgtdev); struct btrfs_device *tgtdev);
static int btrfs_dev_replace_find_srcdev(struct btrfs_root *root, u64 srcdevid,
char *srcdev_name,
struct btrfs_device **device);
static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info); static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info);
static int btrfs_dev_replace_kthread(void *data); static int btrfs_dev_replace_kthread(void *data);
static int btrfs_dev_replace_continue_on_mount(struct btrfs_fs_info *fs_info); static int btrfs_dev_replace_continue_on_mount(struct btrfs_fs_info *fs_info);
...@@ -305,8 +302,8 @@ void btrfs_after_dev_replace_commit(struct btrfs_fs_info *fs_info) ...@@ -305,8 +302,8 @@ void btrfs_after_dev_replace_commit(struct btrfs_fs_info *fs_info)
dev_replace->cursor_left_last_write_of_item; dev_replace->cursor_left_last_write_of_item;
} }
int btrfs_dev_replace_start(struct btrfs_root *root, int btrfs_dev_replace_start(struct btrfs_root *root, char *tgtdev_name,
struct btrfs_ioctl_dev_replace_args *args) u64 srcdevid, char *srcdev_name, int read_src)
{ {
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_fs_info *fs_info = root->fs_info;
...@@ -315,29 +312,16 @@ int btrfs_dev_replace_start(struct btrfs_root *root, ...@@ -315,29 +312,16 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
struct btrfs_device *tgt_device = NULL; struct btrfs_device *tgt_device = NULL;
struct btrfs_device *src_device = NULL; struct btrfs_device *src_device = NULL;
switch (args->start.cont_reading_from_srcdev_mode) {
case BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS:
case BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID:
break;
default:
return -EINVAL;
}
if ((args->start.srcdevid == 0 && args->start.srcdev_name[0] == '\0') ||
args->start.tgtdev_name[0] == '\0')
return -EINVAL;
/* the disk copy procedure reuses the scrub code */ /* the disk copy procedure reuses the scrub code */
mutex_lock(&fs_info->volume_mutex); mutex_lock(&fs_info->volume_mutex);
ret = btrfs_dev_replace_find_srcdev(root, args->start.srcdevid, ret = btrfs_find_device_by_devspec(root, srcdevid,
args->start.srcdev_name, srcdev_name, &src_device);
&src_device);
if (ret) { if (ret) {
mutex_unlock(&fs_info->volume_mutex); mutex_unlock(&fs_info->volume_mutex);
return ret; return ret;
} }
ret = btrfs_init_dev_replace_tgtdev(root, args->start.tgtdev_name, ret = btrfs_init_dev_replace_tgtdev(root, tgtdev_name,
src_device, &tgt_device); src_device, &tgt_device);
mutex_unlock(&fs_info->volume_mutex); mutex_unlock(&fs_info->volume_mutex);
if (ret) if (ret)
...@@ -364,18 +348,17 @@ int btrfs_dev_replace_start(struct btrfs_root *root, ...@@ -364,18 +348,17 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
break; break;
case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED; ret = BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED;
goto leave; goto leave;
} }
dev_replace->cont_reading_from_srcdev_mode = dev_replace->cont_reading_from_srcdev_mode = read_src;
args->start.cont_reading_from_srcdev_mode;
WARN_ON(!src_device); WARN_ON(!src_device);
dev_replace->srcdev = src_device; dev_replace->srcdev = src_device;
WARN_ON(!tgt_device); WARN_ON(!tgt_device);
dev_replace->tgtdev = tgt_device; dev_replace->tgtdev = tgt_device;
btrfs_info_in_rcu(root->fs_info, btrfs_info_in_rcu(fs_info,
"dev_replace from %s (devid %llu) to %s started", "dev_replace from %s (devid %llu) to %s started",
src_device->missing ? "<missing disk>" : src_device->missing ? "<missing disk>" :
rcu_str_deref(src_device->name), rcu_str_deref(src_device->name),
...@@ -396,14 +379,13 @@ int btrfs_dev_replace_start(struct btrfs_root *root, ...@@ -396,14 +379,13 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
dev_replace->item_needs_writeback = 1; dev_replace->item_needs_writeback = 1;
atomic64_set(&dev_replace->num_write_errors, 0); atomic64_set(&dev_replace->num_write_errors, 0);
atomic64_set(&dev_replace->num_uncorrectable_read_errors, 0); atomic64_set(&dev_replace->num_uncorrectable_read_errors, 0);
args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR;
btrfs_dev_replace_unlock(dev_replace, 1); btrfs_dev_replace_unlock(dev_replace, 1);
ret = btrfs_sysfs_add_device_link(tgt_device->fs_devices, tgt_device); ret = btrfs_sysfs_add_device_link(tgt_device->fs_devices, tgt_device);
if (ret) if (ret)
btrfs_err(root->fs_info, "kobj add dev failed %d\n", ret); btrfs_err(fs_info, "kobj add dev failed %d\n", ret);
btrfs_wait_ordered_roots(root->fs_info, -1); btrfs_wait_ordered_roots(fs_info, -1);
/* force writing the updated state information to disk */ /* force writing the updated state information to disk */
trans = btrfs_start_transaction(root, 0); trans = btrfs_start_transaction(root, 0);
...@@ -421,11 +403,9 @@ int btrfs_dev_replace_start(struct btrfs_root *root, ...@@ -421,11 +403,9 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
btrfs_device_get_total_bytes(src_device), btrfs_device_get_total_bytes(src_device),
&dev_replace->scrub_progress, 0, 1); &dev_replace->scrub_progress, 0, 1);
ret = btrfs_dev_replace_finishing(root->fs_info, ret); ret = btrfs_dev_replace_finishing(fs_info, ret);
/* don't warn if EINPROGRESS, someone else might be running scrub */
if (ret == -EINPROGRESS) { if (ret == -EINPROGRESS) {
args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS; ret = BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS;
ret = 0;
} else { } else {
WARN_ON(ret); WARN_ON(ret);
} }
...@@ -440,6 +420,35 @@ int btrfs_dev_replace_start(struct btrfs_root *root, ...@@ -440,6 +420,35 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
return ret; return ret;
} }
int btrfs_dev_replace_by_ioctl(struct btrfs_root *root,
struct btrfs_ioctl_dev_replace_args *args)
{
int ret;
switch (args->start.cont_reading_from_srcdev_mode) {
case BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS:
case BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID:
break;
default:
return -EINVAL;
}
if ((args->start.srcdevid == 0 && args->start.srcdev_name[0] == '\0') ||
args->start.tgtdev_name[0] == '\0')
return -EINVAL;
ret = btrfs_dev_replace_start(root, args->start.tgtdev_name,
args->start.srcdevid,
args->start.srcdev_name,
args->start.cont_reading_from_srcdev_mode);
args->result = ret;
/* don't warn if EINPROGRESS, someone else might be running scrub */
if (ret == BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS)
ret = 0;
return ret;
}
/* /*
* blocked until all flighting bios are finished. * blocked until all flighting bios are finished.
*/ */
...@@ -560,10 +569,9 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, ...@@ -560,10 +569,9 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
ASSERT(list_empty(&src_device->resized_list)); ASSERT(list_empty(&src_device->resized_list));
tgt_device->commit_total_bytes = src_device->commit_total_bytes; tgt_device->commit_total_bytes = src_device->commit_total_bytes;
tgt_device->commit_bytes_used = src_device->bytes_used; tgt_device->commit_bytes_used = src_device->bytes_used;
if (fs_info->sb->s_bdev == src_device->bdev)
fs_info->sb->s_bdev = tgt_device->bdev; btrfs_assign_next_active_device(fs_info, src_device, tgt_device);
if (fs_info->fs_devices->latest_bdev == src_device->bdev)
fs_info->fs_devices->latest_bdev = tgt_device->bdev;
list_add(&tgt_device->dev_alloc_list, &fs_info->fs_devices->alloc_list); list_add(&tgt_device->dev_alloc_list, &fs_info->fs_devices->alloc_list);
fs_info->fs_devices->rw_devices++; fs_info->fs_devices->rw_devices++;
...@@ -626,25 +634,6 @@ static void btrfs_dev_replace_update_device_in_mapping_tree( ...@@ -626,25 +634,6 @@ static void btrfs_dev_replace_update_device_in_mapping_tree(
write_unlock(&em_tree->lock); write_unlock(&em_tree->lock);
} }
static int btrfs_dev_replace_find_srcdev(struct btrfs_root *root, u64 srcdevid,
char *srcdev_name,
struct btrfs_device **device)
{
int ret;
if (srcdevid) {
ret = 0;
*device = btrfs_find_device(root->fs_info, srcdevid, NULL,
NULL);
if (!*device)
ret = -ENOENT;
} else {
ret = btrfs_find_device_missing_or_by_path(root, srcdev_name,
device);
}
return ret;
}
void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info, void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info,
struct btrfs_ioctl_dev_replace_args *args) struct btrfs_ioctl_dev_replace_args *args)
{ {
......
...@@ -25,8 +25,10 @@ int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info); ...@@ -25,8 +25,10 @@ int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info);
int btrfs_run_dev_replace(struct btrfs_trans_handle *trans, int btrfs_run_dev_replace(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info); struct btrfs_fs_info *fs_info);
void btrfs_after_dev_replace_commit(struct btrfs_fs_info *fs_info); void btrfs_after_dev_replace_commit(struct btrfs_fs_info *fs_info);
int btrfs_dev_replace_start(struct btrfs_root *root, int btrfs_dev_replace_by_ioctl(struct btrfs_root *root,
struct btrfs_ioctl_dev_replace_args *args); struct btrfs_ioctl_dev_replace_args *args);
int btrfs_dev_replace_start(struct btrfs_root *root, char *tgtdev_name,
u64 srcdevid, char *srcdev_name, int read_src);
void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info, void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info,
struct btrfs_ioctl_dev_replace_args *args); struct btrfs_ioctl_dev_replace_args *args);
int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info, int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info,
......
...@@ -2676,6 +2676,60 @@ static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg) ...@@ -2676,6 +2676,60 @@ static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg)
return ret; return ret;
} }
static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg)
{
struct btrfs_root *root = BTRFS_I(file_inode(file))->root;
struct btrfs_ioctl_vol_args_v2 *vol_args;
int ret;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
ret = mnt_want_write_file(file);
if (ret)
return ret;
vol_args = memdup_user(arg, sizeof(*vol_args));
if (IS_ERR(vol_args)) {
ret = PTR_ERR(vol_args);
goto err_drop;
}
/* Check for compatibility reject unknown flags */
if (vol_args->flags & ~BTRFS_VOL_ARG_V2_FLAGS_SUPPORTED)
return -EOPNOTSUPP;
if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running,
1)) {
ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS;
goto out;
}
mutex_lock(&root->fs_info->volume_mutex);
if (vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID) {
ret = btrfs_rm_device(root, NULL, vol_args->devid);
} else {
vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0';
ret = btrfs_rm_device(root, vol_args->name, 0);
}
mutex_unlock(&root->fs_info->volume_mutex);
atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0);
if (!ret) {
if (vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID)
btrfs_info(root->fs_info, "device deleted: id %llu",
vol_args->devid);
else
btrfs_info(root->fs_info, "device deleted: %s",
vol_args->name);
}
out:
kfree(vol_args);
err_drop:
mnt_drop_write_file(file);
return ret;
}
static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg) static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
{ {
struct btrfs_root *root = BTRFS_I(file_inode(file))->root; struct btrfs_root *root = BTRFS_I(file_inode(file))->root;
...@@ -2703,7 +2757,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg) ...@@ -2703,7 +2757,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
mutex_lock(&root->fs_info->volume_mutex); mutex_lock(&root->fs_info->volume_mutex);
ret = btrfs_rm_device(root, vol_args->name); ret = btrfs_rm_device(root, vol_args->name, 0);
mutex_unlock(&root->fs_info->volume_mutex); mutex_unlock(&root->fs_info->volume_mutex);
if (!ret) if (!ret)
...@@ -4387,7 +4441,7 @@ static long btrfs_ioctl_dev_replace(struct btrfs_root *root, void __user *arg) ...@@ -4387,7 +4441,7 @@ static long btrfs_ioctl_dev_replace(struct btrfs_root *root, void __user *arg)
1)) { 1)) {
ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS;
} else { } else {
ret = btrfs_dev_replace_start(root, p); ret = btrfs_dev_replace_by_ioctl(root, p);
atomic_set( atomic_set(
&root->fs_info->mutually_exclusive_operation_running, &root->fs_info->mutually_exclusive_operation_running,
0); 0);
...@@ -5480,6 +5534,8 @@ long btrfs_ioctl(struct file *file, unsigned int ...@@ -5480,6 +5534,8 @@ long btrfs_ioctl(struct file *file, unsigned int
return btrfs_ioctl_add_dev(root, argp); return btrfs_ioctl_add_dev(root, argp);
case BTRFS_IOC_RM_DEV: case BTRFS_IOC_RM_DEV:
return btrfs_ioctl_rm_dev(file, argp); return btrfs_ioctl_rm_dev(file, argp);
case BTRFS_IOC_RM_DEV_V2:
return btrfs_ioctl_rm_dev_v2(file, argp);
case BTRFS_IOC_FS_INFO: case BTRFS_IOC_FS_INFO:
return btrfs_ioctl_fs_info(root, argp); return btrfs_ioctl_fs_info(root, argp);
case BTRFS_IOC_DEV_INFO: case BTRFS_IOC_DEV_INFO:
......
This diff is collapsed.
...@@ -340,7 +340,7 @@ struct btrfs_raid_attr { ...@@ -340,7 +340,7 @@ struct btrfs_raid_attr {
}; };
extern const struct btrfs_raid_attr btrfs_raid_array[BTRFS_NR_RAID_TYPES]; extern const struct btrfs_raid_attr btrfs_raid_array[BTRFS_NR_RAID_TYPES];
extern const int btrfs_raid_mindev_error[BTRFS_NR_RAID_TYPES];
extern const u64 btrfs_raid_group[BTRFS_NR_RAID_TYPES]; extern const u64 btrfs_raid_group[BTRFS_NR_RAID_TYPES];
struct map_lookup { struct map_lookup {
...@@ -445,13 +445,18 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, ...@@ -445,13 +445,18 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
struct btrfs_fs_devices **fs_devices_ret); struct btrfs_fs_devices **fs_devices_ret);
int btrfs_close_devices(struct btrfs_fs_devices *fs_devices); int btrfs_close_devices(struct btrfs_fs_devices *fs_devices);
void btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices, int step); void btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices, int step);
void btrfs_assign_next_active_device(struct btrfs_fs_info *fs_info,
struct btrfs_device *device, struct btrfs_device *this_dev);
int btrfs_find_device_missing_or_by_path(struct btrfs_root *root, int btrfs_find_device_missing_or_by_path(struct btrfs_root *root,
char *device_path, char *device_path,
struct btrfs_device **device); struct btrfs_device **device);
int btrfs_find_device_by_devspec(struct btrfs_root *root, u64 devid,
char *devpath,
struct btrfs_device **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);
int btrfs_rm_device(struct btrfs_root *root, char *device_path); int btrfs_rm_device(struct btrfs_root *root, char *device_path, u64 devid);
void btrfs_cleanup_fs_uuids(void); void btrfs_cleanup_fs_uuids(void);
int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len); int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len);
int btrfs_grow_device(struct btrfs_trans_handle *trans, int btrfs_grow_device(struct btrfs_trans_handle *trans,
......
...@@ -36,6 +36,14 @@ struct btrfs_ioctl_vol_args { ...@@ -36,6 +36,14 @@ struct btrfs_ioctl_vol_args {
#define BTRFS_SUBVOL_CREATE_ASYNC (1ULL << 0) #define BTRFS_SUBVOL_CREATE_ASYNC (1ULL << 0)
#define BTRFS_SUBVOL_RDONLY (1ULL << 1) #define BTRFS_SUBVOL_RDONLY (1ULL << 1)
#define BTRFS_SUBVOL_QGROUP_INHERIT (1ULL << 2) #define BTRFS_SUBVOL_QGROUP_INHERIT (1ULL << 2)
#define BTRFS_DEVICE_SPEC_BY_ID (1ULL << 3)
#define BTRFS_VOL_ARG_V2_FLAGS_SUPPORTED \
(BTRFS_SUBVOL_CREATE_ASYNC | \
BTRFS_SUBVOL_RDONLY | \
BTRFS_SUBVOL_QGROUP_INHERIT | \
BTRFS_DEVICE_SPEC_BY_ID)
#define BTRFS_FSID_SIZE 16 #define BTRFS_FSID_SIZE 16
#define BTRFS_UUID_SIZE 16 #define BTRFS_UUID_SIZE 16
#define BTRFS_UUID_UNPARSED_SIZE 37 #define BTRFS_UUID_UNPARSED_SIZE 37
...@@ -76,7 +84,10 @@ struct btrfs_ioctl_vol_args_v2 { ...@@ -76,7 +84,10 @@ struct btrfs_ioctl_vol_args_v2 {
}; };
__u64 unused[4]; __u64 unused[4];
}; };
char name[BTRFS_SUBVOL_NAME_MAX + 1]; union {
char name[BTRFS_SUBVOL_NAME_MAX + 1];
u64 devid;
};
}; };
/* /*
...@@ -659,5 +670,7 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code) ...@@ -659,5 +670,7 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code)
struct btrfs_ioctl_feature_flags[2]) struct btrfs_ioctl_feature_flags[2])
#define BTRFS_IOC_GET_SUPPORTED_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \ #define BTRFS_IOC_GET_SUPPORTED_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \
struct btrfs_ioctl_feature_flags[3]) struct btrfs_ioctl_feature_flags[3])
#define BTRFS_IOC_RM_DEV_V2 _IOW(BTRFS_IOCTL_MAGIC, 58, \
struct btrfs_ioctl_vol_args_v2)
#endif /* _UAPI_LINUX_BTRFS_H */ #endif /* _UAPI_LINUX_BTRFS_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment