aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQu Wenruo <wqu@suse.com>2017-12-12 02:34:34 -0500
committerDavid Sterba <dsterba@suse.com>2018-03-30 20:01:04 -0400
commit8287475a20552af66b32c07704dbdbeeb898ac1f (patch)
treea47e9a69b67d9399ae17f3ba5f093ce796ede144
parent4f5427ccce5d9cb8e2c8f98b49e744e523d246ec (diff)
btrfs: qgroup: Use root::qgroup_meta_rsv_* to record qgroup meta reserved space
For quota disabled->enable case, it's possible that at reservation time quota was not enabled so no bytes were really reserved, while at release time, quota was enabled so we will try to release some bytes we didn't really own. Such situation can cause metadata reserveation underflow, for both types, also less possible for per-trans type since quota enable will commit transaction. To address this, record qgroup meta reserved bytes into root::qgroup_meta_rsv_pertrans and ::prealloc. So at releasing time we won't free any bytes we didn't reserve. For DATA, it's already handled by io_tree, so nothing needs to be done there. Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--fs/btrfs/ctree.h5
-rw-r--r--fs/btrfs/disk-io.c1
-rw-r--r--fs/btrfs/qgroup.c66
3 files changed, 68 insertions, 4 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 7924e50cc528..0eb55825862a 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1264,6 +1264,11 @@ struct btrfs_root {
1264 int send_in_progress; 1264 int send_in_progress;
1265 struct btrfs_subvolume_writers *subv_writers; 1265 struct btrfs_subvolume_writers *subv_writers;
1266 atomic_t will_be_snapshotted; 1266 atomic_t will_be_snapshotted;
1267
1268 /* For qgroup metadata reserved space */
1269 spinlock_t qgroup_meta_rsv_lock;
1270 u64 qgroup_meta_rsv_pertrans;
1271 u64 qgroup_meta_rsv_prealloc;
1267}; 1272};
1268 1273
1269struct btrfs_file_private { 1274struct btrfs_file_private {
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index ad900f821f1e..269374261e36 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1147,6 +1147,7 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info,
1147 spin_lock_init(&root->accounting_lock); 1147 spin_lock_init(&root->accounting_lock);
1148 spin_lock_init(&root->log_extents_lock[0]); 1148 spin_lock_init(&root->log_extents_lock[0]);
1149 spin_lock_init(&root->log_extents_lock[1]); 1149 spin_lock_init(&root->log_extents_lock[1]);
1150 spin_lock_init(&root->qgroup_meta_rsv_lock);
1150 mutex_init(&root->objectid_mutex); 1151 mutex_init(&root->objectid_mutex);
1151 mutex_init(&root->log_mutex); 1152 mutex_init(&root->log_mutex);
1152 mutex_init(&root->ordered_extent_mutex); 1153 mutex_init(&root->ordered_extent_mutex);
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 9ce626579c81..836819c34c95 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -2538,11 +2538,11 @@ void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info,
2538 if (!qgroup) 2538 if (!qgroup)
2539 goto out; 2539 goto out;
2540 2540
2541 /*
2542 * We're freeing all pertrans rsv, get current value from level 0
2543 * qgroup as real num_bytes to free.
2544 */
2545 if (num_bytes == (u64)-1) 2541 if (num_bytes == (u64)-1)
2542 /*
2543 * We're freeing all pertrans rsv, get reserved value from
2544 * level 0 qgroup as real num_bytes to free.
2545 */
2546 num_bytes = qgroup->rsv.values[type]; 2546 num_bytes = qgroup->rsv.values[type];
2547 2547
2548 ulist_reinit(fs_info->qgroup_ulist); 2548 ulist_reinit(fs_info->qgroup_ulist);
@@ -3087,6 +3087,46 @@ int btrfs_qgroup_release_data(struct inode *inode, u64 start, u64 len)
3087 return __btrfs_qgroup_release_data(inode, NULL, start, len, 0); 3087 return __btrfs_qgroup_release_data(inode, NULL, start, len, 0);
3088} 3088}
3089 3089
3090static void add_root_meta_rsv(struct btrfs_root *root, int num_bytes,
3091 enum btrfs_qgroup_rsv_type type)
3092{
3093 if (type != BTRFS_QGROUP_RSV_META_PREALLOC &&
3094 type != BTRFS_QGROUP_RSV_META_PERTRANS)
3095 return;
3096 if (num_bytes == 0)
3097 return;
3098
3099 spin_lock(&root->qgroup_meta_rsv_lock);
3100 if (type == BTRFS_QGROUP_RSV_META_PREALLOC)
3101 root->qgroup_meta_rsv_prealloc += num_bytes;
3102 else
3103 root->qgroup_meta_rsv_pertrans += num_bytes;
3104 spin_unlock(&root->qgroup_meta_rsv_lock);
3105}
3106
3107static int sub_root_meta_rsv(struct btrfs_root *root, int num_bytes,
3108 enum btrfs_qgroup_rsv_type type)
3109{
3110 if (type != BTRFS_QGROUP_RSV_META_PREALLOC &&
3111 type != BTRFS_QGROUP_RSV_META_PERTRANS)
3112 return 0;
3113 if (num_bytes == 0)
3114 return 0;
3115
3116 spin_lock(&root->qgroup_meta_rsv_lock);
3117 if (type == BTRFS_QGROUP_RSV_META_PREALLOC) {
3118 num_bytes = min_t(u64, root->qgroup_meta_rsv_prealloc,
3119 num_bytes);
3120 root->qgroup_meta_rsv_prealloc -= num_bytes;
3121 } else {
3122 num_bytes = min_t(u64, root->qgroup_meta_rsv_pertrans,
3123 num_bytes);
3124 root->qgroup_meta_rsv_pertrans -= num_bytes;
3125 }
3126 spin_unlock(&root->qgroup_meta_rsv_lock);
3127 return num_bytes;
3128}
3129
3090int __btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes, 3130int __btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
3091 enum btrfs_qgroup_rsv_type type, bool enforce) 3131 enum btrfs_qgroup_rsv_type type, bool enforce)
3092{ 3132{
@@ -3102,6 +3142,15 @@ int __btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
3102 ret = qgroup_reserve(root, num_bytes, enforce, type); 3142 ret = qgroup_reserve(root, num_bytes, enforce, type);
3103 if (ret < 0) 3143 if (ret < 0)
3104 return ret; 3144 return ret;
3145 /*
3146 * Record what we have reserved into root.
3147 *
3148 * To avoid quota disabled->enabled underflow.
3149 * In that case, we may try to free space we haven't reserved
3150 * (since quota was disabled), so record what we reserved into root.
3151 * And ensure later release won't underflow this number.
3152 */
3153 add_root_meta_rsv(root, num_bytes, type);
3105 return ret; 3154 return ret;
3106} 3155}
3107 3156
@@ -3129,6 +3178,12 @@ void __btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes,
3129 !is_fstree(root->objectid)) 3178 !is_fstree(root->objectid))
3130 return; 3179 return;
3131 3180
3181 /*
3182 * reservation for META_PREALLOC can happen before quota is enabled,
3183 * which can lead to underflow.
3184 * Here ensure we will only free what we really have reserved.
3185 */
3186 num_bytes = sub_root_meta_rsv(root, num_bytes, type);
3132 BUG_ON(num_bytes != round_down(num_bytes, fs_info->nodesize)); 3187 BUG_ON(num_bytes != round_down(num_bytes, fs_info->nodesize));
3133 trace_qgroup_meta_reserve(root, -(s64)num_bytes); 3188 trace_qgroup_meta_reserve(root, -(s64)num_bytes);
3134 btrfs_qgroup_free_refroot(fs_info, root->objectid, num_bytes, type); 3189 btrfs_qgroup_free_refroot(fs_info, root->objectid, num_bytes, type);
@@ -3187,6 +3242,9 @@ void btrfs_qgroup_convert_reserved_meta(struct btrfs_root *root, int num_bytes)
3187 if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) || 3242 if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) ||
3188 !is_fstree(root->objectid)) 3243 !is_fstree(root->objectid))
3189 return; 3244 return;
3245 /* Same as btrfs_qgroup_free_meta_prealloc() */
3246 num_bytes = sub_root_meta_rsv(root, num_bytes,
3247 BTRFS_QGROUP_RSV_META_PREALLOC);
3190 qgroup_convert_meta(fs_info, root->objectid, num_bytes); 3248 qgroup_convert_meta(fs_info, root->objectid, num_bytes);
3191} 3249}
3192 3250