aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.h1
-rw-r--r--fs/btrfs/disk-io.c174
-rw-r--r--fs/btrfs/disk-io.h5
-rw-r--r--fs/btrfs/extent-tree.c8
-rw-r--r--fs/btrfs/super.c8
-rw-r--r--fs/btrfs/transaction.c2
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
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);
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
23struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr); 23struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr);
24struct buffer_head *find_tree_block(struct btrfs_root *root, u64 blocknr); 24struct buffer_head *btrfs_find_create_tree_block(struct btrfs_root *root,
25 u64 blocknr);
25int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, 26int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
26 struct buffer_head *buf); 27 struct buffer_head *buf);
27int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, 28int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
@@ -37,5 +38,5 @@ int close_ctree(struct btrfs_root *root);
37void btrfs_block_release(struct btrfs_root *root, struct buffer_head *buf); 38void btrfs_block_release(struct btrfs_root *root, struct buffer_head *buf);
38int write_ctree_super(struct btrfs_trans_handle *trans, 39int write_ctree_super(struct btrfs_trans_handle *trans,
39 struct btrfs_root *root); 40 struct btrfs_root *root);
40int mkfs(int fd, u64 num_blocks, u32 blocksize); 41struct 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,
74int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, 74int 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