diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-10-15 16:14:19 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:03:56 -0400 |
commit | 5f39d397dfbe140a14edecd4e73c34ce23c4f9ee (patch) | |
tree | 280561e4b68d573590557dd27df656869eed8023 /fs/btrfs/disk-io.c | |
parent | 50b78c24d594e6985f36a9a8d8e2fb74e1664e90 (diff) |
Btrfs: Create extent_buffer interface for large blocksizes
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r-- | fs/btrfs/disk-io.c | 391 |
1 files changed, 180 insertions, 211 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index ef6d76f2ec20..0c1f90cbedb0 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -23,138 +23,132 @@ | |||
23 | #include <linux/swap.h> | 23 | #include <linux/swap.h> |
24 | #include <linux/radix-tree.h> | 24 | #include <linux/radix-tree.h> |
25 | #include <linux/writeback.h> | 25 | #include <linux/writeback.h> |
26 | #include <linux/buffer_head.h> // for block_sync_page | ||
26 | #include "ctree.h" | 27 | #include "ctree.h" |
27 | #include "disk-io.h" | 28 | #include "disk-io.h" |
28 | #include "transaction.h" | 29 | #include "transaction.h" |
29 | #include "btrfs_inode.h" | 30 | #include "btrfs_inode.h" |
30 | 31 | ||
31 | u64 bh_blocknr(struct buffer_head *bh) | 32 | #if 0 |
33 | static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf) | ||
32 | { | 34 | { |
33 | return bh->b_blocknr; | 35 | if (extent_buffer_blocknr(buf) != btrfs_header_blocknr(buf)) { |
34 | } | 36 | printk(KERN_CRIT "buf blocknr(buf) is %llu, header is %llu\n", |
35 | 37 | (unsigned long long)extent_buffer_blocknr(buf), | |
36 | static int check_tree_block(struct btrfs_root *root, struct buffer_head *buf) | 38 | (unsigned long long)btrfs_header_blocknr(buf)); |
37 | { | ||
38 | struct btrfs_node *node = btrfs_buffer_node(buf); | ||
39 | if (bh_blocknr(buf) != btrfs_header_blocknr(&node->header)) { | ||
40 | printk(KERN_CRIT "bh_blocknr(buf) is %llu, header is %llu\n", | ||
41 | (unsigned long long)bh_blocknr(buf), | ||
42 | (unsigned long long)btrfs_header_blocknr(&node->header)); | ||
43 | return 1; | 39 | return 1; |
44 | } | 40 | } |
45 | return 0; | 41 | return 0; |
46 | } | 42 | } |
43 | #endif | ||
47 | 44 | ||
48 | struct buffer_head *btrfs_find_tree_block(struct btrfs_root *root, u64 blocknr) | 45 | struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root, |
46 | u64 blocknr) | ||
49 | { | 47 | { |
50 | struct address_space *mapping = root->fs_info->btree_inode->i_mapping; | 48 | struct inode *btree_inode = root->fs_info->btree_inode; |
51 | int blockbits = root->fs_info->sb->s_blocksize_bits; | 49 | return find_extent_buffer(&BTRFS_I(btree_inode)->extent_tree, |
52 | unsigned long index = blocknr >> (PAGE_CACHE_SHIFT - blockbits); | 50 | blocknr * root->sectorsize, |
53 | struct page *page; | 51 | root->sectorsize, GFP_NOFS); |
54 | struct buffer_head *bh; | 52 | } |
55 | struct buffer_head *head; | ||
56 | struct buffer_head *ret = NULL; | ||
57 | |||
58 | |||
59 | page = find_lock_page(mapping, index); | ||
60 | if (!page) | ||
61 | return NULL; | ||
62 | |||
63 | if (!page_has_buffers(page)) | ||
64 | goto out_unlock; | ||
65 | 53 | ||
66 | head = page_buffers(page); | 54 | struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, |
67 | bh = head; | 55 | u64 blocknr) |
68 | do { | 56 | { |
69 | if (buffer_mapped(bh) && bh_blocknr(bh) == blocknr) { | 57 | struct inode *btree_inode = root->fs_info->btree_inode; |
70 | ret = bh; | 58 | return alloc_extent_buffer(&BTRFS_I(btree_inode)->extent_tree, |
71 | get_bh(bh); | 59 | blocknr * root->sectorsize, |
72 | goto out_unlock; | 60 | root->sectorsize, GFP_NOFS); |
73 | } | ||
74 | bh = bh->b_this_page; | ||
75 | } while (bh != head); | ||
76 | out_unlock: | ||
77 | unlock_page(page); | ||
78 | page_cache_release(page); | ||
79 | return ret; | ||
80 | } | 61 | } |
81 | 62 | ||
82 | int btrfs_map_bh_to_logical(struct btrfs_root *root, struct buffer_head *bh, | 63 | struct extent_map *btree_get_extent(struct inode *inode, struct page *page, |
83 | u64 logical) | 64 | size_t page_offset, u64 start, u64 end, |
65 | int create) | ||
84 | { | 66 | { |
85 | if (logical == 0) { | 67 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; |
86 | bh->b_bdev = NULL; | 68 | struct extent_map *em; |
87 | bh->b_blocknr = 0; | 69 | int ret; |
88 | set_buffer_mapped(bh); | 70 | |
89 | } else { | 71 | again: |
90 | map_bh(bh, root->fs_info->sb, logical); | 72 | em = lookup_extent_mapping(em_tree, start, end); |
73 | if (em) { | ||
74 | goto out; | ||
91 | } | 75 | } |
92 | return 0; | 76 | em = alloc_extent_map(GFP_NOFS); |
77 | if (!em) { | ||
78 | em = ERR_PTR(-ENOMEM); | ||
79 | goto out; | ||
80 | } | ||
81 | em->start = 0; | ||
82 | em->end = (i_size_read(inode) & ~((u64)PAGE_CACHE_SIZE -1)) - 1; | ||
83 | em->block_start = 0; | ||
84 | em->block_end = em->end; | ||
85 | em->bdev = inode->i_sb->s_bdev; | ||
86 | ret = add_extent_mapping(em_tree, em); | ||
87 | if (ret == -EEXIST) { | ||
88 | free_extent_map(em); | ||
89 | em = NULL; | ||
90 | goto again; | ||
91 | } else if (ret) { | ||
92 | em = ERR_PTR(ret); | ||
93 | } | ||
94 | out: | ||
95 | return em; | ||
93 | } | 96 | } |
94 | 97 | ||
95 | struct buffer_head *btrfs_find_create_tree_block(struct btrfs_root *root, | 98 | static int btree_writepage(struct page *page, struct writeback_control *wbc) |
96 | u64 blocknr) | ||
97 | { | 99 | { |
98 | struct address_space *mapping = root->fs_info->btree_inode->i_mapping; | 100 | struct extent_map_tree *tree; |
99 | int blockbits = root->fs_info->sb->s_blocksize_bits; | 101 | tree = &BTRFS_I(page->mapping->host)->extent_tree; |
100 | unsigned long index = blocknr >> (PAGE_CACHE_SHIFT - blockbits); | 102 | return extent_write_full_page(tree, page, btree_get_extent, wbc); |
101 | struct page *page; | 103 | } |
102 | struct buffer_head *bh; | 104 | int btree_readpage(struct file *file, struct page *page) |
103 | struct buffer_head *head; | 105 | { |
104 | struct buffer_head *ret = NULL; | 106 | struct extent_map_tree *tree; |
105 | int err; | 107 | tree = &BTRFS_I(page->mapping->host)->extent_tree; |
106 | u64 first_block = index << (PAGE_CACHE_SHIFT - blockbits); | 108 | return extent_read_full_page(tree, page, btree_get_extent); |
109 | } | ||
107 | 110 | ||
108 | page = find_or_create_page(mapping, index, GFP_NOFS); | 111 | static int btree_releasepage(struct page *page, gfp_t unused_gfp_flags) |
109 | if (!page) | 112 | { |
110 | return NULL; | 113 | struct extent_map_tree *tree; |
114 | int ret; | ||
111 | 115 | ||
112 | if (!page_has_buffers(page)) | 116 | BUG_ON(page->private != 1); |
113 | create_empty_buffers(page, root->fs_info->sb->s_blocksize, 0); | 117 | tree = &BTRFS_I(page->mapping->host)->extent_tree; |
114 | head = page_buffers(page); | 118 | ret = try_release_extent_mapping(tree, page); |
115 | bh = head; | 119 | if (ret == 1) { |
116 | do { | 120 | ClearPagePrivate(page); |
117 | if (!buffer_mapped(bh)) { | 121 | set_page_private(page, 0); |
118 | err = btrfs_map_bh_to_logical(root, bh, first_block); | 122 | page_cache_release(page); |
119 | BUG_ON(err); | 123 | } |
120 | } | ||
121 | if (bh_blocknr(bh) == blocknr) { | ||
122 | ret = bh; | ||
123 | get_bh(bh); | ||
124 | goto out_unlock; | ||
125 | } | ||
126 | bh = bh->b_this_page; | ||
127 | first_block++; | ||
128 | } while (bh != head); | ||
129 | out_unlock: | ||
130 | unlock_page(page); | ||
131 | if (ret) | ||
132 | touch_buffer(ret); | ||
133 | page_cache_release(page); | ||
134 | return ret; | 124 | return ret; |
135 | } | 125 | } |
136 | 126 | ||
137 | static int btree_get_block(struct inode *inode, sector_t iblock, | 127 | static void btree_invalidatepage(struct page *page, unsigned long offset) |
138 | struct buffer_head *bh, int create) | ||
139 | { | 128 | { |
140 | int err; | 129 | struct extent_map_tree *tree; |
141 | struct btrfs_root *root = BTRFS_I(bh->b_page->mapping->host)->root; | 130 | tree = &BTRFS_I(page->mapping->host)->extent_tree; |
142 | err = btrfs_map_bh_to_logical(root, bh, iblock); | 131 | extent_invalidatepage(tree, page, offset); |
143 | return err; | 132 | btree_releasepage(page, GFP_NOFS); |
144 | } | 133 | } |
145 | 134 | ||
146 | int btrfs_csum_data(struct btrfs_root * root, char *data, size_t len, | 135 | int btrfs_csum_data(struct btrfs_root * root, char *data, size_t len, |
147 | char *result) | 136 | char *result) |
148 | { | 137 | { |
138 | return 0; | ||
139 | #if 0 | ||
149 | u32 crc; | 140 | u32 crc; |
150 | crc = crc32c(0, data, len); | 141 | crc = crc32c(0, data, len); |
151 | memcpy(result, &crc, BTRFS_CRC32_SIZE); | 142 | memcpy(result, &crc, BTRFS_CRC32_SIZE); |
152 | return 0; | 143 | return 0; |
144 | #endif | ||
153 | } | 145 | } |
154 | 146 | ||
155 | static int csum_tree_block(struct btrfs_root *root, struct buffer_head *bh, | 147 | #if 0 |
148 | static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, | ||
156 | int verify) | 149 | int verify) |
157 | { | 150 | { |
151 | return 0; | ||
158 | char result[BTRFS_CRC32_SIZE]; | 152 | char result[BTRFS_CRC32_SIZE]; |
159 | int ret; | 153 | int ret; |
160 | struct btrfs_node *node; | 154 | struct btrfs_node *node; |
@@ -176,7 +170,9 @@ static int csum_tree_block(struct btrfs_root *root, struct buffer_head *bh, | |||
176 | } | 170 | } |
177 | return 0; | 171 | return 0; |
178 | } | 172 | } |
173 | #endif | ||
179 | 174 | ||
175 | #if 0 | ||
180 | static int btree_writepage(struct page *page, struct writeback_control *wbc) | 176 | static int btree_writepage(struct page *page, struct writeback_control *wbc) |
181 | { | 177 | { |
182 | struct buffer_head *bh; | 178 | struct buffer_head *bh; |
@@ -195,87 +191,65 @@ static int btree_writepage(struct page *page, struct writeback_control *wbc) | |||
195 | } while (bh != head); | 191 | } while (bh != head); |
196 | return block_write_full_page(page, btree_get_block, wbc); | 192 | return block_write_full_page(page, btree_get_block, wbc); |
197 | } | 193 | } |
198 | 194 | #endif | |
199 | static int btree_readpage(struct file * file, struct page * page) | ||
200 | { | ||
201 | return block_read_full_page(page, btree_get_block); | ||
202 | } | ||
203 | 195 | ||
204 | static struct address_space_operations btree_aops = { | 196 | static struct address_space_operations btree_aops = { |
205 | .readpage = btree_readpage, | 197 | .readpage = btree_readpage, |
206 | .writepage = btree_writepage, | 198 | .writepage = btree_writepage, |
199 | .releasepage = btree_releasepage, | ||
200 | .invalidatepage = btree_invalidatepage, | ||
207 | .sync_page = block_sync_page, | 201 | .sync_page = block_sync_page, |
208 | }; | 202 | }; |
209 | 203 | ||
210 | int readahead_tree_block(struct btrfs_root *root, u64 blocknr) | 204 | int readahead_tree_block(struct btrfs_root *root, u64 blocknr) |
211 | { | 205 | { |
212 | struct buffer_head *bh = NULL; | 206 | struct extent_buffer *buf = NULL; |
207 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
213 | int ret = 0; | 208 | int ret = 0; |
214 | 209 | ||
215 | bh = btrfs_find_create_tree_block(root, blocknr); | 210 | buf = btrfs_find_create_tree_block(root, blocknr); |
216 | if (!bh) | 211 | if (!buf) |
217 | return 0; | 212 | return 0; |
218 | if (buffer_uptodate(bh)) { | 213 | read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree, |
219 | ret = 1; | 214 | buf, 0); |
220 | goto done; | 215 | free_extent_buffer(buf); |
221 | } | ||
222 | if (test_set_buffer_locked(bh)) { | ||
223 | ret = 1; | ||
224 | goto done; | ||
225 | } | ||
226 | if (!buffer_uptodate(bh)) { | ||
227 | get_bh(bh); | ||
228 | bh->b_end_io = end_buffer_read_sync; | ||
229 | submit_bh(READ, bh); | ||
230 | } else { | ||
231 | unlock_buffer(bh); | ||
232 | ret = 1; | ||
233 | } | ||
234 | done: | ||
235 | brelse(bh); | ||
236 | return ret; | 216 | return ret; |
237 | } | 217 | } |
238 | 218 | ||
239 | struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr) | 219 | struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 blocknr) |
240 | { | 220 | { |
241 | struct buffer_head *bh = NULL; | 221 | struct extent_buffer *buf = NULL; |
242 | 222 | struct inode *btree_inode = root->fs_info->btree_inode; | |
243 | bh = btrfs_find_create_tree_block(root, blocknr); | 223 | |
244 | if (!bh) | 224 | buf = btrfs_find_create_tree_block(root, blocknr); |
245 | return bh; | 225 | if (!buf) |
246 | if (buffer_uptodate(bh)) | 226 | return NULL; |
247 | goto uptodate; | 227 | read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree, |
248 | lock_buffer(bh); | 228 | buf, 1); |
249 | if (!buffer_uptodate(bh)) { | 229 | return buf; |
250 | get_bh(bh); | ||
251 | bh->b_end_io = end_buffer_read_sync; | ||
252 | submit_bh(READ, bh); | ||
253 | wait_on_buffer(bh); | ||
254 | if (!buffer_uptodate(bh)) | ||
255 | goto fail; | ||
256 | } else { | ||
257 | unlock_buffer(bh); | ||
258 | } | ||
259 | uptodate: | ||
260 | if (!buffer_checked(bh)) { | ||
261 | csum_tree_block(root, bh, 1); | ||
262 | set_buffer_checked(bh); | ||
263 | } | ||
264 | if (check_tree_block(root, bh)) | ||
265 | goto fail; | ||
266 | return bh; | ||
267 | fail: | ||
268 | brelse(bh); | ||
269 | return NULL; | ||
270 | } | 230 | } |
271 | 231 | ||
272 | int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, | 232 | int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, |
273 | struct buffer_head *buf) | 233 | struct extent_buffer *buf) |
274 | { | 234 | { |
275 | WARN_ON(atomic_read(&buf->b_count) == 0); | 235 | struct inode *btree_inode = root->fs_info->btree_inode; |
276 | lock_buffer(buf); | 236 | clear_extent_buffer_dirty(&BTRFS_I(btree_inode)->extent_tree, buf); |
277 | clear_buffer_dirty(buf); | 237 | return 0; |
278 | unlock_buffer(buf); | 238 | } |
239 | |||
240 | int wait_on_tree_block_writeback(struct btrfs_root *root, | ||
241 | struct extent_buffer *buf) | ||
242 | { | ||
243 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
244 | wait_on_extent_buffer_writeback(&BTRFS_I(btree_inode)->extent_tree, | ||
245 | buf); | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | int set_tree_block_dirty(struct btrfs_root *root, struct extent_buffer *buf) | ||
250 | { | ||
251 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
252 | set_extent_buffer_dirty(&BTRFS_I(btree_inode)->extent_tree, buf); | ||
279 | return 0; | 253 | return 0; |
280 | } | 254 | } |
281 | 255 | ||
@@ -287,7 +261,9 @@ static int __setup_root(int blocksize, | |||
287 | root->node = NULL; | 261 | root->node = NULL; |
288 | root->inode = NULL; | 262 | root->inode = NULL; |
289 | root->commit_root = NULL; | 263 | root->commit_root = NULL; |
290 | root->blocksize = blocksize; | 264 | root->sectorsize = blocksize; |
265 | root->nodesize = blocksize; | ||
266 | root->leafsize = blocksize; | ||
291 | root->ref_cows = 0; | 267 | root->ref_cows = 0; |
292 | root->fs_info = fs_info; | 268 | root->fs_info = fs_info; |
293 | root->objectid = objectid; | 269 | root->objectid = objectid; |
@@ -332,7 +308,7 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info, | |||
332 | struct btrfs_root *root; | 308 | struct btrfs_root *root; |
333 | struct btrfs_root *tree_root = fs_info->tree_root; | 309 | struct btrfs_root *tree_root = fs_info->tree_root; |
334 | struct btrfs_path *path; | 310 | struct btrfs_path *path; |
335 | struct btrfs_leaf *l; | 311 | struct extent_buffer *l; |
336 | u64 highest_inode; | 312 | u64 highest_inode; |
337 | int ret = 0; | 313 | int ret = 0; |
338 | 314 | ||
@@ -361,11 +337,10 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info, | |||
361 | ret = -ENOENT; | 337 | ret = -ENOENT; |
362 | goto out; | 338 | goto out; |
363 | } | 339 | } |
364 | l = btrfs_buffer_leaf(path->nodes[0]); | 340 | l = path->nodes[0]; |
365 | memcpy(&root->root_item, | 341 | read_extent_buffer(l, &root->root_item, |
366 | btrfs_item_ptr(l, path->slots[0], struct btrfs_root_item), | 342 | btrfs_item_ptr_offset(l, path->slots[0]), |
367 | sizeof(root->root_item)); | 343 | sizeof(root->root_item)); |
368 | memcpy(&root->root_key, location, sizeof(*location)); | ||
369 | ret = 0; | 344 | ret = 0; |
370 | out: | 345 | out: |
371 | btrfs_release_path(root, path); | 346 | btrfs_release_path(root, path); |
@@ -406,21 +381,21 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, | |||
406 | (unsigned long)root->root_key.objectid, | 381 | (unsigned long)root->root_key.objectid, |
407 | root); | 382 | root); |
408 | if (ret) { | 383 | if (ret) { |
409 | brelse(root->node); | 384 | free_extent_buffer(root->node); |
410 | kfree(root); | 385 | kfree(root); |
411 | return ERR_PTR(ret); | 386 | return ERR_PTR(ret); |
412 | } | 387 | } |
413 | 388 | ||
414 | ret = btrfs_set_root_name(root, name, namelen); | 389 | ret = btrfs_set_root_name(root, name, namelen); |
415 | if (ret) { | 390 | if (ret) { |
416 | brelse(root->node); | 391 | free_extent_buffer(root->node); |
417 | kfree(root); | 392 | kfree(root); |
418 | return ERR_PTR(ret); | 393 | return ERR_PTR(ret); |
419 | } | 394 | } |
420 | 395 | ||
421 | ret = btrfs_sysfs_add_root(root); | 396 | ret = btrfs_sysfs_add_root(root); |
422 | if (ret) { | 397 | if (ret) { |
423 | brelse(root->node); | 398 | free_extent_buffer(root->node); |
424 | kfree(root->name); | 399 | kfree(root->name); |
425 | kfree(root); | 400 | kfree(root); |
426 | return ERR_PTR(ret); | 401 | return ERR_PTR(ret); |
@@ -471,6 +446,9 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
471 | fs_info->btree_inode->i_nlink = 1; | 446 | fs_info->btree_inode->i_nlink = 1; |
472 | fs_info->btree_inode->i_size = sb->s_bdev->bd_inode->i_size; | 447 | fs_info->btree_inode->i_size = sb->s_bdev->bd_inode->i_size; |
473 | fs_info->btree_inode->i_mapping->a_ops = &btree_aops; | 448 | fs_info->btree_inode->i_mapping->a_ops = &btree_aops; |
449 | extent_map_tree_init(&BTRFS_I(fs_info->btree_inode)->extent_tree, | ||
450 | fs_info->btree_inode->i_mapping, | ||
451 | GFP_NOFS); | ||
474 | fs_info->do_barriers = 1; | 452 | fs_info->do_barriers = 1; |
475 | fs_info->closing = 0; | 453 | fs_info->closing = 0; |
476 | 454 | ||
@@ -493,10 +471,14 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
493 | 471 | ||
494 | if (!fs_info->sb_buffer) | 472 | if (!fs_info->sb_buffer) |
495 | goto fail_iput; | 473 | goto fail_iput; |
496 | disk_super = (struct btrfs_super_block *)fs_info->sb_buffer->b_data; | ||
497 | fs_info->disk_super = disk_super; | ||
498 | memcpy(&fs_info->super_copy, disk_super, sizeof(fs_info->super_copy)); | ||
499 | 474 | ||
475 | read_extent_buffer(fs_info->sb_buffer, &fs_info->super_copy, 0, | ||
476 | sizeof(fs_info->super_copy)); | ||
477 | |||
478 | read_extent_buffer(fs_info->sb_buffer, fs_info->fsid, | ||
479 | (unsigned long)btrfs_super_fsid(fs_info->sb_buffer), | ||
480 | BTRFS_FSID_SIZE); | ||
481 | disk_super = &fs_info->super_copy; | ||
500 | if (!btrfs_super_root(disk_super)) | 482 | if (!btrfs_super_root(disk_super)) |
501 | goto fail_sb_buffer; | 483 | goto fail_sb_buffer; |
502 | 484 | ||
@@ -530,9 +512,9 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
530 | return tree_root; | 512 | return tree_root; |
531 | 513 | ||
532 | fail_tree_root: | 514 | fail_tree_root: |
533 | btrfs_block_release(tree_root, tree_root->node); | 515 | free_extent_buffer(tree_root->node); |
534 | fail_sb_buffer: | 516 | fail_sb_buffer: |
535 | btrfs_block_release(tree_root, fs_info->sb_buffer); | 517 | free_extent_buffer(fs_info->sb_buffer); |
536 | fail_iput: | 518 | fail_iput: |
537 | iput(fs_info->btree_inode); | 519 | iput(fs_info->btree_inode); |
538 | fail: | 520 | fail: |
@@ -546,31 +528,13 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root | |||
546 | *root) | 528 | *root) |
547 | { | 529 | { |
548 | int ret; | 530 | int ret; |
549 | struct buffer_head *bh = root->fs_info->sb_buffer; | 531 | struct extent_buffer *super = root->fs_info->sb_buffer; |
550 | 532 | struct inode *btree_inode = root->fs_info->btree_inode; | |
551 | lock_buffer(bh); | 533 | |
552 | WARN_ON(atomic_read(&bh->b_count) < 1); | 534 | set_extent_buffer_dirty(&BTRFS_I(btree_inode)->extent_tree, super); |
553 | clear_buffer_dirty(bh); | 535 | ret = sync_page_range_nolock(btree_inode, btree_inode->i_mapping, |
554 | csum_tree_block(root, bh, 0); | 536 | super->start, super->len); |
555 | bh->b_end_io = end_buffer_write_sync; | 537 | return ret; |
556 | get_bh(bh); | ||
557 | if (root->fs_info->do_barriers) | ||
558 | ret = submit_bh(WRITE_BARRIER, bh); | ||
559 | else | ||
560 | ret = submit_bh(WRITE, bh); | ||
561 | if (ret == -EOPNOTSUPP) { | ||
562 | get_bh(bh); | ||
563 | lock_buffer(bh); | ||
564 | set_buffer_uptodate(bh); | ||
565 | root->fs_info->do_barriers = 0; | ||
566 | ret = submit_bh(WRITE, bh); | ||
567 | } | ||
568 | wait_on_buffer(bh); | ||
569 | if (!buffer_uptodate(bh)) { | ||
570 | WARN_ON(1); | ||
571 | return -EIO; | ||
572 | } | ||
573 | return 0; | ||
574 | } | 538 | } |
575 | 539 | ||
576 | int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) | 540 | int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) |
@@ -581,9 +545,9 @@ int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) | |||
581 | if (root->inode) | 545 | if (root->inode) |
582 | iput(root->inode); | 546 | iput(root->inode); |
583 | if (root->node) | 547 | if (root->node) |
584 | brelse(root->node); | 548 | free_extent_buffer(root->node); |
585 | if (root->commit_root) | 549 | if (root->commit_root) |
586 | brelse(root->commit_root); | 550 | free_extent_buffer(root->commit_root); |
587 | if (root->name) | 551 | if (root->name) |
588 | kfree(root->name); | 552 | kfree(root->name); |
589 | kfree(root); | 553 | kfree(root); |
@@ -629,12 +593,10 @@ int close_ctree(struct btrfs_root *root) | |||
629 | mutex_unlock(&fs_info->fs_mutex); | 593 | mutex_unlock(&fs_info->fs_mutex); |
630 | 594 | ||
631 | if (fs_info->extent_root->node) | 595 | if (fs_info->extent_root->node) |
632 | btrfs_block_release(fs_info->extent_root, | 596 | free_extent_buffer(fs_info->extent_root->node); |
633 | fs_info->extent_root->node); | ||
634 | if (fs_info->tree_root->node) | 597 | if (fs_info->tree_root->node) |
635 | btrfs_block_release(fs_info->tree_root, | 598 | free_extent_buffer(fs_info->tree_root->node); |
636 | fs_info->tree_root->node); | 599 | free_extent_buffer(fs_info->sb_buffer); |
637 | btrfs_block_release(root, fs_info->sb_buffer); | ||
638 | truncate_inode_pages(fs_info->btree_inode->i_mapping, 0); | 600 | truncate_inode_pages(fs_info->btree_inode->i_mapping, 0); |
639 | iput(fs_info->btree_inode); | 601 | iput(fs_info->btree_inode); |
640 | 602 | ||
@@ -645,25 +607,32 @@ int close_ctree(struct btrfs_root *root) | |||
645 | return 0; | 607 | return 0; |
646 | } | 608 | } |
647 | 609 | ||
648 | void btrfs_mark_buffer_dirty(struct buffer_head *bh) | 610 | int btrfs_buffer_uptodate(struct extent_buffer *buf) |
611 | { | ||
612 | struct inode *btree_inode = buf->pages[0]->mapping->host; | ||
613 | return extent_buffer_uptodate(&BTRFS_I(btree_inode)->extent_tree, buf); | ||
614 | } | ||
615 | |||
616 | int btrfs_set_buffer_uptodate(struct extent_buffer *buf) | ||
649 | { | 617 | { |
650 | struct btrfs_root *root = BTRFS_I(bh->b_page->mapping->host)->root; | 618 | struct inode *btree_inode = buf->pages[0]->mapping->host; |
651 | u64 transid = btrfs_header_generation(btrfs_buffer_header(bh)); | 619 | return set_extent_buffer_uptodate(&BTRFS_I(btree_inode)->extent_tree, |
620 | buf); | ||
621 | } | ||
652 | 622 | ||
653 | WARN_ON(!atomic_read(&bh->b_count)); | 623 | void btrfs_mark_buffer_dirty(struct extent_buffer *buf) |
624 | { | ||
625 | struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root; | ||
626 | u64 transid = btrfs_header_generation(buf); | ||
627 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
654 | 628 | ||
655 | if (transid != root->fs_info->generation) { | 629 | if (transid != root->fs_info->generation) { |
656 | printk(KERN_CRIT "transid mismatch buffer %llu, found %Lu running %Lu\n", | 630 | printk(KERN_CRIT "transid mismatch buffer %llu, found %Lu running %Lu\n", |
657 | (unsigned long long)bh->b_blocknr, | 631 | (unsigned long long)extent_buffer_blocknr(buf), |
658 | transid, root->fs_info->generation); | 632 | transid, root->fs_info->generation); |
659 | WARN_ON(1); | 633 | WARN_ON(1); |
660 | } | 634 | } |
661 | mark_buffer_dirty(bh); | 635 | set_extent_buffer_dirty(&BTRFS_I(btree_inode)->extent_tree, buf); |
662 | } | ||
663 | |||
664 | void btrfs_block_release(struct btrfs_root *root, struct buffer_head *buf) | ||
665 | { | ||
666 | brelse(buf); | ||
667 | } | 636 | } |
668 | 637 | ||
669 | void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr) | 638 | void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr) |