mirror of
https://github.com/ukui/kernel.git
synced 2026-03-09 10:07:04 -07:00
Btrfs: add new sources for device replace code
This adds a new file to the sources together with the header file and the changes to ioctl.h and ctree.h that are required by the new C source file. Additionally, 4 new functions are added to volume.c that deal with device creation and destruction. Signed-off-by: Stefan Behrens <sbehrens@giantdisaster.de> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
This commit is contained in:
committed by
Josef Bacik
parent
ff023aac31
commit
e93c89c1aa
@@ -8,7 +8,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
|
||||
extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
|
||||
export.o tree-log.o free-space-cache.o zlib.o lzo.o \
|
||||
compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \
|
||||
reada.o backref.o ulist.o qgroup.o send.o
|
||||
reada.o backref.o ulist.o qgroup.o send.o dev-replace.o
|
||||
|
||||
btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
|
||||
btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
|
||||
|
||||
@@ -142,6 +142,8 @@ struct btrfs_ordered_sum;
|
||||
|
||||
#define BTRFS_EMPTY_SUBVOL_DIR_OBJECTID 2
|
||||
|
||||
#define BTRFS_DEV_REPLACE_DEVID 0
|
||||
|
||||
/*
|
||||
* the max metadata block size. This limit is somewhat artificial,
|
||||
* but the memmove costs go through the roof for larger blocks.
|
||||
|
||||
856
fs/btrfs/dev-replace.c
Normal file
856
fs/btrfs/dev-replace.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,24 @@
|
||||
#if !defined(__BTRFS_DEV_REPLACE__)
|
||||
#define __BTRFS_DEV_REPLACE__
|
||||
|
||||
struct btrfs_ioctl_dev_replace_args;
|
||||
|
||||
int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info);
|
||||
int btrfs_run_dev_replace(struct btrfs_trans_handle *trans,
|
||||
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,
|
||||
struct btrfs_ioctl_dev_replace_args *args);
|
||||
void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_ioctl_dev_replace_args *args);
|
||||
int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_ioctl_dev_replace_args *args);
|
||||
void btrfs_dev_replace_suspend_for_unmount(struct btrfs_fs_info *fs_info);
|
||||
int btrfs_resume_dev_replace_async(struct btrfs_fs_info *fs_info);
|
||||
int btrfs_dev_replace_is_ongoing(struct btrfs_dev_replace *dev_replace);
|
||||
void btrfs_dev_replace_lock(struct btrfs_dev_replace *dev_replace);
|
||||
void btrfs_dev_replace_unlock(struct btrfs_dev_replace *dev_replace);
|
||||
|
||||
static inline void btrfs_dev_replace_stats_inc(atomic64_t *stat_value)
|
||||
{
|
||||
atomic64_inc(stat_value);
|
||||
|
||||
@@ -123,6 +123,48 @@ struct btrfs_ioctl_scrub_args {
|
||||
__u64 unused[(1024-32-sizeof(struct btrfs_scrub_progress))/8];
|
||||
};
|
||||
|
||||
#define BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS 0
|
||||
#define BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID 1
|
||||
struct btrfs_ioctl_dev_replace_start_params {
|
||||
__u64 srcdevid; /* in, if 0, use srcdev_name instead */
|
||||
__u8 srcdev_name[BTRFS_PATH_NAME_MAX + 1]; /* in */
|
||||
__u8 tgtdev_name[BTRFS_PATH_NAME_MAX + 1]; /* in */
|
||||
__u64 cont_reading_from_srcdev_mode; /* in, see #define
|
||||
* above */
|
||||
};
|
||||
|
||||
#define BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED 0
|
||||
#define BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED 1
|
||||
#define BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED 2
|
||||
#define BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED 3
|
||||
#define BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED 4
|
||||
struct btrfs_ioctl_dev_replace_status_params {
|
||||
__u64 replace_state; /* out, see #define above */
|
||||
__u64 progress_1000; /* out, 0 <= x <= 1000 */
|
||||
__u64 time_started; /* out, seconds since 1-Jan-1970 */
|
||||
__u64 time_stopped; /* out, seconds since 1-Jan-1970 */
|
||||
__u64 num_write_errors; /* out */
|
||||
__u64 num_uncorrectable_read_errors; /* out */
|
||||
};
|
||||
|
||||
#define BTRFS_IOCTL_DEV_REPLACE_CMD_START 0
|
||||
#define BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS 1
|
||||
#define BTRFS_IOCTL_DEV_REPLACE_CMD_CANCEL 2
|
||||
#define BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR 0
|
||||
#define BTRFS_IOCTL_DEV_REPLACE_RESULT_NOT_STARTED 1
|
||||
#define BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED 2
|
||||
struct btrfs_ioctl_dev_replace_args {
|
||||
__u64 cmd; /* in */
|
||||
__u64 result; /* out */
|
||||
|
||||
union {
|
||||
struct btrfs_ioctl_dev_replace_start_params start;
|
||||
struct btrfs_ioctl_dev_replace_status_params status;
|
||||
}; /* in/out */
|
||||
|
||||
__u64 spare[64];
|
||||
};
|
||||
|
||||
#define BTRFS_DEVICE_PATH_NAME_MAX 1024
|
||||
struct btrfs_ioctl_dev_info_args {
|
||||
__u64 devid; /* in/out */
|
||||
@@ -453,4 +495,7 @@ struct btrfs_ioctl_send_args {
|
||||
struct btrfs_ioctl_qgroup_limit_args)
|
||||
#define BTRFS_IOC_GET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 52, \
|
||||
struct btrfs_ioctl_get_dev_stats)
|
||||
#define BTRFS_IOC_DEV_REPLACE _IOWR(BTRFS_IOCTL_MAGIC, 53, \
|
||||
struct btrfs_ioctl_dev_replace_args)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1537,6 +1537,53 @@ error_undo:
|
||||
goto error_brelse;
|
||||
}
|
||||
|
||||
void btrfs_rm_dev_replace_srcdev(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_device *srcdev)
|
||||
{
|
||||
WARN_ON(!mutex_is_locked(&fs_info->fs_devices->device_list_mutex));
|
||||
list_del_rcu(&srcdev->dev_list);
|
||||
list_del_rcu(&srcdev->dev_alloc_list);
|
||||
fs_info->fs_devices->num_devices--;
|
||||
if (srcdev->missing) {
|
||||
fs_info->fs_devices->missing_devices--;
|
||||
fs_info->fs_devices->rw_devices++;
|
||||
}
|
||||
if (srcdev->can_discard)
|
||||
fs_info->fs_devices->num_can_discard--;
|
||||
if (srcdev->bdev)
|
||||
fs_info->fs_devices->open_devices--;
|
||||
|
||||
call_rcu(&srcdev->rcu, free_device);
|
||||
}
|
||||
|
||||
void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_device *tgtdev)
|
||||
{
|
||||
struct btrfs_device *next_device;
|
||||
|
||||
WARN_ON(!tgtdev);
|
||||
mutex_lock(&fs_info->fs_devices->device_list_mutex);
|
||||
if (tgtdev->bdev) {
|
||||
btrfs_scratch_superblock(tgtdev);
|
||||
fs_info->fs_devices->open_devices--;
|
||||
}
|
||||
fs_info->fs_devices->num_devices--;
|
||||
if (tgtdev->can_discard)
|
||||
fs_info->fs_devices->num_can_discard++;
|
||||
|
||||
next_device = list_entry(fs_info->fs_devices->devices.next,
|
||||
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);
|
||||
|
||||
call_rcu(&tgtdev->rcu, free_device);
|
||||
|
||||
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
|
||||
}
|
||||
|
||||
int btrfs_find_device_by_path(struct btrfs_root *root, char *device_path,
|
||||
struct btrfs_device **device)
|
||||
{
|
||||
@@ -1931,6 +1978,98 @@ error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
|
||||
struct btrfs_device **device_out)
|
||||
{
|
||||
struct request_queue *q;
|
||||
struct btrfs_device *device;
|
||||
struct block_device *bdev;
|
||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||
struct list_head *devices;
|
||||
struct rcu_string *name;
|
||||
int ret = 0;
|
||||
|
||||
*device_out = NULL;
|
||||
if (fs_info->fs_devices->seeding)
|
||||
return -EINVAL;
|
||||
|
||||
bdev = blkdev_get_by_path(device_path, FMODE_WRITE | FMODE_EXCL,
|
||||
fs_info->bdev_holder);
|
||||
if (IS_ERR(bdev))
|
||||
return PTR_ERR(bdev);
|
||||
|
||||
filemap_write_and_wait(bdev->bd_inode->i_mapping);
|
||||
|
||||
devices = &fs_info->fs_devices->devices;
|
||||
list_for_each_entry(device, devices, dev_list) {
|
||||
if (device->bdev == bdev) {
|
||||
ret = -EEXIST;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
device = kzalloc(sizeof(*device), GFP_NOFS);
|
||||
if (!device) {
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
name = rcu_string_strdup(device_path, GFP_NOFS);
|
||||
if (!name) {
|
||||
kfree(device);
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
rcu_assign_pointer(device->name, name);
|
||||
|
||||
q = bdev_get_queue(bdev);
|
||||
if (blk_queue_discard(q))
|
||||
device->can_discard = 1;
|
||||
mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
|
||||
device->writeable = 1;
|
||||
device->work.func = pending_bios_fn;
|
||||
generate_random_uuid(device->uuid);
|
||||
device->devid = BTRFS_DEV_REPLACE_DEVID;
|
||||
spin_lock_init(&device->io_lock);
|
||||
device->generation = 0;
|
||||
device->io_width = root->sectorsize;
|
||||
device->io_align = root->sectorsize;
|
||||
device->sector_size = root->sectorsize;
|
||||
device->total_bytes = i_size_read(bdev->bd_inode);
|
||||
device->disk_total_bytes = device->total_bytes;
|
||||
device->dev_root = fs_info->dev_root;
|
||||
device->bdev = bdev;
|
||||
device->in_fs_metadata = 1;
|
||||
device->is_tgtdev_for_dev_replace = 1;
|
||||
device->mode = FMODE_EXCL;
|
||||
set_blocksize(device->bdev, 4096);
|
||||
device->fs_devices = fs_info->fs_devices;
|
||||
list_add(&device->dev_list, &fs_info->fs_devices->devices);
|
||||
fs_info->fs_devices->num_devices++;
|
||||
fs_info->fs_devices->open_devices++;
|
||||
if (device->can_discard)
|
||||
fs_info->fs_devices->num_can_discard++;
|
||||
mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
|
||||
|
||||
*device_out = device;
|
||||
return ret;
|
||||
|
||||
error:
|
||||
blkdev_put(bdev, FMODE_EXCL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void btrfs_init_dev_replace_tgtdev_for_resume(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_device *tgtdev)
|
||||
{
|
||||
WARN_ON(fs_info->fs_devices->rw_devices == 0);
|
||||
tgtdev->io_width = fs_info->dev_root->sectorsize;
|
||||
tgtdev->io_align = fs_info->dev_root->sectorsize;
|
||||
tgtdev->sector_size = fs_info->dev_root->sectorsize;
|
||||
tgtdev->dev_root = fs_info->dev_root;
|
||||
tgtdev->in_fs_metadata = 1;
|
||||
}
|
||||
|
||||
static noinline int btrfs_update_device(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_device *device)
|
||||
{
|
||||
|
||||
@@ -286,6 +286,8 @@ struct btrfs_device *btrfs_find_device(struct btrfs_fs_info *fs_info, u64 devid,
|
||||
u8 *uuid, u8 *fsid);
|
||||
int btrfs_shrink_device(struct btrfs_device *device, u64 new_size);
|
||||
int btrfs_init_new_device(struct btrfs_root *root, char *path);
|
||||
int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
|
||||
struct btrfs_device **device_out);
|
||||
int btrfs_balance(struct btrfs_balance_control *bctl,
|
||||
struct btrfs_ioctl_balance_args *bargs);
|
||||
int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info);
|
||||
@@ -302,6 +304,12 @@ int btrfs_get_dev_stats(struct btrfs_root *root,
|
||||
int btrfs_init_dev_stats(struct btrfs_fs_info *fs_info);
|
||||
int btrfs_run_dev_stats(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_fs_info *fs_info);
|
||||
void btrfs_rm_dev_replace_srcdev(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_device *srcdev);
|
||||
void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_device *tgtdev);
|
||||
void btrfs_init_dev_replace_tgtdev_for_resume(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_device *tgtdev);
|
||||
int btrfs_scratch_superblock(struct btrfs_device *device);
|
||||
|
||||
static inline void btrfs_dev_stat_inc(struct btrfs_device *dev,
|
||||
|
||||
Reference in New Issue
Block a user