1308 lines
38 KiB
C
1308 lines
38 KiB
C
/*
|
|
* Copyright 1999 Hans Reiser
|
|
*/
|
|
|
|
#include "fsck.h"
|
|
|
|
struct check_relocated {
|
|
__u32 old_dir_id;
|
|
__u32 old_objectid;
|
|
/*mode_t mode;*/
|
|
struct check_relocated * next;
|
|
};
|
|
|
|
struct check_relocated * relocated_list;
|
|
|
|
void to_be_relocated (struct key * key)
|
|
{
|
|
struct check_relocated * cur, * prev, * new_relocated;
|
|
|
|
cur = relocated_list;
|
|
prev = 0;
|
|
|
|
while (cur && comp_short_keys(key, (struct key *)cur) != 1) {
|
|
if (comp_short_keys (key, (struct key *)cur) == 0)
|
|
return;
|
|
prev = cur;
|
|
cur = cur->next;
|
|
}
|
|
|
|
new_relocated = getmem (sizeof (struct check_relocated));
|
|
copy_short_key ((struct key *)new_relocated, key);
|
|
|
|
if (prev) {
|
|
new_relocated->next = prev->next;
|
|
prev->next = new_relocated;
|
|
} else {
|
|
new_relocated->next = 0;
|
|
relocated_list = new_relocated;
|
|
}
|
|
}
|
|
|
|
int should_be_relocated (struct key * key)
|
|
{
|
|
struct check_relocated * cur, * next;
|
|
int ret = 0;
|
|
|
|
cur = relocated_list;
|
|
|
|
while (cur && comp_short_keys(key, (struct key *)cur) != 1) {
|
|
if (comp_short_keys (key, (struct key *)cur) == 0) {
|
|
ret = 1;
|
|
break;
|
|
}
|
|
cur = cur->next;
|
|
}
|
|
|
|
while (relocated_list != cur) {
|
|
next = relocated_list->next;
|
|
freemem (relocated_list);
|
|
relocated_list = next;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
//
|
|
//
|
|
// check S+ tree of the file system
|
|
//
|
|
// 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 fsck with --rebuild-tree */
|
|
static reiserfs_bitmap_t * control_bitmap;
|
|
static reiserfs_bitmap_t * source_bitmap;
|
|
|
|
static int tree_scanning_failed = 0;
|
|
|
|
|
|
/* 1 if block is not marked as used in the bitmap */
|
|
static int is_block_free (reiserfs_filsys_t * fs, unsigned long block)
|
|
{
|
|
return !reiserfs_bitmap_test_bit (source_bitmap, block);
|
|
}
|
|
|
|
|
|
/*static int hits = 0;*/
|
|
|
|
/* we have seen this block in the tree, mark corresponding bit in the
|
|
control bitmap */
|
|
static void we_met_it (unsigned long block)
|
|
{
|
|
reiserfs_bitmap_set_bit (control_bitmap, block);
|
|
/*hits ++;*/
|
|
}
|
|
|
|
|
|
/* have we seen this block somewhere in the tree before? */
|
|
static int did_we_meet_it (unsigned long block)
|
|
{
|
|
return reiserfs_bitmap_test_bit (control_bitmap, block);
|
|
}
|
|
|
|
|
|
static void init_control_bitmap (reiserfs_filsys_t * fs)
|
|
{
|
|
int i;
|
|
unsigned long block;
|
|
unsigned long reserved;
|
|
|
|
|
|
control_bitmap = reiserfs_create_bitmap (get_sb_block_count (fs->fs_ondisk_sb));
|
|
if (!control_bitmap)
|
|
die ("init_control_bitmap: could not create control bitmap");
|
|
|
|
/*printf ("Initially number of zeros in control bitmap %d\n", reiserfs_bitmap_zeros (control_bitmap));*/
|
|
|
|
/* skipped and super block */
|
|
for (i = 0; i <= fs->fs_super_bh->b_blocknr; i ++)
|
|
we_met_it (i);
|
|
|
|
/*printf ("SKIPPED: %d blocks marked used (%d)\n", hits, reiserfs_bitmap_zeros (control_bitmap));
|
|
hits = 0;*/
|
|
|
|
/* bitmaps */
|
|
block = fs->fs_super_bh->b_blocknr + 1;
|
|
for (i = 0; i < get_sb_bmap_nr (fs->fs_ondisk_sb); i ++) {
|
|
we_met_it (block);
|
|
|
|
if (spread_bitmaps (fs))
|
|
block = (block / (fs->fs_blocksize * 8) + 1) * (fs->fs_blocksize * 8);
|
|
else
|
|
block ++;
|
|
}
|
|
/*printf ("BITMAPS: %d blocks marked used (%d)\n", hits, reiserfs_bitmap_zeros (control_bitmap));
|
|
hits = 0;*/
|
|
|
|
/* mark as used area of the main device either containing a journal or
|
|
reserved to hold it */
|
|
|
|
reserved = get_size_of_journal_or_reserved_area (fs->fs_ondisk_sb);
|
|
|
|
/* where does journal area (or reserved journal area) start from */
|
|
|
|
if (!is_new_sb_location (fs->fs_super_bh->b_blocknr, fs->fs_blocksize) &&
|
|
!is_old_sb_location (fs->fs_super_bh->b_blocknr, fs->fs_blocksize))
|
|
die ("init_control_bitmap: wrong super block");
|
|
|
|
block = get_journal_start_must (fs);
|
|
|
|
for (i = block; i < reserved + block; i ++)
|
|
we_met_it (i);
|
|
|
|
if (fs->fs_badblocks_bm)
|
|
for (i = 0; i < get_sb_block_count (fs->fs_ondisk_sb); i ++) {
|
|
if (reiserfs_bitmap_test_bit (fs->fs_badblocks_bm, i))
|
|
we_met_it (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 handle_bitmaps (reiserfs_filsys_t * fs)
|
|
{
|
|
int diff, problem = 0;
|
|
|
|
if (tree_scanning_failed) {
|
|
fsck_progress ("Could not scan whole tree. "
|
|
"--rebuild-tree is required\n");
|
|
return;
|
|
}
|
|
|
|
fsck_progress ("Comparing bitmaps..");
|
|
|
|
/* check free block counter */
|
|
if (get_sb_free_blocks (fs->fs_ondisk_sb) != reiserfs_bitmap_zeros (control_bitmap)) {
|
|
fsck_log ("free block count %lu mismatches with a correct one %lu. \n",
|
|
get_sb_free_blocks (fs->fs_ondisk_sb),
|
|
reiserfs_bitmap_zeros (control_bitmap));
|
|
problem++;
|
|
// one_more_corruption (fs, fatal); /* for now */
|
|
}
|
|
|
|
diff = reiserfs_bitmap_compare (source_bitmap, control_bitmap);
|
|
if (diff) {
|
|
fsck_log ("on-disk bitmap does not match to the correct one. \n", diff);
|
|
problem++;
|
|
}
|
|
|
|
if (problem) {
|
|
if (fsck_mode (fs) == FSCK_FIX_FIXABLE) {
|
|
fsck_progress ("Trying to fix bitmap ..\n", diff);
|
|
/* 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 */
|
|
set_sb_free_blocks (fs->fs_ondisk_sb, reiserfs_bitmap_zeros (source_bitmap));
|
|
reiserfs_bitmap_copy (fs->fs_bitmap2, source_bitmap);
|
|
mark_buffer_dirty (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 */
|
|
// one_more_corruption (fs, fatal);
|
|
fsck_progress (" bitmaps were not recovered. \n"
|
|
"\tYou can either run rebuild-tree or live with %d leaked blocks\n", diff);
|
|
} else {
|
|
fsck_progress ("ok\n");
|
|
}
|
|
} else {
|
|
while (problem) {
|
|
/* fixable corruptions because we can try to recover them w/out rebuilding the tree */
|
|
one_more_corruption (fs, fixable);
|
|
problem --;
|
|
}
|
|
}
|
|
} else
|
|
fsck_progress ("ok\n");
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/* is this block legal to be pointed to by some place of the tree? */
|
|
static int bad_block_number (reiserfs_filsys_t * fs, unsigned long block)
|
|
{
|
|
if (block >= get_sb_block_count (fs->fs_ondisk_sb) ||
|
|
not_data_block (fs, block)) {
|
|
/* block has value which can not be used as a pointer in a tree */
|
|
|
|
return 1;
|
|
/*
|
|
if (is_unfm_pointer) {
|
|
// unformatted node pointer will be zeroed
|
|
one_more_corruption (fs, fixable);
|
|
return 1;
|
|
}
|
|
|
|
// internal nodes can not have wrong pointer
|
|
one_more_corruption (fs, fatal);
|
|
return 1;
|
|
*/
|
|
|
|
}
|
|
|
|
if (is_block_free (fs, block)) {
|
|
/* block is marked free - bitmap problems will be handled later */
|
|
//one_more_corruption (fs, fixable);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int got_already (reiserfs_filsys_t * fs, unsigned long block)
|
|
{
|
|
#if 0
|
|
if (0/*opt_fsck_mode == FSCK_FAST_REBUILD*/){
|
|
if (is_block_used(block)){
|
|
fsck_log ("block %lu is in tree already\n", block);
|
|
return 1;
|
|
}
|
|
} else {
|
|
#endif
|
|
|
|
if (did_we_meet_it (block)) {
|
|
/* block is in tree at least twice */
|
|
return 1;
|
|
}
|
|
we_met_it (block);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* 1 if some of fields in the block head of bh look bad */
|
|
static int bad_block_head (reiserfs_filsys_t * fs, struct buffer_head * bh)
|
|
{
|
|
struct block_head * blkh;
|
|
int sum_length = 0;
|
|
|
|
blkh = B_BLK_HEAD (bh);
|
|
if (get_blkh_nr_items (blkh) > (bh->b_size - BLKH_SIZE) / IH_SIZE) {
|
|
fsck_log ("block %lu has wrong blk_nr_items (%z)\n",
|
|
bh->b_blocknr, bh);
|
|
one_more_corruption (fs, fatal);
|
|
return 1;
|
|
}
|
|
|
|
if (who_is_this (bh->b_data, bh->b_size) != THE_LEAF) {
|
|
fsck_log ("leaf %lu has wrong structure\n", bh->b_blocknr);
|
|
one_more_corruption (fs, fatal);
|
|
return 1;
|
|
}
|
|
|
|
sum_length = (get_blkh_nr_items (blkh) > 0) ?
|
|
get_ih_location (B_N_PITEM_HEAD (bh, get_blkh_nr_items (blkh) - 1)) : bh->b_size;
|
|
|
|
if (get_blkh_free_space (blkh) !=
|
|
sum_length - BLKH_SIZE - IH_SIZE * get_blkh_nr_items (blkh))
|
|
{
|
|
fsck_log ("block (%lu) has wrong blk_free_space (%lu) should be (%lu)",
|
|
bh->b_blocknr, get_blkh_free_space (blkh), sum_length - BLKH_SIZE - IH_SIZE * get_blkh_nr_items (blkh) );
|
|
if (fsck_mode(fs) == FSCK_FIX_FIXABLE) {
|
|
set_blkh_free_space (blkh, sum_length - BLKH_SIZE - IH_SIZE * get_blkh_nr_items (blkh));
|
|
fsck_log (" - fixed on (%lu)\n", get_blkh_free_space (blkh));
|
|
mark_buffer_dirty (bh);
|
|
} else {
|
|
fsck_log ("\n");
|
|
one_more_corruption (fs, fixable);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* 1 if it does not look like reasonable stat data */
|
|
static int bad_stat_data (reiserfs_filsys_t * fs, struct buffer_head * bh, struct item_head * ih)
|
|
{
|
|
unsigned long objectid;
|
|
__u32 pos;
|
|
__u32 links;
|
|
struct stat_data * sd;
|
|
|
|
/*
|
|
if (opt_fsck_mode == FSCK_FAST_REBUILD)
|
|
return 0;
|
|
*/
|
|
objectid = get_key_objectid (&ih->ih_key);
|
|
if (!is_objectid_used (fs, objectid)) {
|
|
/* FIXME: this could be cured right here */
|
|
fsck_log ("\nbad_stat_data: %lu is marked free, but used by an object %k\n",
|
|
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 (is_objectid_really_used (proper_id_map (fs), objectid, &pos)) {
|
|
fsck_log ("\nbad_stat_data: %lu is shared by at least two files\n",
|
|
objectid);
|
|
if (fsck_mode (fs) == FSCK_FIX_FIXABLE)
|
|
to_be_relocated (&ih->ih_key);
|
|
|
|
one_more_corruption (fs, fixable);
|
|
|
|
return 0;
|
|
}
|
|
|
|
sd = (struct stat_data *)B_I_PITEM(bh,ih);
|
|
if (fsck_mode (fs) == FSCK_CHECK) {
|
|
get_sd_nlink (ih, sd, &links);
|
|
if (S_ISDIR(sd->sd_mode)) {
|
|
if (links < 2) {
|
|
fsck_log ("%s: block %lu, [%k], directory SD has bad nlink number\n",
|
|
__FUNCTION__, bh->b_blocknr, &ih->ih_key);
|
|
one_more_corruption (fs, fixable);
|
|
}
|
|
} else {
|
|
if (links == 0) {
|
|
fsck_log ("%s: block %lu, [%k], SD has bad nlink number\n",
|
|
__FUNCTION__, bh->b_blocknr, &ih->ih_key);
|
|
one_more_corruption (fs, fixable);
|
|
}
|
|
}
|
|
} else {
|
|
links = 0;
|
|
set_sd_nlink (ih, sd, &links);
|
|
mark_buffer_dirty (bh);
|
|
}
|
|
|
|
__mark_objectid_really_used (proper_id_map (fs), objectid, pos);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* it looks like we can check item length only */
|
|
static int bad_direct_item (reiserfs_filsys_t * fs, struct buffer_head * bh, struct item_head * ih)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
inline void handle_one_pointer (reiserfs_filsys_t * fs, struct buffer_head * bh, __u32 * ptr) {
|
|
if (fsck_mode (fs) == FSCK_FIX_FIXABLE) {
|
|
fsck_log (" - fixed");
|
|
*ptr = 0;
|
|
mark_buffer_dirty (bh);
|
|
} else {
|
|
one_more_corruption (fs, fixable);
|
|
}
|
|
}
|
|
|
|
/*
|
|
static int bad_badblocks_item (reiserfs_filsys_t * fs, struct buffer_head * bh,
|
|
struct item_head * ih) {
|
|
int i;
|
|
__u32 * ind = (__u32 *)B_I_PITEM (bh, ih);
|
|
|
|
if (get_ih_item_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;
|
|
}
|
|
|
|
for (i = 0; i < I_UNFM_NUM (ih); i ++) {
|
|
// __u32 unfm_ptr;
|
|
|
|
// unfm_ptr = le32_to_cpu (ind [i]);
|
|
if (!le32_to_cpu (ind [i])) {
|
|
fsck_log ("%s: block %lu: badblocks item (%H) has zero pointer.");
|
|
fsck_log ("Not an error, but could be deleted with --fix-fixable\n",
|
|
__FUNCTION__, bh->b_blocknr, ih);
|
|
continue;
|
|
}
|
|
|
|
// check list of badblocks pointers
|
|
if (le32_to_cpu (ind [i]) >= get_sb_block_count (fs->fs_ondisk_sb)) {
|
|
fsck_log ("%s: badblock pointer (block %lu) points out of disk spase (%lu)",
|
|
__FUNCTION__, bh->b_blocknr, le32_to_cpu (ind [i]));
|
|
handle_one_pointer (fs, bh, &ind[i]);
|
|
fsck_log ("\n");
|
|
}
|
|
|
|
if (did_we_meet_it (le32_to_cpu (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 (not_data_block (fs, le32_to_cpu (ind [i]))) {
|
|
fsck_log ("%s: badblock pointer (block %lu) points on fs metadata (%lu)",
|
|
__FUNCTION__, bh->b_blocknr, le32_to_cpu (ind [i]));
|
|
handle_one_pointer (fs, bh, &ind[i]);
|
|
fsck_log ("\n");
|
|
} else {
|
|
one_more_corruption (fs, badblocks);
|
|
fsck_log ("%s: badblock item points to a block"
|
|
" which in the tree already. Use --badblock-file option"
|
|
" to fix the problem\n", __FUNCTION__);
|
|
}
|
|
} else {
|
|
we_met_it (le32_to_cpu (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 bad_indirect_item (reiserfs_filsys_t * fs, struct buffer_head * bh,
|
|
struct item_head * ih)
|
|
{
|
|
int i;
|
|
__u32 * ind = (__u32 *)B_I_PITEM (bh, ih);
|
|
|
|
if (get_ih_item_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;
|
|
}
|
|
|
|
for (i = 0; i < I_UNFM_NUM (ih); i ++) {
|
|
// __u32 unfm_ptr;
|
|
|
|
fsck_check_stat (fs)->unfm_pointers ++;
|
|
// unfm_ptr = le32_to_cpu (ind [i]);
|
|
if (!le32_to_cpu (ind [i])) {
|
|
fsck_check_stat (fs)->zero_unfm_pointers ++;
|
|
continue;
|
|
}
|
|
|
|
/* check unformatted node pointer and mark it used in the
|
|
control bitmap */
|
|
if (bad_block_number (fs, le32_to_cpu (ind [i]))) {
|
|
fsck_log ("%s: block %lu: item %H has bad pointer %d: %lu",
|
|
__FUNCTION__, bh->b_blocknr, ih, i, le32_to_cpu (ind [i]));
|
|
handle_one_pointer (fs, bh, &ind[i]);
|
|
fsck_log ("\n");
|
|
continue;
|
|
}
|
|
|
|
if (got_already (fs, le32_to_cpu (ind [i]))) {
|
|
fsck_log ("%s: block %lu: item %H has a pointer %d "
|
|
"to the block %lu which is in tree already",
|
|
__FUNCTION__, bh->b_blocknr, ih, i, le32_to_cpu (ind [i]));
|
|
handle_one_pointer (fs, bh, &ind [i]);
|
|
fsck_log ("\n");
|
|
continue;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
/* delete this check for 3.6 */
|
|
if (get_ih_free_space (ih) > fs->fs_blocksize - 1) {
|
|
if (fsck_mode (fs) == FSCK_FIX_FIXABLE) {
|
|
/*FIXME: fix it if needed*/
|
|
} else {
|
|
fsck_log ("bad_indirect_item: %H has wrong ih_free_space\n", ih);
|
|
one_more_corruption (fs, fixable);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* FIXME: this was is_bad_directory from pass0.c */
|
|
static int bad_directory_item (reiserfs_filsys_t * fs, struct buffer_head * bh, struct item_head * ih)
|
|
{
|
|
int i;
|
|
char * name;
|
|
int namelen;
|
|
struct reiserfs_de_head * deh = B_I_DEH (bh, ih);
|
|
int min_entry_size = 1;/* we have no way to understand whether the
|
|
filesystem were created in 3.6 format or
|
|
converted to it. So, we assume that minimal name
|
|
length is 1 */
|
|
__u16 state;
|
|
|
|
|
|
/* make sure item looks like a directory */
|
|
if (get_ih_item_len (ih) / (DEH_SIZE + min_entry_size) < get_ih_entry_count (ih)) {
|
|
/* entry count can not be that big */
|
|
fsck_log ("%s: block %lu: directory item %H has corrupted structure\n",
|
|
__FUNCTION__, bh->b_blocknr, ih);
|
|
one_more_corruption (fs, fatal);
|
|
return 1;
|
|
}
|
|
|
|
if (get_deh_location (&deh[get_ih_entry_count (ih) - 1]) != DEH_SIZE * get_ih_entry_count (ih)) {
|
|
/* last entry should start right after array of dir entry headers */
|
|
fsck_log ("%s: block %lu: directory item %H has corrupted structure\n",
|
|
__FUNCTION__, bh->b_blocknr, ih);
|
|
one_more_corruption (fs, fatal);
|
|
return 1;
|
|
}
|
|
|
|
/* check name hashing */
|
|
for (i = 0; i < get_ih_entry_count (ih); i ++, deh ++) {
|
|
namelen = name_in_entry_length (ih, deh, i);
|
|
name = name_in_entry (deh, i);
|
|
if (!is_properly_hashed (fs, name, namelen, get_deh_offset (deh))) {
|
|
fsck_log ("%s: block %lu: directory item %H has hashed bad entry\n",
|
|
__FUNCTION__, bh->b_blocknr, ih);
|
|
one_more_corruption (fs, fatal);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
deh = B_I_DEH (bh, ih);
|
|
state = (1 << DEH_Visible2);
|
|
/* ok, items looks like a directory */
|
|
for (i = 0; i < get_ih_entry_count (ih); i ++, deh ++) {
|
|
if (get_deh_state (deh) != state) {
|
|
fsck_log ("bad_directory_item: block %lu: item %H has entry "
|
|
"\"%.*s\" with wrong deh_state %o - expected %o",
|
|
bh->b_blocknr, ih, name_in_entry_length (ih, deh, i),
|
|
name_in_entry (deh, i), get_deh_state (deh), state );
|
|
if (fsck_mode (fs) == FSCK_FIX_FIXABLE) {
|
|
set_deh_state (deh, 1 << DEH_Visible2);
|
|
mark_buffer_dirty (bh);
|
|
fsck_log (" - fixed");
|
|
} else
|
|
one_more_corruption (fs, fixable);
|
|
|
|
fsck_log ("\n");
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int bad_item (reiserfs_filsys_t * fs, struct buffer_head * bh, int num)
|
|
{
|
|
struct item_head * ih;
|
|
|
|
ih = B_N_PITEM_HEAD (bh, num);
|
|
|
|
if (get_key_dirid (&ih->ih_key) == (__u32)-1) {
|
|
if (get_key_objectid (&ih->ih_key) != (__u32)-1) {
|
|
/* safe link can be
|
|
-1 object_id 0x1 -2 (truncate) or
|
|
-1 object_id blocksize+1 -1 (unlink)
|
|
*/
|
|
|
|
if (is_direct_ih(ih))
|
|
if (get_offset(&ih->ih_key) == fs->fs_blocksize + 1)
|
|
if (get_ih_item_len (ih) == 4) {
|
|
/*fsck_log("vpf-00010: safe link found [%k]\n", &ih->ih_key);*/
|
|
fsck_check_stat(fs)->safe ++;
|
|
return 0;
|
|
}
|
|
|
|
if (is_indirect_ih(ih))
|
|
if(get_offset(&ih->ih_key) == 0x1)
|
|
if (get_ih_item_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 */
|
|
|
|
/* dir_id == -1 can be used only by safe links */
|
|
one_more_corruption (fs, fatal);
|
|
fsck_log ("%s: vpf-10290: block %lu item with wrong key (%k) found\n", __FUNCTION__, bh->b_blocknr, &ih->ih_key);
|
|
return 1;
|
|
} else {
|
|
|
|
/* BAD BLOCK LIST SUPPORT
|
|
if (is_indirect_ih (ih)) {
|
|
// it looks like badblocks item
|
|
if (fs->fs_badblocks_bm)
|
|
return 0;
|
|
else
|
|
return bad_badblocks_item (fs, bh, ih);
|
|
} else {*/
|
|
|
|
one_more_corruption (fs, fatal);
|
|
fsck_log ("%s: vpf-10300: block %lu item with wrong key (%k) found\n", __FUNCTION__, bh->b_blocknr, &ih->ih_key);
|
|
return 1;
|
|
}
|
|
} else if (get_key_objectid (&ih->ih_key) == (__u32)-1) {
|
|
one_more_corruption (fs, fatal);
|
|
fsck_log ("%s: vpf-10310: block %lu item with wrong key (%k) found\n", __FUNCTION__, bh->b_blocknr, &ih->ih_key);
|
|
return 1;
|
|
}
|
|
|
|
if (is_stat_data_ih (ih))
|
|
return bad_stat_data (fs, bh, ih);
|
|
|
|
if (is_direct_ih (ih))
|
|
return bad_direct_item (fs, bh, ih);
|
|
|
|
if (is_indirect_ih(ih))
|
|
return bad_indirect_item (fs, bh, ih);
|
|
|
|
return bad_directory_item (fs, bh, ih);
|
|
}
|
|
|
|
|
|
/* 1 if i-th and (i-1)-th items can not be neighbors in a leaf */
|
|
int bad_pair (reiserfs_filsys_t * fs, struct buffer_head * bh, int pos)
|
|
{
|
|
struct item_head * ih;
|
|
|
|
ih = B_N_PITEM_HEAD (bh, pos);
|
|
|
|
if (comp_keys (&((ih - 1)->ih_key), &ih->ih_key) != -1) {
|
|
if (fsck_mode (fs) != FSCK_REBUILD)
|
|
one_more_corruption (fs, fatal);
|
|
return 1;
|
|
}
|
|
|
|
if (is_stat_data_ih (ih))
|
|
/* left item must be of another object */
|
|
if (comp_short_keys (&((ih - 1)->ih_key), &ih->ih_key) != -1) {
|
|
if (fsck_mode (fs) != FSCK_REBUILD)
|
|
one_more_corruption (fs, fatal);
|
|
return 1;
|
|
}
|
|
|
|
if (get_key_dirid (&ih->ih_key) == (__u32)-1) {
|
|
if (get_key_objectid (&ih->ih_key) == (__u32)-1) {
|
|
/* BAD BLOCK LIST SUPPORT
|
|
if (is_indirect_ih (ih) && comp_short_keys (&((ih - 1)->ih_key), &ih->ih_key) != 0)
|
|
return 0; // badblocks item
|
|
*/
|
|
/* it does not look like badblocks item */
|
|
} else {
|
|
/* safe link ? */
|
|
if (comp_short_keys (&((ih - 1)->ih_key), &ih->ih_key) == 0) {
|
|
if (is_indirect_ih (ih - 1) && is_direct_ih(ih))
|
|
return 0; /* safe link */
|
|
/* they do not look like safe links */
|
|
} else {
|
|
if (is_indirect_ih (ih) || is_direct_ih(ih))
|
|
return 0; /* safe link */
|
|
/* it does not look like safe link */
|
|
}
|
|
}
|
|
}
|
|
|
|
if (is_direct_ih(ih)) {
|
|
/* left item must be indirect or stat data item of the same
|
|
file */
|
|
if (not_of_one_file (&((ih - 1)->ih_key), &ih->ih_key)) {
|
|
if (fsck_mode (fs) != FSCK_REBUILD)
|
|
one_more_corruption (fs, fatal);
|
|
return 1;
|
|
}
|
|
|
|
if (!((is_stat_data_ih (ih - 1) && get_offset (&ih->ih_key) == 1) ||
|
|
(is_indirect_ih (ih - 1) &&
|
|
get_offset (&(ih - 1)->ih_key) + get_bytes_number (ih-1, bh->b_size) ==
|
|
get_offset (&ih->ih_key)))) {
|
|
if (fsck_mode (fs) != FSCK_REBUILD)
|
|
one_more_corruption (fs, fatal);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if (is_indirect_ih (ih) || is_direntry_ih (ih)) {
|
|
/* left item must be stat data of the same object */
|
|
if (not_of_one_file (&((ih - 1)->ih_key), &ih->ih_key) ||
|
|
!is_stat_data_ih (ih - 1)) {
|
|
if (fsck_mode (fs) != FSCK_REBUILD)
|
|
one_more_corruption (fs, fatal);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* 1 if block head or any of items is bad */
|
|
static int bad_leaf (reiserfs_filsys_t * fs, struct buffer_head * bh)
|
|
{
|
|
int i;
|
|
|
|
if (bad_block_head (fs, bh)) {
|
|
return 1;
|
|
}
|
|
|
|
for (i = 0; i < B_NR_ITEMS (bh); i ++) {
|
|
if (bad_item (fs, bh, i)) {
|
|
fsck_log ("bad_leaf: block %lu has invalid item %d: %H\n",
|
|
bh->b_blocknr, i, B_N_PITEM_HEAD (bh, i));
|
|
}
|
|
|
|
if (i && bad_pair (fs, bh, i)) {
|
|
fsck_log ("bad_leaf: block %lu has wrong order of items [%d, %d]: %k %k\n",
|
|
bh->b_blocknr, i-1, i, &B_N_PITEM_HEAD (bh, i-1)->ih_key, &B_N_PITEM_HEAD (bh, i)->ih_key);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* 1 if bh does not look like internal node */
|
|
static int bad_internal (reiserfs_filsys_t * fs, struct buffer_head * bh)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i <= B_NR_ITEMS (bh); i ++) {
|
|
if (i != B_NR_ITEMS (bh) && i != B_NR_ITEMS (bh) - 1)
|
|
/* make sure that keys are in increasing order */
|
|
if (comp_keys (B_N_PDELIM_KEY (bh, i), B_N_PDELIM_KEY (bh, i + 1)) != -1) {
|
|
fsck_log ("%s: vpf-10320: block %lu has wrong order of keys %k, %k\n",
|
|
__FUNCTION__, bh->b_blocknr, B_N_PDELIM_KEY (bh, i), B_N_PDELIM_KEY (bh, i + 1));
|
|
one_more_corruption (fs, fatal);
|
|
return 1;
|
|
}
|
|
|
|
/* make sure that the child is correct */
|
|
if (bad_block_number (fs, get_dc_child_blocknr (B_N_CHILD (bh,i)))) {
|
|
fsck_log ("%s: vpf-10330: block %lu: has bad pointer %d: %lu\n",
|
|
__FUNCTION__, bh->b_blocknr, i, get_dc_child_blocknr (B_N_CHILD (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 get_sb_tree_height (fs->fs_ondisk_sb) - h - 1;
|
|
}
|
|
|
|
|
|
/* bh must be formatted node. blk_level must be tree_height - h + 1 */
|
|
static int bad_node (reiserfs_filsys_t * fs, struct buffer_head ** path,
|
|
int h)
|
|
{
|
|
struct buffer_head ** pbh = &path[h];
|
|
|
|
if (B_LEVEL (*pbh) != h_to_level (fs, h)) {
|
|
fsck_log ("node (%lu) with wrong level (%d) found in the tree (should be %d)\n",
|
|
(*pbh)->b_blocknr, B_LEVEL (*pbh), h_to_level (fs, h));
|
|
one_more_corruption (fs, fatal);
|
|
return 1;
|
|
}
|
|
|
|
if (bad_block_number (fs, (*pbh)->b_blocknr)) {
|
|
one_more_corruption (fs, fatal);
|
|
fsck_log ("%s: vpf-10340: wrong block number %lu found in the tree\n",
|
|
__FUNCTION__, (*pbh)->b_blocknr);
|
|
return 1;
|
|
}
|
|
|
|
if (got_already (fs, (*pbh)->b_blocknr)) {
|
|
fsck_log ("%s: vpf-10350: block number %lu is already in the tree\n",
|
|
__FUNCTION__, (*pbh)->b_blocknr);
|
|
one_more_corruption (fs, fatal);
|
|
return 1;
|
|
}
|
|
|
|
if (is_leaf_node (*pbh)) {
|
|
fsck_check_stat (fs)->leaves ++;
|
|
return bad_leaf (fs, *pbh);
|
|
}
|
|
|
|
fsck_check_stat (fs)->internals ++;
|
|
return bad_internal (fs, *pbh);
|
|
}
|
|
|
|
|
|
/* internal node bh must point to block */
|
|
static int get_pos (struct buffer_head * bh, unsigned long block)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i <= B_NR_ITEMS (bh); i ++) {
|
|
if (get_dc_child_blocknr (B_N_CHILD (bh, i)) == block)
|
|
return i;
|
|
}
|
|
die ("get_pos: position for block %lu not found", block);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* path[h] - leaf node */
|
|
static struct key * lkey (struct buffer_head ** path, int h)
|
|
{
|
|
int pos;
|
|
|
|
while (h > 0) {
|
|
pos = get_pos (path[h - 1], path[h]->b_blocknr);
|
|
if (pos)
|
|
return B_N_PDELIM_KEY(path[h - 1], pos - 1);
|
|
h --;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* path[h] - leaf node */
|
|
static struct key * rkey (struct buffer_head ** path, int h)
|
|
{
|
|
int pos;
|
|
|
|
while (h > 0) {
|
|
pos = get_pos (path[h - 1], path[h]->b_blocknr);
|
|
if (pos != B_NR_ITEMS (path[h - 1]))
|
|
return B_N_PDELIM_KEY (path[h - 1], pos);
|
|
h --;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* are all delimiting keys correct */
|
|
static int bad_path (reiserfs_filsys_t * fs, struct buffer_head ** path, int h1)
|
|
{
|
|
int h = 0;
|
|
struct key * dk;
|
|
int pos = 0;
|
|
|
|
while (path[h])
|
|
h ++;
|
|
|
|
h--;
|
|
|
|
// path[h] is leaf
|
|
if (h != h1)
|
|
die ("bad_path: wrong path");
|
|
|
|
if (h)
|
|
pos = get_pos (path[h - 1], path[h]->b_blocknr);
|
|
|
|
dk = lkey (path, h);
|
|
if (dk && comp_keys (dk, B_N_PKEY (path[h], 0))) {
|
|
/* left delimiting key must be equal to the key of 0-th item in the
|
|
node */
|
|
fsck_log ("bad_path: left delimiting key %k must be equal to %k (block %lu, pos %d)\n",
|
|
dk, B_N_PKEY (path[h], 0), path[h]->b_blocknr, 0);
|
|
one_more_corruption (fs, fatal);
|
|
return 1;
|
|
}
|
|
|
|
dk = rkey (path, h);
|
|
if (dk && comp_keys (dk, B_N_PKEY (path[h],
|
|
get_blkh_nr_items (B_BLK_HEAD (path[h])) - 1)) != 1) {
|
|
/* right delimiting key must be bigger than the key of the last item
|
|
in the node */
|
|
fsck_log ("bad_path: right delimiting key %k must be equal to %k (block %lu, pos %d)\n",
|
|
dk, B_N_PKEY (path[h], get_blkh_nr_items (B_BLK_HEAD (path[h])) - 1),
|
|
path[h]->b_blocknr, get_blkh_nr_items (B_BLK_HEAD (path[h])) - 1);
|
|
one_more_corruption (fs, fatal);
|
|
return 1;
|
|
}
|
|
|
|
if (h && (get_dc_child_size (B_N_CHILD(path[h-1],pos)) +
|
|
get_blkh_free_space ((struct block_head *)path[h]->b_data) +
|
|
BLKH_SIZE != path[h]->b_size))
|
|
{
|
|
/* wrong dc_size */
|
|
|
|
fsck_log ("bad_path: wrong sum of dc_size %d (block %lu, pos %d) ",
|
|
get_dc_child_size (B_N_CHILD(path[h-1],pos)), path[h-1]->b_blocknr, pos);
|
|
fsck_log ("free space %d (block %lu) and BLKH_SIZE %lu",
|
|
get_blkh_free_space ((struct block_head *)path[h]->b_data),
|
|
path[h]->b_blocknr, BLKH_SIZE);
|
|
|
|
if (fsck_mode (fs) == FSCK_FIX_FIXABLE) {
|
|
set_dc_child_size (B_N_CHILD(path[h-1],pos), path[h]->b_size -
|
|
get_blkh_free_space ((struct block_head *)path[h]->b_data) - BLKH_SIZE);
|
|
fsck_log (" - fixed (%lu)\n", get_dc_child_size (B_N_CHILD(path[h-1],pos)));
|
|
mark_buffer_dirty (path[h-1]);
|
|
} else {
|
|
one_more_corruption (fs, fixable);
|
|
fsck_log ("\n");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void before_check_fs_tree (reiserfs_filsys_t * fs) {
|
|
init_control_bitmap (fs);
|
|
|
|
source_bitmap = reiserfs_create_bitmap (get_sb_block_count (fs->fs_ondisk_sb));
|
|
reiserfs_bitmap_copy (source_bitmap, fs->fs_bitmap2);
|
|
|
|
proper_id_map (fs) = init_id_map ();
|
|
}
|
|
|
|
static void after_check_fs_tree (reiserfs_filsys_t * fs) {
|
|
if (fsck_mode(fs) == FSCK_FIX_FIXABLE) {
|
|
fs->fs_dirt = 1;
|
|
reiserfs_flush_to_ondisk_bitmap (fs->fs_bitmap2, fs);
|
|
reiserfs_flush (fs);
|
|
}
|
|
reiserfs_delete_bitmap (source_bitmap);
|
|
reiserfs_delete_bitmap (control_bitmap);
|
|
flush_buffers (fs->fs_dev);
|
|
}
|
|
|
|
/* pass the S+ tree of filesystem */
|
|
void check_fs_tree (reiserfs_filsys_t * fs)
|
|
{
|
|
before_check_fs_tree (fs);
|
|
|
|
fsck_progress ("Checking S+tree..");
|
|
pass_through_tree (fs, bad_node, bad_path);
|
|
/* S+ tree is correct (including all objects have correct
|
|
sequences of items) */
|
|
fsck_progress ("ok\n");
|
|
|
|
/* compare created bitmap with the original */
|
|
handle_bitmaps (fs);
|
|
|
|
after_check_fs_tree (fs);
|
|
}
|
|
|
|
static int clean_attributes_handler (reiserfs_filsys_t * fs, struct buffer_head ** path, int h) {
|
|
struct buffer_head * bh = path[h];
|
|
int i;
|
|
|
|
if (B_LEVEL (bh) != h_to_level (fs, h)) {
|
|
reiserfs_panic ("node (%lu) with wrong level (%d) found in the tree (should be %d)\n",
|
|
bh->b_blocknr, B_LEVEL (bh), h_to_level (fs, h));
|
|
}
|
|
|
|
if (!is_leaf_node (bh))
|
|
return 0;
|
|
|
|
for (i = 0; i < B_NR_ITEMS (bh); i ++) {
|
|
if (is_stat_data_ih (B_N_PITEM_HEAD (bh, i)) &&
|
|
get_ih_item_len (B_N_PITEM_HEAD (bh, i)) == SD_SIZE) {
|
|
set_sd_v2_sd_attrs((struct stat_data *)B_N_PITEM(bh, i), 0);
|
|
mark_buffer_dirty (bh);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void do_clean_attributes (reiserfs_filsys_t * fs) {
|
|
pass_through_tree (fs, clean_attributes_handler, NULL);
|
|
set_sb_v2_flag (fs->fs_ondisk_sb, reiserfs_attrs_cleared);
|
|
mark_buffer_dirty (fs->fs_super_bh);
|
|
}
|
|
|
|
#if 0
|
|
|
|
void remove_internal_pointer(struct super_block * s, struct buffer_head ** path)
|
|
{
|
|
int h = 0;
|
|
int pos, items;
|
|
__u32 block;
|
|
|
|
|
|
while (path[h])
|
|
h ++;
|
|
|
|
h--;
|
|
block = path[h]->b_blocknr;
|
|
printf("\nremove pointer to (%d) block", block);
|
|
brelse(path[h]);
|
|
path[h] = 0;
|
|
h--;
|
|
while (h>=0)
|
|
{
|
|
if (B_NR_ITEMS(path[h]) <= 1)
|
|
{
|
|
block = path[h]->b_blocknr;
|
|
brelse(path[h]);
|
|
path[h] = 0;
|
|
mark_block_free(block);
|
|
/*unmark_block_formatted(block);*/
|
|
used_blocks++;
|
|
h --;
|
|
continue;
|
|
}
|
|
pos = get_pos (path[h], block);
|
|
if (pos)
|
|
{
|
|
memmove (B_N_CHILD(path[h],pos), B_N_CHILD(path[h],pos+1),
|
|
s->s_blocksize - BLKH_SIZE - B_NR_ITEMS(path[h])*KEY_SIZE - DC_SIZE*(pos+1));
|
|
memmove(B_N_PDELIM_KEY(path[h],pos-1), B_N_PDELIM_KEY(path[h],pos),
|
|
s->s_blocksize - BLKH_SIZE - (pos)*KEY_SIZE);
|
|
}else{
|
|
__u32 move_block = path[h]->b_blocknr;
|
|
int move_to_pos;
|
|
int height = h;
|
|
|
|
while(--height >= 0)
|
|
{
|
|
move_to_pos = get_pos (path[height], move_block);
|
|
if (move_to_pos == 0){
|
|
move_block = path[height]->b_blocknr;
|
|
continue;
|
|
}
|
|
*B_N_PDELIM_KEY(path[height], move_to_pos-1) = *B_N_PDELIM_KEY(path[h], 0);
|
|
break;
|
|
}
|
|
|
|
memmove (B_N_CHILD(path[h], 0), B_N_CHILD(path[h], 1),
|
|
s->s_blocksize - BLKH_SIZE - B_NR_ITEMS(path[h])*KEY_SIZE - DC_SIZE);
|
|
memmove(B_N_PDELIM_KEY(path[h], 0), B_N_PDELIM_KEY(path[h], 1),
|
|
s->s_blocksize - BLKH_SIZE - KEY_SIZE);
|
|
}
|
|
set_node_item_number(path[h], node_item_number(path[h]) - 1);
|
|
mark_buffer_dirty(path[h], 1);
|
|
break;
|
|
}
|
|
if (h == -1)
|
|
{
|
|
SB_DISK_SUPER_BLOCK(s)->s_root_block = ~0;
|
|
SB_DISK_SUPER_BLOCK(s)->s_tree_height = ~0;
|
|
mark_buffer_dirty(SB_BUFFER_WITH_SB(s), 1);
|
|
}
|
|
}
|
|
|
|
void handle_buffer(struct super_block * s, struct buffer_head * bh)
|
|
{
|
|
int i, j;
|
|
struct item_head * ih;
|
|
|
|
if (is_leaf_node (bh))
|
|
{
|
|
for (i = 0, ih = B_N_PITEM_HEAD (bh, 0); i < B_NR_ITEMS (bh); i ++, ih ++)
|
|
{
|
|
if (is_indirect_ih(ih))
|
|
for (j = 0; j < I_UNFM_NUM (ih); j ++)
|
|
if (B_I_POS_UNFM_POINTER(bh,ih,j)){
|
|
/*mark_block_unformatted(le32_to_cpu(B_I_POS_UNFM_POINTER(bh,ih,j)));*/
|
|
mark_block_used(le32_to_cpu(B_I_POS_UNFM_POINTER(bh,ih,j)));
|
|
used_blocks++;
|
|
}
|
|
if (is_stat_data_ih (ih)) {
|
|
/*add_event (STAT_DATA_ITEMS);*/
|
|
if (ih_key_format(ih) == KEY_FORMAT_1)
|
|
((struct stat_data_v1 *)B_I_PITEM(bh,ih))->sd_nlink = 0;
|
|
else
|
|
((struct stat_data *)B_I_PITEM(bh,ih))->sd_nlink = 0;
|
|
mark_buffer_dirty(bh, 1);
|
|
}
|
|
}
|
|
}
|
|
mark_block_used(bh->b_blocknr);
|
|
// we_met_it(s, bh->b_blocknr);
|
|
used_blocks++;
|
|
}
|
|
|
|
/* bh must be formatted node. blk_level must be tree_height - h + 1 */
|
|
static int handle_node (struct super_block * s, struct buffer_head ** path, int h)
|
|
{
|
|
if (bad_node(s, path, h)){
|
|
remove_internal_pointer(s, path);
|
|
return 1;
|
|
}
|
|
handle_buffer(s, path[h]);
|
|
return 0;
|
|
}
|
|
|
|
/* are all delimiting keys correct */
|
|
static int handle_path (struct super_block * s, struct buffer_head ** path, int h)
|
|
{
|
|
if (bad_path(s, path, h)){
|
|
remove_internal_pointer(s, path);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//return 1 to run rebuild tree from scratch
|
|
void check_internal_structure(struct super_block * s)
|
|
{
|
|
/* control bitmap is used to keep all blocks we should not put into tree again */
|
|
/* used bitmap is used to keep all inserted blocks. The same as control bitmap plus unfm blocks */
|
|
// init_control_bitmap(s);
|
|
|
|
printf ("Checking S+tree..");
|
|
|
|
pass_through_tree (s, handle_node, handle_path);
|
|
|
|
// compare_bitmaps(s);
|
|
printf ("ok\n");
|
|
}
|
|
|
|
#endif
|
|
/*
|
|
int check_sb (reiserfs_filsys_t * fs)
|
|
{
|
|
|
|
|
|
reiserfs_panic ("Not ready");
|
|
return 0;
|
|
#if 0
|
|
int format_sb = 0;
|
|
int problem = 0;
|
|
struct reiserfs_super_block * sb;
|
|
__u32 block_count;
|
|
unsigned long j_1st_block;
|
|
int sb_version;
|
|
|
|
sb = fs->fs_ondisk_sb;
|
|
j_1st_block = get_jp_journal_1st_block (sb_jp (sb));
|
|
|
|
// in (REISERFS_DISK_OFFSET_IN_BYTES / 4096) block
|
|
if ((is_reiser2fs_magic_string (sb) || is_reiser2fs_jr_magic_string (sb) )&&
|
|
j_1st_block == get_journal_new_start_must (fs)) {
|
|
// 3.6 or >=3.5.22
|
|
printf("\t 3.6.x format SB found\n");
|
|
format_sb = 1;
|
|
goto good_format;
|
|
}
|
|
|
|
if ( (is_reiserfs_magic_string (sb) ||is_reiser2fs_jr_magic_string (sb) ) &&
|
|
j_1st_block == get_journal_new_start_must (fs)) {
|
|
// >3.5.9(10) and <=3.5.21
|
|
printf("\t>=3.5.9 format SB found\n");
|
|
format_sb = 2;
|
|
goto good_format;
|
|
}
|
|
|
|
// in 2 block
|
|
if ( (is_reiser2fs_magic_string (sb) || is_reiser2fs_jr_magic_string (sb) ) &&
|
|
j_1st_block == get_journal_old_start_must (sb)) {
|
|
// <3.5.9(10) converted to new format
|
|
printf("\t< 3.5.9(10) SB converted to new format found \n");
|
|
format_sb = 3;
|
|
goto good_format;
|
|
}
|
|
|
|
if ( (is_reiserfs_magic_string (sb) ||is_reiser2fs_jr_magic_string (sb) ) &&
|
|
j_1st_block == get_journal_old_start_must (sb)) {
|
|
// <3.5.9(10)
|
|
printf("\t< 3.5.9(10) format SB found\n");
|
|
format_sb = 4;
|
|
goto good_format;
|
|
}
|
|
else
|
|
die("check SB: wrong SB format found\n");
|
|
|
|
good_format:
|
|
|
|
printf("\n\t%d-%d\n", get_sb_block_count (sb), get_sb_free_blocks (sb));
|
|
if (fs->fs_blocksize != 4096) {
|
|
//???
|
|
fsck_log("check SB: specified block size (%d) is not correct must be 4096\n",
|
|
fs->fs_blocksize);
|
|
problem++;
|
|
}
|
|
|
|
//for 4096 blocksize only
|
|
if ((get_sb_tree_height (sb) < DISK_LEAF_NODE_LEVEL + 1) ||
|
|
(get_sb_tree_height (sb) > MAX_HEIGHT)){
|
|
fsck_log ("check SB: wrong tree height (%d)\n", get_sb_tree_height (sb));
|
|
problem++;
|
|
}
|
|
|
|
block_count = count_blocks (fs->fs_file_name, fs->fs_blocksize);
|
|
|
|
if (get_sb_block_count (sb) > block_count){
|
|
fsck_log ("check SB: specified block number (%d) is too high\n",
|
|
get_sb_block_count (sb));
|
|
problem++;
|
|
}
|
|
|
|
if ((get_sb_root_block (sb) >= block_count)) {
|
|
fsck_log ("check SB: specified root block number (%d) is too high\n",
|
|
get_sb_root_block (sb));
|
|
problem++;
|
|
}
|
|
|
|
if (get_sb_free_blocks (sb) > get_sb_block_count (sb)) {
|
|
fsck_log ("check SB: specified free block number (%d) is too high\n",
|
|
get_sb_free_blocks (sb));
|
|
problem++;
|
|
}
|
|
|
|
if (get_sb_state (sb) != REISERFS_VALID_FS && get_sb_state (sb) != REISERFS_ERROR_FS){
|
|
fsck_log ("check SB: unknown (%d) state\n", get_sb_state (sb));
|
|
problem++;
|
|
}
|
|
|
|
if (get_sb_bmap_nr (sb) != (get_sb_block_count (sb) + (fs->fs_blocksize * 8 - 1)) / (fs->fs_blocksize * 8)) {
|
|
fsck_log("check SB: wrong bitmap number (%d)\n", get_sb_bmap_nr (sb));
|
|
problem++;
|
|
}
|
|
|
|
sb_version = get_sb_version (sb);
|
|
if (sb_version == REISERFS_VERSION_3 || sb_version == REISERFS_VERSION_2 || sb_version == REISERFS_VERSION_1) {
|
|
if (!((sb_version == REISERFS_VERSION_3 ||sb_version == REISERFS_VERSION_2) && (format_sb == 1 || format_sb == 3)) &&
|
|
!(sb_version == REISERFS_VERSION_1 && (format_sb == 2 || format_sb == 4))) {
|
|
fsck_log("check SB: wrong SB version == %d, format == %d\n",
|
|
sb_version, format_sb);
|
|
problem++;
|
|
}
|
|
} else {
|
|
fsck_log ("check SB: wrong SB version (%d)\n", sb_version);
|
|
problem++;
|
|
}
|
|
|
|
if ((sb_version == REISERFS_VERSION_3 ||sb_version == REISERFS_VERSION_2) &&
|
|
// FIXME:
|
|
(get_sb_hash_code (sb) < 1 || get_sb_hash_code (sb) > 3)) {
|
|
fsck_log("check SB: wrong hash (%d)\n", get_sb_hash_code (sb));
|
|
problem++;
|
|
}
|
|
|
|
|
|
if ((sb_version == REISERFS_VERSION_3 ||sb_version == REISERFS_VERSION_2) ?
|
|
(get_sb_oid_maxsize (sb) != ((fs->fs_blocksize - SB_SIZE) / sizeof(__u32) / 2 * 2)) :
|
|
(get_sb_oid_maxsize (sb) != ((fs->fs_blocksize - SB_SIZE_V1) / sizeof(__u32) / 2 * 2))) {
|
|
fsck_log("check SB: objectid map corrupted max_size == %d\n",
|
|
get_sb_oid_maxsize (sb));
|
|
problem++;
|
|
}
|
|
|
|
if (get_sb_oid_cursize (sb) < 2 ||
|
|
get_sb_oid_cursize (sb) > get_sb_oid_maxsize (sb)) {
|
|
fsck_log("check SB: objectid map corrupted cur_size == %d\n",
|
|
get_sb_oid_cursize (sb));
|
|
problem++;
|
|
}
|
|
|
|
if (get_jp_journal_size (sb_jp (sb)) < JOURNAL_DEFAULT_SIZE/32 ){
|
|
fsck_log("check SB: specified journal size (%d) is not correct must be not less that %d\n",
|
|
get_jp_journal_size (sb_jp (sb)), JOURNAL_DEFAULT_SIZE/32);
|
|
problem++;
|
|
}
|
|
|
|
if (!problem) {
|
|
fsck_progress ("\t No problem found\n");
|
|
} else if (fsck_log_file (fs) != stderr)
|
|
fsck_progress ("Look for super block corruptions in the log file\n");
|
|
|
|
return format_sb;
|
|
|
|
#endif
|
|
}
|
|
|
|
*/
|