diff options
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/ctree.h | 1 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 174 | ||||
-rw-r--r-- | fs/btrfs/disk-io.h | 5 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 8 | ||||
-rw-r--r-- | fs/btrfs/super.c | 8 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 2 |
6 files changed, 174 insertions, 24 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 1897f3a65b4f..b2ebed756c13 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -233,6 +233,7 @@ struct btrfs_fs_info { | |||
233 | struct btrfs_super_block *disk_super; | 233 | struct btrfs_super_block *disk_super; |
234 | struct buffer_head *sb_buffer; | 234 | struct buffer_head *sb_buffer; |
235 | struct super_block *sb; | 235 | struct super_block *sb; |
236 | struct inode *btree_inode; | ||
236 | struct mutex trans_mutex; | 237 | struct mutex trans_mutex; |
237 | struct mutex fs_mutex; | 238 | struct mutex fs_mutex; |
238 | }; | 239 | }; |
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); |
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index 099f7eea0ec7..c2c38bda704d 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h | |||
@@ -21,7 +21,8 @@ static inline struct btrfs_header *btrfs_buffer_header(struct buffer_head *bh) | |||
21 | } | 21 | } |
22 | 22 | ||
23 | struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr); | 23 | struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr); |
24 | struct buffer_head *find_tree_block(struct btrfs_root *root, u64 blocknr); | 24 | struct buffer_head *btrfs_find_create_tree_block(struct btrfs_root *root, |
25 | u64 blocknr); | ||
25 | int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, | 26 | int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, |
26 | struct buffer_head *buf); | 27 | struct buffer_head *buf); |
27 | int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, | 28 | int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, |
@@ -37,5 +38,5 @@ int close_ctree(struct btrfs_root *root); | |||
37 | void btrfs_block_release(struct btrfs_root *root, struct buffer_head *buf); | 38 | void btrfs_block_release(struct btrfs_root *root, struct buffer_head *buf); |
38 | int write_ctree_super(struct btrfs_trans_handle *trans, | 39 | int write_ctree_super(struct btrfs_trans_handle *trans, |
39 | struct btrfs_root *root); | 40 | struct btrfs_root *root); |
40 | int mkfs(int fd, u64 num_blocks, u32 blocksize); | 41 | struct buffer_head *btrfs_find_tree_block(struct btrfs_root *root, u64 blocknr); |
41 | #endif | 42 | #endif |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 176c6dc534ba..b2ae8e768b6c 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -172,8 +172,8 @@ static int pin_down_block(struct btrfs_root *root, u64 blocknr, int pending) | |||
172 | struct buffer_head *bh; | 172 | struct buffer_head *bh; |
173 | 173 | ||
174 | if (!pending) { | 174 | if (!pending) { |
175 | bh = sb_find_get_block(root->fs_info->sb, blocknr); | 175 | bh = btrfs_find_tree_block(root, blocknr); |
176 | if (bh) { | 176 | if (bh && buffer_uptodate(bh)) { |
177 | header = btrfs_buffer_header(bh); | 177 | header = btrfs_buffer_header(bh); |
178 | if (btrfs_header_generation(header) == | 178 | if (btrfs_header_generation(header) == |
179 | root->fs_info->running_transaction->transid) { | 179 | root->fs_info->running_transaction->transid) { |
@@ -291,12 +291,10 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
291 | *root, u64 blocknr, u64 num_blocks, int pin) | 291 | *root, u64 blocknr, u64 num_blocks, int pin) |
292 | { | 292 | { |
293 | struct btrfs_root *extent_root = root->fs_info->extent_root; | 293 | struct btrfs_root *extent_root = root->fs_info->extent_root; |
294 | struct buffer_head *t; | ||
295 | int pending_ret; | 294 | int pending_ret; |
296 | int ret; | 295 | int ret; |
297 | 296 | ||
298 | if (root == extent_root) { | 297 | if (root == extent_root) { |
299 | t = find_tree_block(root, blocknr); | ||
300 | pin_down_block(root, blocknr, 1); | 298 | pin_down_block(root, blocknr, 1); |
301 | return 0; | 299 | return 0; |
302 | } | 300 | } |
@@ -482,7 +480,7 @@ struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, | |||
482 | BUG(); | 480 | BUG(); |
483 | return NULL; | 481 | return NULL; |
484 | } | 482 | } |
485 | buf = find_tree_block(root, ins.objectid); | 483 | buf = btrfs_find_create_tree_block(root, ins.objectid); |
486 | set_buffer_uptodate(buf); | 484 | set_buffer_uptodate(buf); |
487 | return buf; | 485 | return buf; |
488 | } | 486 | } |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 67659b6ce962..8f07f462236a 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -474,6 +474,8 @@ static int btrfs_fill_super(struct super_block * sb, void * data, int silent) | |||
474 | disk_super = (struct btrfs_super_block *)bh->b_data; | 474 | disk_super = (struct btrfs_super_block *)bh->b_data; |
475 | root = open_ctree(sb, bh, disk_super); | 475 | root = open_ctree(sb, bh, disk_super); |
476 | sb->s_fs_info = root; | 476 | sb->s_fs_info = root; |
477 | disk_super = root->fs_info->disk_super; | ||
478 | |||
477 | if (!root) { | 479 | if (!root) { |
478 | printk("btrfs: open_ctree failed\n"); | 480 | printk("btrfs: open_ctree failed\n"); |
479 | return -EIO; | 481 | return -EIO; |
@@ -734,15 +736,15 @@ static int btrfs_sync_fs(struct super_block *sb, int wait) | |||
734 | struct btrfs_trans_handle *trans; | 736 | struct btrfs_trans_handle *trans; |
735 | struct btrfs_root *root; | 737 | struct btrfs_root *root; |
736 | int ret; | 738 | int ret; |
739 | root = btrfs_sb(sb); | ||
737 | 740 | ||
738 | sb->s_dirt = 0; | 741 | sb->s_dirt = 0; |
739 | if (!wait) { | 742 | if (!wait) { |
740 | filemap_flush(sb->s_bdev->bd_inode->i_mapping); | 743 | filemap_flush(root->fs_info->btree_inode->i_mapping); |
741 | return 0; | 744 | return 0; |
742 | } | 745 | } |
743 | filemap_write_and_wait(sb->s_bdev->bd_inode->i_mapping); | 746 | filemap_write_and_wait(root->fs_info->btree_inode->i_mapping); |
744 | 747 | ||
745 | root = btrfs_sb(sb); | ||
746 | mutex_lock(&root->fs_info->fs_mutex); | 748 | mutex_lock(&root->fs_info->fs_mutex); |
747 | trans = btrfs_start_transaction(root, 1); | 749 | trans = btrfs_start_transaction(root, 1); |
748 | ret = btrfs_commit_transaction(trans, root); | 750 | ret = btrfs_commit_transaction(trans, root); |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 46a596e345f0..b20fb53a0d27 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -74,7 +74,7 @@ int btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
74 | int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, | 74 | int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, |
75 | struct btrfs_root *root) | 75 | struct btrfs_root *root) |
76 | { | 76 | { |
77 | filemap_write_and_wait(root->fs_info->sb->s_bdev->bd_inode->i_mapping); | 77 | filemap_write_and_wait(root->fs_info->btree_inode->i_mapping); |
78 | return 0; | 78 | return 0; |
79 | } | 79 | } |
80 | 80 | ||