aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/free-space-cache.c
diff options
context:
space:
mode:
authorJosef Bacik <josef@redhat.com>2010-06-21 14:48:16 -0400
committerJosef Bacik <josef@redhat.com>2010-10-28 15:59:09 -0400
commit0af3d00bad38d3bb9912a60928ad0669f17bdb76 (patch)
treeabbf4c773138a33dcde483ac60f016c4b5e55dcc /fs/btrfs/free-space-cache.c
parentf6f94e2ab1b33f0082ac22d71f66385a60d8157f (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/free-space-cache.c')
-rw-r--r--fs/btrfs/free-space-cache.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index f488fac04d99..05efcc7061a7 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -23,10 +23,165 @@
23#include "ctree.h" 23#include "ctree.h"
24#include "free-space-cache.h" 24#include "free-space-cache.h"
25#include "transaction.h" 25#include "transaction.h"
26#include "disk-io.h"
26 27
27#define BITS_PER_BITMAP (PAGE_CACHE_SIZE * 8) 28#define BITS_PER_BITMAP (PAGE_CACHE_SIZE * 8)
28#define MAX_CACHE_BYTES_PER_GIG (32 * 1024) 29#define MAX_CACHE_BYTES_PER_GIG (32 * 1024)
29 30
31struct inode *lookup_free_space_inode(struct btrfs_root *root,
32 struct btrfs_block_group_cache
33 *block_group, struct btrfs_path *path)
34{
35 struct btrfs_key key;
36 struct btrfs_key location;
37 struct btrfs_disk_key disk_key;
38 struct btrfs_free_space_header *header;
39 struct extent_buffer *leaf;
40 struct inode *inode = NULL;
41 int ret;
42
43 spin_lock(&block_group->lock);
44 if (block_group->inode)
45 inode = igrab(block_group->inode);
46 spin_unlock(&block_group->lock);
47 if (inode)
48 return inode;
49
50 key.objectid = BTRFS_FREE_SPACE_OBJECTID;
51 key.offset = block_group->key.objectid;
52 key.type = 0;
53
54 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
55 if (ret < 0)
56 return ERR_PTR(ret);
57 if (ret > 0) {
58 btrfs_release_path(root, path);
59 return ERR_PTR(-ENOENT);
60 }
61
62 leaf = path->nodes[0];
63 header = btrfs_item_ptr(leaf, path->slots[0],
64 struct btrfs_free_space_header);
65 btrfs_free_space_key(leaf, header, &disk_key);
66 btrfs_disk_key_to_cpu(&location, &disk_key);
67 btrfs_release_path(root, path);
68
69 inode = btrfs_iget(root->fs_info->sb, &location, root, NULL);
70 if (!inode)
71 return ERR_PTR(-ENOENT);
72 if (IS_ERR(inode))
73 return inode;
74 if (is_bad_inode(inode)) {
75 iput(inode);
76 return ERR_PTR(-ENOENT);
77 }
78
79 spin_lock(&block_group->lock);
80 if (!root->fs_info->closing) {
81 block_group->inode = igrab(inode);
82 block_group->iref = 1;
83 }
84 spin_unlock(&block_group->lock);
85
86 return inode;
87}
88
89int create_free_space_inode(struct btrfs_root *root,
90 struct btrfs_trans_handle *trans,
91 struct btrfs_block_group_cache *block_group,
92 struct btrfs_path *path)
93{
94 struct btrfs_key key;
95 struct btrfs_disk_key disk_key;
96 struct btrfs_free_space_header *header;
97 struct btrfs_inode_item *inode_item;
98 struct extent_buffer *leaf;
99 u64 objectid;
100 int ret;
101
102 ret = btrfs_find_free_objectid(trans, root, 0, &objectid);
103 if (ret < 0)
104 return ret;
105
106 ret = btrfs_insert_empty_inode(trans, root, path, objectid);
107 if (ret)
108 return ret;
109
110 leaf = path->nodes[0];
111 inode_item = btrfs_item_ptr(leaf, path->slots[0],
112 struct btrfs_inode_item);
113 btrfs_item_key(leaf, &disk_key, path->slots[0]);
114 memset_extent_buffer(leaf, 0, (unsigned long)inode_item,
115 sizeof(*inode_item));
116 btrfs_set_inode_generation(leaf, inode_item, trans->transid);
117 btrfs_set_inode_size(leaf, inode_item, 0);
118 btrfs_set_inode_nbytes(leaf, inode_item, 0);
119 btrfs_set_inode_uid(leaf, inode_item, 0);
120 btrfs_set_inode_gid(leaf, inode_item, 0);
121 btrfs_set_inode_mode(leaf, inode_item, S_IFREG | 0600);
122 btrfs_set_inode_flags(leaf, inode_item, BTRFS_INODE_NOCOMPRESS |
123 BTRFS_INODE_PREALLOC | BTRFS_INODE_NODATASUM);
124 btrfs_set_inode_nlink(leaf, inode_item, 1);
125 btrfs_set_inode_transid(leaf, inode_item, trans->transid);
126 btrfs_set_inode_block_group(leaf, inode_item,
127 block_group->key.objectid);
128 btrfs_mark_buffer_dirty(leaf);
129 btrfs_release_path(root, path);
130
131 key.objectid = BTRFS_FREE_SPACE_OBJECTID;
132 key.offset = block_group->key.objectid;
133 key.type = 0;
134
135 ret = btrfs_insert_empty_item(trans, root, path, &key,
136 sizeof(struct btrfs_free_space_header));
137 if (ret < 0) {
138 btrfs_release_path(root, path);
139 return ret;
140 }
141 leaf = path->nodes[0];
142 header = btrfs_item_ptr(leaf, path->slots[0],
143 struct btrfs_free_space_header);
144 memset_extent_buffer(leaf, 0, (unsigned long)header, sizeof(*header));
145 btrfs_set_free_space_key(leaf, header, &disk_key);
146 btrfs_mark_buffer_dirty(leaf);
147 btrfs_release_path(root, path);
148
149 return 0;
150}
151
152int btrfs_truncate_free_space_cache(struct btrfs_root *root,
153 struct btrfs_trans_handle *trans,
154 struct btrfs_path *path,
155 struct inode *inode)
156{
157 loff_t oldsize;
158 int ret = 0;
159
160 trans->block_rsv = root->orphan_block_rsv;
161 ret = btrfs_block_rsv_check(trans, root,
162 root->orphan_block_rsv,
163 0, 5);
164 if (ret)
165 return ret;
166
167 oldsize = i_size_read(inode);
168 btrfs_i_size_write(inode, 0);
169 truncate_pagecache(inode, oldsize, 0);
170
171 /*
172 * We don't need an orphan item because truncating the free space cache
173 * will never be split across transactions.
174 */
175 ret = btrfs_truncate_inode_items(trans, root, inode,
176 0, BTRFS_EXTENT_DATA_KEY);
177 if (ret) {
178 WARN_ON(1);
179 return ret;
180 }
181
182 return btrfs_update_inode(trans, root, inode);
183}
184
30static inline unsigned long offset_to_bit(u64 bitmap_start, u64 sectorsize, 185static inline unsigned long offset_to_bit(u64 bitmap_start, u64 sectorsize,
31 u64 offset) 186 u64 offset)
32{ 187{