示例#1
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;

}
示例#2
0
/* The function is NOT SCHEDULE-SAFE!  
** because the bitmap block we want to change could be locked, and on its
** way to the disk when we want to read it, and because of the 
** flush_async_commits.  Per bitmap block locks won't help much, and 
** really aren't needed, as we retry later on if we try to set the bit
** and it is already set.
*/
static int find_zero_bit_in_bitmap (struct super_block * s, 
                                    unsigned long search_start, 
				    int * bmap_nr, int * offset, 
				    int for_unformatted)
{
  int retry_count = 0 ;
  /* get bit location (bitmap number and bit offset) of search_start block */
  get_bit_address (s, search_start, bmap_nr, offset);

    /* note that we search forward in the bitmap, benchmarks have shown that it is better to allocate in increasing
       sequence, which is probably due to the disk spinning in the forward direction.. */
    if (find_forward (s, bmap_nr, offset, for_unformatted) == 0) {
      /* there wasn't a free block with number greater than our
         starting point, so we are going to go to the beginning of the disk */

retry:
      search_start = 0; /* caller will reset search_start for itself also. */
      get_bit_address (s, search_start, bmap_nr, offset);
      if (find_forward (s, bmap_nr,offset,for_unformatted) == 0) {
	if (for_unformatted) {	/* why only unformatted nodes? -Hans */
	  if (retry_count == 0) {
	    /* we've got a chance that flushing async commits will free up
	    ** some space.  Sync then retry
	    */
	    flush_async_commits(s) ;
	    retry_count++ ;
	    goto retry ;
	  } else if (retry_count > 0) {
	    /* nothing more we can do.  Make the others wait, flush
	    ** all log blocks to disk, and flush to their home locations.
	    ** this will free up any blocks held by the journal
	    */
	    SB_JOURNAL(s)->j_must_wait = 1 ;
	  }
	}
        return 0;
      }
    }
  return 1;
}
示例#3
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;
}
示例#4
0
static void _reiserfs_free_block (struct reiserfs_transaction_handle *th,
                                  struct inode *inode, b_blocknr_t block,
                                  int for_unformatted)
{
    struct super_block * s = th->t_super;
    struct reiserfs_super_block * rs;
    struct buffer_head * sbh;
    struct reiserfs_bitmap_info *apbi;
    int nr, offset;

    BUG_ON (!th->t_trans_id);

    PROC_INFO_INC( s, free_block );

    rs = SB_DISK_SUPER_BLOCK (s);
    sbh = SB_BUFFER_WITH_SB (s);
    apbi = SB_AP_BITMAP(s);

    get_bit_address (s, block, &nr, &offset);

    if (nr >= sb_bmap_nr (rs)) {
        reiserfs_warning (s, "vs-4075: reiserfs_free_block: "
                          "block %lu is out of range on %s",
                          block, reiserfs_bdevname (s));
        return;
    }

    reiserfs_prepare_for_journal(s, apbi[nr].bh, 1 ) ;

    /* clear bit for the given block in bit map */
    if (!reiserfs_test_and_clear_le_bit (offset, apbi[nr].bh->b_data)) {
        reiserfs_warning (s, "vs-4080: reiserfs_free_block: "
                          "free_block (%s:%lu)[dev:blocknr]: bit already cleared",
                          reiserfs_bdevname (s), block);
    }
    apbi[nr].free_count ++;
    journal_mark_dirty (th, s, apbi[nr].bh);

    reiserfs_prepare_for_journal(s, sbh, 1) ;
    /* update super block */
    set_sb_free_blocks( rs, sb_free_blocks(rs) + 1 );

    journal_mark_dirty (th, s, sbh);
    if (for_unformatted)
        DQUOT_FREE_BLOCK_NODIRTY(inode, 1);
}
示例#5
0
static void _reiserfs_free_block (struct reiserfs_transaction_handle *th,
                                  b_blocknr_t block)
{
    struct super_block * s = th->t_super;
    struct reiserfs_super_block * rs;
    struct buffer_head * sbh;
    struct reiserfs_bitmap_info *apbi;
    int nr, offset;

    PROC_INFO_INC( s, free_block );

    rs = SB_DISK_SUPER_BLOCK (s);
    sbh = SB_BUFFER_WITH_SB (s);
    apbi = SB_AP_BITMAP(s);

    get_bit_address (s, block, &nr, &offset);

    if (nr >= sb_bmap_nr (rs)) {
        reiserfs_warning ("vs-4075: reiserfs_free_block: "
                          "block %lu is out of range on %s\n",
                          block, bdevname(s->s_dev));
        return;
    }

    reiserfs_prepare_for_journal(s, apbi[nr].bh, 1 ) ;

    /* clear bit for the given block in bit map */
    if (!reiserfs_test_and_clear_le_bit (offset, apbi[nr].bh->b_data)) {
        reiserfs_warning ("vs-4080: reiserfs_free_block: "
                          "free_block (%04x:%lu)[dev:blocknr]: bit already cleared\n",
                          s->s_dev, block);
    }
    if (offset < apbi[nr].first_zero_hint) {
        apbi[nr].first_zero_hint = offset;
    }
    apbi[nr].free_count ++;
    journal_mark_dirty (th, s, apbi[nr].bh);

    reiserfs_prepare_for_journal(s, sbh, 1) ;
    /* update super block */
    set_sb_free_blocks( rs, sb_free_blocks(rs) + 1 );

    journal_mark_dirty (th, s, sbh);
}
示例#6
0
				/* I wonder if it would be less modest
                                   now that we use journaling. -Hans */
