diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-21 20:49:22 +0300 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-21 20:49:22 +0300 | 
| commit | 07be1337b9e8bfcd855c6e9175b5066a30ac609b (patch) | |
| tree | e40ad01dc89f6eb17d461939b809fea3387fc2a5 /fs/btrfs/dev-replace.c | |
| parent | 63d222b9d277c4d7bf08afd1631a7f8e327a825c (diff) | |
| parent | c315ef8d9db7f1a0ebd023a395ebdfde1c68057e (diff) | |
| download | linux-07be1337b9e8bfcd855c6e9175b5066a30ac609b.tar.xz | |
Merge branch 'for-linus-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs
Pull btrfs updates from Chris Mason:
 "This has our merge window series of cleanups and fixes.  These target
  a wide range of issues, but do include some important fixes for
  qgroups, O_DIRECT, and fsync handling.  Jeff Mahoney moved around a
  few definitions to make them easier for userland to consume.
  Also whiteout support is included now that issues with overlayfs have
  been cleared up.
  I have one more fix pending for page faults during btrfs_copy_from_user,
  but I wanted to get this bulk out the door first"
* 'for-linus-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: (90 commits)
  btrfs: fix memory leak during RAID 5/6 device replacement
  Btrfs: add semaphore to synchronize direct IO writes with fsync
  Btrfs: fix race between block group relocation and nocow writes
  Btrfs: fix race between fsync and direct IO writes for prealloc extents
  Btrfs: fix number of transaction units for renames with whiteout
  Btrfs: pin logs earlier when doing a rename exchange operation
  Btrfs: unpin logs if rename exchange operation fails
  Btrfs: fix inode leak on failure to setup whiteout inode in rename
  btrfs: add support for RENAME_EXCHANGE and RENAME_WHITEOUT
  Btrfs: pin log earlier when renaming
  Btrfs: unpin log if rename operation fails
  Btrfs: don't do unnecessary delalloc flushes when relocating
  Btrfs: don't wait for unrelated IO to finish before relocation
  Btrfs: fix empty symlink after creating symlink and fsync parent dir
  Btrfs: fix for incorrect directory entries after fsync log replay
  btrfs: build fixup for qgroup_account_snapshot
  btrfs: qgroup: Fix qgroup accounting when creating snapshot
  Btrfs: fix fspath error deallocation
  btrfs: make find_workspace warn if there are no workspaces
  btrfs: make find_workspace always succeed
  ...
Diffstat (limited to 'fs/btrfs/dev-replace.c')
| -rw-r--r-- | fs/btrfs/dev-replace.c | 101 | 
1 files changed, 45 insertions, 56 deletions
| diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index 26bcb487f958..85f12e6e28d2 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -44,9 +44,6 @@ static void btrfs_dev_replace_update_device_in_mapping_tree(  						struct btrfs_fs_info *fs_info,  						struct btrfs_device *srcdev,  						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 int btrfs_dev_replace_kthread(void *data);  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;  } -int btrfs_dev_replace_start(struct btrfs_root *root, -			    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)  {  	struct btrfs_trans_handle *trans;  	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 *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 */  	mutex_lock(&fs_info->volume_mutex); -	ret = btrfs_dev_replace_find_srcdev(root, args->start.srcdevid, -					    args->start.srcdev_name, -					    &src_device); +	ret = btrfs_find_device_by_devspec(root, srcdevid, +					    srcdev_name, &src_device);  	if (ret) {  		mutex_unlock(&fs_info->volume_mutex);  		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);  	mutex_unlock(&fs_info->volume_mutex);  	if (ret) @@ -364,18 +348,17 @@ int btrfs_dev_replace_start(struct btrfs_root *root,  		break;  	case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:  	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;  	} -	dev_replace->cont_reading_from_srcdev_mode = -		args->start.cont_reading_from_srcdev_mode; +	dev_replace->cont_reading_from_srcdev_mode = read_src;  	WARN_ON(!src_device);  	dev_replace->srcdev = src_device;  	WARN_ON(!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",  		      src_device->missing ? "<missing disk>" :  		        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;  	atomic64_set(&dev_replace->num_write_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);  	ret = btrfs_sysfs_add_device_link(tgt_device->fs_devices, tgt_device);  	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(root->fs_info, -1, 0, (u64)-1);  	/* force writing the updated state information to disk */  	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),  			      &dev_replace->scrub_progress, 0, 1); -	ret = btrfs_dev_replace_finishing(root->fs_info, ret); -	/* don't warn if EINPROGRESS, someone else might be running scrub */ +	ret = btrfs_dev_replace_finishing(fs_info, ret);  	if (ret == -EINPROGRESS) { -		args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS; -		ret = 0; +		ret = BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS;  	} else {  		WARN_ON(ret);  	} @@ -440,6 +420,35 @@ leave:  	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.   */ @@ -495,7 +504,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,  		mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);  		return ret;  	} -	btrfs_wait_ordered_roots(root->fs_info, -1); +	btrfs_wait_ordered_roots(root->fs_info, -1, 0, (u64)-1);  	trans = btrfs_start_transaction(root, 0);  	if (IS_ERR(trans)) { @@ -560,10 +569,9 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,  	ASSERT(list_empty(&src_device->resized_list));  	tgt_device->commit_total_bytes = src_device->commit_total_bytes;  	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; -	if (fs_info->fs_devices->latest_bdev == src_device->bdev) -		fs_info->fs_devices->latest_bdev = tgt_device->bdev; + +	btrfs_assign_next_active_device(fs_info, src_device, tgt_device); +  	list_add(&tgt_device->dev_alloc_list, &fs_info->fs_devices->alloc_list);  	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);  } -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,  			      struct btrfs_ioctl_dev_replace_args *args)  { | 
