/* * Copyright 1996-2004 by Hans Reiser, licensing governed by * reiserfsprogs/README */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "fsck.h" #include "misc/malloc.h" #include "misc/unaligned.h" #include "util/misc.h" #include "util/device.h" #include #include #include #include /* * Pass0 scans the used part of the partition. It creates two maps which will * be used on the pass 1. These are a map of nodes looking like leaves and * a map of "bad" unformatted nodes. After pass 0 we can detect unformatted * node pointers pointing to leaves. */ /* leaves */ reiserfs_bitmap_t * leaves_bitmap; #define pass0_block_mkleaf(block) \ reiserfs_bitmap_set_bit(leaves_bitmap, block) int pass0_block_isleaf(unsigned long block) { return reiserfs_bitmap_test_bit(leaves_bitmap, block); } void pass0_block_clleaf(unsigned long block) { reiserfs_bitmap_clear_bit(leaves_bitmap, block); } /* nodes which are referred to from only one extent item */ reiserfs_bitmap_t * good_unfm_bitmap; #define pass0_block_mkgood_unfm(block) \ reiserfs_bitmap_set_bit(good_unfm_bitmap, block) #define pass0_block_clgood_unfm(block) \ reiserfs_bitmap_clear_bit(good_unfm_bitmap, block) int pass0_block_isgood_unfm(unsigned long block) { return reiserfs_bitmap_test_bit(good_unfm_bitmap, block); } /* nodes which are referred to from more than one extent item */ reiserfs_bitmap_t * bad_unfm_bitmap; #define pass0_block_mkbad_unfm(block) \ reiserfs_bitmap_set_bit(bad_unfm_bitmap, block) #define pass0_block_clbad_unfm(block) \ reiserfs_bitmap_clear_bit(bad_unfm_bitmap, block) int pass0_block_isbad_unfm(unsigned long block) { return reiserfs_bitmap_test_bit(bad_unfm_bitmap, block); } static int correct_direct_item_offset (reiserfs_ih_t *ih, reiserfs_filsys_t *fs) { __u64 offset; __u64 len; int format; offset = reiserfs_key_get_off (&ih->ih_key); format = reiserfs_key_format (&ih->ih_key); if (offset == 0) return 0; if (format == KEY_FORMAT_2) { if ((offset - 1) % 8 != 0) return 0; } len = reiserfs_ih_get_len(ih) + offset - 1; offset = MISC_DOWN(offset - 1, fs->fs_blocksize); if (reiserfs_policy_ext (len, len - offset, fs->fs_blocksize)) return 0; return 1; } /* bitmaps which are built on pass 0 and are used on pass 1 */ static void fsck_pass0_aux_prep (reiserfs_filsys_t * fs) { reiserfs_sb_t * sb; sb = fs->fs_ondisk_sb; /* bitmap of leaves found on the device */ leaves_bitmap = reiserfs_bitmap_create (reiserfs_sb_get_blocks (sb)); good_unfm_bitmap = reiserfs_bitmap_create (reiserfs_sb_get_blocks (sb)); bad_unfm_bitmap = reiserfs_bitmap_create (reiserfs_sb_get_blocks (sb)); } void fsck_pass0_aux_fini (void) { reiserfs_bitmap_delete (leaves_bitmap); reiserfs_bitmap_delete (good_unfm_bitmap); reiserfs_bitmap_delete (bad_unfm_bitmap); } /* register block some extent item points to */ static void register_unfm (unsigned long block) { if (!pass0_block_isgood_unfm (block) && !pass0_block_isbad_unfm (block)) { /* this block was not pointed by other extent items yet */ pass0_block_mkgood_unfm (block); return; } if (pass0_block_isgood_unfm (block)) { /* block was pointed once already, unmark it in bitmap of good unformatted nodes and mark in bitmap of bad pointers */ pass0_block_clgood_unfm (block); pass0_block_mkbad_unfm (block); return; } assert (pass0_block_isbad_unfm (block)); } /* 'upper' item is correct if 'upper + 2' exists and its key is greater than key of 'upper' */ static int upper_correct (reiserfs_bh_t * bh, reiserfs_ih_t * upper, int upper_item_num) { if (upper_item_num + 2 < reiserfs_node_items (bh)) { if (reiserfs_key_comp (&upper->ih_key, &(upper + 2)->ih_key) != -1) /* item-num's item is out of order of order */ return 0; return 1; } /* there is no item above the "bad pair" */ return 2; } /* 'lower' item is correct if 'lower - 2' exists and its key is smaller than key of 'lower' */ static int lower_correct (reiserfs_bh_t * bh, reiserfs_ih_t * lower, int lower_item_num) { if (lower_item_num - 2 >= 0) { if (reiserfs_key_comp (&(lower - 2)->ih_key, &lower->ih_key) != -1) return 0; return 1; } return 2; } /* return 1 if something was changed */ static int correct_key_format (reiserfs_ih_t * ih, int symlink) { int dirty = 0; if (reiserfs_ih_stat (ih)) { /* for stat data we have no way to check whether key format in item head matches to the key format found from the key directly */ if (reiserfs_ih_get_len (ih) == REISERFS_SD_SIZE_V1) { if (reiserfs_ih_get_format (ih) != KEY_FORMAT_1) { /*fsck_log ("correct_key_format: ih key format of (%H) is " "set to format 1\n", ih);*/ reiserfs_ih_set_format (ih, KEY_FORMAT_1); return 1; } return 0; } if (reiserfs_ih_get_len (ih) == REISERFS_SD_SIZE) { if (reiserfs_ih_get_format (ih) != KEY_FORMAT_2) { /*fsck_log ("correct_key_format: ih key format of (%H) " "is set to format 2\n", ih);*/ reiserfs_ih_set_format (ih, KEY_FORMAT_2); return 1; } return 0; } misc_die ("stat_data item of the wrong length"); } if (symlink && (reiserfs_key_format(&ih->ih_key) != KEY_FORMAT_1)) { /* All symlinks are of 3.5 format */ /*fsck_log ("correct_key_format: Symlink keys should be of 3.5 " "format. %k - fixed.\n", &ih->ih_key); */ reiserfs_key_set_sec(KEY_FORMAT_1, &ih->ih_key, reiserfs_key_get_off(&ih->ih_key), reiserfs_key_get_type(&ih->ih_key)); } if (reiserfs_key_format (&ih->ih_key) != reiserfs_ih_get_format (ih)) { /*fsck_log ("correct_key_format: ih key format of (%H) is " "set to format found in the key\n", ih);*/ reiserfs_ih_set_format (ih, reiserfs_key_format (&ih->ih_key)); dirty = 1; } return dirty; } static void hash_hits_init (reiserfs_filsys_t * fs) { fsck_data (fs)->rebuild.hash_amount = REISERFS_HASH_LAST; fsck_data (fs)->rebuild.hash_hits = misc_getmem (sizeof (unsigned long) * fsck_data (fs)->rebuild.hash_amount); } static void add_hash_hit (reiserfs_filsys_t * fs, int hash_code) { fsck_data (fs)->rebuild.hash_hits [hash_code] ++; } /* deh_location look reasonable, try to find name length. return 0 if we failed */ static int try_to_get_name_length (reiserfs_ih_t * ih, reiserfs_deh_t * deh, int i) { int len; if (i == 0 || !reiserfs_deh_locbad (deh - 1)) { len = reiserfs_direntry_name_len (ih, deh, i); return (len > 0) ? len : 0; } /* previous entry had bad location so we had no way to find name length */ return 0; } /* define this if you are using -t to debug recovering of corrupted directory item */ #define DEBUG_VERIFY_DENTRY #undef DEBUG_VERIFY_DENTRY /* check directory item and try to recover something */ static int verify_directory_item (reiserfs_filsys_t * fs, reiserfs_bh_t * bh, int item_num) { reiserfs_ih_t * ih; reiserfs_ih_t tmp; char * item; reiserfs_deh_t * deh; char * name; int name_len; int bad, lost_found; int i, j; int dirty; int hash_code; int bad_locations; int min_entry_size = 1; #ifdef DEBUG_VERIFY_DENTRY char * direntries; #endif ih = reiserfs_ih_at (bh, item_num); item = reiserfs_item_by_ih (bh,ih); deh = (reiserfs_deh_t *)item; dirty = 0; bad_locations = 0; if ( (reiserfs_ih_get_entries (ih) > (reiserfs_ih_get_len(ih) / (REISERFS_DEH_SIZE + min_entry_size))) || (reiserfs_ih_get_entries (ih) == 0)) { reiserfs_ih_set_entries (ih, (int)reiserfs_ih_get_len(ih) / (REISERFS_DEH_SIZE + min_entry_size)); reiserfs_buffer_mkdirty (bh); } if (reiserfs_ih_get_entries (ih) == 0) { reiserfs_leaf_delete_item (fs, bh, item_num); return -1; } /* check deh_location */ for (i = 0; i < reiserfs_ih_get_entries (ih); i ++) { /* silently fix deh_state */ if (reiserfs_deh_get_state (deh + i) != (1 << DEH_Visible2)) { reiserfs_deh_set_state (deh + i, (1 << DEH_Visible2)); reiserfs_buffer_mkdirty (bh); } if (reiserfs_direntry_loc_check (deh + i, ih, !i)) reiserfs_deh_set_locbad (deh + i); } #ifdef DEBUG_VERIFY_DENTRY direntries = misc_getmem (ih_entry_count (ih) * sizeof (int)); printf ("Entries with bad locations within the directory: "); for (i = 0; i < ih_entry_count (ih); i ++) { if (reiserfs_deh_locbad (deh + i)) printf ("%d ", i); } printf ("\n"); #endif /* DEBUG_VERIFY_DENTRY */ /* find entries names in which have mismatching deh_offset */ for (i = reiserfs_ih_get_entries (ih) - 1; i >= 0; i --) { if (reiserfs_deh_bad (deh + i)) /* bad location */ continue; if (i) { if (reiserfs_deh_get_loc (deh + i - 1) < reiserfs_deh_get_loc (deh + i)) { reiserfs_deh_set_locbad (deh + i - 1); } } name = reiserfs_deh_name (deh + i, i); /* Although we found a name, we not always can get its length as it depends on deh_location of previous entry. */ name_len = try_to_get_name_length (ih, deh + i, i); #ifdef DEBUG_VERIFY_DENTRY if (name_len == 0) printf ("Trying to find the name length for %d-th entry\n", i); #endif /* DEBUG_VERIFY_DENTRY */ if (is_dot (name, name_len)) { if (i != 0) fsck_log ("block %lu: item %d: \".\" must be the first entry, " "but it is the %d-th entry\n", bh->b_blocknr, item_num, i); /* check and fix "." */ if (reiserfs_deh_get_off (deh + i) != OFFSET_DOT) { reiserfs_deh_set_off (deh + i, OFFSET_DOT); reiserfs_buffer_mkdirty (bh); } /* "." must point to the directory it is in */ /* if (reiserfs_key_comp2 (&(deh[i].deh2_dir_id), &(ih->ih_key))) { fsck_log ("verify_direntry: block %lu, item %H has entry \".\" " "pointing to (%K) instead of (%K)\n", bh->b_blocknr, ih, &(deh[i].deh2_dir_id), &(ih->ih_key)); reiserfs_deh_set_did (deh + i, reiserfs_key_get_did (&ih->ih_key)); reiserfs_deh_set_obid (deh + i, reiserfs_key_get_oid (&ih->ih_key)); reiserfs_buffer_mkdirty (bh); } */ } else if (is_dot_dot (name, name_len)) { if (i != 1) fsck_log ("block %lu: item %d: \"..\" is %d-th entry\n", bh->b_blocknr, item_num, i); /* check and fix ".." */ if (reiserfs_deh_get_off (deh + i) != OFFSET_DOT_DOT) { reiserfs_deh_set_off (deh + i, OFFSET_DOT_DOT); reiserfs_buffer_mkdirty (bh); } } else { int min_length, max_length; /* check other name */ if (name_len == 0) { /* we do not know the length of name - we will try to find it */ min_length = 1; max_length = item + reiserfs_ih_get_len (ih) - name; } else /* we kow name length, so we will try only one name length */ min_length = max_length = name_len; hash_code = 0; for (j = min_length; j <= max_length; j ++) { hash_code = reiserfs_hash_find (name, j, reiserfs_deh_get_off(deh + i), reiserfs_sb_get_hash(fs->fs_ondisk_sb)); /* add_hash_hit (fs, hash_code);*/ if (reiserfs_hash_func (hash_code) != 0) { /* deh_offset matches to some hash of the name */ if (fsck_hash_defined (fs) && hash_code != reiserfs_hash_code (fs->hash)) { /* wrong hash selected - so we can skip this leaf */ return 1; } if (!name_len) { fsck_log ("%s: block %lu, item %H: Found a name " "\"%.*s\" for %d-th entry matching to the " "hash %u.\n", __FUNCTION__, bh->b_blocknr, ih, j, name, i, reiserfs_deh_get_off (deh + i)); /* FIXME: if next byte is 0 we think that the name is aligned to 8 byte boundary */ if (i) { reiserfs_deh_set_loc (&deh[i - 1], reiserfs_deh_get_loc (deh + i) + ((name[j] || fs->fs_format == REISERFS_FORMAT_3_5) ? j : MISC_ROUND_UP (j))); reiserfs_deh_set_locok (deh + i - 1); reiserfs_buffer_mkdirty (bh); } } break; } } add_hash_hit (fs, hash_code); if (j == max_length + 1) { /* deh_offset does not match to anything. it will be deleted for now, but maybe we could just fix a deh_offset if it is in ordeer */ reiserfs_deh_set_offbad (deh + i); } } } /* for */ #ifdef DEBUG_VERIFY_DENTRY printf ("Entries with mismatching hash: "); for (i = 0; i < ih_entry_count (ih); i ++) { if (reiserfs_deh_offbad (deh + i)) printf ("%d ", i); } printf ("\n"); #endif /* DEBUG_VERIFY_DENTRY */ /* correct deh_locations such that code cutting entries will not get screwed up */ { int prev_loc; int loc_fixed; prev_loc = reiserfs_ih_get_len (ih); for (i = 0; i < reiserfs_ih_get_entries (ih); i ++) { loc_fixed = 0; if (reiserfs_deh_locbad (deh + i)) { reiserfs_deh_set_loc (deh + i, prev_loc/* - 1*/); reiserfs_buffer_mkdirty (bh); loc_fixed = 1; } else { if (reiserfs_deh_get_loc (deh + i) >= prev_loc) { reiserfs_deh_set_loc (deh + i, prev_loc/* - 1*/); reiserfs_buffer_mkdirty (bh); loc_fixed = 1; } } prev_loc = reiserfs_deh_get_loc (deh + i); if (i == reiserfs_ih_get_entries (ih) - 1) { /* last entry starts right after an array of direntry headers */ if (!reiserfs_deh_bad (deh + i) && reiserfs_deh_get_loc (deh + i) != (REISERFS_DEH_SIZE * reiserfs_ih_get_entries (ih))) { /* free space in the directory item */ fsck_log ("%s: block %lu, item %H: Directory item has a " "free space - deleting\n", __FUNCTION__, bh->b_blocknr, ih); reiserfs_leaf_delete_entry (fs, bh, item_num, reiserfs_ih_get_entries (ih), 0); } if (reiserfs_deh_get_loc (deh + i) != (REISERFS_DEH_SIZE * reiserfs_ih_get_entries (ih))) { reiserfs_deh_set_loc (&deh[i], (REISERFS_DEH_SIZE * reiserfs_ih_get_entries (ih))); loc_fixed = 1; reiserfs_buffer_mkdirty (bh); } } #ifdef DEBUG_VERIFY_DENTRY if (loc_fixed) direntries [i] = 1; #endif } /* for */ #ifdef DEBUG_VERIFY_DENTRY printf ("Entries with fixed deh_locations: "); for (i = 0; i < ih_entry_count (ih); i ++) { if (direntries [i]) printf ("%d ", i); } printf ("\n"); #endif /* DEBUG_VERIFY_DENTRY */ } #ifdef DEBUG_VERIFY_DENTRY printf (" N location name\n"); for (i = 0; i < ih_entry_count (ih); i ++) { if (reiserfs_deh_bad (deh + i) || (i && reiserfs_deh_bad (deh + i - 1)) || /* previous entry marked bad */ (i < ih_entry_count (ih) - 1 && reiserfs_deh_bad (deh + i + 1))) { /* next entry is marked bad */ /* print only entries to be deleted and their nearest neighbors */ printf ("%3d: %8d ", i, deh_location (deh + i)); if (reiserfs_deh_bad (deh + i)) printf ("will be deleted\n"); else printf ("\"%.*s\"\n", reiserfs_direntry_name_len (ih, deh + i, i), reiserfs_deh_name (deh + i, i)); } } #endif bad = lost_found = 0; tmp = *ih; /* mark enries of /lost+found as bad */ deh = reiserfs_deh (bh, ih); for (i = 0; i < reiserfs_ih_get_entries (ih); i ++, deh ++) { unsigned int dirid, objectid; char buf[REISERFS_NAME_MAX]; if (reiserfs_deh_bad (deh)) continue; buf[0] = '\0'; sprintf (buf, "%.*s", reiserfs_direntry_name_len (ih, deh, i), reiserfs_deh_name (deh, i)); if (sscanf (buf, "%d_%d", &dirid, &objectid) != 2) continue; if (reiserfs_deh_get_did (deh) != dirid || reiserfs_deh_get_obid (deh) != objectid) continue; /* entry in lost+found */ // printf ("%s - will be deleted\n", buf); lost_found++; reiserfs_deh_set_offbad (deh); } /* delete entries which are marked bad */ for (i = 0; i < reiserfs_ih_get_entries (ih); i ++) { deh = reiserfs_deh (bh, ih) + i; if (reiserfs_deh_bad (deh)) { bad ++; if (reiserfs_ih_get_entries (ih) == 1) { reiserfs_leaf_delete_item (fs, bh, item_num); fsck_log ("%s: block %lu, item %H: All entries were deleted from " "the directory\n", __FUNCTION__, bh->b_blocknr, &tmp); return -1; } else { reiserfs_leaf_delete_entry (fs, bh, item_num, i, 1); } i --; } } deh = reiserfs_deh (bh, ih); if (reiserfs_key_get_off (&ih->ih_key) != reiserfs_deh_get_off (deh)) { fsck_log ("verify_direntry: block %lu, item %H: Key's offset %k must " "match the directory's hash (%u) - changed.\n", bh->b_blocknr, ih, &ih->ih_key, reiserfs_deh_get_off (deh)); reiserfs_key_set_off (reiserfs_key_format (&ih->ih_key), &ih->ih_key, reiserfs_deh_get_off (deh)); reiserfs_buffer_mkdirty (bh); } if (bad > lost_found) fsck_log ("pass0: block %lu, item %H: %d entries were deleted\n", bh->b_blocknr, &tmp, bad - lost_found); return 0; } static __inline__ int does_it_fit_into_dev (__u64 offset, __u64 fs_size) { /* Count of unformatted pointers : offset / blocksize Count of blocks to store them : REISERFS_EXT_SIZE * offset / blocksize / REISERFS_ITEM_MAX Size to store it : blocksize * REISERFS_EXT_SIZE * offset / blocksize / REISERFS_ITEM_MAX */ return ( REISERFS_EXT_SIZE * offset / REISERFS_ITEM_MAX(fs->fs_blocksize) < fs_size) ? 1 : 0; } static int is_wrong_short_key (reiserfs_key_t * key) { if (reiserfs_key_get_did (key) == 0 || reiserfs_key_get_oid (key) == 0 || reiserfs_key_get_oid (key) == 1 || reiserfs_key_get_did (key) == ~(__u32)0 || reiserfs_key_get_oid (key) == ~(__u32)0 || reiserfs_key_get_did (key) == reiserfs_key_get_oid (key) || /* the alloc=packing_groups used to allow dirid = 1 (reiserfs_key_get_did (key) == 1 && reiserfs_key_get_oid (key) != 2) || */ (reiserfs_key_get_did (key) != 1 && reiserfs_key_get_oid (key) == 2) ) { return 1; } return 0; } /* do this on pass 0 with every leaf marked used */ /* FIXME: we can improve fixing of broken keys: we can ssfe direct items which go after stat data and have broken keys */ static void pass0_correct_leaf (reiserfs_filsys_t * fs, reiserfs_bh_t * bh) { int file_format = KEY_FORMAT_UNDEFINED; reiserfs_ih_t * ih; __u32 * ind_item; __u64 fs_size; __u64 offset; int symlnk = 0; int bad_order; unsigned long unfm_ptr; // unsigned int nr_items; int i, j, nr_items; int dirty = 0; fsck_leaf_check_header(fs, bh); /* Delete all safe links. */ for (i = reiserfs_nh_get_items (NODE_HEAD (bh)) - 1; i >= 0; i--) { if (reiserfs_key_get_did (&reiserfs_ih_at (bh, i)->ih_key) == ~(__u32)0) { reiserfs_leaf_delete_item (fs, bh, i); pass_0_stat(fs)->removed++; } if (reiserfs_key_get_did (&reiserfs_ih_at (bh, i)->ih_key) == REISERFS_BAD_DID && reiserfs_key_get_oid (&reiserfs_ih_at (bh, i)->ih_key) == REISERFS_BAD_OID) { reiserfs_leaf_delete_item (fs, bh, i); pass_0_stat(fs)->removed++; } } fs_size = (__u64)fs->fs_blocksize * reiserfs_sb_get_blocks (fs->fs_ondisk_sb); start_again: ih = reiserfs_ih_at (bh, 0); bad_order = 0; nr_items = reiserfs_nh_get_items (NODE_HEAD (bh)); for (i = 0; i < nr_items; i ++, ih ++) { if (reiserfs_ih_ext(ih) && (reiserfs_ih_get_len (ih) % 4 != 0)) { reiserfs_key_set_type(reiserfs_ih_get_format(ih), &ih->ih_key, TYPE_UNKNOWN); dirty = 1; } if (reiserfs_key_unkn (&ih->ih_key)) { if ((reiserfs_ih_get_len (ih) == REISERFS_SD_SIZE) || (reiserfs_ih_get_len (ih) == REISERFS_SD_SIZE_V1)) { reiserfs_key_set_sec (KEY_FORMAT_1, &ih->ih_key, OFFSET_SD, TYPE_STAT_DATA); dirty = 1; fsck_log("pass0: vpf-10100: block %lu, item (%d): Unknown item " "type of StatData size, type set to StatData %k\n", bh->b_blocknr, i, &ih->ih_key); } else { fsck_log("pass0: vpf-10110: block %lu, item (%d): Unknown item " "type found %k - deleted\n", bh->b_blocknr, i, &ih->ih_key); reiserfs_leaf_delete_item (fs, bh, i); pass_0_stat(fs)->removed++; goto start_again; } } if (is_wrong_short_key (&ih->ih_key)) { /* sometimes stat datas get k_objectid==0 or k_dir_id==0 */ /* if (i == (nr_items - 1)) { if (i == 0) { fsck_log ("block %lu: item %d: (%H) id equals 0\n", bh->b_blocknr, i, ih); return; } // delete last item fsck_log ("block %lu: item %d: (%H) id equals 0\n", bh->b_blocknr, i, ih); reiserfs_leaf_delete_item (fs, bh, i - 1); pass_0_stat(fs)->removed++; return; } */ /* FIXME: 18842 19034 0x1 EXT (2) 19035 19035 0x0 SD (0) 18842 1 0x1 EXT (1) 18842 1 0x1001 DRCT (2) */ /* there is next item: if it is not stat data - take its k_dir_id and k_objectid. if key order will be still wrong - the changed item will be deleted */ if (i && !reiserfs_ih_stat (ih)) { /* previous item has a wrong short_key */ fsck_log ("pass0: vpf-10120: block %lu: item %d: Wrong key %k, " "corrected to ", bh->b_blocknr, i, &ih->ih_key); reiserfs_key_set_did (&ih->ih_key, reiserfs_key_get_did (&(ih - 1)->ih_key)); reiserfs_key_set_oid (&ih->ih_key, reiserfs_key_get_oid (&(ih - 1)->ih_key)); fsck_log ("%k\n", &ih->ih_key); dirty = 1; } else if ((i < nr_items - 1) && !reiserfs_ih_stat (ih + 1)) { if (!is_wrong_short_key(&(ih + 1)->ih_key)) { fsck_log ("pass0: vpf-10130: block %lu: item %d: Wrong " "key %k, corrected to ", bh->b_blocknr, i, &ih->ih_key); reiserfs_key_set_did (&ih->ih_key, reiserfs_key_get_did (&(ih + 1)->ih_key)); reiserfs_key_set_oid (&ih->ih_key, reiserfs_key_get_oid (&(ih + 1)->ih_key)); /* reiserfs_key_set_off (KEY_FORMAT_1, &ih->ih_key, 0); reiserfs_key_set_type (KEY_FORMAT_1, &ih->ih_key, TYPE_STAT_DATA);*/ fsck_log ("%k\n", &ih->ih_key); dirty = 1; goto start_again; } else { fsck_log ("pass0: vpf-10140: block %lu: items %d and %d " "have bad short keys %k, %k, both deleted\n", bh->b_blocknr, i, i+1, &ih->ih_key, &(ih + 1)->ih_key); reiserfs_leaf_delete_item (fs, bh, i); reiserfs_leaf_delete_item (fs, bh, i); pass_0_stat(fs)->removed += 2; goto start_again; } } else { fsck_log ("pass0: vpf-10150: block %lu: item %d: Wrong key " "%k, deleted\n", bh->b_blocknr, i, &ih->ih_key); reiserfs_leaf_delete_item (fs, bh, i); pass_0_stat(fs)->removed++; goto start_again; } } #if 0 if (i && i + 1 < nr_items) { if (reiserfs_ih_stat (ih - 1) && !reiserfs_ih_stat (ih) && !reiserfs_ih_direct (ih + 1) && !reiserfs_ih_stat (ih + 1)) { /* i or i+1 item should be SD or i+1 should be direct item */ if ((reiserfs_ih_get_len (ih) == REISERFS_SD_SIZE) || (reiserfs_ih_get_len (ih) == REISERFS_SD_SIZE_V1)) { /* make i as SD */ fsck_log("pass0: vpf-10400: block %lu, item %d: Wrong " "order of items - change the type of the key %k " "to StatData\n", bh->b_blocknr, i, &ih->ih_key); reiserfs_key_set_sec (KEY_FORMAT_1, &ih->ih_key, OFFSET_SD, TYPE_STAT_DATA); dirty = 1; } else if ((reiserfs_ih_get_len (ih+1) == REISERFS_SD_SIZE) || (reiserfs_ih_get_len (ih+1) == REISERFS_SD_SIZE_V1)) { /* make i+1 as SD */ fsck_log("pass0: vpf-10410: block %lu, item %d: Wrong " "order of items - change the type of the key %k " "to StatData\n", bh->b_blocknr, i + 1, &(ih + 1)->ih_key); reiserfs_key_set_sec (KEY_FORMAT_1, &(ih + 1)->ih_key, OFFSET_SD, TYPE_STAT_DATA); dirty = 1; } else if (reiserfs_ih_ext(ih)) { fsck_log("pass0: vpf-10420: block %lu, item %d: Wrong " "order of items - change the type of the key %k " "to Direct\n", bh->b_blocknr, i+1, &(ih + 1)->ih_key); reiserfs_key_set_type (reiserfs_ih_get_format(ih+1), &(ih + 1)->ih_key, TYPE_DIRECT); dirty = 1; } } } #endif if (i && ((reiserfs_ih_stat (ih - 1) && !reiserfs_ih_stat (ih) && (reiserfs_key_get_did (&(ih - 1)->ih_key) != reiserfs_key_get_did (&ih->ih_key))) || (reiserfs_ih_stat (ih) && (reiserfs_key_get_did (&(ih - 1)->ih_key) > reiserfs_key_get_did (&ih->ih_key))))) { /* not the same dir_id of the same file or not increasing dir_id of different files */ if ((i > 1) && reiserfs_key_get_did (&(ih - 2)->ih_key) == reiserfs_key_get_did (&(ih - 1)->ih_key)) { /* fix i-th */ if (!reiserfs_ih_stat (ih)) { fsck_log("pass0: vpf-10430: block %lu, item %d: Wrong " "order of items - change the dir_id of the key " "%k to %lu\n", bh->b_blocknr, i, &ih->ih_key, reiserfs_key_get_did (&(ih - 1)->ih_key)); reiserfs_key_set_did (&ih->ih_key, reiserfs_key_get_did (&(ih - 1)->ih_key)); dirty = 1; } else if (i + 1 < nr_items) { fsck_log("pass0: vpf-10440: block %lu, item %d: Wrong " "order of items - change the dir_id of the key " "%k to %lu\n", bh->b_blocknr, i, &ih->ih_key, reiserfs_key_get_did (&(ih + 1)->ih_key)); reiserfs_key_set_did (&ih->ih_key, reiserfs_key_get_did (&(ih + 1)->ih_key)); dirty = 1; } } else if ((i + 1 < nr_items) && reiserfs_key_get_did (&ih->ih_key) == reiserfs_key_get_did (&(ih + 1)->ih_key)) { fsck_log("pass0: vpf-10450: block %lu, item %d: Wrong order of " "items - change the dir_id of the key %k to %lu\n", bh->b_blocknr, i - 1, &(ih - 1)->ih_key, reiserfs_key_get_did (&ih->ih_key)); /* fix (i - 1)-th */ reiserfs_key_set_did (&(ih - 1)->ih_key, reiserfs_key_get_did (&ih->ih_key)); dirty = 1; } } if (i && i + 1 < nr_items) { /* there is a previous and a next items */ if ((reiserfs_key_get_did (&(ih - 1)->ih_key) == reiserfs_key_get_did (&(ih + 1)->ih_key)) && (reiserfs_key_get_did (&(ih - 1)->ih_key) != reiserfs_key_get_did (&ih->ih_key))) { fsck_log("pass0: vpf-10460: block %lu, item %d: Wrong order of " "items - change the dir_id of the key %k to %lu\n", bh->b_blocknr, i, &ih->ih_key, reiserfs_key_get_did (&(ih - 1)->ih_key)); reiserfs_key_set_did (&ih->ih_key, reiserfs_key_get_did (&(ih - 1)->ih_key)); dirty = 1; } if ((reiserfs_key_get_oid (&(ih - 1)->ih_key) == reiserfs_key_get_oid (&(ih + 1)->ih_key)) && (reiserfs_key_get_oid (&(ih - 1)->ih_key) != reiserfs_key_get_oid (&ih->ih_key))) { fsck_log("pass0: vpf-10470: block %lu, item %d: Wrong " "order of items - change the object_id of the " "key %k to %lu\n", bh->b_blocknr, i, &ih->ih_key, reiserfs_key_get_oid (&(ih - 1)->ih_key)); reiserfs_key_set_oid (&ih->ih_key, reiserfs_key_get_oid (&(ih - 1)->ih_key)); dirty = 1; } if (reiserfs_ih_stat (ih - 1) && (reiserfs_ih_ext (ih) && reiserfs_ih_direct (ih + 1))) { if ((reiserfs_key_get_oid (&(ih - 1)->ih_key) == reiserfs_key_get_oid (&ih->ih_key)) && (reiserfs_key_get_oid (&(ih - 1)->ih_key) != reiserfs_key_get_oid (&(ih + 1)->ih_key))) { fsck_log("pass0: vpf-10480: block %lu, item %d: Wrong " "order of items - change the object_id of the " "key %k to %lu\n", bh->b_blocknr, i + 1, &(ih+1)->ih_key, reiserfs_key_get_oid (&(ih - 1)->ih_key)); reiserfs_key_set_oid (&(ih + 1)->ih_key, reiserfs_key_get_oid (&(ih - 1)->ih_key)); dirty = 1; } if ((reiserfs_key_get_oid (&ih->ih_key) == reiserfs_key_get_oid (&(ih + 1)->ih_key)) && (reiserfs_key_get_oid (&(ih - 1)->ih_key) != reiserfs_key_get_oid (&(ih + 1)->ih_key))) { fsck_log("pass0: vpf-10490: block %lu, item %d: Wrong " "order of items - change the object_id of the " "key %k to %lu\n", bh->b_blocknr, i - 1, &(ih-1)->ih_key, reiserfs_key_get_oid (&(ih + 1)->ih_key)); reiserfs_key_set_oid (&(ih - 1)->ih_key, reiserfs_key_get_oid (&(ih + 1)->ih_key)); dirty = 1; } if ((reiserfs_key_get_did (&(ih - 1)->ih_key) == reiserfs_key_get_did (&ih->ih_key)) && (reiserfs_key_get_did (&(ih - 1)->ih_key) != reiserfs_key_get_did (&(ih + 1)->ih_key))) { fsck_log("pass0: vpf-10500: block %lu, item %d: Wrong " "order of items - change the dir_id of the key " "%k to %lu\n", bh->b_blocknr, i + 1, &(ih+1)->ih_key, reiserfs_key_get_did (&(ih - 1)->ih_key)); reiserfs_key_set_did (&(ih + 1)->ih_key, reiserfs_key_get_did (&(ih - 1)->ih_key)); dirty = 1; } if ((reiserfs_key_get_did (&ih->ih_key) == reiserfs_key_get_did (&(ih + 1)->ih_key)) && (reiserfs_key_get_did (&(ih - 1)->ih_key) != reiserfs_key_get_did (&(ih + 1)->ih_key))) { fsck_log("pass0: vpf-10510: block %lu, item %d: Wrong " "order of items - change the dir_id of the key %k " "to %lu\n", bh->b_blocknr, i - 1, &(ih-1)->ih_key, reiserfs_key_get_did (&(ih + 1)->ih_key)); reiserfs_key_set_did (&(ih - 1)->ih_key, reiserfs_key_get_did (&(ih + 1)->ih_key)); dirty = 1; } } } if (i && reiserfs_ih_stat (ih) && reiserfs_key_get_did (&(ih - 1)->ih_key) == reiserfs_key_get_did (&ih->ih_key) && reiserfs_key_get_oid (&(ih - 1)->ih_key) >= reiserfs_key_get_oid (&ih->ih_key)) { if ((i + 1 < nr_items) && !reiserfs_ih_stat (ih + 1)) { if (reiserfs_key_get_oid (&(ih - 1)->ih_key) < reiserfs_key_get_oid (&(ih + 1)->ih_key)) { fsck_log("pass0: vpf-10520: block %lu, item %d: Wrong " "order of items - change the object_id of the key " "%k to %lu\n", bh->b_blocknr, i - 1, &(ih-1)->ih_key, reiserfs_key_get_oid (&(ih + 1)->ih_key)); reiserfs_key_set_oid (&ih->ih_key, reiserfs_key_get_oid (&(ih + 1)->ih_key)); dirty = 1; } } } if (i && reiserfs_ih_stat (ih - 1) && !reiserfs_ih_stat (ih) && (reiserfs_key_get_oid (&(ih - 1)->ih_key) != reiserfs_key_get_oid (&ih->ih_key))) { int err = 0; if (i > 1) { if (reiserfs_key_comp2 (&(ih - 2)->ih_key, &(ih - 1)->ih_key) != -1) { misc_set_bit (1, &err); } if (reiserfs_key_comp2 (&(ih - 2)->ih_key, &ih->ih_key) != -1) { misc_set_bit (2, &err); } } if (i + 1 < nr_items) { if (reiserfs_key_comp2 (&(ih - 1)->ih_key, &(ih + 1)->ih_key) != -1) { misc_set_bit (3, &err); } if (reiserfs_key_comp2 (&ih->ih_key, &(ih + 1)->ih_key) != -1) { misc_set_bit (4, &err); } } /* if ((test_bit (1, err) || test_bit (3, err)) && (test_bit (2, err) || test_bit (4, err))) { // thera are no problem-free keys, delete them both reiserfs_leaf_delete_item (fs, bh, i - 1); reiserfs_leaf_delete_item (fs, bh, i - 1); pass_0_stat(fs)->removed += 2; goto start_again; } */ if (!misc_test_bit (1, &err) && !misc_test_bit (3, &err) && !misc_test_bit (2, &err) && !misc_test_bit (4, &err)) { if (i <= 1) { /* take bigger */ if (reiserfs_key_comp2 (&(ih - 1)->ih_key, &ih->ih_key) == 1) { fsck_log("pass0: vpf-10530: block %lu, item %d: Wrong " "order of items - change the object_id of the " "key %k to %lu\n", bh->b_blocknr, i, &ih->ih_key, reiserfs_key_get_oid (&(ih - 1)->ih_key)); reiserfs_key_set_oid (&ih->ih_key, reiserfs_key_get_oid (&(ih - 1)->ih_key)); } else { fsck_log("pass0: vpf-10540: block %lu, item %d: Wrong " "order of items - change the object_id of the " "key %k to %lu\n", bh->b_blocknr, i - 1, &(ih - 1)->ih_key, reiserfs_key_get_oid (&ih->ih_key)); reiserfs_key_set_oid (&(ih - 1)->ih_key, reiserfs_key_get_oid (&ih->ih_key)); } } else { /* take smaller */ if (reiserfs_key_comp2 (&(ih - 1)->ih_key, &ih->ih_key) == 1) { fsck_log("pass0: vpf-10550: block %lu, item %d: Wrong " "order of items - change the object_id of the " "key %k to %lu\n", bh->b_blocknr, i - 1, &(ih - 1)->ih_key, reiserfs_key_get_oid (&ih->ih_key)); reiserfs_key_set_oid (&(ih - 1)->ih_key, reiserfs_key_get_oid (&ih->ih_key)); } else { fsck_log("pass0: vpf-10560: block %lu, item %d: Wrong " "order of items - change the object_id of the " "key %k to %lu\n", bh->b_blocknr, i, &ih->ih_key, reiserfs_key_get_oid (&(ih - 1)->ih_key)); reiserfs_key_set_oid (&ih->ih_key, reiserfs_key_get_oid (&(ih - 1)->ih_key)); } } dirty = 1; } else if (!misc_test_bit (1, &err) && !misc_test_bit (3, &err)) { /* take i - 1 */ fsck_log("pass0: vpf-10590: block %lu, item %d: Wrong order " "of items - change the object_id of the key %k to " "%lu\n", bh->b_blocknr, i, &ih->ih_key, reiserfs_key_get_oid (&(ih - 1)->ih_key)); reiserfs_key_set_oid (&ih->ih_key, reiserfs_key_get_oid (&(ih - 1)->ih_key)); dirty = 1; } else if (!misc_test_bit (2, &err) && !misc_test_bit (4, &err)) { /* take i */ fsck_log("pass0: vpf-10600: block %lu, item %d: Wrong order " "of items - change the object_id of the key %k to " "%lu\n", bh->b_blocknr, i - 1, &(ih - 1)->ih_key, reiserfs_key_get_oid (&ih->ih_key)); reiserfs_key_set_oid (&(ih - 1)->ih_key, reiserfs_key_get_oid (&ih->ih_key)); dirty = 1; } } /* this recovers corruptions like the below: 1774 1732 0 0 116262638 1732 1 3 1774 1736 0 0 */ if (i && reiserfs_ih_stat (ih - 1) && !reiserfs_ih_stat (ih)) { if (reiserfs_key_get_oid (&ih->ih_key) != reiserfs_key_get_oid (&(ih - 1)->ih_key) || reiserfs_key_get_did (&ih->ih_key) != reiserfs_key_get_did (&(ih - 1)->ih_key)) { fsck_log ("pass0: vpf-10170: block %lu: item %d: Wrong " "order of items - the item \n\t%H fixed to ", bh->b_blocknr, i, ih); reiserfs_key_set_did (&ih->ih_key, reiserfs_key_get_did (&(ih - 1)->ih_key)); reiserfs_key_set_oid (&ih->ih_key, reiserfs_key_get_oid (&(ih - 1)->ih_key)); dirty = 1; fsck_log ("\n\t%H\n", ih); } #if 0 if (!reiserfs_ih_dir (ih) && reiserfs_key_get_off (&ih->ih_key) != 1) { fsck_log ("pass0: vpf-10170: block %lu: item %d: Wrong " "offset of the item\n\t%H which follows a StatDtat " "item, fixed to 1", bh->b_blocknr, i, ih); if (reiserfs_ih_get_len (ih - 1) == REISERFS_SD_SIZE) { /* stat data is new, therefore this item is new too */ reiserfs_key_set_off (KEY_FORMAT_2, &(ih->ih_key), 1); if ((reiserfs_ih_get_entries (ih) != 0xffff) && (reiserfs_ih_get_len (ih) % 4 == 0)) { reiserfs_key_set_type (KEY_FORMAT_2, &(ih->ih_key), TYPE_EXTENT); } else { reiserfs_key_set_type (KEY_FORMAT_2, &(ih->ih_key), TYPE_DIRECT); } reiserfs_ih_set_format (ih, KEY_FORMAT_2); } else { /* stat data is old, therefore this item is old too */ reiserfs_key_set_off(KEY_FORMAT_1, &(ih->ih_key), 1); if ((reiserfs_ih_get_entries (ih) != 0xffff) && (reiserfs_ih_get_len (ih) % 4 == 0)) { reiserfs_key_set_type (KEY_FORMAT_1, &(ih->ih_key), TYPE_EXTENT); } else { reiserfs_key_set_type (KEY_FORMAT_1, &(ih->ih_key), TYPE_DIRECT); reiserfs_ih_set_free (ih, 0xffff); } reiserfs_ih_set_format (ih, KEY_FORMAT_1); } } #endif } /* FIXME: corruptions like: 56702 66802 1 2 56702 65536 0 0 56702 66803 1 2 do not get recovered (both last items will be deleted) */ /* delete item if it is not in correct order of object items */ if (i && reiserfs_key_comp2 (&ih->ih_key, &(ih - 1)->ih_key) && !reiserfs_ih_stat (ih)) { fsck_log ("pass0: vpf-10180: block %lu: item %d: The item %k, " "which follows non StatData item %k, is deleted\n", bh->b_blocknr, i, &ih->ih_key, &(ih - 1)->ih_key); reiserfs_leaf_delete_item (fs, bh, i); pass_0_stat(fs)->removed++; goto start_again; } if (reiserfs_ih_stat (ih)) { if (reiserfs_key_get_off (&ih->ih_key) != 0) { reiserfs_key_set_off(KEY_FORMAT_1, &ih->ih_key, 0); dirty = 1; } } else if (!reiserfs_ih_dir (ih)) { int format; format = reiserfs_key_format(&ih->ih_key); /* not SD, not direntry */ if (i && reiserfs_key_comp2 (&(ih - 1)->ih_key, &ih->ih_key) == 0) { if (reiserfs_ih_stat (ih - 1)) { if (reiserfs_key_get_off (&ih->ih_key) != 1) { reiserfs_key_set_off(format, &ih->ih_key, 1); dirty = 1; } } else if (!reiserfs_ih_dir (ih - 1)) { /* Both @(ih-1) and @ih are not SD not DIR items. */ if (reiserfs_key_get_off (&ih->ih_key) < reiserfs_key_get_off(&(ih - 1)->ih_key) + reiserfs_leaf_ibytes(ih - 1, fs->fs_blocksize)) { fsck_log("pass0: vpf-10250: block %lu, item %d: The " "item %k with wrong offset, fixed to %llu\n", bh->b_blocknr, i, &ih->ih_key, reiserfs_key_get_off(&(ih - 1)->ih_key) + reiserfs_ext_count (ih - 1) * fs->fs_blocksize); reiserfs_key_set_off( format, &ih->ih_key, reiserfs_key_get_off(&(ih - 1)->ih_key) + reiserfs_ext_count (ih - 1) * fs->fs_blocksize); dirty = 1; } } else { /* if extent item or not the first direct item in leaf */ fsck_log("pass0: vpf-10250: block %lu, item %d: The item " "%k with wrong type is deleted\n", bh->b_blocknr, i, &ih->ih_key); reiserfs_leaf_delete_item (fs, bh, i); pass_0_stat(fs)->removed++; goto start_again; } } else { /*first item in the node or first item of the file */ if (i) { /* first item of the file, but not SD - delete */ fsck_log("pass0: vpf-10190: block %lu, item %d: The item " "%k, which follows non StatData item %k, is " "deleted\n", bh->b_blocknr, i, &ih->ih_key, &(ih - 1)->ih_key ); reiserfs_leaf_delete_item (fs, bh, i); pass_0_stat(fs)->removed++; goto start_again; } } /* extent or direct is the first in the leaf */ offset = (__u64)reiserfs_key_get_off (&ih->ih_key); if (reiserfs_ih_ext (ih)) { if (offset % fs->fs_blocksize != 1) { fsck_log("pass0: vpf-10200: block %lu, item %d: The " "item %k with wrong offset is deleted\n", bh->b_blocknr, i, &ih->ih_key); reiserfs_leaf_delete_item (fs, bh, i); pass_0_stat(fs)->removed++; goto start_again; } } /* Check the lenght of the direct item; offset should be ok already. */ if (reiserfs_ih_direct (ih) && !correct_direct_item_offset(ih, fs)) { fsck_log("pass0: vpf-10700: block %lu, item %d: " "The item with wrong offset or length " "found %k, len % lu - deleted\n", bh->b_blocknr, i, &ih->ih_key, reiserfs_ih_get_len (ih)); reiserfs_leaf_delete_item (fs, bh, i); pass_0_stat(fs)->removed++; goto start_again; } offset += reiserfs_leaf_ibytes (ih, fs->fs_blocksize); if (!does_it_fit_into_dev (offset, fs_size) || (format == KEY_FORMAT_1 && offset >= (1ull << 32)) || (format == KEY_FORMAT_2 && offset >= (1ull << 60))) { fsck_log("pass0: vpf-10230: block %lu, item %d: The item " "offset is is too big %k - deleted\n", bh->b_blocknr, i, &ih->ih_key); reiserfs_leaf_delete_item (fs, bh, i); pass_0_stat(fs)->removed++; goto start_again; } } if (i && reiserfs_key_comp (&(ih - 1)->ih_key, &ih->ih_key) != -1) { /* previous item has key not smaller than the key of currect item */ if (reiserfs_ih_stat (ih - 1) && !reiserfs_ih_stat (ih)) { /* fix stat data key such as if it was stat data of that item */ fsck_log ("pass0: block %lu, items %d, %d: Wrong order of " "items - make the StatData item %k of the file %k\n", bh->b_blocknr, i - 1, i, &(ih - 1)->ih_key, &ih->ih_key); reiserfs_key_set_did (&(ih - 1)->ih_key, reiserfs_key_get_did (&ih->ih_key)); reiserfs_key_set_oid (&(ih - 1)->ih_key, reiserfs_key_get_oid (&ih->ih_key)); reiserfs_key_set_off (KEY_FORMAT_1, &(ih - 1)->ih_key, 0); reiserfs_key_set_type (KEY_FORMAT_1, &(ih - 1)->ih_key, TYPE_STAT_DATA); dirty = 1; } else { /* ok, we have to delete one of these two - decide which one */ int retval; /* something will be deleted */ dirty = 1; retval = upper_correct (bh, ih - 1, i - 1); switch (retval) { case 0: /* delete upper item */ fsck_log ("pass0: block %lu, item %d (upper): Item %k is " "out of order - deleted\n", bh->b_blocknr, i - 1, &(ih - 1)->ih_key); reiserfs_leaf_delete_item (fs, bh, i - 1); pass_0_stat(fs)->removed++; goto start_again; case 1: /* delete lower item */ fsck_log ("pass0: block %lu, item %d (lower): Item %k is " "out of order - deleted\n", bh->b_blocknr, i, &ih->ih_key); reiserfs_leaf_delete_item (fs, bh, i); pass_0_stat(fs)->removed++; goto start_again; default: /* upper item was the first item of a node */ /* to make gcc 3.2 do not sware here */; } retval = lower_correct (bh, ih, i); switch (retval) { case 0: /* delete lower item */ fsck_log ("pass0: block %lu, item %d (lower): Item %k is " "out of order - deleted\n", bh->b_blocknr, i, &ih->ih_key); reiserfs_leaf_delete_item (fs, bh, i); pass_0_stat(fs)->removed++; goto start_again; case 1: /* delete upper item */ fsck_log ("pass0: block %lu, %d (upper): Item %k is " "out of order - deleted\n", bh->b_blocknr, i - 1, &(ih - 1)->ih_key); reiserfs_leaf_delete_item (fs, bh, i - 1); pass_0_stat(fs)->removed++; goto start_again; default: /* only 2 items in the node, how to decide what to delete, go and ask user */ /* to make gcc 3.2 do not sware here */; } fsck_log ("pass0: block %lu, items %d and %d: Which of these " "items looks better (the other will be deleted.)?\n" "%k\n%k\n", bh->b_blocknr, i-1, i, &(ih - 1)->ih_key, &ih->ih_key); if (fsck_info_ask (fs, "1 or 2?", "1\n", 1)) { reiserfs_leaf_delete_item (fs, bh, i - 1); } else { reiserfs_leaf_delete_item (fs, bh, i); } pass_0_stat(fs)->removed++; goto start_again; } } if (reiserfs_ih_stat (ih) && (reiserfs_ih_get_len (ih) != REISERFS_SD_SIZE && reiserfs_ih_get_len (ih) != REISERFS_SD_SIZE_V1)) { fsck_log ("pass0: block %lu, item %d: StatData item of wrong " "length found %H - deleted\n", bh->b_blocknr, i, ih); reiserfs_leaf_delete_item (fs, bh, i); pass_0_stat(fs)->removed++; goto start_again; } dirty += correct_key_format (ih, symlnk); if (reiserfs_ih_stat (ih)) { __u16 mode; file_format = reiserfs_ih_get_format (ih); reiserfs_stat_get_mode (ih, reiserfs_item_at(bh,i), &mode); symlnk = ( S_ISLNK(mode) ? 1 : 0); ;/*correct_stat_data (fs, bh, i);*/ } else if ( !reiserfs_ih_dir(ih) && !symlnk && (file_format != KEY_FORMAT_UNDEFINED) && (file_format != reiserfs_ih_get_format (ih))) { fsck_log("pass0: vpf-10240: block %lu, item (%d): Item %k, which " "format (%d) is not equal to StatData format (%d), is " "deleted\n", bh->b_blocknr, i, &ih->ih_key, reiserfs_ih_get_format(ih), file_format); reiserfs_leaf_delete_item (fs, bh, i); pass_0_stat(fs)->removed++; goto start_again; } else { file_format = KEY_FORMAT_UNDEFINED; symlnk = 0; } if (i && reiserfs_ih_stat (ih - 1) && !reiserfs_key_comp2 (&ih->ih_key, &(ih - 1)->ih_key)) { __u16 mode; reiserfs_stat_get_mode (ih - 1, reiserfs_item_by_ih (bh, ih - 1), &mode); if (not_a_directory (reiserfs_item_by_ih (bh, ih - 1)) && reiserfs_ih_dir (ih)) { /* make SD mode SD of dir */ fsck_log ("pass0: block %lu, item %d: Not the directory %K has " "the wrong mode (%M), corrected to ", bh->b_blocknr, i, &ih->ih_key, mode); mode &= ~S_IFMT; mode |= S_IFDIR; fsck_log ("(%M)\n", mode); reiserfs_stat_set_mode (ih - 1, reiserfs_item_by_ih (bh, ih - 1), &mode); dirty = 1; } else if (!not_a_directory (reiserfs_item_by_ih (bh, ih - 1)) && !reiserfs_ih_dir (ih)) { /* make SD mode SD of regular file */ fsck_log ("pass0: block %lu, item %d: the directory %K " "has the wrong mode (%M), corrected to ", bh->b_blocknr, i, &ih->ih_key, mode); mode &= ~S_IFMT; mode |= S_IFREG; fsck_log ("(%M)\n", mode); reiserfs_stat_set_mode (ih - 1, reiserfs_item_by_ih (bh, ih - 1), &mode); dirty = 1; } #if 0 if (not_a_regfile (reiserfs_item_by_ih (bh, ih - 1)) && reiserfs_ih_ext (ih)) { fsck_log ("pass0: block %lu, item %d: The file %K has the " "wrong mode (%M), corrected to ", bh->b_blocknr, i, &ih->ih_key, mode); mode &= ~S_IFMT; mode |= S_IFREG; fsck_log ("(%M)\n", mode); reiserfs_stat_set_mode (ih - 1, reiserfs_item_by_ih (bh, ih - 1), &mode); dirty = 1; } #endif } if (reiserfs_ih_dir (ih)) { j = verify_directory_item (fs, bh, i); if (j == 1) { /* wrong hash, skip the leaf */ pass_0_stat (fs)->too_old_leaves ++; reiserfs_buffer_mkclean (bh); return; } else if (j == -1) { /* item was deleted */ goto start_again; } continue; } /*DEBUG*/ if (!reiserfs_ih_stat (ih) && reiserfs_key_get_off (&ih->ih_key) == 0) { reiserfs_panic ("block %lu, item %d: Zero offset can have " "StatData items only, but found %k\n", bh->b_blocknr, i, &ih->ih_key); } if (!reiserfs_ih_ext (ih)) continue; ind_item = (__u32 *)reiserfs_item_by_ih (bh, ih); for (j = 0; j < (int)reiserfs_ext_count (ih); j ++) { unfm_ptr = d32_get (ind_item, j); if (!unfm_ptr) continue; if ((reiserfs_fs_block(fs, unfm_ptr) != BT_UNKNOWN) || (fs->fs_badblocks_bm && reiserfs_bitmap_test_bit(fs->fs_badblocks_bm, unfm_ptr))) { pass_0_stat (fs)->wrong_pointers ++; /* fsck_log ("pass0: %d-th pointer (%lu) in item %k (leaf " "block %lu) is wrong\n", j, unfm_ptr, &ih->ih_key, bh->b_blocknr); */ d32_put(ind_item, j, 0); dirty = 1; continue; } /* mark block in bitmaps of unformatted nodes */ register_unfm (unfm_ptr); } } /* mark all objectids in use */ ih = reiserfs_ih_at (bh, 0); for (i = 0; i < reiserfs_nh_get_items (NODE_HEAD (bh)); i ++, ih ++) { reiserfs_deh_t * deh; id_map_mark(proper_id_map (fs), reiserfs_key_get_did (&ih->ih_key)); id_map_mark(proper_id_map (fs), reiserfs_key_get_oid (&ih->ih_key)); if (reiserfs_ih_dir(ih)) { for (j = 0, deh = reiserfs_deh (bh, ih); j < reiserfs_ih_get_entries (ih); j ++, deh++) { id_map_mark(proper_id_map(fs), reiserfs_deh_get_obid(deh)); } } } if (reiserfs_nh_get_items (NODE_HEAD (bh)) < 1) { /* pass 1 will skip this */ pass_0_stat (fs)->all_contents_removed ++; fsck_log ("pass0: block %lu: no correct item is found. " "Leave block untouched.\n", bh->b_blocknr); dirty = 0; reiserfs_buffer_mkclean (bh); } else { /* pass1 will use this bitmap */ pass0_block_mkleaf (bh->b_blocknr); /*fsck_data (fs)->rebuild.leaves ++;*/ } if (dirty) { pass_0_stat (fs)->leaves_corrected ++; reiserfs_buffer_mkdirty (bh); } } static int is_to_be_read (reiserfs_filsys_t * fs, unsigned long block) { return reiserfs_bitmap_test_bit (fsck_source_bitmap (fs), block); } static void do_pass_0 (reiserfs_filsys_t * fs) { reiserfs_bh_t * bh; unsigned long i; int what_node; unsigned long done = 0, total; if (fsck_mode (fs) == DO_TEST) { /* just to test pass0_correct_leaf */ bh = reiserfs_buffer_read (fs->fs_dev, fsck_data (fs)->rebuild.test, fs->fs_blocksize); if (!bh) { fsck_progress ("%s: Reading of the block %lu failed\n", __FUNCTION__, fsck_data (fs)->rebuild.test); reiserfs_fs_free (fs); exit(0); } if (fsck_leaf_check(bh)) fsck_progress ("############### bad #################\n"); pass0_correct_leaf (fs, bh); reiserfs_node_print (stdout, fs, bh, 3, -1, -1); if (fsck_leaf_check(bh)) fsck_progress ("############### still bad #################\n"); reiserfs_buffer_close (bh); reiserfs_fs_free (fs); exit(0); } total = reiserfs_bitmap_ones (fsck_source_bitmap (fs)); for (i = 0; i < reiserfs_sb_get_blocks (fs->fs_ondisk_sb); i ++) { if (!is_to_be_read (fs, i)) continue; if (!fsck_quiet(fs)) { util_misc_progress (fsck_progress_file (fs), &done, total, 1, 0); } if (!(bh = reiserfs_buffer_read (fs->fs_dev, i, fs->fs_blocksize))) { fsck_progress ("%s: Reading of the block %lu failed\n", __FUNCTION__, i); continue; } if (fs->fs_badblocks_bm && reiserfs_bitmap_test_bit(fs->fs_badblocks_bm, i)) { reiserfs_panic ("The block (%lu), specified in badblock " "list, was read.", i); } if (reiserfs_fs_block(fs, i) != BT_UNKNOWN) { /* block which could not be pointed by extent item */ if (!(reiserfs_journal_block (fs, i) && fsck_data(fs)->rebuild.use_journal_area)) { reiserfs_panic ("The block (%lu) from non " "data area was read.", i); } } pass_0_stat (fs)->dealt_with ++; what_node = reiserfs_node_type (bh); if ( what_node != NT_LEAF && what_node != NT_IH_ARRAY ) { reiserfs_buffer_close (bh); continue; } pass_0_stat (fs)->leaves ++; pass0_correct_leaf (fs, bh); reiserfs_buffer_close (bh); } if (!fsck_quiet(fs)) fsck_progress ("\n"); /* just in case */ id_map_mark(proper_id_map (fs), REISERFS_ROOT_OBJECTID); } static void choose_hash_function (reiserfs_filsys_t * fs) { unsigned long max; unsigned int hash_code; int i; if (fsck_hash_defined (fs)) return; max = 0; hash_code = reiserfs_hash_code (0); for (i = 0; i < fsck_data (fs)->rebuild.hash_amount; i ++) { /* remember hash whihc got more hits */ if (fsck_data (fs)->rebuild.hash_hits [i] > max) { hash_code = i; max = fsck_data (fs)->rebuild.hash_hits [i]; } if (fsck_data (fs)->rebuild.hash_hits [i]) { fsck_log ("%lu directory entries were hashed with %s hash.\n", fsck_data (fs)->rebuild.hash_hits [i], reiserfs_hash_name(i)); } } if (max == 0 || hash_code == 0) { /* no names were found. take either super block value or default */ hash_code = reiserfs_sb_get_hash (fs->fs_ondisk_sb); if (!hash_code) hash_code = DEFAULT_HASH; fsck_log ("Could not find a hash in use. Using %s\n", reiserfs_hash_name (hash_code)); } /* compare the most appropriate hash with the hash set in super block */ if (hash_code != reiserfs_sb_get_hash (fs->fs_ondisk_sb)) { fsck_progress ("Selected hash (%s) does not match to " "the hash set in the super block (%s).\n", reiserfs_hash_name (hash_code), reiserfs_hash_name ( reiserfs_sb_get_hash (fs->fs_ondisk_sb))); reiserfs_sb_set_hash (fs->fs_ondisk_sb, hash_code); } fs->hash = reiserfs_hash_func (hash_code); } /* create bitmap of blocks the tree is to be built off */ /* debugreiserfs and pass0 should share this code -s should show the same as we could recover - test: zero first 32M */ static void init_source_bitmap (reiserfs_filsys_t * fs) { unsigned long count, block, bmap_nr, bits_amount; unsigned long i, j, tmp, reserved; FILE * fp; count = reiserfs_sb_get_blocks (fs->fs_ondisk_sb); switch (fsck_data (fs)->rebuild.scan_area) { case ALL_BLOCKS: fsck_source_bitmap (fs) = reiserfs_bitmap_create (count); reiserfs_bitmap_fill (fsck_source_bitmap (fs)); fsck_progress ("The whole partition (%d blocks) is to be scanned\n", reiserfs_bitmap_ones (fsck_source_bitmap (fs))); break; case USED_BLOCKS: fsck_progress ("Loading on-disk bitmap .. "); fsck_source_bitmap (fs) = reiserfs_bitmap_create (count); reiserfs_bitmap_copy (fsck_source_bitmap (fs), fs->fs_bitmap2); fsck_progress ("ok, %d blocks marked used\n", reiserfs_bitmap_ones (fsck_source_bitmap (fs))); break; case EXTERN_BITMAP: fp = fopen (fsck_data (fs)->rebuild.bitmap_file_name, "r"); if (!fp) { reiserfs_exit (EXIT_OPER, "Could not load bitmap: %s\n", strerror(errno)); } fsck_source_bitmap (fs) = reiserfs_bitmap_load (fp); if (!fsck_source_bitmap (fs)) { reiserfs_exit (EXIT_OPER, "Could not load fitmap from \"%s\"", fsck_data (fs)->rebuild.bitmap_file_name); } fsck_progress ("%d blocks marked used in extern bitmap\n", reiserfs_bitmap_ones (fsck_source_bitmap (fs))); fclose (fp); break; default: reiserfs_panic ("No area to scan specified"); } tmp = 0; /* unmark bitmaps */ block = fs->fs_super_bh->b_blocknr + 1; reserved = fsck_source_bitmap(fs)->bm_bit_size; bmap_nr = reiserfs_bmap_nr(count, fs->fs_blocksize); for (i = 0; i < bmap_nr; i ++) { if (!reiserfs_bitmap_test_bit (fsck_source_bitmap (fs), block)) { /* bitmap is definitely broken, mark all blocks of this bitmap block as used */ bits_amount = (reserved < fs->fs_blocksize * 8) ? reserved : fs->fs_blocksize * 8; fsck_log("%s: Bitmap %lu (of %lu bits) is wrong - " "mark all blocks [%lu - %lu] as used\n", __FUNCTION__, i, bits_amount, i * fs->fs_blocksize * 8, fs->fs_blocksize * 8 * i + bits_amount); for (j = i * fs->fs_blocksize * 8; j < i * fs->fs_blocksize * 8 + bits_amount; j++) { if (!reiserfs_bitmap_test_bit (fsck_source_bitmap(fs), j)) reiserfs_bitmap_set_bit (fsck_source_bitmap(fs), j); } } reiserfs_bitmap_clear_bit (fsck_source_bitmap (fs), block); reserved -= fs->fs_blocksize * 8; tmp ++; /* next block fo bitmap */ if (reiserfs_bitmap_spread (fs)) { block = (block / (fs->fs_blocksize * 8) + 1) * (fs->fs_blocksize * 8); } else { block ++; } } /* pass 0 will skip super block and journal areas and bitmap blocks, find how many blocks have to be read */ for (i = 0; i <= fs->fs_super_bh->b_blocknr; i ++) { if (!reiserfs_bitmap_test_bit (fsck_source_bitmap (fs), i)) continue; reiserfs_bitmap_clear_bit (fsck_source_bitmap (fs), i); tmp ++; } /* unmark journal area as used if journal is standard or it is non standard and initialy has been created on a main device */ reserved = reiserfs_journal_hostsize (fs->fs_ondisk_sb); /* where does journal area (or reserved journal area) start from */ if (!reiserfs_new_location (fs->fs_super_bh->b_blocknr, fs->fs_blocksize) && !reiserfs_old_location (fs->fs_super_bh->b_blocknr, fs->fs_blocksize)) { misc_die ("init_source_bitmap: Wrong super block location, " "you must run --rebuild-sb."); } block = reiserfs_journal_start_must (fs); for (i = block; i < reserved + block; i ++) { if (!reiserfs_bitmap_test_bit (fsck_source_bitmap (fs), i)) continue; reiserfs_bitmap_clear_bit (fsck_source_bitmap (fs), i); tmp ++; } if (fs->fs_badblocks_bm) for (i = 0; i < count; i ++) { if (reiserfs_bitmap_test_bit (fs->fs_badblocks_bm, i)) reiserfs_bitmap_clear_bit (fsck_source_bitmap (fs), i); } fsck_source_bitmap (fs)->bm_set_bits = reiserfs_bitmap_ones (fsck_source_bitmap (fs)); fsck_progress ("Skipping %d blocks (super block, journal, " "bitmaps) %d blocks will be read\n", tmp, fsck_source_bitmap (fs)->bm_set_bits); } static void fsck_pass0_prep (reiserfs_filsys_t * fs) { /* bitmap of blocks to be read */ init_source_bitmap (fs); /* bitmap of leaves, good and bad unformatted */ fsck_pass0_aux_prep (fs); /* on pass0 all objectids will be marked here as used */ proper_id_map (fs) = id_map_init(); /* pass0 gathers statistics about hash hits */ hash_hits_init (fs); } static void fsck_pass0_save_result (reiserfs_filsys_t * fs) { FILE * file; int retval; /* save bitmaps with which we will be able start reiserfs from pass 1 */ file = util_file_open ("temp_fsck_file.deleteme", "w+"); if (!file) return; fsck_stage_start_put (file, PASS_0_DONE); reiserfs_bitmap_save (file, leaves_bitmap); reiserfs_bitmap_save (file, good_unfm_bitmap); reiserfs_bitmap_save (file, bad_unfm_bitmap); fsck_stage_end_put (file); fclose (file); retval = rename ("temp_fsck_file.deleteme", state_dump_file (fs)); if (retval != 0) fsck_progress ("%s: Could not rename the temporary file " "temp_fsck_file.deleteme to %s", __FUNCTION__, state_dump_file (fs)); } /* file 'fp' must contain 3 bitmaps saved during last pass 0: bitmap of leaves, bitmaps of good and bad unfms*/ void fsck_pass0_load_result (FILE * fp, reiserfs_filsys_t * fs) { leaves_bitmap = reiserfs_bitmap_load (fp); good_unfm_bitmap = reiserfs_bitmap_load (fp); bad_unfm_bitmap = reiserfs_bitmap_load (fp); if (!leaves_bitmap || !good_unfm_bitmap || !bad_unfm_bitmap) fsck_exit ("State dump file seems corrupted. Run without -d"); fsck_source_bitmap (fs) = leaves_bitmap; /* on pass 1 we do not need proper objectid map */ fsck_progress ("Pass 0 result loaded. %d leaves, %d/%d good/bad data blocks\n", reiserfs_bitmap_ones (leaves_bitmap), reiserfs_bitmap_ones (good_unfm_bitmap), reiserfs_bitmap_ones (bad_unfm_bitmap)); } static void fsck_pass0_fini (reiserfs_filsys_t * fs) { time_t t; /* update super block: hash, objectid map, fsck state */ choose_hash_function (fs); id_map_flush(proper_id_map (fs), fs); reiserfs_sb_set_state (fs->fs_ondisk_sb, PASS_0_DONE); reiserfs_buffer_mkdirty (fs->fs_super_bh); /* write all dirty blocks */ fsck_progress ("Flushing.."); fs->fs_dirt = 1; reiserfs_fs_flush (fs); fsck_progress ("finished\n"); fsck_stage_report (FS_PASS0, fs); /* free what we do not need anymore */ if (!fsck_run_one_step (fs)) { if (fsck_info_ask (fs, "Continue? (Yes):", "Yes\n", 1)) { /* reiserfsck continues */ reiserfs_bitmap_delete (fsck_source_bitmap (fs)); fsck_source_bitmap (fs) = 0; fsck_source_bitmap (fs) = leaves_bitmap; return; } } else fsck_pass0_save_result (fs); reiserfs_bitmap_flush (fsck_source_bitmap (fs), fs); reiserfs_bitmap_delete (fsck_source_bitmap (fs)); fsck_source_bitmap (fs) = 0; id_map_free(proper_id_map (fs)); proper_id_map (fs) = 0; time (&t); fsck_progress ("###########\n" "reiserfsck finished pass 0 at %s" "###########\n", ctime (&t)); fs->fs_dirt = 1; reiserfs_fs_close (fs); exit(0); } void fsck_pass0 (reiserfs_filsys_t * fs) { if (reiserfs_super_format (fs->fs_ondisk_sb) != fs->fs_format || reiserfs_super_format (fs->fs_ondisk_sb) == REISERFS_FORMAT_UNKNOWN) { reiserfs_exit (EXIT_OPER, "pass 0: ReiserFS format version mismatch " "found, you should run --rebuild-sb"); } fsck_progress ("Pass 0:\n"); if (fsck_log_file (fs) != stderr) /* this is just to separate warnings in the log file */ fsck_log ("####### Pass 0 #######\n"); fsck_pass0_prep (fs); /* scan the partition, find leaves and correct them */ do_pass_0 (fs); fsck_pass0_fini (fs); }