void reiserfs_free_block (struct reiserfs_transaction_handle *th, unsigned long block)
{
    struct super_block * s = th->t_super;
    struct reiserfs_super_block * rs;
    struct buffer_head * sbh;
    struct buffer_head ** apbh;
    int nr, offset;

  RFALSE(!s, "vs-4060: trying to free block on nonexistent device");
  RFALSE(is_reusable (s, block, 1) == 0, "vs-4070: can not free such block");

  PROC_INFO_INC( s, free_block );

  rs = SB_DISK_SUPER_BLOCK (s);
  sbh = SB_BUFFER_WITH_SB (s);
  apbh = SB_AP_BITMAP (s);

  get_bit_address (s, block, &nr, &offset);

  /* mark it before we clear it, just in case */
  journal_mark_freed(th, s, block) ;

  reiserfs_prepare_for_journal(s, apbh[nr], 1 ) ;

  /* clear bit for the given block in bit map */
  if (!reiserfs_test_and_clear_le_bit (offset, apbh[nr]->b_data)) {
      reiserfs_warning ("vs-4080: reiserfs_free_block: "
			"free_block (%04x:%lu)[dev:blocknr]: bit already cleared\n", 
	    s->s_dev, block);
  }
  journal_mark_dirty (th, s, apbh[nr]);

  reiserfs_prepare_for_journal(s, sbh, 1) ;
  /* update super block */
  set_sb_free_blocks( rs, sb_free_blocks(rs) + 1 );

  journal_mark_dirty (th, s, sbh);
  s->s_dirt = 1;
}
示例#7
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;

}
示例#8
0
/* The function is NOT SCHEDULE-SAFE! */
static int find_forward (struct super_block * s, int * bmap_nr, int * offset, int for_unformatted)
{
  int i, j;
  struct buffer_head * bh;
  unsigned long block_to_try = 0;
  unsigned long next_block_to_try = 0 ;

  PROC_INFO_INC( s, find_forward.call );

  for (i = *bmap_nr; i < SB_BMAP_NR (s); i ++, *offset = 0, 
	       PROC_INFO_INC( s, find_forward.bmap )) {
    /* get corresponding bitmap block */
    bh = SB_AP_BITMAP (s)[i];
    if (buffer_locked (bh)) {
	PROC_INFO_INC( s, find_forward.wait );
        __wait_on_buffer (bh);
    }
retry:
    j = reiserfs_find_next_zero_le_bit ((unsigned long *)bh->b_data, 
                                         s->s_blocksize << 3, *offset);

    /* wow, this really needs to be redone.  We can't allocate a block if
    ** it is in the journal somehow.  reiserfs_in_journal makes a suggestion
    ** for a good block if the one you ask for is in the journal.  Note,
    ** reiserfs_in_journal might reject the block it suggests.  The big
    ** gain from the suggestion is when a big file has been deleted, and
    ** many blocks show free in the real bitmap, but are all not free
    ** in the journal list bitmaps.
    **
    ** this whole system sucks.  The bitmaps should reflect exactly what
    ** can and can't be allocated, and the journal should update them as
    ** it goes.  TODO.
    */
    if (j < (s->s_blocksize << 3)) {
      block_to_try = (i * (s->s_blocksize << 3)) + j; 

      /* the block is not in the journal, we can proceed */
      if (!(reiserfs_in_journal(s, s->s_dev, block_to_try, s->s_blocksize, for_unformatted, &next_block_to_try))) {
	*bmap_nr = i;
	*offset = j;
	return 1;
      } 
      /* the block is in the journal */
      else if ((j+1) < (s->s_blocksize << 3)) { /* try again */
	/* reiserfs_in_journal suggested a new block to try */
	if (next_block_to_try > 0) {
	  int new_i ;
	  get_bit_address (s, next_block_to_try, &new_i, offset);

	  PROC_INFO_INC( s, find_forward.in_journal_hint );

	  /* block is not in this bitmap. reset i and continue
	  ** we only reset i if new_i is in a later bitmap.
	  */
	  if (new_i > i) {
	    i = (new_i - 1 ); /* i gets incremented by the for loop */
	    PROC_INFO_INC( s, find_forward.in_journal_out );
	    continue ;
	  }
	} else {
	  /* no suggestion was made, just try the next block */
	  *offset = j+1 ;
	}
	PROC_INFO_INC( s, find_forward.retry );
	goto retry ;
      }
    }
  }
    /* zero bit not found */
    return 0;
}