blob: c2a8cec0d2bdb75be8222560fba0baa7cfda9278 [file]
/*
* Copyright 2000-2004 by Hans Reiser, licensing governed by
* reiserfsprogs/README
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#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++;
}
}