Example #1
0
/* this makes a map of blocks which can be allocated when fsck will continue: */
static void find_allocable_blocks (reiserfs_filsys_t fs)
{
    int i;
 

    fsck_progress ("Looking for allocable blocks .. ");
    stats (fs)->all_blocks = SB_BLOCK_COUNT (fs);

    /* find how many leaves are not pointed by any indirect items */
    for (i = 0; i < SB_BLOCK_COUNT (fs); i ++) {
	if (not_data_block (fs, i))
	    continue;

#if 0
	if (!was_block_used (i)) {
	    /* marked free in the on-disk bitmap - so it is allocable */
	    make_allocable (i);
	    stat_allocable_found (fs);
	    continue;
	}
#endif

	if (pass0_is_leaf (i)) {
	    /* block looks like a reiserfs leaf */
	    stats(fs)->leaves ++;
	    if (pass0_is_good_unfm (i) || pass0_is_bad_unfm (i))
		/* leaf to which one or more indirect items point to */
		stats(fs)->pointed_leaves ++;
	}

	if (pass0_is_good_unfm (i) && pass0_is_bad_unfm (i))
	    die ("find_allocable_blocks: bad and good unformatted");

	if (pass0_is_good_unfm (i)) {
	    /* blocks which were pointed only once */
	    stats(fs)->pointed ++;
	    stats(fs)->pointed_once ++;
	    continue;
	}
	if (pass0_is_bad_unfm (i)) {
	    /* blocks pointed more than once */
	    stats(fs)->pointed ++;
	    stats(fs)->pointed_more_than_once ++;
	    continue;
	}

	/* blocks which marked used but are not leaves and are not
	   pointed (internals in short) get into bitmap of allocable
	   blocks */
	if (!pass0_is_leaf (i)) {
	    make_allocable (i);
	    stats(fs)->allocable ++;
	}
    }
    fsck_progress ("ok\n");
}
Example #2
0
/* there are three way to say of which blocks the tree should be built off:
 default - */
static void make_aux_bitmaps (reiserfs_filsys_t fs)
{

    /* bitmap of leaves found on the device. It will be saved if -c specified */
    leaves_bitmap = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));

    good_unfm_bitmap = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));

    bad_unfm_bitmap = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));

}
Example #3
0
int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *hint,
                               b_blocknr_t * new_blocknrs, int amount_needed,
                               int reserved_by_us /* Amount of blocks we have
						      already reserved */)
{
    int initial_amount_needed = amount_needed;
    int ret;
    struct super_block *s = hint->th->t_super;

    /* Check if there is enough space, taking into account reserved space */
    if ( SB_FREE_BLOCKS(s) - REISERFS_SB(s)->reserved_blocks <
            amount_needed - reserved_by_us)
        return NO_DISK_SPACE;
    /* should this be if !hint->inode &&  hint->preallocate? */
    /* do you mean hint->formatted_node can be removed ? - Zam */
    /* hint->formatted_node cannot be removed because we try to access
       inode information here, and there is often no inode assotiated with
       metadata allocations - green */

    if (!hint->formatted_node && hint->preallocate) {
        amount_needed = use_preallocated_list_if_available
                        (hint, new_blocknrs, amount_needed);
        if (amount_needed == 0)	/* all blocknrs we need we got from
                                   prealloc. list */
            return CARRY_ON;
        new_blocknrs += (initial_amount_needed - amount_needed);
    }

    /* find search start and save it in hint structure */
    determine_search_start(hint, amount_needed);
    if (hint->search_start >= SB_BLOCK_COUNT(s))
        hint->search_start = SB_BLOCK_COUNT(s) - 1;

    /* allocation itself; fill new_blocknrs and preallocation arrays */
    ret = blocknrs_and_prealloc_arrays_from_search_start
          (hint, new_blocknrs, amount_needed);

    /* we used prealloc. list to fill (partially) new_blocknrs array. If final allocation fails we
     * need to return blocks back to prealloc. list or just free them. -- Zam (I chose second
     * variant) */

    if (ret != CARRY_ON) {
        while (amount_needed ++ < initial_amount_needed) {
            reiserfs_free_block(hint->th, hint->inode, *(--new_blocknrs), 1);
        }
    }
    return ret;
}
Example #4
0
static inline int blocknrs_and_prealloc_arrays_from_search_start
(reiserfs_blocknr_hint_t *hint, b_blocknr_t *new_blocknrs, int amount_needed)
{
    struct super_block *s = hint->th->t_super;
    b_blocknr_t start = hint->search_start;
    b_blocknr_t finish = SB_BLOCK_COUNT(s) - 1;
    int second_pass = 0;
    int nr_allocated = 0;

    determine_prealloc_size(hint);
    while((nr_allocated
            += allocate_without_wrapping_disk(hint, new_blocknrs + nr_allocated, start, finish,
                    amount_needed - nr_allocated, hint->prealloc_size))
            < amount_needed) {

        /* not all blocks were successfully allocated yet*/
        if (second_pass) {	/* it was a second pass; we must free all blocks */
            while (nr_allocated --)
                reiserfs_free_block(hint->th, new_blocknrs[nr_allocated]);

            return NO_DISK_SPACE;
        } else {		/* refine search parameters for next pass */
            second_pass = 1;
            finish = start;
            start = 0;
            continue;
        }
    }
    return CARRY_ON;
}
Example #5
0
int is_reusable (struct super_block * s, b_blocknr_t block, int bit_value)
{
    int i, j;

    if (block == 0 || block >= SB_BLOCK_COUNT (s)) {
        reiserfs_warning (s, "vs-4010: is_reusable: block number is out of range %lu (%u)",
                          block, SB_BLOCK_COUNT (s));
        return 0;
    }

    /* it can't be one of the bitmap blocks */
    for (i = 0; i < SB_BMAP_NR (s); i ++)
        if (block == SB_AP_BITMAP (s)[i].bh->b_blocknr) {
            reiserfs_warning (s, "vs: 4020: is_reusable: "
                              "bitmap block %lu(%u) can't be freed or reused",
                              block, SB_BMAP_NR (s));
            return 0;
        }

    get_bit_address (s, block, &i, &j);

    if (i >= SB_BMAP_NR (s)) {
        reiserfs_warning (s, "vs-4030: is_reusable: there is no so many bitmap blocks: "
                          "block=%lu, bitmap_nr=%d", block, i);
        return 0;
    }

    if ((bit_value == 0 &&
            reiserfs_test_le_bit(j, SB_AP_BITMAP(s)[i].bh->b_data)) ||
            (bit_value == 1 &&
             reiserfs_test_le_bit(j, SB_AP_BITMAP (s)[i].bh->b_data) == 0)) {
        reiserfs_warning (s, "vs-4040: is_reusable: corresponding bit of block %lu does not "
                          "match required value (i==%d, j==%d) test_bit==%d",
                          block, i, j, reiserfs_test_le_bit (j, SB_AP_BITMAP (s)[i].bh->b_data));

        return 0;
    }

    if (bit_value == 0 && block == SB_ROOT_BLOCK (s)) {
        reiserfs_warning (s, "vs-4050: is_reusable: this is root block (%u), "
                          "it must be busy", SB_ROOT_BLOCK (s));
        return 0;
    }

    return 1;
}
Example #6
0
/* should be, if formatted node, then try to put on first part of the device
   specified as number of percent with mount option device, else try to put
   on last of device.  This is not to say it is good code to do so,
   but the effect should be measured.  */
static void inline set_border_in_hint(struct super_block *s, reiserfs_blocknr_hint_t *hint)
{
    b_blocknr_t border = SB_BLOCK_COUNT(hint->th->t_super) / s->u.reiserfs_sb.s_alloc_options.border;

    if (hint->formatted_node)
        hint->end = border - 1;
    else
        hint->beg = border;
}
Example #7
0
/* should be, if formatted node, then try to put on first part of the device
   specified as number of percent with mount option device, else try to put
   on last of device.  This is not to say it is good code to do so,
   but the effect should be measured.  */
static inline void set_border_in_hint(struct super_block *s, reiserfs_blocknr_hint_t *hint)
{
    b_blocknr_t border = SB_BLOCK_COUNT(s) / REISERFS_SB(s)->s_alloc_options.border;

    if (hint->formatted_node)
        hint->end = border - 1;
    else
        hint->beg = border;
}
Example #8
0
static int get_total_block_number (void)
{
  int i, j;
  int retval = 0;
    
  retval = 0;
    
  if (opt_pack_all)
    retval = SB_BLOCK_COUNT (&g_sb);
  else {
    for (i = 0; i < SB_BMAP_NR (&g_sb); i ++) {
      for (j = 0; j < g_sb.s_blocksize * 8; j ++)
	if (i * g_sb.s_blocksize * 8 + j < SB_BLOCK_COUNT (&g_sb) &&
	    test_bit (j, SB_AP_BITMAP (&g_sb)[i]->b_data))
	  retval ++;
    }
  }
  return retval;
}
Example #9
0
int are_there_used_leaves (unsigned long from, int count)
{
    int i;
    int used;

    used = 0;
    for (i = 0; i < count; i ++) {
	if ((SB_BLOCK_COUNT (fs) > from + i) &&
	    pass0_is_leaf (from + i))
	    used ++;
    }
    return used;
}
Example #10
0
void check_bitmap (struct super_block * s)
{
  int i = 0;
  int free = 0;
  char * buf;

  while (i < SB_BLOCK_COUNT (s)) {
    buf = SB_AP_BITMAP (s)[i / (s->s_blocksize * 8)]->b_data;
    if (!reiserfs_test_le_bit (i % (s->s_blocksize * 8), buf))
      free ++;
    i ++;
  }

  if (free != SB_FREE_BLOCKS (s))
    reiserfs_warning ("vs-4000: check_bitmap: %d free blocks, must be %d\n",
		      free, SB_FREE_BLOCKS (s));
}
Example #11
0
/* Tries to find contiguous zero bit window (given size) in given region of
 * bitmap and place new blocks there. Returns number of allocated blocks. */
