diff options
author | Josef Bacik <josef@redhat.com> | 2010-06-21 14:48:16 -0400 |
---|---|---|
committer | Josef Bacik <josef@redhat.com> | 2010-10-28 15:59:09 -0400 |
commit | 0af3d00bad38d3bb9912a60928ad0669f17bdb76 (patch) | |
tree | abbf4c773138a33dcde483ac60f016c4b5e55dcc /fs/btrfs/relocation.c | |
parent | f6f94e2ab1b33f0082ac22d71f66385a60d8157f (diff) |
Btrfs: create special free space cache inode
In order to save free space cache, we need an inode to hold the data, and we
need a special item to point at the right inode for the right block group. So
first, create a special item that will point to the right inode, and the number
of extent entries we will have and the number of bitmaps we will have. We
truncate and pre-allocate space everytime to make sure it's uptodate.
This feature will be turned on as soon as you mount with -o space_cache, however
it is safe to boot into old kernels, they will just generate the cache the old
fashion way. When you boot back into a newer kernel we will notice that we
modified and not the cache and automatically discard the cache.
Signed-off-by: Josef Bacik <josef@redhat.com>
Diffstat (limited to 'fs/btrfs/relocation.c')
-rw-r--r-- | fs/btrfs/relocation.c | 91 |
1 files changed, 87 insertions, 4 deletions
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index b37d723b9d4a..af339eee55b8 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include "locking.h" | 29 | #include "locking.h" |
30 | #include "btrfs_inode.h" | 30 | #include "btrfs_inode.h" |
31 | #include "async-thread.h" | 31 | #include "async-thread.h" |
32 | #include "free-space-cache.h" | ||
32 | 33 | ||
33 | /* | 34 | /* |
34 | * backref_node, mapping_node and tree_block start with this | 35 | * backref_node, mapping_node and tree_block start with this |
@@ -3191,6 +3192,54 @@ static int block_use_full_backref(struct reloc_control *rc, | |||
3191 | return ret; | 3192 | return ret; |
3192 | } | 3193 | } |
3193 | 3194 | ||
3195 | static int delete_block_group_cache(struct btrfs_fs_info *fs_info, | ||
3196 | struct inode *inode, u64 ino) | ||
3197 | { | ||
3198 | struct btrfs_key key; | ||
3199 | struct btrfs_path *path; | ||
3200 | struct btrfs_root *root = fs_info->tree_root; | ||
3201 | struct btrfs_trans_handle *trans; | ||
3202 | unsigned long nr; | ||
3203 | int ret = 0; | ||
3204 | |||
3205 | if (inode) | ||
3206 | goto truncate; | ||
3207 | |||
3208 | key.objectid = ino; | ||
3209 | key.type = BTRFS_INODE_ITEM_KEY; | ||
3210 | key.offset = 0; | ||
3211 | |||
3212 | inode = btrfs_iget(fs_info->sb, &key, root, NULL); | ||
3213 | if (!inode || IS_ERR(inode) || is_bad_inode(inode)) { | ||
3214 | if (inode && !IS_ERR(inode)) | ||
3215 | iput(inode); | ||
3216 | return -ENOENT; | ||
3217 | } | ||
3218 | |||
3219 | truncate: | ||
3220 | path = btrfs_alloc_path(); | ||
3221 | if (!path) { | ||
3222 | ret = -ENOMEM; | ||
3223 | goto out; | ||
3224 | } | ||
3225 | |||
3226 | trans = btrfs_join_transaction(root, 0); | ||
3227 | if (IS_ERR(trans)) { | ||
3228 | btrfs_free_path(path); | ||
3229 | goto out; | ||
3230 | } | ||
3231 | |||
3232 | ret = btrfs_truncate_free_space_cache(root, trans, path, inode); | ||
3233 | |||
3234 | btrfs_free_path(path); | ||
3235 | nr = trans->blocks_used; | ||
3236 | btrfs_end_transaction(trans, root); | ||
3237 | btrfs_btree_balance_dirty(root, nr); | ||
3238 | out: | ||
3239 | iput(inode); | ||
3240 | return ret; | ||
3241 | } | ||
3242 | |||
3194 | /* | 3243 | /* |
3195 | * helper to add tree blocks for backref of type BTRFS_EXTENT_DATA_REF_KEY | 3244 | * helper to add tree blocks for backref of type BTRFS_EXTENT_DATA_REF_KEY |
3196 | * this function scans fs tree to find blocks reference the data extent | 3245 | * this function scans fs tree to find blocks reference the data extent |
@@ -3217,15 +3266,27 @@ static int find_data_references(struct reloc_control *rc, | |||
3217 | int counted; | 3266 | int counted; |
3218 | int ret; | 3267 | int ret; |
3219 | 3268 | ||
3220 | path = btrfs_alloc_path(); | ||
3221 | if (!path) | ||
3222 | return -ENOMEM; | ||
3223 | |||
3224 | ref_root = btrfs_extent_data_ref_root(leaf, ref); | 3269 | ref_root = btrfs_extent_data_ref_root(leaf, ref); |
3225 | ref_objectid = btrfs_extent_data_ref_objectid(leaf, ref); | 3270 | ref_objectid = btrfs_extent_data_ref_objectid(leaf, ref); |
3226 | ref_offset = btrfs_extent_data_ref_offset(leaf, ref); | 3271 | ref_offset = btrfs_extent_data_ref_offset(leaf, ref); |
3227 | ref_count = btrfs_extent_data_ref_count(leaf, ref); | 3272 | ref_count = btrfs_extent_data_ref_count(leaf, ref); |
3228 | 3273 | ||
3274 | /* | ||
3275 | * This is an extent belonging to the free space cache, lets just delete | ||
3276 | * it and redo the search. | ||
3277 | */ | ||
3278 | if (ref_root == BTRFS_ROOT_TREE_OBJECTID) { | ||
3279 | ret = delete_block_group_cache(rc->extent_root->fs_info, | ||
3280 | NULL, ref_objectid); | ||
3281 | if (ret != -ENOENT) | ||
3282 | return ret; | ||
3283 | ret = 0; | ||
3284 | } | ||
3285 | |||
3286 | path = btrfs_alloc_path(); | ||
3287 | if (!path) | ||
3288 | return -ENOMEM; | ||
3289 | |||
3229 | root = read_fs_root(rc->extent_root->fs_info, ref_root); | 3290 | root = read_fs_root(rc->extent_root->fs_info, ref_root); |
3230 | if (IS_ERR(root)) { | 3291 | if (IS_ERR(root)) { |
3231 | err = PTR_ERR(root); | 3292 | err = PTR_ERR(root); |
@@ -3860,6 +3921,8 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start) | |||
3860 | { | 3921 | { |
3861 | struct btrfs_fs_info *fs_info = extent_root->fs_info; | 3922 | struct btrfs_fs_info *fs_info = extent_root->fs_info; |
3862 | struct reloc_control *rc; | 3923 | struct reloc_control *rc; |
3924 | struct inode *inode; | ||
3925 | struct btrfs_path *path; | ||
3863 | int ret; | 3926 | int ret; |
3864 | int rw = 0; | 3927 | int rw = 0; |
3865 | int err = 0; | 3928 | int err = 0; |
@@ -3882,6 +3945,26 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start) | |||
3882 | rw = 1; | 3945 | rw = 1; |
3883 | } | 3946 | } |
3884 | 3947 | ||
3948 | path = btrfs_alloc_path(); | ||
3949 | if (!path) { | ||
3950 | err = -ENOMEM; | ||
3951 | goto out; | ||
3952 | } | ||
3953 | |||
3954 | inode = lookup_free_space_inode(fs_info->tree_root, rc->block_group, | ||
3955 | path); | ||
3956 | btrfs_free_path(path); | ||
3957 | |||
3958 | if (!IS_ERR(inode)) | ||
3959 | ret = delete_block_group_cache(fs_info, inode, 0); | ||
3960 | else | ||
3961 | ret = PTR_ERR(inode); | ||
3962 | |||
3963 | if (ret && ret != -ENOENT) { | ||
3964 | err = ret; | ||
3965 | goto out; | ||
3966 | } | ||
3967 | |||
3885 | rc->data_inode = create_reloc_inode(fs_info, rc->block_group); | 3968 | rc->data_inode = create_reloc_inode(fs_info, rc->block_group); |
3886 | if (IS_ERR(rc->data_inode)) { | 3969 | if (IS_ERR(rc->data_inode)) { |
3887 | err = PTR_ERR(rc->data_inode); | 3970 | err = PTR_ERR(rc->data_inode); |