xref: /openbmc/linux/fs/reiserfs/bitmap.c (revision 3eb66e91a25497065c5322b1268cbc3953642227)
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