Commit d6025579 authored by Chris Mason's avatar Chris Mason Committed by David Woodhouse

Btrfs: corruption hunt continues

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 22b0ebda
...@@ -16,12 +16,14 @@ int set_radix_bit(struct radix_tree_root *radix, unsigned long bit) ...@@ -16,12 +16,14 @@ int set_radix_bit(struct radix_tree_root *radix, unsigned long bit)
bits = radix_tree_lookup(radix, slot); bits = radix_tree_lookup(radix, slot);
if (!bits) { if (!bits) {
bits = kmalloc(BIT_ARRAY_BYTES, GFP_NOIO); bits = kmalloc(BIT_ARRAY_BYTES, GFP_NOFS);
if (!bits) if (!bits)
return -ENOMEM; return -ENOMEM;
memset(bits + 1, 0, BIT_ARRAY_BYTES - sizeof(unsigned long)); memset(bits + 1, 0, BIT_ARRAY_BYTES - sizeof(unsigned long));
bits[0] = slot; bits[0] = slot;
radix_tree_preload(GFP_NOFS);
ret = radix_tree_insert(radix, slot, bits); ret = radix_tree_insert(radix, slot, bits);
radix_tree_preload_end();
if (ret) if (ret)
return ret; return ret;
} }
...@@ -59,7 +61,7 @@ int clear_radix_bit(struct radix_tree_root *radix, unsigned long bit) ...@@ -59,7 +61,7 @@ int clear_radix_bit(struct radix_tree_root *radix, unsigned long bit)
if (!bits) if (!bits)
return 0; return 0;
clear_bit(bit_slot, bits + 1); clear_bit(bit_slot, bits + 1);
#if 0
for (i = 1; i < BIT_ARRAY_BYTES / sizeof(unsigned long); i++) { for (i = 1; i < BIT_ARRAY_BYTES / sizeof(unsigned long); i++) {
if (bits[i]) { if (bits[i]) {
empty = 0; empty = 0;
...@@ -69,8 +71,11 @@ int clear_radix_bit(struct radix_tree_root *radix, unsigned long bit) ...@@ -69,8 +71,11 @@ int clear_radix_bit(struct radix_tree_root *radix, unsigned long bit)
if (empty) { if (empty) {
bits = radix_tree_delete(radix, slot); bits = radix_tree_delete(radix, slot);
synchronize_rcu();
BUG_ON(!bits); BUG_ON(!bits);
kfree(bits);
} }
#endif
return 0; return 0;
} }
......
This diff is collapsed.
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#define __BTRFS__ #define __BTRFS__
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/buffer_head.h>
#include "bit-radix.h" #include "bit-radix.h"
struct btrfs_trans_handle; struct btrfs_trans_handle;
...@@ -834,6 +835,37 @@ static inline struct btrfs_root *btrfs_sb(struct super_block *sb) ...@@ -834,6 +835,37 @@ static inline struct btrfs_root *btrfs_sb(struct super_block *sb)
return sb->s_fs_info; return sb->s_fs_info;
} }
static inline void btrfs_check_bounds(void *vptr, size_t len,
void *vcontainer, size_t container_len)
{
char *ptr = vptr;
char *container = vcontainer;
WARN_ON(ptr < container);
WARN_ON(ptr + len > container + container_len);
}
static inline void btrfs_memcpy(struct btrfs_root *root,
void *dst_block,
void *dst, const void *src, size_t nr)
{
btrfs_check_bounds(dst, nr, dst_block, root->fs_info->sb->s_blocksize);
memcpy(dst, src, nr);
}
static inline void btrfs_memmove(struct btrfs_root *root,
void *dst_block,
void *dst, void *src, size_t nr)
{
btrfs_check_bounds(dst, nr, dst_block, root->fs_info->sb->s_blocksize);
memmove(dst, src, nr);
}
static inline void btrfs_mark_buffer_dirty(struct buffer_head *bh)
{
WARN_ON(!atomic_read(&bh->b_count));
mark_buffer_dirty(bh);
}
/* helper function to cast into the data area of the leaf. */ /* helper function to cast into the data area of the leaf. */
#define btrfs_item_ptr(leaf, slot, type) \ #define btrfs_item_ptr(leaf, slot, type) \
((type *)(btrfs_leaf_data(leaf) + \ ((type *)(btrfs_leaf_data(leaf) + \
......
...@@ -34,10 +34,8 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -34,10 +34,8 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_set_dir_flags(dir_item, 0); btrfs_set_dir_flags(dir_item, 0);
btrfs_set_dir_name_len(dir_item, name_len); btrfs_set_dir_name_len(dir_item, name_len);
name_ptr = (char *)(dir_item + 1); name_ptr = (char *)(dir_item + 1);
memcpy(name_ptr, name, name_len); btrfs_memcpy(root, path.nodes[0]->b_data, name_ptr, name, name_len);
if (name_ptr + name_len > path.nodes[0]->b_data + 4096) btrfs_mark_buffer_dirty(path.nodes[0]);
WARN_ON(1);
mark_buffer_dirty(path.nodes[0]);
out: out:
btrfs_release_path(root, &path); btrfs_release_path(root, &path);
return ret; return ret;
......
...@@ -8,6 +8,17 @@ ...@@ -8,6 +8,17 @@
#include "disk-io.h" #include "disk-io.h"
#include "transaction.h" #include "transaction.h"
#define PATTERN 0xDEADBEEFUL
static inline void check_pattern(struct buffer_head *buf)
{
if (buf->b_private != (void *)PATTERN)
WARN_ON(1);
}
static inline void set_pattern(struct buffer_head *buf)
{
buf->b_private = (void *)PATTERN;
}
static int check_tree_block(struct btrfs_root *root, struct buffer_head *buf) static int check_tree_block(struct btrfs_root *root, struct buffer_head *buf)
{ {
...@@ -51,8 +62,10 @@ struct buffer_head *btrfs_find_tree_block(struct btrfs_root *root, u64 blocknr) ...@@ -51,8 +62,10 @@ struct buffer_head *btrfs_find_tree_block(struct btrfs_root *root, u64 blocknr)
} while (bh != head); } while (bh != head);
out_unlock: out_unlock:
unlock_page(page); unlock_page(page);
if (ret) if (ret) {
touch_buffer(ret); touch_buffer(ret);
check_pattern(ret);
}
page_cache_release(page); page_cache_release(page);
return ret; return ret;
} }
...@@ -82,6 +95,7 @@ struct buffer_head *btrfs_find_create_tree_block(struct btrfs_root *root, ...@@ -82,6 +95,7 @@ struct buffer_head *btrfs_find_create_tree_block(struct btrfs_root *root,
bh->b_bdev = root->fs_info->sb->s_bdev; bh->b_bdev = root->fs_info->sb->s_bdev;
bh->b_blocknr = first_block; bh->b_blocknr = first_block;
set_buffer_mapped(bh); set_buffer_mapped(bh);
set_pattern(bh);
} }
if (bh->b_blocknr == blocknr) { if (bh->b_blocknr == blocknr) {
ret = bh; ret = bh;
...@@ -225,6 +239,7 @@ struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr) ...@@ -225,6 +239,7 @@ struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr)
if (!buffer_uptodate(bh)) if (!buffer_uptodate(bh))
goto fail; goto fail;
csum_tree_block(root, bh, 1); csum_tree_block(root, bh, 1);
set_pattern(bh);
} else { } else {
unlock_buffer(bh); unlock_buffer(bh);
} }
...@@ -240,6 +255,7 @@ struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr) ...@@ -240,6 +255,7 @@ struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr)
int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct buffer_head *buf) struct buffer_head *buf)
{ {
WARN_ON(atomic_read(&buf->b_count) == 0);
mark_buffer_dirty(buf); mark_buffer_dirty(buf);
return 0; return 0;
} }
...@@ -247,6 +263,7 @@ int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, ...@@ -247,6 +263,7 @@ int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct buffer_head *buf) struct buffer_head *buf)
{ {
WARN_ON(atomic_read(&buf->b_count) == 0);
clear_buffer_dirty(buf); clear_buffer_dirty(buf);
return 0; return 0;
} }
...@@ -431,6 +448,7 @@ int close_ctree(struct btrfs_root *root) ...@@ -431,6 +448,7 @@ int close_ctree(struct btrfs_root *root)
void btrfs_block_release(struct btrfs_root *root, struct buffer_head *buf) void btrfs_block_release(struct btrfs_root *root, struct buffer_head *buf)
{ {
check_pattern(buf);
brelse(buf); brelse(buf);
} }
...@@ -39,7 +39,7 @@ static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -39,7 +39,7 @@ static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
item = btrfs_item_ptr(l, path.slots[0], struct btrfs_extent_item); item = btrfs_item_ptr(l, path.slots[0], struct btrfs_extent_item);
refs = btrfs_extent_refs(item); refs = btrfs_extent_refs(item);
btrfs_set_extent_refs(item, refs + 1); btrfs_set_extent_refs(item, refs + 1);
mark_buffer_dirty(path.nodes[0]); btrfs_mark_buffer_dirty(path.nodes[0]);
btrfs_release_path(root->fs_info->extent_root, &path); btrfs_release_path(root->fs_info->extent_root, &path);
finish_current_insert(trans, root->fs_info->extent_root); finish_current_insert(trans, root->fs_info->extent_root);
...@@ -177,10 +177,10 @@ static int pin_down_block(struct btrfs_root *root, u64 blocknr, int pending) ...@@ -177,10 +177,10 @@ static int pin_down_block(struct btrfs_root *root, u64 blocknr, int pending)
header = btrfs_buffer_header(bh); header = btrfs_buffer_header(bh);
if (btrfs_header_generation(header) == if (btrfs_header_generation(header) ==
root->fs_info->running_transaction->transid) { root->fs_info->running_transaction->transid) {
brelse(bh); btrfs_block_release(root, bh);
return 0; return 0;
} }
brelse(bh); btrfs_block_release(root, bh);
} }
err = set_radix_bit(&root->fs_info->pinned_radix, blocknr); err = set_radix_bit(&root->fs_info->pinned_radix, blocknr);
} else { } else {
...@@ -224,7 +224,7 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -224,7 +224,7 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
BUG_ON(ei->refs == 0); BUG_ON(ei->refs == 0);
refs = btrfs_extent_refs(ei) - 1; refs = btrfs_extent_refs(ei) - 1;
btrfs_set_extent_refs(ei, refs); btrfs_set_extent_refs(ei, refs);
mark_buffer_dirty(path.nodes[0]); btrfs_mark_buffer_dirty(path.nodes[0]);
if (refs == 0) { if (refs == 0) {
u64 super_blocks_used; u64 super_blocks_used;
......
...@@ -34,7 +34,7 @@ int btrfs_alloc_file_extent(struct btrfs_trans_handle *trans, ...@@ -34,7 +34,7 @@ int btrfs_alloc_file_extent(struct btrfs_trans_handle *trans,
btrfs_set_file_extent_offset(item, 0); btrfs_set_file_extent_offset(item, 0);
btrfs_set_file_extent_num_blocks(item, ins.offset); btrfs_set_file_extent_num_blocks(item, ins.offset);
btrfs_set_file_extent_generation(item, trans->transid); btrfs_set_file_extent_generation(item, trans->transid);
mark_buffer_dirty(path.nodes[0]); btrfs_mark_buffer_dirty(path.nodes[0]);
*result = ins.objectid; *result = ins.objectid;
btrfs_release_path(root, &path); btrfs_release_path(root, &path);
return 0; return 0;
...@@ -81,7 +81,7 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans, ...@@ -81,7 +81,7 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
struct btrfs_csum_item); struct btrfs_csum_item);
ret = 0; ret = 0;
ret = btrfs_csum_data(root, data, len, item->csum); ret = btrfs_csum_data(root, data, len, item->csum);
mark_buffer_dirty(path.nodes[0]); btrfs_mark_buffer_dirty(path.nodes[0]);
fail: fail:
btrfs_release_path(root, &path); btrfs_release_path(root, &path);
return ret; return ret;
......
...@@ -109,7 +109,7 @@ int btrfs_insert_inode_map(struct btrfs_trans_handle *trans, ...@@ -109,7 +109,7 @@ int btrfs_insert_inode_map(struct btrfs_trans_handle *trans,
inode_item = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]), inode_item = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]),
path.slots[0], struct btrfs_inode_map_item); path.slots[0], struct btrfs_inode_map_item);
btrfs_cpu_key_to_disk(&inode_item->key, location); btrfs_cpu_key_to_disk(&inode_item->key, location);
mark_buffer_dirty(path.nodes[0]); btrfs_mark_buffer_dirty(path.nodes[0]);
out: out:
btrfs_release_path(inode_root, &path); btrfs_release_path(inode_root, &path);
return ret; return ret;
......
...@@ -45,6 +45,7 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -45,6 +45,7 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
struct btrfs_leaf *l; struct btrfs_leaf *l;
int ret; int ret;
int slot; int slot;
struct btrfs_root_item *update_item;
btrfs_init_path(&path); btrfs_init_path(&path);
ret = btrfs_search_slot(trans, root, key, &path, 0, 1); ret = btrfs_search_slot(trans, root, key, &path, 0, 1);
...@@ -53,9 +54,9 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -53,9 +54,9 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
BUG_ON(ret != 0); BUG_ON(ret != 0);
l = btrfs_buffer_leaf(path.nodes[0]); l = btrfs_buffer_leaf(path.nodes[0]);
slot = path.slots[0]; slot = path.slots[0];
memcpy(btrfs_item_ptr(l, slot, struct btrfs_root_item), item, update_item = btrfs_item_ptr(l, slot, struct btrfs_root_item);
sizeof(*item)); btrfs_memcpy(root, l, update_item, item, sizeof(*item));
mark_buffer_dirty(path.nodes[0]); btrfs_mark_buffer_dirty(path.nodes[0]);
out: out:
btrfs_release_path(root, &path); btrfs_release_path(root, &path);
return ret; return ret;
......
...@@ -557,7 +557,7 @@ static int btrfs_update_inode(struct btrfs_trans_handle *trans, ...@@ -557,7 +557,7 @@ static int btrfs_update_inode(struct btrfs_trans_handle *trans,
struct btrfs_inode_item); struct btrfs_inode_item);
fill_inode_item(inode_item, inode); fill_inode_item(inode_item, inode);
mark_buffer_dirty(path.nodes[0]); btrfs_mark_buffer_dirty(path.nodes[0]);
failed: failed:
btrfs_release_path(root, &path); btrfs_release_path(root, &path);
return 0; return 0;
......
...@@ -66,6 +66,7 @@ int btrfs_end_transaction(struct btrfs_trans_handle *trans, ...@@ -66,6 +66,7 @@ int btrfs_end_transaction(struct btrfs_trans_handle *trans,
cur_trans->num_writers--; cur_trans->num_writers--;
put_transaction(cur_trans); put_transaction(cur_trans);
mutex_unlock(&root->fs_info->trans_mutex); mutex_unlock(&root->fs_info->trans_mutex);
memset(trans, 0, sizeof(*trans));
kfree(trans); kfree(trans);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment