diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-03-30 08:47:31 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-03-30 08:47:31 -0400 |
commit | 22b0ebda6c63a1ad66b6a9e806bd226a4a03a049 (patch) | |
tree | 391d141c7c143914969a98409e72e615cdcac226 /fs | |
parent | f254e52c1ce550fdaa0d31f5e068f0d67c2485d4 (diff) |
Btrfs: hunting slab corruption
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/ctree.c | 2 | ||||
-rw-r--r-- | fs/btrfs/dir-item.c | 2 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 16 | ||||
-rw-r--r-- | fs/btrfs/super.c | 7 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 6 |
5 files changed, 27 insertions, 6 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 1eb333e2e18b..b7f3fcb72c62 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -457,6 +457,8 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root | |||
457 | int ret; | 457 | int ret; |
458 | int level; | 458 | int level; |
459 | 459 | ||
460 | WARN_ON(p->nodes[0] != NULL); | ||
461 | WARN_ON(!mutex_is_locked(&root->fs_info->fs_mutex)); | ||
460 | again: | 462 | again: |
461 | b = root->node; | 463 | b = root->node; |
462 | get_bh(b); | 464 | get_bh(b); |
diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c index c18f81797a88..18d3e168ad0a 100644 --- a/fs/btrfs/dir-item.c +++ b/fs/btrfs/dir-item.c | |||
@@ -35,6 +35,8 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root | |||
35 | btrfs_set_dir_name_len(dir_item, name_len); | 35 | btrfs_set_dir_name_len(dir_item, name_len); |
36 | name_ptr = (char *)(dir_item + 1); | 36 | name_ptr = (char *)(dir_item + 1); |
37 | memcpy(name_ptr, name, name_len); | 37 | memcpy(name_ptr, name, name_len); |
38 | if (name_ptr + name_len > path.nodes[0]->b_data + 4096) | ||
39 | WARN_ON(1); | ||
38 | mark_buffer_dirty(path.nodes[0]); | 40 | mark_buffer_dirty(path.nodes[0]); |
39 | out: | 41 | out: |
40 | btrfs_release_path(root, &path); | 42 | btrfs_release_path(root, &path); |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index f5db2b936502..6c010463b9db 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include <linux/blkdev.h> | 3 | #include <linux/blkdev.h> |
4 | #include <linux/crypto.h> | 4 | #include <linux/crypto.h> |
5 | #include <linux/scatterlist.h> | 5 | #include <linux/scatterlist.h> |
6 | #include <linux/swap.h> | ||
6 | #include "ctree.h" | 7 | #include "ctree.h" |
7 | #include "disk-io.h" | 8 | #include "disk-io.h" |
8 | #include "transaction.h" | 9 | #include "transaction.h" |
@@ -50,6 +51,8 @@ struct buffer_head *btrfs_find_tree_block(struct btrfs_root *root, u64 blocknr) | |||
50 | } while (bh != head); | 51 | } while (bh != head); |
51 | out_unlock: | 52 | out_unlock: |
52 | unlock_page(page); | 53 | unlock_page(page); |
54 | if (ret) | ||
55 | touch_buffer(ret); | ||
53 | page_cache_release(page); | 56 | page_cache_release(page); |
54 | return ret; | 57 | return ret; |
55 | } | 58 | } |
@@ -65,6 +68,7 @@ struct buffer_head *btrfs_find_create_tree_block(struct btrfs_root *root, | |||
65 | struct buffer_head *head; | 68 | struct buffer_head *head; |
66 | struct buffer_head *ret = NULL; | 69 | struct buffer_head *ret = NULL; |
67 | u64 first_block = index << (PAGE_CACHE_SHIFT - blockbits); | 70 | u64 first_block = index << (PAGE_CACHE_SHIFT - blockbits); |
71 | |||
68 | page = grab_cache_page(mapping, index); | 72 | page = grab_cache_page(mapping, index); |
69 | if (!page) | 73 | if (!page) |
70 | return NULL; | 74 | return NULL; |
@@ -89,6 +93,8 @@ struct buffer_head *btrfs_find_create_tree_block(struct btrfs_root *root, | |||
89 | } while (bh != head); | 93 | } while (bh != head); |
90 | out_unlock: | 94 | out_unlock: |
91 | unlock_page(page); | 95 | unlock_page(page); |
96 | if (ret) | ||
97 | touch_buffer(ret); | ||
92 | page_cache_release(page); | 98 | page_cache_release(page); |
93 | return ret; | 99 | return ret; |
94 | } | 100 | } |
@@ -139,7 +145,7 @@ int btrfs_csum_data(struct btrfs_root * root, char *data, size_t len, | |||
139 | desc.flags = 0; | 145 | desc.flags = 0; |
140 | sg_init_one(&sg, data, len); | 146 | sg_init_one(&sg, data, len); |
141 | spin_lock(&root->fs_info->hash_lock); | 147 | spin_lock(&root->fs_info->hash_lock); |
142 | ret = crypto_hash_digest(&desc, &sg, len, result); | 148 | ret = crypto_hash_digest(&desc, &sg, 1, result); |
143 | spin_unlock(&root->fs_info->hash_lock); | 149 | spin_unlock(&root->fs_info->hash_lock); |
144 | if (ret) { | 150 | if (ret) { |
145 | printk("sha256 digest failed\n"); | 151 | printk("sha256 digest failed\n"); |
@@ -153,6 +159,7 @@ static int csum_tree_block(struct btrfs_root *root, struct buffer_head *bh, | |||
153 | int ret; | 159 | int ret; |
154 | struct btrfs_node *node; | 160 | struct btrfs_node *node; |
155 | 161 | ||
162 | return 0; | ||
156 | ret = btrfs_csum_data(root, bh->b_data + BTRFS_CSUM_SIZE, | 163 | ret = btrfs_csum_data(root, bh->b_data + BTRFS_CSUM_SIZE, |
157 | bh->b_size - BTRFS_CSUM_SIZE, result); | 164 | bh->b_size - BTRFS_CSUM_SIZE, result); |
158 | if (ret) | 165 | if (ret) |
@@ -165,17 +172,17 @@ static int csum_tree_block(struct btrfs_root *root, struct buffer_head *bh, | |||
165 | } | 172 | } |
166 | } else { | 173 | } else { |
167 | node = btrfs_buffer_node(bh); | 174 | node = btrfs_buffer_node(bh); |
168 | memcpy(&node->header.csum, result, BTRFS_CSUM_SIZE); | 175 | memcpy(node->header.csum, result, BTRFS_CSUM_SIZE); |
169 | } | 176 | } |
170 | return 0; | 177 | return 0; |
171 | } | 178 | } |
172 | 179 | ||
173 | static int btree_writepage(struct page *page, struct writeback_control *wbc) | 180 | static int btree_writepage(struct page *page, struct writeback_control *wbc) |
174 | { | 181 | { |
182 | #if 0 | ||
175 | struct buffer_head *bh; | 183 | struct buffer_head *bh; |
176 | struct btrfs_root *root = btrfs_sb(page->mapping->host->i_sb); | 184 | struct btrfs_root *root = btrfs_sb(page->mapping->host->i_sb); |
177 | struct buffer_head *head; | 185 | struct buffer_head *head; |
178 | |||
179 | if (!page_has_buffers(page)) { | 186 | if (!page_has_buffers(page)) { |
180 | create_empty_buffers(page, root->fs_info->sb->s_blocksize, | 187 | create_empty_buffers(page, root->fs_info->sb->s_blocksize, |
181 | (1 << BH_Dirty)|(1 << BH_Uptodate)); | 188 | (1 << BH_Dirty)|(1 << BH_Uptodate)); |
@@ -187,6 +194,7 @@ static int btree_writepage(struct page *page, struct writeback_control *wbc) | |||
187 | csum_tree_block(root, bh, 0); | 194 | csum_tree_block(root, bh, 0); |
188 | bh = bh->b_this_page; | 195 | bh = bh->b_this_page; |
189 | } while (bh != head); | 196 | } while (bh != head); |
197 | #endif | ||
190 | return block_write_full_page(page, btree_get_block, wbc); | 198 | return block_write_full_page(page, btree_get_block, wbc); |
191 | } | 199 | } |
192 | 200 | ||
@@ -312,6 +320,8 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
312 | fs_info->btree_inode->i_ino = 1; | 320 | fs_info->btree_inode->i_ino = 1; |
313 | fs_info->btree_inode->i_size = sb->s_bdev->bd_inode->i_size; | 321 | fs_info->btree_inode->i_size = sb->s_bdev->bd_inode->i_size; |
314 | fs_info->btree_inode->i_mapping->a_ops = &btree_aops; | 322 | fs_info->btree_inode->i_mapping->a_ops = &btree_aops; |
323 | insert_inode_hash(fs_info->btree_inode); | ||
324 | |||
315 | mapping_set_gfp_mask(fs_info->btree_inode->i_mapping, GFP_NOFS); | 325 | mapping_set_gfp_mask(fs_info->btree_inode->i_mapping, GFP_NOFS); |
316 | fs_info->hash_tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC); | 326 | fs_info->hash_tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC); |
317 | spin_lock_init(&fs_info->hash_lock); | 327 | spin_lock_init(&fs_info->hash_lock); |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 04428137d75f..ab5419eea93a 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -361,13 +361,16 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, | |||
361 | struct nameidata *nd) | 361 | struct nameidata *nd) |
362 | { | 362 | { |
363 | struct inode * inode; | 363 | struct inode * inode; |
364 | struct btrfs_root *root = btrfs_sb(dir->i_sb); | ||
364 | ino_t ino; | 365 | ino_t ino; |
365 | int ret; | 366 | int ret; |
366 | 367 | ||
367 | if (dentry->d_name.len > BTRFS_NAME_LEN) | 368 | if (dentry->d_name.len > BTRFS_NAME_LEN) |
368 | return ERR_PTR(-ENAMETOOLONG); | 369 | return ERR_PTR(-ENAMETOOLONG); |
369 | 370 | ||
371 | mutex_lock(&root->fs_info->fs_mutex); | ||
370 | ret = btrfs_inode_by_name(dir, dentry, &ino); | 372 | ret = btrfs_inode_by_name(dir, dentry, &ino); |
373 | mutex_unlock(&root->fs_info->fs_mutex); | ||
371 | if (ret < 0) | 374 | if (ret < 0) |
372 | return ERR_PTR(ret); | 375 | return ERR_PTR(ret); |
373 | inode = NULL; | 376 | inode = NULL; |
@@ -395,6 +398,7 @@ static int btrfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
395 | unsigned char d_type = DT_UNKNOWN; | 398 | unsigned char d_type = DT_UNKNOWN; |
396 | int over = 0; | 399 | int over = 0; |
397 | 400 | ||
401 | mutex_lock(&root->fs_info->fs_mutex); | ||
398 | key.objectid = inode->i_ino; | 402 | key.objectid = inode->i_ino; |
399 | key.flags = 0; | 403 | key.flags = 0; |
400 | btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); | 404 | btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); |
@@ -446,6 +450,7 @@ static int btrfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
446 | ret = 0; | 450 | ret = 0; |
447 | err: | 451 | err: |
448 | btrfs_release_path(root, &path); | 452 | btrfs_release_path(root, &path); |
453 | mutex_unlock(&root->fs_info->fs_mutex); | ||
449 | return ret; | 454 | return ret; |
450 | } | 455 | } |
451 | 456 | ||
@@ -667,8 +672,8 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, | |||
667 | inode->i_op = &btrfs_file_inode_operations; | 672 | inode->i_op = &btrfs_file_inode_operations; |
668 | } | 673 | } |
669 | dir->i_sb->s_dirt = 1; | 674 | dir->i_sb->s_dirt = 1; |
670 | btrfs_end_transaction(trans, root); | ||
671 | out_unlock: | 675 | out_unlock: |
676 | btrfs_end_transaction(trans, root); | ||
672 | mutex_unlock(&root->fs_info->fs_mutex); | 677 | mutex_unlock(&root->fs_info->fs_mutex); |
673 | if (drop_inode) { | 678 | if (drop_inode) { |
674 | inode_dec_link_count(inode); | 679 | inode_dec_link_count(inode); |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index b20fb53a0d27..a146463c5049 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -197,8 +197,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
197 | 197 | ||
198 | ret = btrfs_del_root(trans, root->fs_info->tree_root, | 198 | ret = btrfs_del_root(trans, root->fs_info->tree_root, |
199 | &snap_key); | 199 | &snap_key); |
200 | BUG_ON(ret); root->fs_info->generation = root->root_key.offset + 1; ret = btrfs_end_transaction(trans, root); BUG_ON(ret); | 200 | BUG_ON(ret); |
201 | printk("at free, total trans %d\n", total_trans); | 201 | root->fs_info->generation = root->root_key.offset + 1; |
202 | ret = btrfs_end_transaction(trans, root); | ||
203 | BUG_ON(ret); | ||
202 | } | 204 | } |
203 | 205 | ||
204 | return ret; | 206 | return ret; |