mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-03 10:10:33 +02:00 
			
		
		
		
	Btrfs: implement online profile changing
Profile changing is done by launching a balance with BTRFS_BALANCE_CONVERT bits set and target fields of respective btrfs_balance_args structs initialized. Profile reducing code in this case will pick restriper's target profile if it's available instead of doing a blind reduce. If target profile is not yet available it goes back to a plain reduce. Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
This commit is contained in:
		
							parent
							
								
									70922617b0
								
							
						
					
					
						commit
						e4d8ec0f65
					
				
					 3 changed files with 129 additions and 1 deletions
				
			
		| 
						 | 
				
			
			@ -3030,7 +3030,9 @@ static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
 | 
			
		|||
/*
 | 
			
		||||
 * @flags: available profiles in extended format (see ctree.h)
 | 
			
		||||
 *
 | 
			
		||||
 * Returns reduced profile in chunk format.
 | 
			
		||||
 * Returns reduced profile in chunk format.  If profile changing is in
 | 
			
		||||
 * progress (either running or paused) picks the target profile (if it's
 | 
			
		||||
 * already available), otherwise falls back to plain reducing.
 | 
			
		||||
 */
 | 
			
		||||
u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -3042,6 +3044,34 @@ u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags)
 | 
			
		|||
	u64 num_devices = root->fs_info->fs_devices->rw_devices +
 | 
			
		||||
		root->fs_info->fs_devices->missing_devices;
 | 
			
		||||
 | 
			
		||||
	/* pick restriper's target profile if it's available */
 | 
			
		||||
	spin_lock(&root->fs_info->balance_lock);
 | 
			
		||||
	if (root->fs_info->balance_ctl) {
 | 
			
		||||
		struct btrfs_balance_control *bctl = root->fs_info->balance_ctl;
 | 
			
		||||
		u64 tgt = 0;
 | 
			
		||||
 | 
			
		||||
		if ((flags & BTRFS_BLOCK_GROUP_DATA) &&
 | 
			
		||||
		    (bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
 | 
			
		||||
		    (flags & bctl->data.target)) {
 | 
			
		||||
			tgt = BTRFS_BLOCK_GROUP_DATA | bctl->data.target;
 | 
			
		||||
		} else if ((flags & BTRFS_BLOCK_GROUP_SYSTEM) &&
 | 
			
		||||
			   (bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
 | 
			
		||||
			   (flags & bctl->sys.target)) {
 | 
			
		||||
			tgt = BTRFS_BLOCK_GROUP_SYSTEM | bctl->sys.target;
 | 
			
		||||
		} else if ((flags & BTRFS_BLOCK_GROUP_METADATA) &&
 | 
			
		||||
			   (bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
 | 
			
		||||
			   (flags & bctl->meta.target)) {
 | 
			
		||||
			tgt = BTRFS_BLOCK_GROUP_METADATA | bctl->meta.target;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (tgt) {
 | 
			
		||||
			spin_unlock(&root->fs_info->balance_lock);
 | 
			
		||||
			flags = tgt;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	spin_unlock(&root->fs_info->balance_lock);
 | 
			
		||||
 | 
			
		||||
	if (num_devices == 1)
 | 
			
		||||
		flags &= ~(BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID0);
 | 
			
		||||
	if (num_devices < 4)
 | 
			
		||||
| 
						 | 
				
			
			@ -3065,6 +3095,7 @@ u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags)
 | 
			
		|||
		flags &= ~BTRFS_BLOCK_GROUP_RAID0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	/* extended -> chunk profile */
 | 
			
		||||
	flags &= ~BTRFS_AVAIL_ALLOC_BIT_SINGLE;
 | 
			
		||||
	return flags;
 | 
			
		||||
| 
						 | 
				
			
			@ -6795,6 +6826,29 @@ static u64 update_block_group_flags(struct btrfs_root *root, u64 flags)
 | 
			
		|||
	u64 stripped = BTRFS_BLOCK_GROUP_RAID0 |
 | 
			
		||||
		BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10;
 | 
			
		||||
 | 
			
		||||
	if (root->fs_info->balance_ctl) {
 | 
			
		||||
		struct btrfs_balance_control *bctl = root->fs_info->balance_ctl;
 | 
			
		||||
		u64 tgt = 0;
 | 
			
		||||
 | 
			
		||||
		/* pick restriper's target profile and return */
 | 
			
		||||
		if (flags & BTRFS_BLOCK_GROUP_DATA &&
 | 
			
		||||
		    bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) {
 | 
			
		||||
			tgt = BTRFS_BLOCK_GROUP_DATA | bctl->data.target;
 | 
			
		||||
		} else if (flags & BTRFS_BLOCK_GROUP_SYSTEM &&
 | 
			
		||||
			   bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) {
 | 
			
		||||
			tgt = BTRFS_BLOCK_GROUP_SYSTEM | bctl->sys.target;
 | 
			
		||||
		} else if (flags & BTRFS_BLOCK_GROUP_METADATA &&
 | 
			
		||||
			   bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) {
 | 
			
		||||
			tgt = BTRFS_BLOCK_GROUP_METADATA | bctl->meta.target;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (tgt) {
 | 
			
		||||
			/* extended -> chunk profile */
 | 
			
		||||
			tgt &= ~BTRFS_AVAIL_ALLOC_BIT_SINGLE;
 | 
			
		||||
			return tgt;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * we add in the count of missing devices because we want
 | 
			
		||||
	 * to make sure that any RAID levels on a degraded FS
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2438,6 +2438,75 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Profile changing sanity checks.  Skip them if a simple
 | 
			
		||||
	 * balance is requested.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!((bctl->data.flags | bctl->sys.flags | bctl->meta.flags) &
 | 
			
		||||
	      BTRFS_BALANCE_ARGS_CONVERT))
 | 
			
		||||
		goto do_balance;
 | 
			
		||||
 | 
			
		||||
	allowed = BTRFS_AVAIL_ALLOC_BIT_SINGLE;
 | 
			
		||||
	if (fs_info->fs_devices->num_devices == 1)
 | 
			
		||||
		allowed |= BTRFS_BLOCK_GROUP_DUP;
 | 
			
		||||
	else if (fs_info->fs_devices->num_devices < 4)
 | 
			
		||||
		allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1);
 | 
			
		||||
	else
 | 
			
		||||
		allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 |
 | 
			
		||||
				BTRFS_BLOCK_GROUP_RAID10);
 | 
			
		||||
 | 
			
		||||
	if (!profile_is_valid(bctl->data.target, 1) ||
 | 
			
		||||
	    bctl->data.target & ~allowed) {
 | 
			
		||||
		printk(KERN_ERR "btrfs: unable to start balance with target "
 | 
			
		||||
		       "data profile %llu\n",
 | 
			
		||||
		       (unsigned long long)bctl->data.target);
 | 
			
		||||
		ret = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	if (!profile_is_valid(bctl->meta.target, 1) ||
 | 
			
		||||
	    bctl->meta.target & ~allowed) {
 | 
			
		||||
		printk(KERN_ERR "btrfs: unable to start balance with target "
 | 
			
		||||
		       "metadata profile %llu\n",
 | 
			
		||||
		       (unsigned long long)bctl->meta.target);
 | 
			
		||||
		ret = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	if (!profile_is_valid(bctl->sys.target, 1) ||
 | 
			
		||||
	    bctl->sys.target & ~allowed) {
 | 
			
		||||
		printk(KERN_ERR "btrfs: unable to start balance with target "
 | 
			
		||||
		       "system profile %llu\n",
 | 
			
		||||
		       (unsigned long long)bctl->sys.target);
 | 
			
		||||
		ret = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (bctl->data.target & BTRFS_BLOCK_GROUP_DUP) {
 | 
			
		||||
		printk(KERN_ERR "btrfs: dup for data is not allowed\n");
 | 
			
		||||
		ret = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* allow to reduce meta or sys integrity only if force set */
 | 
			
		||||
	allowed = BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1 |
 | 
			
		||||
			BTRFS_BLOCK_GROUP_RAID10;
 | 
			
		||||
	if (((bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
 | 
			
		||||
	     (fs_info->avail_system_alloc_bits & allowed) &&
 | 
			
		||||
	     !(bctl->sys.target & allowed)) ||
 | 
			
		||||
	    ((bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
 | 
			
		||||
	     (fs_info->avail_metadata_alloc_bits & allowed) &&
 | 
			
		||||
	     !(bctl->meta.target & allowed))) {
 | 
			
		||||
		if (bctl->flags & BTRFS_BALANCE_FORCE) {
 | 
			
		||||
			printk(KERN_INFO "btrfs: force reducing metadata "
 | 
			
		||||
			       "integrity\n");
 | 
			
		||||
		} else {
 | 
			
		||||
			printk(KERN_ERR "btrfs: balance will reduce metadata "
 | 
			
		||||
			       "integrity, use force if you want this\n");
 | 
			
		||||
			ret = -EINVAL;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
do_balance:
 | 
			
		||||
	set_balance_control(bctl);
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&fs_info->balance_mutex);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -196,6 +196,9 @@ struct map_lookup {
 | 
			
		|||
#define BTRFS_BALANCE_TYPE_MASK		(BTRFS_BALANCE_DATA |	    \
 | 
			
		||||
					 BTRFS_BALANCE_SYSTEM |	    \
 | 
			
		||||
					 BTRFS_BALANCE_METADATA)
 | 
			
		||||
 | 
			
		||||
#define BTRFS_BALANCE_FORCE		(1ULL << 3)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Balance filters
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -205,6 +208,8 @@ struct map_lookup {
 | 
			
		|||
#define BTRFS_BALANCE_ARGS_DRANGE	(1ULL << 3)
 | 
			
		||||
#define BTRFS_BALANCE_ARGS_VRANGE	(1ULL << 4)
 | 
			
		||||
 | 
			
		||||
#define BTRFS_BALANCE_ARGS_CONVERT	(1ULL << 8)
 | 
			
		||||
 | 
			
		||||
struct btrfs_balance_args;
 | 
			
		||||
struct btrfs_balance_control {
 | 
			
		||||
	struct btrfs_fs_info *fs_info;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue