Files
reiserfsprogs/utils/fsck/pass0.c
T

2019 lines
60 KiB
C

/*
* 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 <assert.h>
#include <sys/stat.h>
#include <errno.h>
#include <time.h>
/*
* 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);
}