Ejemplo n.º 1
0
/* it searches for a window of zero bits with given minimum and maximum lengths in one bitmap
 * block; */
static int scan_bitmap_block (struct reiserfs_transaction_handle *th,
                              int bmap_n, int *beg, int boundary, int min, int max, int unfm)
{
    struct super_block *s = th->t_super;
    struct reiserfs_bitmap_info *bi=&SB_AP_BITMAP(s)[bmap_n];
    int end, next;
    int org = *beg;

    BUG_ON (!th->t_trans_id);

    RFALSE(bmap_n >= SB_BMAP_NR (s), "Bitmap %d is out of range (0..%d)",bmap_n, SB_BMAP_NR (s) - 1);
    PROC_INFO_INC( s, scan_bitmap.bmap );
    /* this is unclear and lacks comments, explain how journal bitmaps
       work here for the reader.  Convey a sense of the design here. What
       is a window? */
    /* - I mean `a window of zero bits' as in description of this function - Zam. */

    if ( !bi ) {
        reiserfs_warning (s, "NULL bitmap info pointer for bitmap %d", bmap_n);
        return 0;
    }
    if (buffer_locked (bi->bh)) {
        PROC_INFO_INC( s, scan_bitmap.wait );
        __wait_on_buffer (bi->bh);
    }

    while (1) {
cont:
        if (bi->free_count < min)
            return 0; // No free blocks in this bitmap

        /* search for a first zero bit -- beggining of a window */
        *beg = reiserfs_find_next_zero_le_bit
               ((unsigned long*)(bi->bh->b_data), boundary, *beg);

        if (*beg + min > boundary) {
            /* search for a zero bit fails or the rest of bitmap block
            			      * cannot contain a zero window of minimum size */
            return 0;
        }

        if (unfm && is_block_in_journal(s,bmap_n, *beg, beg))
            continue;
        /* first zero bit found; we check next bits */
        for (end = *beg + 1;; end ++) {
            if (end >= *beg + max || end >= boundary || reiserfs_test_le_bit (end, bi->bh->b_data)) {
                next = end;
                break;
            }
            /* finding the other end of zero bit window requires looking into journal structures (in
             * case of searching for free blocks for unformatted nodes) */
            if (unfm && is_block_in_journal(s, bmap_n, end, &next))
                break;
        }

        /* now (*beg) points to beginning of zero bits window,
         * (end) points to one bit after the window end */
        if (end - *beg >= min) { /* it seems we have found window of proper size */
            int i;
            reiserfs_prepare_for_journal (s, bi->bh, 1);
            /* try to set all blocks used checking are they still free */
            for (i = *beg; i < end; i++) {
                /* It seems that we should not check in journal again. */
                if (reiserfs_test_and_set_le_bit (i, bi->bh->b_data)) {
                    /* bit was set by another process
                     * while we slept in prepare_for_journal() */
                    PROC_INFO_INC( s, scan_bitmap.stolen );
                    if (i >= *beg + min)	{
                        /* we can continue with smaller set of allocated blocks,
                        		   * if length of this set is more or equal to `min' */
                        end = i;
                        break;
                    }
                    /* otherwise we clear all bit were set ... */
                    while (--i >= *beg)
                        reiserfs_test_and_clear_le_bit (i, bi->bh->b_data);
                    reiserfs_restore_prepared_buffer (s, bi->bh);
                    *beg = org;
                    /* ... and search again in current block from beginning */
                    goto cont;
                }
            }
            bi->free_count -= (end - *beg);
            journal_mark_dirty (th, s, bi->bh);

            /* free block count calculation */
            reiserfs_prepare_for_journal (s, SB_BUFFER_WITH_SB(s), 1);
            PUT_SB_FREE_BLOCKS(s, SB_FREE_BLOCKS(s) - (end - *beg));
            journal_mark_dirty (th, s, SB_BUFFER_WITH_SB(s));

            return end - (*beg);
        } else {
            *beg = next;
        }
    }
}
Ejemplo n.º 2
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;
}