11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
31da177e4SLinus Torvalds */
41da177e4SLinus Torvalds /* Reiserfs block (de)allocator, bitmap-based. */
51da177e4SLinus Torvalds
61da177e4SLinus Torvalds #include <linux/time.h>
7f466c6fdSAl Viro #include "reiserfs.h"
81da177e4SLinus Torvalds #include <linux/errno.h>
91da177e4SLinus Torvalds #include <linux/buffer_head.h>
101da177e4SLinus Torvalds #include <linux/kernel.h>
111da177e4SLinus Torvalds #include <linux/pagemap.h>
126f01046bSJeff Mahoney #include <linux/vmalloc.h>
131da177e4SLinus Torvalds #include <linux/quotaops.h>
14c3aa0776SJan Kara #include <linux/seq_file.h>
151da177e4SLinus Torvalds
161da177e4SLinus Torvalds #define PREALLOCATION_SIZE 9
171da177e4SLinus Torvalds
181da177e4SLinus Torvalds /* different reiserfs block allocator options */
191da177e4SLinus Torvalds
201da177e4SLinus Torvalds #define SB_ALLOC_OPTS(s) (REISERFS_SB(s)->s_alloc_options.bits)
211da177e4SLinus Torvalds
221da177e4SLinus Torvalds #define _ALLOC_concentrating_formatted_nodes 0
231da177e4SLinus Torvalds #define _ALLOC_displacing_large_files 1
241da177e4SLinus Torvalds #define _ALLOC_displacing_new_packing_localities 2
251da177e4SLinus Torvalds #define _ALLOC_old_hashed_relocation 3
261da177e4SLinus Torvalds #define _ALLOC_new_hashed_relocation 4
271da177e4SLinus Torvalds #define _ALLOC_skip_busy 5
281da177e4SLinus Torvalds #define _ALLOC_displace_based_on_dirid 6
291da177e4SLinus Torvalds #define _ALLOC_hashed_formatted_nodes 7
301da177e4SLinus Torvalds #define _ALLOC_old_way 8
311da177e4SLinus Torvalds #define _ALLOC_hundredth_slices 9
321da177e4SLinus Torvalds #define _ALLOC_dirid_groups 10
331da177e4SLinus Torvalds #define _ALLOC_oid_groups 11
341da177e4SLinus Torvalds #define _ALLOC_packing_groups 12
351da177e4SLinus Torvalds
361da177e4SLinus Torvalds #define concentrating_formatted_nodes(s) test_bit(_ALLOC_concentrating_formatted_nodes, &SB_ALLOC_OPTS(s))
371da177e4SLinus Torvalds #define displacing_large_files(s) test_bit(_ALLOC_displacing_large_files, &SB_ALLOC_OPTS(s))
381da177e4SLinus Torvalds #define displacing_new_packing_localities(s) test_bit(_ALLOC_displacing_new_packing_localities, &SB_ALLOC_OPTS(s))
391da177e4SLinus Torvalds
401da177e4SLinus Torvalds #define SET_OPTION(optname) \
411da177e4SLinus Torvalds do { \
421d889d99SJeff Mahoney reiserfs_info(s, "block allocator option \"%s\" is set", #optname); \
431da177e4SLinus Torvalds set_bit(_ALLOC_ ## optname , &SB_ALLOC_OPTS(s)); \
441da177e4SLinus Torvalds } while(0)
451da177e4SLinus Torvalds #define TEST_OPTION(optname, s) \
461da177e4SLinus Torvalds test_bit(_ALLOC_ ## optname , &SB_ALLOC_OPTS(s))
471da177e4SLinus Torvalds
get_bit_address(struct super_block * s,b_blocknr_t block,unsigned int * bmap_nr,unsigned int * offset)481da177e4SLinus Torvalds static inline void get_bit_address(struct super_block *s,
493ee16670SJeff Mahoney b_blocknr_t block,
503ee16670SJeff Mahoney unsigned int *bmap_nr,
513ee16670SJeff Mahoney unsigned int *offset)
521da177e4SLinus Torvalds {
53098297b2SJeff Mahoney /*
54098297b2SJeff Mahoney * It is in the bitmap block number equal to the block
55098297b2SJeff Mahoney * number divided by the number of bits in a block.
56098297b2SJeff Mahoney */
57e1fabd3cSJeff Mahoney *bmap_nr = block >> (s->s_blocksize_bits + 3);
581da177e4SLinus Torvalds /* Within that bitmap block it is located at bit offset *offset. */
591da177e4SLinus Torvalds *offset = block & ((s->s_blocksize << 3) - 1);
601da177e4SLinus Torvalds }
611da177e4SLinus Torvalds
is_reusable(struct super_block * s,b_blocknr_t block,int bit_value)621da177e4SLinus Torvalds int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value)
631da177e4SLinus Torvalds {
643ee16670SJeff Mahoney unsigned int bmap, offset;
65cb680c1bSJeff Mahoney unsigned int bmap_count = reiserfs_bmap_count(s);
661da177e4SLinus Torvalds
671da177e4SLinus Torvalds if (block == 0 || block >= SB_BLOCK_COUNT(s)) {
680030b645SJeff Mahoney reiserfs_error(s, "vs-4010",
6945b03d5eSJeff Mahoney "block number is out of range %lu (%u)",
701da177e4SLinus Torvalds block, SB_BLOCK_COUNT(s));
711da177e4SLinus Torvalds return 0;
721da177e4SLinus Torvalds }
731da177e4SLinus Torvalds
74e1fabd3cSJeff Mahoney get_bit_address(s, block, &bmap, &offset);
75e1fabd3cSJeff Mahoney
76098297b2SJeff Mahoney /*
77098297b2SJeff Mahoney * Old format filesystem? Unlikely, but the bitmaps are all
78098297b2SJeff Mahoney * up front so we need to account for it.
79098297b2SJeff Mahoney */
80e1fabd3cSJeff Mahoney if (unlikely(test_bit(REISERFS_OLD_FORMAT,
81a228bf8fSJeff Mahoney &REISERFS_SB(s)->s_properties))) {
82e1fabd3cSJeff Mahoney b_blocknr_t bmap1 = REISERFS_SB(s)->s_sbh->b_blocknr + 1;
83cb680c1bSJeff Mahoney if (block >= bmap1 &&
84cb680c1bSJeff Mahoney block <= bmap1 + bmap_count) {
850030b645SJeff Mahoney reiserfs_error(s, "vs-4019", "bitmap block %lu(%u) "
8645b03d5eSJeff Mahoney "can't be freed or reused",
87cb680c1bSJeff Mahoney block, bmap_count);
88e1fabd3cSJeff Mahoney return 0;
89e1fabd3cSJeff Mahoney }
90e1fabd3cSJeff Mahoney } else {
91e1fabd3cSJeff Mahoney if (offset == 0) {
920030b645SJeff Mahoney reiserfs_error(s, "vs-4020", "bitmap block %lu(%u) "
9345b03d5eSJeff Mahoney "can't be freed or reused",
94cb680c1bSJeff Mahoney block, bmap_count);
951da177e4SLinus Torvalds return 0;
961da177e4SLinus Torvalds }
97e1fabd3cSJeff Mahoney }
981da177e4SLinus Torvalds
99cb680c1bSJeff Mahoney if (bmap >= bmap_count) {
1000030b645SJeff Mahoney reiserfs_error(s, "vs-4030", "bitmap for requested block "
10145b03d5eSJeff Mahoney "is out of range: block=%lu, bitmap_nr=%u",
10245b03d5eSJeff Mahoney block, bmap);
1031da177e4SLinus Torvalds return 0;
1041da177e4SLinus Torvalds }
1051da177e4SLinus Torvalds
1061da177e4SLinus Torvalds if (bit_value == 0 && block == SB_ROOT_BLOCK(s)) {
1070030b645SJeff Mahoney reiserfs_error(s, "vs-4050", "this is root block (%u), "
1081da177e4SLinus Torvalds "it must be busy", SB_ROOT_BLOCK(s));
1091da177e4SLinus Torvalds return 0;
1101da177e4SLinus Torvalds }
1111da177e4SLinus Torvalds
1121da177e4SLinus Torvalds return 1;
1131da177e4SLinus Torvalds }
1141da177e4SLinus Torvalds
115098297b2SJeff Mahoney /*
116098297b2SJeff Mahoney * Searches in journal structures for a given block number (bmap, off).
117098297b2SJeff Mahoney * If block is found in reiserfs journal it suggests next free block
118098297b2SJeff Mahoney * candidate to test.
119098297b2SJeff Mahoney */
is_block_in_journal(struct super_block * s,unsigned int bmap,int off,int * next)1203ee16670SJeff Mahoney static inline int is_block_in_journal(struct super_block *s, unsigned int bmap,
1213ee16670SJeff Mahoney int off, int *next)
1221da177e4SLinus Torvalds {
1231da177e4SLinus Torvalds b_blocknr_t tmp;
1241da177e4SLinus Torvalds
1251da177e4SLinus Torvalds if (reiserfs_in_journal(s, bmap, off, 1, &tmp)) {
1261da177e4SLinus Torvalds if (tmp) { /* hint supplied */
1271da177e4SLinus Torvalds *next = tmp;
1281da177e4SLinus Torvalds PROC_INFO_INC(s, scan_bitmap.in_journal_hint);
1291da177e4SLinus Torvalds } else {
1301da177e4SLinus Torvalds (*next) = off + 1; /* inc offset to avoid looping. */
1311da177e4SLinus Torvalds PROC_INFO_INC(s, scan_bitmap.in_journal_nohint);
1321da177e4SLinus Torvalds }
1331da177e4SLinus Torvalds PROC_INFO_INC(s, scan_bitmap.retry);
1341da177e4SLinus Torvalds return 1;
1351da177e4SLinus Torvalds }
1361da177e4SLinus Torvalds return 0;
1371da177e4SLinus Torvalds }
1381da177e4SLinus Torvalds
139098297b2SJeff Mahoney /*
140098297b2SJeff Mahoney * Searches for a window of zero bits with given minimum and maximum
141098297b2SJeff Mahoney * lengths in one bitmap block
142098297b2SJeff Mahoney */
scan_bitmap_block(struct reiserfs_transaction_handle * th,unsigned int bmap_n,int * beg,int boundary,int min,int max,int unfm)1431da177e4SLinus Torvalds static int scan_bitmap_block(struct reiserfs_transaction_handle *th,
1443ee16670SJeff Mahoney unsigned int bmap_n, int *beg, int boundary,
1453ee16670SJeff Mahoney int min, int max, int unfm)
1461da177e4SLinus Torvalds {
1471da177e4SLinus Torvalds struct super_block *s = th->t_super;
1481da177e4SLinus Torvalds struct reiserfs_bitmap_info *bi = &SB_AP_BITMAP(s)[bmap_n];
1490b3dc17bSJeff Mahoney struct buffer_head *bh;
1501da177e4SLinus Torvalds int end, next;
1511da177e4SLinus Torvalds int org = *beg;
1521da177e4SLinus Torvalds
1531da177e4SLinus Torvalds BUG_ON(!th->t_trans_id);
154cb680c1bSJeff Mahoney RFALSE(bmap_n >= reiserfs_bmap_count(s), "Bitmap %u is out of "
155cb680c1bSJeff Mahoney "range (0..%u)", bmap_n, reiserfs_bmap_count(s) - 1);
1561da177e4SLinus Torvalds PROC_INFO_INC(s, scan_bitmap.bmap);
1571da177e4SLinus Torvalds
1581da177e4SLinus Torvalds if (!bi) {
1590030b645SJeff Mahoney reiserfs_error(s, "jdm-4055", "NULL bitmap info pointer "
16045b03d5eSJeff Mahoney "for bitmap %d", bmap_n);
1611da177e4SLinus Torvalds return 0;
1621da177e4SLinus Torvalds }
1630b3dc17bSJeff Mahoney
1645065227bSJeff Mahoney bh = reiserfs_read_bitmap_block(s, bmap_n);
1655065227bSJeff Mahoney if (bh == NULL)
1665065227bSJeff Mahoney return 0;
1671da177e4SLinus Torvalds
1681da177e4SLinus Torvalds while (1) {
1691da177e4SLinus Torvalds cont:
1700b3dc17bSJeff Mahoney if (bi->free_count < min) {
1710b3dc17bSJeff Mahoney brelse(bh);
172098297b2SJeff Mahoney return 0; /* No free blocks in this bitmap */
1730b3dc17bSJeff Mahoney }
1741da177e4SLinus Torvalds
1753ad2f3fbSDaniel Mack /* search for a first zero bit -- beginning of a window */
1761da177e4SLinus Torvalds *beg = reiserfs_find_next_zero_le_bit
1770b3dc17bSJeff Mahoney ((unsigned long *)(bh->b_data), boundary, *beg);
1781da177e4SLinus Torvalds
179098297b2SJeff Mahoney /*
180098297b2SJeff Mahoney * search for a zero bit fails or the rest of bitmap block
181098297b2SJeff Mahoney * cannot contain a zero window of minimum size
182098297b2SJeff Mahoney */
183098297b2SJeff Mahoney if (*beg + min > boundary) {
1840b3dc17bSJeff Mahoney brelse(bh);
1851da177e4SLinus Torvalds return 0;
1861da177e4SLinus Torvalds }
1871da177e4SLinus Torvalds
1881da177e4SLinus Torvalds if (unfm && is_block_in_journal(s, bmap_n, *beg, beg))
1891da177e4SLinus Torvalds continue;
1901da177e4SLinus Torvalds /* first zero bit found; we check next bits */
1911da177e4SLinus Torvalds for (end = *beg + 1;; end++) {
192bd4c625cSLinus Torvalds if (end >= *beg + max || end >= boundary
1930b3dc17bSJeff Mahoney || reiserfs_test_le_bit(end, bh->b_data)) {
1941da177e4SLinus Torvalds next = end;
1951da177e4SLinus Torvalds break;
1961da177e4SLinus Torvalds }
197098297b2SJeff Mahoney
198098297b2SJeff Mahoney /*
199098297b2SJeff Mahoney * finding the other end of zero bit window requires
200098297b2SJeff Mahoney * looking into journal structures (in case of
201098297b2SJeff Mahoney * searching for free blocks for unformatted nodes)
202098297b2SJeff Mahoney */
2031da177e4SLinus Torvalds if (unfm && is_block_in_journal(s, bmap_n, end, &next))
2041da177e4SLinus Torvalds break;
2051da177e4SLinus Torvalds }
2061da177e4SLinus Torvalds
207098297b2SJeff Mahoney /*
208098297b2SJeff Mahoney * now (*beg) points to beginning of zero bits window,
209098297b2SJeff Mahoney * (end) points to one bit after the window end
210098297b2SJeff Mahoney */
211098297b2SJeff Mahoney
212098297b2SJeff Mahoney /* found window of proper size */
213098297b2SJeff Mahoney if (end - *beg >= min) {
2141da177e4SLinus Torvalds int i;
2150b3dc17bSJeff Mahoney reiserfs_prepare_for_journal(s, bh, 1);
216098297b2SJeff Mahoney /*
217098297b2SJeff Mahoney * try to set all blocks used checking are
218098297b2SJeff Mahoney * they still free
219098297b2SJeff Mahoney */
2201da177e4SLinus Torvalds for (i = *beg; i < end; i++) {
221098297b2SJeff Mahoney /* Don't check in journal again. */
222bd4c625cSLinus Torvalds if (reiserfs_test_and_set_le_bit
2230b3dc17bSJeff Mahoney (i, bh->b_data)) {
224098297b2SJeff Mahoney /*
225098297b2SJeff Mahoney * bit was set by another process while
226098297b2SJeff Mahoney * we slept in prepare_for_journal()
227098297b2SJeff Mahoney */
2281da177e4SLinus Torvalds PROC_INFO_INC(s, scan_bitmap.stolen);
229098297b2SJeff Mahoney
230098297b2SJeff Mahoney /*
231098297b2SJeff Mahoney * we can continue with smaller set
232098297b2SJeff Mahoney * of allocated blocks, if length of
233098297b2SJeff Mahoney * this set is more or equal to `min'
234098297b2SJeff Mahoney */
235098297b2SJeff Mahoney if (i >= *beg + min) {
2361da177e4SLinus Torvalds end = i;
2371da177e4SLinus Torvalds break;
2381da177e4SLinus Torvalds }
239098297b2SJeff Mahoney
240098297b2SJeff Mahoney /*
241098297b2SJeff Mahoney * otherwise we clear all bit
242098297b2SJeff Mahoney * were set ...
243098297b2SJeff Mahoney */
2441da177e4SLinus Torvalds while (--i >= *beg)
2450c2fd1bfSAkinobu Mita reiserfs_clear_le_bit
2460b3dc17bSJeff Mahoney (i, bh->b_data);
2470b3dc17bSJeff Mahoney reiserfs_restore_prepared_buffer(s, bh);
2481da177e4SLinus Torvalds *beg = org;
249098297b2SJeff Mahoney
250098297b2SJeff Mahoney /*
251098297b2SJeff Mahoney * Search again in current block
252098297b2SJeff Mahoney * from beginning
253098297b2SJeff Mahoney */
2541da177e4SLinus Torvalds goto cont;
2551da177e4SLinus Torvalds }
2561da177e4SLinus Torvalds }
2571da177e4SLinus Torvalds bi->free_count -= (end - *beg);
25809f1b80bSJeff Mahoney journal_mark_dirty(th, bh);
2590b3dc17bSJeff Mahoney brelse(bh);
2601da177e4SLinus Torvalds
2611da177e4SLinus Torvalds /* free block count calculation */
262bd4c625cSLinus Torvalds reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s),
263bd4c625cSLinus Torvalds 1);
2641da177e4SLinus Torvalds PUT_SB_FREE_BLOCKS(s, SB_FREE_BLOCKS(s) - (end - *beg));
26509f1b80bSJeff Mahoney journal_mark_dirty(th, SB_BUFFER_WITH_SB(s));
2661da177e4SLinus Torvalds
2671da177e4SLinus Torvalds return end - (*beg);
2681da177e4SLinus Torvalds } else {
2691da177e4SLinus Torvalds *beg = next;
2701da177e4SLinus Torvalds }
2711da177e4SLinus Torvalds }
2721da177e4SLinus Torvalds }
2731da177e4SLinus Torvalds
bmap_hash_id(struct super_block * s,u32 id)274bd4c625cSLinus Torvalds static int bmap_hash_id(struct super_block *s, u32 id)
275bd4c625cSLinus Torvalds {
2761da177e4SLinus Torvalds char *hash_in = NULL;
2771da177e4SLinus Torvalds unsigned long hash;
2781da177e4SLinus Torvalds unsigned bm;
2791da177e4SLinus Torvalds
2801da177e4SLinus Torvalds if (id <= 2) {
2811da177e4SLinus Torvalds bm = 1;
2821da177e4SLinus Torvalds } else {
2831da177e4SLinus Torvalds hash_in = (char *)(&id);
2841da177e4SLinus Torvalds hash = keyed_hash(hash_in, 4);
285cb680c1bSJeff Mahoney bm = hash % reiserfs_bmap_count(s);
2861da177e4SLinus Torvalds if (!bm)
2871da177e4SLinus Torvalds bm = 1;
2881da177e4SLinus Torvalds }
2891da177e4SLinus Torvalds /* this can only be true when SB_BMAP_NR = 1 */
290cb680c1bSJeff Mahoney if (bm >= reiserfs_bmap_count(s))
2911da177e4SLinus Torvalds bm = 0;
2921da177e4SLinus Torvalds return bm;
2931da177e4SLinus Torvalds }
2941da177e4SLinus Torvalds
2951da177e4SLinus Torvalds /*
2961da177e4SLinus Torvalds * hashes the id and then returns > 0 if the block group for the
2971da177e4SLinus Torvalds * corresponding hash is full
2981da177e4SLinus Torvalds */
block_group_used(struct super_block * s,u32 id)299bd4c625cSLinus Torvalds static inline int block_group_used(struct super_block *s, u32 id)
300bd4c625cSLinus Torvalds {
3015065227bSJeff Mahoney int bm = bmap_hash_id(s, id);
3025065227bSJeff Mahoney struct reiserfs_bitmap_info *info = &SB_AP_BITMAP(s)[bm];
3035065227bSJeff Mahoney
304098297b2SJeff Mahoney /*
305098297b2SJeff Mahoney * If we don't have cached information on this bitmap block, we're
3065065227bSJeff Mahoney * going to have to load it later anyway. Loading it here allows us
307c78bad11SJoe Perches * to make a better decision. This favors long-term performance gain
3085065227bSJeff Mahoney * with a better on-disk layout vs. a short term gain of skipping the
309098297b2SJeff Mahoney * read and potentially having a bad placement.
310098297b2SJeff Mahoney */
3114d20851dSJeff Mahoney if (info->free_count == UINT_MAX) {
3125065227bSJeff Mahoney struct buffer_head *bh = reiserfs_read_bitmap_block(s, bm);
3135065227bSJeff Mahoney brelse(bh);
3145065227bSJeff Mahoney }
3155065227bSJeff Mahoney
3165065227bSJeff Mahoney if (info->free_count > ((s->s_blocksize << 3) * 60 / 100)) {
3171da177e4SLinus Torvalds return 0;
3181da177e4SLinus Torvalds }
3191da177e4SLinus Torvalds return 1;
3201da177e4SLinus Torvalds }
3211da177e4SLinus Torvalds
3221da177e4SLinus Torvalds /*
3231da177e4SLinus Torvalds * the packing is returned in disk byte order
3241da177e4SLinus Torvalds */
reiserfs_choose_packing(struct inode * dir)3253e8962beSAl Viro __le32 reiserfs_choose_packing(struct inode * dir)
3263e8962beSAl Viro {
3273e8962beSAl Viro __le32 packing;
3281da177e4SLinus Torvalds if (TEST_OPTION(packing_groups, dir->i_sb)) {
3291da177e4SLinus Torvalds u32 parent_dir = le32_to_cpu(INODE_PKEY(dir)->k_dir_id);
3301da177e4SLinus Torvalds /*
3311da177e4SLinus Torvalds * some versions of reiserfsck expect packing locality 1 to be
3321da177e4SLinus Torvalds * special
3331da177e4SLinus Torvalds */
3341da177e4SLinus Torvalds if (parent_dir == 1 || block_group_used(dir->i_sb, parent_dir))
3351da177e4SLinus Torvalds packing = INODE_PKEY(dir)->k_objectid;
3361da177e4SLinus Torvalds else
3371da177e4SLinus Torvalds packing = INODE_PKEY(dir)->k_dir_id;
3381da177e4SLinus Torvalds } else
3391da177e4SLinus Torvalds packing = INODE_PKEY(dir)->k_objectid;
3401da177e4SLinus Torvalds return packing;
3411da177e4SLinus Torvalds }
3421da177e4SLinus Torvalds
343098297b2SJeff Mahoney /*
344098297b2SJeff Mahoney * Tries to find contiguous zero bit window (given size) in given region of
345098297b2SJeff Mahoney * bitmap and place new blocks there. Returns number of allocated blocks.
346098297b2SJeff Mahoney */
scan_bitmap(struct reiserfs_transaction_handle * th,b_blocknr_t * start,b_blocknr_t finish,int min,int max,int unfm,sector_t file_block)3471da177e4SLinus Torvalds static int scan_bitmap(struct reiserfs_transaction_handle *th,
3481da177e4SLinus Torvalds b_blocknr_t * start, b_blocknr_t finish,
3493ee16670SJeff Mahoney int min, int max, int unfm, sector_t file_block)
3501da177e4SLinus Torvalds {
3511da177e4SLinus Torvalds int nr_allocated = 0;
3521da177e4SLinus Torvalds struct super_block *s = th->t_super;
3533ee16670SJeff Mahoney unsigned int bm, off;
3543ee16670SJeff Mahoney unsigned int end_bm, end_off;
3553ee16670SJeff Mahoney unsigned int off_max = s->s_blocksize << 3;
3561da177e4SLinus Torvalds
3571da177e4SLinus Torvalds BUG_ON(!th->t_trans_id);
3581da177e4SLinus Torvalds PROC_INFO_INC(s, scan_bitmap.call);
359098297b2SJeff Mahoney
360098297b2SJeff Mahoney /* No point in looking for more free blocks */
3611da177e4SLinus Torvalds if (SB_FREE_BLOCKS(s) <= 0)
362098297b2SJeff Mahoney return 0;
3631da177e4SLinus Torvalds
3641da177e4SLinus Torvalds get_bit_address(s, *start, &bm, &off);
3651da177e4SLinus Torvalds get_bit_address(s, finish, &end_bm, &end_off);
366cb680c1bSJeff Mahoney if (bm > reiserfs_bmap_count(s))
3671da177e4SLinus Torvalds return 0;
368cb680c1bSJeff Mahoney if (end_bm > reiserfs_bmap_count(s))
369cb680c1bSJeff Mahoney end_bm = reiserfs_bmap_count(s);
3701da177e4SLinus Torvalds
371098297b2SJeff Mahoney /*
372098297b2SJeff Mahoney * When the bitmap is more than 10% free, anyone can allocate.
3731da177e4SLinus Torvalds * When it's less than 10% free, only files that already use the
3741da177e4SLinus Torvalds * bitmap are allowed. Once we pass 80% full, this restriction
3751da177e4SLinus Torvalds * is lifted.
3761da177e4SLinus Torvalds *
3771da177e4SLinus Torvalds * We do this so that files that grow later still have space close to
3781da177e4SLinus Torvalds * their original allocation. This improves locality, and presumably
3791da177e4SLinus Torvalds * performance as a result.
3801da177e4SLinus Torvalds *
3811da177e4SLinus Torvalds * This is only an allocation policy and does not make up for getting a
3821da177e4SLinus Torvalds * bad hint. Decent hinting must be implemented for this to work well.
3831da177e4SLinus Torvalds */
384bd4c625cSLinus Torvalds if (TEST_OPTION(skip_busy, s)
385bd4c625cSLinus Torvalds && SB_FREE_BLOCKS(s) > SB_BLOCK_COUNT(s) / 20) {
3861da177e4SLinus Torvalds for (; bm < end_bm; bm++, off = 0) {
387bd4c625cSLinus Torvalds if ((off && (!unfm || (file_block != 0)))
388bd4c625cSLinus Torvalds || SB_AP_BITMAP(s)[bm].free_count >
389bd4c625cSLinus Torvalds (s->s_blocksize << 3) / 10)
390bd4c625cSLinus Torvalds nr_allocated =
391bd4c625cSLinus Torvalds scan_bitmap_block(th, bm, &off, off_max,
392bd4c625cSLinus Torvalds min, max, unfm);
3931da177e4SLinus Torvalds if (nr_allocated)
3941da177e4SLinus Torvalds goto ret;
3951da177e4SLinus Torvalds }
3961da177e4SLinus Torvalds /* we know from above that start is a reasonable number */
3971da177e4SLinus Torvalds get_bit_address(s, *start, &bm, &off);
3981da177e4SLinus Torvalds }
3991da177e4SLinus Torvalds
4001da177e4SLinus Torvalds for (; bm < end_bm; bm++, off = 0) {
401bd4c625cSLinus Torvalds nr_allocated =
402bd4c625cSLinus Torvalds scan_bitmap_block(th, bm, &off, off_max, min, max, unfm);
4031da177e4SLinus Torvalds if (nr_allocated)
4041da177e4SLinus Torvalds goto ret;
4051da177e4SLinus Torvalds }
4061da177e4SLinus Torvalds
407bd4c625cSLinus Torvalds nr_allocated =
408bd4c625cSLinus Torvalds scan_bitmap_block(th, bm, &off, end_off + 1, min, max, unfm);
4091da177e4SLinus Torvalds
4101da177e4SLinus Torvalds ret:
4111da177e4SLinus Torvalds *start = bm * off_max + off;
4121da177e4SLinus Torvalds return nr_allocated;
4131da177e4SLinus Torvalds
4141da177e4SLinus Torvalds }
4151da177e4SLinus Torvalds
_reiserfs_free_block(struct reiserfs_transaction_handle * th,struct inode * inode,b_blocknr_t block,int for_unformatted)4161da177e4SLinus Torvalds static void _reiserfs_free_block(struct reiserfs_transaction_handle *th,
4171da177e4SLinus Torvalds struct inode *inode, b_blocknr_t block,
4181da177e4SLinus Torvalds int for_unformatted)
4191da177e4SLinus Torvalds {
4201da177e4SLinus Torvalds struct super_block *s = th->t_super;
4211da177e4SLinus Torvalds struct reiserfs_super_block *rs;
4220b3dc17bSJeff Mahoney struct buffer_head *sbh, *bmbh;
4231da177e4SLinus Torvalds struct reiserfs_bitmap_info *apbi;
4243ee16670SJeff Mahoney unsigned int nr, offset;
4251da177e4SLinus Torvalds
4261da177e4SLinus Torvalds BUG_ON(!th->t_trans_id);
4271da177e4SLinus Torvalds PROC_INFO_INC(s, free_block);
4281da177e4SLinus Torvalds rs = SB_DISK_SUPER_BLOCK(s);
4291da177e4SLinus Torvalds sbh = SB_BUFFER_WITH_SB(s);
4301da177e4SLinus Torvalds apbi = SB_AP_BITMAP(s);
4311da177e4SLinus Torvalds
4321da177e4SLinus Torvalds get_bit_address(s, block, &nr, &offset);
4331da177e4SLinus Torvalds
434cb680c1bSJeff Mahoney if (nr >= reiserfs_bmap_count(s)) {
4350030b645SJeff Mahoney reiserfs_error(s, "vs-4075", "block %lu is out of range",
43645b03d5eSJeff Mahoney block);
4371da177e4SLinus Torvalds return;
4381da177e4SLinus Torvalds }
4391da177e4SLinus Torvalds
4405065227bSJeff Mahoney bmbh = reiserfs_read_bitmap_block(s, nr);
4415065227bSJeff Mahoney if (!bmbh)
4425065227bSJeff Mahoney return;
4430b3dc17bSJeff Mahoney
4440b3dc17bSJeff Mahoney reiserfs_prepare_for_journal(s, bmbh, 1);
4451da177e4SLinus Torvalds
4461da177e4SLinus Torvalds /* clear bit for the given block in bit map */
4470b3dc17bSJeff Mahoney if (!reiserfs_test_and_clear_le_bit(offset, bmbh->b_data)) {
4480030b645SJeff Mahoney reiserfs_error(s, "vs-4080",
44945b03d5eSJeff Mahoney "block %lu: bit already cleared", block);
4501da177e4SLinus Torvalds }
4511da177e4SLinus Torvalds apbi[nr].free_count++;
45209f1b80bSJeff Mahoney journal_mark_dirty(th, bmbh);
4530b3dc17bSJeff Mahoney brelse(bmbh);
4541da177e4SLinus Torvalds
4551da177e4SLinus Torvalds reiserfs_prepare_for_journal(s, sbh, 1);
4561da177e4SLinus Torvalds /* update super block */
4571da177e4SLinus Torvalds set_sb_free_blocks(rs, sb_free_blocks(rs) + 1);
4581da177e4SLinus Torvalds
45909f1b80bSJeff Mahoney journal_mark_dirty(th, sbh);
460d2d0395fSJeff Mahoney if (for_unformatted) {
461d2d0395fSJeff Mahoney int depth = reiserfs_write_unlock_nested(s);
4625dd4056dSChristoph Hellwig dquot_free_block_nodirty(inode, 1);
463d2d0395fSJeff Mahoney reiserfs_write_lock_nested(s, depth);
464d2d0395fSJeff Mahoney }
4651da177e4SLinus Torvalds }
4661da177e4SLinus Torvalds
reiserfs_free_block(struct reiserfs_transaction_handle * th,struct inode * inode,b_blocknr_t block,int for_unformatted)4671da177e4SLinus Torvalds void reiserfs_free_block(struct reiserfs_transaction_handle *th,
4681da177e4SLinus Torvalds struct inode *inode, b_blocknr_t block,
4691da177e4SLinus Torvalds int for_unformatted)
4701da177e4SLinus Torvalds {
4711da177e4SLinus Torvalds struct super_block *s = th->t_super;
4721da177e4SLinus Torvalds
473ae0a50abSFabian Frederick BUG_ON(!th->t_trans_id);
4741da177e4SLinus Torvalds RFALSE(!s, "vs-4061: trying to free block on nonexistent device");
475d4c3d19dSJeff Mahoney if (!is_reusable(s, block, 1))
476d4c3d19dSJeff Mahoney return;
477d4c3d19dSJeff Mahoney
478d4c3d19dSJeff Mahoney if (block > sb_block_count(REISERFS_SB(s)->s_rs)) {
4790030b645SJeff Mahoney reiserfs_error(th->t_super, "bitmap-4072",
480d4c3d19dSJeff Mahoney "Trying to free block outside file system "
481d4c3d19dSJeff Mahoney "boundaries (%lu > %lu)",
482d4c3d19dSJeff Mahoney block, sb_block_count(REISERFS_SB(s)->s_rs));
483d4c3d19dSJeff Mahoney return;
484d4c3d19dSJeff Mahoney }
4851da177e4SLinus Torvalds /* mark it before we clear it, just in case */
4861da177e4SLinus Torvalds journal_mark_freed(th, s, block);
4871da177e4SLinus Torvalds _reiserfs_free_block(th, inode, block, for_unformatted);
4881da177e4SLinus Torvalds }
4891da177e4SLinus Torvalds
4901da177e4SLinus Torvalds /* preallocated blocks don't need to be run through journal_mark_freed */
reiserfs_free_prealloc_block(struct reiserfs_transaction_handle * th,struct inode * inode,b_blocknr_t block)4911da177e4SLinus Torvalds static void reiserfs_free_prealloc_block(struct reiserfs_transaction_handle *th,
492bd4c625cSLinus Torvalds struct inode *inode, b_blocknr_t block)
493bd4c625cSLinus Torvalds {
494d4c3d19dSJeff Mahoney BUG_ON(!th->t_trans_id);
495bd4c625cSLinus Torvalds RFALSE(!th->t_super,
496bd4c625cSLinus Torvalds "vs-4060: trying to free block on nonexistent device");
497d4c3d19dSJeff Mahoney if (!is_reusable(th->t_super, block, 1))
498d4c3d19dSJeff Mahoney return;
4991da177e4SLinus Torvalds _reiserfs_free_block(th, inode, block, 1);
5001da177e4SLinus Torvalds }
5011da177e4SLinus Torvalds
__discard_prealloc(struct reiserfs_transaction_handle * th,struct reiserfs_inode_info * ei)5021da177e4SLinus Torvalds static void __discard_prealloc(struct reiserfs_transaction_handle *th,
5031da177e4SLinus Torvalds struct reiserfs_inode_info *ei)
5041da177e4SLinus Torvalds {
5051da177e4SLinus Torvalds unsigned long save = ei->i_prealloc_block;
5061da177e4SLinus Torvalds int dirty = 0;
5071da177e4SLinus Torvalds struct inode *inode = &ei->vfs_inode;
508ae0a50abSFabian Frederick
5091da177e4SLinus Torvalds BUG_ON(!th->t_trans_id);
5101da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_CHECK
5111da177e4SLinus Torvalds if (ei->i_prealloc_count < 0)
5120030b645SJeff Mahoney reiserfs_error(th->t_super, "zam-4001",
51345b03d5eSJeff Mahoney "inode has negative prealloc blocks count.");
5141da177e4SLinus Torvalds #endif
5151da177e4SLinus Torvalds while (ei->i_prealloc_count > 0) {
51608db141bSJeff Mahoney b_blocknr_t block_to_free;
51708db141bSJeff Mahoney
51808db141bSJeff Mahoney /*
51908db141bSJeff Mahoney * reiserfs_free_prealloc_block can drop the write lock,
52008db141bSJeff Mahoney * which could allow another caller to free the same block.
52108db141bSJeff Mahoney * We can protect against it by modifying the prealloc
52208db141bSJeff Mahoney * state before calling it.
52308db141bSJeff Mahoney */
52408db141bSJeff Mahoney block_to_free = ei->i_prealloc_block++;
5251da177e4SLinus Torvalds ei->i_prealloc_count--;
52608db141bSJeff Mahoney reiserfs_free_prealloc_block(th, inode, block_to_free);
5271da177e4SLinus Torvalds dirty = 1;
5281da177e4SLinus Torvalds }
5291da177e4SLinus Torvalds if (dirty)
5301da177e4SLinus Torvalds reiserfs_update_sd(th, inode);
5311da177e4SLinus Torvalds ei->i_prealloc_block = save;
532a228bf8fSJeff Mahoney list_del_init(&ei->i_prealloc_list);
5331da177e4SLinus Torvalds }
5341da177e4SLinus Torvalds
5351da177e4SLinus Torvalds /* FIXME: It should be inline function */
reiserfs_discard_prealloc(struct reiserfs_transaction_handle * th,struct inode * inode)5361da177e4SLinus Torvalds void reiserfs_discard_prealloc(struct reiserfs_transaction_handle *th,
5371da177e4SLinus Torvalds struct inode *inode)
5381da177e4SLinus Torvalds {
5391da177e4SLinus Torvalds struct reiserfs_inode_info *ei = REISERFS_I(inode);
540ae0a50abSFabian Frederick
5411da177e4SLinus Torvalds BUG_ON(!th->t_trans_id);
5421da177e4SLinus Torvalds if (ei->i_prealloc_count)
5431da177e4SLinus Torvalds __discard_prealloc(th, ei);
5441da177e4SLinus Torvalds }
5451da177e4SLinus Torvalds
reiserfs_discard_all_prealloc(struct reiserfs_transaction_handle * th)5461da177e4SLinus Torvalds void reiserfs_discard_all_prealloc(struct reiserfs_transaction_handle *th)
5471da177e4SLinus Torvalds {
5481da177e4SLinus Torvalds struct list_head *plist = &SB_JOURNAL(th->t_super)->j_prealloc_list;
5491da177e4SLinus Torvalds
5501da177e4SLinus Torvalds BUG_ON(!th->t_trans_id);
5511da177e4SLinus Torvalds while (!list_empty(plist)) {
5521da177e4SLinus Torvalds struct reiserfs_inode_info *ei;
553bd4c625cSLinus Torvalds ei = list_entry(plist->next, struct reiserfs_inode_info,
554bd4c625cSLinus Torvalds i_prealloc_list);
5551da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_CHECK
5561da177e4SLinus Torvalds if (!ei->i_prealloc_count) {
5570030b645SJeff Mahoney reiserfs_error(th->t_super, "zam-4001",
55845b03d5eSJeff Mahoney "inode is in prealloc list but has "
55945b03d5eSJeff Mahoney "no preallocated blocks.");
5601da177e4SLinus Torvalds }
5611da177e4SLinus Torvalds #endif
5621da177e4SLinus Torvalds __discard_prealloc(th, ei);
5631da177e4SLinus Torvalds }
5641da177e4SLinus Torvalds }
5651da177e4SLinus Torvalds
reiserfs_init_alloc_options(struct super_block * s)5661da177e4SLinus Torvalds void reiserfs_init_alloc_options(struct super_block *s)
5671da177e4SLinus Torvalds {
5681da177e4SLinus Torvalds set_bit(_ALLOC_skip_busy, &SB_ALLOC_OPTS(s));
5691da177e4SLinus Torvalds set_bit(_ALLOC_dirid_groups, &SB_ALLOC_OPTS(s));
5701da177e4SLinus Torvalds set_bit(_ALLOC_packing_groups, &SB_ALLOC_OPTS(s));
5711da177e4SLinus Torvalds }
5721da177e4SLinus Torvalds
5731da177e4SLinus Torvalds /* block allocator related options are parsed here */
reiserfs_parse_alloc_options(struct super_block * s,char * options)5741da177e4SLinus Torvalds int reiserfs_parse_alloc_options(struct super_block *s, char *options)
5751da177e4SLinus Torvalds {
5761da177e4SLinus Torvalds char *this_char, *value;
5771da177e4SLinus Torvalds
578098297b2SJeff Mahoney /* clear default settings */
579098297b2SJeff Mahoney REISERFS_SB(s)->s_alloc_options.bits = 0;
5801da177e4SLinus Torvalds
5811da177e4SLinus Torvalds while ((this_char = strsep(&options, ":")) != NULL) {
5821da177e4SLinus Torvalds if ((value = strchr(this_char, '=')) != NULL)
5831da177e4SLinus Torvalds *value++ = 0;
5841da177e4SLinus Torvalds
5851da177e4SLinus Torvalds if (!strcmp(this_char, "concentrating_formatted_nodes")) {
5861da177e4SLinus Torvalds int temp;
5871da177e4SLinus Torvalds SET_OPTION(concentrating_formatted_nodes);
588bd4c625cSLinus Torvalds temp = (value
589bd4c625cSLinus Torvalds && *value) ? simple_strtoul(value, &value,
590bd4c625cSLinus Torvalds 0) : 10;
5911da177e4SLinus Torvalds if (temp <= 0 || temp > 100) {
5921da177e4SLinus Torvalds REISERFS_SB(s)->s_alloc_options.border = 10;
5931da177e4SLinus Torvalds } else {
594bd4c625cSLinus Torvalds REISERFS_SB(s)->s_alloc_options.border =
595bd4c625cSLinus Torvalds 100 / temp;
5961da177e4SLinus Torvalds }
5971da177e4SLinus Torvalds continue;
5981da177e4SLinus Torvalds }
5991da177e4SLinus Torvalds if (!strcmp(this_char, "displacing_large_files")) {
6001da177e4SLinus Torvalds SET_OPTION(displacing_large_files);
6011da177e4SLinus Torvalds REISERFS_SB(s)->s_alloc_options.large_file_size =
602bd4c625cSLinus Torvalds (value
603bd4c625cSLinus Torvalds && *value) ? simple_strtoul(value, &value, 0) : 16;
6041da177e4SLinus Torvalds continue;
6051da177e4SLinus Torvalds }
6061da177e4SLinus Torvalds if (!strcmp(this_char, "displacing_new_packing_localities")) {
6071da177e4SLinus Torvalds SET_OPTION(displacing_new_packing_localities);
6081da177e4SLinus Torvalds continue;
609ae0a50abSFabian Frederick }
6101da177e4SLinus Torvalds
6111da177e4SLinus Torvalds if (!strcmp(this_char, "old_hashed_relocation")) {
6121da177e4SLinus Torvalds SET_OPTION(old_hashed_relocation);
6131da177e4SLinus Torvalds continue;
6141da177e4SLinus Torvalds }
6151da177e4SLinus Torvalds
6161da177e4SLinus Torvalds if (!strcmp(this_char, "new_hashed_relocation")) {
6171da177e4SLinus Torvalds SET_OPTION(new_hashed_relocation);
6181da177e4SLinus Torvalds continue;
6191da177e4SLinus Torvalds }
6201da177e4SLinus Torvalds
6211da177e4SLinus Torvalds if (!strcmp(this_char, "dirid_groups")) {
6221da177e4SLinus Torvalds SET_OPTION(dirid_groups);
6231da177e4SLinus Torvalds continue;
6241da177e4SLinus Torvalds }
6251da177e4SLinus Torvalds if (!strcmp(this_char, "oid_groups")) {
6261da177e4SLinus Torvalds SET_OPTION(oid_groups);
6271da177e4SLinus Torvalds continue;
6281da177e4SLinus Torvalds }
6291da177e4SLinus Torvalds if (!strcmp(this_char, "packing_groups")) {
6301da177e4SLinus Torvalds SET_OPTION(packing_groups);
6311da177e4SLinus Torvalds continue;
6321da177e4SLinus Torvalds }
6331da177e4SLinus Torvalds if (!strcmp(this_char, "hashed_formatted_nodes")) {
6341da177e4SLinus Torvalds SET_OPTION(hashed_formatted_nodes);
6351da177e4SLinus Torvalds continue;
6361da177e4SLinus Torvalds }
6371da177e4SLinus Torvalds
6381da177e4SLinus Torvalds if (!strcmp(this_char, "skip_busy")) {
6391da177e4SLinus Torvalds SET_OPTION(skip_busy);
6401da177e4SLinus Torvalds continue;
6411da177e4SLinus Torvalds }
6421da177e4SLinus Torvalds
6431da177e4SLinus Torvalds if (!strcmp(this_char, "hundredth_slices")) {
6441da177e4SLinus Torvalds SET_OPTION(hundredth_slices);
6451da177e4SLinus Torvalds continue;
6461da177e4SLinus Torvalds }
6471da177e4SLinus Torvalds
6481da177e4SLinus Torvalds if (!strcmp(this_char, "old_way")) {
6491da177e4SLinus Torvalds SET_OPTION(old_way);
6501da177e4SLinus Torvalds continue;
6511da177e4SLinus Torvalds }
6521da177e4SLinus Torvalds
6531da177e4SLinus Torvalds if (!strcmp(this_char, "displace_based_on_dirid")) {
6541da177e4SLinus Torvalds SET_OPTION(displace_based_on_dirid);
6551da177e4SLinus Torvalds continue;
6561da177e4SLinus Torvalds }
6571da177e4SLinus Torvalds
6581da177e4SLinus Torvalds if (!strcmp(this_char, "preallocmin")) {
6591da177e4SLinus Torvalds REISERFS_SB(s)->s_alloc_options.preallocmin =
660bd4c625cSLinus Torvalds (value
661bd4c625cSLinus Torvalds && *value) ? simple_strtoul(value, &value, 0) : 4;
6621da177e4SLinus Torvalds continue;
6631da177e4SLinus Torvalds }
6641da177e4SLinus Torvalds
6651da177e4SLinus Torvalds if (!strcmp(this_char, "preallocsize")) {
6661da177e4SLinus Torvalds REISERFS_SB(s)->s_alloc_options.preallocsize =
667bd4c625cSLinus Torvalds (value
668bd4c625cSLinus Torvalds && *value) ? simple_strtoul(value, &value,
669bd4c625cSLinus Torvalds 0) :
670bd4c625cSLinus Torvalds PREALLOCATION_SIZE;
6711da177e4SLinus Torvalds continue;
6721da177e4SLinus Torvalds }
6731da177e4SLinus Torvalds
67445b03d5eSJeff Mahoney reiserfs_warning(s, "zam-4001", "unknown option - %s",
67545b03d5eSJeff Mahoney this_char);
6761da177e4SLinus Torvalds return 1;
6771da177e4SLinus Torvalds }
6781da177e4SLinus Torvalds
6791d889d99SJeff Mahoney reiserfs_info(s, "allocator options = [%08x]\n", SB_ALLOC_OPTS(s));
6801da177e4SLinus Torvalds return 0;
6811da177e4SLinus Torvalds }
6821da177e4SLinus Torvalds
print_sep(struct seq_file * seq,int * first)683c3aa0776SJan Kara static void print_sep(struct seq_file *seq, int *first)
684c3aa0776SJan Kara {
685c3aa0776SJan Kara if (!*first)
686c3aa0776SJan Kara seq_puts(seq, ":");
687c3aa0776SJan Kara else
688c3aa0776SJan Kara *first = 0;
689c3aa0776SJan Kara }
690c3aa0776SJan Kara
show_alloc_options(struct seq_file * seq,struct super_block * s)691c3aa0776SJan Kara void show_alloc_options(struct seq_file *seq, struct super_block *s)
692c3aa0776SJan Kara {
693c3aa0776SJan Kara int first = 1;
694c3aa0776SJan Kara
695c3aa0776SJan Kara if (SB_ALLOC_OPTS(s) == ((1 << _ALLOC_skip_busy) |
696c3aa0776SJan Kara (1 << _ALLOC_dirid_groups) | (1 << _ALLOC_packing_groups)))
697c3aa0776SJan Kara return;
698c3aa0776SJan Kara
699c3aa0776SJan Kara seq_puts(seq, ",alloc=");
700c3aa0776SJan Kara
701c3aa0776SJan Kara if (TEST_OPTION(concentrating_formatted_nodes, s)) {
702c3aa0776SJan Kara print_sep(seq, &first);
703c3aa0776SJan Kara if (REISERFS_SB(s)->s_alloc_options.border != 10) {
704c3aa0776SJan Kara seq_printf(seq, "concentrating_formatted_nodes=%d",
705c3aa0776SJan Kara 100 / REISERFS_SB(s)->s_alloc_options.border);
706c3aa0776SJan Kara } else
707c3aa0776SJan Kara seq_puts(seq, "concentrating_formatted_nodes");
708c3aa0776SJan Kara }
709c3aa0776SJan Kara if (TEST_OPTION(displacing_large_files, s)) {
710c3aa0776SJan Kara print_sep(seq, &first);
711c3aa0776SJan Kara if (REISERFS_SB(s)->s_alloc_options.large_file_size != 16) {
712c3aa0776SJan Kara seq_printf(seq, "displacing_large_files=%lu",
713c3aa0776SJan Kara REISERFS_SB(s)->s_alloc_options.large_file_size);
714c3aa0776SJan Kara } else
715c3aa0776SJan Kara seq_puts(seq, "displacing_large_files");
716c3aa0776SJan Kara }
717c3aa0776SJan Kara if (TEST_OPTION(displacing_new_packing_localities, s)) {
718c3aa0776SJan Kara print_sep(seq, &first);
719c3aa0776SJan Kara seq_puts(seq, "displacing_new_packing_localities");
720c3aa0776SJan Kara }
721c3aa0776SJan Kara if (TEST_OPTION(old_hashed_relocation, s)) {
722c3aa0776SJan Kara print_sep(seq, &first);
723c3aa0776SJan Kara seq_puts(seq, "old_hashed_relocation");
724c3aa0776SJan Kara }
725c3aa0776SJan Kara if (TEST_OPTION(new_hashed_relocation, s)) {
726c3aa0776SJan Kara print_sep(seq, &first);
727c3aa0776SJan Kara seq_puts(seq, "new_hashed_relocation");
728c3aa0776SJan Kara }
729c3aa0776SJan Kara if (TEST_OPTION(dirid_groups, s)) {
730c3aa0776SJan Kara print_sep(seq, &first);
731c3aa0776SJan Kara seq_puts(seq, "dirid_groups");
732c3aa0776SJan Kara }
733c3aa0776SJan Kara if (TEST_OPTION(oid_groups, s)) {
734c3aa0776SJan Kara print_sep(seq, &first);
735c3aa0776SJan Kara seq_puts(seq, "oid_groups");
736c3aa0776SJan Kara }
737c3aa0776SJan Kara if (TEST_OPTION(packing_groups, s)) {
738c3aa0776SJan Kara print_sep(seq, &first);
739c3aa0776SJan Kara seq_puts(seq, "packing_groups");
740c3aa0776SJan Kara }
741c3aa0776SJan Kara if (TEST_OPTION(hashed_formatted_nodes, s)) {
742c3aa0776SJan Kara print_sep(seq, &first);
743c3aa0776SJan Kara seq_puts(seq, "hashed_formatted_nodes");
744c3aa0776SJan Kara }
745c3aa0776SJan Kara if (TEST_OPTION(skip_busy, s)) {
746c3aa0776SJan Kara print_sep(seq, &first);
747c3aa0776SJan Kara seq_puts(seq, "skip_busy");
748c3aa0776SJan Kara }
749c3aa0776SJan Kara if (TEST_OPTION(hundredth_slices, s)) {
750c3aa0776SJan Kara print_sep(seq, &first);
751c3aa0776SJan Kara seq_puts(seq, "hundredth_slices");
752c3aa0776SJan Kara }
753c3aa0776SJan Kara if (TEST_OPTION(old_way, s)) {
754c3aa0776SJan Kara print_sep(seq, &first);
755c3aa0776SJan Kara seq_puts(seq, "old_way");
756c3aa0776SJan Kara }
757c3aa0776SJan Kara if (TEST_OPTION(displace_based_on_dirid, s)) {
758c3aa0776SJan Kara print_sep(seq, &first);
759c3aa0776SJan Kara seq_puts(seq, "displace_based_on_dirid");
760c3aa0776SJan Kara }
761c3aa0776SJan Kara if (REISERFS_SB(s)->s_alloc_options.preallocmin != 0) {
762c3aa0776SJan Kara print_sep(seq, &first);
763c3aa0776SJan Kara seq_printf(seq, "preallocmin=%d",
764c3aa0776SJan Kara REISERFS_SB(s)->s_alloc_options.preallocmin);
765c3aa0776SJan Kara }
766c3aa0776SJan Kara if (REISERFS_SB(s)->s_alloc_options.preallocsize != 17) {
767c3aa0776SJan Kara print_sep(seq, &first);
768c3aa0776SJan Kara seq_printf(seq, "preallocsize=%d",
769c3aa0776SJan Kara REISERFS_SB(s)->s_alloc_options.preallocsize);
770c3aa0776SJan Kara }
771c3aa0776SJan Kara }
772c3aa0776SJan Kara
new_hashed_relocation(reiserfs_blocknr_hint_t * hint)7731da177e4SLinus Torvalds static inline void new_hashed_relocation(reiserfs_blocknr_hint_t * hint)
7741da177e4SLinus Torvalds {
7751da177e4SLinus Torvalds char *hash_in;
776ae0a50abSFabian Frederick
7771da177e4SLinus Torvalds if (hint->formatted_node) {
7781da177e4SLinus Torvalds hash_in = (char *)&hint->key.k_dir_id;
7791da177e4SLinus Torvalds } else {
7801da177e4SLinus Torvalds if (!hint->inode) {
781098297b2SJeff Mahoney /*hint->search_start = hint->beg;*/
7821da177e4SLinus Torvalds hash_in = (char *)&hint->key.k_dir_id;
7831da177e4SLinus Torvalds } else
7841da177e4SLinus Torvalds if (TEST_OPTION(displace_based_on_dirid, hint->th->t_super))
7851da177e4SLinus Torvalds hash_in = (char *)(&INODE_PKEY(hint->inode)->k_dir_id);
7861da177e4SLinus Torvalds else
787bd4c625cSLinus Torvalds hash_in =
788bd4c625cSLinus Torvalds (char *)(&INODE_PKEY(hint->inode)->k_objectid);
7891da177e4SLinus Torvalds }
7901da177e4SLinus Torvalds
791bd4c625cSLinus Torvalds hint->search_start =
792bd4c625cSLinus Torvalds hint->beg + keyed_hash(hash_in, 4) % (hint->end - hint->beg);
7931da177e4SLinus Torvalds }
7941da177e4SLinus Torvalds
7951da177e4SLinus Torvalds /*
7961da177e4SLinus Torvalds * Relocation based on dirid, hashing them into a given bitmap block
797c78bad11SJoe Perches * files. Formatted nodes are unaffected, a separate policy covers them
7981da177e4SLinus Torvalds */
dirid_groups(reiserfs_blocknr_hint_t * hint)799bd4c625cSLinus Torvalds static void dirid_groups(reiserfs_blocknr_hint_t * hint)
8001da177e4SLinus Torvalds {
8011da177e4SLinus Torvalds unsigned long hash;
8021da177e4SLinus Torvalds __u32 dirid = 0;
8031da177e4SLinus Torvalds int bm = 0;
8041da177e4SLinus Torvalds struct super_block *sb = hint->th->t_super;
805ae0a50abSFabian Frederick
8061da177e4SLinus Torvalds if (hint->inode)
8071da177e4SLinus Torvalds dirid = le32_to_cpu(INODE_PKEY(hint->inode)->k_dir_id);
8081da177e4SLinus Torvalds else if (hint->formatted_node)
8091da177e4SLinus Torvalds dirid = hint->key.k_dir_id;
8101da177e4SLinus Torvalds
8111da177e4SLinus Torvalds if (dirid) {
8121da177e4SLinus Torvalds bm = bmap_hash_id(sb, dirid);
8131da177e4SLinus Torvalds hash = bm * (sb->s_blocksize << 3);
8141da177e4SLinus Torvalds /* give a portion of the block group to metadata */
8151da177e4SLinus Torvalds if (hint->inode)
8161da177e4SLinus Torvalds hash += sb->s_blocksize / 2;
8171da177e4SLinus Torvalds hint->search_start = hash;
8181da177e4SLinus Torvalds }
8191da177e4SLinus Torvalds }
8201da177e4SLinus Torvalds
8211da177e4SLinus Torvalds /*
8221da177e4SLinus Torvalds * Relocation based on oid, hashing them into a given bitmap block
823c78bad11SJoe Perches * files. Formatted nodes are unaffected, a separate policy covers them
8241da177e4SLinus Torvalds */
oid_groups(reiserfs_blocknr_hint_t * hint)825bd4c625cSLinus Torvalds static void oid_groups(reiserfs_blocknr_hint_t * hint)
8261da177e4SLinus Torvalds {
8271da177e4SLinus Torvalds if (hint->inode) {
8281da177e4SLinus Torvalds unsigned long hash;
8291da177e4SLinus Torvalds __u32 oid;
8301da177e4SLinus Torvalds __u32 dirid;
8311da177e4SLinus Torvalds int bm;
8321da177e4SLinus Torvalds
8331da177e4SLinus Torvalds dirid = le32_to_cpu(INODE_PKEY(hint->inode)->k_dir_id);
8341da177e4SLinus Torvalds
835098297b2SJeff Mahoney /*
836098297b2SJeff Mahoney * keep the root dir and it's first set of subdirs close to
8371da177e4SLinus Torvalds * the start of the disk
8381da177e4SLinus Torvalds */
8391da177e4SLinus Torvalds if (dirid <= 2)
8401da177e4SLinus Torvalds hash = (hint->inode->i_sb->s_blocksize << 3);
8411da177e4SLinus Torvalds else {
8421da177e4SLinus Torvalds oid = le32_to_cpu(INODE_PKEY(hint->inode)->k_objectid);
8431da177e4SLinus Torvalds bm = bmap_hash_id(hint->inode->i_sb, oid);
8441da177e4SLinus Torvalds hash = bm * (hint->inode->i_sb->s_blocksize << 3);
8451da177e4SLinus Torvalds }
8461da177e4SLinus Torvalds hint->search_start = hash;
8471da177e4SLinus Torvalds }
8481da177e4SLinus Torvalds }
8491da177e4SLinus Torvalds
850098297b2SJeff Mahoney /*
851098297b2SJeff Mahoney * returns 1 if it finds an indirect item and gets valid hint info
8521da177e4SLinus Torvalds * from it, otherwise 0
8531da177e4SLinus Torvalds */
get_left_neighbor(reiserfs_blocknr_hint_t * hint)8541da177e4SLinus Torvalds static int get_left_neighbor(reiserfs_blocknr_hint_t * hint)
8551da177e4SLinus Torvalds {
856fec6d055SJosef "Jeff" Sipek struct treepath *path;
8571da177e4SLinus Torvalds struct buffer_head *bh;
8581da177e4SLinus Torvalds struct item_head *ih;
8591da177e4SLinus Torvalds int pos_in_item;
8603e8962beSAl Viro __le32 *item;
8611da177e4SLinus Torvalds int ret = 0;
8621da177e4SLinus Torvalds
863098297b2SJeff Mahoney /*
864098297b2SJeff Mahoney * reiserfs code can call this function w/o pointer to path
865098297b2SJeff Mahoney * structure supplied; then we rely on supplied search_start
866098297b2SJeff Mahoney */
867098297b2SJeff Mahoney if (!hint->path)
8681da177e4SLinus Torvalds return 0;
8691da177e4SLinus Torvalds
8701da177e4SLinus Torvalds path = hint->path;
8711da177e4SLinus Torvalds bh = get_last_bh(path);
8721da177e4SLinus Torvalds RFALSE(!bh, "green-4002: Illegal path specified to get_left_neighbor");
8734cf5f7adSJeff Mahoney ih = tp_item_head(path);
8741da177e4SLinus Torvalds pos_in_item = path->pos_in_item;
8754cf5f7adSJeff Mahoney item = tp_item_body(path);
8761da177e4SLinus Torvalds
8771da177e4SLinus Torvalds hint->search_start = bh->b_blocknr;
8781da177e4SLinus Torvalds
879098297b2SJeff Mahoney /*
880098297b2SJeff Mahoney * for indirect item: go to left and look for the first non-hole entry
881098297b2SJeff Mahoney * in the indirect item
882098297b2SJeff Mahoney */
8831da177e4SLinus Torvalds if (!hint->formatted_node && is_indirect_le_ih(ih)) {
8841da177e4SLinus Torvalds if (pos_in_item == I_UNFM_NUM(ih))
8851da177e4SLinus Torvalds pos_in_item--;
8861da177e4SLinus Torvalds while (pos_in_item >= 0) {
8871da177e4SLinus Torvalds int t = get_block_num(item, pos_in_item);
8881da177e4SLinus Torvalds if (t) {
8891da177e4SLinus Torvalds hint->search_start = t;
8901da177e4SLinus Torvalds ret = 1;
8911da177e4SLinus Torvalds break;
8921da177e4SLinus Torvalds }
8931da177e4SLinus Torvalds pos_in_item--;
8941da177e4SLinus Torvalds }
8951da177e4SLinus Torvalds }
8961da177e4SLinus Torvalds
8971da177e4SLinus Torvalds /* does result value fit into specified region? */
8981da177e4SLinus Torvalds return ret;
8991da177e4SLinus Torvalds }
9001da177e4SLinus Torvalds
901098297b2SJeff Mahoney /*
902098297b2SJeff Mahoney * should be, if formatted node, then try to put on first part of the device
903098297b2SJeff Mahoney * specified as number of percent with mount option device, else try to put
904098297b2SJeff Mahoney * on last of device. This is not to say it is good code to do so,
905098297b2SJeff Mahoney * but the effect should be measured.
906098297b2SJeff Mahoney */
set_border_in_hint(struct super_block * s,reiserfs_blocknr_hint_t * hint)907bd4c625cSLinus Torvalds static inline void set_border_in_hint(struct super_block *s,
908bd4c625cSLinus Torvalds reiserfs_blocknr_hint_t * hint)
9091da177e4SLinus Torvalds {
910bd4c625cSLinus Torvalds b_blocknr_t border =
911bd4c625cSLinus Torvalds SB_BLOCK_COUNT(s) / REISERFS_SB(s)->s_alloc_options.border;
9121da177e4SLinus Torvalds
9131da177e4SLinus Torvalds if (hint->formatted_node)
9141da177e4SLinus Torvalds hint->end = border - 1;
9151da177e4SLinus Torvalds else
9161da177e4SLinus Torvalds hint->beg = border;
9171da177e4SLinus Torvalds }
9181da177e4SLinus Torvalds
displace_large_file(reiserfs_blocknr_hint_t * hint)9191da177e4SLinus Torvalds static inline void displace_large_file(reiserfs_blocknr_hint_t * hint)
9201da177e4SLinus Torvalds {
9211da177e4SLinus Torvalds if (TEST_OPTION(displace_based_on_dirid, hint->th->t_super))
922bd4c625cSLinus Torvalds hint->search_start =
923bd4c625cSLinus Torvalds hint->beg +
924bd4c625cSLinus Torvalds keyed_hash((char *)(&INODE_PKEY(hint->inode)->k_dir_id),
925bd4c625cSLinus Torvalds 4) % (hint->end - hint->beg);
9261da177e4SLinus Torvalds else
927bd4c625cSLinus Torvalds hint->search_start =
928bd4c625cSLinus Torvalds hint->beg +
929bd4c625cSLinus Torvalds keyed_hash((char *)(&INODE_PKEY(hint->inode)->k_objectid),
930bd4c625cSLinus Torvalds 4) % (hint->end - hint->beg);
9311da177e4SLinus Torvalds }
9321da177e4SLinus Torvalds
hash_formatted_node(reiserfs_blocknr_hint_t * hint)9331da177e4SLinus Torvalds static inline void hash_formatted_node(reiserfs_blocknr_hint_t * hint)
9341da177e4SLinus Torvalds {
9351da177e4SLinus Torvalds char *hash_in;
9361da177e4SLinus Torvalds
9371da177e4SLinus Torvalds if (!hint->inode)
9381da177e4SLinus Torvalds hash_in = (char *)&hint->key.k_dir_id;
9391da177e4SLinus Torvalds else if (TEST_OPTION(displace_based_on_dirid, hint->th->t_super))
9401da177e4SLinus Torvalds hash_in = (char *)(&INODE_PKEY(hint->inode)->k_dir_id);
9411da177e4SLinus Torvalds else
9421da177e4SLinus Torvalds hash_in = (char *)(&INODE_PKEY(hint->inode)->k_objectid);
9431da177e4SLinus Torvalds
944bd4c625cSLinus Torvalds hint->search_start =
945bd4c625cSLinus Torvalds hint->beg + keyed_hash(hash_in, 4) % (hint->end - hint->beg);
9461da177e4SLinus Torvalds }
9471da177e4SLinus Torvalds
948bd4c625cSLinus Torvalds static inline int
this_blocknr_allocation_would_make_it_a_large_file(reiserfs_blocknr_hint_t * hint)949bd4c625cSLinus Torvalds this_blocknr_allocation_would_make_it_a_large_file(reiserfs_blocknr_hint_t *
950bd4c625cSLinus Torvalds hint)
9511da177e4SLinus Torvalds {
952bd4c625cSLinus Torvalds return hint->block ==
953bd4c625cSLinus Torvalds REISERFS_SB(hint->th->t_super)->s_alloc_options.large_file_size;
9541da177e4SLinus Torvalds }
9551da177e4SLinus Torvalds
9561da177e4SLinus Torvalds #ifdef DISPLACE_NEW_PACKING_LOCALITIES
displace_new_packing_locality(reiserfs_blocknr_hint_t * hint)9571da177e4SLinus Torvalds static inline void displace_new_packing_locality(reiserfs_blocknr_hint_t * hint)
9581da177e4SLinus Torvalds {
9596a3a16f2SAl Viro struct in_core_key *key = &hint->key;
9601da177e4SLinus Torvalds
9611da177e4SLinus Torvalds hint->th->displace_new_blocks = 0;
962bd4c625cSLinus Torvalds hint->search_start =
963bd4c625cSLinus Torvalds hint->beg + keyed_hash((char *)(&key->k_objectid),
964bd4c625cSLinus Torvalds 4) % (hint->end - hint->beg);
9651da177e4SLinus Torvalds }
9661da177e4SLinus Torvalds #endif
9671da177e4SLinus Torvalds
old_hashed_relocation(reiserfs_blocknr_hint_t * hint)9681da177e4SLinus Torvalds static inline int old_hashed_relocation(reiserfs_blocknr_hint_t * hint)
9691da177e4SLinus Torvalds {
9701da177e4SLinus Torvalds b_blocknr_t border;
9711da177e4SLinus Torvalds u32 hash_in;
9721da177e4SLinus Torvalds
9731da177e4SLinus Torvalds if (hint->formatted_node || hint->inode == NULL) {
9741da177e4SLinus Torvalds return 0;
9751da177e4SLinus Torvalds }
9761da177e4SLinus Torvalds
9771da177e4SLinus Torvalds hash_in = le32_to_cpu((INODE_PKEY(hint->inode))->k_dir_id);
978bd4c625cSLinus Torvalds border =
979bd4c625cSLinus Torvalds hint->beg + (u32) keyed_hash(((char *)(&hash_in)),
980bd4c625cSLinus Torvalds 4) % (hint->end - hint->beg - 1);
9811da177e4SLinus Torvalds if (border > hint->search_start)
9821da177e4SLinus Torvalds hint->search_start = border;
9831da177e4SLinus Torvalds
9841da177e4SLinus Torvalds return 1;
9851da177e4SLinus Torvalds }
9861da177e4SLinus Torvalds
old_way(reiserfs_blocknr_hint_t * hint)9871da177e4SLinus Torvalds static inline int old_way(reiserfs_blocknr_hint_t * hint)
9881da177e4SLinus Torvalds {
9891da177e4SLinus Torvalds b_blocknr_t border;
9901da177e4SLinus Torvalds
9911da177e4SLinus Torvalds if (hint->formatted_node || hint->inode == NULL) {
9921da177e4SLinus Torvalds return 0;
9931da177e4SLinus Torvalds }
9941da177e4SLinus Torvalds
995bd4c625cSLinus Torvalds border =
996bd4c625cSLinus Torvalds hint->beg +
997bd4c625cSLinus Torvalds le32_to_cpu(INODE_PKEY(hint->inode)->k_dir_id) % (hint->end -
998bd4c625cSLinus Torvalds hint->beg);
9991da177e4SLinus Torvalds if (border > hint->search_start)
10001da177e4SLinus Torvalds hint->search_start = border;
10011da177e4SLinus Torvalds
10021da177e4SLinus Torvalds return 1;
10031da177e4SLinus Torvalds }
10041da177e4SLinus Torvalds
hundredth_slices(reiserfs_blocknr_hint_t * hint)10051da177e4SLinus Torvalds static inline void hundredth_slices(reiserfs_blocknr_hint_t * hint)
10061da177e4SLinus Torvalds {
10076a3a16f2SAl Viro struct in_core_key *key = &hint->key;
10081da177e4SLinus Torvalds b_blocknr_t slice_start;
10091da177e4SLinus Torvalds
1010bd4c625cSLinus Torvalds slice_start =
1011bd4c625cSLinus Torvalds (keyed_hash((char *)(&key->k_dir_id), 4) % 100) * (hint->end / 100);
1012bd4c625cSLinus Torvalds if (slice_start > hint->search_start
1013bd4c625cSLinus Torvalds || slice_start + (hint->end / 100) <= hint->search_start) {
10141da177e4SLinus Torvalds hint->search_start = slice_start;
10151da177e4SLinus Torvalds }
10161da177e4SLinus Torvalds }
10171da177e4SLinus Torvalds
determine_search_start(reiserfs_blocknr_hint_t * hint,int amount_needed)10181da177e4SLinus Torvalds static void determine_search_start(reiserfs_blocknr_hint_t * hint,
10191da177e4SLinus Torvalds int amount_needed)
10201da177e4SLinus Torvalds {
10211da177e4SLinus Torvalds struct super_block *s = hint->th->t_super;
10221da177e4SLinus Torvalds int unfm_hint;
10231da177e4SLinus Torvalds
10241da177e4SLinus Torvalds hint->beg = 0;
10251da177e4SLinus Torvalds hint->end = SB_BLOCK_COUNT(s) - 1;
10261da177e4SLinus Torvalds
10271da177e4SLinus Torvalds /* This is former border algorithm. Now with tunable border offset */
10281da177e4SLinus Torvalds if (concentrating_formatted_nodes(s))
10291da177e4SLinus Torvalds set_border_in_hint(s, hint);
10301da177e4SLinus Torvalds
10311da177e4SLinus Torvalds #ifdef DISPLACE_NEW_PACKING_LOCALITIES
1032098297b2SJeff Mahoney /*
1033098297b2SJeff Mahoney * whenever we create a new directory, we displace it. At first
1034098297b2SJeff Mahoney * we will hash for location, later we might look for a moderately
1035098297b2SJeff Mahoney * empty place for it
1036098297b2SJeff Mahoney */
10371da177e4SLinus Torvalds if (displacing_new_packing_localities(s)
10381da177e4SLinus Torvalds && hint->th->displace_new_blocks) {
10391da177e4SLinus Torvalds displace_new_packing_locality(hint);
10401da177e4SLinus Torvalds
1041098297b2SJeff Mahoney /*
1042098297b2SJeff Mahoney * we do not continue determine_search_start,
1043098297b2SJeff Mahoney * if new packing locality is being displaced
1044098297b2SJeff Mahoney */
10451da177e4SLinus Torvalds return;
10461da177e4SLinus Torvalds }
10471da177e4SLinus Torvalds #endif
10481da177e4SLinus Torvalds
1049098297b2SJeff Mahoney /*
1050098297b2SJeff Mahoney * all persons should feel encouraged to add more special cases
1051098297b2SJeff Mahoney * here and test them
1052098297b2SJeff Mahoney */
10531da177e4SLinus Torvalds
10541da177e4SLinus Torvalds if (displacing_large_files(s) && !hint->formatted_node
10551da177e4SLinus Torvalds && this_blocknr_allocation_would_make_it_a_large_file(hint)) {
10561da177e4SLinus Torvalds displace_large_file(hint);
10571da177e4SLinus Torvalds return;
10581da177e4SLinus Torvalds }
10591da177e4SLinus Torvalds
1060098297b2SJeff Mahoney /*
1061098297b2SJeff Mahoney * if none of our special cases is relevant, use the left
1062098297b2SJeff Mahoney * neighbor in the tree order of the new node we are allocating for
1063098297b2SJeff Mahoney */
10641da177e4SLinus Torvalds if (hint->formatted_node && TEST_OPTION(hashed_formatted_nodes, s)) {
10651da177e4SLinus Torvalds hash_formatted_node(hint);
10661da177e4SLinus Torvalds return;
10671da177e4SLinus Torvalds }
10681da177e4SLinus Torvalds
10691da177e4SLinus Torvalds unfm_hint = get_left_neighbor(hint);
10701da177e4SLinus Torvalds
1071098297b2SJeff Mahoney /*
1072098297b2SJeff Mahoney * Mimic old block allocator behaviour, that is if VFS allowed for
1073098297b2SJeff Mahoney * preallocation, new blocks are displaced based on directory ID.
1074098297b2SJeff Mahoney * Also, if suggested search_start is less than last preallocated
1075098297b2SJeff Mahoney * block, we start searching from it, assuming that HDD dataflow
1076098297b2SJeff Mahoney * is faster in forward direction
1077098297b2SJeff Mahoney */
10781da177e4SLinus Torvalds if (TEST_OPTION(old_way, s)) {
10791da177e4SLinus Torvalds if (!hint->formatted_node) {
10801da177e4SLinus Torvalds if (!reiserfs_hashed_relocation(s))
10811da177e4SLinus Torvalds old_way(hint);
10821da177e4SLinus Torvalds else if (!reiserfs_no_unhashed_relocation(s))
10831da177e4SLinus Torvalds old_hashed_relocation(hint);
10841da177e4SLinus Torvalds
1085bd4c625cSLinus Torvalds if (hint->inode
1086bd4c625cSLinus Torvalds && hint->search_start <
1087bd4c625cSLinus Torvalds REISERFS_I(hint->inode)->i_prealloc_block)
1088bd4c625cSLinus Torvalds hint->search_start =
1089bd4c625cSLinus Torvalds REISERFS_I(hint->inode)->i_prealloc_block;
10901da177e4SLinus Torvalds }
10911da177e4SLinus Torvalds return;
10921da177e4SLinus Torvalds }
10931da177e4SLinus Torvalds
10941da177e4SLinus Torvalds /* This is an approach proposed by Hans */
1095bd4c625cSLinus Torvalds if (TEST_OPTION(hundredth_slices, s)
1096bd4c625cSLinus Torvalds && !(displacing_large_files(s) && !hint->formatted_node)) {
10971da177e4SLinus Torvalds hundredth_slices(hint);
10981da177e4SLinus Torvalds return;
10991da177e4SLinus Torvalds }
11001da177e4SLinus Torvalds
11011da177e4SLinus Torvalds /* old_hashed_relocation only works on unformatted */
11021da177e4SLinus Torvalds if (!unfm_hint && !hint->formatted_node &&
1103bd4c625cSLinus Torvalds TEST_OPTION(old_hashed_relocation, s)) {
11041da177e4SLinus Torvalds old_hashed_relocation(hint);
11051da177e4SLinus Torvalds }
1106098297b2SJeff Mahoney
11071da177e4SLinus Torvalds /* new_hashed_relocation works with both formatted/unformatted nodes */
11081da177e4SLinus Torvalds if ((!unfm_hint || hint->formatted_node) &&
1109bd4c625cSLinus Torvalds TEST_OPTION(new_hashed_relocation, s)) {
11101da177e4SLinus Torvalds new_hashed_relocation(hint);
11111da177e4SLinus Torvalds }
1112098297b2SJeff Mahoney
11131da177e4SLinus Torvalds /* dirid grouping works only on unformatted nodes */
1114bd4c625cSLinus Torvalds if (!unfm_hint && !hint->formatted_node && TEST_OPTION(dirid_groups, s)) {
11151da177e4SLinus Torvalds dirid_groups(hint);
11161da177e4SLinus Torvalds }
11171da177e4SLinus Torvalds #ifdef DISPLACE_NEW_PACKING_LOCALITIES
1118bd4c625cSLinus Torvalds if (hint->formatted_node && TEST_OPTION(dirid_groups, s)) {
11191da177e4SLinus Torvalds dirid_groups(hint);
11201da177e4SLinus Torvalds }
11211da177e4SLinus Torvalds #endif
11221da177e4SLinus Torvalds
11231da177e4SLinus Torvalds /* oid grouping works only on unformatted nodes */
1124bd4c625cSLinus Torvalds if (!unfm_hint && !hint->formatted_node && TEST_OPTION(oid_groups, s)) {
11251da177e4SLinus Torvalds oid_groups(hint);
11261da177e4SLinus Torvalds }
11271da177e4SLinus Torvalds return;
11281da177e4SLinus Torvalds }
11291da177e4SLinus Torvalds
determine_prealloc_size(reiserfs_blocknr_hint_t * hint)11301da177e4SLinus Torvalds static int determine_prealloc_size(reiserfs_blocknr_hint_t * hint)
11311da177e4SLinus Torvalds {
11321da177e4SLinus Torvalds /* make minimum size a mount option and benchmark both ways */
11331da177e4SLinus Torvalds /* we preallocate blocks only for regular files, specific size */
11341da177e4SLinus Torvalds /* benchmark preallocating always and see what happens */
11351da177e4SLinus Torvalds
11361da177e4SLinus Torvalds hint->prealloc_size = 0;
11371da177e4SLinus Torvalds
11381da177e4SLinus Torvalds if (!hint->formatted_node && hint->preallocate) {
113954930dfeSJeff Mahoney if (S_ISREG(hint->inode->i_mode) && !IS_PRIVATE(hint->inode)
1140bd4c625cSLinus Torvalds && hint->inode->i_size >=
1141bd4c625cSLinus Torvalds REISERFS_SB(hint->th->t_super)->s_alloc_options.
1142bd4c625cSLinus Torvalds preallocmin * hint->inode->i_sb->s_blocksize)
1143bd4c625cSLinus Torvalds hint->prealloc_size =
1144bd4c625cSLinus Torvalds REISERFS_SB(hint->th->t_super)->s_alloc_options.
1145bd4c625cSLinus Torvalds preallocsize - 1;
11461da177e4SLinus Torvalds }
11471da177e4SLinus Torvalds return CARRY_ON;
11481da177e4SLinus Torvalds }
11491da177e4SLinus Torvalds
allocate_without_wrapping_disk(reiserfs_blocknr_hint_t * hint,b_blocknr_t * new_blocknrs,b_blocknr_t start,b_blocknr_t finish,int min,int amount_needed,int prealloc_size)11501da177e4SLinus Torvalds static inline int allocate_without_wrapping_disk(reiserfs_blocknr_hint_t * hint,
11511da177e4SLinus Torvalds b_blocknr_t * new_blocknrs,
1152bd4c625cSLinus Torvalds b_blocknr_t start,
1153bd4c625cSLinus Torvalds b_blocknr_t finish, int min,
1154bd4c625cSLinus Torvalds int amount_needed,
1155bd4c625cSLinus Torvalds int prealloc_size)
11561da177e4SLinus Torvalds {
11571da177e4SLinus Torvalds int rest = amount_needed;
11581da177e4SLinus Torvalds int nr_allocated;
11591da177e4SLinus Torvalds
11601da177e4SLinus Torvalds while (rest > 0 && start <= finish) {
11611da177e4SLinus Torvalds nr_allocated = scan_bitmap(hint->th, &start, finish, min,
1162bd4c625cSLinus Torvalds rest + prealloc_size,
1163bd4c625cSLinus Torvalds !hint->formatted_node, hint->block);
11641da177e4SLinus Torvalds
11651da177e4SLinus Torvalds if (nr_allocated == 0) /* no new blocks allocated, return */
11661da177e4SLinus Torvalds break;
11671da177e4SLinus Torvalds
11681da177e4SLinus Torvalds /* fill free_blocknrs array first */
11691da177e4SLinus Torvalds while (rest > 0 && nr_allocated > 0) {
11701da177e4SLinus Torvalds *new_blocknrs++ = start++;
1171bd4c625cSLinus Torvalds rest--;
1172bd4c625cSLinus Torvalds nr_allocated--;
11731da177e4SLinus Torvalds }
11741da177e4SLinus Torvalds
11751da177e4SLinus Torvalds /* do we have something to fill prealloc. array also ? */
11761da177e4SLinus Torvalds if (nr_allocated > 0) {
1177098297b2SJeff Mahoney /*
1178098297b2SJeff Mahoney * it means prealloc_size was greater that 0 and
1179098297b2SJeff Mahoney * we do preallocation
1180098297b2SJeff Mahoney */
11811da177e4SLinus Torvalds list_add(&REISERFS_I(hint->inode)->i_prealloc_list,
1182bd4c625cSLinus Torvalds &SB_JOURNAL(hint->th->t_super)->
1183bd4c625cSLinus Torvalds j_prealloc_list);
11841da177e4SLinus Torvalds REISERFS_I(hint->inode)->i_prealloc_block = start;
1185bd4c625cSLinus Torvalds REISERFS_I(hint->inode)->i_prealloc_count =
1186bd4c625cSLinus Torvalds nr_allocated;
11871da177e4SLinus Torvalds break;
11881da177e4SLinus Torvalds }
11891da177e4SLinus Torvalds }
11901da177e4SLinus Torvalds
11911da177e4SLinus Torvalds return (amount_needed - rest);
11921da177e4SLinus Torvalds }
11931da177e4SLinus Torvalds
blocknrs_and_prealloc_arrays_from_search_start(reiserfs_blocknr_hint_t * hint,b_blocknr_t * new_blocknrs,int amount_needed)11941da177e4SLinus Torvalds static inline int blocknrs_and_prealloc_arrays_from_search_start
1195bd4c625cSLinus Torvalds (reiserfs_blocknr_hint_t * hint, b_blocknr_t * new_blocknrs,
1196bd4c625cSLinus Torvalds int amount_needed) {
11971da177e4SLinus Torvalds struct super_block *s = hint->th->t_super;
11981da177e4SLinus Torvalds b_blocknr_t start = hint->search_start;
11991da177e4SLinus Torvalds b_blocknr_t finish = SB_BLOCK_COUNT(s) - 1;
12001da177e4SLinus Torvalds int passno = 0;
12011da177e4SLinus Torvalds int nr_allocated = 0;
1202d2d0395fSJeff Mahoney int depth;
12031da177e4SLinus Torvalds
12041da177e4SLinus Torvalds determine_prealloc_size(hint);
12051da177e4SLinus Torvalds if (!hint->formatted_node) {
12061da177e4SLinus Torvalds int quota_ret;
12071da177e4SLinus Torvalds #ifdef REISERQUOTA_DEBUG
1208bd4c625cSLinus Torvalds reiserfs_debug(s, REISERFS_DEBUG_CODE,
1209bd4c625cSLinus Torvalds "reiserquota: allocating %d blocks id=%u",
1210bd4c625cSLinus Torvalds amount_needed, hint->inode->i_uid);
12111da177e4SLinus Torvalds #endif
1212d2d0395fSJeff Mahoney depth = reiserfs_write_unlock_nested(s);
1213bd4c625cSLinus Torvalds quota_ret =
12145dd4056dSChristoph Hellwig dquot_alloc_block_nodirty(hint->inode, amount_needed);
1215d2d0395fSJeff Mahoney if (quota_ret) { /* Quota exceeded? */
1216d2d0395fSJeff Mahoney reiserfs_write_lock_nested(s, depth);
12171da177e4SLinus Torvalds return QUOTA_EXCEEDED;
1218d2d0395fSJeff Mahoney }
12191da177e4SLinus Torvalds if (hint->preallocate && hint->prealloc_size) {
12201da177e4SLinus Torvalds #ifdef REISERQUOTA_DEBUG
1221bd4c625cSLinus Torvalds reiserfs_debug(s, REISERFS_DEBUG_CODE,
1222bd4c625cSLinus Torvalds "reiserquota: allocating (prealloc) %d blocks id=%u",
1223bd4c625cSLinus Torvalds hint->prealloc_size, hint->inode->i_uid);
12241da177e4SLinus Torvalds #endif
12255dd4056dSChristoph Hellwig quota_ret = dquot_prealloc_block_nodirty(hint->inode,
1226bd4c625cSLinus Torvalds hint->prealloc_size);
12271da177e4SLinus Torvalds if (quota_ret)
12281da177e4SLinus Torvalds hint->preallocate = hint->prealloc_size = 0;
12291da177e4SLinus Torvalds }
12301da177e4SLinus Torvalds /* for unformatted nodes, force large allocations */
1231d2d0395fSJeff Mahoney reiserfs_write_lock_nested(s, depth);
12321da177e4SLinus Torvalds }
12331da177e4SLinus Torvalds
12341da177e4SLinus Torvalds do {
12351da177e4SLinus Torvalds switch (passno++) {
12361da177e4SLinus Torvalds case 0: /* Search from hint->search_start to end of disk */
12371da177e4SLinus Torvalds start = hint->search_start;
12381da177e4SLinus Torvalds finish = SB_BLOCK_COUNT(s) - 1;
12391da177e4SLinus Torvalds break;
12401da177e4SLinus Torvalds case 1: /* Search from hint->beg to hint->search_start */
12411da177e4SLinus Torvalds start = hint->beg;
12421da177e4SLinus Torvalds finish = hint->search_start;
12431da177e4SLinus Torvalds break;
12441da177e4SLinus Torvalds case 2: /* Last chance: Search from 0 to hint->beg */
12451da177e4SLinus Torvalds start = 0;
12461da177e4SLinus Torvalds finish = hint->beg;
12471da177e4SLinus Torvalds break;
1248098297b2SJeff Mahoney default:
1249098297b2SJeff Mahoney /* We've tried searching everywhere, not enough space */
12501da177e4SLinus Torvalds /* Free the blocks */
12511da177e4SLinus Torvalds if (!hint->formatted_node) {
12521da177e4SLinus Torvalds #ifdef REISERQUOTA_DEBUG
1253bd4c625cSLinus Torvalds reiserfs_debug(s, REISERFS_DEBUG_CODE,
1254bd4c625cSLinus Torvalds "reiserquota: freeing (nospace) %d blocks id=%u",
1255bd4c625cSLinus Torvalds amount_needed +
1256bd4c625cSLinus Torvalds hint->prealloc_size -
1257bd4c625cSLinus Torvalds nr_allocated,
1258bd4c625cSLinus Torvalds hint->inode->i_uid);
12591da177e4SLinus Torvalds #endif
126077db4f25SJan Kara /* Free not allocated blocks */
1261d2d0395fSJeff Mahoney depth = reiserfs_write_unlock_nested(s);
12625dd4056dSChristoph Hellwig dquot_free_block_nodirty(hint->inode,
126377db4f25SJan Kara amount_needed + hint->prealloc_size -
126477db4f25SJan Kara nr_allocated);
1265d2d0395fSJeff Mahoney reiserfs_write_lock_nested(s, depth);
12661da177e4SLinus Torvalds }
12671da177e4SLinus Torvalds while (nr_allocated--)
1268bd4c625cSLinus Torvalds reiserfs_free_block(hint->th, hint->inode,
1269bd4c625cSLinus Torvalds new_blocknrs[nr_allocated],
1270bd4c625cSLinus Torvalds !hint->formatted_node);
12711da177e4SLinus Torvalds
12721da177e4SLinus Torvalds return NO_DISK_SPACE;
12731da177e4SLinus Torvalds }
12741da177e4SLinus Torvalds } while ((nr_allocated += allocate_without_wrapping_disk(hint,
1275bd4c625cSLinus Torvalds new_blocknrs +
1276bd4c625cSLinus Torvalds nr_allocated,
1277bd4c625cSLinus Torvalds start, finish,
12789ea0f949SJeff Mahoney 1,
1279bd4c625cSLinus Torvalds amount_needed -
1280bd4c625cSLinus Torvalds nr_allocated,
1281bd4c625cSLinus Torvalds hint->
1282bd4c625cSLinus Torvalds prealloc_size))
12831da177e4SLinus Torvalds < amount_needed);
12841da177e4SLinus Torvalds if (!hint->formatted_node &&
12851da177e4SLinus Torvalds amount_needed + hint->prealloc_size >
12861da177e4SLinus Torvalds nr_allocated + REISERFS_I(hint->inode)->i_prealloc_count) {
12871da177e4SLinus Torvalds /* Some of preallocation blocks were not allocated */
12881da177e4SLinus Torvalds #ifdef REISERQUOTA_DEBUG
1289bd4c625cSLinus Torvalds reiserfs_debug(s, REISERFS_DEBUG_CODE,
1290bd4c625cSLinus Torvalds "reiserquota: freeing (failed prealloc) %d blocks id=%u",
1291bd4c625cSLinus Torvalds amount_needed + hint->prealloc_size -
1292bd4c625cSLinus Torvalds nr_allocated -
1293bd4c625cSLinus Torvalds REISERFS_I(hint->inode)->i_prealloc_count,
1294bd4c625cSLinus Torvalds hint->inode->i_uid);
12951da177e4SLinus Torvalds #endif
1296d2d0395fSJeff Mahoney
1297d2d0395fSJeff Mahoney depth = reiserfs_write_unlock_nested(s);
12985dd4056dSChristoph Hellwig dquot_free_block_nodirty(hint->inode, amount_needed +
12991da177e4SLinus Torvalds hint->prealloc_size - nr_allocated -
1300bd4c625cSLinus Torvalds REISERFS_I(hint->inode)->
1301bd4c625cSLinus Torvalds i_prealloc_count);
1302d2d0395fSJeff Mahoney reiserfs_write_lock_nested(s, depth);
13031da177e4SLinus Torvalds }
13041da177e4SLinus Torvalds
13051da177e4SLinus Torvalds return CARRY_ON;
13061da177e4SLinus Torvalds }
13071da177e4SLinus Torvalds
13081da177e4SLinus Torvalds /* grab new blocknrs from preallocated list */
13091da177e4SLinus Torvalds /* return amount still needed after using them */
use_preallocated_list_if_available(reiserfs_blocknr_hint_t * hint,b_blocknr_t * new_blocknrs,int amount_needed)13101da177e4SLinus Torvalds static int use_preallocated_list_if_available(reiserfs_blocknr_hint_t * hint,
1311bd4c625cSLinus Torvalds b_blocknr_t * new_blocknrs,
1312bd4c625cSLinus Torvalds int amount_needed)
13131da177e4SLinus Torvalds {
13141da177e4SLinus Torvalds struct inode *inode = hint->inode;
13151da177e4SLinus Torvalds
13161da177e4SLinus Torvalds if (REISERFS_I(inode)->i_prealloc_count > 0) {
13171da177e4SLinus Torvalds while (amount_needed) {
13181da177e4SLinus Torvalds
13191da177e4SLinus Torvalds *new_blocknrs++ = REISERFS_I(inode)->i_prealloc_block++;
13201da177e4SLinus Torvalds REISERFS_I(inode)->i_prealloc_count--;
13211da177e4SLinus Torvalds
13221da177e4SLinus Torvalds amount_needed--;
13231da177e4SLinus Torvalds
13241da177e4SLinus Torvalds if (REISERFS_I(inode)->i_prealloc_count <= 0) {
13251da177e4SLinus Torvalds list_del(&REISERFS_I(inode)->i_prealloc_list);
13261da177e4SLinus Torvalds break;
13271da177e4SLinus Torvalds }
13281da177e4SLinus Torvalds }
13291da177e4SLinus Torvalds }
13301da177e4SLinus Torvalds /* return amount still needed after using preallocated blocks */
13311da177e4SLinus Torvalds return amount_needed;
13321da177e4SLinus Torvalds }
13331da177e4SLinus Torvalds
reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t * hint,b_blocknr_t * new_blocknrs,int amount_needed,int reserved_by_us)1334098297b2SJeff Mahoney int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *hint,
1335098297b2SJeff Mahoney b_blocknr_t *new_blocknrs,
1336098297b2SJeff Mahoney int amount_needed,
1337098297b2SJeff Mahoney /* Amount of blocks we have already reserved */
1338098297b2SJeff Mahoney int reserved_by_us)
13391da177e4SLinus Torvalds {
13401da177e4SLinus Torvalds int initial_amount_needed = amount_needed;
13411da177e4SLinus Torvalds int ret;
13421da177e4SLinus Torvalds struct super_block *s = hint->th->t_super;
13431da177e4SLinus Torvalds
13441da177e4SLinus Torvalds /* Check if there is enough space, taking into account reserved space */
13451da177e4SLinus Torvalds if (SB_FREE_BLOCKS(s) - REISERFS_SB(s)->reserved_blocks <
13461da177e4SLinus Torvalds amount_needed - reserved_by_us)
13471da177e4SLinus Torvalds return NO_DISK_SPACE;
13481da177e4SLinus Torvalds /* should this be if !hint->inode && hint->preallocate? */
13491da177e4SLinus Torvalds /* do you mean hint->formatted_node can be removed ? - Zam */
1350098297b2SJeff Mahoney /*
1351098297b2SJeff Mahoney * hint->formatted_node cannot be removed because we try to access
1352098297b2SJeff Mahoney * inode information here, and there is often no inode associated with
1353098297b2SJeff Mahoney * metadata allocations - green
1354098297b2SJeff Mahoney */
13551da177e4SLinus Torvalds
13561da177e4SLinus Torvalds if (!hint->formatted_node && hint->preallocate) {
13571da177e4SLinus Torvalds amount_needed = use_preallocated_list_if_available
13581da177e4SLinus Torvalds (hint, new_blocknrs, amount_needed);
1359098297b2SJeff Mahoney
1360098297b2SJeff Mahoney /*
1361098297b2SJeff Mahoney * We have all the block numbers we need from the
1362098297b2SJeff Mahoney * prealloc list
1363098297b2SJeff Mahoney */
1364098297b2SJeff Mahoney if (amount_needed == 0)
13651da177e4SLinus Torvalds return CARRY_ON;
13661da177e4SLinus Torvalds new_blocknrs += (initial_amount_needed - amount_needed);
13671da177e4SLinus Torvalds }
13681da177e4SLinus Torvalds
13691da177e4SLinus Torvalds /* find search start and save it in hint structure */
13701da177e4SLinus Torvalds determine_search_start(hint, amount_needed);
13711da177e4SLinus Torvalds if (hint->search_start >= SB_BLOCK_COUNT(s))
13721da177e4SLinus Torvalds hint->search_start = SB_BLOCK_COUNT(s) - 1;
13731da177e4SLinus Torvalds
13741da177e4SLinus Torvalds /* allocation itself; fill new_blocknrs and preallocation arrays */
13751da177e4SLinus Torvalds ret = blocknrs_and_prealloc_arrays_from_search_start
13761da177e4SLinus Torvalds (hint, new_blocknrs, amount_needed);
13771da177e4SLinus Torvalds
1378098297b2SJeff Mahoney /*
1379098297b2SJeff Mahoney * We used prealloc. list to fill (partially) new_blocknrs array.
1380098297b2SJeff Mahoney * If final allocation fails we need to return blocks back to
1381098297b2SJeff Mahoney * prealloc. list or just free them. -- Zam (I chose second
1382098297b2SJeff Mahoney * variant)
1383098297b2SJeff Mahoney */
13841da177e4SLinus Torvalds if (ret != CARRY_ON) {
13851da177e4SLinus Torvalds while (amount_needed++ < initial_amount_needed) {
1386bd4c625cSLinus Torvalds reiserfs_free_block(hint->th, hint->inode,
1387bd4c625cSLinus Torvalds *(--new_blocknrs), 1);
13881da177e4SLinus Torvalds }
13891da177e4SLinus Torvalds }
13901da177e4SLinus Torvalds return ret;
13911da177e4SLinus Torvalds }
13921da177e4SLinus Torvalds
reiserfs_cache_bitmap_metadata(struct super_block * sb,struct buffer_head * bh,struct reiserfs_bitmap_info * info)13936f01046bSJeff Mahoney void reiserfs_cache_bitmap_metadata(struct super_block *sb,
13946f01046bSJeff Mahoney struct buffer_head *bh,
13956f01046bSJeff Mahoney struct reiserfs_bitmap_info *info)
13966f01046bSJeff Mahoney {
13976f01046bSJeff Mahoney unsigned long *cur = (unsigned long *)(bh->b_data + bh->b_size);
13986f01046bSJeff Mahoney
13994d20851dSJeff Mahoney /* The first bit must ALWAYS be 1 */
14000030b645SJeff Mahoney if (!reiserfs_test_le_bit(0, (unsigned long *)bh->b_data))
14010030b645SJeff Mahoney reiserfs_error(sb, "reiserfs-2025", "bitmap block %lu is "
14020030b645SJeff Mahoney "corrupted: first bit must be 1", bh->b_blocknr);
14034d20851dSJeff Mahoney
14044d20851dSJeff Mahoney info->free_count = 0;
14056f01046bSJeff Mahoney
14066f01046bSJeff Mahoney while (--cur >= (unsigned long *)bh->b_data) {
14076f01046bSJeff Mahoney /* 0 and ~0 are special, we can optimize for them */
14084d20851dSJeff Mahoney if (*cur == 0)
14096f01046bSJeff Mahoney info->free_count += BITS_PER_LONG;
14104d20851dSJeff Mahoney else if (*cur != ~0L) /* A mix, investigate */
14119d6bf5aaSAkinobu Mita info->free_count += BITS_PER_LONG - hweight_long(*cur);
14126f01046bSJeff Mahoney }
14136f01046bSJeff Mahoney }
14146f01046bSJeff Mahoney
reiserfs_read_bitmap_block(struct super_block * sb,unsigned int bitmap)14156f01046bSJeff Mahoney struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb,
14166f01046bSJeff Mahoney unsigned int bitmap)
14176f01046bSJeff Mahoney {
14186f01046bSJeff Mahoney b_blocknr_t block = (sb->s_blocksize << 3) * bitmap;
14195065227bSJeff Mahoney struct reiserfs_bitmap_info *info = SB_AP_BITMAP(sb) + bitmap;
14206f01046bSJeff Mahoney struct buffer_head *bh;
14216f01046bSJeff Mahoney
1422098297b2SJeff Mahoney /*
1423098297b2SJeff Mahoney * Way old format filesystems had the bitmaps packed up front.
1424098297b2SJeff Mahoney * I doubt there are any of these left, but just in case...
1425098297b2SJeff Mahoney */
14266f01046bSJeff Mahoney if (unlikely(test_bit(REISERFS_OLD_FORMAT,
1427a228bf8fSJeff Mahoney &REISERFS_SB(sb)->s_properties)))
14286f01046bSJeff Mahoney block = REISERFS_SB(sb)->s_sbh->b_blocknr + 1 + bitmap;
14296f01046bSJeff Mahoney else if (bitmap == 0)
14306f01046bSJeff Mahoney block = (REISERFS_DISK_OFFSET_IN_BYTES >> sb->s_blocksize_bits) + 1;
14316f01046bSJeff Mahoney
14325065227bSJeff Mahoney bh = sb_bread(sb, block);
14335065227bSJeff Mahoney if (bh == NULL)
143400079e04SEric Eric Sesterhenn reiserfs_warning(sb, "sh-2029: %s: bitmap block (#%u) "
1435fbe5498bSHarvey Harrison "reading failed", __func__, block);
14365065227bSJeff Mahoney else {
14375065227bSJeff Mahoney if (buffer_locked(bh)) {
1438278f6679SJeff Mahoney int depth;
14395065227bSJeff Mahoney PROC_INFO_INC(sb, scan_bitmap.wait);
1440278f6679SJeff Mahoney depth = reiserfs_write_unlock_nested(sb);
14415065227bSJeff Mahoney __wait_on_buffer(bh);
1442278f6679SJeff Mahoney reiserfs_write_lock_nested(sb, depth);
14435065227bSJeff Mahoney }
14445065227bSJeff Mahoney BUG_ON(!buffer_uptodate(bh));
14455065227bSJeff Mahoney BUG_ON(atomic_read(&bh->b_count) == 0);
14465065227bSJeff Mahoney
14474d20851dSJeff Mahoney if (info->free_count == UINT_MAX)
14485065227bSJeff Mahoney reiserfs_cache_bitmap_metadata(sb, bh, info);
14495065227bSJeff Mahoney }
14506f01046bSJeff Mahoney
14516f01046bSJeff Mahoney return bh;
14526f01046bSJeff Mahoney }
14536f01046bSJeff Mahoney
reiserfs_init_bitmap_cache(struct super_block * sb)14546f01046bSJeff Mahoney int reiserfs_init_bitmap_cache(struct super_block *sb)
14556f01046bSJeff Mahoney {
14566f01046bSJeff Mahoney struct reiserfs_bitmap_info *bitmap;
1457cb680c1bSJeff Mahoney unsigned int bmap_nr = reiserfs_bmap_count(sb);
14586f01046bSJeff Mahoney
1459*42bc47b3SKees Cook bitmap = vmalloc(array_size(bmap_nr, sizeof(*bitmap)));
14606f01046bSJeff Mahoney if (bitmap == NULL)
14616f01046bSJeff Mahoney return -ENOMEM;
14626f01046bSJeff Mahoney
1463cb680c1bSJeff Mahoney memset(bitmap, 0xff, sizeof(*bitmap) * bmap_nr);
14646f01046bSJeff Mahoney
14656f01046bSJeff Mahoney SB_AP_BITMAP(sb) = bitmap;
14666f01046bSJeff Mahoney
14676f01046bSJeff Mahoney return 0;
14686f01046bSJeff Mahoney }
14695065227bSJeff Mahoney
reiserfs_free_bitmap_cache(struct super_block * sb)14705065227bSJeff Mahoney void reiserfs_free_bitmap_cache(struct super_block *sb)
14715065227bSJeff Mahoney {
14725065227bSJeff Mahoney if (SB_AP_BITMAP(sb)) {
14735065227bSJeff Mahoney vfree(SB_AP_BITMAP(sb));
14745065227bSJeff Mahoney SB_AP_BITMAP(sb) = NULL;
14755065227bSJeff Mahoney }
14765065227bSJeff Mahoney }
1477