summaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ioctl.c
diff options
context:
space:
mode:
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,