mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	btrfs: qgroup: add new quota mode for simple quotas
Add a new quota mode called "simple quotas". It can be enabled by the existing quota enable ioctl via a new command, and sets an incompat bit, as the implementation of simple quotas will make backwards incompatible changes to the disk format of the extent tree. Signed-off-by: Boris Burkov <boris@bur.io> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
		
							parent
							
								
									6b0cd63bc7
								
							
						
					
					
						commit
						182940f4f4
					
				
					 9 changed files with 115 additions and 45 deletions
				
			
		| 
						 | 
				
			
			@ -959,8 +959,7 @@ int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans,
 | 
			
		|||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) &&
 | 
			
		||||
	    !generic_ref->skip_qgroup) {
 | 
			
		||||
	if (btrfs_qgroup_enabled(fs_info) && !generic_ref->skip_qgroup) {
 | 
			
		||||
		record = kzalloc(sizeof(*record), GFP_NOFS);
 | 
			
		||||
		if (!record) {
 | 
			
		||||
			kmem_cache_free(btrfs_delayed_tree_ref_cachep, ref);
 | 
			
		||||
| 
						 | 
				
			
			@ -1063,8 +1062,7 @@ int btrfs_add_delayed_data_ref(struct btrfs_trans_handle *trans,
 | 
			
		|||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) &&
 | 
			
		||||
	    !generic_ref->skip_qgroup) {
 | 
			
		||||
	if (btrfs_qgroup_enabled(fs_info) && !generic_ref->skip_qgroup) {
 | 
			
		||||
		record = kzalloc(sizeof(*record), GFP_NOFS);
 | 
			
		||||
		if (!record) {
 | 
			
		||||
			kmem_cache_free(btrfs_delayed_data_ref_cachep, ref);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -220,7 +220,8 @@ enum {
 | 
			
		|||
	 BTRFS_FEATURE_INCOMPAT_NO_HOLES	|	\
 | 
			
		||||
	 BTRFS_FEATURE_INCOMPAT_METADATA_UUID	|	\
 | 
			
		||||
	 BTRFS_FEATURE_INCOMPAT_RAID1C34	|	\
 | 
			
		||||
	 BTRFS_FEATURE_INCOMPAT_ZONED)
 | 
			
		||||
	 BTRFS_FEATURE_INCOMPAT_ZONED		|	\
 | 
			
		||||
	 BTRFS_FEATURE_INCOMPAT_SIMPLE_QUOTA)
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_BTRFS_DEBUG
 | 
			
		||||
	/*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3697,7 +3697,8 @@ static long btrfs_ioctl_quota_ctl(struct file *file, void __user *arg)
 | 
			
		|||
 | 
			
		||||
	switch (sa->cmd) {
 | 
			
		||||
	case BTRFS_QUOTA_CTL_ENABLE:
 | 
			
		||||
		ret = btrfs_quota_enable(fs_info);
 | 
			
		||||
	case BTRFS_QUOTA_CTL_ENABLE_SIMPLE_QUOTA:
 | 
			
		||||
		ret = btrfs_quota_enable(fs_info, sa);
 | 
			
		||||
		break;
 | 
			
		||||
	case BTRFS_QUOTA_CTL_DISABLE:
 | 
			
		||||
		ret = btrfs_quota_disable(fs_info);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,9 +34,21 @@ enum btrfs_qgroup_mode btrfs_qgroup_mode(struct btrfs_fs_info *fs_info)
 | 
			
		|||
{
 | 
			
		||||
	if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
 | 
			
		||||
		return BTRFS_QGROUP_MODE_DISABLED;
 | 
			
		||||
	if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE)
 | 
			
		||||
		return BTRFS_QGROUP_MODE_SIMPLE;
 | 
			
		||||
	return BTRFS_QGROUP_MODE_FULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool btrfs_qgroup_enabled(struct btrfs_fs_info *fs_info)
 | 
			
		||||
{
 | 
			
		||||
	return btrfs_qgroup_mode(fs_info) != BTRFS_QGROUP_MODE_DISABLED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool btrfs_qgroup_full_accounting(struct btrfs_fs_info *fs_info)
 | 
			
		||||
{
 | 
			
		||||
	return btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_FULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Helpers to access qgroup reservation
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -350,6 +362,8 @@ int btrfs_verify_qgroup_counts(struct btrfs_fs_info *fs_info, u64 qgroupid,
 | 
			
		|||
 | 
			
		||||
static void qgroup_mark_inconsistent(struct btrfs_fs_info *fs_info)
 | 
			
		||||
{
 | 
			
		||||
	if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE)
 | 
			
		||||
		return;
 | 
			
		||||
	fs_info->qgroup_flags |= (BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT |
 | 
			
		||||
				  BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN |
 | 
			
		||||
				  BTRFS_QGROUP_RUNTIME_FLAG_NO_ACCOUNTING);
 | 
			
		||||
| 
						 | 
				
			
			@ -370,8 +384,9 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info)
 | 
			
		|||
	int ret = 0;
 | 
			
		||||
	u64 flags = 0;
 | 
			
		||||
	u64 rescan_progress = 0;
 | 
			
		||||
	bool simple;
 | 
			
		||||
 | 
			
		||||
	if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
 | 
			
		||||
	if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	fs_info->qgroup_ulist = ulist_alloc(GFP_KERNEL);
 | 
			
		||||
| 
						 | 
				
			
			@ -421,14 +436,14 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info)
 | 
			
		|||
				 "old qgroup version, quota disabled");
 | 
			
		||||
				goto out;
 | 
			
		||||
			}
 | 
			
		||||
			fs_info->qgroup_flags = btrfs_qgroup_status_flags(l, ptr);
 | 
			
		||||
			simple = (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE);
 | 
			
		||||
			if (btrfs_qgroup_status_generation(l, ptr) !=
 | 
			
		||||
			    fs_info->generation) {
 | 
			
		||||
			    fs_info->generation && !simple) {
 | 
			
		||||
				qgroup_mark_inconsistent(fs_info);
 | 
			
		||||
				btrfs_err(fs_info,
 | 
			
		||||
					"qgroup generation mismatch, marked as inconsistent");
 | 
			
		||||
			}
 | 
			
		||||
			fs_info->qgroup_flags = btrfs_qgroup_status_flags(l,
 | 
			
		||||
									  ptr);
 | 
			
		||||
			rescan_progress = btrfs_qgroup_status_rescan(l, ptr);
 | 
			
		||||
			goto next1;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -571,7 +586,7 @@ bool btrfs_check_quota_leak(struct btrfs_fs_info *fs_info)
 | 
			
		|||
	struct rb_node *node;
 | 
			
		||||
	bool ret = false;
 | 
			
		||||
 | 
			
		||||
	if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
 | 
			
		||||
	if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED)
 | 
			
		||||
		return ret;
 | 
			
		||||
	/*
 | 
			
		||||
	 * Since we're unmounting, there is no race and no need to grab qgroup
 | 
			
		||||
| 
						 | 
				
			
			@ -970,7 +985,8 @@ static int btrfs_clean_quota_tree(struct btrfs_trans_handle *trans,
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int btrfs_quota_enable(struct btrfs_fs_info *fs_info)
 | 
			
		||||
int btrfs_quota_enable(struct btrfs_fs_info *fs_info,
 | 
			
		||||
		       struct btrfs_ioctl_quota_ctl_args *quota_ctl_args)
 | 
			
		||||
{
 | 
			
		||||
	struct btrfs_root *quota_root;
 | 
			
		||||
	struct btrfs_root *tree_root = fs_info->tree_root;
 | 
			
		||||
| 
						 | 
				
			
			@ -983,6 +999,7 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info)
 | 
			
		|||
	struct btrfs_qgroup *prealloc = NULL;
 | 
			
		||||
	struct btrfs_trans_handle *trans = NULL;
 | 
			
		||||
	struct ulist *ulist = NULL;
 | 
			
		||||
	const bool simple = (quota_ctl_args->cmd == BTRFS_QUOTA_CTL_ENABLE_SIMPLE_QUOTA);
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
	int slot;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1085,8 +1102,11 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info)
 | 
			
		|||
				 struct btrfs_qgroup_status_item);
 | 
			
		||||
	btrfs_set_qgroup_status_generation(leaf, ptr, trans->transid);
 | 
			
		||||
	btrfs_set_qgroup_status_version(leaf, ptr, BTRFS_QGROUP_STATUS_VERSION);
 | 
			
		||||
	fs_info->qgroup_flags = BTRFS_QGROUP_STATUS_FLAG_ON |
 | 
			
		||||
				BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
 | 
			
		||||
	fs_info->qgroup_flags = BTRFS_QGROUP_STATUS_FLAG_ON;
 | 
			
		||||
	if (simple)
 | 
			
		||||
		fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE;
 | 
			
		||||
	else
 | 
			
		||||
		fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
 | 
			
		||||
	btrfs_set_qgroup_status_flags(leaf, ptr, fs_info->qgroup_flags &
 | 
			
		||||
				      BTRFS_QGROUP_STATUS_FLAGS_MASK);
 | 
			
		||||
	btrfs_set_qgroup_status_rescan(leaf, ptr, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -1214,8 +1234,14 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info)
 | 
			
		|||
	spin_lock(&fs_info->qgroup_lock);
 | 
			
		||||
	fs_info->quota_root = quota_root;
 | 
			
		||||
	set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
 | 
			
		||||
	if (simple)
 | 
			
		||||
		btrfs_set_fs_incompat(fs_info, SIMPLE_QUOTA);
 | 
			
		||||
	spin_unlock(&fs_info->qgroup_lock);
 | 
			
		||||
 | 
			
		||||
	/* Skip rescan for simple qgroups. */
 | 
			
		||||
	if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE)
 | 
			
		||||
		goto out_free_path;
 | 
			
		||||
 | 
			
		||||
	ret = qgroup_rescan_init(fs_info, 0, 1);
 | 
			
		||||
	if (!ret) {
 | 
			
		||||
	        qgroup_rescan_zero_tracking(fs_info);
 | 
			
		||||
| 
						 | 
				
			
			@ -1330,6 +1356,7 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
 | 
			
		|||
	quota_root = fs_info->quota_root;
 | 
			
		||||
	fs_info->quota_root = NULL;
 | 
			
		||||
	fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_ON;
 | 
			
		||||
	fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE;
 | 
			
		||||
	fs_info->qgroup_drop_subtree_thres = BTRFS_MAX_LEVEL;
 | 
			
		||||
	spin_unlock(&fs_info->qgroup_lock);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1810,6 +1837,9 @@ int btrfs_qgroup_trace_extent_nolock(struct btrfs_fs_info *fs_info,
 | 
			
		|||
	struct btrfs_qgroup_extent_record *entry;
 | 
			
		||||
	u64 bytenr = record->bytenr;
 | 
			
		||||
 | 
			
		||||
	if (!btrfs_qgroup_full_accounting(fs_info))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	lockdep_assert_held(&delayed_refs->lock);
 | 
			
		||||
	trace_btrfs_qgroup_trace_extent(fs_info, record);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1863,6 +1893,8 @@ int btrfs_qgroup_trace_extent_post(struct btrfs_trans_handle *trans,
 | 
			
		|||
	struct btrfs_backref_walk_ctx ctx = { 0 };
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (!btrfs_qgroup_full_accounting(trans->fs_info))
 | 
			
		||||
		return 0;
 | 
			
		||||
	/*
 | 
			
		||||
	 * We are always called in a context where we are already holding a
 | 
			
		||||
	 * transaction handle. Often we are called when adding a data delayed
 | 
			
		||||
| 
						 | 
				
			
			@ -1931,8 +1963,7 @@ int btrfs_qgroup_trace_extent(struct btrfs_trans_handle *trans, u64 bytenr,
 | 
			
		|||
	struct btrfs_delayed_ref_root *delayed_refs;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)
 | 
			
		||||
	    || bytenr == 0 || num_bytes == 0)
 | 
			
		||||
	if (!btrfs_qgroup_full_accounting(fs_info) || bytenr == 0 || num_bytes == 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
	record = kzalloc(sizeof(*record), GFP_NOFS);
 | 
			
		||||
	if (!record)
 | 
			
		||||
| 
						 | 
				
			
			@ -1970,7 +2001,7 @@ int btrfs_qgroup_trace_leaf_items(struct btrfs_trans_handle *trans,
 | 
			
		|||
	u64 bytenr, num_bytes;
 | 
			
		||||
 | 
			
		||||
	/* We can be called directly from walk_up_proc() */
 | 
			
		||||
	if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
 | 
			
		||||
	if (!btrfs_qgroup_full_accounting(fs_info))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < nr; i++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2346,7 +2377,7 @@ static int qgroup_trace_subtree_swap(struct btrfs_trans_handle *trans,
 | 
			
		|||
	int level;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
 | 
			
		||||
	if (!btrfs_qgroup_full_accounting(fs_info))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	/* Wrong parameter order */
 | 
			
		||||
| 
						 | 
				
			
			@ -2413,7 +2444,7 @@ int btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans,
 | 
			
		|||
	BUG_ON(root_level < 0 || root_level >= BTRFS_MAX_LEVEL);
 | 
			
		||||
	BUG_ON(root_eb == NULL);
 | 
			
		||||
 | 
			
		||||
	if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
 | 
			
		||||
	if (!btrfs_qgroup_full_accounting(fs_info))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	spin_lock(&fs_info->qgroup_lock);
 | 
			
		||||
| 
						 | 
				
			
			@ -2747,7 +2778,7 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr,
 | 
			
		|||
	 * If quotas get disabled meanwhile, the resources need to be freed and
 | 
			
		||||
	 * we can't just exit here.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) ||
 | 
			
		||||
	if (!btrfs_qgroup_full_accounting(fs_info) ||
 | 
			
		||||
	    fs_info->qgroup_flags & BTRFS_QGROUP_RUNTIME_FLAG_NO_ACCOUNTING)
 | 
			
		||||
		goto out_free;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2816,6 +2847,9 @@ int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans)
 | 
			
		|||
	u64 qgroup_to_skip;
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	delayed_refs = &trans->transaction->delayed_refs;
 | 
			
		||||
	qgroup_to_skip = delayed_refs->qgroup_to_skip;
 | 
			
		||||
	while ((node = rb_first(&delayed_refs->dirty_extent_root))) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2931,7 +2965,7 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans)
 | 
			
		|||
			qgroup_mark_inconsistent(fs_info);
 | 
			
		||||
		spin_lock(&fs_info->qgroup_lock);
 | 
			
		||||
	}
 | 
			
		||||
	if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
 | 
			
		||||
	if (btrfs_qgroup_enabled(fs_info))
 | 
			
		||||
		fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_ON;
 | 
			
		||||
	else
 | 
			
		||||
		fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_ON;
 | 
			
		||||
| 
						 | 
				
			
			@ -2990,7 +3024,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
 | 
			
		|||
 | 
			
		||||
	if (!committing)
 | 
			
		||||
		mutex_lock(&fs_info->qgroup_ioctl_lock);
 | 
			
		||||
	if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
 | 
			
		||||
	if (!btrfs_qgroup_enabled(fs_info))
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	quota_root = fs_info->quota_root;
 | 
			
		||||
| 
						 | 
				
			
			@ -3076,7 +3110,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
 | 
			
		|||
		qgroup_dirty(fs_info, dstgroup);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (srcid) {
 | 
			
		||||
	if (srcid && btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_FULL) {
 | 
			
		||||
		srcgroup = find_qgroup_rb(fs_info, srcid);
 | 
			
		||||
		if (!srcgroup)
 | 
			
		||||
			goto unlock;
 | 
			
		||||
| 
						 | 
				
			
			@ -3339,6 +3373,9 @@ static int qgroup_rescan_leaf(struct btrfs_trans_handle *trans,
 | 
			
		|||
	int slot;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (!btrfs_qgroup_full_accounting(fs_info))
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&fs_info->qgroup_rescan_lock);
 | 
			
		||||
	extent_root = btrfs_extent_root(fs_info,
 | 
			
		||||
				fs_info->qgroup_rescan_progress.objectid);
 | 
			
		||||
| 
						 | 
				
			
			@ -3419,10 +3456,15 @@ static int qgroup_rescan_leaf(struct btrfs_trans_handle *trans,
 | 
			
		|||
 | 
			
		||||
static bool rescan_should_stop(struct btrfs_fs_info *fs_info)
 | 
			
		||||
{
 | 
			
		||||
	return btrfs_fs_closing(fs_info) ||
 | 
			
		||||
		test_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state) ||
 | 
			
		||||
		!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) ||
 | 
			
		||||
			  fs_info->qgroup_flags & BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN;
 | 
			
		||||
	if (btrfs_fs_closing(fs_info))
 | 
			
		||||
		return true;
 | 
			
		||||
	if (test_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state))
 | 
			
		||||
		return true;
 | 
			
		||||
	if (!btrfs_qgroup_enabled(fs_info))
 | 
			
		||||
		return true;
 | 
			
		||||
	if (fs_info->qgroup_flags & BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN)
 | 
			
		||||
		return true;
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
 | 
			
		||||
| 
						 | 
				
			
			@ -3436,6 +3478,9 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
 | 
			
		|||
	bool stopped = false;
 | 
			
		||||
	bool did_leaf_rescans = false;
 | 
			
		||||
 | 
			
		||||
	if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	path = btrfs_alloc_path();
 | 
			
		||||
	if (!path)
 | 
			
		||||
		goto out;
 | 
			
		||||
| 
						 | 
				
			
			@ -3539,6 +3584,11 @@ qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid,
 | 
			
		|||
{
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE) {
 | 
			
		||||
		btrfs_warn(fs_info, "qgroup rescan init failed, running in simple mode");
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!init_flags) {
 | 
			
		||||
		/* we're resuming qgroup rescan at mount time */
 | 
			
		||||
		if (!(fs_info->qgroup_flags &
 | 
			
		||||
| 
						 | 
				
			
			@ -3569,7 +3619,7 @@ qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid,
 | 
			
		|||
			btrfs_warn(fs_info,
 | 
			
		||||
			"qgroup rescan init failed, qgroup is not enabled");
 | 
			
		||||
			ret = -EINVAL;
 | 
			
		||||
		} else if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) {
 | 
			
		||||
		} else if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED) {
 | 
			
		||||
			/* Quota disable is in progress */
 | 
			
		||||
			ret = -EBUSY;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -3828,7 +3878,7 @@ static int qgroup_reserve_data(struct btrfs_inode *inode,
 | 
			
		|||
	u64 to_reserve;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &root->fs_info->flags) ||
 | 
			
		||||
	if (btrfs_qgroup_mode(root->fs_info) == BTRFS_QGROUP_MODE_DISABLED ||
 | 
			
		||||
	    !is_fstree(root->root_key.objectid) || len == 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3960,7 +4010,7 @@ static int __btrfs_qgroup_release_data(struct btrfs_inode *inode,
 | 
			
		|||
	int trace_op = QGROUP_RELEASE;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &inode->root->fs_info->flags))
 | 
			
		||||
	if (btrfs_qgroup_mode(inode->root->fs_info) == BTRFS_QGROUP_MODE_DISABLED)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	/* In release case, we shouldn't have @reserved */
 | 
			
		||||
| 
						 | 
				
			
			@ -4071,7 +4121,7 @@ int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
 | 
			
		|||
	struct btrfs_fs_info *fs_info = root->fs_info;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) ||
 | 
			
		||||
	if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED ||
 | 
			
		||||
	    !is_fstree(root->root_key.objectid) || num_bytes == 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4116,7 +4166,7 @@ void btrfs_qgroup_free_meta_all_pertrans(struct btrfs_root *root)
 | 
			
		|||
{
 | 
			
		||||
	struct btrfs_fs_info *fs_info = root->fs_info;
 | 
			
		||||
 | 
			
		||||
	if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) ||
 | 
			
		||||
	if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED ||
 | 
			
		||||
	    !is_fstree(root->root_key.objectid))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4132,7 +4182,7 @@ void __btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes,
 | 
			
		|||
{
 | 
			
		||||
	struct btrfs_fs_info *fs_info = root->fs_info;
 | 
			
		||||
 | 
			
		||||
	if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) ||
 | 
			
		||||
	if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED ||
 | 
			
		||||
	    !is_fstree(root->root_key.objectid))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4191,7 +4241,7 @@ void btrfs_qgroup_convert_reserved_meta(struct btrfs_root *root, int num_bytes)
 | 
			
		|||
{
 | 
			
		||||
	struct btrfs_fs_info *fs_info = root->fs_info;
 | 
			
		||||
 | 
			
		||||
	if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) ||
 | 
			
		||||
	if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_DISABLED ||
 | 
			
		||||
	    !is_fstree(root->root_key.objectid))
 | 
			
		||||
		return;
 | 
			
		||||
	/* Same as btrfs_qgroup_free_meta_prealloc() */
 | 
			
		||||
| 
						 | 
				
			
			@ -4299,7 +4349,7 @@ int btrfs_qgroup_add_swapped_blocks(struct btrfs_trans_handle *trans,
 | 
			
		|||
	int level = btrfs_header_level(subvol_parent) - 1;
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
 | 
			
		||||
	if (!btrfs_qgroup_full_accounting(fs_info))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (btrfs_node_ptr_generation(subvol_parent, subvol_slot) >
 | 
			
		||||
| 
						 | 
				
			
			@ -4409,7 +4459,7 @@ int btrfs_qgroup_trace_subtree_after_cow(struct btrfs_trans_handle *trans,
 | 
			
		|||
	int ret = 0;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
 | 
			
		||||
	if (!btrfs_qgroup_full_accounting(fs_info))
 | 
			
		||||
		return 0;
 | 
			
		||||
	if (!is_fstree(root->root_key.objectid) || !root->reloc_root)
 | 
			
		||||
		return 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -101,8 +101,15 @@
 | 
			
		|||
 *     subtree rescan for them.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN		(1UL << 3)
 | 
			
		||||
#define BTRFS_QGROUP_RUNTIME_FLAG_NO_ACCOUNTING		(1UL << 4)
 | 
			
		||||
/*
 | 
			
		||||
 * These flags share the flags field of the btrfs_qgroup_status_item with the
 | 
			
		||||
 * persisted flags defined in btrfs_tree.h.
 | 
			
		||||
 *
 | 
			
		||||
 * To minimize the chance of collision with new persisted status flags, these
 | 
			
		||||
 * count backwards from the MSB.
 | 
			
		||||
 */
 | 
			
		||||
#define BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN		(1ULL << 63)
 | 
			
		||||
#define BTRFS_QGROUP_RUNTIME_FLAG_NO_ACCOUNTING		(1ULL << 62)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Record a dirty extent, and info qgroup to update quota on it
 | 
			
		||||
| 
						 | 
				
			
			@ -276,13 +283,17 @@ enum {
 | 
			
		|||
	ENUM_BIT(QGROUP_FREE),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int btrfs_quota_enable(struct btrfs_fs_info *fs_info);
 | 
			
		||||
enum btrfs_qgroup_mode {
 | 
			
		||||
	BTRFS_QGROUP_MODE_DISABLED,
 | 
			
		||||
	BTRFS_QGROUP_MODE_FULL,
 | 
			
		||||
	BTRFS_QGROUP_MODE_SIMPLE
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum btrfs_qgroup_mode btrfs_qgroup_mode(struct btrfs_fs_info *fs_info);
 | 
			
		||||
bool btrfs_qgroup_enabled(struct btrfs_fs_info *fs_info);
 | 
			
		||||
bool btrfs_qgroup_full_accounting(struct btrfs_fs_info *fs_info);
 | 
			
		||||
int btrfs_quota_enable(struct btrfs_fs_info *fs_info,
 | 
			
		||||
		       struct btrfs_ioctl_quota_ctl_args *quota_ctl_args);
 | 
			
		||||
int btrfs_quota_disable(struct btrfs_fs_info *fs_info);
 | 
			
		||||
int btrfs_qgroup_rescan(struct btrfs_fs_info *fs_info);
 | 
			
		||||
void btrfs_qgroup_rescan_resume(struct btrfs_fs_info *fs_info);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -510,7 +510,7 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
 | 
			
		|||
	struct btrfs_fs_info *fs_info = root->fs_info;
 | 
			
		||||
	struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
 | 
			
		||||
 | 
			
		||||
	if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) {
 | 
			
		||||
	if (btrfs_qgroup_enabled(fs_info)) {
 | 
			
		||||
		/* One for parent inode, two for dir entries */
 | 
			
		||||
		qgroup_num_bytes = 3 * fs_info->nodesize;
 | 
			
		||||
		ret = btrfs_qgroup_reserve_meta_prealloc(root,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1620,11 +1620,10 @@ static int qgroup_account_snapshot(struct btrfs_trans_handle *trans,
 | 
			
		|||
	int ret;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Save some performance in the case that qgroups are not
 | 
			
		||||
	 * enabled. If this check races with the ioctl, rescan will
 | 
			
		||||
	 * kick in anyway.
 | 
			
		||||
	 * Save some performance in the case that full qgroups are not enabled.
 | 
			
		||||
	 * If this check races with the ioctl, rescan will kick in anyway.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
 | 
			
		||||
	if (!btrfs_qgroup_full_accounting(fs_info))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -334,6 +334,7 @@ struct btrfs_ioctl_fs_info_args {
 | 
			
		|||
#define BTRFS_FEATURE_INCOMPAT_ZONED		(1ULL << 12)
 | 
			
		||||
#define BTRFS_FEATURE_INCOMPAT_EXTENT_TREE_V2	(1ULL << 13)
 | 
			
		||||
#define BTRFS_FEATURE_INCOMPAT_RAID_STRIPE_TREE	(1ULL << 14)
 | 
			
		||||
#define BTRFS_FEATURE_INCOMPAT_SIMPLE_QUOTA	(1ULL << 16)
 | 
			
		||||
 | 
			
		||||
struct btrfs_ioctl_feature_flags {
 | 
			
		||||
	__u64 compat_flags;
 | 
			
		||||
| 
						 | 
				
			
			@ -754,6 +755,7 @@ struct btrfs_ioctl_get_dev_stats {
 | 
			
		|||
#define BTRFS_QUOTA_CTL_ENABLE	1
 | 
			
		||||
#define BTRFS_QUOTA_CTL_DISABLE	2
 | 
			
		||||
#define BTRFS_QUOTA_CTL_RESCAN__NOTUSED	3
 | 
			
		||||
#define BTRFS_QUOTA_CTL_ENABLE_SIMPLE_QUOTA 4
 | 
			
		||||
struct btrfs_ioctl_quota_ctl_args {
 | 
			
		||||
	__u64 cmd;
 | 
			
		||||
	__u64 status;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1233,9 +1233,17 @@ static inline __u16 btrfs_qgroup_level(__u64 qgroupid)
 | 
			
		|||
 */
 | 
			
		||||
#define BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT	(1ULL << 2)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Whether or not this filesystem is using simple quotas.  Not exactly the
 | 
			
		||||
 * incompat bit, because we support using simple quotas, disabling it, then
 | 
			
		||||
 * going back to full qgroup quotas.
 | 
			
		||||
 */
 | 
			
		||||
#define BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE	(1ULL << 3)
 | 
			
		||||
 | 
			
		||||
#define BTRFS_QGROUP_STATUS_FLAGS_MASK	(BTRFS_QGROUP_STATUS_FLAG_ON |		\
 | 
			
		||||
					 BTRFS_QGROUP_STATUS_FLAG_RESCAN |	\
 | 
			
		||||
					 BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT)
 | 
			
		||||
					 BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT | \
 | 
			
		||||
					 BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE)
 | 
			
		||||
 | 
			
		||||
#define BTRFS_QGROUP_STATUS_VERSION        1
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue