190 lines
4.6 KiB
C
190 lines
4.6 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 "util/misc.h"
|
|
|
|
static int fsck_squeeze(reiserfs_filsys_t *fs, reiserfs_path_t *path) {
|
|
reiserfs_bh_t *bh_left, *bh;
|
|
REISERFS_PATH_INIT(lpath);
|
|
reiserfs_key_t key;
|
|
__u64 off;
|
|
__u32 oid;
|
|
int res;
|
|
|
|
bh = REISERFS_PATH_LEAF(path);
|
|
|
|
key = *(reiserfs_ih_key_at(bh, 0));
|
|
if ((off = reiserfs_key_get_off(&key)) == 0) {
|
|
if ((oid = reiserfs_key_get_oid(&key)) == 0)
|
|
reiserfs_panic("Object id 0 found in the tree.");
|
|
|
|
reiserfs_key_set_oid(&key, reiserfs_key_get_oid(&key) - 1);
|
|
reiserfs_key_set_off(reiserfs_key_format(&key), &key, -1ull);
|
|
} else {
|
|
reiserfs_key_set_off(reiserfs_key_format(&key), &key,
|
|
reiserfs_key_get_off(&key) - 1);
|
|
}
|
|
|
|
reiserfs_tree_search_item (fs, &key, &lpath);
|
|
bh_left = REISERFS_PATH_LEAF (&lpath);
|
|
|
|
if (bh->b_blocknr == bh_left->b_blocknr ||
|
|
!reiserfs_tree_node_mergeable(bh_left, bh))
|
|
{
|
|
reiserfs_tree_pathrelse(&lpath);
|
|
return 0;
|
|
}
|
|
|
|
/* Mergeable leaves must be merged. */
|
|
res = reiserfs_tree_merge(fs, &lpath, path);
|
|
reiserfs_tree_pathrelse(&lpath);
|
|
reiserfs_bitmap_clear_bit(fsck_new_bitmap (fs), bh->b_blocknr);
|
|
return res;
|
|
}
|
|
|
|
void fsck_cleanup (void) {
|
|
const reiserfs_key_t * rdkey;
|
|
reiserfs_path_t path;
|
|
reiserfs_key_t key;
|
|
reiserfs_bh_t * bh;
|
|
reiserfs_ih_t * ih;
|
|
unsigned long items;
|
|
int i, res;
|
|
|
|
path.path_length = REISERFS_PATH_OFFILL;
|
|
key = root_dir_key;
|
|
|
|
fsck_progress ("Pass 4 - ");
|
|
items = 0;
|
|
|
|
while (1) {
|
|
res = reiserfs_tree_search_item (fs, &key, &path);
|
|
|
|
bh = REISERFS_PATH_LEAF (&path);
|
|
ih = REISERFS_PATH_IH (&path);
|
|
|
|
if (res != ITEM_FOUND) {
|
|
if (REISERFS_PATH_LEAF_POS (&path) == 0)
|
|
break;
|
|
|
|
REISERFS_PATH_LEAF_POS (&path) --;
|
|
ih = REISERFS_PATH_IH (&path);
|
|
|
|
if (reiserfs_key_comp2(&key, &ih->ih_key))
|
|
break;
|
|
|
|
/* Position found. */
|
|
//fsck_log("Warning: Node %lu, item %u, %k: item start is expected, "
|
|
// "not a unit.\n", bh->b_blocknr,
|
|
// REISERFS_PATH_LEAF_POS (&path), &ih->ih_key);
|
|
}
|
|
|
|
/* print ~ how many leaves were scanned and how fast it was */
|
|
if (!fsck_quiet (fs))
|
|
util_misc_speed (fsck_progress_file(fs), items++, 0, 50, 0);
|
|
|
|
for (i = REISERFS_PATH_LEAF_POS (&path);
|
|
i < reiserfs_node_items (bh); i ++, ih ++)
|
|
{
|
|
if (!fsck_item_reach(ih)) {
|
|
REISERFS_PATH_LEAF_POS (&path) = i;
|
|
rdkey = reiserfs_tree_next_key(&path, fs);
|
|
if (rdkey)
|
|
key = *rdkey;
|
|
else
|
|
memset (&key, 0xff, REISERFS_KEY_SIZE);
|
|
|
|
pass_4_stat (fs)->deleted_items ++;
|
|
|
|
/* fsck_log("Node %lu, item %u, %k: delete.\n",
|
|
bh->b_blocknr, i, &ih->ih_key); */
|
|
reiserfs_tree_delete (fs, &path, 0);
|
|
goto cont;
|
|
}
|
|
|
|
if (reiserfs_ih_get_flags(ih) != 0) {
|
|
reiserfs_ih_clflags(ih);
|
|
reiserfs_buffer_mkdirty(bh);
|
|
}
|
|
|
|
/* Merge mergeable items. */
|
|
if (i == 0)
|
|
continue;
|
|
|
|
if (reiserfs_ih_stat(ih))
|
|
continue;
|
|
|
|
/* If not stat data and types match, try to merge items. */
|
|
if (reiserfs_key_get_type(&ih->ih_key) !=
|
|
reiserfs_key_get_type(&(ih - 1)->ih_key))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (reiserfs_ih_dir(ih) ||
|
|
must_there_be_a_hole(ih - 1, &ih->ih_key) == 0)
|
|
{
|
|
REISERFS_PATH_LEAF_POS (&path) = i;
|
|
rdkey = reiserfs_tree_next_key(&path, fs);
|
|
if (rdkey)
|
|
key = *rdkey;
|
|
else
|
|
memset (&key, 0xff, REISERFS_KEY_SIZE);
|
|
|
|
/* fsck_log ("%s: 2 items of the same type %k, %k are found "
|
|
"in the same node (%d), pos (%u). Merged.\n",
|
|
__FUNCTION__, &ih->ih_key, &(ih + 1)->ih_key,
|
|
bh->b_blocknr, REISERFS_PATH_LEAF_POS(&path)); */
|
|
fsck_tree_merge(&path);
|
|
goto cont;
|
|
}
|
|
}
|
|
|
|
REISERFS_PATH_LEAF_POS(&path) = i - 1;
|
|
rdkey = reiserfs_tree_next_key (&path, fs);
|
|
if (rdkey)
|
|
key = *rdkey;
|
|
else
|
|
memset (&key, 0xff, REISERFS_KEY_SIZE);
|
|
|
|
fsck_squeeze(fs, &path);
|
|
|
|
reiserfs_tree_pathrelse (&path);
|
|
cont:
|
|
/* to make gcc 3.2 do not sware here */;
|
|
}
|
|
|
|
reiserfs_tree_pathrelse (&path);
|
|
|
|
fsck_progress ("finished\n");
|
|
fsck_stage_report (FS_CLEANUP, fs);
|
|
|
|
/* after pass 4 */
|
|
|
|
/* put bitmap on place */
|
|
reiserfs_bitmap_copy (fs->fs_bitmap2, fsck_new_bitmap (fs));
|
|
|
|
/* update super block */
|
|
reiserfs_sb_set_free (fs->fs_ondisk_sb,
|
|
reiserfs_bitmap_zeros (fsck_new_bitmap (fs)));
|
|
|
|
reiserfs_buffer_mkdirty (fs->fs_super_bh);
|
|
|
|
/* write all dirty blocks */
|
|
fsck_progress ("Flushing..");
|
|
fs->fs_dirt = 1;
|
|
reiserfs_bitmap_flush (fs->fs_bitmap2, fs);
|
|
reiserfs_fs_flush (fs);
|
|
fsck_progress ("finished\n");
|
|
|
|
|
|
return;
|
|
}
|