diff options
Diffstat (limited to 'fs/btrfs/dev-replace.c')
| -rw-r--r-- | fs/btrfs/dev-replace.c | 35 | 
1 files changed, 25 insertions, 10 deletions
| diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index 55c15f31d00d..ee0989c7e3a9 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -603,17 +603,33 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,  	}  	btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1); -	trans = btrfs_start_transaction(root, 0); -	if (IS_ERR(trans)) { -		mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); -		return PTR_ERR(trans); +	/* +	 * We have to use this loop approach because at this point src_device +	 * has to be available for transaction commit to complete, yet new +	 * chunks shouldn't be allocated on the device. +	 */ +	while (1) { +		trans = btrfs_start_transaction(root, 0); +		if (IS_ERR(trans)) { +			mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); +			return PTR_ERR(trans); +		} +		ret = btrfs_commit_transaction(trans); +		WARN_ON(ret); + +		/* Prevent write_all_supers() during the finishing procedure */ +		mutex_lock(&fs_info->fs_devices->device_list_mutex); +		/* Prevent new chunks being allocated on the source device */ +		mutex_lock(&fs_info->chunk_mutex); + +		if (!list_empty(&src_device->post_commit_list)) { +			mutex_unlock(&fs_info->fs_devices->device_list_mutex); +			mutex_unlock(&fs_info->chunk_mutex); +		} else { +			break; +		}  	} -	ret = btrfs_commit_transaction(trans); -	WARN_ON(ret); -	/* keep away write_all_supers() during the finishing procedure */ -	mutex_lock(&fs_info->fs_devices->device_list_mutex); -	mutex_lock(&fs_info->chunk_mutex);  	down_write(&dev_replace->rwsem);  	dev_replace->replace_state =  		scrub_ret ? BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED @@ -662,7 +678,6 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,  	btrfs_device_set_disk_total_bytes(tgt_device,  					  src_device->disk_total_bytes);  	btrfs_device_set_bytes_used(tgt_device, src_device->bytes_used); -	ASSERT(list_empty(&src_device->post_commit_list));  	tgt_device->commit_total_bytes = src_device->commit_total_bytes;  	tgt_device->commit_bytes_used = src_device->bytes_used; | 
