/* * Copyright 1996-2004 by Hans Reiser, licensing governed by * reiserfsprogs/README */ #include "fsck.h" #include "progbar.h" struct tree_balance *cur_tb = 0; void reiserfsck_paste_into_item(struct reiserfs_path *path, const char *body, int size) { struct tree_balance tb; init_tb_struct(&tb, fs, path, size); if (fix_nodes( /*tb.transaction_handle, */ M_PASTE, &tb, 0 /*ih */ ) != CARRY_ON) //fix_nodes(options, tree_balance, ih_to_option, body_to_option) die("reiserfsck_paste_into_item: fix_nodes failed"); do_balance( /*tb.transaction_handle, */ &tb, 0, body, M_PASTE, 0 /*zero num */ ); } void reiserfsck_insert_item(struct reiserfs_path *path, struct item_head *ih, const char *body) { struct tree_balance tb; init_tb_struct(&tb, fs, path, IH_SIZE + get_ih_item_len(ih)); if (fix_nodes ( /*tb.transaction_handle, */ M_INSERT, &tb, ih /*, body */ ) != CARRY_ON) die("reiserfsck_insert_item: fix_nodes failed"); do_balance( /*tb.transaction_handle, */ &tb, ih, body, M_INSERT, 0 /*zero num */ ); } static void free_unformatted_nodes(struct item_head *ih, struct buffer_head *bh) { __u32 *punfm = (__u32 *) ih_item_body(bh, ih); unsigned int i; for (i = 0; i < I_UNFM_NUM(ih); i++) { __u32 unfm = d32_get(punfm, i); if (unfm != 0) { struct buffer_head *to_be_forgotten; to_be_forgotten = find_buffer(fs->fs_dev, unfm, fs->fs_blocksize); if (to_be_forgotten) { //atomic_inc(&to_be_forgotten->b_count); to_be_forgotten->b_count++; bforget(to_be_forgotten); } reiserfs_free_block(fs, unfm); } } } void reiserfsck_delete_item(struct reiserfs_path *path, int temporary) { struct tree_balance tb; struct item_head *ih = tp_item_head(path); if (is_indirect_ih(ih) && !temporary) free_unformatted_nodes(ih, PATH_PLAST_BUFFER(path)); init_tb_struct(&tb, fs, path, -(IH_SIZE + get_ih_item_len(ih))); if (fix_nodes( /*tb.transaction_handle, */ M_DELETE, &tb, 0 /*ih */ ) != CARRY_ON) die("reiserfsck_delete_item: fix_nodes failed"); do_balance( /*tb.transaction_handle, */ &tb, 0, 0, M_DELETE, 0 /*zero num */ ); } void reiserfsck_cut_from_item(struct reiserfs_path *path, int cut_size) { struct tree_balance tb; struct item_head *ih; if (cut_size >= 0) die("reiserfsck_cut_from_item: cut size == %d", cut_size); if (is_indirect_ih(ih = tp_item_head(path))) { struct buffer_head *bh = PATH_PLAST_BUFFER(path); __u32 unfm_ptr = d32_get((__u32 *) ih_item_body(bh, ih), I_UNFM_NUM(ih) - 1); if (unfm_ptr != 0) { struct buffer_head *to_be_forgotten; to_be_forgotten = find_buffer(fs->fs_dev, unfm_ptr, fs->fs_blocksize); if (to_be_forgotten) { //atomic_inc(&to_be_forgotten->b_count); to_be_forgotten->b_count++; bforget(to_be_forgotten); } reiserfs_free_block(fs, unfm_ptr); } } init_tb_struct(&tb, fs, path, cut_size); if (fix_nodes( /*tb.transaction_handle, */ M_CUT, &tb, 0) != CARRY_ON) die("reiserfsck_cut_from_item: fix_nodes failed"); do_balance( /*tb.transaction_handle, */ &tb, 0, 0, M_CUT, 0 /*zero num */ ); } /* uget_rkey is utils clone of stree.c/get_rkey */ /* struct reiserfs_key *uget_rkey (struct reiserfs_path *path) { int pos, offset = path->path_length; struct buffer_head * bh; if (offset < FIRST_PATH_ELEMENT_OFFSET) die ("uget_rkey: illegal offset in the path (%d)", offset); while (offset-- > FIRST_PATH_ELEMENT_OFFSET) { if (! buffer_uptodate (PATH_OFFSET_PBUFFER (path, offset))) die ("uget_rkey: parent is not uptodate"); // Parent at the path is not in the tree now. if (! B_IS_IN_TREE (bh = PATH_OFFSET_PBUFFER (path, offset))) die ("uget_rkey: buffer on the path is not in tree"); // Check whether position in the parrent is correct. if ((pos = PATH_OFFSET_POSITION (path, offset)) > B_NR_ITEMS (bh)) die ("uget_rkey: invalid position (%d) in the path", pos); // Check whether parent at the path really points to the child. if (get_dc_child_blocknr (B_N_CHILD (bh, pos)) != PATH_OFFSET_PBUFFER (path, offset + 1)->b_blocknr) die ("uget_rkey: invalid block number (%d). Must be %ld", get_dc_child_blocknr (B_N_CHILD (bh, pos)), PATH_OFFSET_PBUFFER (path, offset + 1)->b_blocknr); // Return delimiting key if position in the parent is not the last one. if (pos != B_NR_ITEMS (bh)) return internal_key(bh, pos); } // there is no right delimiting key return 0; } */ static unsigned long first_child(struct buffer_head *bh) { return get_dc_child_blocknr(B_N_CHILD(bh, 0)); } #if 0 static unsigned long last_child(struct buffer_head *bh) { return child_block_number(bh, node_item_number(bh)); } #endif static unsigned long get_child(int pos, struct buffer_head *parent) { if (pos == -1) return -1; if (pos > B_NR_ITEMS(parent)) die("get_child: no child found, should not happen: %d of %d", pos, B_NR_ITEMS(parent)); return get_dc_child_blocknr(B_N_CHILD(parent, pos)); } static void print(int cur, int total) { if (fsck_quiet(fs)) return; printf("/%3d (of %3d)", cur, total); fflush(stdout); } /* erase /XXX(of XXX) */ static void erase(void) { if (fsck_quiet(fs)) return; printf("\b\b\b\b\b\b\b\b\b\b\b\b\b"); printf(" "); printf("\b\b\b\b\b\b\b\b\b\b\b\b\b"); fflush(stdout); } void pass_through_tree(reiserfs_filsys_t *fs, do_after_read_t action1, do_on_full_path_t action2, int depth) { struct buffer_head *path[MAX_HEIGHT] = { 0, }; int total[MAX_HEIGHT] = { 0, }; int cur[MAX_HEIGHT] = { 0, }; int h = 0; unsigned long block = get_sb_root_block(fs->fs_ondisk_sb); int problem; struct spinner spinner; spinner_init(&spinner, fsck_progress_file(fs)); if (block >= get_sb_block_count(fs->fs_ondisk_sb) || not_data_block(fs, block)) { die("\nBad root block %lu. (--rebuild-tree did not complete)\n", block); } while (1) { problem = 0; if (path[h]) die("pass_through_tree: empty slot expected"); if (h) print(cur[h - 1], total[h - 1]); if (fs->fs_badblocks_bm && reiserfs_bitmap_test_bit(fs->fs_badblocks_bm, block)) { fsck_log ("%s: block %lu specified in badblock list found in tree, whole subtree skipped\n", __FUNCTION__, block); fsck_data(fs)->check.bad_nodes++; one_more_corruption(fs, FATAL); if (h == 0) { brelse(path[h]); path[h] = 0; break; } problem = 1; } else { spinner_touch(&spinner); path[h] = bread(fs->fs_dev, block, fs->fs_blocksize); if (path[h] == 0) /* FIXME: handle case when read failed */ die("pass_through_tree: unable to read %lu block on device 0x%x\n", block, fs->fs_dev); if (action1) if ((problem = action1(fs, path, h))) { fsck_log (" the problem in the internal node occured (%lu), whole subtree is skipped\n", path[h]->b_blocknr); fsck_data(fs)->check.bad_nodes++; if (h == 0) { brelse(path[h]); path[h] = 0; break; } } } /* Time to stop. */ if (h == depth) problem++; if (problem || is_leaf_node(path[h])) { if (!problem && action2) action2(fs, path, h); brelse(path[h]); if (h) erase(); while (h && (cur[h - 1] == total[h - 1] || problem)) { problem = 0; path[h] = 0; h--; brelse(path[h]); if (h) erase(); } if (h == 0) { path[h] = 0; break; } block = get_child(cur[h - 1], path[h - 1]); cur[h - 1]++; path[h] = 0; continue; } total[h] = B_NR_ITEMS(path[h]) + 1; cur[h] = 1; block = first_child(path[h]); h++; } spinner_clear(&spinner); }