diff options
Diffstat (limited to 'fs/btrfs/dev-replace.c')
| -rw-r--r-- | fs/btrfs/dev-replace.c | 76 | 
1 files changed, 42 insertions, 34 deletions
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index bee3edeea7a3..7c655f9a7a50 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -639,11 +639,39 @@ static void btrfs_dev_replace_update_device_in_mapping_tree(  	write_unlock(&em_tree->lock);  } +/* + * Read progress of device replace status according to the state and last + * stored position. The value format is the same as for + * btrfs_dev_replace::progress_1000 + */ +static u64 btrfs_dev_replace_progress(struct btrfs_fs_info *fs_info) +{ +	struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; +	u64 ret = 0; + +	switch (dev_replace->replace_state) { +	case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED: +	case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED: +		ret = 0; +		break; +	case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED: +		ret = 1000; +		break; +	case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: +	case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: +		ret = div64_u64(dev_replace->cursor_left, +				div_u64(btrfs_device_get_total_bytes( +						dev_replace->srcdev), 1000)); +		break; +	} + +	return ret; +} +  void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info,  			      struct btrfs_ioctl_dev_replace_args *args)  {  	struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; -	struct btrfs_device *srcdev;  	btrfs_dev_replace_lock(dev_replace, 0);  	/* even if !dev_replace_is_valid, the values are good enough for @@ -656,21 +684,7 @@ void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info,  		atomic64_read(&dev_replace->num_write_errors);  	args->status.num_uncorrectable_read_errors =  		atomic64_read(&dev_replace->num_uncorrectable_read_errors); -	switch (dev_replace->replace_state) { -	case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED: -	case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED: -		args->status.progress_1000 = 0; -		break; -	case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED: -		args->status.progress_1000 = 1000; -		break; -	case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: -	case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: -		srcdev = dev_replace->srcdev; -		args->status.progress_1000 = div64_u64(dev_replace->cursor_left, -			div_u64(btrfs_device_get_total_bytes(srcdev), 1000)); -		break; -	} +	args->status.progress_1000 = btrfs_dev_replace_progress(fs_info);  	btrfs_dev_replace_unlock(dev_replace, 0);  } @@ -690,7 +704,7 @@ static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info)  	u64 result;  	int ret; -	if (fs_info->sb->s_flags & MS_RDONLY) +	if (sb_rdonly(fs_info->sb))  		return -EROFS;  	mutex_lock(&dev_replace->lock_finishing_cancel_unmount); @@ -795,25 +809,19 @@ static int btrfs_dev_replace_kthread(void *data)  {  	struct btrfs_fs_info *fs_info = data;  	struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; -	struct btrfs_ioctl_dev_replace_args *status_args;  	u64 progress; -	status_args = kzalloc(sizeof(*status_args), GFP_KERNEL); -	if (status_args) { -		btrfs_dev_replace_status(fs_info, status_args); -		progress = status_args->status.progress_1000; -		kfree(status_args); -		progress = div_u64(progress, 10); -		btrfs_info_in_rcu(fs_info, -			"continuing dev_replace from %s (devid %llu) to %s @%u%%", -			dev_replace->srcdev->missing ? "<missing disk>" : -			rcu_str_deref(dev_replace->srcdev->name), -			dev_replace->srcdev->devid, -			dev_replace->tgtdev ? -			rcu_str_deref(dev_replace->tgtdev->name) : -			"<missing target disk>", -			(unsigned int)progress); -	} +	progress = btrfs_dev_replace_progress(fs_info); +	progress = div_u64(progress, 10); +	btrfs_info_in_rcu(fs_info, +		"continuing dev_replace from %s (devid %llu) to %s @%u%%", +		dev_replace->srcdev->missing ? "<missing disk>" +			: rcu_str_deref(dev_replace->srcdev->name), +		dev_replace->srcdev->devid, +		dev_replace->tgtdev ? rcu_str_deref(dev_replace->tgtdev->name) +			: "<missing target disk>", +		(unsigned int)progress); +  	btrfs_dev_replace_continue_on_mount(fs_info);  	clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags);  |