static int scan_bitmap (struct reiserfs_transaction_handle *th,
                        unsigned long *start, unsigned long finish,
                        int min, int max, int unfm, unsigned long file_block)
{
    int nr_allocated=0;
    struct super_block * s = th->t_super;
    /* find every bm and bmap and bmap_nr in this file, and change them all to bitmap_blocknr
     * - Hans, it is not a block number - Zam. */

    int bm, off;
    int end_bm, end_off;
    int off_max = s->s_blocksize << 3;

    PROC_INFO_INC( s, scan_bitmap.call );
    if ( SB_FREE_BLOCKS(s) <= 0)
        return 0; // No point in looking for more free blocks

    get_bit_address (s, *start, &bm, &off);
    get_bit_address (s, finish, &end_bm, &end_off);

    // With this option set first we try to find a bitmap that is at least 10%
    // free, and if that fails, then we fall back to old whole bitmap scanning
    if ( TEST_OPTION(skip_busy, s) && SB_FREE_BLOCKS(s) > SB_BLOCK_COUNT(s)/20 ) {
        for (; bm < end_bm; bm++, off = 0) {
            if ( ( off && (!unfm || (file_block != 0))) || SB_AP_BITMAP(s)[bm].free_count > (s->s_blocksize << 3) / 10 )
                nr_allocated = scan_bitmap_block(th, bm, &off, off_max, min, max, unfm);
            if (nr_allocated)
                goto ret;
        }
        get_bit_address (s, *start, &bm, &off);
    }

    for (; bm < end_bm; bm++, off = 0) {
        nr_allocated = scan_bitmap_block(th, bm, &off, off_max, min, max, unfm);
        if (nr_allocated)
            goto ret;
    }

    nr_allocated = scan_bitmap_block(th, bm, &off, end_off + 1, min, max, unfm);

ret:
    *start = bm * off_max + off;
    return nr_allocated;

}
Example #12
0
void pack_partition (struct super_block * s)
{
    int i, j, k;
    uint32_t blocknumber32;
    uint16_t reclen16, data16;
    __u32 done = 0;
    char * data;
    long long bytes_to_transfer = 0;
    struct buffer_head * bh;
    int total_block_number;


    total_block_number = get_total_block_number ();
    

    /* write filesystem's block size to stdout as 16 bit number */
    reclen16 = htons (s->s_blocksize);
    if (opt_pack == 'p' || opt_pack_all == 'p')
	write (1, &reclen16, sizeof (uint16_t));
    bytes_to_transfer = sizeof (uint16_t);

    /* go through blocks which are marked used in cautious bitmap */
    for (i = 0; i < SB_BMAP_NR (s); i ++) {
	for (j = 0; j < s->s_blocksize; j ++) {
	    /* make sure, that we are not out of the device */
	    if (i * s->s_blocksize * 8 + j * 8 == SB_BLOCK_COUNT (s))
		goto out_of_bitmap;

	    if (i * s->s_blocksize * 8 + j * 8 + 8 > SB_BLOCK_COUNT (s))
		die ("build_the_tree: Out of bitmap");

	    if (opt_pack_all == 0)
		if (SB_AP_BITMAP (s)[i]->b_data[j] == 0) {
		    /* skip busy block if 'a' not specified */
		    continue;
		}

	    /* read 8 blocks at once */
	    bh = bread (s->s_dev, i * s->s_blocksize + j, s->s_blocksize * 8);
	    for (k = 0; k < 8; k ++) {
		__u32 block;
		
		block = i * s->s_blocksize * 8 + j * 8 + k;
		
		if (opt_pack_all == 0 && (SB_AP_BITMAP (s)[i]->b_data[j] & (1 << k)) == 0)
		    continue;
#if 0
		if ((SB_AP_BITMAP (s)[i]->b_data[j] & (1 << k)) == 0  || /* k-th block is free */
		    block < SB_BUFFER_WITH_SB (s)->b_blocknr) /* is in skipped for drive manager area */
		    continue;
#endif
		
		print_how_far (&done, total_block_number);
		
		data = bh->b_data + k * s->s_blocksize;

		if (not_formatted_node (data, s->s_blocksize)) {
		    /* ok, could not find formatted node here. But
                       this can be commit block, or bitmap which has
                       to be transferred */
		    if (!not_data_block (s, block)) {
			/* this is usual unformatted node. Transfer
                           its number only to erase previously existed
                           formatted nodes on the partition we will
                           apply transferred metadata to */
	    
			/* size of following record in network byte order */
			reclen16 = htons (2);

			/* the record record */
			data16 = htons (MAX_HEIGHT + 1);/*?*/
			data = (char *)&data16;
		    } else {
			/* write super block and bitmap block must be transferred as are */
			/* size of record  */
			reclen16 = htons (s->s_blocksize);
	    
			/* the record itself */
			data = data;
		    }
		} else {
		    /* any kind of formatted nodes gets here (super
                       block, desc block of journal): FIXME: it would
                       be useful to be able to find commit blocks */
		    zero_direct_items (data);
		    /* FIXME: do other packing */
		    /* write size of following record */
		    reclen16 = htons (s->s_blocksize);
		    
		    /* the record itself */
		    data = data;

#if 0
		    if (blkh->blk_level > DISK_LEAF_NODE_LEVEL) {
			/* block must look like internal node on the target
			   partition. But (currently) fsck do not consider internal
			   nodes, therefore we do not have to transfer contents of
			   internal nodes */
	    
			/* size of following record in network byte order */
			reclen16 = htons (2);
	    
			/* the record itself */
			data16 = htons (DISK_LEAF_NODE_LEVEL + 1);
			data = (char *)&data16;	  
		    } else {
	    
			/* leaf node found */
			ih = (struct item_head *)(blkh + 1);
	    
			/* fill direct items with 0s */
			for (l = 0; l < blkh->blk_nr_item; l ++, ih ++)
			    if (I_IS_DIRECT_ITEM (ih)) {
				direct_items ++;
				direct_item_total_length += ih->ih_item_len;
				memset ((char *)blkh + ih->ih_item_location, 0, ih->ih_item_len);
			    }
	    
			/* write size of following record */
			reclen16 = htons (s->s_blocksize);
	    
			/* the record itself */
			data = (char *)blkh;
		    }
#endif
		}
	  
		/*fprintf (stderr, "block %d, reclen %d\n", block, ntohs (reclen16));*/
	
		/* write block number */
		blocknumber32 = htonl (block);
		bytes_to_transfer += sizeof (uint32_t) + sizeof (uint16_t) + ntohs (reclen16);
		if (opt_pack == 'p' || opt_pack_all == 'p') {
		    write (1, &blocknumber32, sizeof (uint32_t));
		    /* write record len */
		    write (1, &reclen16, sizeof (uint16_t));
		    /* write the record */
		    write (1, data, ntohs (reclen16));
		}
	    }
      
	    bforget (bh);
	}
    }
    
 out_of_bitmap:
    fprintf (stderr, "done\n");
    if (opt_pack == 'c' || opt_pack_all == 'c')
	fprintf (stderr, "Bytes to transfer %Ld, sequential 0s %d in %d sequeneces (%items (%d unreacable))\n",
		 bytes_to_transfer, direct_item_total_length, direct_items, items, unreachable_items);
    else
	fprintf (stderr, "Bytes dumped %Ld, sequential 0s %d in %d sequeneces\n",
		 bytes_to_transfer, direct_item_total_length, direct_items);
    
    
}
Example #13
0
/* Tries to find contiguous zero bit window (given size) in given region of
 * bitmap and place new blocks there. Returns number of allocated blocks. */
