diff options
Diffstat (limited to 'fs/btrfs/qgroup.c')
| -rw-r--r-- | fs/btrfs/qgroup.c | 62 | 
1 files changed, 52 insertions, 10 deletions
| diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 93ee1c18ef9d..8db2e29fdcf4 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -995,7 +995,7 @@ int btrfs_quota_disable(struct btrfs_trans_handle *trans,  		goto out;  	fs_info->quota_enabled = 0;  	fs_info->pending_quota_state = 0; -	btrfs_qgroup_wait_for_completion(fs_info); +	btrfs_qgroup_wait_for_completion(fs_info, false);  	spin_lock(&fs_info->qgroup_lock);  	quota_root = fs_info->quota_root;  	fs_info->quota_root = NULL; @@ -1453,10 +1453,9 @@ int btrfs_qgroup_prepare_account_extents(struct btrfs_trans_handle *trans,  	return ret;  } -struct btrfs_qgroup_extent_record * -btrfs_qgroup_insert_dirty_extent(struct btrfs_fs_info *fs_info, -				 struct btrfs_delayed_ref_root *delayed_refs, -				 struct btrfs_qgroup_extent_record *record) +int btrfs_qgroup_insert_dirty_extent_nolock(struct btrfs_fs_info *fs_info, +				struct btrfs_delayed_ref_root *delayed_refs, +				struct btrfs_qgroup_extent_record *record)  {  	struct rb_node **p = &delayed_refs->dirty_extent_root.rb_node;  	struct rb_node *parent_node = NULL; @@ -1475,12 +1474,42 @@ btrfs_qgroup_insert_dirty_extent(struct btrfs_fs_info *fs_info,  		else if (bytenr > entry->bytenr)  			p = &(*p)->rb_right;  		else -			return entry; +			return 1;  	}  	rb_link_node(&record->node, parent_node, p);  	rb_insert_color(&record->node, &delayed_refs->dirty_extent_root); -	return NULL; +	return 0; +} + +int btrfs_qgroup_insert_dirty_extent(struct btrfs_trans_handle *trans, +		struct btrfs_fs_info *fs_info, u64 bytenr, u64 num_bytes, +		gfp_t gfp_flag) +{ +	struct btrfs_qgroup_extent_record *record; +	struct btrfs_delayed_ref_root *delayed_refs; +	int ret; + +	if (!fs_info->quota_enabled || bytenr == 0 || num_bytes == 0) +		return 0; +	if (WARN_ON(trans == NULL)) +		return -EINVAL; +	record = kmalloc(sizeof(*record), gfp_flag); +	if (!record) +		return -ENOMEM; + +	delayed_refs = &trans->transaction->delayed_refs; +	record->bytenr = bytenr; +	record->num_bytes = num_bytes; +	record->old_roots = NULL; + +	spin_lock(&delayed_refs->lock); +	ret = btrfs_qgroup_insert_dirty_extent_nolock(fs_info, delayed_refs, +						      record); +	spin_unlock(&delayed_refs->lock); +	if (ret > 0) +		kfree(record); +	return 0;  }  #define UPDATE_NEW	0 @@ -2303,6 +2332,10 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)  	int err = -ENOMEM;  	int ret = 0; +	mutex_lock(&fs_info->qgroup_rescan_lock); +	fs_info->qgroup_rescan_running = true; +	mutex_unlock(&fs_info->qgroup_rescan_lock); +  	path = btrfs_alloc_path();  	if (!path)  		goto out; @@ -2369,6 +2402,9 @@ out:  	}  done: +	mutex_lock(&fs_info->qgroup_rescan_lock); +	fs_info->qgroup_rescan_running = false; +	mutex_unlock(&fs_info->qgroup_rescan_lock);  	complete_all(&fs_info->qgroup_rescan_completion);  } @@ -2487,20 +2523,26 @@ btrfs_qgroup_rescan(struct btrfs_fs_info *fs_info)  	return 0;  } -int btrfs_qgroup_wait_for_completion(struct btrfs_fs_info *fs_info) +int btrfs_qgroup_wait_for_completion(struct btrfs_fs_info *fs_info, +				     bool interruptible)  {  	int running;  	int ret = 0;  	mutex_lock(&fs_info->qgroup_rescan_lock);  	spin_lock(&fs_info->qgroup_lock); -	running = fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN; +	running = fs_info->qgroup_rescan_running;  	spin_unlock(&fs_info->qgroup_lock);  	mutex_unlock(&fs_info->qgroup_rescan_lock); -	if (running) +	if (!running) +		return 0; + +	if (interruptible)  		ret = wait_for_completion_interruptible(  					&fs_info->qgroup_rescan_completion); +	else +		wait_for_completion(&fs_info->qgroup_rescan_completion);  	return ret;  } |