diff -Nru linux/fs/reiserfs/fix_node.c linux.old/fs/reiserfs/fix_node.c --- linux/fs/reiserfs/fix_node.c Fri Apr 20 11:43:58 2001 +++ linux.old/fs/reiserfs/fix_node.c Fri Apr 20 11:43:58 2001 @@ -2087,6 +2087,7 @@ unsigned long n_son_number; struct super_block * p_s_sb = p_s_tb->tb_sb; struct buffer_head * p_s_bh; + int was_read; if ( p_s_tb->lnum[n_h] ) { @@ -2100,7 +2101,7 @@ n_child_position = ( p_s_bh == p_s_tb->FL[n_h] ) ? p_s_tb->lkey[n_h] : B_NR_ITEMS (p_s_tb->FL[n_h]); n_son_number = B_N_CHILD_NUM(p_s_tb->FL[n_h], n_child_position); - p_s_bh = reiserfs_bread(p_s_sb->s_dev, n_son_number, p_s_sb->s_blocksize); + p_s_bh = reiserfs_read_node (p_s_sb, n_son_number, &was_read); if (!p_s_bh) return IO_ERROR; if ( FILESYSTEM_CHANGED_TB (p_s_tb) ) { @@ -2108,6 +2109,15 @@ return REPEAT_SEARCH; } + if ( +#ifndef CONFIG_REISERFS_CHECK + was_read && +#endif + reiserfs_check_node(p_s_bh, n_h + 1)) { + brelse (p_s_bh); + return IO_ERROR; + } + #ifdef CONFIG_REISERFS_CHECK if ( ! B_IS_IN_TREE(p_s_tb->FL[n_h]) || n_child_position > B_NR_ITEMS(p_s_tb->FL[n_h]) || B_N_CHILD_NUM(p_s_tb->FL[n_h], n_child_position) != p_s_bh->b_blocknr ) @@ -2134,13 +2144,23 @@ n_child_position = ( p_s_bh == p_s_tb->FR[n_h] ) ? p_s_tb->rkey[n_h] + 1 : 0; n_son_number = B_N_CHILD_NUM(p_s_tb->FR[n_h], n_child_position); - p_s_bh = reiserfs_bread(p_s_sb->s_dev, n_son_number, p_s_sb->s_blocksize); + p_s_bh = reiserfs_read_node(p_s_sb, n_son_number, &was_read); if (!p_s_bh) return IO_ERROR; if ( FILESYSTEM_CHANGED_TB (p_s_tb) ) { decrement_bcount(p_s_bh); return REPEAT_SEARCH; } + + if ( +#ifndef CONFIG_REISERFS_CHECK + was_read && +#endif + reiserfs_check_node(p_s_bh, n_h + 1)) { + brelse (p_s_bh); + return IO_ERROR; + } + decrement_bcount(p_s_tb->R[n_h]); p_s_tb->R[n_h] = p_s_bh; diff -Nru linux/fs/reiserfs/item_ops.c linux.old/fs/reiserfs/item_ops.c --- linux/fs/reiserfs/item_ops.c Fri Apr 20 11:43:58 2001 +++ linux.old/fs/reiserfs/item_ops.c Fri Apr 20 11:43:58 2001 @@ -20,6 +20,8 @@ /* and where are the comments? how about saying where we can find an explanation of each item handler method? -Hans */ +#define check_key_version(ih, key) (ih_version(ih) == le_key_version(key)) + ////////////////////////////////////////////////////////////////////////////// // stat data functions // @@ -74,9 +76,12 @@ } } -static void sd_check_item (struct item_head * ih, char * item) +static int sd_check_item (struct item_head * ih, char * item) { - // FIXME: type something here! + if (ih_version(ih) == ITEM_VERSION_1) { + return (ih_item_len(ih) == SD_V1_SIZE); + } + return (ih_item_len(ih) == SD_SIZE); } @@ -178,9 +183,9 @@ } -static void direct_check_item (struct item_head * ih, char * item) +static int direct_check_item (struct item_head * ih, char * item) { - // FIXME: type something here! + return check_key_version(ih, &(ih)->ih_key); } @@ -329,9 +334,9 @@ printk ("]\n"); } -static void indirect_check_item (struct item_head * ih, char * item) +static int indirect_check_item (struct item_head * ih, char * item) { - // FIXME: type something here! + return check_key_version(ih, &(ih)->ih_key); } @@ -464,7 +469,7 @@ } -static void direntry_check_item (struct item_head * ih, char * item) +static int direntry_check_item (struct item_head * ih, char * item) { int i; struct reiserfs_de_head * deh; @@ -474,6 +479,13 @@ for (i = 0; i < I_ENTRY_COUNT (ih); i ++, deh ++) { ; } + if (ih_version(ih) != ITEM_VERSION_1 || + le_key_version(&ih->ih_key)) { + reiserfs_warning ("direntry_check_item: item or item key version " + "is not suitable here.\n"); + return 0; + } + return 1; } diff -Nru linux/fs/reiserfs/stree.c linux.old/fs/reiserfs/stree.c --- linux/fs/reiserfs/stree.c Fri Apr 20 11:43:58 2001 +++ linux.old/fs/reiserfs/stree.c Fri Apr 20 11:43:58 2001 @@ -568,6 +568,12 @@ reiserfs_warning ("is_leaf: item location seems wrong (second one): %h\n", ih); return 0; } + + if (!op_check_item(ih, B_I_PITEM(bh,ih))) { + reiserfs_warning ("is_leaf: item (%h) has not passed internal check\n", ih); + return 0; + } + prev_location = ih_location (ih); } @@ -608,20 +614,26 @@ return 1; } - -// make sure that bh contains formatted node of reiserfs tree of -// 'level'-th level -static int is_tree_node (struct buffer_head * bh, int level) +int reiserfs_check_node (struct buffer_head *bh, int level) { if (B_LEVEL (bh) != level) { - printk ("is_tree_node: node level %d does not match to the expected one %d\n", + printk (__FUNCTION__ ": node level %d does not match to the expected one %d\n", B_LEVEL (bh), level); + goto error; + } + + if (level == DISK_LEAF_NODE_LEVEL) { + if (is_leaf (bh->b_data, bh->b_size, bh)) + return 0; /* OK */ + } else if (is_internal (bh->b_data, bh->b_size, bh)) { return 0; } - if (level == DISK_LEAF_NODE_LEVEL) - return is_leaf (bh->b_data, bh->b_size, bh); - return is_internal (bh->b_data, bh->b_size, bh); + error: + mark_buffer_uptodate(bh, 0); + reiserfs_warning("zam-5100: " __FUNCTION__ ": " + "reiserfs format violation in block %lu\n", bh->b_blocknr); + return IO_ERROR; } @@ -646,6 +658,28 @@ #endif +struct buffer_head * reiserfs_read_node (struct super_block *sb, + int block, + int * was_read) +{ + struct buffer_head *bh; + + bh = getblk(sb->s_dev, block, sb->s_blocksize); + if (buffer_uptodate(bh)) { + *was_read = 0; + return bh; + } else { + *was_read = 1; + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + if (buffer_uptodate(bh)) + return bh; + } + + brelse(bh); + return NULL; +} + /************************************************************************** * Algorithm SearchByKey * * look for item in the Disk S+Tree by its key * @@ -680,15 +714,14 @@ stop at leaf level - set to DISK_LEAF_NODE_LEVEL */ ) { - kdev_t n_dev = p_s_sb->s_dev; - int n_block_number = SB_ROOT_BLOCK (p_s_sb), - expected_level = SB_TREE_HEIGHT (p_s_sb), - n_block_size = p_s_sb->s_blocksize; + int n_block_number = SB_ROOT_BLOCK (p_s_sb); + int expected_level = SB_TREE_HEIGHT (p_s_sb); struct buffer_head * p_s_bh; struct path_element * p_s_last_element; int n_node_level, n_retval; int right_neighbor_of_leaf_node; int fs_gen; + int was_read; #ifdef CONFIG_REISERFS_CHECK int n_repeat_counter = 0; @@ -727,8 +760,10 @@ /* Read the next tree node, and set the last element in the path to have a pointer to it. */ - if ( ! (p_s_bh = p_s_last_element->pe_buffer = - reiserfs_bread(n_dev, n_block_number, n_block_size)) ) { + p_s_bh = p_s_last_element->pe_buffer = + reiserfs_read_node(p_s_sb, n_block_number, &was_read); + + if (!p_s_bh) { p_s_search_path->path_length --; pathrelse(p_s_search_path); return IO_ERROR; @@ -764,7 +799,11 @@ // make sure, that the node contents look like a node of // certain level - if (!is_tree_node (p_s_bh, expected_level)) { + if ( +#ifndef CONFIG_REISERFS_CHECK + was_read && +#endif + reiserfs_check_node (p_s_bh, expected_level)) { reiserfs_warning ("vs-5150: search_by_key: " "invalid format found in block %d. Fsck?\n", p_s_bh->b_blocknr); pathrelse (p_s_search_path); diff -Nru a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h --- a/include/linux/reiserfs_fs.h Fri Apr 20 11:43:58 2001 +++ b/include/linux/reiserfs_fs.h Fri Apr 20 11:43:58 2001 @@ -1398,7 +1398,7 @@ void (*decrement_key) (struct cpu_key *); int (*is_left_mergeable) (struct key * ih, unsigned long bsize); void (*print_item) (struct item_head *, char * item); - void (*check_item) (struct item_head *, char * item); + int (*check_item) (struct item_head *, char * item); int (*create_vi) (struct virtual_node * vn, struct virtual_item * vi, int is_affected, int insert_size); @@ -1714,6 +1714,8 @@ int comp_items (struct item_head * p_s_ih, struct path * p_s_path); struct key * get_rkey (struct path * p_s_chk_path, struct super_block * p_s_sb); inline int bin_search (void * p_v_key, void * p_v_base, int p_n_num, int p_n_width, int * p_n_pos); +struct buffer_head * reiserfs_read_node (struct super_block*, int, int*); +int reiserfs_check_node (struct buffer_head*, int); int search_by_key (struct super_block *, struct cpu_key *, struct path *, int); #define search_item(s,key,path) search_by_key (s, key, path, DISK_LEAF_NODE_LEVEL) int search_for_position_by_key (struct super_block * p_s_sb, struct cpu_key * p_s_cpu_key, struct path * p_s_search_path); .