aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/disk-io.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-03-28 13:57:48 -0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-03-28 13:57:48 -0400
commitd98237b3ede7ab98892f7fa62201a13694c526e2 (patch)
treecdf99f2d1e9bc088027cd98e5ed0e4efc79698e3 /fs/btrfs/disk-io.c
parent5f443fd280c76a2170259cebaa4108c9daad6e1b (diff)
Btrfs: use a btree inode instead of sb_getblk
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r--fs/btrfs/disk-io.c174
1 files changed, 161 insertions, 13 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 758a62aba063..970103f2cacd 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1,14 +1,17 @@
1#include <linux/module.h> 1#include <linux/module.h>
2#include <linux/fs.h> 2#include <linux/fs.h>
3#include <linux/blkdev.h>
3#include "ctree.h" 4#include "ctree.h"
4#include "disk-io.h" 5#include "disk-io.h"
5#include "transaction.h" 6#include "transaction.h"
6 7
8
7static int check_tree_block(struct btrfs_root *root, struct buffer_head *buf) 9static int check_tree_block(struct btrfs_root *root, struct buffer_head *buf)
8{ 10{
9 struct btrfs_node *node = btrfs_buffer_node(buf); 11 struct btrfs_node *node = btrfs_buffer_node(buf);
10 if (buf->b_blocknr != btrfs_header_blocknr(&node->header)) 12 if (buf->b_blocknr != btrfs_header_blocknr(&node->header)) {
11 BUG(); 13 BUG();
14 }
12 if (root->node && btrfs_header_parentid(&node->header) != 15 if (root->node && btrfs_header_parentid(&node->header) !=
13 btrfs_header_parentid(btrfs_buffer_header(root->node))) { 16 btrfs_header_parentid(btrfs_buffer_header(root->node))) {
14 BUG(); 17 BUG();
@@ -16,25 +19,154 @@ static int check_tree_block(struct btrfs_root *root, struct buffer_head *buf)
16 return 0; 19 return 0;
17} 20}
18 21
19struct buffer_head *alloc_tree_block(struct btrfs_root *root, u64 blocknr) 22struct buffer_head *btrfs_find_tree_block(struct btrfs_root *root, u64 blocknr)
23{
24 struct address_space *mapping = root->fs_info->btree_inode->i_mapping;
25 int blockbits = root->fs_info->sb->s_blocksize_bits;
26 unsigned long index = blocknr >> (PAGE_CACHE_SHIFT - blockbits);
27 struct page *page;
28 struct buffer_head *bh;
29 struct buffer_head *head;
30 struct buffer_head *ret = NULL;
31
32 page = find_lock_page(mapping, index);
33 if (!page)
34 return NULL;
35
36 if (!page_has_buffers(page))
37 goto out_unlock;
38
39 head = page_buffers(page);
40 bh = head;
41 do {
42 if (buffer_mapped(bh) && bh->b_blocknr == blocknr) {
43 ret = bh;
44 get_bh(bh);
45 goto out_unlock;
46 }
47 bh = bh->b_this_page;
48 } while (bh != head);
49out_unlock:
50 unlock_page(page);
51 page_cache_release(page);
52 return ret;
53}
54
55struct buffer_head *btrfs_find_create_tree_block(struct btrfs_root *root,
56 u64 blocknr)
57{
58 struct address_space *mapping = root->fs_info->btree_inode->i_mapping;
59 int blockbits = root->fs_info->sb->s_blocksize_bits;
60 unsigned long index = blocknr >> (PAGE_CACHE_SHIFT - blockbits);
61 struct page *page;
62 struct buffer_head *bh;
63 struct buffer_head *head;
64 struct buffer_head *ret = NULL;
65 u64 first_block = index << (PAGE_CACHE_SHIFT - blockbits);
66 page = grab_cache_page(mapping, index);
67 if (!page)
68 return NULL;
69
70 wait_on_page_writeback(page);
71 if (!page_has_buffers(page))
72 create_empty_buffers(page, root->fs_info->sb->s_blocksize, 0);
73 head = page_buffers(page);
74 bh = head;
75 do {
76 if (!buffer_mapped(bh)) {
77 bh->b_bdev = root->fs_info->sb->s_bdev;
78 bh->b_blocknr = first_block;
79 set_buffer_mapped(bh);
80 }
81 if (bh->b_blocknr == blocknr) {
82 ret = bh;
83 get_bh(bh);
84 goto out_unlock;
85 }
86 bh = bh->b_this_page;
87 first_block++;
88 } while (bh != head);
89out_unlock:
90 unlock_page(page);
91 page_cache_release(page);
92 return ret;
93}
94
95static sector_t max_block(struct block_device *bdev)
96{
97 sector_t retval = ~((sector_t)0);
98 loff_t sz = i_size_read(bdev->bd_inode);
99
100 if (sz) {
101 unsigned int size = block_size(bdev);
102 unsigned int sizebits = blksize_bits(size);
103 retval = (sz >> sizebits);
104 }
105 return retval;
106}
107
108static int btree_get_block(struct inode *inode, sector_t iblock,
109 struct buffer_head *bh, int create)
110{
111 if (iblock >= max_block(inode->i_sb->s_bdev)) {
112 if (create)
113 return -EIO;
114
115 /*
116 * for reads, we're just trying to fill a partial page.
117 * return a hole, they will have to call get_block again
118 * before they can fill it, and they will get -EIO at that
119 * time
120 */
121 return 0;
122 }
123 bh->b_bdev = inode->i_sb->s_bdev;
124 bh->b_blocknr = iblock;
125 set_buffer_mapped(bh);
126 return 0;
127}
128
129static int btree_writepage(struct page *page, struct writeback_control *wbc)
20{ 130{
21 return sb_getblk(root->fs_info->sb, blocknr); 131 return block_write_full_page(page, btree_get_block, wbc);
22} 132}
23 133
24struct buffer_head *find_tree_block(struct btrfs_root *root, u64 blocknr) 134static int btree_readpage(struct file * file, struct page * page)
25{ 135{
26 return sb_getblk(root->fs_info->sb, blocknr); 136 return block_read_full_page(page, btree_get_block);
27} 137}
28 138
139static struct address_space_operations btree_aops = {
140 .readpage = btree_readpage,
141 .writepage = btree_writepage,
142 .sync_page = block_sync_page,
143};
144
29struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr) 145struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr)
30{ 146{
31 struct buffer_head *buf = sb_bread(root->fs_info->sb, blocknr); 147 struct buffer_head *bh = NULL;
32 148
33 if (!buf) 149 bh = btrfs_find_create_tree_block(root, blocknr);
34 return buf; 150 if (!bh)
35 if (check_tree_block(root, buf)) 151 return bh;
152 lock_buffer(bh);
153 if (!buffer_uptodate(bh)) {
154 get_bh(bh);
155 bh->b_end_io = end_buffer_read_sync;
156 submit_bh(READ, bh);
157 wait_on_buffer(bh);
158 if (!buffer_uptodate(bh))
159 goto fail;
160 } else {
161 unlock_buffer(bh);
162 }
163 if (check_tree_block(root, bh))
36 BUG(); 164 BUG();
37 return buf; 165 return bh;
166fail:
167 brelse(bh);
168 return NULL;
169
38} 170}
39 171
40int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, 172int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
@@ -101,11 +233,11 @@ struct btrfs_root *open_ctree(struct super_block *sb,
101 GFP_NOFS); 233 GFP_NOFS);
102 int ret; 234 int ret;
103 235
104 /* FIXME: don't be stupid */
105 if (!btrfs_super_root(disk_super)) 236 if (!btrfs_super_root(disk_super))
106 return NULL; 237 return NULL;
107 init_bit_radix(&fs_info->pinned_radix); 238 init_bit_radix(&fs_info->pinned_radix);
108 init_bit_radix(&fs_info->pending_del_radix); 239 init_bit_radix(&fs_info->pending_del_radix);
240 sb_set_blocksize(sb, sb_buffer->b_size);
109 fs_info->running_transaction = NULL; 241 fs_info->running_transaction = NULL;
110 fs_info->fs_root = root; 242 fs_info->fs_root = root;
111 fs_info->tree_root = tree_root; 243 fs_info->tree_root = tree_root;
@@ -114,14 +246,30 @@ struct btrfs_root *open_ctree(struct super_block *sb,
114 fs_info->last_inode_alloc = 0; 246 fs_info->last_inode_alloc = 0;
115 fs_info->last_inode_alloc_dirid = 0; 247 fs_info->last_inode_alloc_dirid = 0;
116 fs_info->disk_super = disk_super; 248 fs_info->disk_super = disk_super;
117 fs_info->sb_buffer = sb_buffer;
118 fs_info->sb = sb; 249 fs_info->sb = sb;
250 fs_info->btree_inode = new_inode(sb);
251 fs_info->btree_inode->i_ino = 1;
252 fs_info->btree_inode->i_size = sb->s_bdev->bd_inode->i_size;
253 fs_info->btree_inode->i_mapping->a_ops = &btree_aops;
254 mapping_set_gfp_mask(fs_info->btree_inode->i_mapping, GFP_NOFS);
255
119 mutex_init(&fs_info->trans_mutex); 256 mutex_init(&fs_info->trans_mutex);
120 mutex_init(&fs_info->fs_mutex); 257 mutex_init(&fs_info->fs_mutex);
121 memset(&fs_info->current_insert, 0, sizeof(fs_info->current_insert)); 258 memset(&fs_info->current_insert, 0, sizeof(fs_info->current_insert));
122 memset(&fs_info->last_insert, 0, sizeof(fs_info->last_insert)); 259 memset(&fs_info->last_insert, 0, sizeof(fs_info->last_insert));
123 260
124 __setup_root(disk_super, tree_root, fs_info, BTRFS_ROOT_TREE_OBJECTID); 261 __setup_root(disk_super, tree_root, fs_info, BTRFS_ROOT_TREE_OBJECTID);
262
263 fs_info->sb_buffer = read_tree_block(tree_root, sb_buffer->b_blocknr);
264
265 if (!fs_info->sb_buffer)
266 return NULL;
267
268 brelse(sb_buffer);
269 sb_buffer = NULL;
270 disk_super = (struct btrfs_super_block *)fs_info->sb_buffer->b_data;
271 fs_info->disk_super = disk_super;
272
125 tree_root->node = read_tree_block(tree_root, 273 tree_root->node = read_tree_block(tree_root,
126 btrfs_super_root(disk_super)); 274 btrfs_super_root(disk_super));
127 BUG_ON(!tree_root->node); 275 BUG_ON(!tree_root->node);
@@ -137,7 +285,6 @@ struct btrfs_root *open_ctree(struct super_block *sb,
137 ret = find_and_setup_root(disk_super, tree_root, fs_info, 285 ret = find_and_setup_root(disk_super, tree_root, fs_info,
138 BTRFS_FS_TREE_OBJECTID, root); 286 BTRFS_FS_TREE_OBJECTID, root);
139 BUG_ON(ret); 287 BUG_ON(ret);
140
141 root->commit_root = root->node; 288 root->commit_root = root->node;
142 get_bh(root->node); 289 get_bh(root->node);
143 root->ref_cows = 1; 290 root->ref_cows = 1;
@@ -191,6 +338,7 @@ int close_ctree(struct btrfs_root *root)
191 root->fs_info->tree_root->node); 338 root->fs_info->tree_root->node);
192 btrfs_block_release(root, root->commit_root); 339 btrfs_block_release(root, root->commit_root);
193 btrfs_block_release(root, root->fs_info->sb_buffer); 340 btrfs_block_release(root, root->fs_info->sb_buffer);
341 iput(root->fs_info->btree_inode);
194 kfree(root->fs_info->extent_root); 342 kfree(root->fs_info->extent_root);
195 kfree(root->fs_info->inode_root); 343 kfree(root->fs_info->inode_root);
196 kfree(root->fs_info->tree_root); 344 kfree(root->fs_info->tree_root);