Merge branch 'foreign/anand/dev-del-by-id-ext' into for-chris-4.7-20160516
This commit is contained in:
commit
36fac9e9ff
@ -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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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 @@ leave:
|
|||||||
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,
|
|||||||
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(
|
|||||||
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);
|
|||||||
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 @@ out:
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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
|
|||||||
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:
|
||||||
|
@ -118,6 +118,21 @@ const u64 btrfs_raid_group[BTRFS_NR_RAID_TYPES] = {
|
|||||||
[BTRFS_RAID_RAID6] = BTRFS_BLOCK_GROUP_RAID6,
|
[BTRFS_RAID_RAID6] = BTRFS_BLOCK_GROUP_RAID6,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Table to convert BTRFS_RAID_* to the error code if minimum number of devices
|
||||||
|
* condition is not met. Zero means there's no corresponding
|
||||||
|
* BTRFS_ERROR_DEV_*_NOT_MET value.
|
||||||
|
*/
|
||||||
|
const int btrfs_raid_mindev_error[BTRFS_NR_RAID_TYPES] = {
|
||||||
|
[BTRFS_RAID_RAID10] = BTRFS_ERROR_DEV_RAID10_MIN_NOT_MET,
|
||||||
|
[BTRFS_RAID_RAID1] = BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET,
|
||||||
|
[BTRFS_RAID_DUP] = 0,
|
||||||
|
[BTRFS_RAID_RAID0] = 0,
|
||||||
|
[BTRFS_RAID_SINGLE] = 0,
|
||||||
|
[BTRFS_RAID_RAID5] = BTRFS_ERROR_DEV_RAID5_MIN_NOT_MET,
|
||||||
|
[BTRFS_RAID_RAID6] = BTRFS_ERROR_DEV_RAID6_MIN_NOT_MET,
|
||||||
|
};
|
||||||
|
|
||||||
static int init_first_rw_device(struct btrfs_trans_handle *trans,
|
static int init_first_rw_device(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
struct btrfs_device *device);
|
struct btrfs_device *device);
|
||||||
@ -699,7 +714,8 @@ static noinline int device_list_add(const char *path,
|
|||||||
* if there is new btrfs on an already registered device,
|
* if there is new btrfs on an already registered device,
|
||||||
* then remove the stale device entry.
|
* then remove the stale device entry.
|
||||||
*/
|
*/
|
||||||
btrfs_free_stale_device(device);
|
if (ret > 0)
|
||||||
|
btrfs_free_stale_device(device);
|
||||||
|
|
||||||
*fs_devices_ret = fs_devices;
|
*fs_devices_ret = fs_devices;
|
||||||
|
|
||||||
@ -988,6 +1004,56 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void btrfs_release_disk_super(struct page *page)
|
||||||
|
{
|
||||||
|
kunmap(page);
|
||||||
|
put_page(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
int btrfs_read_disk_super(struct block_device *bdev, u64 bytenr,
|
||||||
|
struct page **page, struct btrfs_super_block **disk_super)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
pgoff_t index;
|
||||||
|
|
||||||
|
/* make sure our super fits in the device */
|
||||||
|
if (bytenr + PAGE_SIZE >= i_size_read(bdev->bd_inode))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* make sure our super fits in the page */
|
||||||
|
if (sizeof(**disk_super) > PAGE_SIZE)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* make sure our super doesn't straddle pages on disk */
|
||||||
|
index = bytenr >> PAGE_SHIFT;
|
||||||
|
if ((bytenr + sizeof(**disk_super) - 1) >> PAGE_SHIFT != index)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* pull in the page with our super */
|
||||||
|
*page = read_cache_page_gfp(bdev->bd_inode->i_mapping,
|
||||||
|
index, GFP_KERNEL);
|
||||||
|
|
||||||
|
if (IS_ERR_OR_NULL(*page))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
p = kmap(*page);
|
||||||
|
|
||||||
|
/* align our pointer to the offset of the super block */
|
||||||
|
*disk_super = p + (bytenr & ~PAGE_MASK);
|
||||||
|
|
||||||
|
if (btrfs_super_bytenr(*disk_super) != bytenr ||
|
||||||
|
btrfs_super_magic(*disk_super) != BTRFS_MAGIC) {
|
||||||
|
btrfs_release_disk_super(*page);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((*disk_super)->label[0] &&
|
||||||
|
(*disk_super)->label[BTRFS_LABEL_SIZE - 1])
|
||||||
|
(*disk_super)->label[BTRFS_LABEL_SIZE - 1] = '\0';
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Look for a btrfs signature on a device. This may be called out of the mount path
|
* Look for a btrfs signature on a device. This may be called out of the mount path
|
||||||
* and we are not allowed to call set_blocksize during the scan. The superblock
|
* and we are not allowed to call set_blocksize during the scan. The superblock
|
||||||
@ -999,13 +1065,11 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
|
|||||||
struct btrfs_super_block *disk_super;
|
struct btrfs_super_block *disk_super;
|
||||||
struct block_device *bdev;
|
struct block_device *bdev;
|
||||||
struct page *page;
|
struct page *page;
|
||||||
void *p;
|
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
u64 devid;
|
u64 devid;
|
||||||
u64 transid;
|
u64 transid;
|
||||||
u64 total_devices;
|
u64 total_devices;
|
||||||
u64 bytenr;
|
u64 bytenr;
|
||||||
pgoff_t index;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* we would like to check all the supers, but that would make
|
* we would like to check all the supers, but that would make
|
||||||
@ -1018,41 +1082,14 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
|
|||||||
mutex_lock(&uuid_mutex);
|
mutex_lock(&uuid_mutex);
|
||||||
|
|
||||||
bdev = blkdev_get_by_path(path, flags, holder);
|
bdev = blkdev_get_by_path(path, flags, holder);
|
||||||
|
|
||||||
if (IS_ERR(bdev)) {
|
if (IS_ERR(bdev)) {
|
||||||
ret = PTR_ERR(bdev);
|
ret = PTR_ERR(bdev);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* make sure our super fits in the device */
|
if (btrfs_read_disk_super(bdev, bytenr, &page, &disk_super))
|
||||||
if (bytenr + PAGE_SIZE >= i_size_read(bdev->bd_inode))
|
|
||||||
goto error_bdev_put;
|
goto error_bdev_put;
|
||||||
|
|
||||||
/* make sure our super fits in the page */
|
|
||||||
if (sizeof(*disk_super) > PAGE_SIZE)
|
|
||||||
goto error_bdev_put;
|
|
||||||
|
|
||||||
/* make sure our super doesn't straddle pages on disk */
|
|
||||||
index = bytenr >> PAGE_SHIFT;
|
|
||||||
if ((bytenr + sizeof(*disk_super) - 1) >> PAGE_SHIFT != index)
|
|
||||||
goto error_bdev_put;
|
|
||||||
|
|
||||||
/* pull in the page with our super */
|
|
||||||
page = read_cache_page_gfp(bdev->bd_inode->i_mapping,
|
|
||||||
index, GFP_NOFS);
|
|
||||||
|
|
||||||
if (IS_ERR_OR_NULL(page))
|
|
||||||
goto error_bdev_put;
|
|
||||||
|
|
||||||
p = kmap(page);
|
|
||||||
|
|
||||||
/* align our pointer to the offset of the super block */
|
|
||||||
disk_super = p + (bytenr & ~PAGE_MASK);
|
|
||||||
|
|
||||||
if (btrfs_super_bytenr(disk_super) != bytenr ||
|
|
||||||
btrfs_super_magic(disk_super) != BTRFS_MAGIC)
|
|
||||||
goto error_unmap;
|
|
||||||
|
|
||||||
devid = btrfs_stack_device_id(&disk_super->dev_item);
|
devid = btrfs_stack_device_id(&disk_super->dev_item);
|
||||||
transid = btrfs_super_generation(disk_super);
|
transid = btrfs_super_generation(disk_super);
|
||||||
total_devices = btrfs_super_num_devices(disk_super);
|
total_devices = btrfs_super_num_devices(disk_super);
|
||||||
@ -1060,8 +1097,6 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
|
|||||||
ret = device_list_add(path, disk_super, devid, fs_devices_ret);
|
ret = device_list_add(path, disk_super, devid, fs_devices_ret);
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
if (disk_super->label[0]) {
|
if (disk_super->label[0]) {
|
||||||
if (disk_super->label[BTRFS_LABEL_SIZE - 1])
|
|
||||||
disk_super->label[BTRFS_LABEL_SIZE - 1] = '\0';
|
|
||||||
printk(KERN_INFO "BTRFS: device label %s ", disk_super->label);
|
printk(KERN_INFO "BTRFS: device label %s ", disk_super->label);
|
||||||
} else {
|
} else {
|
||||||
printk(KERN_INFO "BTRFS: device fsid %pU ", disk_super->fsid);
|
printk(KERN_INFO "BTRFS: device fsid %pU ", disk_super->fsid);
|
||||||
@ -1073,9 +1108,7 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
|
|||||||
if (!ret && fs_devices_ret)
|
if (!ret && fs_devices_ret)
|
||||||
(*fs_devices_ret)->total_devices = total_devices;
|
(*fs_devices_ret)->total_devices = total_devices;
|
||||||
|
|
||||||
error_unmap:
|
btrfs_release_disk_super(page);
|
||||||
kunmap(page);
|
|
||||||
put_page(page);
|
|
||||||
|
|
||||||
error_bdev_put:
|
error_bdev_put:
|
||||||
blkdev_put(bdev, flags);
|
blkdev_put(bdev, flags);
|
||||||
@ -1688,31 +1721,91 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_rm_device(struct btrfs_root *root, char *device_path)
|
/*
|
||||||
|
* Verify that @num_devices satisfies the RAID profile constraints in the whole
|
||||||
|
* filesystem. It's up to the caller to adjust that number regarding eg. device
|
||||||
|
* replace.
|
||||||
|
*/
|
||||||
|
static int btrfs_check_raid_min_devices(struct btrfs_fs_info *fs_info,
|
||||||
|
u64 num_devices)
|
||||||
{
|
{
|
||||||
struct btrfs_device *device;
|
|
||||||
struct btrfs_device *next_device;
|
|
||||||
struct block_device *bdev;
|
|
||||||
struct buffer_head *bh = NULL;
|
|
||||||
struct btrfs_super_block *disk_super;
|
|
||||||
struct btrfs_fs_devices *cur_devices;
|
|
||||||
u64 all_avail;
|
u64 all_avail;
|
||||||
u64 devid;
|
|
||||||
u64 num_devices;
|
|
||||||
u8 *dev_uuid;
|
|
||||||
unsigned seq;
|
unsigned seq;
|
||||||
int ret = 0;
|
int i;
|
||||||
bool clear_super = false;
|
|
||||||
|
|
||||||
mutex_lock(&uuid_mutex);
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
seq = read_seqbegin(&root->fs_info->profiles_lock);
|
seq = read_seqbegin(&fs_info->profiles_lock);
|
||||||
|
|
||||||
all_avail = root->fs_info->avail_data_alloc_bits |
|
all_avail = fs_info->avail_data_alloc_bits |
|
||||||
root->fs_info->avail_system_alloc_bits |
|
fs_info->avail_system_alloc_bits |
|
||||||
root->fs_info->avail_metadata_alloc_bits;
|
fs_info->avail_metadata_alloc_bits;
|
||||||
} while (read_seqretry(&root->fs_info->profiles_lock, seq));
|
} while (read_seqretry(&fs_info->profiles_lock, seq));
|
||||||
|
|
||||||
|
for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) {
|
||||||
|
if (!(all_avail & btrfs_raid_group[i]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (num_devices < btrfs_raid_array[i].devs_min) {
|
||||||
|
int ret = btrfs_raid_mindev_error[i];
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct btrfs_device *btrfs_find_next_active_device(struct btrfs_fs_devices *fs_devs,
|
||||||
|
struct btrfs_device *device)
|
||||||
|
{
|
||||||
|
struct btrfs_device *next_device;
|
||||||
|
|
||||||
|
list_for_each_entry(next_device, &fs_devs->devices, dev_list) {
|
||||||
|
if (next_device != device &&
|
||||||
|
!next_device->missing && next_device->bdev)
|
||||||
|
return next_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper function to check if the given device is part of s_bdev / latest_bdev
|
||||||
|
* and replace it with the provided or the next active device, in the context
|
||||||
|
* where this function called, there should be always be another device (or
|
||||||
|
* this_dev) which is active.
|
||||||
|
*/
|
||||||
|
void btrfs_assign_next_active_device(struct btrfs_fs_info *fs_info,
|
||||||
|
struct btrfs_device *device, struct btrfs_device *this_dev)
|
||||||
|
{
|
||||||
|
struct btrfs_device *next_device;
|
||||||
|
|
||||||
|
if (this_dev)
|
||||||
|
next_device = this_dev;
|
||||||
|
else
|
||||||
|
next_device = btrfs_find_next_active_device(fs_info->fs_devices,
|
||||||
|
device);
|
||||||
|
ASSERT(next_device);
|
||||||
|
|
||||||
|
if (fs_info->sb->s_bdev &&
|
||||||
|
(fs_info->sb->s_bdev == device->bdev))
|
||||||
|
fs_info->sb->s_bdev = next_device->bdev;
|
||||||
|
|
||||||
|
if (fs_info->fs_devices->latest_bdev == device->bdev)
|
||||||
|
fs_info->fs_devices->latest_bdev = next_device->bdev;
|
||||||
|
}
|
||||||
|
|
||||||
|
int btrfs_rm_device(struct btrfs_root *root, char *device_path, u64 devid)
|
||||||
|
{
|
||||||
|
struct btrfs_device *device;
|
||||||
|
struct btrfs_fs_devices *cur_devices;
|
||||||
|
u64 num_devices;
|
||||||
|
int ret = 0;
|
||||||
|
bool clear_super = false;
|
||||||
|
char *dev_name = NULL;
|
||||||
|
|
||||||
|
mutex_lock(&uuid_mutex);
|
||||||
|
|
||||||
num_devices = root->fs_info->fs_devices->num_devices;
|
num_devices = root->fs_info->fs_devices->num_devices;
|
||||||
btrfs_dev_replace_lock(&root->fs_info->dev_replace, 0);
|
btrfs_dev_replace_lock(&root->fs_info->dev_replace, 0);
|
||||||
@ -1722,78 +1815,23 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
|
|||||||
}
|
}
|
||||||
btrfs_dev_replace_unlock(&root->fs_info->dev_replace, 0);
|
btrfs_dev_replace_unlock(&root->fs_info->dev_replace, 0);
|
||||||
|
|
||||||
if ((all_avail & BTRFS_BLOCK_GROUP_RAID10) && num_devices <= 4) {
|
ret = btrfs_check_raid_min_devices(root->fs_info, num_devices - 1);
|
||||||
ret = BTRFS_ERROR_DEV_RAID10_MIN_NOT_MET;
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
|
|
||||||
if ((all_avail & BTRFS_BLOCK_GROUP_RAID1) && num_devices <= 2) {
|
ret = btrfs_find_device_by_devspec(root, devid, device_path,
|
||||||
ret = BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET;
|
&device);
|
||||||
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
|
|
||||||
if ((all_avail & BTRFS_BLOCK_GROUP_RAID5) &&
|
|
||||||
root->fs_info->fs_devices->rw_devices <= 2) {
|
|
||||||
ret = BTRFS_ERROR_DEV_RAID5_MIN_NOT_MET;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if ((all_avail & BTRFS_BLOCK_GROUP_RAID6) &&
|
|
||||||
root->fs_info->fs_devices->rw_devices <= 3) {
|
|
||||||
ret = BTRFS_ERROR_DEV_RAID6_MIN_NOT_MET;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(device_path, "missing") == 0) {
|
|
||||||
struct list_head *devices;
|
|
||||||
struct btrfs_device *tmp;
|
|
||||||
|
|
||||||
device = NULL;
|
|
||||||
devices = &root->fs_info->fs_devices->devices;
|
|
||||||
/*
|
|
||||||
* It is safe to read the devices since the volume_mutex
|
|
||||||
* is held.
|
|
||||||
*/
|
|
||||||
list_for_each_entry(tmp, devices, dev_list) {
|
|
||||||
if (tmp->in_fs_metadata &&
|
|
||||||
!tmp->is_tgtdev_for_dev_replace &&
|
|
||||||
!tmp->bdev) {
|
|
||||||
device = tmp;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bdev = NULL;
|
|
||||||
bh = NULL;
|
|
||||||
disk_super = NULL;
|
|
||||||
if (!device) {
|
|
||||||
ret = BTRFS_ERROR_DEV_MISSING_NOT_FOUND;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ret = btrfs_get_bdev_and_sb(device_path,
|
|
||||||
FMODE_WRITE | FMODE_EXCL,
|
|
||||||
root->fs_info->bdev_holder, 0,
|
|
||||||
&bdev, &bh);
|
|
||||||
if (ret)
|
|
||||||
goto out;
|
|
||||||
disk_super = (struct btrfs_super_block *)bh->b_data;
|
|
||||||
devid = btrfs_stack_device_id(&disk_super->dev_item);
|
|
||||||
dev_uuid = disk_super->dev_item.uuid;
|
|
||||||
device = btrfs_find_device(root->fs_info, devid, dev_uuid,
|
|
||||||
disk_super->fsid);
|
|
||||||
if (!device) {
|
|
||||||
ret = -ENOENT;
|
|
||||||
goto error_brelse;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (device->is_tgtdev_for_dev_replace) {
|
if (device->is_tgtdev_for_dev_replace) {
|
||||||
ret = BTRFS_ERROR_DEV_TGT_REPLACE;
|
ret = BTRFS_ERROR_DEV_TGT_REPLACE;
|
||||||
goto error_brelse;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device->writeable && root->fs_info->fs_devices->rw_devices == 1) {
|
if (device->writeable && root->fs_info->fs_devices->rw_devices == 1) {
|
||||||
ret = BTRFS_ERROR_DEV_ONLY_WRITABLE;
|
ret = BTRFS_ERROR_DEV_ONLY_WRITABLE;
|
||||||
goto error_brelse;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device->writeable) {
|
if (device->writeable) {
|
||||||
@ -1801,6 +1839,11 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
|
|||||||
list_del_init(&device->dev_alloc_list);
|
list_del_init(&device->dev_alloc_list);
|
||||||
device->fs_devices->rw_devices--;
|
device->fs_devices->rw_devices--;
|
||||||
unlock_chunks(root);
|
unlock_chunks(root);
|
||||||
|
dev_name = kstrdup(device->name->str, GFP_KERNEL);
|
||||||
|
if (!dev_name) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto error_undo;
|
||||||
|
}
|
||||||
clear_super = true;
|
clear_super = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1842,12 +1885,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
|
|||||||
if (device->missing)
|
if (device->missing)
|
||||||
device->fs_devices->missing_devices--;
|
device->fs_devices->missing_devices--;
|
||||||
|
|
||||||
next_device = list_entry(root->fs_info->fs_devices->devices.next,
|
btrfs_assign_next_active_device(root->fs_info, device, NULL);
|
||||||
struct btrfs_device, dev_list);
|
|
||||||
if (device->bdev == root->fs_info->sb->s_bdev)
|
|
||||||
root->fs_info->sb->s_bdev = next_device->bdev;
|
|
||||||
if (device->bdev == root->fs_info->fs_devices->latest_bdev)
|
|
||||||
root->fs_info->fs_devices->latest_bdev = next_device->bdev;
|
|
||||||
|
|
||||||
if (device->bdev) {
|
if (device->bdev) {
|
||||||
device->fs_devices->open_devices--;
|
device->fs_devices->open_devices--;
|
||||||
@ -1883,63 +1921,23 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
|
|||||||
* at this point, the device is zero sized. We want to
|
* at this point, the device is zero sized. We want to
|
||||||
* remove it from the devices list and zero out the old super
|
* remove it from the devices list and zero out the old super
|
||||||
*/
|
*/
|
||||||
if (clear_super && disk_super) {
|
if (clear_super) {
|
||||||
u64 bytenr;
|
struct block_device *bdev;
|
||||||
int i;
|
|
||||||
|
|
||||||
/* make sure this device isn't detected as part of
|
bdev = blkdev_get_by_path(dev_name, FMODE_READ | FMODE_EXCL,
|
||||||
* the FS anymore
|
root->fs_info->bdev_holder);
|
||||||
*/
|
if (!IS_ERR(bdev)) {
|
||||||
memset(&disk_super->magic, 0, sizeof(disk_super->magic));
|
btrfs_scratch_superblocks(bdev, dev_name);
|
||||||
set_buffer_dirty(bh);
|
blkdev_put(bdev, FMODE_READ | FMODE_EXCL);
|
||||||
sync_dirty_buffer(bh);
|
|
||||||
|
|
||||||
/* clear the mirror copies of super block on the disk
|
|
||||||
* being removed, 0th copy is been taken care above and
|
|
||||||
* the below would take of the rest
|
|
||||||
*/
|
|
||||||
for (i = 1; i < BTRFS_SUPER_MIRROR_MAX; i++) {
|
|
||||||
bytenr = btrfs_sb_offset(i);
|
|
||||||
if (bytenr + BTRFS_SUPER_INFO_SIZE >=
|
|
||||||
i_size_read(bdev->bd_inode))
|
|
||||||
break;
|
|
||||||
|
|
||||||
brelse(bh);
|
|
||||||
bh = __bread(bdev, bytenr / 4096,
|
|
||||||
BTRFS_SUPER_INFO_SIZE);
|
|
||||||
if (!bh)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
disk_super = (struct btrfs_super_block *)bh->b_data;
|
|
||||||
|
|
||||||
if (btrfs_super_bytenr(disk_super) != bytenr ||
|
|
||||||
btrfs_super_magic(disk_super) != BTRFS_MAGIC) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
memset(&disk_super->magic, 0,
|
|
||||||
sizeof(disk_super->magic));
|
|
||||||
set_buffer_dirty(bh);
|
|
||||||
sync_dirty_buffer(bh);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
if (bdev) {
|
|
||||||
/* Notify udev that device has changed */
|
|
||||||
btrfs_kobject_uevent(bdev, KOBJ_CHANGE);
|
|
||||||
|
|
||||||
/* Update ctime/mtime for device path for libblkid */
|
|
||||||
update_dev_time(device_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
error_brelse:
|
|
||||||
brelse(bh);
|
|
||||||
if (bdev)
|
|
||||||
blkdev_put(bdev, FMODE_READ | FMODE_EXCL);
|
|
||||||
out:
|
out:
|
||||||
|
kfree(dev_name);
|
||||||
|
|
||||||
mutex_unlock(&uuid_mutex);
|
mutex_unlock(&uuid_mutex);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
error_undo:
|
error_undo:
|
||||||
if (device->writeable) {
|
if (device->writeable) {
|
||||||
lock_chunks(root);
|
lock_chunks(root);
|
||||||
@ -1948,7 +1946,7 @@ error_undo:
|
|||||||
device->fs_devices->rw_devices++;
|
device->fs_devices->rw_devices++;
|
||||||
unlock_chunks(root);
|
unlock_chunks(root);
|
||||||
}
|
}
|
||||||
goto error_brelse;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_fs_info *fs_info,
|
void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_fs_info *fs_info,
|
||||||
@ -2017,8 +2015,6 @@ void btrfs_rm_dev_replace_free_srcdev(struct btrfs_fs_info *fs_info,
|
|||||||
void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
|
void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
|
||||||
struct btrfs_device *tgtdev)
|
struct btrfs_device *tgtdev)
|
||||||
{
|
{
|
||||||
struct btrfs_device *next_device;
|
|
||||||
|
|
||||||
mutex_lock(&uuid_mutex);
|
mutex_lock(&uuid_mutex);
|
||||||
WARN_ON(!tgtdev);
|
WARN_ON(!tgtdev);
|
||||||
mutex_lock(&fs_info->fs_devices->device_list_mutex);
|
mutex_lock(&fs_info->fs_devices->device_list_mutex);
|
||||||
@ -2030,12 +2026,8 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
|
|||||||
|
|
||||||
fs_info->fs_devices->num_devices--;
|
fs_info->fs_devices->num_devices--;
|
||||||
|
|
||||||
next_device = list_entry(fs_info->fs_devices->devices.next,
|
btrfs_assign_next_active_device(fs_info, tgtdev, NULL);
|
||||||
struct btrfs_device, dev_list);
|
|
||||||
if (tgtdev->bdev == fs_info->sb->s_bdev)
|
|
||||||
fs_info->sb->s_bdev = next_device->bdev;
|
|
||||||
if (tgtdev->bdev == fs_info->fs_devices->latest_bdev)
|
|
||||||
fs_info->fs_devices->latest_bdev = next_device->bdev;
|
|
||||||
list_del_rcu(&tgtdev->dev_list);
|
list_del_rcu(&tgtdev->dev_list);
|
||||||
|
|
||||||
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
|
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
|
||||||
@ -2109,6 +2101,31 @@ int btrfs_find_device_missing_or_by_path(struct btrfs_root *root,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lookup a device given by device id, or the path if the id is 0.
|
||||||
|
*/
|
||||||
|
int btrfs_find_device_by_devspec(struct btrfs_root *root, u64 devid,
|
||||||
|
char *devpath,
|
||||||
|
struct btrfs_device **device)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (devid) {
|
||||||
|
ret = 0;
|
||||||
|
*device = btrfs_find_device(root->fs_info, devid, NULL,
|
||||||
|
NULL);
|
||||||
|
if (!*device)
|
||||||
|
ret = -ENOENT;
|
||||||
|
} else {
|
||||||
|
if (!devpath || !devpath[0])
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
ret = btrfs_find_device_missing_or_by_path(root, devpath,
|
||||||
|
device);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* does all the dirty work required for changing file system's UUID.
|
* does all the dirty work required for changing file system's UUID.
|
||||||
*/
|
*/
|
||||||
|
@ -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,
|
|||||||
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 {
|
|||||||
#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 {
|
|||||||
};
|
};
|
||||||
__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)
|
|||||||
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 */
|
||||||
|
Loading…
Reference in New Issue
Block a user