diff options
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 63 |
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 | */ | ||
2949 | static 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); | ||
2975 | out: | ||
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]); |
2998 | process_slot: | 3036 | process_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, |