/* * Copyright 1996, 1997 Hans Reiser */ #include "fsck.h" /* this goes through buffers checking delimiting keys */ struct buffer_head * g_left = 0; struct buffer_head * g_right = 0; struct key * g_dkey = 0; static void check_directory_item (struct item_head * ih, struct buffer_head * bh) { int i; struct reiserfs_de_head * deh; for (i = 0, deh = B_I_DEH (bh, ih); i < get_ih_entry_count (ih) - 1; i ++) if (get_deh_offset(&deh[i]) > get_deh_offset(&deh[i + 1])) die ("check_directory_item: entries are not sorted properly"); } static void check_items (struct buffer_head * bh) { int i; struct item_head * ih; for (i = 0; i < B_NR_ITEMS (bh); i++) { ih = B_N_PITEM_HEAD (bh, i); if (is_direntry_ih (ih)) check_directory_item (ih, bh); } } static void compare_neighboring_leaves_in_pass1 (void) { struct key * left = B_N_PKEY (g_left, B_NR_ITEMS (g_left) - 1); if (comp_keys (left, B_N_PKEY (g_right, 0)) != -1/*SECOND_GREATER*/) die ("compare_neighboring_leaves_in_pass1: left key is greater, that the right one"); if (/*comp_keys (B_PRIGHT_DELIM_KEY (g_left), g_dkey) == FIRST_GREATER ||*/ comp_keys (g_dkey, B_N_PKEY (g_right, 0))) { reiserfs_panic (0, "compare_neighboring_leaves_in_pass1: dkey %k, first key in right %k", g_dkey, B_N_PKEY (g_right, 0)); } check_items (g_left); /*&&&&&&&&&&&&&&&&&&&&&&&&&& for (i = 0, ih = B_N_PITEM_HEAD (g_left, i); i < B_NR_ITEMS (g_left); i ++, ih ++) if (is_item_accessed (ih) == YES) die ("compare_neighboring_leaves_in_pass1: item marked as accessed in g_left"); for (i = 0, ih = B_N_PITEM_HEAD (g_right, i); i < B_NR_ITEMS (g_right); i ++, ih ++) if (is_item_accessed (ih) == YES) die ("compare_neighboring_leaves_in_pass1: item marked as accessed in g_right"); &&&&&&&&&&&&&&&&&&&&&&&&&&&*/ } static void is_there_unaccessed_items (struct buffer_head * bh) { int i; struct item_head * ih; ih = B_N_PITEM_HEAD (bh, 0); for (i = 0; i < B_NR_ITEMS (bh); i ++, ih ++) { if (is_objectid_used (fs, get_key_objectid (&ih->ih_key)) == 0) die ("is_there_unaccessed_items: %lu is not marked as used", ( long unsigned ) get_key_objectid (&ih->ih_key)); if (!is_item_reachable (ih)) { die ("is_there_unaccessed_items: block %lu - unaccessed item found", bh->b_blocknr); } } } static void compare_neighboring_leaves_after_all (void) { struct item_head * left = B_N_PITEM_HEAD(g_left, B_NR_ITEMS (g_left) - 1); struct item_head * right = B_N_PITEM_HEAD(g_right, 0); /* struct key * left = B_N_PKEY (g_left, B_NR_ITEMS (g_left) - 1); struct key * right = B_N_PKEY (g_right, 0);*/ /* if (comp_keys (&left->ih_key, B_PRIGHT_DELIM_KEY (g_left)) != SECOND_GREATER) die ("compare_neighboring_leaves_after_all: invalid right delimiting key"); */ if (comp_keys (&left->ih_key, B_N_PKEY (g_right, 0)) != -1/*SECOND_GREATER*/) die ("compare_neighboring_leaves_after_all: left key is greater than the right one"); if (//comp_le_keys (B_PRIGHT_DELIM_KEY (g_left), g_dkey) != KEYS_IDENTICAL || comp_keys (g_dkey, B_N_PKEY (g_right, 0))) { reiserfs_panic (0, "compare_neighboring_leaves_after all: invalid delimiting keys from left to right (%k %k)", g_dkey, B_N_PKEY (g_right, 0)); } if (!not_of_one_file (&left->ih_key, &right->ih_key)) { // items of one file: check offset correctness if (is_direct_ih (left) || is_indirect_ih (left)) //if (get_offset(&right->ih_key) != get_offset(&left->ih_key) + get_bytes_number (g_left, left /*B_NR_ITEMS (g_left) - 1*/, 0, CHECK_FREE_BYTES)) if (get_offset(&right->ih_key) != get_offset(&left->ih_key) + get_bytes_number (left, g_left->b_size)) die ("compare_neighboring_leaves_after all: hole between items or items are overlapped"); } is_there_unaccessed_items (g_left); } typedef void (check_function_t)(void); /* only directory item can be fatally bad */ static int is_leaf_bad_xx (struct buffer_head * bh) { int i; struct item_head * ih; if (!is_leaf_node (bh)) return 0; for (i = 0, ih = B_N_PITEM_HEAD (bh, 0); i < B_NR_ITEMS (bh); i ++, ih ++) if (is_bad_item (bh, ih, B_I_PITEM (bh, ih))) { return 1; } return 0; } static void reiserfsck_check_tree (int dev, unsigned long block, int size, check_function_t comp_func) { struct buffer_head * bh; int what_node; bh = bread (dev, block, size); if (bh == 0) reiserfs_panic("reiserfsck_check_tree: unable to read %lu block on device 0x%x\n", block, dev); if (!B_IS_IN_TREE (bh)) { reiserfs_panic (0, "reiserfsck_check_tree: buffer (%b %z) not in tree", bh, bh); } what_node = who_is_this (bh->b_data, bh->b_size); if (what_node != THE_LEAF && what_node != THE_INTERNAL) die ("Not formatted node"); if (!is_block_used (bh->b_blocknr)) die ("Not marked as used"); if (is_leaf_node (bh) && is_leaf_bad_xx (bh)) die ("Bad leaf %lu", bh->b_blocknr); if (is_internal_node(bh) && is_internal_bad (bh)) die ("bad internal"); if (is_internal_node (bh)) { int i; struct disk_child * dc; dc = B_N_CHILD (bh, 0); for (i = 0; i <= B_NR_ITEMS (bh); i ++, dc ++) { reiserfsck_check_tree (dev, get_dc_child_blocknr (dc), size, comp_func); g_dkey = B_N_PDELIM_KEY (bh, i); } } else if (is_leaf_node (bh)) { g_right = bh; if (g_left != 0 && g_dkey != 0) { comp_func (); brelse (g_left); } g_left = g_right; return; } else { reiserfs_panic ("reiserfsck_check_tree: block %lu has bad block type (%b)", bh->b_blocknr, bh); } brelse (bh); } static void reiserfsck_check_cached_tree (int dev, unsigned long block, int size) { struct buffer_head * bh; int what_node; bh = find_buffer(dev, block, size); if (bh == 0) return; if (!buffer_uptodate (bh)) { die ("reiserfsck_check_cached_tree: found notuptodate buffer"); } bh->b_count ++; if (!B_IS_IN_TREE (bh)) { reiserfs_panic ("reiserfsck_check_cached_tree: buffer (%b %z) not in tree", bh, bh); } what_node = who_is_this (bh->b_data, bh->b_size); if ((what_node != THE_LEAF && what_node != THE_INTERNAL) || !is_block_used (bh->b_blocknr) || (is_leaf_node (bh) && is_leaf_bad (bh)) || (is_internal_node(bh) && is_internal_bad (bh))) die ("reiserfsck_check_cached_tree: bad node in the tree"); if (is_internal_node (bh)) { int i; struct disk_child * dc; dc = B_N_CHILD (bh, 0); for (i = 0; i <= B_NR_ITEMS (bh); i ++, dc ++) { reiserfsck_check_cached_tree (dev, get_dc_child_blocknr (dc), size); g_dkey = B_N_PDELIM_KEY (bh, i); } } else if (is_leaf_node (bh)) { brelse (bh); return; } else { reiserfs_panic ("reiserfsck_check_cached_tree: block %lu has bad block type (%b)", bh->b_blocknr, bh); } brelse (bh); } void reiserfsck_tree_check (check_function_t how_to_compare_neighbors) { g_left = 0; g_dkey = 0; reiserfsck_check_tree (fs->fs_dev, get_sb_root_block (fs->fs_ondisk_sb), fs->fs_blocksize, how_to_compare_neighbors); brelse (g_right); } void reiserfsck_check_pass1 () { /* if (opt_check == 1)*/ reiserfsck_tree_check (compare_neighboring_leaves_in_pass1); } void check_cached_tree () { reiserfsck_check_cached_tree (fs->fs_dev, get_sb_root_block (fs->fs_ondisk_sb), fs->fs_blocksize); } void reiserfsck_check_after_all () { reiserfsck_tree_check (compare_neighboring_leaves_after_all); } #if 0 static int is_bad_sd (struct item_head * ih, char * item) { struct stat_data * sd = (struct stat_data *)item; if (!S_ISDIR (sd->sd_mode) && !S_ISREG(sd->sd_mode) && !S_ISCHR (sd->sd_mode) && !S_ISBLK(sd->sd_mode) && !S_ISLNK (sd->sd_mode) && !S_ISFIFO(sd->sd_mode) && !S_ISSOCK(sd->sd_mode)) { fsck_log ("file %k unexpected mode encountered 0%o\n", &ih->ih_key, sd->sd_mode); } return 0; } #endif #include #include unsigned long blocks_on_device (int dev, int blocksize) { unsigned long size; if (ioctl (dev, BLKGETSIZE, &size) >= 0) { return size / (blocksize / 512); } if (ioctl (dev, BLKGETSIZE, &size) >= 0) { return size / (blocksize / 512); } else { struct stat stat_buf; memset(&stat_buf, '\0', sizeof(struct stat)); if(fstat(dev, &stat_buf) >= 0) { return stat_buf.st_size / (blocksize / 512); } else { die ("can not calculate device size\n"); } } return 0; } int is_internal_bad (struct buffer_head * bh) { struct key * key; int i; if (!is_internal_node(bh)) return 0; for (i = 0; i < B_NR_ITEMS (bh); i ++) { key = B_N_PDELIM_KEY (bh, i); if (!KEY_IS_STAT_DATA_KEY (key) && !KEY_IS_DIRECTORY_KEY (key) && !KEY_IS_DIRECT_KEY (key) && !KEY_IS_INDIRECT_KEY (key)) /* key of unknown item */ return 1; } return 0; }