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/free-space-cache.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/free-space-cache.c')
-rw-r--r-- | fs/btrfs/free-space-cache.c | 155 |
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 | ||
31 | struct 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 | |||
89 | int 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 | |||
152 | int 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 | |||
30 | static inline unsigned long offset_to_bit(u64 bitmap_start, u64 sectorsize, | 185 | static inline unsigned long offset_to_bit(u64 bitmap_start, u64 sectorsize, |
31 | u64 offset) | 186 | u64 offset) |
32 | { | 187 | { |