static int scan_bitmap (struct reiserfs_transaction_handle *th,
                        b_blocknr_t *start, b_blocknr_t finish,
                        int min, int max, int unfm, unsigned long file_block)
{
    int nr_allocated=0;
    struct super_block * s = th->t_super;
    /* find every bm and bmap and bmap_nr in this file, and change them all to bitmap_blocknr
     * - Hans, it is not a block number - Zam. */

    int bm, off;
    int end_bm, end_off;
    int off_max = s->s_blocksize << 3;

    BUG_ON (!th->t_trans_id);

    PROC_INFO_INC( s, scan_bitmap.call );
    if ( SB_FREE_BLOCKS(s) <= 0)
        return 0; // No point in looking for more free blocks

    get_bit_address (s, *start, &bm, &off);
    get_bit_address (s, finish, &end_bm, &end_off);
    if (bm > SB_BMAP_NR(s))
        return 0;
    if (end_bm > SB_BMAP_NR(s))
        end_bm = SB_BMAP_NR(s);

    /* When the bitmap is more than 10% free, anyone can allocate.
     * When it's less than 10% free, only files that already use the
     * bitmap are allowed. Once we pass 80% full, this restriction
     * is lifted.
     *
     * We do this so that files that grow later still have space close to
     * their original allocation. This improves locality, and presumably
     * performance as a result.
     *
     * This is only an allocation policy and does not make up for getting a
     * bad hint. Decent hinting must be implemented for this to work well.
     */
    if ( TEST_OPTION(skip_busy, s) && SB_FREE_BLOCKS(s) > SB_BLOCK_COUNT(s)/20 ) {
        for (; bm < end_bm; bm++, off = 0) {
            if ( ( off && (!unfm || (file_block != 0))) || SB_AP_BITMAP(s)[bm].free_count > (s->s_blocksize << 3) / 10 )
                nr_allocated = scan_bitmap_block(th, bm, &off, off_max, min, max, unfm);
            if (nr_allocated)
                goto ret;
        }
        /* we know from above that start is a reasonable number */
        get_bit_address (s, *start, &bm, &off);
    }

    for (; bm < end_bm; bm++, off = 0) {
        nr_allocated = scan_bitmap_block(th, bm, &off, off_max, min, max, unfm);
        if (nr_allocated)
            goto ret;
    }

    nr_allocated = scan_bitmap_block(th, bm, &off, end_off + 1, min, max, unfm);

ret:
    *start = bm * off_max + off;
    return nr_allocated;

}
int reiserfs_resize(struct super_block *s, unsigned long block_count_new)
{
	int err = 0;
	struct reiserfs_super_block *sb;
	struct reiserfs_bitmap_info *bitmap;
	struct reiserfs_bitmap_info *info;
	struct reiserfs_bitmap_info *old_bitmap = SB_AP_BITMAP(s);
	struct buffer_head *bh;
	struct reiserfs_transaction_handle th;
	unsigned int bmap_nr_new, bmap_nr;
	unsigned int block_r_new, block_r;

	struct reiserfs_list_bitmap *jb;
	struct reiserfs_list_bitmap jbitmap[JOURNAL_NUM_BITMAPS];

	unsigned long int block_count, free_blocks;
	int i;
	int copy_size;

	sb = SB_DISK_SUPER_BLOCK(s);

	if (SB_BLOCK_COUNT(s) >= block_count_new) {
		printk("can\'t shrink filesystem on-line\n");
		return -EINVAL;
	}

	/* check the device size */
	bh = sb_bread(s, block_count_new - 1);
	if (!bh) {
		printk("reiserfs_resize: can\'t read last block\n");
		return -EINVAL;
	}
	bforget(bh);

	/* old disk layout detection; those partitions can be mounted, but
	 * cannot be resized */
	if (SB_BUFFER_WITH_SB(s)->b_blocknr * SB_BUFFER_WITH_SB(s)->b_size
	    != REISERFS_DISK_OFFSET_IN_BYTES) {
		printk
		    ("reiserfs_resize: unable to resize a reiserfs without distributed bitmap (fs version < 3.5.12)\n");
		return -ENOTSUPP;
	}

	/* count used bits in last bitmap block */
	block_r = SB_BLOCK_COUNT(s) -
			(reiserfs_bmap_count(s) - 1) * s->s_blocksize * 8;

	/* count bitmap blocks in new fs */
	bmap_nr_new = block_count_new / (s->s_blocksize * 8);
	block_r_new = block_count_new - bmap_nr_new * s->s_blocksize * 8;
	if (block_r_new)
		bmap_nr_new++;
	else
		block_r_new = s->s_blocksize * 8;

	/* save old values */
	block_count = SB_BLOCK_COUNT(s);
	bmap_nr = reiserfs_bmap_count(s);

	/* resizing of reiserfs bitmaps (journal and real), if needed */
	if (bmap_nr_new > bmap_nr) {
		/* reallocate journal bitmaps */
		if (reiserfs_allocate_list_bitmaps(s, jbitmap, bmap_nr_new) < 0) {
			printk
			    ("reiserfs_resize: unable to allocate memory for journal bitmaps\n");
			return -ENOMEM;
		}
		/* the new journal bitmaps are zero filled, now we copy in the bitmap
		 ** node pointers from the old journal bitmap structs, and then
		 ** transfer the new data structures into the journal struct.
		 **
		 ** using the copy_size var below allows this code to work for
		 ** both shrinking and expanding the FS.
		 */
		copy_size = bmap_nr_new < bmap_nr ? bmap_nr_new : bmap_nr;
		copy_size =
		    copy_size * sizeof(struct reiserfs_list_bitmap_node *);
		for (i = 0; i < JOURNAL_NUM_BITMAPS; i++) {
			struct reiserfs_bitmap_node **node_tmp;
			jb = SB_JOURNAL(s)->j_list_bitmap + i;
			memcpy(jbitmap[i].bitmaps, jb->bitmaps, copy_size);

			/* just in case vfree schedules on us, copy the new
			 ** pointer into the journal struct before freeing the
			 ** old one
			 */
			node_tmp = jb->bitmaps;
			jb->bitmaps = jbitmap[i].bitmaps;
			vfree(node_tmp);
		}

		/* allocate additional bitmap blocks, reallocate array of bitmap
		 * block pointers */
		bitmap =
		    vzalloc(sizeof(struct reiserfs_bitmap_info) * bmap_nr_new);
		if (!bitmap) {
			/* Journal bitmaps are still supersized, but the memory isn't
			 * leaked, so I guess it's ok */
			printk("reiserfs_resize: unable to allocate memory.\n");
			return -ENOMEM;
		}
		for (i = 0; i < bmap_nr; i++)
			bitmap[i] = old_bitmap[i];

		/* This doesn't go through the journal, but it doesn't have to.
		 * The changes are still atomic: We're synced up when the journal
		 * transaction begins, and the new bitmaps don't matter if the
		 * transaction fails. */
		for (i = bmap_nr; i < bmap_nr_new; i++) {
			/* don't use read_bitmap_block since it will cache
			 * the uninitialized bitmap */
			bh = sb_bread(s, i * s->s_blocksize * 8);
			if (!bh) {
				vfree(bitmap);
				return -EIO;
			}
			memset(bh->b_data, 0, sb_blocksize(sb));
			reiserfs_set_le_bit(0, bh->b_data);
			reiserfs_cache_bitmap_metadata(s, bh, bitmap + i);

			set_buffer_uptodate(bh);
			mark_buffer_dirty(bh);
			reiserfs_write_unlock(s);
			sync_dirty_buffer(bh);
			reiserfs_write_lock(s);
			// update bitmap_info stuff
			bitmap[i].free_count = sb_blocksize(sb) * 8 - 1;
			brelse(bh);
		}
		/* free old bitmap blocks array */
		SB_AP_BITMAP(s) = bitmap;
		vfree(old_bitmap);
	}

	/* begin transaction, if there was an error, it's fine. Yes, we have
	 * incorrect bitmaps now, but none of it is ever going to touch the
	 * disk anyway. */
	err = journal_begin(&th, s, 10);
	if (err)
		return err;

	/* Extend old last bitmap block - new blocks have been made available */
	info = SB_AP_BITMAP(s) + bmap_nr - 1;
	bh = reiserfs_read_bitmap_block(s, bmap_nr - 1);
	if (!bh) {
		int jerr = journal_end(&th, s, 10);
		if (jerr)
			return jerr;
		return -EIO;
	}

	reiserfs_prepare_for_journal(s, bh, 1);
	for (i = block_r; i < s->s_blocksize * 8; i++)
		reiserfs_clear_le_bit(i, bh->b_data);
	info->free_count += s->s_blocksize * 8 - block_r;

	journal_mark_dirty(&th, s, bh);
	brelse(bh);

	/* Correct new last bitmap block - It may not be full */
	info = SB_AP_BITMAP(s) + bmap_nr_new - 1;
	bh = reiserfs_read_bitmap_block(s, bmap_nr_new - 1);
	if (!bh) {
		int jerr = journal_end(&th, s, 10);
		if (jerr)
			return jerr;
		return -EIO;
	}

	reiserfs_prepare_for_journal(s, bh, 1);
	for (i = block_r_new; i < s->s_blocksize * 8; i++)
		reiserfs_set_le_bit(i, bh->b_data);
	journal_mark_dirty(&th, s, bh);
	brelse(bh);

	info->free_count -= s->s_blocksize * 8 - block_r_new;
	/* update super */
	reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
	free_blocks = SB_FREE_BLOCKS(s);
	PUT_SB_FREE_BLOCKS(s,
			   free_blocks + (block_count_new - block_count -
					  (bmap_nr_new - bmap_nr)));
	PUT_SB_BLOCK_COUNT(s, block_count_new);
	PUT_SB_BMAP_NR(s, bmap_would_wrap(bmap_nr_new) ? : bmap_nr_new);

	journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s));

	SB_JOURNAL(s)->j_must_wait = 1;
	return journal_end(&th, s, 10);
}
int reiserfs_resize (struct super_block * s, unsigned long block_count_new)
{
	struct reiserfs_super_block * sb;
        struct reiserfs_bitmap_info *bitmap;
	struct buffer_head * bh;
	struct reiserfs_transaction_handle th;
	unsigned int bmap_nr_new, bmap_nr;
	unsigned int block_r_new, block_r;
	
	struct reiserfs_list_bitmap * jb;
	struct reiserfs_list_bitmap jbitmap[JOURNAL_NUM_BITMAPS];
	
	unsigned long int block_count, free_blocks;
	int i;
	int copy_size ;

	sb = SB_DISK_SUPER_BLOCK(s);

	if (SB_BLOCK_COUNT(s) >= block_count_new) {
		printk("can\'t shrink filesystem on-line\n");
		return -EINVAL;
	}

	/* check the device size */
	bh = sb_bread(s, block_count_new - 1);
	if (!bh) {
		printk("reiserfs_resize: can\'t read last block\n");
		return -EINVAL;
	}	
	bforget(bh);

	/* old disk layout detection; those partitions can be mounted, but
	 * cannot be resized */
	if (SB_BUFFER_WITH_SB(s)->b_blocknr *	SB_BUFFER_WITH_SB(s)->b_size 
		!= REISERFS_DISK_OFFSET_IN_BYTES ) {
		printk("reiserfs_resize: unable to resize a reiserfs without distributed bitmap (fs version < 3.5.12)\n");
		return -ENOTSUPP;
	}
       
	/* count used bits in last bitmap block */
	block_r = SB_BLOCK_COUNT(s) -
	        (SB_BMAP_NR(s) - 1) * s->s_blocksize * 8;
	
	/* count bitmap blocks in new fs */
	bmap_nr_new = block_count_new / ( s->s_blocksize * 8 );
	block_r_new = block_count_new - bmap_nr_new * s->s_blocksize * 8;
	if (block_r_new) 
		bmap_nr_new++;
	else
		block_r_new = s->s_blocksize * 8;

	/* save old values */
	block_count = SB_BLOCK_COUNT(s);
	bmap_nr     = SB_BMAP_NR(s);

	/* resizing of reiserfs bitmaps (journal and real), if needed */
	if (bmap_nr_new > bmap_nr) {	    
	    /* reallocate journal bitmaps */
	    if (reiserfs_allocate_list_bitmaps(s, jbitmap, bmap_nr_new) < 0) {
		printk("reiserfs_resize: unable to allocate memory for journal bitmaps\n");
		unlock_super(s) ;
		return -ENOMEM ;
	    }
	    /* the new journal bitmaps are zero filled, now we copy in the bitmap
	    ** node pointers from the old journal bitmap structs, and then
	    ** transfer the new data structures into the journal struct.
	    **
	    ** using the copy_size var below allows this code to work for
	    ** both shrinking and expanding the FS.
	    */
	    copy_size = bmap_nr_new < bmap_nr ? bmap_nr_new : bmap_nr ;
	    copy_size = copy_size * sizeof(struct reiserfs_list_bitmap_node *) ;
	    for (i = 0 ; i < JOURNAL_NUM_BITMAPS ; i++) {
		struct reiserfs_bitmap_node **node_tmp ;
		jb = SB_JOURNAL(s)->j_list_bitmap + i ;
		memcpy(jbitmap[i].bitmaps, jb->bitmaps, copy_size) ;

		/* just in case vfree schedules on us, copy the new
		** pointer into the journal struct before freeing the 
		** old one
		*/
		node_tmp = jb->bitmaps ;
		jb->bitmaps = jbitmap[i].bitmaps ;
		vfree(node_tmp) ;
	    }	
	
	    /* allocate additional bitmap blocks, reallocate array of bitmap
	     * block pointers */
	    bitmap = vmalloc(sizeof(struct reiserfs_bitmap_info) * bmap_nr_new);
	    if (!bitmap) {
		printk("reiserfs_resize: unable to allocate memory.\n");
		return -ENOMEM;
	    }
	    memset (bitmap, 0, sizeof (struct reiserfs_bitmap_info) * SB_BMAP_NR(s));
	    for (i = 0; i < bmap_nr; i++)
		bitmap[i] = SB_AP_BITMAP(s)[i];
	    for (i = bmap_nr; i < bmap_nr_new; i++) {
		bitmap[i].bh = sb_getblk(s, i * s->s_blocksize * 8);
		memset(bitmap[i].bh->b_data, 0, sb_blocksize(sb));
		reiserfs_test_and_set_le_bit(0, bitmap[i].bh->b_data);

		set_buffer_uptodate(bitmap[i].bh);
		mark_buffer_dirty(bitmap[i].bh) ;
		sync_dirty_buffer(bitmap[i].bh);
		// update bitmap_info stuff
		bitmap[i].first_zero_hint=1;
		bitmap[i].free_count = sb_blocksize(sb) * 8 - 1;
	    }	
	    /* free old bitmap blocks array */
	    vfree(SB_AP_BITMAP(s));
	    SB_AP_BITMAP(s) = bitmap;
	}
	
	/* begin transaction */
	journal_begin(&th, s, 10);

	/* correct last bitmap blocks in old and new disk layout */
	reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr - 1].bh, 1);
	for (i = block_r; i < s->s_blocksize * 8; i++)
	    reiserfs_test_and_clear_le_bit(i, 
					   SB_AP_BITMAP(s)[bmap_nr - 1].bh->b_data);
	SB_AP_BITMAP(s)[bmap_nr - 1].free_count += s->s_blocksize * 8 - block_r;
	if ( !SB_AP_BITMAP(s)[bmap_nr - 1].first_zero_hint)
	    SB_AP_BITMAP(s)[bmap_nr - 1].first_zero_hint = block_r;

	journal_mark_dirty(&th, s, SB_AP_BITMAP(s)[bmap_nr - 1].bh);

	reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr_new - 1].bh, 1);
	for (i = block_r_new; i < s->s_blocksize * 8; i++)
	    reiserfs_test_and_set_le_bit(i,
					 SB_AP_BITMAP(s)[bmap_nr_new - 1].bh->b_data);
	journal_mark_dirty(&th, s, SB_AP_BITMAP(s)[bmap_nr_new - 1].bh);
 
	SB_AP_BITMAP(s)[bmap_nr_new - 1].free_count -= s->s_blocksize * 8 - block_r_new;
	/* Extreme case where last bitmap is the only valid block in itself. */
	if ( !SB_AP_BITMAP(s)[bmap_nr_new - 1].free_count )
	    SB_AP_BITMAP(s)[bmap_nr_new - 1].first_zero_hint = 0;
 	/* update super */
	reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
	free_blocks = SB_FREE_BLOCKS(s);
	PUT_SB_FREE_BLOCKS(s, free_blocks + (block_count_new - block_count - (bmap_nr_new - bmap_nr)));
	PUT_SB_BLOCK_COUNT(s, block_count_new);
	PUT_SB_BMAP_NR(s, bmap_nr_new);
	s->s_dirt = 1;

	journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s));
	
	SB_JOURNAL(s)->j_must_wait = 1;
	journal_end(&th, s, 10);

	return 0;
}
int main(int argc, char *argv[]) {
    char * bytes_count_str = NULL;
    char * devname;
    reiserfs_filsys_t fs;
    struct reiserfs_super_block * rs;

    int c;
    int error;

    struct reiserfs_super_block *sb_old;

    unsigned long block_count_new;

    print_banner ("resize_reiserfs");

    while ((c = getopt(argc, argv, "fvcqs:")) != EOF) {
        switch (c) {
        case 's' :
            if (!optarg)
                die("%s: Missing argument to -s option", argv[0]);
            bytes_count_str = optarg;
            break;
        case 'f':
            opt_force = 1;
            break;
        case 'v':
            opt_verbose++;
            break;
        case 'n':
            /* no nowrite option at this moment */
            /* opt_nowrite = 1; */
            break;
        case 'c':
            opt_safe = 1;
            break;
        case 'q':
            opt_verbose = 0;
            break;
        default:
            print_usage_and_exit ();
        }
    }

    if (optind == argc )
        print_usage_and_exit();
    devname = argv[optind];

    fs = reiserfs_open(devname, O_RDONLY, &error, 0);
    if (!fs)
        die ("%s: can not open '%s': %s", argv[0], devname, strerror(error));

    if (no_reiserfs_found (fs)) {
        die ("resize_reiserfs: no reiserfs found on the device");
    }
    if (!spread_bitmaps (fs)) {
        die ("resize_reiserfs: cannot resize reiserfs in old (not spread bitmap) format.\n");
    }

    rs = fs->s_rs;

    if(bytes_count_str) {	/* new fs size is specified by user */
        block_count_new = calc_new_fs_size(rs_block_count(rs), fs->s_blocksize, bytes_count_str);
    } else {		/* use whole device */
        block_count_new = count_blocks(devname, fs->s_blocksize, -1);
    }

    if (is_mounted (devname)) {
        reiserfs_close(fs);
        return resize_fs_online(devname, block_count_new);
    }

    if (rs_state(rs) != REISERFS_VALID_FS)
        die ("%s: the file system isn't in valid state\n", argv[0]);

    if(!valid_offset(fs->s_dev, (loff_t) block_count_new * fs->s_blocksize - 1))
        die ("%s: %s too small", argv[0], devname);

    sb_old = 0;		/* Needed to keep idiot compiler from issuing false warning */
    /* save SB for reporting */
    if(opt_verbose) {
        sb_old = getmem(SB_SIZE);
        memcpy(sb_old, SB_DISK_SUPER_BLOCK(fs), SB_SIZE);
    }

    if (block_count_new == SB_BLOCK_COUNT(fs))
        die ("%s: Calculated fs size is the same as the previous one.", argv[0]);

    if (block_count_new > SB_BLOCK_COUNT(fs))
        expand_fs(fs, block_count_new);
    else
        shrink_fs(fs, block_count_new);

    if(opt_verbose) {
        sb_report(rs, sb_old);
        freemem(sb_old);
    }

    set_state (rs, REISERFS_VALID_FS);
    bwrite_cond(SB_BUFFER_WITH_SB(fs));

    if (opt_verbose) {
        printf("\nSyncing..");
        fflush(stdout);
    }
    reiserfs_close (fs);
    if (opt_verbose)
        printf("done\n");

    return 0;
}
Example #17
0
/* FIXME: we can improve fixing of broken keys: we can ssfe direct items which
   go after stat data and have broken keys */
