/*
 * Copyright 1996-2004 by Hans Reiser, licensing governed by 
 * reiserfsprogs/README
 */

#include "fsck.h"

/* g_disk_bitmap initially contains copy of disk bitmaps
   (cautious version of it);

   g_new_bitmap initially has marked only super block, bitmap blocks
   and bits after the end of bitmap

   in pass 1 we go through g_disk_bitmap. 

   If block does not look like formatted node, we skip it.

   If block contains internal node, put 0 in g_disk_bitmap if block is
   not used in new tree yet.

   If block contains leaf and is used already (by an indirect item
   handled already to this time) save all items. They will be inserted
   into tree after pass 1.

   If block looking like leaf is not used in the new tree, try to
   insert in into tree. If it is not possible, mark block in
   g_uninsertable_leaf_bitmap. Blocks marked in this bitmap will be inserted into tree in pass 2. They can not be

  This means, that in pass 1 when we have
   found block containing the internal nodes we mark it in
   g_disk_bitmap as free (reiserfs_free_internal_block). When block
   gets into new tree it is marked in g_new_bitmap (mark_block_used)
   When collecting resources for do_balance, we mark new blocks with
   mark_block_used. After do_balance we unmark unused new blocks in
   g_new_bitmap (bitmap.c:/reiserfs_free_block)

   Allocating of new blocks: look for 0 bit in g_disk_bitmap
   (find_zero_bit_in_bitmap), make sure, that g_new_bitmap contains 0
   at the corresponding bit (is_block_used).
      
 */



/* is blocks used (marked by 1 in new bitmap) in the tree which is being built
   (as leaf, internal, bitmap, or unformatted node) */
int is_block_used (unsigned long block)
{
    return reiserfs_bitmap_test_bit (fsck_new_bitmap (fs), block);
}

void mark_block_used (unsigned long block, int check_hardware)
{
    if (!block)
	return;
    if (is_block_used (block)) {
	if (check_hardware)
	    check_memory_msg();
	die ("mark_block_used: (%lu) used already", block);
    }

    reiserfs_bitmap_set_bit (fsck_new_bitmap (fs), block);
}


void mark_block_free (unsigned long block)
{
    if (!is_block_used (block))
	die ("mark_block_free: (%lu) is free already", block);

    reiserfs_bitmap_clear_bit (fsck_new_bitmap (fs), block);
}


int is_block_uninsertable (unsigned long block)
{
    return !reiserfs_bitmap_test_bit (fsck_uninsertables (fs), block);
}


/* uninsertable block is marked by bit clearing */
void mark_block_uninsertable (unsigned long block)
{
    if (is_block_uninsertable (block))
	die ("mark_block_uninsertable: (%lu) is uninsertable already", block);

    reiserfs_bitmap_clear_bit (fsck_uninsertables (fs), block);
    /* we do not need thsi actually */
    pass_1_stat (fs)->uninsertable_leaves ++;
}


/* FIXME: should be able to work around no disk space */
int reiserfsck_reiserfs_new_blocknrs (reiserfs_filsys_t * fs,
				      unsigned long * free_blocknrs,
				      unsigned long start, int amount_needed)
{
    int i;

    if (!are_there_allocable_blocks (amount_needed))
	die ("out of disk space");
    for (i = 0; i < amount_needed; i ++) {
	free_blocknrs[i] = alloc_block ();
	if (!free_blocknrs[i])
	    die ("reiserfs_new_blocknrs: 0 is allocated");
	mark_block_used (free_blocknrs[i], 0);
    }
    return CARRY_ON;
}


// FIXME: do you check readability of a block? If f_read fails - you
// free block in bitmap or if you mark bad blocks used to avoid their
// allocation in future you should have bad block counter in a super
// block. Another minor issue: users of _get_new_buffer expect buffer
// to be filled with 0s
struct buffer_head * reiserfsck_get_new_buffer (unsigned long start)
{
    unsigned long blocknr = 0;
    struct buffer_head * bh = NULL;

    reiserfs_new_blocknrs (fs, &blocknr, start, 1);
    bh = getblk (fs->fs_dev, blocknr, fs->fs_blocksize);
    return bh;
}


/* free block in new bitmap */
int reiserfsck_reiserfs_free_block (reiserfs_filsys_t * fs, unsigned long block)
{
    mark_block_free (block);

    /* put it back to pool of blocks for allocation */
    make_allocable (block);
    return 0;
}






















































