blob: 721a5360b921e29f83e87cc63bf30b3ba98d5d82 [file] [log] [blame]
/*
* Copyright 1999-2004 by Hans Reiser, licensing governed by
* reiserfsprogs/README
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "fsck.h"
#include "misc/unaligned.h"
/* check_fs_tree stops and recommends to run fsck --rebuild-tree when:
1. read fails
2. node of wrong level found in the tree
3. something in the tree points to wrong block number
out of filesystem boundary is pointed by tree
to block marked as free in bitmap
the same block is pointed from more than one place
not data blocks (journal area, super block, bitmaps)
4. bad formatted node found
5. delimiting keys are incorrect
*/
/* mark every block we see in the tree in control_bitmap, so, when to make
sure, that no blocks are pointed to from more than one place we use
additional bitmap (control_bitmap). If we see pointer to a block we set
corresponding bit to 1. If it is set already - run with --rebuild-tree */
static reiserfs_bitmap_t * control_bitmap;
static reiserfs_bitmap_t * source_bitmap;
static void fsck_tree_check_bitmap_prep (reiserfs_filsys_t * fs) {
unsigned int i;
unsigned long nr;
unsigned long block;
unsigned long reserved;
unsigned long bmap_nr;
nr = reiserfs_sb_get_blocks(fs->fs_ondisk_sb);
control_bitmap = reiserfs_bitmap_create(nr);
if (!control_bitmap)
misc_die ("%s: Failed to allocate a control bitmap.", __FUNCTION__);
/* skipped and super block */
for (i = 0; i <= fs->fs_super_bh->b_blocknr; i ++)
reiserfs_bitmap_set_bit (control_bitmap, i);
/* bitmaps */
bmap_nr = reiserfs_bmap_nr(nr, fs->fs_blocksize);
block = fs->fs_super_bh->b_blocknr + 1;
for (i = 0; i < bmap_nr; i ++) {
reiserfs_bitmap_set_bit (control_bitmap, block);
if (reiserfs_bitmap_spread (fs))
block = (block / (fs->fs_blocksize * 8) + 1) *
(fs->fs_blocksize * 8);
else
block ++;
}
/* mark as used area of the main device either containing a journal or
reserved to hold it */
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 ("%s: Wrong super block location. You must "
"run --rebuild-sb.", __FUNCTION__);
}
block = reiserfs_journal_start_must (fs);
for (i = block; i < reserved + block; i ++)
reiserfs_bitmap_set_bit (control_bitmap, i);
if (fs->fs_badblocks_bm)
for (i = 0; i < nr; i ++) {
if (reiserfs_bitmap_test_bit (fs->fs_badblocks_bm, i))
reiserfs_bitmap_set_bit (control_bitmap, i);
}
}
/* if we managed to complete tree scanning and if control bitmap and/or proper
amount of free blocks mismatch with bitmap on disk and super block's
s_free_blocks - we can fix that */
static void fsck_tree_check_bitmap_fini (reiserfs_filsys_t * fs) {
int problem = 0;
/* check free block counter */
if (reiserfs_sb_get_free (fs->fs_ondisk_sb) !=
reiserfs_bitmap_zeros (control_bitmap))
{
/* fsck_log ("vpf-10630: The count of free blocks in the on-disk bitmap "
"(%lu) mismatches with the correct one (%lu).\n",
reiserfs_sb_get_free (fs->fs_ondisk_sb),
reiserfs_bitmap_zeros (control_bitmap));
*/
problem++;
}
if (reiserfs_bitmap_compare (source_bitmap, control_bitmap))
problem++;
if (problem) {
if (fsck_mode (fs) == FSCK_FIX_FIXABLE) {
fsck_log ("vpf-10630: The on-disk and the correct "
"bitmaps differs. Will be fixed later.\n");
// fsck_progress ("Trying to fix bitmap ..\n");
/* mark blocks as used in source bitmap if they are used in
control bitmap */
reiserfs_bitmap_disjunction (source_bitmap, control_bitmap);
/* change used blocks count accordinly source bitmap, copy
bitmap changes to on_disk bitmap */
reiserfs_sb_set_free (fs->fs_ondisk_sb,
reiserfs_bitmap_zeros(source_bitmap));
reiserfs_bitmap_copy (fs->fs_bitmap2, source_bitmap);
reiserfs_buffer_mkdirty (fs->fs_super_bh);
/*
// check again
if ((diff = reiserfs_bitmap_compare(source_bitmap,
control_bitmap)) != 0)
{
// do not mark them as fatal or fixable because one can live
// with leaked space. So this is not a fatal corruption, and
// fix-fixable cannot fix it
fsck_progress (" bitmaps were not recovered.\n\tYou can either "
"run rebuild-tree or live with %d leaked blocks\n", diff);
} else {
fsck_progress ("finished\n");
}
*/
} else if (problem) {
fsck_log ("vpf-10640: The on-disk and the "
"correct bitmaps differs.\n");
while (problem) {
/* fixable corruptions because we can try to recover them
without rebuilding the tree */
one_more_corruption (fs, FIXABLE);
problem --;
}
}
} else
//fsck_progress ("finished\n");
return;
}
static int fsck_tree_check_bitmap_auto (reiserfs_filsys_t *fs) {
unsigned long i;
if (source_bitmap->bm_byte_size != control_bitmap->bm_byte_size)
return -1;
for (i = 0; i < source_bitmap->bm_byte_size; i ++) {
if (control_bitmap->bm_map[i] & ~source_bitmap->bm_map[i]) {
return 1;
}
}
return 0;
}
/* is this block legal to be pointed to by some place of the tree? */
static int fsck_tree_check_blknr (reiserfs_filsys_t * fs, unsigned long block) {
if (reiserfs_fs_block(fs, block) != BT_UNKNOWN) {
/* block has value which can not be used as a pointer in a tree */
return 1;
}
return 0;
}
static int fsck_tree_check_mark_block (unsigned long block) {
if (reiserfs_bitmap_test_bit (control_bitmap, block)) {
/* block is in tree at least twice */
return 1;
}
reiserfs_bitmap_set_bit (control_bitmap, block);
return 0;
}
/* 1 if it does not look like reasonable stat data */
static int fsck_tree_check_stat (reiserfs_filsys_t * fs,
reiserfs_bh_t * bh,
reiserfs_ih_t * ih)
{
unsigned long objectid;
objectid = reiserfs_key_get_oid (&ih->ih_key);
if (!reiserfs_objmap_test (fs, objectid)) {
/* FIXME: this could be cured right here */
fsck_log ("%s: The objectid (%lu) is marked free, but used by an "
"object %k\n", __FUNCTION__, objectid, &ih->ih_key);
/* if it is FIX_FIXABLE we flush objectid map at the end
no way to call one_less_corruption later
*/
if (fsck_mode (fs) != FSCK_FIX_FIXABLE)
one_more_corruption (fs, FIXABLE);
}
if (id_map_mark(proper_id_map (fs), objectid)) {
fsck_log ("%s: The objectid (%lu) is shared by at least "
"two files. Can be fixed with --rebuild-tree "
"only.\n", __FUNCTION__, objectid);
}
return 0;
}
static inline void handle_one_pointer (reiserfs_filsys_t * fs,
reiserfs_bh_t * bh,
__u32 * item,
int offset)
{
if (fsck_mode (fs) == FSCK_FIX_FIXABLE) {
fsck_log (" - zeroed");
d32_put (item, offset, 0);
reiserfs_buffer_mkdirty (bh);
} else {
one_more_corruption (fs, FIXABLE);
}
}
static int fsck_tree_check_badblock (reiserfs_filsys_t * fs,
reiserfs_bh_t * bh,
reiserfs_ih_t * ih)
{
__u32 i;
__u32 * ind = (__u32 *)reiserfs_item_by_ih (bh, ih);
if (reiserfs_ih_get_len (ih) % 4) {
fsck_log ("%s: block %lu: item (%H) has bad length\n",
__FUNCTION__, bh->b_blocknr, ih);
one_more_corruption (fs, FATAL);
return 1;
}
/* All valid badblocks are given in badblock bitmap.
Nothing to check anymore. */
if (fs->fs_badblocks_bm)
return 0;
for (i = 0; i < reiserfs_ext_count (ih); i ++) {
if (!d32_get (ind, i)) {
/* fsck_log ("%s: block %lu: badblocks item (%H) has "
"zero pointer.", __FUNCTION__, bh->b_blocknr, ih);
if (fsck_mode(fs) != FSCK_FIX_FIXABLE) {
fsck_log("Not an error, but could be deleted "
"with --fix-fixable\n");
} else {
fsck_log("Will be deleted later.\n");
} */
continue;
}
/* check list of badblocks pointers */
if (d32_get (ind, i) >= reiserfs_sb_get_blocks (fs->fs_ondisk_sb)) {
fsck_log ("%s: badblock pointer (block %lu) points "
"out of disk spase (%lu)", __FUNCTION__,
bh->b_blocknr, d32_get (ind, i));
handle_one_pointer (fs, bh, ind, i);
fsck_log ("\n");
}
if (reiserfs_bitmap_test_bit (control_bitmap, d32_get (ind, i))) {
/* it can be
1. not_data_block
delete pointer
2. ind [i] or internal/leaf
advice to run fix-fixable if there is no fatal errors
with list of badblocks, say that it could fix it. */
if (reiserfs_fs_block(fs, d32_get (ind, i)) != BT_UNKNOWN ) {
fsck_log ("%s: badblock pointer (block %lu) points on fs "
"metadata (%lu)", __FUNCTION__, bh->b_blocknr,
d32_get (ind, i));
handle_one_pointer (fs, bh, ind, i);
fsck_log ("\n");
} else {
one_more_corruption(fs, FIXABLE);
fsck_log ("%s: badblock pointer (block %lu) points to "
"a block (%lu) which is in the tree already. "
"Use badblock option (-B) to fix the problem\n",
__FUNCTION__, bh->b_blocknr, d32_get (ind, i));
}
continue;
}
reiserfs_bitmap_set_bit (control_bitmap, d32_get(ind, i));
}
return 0;
}
/* for each unformatted node pointer: make sure it points to data area and
that it is not in the tree yet */
static int fsck_tree_check_ext (reiserfs_filsys_t * fs,
reiserfs_bh_t * bh,
reiserfs_ih_t * ih)
{
__u32 * ind = (__u32 *)reiserfs_item_by_ih (bh, ih);
unsigned int i;
if (reiserfs_ih_get_len (ih) % REISERFS_EXT_SIZE) {
fsck_log ("%s: block %lu: The item (%H) has the bad length (%u)\n",
__FUNCTION__, bh->b_blocknr, ih, reiserfs_ih_get_len (ih));
one_more_corruption (fs, FATAL);
return 1;
}
for (i = 0; i < reiserfs_ext_count (ih); i ++) {
fsck_check_stat (fs)->unfm_pointers ++;
if (!d32_get (ind, i)) {
fsck_check_stat (fs)->zero_unfm_pointers ++;
continue;
}
/* check unformatted node pointer and mark it used in the
control bitmap */
if (fsck_tree_check_blknr(fs, d32_get (ind, i))) {
fsck_log ("%s: block %lu: The item %k has the bad pointer (%d) to "
"the block (%lu)", __FUNCTION__, bh->b_blocknr,
&ih->ih_key, i, d32_get (ind, i));
handle_one_pointer (fs, bh, ind, i);
fsck_log ("\n");
continue;
}
if (fsck_tree_check_mark_block (d32_get (ind, i))) {
fsck_log ("%s: block %lu: The item (%H) has the bad pointer (%d) "
"to the block (%lu), which is in tree already",
__FUNCTION__, bh->b_blocknr, ih, i, d32_get (ind, i));
handle_one_pointer (fs, bh, ind, i);
fsck_log ("\n");
continue;
}
}
#if 0
/* delete this check for 3.6 */
if (reiserfs_ih_get_free (ih) > fs->fs_blocksize - 1) {
if (fsck_mode (fs) == FSCK_FIX_FIXABLE) {
/*FIXME: fix it if needed*/
} else {
fsck_log ("%s: %H has wrong ih_free_space\n", __FUNCTION__, ih);
one_more_corruption (fs, fixable);
}
}
#endif
return 0;
}
static int fsck_tree_check_dir (reiserfs_filsys_t * fs,
reiserfs_bh_t * bh,
reiserfs_ih_t * ih)
{
char *name, *prev_name;
__u32 off, prev_off;
unsigned int count, i;
reiserfs_deh_t * deh = reiserfs_deh (bh, ih);
int min_entry_size = 1;/* We have no way to understand whether the
filesystem was created in 3.6 format or
converted to it. So, we assume that minimal name
length is 1 */
__u16 state;
int namelen;
count = reiserfs_ih_get_entries (ih);
if (count == 0) {
one_more_corruption (fs, FATAL);
return 1;
}
/* make sure item looks like a directory */
if (reiserfs_ih_get_len (ih) /
(REISERFS_DEH_SIZE + min_entry_size) < count)
{
/* entry count can not be that big */
fsck_log ("%s: block %lu: The directory item %k has the exsessively "
"big entry count (%u)\n", __FUNCTION__, bh->b_blocknr,
&ih->ih_key, count);
one_more_corruption (fs, FATAL);
return 1;
}
if (reiserfs_deh_get_loc (&deh[count - 1]) != REISERFS_DEH_SIZE * count) {
/* last entry should start right after array of dir entry headers */
fsck_log ("%s: block %lu: The directory item %k has the corrupted "
"entry structure\n", __FUNCTION__, bh->b_blocknr,
&ih->ih_key);
one_more_corruption (fs, FATAL);
return 1;
}
/* check name hashing */
prev_name = reiserfs_item_by_ih(bh, ih) + reiserfs_ih_get_len(ih);
prev_off = 0;
for (i = 0; i < count; i ++, deh ++) {
namelen = reiserfs_direntry_name_len (ih, deh, i);
name = reiserfs_deh_name (deh, i);
off = reiserfs_deh_get_off (deh);
if (namelen > REISERFS_NAME_MAX ||
name >= prev_name || off <= prev_off)
{
fsck_log ("%s: block %lu: The directory item %k has a broken entry "
"(%d)\n", __FUNCTION__, bh->b_blocknr, &ih->ih_key, i);
one_more_corruption (fs, FATAL);
return 1;
}
if (!reiserfs_hash_correct (&fs->hash, name, namelen, off)) {
fsck_log ("%s: block %lu: The directory item %k has a not properly "
"hashed entry (%d)\n", __FUNCTION__, bh->b_blocknr,
&ih->ih_key, i);
one_more_corruption (fs, FATAL);
return 1;
}
prev_name = name;
prev_off = off;
}
deh = reiserfs_deh (bh, ih);
state = (1 << DEH_Visible2);
/* ok, items looks like a directory */
for (i = 0; i < count; i ++, deh ++) {
if (reiserfs_deh_get_state (deh) != state) {
fsck_log ("%s: block %lu: The directory item %k has the entry (%d) "
"\"%.*s\" with a not legal state (%o), (%o) expected",
__FUNCTION__, bh->b_blocknr, &ih->ih_key, i,
reiserfs_direntry_name_len (ih, deh, i),
reiserfs_deh_name (deh, i),
reiserfs_deh_get_state (deh), state);
if (fsck_mode (fs) == FSCK_FIX_FIXABLE) {
reiserfs_deh_set_state (deh, 1 << DEH_Visible2);
reiserfs_buffer_mkdirty (bh);
fsck_log (" - corrected\n");
} else
one_more_corruption (fs, FIXABLE);
fsck_log ("\n");
}
}
return 0;
}
static int fsck_tree_check_item (reiserfs_filsys_t * fs,
reiserfs_bh_t * bh,
int num)
{
reiserfs_ih_t * ih;
int format;
ih = reiserfs_ih_at (bh, num);
if ((reiserfs_ih_get_flags(ih)) != 0) {
if (fsck_mode(fs) != FSCK_FIX_FIXABLE) {
one_more_corruption (fs, FIXABLE);
fsck_log ("%s: vpf-10570: block %lu: The item header (%d) has not "
"cleaned flags.\n", __FUNCTION__, bh->b_blocknr, num);
} else {
fsck_log ("%s: vpf-10580: block %lu: Flags in the item header "
"(%d) were cleaned\n", __FUNCTION__, bh->b_blocknr, num);
reiserfs_ih_clflags(ih);
reiserfs_buffer_mkdirty(bh);
}
}
if (reiserfs_ih_stat(ih) &&
reiserfs_ih_get_len(ih) == REISERFS_SD_SIZE)
{
format = KEY_FORMAT_2;
} else if (reiserfs_ih_stat(ih) &&
reiserfs_ih_get_len(ih) == REISERFS_SD_SIZE_V1)
{
format = KEY_FORMAT_1;
} else {
format = reiserfs_key_format(&ih->ih_key);
}
if (format != reiserfs_ih_get_format(ih)) {
if (fsck_mode(fs) != FSCK_FIX_FIXABLE) {
one_more_corruption (fs, FIXABLE);
fsck_log ("%s: vpf-10710: block %lu: The format (%d) specified "
"in the item header (%d) differs from the key format "
"(%d).\n", __FUNCTION__, bh->b_blocknr,
reiserfs_ih_get_format(ih), num, format);
} else {
fsck_log ("%s: vpf-10720: block %lu: The format (%d) specified "
"in the item header (%d) was fixed to the key format "
"(%d).\n", __FUNCTION__, bh->b_blocknr,
reiserfs_ih_get_format(ih), num, format);
reiserfs_ih_set_format(ih, format);
reiserfs_buffer_mkdirty(bh);
}
}
if (reiserfs_key_get_oid (&ih->ih_key) == REISERFS_BAD_OID) {
if (reiserfs_key_get_did (&ih->ih_key) == REISERFS_BAD_DID &&
reiserfs_ih_ext (ih))
{
/* Bad Block support. */
return fsck_tree_check_badblock (fs, bh, ih);
}
goto error;
} else {
if (reiserfs_key_get_did (&ih->ih_key) == (__u32)-1) {
/* Safe Link support. Allowable safe links are:
-1 object_id 0x1 EXTENT (truncate) or
-1 object_id blocksize+1 DIRECT (unlink) */
if (reiserfs_ih_direct(ih) &&
reiserfs_key_get_off(&ih->ih_key) == fs->fs_blocksize + 1)
{
if (reiserfs_ih_get_len (ih) == 4) {
/* fsck_log("vpf-00010: safe link found %k\n", &ih->ih_key);*/
fsck_check_stat(fs)->safe ++;
return 0;
}
}
if (reiserfs_ih_ext(ih) &&
reiserfs_key_get_off(&ih->ih_key) == 0x1)
{
if (reiserfs_ih_get_len (ih) == 4) {
/* fsck_log("vpf-00020: safe link found %k\n", &ih->ih_key);*/
fsck_check_stat(fs)->safe ++;
return 0;
}
}
/* it does not look like safe link */
goto error;
}
}
if (reiserfs_ih_stat (ih))
return fsck_tree_check_stat (fs, bh, ih);
if (reiserfs_ih_direct (ih))
return 0;
if (reiserfs_ih_ext(ih))
return fsck_tree_check_ext (fs, bh, ih);
return fsck_tree_check_dir (fs, bh, ih);
error:
one_more_corruption (fs, FATAL);
fsck_log ("%s: vpf-10310: block %lu, item %d: The item has a wrong "
"key %k\n", __FUNCTION__, num, bh->b_blocknr, &ih->ih_key);
return 1;
}
/* 1 if block head or any of items is bad */
static int fsck_tree_leaf_check (reiserfs_filsys_t * fs, reiserfs_bh_t * bh) {
int i;
if (fsck_leaf_check_header(fs, bh))
return 1;
for (i = 0; i < reiserfs_node_items (bh); i ++) {
if (fsck_tree_check_item (fs, bh, i)) {
fsck_log ("%s: block %lu, item %d: The corrupted item found (%H)\n",
__FUNCTION__, bh->b_blocknr, i, reiserfs_ih_at (bh, i));
}
if (i && fsck_leaf_check_neigh (fs, bh, i)) {
fsck_log ("%s: block %lu, items %d and %d: The wrong order of "
"items: %k, %k\n", __FUNCTION__, bh->b_blocknr, i - 1, i,
&reiserfs_ih_at (bh, i - 1)->ih_key,
&reiserfs_ih_at (bh, i)->ih_key);
}
}
return 0;
}
/* 1 if bh does not look like internal node */
static int fsck_tree_check_internal (reiserfs_filsys_t * fs,
reiserfs_bh_t * bh)
{
int i;
for (i = 0; i <= reiserfs_node_items (bh); i ++) {
if (i != reiserfs_node_items (bh) && i !=
reiserfs_node_items (bh) - 1)
{
/* make sure that keys are in increasing order */
if (reiserfs_key_comp (reiserfs_int_key_at (bh, i),
reiserfs_int_key_at (bh, i + 1)) != -1)
{
fsck_log ("%s: vpf-10320: block %lu, items %d and %d: The "
"wrong order of items: %k, %k\n", __FUNCTION__,
bh->b_blocknr, i, i + 1, reiserfs_int_key_at (bh, i),
reiserfs_int_key_at (bh, i + 1));
one_more_corruption (fs, FATAL);
return 1;
}
}
/* make sure that the child is correct */
if (fsck_tree_check_blknr(fs, reiserfs_dc_get_nr (reiserfs_int_at (bh,i))))
{
fsck_log ("%s: vpf-10330: block %lu, item %d: The internal "
"item points to the not legal block (%lu)\n",
__FUNCTION__, bh->b_blocknr, i,
reiserfs_dc_get_nr (reiserfs_int_at (bh,i)));
one_more_corruption (fs, FATAL);
return 1;
}
}
return 0;
}
/* h == 0 for root level. block head's level == 1 for leaf level */
static inline int h_to_level (reiserfs_filsys_t * fs, int h) {
return reiserfs_sb_get_height (fs->fs_ondisk_sb) - h + 1;
}
/* bh must be formatted node. blk_level must be tree_height - path.path_length */
static int fsck_tree_check_node (reiserfs_filsys_t * fs,
reiserfs_path_t * path)
{
reiserfs_bh_t *pbh = REISERFS_PATH_LEAF(path);
if (reiserfs_node_level(pbh) != h_to_level (fs, path->path_length)) {
fsck_log ("block %lu: The level of the node (%d) is not "
"correct, (%d) expected\n", pbh->b_blocknr,
reiserfs_node_level(pbh), h_to_level(fs, path->path_length));
one_more_corruption (fs, FATAL);
return 1;
}
if (fsck_tree_check_blknr(fs, pbh->b_blocknr)) {
one_more_corruption (fs, FATAL);
fsck_log ("%s: vpf-10340: The node in the wrong block number (%lu) "
"found in the tree\n", __FUNCTION__, pbh->b_blocknr);
return 1;
}
if (fsck_tree_check_mark_block (pbh->b_blocknr)) {
fsck_log ("%s: vpf-10350: The block (%lu) is used more than once "
"in the tree.\n", __FUNCTION__, pbh->b_blocknr);
one_more_corruption (fs, FATAL);
return 1;
}
if (reiserfs_leaf_head(pbh)) {
fsck_check_stat (fs)->leaves ++;
return fsck_tree_leaf_check (fs, pbh);
}
fsck_check_stat (fs)->internals ++;
return fsck_tree_check_internal (fs, pbh);
}
/* are all delimiting keys correct */
static int fsck_tree_check_path (reiserfs_filsys_t * fs,
reiserfs_path_t * path)
{
const reiserfs_key_t *dk;
reiserfs_bh_t *parent;
reiserfs_bh_t *bh;
int items;
int pos;
int h1;
h1 = REISERFS_PATH_OFFILL;
while (path->path_elements[h1 + 1].pe_buffer)
h1 ++;
// path[h] is leaf
if (h1 != path->path_length)
misc_die ("%s: The leaf is expected as the last "
"element in the path.", __FUNCTION__);
bh = REISERFS_PATH_LEAF(path);
if (h1 != REISERFS_PATH_OFFINIT) {
parent = REISERFS_PATH_BUFFER(path, h1 - 1);
pos = reiserfs_internal_get_pos (parent, bh->b_blocknr);
} else {
parent = NULL;
pos = 0;
}
dk = reiserfs_tree_lkey (path, fs);
if (dk != &MIN_KEY &&
reiserfs_key_comp (dk, reiserfs_ih_key_at (bh, 0)))
{
/* left delimiting key must be equal to the key of 0-th item in the
node */
fsck_log ("%s: The left delimiting key %k of the node (%lu) must "
"be equal to the first element's key %k within the node.\n",
__FUNCTION__, dk, bh->b_blocknr, reiserfs_ih_key_at(bh, 0));
one_more_corruption (fs, FATAL);
return 1;
}
items = reiserfs_nh_get_items( NODE_HEAD(bh) ) - 1;
dk = reiserfs_tree_rkey (path, fs);
if (dk != &MAX_KEY &&
reiserfs_key_comp (dk, reiserfs_ih_key_at (bh, items)) != 1)
{
/* right delimiting key must be greather then the key of the last
item in the node */
fsck_log ("%s: The right delimiting key %k of the node (%lu) must "
"be greater than the last (%d) element's key %k within "
"the node.\n", __FUNCTION__, dk, bh->b_blocknr,
reiserfs_nh_get_items (NODE_HEAD (bh)) - 1,
reiserfs_ih_key_at (bh, items));
one_more_corruption (fs, FATAL);
return 1;
}
if ((h1 != REISERFS_PATH_OFFINIT) &&
(reiserfs_dc_get_size(reiserfs_int_at(parent, pos)) +
reiserfs_nh_get_free(NODE_HEAD(bh)) +
REISERFS_NODEH_SIZE != bh->b_size))
{
/* wrong dc_size */
fsck_log ("bad_path: block %lu, pointer %d: The used space (%d) "
"of the child block (%lu)", parent->b_blocknr, pos,
reiserfs_dc_get_size(reiserfs_int_at(parent, pos)),
bh->b_blocknr);
fsck_log (" is not equal to the (blocksize (4096) - free space (%d) - "
"header size (%u))", reiserfs_nh_get_free(NODE_HEAD(bh)),
REISERFS_NODEH_SIZE);
if (fsck_mode (fs) == FSCK_FIX_FIXABLE) {
reiserfs_dc_set_size (
reiserfs_int_at(parent, pos), bh->b_size -
reiserfs_nh_get_free(NODE_HEAD(bh)) - REISERFS_NODEH_SIZE);
fsck_log (" - corrected to (%lu)\n",
reiserfs_dc_get_size (reiserfs_int_at(parent, pos)));
reiserfs_buffer_mkdirty (parent);
} else {
one_more_corruption (fs, FIXABLE);
fsck_log ("\n");
return 1;
}
}
return 0;
}
static void fsck_tree_check_prep (reiserfs_filsys_t * fs) {
fsck_tree_check_bitmap_prep (fs);
source_bitmap =
reiserfs_bitmap_create (reiserfs_sb_get_blocks (fs->fs_ondisk_sb));
reiserfs_bitmap_copy (source_bitmap, fs->fs_bitmap2);
proper_id_map (fs) = id_map_init();
}
static void fsck_tree_check_fini (reiserfs_filsys_t * fs) {
if (fsck_mode(fs) == FSCK_FIX_FIXABLE) {
reiserfs_bitmap_flush(fs->fs_bitmap2, fs);
reiserfs_fs_flush (fs);
fs->fs_dirt = 1;
reiserfs_bitmap_delta (source_bitmap, control_bitmap);
fsck_deallocate_bitmap(fs) = source_bitmap;
} else
reiserfs_bitmap_delete (source_bitmap);
reiserfs_bitmap_delete (control_bitmap);
reiserfs_buffer_flush_all (fs->fs_dev);
}
/* pass internal tree of filesystem */
void check_fs_tree (reiserfs_filsys_t * fs)
{
fsck_tree_check_prep (fs);
fsck_progress ("Checking Internal tree...\n");
fsck_tree_trav (fs, fsck_tree_check_node,
fsck_tree_check_path,
fsck_mode(fs) == FSCK_AUTO ? 2 : -1);
if (!fsck_quiet(fs))
fsck_progress("\n");
/* compare created bitmap with the original */
if (fsck_mode(fs) == FSCK_AUTO) {
if (fsck_tree_check_bitmap_auto(fs)) {
fprintf(stderr, "The on-disk bitmap looks corrupted.");
one_more_corruption(fs, FIXABLE);
}
id_map_free(proper_id_map(fs));
} else
fsck_tree_check_bitmap_fini(fs);
fsck_tree_check_fini (fs);
}
static int clean_attributes_handler (reiserfs_filsys_t * fs,
reiserfs_path_t * path)
{
reiserfs_bh_t * bh = REISERFS_PATH_LEAF(path);
int i;
if (reiserfs_node_level (bh) != h_to_level (fs, path->path_length)) {
reiserfs_panic ("The node (%lu) with wrong level (%d) "
"found in the tree, (%d) expected\n",
bh->b_blocknr, reiserfs_node_level (bh),
h_to_level (fs, path->path_length));
}
if (!reiserfs_leaf_head (bh))
return 0;
for (i = 0; i < reiserfs_node_items (bh); i ++) {
if (reiserfs_ih_stat (reiserfs_ih_at (bh, i)) &&
reiserfs_ih_get_len (reiserfs_ih_at (bh, i)) ==
REISERFS_SD_SIZE)
{
reiserfs_set_sd_v2_attrs
((reiserfs_sd_t *)reiserfs_item_at(bh, i), 0);
reiserfs_buffer_mkdirty (bh);
}
}
return 0;
}
void fsck_tree_clean_attr (reiserfs_filsys_t * fs) {
fsck_tree_trav (fs, clean_attributes_handler, NULL, -1);
reiserfs_sb_mkflag (fs->fs_ondisk_sb, reiserfs_attrs_cleared);
reiserfs_buffer_mkdirty (fs->fs_super_bh);
}