static void pass0_correct_leaf (reiserfs_filsys_t fs,
				struct buffer_head * bh)
{
    int i, j;
    struct item_head * ih;
    __u32 * ind_item;
    unsigned long unfm_ptr;
    int dirty = 0;

 start_again:

    ih = B_N_PITEM_HEAD (bh, 0);
    for (i = 0; i < node_item_number (bh); i ++, ih ++) {
	if (ih->ih_key.k_dir_id == 0 || ih->ih_key.k_objectid == 0) {
	    /* sometimes stat datas get k_objectid==0 or k_dir_id==0 */
	    if (i == (node_item_number (bh) - 1)) {
		/* */
		if (i == 0) {
		    fsck_log ("block %lu: item %d: (%H) is alone in the block\n",
			      bh->b_blocknr, i, ih);
		    return;
		}
		/* delete last item */
		delete_item (fs, bh, i - 1);
		return;
	    }

	    /* there is next item: if it is not stat data - take its k_dir_id
               and k_objectid. if key order will be still wrong - the changed
               item will be deleted */
	    if (!is_stat_data_ih (ih + 1)) {
		fsck_log ("block %lu: item %d: (%H) fixed to ", bh->b_blocknr, i, ih);
		ih->ih_key.k_dir_id = (ih + 1)->ih_key.k_dir_id;
		ih->ih_key.k_objectid = (ih + 1)->ih_key.k_objectid;
		set_offset (KEY_FORMAT_1, &ih->ih_key, 0);
		set_type (KEY_FORMAT_1, &ih->ih_key, TYPE_STAT_DATA);
		fsck_log ("(%H)\n", ih);
		dirty = 1;
	    } else if (i == 0) {
		delete_item (fs, bh, i);
		goto start_again;
	    }
	}

	/* this recovers corruptions like the below: 
	   1774 1732 0 0
	   116262638 1732 1 3
	   1774 1736 0 0 */
	if (i && is_stat_data_ih (ih - 1) && !is_stat_data_ih (ih)) {
	    if (ih->ih_key.k_objectid != (ih - 1)->ih_key.k_objectid ||
		ih->ih_key.k_dir_id != (ih - 1)->ih_key.k_dir_id ||
		get_offset (&ih->ih_key) != 1) {
		if (is_direntry_ih (ih)) {
		    fsck_log ("block %lu: item %d: no \".\" entry found in "
			      "the first item of a directory\n", bh->b_blocknr, i);
		} else {
		    fsck_log ("block %lu: item %d: (%H) fixed to ", 
			  bh->b_blocknr, i, ih);
		    ih->ih_key.k_dir_id = (ih - 1)->ih_key.k_dir_id;
		    ih->ih_key.k_objectid = (ih - 1)->ih_key.k_objectid;
		    
		    if (ih_item_len (ih - 1) == SD_SIZE) {
			/* stat data is new, therefore this item is new too */
			set_offset (KEY_FORMAT_2, &(ih->ih_key), 1);
			if (ih_entry_count (ih) != 0xffff)
			    set_type (KEY_FORMAT_2, &(ih->ih_key), TYPE_INDIRECT);
			else
			    set_type (KEY_FORMAT_2, &(ih->ih_key), TYPE_DIRECT);
			set_ih_key_format (ih, KEY_FORMAT_2);
		    } else {
			/* stat data is old, therefore this item is old too */
			set_offset (KEY_FORMAT_1, &(ih->ih_key), 1);
			if (ih_entry_count (ih) != 0xffff)
			    set_type (KEY_FORMAT_1, &(ih->ih_key), TYPE_INDIRECT);
			else
			    set_type (KEY_FORMAT_1, &(ih->ih_key), TYPE_DIRECT);
			set_ih_key_format (ih, KEY_FORMAT_1);
		    }
		    fsck_log ("%H\n", ih);
		    dirty = 1;
		}
	    }
	}

	/* FIXME: corruptions like:
	   56702 66802 1 2
	   56702 65536 0 0
	   56702 66803 1 2
	   do not get recovered (both last items will be deleted) */
	/* delete item if it is not in correct order of object items */
	if (i && not_of_one_file (&ih->ih_key, &(ih - 1)->ih_key) &&
	    !is_stat_data_ih (ih)) {
	    fsck_log ("block %lu: item %d: %H follows non stat item %H - deleted\n",
		      bh->b_blocknr, i, ih, ih - 1);
	    delete_item (fs, bh, i);
	    goto start_again;
	}

	if (i &&  comp_keys (&(ih - 1)->ih_key, &ih->ih_key) != -1) {
	    /* previous item has key not smaller than the key of currect item */
	    if (is_stat_data_ih (ih - 1) && !is_stat_data_ih (ih)) {
		/* fix key of stat data such as if it was stat data of that item */
		fsck_log ("pass0: block %lu: %d-th item %k is out of order, made a stat data of %d-th (%k)\n",
			  bh->b_blocknr, i - 1, &(ih - 1)->ih_key, i, &ih->ih_key);
		(ih - 1)->ih_key.k_dir_id = ih->ih_key.k_dir_id;
		(ih - 1)->ih_key.k_objectid = ih->ih_key.k_objectid;
		set_offset (KEY_FORMAT_1, &(ih - 1)->ih_key, 0);
		set_type (KEY_FORMAT_1, &(ih - 1)->ih_key, TYPE_STAT_DATA);
		dirty = 1;
	    } else {
		/* ok, we have to delete one of these two - decide which one */
		int retval;

		/* something will be deleted */
		dirty = 1;
		retval = upper_correct (bh, ih - 1, i - 1);
		switch (retval) {
		case 0:
		    /* delete upper item */
		    fsck_log ("pass0: block %lu: %d-th (upper) item (%k) is out of order, deleted\n",
			      bh->b_blocknr, i - 1, &(ih - 1)->ih_key);
		    delete_item (fs, bh, i - 1);
		    goto start_again;

		case 1:
		    /* delete lower item */
		    fsck_log ("pass0: block %lu: %d-th (lower) item (%k) is out of order, deleted\n",
			      bh->b_blocknr, i, &ih->ih_key);
		    delete_item (fs, bh, i);
		    goto start_again;

		default:
		    /* upper item was the first item of a node */
		}

		retval = lower_correct (bh, ih, i);
		switch (retval) {
		case 0:
		    /* delete lower item */
		    fsck_log ("pass0: block %lu: %d-th (lower) item (%k) is out of order, deleted\n",
			      bh->b_blocknr, i, &ih->ih_key);
		    delete_item (fs, bh, i);
		    goto start_again;

		case 1:
		    /* delete upper item */
		    fsck_log ("pass0: block %lu: %d-th (upper) item (%k) is out of order, deleted\n",
			      bh->b_blocknr, i - 1, &(ih - 1)->ih_key);
		    delete_item (fs, bh, i - 1);
		    goto start_again;

		default:
		    /* there wer only two items in a node, so we could not
                       decide what to delete, go and ask user */
		}
		fsck_log ("pass0: which of these items looks better (other will be deleted)?\n"
			  "%H\n%H\n", ih - 1, ih);
		if (fsck_user_confirmed (fs, "1 or 2?", "1\n", 1))
		    delete_item (fs, bh, i - 1);
		else
		    delete_item (fs, bh, i);
		goto start_again;
	    }
	}

	if (is_stat_data_ih (ih) && (ih_item_len (ih) != SD_SIZE &&
				     ih_item_len (ih) != SD_V1_SIZE)) {
	    fsck_log ("pass0: block %lu, stat data of wrong length %H - deleted\n",
		      bh, ih);
	    delete_item (fs, bh, i);
	    goto start_again;
	}

	dirty += correct_key_format (ih);

	if (is_stat_data_ih (ih)) {
	    ;/*correct_stat_data (fs, bh, i);*/
	}

	if (is_direntry_ih (ih)) {
	    verify_directory_item (fs, bh, i);
	    continue;
	}

	if (!is_indirect_ih (ih))
	    continue;
	
	ind_item = (__u32 *)B_I_PITEM (bh, ih);
	for (j = 0; j < I_UNFM_NUM (ih); j ++) {
	    unfm_ptr = le32_to_cpu (ind_item [j]);
	    if (!unfm_ptr)
		continue;
	    
	    if (fsck_mode (fs) == FSCK_ZERO_FILES) {
		/* FIXME: this is temporary mode of fsck */
		ind_item [j] = 0;
		reiserfs_bitmap_clear_bit (fsck_new_bitmap(fs), unfm_ptr);
		tmp_zeroed ++;
		dirty = 1;
		continue;
	    }

	    if (not_data_block (fs, unfm_ptr) || /* journal area or bitmap or super block */
		unfm_ptr >= SB_BLOCK_COUNT (fs)) {/* garbage in pointer */

		stats (fs)->wrong_pointers ++;
		/*
		fsck_log ("pass0: %d-th pointer (%lu) in item %k (leaf block %lu) is wrong\n",
			  j, unfm_ptr, &ih->ih_key, bh->b_blocknr);
		*/
		ind_item [j] = 0;
		dirty = 1;
		continue;
	    }
#if 0
	    if (!was_block_used (unfm_ptr)) {
	      /* this will get to a pool of allocable blocks */
	      ind_item [j] = 0;
	      dirty = 1;
	      stat_wrong_pointer_found (fs);
	      continue;
	    }
#endif
	    /* mark block in bitmaps of unformatted nodes */
	    register_unfm (unfm_ptr);
	}
    }

