mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 02:39:48 +00:00
btrfs: qgroup: Split meta rsv type into meta_prealloc and meta_pertrans
Btrfs uses 2 different methods to reseve metadata qgroup space. 1) Reserve at btrfs_start_transaction() time This is quite straightforward, caller will use the trans handler allocated to modify b-trees. In this case, reserved metadata should be kept until qgroup numbers are updated. 2) Reserve by using block_rsv first, and later btrfs_join_transaction() This is more complicated, caller will reserve space using block_rsv first, and then later call btrfs_join_transaction() to get a trans handle. In this case, before we modify trees, the reserved space can be modified on demand, and after btrfs_join_transaction(), such reserved space should also be kept until qgroup numbers are updated. Since these two types behave differently, split the original "META" reservation type into 2 sub-types: META_PERTRANS: For above case 1) META_PREALLOC: For reservations that happened before btrfs_join_transaction() of case 2) NOTE: This patch will only convert existing qgroup meta reservation callers according to its situation, not ensuring all callers are at correct timing. Such fix will be added in later patches. Signed-off-by: Qu Wenruo <wqu@suse.com> [ update comments ] Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
5c40507ffb
commit
733e03a0b2
5 changed files with 87 additions and 25 deletions
|
@ -5977,7 +5977,7 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
|
||||||
if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) {
|
if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) {
|
||||||
/* One for parent inode, two for dir entries */
|
/* One for parent inode, two for dir entries */
|
||||||
num_bytes = 3 * fs_info->nodesize;
|
num_bytes = 3 * fs_info->nodesize;
|
||||||
ret = btrfs_qgroup_reserve_meta(root, num_bytes, true);
|
ret = btrfs_qgroup_reserve_meta_prealloc(root, num_bytes, true);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
} else {
|
} else {
|
||||||
|
@ -5996,7 +5996,7 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
|
||||||
ret = btrfs_block_rsv_migrate(global_rsv, rsv, num_bytes, 1);
|
ret = btrfs_block_rsv_migrate(global_rsv, rsv, num_bytes, 1);
|
||||||
|
|
||||||
if (ret && *qgroup_reserved)
|
if (ret && *qgroup_reserved)
|
||||||
btrfs_qgroup_free_meta(root, *qgroup_reserved);
|
btrfs_qgroup_free_meta_prealloc(root, *qgroup_reserved);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -6072,7 +6072,7 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes)
|
||||||
spin_unlock(&inode->lock);
|
spin_unlock(&inode->lock);
|
||||||
|
|
||||||
if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) {
|
if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) {
|
||||||
ret = btrfs_qgroup_reserve_meta(root,
|
ret = btrfs_qgroup_reserve_meta_prealloc(root,
|
||||||
nr_extents * fs_info->nodesize, true);
|
nr_extents * fs_info->nodesize, true);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_fail;
|
goto out_fail;
|
||||||
|
@ -6080,7 +6080,7 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes)
|
||||||
|
|
||||||
ret = btrfs_inode_rsv_refill(inode, flush);
|
ret = btrfs_inode_rsv_refill(inode, flush);
|
||||||
if (unlikely(ret)) {
|
if (unlikely(ret)) {
|
||||||
btrfs_qgroup_free_meta(root,
|
btrfs_qgroup_free_meta_prealloc(root,
|
||||||
nr_extents * fs_info->nodesize);
|
nr_extents * fs_info->nodesize);
|
||||||
goto out_fail;
|
goto out_fail;
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,8 +69,10 @@ static const char *qgroup_rsv_type_str(enum btrfs_qgroup_rsv_type type)
|
||||||
{
|
{
|
||||||
if (type == BTRFS_QGROUP_RSV_DATA)
|
if (type == BTRFS_QGROUP_RSV_DATA)
|
||||||
return "data";
|
return "data";
|
||||||
if (type == BTRFS_QGROUP_RSV_META)
|
if (type == BTRFS_QGROUP_RSV_META_PERTRANS)
|
||||||
return "meta";
|
return "meta_pertrans";
|
||||||
|
if (type == BTRFS_QGROUP_RSV_META_PREALLOC)
|
||||||
|
return "meta_prealloc";
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -3065,8 +3067,8 @@ int btrfs_qgroup_release_data(struct inode *inode, u64 start, u64 len)
|
||||||
return __btrfs_qgroup_release_data(inode, NULL, start, len, 0);
|
return __btrfs_qgroup_release_data(inode, NULL, start, len, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
|
int __btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
|
||||||
bool enforce)
|
enum btrfs_qgroup_rsv_type type, bool enforce)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -3077,14 +3079,14 @@ int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
|
||||||
|
|
||||||
BUG_ON(num_bytes != round_down(num_bytes, fs_info->nodesize));
|
BUG_ON(num_bytes != round_down(num_bytes, fs_info->nodesize));
|
||||||
trace_qgroup_meta_reserve(root, (s64)num_bytes);
|
trace_qgroup_meta_reserve(root, (s64)num_bytes);
|
||||||
ret = qgroup_reserve(root, num_bytes, enforce, BTRFS_QGROUP_RSV_META);
|
ret = qgroup_reserve(root, num_bytes, enforce, type);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
atomic64_add(num_bytes, &root->qgroup_meta_rsv);
|
atomic64_add(num_bytes, &root->qgroup_meta_rsv);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void btrfs_qgroup_free_meta_all(struct btrfs_root *root)
|
void btrfs_qgroup_free_meta_all_pertrans(struct btrfs_root *root)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||||
u64 reserved;
|
u64 reserved;
|
||||||
|
@ -3098,10 +3100,11 @@ void btrfs_qgroup_free_meta_all(struct btrfs_root *root)
|
||||||
return;
|
return;
|
||||||
trace_qgroup_meta_reserve(root, -(s64)reserved);
|
trace_qgroup_meta_reserve(root, -(s64)reserved);
|
||||||
btrfs_qgroup_free_refroot(fs_info, root->objectid, reserved,
|
btrfs_qgroup_free_refroot(fs_info, root->objectid, reserved,
|
||||||
BTRFS_QGROUP_RSV_META);
|
BTRFS_QGROUP_RSV_META_PERTRANS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes)
|
void __btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes,
|
||||||
|
enum btrfs_qgroup_rsv_type type)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||||
|
|
||||||
|
@ -3113,8 +3116,7 @@ void btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes)
|
||||||
WARN_ON(atomic64_read(&root->qgroup_meta_rsv) < num_bytes);
|
WARN_ON(atomic64_read(&root->qgroup_meta_rsv) < num_bytes);
|
||||||
atomic64_sub(num_bytes, &root->qgroup_meta_rsv);
|
atomic64_sub(num_bytes, &root->qgroup_meta_rsv);
|
||||||
trace_qgroup_meta_reserve(root, -(s64)num_bytes);
|
trace_qgroup_meta_reserve(root, -(s64)num_bytes);
|
||||||
btrfs_qgroup_free_refroot(fs_info, root->objectid, num_bytes,
|
btrfs_qgroup_free_refroot(fs_info, root->objectid, num_bytes, type);
|
||||||
BTRFS_QGROUP_RSV_META);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -61,9 +61,31 @@ struct btrfs_qgroup_extent_record {
|
||||||
struct ulist *old_roots;
|
struct ulist *old_roots;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Qgroup reservation types:
|
||||||
|
*
|
||||||
|
* DATA:
|
||||||
|
* space reserved for data
|
||||||
|
*
|
||||||
|
* META_PERTRANS:
|
||||||
|
* Space reserved for metadata (per-transaction)
|
||||||
|
* Due to the fact that qgroup data is only updated at transaction commit
|
||||||
|
* time, reserved space for metadata must be kept until transaction
|
||||||
|
* commits.
|
||||||
|
* Any metadata reserved that are used in btrfs_start_transaction() should
|
||||||
|
* be of this type.
|
||||||
|
*
|
||||||
|
* META_PREALLOC:
|
||||||
|
* There are cases where metadata space is reserved before starting
|
||||||
|
* transaction, and then btrfs_join_transaction() to get a trans handle.
|
||||||
|
* Any metadata reserved for such usage should be of this type.
|
||||||
|
* And after join_transaction() part (or all) of such reservation should
|
||||||
|
* be converted into META_PERTRANS.
|
||||||
|
*/
|
||||||
enum btrfs_qgroup_rsv_type {
|
enum btrfs_qgroup_rsv_type {
|
||||||
BTRFS_QGROUP_RSV_DATA = 0,
|
BTRFS_QGROUP_RSV_DATA = 0,
|
||||||
BTRFS_QGROUP_RSV_META,
|
BTRFS_QGROUP_RSV_META_PERTRANS,
|
||||||
|
BTRFS_QGROUP_RSV_META_PREALLOC,
|
||||||
BTRFS_QGROUP_RSV_LAST,
|
BTRFS_QGROUP_RSV_LAST,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -269,9 +291,46 @@ int btrfs_qgroup_release_data(struct inode *inode, u64 start, u64 len);
|
||||||
int btrfs_qgroup_free_data(struct inode *inode,
|
int btrfs_qgroup_free_data(struct inode *inode,
|
||||||
struct extent_changeset *reserved, u64 start, u64 len);
|
struct extent_changeset *reserved, u64 start, u64 len);
|
||||||
|
|
||||||
int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
|
int __btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
|
||||||
bool enforce);
|
enum btrfs_qgroup_rsv_type type, bool enforce);
|
||||||
void btrfs_qgroup_free_meta_all(struct btrfs_root *root);
|
/* Reserve metadata space for pertrans and prealloc type */
|
||||||
void btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes);
|
static inline int btrfs_qgroup_reserve_meta_pertrans(struct btrfs_root *root,
|
||||||
|
int num_bytes, bool enforce)
|
||||||
|
{
|
||||||
|
return __btrfs_qgroup_reserve_meta(root, num_bytes,
|
||||||
|
BTRFS_QGROUP_RSV_META_PERTRANS, enforce);
|
||||||
|
}
|
||||||
|
static inline int btrfs_qgroup_reserve_meta_prealloc(struct btrfs_root *root,
|
||||||
|
int num_bytes, bool enforce)
|
||||||
|
{
|
||||||
|
return __btrfs_qgroup_reserve_meta(root, num_bytes,
|
||||||
|
BTRFS_QGROUP_RSV_META_PREALLOC, enforce);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes,
|
||||||
|
enum btrfs_qgroup_rsv_type type);
|
||||||
|
|
||||||
|
/* Free per-transaction meta reservation for error handling */
|
||||||
|
static inline void btrfs_qgroup_free_meta_pertrans(struct btrfs_root *root,
|
||||||
|
int num_bytes)
|
||||||
|
{
|
||||||
|
__btrfs_qgroup_free_meta(root, num_bytes,
|
||||||
|
BTRFS_QGROUP_RSV_META_PERTRANS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pre-allocated meta reservation can be freed at need */
|
||||||
|
static inline void btrfs_qgroup_free_meta_prealloc(struct btrfs_root *root,
|
||||||
|
int num_bytes)
|
||||||
|
{
|
||||||
|
__btrfs_qgroup_free_meta(root, num_bytes,
|
||||||
|
BTRFS_QGROUP_RSV_META_PREALLOC);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Per-transaction meta reservation should be all freed at transaction commit
|
||||||
|
* time
|
||||||
|
*/
|
||||||
|
void btrfs_qgroup_free_meta_all_pertrans(struct btrfs_root *root);
|
||||||
|
|
||||||
void btrfs_qgroup_check_reserved_leak(struct inode *inode);
|
void btrfs_qgroup_check_reserved_leak(struct inode *inode);
|
||||||
#endif /* __BTRFS_QGROUP__ */
|
#endif /* __BTRFS_QGROUP__ */
|
||||||
|
|
|
@ -498,7 +498,7 @@ start_transaction(struct btrfs_root *root, unsigned int num_items,
|
||||||
*/
|
*/
|
||||||
if (num_items && root != fs_info->chunk_root) {
|
if (num_items && root != fs_info->chunk_root) {
|
||||||
qgroup_reserved = num_items * fs_info->nodesize;
|
qgroup_reserved = num_items * fs_info->nodesize;
|
||||||
ret = btrfs_qgroup_reserve_meta(root, qgroup_reserved,
|
ret = btrfs_qgroup_reserve_meta_pertrans(root, qgroup_reserved,
|
||||||
enforce_qgroups);
|
enforce_qgroups);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
|
@ -596,7 +596,7 @@ start_transaction(struct btrfs_root *root, unsigned int num_items,
|
||||||
btrfs_block_rsv_release(fs_info, &fs_info->trans_block_rsv,
|
btrfs_block_rsv_release(fs_info, &fs_info->trans_block_rsv,
|
||||||
num_bytes);
|
num_bytes);
|
||||||
reserve_fail:
|
reserve_fail:
|
||||||
btrfs_qgroup_free_meta(root, qgroup_reserved);
|
btrfs_qgroup_free_meta_pertrans(root, qgroup_reserved);
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1284,7 +1284,7 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans)
|
||||||
spin_lock(&fs_info->fs_roots_radix_lock);
|
spin_lock(&fs_info->fs_roots_radix_lock);
|
||||||
if (err)
|
if (err)
|
||||||
break;
|
break;
|
||||||
btrfs_qgroup_free_meta_all(root);
|
btrfs_qgroup_free_meta_all_pertrans(root);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spin_unlock(&fs_info->fs_roots_radix_lock);
|
spin_unlock(&fs_info->fs_roots_radix_lock);
|
||||||
|
|
|
@ -74,7 +74,8 @@ TRACE_DEFINE_ENUM(COMMIT_TRANS);
|
||||||
#define show_qgroup_rsv_type(type) \
|
#define show_qgroup_rsv_type(type) \
|
||||||
__print_symbolic(type, \
|
__print_symbolic(type, \
|
||||||
{ BTRFS_QGROUP_RSV_DATA, "DATA" }, \
|
{ BTRFS_QGROUP_RSV_DATA, "DATA" }, \
|
||||||
{ BTRFS_QGROUP_RSV_META, "META" })
|
{ BTRFS_QGROUP_RSV_META_PERTRANS, "META_PERTRANS" }, \
|
||||||
|
{ BTRFS_QGROUP_RSV_META_PREALLOC, "META_PREALLOC" })
|
||||||
|
|
||||||
#define BTRFS_GROUP_FLAGS \
|
#define BTRFS_GROUP_FLAGS \
|
||||||
{ BTRFS_BLOCK_GROUP_DATA, "DATA"}, \
|
{ BTRFS_BLOCK_GROUP_DATA, "DATA"}, \
|
||||||
|
|
Loading…
Reference in a new issue