diff options
| author | Qu Wenruo <quwenruo@cn.fujitsu.com> | 2015-10-12 16:05:40 +0800 | 
|---|---|---|
| committer | Chris Mason <clm@fb.com> | 2015-10-21 18:37:45 -0700 | 
| commit | 524725537023bb25a371722b1329446e5a2adcdb (patch) | |
| tree | 40e4d0798939f7a6c9f4ee27c7bf3225c3aa5bb0 /fs | |
| parent | fefdc55702a5f9f99778b6bdce4c4e1185ff943f (diff) | |
btrfs: qgroup: Introduce btrfs_qgroup_reserve_data function
Introduce a new function, btrfs_qgroup_reserve_data(), which will use
io_tree to accurate qgroup reserve, to avoid reserved space leaking.
Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/btrfs/extent_io.h | 1 | ||||
| -rw-r--r-- | fs/btrfs/qgroup.c | 49 | ||||
| -rw-r--r-- | fs/btrfs/qgroup.h | 2 | 
3 files changed, 52 insertions, 0 deletions
| diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 51e1b7143256..f4c1ae11855f 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -19,6 +19,7 @@  #define EXTENT_NEED_WAIT	(1U << 13)  #define EXTENT_DAMAGED		(1U << 14)  #define EXTENT_NORESERVE	(1U << 15) +#define EXTENT_QGROUP_RESERVED	(1U << 16)  #define EXTENT_IOBITS		(EXTENT_LOCKED | EXTENT_WRITEBACK)  #define EXTENT_CTLBITS		(EXTENT_DO_ACCOUNTING | EXTENT_FIRST_DELALLOC) diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index d904ee1c5349..50662748532a 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -2486,3 +2486,52 @@ btrfs_qgroup_rescan_resume(struct btrfs_fs_info *fs_info)  		btrfs_queue_work(fs_info->qgroup_rescan_workers,  				 &fs_info->qgroup_rescan_work);  } + +/* + * Reserve qgroup space for range [start, start + len). + * + * This function will either reserve space from related qgroups or doing + * nothing if the range is already reserved. + * + * Return 0 for successful reserve + * Return <0 for error (including -EQUOT) + * + * NOTE: this function may sleep for memory allocation. + */ +int btrfs_qgroup_reserve_data(struct inode *inode, u64 start, u64 len) +{ +	struct btrfs_root *root = BTRFS_I(inode)->root; +	struct extent_changeset changeset; +	struct ulist_node *unode; +	struct ulist_iterator uiter; +	int ret; + +	if (!root->fs_info->quota_enabled || !is_fstree(root->objectid) || +	    len == 0) +		return 0; + +	changeset.bytes_changed = 0; +	changeset.range_changed = ulist_alloc(GFP_NOFS); + +	ret = set_record_extent_bits(&BTRFS_I(inode)->io_tree, start, +			start + len -1, EXTENT_QGROUP_RESERVED, GFP_NOFS, +			&changeset); +	if (ret < 0) +		goto cleanup; +	ret = btrfs_qgroup_reserve(root, changeset.bytes_changed); +	if (ret < 0) +		goto cleanup; + +	ulist_free(changeset.range_changed); +	return ret; + +cleanup: +	/* cleanup already reserved ranges */ +	ULIST_ITER_INIT(&uiter); +	while ((unode = ulist_next(changeset.range_changed, &uiter))) +		clear_extent_bit(&BTRFS_I(inode)->io_tree, unode->val, +				 unode->aux, EXTENT_QGROUP_RESERVED, 0, 0, NULL, +				 GFP_NOFS); +	ulist_free(changeset.range_changed); +	return ret; +} diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h index 6387dcfa354c..bd17cc24335c 100644 --- a/fs/btrfs/qgroup.h +++ b/fs/btrfs/qgroup.h @@ -81,4 +81,6 @@ int btrfs_verify_qgroup_counts(struct btrfs_fs_info *fs_info, u64 qgroupid,  			       u64 rfer, u64 excl);  #endif +/* New io_tree based accurate qgroup reserve API */ +int btrfs_qgroup_reserve_data(struct inode *inode, u64 start, u64 len);  #endif /* __BTRFS_QGROUP__ */ | 