    /* mark all objectids in use */
    ih = B_N_PITEM_HEAD (bh, 0);
    for (i = 0; i < node_item_number (bh); i ++, ih ++) {
	mark_objectid_really_used (proper_id_map (fs), le32_to_cpu (ih->ih_key.k_dir_id));
	mark_objectid_really_used (proper_id_map (fs), le32_to_cpu (ih->ih_key.k_objectid));
    }

    if (node_item_number (bh) < 1) {
	/* pass 1 will skip this */
	stats(fs)->all_contents_removed ++;
	fsck_log ("pass0: block %lu got all items deleted\n",
		  bh->b_blocknr);
    } else {
	/* pass1 will use this bitmap */
	pass0_mark_leaf (bh->b_blocknr);

    }
    if (dirty) {
	stats(fs)->leaves_corrected ++;
	mark_buffer_dirty (bh);
    }
}


static int is_bad_sd (struct item_head * ih, char * item)
{
    struct stat_data * sd = (struct stat_data *)item;

    if (le32_to_cpu(ih->ih_key.u.k_offset_v1.k_offset) || le32_to_cpu(ih->ih_key.u.k_offset_v1.k_uniqueness)) {
	reiserfs_warning (stderr, "Bad SD? %H\n", ih);
	return 1;
    }

    if (ih_item_len (ih) == SD_V1_SIZE) {
	/* looks like old stat data */
	if (ih_key_format (ih) != KEY_FORMAT_1)
	    fsck_log ("item %H has wrong format\n", ih);
	return 0;
    }

    if (!S_ISDIR (sd_v2_mode(sd)) && !S_ISREG(sd_v2_mode(sd)) &&
	!S_ISCHR (sd_v2_mode(sd)) && !S_ISBLK(sd_v2_mode(sd)) &&
	!S_ISLNK (sd_v2_mode(sd)) && !S_ISFIFO(sd_v2_mode(sd)) &&
	!S_ISSOCK(sd_v2_mode(sd))) {	
	/*fsck_log ("file %k unexpected mode encountered 0%o\n", &ih->ih_key, sd_v2_mode(sd))*/;
    }
    return 0;
}


