aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/disk-io.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-10-15 16:19:22 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:03:56 -0400
commit19c00ddcc31ad4bdfb86b57085e06d6135b9b1d7 (patch)
treea48cbaac47070057912c1b35d270b61b7e14386c /fs/btrfs/disk-io.c
parent0f82731fc56448c2733f58e1f5db6c2cbfc90652 (diff)
Btrfs: Add back metadata checksumming
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r--fs/btrfs/disk-io.c215
1 files changed, 155 insertions, 60 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 16f0260fca66..1176e5420c56 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -60,7 +60,7 @@ struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root,
60 struct extent_buffer *eb; 60 struct extent_buffer *eb;
61 61
62 eb = alloc_extent_buffer(&BTRFS_I(btree_inode)->extent_tree, 62 eb = alloc_extent_buffer(&BTRFS_I(btree_inode)->extent_tree,
63 bytenr, blocksize, GFP_NOFS); 63 bytenr, blocksize, NULL, GFP_NOFS);
64 return eb; 64 return eb;
65} 65}
66 66
@@ -99,10 +99,102 @@ out:
99 return em; 99 return em;
100} 100}
101 101
102u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len)
103{
104 return crc32c(seed, data, len);
105}
106
107void btrfs_csum_final(u32 crc, char *result)
108{
109 *(__le32 *)result = ~cpu_to_le32(crc);
110}
111
112static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
113 int verify)
114{
115 char result[BTRFS_CRC32_SIZE];
116 unsigned long len;
117 unsigned long cur_len;
118 unsigned long offset = BTRFS_CSUM_SIZE;
119 char *map_token = NULL;
120 char *kaddr;
121 unsigned long map_start;
122 unsigned long map_len;
123 int err;
124 u32 crc = ~(u32)0;
125
126 len = buf->len - offset;
127 while(len > 0) {
128 err = map_private_extent_buffer(buf, offset, 32,
129 &map_token, &kaddr,
130 &map_start, &map_len, KM_USER0);
131 if (err) {
132 printk("failed to map extent buffer! %lu\n",
133 offset);
134 return 1;
135 }
136 cur_len = min(len, map_len - (offset - map_start));
137 crc = btrfs_csum_data(root, kaddr + offset - map_start,
138 crc, cur_len);
139 len -= cur_len;
140 offset += cur_len;
141 unmap_extent_buffer(buf, map_token, KM_USER0);
142 }
143 btrfs_csum_final(crc, result);
144
145 if (verify) {
146 if (memcmp_extent_buffer(buf, result, 0, BTRFS_CRC32_SIZE)) {
147 printk("btrfs: %s checksum verify failed on %llu\n",
148 root->fs_info->sb->s_id,
149 buf->start);
150 return 1;
151 }
152 } else {
153 write_extent_buffer(buf, result, 0, BTRFS_CRC32_SIZE);
154 }
155 return 0;
156}
157
158
159int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
160{
161 struct extent_map_tree *tree;
162 u64 start = page->index << PAGE_CACHE_SHIFT;
163 u64 found_start;
164 int found_level;
165 unsigned long len;
166 struct extent_buffer *eb;
167 tree = &BTRFS_I(page->mapping->host)->extent_tree;
168
169 if (page->private == EXTENT_PAGE_PRIVATE)
170 goto out;
171 if (!page->private)
172 goto out;
173 len = page->private >> 2;
174 if (len == 0) {
175 WARN_ON(1);
176 }
177 eb = alloc_extent_buffer(tree, start, len, page, GFP_NOFS);
178 read_extent_buffer_pages(tree, eb, start + PAGE_CACHE_SIZE, 1);
179 found_start = btrfs_header_bytenr(eb);
180 if (found_start != start) {
181 printk("warning: eb start incorrect %Lu buffer %Lu len %lu\n",
182 start, found_start, len);
183 }
184 found_level = btrfs_header_level(eb);
185 csum_tree_block(root, eb, 0);
186 free_extent_buffer(eb);
187out:
188 return 0;
189}
190
102static int btree_writepage(struct page *page, struct writeback_control *wbc) 191static int btree_writepage(struct page *page, struct writeback_control *wbc)
103{ 192{
104 struct extent_map_tree *tree; 193 struct extent_map_tree *tree;
194 struct btrfs_root *root = BTRFS_I(page->mapping->host)->root;
105 tree = &BTRFS_I(page->mapping->host)->extent_tree; 195 tree = &BTRFS_I(page->mapping->host)->extent_tree;
196
197 csum_dirty_buffer(root, page);
106 return extent_write_full_page(tree, page, btree_get_extent, wbc); 198 return extent_write_full_page(tree, page, btree_get_extent, wbc);
107} 199}
108int btree_readpage(struct file *file, struct page *page) 200int btree_readpage(struct file *file, struct page *page)
@@ -117,7 +209,6 @@ static int btree_releasepage(struct page *page, gfp_t unused_gfp_flags)
117 struct extent_map_tree *tree; 209 struct extent_map_tree *tree;
118 int ret; 210 int ret;
119 211
120 BUG_ON(page->private != 1);
121 tree = &BTRFS_I(page->mapping->host)->extent_tree; 212 tree = &BTRFS_I(page->mapping->host)->extent_tree;
122 ret = try_release_extent_mapping(tree, page); 213 ret = try_release_extent_mapping(tree, page);
123 if (ret == 1) { 214 if (ret == 1) {
@@ -136,46 +227,6 @@ static void btree_invalidatepage(struct page *page, unsigned long offset)
136 btree_releasepage(page, GFP_NOFS); 227 btree_releasepage(page, GFP_NOFS);
137} 228}
138 229
139int btrfs_csum_data(struct btrfs_root * root, char *data, size_t len,
140 char *result)
141{
142 return 0;
143#if 0
144 u32 crc;
145 crc = crc32c(0, data, len);
146 memcpy(result, &crc, BTRFS_CRC32_SIZE);
147 return 0;
148#endif
149}
150
151#if 0
152static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
153 int verify)
154{
155 return 0;
156 char result[BTRFS_CRC32_SIZE];
157 int ret;
158 struct btrfs_node *node;
159
160 ret = btrfs_csum_data(root, bh->b_data + BTRFS_CSUM_SIZE,
161 bh->b_size - BTRFS_CSUM_SIZE, result);
162 if (ret)
163 return ret;
164 if (verify) {
165 if (memcmp(bh->b_data, result, BTRFS_CRC32_SIZE)) {
166 printk("btrfs: %s checksum verify failed on %llu\n",
167 root->fs_info->sb->s_id,
168 (unsigned long long)bh_blocknr(bh));
169 return 1;
170 }
171 } else {
172 node = btrfs_buffer_node(bh);
173 memcpy(node->header.csum, result, BTRFS_CRC32_SIZE);
174 }
175 return 0;
176}
177#endif
178
179#if 0 230#if 0
180static int btree_writepage(struct page *page, struct writeback_control *wbc) 231static int btree_writepage(struct page *page, struct writeback_control *wbc)
181{ 232{
@@ -215,7 +266,7 @@ int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize)
215 if (!buf) 266 if (!buf)
216 return 0; 267 return 0;
217 read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree, 268 read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree,
218 buf, 0); 269 buf, 0, 0);
219 free_extent_buffer(buf); 270 free_extent_buffer(buf);
220 return ret; 271 return ret;
221} 272}
@@ -225,12 +276,29 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
225{ 276{
226 struct extent_buffer *buf = NULL; 277 struct extent_buffer *buf = NULL;
227 struct inode *btree_inode = root->fs_info->btree_inode; 278 struct inode *btree_inode = root->fs_info->btree_inode;
279 struct extent_map_tree *extent_tree;
280 int ret;
281
282 extent_tree = &BTRFS_I(btree_inode)->extent_tree;
228 283
229 buf = btrfs_find_create_tree_block(root, bytenr, blocksize); 284 buf = btrfs_find_create_tree_block(root, bytenr, blocksize);
230 if (!buf) 285 if (!buf)
231 return NULL; 286 return NULL;
232 read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree, 287 read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree,
233 buf, 1); 288 buf, 0, 1);
289 if (buf->flags & EXTENT_CSUM) {
290 return buf;
291 }
292 if (test_range_bit(extent_tree, buf->start, buf->start + buf->len - 1,
293 EXTENT_CSUM, 1)) {
294 buf->flags |= EXTENT_CSUM;
295 return buf;
296 }
297 ret = csum_tree_block(root, buf, 1);
298 set_extent_bits(extent_tree, buf->start,
299 buf->start + buf->len - 1,
300 EXTENT_CSUM, GFP_NOFS);
301 buf->flags |= EXTENT_CSUM;
234 return buf; 302 return buf;
235} 303}
236 304
@@ -251,13 +319,6 @@ int wait_on_tree_block_writeback(struct btrfs_root *root,
251 return 0; 319 return 0;
252} 320}
253 321
254int set_tree_block_dirty(struct btrfs_root *root, struct extent_buffer *buf)
255{
256 struct inode *btree_inode = root->fs_info->btree_inode;
257 set_extent_buffer_dirty(&BTRFS_I(btree_inode)->extent_tree, buf);
258 return 0;
259}
260
261static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, 322static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
262 struct btrfs_root *root, 323 struct btrfs_root *root,
263 struct btrfs_fs_info *fs_info, 324 struct btrfs_fs_info *fs_info,
@@ -416,7 +477,24 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
416 477
417 return root; 478 return root;
418} 479}
419 480#if 0
481static int add_hasher(struct btrfs_fs_info *info, char *type) {
482 struct btrfs_hasher *hasher;
483
484 hasher = kmalloc(sizeof(*hasher), GFP_NOFS);
485 if (!hasher)
486 return -ENOMEM;
487 hasher->hash_tfm = crypto_alloc_hash(type, 0, CRYPTO_ALG_ASYNC);
488 if (!hasher->hash_tfm) {
489 kfree(hasher);
490 return -EINVAL;
491 }
492 spin_lock(&info->hash_lock);
493 list_add(&hasher->list, &info->hashers);
494 spin_unlock(&info->hash_lock);
495 return 0;
496}
497#endif
420struct btrfs_root *open_ctree(struct super_block *sb) 498struct btrfs_root *open_ctree(struct super_block *sb)
421{ 499{
422 u32 sectorsize; 500 u32 sectorsize;
@@ -440,6 +518,9 @@ struct btrfs_root *open_ctree(struct super_block *sb)
440 INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_NOFS); 518 INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_NOFS);
441 INIT_LIST_HEAD(&fs_info->trans_list); 519 INIT_LIST_HEAD(&fs_info->trans_list);
442 INIT_LIST_HEAD(&fs_info->dead_roots); 520 INIT_LIST_HEAD(&fs_info->dead_roots);
521 INIT_LIST_HEAD(&fs_info->hashers);
522 spin_lock_init(&fs_info->hash_lock);
523
443 memset(&fs_info->super_kobj, 0, sizeof(fs_info->super_kobj)); 524 memset(&fs_info->super_kobj, 0, sizeof(fs_info->super_kobj));
444 init_completion(&fs_info->kobj_unregister); 525 init_completion(&fs_info->kobj_unregister);
445 sb_set_blocksize(sb, 4096); 526 sb_set_blocksize(sb, 4096);
@@ -479,6 +560,14 @@ struct btrfs_root *open_ctree(struct super_block *sb)
479 mutex_init(&fs_info->trans_mutex); 560 mutex_init(&fs_info->trans_mutex);
480 mutex_init(&fs_info->fs_mutex); 561 mutex_init(&fs_info->fs_mutex);
481 562
563#if 0
564 ret = add_hasher(fs_info, "crc32c");
565 if (ret) {
566 printk("btrfs: failed hash setup, modprobe cryptomgr?\n");
567 err = -ENOMEM;
568 goto fail_iput;
569 }
570#endif
482 __setup_root(512, 512, 512, tree_root, 571 __setup_root(512, 512, 512, tree_root,
483 fs_info, BTRFS_ROOT_TREE_OBJECTID); 572 fs_info, BTRFS_ROOT_TREE_OBJECTID);
484 573
@@ -509,25 +598,21 @@ struct btrfs_root *open_ctree(struct super_block *sb)
509 i_size_write(fs_info->btree_inode, 598 i_size_write(fs_info->btree_inode,
510 btrfs_super_total_bytes(disk_super)); 599 btrfs_super_total_bytes(disk_super));
511 600
512
513 if (strncmp((char *)(&disk_super->magic), BTRFS_MAGIC, 601 if (strncmp((char *)(&disk_super->magic), BTRFS_MAGIC,
514 sizeof(disk_super->magic))) { 602 sizeof(disk_super->magic))) {
515 printk("btrfs: valid FS not found on %s\n", sb->s_id); 603 printk("btrfs: valid FS not found on %s\n", sb->s_id);
516 goto fail_sb_buffer; 604 goto fail_sb_buffer;
517 } 605 }
606
518 blocksize = btrfs_level_size(tree_root, 607 blocksize = btrfs_level_size(tree_root,
519 btrfs_super_root_level(disk_super)); 608 btrfs_super_root_level(disk_super));
609
520 tree_root->node = read_tree_block(tree_root, 610 tree_root->node = read_tree_block(tree_root,
521 btrfs_super_root(disk_super), 611 btrfs_super_root(disk_super),
522 blocksize); 612 blocksize);
523 if (!tree_root->node) 613 if (!tree_root->node)
524 goto fail_sb_buffer; 614 goto fail_sb_buffer;
525 615
526#if 0
527 btrfs_print_leaf(tree_root, tree_root->node);
528 err = -EIO;
529 goto fail_tree_root;
530#endif
531 mutex_lock(&fs_info->fs_mutex); 616 mutex_lock(&fs_info->fs_mutex);
532 617
533 ret = find_and_setup_root(tree_root, fs_info, 618 ret = find_and_setup_root(tree_root, fs_info,
@@ -634,9 +719,19 @@ int close_ctree(struct btrfs_root *root)
634 719
635 btrfs_free_block_groups(root->fs_info); 720 btrfs_free_block_groups(root->fs_info);
636 del_fs_roots(fs_info); 721 del_fs_roots(fs_info);
637 extent_map_tree_cleanup(&BTRFS_I(fs_info->btree_inode)->extent_tree); 722 extent_map_tree_empty_lru(&BTRFS_I(fs_info->btree_inode)->extent_tree);
638 truncate_inode_pages(fs_info->btree_inode->i_mapping, 0); 723 truncate_inode_pages(fs_info->btree_inode->i_mapping, 0);
639 iput(fs_info->btree_inode); 724 iput(fs_info->btree_inode);
725#if 0
726 while(!list_empty(&fs_info->hashers)) {
727 struct btrfs_hasher *hasher;
728 hasher = list_entry(fs_info->hashers.next, struct btrfs_hasher,
729 hashers);
730 list_del(&hasher->hashers);
731 crypto_free_hash(&fs_info->hash_tfm);
732 kfree(hasher);
733 }
734#endif
640 kfree(fs_info->extent_root); 735 kfree(fs_info->extent_root);
641 kfree(fs_info->tree_root); 736 kfree(fs_info->tree_root);
642 return 0; 737 return 0;
@@ -733,5 +828,5 @@ int btrfs_read_buffer(struct extent_buffer *buf)
733 struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; 828 struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root;
734 struct inode *btree_inode = root->fs_info->btree_inode; 829 struct inode *btree_inode = root->fs_info->btree_inode;
735 return read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree, 830 return read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree,
736 buf, 1); 831 buf, 0, 1);
737} 832}