/* 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; } } }
/* 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; }