int is_bad_directory (struct item_head * ih, char * item, int dev, int blocksize)
{
    int i;
    char * name;
    int namelen, entrylen;
    struct reiserfs_de_head * deh = (struct reiserfs_de_head *)item;
    __u32 prev_offset = 0;
    __u16 prev_location = ih_item_len (ih);
    int min_entry_size = 1;/* we have no way to understand whether the
                              filesystem were created in 3.6 format or
                              converted to it. So, we assume that minimal name
                              length is 1 */

    if (ih_item_len (ih) / (DEH_SIZE + min_entry_size) < ih_entry_count (ih))
	/* entry count is too big */
	return 1;

    for (i = 0; i < ih_entry_count (ih); i ++, deh ++) {
	entrylen = entry_length(ih, deh, i);
	if (entrylen > REISERFS_MAX_NAME_LEN (blocksize)) {
	    return 1;
	}
	if (deh_offset (deh) <= prev_offset) {
	    return 1;
	}
	prev_offset = deh_offset (deh);

	if (deh_location(deh) + entrylen != prev_location) {
	    return 1;
	}
	prev_location = deh_location (deh);

	namelen = name_length (ih, deh, i);
	name = name_in_entry (deh, i);
	if (!is_properly_hashed (fs, name, namelen, deh_offset (deh))) {
	    return 1;
	}
    }
    return 0;
}


