diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-03-28 13:57:48 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-03-28 13:57:48 -0400 |
commit | d98237b3ede7ab98892f7fa62201a13694c526e2 (patch) | |
tree | cdf99f2d1e9bc088027cd98e5ed0e4efc79698e3 /fs/btrfs/disk-io.c | |
parent | 5f443fd280c76a2170259cebaa4108c9daad6e1b (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.c | 174 |
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 | |||
7 | static int check_tree_block(struct btrfs_root *root, struct buffer_head *buf) | 9 | static 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 | ||
19 | struct buffer_head *alloc_tree_block(struct btrfs_root *root, u64 blocknr) | 22 | struct 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); | ||
49 | out_unlock: | ||
50 | unlock_page(page); | ||
51 | page_cache_release(page); | ||
52 | return ret; | ||
53 | } | ||
54 | |||
55 | struct 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); | ||
89 | out_unlock: | ||
90 | unlock_page(page); | ||
91 | page_cache_release(page); | ||
92 | return ret; | ||
93 | } | ||
94 | |||
95 | static 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 | |||
108 | static 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 | |||
129 | static 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 | ||
24 | struct buffer_head *find_tree_block(struct btrfs_root *root, u64 blocknr) | 134 | static 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 | ||
139 | static struct address_space_operations btree_aops = { | ||
140 | .readpage = btree_readpage, | ||
141 | .writepage = btree_writepage, | ||
142 | .sync_page = block_sync_page, | ||
143 | }; | ||
144 | |||
29 | struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr) | 145 | struct 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; |
166 | fail: | ||
167 | brelse(bh); | ||
168 | return NULL; | ||
169 | |||
38 | } | 170 | } |
39 | 171 | ||
40 | int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, | 172 | int 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); |