aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQu Wenruo <wqu@suse.com>2017-12-12 02:34:29 -0500
committerDavid Sterba <dsterba@suse.com>2018-03-30 19:41:14 -0400
commit733e03a0b26a463d75aa86083c9fab856571e7fc (patch)
tree6b703eeb697165fdf06b8cad3930ec5143da224f
parent5c40507ffb1bbbc8eeeaa6d8da181f431cb83d97 (diff)
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>
-rw-r--r--fs/btrfs/extent-tree.c8
-rw-r--r--fs/btrfs/qgroup.c22
-rw-r--r--fs/btrfs/qgroup.h69
-rw-r--r--fs/btrfs/transaction.c8
-rw-r--r--include/trace/events/btrfs.h5
5 files changed, 87 insertions, 25 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 0b1f01dd02de..020c1a1a6526 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -5977,7 +5977,7 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
5977 if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) { 5977 if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) {
5978 /* One for parent inode, two for dir entries */ 5978 /* One for parent inode, two for dir entries */
5979 num_bytes = 3 * fs_info->nodesize; 5979 num_bytes = 3 * fs_info->nodesize;
5980 ret = btrfs_qgroup_reserve_meta(root, num_bytes, true); 5980 ret = btrfs_qgroup_reserve_meta_prealloc(root, num_bytes, true);
5981 if (ret) 5981 if (ret)
5982 return ret; 5982 return ret;
5983 } else { 5983 } else {
@@ -5996,7 +5996,7 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
5996 ret = btrfs_block_rsv_migrate(global_rsv, rsv, num_bytes, 1); 5996 ret = btrfs_block_rsv_migrate(global_rsv, rsv, num_bytes, 1);
5997 5997
5998 if (ret && *qgroup_reserved) 5998 if (ret && *qgroup_reserved)
5999 btrfs_qgroup_free_meta(root, *qgroup_reserved); 5999 btrfs_qgroup_free_meta_prealloc(root, *qgroup_reserved);
6000 6000
6001 return ret; 6001 return ret;
6002} 6002}
@@ -6072,7 +6072,7 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes)
6072 spin_unlock(&inode->lock); 6072 spin_unlock(&inode->lock);
6073 6073
6074 if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) { 6074 if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) {
6075 ret = btrfs_qgroup_reserve_meta(root, 6075 ret = btrfs_qgroup_reserve_meta_prealloc(root,
6076 nr_extents * fs_info->nodesize, true); 6076 nr_extents * fs_info->nodesize, true);
6077 if (ret) 6077 if (ret)
6078 goto out_fail; 6078 goto out_fail;
@@ -6080,7 +6080,7 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes)
6080 6080
6081 ret = btrfs_inode_rsv_refill(inode, flush); 6081 ret = btrfs_inode_rsv_refill(inode, flush);
6082 if (unlikely(ret)) { 6082 if (unlikely(ret)) {
6083 btrfs_qgroup_free_meta(root, 6083 btrfs_qgroup_free_meta_prealloc(root,
6084 nr_extents * fs_info->nodesize); 6084 nr_extents * fs_info->nodesize);
6085 goto out_fail; 6085 goto out_fail;
6086 } 6086 }
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index c0deebfecd93..8831eaa14204 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -69,8 +69,10 @@ static const char *qgroup_rsv_type_str(enum btrfs_qgroup_rsv_type type)
69{ 69{
70 if (type == BTRFS_QGROUP_RSV_DATA) 70 if (type == BTRFS_QGROUP_RSV_DATA)
71 return "data"; 71 return "data";
72 if (type == BTRFS_QGROUP_RSV_META) 72 if (type == BTRFS_QGROUP_RSV_META_PERTRANS)
73 return "meta"; 73 return "meta_pertrans";
74 if (type == BTRFS_QGROUP_RSV_META_PREALLOC)
75 return "meta_prealloc";
74 return NULL; 76 return NULL;
75} 77}
76#endif 78#endif
@@ -3065,8 +3067,8 @@ int btrfs_qgroup_release_data(struct inode *inode, u64 start, u64 len)
3065 return __btrfs_qgroup_release_data(inode, NULL, start, len, 0); 3067 return __btrfs_qgroup_release_data(inode, NULL, start, len, 0);
3066} 3068}
3067 3069
3068int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes, 3070int __btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
3069 bool enforce) 3071 enum btrfs_qgroup_rsv_type type, bool enforce)
3070{ 3072{
3071 struct btrfs_fs_info *fs_info = root->fs_info; 3073 struct btrfs_fs_info *fs_info = root->fs_info;
3072 int ret; 3074 int ret;
@@ -3077,14 +3079,14 @@ int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
3077 3079
3078 BUG_ON(num_bytes != round_down(num_bytes, fs_info->nodesize)); 3080 BUG_ON(num_bytes != round_down(num_bytes, fs_info->nodesize));
3079 trace_qgroup_meta_reserve(root, (s64)num_bytes); 3081 trace_qgroup_meta_reserve(root, (s64)num_bytes);
3080 ret = qgroup_reserve(root, num_bytes, enforce, BTRFS_QGROUP_RSV_META); 3082 ret = qgroup_reserve(root, num_bytes, enforce, type);
3081 if (ret < 0) 3083 if (ret < 0)
3082 return ret; 3084 return ret;
3083 atomic64_add(num_bytes, &root->qgroup_meta_rsv); 3085 atomic64_add(num_bytes, &root->qgroup_meta_rsv);
3084 return ret; 3086 return ret;
3085} 3087}
3086 3088
3087void btrfs_qgroup_free_meta_all(struct btrfs_root *root) 3089void btrfs_qgroup_free_meta_all_pertrans(struct btrfs_root *root)
3088{ 3090{
3089 struct btrfs_fs_info *fs_info = root->fs_info; 3091 struct btrfs_fs_info *fs_info = root->fs_info;
3090 u64 reserved; 3092 u64 reserved;
@@ -3098,10 +3100,11 @@ void btrfs_qgroup_free_meta_all(struct btrfs_root *root)
3098 return; 3100 return;
3099 trace_qgroup_meta_reserve(root, -(s64)reserved); 3101 trace_qgroup_meta_reserve(root, -(s64)reserved);
3100 btrfs_qgroup_free_refroot(fs_info, root->objectid, reserved, 3102 btrfs_qgroup_free_refroot(fs_info, root->objectid, reserved,
3101 BTRFS_QGROUP_RSV_META); 3103 BTRFS_QGROUP_RSV_META_PERTRANS);
3102} 3104}
3103 3105
3104void btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes) 3106void __btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes,
3107 enum btrfs_qgroup_rsv_type type)
3105{ 3108{
3106 struct btrfs_fs_info *fs_info = root->fs_info; 3109 struct btrfs_fs_info *fs_info = root->fs_info;
3107 3110
@@ -3113,8 +3116,7 @@ void btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes)
3113 WARN_ON(atomic64_read(&root->qgroup_meta_rsv) < num_bytes); 3116 WARN_ON(atomic64_read(&root->qgroup_meta_rsv) < num_bytes);
3114 atomic64_sub(num_bytes, &root->qgroup_meta_rsv); 3117 atomic64_sub(num_bytes, &root->qgroup_meta_rsv);
3115 trace_qgroup_meta_reserve(root, -(s64)num_bytes); 3118 trace_qgroup_meta_reserve(root, -(s64)num_bytes);
3116 btrfs_qgroup_free_refroot(fs_info, root->objectid, num_bytes, 3119 btrfs_qgroup_free_refroot(fs_info, root->objectid, num_bytes, type);
3117 BTRFS_QGROUP_RSV_META);
3118} 3120}
3119 3121
3120/* 3122/*
diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h
index 279e71a21695..987a5a49deb8 100644
--- a/fs/btrfs/qgroup.h
+++ b/fs/btrfs/qgroup.h
@@ -61,9 +61,31 @@ struct btrfs_qgroup_extent_record {
61 struct ulist *old_roots; 61 struct ulist *old_roots;
62}; 62};
63 63
64/*
65 * Qgroup reservation types:
66 *
67 * DATA:
68 * space reserved for data
69 *
70 * META_PERTRANS:
71 * Space reserved for metadata (per-transaction)
72 * Due to the fact that qgroup data is only updated at transaction commit
73 * time, reserved space for metadata must be kept until transaction
74 * commits.
75 * Any metadata reserved that are used in btrfs_start_transaction() should
76 * be of this type.
77 *
78 * META_PREALLOC:
79 * There are cases where metadata space is reserved before starting
80 * transaction, and then btrfs_join_transaction() to get a trans handle.
81 * Any metadata reserved for such usage should be of this type.
82 * And after join_transaction() part (or all) of such reservation should
83 * be converted into META_PERTRANS.
84 */
64enum btrfs_qgroup_rsv_type { 85enum btrfs_qgroup_rsv_type {
65 BTRFS_QGROUP_RSV_DATA = 0, 86 BTRFS_QGROUP_RSV_DATA = 0,
66 BTRFS_QGROUP_RSV_META, 87 BTRFS_QGROUP_RSV_META_PERTRANS,
88 BTRFS_QGROUP_RSV_META_PREALLOC,
67 BTRFS_QGROUP_RSV_LAST, 89 BTRFS_QGROUP_RSV_LAST,
68}; 90};
69 91
@@ -269,9 +291,46 @@ int btrfs_qgroup_release_data(struct inode *inode, u64 start, u64 len);
269int btrfs_qgroup_free_data(struct inode *inode, 291int btrfs_qgroup_free_data(struct inode *inode,
270 struct extent_changeset *reserved, u64 start, u64 len); 292 struct extent_changeset *reserved, u64 start, u64 len);
271 293
272int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes, 294int __btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
273 bool enforce); 295 enum btrfs_qgroup_rsv_type type, bool enforce);
274void btrfs_qgroup_free_meta_all(struct btrfs_root *root); 296/* Reserve metadata space for pertrans and prealloc type */
275void btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes); 297static inline int btrfs_qgroup_reserve_meta_pertrans(struct btrfs_root *root,
298 int num_bytes, bool enforce)
299{
300 return __btrfs_qgroup_reserve_meta(root, num_bytes,
301 BTRFS_QGROUP_RSV_META_PERTRANS, enforce);
302}
303static inline int btrfs_qgroup_reserve_meta_prealloc(struct btrfs_root *root,
304 int num_bytes, bool enforce)
305{
306 return __btrfs_qgroup_reserve_meta(root, num_bytes,
307 BTRFS_QGROUP_RSV_META_PREALLOC, enforce);
308}
309
310void __btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes,
311 enum btrfs_qgroup_rsv_type type);
312
313/* Free per-transaction meta reservation for error handling */
314static inline void btrfs_qgroup_free_meta_pertrans(struct btrfs_root *root,
315 int num_bytes)
316{
317 __btrfs_qgroup_free_meta(root, num_bytes,
318 BTRFS_QGROUP_RSV_META_PERTRANS);
319}
320
321/* Pre-allocated meta reservation can be freed at need */
322static inline void btrfs_qgroup_free_meta_prealloc(struct btrfs_root *root,
323 int num_bytes)
324{
325 __btrfs_qgroup_free_meta(root, num_bytes,
326 BTRFS_QGROUP_RSV_META_PREALLOC);
327}
328
329/*
330 * Per-transaction meta reservation should be all freed at transaction commit
331 * time
332 */
333void btrfs_qgroup_free_meta_all_pertrans(struct btrfs_root *root);
334
276void btrfs_qgroup_check_reserved_leak(struct inode *inode); 335void btrfs_qgroup_check_reserved_leak(struct inode *inode);
277#endif /* __BTRFS_QGROUP__ */ 336#endif /* __BTRFS_QGROUP__ */
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 15f6541303bc..5c4cf0f9146b 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -498,8 +498,8 @@ start_transaction(struct btrfs_root *root, unsigned int num_items,
498 */ 498 */
499 if (num_items && root != fs_info->chunk_root) { 499 if (num_items && root != fs_info->chunk_root) {
500 qgroup_reserved = num_items * fs_info->nodesize; 500 qgroup_reserved = num_items * fs_info->nodesize;
501 ret = btrfs_qgroup_reserve_meta(root, qgroup_reserved, 501 ret = btrfs_qgroup_reserve_meta_pertrans(root, qgroup_reserved,
502 enforce_qgroups); 502 enforce_qgroups);
503 if (ret) 503 if (ret)
504 return ERR_PTR(ret); 504 return ERR_PTR(ret);
505 505
@@ -596,7 +596,7 @@ alloc_fail:
596 btrfs_block_rsv_release(fs_info, &fs_info->trans_block_rsv, 596 btrfs_block_rsv_release(fs_info, &fs_info->trans_block_rsv,
597 num_bytes); 597 num_bytes);
598reserve_fail: 598reserve_fail:
599 btrfs_qgroup_free_meta(root, qgroup_reserved); 599 btrfs_qgroup_free_meta_pertrans(root, qgroup_reserved);
600 return ERR_PTR(ret); 600 return ERR_PTR(ret);
601} 601}
602 602
@@ -1284,7 +1284,7 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans)
1284 spin_lock(&fs_info->fs_roots_radix_lock); 1284 spin_lock(&fs_info->fs_roots_radix_lock);
1285 if (err) 1285 if (err)
1286 break; 1286 break;
1287 btrfs_qgroup_free_meta_all(root); 1287 btrfs_qgroup_free_meta_all_pertrans(root);
1288 } 1288 }
1289 } 1289 }
1290 spin_unlock(&fs_info->fs_roots_radix_lock); 1290 spin_unlock(&fs_info->fs_roots_radix_lock);
diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h
index 54b9af822a3a..eee778ba1414 100644
--- a/include/trace/events/btrfs.h
+++ b/include/trace/events/btrfs.h
@@ -73,8 +73,9 @@ TRACE_DEFINE_ENUM(COMMIT_TRANS);
73 73
74#define show_qgroup_rsv_type(type) \ 74#define show_qgroup_rsv_type(type) \
75 __print_symbolic(type, \ 75 __print_symbolic(type, \
76 { BTRFS_QGROUP_RSV_DATA, "DATA" }, \ 76 { BTRFS_QGROUP_RSV_DATA, "DATA" }, \
77 { BTRFS_QGROUP_RSV_META, "META" }) 77 { BTRFS_QGROUP_RSV_META_PERTRANS, "META_PERTRANS" }, \
78 { BTRFS_QGROUP_RSV_META_PREALLOC, "META_PREALLOC" })
78 79
79#define BTRFS_GROUP_FLAGS \ 80#define BTRFS_GROUP_FLAGS \
80 { BTRFS_BLOCK_GROUP_DATA, "DATA"}, \ 81 { BTRFS_BLOCK_GROUP_DATA, "DATA"}, \