/* * Copyright 2000-2004 by Hans Reiser, licensing governed by * reiserfsprogs/README */ #ifdef HAVE_CONFIG_H # include #endif #include "reiserfs/libreiserfs.h" #include "misc/unaligned.h" #include "misc/misc.h" reiserfs_key_t badblock_key = {REISERFS_BAD_DID, REISERFS_BAD_OID, {{0, 0},}}; void reiserfs_badblock_traverse(reiserfs_filsys_t * fs, badblock_func_t action, void *data) { reiserfs_path_t badblock_path; reiserfs_key_t rd_key = badblock_key; const reiserfs_key_t *key; badblock_path.path_length = REISERFS_PATH_OFFILL; reiserfs_key_set_sec (KEY_FORMAT_2, &badblock_key, 1, TYPE_EXTENT); while (1) { if (reiserfs_tree_search_item (fs, &rd_key, &badblock_path) == IO_ERROR) { fprintf (stderr, "%s: Some problems while searching by the key " "occured. Probably due to tree corruptions.\n", __FUNCTION__); reiserfs_tree_pathrelse (&badblock_path); break; } if (reiserfs_nh_get_items (NODE_HEAD (REISERFS_PATH_LEAF (&badblock_path))) <= REISERFS_PATH_LEAF_POS (&badblock_path)) { reiserfs_tree_pathrelse (&badblock_path); break; } rd_key = REISERFS_PATH_IH(&badblock_path)->ih_key; if (reiserfs_key_get_did(&rd_key) != REISERFS_BAD_DID || reiserfs_key_get_oid(&rd_key) != REISERFS_BAD_OID || !reiserfs_key_ext(&rd_key)) { reiserfs_tree_pathrelse (&badblock_path); break; } if ((key = reiserfs_tree_next_key(&badblock_path, fs))) rd_key = *key; else memset(&rd_key, 0, sizeof(rd_key)); action(fs, &badblock_path, data); if (reiserfs_key_get_did(&rd_key) == 0) break; } } static void callback_badblock_rm(reiserfs_filsys_t *fs, reiserfs_path_t *badblock_path, void *data) { reiserfs_tb_t tb; reiserfs_ih_t * tmp_ih; tmp_ih = REISERFS_PATH_IH(badblock_path); memset (REISERFS_PATH_ITEM (badblock_path), 0, reiserfs_ih_get_len (tmp_ih)); reiserfs_tb_init (&tb, fs, badblock_path, -(REISERFS_IH_SIZE + reiserfs_ih_get_len(REISERFS_PATH_IH(badblock_path)))); if (reiserfs_fix_nodes (M_DELETE, &tb, 0) != CARRY_ON) misc_die ("%s: reiserfs_fix_nodes failed", __FUNCTION__); reiserfs_tb_balance (&tb, 0, 0, M_DELETE, 0/*zero num*/); } void reiserfs_badblock_extract(reiserfs_filsys_t *fs, reiserfs_path_t *badblock_path, void *data) { reiserfs_ih_t *tmp_ih; __u32 *ind_item; __u32 i; if (!fs->fs_badblocks_bm) { fs->fs_badblocks_bm = reiserfs_bitmap_create(reiserfs_sb_get_blocks(fs->fs_ondisk_sb)); reiserfs_bitmap_zero (fs->fs_badblocks_bm); } tmp_ih = REISERFS_PATH_IH(badblock_path); ind_item = (__u32 *)REISERFS_PATH_ITEM(badblock_path); for (i = 0; i < reiserfs_ext_count(tmp_ih); i++) { reiserfs_bitmap_set_bit(fs->fs_badblocks_bm, d32_get(ind_item, i)); } reiserfs_tree_pathrelse (badblock_path); } static int reiserfs_alloc_blocks (reiserfs_filsys_t * fs, unsigned long *blknr, unsigned long start, int count) { int i; for (i = 0; i < count; i ++) { blknr[i] = 0; if (reiserfs_bitmap_find_zero_bit(fs->fs_bitmap2, blknr + i)) misc_die ("%s: failed to allocate a block.", __FUNCTION__); reiserfs_bitmap_set_bit(fs->fs_bitmap2, blknr[i]); } return CARRY_ON; } void reiserfs_badblock_flush (reiserfs_filsys_t * fs, int replace) { reiserfs_tb_t tb; reiserfs_path_t badblock_path; reiserfs_ih_t badblock_ih; __u32 ni; __u64 offset; __u32 i, j; if (fs->fs_badblocks_bm == NULL) return; /* delete all items with badblock_key */ if (replace) reiserfs_badblock_traverse(fs, callback_badblock_rm, NULL); memset(&badblock_ih, 0, sizeof(badblock_ih)); reiserfs_ih_set_format (&badblock_ih, KEY_FORMAT_2); reiserfs_ih_set_len (&badblock_ih, REISERFS_EXT_SIZE); reiserfs_ih_set_free (&badblock_ih, 0); reiserfs_ih_set_loc (&badblock_ih, 0); reiserfs_key_set_did (&badblock_ih.ih_key, REISERFS_BAD_DID); reiserfs_key_set_oid (&badblock_ih.ih_key, REISERFS_BAD_OID); reiserfs_key_set_type (KEY_FORMAT_2, &badblock_ih.ih_key, TYPE_EXTENT); j = 0; fs->block_allocator = reiserfs_alloc_blocks; /* insert all badblock pointers */ for (i = 0; i < fs->fs_badblocks_bm->bm_bit_size; i++) { int retval; if (!reiserfs_bitmap_test_bit (fs->fs_badblocks_bm, i)) continue; offset = j * fs->fs_blocksize + 1; reiserfs_key_set_off (KEY_FORMAT_2, &badblock_ih.ih_key, offset); ni = cpu_to_le32 (i); retval = reiserfs_tree_search_position (fs, &badblock_ih.ih_key, &badblock_path); switch (retval) { case (FILE_NOT_FOUND): reiserfs_tb_init (&tb, fs, &badblock_path, REISERFS_IH_SIZE + reiserfs_ih_get_len(&badblock_ih)); if (reiserfs_fix_nodes (M_INSERT, &tb, &badblock_ih) != CARRY_ON) misc_die ("reiserfs_badblock_flush: reiserfs_fix_nodes failed"); reiserfs_tb_balance (&tb, &badblock_ih, (void *)&ni , M_INSERT, 0); break; case (POSITION_NOT_FOUND): case (POSITION_FOUND): /* Insert the new item to the found position. */ reiserfs_tb_init (&tb, fs, &badblock_path, REISERFS_EXT_SIZE); if (reiserfs_fix_nodes (M_PASTE, &tb, 0) != CARRY_ON) misc_die ("reiserfs_badblock_flush: reiserfs_fix_nodes failed"); reiserfs_tb_balance (&tb, 0, (const char *)&ni, M_PASTE, 0); break; } j++; } }