839 lines
23 KiB
C
839 lines
23 KiB
C
/*
|
|
* Copyright 1996-2004 by Hans Reiser, licensing governed by
|
|
* reiserfsprogs/README
|
|
*/
|
|
|
|
#include "fsck.h"
|
|
|
|
reiserfs_bitmap_t *bad_unfm_in_tree_once_bitmap;
|
|
|
|
//int step = 0; // 0 - find stat_data or any item ; 1 - find item ; 2 - already found
|
|
|
|
/* allocates buffer head and copy buffer content */
|
|
struct buffer_head *make_buffer(int dev, unsigned long blocknr, int size,
|
|
char *data)
|
|
{
|
|
struct buffer_head *bh;
|
|
|
|
bh = getblk(dev, blocknr, size);
|
|
if (buffer_uptodate(bh))
|
|
return bh;
|
|
// die ("make_buffer: uptodate buffer found");
|
|
memcpy(bh->b_data, data, size);
|
|
misc_set_bit(BH_Uptodate, (char *)&bh->b_state);
|
|
return bh;
|
|
}
|
|
|
|
static int find_not_of_one_file(struct reiserfs_key *to_find,
|
|
struct reiserfs_key *key)
|
|
{
|
|
if ((get_key_objectid(to_find) != ~(__u32) 0) &&
|
|
(get_key_objectid(to_find) != get_key_objectid(key)))
|
|
return 1;
|
|
if ((get_key_dirid(to_find) != ~(__u32) 0) &&
|
|
(get_key_dirid(to_find) != get_key_dirid(key)))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
int is_item_reachable(struct item_head *ih)
|
|
{
|
|
return ih_reachable(ih) ? 1 : 0;
|
|
}
|
|
|
|
void mark_item_unreachable(struct item_head *ih)
|
|
{
|
|
clean_ih_flags(ih);
|
|
mark_ih_unreachable(ih);
|
|
|
|
if (is_indirect_ih(ih))
|
|
set_ih_free_space(ih, 0);
|
|
}
|
|
|
|
void mark_item_reachable(struct item_head *ih, struct buffer_head *bh)
|
|
{
|
|
mark_ih_reachable(ih);
|
|
mark_buffer_dirty(bh);
|
|
}
|
|
|
|
static void stat_data_in_tree(struct buffer_head *bh, struct item_head *ih)
|
|
{
|
|
#if 0
|
|
__u32 objectid;
|
|
|
|
objectid = get_key_objectid(&ih->ih_key);
|
|
|
|
if (mark_objectid_really_used(proper_id_map(fs), objectid)) {
|
|
stat_shared_objectid_found(fs);
|
|
mark_objectid_really_used(shared_id_map(fs), objectid);
|
|
}
|
|
#endif
|
|
|
|
zero_nlink(ih, ih_item_body(bh, ih));
|
|
}
|
|
|
|
static char *still_bad_unfm_ptr_to_string(int val)
|
|
{
|
|
switch (val) {
|
|
case 1:
|
|
return "a leaf";
|
|
case 2:
|
|
return "shared between a few files";
|
|
case 3:
|
|
return "not a data block";
|
|
case 4:
|
|
return "not used in on-disk bitmap";
|
|
case 5:
|
|
return "out of partition boundary";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
/* this just marks blocks pointed by an indirect item as used in the
|
|
new bitmap */
|
|
static void indirect_in_tree(struct buffer_head *bh, struct item_head *ih)
|
|
{
|
|
unsigned int i;
|
|
__u32 *unp;
|
|
__u32 unfm_ptr;
|
|
int ret;
|
|
|
|
unp = (__u32 *) ih_item_body(bh, ih);
|
|
|
|
for (i = 0; i < I_UNFM_NUM(ih); i++) {
|
|
unfm_ptr = d32_get(unp, i);
|
|
if (unfm_ptr == 0)
|
|
continue;
|
|
if ((ret = still_bad_unfm_ptr_1(unfm_ptr)))
|
|
reiserfs_panic
|
|
("%s: block %lu: The file %k points to the block (%u) which is %s",
|
|
__FUNCTION__, bh->b_blocknr, &ih->ih_key, unfm_ptr,
|
|
still_bad_unfm_ptr_to_string(ret));
|
|
|
|
mark_block_used(unfm_ptr, 1);
|
|
}
|
|
}
|
|
|
|
static void leaf_is_in_tree_now(struct buffer_head *bh)
|
|
{
|
|
item_action_t actions[] = { stat_data_in_tree, indirect_in_tree,
|
|
NULL, NULL };
|
|
|
|
mark_block_used((bh)->b_blocknr, 1);
|
|
|
|
for_every_item(bh, mark_item_unreachable, actions);
|
|
|
|
pass_1_stat(fs)->inserted_leaves++;
|
|
|
|
mark_buffer_dirty(bh);
|
|
}
|
|
|
|
static void insert_pointer(struct buffer_head *bh, struct reiserfs_path *path)
|
|
{
|
|
struct item_head *ih;
|
|
char *body;
|
|
int retval;
|
|
struct tree_balance tb;
|
|
|
|
init_tb_struct(&tb, fs, path, 0x7fff);
|
|
|
|
/* fix_nodes & do_balance must work for internal nodes only */
|
|
ih = NULL;
|
|
|
|
retval = fix_nodes( /*tb.transaction_handle, */ M_INTERNAL, &tb, ih);
|
|
if (retval != CARRY_ON)
|
|
die("insert_pointer: fix_nodes failed with retval == %d",
|
|
retval);
|
|
|
|
/* child_pos: we insert after position child_pos: this feature of the insert_child */
|
|
/* there is special case: we insert pointer after
|
|
(-1)-st key (before 0-th key) in the parent */
|
|
if (PATH_LAST_POSITION(path) == 0 && path->pos_in_item == 0)
|
|
PATH_H_B_ITEM_ORDER(path, 0) = -1;
|
|
else {
|
|
if (PATH_H_PPARENT(path, 0) == NULL)
|
|
PATH_H_B_ITEM_ORDER(path, 0) = 0;
|
|
/* PATH_H_B_ITEM_ORDER (path, 0) = PATH_H_PPARENT (path, 0) ? PATH_H_B_ITEM_ORDER (path, 0) : 0;*/
|
|
}
|
|
|
|
ih = NULL;
|
|
body = (char *)bh;
|
|
//memmode = 0;
|
|
|
|
do_balance(&tb, ih, body, M_INTERNAL, 0);
|
|
|
|
leaf_is_in_tree_now(bh);
|
|
}
|
|
|
|
/* return 1 if left and right can be joined. 0 otherwise */
|
|
static int balance_condition_fails(struct buffer_head *left,
|
|
struct buffer_head *right)
|
|
{
|
|
if (B_FREE_SPACE(left) >= B_CHILD_SIZE(right) -
|
|
(are_items_mergeable
|
|
(item_head(left, B_NR_ITEMS(left) - 1),
|
|
item_head(right, 0), left->b_size) ? IH_SIZE : 0))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
/* return 1 if new can be joined with last node on the path or with
|
|
its right neighbor, 0 otherwise */
|
|
static int balance_condition_2_fails(struct buffer_head *new,
|
|
struct reiserfs_path *path)
|
|
{
|
|
struct buffer_head *bh;
|
|
struct reiserfs_key *right_dkey;
|
|
int pos, used_space;
|
|
|
|
bh = PATH_PLAST_BUFFER(path);
|
|
|
|
if (balance_condition_fails(bh, new))
|
|
/* new node can be joined with last buffer on the path */
|
|
return 1;
|
|
|
|
/* new node can not be joined with its left neighbor */
|
|
|
|
right_dkey = uget_rkey(path);
|
|
if (right_dkey == NULL)
|
|
/* there is no right neighbor */
|
|
return 0;
|
|
|
|
pos = PATH_H_POSITION(path, 1);
|
|
if (pos == B_NR_ITEMS(bh = PATH_H_PBUFFER(path, 1))) {
|
|
/* we have to read parent of right neighbor. For simplicity we
|
|
call search_by_key, which will read right neighbor as well */
|
|
INITIALIZE_REISERFS_PATH(path_to_right_neighbor);
|
|
|
|
if (reiserfs_search_by_key_4
|
|
(fs, right_dkey, &path_to_right_neighbor) != ITEM_FOUND)
|
|
reiserfs_panic
|
|
("%s: block %lu, pointer %d: The left delimiting key %k of the block (%lu) is wrong,"
|
|
"the item cannot be found", __FUNCTION__,
|
|
PATH_H_PBUFFER(path, 1)->b_blocknr, pos,
|
|
right_dkey,
|
|
get_dc_child_blocknr(B_N_CHILD(bh, pos + 1)));
|
|
|
|
used_space =
|
|
B_CHILD_SIZE(PATH_PLAST_BUFFER(&path_to_right_neighbor));
|
|
pathrelse(&path_to_right_neighbor);
|
|
} else
|
|
used_space = get_dc_child_size(B_N_CHILD(bh, pos + 1));
|
|
|
|
if (B_FREE_SPACE(new) >= used_space -
|
|
(are_items_mergeable
|
|
(item_head(new, B_NR_ITEMS(new) - 1),
|
|
(struct item_head *)right_dkey, new->b_size) ? IH_SIZE : 0))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void get_max_buffer_key(struct buffer_head *bh, struct reiserfs_key *key)
|
|
{
|
|
struct item_head *ih;
|
|
|
|
ih = item_head(bh, B_NR_ITEMS(bh) - 1);
|
|
copy_key(key, &(ih->ih_key));
|
|
|
|
if (is_direntry_key(key)) {
|
|
/* copy deh_offset 3-rd and 4-th key components of the last entry */
|
|
set_offset(KEY_FORMAT_1, key,
|
|
get_deh_offset(B_I_DEH(bh, ih) +
|
|
get_ih_entry_count(ih) - 1));
|
|
|
|
} else if (!is_stat_data_key(key))
|
|
/* get key of the last byte, which is contained in the item */
|
|
set_offset(key_format(key), key,
|
|
get_offset(key) + get_bytes_number(ih,
|
|
bh->b_size) - 1);
|
|
}
|
|
|
|
int tree_is_empty(void)
|
|
{
|
|
return (get_sb_root_block(fs->fs_ondisk_sb) == ~(__u32) 0 ||
|
|
get_sb_root_block(fs->fs_ondisk_sb) == 0) ? 1 : 0;
|
|
}
|
|
|
|
void make_single_leaf_tree(struct buffer_head *bh)
|
|
{
|
|
/* tree is empty, make tree root */
|
|
set_sb_root_block(fs->fs_ondisk_sb, bh->b_blocknr);
|
|
set_sb_tree_height(fs->fs_ondisk_sb, 2);
|
|
mark_buffer_dirty(fs->fs_super_bh);
|
|
leaf_is_in_tree_now(bh);
|
|
}
|
|
|
|
/* inserts pointer to leaf into tree if possible. If not, marks node as
|
|
uninsertable in special bitmap */
|
|
static void try_to_insert_pointer_to_leaf(struct buffer_head *new_bh)
|
|
{
|
|
INITIALIZE_REISERFS_PATH(path);
|
|
struct buffer_head *bh; /* last path buffer */
|
|
struct reiserfs_key *first_bh_key, last_bh_key; /* first and last keys of new buffer */
|
|
struct reiserfs_key last_path_buffer_last_key, *right_dkey;
|
|
int ret_value;
|
|
|
|
if (tree_is_empty() == 1) {
|
|
make_single_leaf_tree(new_bh);
|
|
return;
|
|
}
|
|
|
|
first_bh_key = leaf_key(new_bh, 0);
|
|
|
|
/* try to find place in the tree for the first key of the coming node */
|
|
ret_value = reiserfs_search_by_key_4(fs, first_bh_key, &path);
|
|
if (ret_value == ITEM_FOUND)
|
|
goto cannot_insert;
|
|
|
|
/* get max key in the new node */
|
|
get_max_buffer_key(new_bh, &last_bh_key);
|
|
|
|
bh = PATH_PLAST_BUFFER(&path);
|
|
if (comp_keys(leaf_key(bh, 0), &last_bh_key) ==
|
|
1 /* first is greater */ ) {
|
|
/* new buffer falls before the leftmost leaf */
|
|
if (balance_condition_fails(new_bh, bh))
|
|
goto cannot_insert;
|
|
|
|
if (uget_lkey(&path) != NULL ||
|
|
PATH_LAST_POSITION(&path) != 0)
|
|
die("try_to_insert_pointer_to_leaf: bad search result");
|
|
|
|
path.pos_in_item = 0;
|
|
goto insert;
|
|
}
|
|
|
|
/* get max key of buffer, that is in tree */
|
|
get_max_buffer_key(bh, &last_path_buffer_last_key);
|
|
if (comp_keys(&last_path_buffer_last_key, first_bh_key) !=
|
|
-1 /* second is greater */ )
|
|
/* first key of new buffer falls in the middle of node that is in tree */
|
|
goto cannot_insert;
|
|
|
|
right_dkey = uget_rkey(&path);
|
|
if (right_dkey
|
|
&& comp_keys(right_dkey, &last_bh_key) != 1 /* first is greater */ )
|
|
goto cannot_insert;
|
|
|
|
if (balance_condition_2_fails(new_bh, &path))
|
|
goto cannot_insert;
|
|
|
|
insert:
|
|
insert_pointer(new_bh, &path);
|
|
goto out;
|
|
|
|
cannot_insert:
|
|
/* statistic */
|
|
|
|
mark_block_uninsertable(new_bh->b_blocknr);
|
|
|
|
out:
|
|
pathrelse(&path);
|
|
return;
|
|
}
|
|
|
|
/* everything should be correct already in the leaf but contents of indirect
|
|
items. So we only
|
|
1. zero slots pointing to a leaf
|
|
2. zero pointers to blocks which are pointed already
|
|
3. what we should do with directory entries hashed by another hash?
|
|
they are deleted for now
|
|
*/
|
|
static void pass1_correct_leaf(reiserfs_filsys_t *fs, struct buffer_head *bh)
|
|
{
|
|
unsigned int i, j;
|
|
struct item_head *ih;
|
|
__u32 *ind_item;
|
|
__u32 unfm_ptr;
|
|
int dirty = 0;
|
|
|
|
ih = item_head(bh, 0);
|
|
for (i = 0; i < B_NR_ITEMS(bh); i++, ih++) {
|
|
if (is_direntry_ih(ih)) {
|
|
struct reiserfs_de_head *deh;
|
|
__u32 offset;
|
|
char *name;
|
|
int name_len;
|
|
unsigned int hash_code;
|
|
|
|
deh = B_I_DEH(bh, ih);
|
|
offset = 0;
|
|
for (j = 0; j < get_ih_entry_count(ih); j++) {
|
|
name = name_in_entry(deh + j, j);
|
|
name_len = name_in_entry_length(ih, deh + j, j);
|
|
|
|
if ((j == 0 && is_dot(name, name_len)) ||
|
|
(j == 1 && is_dot_dot(name, name_len))) {
|
|
continue;
|
|
}
|
|
|
|
hash_code =
|
|
find_hash_in_use(name, name_len,
|
|
get_deh_offset(deh + j),
|
|
get_sb_hash_code(fs->
|
|
fs_ondisk_sb));
|
|
if (hash_code !=
|
|
get_sb_hash_code(fs->fs_ondisk_sb)) {
|
|
fsck_log
|
|
("pass1: block %lu, item %d, entry %d: The entry \"%.*s\" of the %k is hashed with %s "
|
|
"whereas proper hash is %s",
|
|
bh->b_blocknr, i, j, name_len,
|
|
name, &ih->ih_key,
|
|
code2name(hash_code),
|
|
code2name(get_sb_hash_code
|
|
(fs->fs_ondisk_sb)));
|
|
if (get_ih_entry_count(ih) == 1) {
|
|
delete_item(fs, bh, i);
|
|
fsck_log
|
|
(" - the only entry - item was deleted\n");
|
|
i--;
|
|
ih--;
|
|
break;
|
|
} else {
|
|
cut_entry(fs, bh, i, j, 1);
|
|
fsck_log(" - deleted\n");
|
|
j--;
|
|
deh = B_I_DEH(bh, ih);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (j && offset >= get_deh_offset(deh + j)) {
|
|
fsck_log
|
|
("pass1: block %lu, item %d, entry %d: The entry "
|
|
"\"%.*s\" of the %k has hash offset %lu not "
|
|
"larger smaller than the previous one %lu. The "
|
|
"entry is deleted.\n",
|
|
bh->b_blocknr, i, j, name_len,
|
|
name, &ih->ih_key,
|
|
get_deh_offset(deh + j), offset);
|
|
cut_entry(fs, bh, i, j, 1);
|
|
j--;
|
|
deh = B_I_DEH(bh, ih);
|
|
continue;
|
|
}
|
|
|
|
offset = get_deh_offset(deh + j);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (!is_indirect_ih(ih))
|
|
continue;
|
|
|
|
/* correct indirect items */
|
|
ind_item = (__u32 *) ih_item_body(bh, ih);
|
|
|
|
for (j = 0; j < I_UNFM_NUM(ih); j++) {
|
|
unfm_ptr = d32_get(ind_item, j);
|
|
|
|
if (!unfm_ptr)
|
|
continue;
|
|
|
|
/* this corruption of indirect item had to be fixed in pass0 */
|
|
if (not_data_block(fs, unfm_ptr)
|
|
|| unfm_ptr >= get_sb_block_count(fs->fs_ondisk_sb))
|
|
/*!was_block_used (unfm_ptr)) */
|
|
reiserfs_panic
|
|
("%s: block %lu, item %d, pointer %d: The wrong pointer (%u) in the file %K. "
|
|
"Must be fixed on pass0.", __FUNCTION__,
|
|
bh->b_blocknr, i, j, unfm_ptr,
|
|
&ih->ih_key);
|
|
|
|
/* 1. zero slots pointing to a leaf */
|
|
if (is_used_leaf(unfm_ptr)) {
|
|
dirty++;
|
|
d32_put(ind_item, j, 0);
|
|
pass_1_stat(fs)->pointed_leaves++;
|
|
continue;
|
|
}
|
|
|
|
/* 2. zero pointers to blocks which are pointed already */
|
|
if (is_bad_unformatted(unfm_ptr)) {
|
|
/* this unformatted pointed more than once. Did we see it already? */
|
|
if (!is_bad_unfm_in_tree_once(unfm_ptr))
|
|
/* keep first reference to it and mark about that in
|
|
special bitmap */
|
|
mark_bad_unfm_in_tree_once(unfm_ptr);
|
|
else {
|
|
/* Yes, we have seen this pointer already, zero other pointers to it. */
|
|
dirty++;
|
|
d32_put(ind_item, j, 0);
|
|
pass_1_stat(fs)->non_unique_pointers++;
|
|
continue;
|
|
}
|
|
} else
|
|
pass_1_stat(fs)->correct_pointers++;
|
|
}
|
|
}
|
|
|
|
if (dirty)
|
|
mark_buffer_dirty(bh);
|
|
}
|
|
|
|
struct si *remove_saved_item(struct si *si)
|
|
{
|
|
struct si *tmp = si->si_next;
|
|
|
|
freemem(si->si_dnm_data);
|
|
freemem(si);
|
|
return tmp;
|
|
}
|
|
|
|
/* fsck starts creating of this bitmap on pass 1. It will then become
|
|
on-disk bitmap */
|
|
static void init_new_bitmap(reiserfs_filsys_t *fs)
|
|
{
|
|
unsigned int i;
|
|
unsigned long block;
|
|
unsigned long reserved;
|
|
|
|
fsck_new_bitmap(fs) =
|
|
reiserfs_create_bitmap(get_sb_block_count(fs->fs_ondisk_sb));
|
|
|
|
/* mark_block_used skips 0, set the bit explicitly */
|
|
reiserfs_bitmap_set_bit(fsck_new_bitmap(fs), 0);
|
|
|
|
/* mark other skipped blocks and super block used */
|
|
for (i = 1; i <= fs->fs_super_bh->b_blocknr; i++)
|
|
mark_block_used(i, 1);
|
|
|
|
/* mark bitmap blocks as used */
|
|
block = fs->fs_super_bh->b_blocknr + 1;
|
|
for (i = 0; i < reiserfs_fs_bmap_nr(fs); i++) {
|
|
mark_block_used(block, 1);
|
|
if (spread_bitmaps(fs))
|
|
block =
|
|
(block / (fs->fs_blocksize * 8) +
|
|
1) * (fs->fs_blocksize * 8);
|
|
else
|
|
block++;
|
|
}
|
|
|
|
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_new_bitmap: Wrong super block location, you must run --rebuild-sb.");
|
|
|
|
block = get_journal_start_must(fs);
|
|
|
|
for (i = block; i < reserved + block; i++)
|
|
mark_block_used(i, 1);
|
|
|
|
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)) {
|
|
if (reiserfs_bitmap_test_bit
|
|
(fsck_new_bitmap(fs), i))
|
|
reiserfs_panic
|
|
("%s: The block pointer to not data area, must be fixed on the pass0.\n",
|
|
__FUNCTION__);
|
|
reiserfs_bitmap_set_bit(fsck_new_bitmap(fs), i);
|
|
}
|
|
}
|
|
#if 0
|
|
/* mark journal area as used if journal is standard or it is non standard
|
|
and initialy has been created on a main device */
|
|
reserved = 0;
|
|
if (!is_reiserfs_jr_magic_string(fs->fs_ondisk_sb))
|
|
reserved = get_jp_journal_size(sb_jp(fs->fs_ondisk_sb));
|
|
if (get_sb_reserved_for_journal(fs->fs_ondisk_sb))
|
|
reserved = get_sb_reserved_for_journal(fs->fs_ondisk_sb);
|
|
if (reserved) {
|
|
for (i = 0; i <= reserved; i++)
|
|
mark_block_used(i + get_jp_journal_1st_block(sb_jp
|
|
(fs->
|
|
fs_ondisk_sb)));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* this makes a map of blocks which can be allocated when fsck will
|
|
continue */
|
|
static void find_allocable_blocks(reiserfs_filsys_t *fs)
|
|
{
|
|
unsigned long i;
|
|
|
|
fsck_progress("Looking for allocable blocks .. ");
|
|
|
|
fsck_allocable_bitmap(fs) =
|
|
reiserfs_create_bitmap(get_sb_block_count(fs->fs_ondisk_sb));
|
|
reiserfs_bitmap_fill(fsck_allocable_bitmap(fs));
|
|
|
|
/* find how many leaves are not pointed by any indirect items */
|
|
for (i = 0; i < get_sb_block_count(fs->fs_ondisk_sb); i++) {
|
|
if (not_data_block(fs, i))
|
|
/* journal (or reserved for it area), bitmaps, super block and
|
|
blocks before it */
|
|
continue;
|
|
|
|
if (is_good_unformatted(i) && is_bad_unformatted(i))
|
|
die("find_allocable_blocks: The block (%lu) is masr as good and as bad at once.", i);
|
|
|
|
if (is_good_unformatted(i) || is_bad_unformatted(i)) {
|
|
/* blocks which were pointed once or more thn onec from indirect
|
|
items - they will not be allocated */
|
|
continue;
|
|
}
|
|
|
|
/* make allocable not leaves, not bad blocks */
|
|
if (!is_used_leaf(i) && (!fs->fs_badblocks_bm ||
|
|
!reiserfs_bitmap_test_bit(fs->
|
|
fs_badblocks_bm,
|
|
i))) {
|
|
/* this is not leaf and it is not pointed by found indirect items,
|
|
so it does not contains anything valuable */
|
|
make_allocable(i);
|
|
pass_1_stat(fs)->allocable_blocks++;
|
|
}
|
|
}
|
|
fsck_progress("finished\n");
|
|
|
|
fs->block_allocator = reiserfsck_reiserfs_new_blocknrs;
|
|
fs->block_deallocator = reiserfsck_reiserfs_free_block;
|
|
}
|
|
|
|
static void before_pass_1(reiserfs_filsys_t *fs)
|
|
{
|
|
/* this will become an on-disk bitmap */
|
|
init_new_bitmap(fs);
|
|
|
|
/* bitmap of leaves which could not be inserted on pass 1. FIXME:
|
|
no need to have 1 bit per block */
|
|
fsck_uninsertables(fs) =
|
|
reiserfs_create_bitmap(get_sb_block_count(fs->fs_ondisk_sb));
|
|
reiserfs_bitmap_fill(fsck_uninsertables(fs));
|
|
|
|
/* find blocks which can be allocated */
|
|
find_allocable_blocks(fs);
|
|
|
|
/* bitmap of bad unformatted nodes which are in the tree already */
|
|
bad_unfm_in_tree_once_bitmap =
|
|
reiserfs_create_bitmap(get_sb_block_count(fs->fs_ondisk_sb));
|
|
|
|
/* pass 1 does not deal with objectid */
|
|
}
|
|
|
|
static void save_pass_1_result(reiserfs_filsys_t *fs)
|
|
{
|
|
FILE *file;
|
|
int retval;
|
|
|
|
file = open_file("temp_fsck_file.deleteme", "w+");
|
|
if (!file)
|
|
return;
|
|
|
|
/* to be able to get a new bitmap on pass2 we should flush it on disk
|
|
new_bitmap should not be flushed on disk if run without -d option, as
|
|
if fsck fails on pass1 we get wrong bitmap on the next fsck start */
|
|
reiserfs_flush_to_ondisk_bitmap(fsck_new_bitmap(fs), fs);
|
|
|
|
/* to be able to restart with pass 2 we need bitmap of
|
|
uninsertable blocks and bitmap of alocable blocks */
|
|
reiserfs_begin_stage_info_save(file, PASS_1_DONE);
|
|
reiserfs_bitmap_save(file, fsck_uninsertables(fs));
|
|
reiserfs_bitmap_save(file, fsck_allocable_bitmap(fs));
|
|
reiserfs_end_stage_info_save(file);
|
|
close_file(file);
|
|
retval = rename("temp_fsck_file.deleteme", state_dump_file(fs));
|
|
if (retval != 0)
|
|
fsck_progress
|
|
("pass 1: Could not rename the temporary file temp_fsck_file.deleteme to %s",
|
|
state_dump_file(fs));
|
|
}
|
|
|
|
void load_pass_1_result(FILE * fp, reiserfs_filsys_t *fs)
|
|
{
|
|
fsck_new_bitmap(fs) =
|
|
reiserfs_create_bitmap(get_sb_block_count(fs->fs_ondisk_sb));
|
|
reiserfs_bitmap_copy(fsck_new_bitmap(fs), fs->fs_bitmap2);
|
|
|
|
fsck_uninsertables(fs) = reiserfs_bitmap_load(fp);
|
|
fsck_allocable_bitmap(fs) = reiserfs_bitmap_load(fp);
|
|
|
|
fs->block_allocator = reiserfsck_reiserfs_new_blocknrs;
|
|
fs->block_deallocator = reiserfsck_reiserfs_free_block;
|
|
|
|
if (!fsck_new_bitmap(fs) || !fsck_allocable_bitmap(fs) ||
|
|
!fsck_allocable_bitmap(fs))
|
|
fsck_exit("State dump file seems corrupted. Run without -d");
|
|
|
|
/* we need objectid map on pass 2 to be able to relocate files */
|
|
proper_id_map(fs) = id_map_init();
|
|
/* Not implemented yet.
|
|
fetch_objectid_map (proper_id_map (fs), fs);
|
|
*/
|
|
|
|
fsck_progress("Pass 1 result loaded. %u blocks used, %u allocable, "
|
|
"still to be inserted %u\n",
|
|
reiserfs_bitmap_ones(fsck_new_bitmap(fs)),
|
|
reiserfs_bitmap_zeros(fsck_allocable_bitmap(fs)),
|
|
reiserfs_bitmap_zeros(fsck_uninsertables(fs)));
|
|
}
|
|
|
|
/* reads blocks marked in leaves_bitmap and tries to insert them into
|
|
tree */
|
|
static void do_pass_1(reiserfs_filsys_t *fs)
|
|
{
|
|
struct buffer_head *bh;
|
|
unsigned long i;
|
|
int what_node;
|
|
unsigned long done = 0, total;
|
|
|
|
/* on pass0 we have found that amount of leaves */
|
|
total = reiserfs_bitmap_ones(leaves_bitmap);
|
|
|
|
/* read all leaves found on the pass 0 */
|
|
for (i = 0; i < get_sb_block_count(fs->fs_ondisk_sb); i++) {
|
|
if (!is_used_leaf(i))
|
|
continue;
|
|
|
|
print_how_far(fsck_progress_file(fs), &done, total, 1,
|
|
fsck_quiet(fs));
|
|
|
|
/* at least one of nr_to_read blocks is to be checked */
|
|
bh = bread(fs->fs_dev, i, fs->fs_blocksize);
|
|
if (!bh) {
|
|
/* we were reading one block at time, and failed, so mark
|
|
block bad */
|
|
fsck_progress
|
|
("pass1: Reading of the block %lu failed\n", i);
|
|
continue;
|
|
}
|
|
|
|
what_node = who_is_this(bh->b_data, bh->b_size);
|
|
if (what_node != THE_LEAF) {
|
|
check_memory_msg();
|
|
die("build_the_tree: Nothing but leaves are expected. Block %lu - %s\n", i, which_block(what_node));
|
|
}
|
|
|
|
if (is_block_used(i) && !(block_of_journal(fs, i) &&
|
|
fsck_data(fs)->rebuild.
|
|
use_journal_area))
|
|
/* block is in new tree already */
|
|
die("build_the_tree: The leaf (%lu) is in the tree already\n", i);
|
|
|
|
/* fprintf (block_list, "leaf %d\n", i + j); */
|
|
pass_1_stat(fs)->leaves++;
|
|
|
|
/* the leaf may still contain indirect items with wrong
|
|
slots. Fix that */
|
|
pass1_correct_leaf(fs, bh);
|
|
|
|
if (get_blkh_nr_items(B_BLK_HEAD(bh)) == 0) {
|
|
/* all items were deleted on pass 0 or pass 1 */
|
|
mark_buffer_clean(bh);
|
|
brelse(bh);
|
|
continue;
|
|
}
|
|
|
|
if (is_leaf_bad(bh)) {
|
|
/* FIXME: will die */
|
|
fsck_log
|
|
("is_leaf_bad: WARNING: The leaf (%lu) is formatted badly. Will be handled on the the pass2.\n",
|
|
bh->b_blocknr);
|
|
mark_block_uninsertable(bh->b_blocknr);
|
|
brelse(bh);
|
|
continue;
|
|
}
|
|
|
|
if (block_of_journal(fs, i)
|
|
&& fsck_data(fs)->rebuild.use_journal_area) {
|
|
/* FIXME: temporary thing */
|
|
if (tree_is_empty()) {
|
|
/* we insert inot tree only first leaf of journal */
|
|
unsigned long block;
|
|
struct buffer_head *new_bh;
|
|
|
|
block = alloc_block();
|
|
if (!block)
|
|
die("could not allocate block");
|
|
new_bh = getblk(bh->b_dev, block, bh->b_size);
|
|
memcpy(new_bh->b_data, bh->b_data, bh->b_size);
|
|
mark_buffer_uptodate(new_bh, 1);
|
|
mark_buffer_dirty(new_bh);
|
|
make_single_leaf_tree(new_bh);
|
|
brelse(new_bh);
|
|
brelse(bh);
|
|
continue;
|
|
}
|
|
|
|
/* other blocks of journal will be inserted in pass 2 */
|
|
mark_block_uninsertable(bh->b_blocknr);
|
|
brelse(bh);
|
|
continue;
|
|
}
|
|
|
|
try_to_insert_pointer_to_leaf(bh);
|
|
brelse(bh);
|
|
}
|
|
|
|
fsck_progress("\n");
|
|
|
|
}
|
|
|
|
static void after_pass_1(reiserfs_filsys_t *fs)
|
|
{
|
|
time_t t;
|
|
|
|
/* update fsck_state */
|
|
|
|
/* we should not flush bitmaps on disk after pass1, because
|
|
new_bitmap contains only those blocks which are good leaves or
|
|
just allocated internal blocks. */
|
|
|
|
set_sb_fs_state(fs->fs_ondisk_sb, PASS_1_DONE);
|
|
mark_buffer_dirty(fs->fs_super_bh);
|
|
|
|
/* write all dirty blocks */
|
|
fsck_progress("Flushing..");
|
|
fs->fs_dirt = 1;
|
|
reiserfs_flush(fs);
|
|
fsck_progress("finished\n");
|
|
|
|
stage_report(1, fs);
|
|
|
|
/* we do not need this anymore */
|
|
delete_aux_bitmaps();
|
|
reiserfs_delete_bitmap(bad_unfm_in_tree_once_bitmap);
|
|
|
|
if (!fsck_run_one_step(fs)) {
|
|
if (fsck_user_confirmed(fs, "Continue? (Yes):", "Yes\n", 1))
|
|
/* reiserfsck continues */
|
|
return;
|
|
} else
|
|
save_pass_1_result(fs);
|
|
|
|
if (proper_id_map(fs)) {
|
|
/* when we run pass 1 only - we do not have proper_id_map */
|
|
id_map_free(proper_id_map(fs));
|
|
proper_id_map(fs) = NULL;
|
|
}
|
|
|
|
time(&t);
|
|
fsck_progress("###########\n"
|
|
"reiserfsck finished pass 1 at %s"
|
|
"###########\n", ctime(&t));
|
|
fs->fs_dirt = 1;
|
|
reiserfs_close(fs);
|
|
exit(0);
|
|
}
|
|
|
|
void pass_1(reiserfs_filsys_t *fs)
|
|
{
|
|
fsck_progress("\nPass 1 (will try to insert %lu leaves):\n",
|
|
reiserfs_bitmap_ones(fsck_source_bitmap(fs)));
|
|
if (fsck_log_file(fs) != stderr)
|
|
fsck_log("####### Pass 1 #######\n");
|
|
|
|
before_pass_1(fs);
|
|
|
|
/* try to insert leaves found during pass 0 */
|
|
do_pass_1(fs);
|
|
|
|
after_pass_1(fs);
|
|
}
|