/* change incorrect block adresses by 0. Do not consider such item as incorrect */
static int is_bad_indirect (struct item_head * ih, char * item, int dev, int blocksize)
{
    int i;
    int bad = 0;
    int blocks;

    if (ih_item_len(ih) % UNFM_P_SIZE) {
	fsck_log ("is_bad_indirect: indirect item of %H of invalid length\n", ih);
	return 1;
    }

    blocks = SB_BLOCK_COUNT (fs);
  
    for (i = 0; i < I_UNFM_NUM (ih); i ++) {
	__u32 * ind = (__u32 *)item;

	if (le32_to_cpu (ind[i]) >= blocks) {
	    bad ++;
	    fsck_log ("is_bad_indirect: %d-th pointer of item %H looks bad (%lu)\n",
		      i, ih, le32_to_cpu (ind [i]));
	    continue;
	}
    }
    return bad;
}
Example #18
0
static void determine_search_start(reiserfs_blocknr_hint_t *hint,
                                   int amount_needed)
{
    struct super_block *s = hint->th->t_super;
    int unfm_hint;

    hint->beg = 0;
    hint->end = SB_BLOCK_COUNT(s) - 1;

    /* This is former border algorithm. Now with tunable border offset */
    if (concentrating_formatted_nodes(s))
        set_border_in_hint(s, hint);

#ifdef DISPLACE_NEW_PACKING_LOCALITIES
    /* whenever we create a new directory, we displace it.  At first we will
       hash for location, later we might look for a moderately empty place for
       it */
    if (displacing_new_packing_localities(s)
            && hint->th->displace_new_blocks) {
        displace_new_packing_locality(hint);

        /* we do not continue determine_search_start,
         * if new packing locality is being displaced */
        return;
    }
#endif

    /* all persons should feel encouraged to add more special cases here and
     * test them */

    if (displacing_large_files(s) && !hint->formatted_node
            && this_blocknr_allocation_would_make_it_a_large_file(hint)) {
        displace_large_file(hint);
        return;
    }

    /* if none of our special cases is relevant, use the left neighbor in the
       tree order of the new node we are allocating for */
    if (hint->formatted_node && TEST_OPTION(hashed_formatted_nodes,s)) {
        hash_formatted_node(hint);
        return;
    }

    unfm_hint = get_left_neighbor(hint);

    /* Mimic old block allocator behaviour, that is if VFS allowed for preallocation,
       new blocks are displaced based on directory ID. Also, if suggested search_start
       is less than last preallocated block, we start searching from it, assuming that
       HDD dataflow is faster in forward direction */
    if ( TEST_OPTION(old_way, s)) {
        if (!hint->formatted_node) {
            if ( !reiserfs_hashed_relocation(s))
                old_way(hint);
            else if (!reiserfs_no_unhashed_relocation(s))
                old_hashed_relocation(hint);

            if ( hint->inode && hint->search_start < REISERFS_I(hint->inode)->i_prealloc_block)
                hint->search_start = REISERFS_I(hint->inode)->i_prealloc_block;
        }
        return;
    }

    /* This is an approach proposed by Hans */
    if ( TEST_OPTION(hundredth_slices, s) && ! (displacing_large_files(s) && !hint->formatted_node)) {
        hundredth_slices(hint);
        return;
    }

    /* old_hashed_relocation only works on unformatted */
    if (!unfm_hint && !hint->formatted_node &&
            TEST_OPTION(old_hashed_relocation, s))
    {
        old_hashed_relocation(hint);
    }
    /* new_hashed_relocation works with both formatted/unformatted nodes */
    if ((!unfm_hint || hint->formatted_node) &&
            TEST_OPTION(new_hashed_relocation, s))
    {
        new_hashed_relocation(hint);
    }
    /* dirid grouping works only on unformatted nodes */
    if (!unfm_hint && !hint->formatted_node && TEST_OPTION(dirid_groups,s))
    {
        dirid_groups(hint);
    }

#ifdef DISPLACE_NEW_PACKING_LOCALITIES
    if (hint->formatted_node && TEST_OPTION(dirid_groups,s))
    {
        dirid_groups(hint);
    }
#endif

    /* oid grouping works only on unformatted nodes */
    if (!unfm_hint && !hint->formatted_node && TEST_OPTION(oid_groups,s))
    {
        oid_groups(hint);
    }
    return;
}
Example #19
0
int shrink_fs(reiserfs_filsys_t reiserfs, unsigned long blocks)
{
	unsigned long n_root_block;
	unsigned int bmap_nr_new;
	unsigned long int i;
	
	fs = reiserfs;
	rs = fs->s_rs;
	
	/* warn about alpha version */
	{
		int c;

		printf(
			"You are running BETA version of reiserfs shrinker.\n"
			"This version is only for testing or VERY CAREFUL use.\n"
			"Backup of you data is recommended.\n\n"
			"Do you want to continue? [y/N]:"
			);
		c = getchar();
		if (c != 'y' && c != 'Y')
			exit(1);
	}

	bmap_nr_new = (blocks - 1) / (8 * fs->s_blocksize) + 1;
	
	/* is shrinking possible ? */
	if (rs_block_count(rs) - blocks > rs_free_blocks(rs) + rs_bmap_nr(rs) - bmap_nr_new) {
	    fprintf(stderr, "resize_reiserfs: can\'t shrink fs; too many blocks already allocated\n");
	    return -1;
	}

	reiserfs_reopen(fs, O_RDWR);
	set_state (fs->s_rs, REISERFS_ERROR_FS);
	mark_buffer_uptodate(SB_BUFFER_WITH_SB(fs), 1);
	mark_buffer_dirty(SB_BUFFER_WITH_SB(fs));
	bwrite(SB_BUFFER_WITH_SB(fs));

	/* calculate number of data blocks */		
	blocks_used = 
	    SB_BLOCK_COUNT(fs)
	    - SB_FREE_BLOCKS(fs)
	    - SB_BMAP_NR(fs)
	    - SB_JOURNAL_SIZE(fs)
	    - REISERFS_DISK_OFFSET_IN_BYTES / fs->s_blocksize
	    - 2; /* superblock itself and 1 descriptor after the journal */

	bmp = reiserfs_create_bitmap(rs_block_count(rs));
	reiserfs_fetch_disk_bitmap(bmp, fs);

	unused_block = 1;

	if (opt_verbose) {
		printf("Processing the tree: ");
		fflush(stdout);
	}

	n_root_block = move_formatted_block(rs_root_block(rs), blocks, 0);
	if (n_root_block) {
		set_root_block (rs, n_root_block);
	}

	if (opt_verbose)
	    printf ("\n\nnodes processed (moved):\n"
		    "int        %lu (%lu),\n"
		    "leaves     %lu (%lu),\n" 
		    "unfm       %lu (%lu),\n"
		    "total      %lu (%lu).\n\n",
		    int_node_cnt, int_moved_cnt,
		    leaf_node_cnt, leaf_moved_cnt, 
		    unfm_node_cnt, unfm_moved_cnt,
		    (unsigned long)total_node_cnt, total_moved_cnt);

	if (block_count_mismatch) {
	    fprintf(stderr, "resize_reiserfs: data block count %lu"
		    " doesn\'t match data block count %lu from super block\n",
		    (unsigned long)total_node_cnt, blocks_used);
	}
#if 0
	printf("check for used blocks in truncated region\n");
	{
		unsigned long l;
		for (l = blocks; l < rs_block_count(rs); l++)
			if (is_block_used(bmp, l))
				printf("<%lu>", l);
		printf("\n");
	}
#endif /* 0 */

	reiserfs_free_bitmap_blocks(fs);
	
	set_free_blocks (rs, rs_free_blocks(rs) - (rs_block_count(rs) - blocks) + (rs_bmap_nr(rs) - bmap_nr_new));
	set_block_count (rs, blocks);
	set_bmap_nr (rs, bmap_nr_new);

	reiserfs_read_bitmap_blocks(fs);
	
	for (i = blocks; i < bmap_nr_new * fs->s_blocksize; i++)
		reiserfs_bitmap_set_bit(bmp, i);
#if 0
	PUT_SB_FREE_BLOCKS(s, SB_FREE_BLOCKS(s) - (SB_BLOCK_COUNT(s) - blocks) + (SB_BMAP_NR(s) - bmap_nr_new));
	PUT_SB_BLOCK_COUNT(s, blocks);
	PUT_SB_BMAP_NR(s, bmap_nr_new);
#endif
	reiserfs_flush_bitmap(bmp, fs);

	return 0;
}
Example #20
0
static void go_through (reiserfs_filsys_t fs)
{
    struct buffer_head * bh;
    int i;
    int what_node;
    unsigned long done = 0, total;

    if (fsck_mode (fs) == DO_TEST) {
	/* just to test pass0_correct_leaf */
	bh = bread (fs->s_dev, stats(fs)->test, fs->s_blocksize);

	/*
	if (is_leaf_bad (bh)) {
	    fsck_progress ("###############  bad #################\n");
	}
	*/
	pass0_correct_leaf (fs, bh);
	
	print_block (stdout, fs, bh, 3, -1, -1);

	if (is_leaf_bad (bh)) {
	    fsck_progress ("############### still bad #################\n");
	}
	brelse (bh);
	reiserfs_free (fs);
	exit(4);
    }


    total = reiserfs_bitmap_ones (fsck_disk_bitmap (fs));
    fsck_progress ("\nPass 0 (%lu (of %lu) blocks will be read):\n",
		   total, SB_BLOCK_COUNT (fs));


    for (i = 0; i < SB_BLOCK_COUNT (fs); i ++) {
	if (!is_to_be_read (fs, i))
	    continue;

	print_how_far (&done, total, 1, fsck_quiet (fs));

	bh = bread (fs->s_dev, i, fs->s_blocksize);
	if (!bh) {
	    /* we were reading one block at time, and failed, so mark
	       block bad */
	    fsck_progress ("pass0: reading block %lu failed\n", i);
	    continue;
	}

	if (not_data_block (fs, i))
	    reiserfs_panic ("not data block found");
	
	stats (fs)->analyzed ++;
	what_node = who_is_this (bh->b_data, fs->s_blocksize);
	if ( what_node != THE_LEAF ) {
	    brelse (bh);
	    continue;
	}
	pass0_correct_leaf (fs, bh);
	brelse (bh);
    }


#if 0
    for (i = 0; i < SB_BLOCK_COUNT (fs); i += nr_to_read) {
	to_scan = how_many_to_scan (fs, i, nr_to_read);
	if (to_scan) {
	    print_how_far (&done, total, to_scan, fsck_quiet (fs));

	    /* at least one of nr_to_read blocks is to be checked */
	    bbh = bread (fs->s_dev, i / nr_to_read, fs->s_blocksize * nr_to_read);
	    if (bbh) {
		for (j = 0; j < nr_to_read; j ++) {
		    if (!is_to_be_read (fs, i + j))
			continue;

		    if (not_data_block (fs, i + j))
			reiserfs_panic ("not data block found");

		    stats (fs)->analyzed ++;

		    data = bbh->b_data + j * fs->s_blocksize;
		    what_node = who_is_this (data, fs->s_blocksize);
		    if ( what_node != THE_LEAF ) {
			continue;
		    }

		    /* the node looks like a leaf, but it still can be
		       not perfect */
		    bh = make_buffer (fs->s_dev, i + j, fs->s_blocksize, data);

		    /*printf ("block %lu .. ", bh->b_blocknr);fflush(stdout);*/
		    pass0_correct_leaf (fs, bh);
		    /*printf ("ok\n");fflush(stdout);*/

		    brelse (bh);
		}

		if (buffer_dirty (bbh))
		    bwrite (bbh);
		bforget (bbh);
	    } else {
		done -= to_scan;
		/* bread failed */
		if (nr_to_read != 1) {
		    /* we tryied to read bunch of blocks. Try to read them by one */
		    nr_to_read = 1;
		    i --;
		    continue;
		} else {
		    /* we were reading one block at time, and failed, so mark
                       block bad */
		    fsck_progress ("pass0: block %lu is bad, marked used\n", i);
		}
	    }
	}

	if (nr_to_read == 1 && ((i + 1) % NR_TO_READ) == 0) {
	    /* we have read NR_TO_READ blocks one at time, switch back to
               reading NR_TO_READ blocks at time */
	    i -= (NR_TO_READ - 1);
	    nr_to_read = NR_TO_READ;
	}
    }
#endif


    /* just in case */
    mark_objectid_really_used (proper_id_map (fs), REISERFS_ROOT_OBJECTID);

    fsck_progress ("\n");

    if (fsck_save_leaf_bitmap (fs)) {
	reiserfs_bitmap_save (stats (fs)->new_bitmap_file_name, leaves_bitmap);
    }
}
Example #21
0
static inline int blocknrs_and_prealloc_arrays_from_search_start
(reiserfs_blocknr_hint_t *hint, b_blocknr_t *new_blocknrs, int amount_needed)
{
    struct super_block *s = hint->th->t_super;
    b_blocknr_t start = hint->search_start;
    b_blocknr_t finish = SB_BLOCK_COUNT(s) - 1;
    int passno = 0;
    int nr_allocated = 0;
    int bigalloc = 0;

    determine_prealloc_size(hint);
    if (!hint->formatted_node) {
        int quota_ret;
#ifdef REISERQUOTA_DEBUG
        reiserfs_debug (s, REISERFS_DEBUG_CODE, "reiserquota: allocating %d blocks id=%u", amount_needed, hint->inode->i_uid);
#endif
        quota_ret = DQUOT_ALLOC_BLOCK_NODIRTY(hint->inode, amount_needed);
        if (quota_ret)    /* Quota exceeded? */
            return QUOTA_EXCEEDED;
        if (hint->preallocate && hint->prealloc_size ) {
#ifdef REISERQUOTA_DEBUG
            reiserfs_debug (s, REISERFS_DEBUG_CODE, "reiserquota: allocating (prealloc) %d blocks id=%u", hint->prealloc_size, hint->inode->i_uid);
#endif
            quota_ret = DQUOT_PREALLOC_BLOCK_NODIRTY(hint->inode, hint->prealloc_size);
            if (quota_ret)
                hint->preallocate=hint->prealloc_size=0;
        }
        /* for unformatted nodes, force large allocations */
        bigalloc = amount_needed;
    }

    do {
        /* in bigalloc mode, nr_allocated should stay zero until
         * the entire allocation is filled
         */
        if (unlikely(bigalloc && nr_allocated)) {
            reiserfs_warning(s, "bigalloc is %d, nr_allocated %d\n",
                             bigalloc, nr_allocated);
            /* reset things to a sane value */
            bigalloc = amount_needed - nr_allocated;
        }
        /*
         * try pass 0 and pass 1 looking for a nice big
         * contiguous allocation.  Then reset and look
         * for anything you can find.
         */
        if (passno == 2 && bigalloc) {
            passno = 0;
            bigalloc = 0;
        }
        switch (passno++) {
        case 0: /* Search from hint->search_start to end of disk */
            start = hint->search_start;
            finish = SB_BLOCK_COUNT(s) - 1;
            break;
        case 1: /* Search from hint->beg to hint->search_start */
            start = hint->beg;
            finish = hint->search_start;
            break;
        case 2: /* Last chance: Search from 0 to hint->beg */
            start = 0;
            finish = hint->beg;
            break;
        default: /* We've tried searching everywhere, not enough space */
            /* Free the blocks */
            if (!hint->formatted_node) {
#ifdef REISERQUOTA_DEBUG
                reiserfs_debug (s, REISERFS_DEBUG_CODE, "reiserquota: freeing (nospace) %d blocks id=%u", amount_needed + hint->prealloc_size - nr_allocated, hint->inode->i_uid);
#endif
                DQUOT_FREE_BLOCK_NODIRTY(hint->inode, amount_needed + hint->prealloc_size - nr_allocated);     /* Free not allocated blocks */
            }
            while (nr_allocated --)
                reiserfs_free_block(hint->th, hint->inode, new_blocknrs[nr_allocated], !hint->formatted_node);

            return NO_DISK_SPACE;
        }
    } while ((nr_allocated += allocate_without_wrapping_disk (hint,
                              new_blocknrs + nr_allocated, start, finish,
                              bigalloc ? bigalloc : 1,
                              amount_needed - nr_allocated,
                              hint->prealloc_size))
             < amount_needed);
    if ( !hint->formatted_node &&
            amount_needed + hint->prealloc_size >
            nr_allocated + REISERFS_I(hint->inode)->i_prealloc_count) {
        /* Some of preallocation blocks were not allocated */
#ifdef REISERQUOTA_DEBUG
        reiserfs_debug (s, REISERFS_DEBUG_CODE, "reiserquota: freeing (failed prealloc) %d blocks id=%u", amount_needed + hint->prealloc_size - nr_allocated - REISERFS_I(hint->inode)->i_prealloc_count, hint->inode->i_uid);
#endif
        DQUOT_FREE_BLOCK_NODIRTY(hint->inode, amount_needed +
                                 hint->prealloc_size - nr_allocated -
                                 REISERFS_I(hint->inode)->i_prealloc_count);
    }

    return CARRY_ON;
}
Example #22
0
/* 
** We pre-allocate 8 blocks.  Pre-allocation is used for files > 16 KB only.
** This lowers fragmentation on large files by grabbing a contiguous set of
** blocks at once.  It also limits the number of times the bitmap block is
** logged by making X number of allocation changes in a single transaction.
**
** We are using a border to divide the disk into two parts.  The first part
** is used for tree blocks, which have a very high turnover rate (they
** are constantly allocated then freed)
**
** The second part of the disk is for the unformatted nodes of larger files.
** Putting them away from the tree blocks lowers fragmentation, and makes
** it easier to group files together.  There are a number of different
** allocation schemes being tried right now, each is documented below.
**
** A great deal of the allocator's speed comes because reiserfs_get_block
** sends us the block number of the last unformatted node in the file.  Once
** a given block is allocated past the border, we don't collide with the
** blocks near the search_start again.
** 
*/
int reiserfs_new_unf_blocknrs2 (struct reiserfs_transaction_handle *th, 
				struct inode       * p_s_inode,
				unsigned long      * free_blocknrs,
				unsigned long        search_start)
{
  int ret=0, blks_gotten=0;
  unsigned long border = 0;
  unsigned long bstart = 0;
  unsigned long hash_in, hash_out;
  unsigned long saved_search_start=search_start;
  int allocated[PREALLOCATION_SIZE];
  int blks;

  if (!reiserfs_no_border(th->t_super)) {
    /* we default to having the border at the 10% mark of the disk.  This
    ** is an arbitrary decision and it needs tuning.  It also needs a limit
    ** to prevent it from taking too much space on huge drives.
    */
    bstart = (SB_BLOCK_COUNT(th->t_super) / 10); 
  }
  if (!reiserfs_no_unhashed_relocation(th->t_super)) {
    /* this is a very simple first attempt at preventing too much grouping
    ** around the border value.  Since k_dir_id is never larger than the
    ** highest allocated oid, it is far from perfect, and files will tend
    ** to be grouped towards the start of the border
    */
    border = le32_to_cpu(INODE_PKEY(p_s_inode)->k_dir_id) % (SB_BLOCK_COUNT(th->t_super) - bstart - 1) ;
  } else {
    /* why would we want to delcare a local variable to this if statement
    ** name border????? -chris
    ** unsigned long border = 0;
    */
    if (!reiserfs_hashed_relocation(th->t_super)) {
      hash_in = le32_to_cpu((INODE_PKEY(p_s_inode))->k_dir_id);
				/* I wonder if the CPU cost of the
                                   hash will obscure the layout
                                   effect? Of course, whether that
                                   effect is good or bad we don't
                                   know.... :-) */
      
      hash_out = keyed_hash(((char *) (&hash_in)), 4);
      border = hash_out % (SB_BLOCK_COUNT(th->t_super) - bstart - 1) ;
    }
  }
  border += bstart ;
  allocated[0] = 0 ; /* important.  Allows a check later on to see if at
                      * least one block was allocated.  This prevents false
		      * no disk space returns
		      */

  if ( (p_s_inode->i_size < 4 * 4096) || 
       !(S_ISREG(p_s_inode->i_mode)) )
    {
      if ( search_start < border 
	   || (
				/* allow us to test whether it is a
                                   good idea to prevent files from
                                   getting too far away from their
                                   packing locality by some unexpected
                                   means.  This might be poor code for
                                   directories whose files total
                                   larger than 1/10th of the disk, and
                                   it might be good code for
                                   suffering from old insertions when the disk
                                   was almost full. */
               /* changed from !reiserfs_test3(th->t_super), which doesn't
               ** seem like a good idea.  Think about adding blocks to
               ** a large file.  If you've allocated 10% of the disk
               ** in contiguous blocks, you start over at the border value
               ** for every new allocation.  This throws away all the
               ** information sent in about the last block that was allocated
               ** in the file.  Not a good general case at all.
               ** -chris
               */
	       reiserfs_test4(th->t_super) && 
	       (search_start > border + (SB_BLOCK_COUNT(th->t_super) / 10))
	       )
	   )
	search_start=border;
  
      ret = do_reiserfs_new_blocknrs(th, free_blocknrs, search_start, 
				     1/*amount_needed*/, 
				     0/*use reserved blocks for root */,
				     1/*for_formatted*/,
				     0/*for prealloc */) ;  
      return ret;
    }

  /* take a block off the prealloc list and return it -Hans */
  if (p_s_inode->u.reiserfs_i.i_prealloc_count > 0) {
    p_s_inode->u.reiserfs_i.i_prealloc_count--;
    *free_blocknrs = p_s_inode->u.reiserfs_i.i_prealloc_block++;

    /* if no more preallocated blocks, remove inode from list */
    if (! p_s_inode->u.reiserfs_i.i_prealloc_count) {
      list_del(&p_s_inode->u.reiserfs_i.i_prealloc_list);
    }
    
    return ret;
  }

				/* else get a new preallocation for the file */
  reiserfs_discard_prealloc (th, p_s_inode);
  /* this uses the last preallocated block as the search_start.  discard
  ** prealloc does not zero out this number.
  */
  if (search_start <= p_s_inode->u.reiserfs_i.i_prealloc_block) {
    search_start = p_s_inode->u.reiserfs_i.i_prealloc_block;
  }
  
  /* doing the compare again forces search_start to be >= the border,
  ** even if the file already had prealloction done.  This seems extra,
  ** and should probably be removed
  */
  if ( search_start < border ) search_start=border; 

  /* If the disk free space is already below 10% we should 
  ** start looking for the free blocks from the beginning 
  ** of the partition, before the border line.
  */
  if ( SB_FREE_BLOCKS(th->t_super) <= (SB_BLOCK_COUNT(th->t_super) / 10) ) {
    search_start=saved_search_start;
  }

  *free_blocknrs = 0;
  blks = PREALLOCATION_SIZE-1;
  for (blks_gotten=0; blks_gotten<PREALLOCATION_SIZE; blks_gotten++) {
    ret = do_reiserfs_new_blocknrs(th, free_blocknrs, search_start, 
				   1/*amount_needed*/, 
				   0/*for root reserved*/,
				   1/*for_formatted*/,
				   (blks_gotten > 0)/*must_be_contiguous*/) ;
    /* if we didn't find a block this time, adjust blks to reflect
    ** the actual number of blocks allocated
    */ 
    if (ret != CARRY_ON) {
      blks = blks_gotten > 0 ? (blks_gotten - 1) : 0 ;
      break ;
    }
    allocated[blks_gotten]= *free_blocknrs;
#ifdef CONFIG_REISERFS_CHECK
    if ( (blks_gotten>0) && (allocated[blks_gotten] - allocated[blks_gotten-1]) != 1 ) {
      /* this should be caught by new_blocknrs now, checking code */
      reiserfs_warning("yura-1, reiserfs_new_unf_blocknrs2: pre-allocated not contiguous set of blocks!\n") ;
      reiserfs_free_block(th, allocated[blks_gotten]);
      blks = blks_gotten-1; 
      break;
    }
#endif
    if (blks_gotten==0) {
      p_s_inode->u.reiserfs_i.i_prealloc_block = *free_blocknrs;
    }
    search_start = *free_blocknrs; 
    *free_blocknrs = 0;
  }
  p_s_inode->u.reiserfs_i.i_prealloc_count = blks;
  *free_blocknrs = p_s_inode->u.reiserfs_i.i_prealloc_block;
  p_s_inode->u.reiserfs_i.i_prealloc_block++;

  /* if inode has preallocated blocks, link him to list */
  if (p_s_inode->u.reiserfs_i.i_prealloc_count) {
    list_add(&p_s_inode->u.reiserfs_i.i_prealloc_list,
	     &SB_JOURNAL(th->t_super)->j_prealloc_list);
  } 
  /* we did actually manage to get 1 block */
  if (ret != CARRY_ON && allocated[0] > 0) {
    return CARRY_ON ;
  }
  /* NO_MORE_UNUSED_CONTIGUOUS_BLOCKS should only mean something to
  ** the preallocation code.  The rest of the filesystem asks for a block
  ** and should either get it, or know the disk is full.  The code
  ** above should never allow ret == NO_MORE_UNUSED_CONTIGUOUS_BLOCK,
  ** as it doesn't send for_prealloc = 1 to do_reiserfs_new_blocknrs
  ** unless it has already successfully allocated at least one block.
  ** Just in case, we translate into a return value the rest of the
  ** filesystem can understand.
  **
  ** It is an error to change this without making the
  ** rest of the filesystem understand NO_MORE_UNUSED_CONTIGUOUS_BLOCKS
  ** If you consider it a bug to return NO_DISK_SPACE here, fix the rest
  ** of the fs first.
  */
  if (ret == NO_MORE_UNUSED_CONTIGUOUS_BLOCKS) {
#ifdef CONFIG_REISERFS_CHECK
    reiserfs_warning("reiser-2015: this shouldn't happen, may cause false out of disk space error");
#endif
     return NO_DISK_SPACE; 
  }
  return ret;
}