aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ioctl.c
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fb.com>2014-05-13 20:30:47 -0400
committerChris Mason <clm@fb.com>2014-06-09 20:20:48 -0400
commitfcebe4562dec83b3f8d3088d77584727b09130b2 (patch)
tree80cf5cf51b8ccbada232486acf57c4bb1cbcf3b4 /fs/btrfs/ioctl.c
parent5dca6eea91653e9949ce6eb9e9acab6277e2f2c4 (diff)
Btrfs: rework qgroup accounting
Currently qgroups account for space by intercepting delayed ref updates to fs trees. It does this by adding sequence numbers to delayed ref updates so that it can figure out how the tree looked before the update so we can adjust the counters properly. The problem with this is that it does not allow delayed refs to be merged, so if you say are defragging an extent with 5k snapshots pointing to it we will thrash the delayed ref lock because we need to go back and manually merge these things together. Instead we want to process quota changes when we know they are going to happen, like when we first allocate an extent, we free a reference for an extent, we add new references etc. This patch accomplishes this by only adding qgroup operations for real ref changes. We only modify the sequence number when we need to lookup roots for bytenrs, this reduces the amount of churn on the sequence number and allows us to merge delayed refs as we add them most of the time. This patch encompasses a bunch of architectural changes 1) qgroup ref operations: instead of tracking qgroup operations through the delayed refs we simply add new ref operations whenever we notice that we need to when we've modified the refs themselves. 2) tree mod seq: we no longer have this separation of major/minor counters. this makes the sequence number stuff much more sane and we can remove some locking that was needed to protect the counter. 3) delayed ref seq: we now read the tree mod seq number and use that as our sequence. This means each new delayed ref doesn't have it's own unique sequence number, rather whenever we go to lookup backrefs we inc the sequence number so we can make sure to keep any new operations from screwing up our world view at that given point. This allows us to merge delayed refs during runtime. With all of these changes the delayed ref stuff is a little saner and the qgroup accounting stuff no longer goes negative in some cases like it was before. Thanks, Signed-off-by: Josef Bacik <jbacik@fb.com> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r--fs/btrfs/ioctl.c63
1 files changed, 62 insertions, 1 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 242a37cd26b2..a21a4ac537b7 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -58,6 +58,7 @@
58#include "dev-replace.h" 58#include "dev-replace.h"
59#include "props.h" 59#include "props.h"
60#include "sysfs.h" 60#include "sysfs.h"
61#include "qgroup.h"
61 62
62#ifdef CONFIG_64BIT 63#ifdef CONFIG_64BIT
63/* If we have a 32-bit userspace and 64-bit kernel, then the UAPI 64/* If we have a 32-bit userspace and 64-bit kernel, then the UAPI
@@ -2941,6 +2942,41 @@ out:
2941 return ret; 2942 return ret;
2942} 2943}
2943 2944
2945/* Helper to check and see if this root currently has a ref on the given disk
2946 * bytenr. If it does then we need to update the quota for this root. This
2947 * doesn't do anything if quotas aren't enabled.
2948 */
2949static int check_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
2950 u64 disko)
2951{
2952 struct seq_list tree_mod_seq_elem = {};
2953 struct ulist *roots;
2954 struct ulist_iterator uiter;
2955 struct ulist_node *root_node = NULL;
2956 int ret;
2957
2958 if (!root->fs_info->quota_enabled)
2959 return 1;
2960
2961 btrfs_get_tree_mod_seq(root->fs_info, &tree_mod_seq_elem);
2962 ret = btrfs_find_all_roots(trans, root->fs_info, disko,
2963 tree_mod_seq_elem.seq, &roots);
2964 if (ret < 0)
2965 goto out;
2966 ret = 0;
2967 ULIST_ITER_INIT(&uiter);
2968 while ((root_node = ulist_next(roots, &uiter))) {
2969 if (root_node->val == root->objectid) {
2970 ret = 1;
2971 break;
2972 }
2973 }
2974 ulist_free(roots);
2975out:
2976 btrfs_put_tree_mod_seq(root->fs_info, &tree_mod_seq_elem);
2977 return ret;
2978}
2979
2944/** 2980/**
2945 * btrfs_clone() - clone a range from inode file to another 2981 * btrfs_clone() - clone a range from inode file to another
2946 * 2982 *
@@ -2964,7 +3000,9 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
2964 u32 nritems; 3000 u32 nritems;
2965 int slot; 3001 int slot;
2966 int ret; 3002 int ret;
3003 int no_quota;
2967 u64 len = olen_aligned; 3004 u64 len = olen_aligned;
3005 u64 last_disko = 0;
2968 3006
2969 ret = -ENOMEM; 3007 ret = -ENOMEM;
2970 buf = vmalloc(btrfs_level_size(root, 0)); 3008 buf = vmalloc(btrfs_level_size(root, 0));
@@ -2996,6 +3034,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
2996 3034
2997 nritems = btrfs_header_nritems(path->nodes[0]); 3035 nritems = btrfs_header_nritems(path->nodes[0]);
2998process_slot: 3036process_slot:
3037 no_quota = 1;
2999 if (path->slots[0] >= nritems) { 3038 if (path->slots[0] >= nritems) {
3000 ret = btrfs_next_leaf(BTRFS_I(src)->root, path); 3039 ret = btrfs_next_leaf(BTRFS_I(src)->root, path);
3001 if (ret < 0) 3040 if (ret < 0)
@@ -3128,6 +3167,28 @@ process_slot:
3128 datao); 3167 datao);
3129 btrfs_set_file_extent_num_bytes(leaf, extent, 3168 btrfs_set_file_extent_num_bytes(leaf, extent,
3130 datal); 3169 datal);
3170
3171 /*
3172 * We need to look up the roots that point at
3173 * this bytenr and see if the new root does. If
3174 * it does not we need to make sure we update
3175 * quotas appropriately.
3176 */
3177 if (disko && root != BTRFS_I(src)->root &&
3178 disko != last_disko) {
3179 no_quota = check_ref(trans, root,
3180 disko);
3181 if (no_quota < 0) {
3182 btrfs_abort_transaction(trans,
3183 root,
3184 ret);
3185 btrfs_end_transaction(trans,
3186 root);
3187 ret = no_quota;
3188 goto out;
3189 }
3190 }
3191
3131 if (disko) { 3192 if (disko) {
3132 inode_add_bytes(inode, datal); 3193 inode_add_bytes(inode, datal);
3133 ret = btrfs_inc_extent_ref(trans, root, 3194 ret = btrfs_inc_extent_ref(trans, root,
@@ -3135,7 +3196,7 @@ process_slot:
3135 root->root_key.objectid, 3196 root->root_key.objectid,
3136 btrfs_ino(inode), 3197 btrfs_ino(inode),
3137 new_key.offset - datao, 3198 new_key.offset - datao,
3138 0); 3199 no_quota);
3139 if (ret) { 3200 if (ret) {
3140 btrfs_abort_transaction(trans, 3201 btrfs_abort_transaction(trans,
3141 root, 3202 root,