/* Returns 1 if buf looks like an internal node, 0 otherwise */ static int is_internal(char *buf, int blocksize, struct buf *bp) { int nr, used_space; struct block_head *blkh; blkh = (struct block_head *)buf; nr = blkh_level(blkh); if (nr <= DISK_LEAF_NODE_LEVEL || nr > MAX_HEIGHT) { /* This level is not possible for internal nodes */ reiserfs_log(LOG_WARNING, "this should be caught earlier\n"); return (0); } nr = blkh_nr_item(blkh); if (nr > (blocksize - BLKH_SIZE - DC_SIZE) / (KEY_SIZE + DC_SIZE)) { /* * For internal which is not root we might check min * number of keys */ reiserfs_log(LOG_WARNING, "number of key seems wrong\n"); return (0); } used_space = BLKH_SIZE + KEY_SIZE * nr + DC_SIZE * (nr + 1); if (used_space != blocksize - blkh_free_space(blkh)) { reiserfs_log(LOG_WARNING, "is_internal: free space seems wrong\n"); return (0); } /* One may imagine much more checks */ return (1); }
/* returns 1 if buf looks like an internal node, 0 otherwise */ static int is_internal(char *buf, int blocksize, struct buffer_head *bh) { struct block_head *blkh; int nr; int used_space; blkh = (struct block_head *)buf; nr = blkh_level(blkh); if (nr <= DISK_LEAF_NODE_LEVEL || nr > MAX_HEIGHT) { /* this level is not possible for internal nodes */ reiserfs_warning(NULL, "reiserfs-5087", "this should be caught earlier"); return 0; } nr = blkh_nr_item(blkh); if (nr > (blocksize - BLKH_SIZE - DC_SIZE) / (KEY_SIZE + DC_SIZE)) { /* for internal which is not root we might check min number of keys */ reiserfs_warning(NULL, "reiserfs-5088", "number of key seems wrong: %z", bh); return 0; } used_space = BLKH_SIZE + KEY_SIZE * nr + DC_SIZE * (nr + 1); if (used_space != blocksize - blkh_free_space(blkh)) { reiserfs_warning(NULL, "reiserfs-5089", "free space seems wrong: %z", bh); return 0; } // one may imagine much more checks return 1; }
/* Read in the node at the current path and depth into the node cache. * You must set INFO->blocks[depth] before. */ static char * read_tree_node( __u32 blockNr, __u16 depth ) { char *cache = CACHE(depth); int num_cached = INFO->cached_slots; errnum = 0; if ( depth < num_cached ) { /* This is the cached part of the path. Check if same block is needed. */ if ( blockNr == INFO->blocks[depth] ) return cache; } else cache = CACHE(num_cached); DEBUG_F( " next read_in: block=%u (depth=%u)\n", blockNr, depth ); if ( !block_read( blockNr, 0, INFO->blocksize, cache ) ) { DEBUG_F( "block_read failed\n" ); return 0; } DEBUG_F( "FOUND: blk_level=%u, blk_nr_item=%u, blk_free_space=%u\n", blkh_level(BLOCKHEAD(cache)), blkh_nr_item(BLOCKHEAD(cache)), le16_to_cpu(BLOCKHEAD(cache)->blk_free_space) ); /* Make sure it has the right node level */ if ( blkh_level(BLOCKHEAD(cache)) != depth ) { DEBUG_F( "depth = %u != %u\n", blkh_level(BLOCKHEAD(cache)), depth ); DEBUG_LEAVE(FILE_ERR_BAD_FSYS); errnum = FILE_ERR_BAD_FSYS; return 0; } INFO->blocks[depth] = blockNr; return cache; }
static int is_leaf(char *buf, int blocksize, struct buf *bp) { struct item_head *ih; struct block_head *blkh; int used_space, prev_location, i, nr; blkh = (struct block_head *)buf; if (blkh_level(blkh) != DISK_LEAF_NODE_LEVEL) { reiserfs_log(LOG_WARNING, "this should be caught earlier"); return (0); } nr = blkh_nr_item(blkh); if (nr < 1 || nr > ((blocksize - BLKH_SIZE) / (IH_SIZE + MIN_ITEM_LEN))) { /* Item number is too big or too small */ reiserfs_log(LOG_WARNING, "nr_item seems wrong\n"); return (0); } ih = (struct item_head *)(buf + BLKH_SIZE) + nr - 1; used_space = BLKH_SIZE + IH_SIZE * nr + (blocksize - ih_location(ih)); if (used_space != blocksize - blkh_free_space(blkh)) { /* * Free space does not match to calculated amount of * use space */ reiserfs_log(LOG_WARNING, "free space seems wrong\n"); return (0); } /* FIXME: it is_leaf will hit performance too much - we may have * return 1 here */ /* Check tables of item heads */ ih = (struct item_head *)(buf + BLKH_SIZE); prev_location = blocksize; for (i = 0; i < nr; i++, ih++) { if (le_ih_k_type(ih) == TYPE_ANY) { reiserfs_log(LOG_WARNING, "wrong item type for item\n"); return (0); } if (ih_location(ih) >= blocksize || ih_location(ih) < IH_SIZE * nr) { reiserfs_log(LOG_WARNING, "item location seems wrong\n"); return (0); } if (ih_item_len(ih) < 1 || ih_item_len(ih) > MAX_ITEM_LEN(blocksize)) { reiserfs_log(LOG_WARNING, "item length seems wrong\n"); return (0); } if (prev_location - ih_location(ih) != ih_item_len(ih)) { reiserfs_log(LOG_WARNING, "item location seems wrong (second one)\n"); return (0); } prev_location = ih_location(ih); } /* One may imagine much more checks */ return 1; }
static int is_leaf(char *buf, int blocksize, struct buffer_head *bh) { struct block_head *blkh; struct item_head *ih; int used_space; int prev_location; int i; int nr; blkh = (struct block_head *)buf; if (blkh_level(blkh) != DISK_LEAF_NODE_LEVEL) { reiserfs_warning(NULL, "reiserfs-5080", "this should be caught earlier"); return 0; } nr = blkh_nr_item(blkh); if (nr < 1 || nr > ((blocksize - BLKH_SIZE) / (IH_SIZE + MIN_ITEM_LEN))) { /* item number is too big or too small */ reiserfs_warning(NULL, "reiserfs-5081", "nr_item seems wrong: %z", bh); return 0; } ih = (struct item_head *)(buf + BLKH_SIZE) + nr - 1; used_space = BLKH_SIZE + IH_SIZE * nr + (blocksize - ih_location(ih)); if (used_space != blocksize - blkh_free_space(blkh)) { /* free space does not match to calculated amount of use space */ reiserfs_warning(NULL, "reiserfs-5082", "free space seems wrong: %z", bh); return 0; } // return 1 here /* check tables of item heads */ ih = (struct item_head *)(buf + BLKH_SIZE); prev_location = blocksize; for (i = 0; i < nr; i++, ih++) { if (le_ih_k_type(ih) == TYPE_ANY) { reiserfs_warning(NULL, "reiserfs-5083", "wrong item type for item %h", ih); return 0; } if (ih_location(ih) >= blocksize || ih_location(ih) < IH_SIZE * nr) { reiserfs_warning(NULL, "reiserfs-5084", "item location seems wrong: %h", ih); return 0; } if (ih_item_len(ih) < 1 || ih_item_len(ih) > MAX_ITEM_LEN(blocksize)) { reiserfs_warning(NULL, "reiserfs-5085", "item length seems wrong: %h", ih); return 0; } if (prev_location - ih_location(ih) != ih_item_len(ih)) { reiserfs_warning(NULL, "reiserfs-5086", "item location seems wrong " "(second one): %h", ih); return 0; } prev_location = ih_location(ih); } // one may imagine much more checks return 1; }
/* check filesystem types and read superblock into memory buffer */ static int reiserfs_read_super( void ) { struct reiserfs_super_block super; __u64 superblock = REISERFS_SUPERBLOCK_BLOCK; if (read_disk_block(INFO->file, superblock, 0, sizeof(super), &super) != sizeof(super)) { DEBUG_F("read_disk_block failed!\n"); return 0; } DEBUG_F( "Found super->magic: \"%s\"\n", super.s_magic ); if( strcmp( REISER2FS_SUPER_MAGIC_STRING, super.s_magic ) != 0 && strcmp( REISERFS_SUPER_MAGIC_STRING, super.s_magic ) != 0 ) { /* Try old super block position */ superblock = REISERFS_OLD_SUPERBLOCK_BLOCK; if (read_disk_block( INFO->file, superblock, 0, sizeof (super), &super ) != sizeof(super)) { DEBUG_F("read_disk_block failed!\n"); return 0; } if ( strcmp( REISER2FS_SUPER_MAGIC_STRING, super.s_magic ) != 0 && strcmp( REISERFS_SUPER_MAGIC_STRING, super.s_magic ) != 0 ) { /* pre journaling super block - untested */ if ( strcmp( REISERFS_SUPER_MAGIC_STRING, (char *) ((__u32) &super + 20 ) ) != 0 ) return 0; super.s_blocksize = cpu_to_le16(REISERFS_OLD_BLOCKSIZE); super.s_journal_block = 0; super.s_version = 0; } } DEBUG_F( "ReiserFS superblock data:\n" ); DEBUG_F( "Block count: %u\n", le32_to_cpu(super.s_block_count) ) DEBUG_F( "Free blocks: %u\n", le32_to_cpu(super.s_free_blocks) ); DEBUG_F( "Journal block: %u\n", le32_to_cpu(super.s_journal_block) ); DEBUG_F( "Journal size (in blocks): %u\n", le32_to_cpu(super.s_orig_journal_size) ); DEBUG_F( "Root block: %u\n\n", le32_to_cpu(super.s_root_block) ); INFO->version = le16_to_cpu(super.s_version); INFO->blocksize = le16_to_cpu(super.s_blocksize); INFO->blocksize_shift = log2( INFO->blocksize ); INFO->journal_block = le32_to_cpu(super.s_journal_block); INFO->journal_block_count = le32_to_cpu(super.s_orig_journal_size); INFO->cached_slots = (FSYSREISER_CACHE_SIZE >> INFO->blocksize_shift) - 1; /* At this point, we've found a valid superblock. If we run into problems * mounting the FS, the user should probably know. */ /* A few sanity checks ... */ if ( INFO->version > REISERFS_MAX_SUPPORTED_VERSION ) { prom_printf( "ReiserFS: Unsupported version field: %u\n", INFO->version ); return 0; } if ( INFO->blocksize < FSYSREISER_MIN_BLOCKSIZE || INFO->blocksize > FSYSREISER_MAX_BLOCKSIZE ) { prom_printf( "ReiserFS: Unsupported block size: %u\n", INFO->blocksize ); return 0; } /* Setup the journal.. */ if ( INFO->journal_block != 0 ) { if ( !is_power_of_two( INFO->journal_block_count ) ) { prom_printf( "ReiserFS: Unsupported journal size, " "not a power of 2: %u\n", INFO->journal_block_count ); return 0; } journal_init(); /* Read in super block again, maybe it is in the journal */ block_read( superblock, 0, sizeof (struct reiserfs_super_block), (char *) &super ); } /* Read in the root block */ if ( !block_read( le32_to_cpu(super.s_root_block), 0, INFO->blocksize, ROOT ) ) { prom_printf( "ReiserFS: Failed to read in root block\n" ); return 0; } /* The root node is always the "deepest", so we can determine the hieght of the tree using it. */ INFO->tree_depth = blkh_level(BLOCKHEAD(ROOT)); DEBUG_F( "root read_in: block=%u, depth=%u\n", le32_to_cpu(super.s_root_block), INFO->tree_depth ); if ( INFO->tree_depth >= REISERFS_MAX_TREE_HEIGHT ) { prom_printf( "ReiserFS: Unsupported tree depth (too deep): %u\n", INFO->tree_depth ); return 0; } if ( INFO->tree_depth == BLKH_LEVEL_LEAF ) { /* There is only one node in the whole filesystem, which is simultanously leaf and root */ memcpy( LEAF, ROOT, INFO->blocksize ); } return 1; }