Blame view

fs/reiserfs/bitmap.c 39.6 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
  /*
   * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
   */
  /* Reiserfs block (de)allocator, bitmap-based. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
  #include <linux/time.h>
f466c6fdb   Al Viro   move private bits...
6
  #include "reiserfs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
  #include <linux/errno.h>
  #include <linux/buffer_head.h>
  #include <linux/kernel.h>
  #include <linux/pagemap.h>
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
11
  #include <linux/vmalloc.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
  #include <linux/quotaops.h>
c3aa07764   Jan Kara   reiserfs: Properl...
13
  #include <linux/seq_file.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
  
  #define PREALLOCATION_SIZE 9
  
  /* different reiserfs block allocator options */
  
  #define SB_ALLOC_OPTS(s) (REISERFS_SB(s)->s_alloc_options.bits)
  
  #define  _ALLOC_concentrating_formatted_nodes 0
  #define  _ALLOC_displacing_large_files 1
  #define  _ALLOC_displacing_new_packing_localities 2
  #define  _ALLOC_old_hashed_relocation 3
  #define  _ALLOC_new_hashed_relocation 4
  #define  _ALLOC_skip_busy 5
  #define  _ALLOC_displace_based_on_dirid 6
  #define  _ALLOC_hashed_formatted_nodes 7
  #define  _ALLOC_old_way 8
  #define  _ALLOC_hundredth_slices 9
  #define  _ALLOC_dirid_groups 10
  #define  _ALLOC_oid_groups 11
  #define  _ALLOC_packing_groups 12
  
  #define  concentrating_formatted_nodes(s)	test_bit(_ALLOC_concentrating_formatted_nodes, &SB_ALLOC_OPTS(s))
  #define  displacing_large_files(s)		test_bit(_ALLOC_displacing_large_files, &SB_ALLOC_OPTS(s))
  #define  displacing_new_packing_localities(s)	test_bit(_ALLOC_displacing_new_packing_localities, &SB_ALLOC_OPTS(s))
  
  #define SET_OPTION(optname) \
     do { \
1d889d995   Jeff Mahoney   reiserfs: make so...
41
42
  	reiserfs_info(s, "block allocator option \"%s\" is set", #optname); \
  	set_bit(_ALLOC_ ## optname , &SB_ALLOC_OPTS(s)); \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
      } while(0)
  #define TEST_OPTION(optname, s) \
      test_bit(_ALLOC_ ## optname , &SB_ALLOC_OPTS(s))
bd4c625c0   Linus Torvalds   reiserfs: run scr...
46
  static inline void get_bit_address(struct super_block *s,
3ee166704   Jeff Mahoney   reiserfs: fix usa...
47
48
49
  				   b_blocknr_t block,
  				   unsigned int *bmap_nr,
  				   unsigned int *offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
  {
098297b27   Jeff Mahoney   reiserfs: cleanup...
51
52
53
54
  	/*
  	 * It is in the bitmap block number equal to the block
  	 * number divided by the number of bits in a block.
  	 */
e1fabd3cc   Jeff Mahoney   [PATCH] reiserfs:...
55
  	*bmap_nr = block >> (s->s_blocksize_bits + 3);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
56
57
  	/* Within that bitmap block it is located at bit offset *offset. */
  	*offset = block & ((s->s_blocksize << 3) - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
59
  int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
  {
3ee166704   Jeff Mahoney   reiserfs: fix usa...
61
  	unsigned int bmap, offset;
cb680c1be   Jeff Mahoney   reiserfs: ignore ...
62
  	unsigned int bmap_count = reiserfs_bmap_count(s);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63

bd4c625c0   Linus Torvalds   reiserfs: run scr...
64
  	if (block == 0 || block >= SB_BLOCK_COUNT(s)) {
0030b6457   Jeff Mahoney   reiserfs: use rei...
65
66
67
  		reiserfs_error(s, "vs-4010",
  			       "block number is out of range %lu (%u)",
  			       block, SB_BLOCK_COUNT(s));
bd4c625c0   Linus Torvalds   reiserfs: run scr...
68
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70

e1fabd3cc   Jeff Mahoney   [PATCH] reiserfs:...
71
  	get_bit_address(s, block, &bmap, &offset);
098297b27   Jeff Mahoney   reiserfs: cleanup...
72
73
74
75
  	/*
  	 * Old format filesystem? Unlikely, but the bitmaps are all
  	 * up front so we need to account for it.
  	 */
e1fabd3cc   Jeff Mahoney   [PATCH] reiserfs:...
76
  	if (unlikely(test_bit(REISERFS_OLD_FORMAT,
a228bf8f0   Jeff Mahoney   reiserfs: cleanup...
77
  			      &REISERFS_SB(s)->s_properties))) {
e1fabd3cc   Jeff Mahoney   [PATCH] reiserfs:...
78
  		b_blocknr_t bmap1 = REISERFS_SB(s)->s_sbh->b_blocknr + 1;
cb680c1be   Jeff Mahoney   reiserfs: ignore ...
79
80
  		if (block >= bmap1 &&
  		    block <= bmap1 + bmap_count) {
0030b6457   Jeff Mahoney   reiserfs: use rei...
81
82
83
  			reiserfs_error(s, "vs-4019", "bitmap block %lu(%u) "
  				       "can't be freed or reused",
  				       block, bmap_count);
e1fabd3cc   Jeff Mahoney   [PATCH] reiserfs:...
84
85
86
87
  			return 0;
  		}
  	} else {
  		if (offset == 0) {
0030b6457   Jeff Mahoney   reiserfs: use rei...
88
89
90
  			reiserfs_error(s, "vs-4020", "bitmap block %lu(%u) "
  				       "can't be freed or reused",
  				       block, bmap_count);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
91
92
  			return 0;
  		}
e1fabd3cc   Jeff Mahoney   [PATCH] reiserfs:...
93
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94

cb680c1be   Jeff Mahoney   reiserfs: ignore ...
95
  	if (bmap >= bmap_count) {
0030b6457   Jeff Mahoney   reiserfs: use rei...
96
97
98
  		reiserfs_error(s, "vs-4030", "bitmap for requested block "
  			       "is out of range: block=%lu, bitmap_nr=%u",
  			       block, bmap);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
99
100
  		return 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101

bd4c625c0   Linus Torvalds   reiserfs: run scr...
102
  	if (bit_value == 0 && block == SB_ROOT_BLOCK(s)) {
0030b6457   Jeff Mahoney   reiserfs: use rei...
103
104
  		reiserfs_error(s, "vs-4050", "this is root block (%u), "
  			       "it must be busy", SB_ROOT_BLOCK(s));
bd4c625c0   Linus Torvalds   reiserfs: run scr...
105
106
107
108
  		return 0;
  	}
  
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110

098297b27   Jeff Mahoney   reiserfs: cleanup...
111
112
113
114
115
  /*
   * Searches in journal structures for a given block number (bmap, off).
   * If block is found in reiserfs journal it suggests next free block
   * candidate to test.
   */
3ee166704   Jeff Mahoney   reiserfs: fix usa...
116
117
  static inline int is_block_in_journal(struct super_block *s, unsigned int bmap,
  				      int off, int *next)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
119
120
121
122
123
124
125
  	b_blocknr_t tmp;
  
  	if (reiserfs_in_journal(s, bmap, off, 1, &tmp)) {
  		if (tmp) {	/* hint supplied */
  			*next = tmp;
  			PROC_INFO_INC(s, scan_bitmap.in_journal_hint);
  		} else {
098297b27   Jeff Mahoney   reiserfs: cleanup...
126
  			(*next) = off + 1;  /* inc offset to avoid looping. */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
127
128
129
130
  			PROC_INFO_INC(s, scan_bitmap.in_journal_nohint);
  		}
  		PROC_INFO_INC(s, scan_bitmap.retry);
  		return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
  	}
bd4c625c0   Linus Torvalds   reiserfs: run scr...
132
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
  }
098297b27   Jeff Mahoney   reiserfs: cleanup...
134
135
136
137
  /*
   * Searches for a window of zero bits with given minimum and maximum
   * lengths in one bitmap block
   */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
138
  static int scan_bitmap_block(struct reiserfs_transaction_handle *th,
3ee166704   Jeff Mahoney   reiserfs: fix usa...
139
140
  			     unsigned int bmap_n, int *beg, int boundary,
  			     int min, int max, int unfm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
142
143
  	struct super_block *s = th->t_super;
  	struct reiserfs_bitmap_info *bi = &SB_AP_BITMAP(s)[bmap_n];
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
144
  	struct buffer_head *bh;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
145
146
  	int end, next;
  	int org = *beg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147

bd4c625c0   Linus Torvalds   reiserfs: run scr...
148
  	BUG_ON(!th->t_trans_id);
cb680c1be   Jeff Mahoney   reiserfs: ignore ...
149
150
  	RFALSE(bmap_n >= reiserfs_bmap_count(s), "Bitmap %u is out of "
  	       "range (0..%u)", bmap_n, reiserfs_bmap_count(s) - 1);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
151
  	PROC_INFO_INC(s, scan_bitmap.bmap);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152

bd4c625c0   Linus Torvalds   reiserfs: run scr...
153
  	if (!bi) {
0030b6457   Jeff Mahoney   reiserfs: use rei...
154
155
  		reiserfs_error(s, "jdm-4055", "NULL bitmap info pointer "
  			       "for bitmap %d", bmap_n);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
156
157
  		return 0;
  	}
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
158

5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
159
160
161
  	bh = reiserfs_read_bitmap_block(s, bmap_n);
  	if (bh == NULL)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162

bd4c625c0   Linus Torvalds   reiserfs: run scr...
163
  	while (1) {
cf776a7a4   Jeff Mahoney   reiserfs: cleanup...
164
  cont:
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
165
166
  		if (bi->free_count < min) {
  			brelse(bh);
098297b27   Jeff Mahoney   reiserfs: cleanup...
167
  			return 0;	/* No free blocks in this bitmap */
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
168
  		}
bd4c625c0   Linus Torvalds   reiserfs: run scr...
169

3ad2f3fbb   Daniel Mack   tree-wide: Assort...
170
  		/* search for a first zero bit -- beginning of a window */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
171
  		*beg = reiserfs_find_next_zero_le_bit
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
172
  		    ((unsigned long *)(bh->b_data), boundary, *beg);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
173

098297b27   Jeff Mahoney   reiserfs: cleanup...
174
175
176
177
178
  		/*
  		 * search for a zero bit fails or the rest of bitmap block
  		 * cannot contain a zero window of minimum size
  		 */
  		if (*beg + min > boundary) {
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
179
  			brelse(bh);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
180
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182

bd4c625c0   Linus Torvalds   reiserfs: run scr...
183
184
185
186
187
  		if (unfm && is_block_in_journal(s, bmap_n, *beg, beg))
  			continue;
  		/* first zero bit found; we check next bits */
  		for (end = *beg + 1;; end++) {
  			if (end >= *beg + max || end >= boundary
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
188
  			    || reiserfs_test_le_bit(end, bh->b_data)) {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
189
190
191
  				next = end;
  				break;
  			}
098297b27   Jeff Mahoney   reiserfs: cleanup...
192
193
194
195
196
197
  
  			/*
  			 * finding the other end of zero bit window requires
  			 * looking into journal structures (in case of
  			 * searching for free blocks for unformatted nodes)
  			 */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
198
199
200
  			if (unfm && is_block_in_journal(s, bmap_n, end, &next))
  				break;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201

098297b27   Jeff Mahoney   reiserfs: cleanup...
202
203
204
205
206
207
208
  		/*
  		 * now (*beg) points to beginning of zero bits window,
  		 * (end) points to one bit after the window end
  		 */
  
  		/* found window of proper size */
  		if (end - *beg >= min) {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
209
  			int i;
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
210
  			reiserfs_prepare_for_journal(s, bh, 1);
098297b27   Jeff Mahoney   reiserfs: cleanup...
211
212
213
214
  			/*
  			 * try to set all blocks used checking are
  			 * they still free
  			 */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
215
  			for (i = *beg; i < end; i++) {
098297b27   Jeff Mahoney   reiserfs: cleanup...
216
  				/* Don't check in journal again. */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
217
  				if (reiserfs_test_and_set_le_bit
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
218
  				    (i, bh->b_data)) {
098297b27   Jeff Mahoney   reiserfs: cleanup...
219
220
221
222
  					/*
  					 * bit was set by another process while
  					 * we slept in prepare_for_journal()
  					 */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
223
  					PROC_INFO_INC(s, scan_bitmap.stolen);
098297b27   Jeff Mahoney   reiserfs: cleanup...
224
225
226
227
228
229
230
  
  					/*
  					 * we can continue with smaller set
  					 * of allocated blocks, if length of
  					 * this set is more or equal to `min'
  					 */
  					if (i >= *beg + min) {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
231
232
233
  						end = i;
  						break;
  					}
098297b27   Jeff Mahoney   reiserfs: cleanup...
234
235
236
237
238
  
  					/*
  					 * otherwise we clear all bit
  					 * were set ...
  					 */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
239
  					while (--i >= *beg)
0c2fd1bfb   Akinobu Mita   reiserfs: use pro...
240
  						reiserfs_clear_le_bit
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
241
242
  						    (i, bh->b_data);
  					reiserfs_restore_prepared_buffer(s, bh);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
243
  					*beg = org;
098297b27   Jeff Mahoney   reiserfs: cleanup...
244
245
246
247
248
  
  					/*
  					 * Search again in current block
  					 * from beginning
  					 */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
249
250
251
252
  					goto cont;
  				}
  			}
  			bi->free_count -= (end - *beg);
09f1b80ba   Jeff Mahoney   reiserfs: cleanup...
253
  			journal_mark_dirty(th, bh);
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
254
  			brelse(bh);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
255
256
257
258
259
  
  			/* free block count calculation */
  			reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s),
  						     1);
  			PUT_SB_FREE_BLOCKS(s, SB_FREE_BLOCKS(s) - (end - *beg));
09f1b80ba   Jeff Mahoney   reiserfs: cleanup...
260
  			journal_mark_dirty(th, SB_BUFFER_WITH_SB(s));
bd4c625c0   Linus Torvalds   reiserfs: run scr...
261
262
263
264
265
  
  			return end - (*beg);
  		} else {
  			*beg = next;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
268
269
270
271
272
273
274
275
276
277
278
  static int bmap_hash_id(struct super_block *s, u32 id)
  {
  	char *hash_in = NULL;
  	unsigned long hash;
  	unsigned bm;
  
  	if (id <= 2) {
  		bm = 1;
  	} else {
  		hash_in = (char *)(&id);
  		hash = keyed_hash(hash_in, 4);
cb680c1be   Jeff Mahoney   reiserfs: ignore ...
279
  		bm = hash % reiserfs_bmap_count(s);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
280
281
282
283
  		if (!bm)
  			bm = 1;
  	}
  	/* this can only be true when SB_BMAP_NR = 1 */
cb680c1be   Jeff Mahoney   reiserfs: ignore ...
284
  	if (bm >= reiserfs_bmap_count(s))
bd4c625c0   Linus Torvalds   reiserfs: run scr...
285
286
  		bm = 0;
  	return bm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
289
290
291
292
  }
  
  /*
   * hashes the id and then returns > 0 if the block group for the
   * corresponding hash is full
   */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
293
294
  static inline int block_group_used(struct super_block *s, u32 id)
  {
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
295
296
  	int bm = bmap_hash_id(s, id);
  	struct reiserfs_bitmap_info *info = &SB_AP_BITMAP(s)[bm];
098297b27   Jeff Mahoney   reiserfs: cleanup...
297
298
  	/*
  	 * If we don't have cached information on this bitmap block, we're
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
299
  	 * going to have to load it later anyway. Loading it here allows us
c78bad11f   Joe Perches   fs/: Spelling fixes
300
  	 * to make a better decision. This favors long-term performance gain
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
301
  	 * with a better on-disk layout vs. a short term gain of skipping the
098297b27   Jeff Mahoney   reiserfs: cleanup...
302
303
  	 * read and potentially having a bad placement.
  	 */
4d20851d3   Jeff Mahoney   reiserfs: remove ...
304
  	if (info->free_count == UINT_MAX) {
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
305
306
307
308
309
  		struct buffer_head *bh = reiserfs_read_bitmap_block(s, bm);
  		brelse(bh);
  	}
  
  	if (info->free_count > ((s->s_blocksize << 3) * 60 / 100)) {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
310
311
312
  		return 0;
  	}
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
314
315
316
317
  }
  
  /*
   * the packing is returned in disk byte order
   */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
318
  __le32 reiserfs_choose_packing(struct inode * dir)
3e8962be9   Al Viro   [PATCH] reiserfs ...
319
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
320
321
322
323
324
325
326
327
328
329
330
331
332
333
  	__le32 packing;
  	if (TEST_OPTION(packing_groups, dir->i_sb)) {
  		u32 parent_dir = le32_to_cpu(INODE_PKEY(dir)->k_dir_id);
  		/*
  		 * some versions of reiserfsck expect packing locality 1 to be
  		 * special
  		 */
  		if (parent_dir == 1 || block_group_used(dir->i_sb, parent_dir))
  			packing = INODE_PKEY(dir)->k_objectid;
  		else
  			packing = INODE_PKEY(dir)->k_dir_id;
  	} else
  		packing = INODE_PKEY(dir)->k_objectid;
  	return packing;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
335

098297b27   Jeff Mahoney   reiserfs: cleanup...
336
337
338
339
  /*
   * Tries to find contiguous zero bit window (given size) in given region of
   * bitmap and place new blocks there. Returns number of allocated blocks.
   */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
340
341
  static int scan_bitmap(struct reiserfs_transaction_handle *th,
  		       b_blocknr_t * start, b_blocknr_t finish,
3ee166704   Jeff Mahoney   reiserfs: fix usa...
342
  		       int min, int max, int unfm, sector_t file_block)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
344
345
  	int nr_allocated = 0;
  	struct super_block *s = th->t_super;
3ee166704   Jeff Mahoney   reiserfs: fix usa...
346
347
348
  	unsigned int bm, off;
  	unsigned int end_bm, end_off;
  	unsigned int off_max = s->s_blocksize << 3;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
349
350
  
  	BUG_ON(!th->t_trans_id);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
351
  	PROC_INFO_INC(s, scan_bitmap.call);
098297b27   Jeff Mahoney   reiserfs: cleanup...
352
353
  
  	/* No point in looking for more free blocks */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
354
  	if (SB_FREE_BLOCKS(s) <= 0)
098297b27   Jeff Mahoney   reiserfs: cleanup...
355
  		return 0;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
356
357
358
  
  	get_bit_address(s, *start, &bm, &off);
  	get_bit_address(s, finish, &end_bm, &end_off);
cb680c1be   Jeff Mahoney   reiserfs: ignore ...
359
  	if (bm > reiserfs_bmap_count(s))
bd4c625c0   Linus Torvalds   reiserfs: run scr...
360
  		return 0;
cb680c1be   Jeff Mahoney   reiserfs: ignore ...
361
362
  	if (end_bm > reiserfs_bmap_count(s))
  		end_bm = reiserfs_bmap_count(s);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
363

098297b27   Jeff Mahoney   reiserfs: cleanup...
364
365
  	/*
  	 * When the bitmap is more than 10% free, anyone can allocate.
bd4c625c0   Linus Torvalds   reiserfs: run scr...
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
  	 * When it's less than 10% free, only files that already use the
  	 * bitmap are allowed. Once we pass 80% full, this restriction
  	 * is lifted.
  	 *
  	 * We do this so that files that grow later still have space close to
  	 * their original allocation. This improves locality, and presumably
  	 * performance as a result.
  	 *
  	 * This is only an allocation policy and does not make up for getting a
  	 * bad hint. Decent hinting must be implemented for this to work well.
  	 */
  	if (TEST_OPTION(skip_busy, s)
  	    && SB_FREE_BLOCKS(s) > SB_BLOCK_COUNT(s) / 20) {
  		for (; bm < end_bm; bm++, off = 0) {
  			if ((off && (!unfm || (file_block != 0)))
  			    || SB_AP_BITMAP(s)[bm].free_count >
  			    (s->s_blocksize << 3) / 10)
  				nr_allocated =
  				    scan_bitmap_block(th, bm, &off, off_max,
  						      min, max, unfm);
  			if (nr_allocated)
  				goto ret;
  		}
  		/* we know from above that start is a reasonable number */
  		get_bit_address(s, *start, &bm, &off);
  	}
  
  	for (; bm < end_bm; bm++, off = 0) {
  		nr_allocated =
  		    scan_bitmap_block(th, bm, &off, off_max, min, max, unfm);
  		if (nr_allocated)
  			goto ret;
  	}
  
  	nr_allocated =
  	    scan_bitmap_block(th, bm, &off, end_off + 1, min, max, unfm);
cf776a7a4   Jeff Mahoney   reiserfs: cleanup...
402
  ret:
bd4c625c0   Linus Torvalds   reiserfs: run scr...
403
404
  	*start = bm * off_max + off;
  	return nr_allocated;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
406
  
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
407
408
409
  static void _reiserfs_free_block(struct reiserfs_transaction_handle *th,
  				 struct inode *inode, b_blocknr_t block,
  				 int for_unformatted)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
411
412
  	struct super_block *s = th->t_super;
  	struct reiserfs_super_block *rs;
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
413
  	struct buffer_head *sbh, *bmbh;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
414
  	struct reiserfs_bitmap_info *apbi;
3ee166704   Jeff Mahoney   reiserfs: fix usa...
415
  	unsigned int nr, offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416

bd4c625c0   Linus Torvalds   reiserfs: run scr...
417
  	BUG_ON(!th->t_trans_id);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
418
  	PROC_INFO_INC(s, free_block);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
419
420
421
  	rs = SB_DISK_SUPER_BLOCK(s);
  	sbh = SB_BUFFER_WITH_SB(s);
  	apbi = SB_AP_BITMAP(s);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422

bd4c625c0   Linus Torvalds   reiserfs: run scr...
423
  	get_bit_address(s, block, &nr, &offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424

cb680c1be   Jeff Mahoney   reiserfs: ignore ...
425
  	if (nr >= reiserfs_bmap_count(s)) {
0030b6457   Jeff Mahoney   reiserfs: use rei...
426
427
  		reiserfs_error(s, "vs-4075", "block %lu is out of range",
  			       block);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
428
429
  		return;
  	}
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
430
431
432
  	bmbh = reiserfs_read_bitmap_block(s, nr);
  	if (!bmbh)
  		return;
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
433
434
  
  	reiserfs_prepare_for_journal(s, bmbh, 1);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
435
436
  
  	/* clear bit for the given block in bit map */
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
437
  	if (!reiserfs_test_and_clear_le_bit(offset, bmbh->b_data)) {
0030b6457   Jeff Mahoney   reiserfs: use rei...
438
439
  		reiserfs_error(s, "vs-4080",
  			       "block %lu: bit already cleared", block);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
440
441
  	}
  	apbi[nr].free_count++;
09f1b80ba   Jeff Mahoney   reiserfs: cleanup...
442
  	journal_mark_dirty(th, bmbh);
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
443
  	brelse(bmbh);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
444
445
446
447
  
  	reiserfs_prepare_for_journal(s, sbh, 1);
  	/* update super block */
  	set_sb_free_blocks(rs, sb_free_blocks(rs) + 1);
09f1b80ba   Jeff Mahoney   reiserfs: cleanup...
448
  	journal_mark_dirty(th, sbh);
d2d0395fd   Jeff Mahoney   reiserfs: locking...
449
450
  	if (for_unformatted) {
  		int depth = reiserfs_write_unlock_nested(s);
5dd4056db   Christoph Hellwig   dquot: cleanup sp...
451
  		dquot_free_block_nodirty(inode, 1);
d2d0395fd   Jeff Mahoney   reiserfs: locking...
452
453
  		reiserfs_write_lock_nested(s, depth);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
455
456
457
  void reiserfs_free_block(struct reiserfs_transaction_handle *th,
  			 struct inode *inode, b_blocknr_t block,
  			 int for_unformatted)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
459
  	struct super_block *s = th->t_super;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460

ae0a50aba   Fabian Frederick   fs/reiserfs/bitma...
461
  	BUG_ON(!th->t_trans_id);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
462
  	RFALSE(!s, "vs-4061: trying to free block on nonexistent device");
d4c3d19d0   Jeff Mahoney   reiserfs: use is_...
463
464
465
466
  	if (!is_reusable(s, block, 1))
  		return;
  
  	if (block > sb_block_count(REISERFS_SB(s)->s_rs)) {
0030b6457   Jeff Mahoney   reiserfs: use rei...
467
  		reiserfs_error(th->t_super, "bitmap-4072",
d4c3d19d0   Jeff Mahoney   reiserfs: use is_...
468
469
470
471
472
  			       "Trying to free block outside file system "
  			       "boundaries (%lu > %lu)",
  			       block, sb_block_count(REISERFS_SB(s)->s_rs));
  		return;
  	}
bd4c625c0   Linus Torvalds   reiserfs: run scr...
473
474
475
  	/* mark it before we clear it, just in case */
  	journal_mark_freed(th, s, block);
  	_reiserfs_free_block(th, inode, block, for_unformatted);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
477
478
  }
  
  /* preallocated blocks don't need to be run through journal_mark_freed */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
479
480
481
  static void reiserfs_free_prealloc_block(struct reiserfs_transaction_handle *th,
  					 struct inode *inode, b_blocknr_t block)
  {
d4c3d19d0   Jeff Mahoney   reiserfs: use is_...
482
  	BUG_ON(!th->t_trans_id);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
483
484
  	RFALSE(!th->t_super,
  	       "vs-4060: trying to free block on nonexistent device");
d4c3d19d0   Jeff Mahoney   reiserfs: use is_...
485
486
  	if (!is_reusable(th->t_super, block, 1))
  		return;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
487
  	_reiserfs_free_block(th, inode, block, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
489
490
  static void __discard_prealloc(struct reiserfs_transaction_handle *th,
  			       struct reiserfs_inode_info *ei)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
492
493
494
  	unsigned long save = ei->i_prealloc_block;
  	int dirty = 0;
  	struct inode *inode = &ei->vfs_inode;
ae0a50aba   Fabian Frederick   fs/reiserfs/bitma...
495

bd4c625c0   Linus Torvalds   reiserfs: run scr...
496
  	BUG_ON(!th->t_trans_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
  #ifdef CONFIG_REISERFS_CHECK
bd4c625c0   Linus Torvalds   reiserfs: run scr...
498
  	if (ei->i_prealloc_count < 0)
0030b6457   Jeff Mahoney   reiserfs: use rei...
499
500
  		reiserfs_error(th->t_super, "zam-4001",
  			       "inode has negative prealloc blocks count.");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
  #endif
bd4c625c0   Linus Torvalds   reiserfs: run scr...
502
  	while (ei->i_prealloc_count > 0) {
08db141b5   Jeff Mahoney   reiserfs: fix rac...
503
504
505
506
507
508
509
510
511
  		b_blocknr_t block_to_free;
  
  		/*
  		 * reiserfs_free_prealloc_block can drop the write lock,
  		 * which could allow another caller to free the same block.
  		 * We can protect against it by modifying the prealloc
  		 * state before calling it.
  		 */
  		block_to_free = ei->i_prealloc_block++;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
512
  		ei->i_prealloc_count--;
08db141b5   Jeff Mahoney   reiserfs: fix rac...
513
  		reiserfs_free_prealloc_block(th, inode, block_to_free);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
514
515
516
517
518
  		dirty = 1;
  	}
  	if (dirty)
  		reiserfs_update_sd(th, inode);
  	ei->i_prealloc_block = save;
a228bf8f0   Jeff Mahoney   reiserfs: cleanup...
519
  	list_del_init(&ei->i_prealloc_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
521
522
  }
  
  /* FIXME: It should be inline function */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
523
524
  void reiserfs_discard_prealloc(struct reiserfs_transaction_handle *th,
  			       struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
526
  	struct reiserfs_inode_info *ei = REISERFS_I(inode);
ae0a50aba   Fabian Frederick   fs/reiserfs/bitma...
527

bd4c625c0   Linus Torvalds   reiserfs: run scr...
528
529
530
  	BUG_ON(!th->t_trans_id);
  	if (ei->i_prealloc_count)
  		__discard_prealloc(th, ei);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
532
  void reiserfs_discard_all_prealloc(struct reiserfs_transaction_handle *th)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
534
  	struct list_head *plist = &SB_JOURNAL(th->t_super)->j_prealloc_list;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535

bd4c625c0   Linus Torvalds   reiserfs: run scr...
536
  	BUG_ON(!th->t_trans_id);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
537
538
539
540
  	while (!list_empty(plist)) {
  		struct reiserfs_inode_info *ei;
  		ei = list_entry(plist->next, struct reiserfs_inode_info,
  				i_prealloc_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
  #ifdef CONFIG_REISERFS_CHECK
bd4c625c0   Linus Torvalds   reiserfs: run scr...
542
  		if (!ei->i_prealloc_count) {
0030b6457   Jeff Mahoney   reiserfs: use rei...
543
544
545
  			reiserfs_error(th->t_super, "zam-4001",
  				       "inode is in prealloc list but has "
  				       "no preallocated blocks.");
bd4c625c0   Linus Torvalds   reiserfs: run scr...
546
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
  #endif
bd4c625c0   Linus Torvalds   reiserfs: run scr...
548
549
  		__discard_prealloc(th, ei);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
551
  void reiserfs_init_alloc_options(struct super_block *s)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
552
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
553
554
555
  	set_bit(_ALLOC_skip_busy, &SB_ALLOC_OPTS(s));
  	set_bit(_ALLOC_dirid_groups, &SB_ALLOC_OPTS(s));
  	set_bit(_ALLOC_packing_groups, &SB_ALLOC_OPTS(s));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
557
558
  }
  
  /* block allocator related options are parsed here */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
559
  int reiserfs_parse_alloc_options(struct super_block *s, char *options)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
561
  	char *this_char, *value;
098297b27   Jeff Mahoney   reiserfs: cleanup...
562
563
  	/* clear default settings */
  	REISERFS_SB(s)->s_alloc_options.bits = 0;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
  
  	while ((this_char = strsep(&options, ":")) != NULL) {
  		if ((value = strchr(this_char, '=')) != NULL)
  			*value++ = 0;
  
  		if (!strcmp(this_char, "concentrating_formatted_nodes")) {
  			int temp;
  			SET_OPTION(concentrating_formatted_nodes);
  			temp = (value
  				&& *value) ? simple_strtoul(value, &value,
  							    0) : 10;
  			if (temp <= 0 || temp > 100) {
  				REISERFS_SB(s)->s_alloc_options.border = 10;
  			} else {
  				REISERFS_SB(s)->s_alloc_options.border =
  				    100 / temp;
  			}
  			continue;
  		}
  		if (!strcmp(this_char, "displacing_large_files")) {
  			SET_OPTION(displacing_large_files);
  			REISERFS_SB(s)->s_alloc_options.large_file_size =
  			    (value
  			     && *value) ? simple_strtoul(value, &value, 0) : 16;
  			continue;
  		}
  		if (!strcmp(this_char, "displacing_new_packing_localities")) {
  			SET_OPTION(displacing_new_packing_localities);
  			continue;
ae0a50aba   Fabian Frederick   fs/reiserfs/bitma...
593
  		}
bd4c625c0   Linus Torvalds   reiserfs: run scr...
594
595
596
597
598
  
  		if (!strcmp(this_char, "old_hashed_relocation")) {
  			SET_OPTION(old_hashed_relocation);
  			continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599

bd4c625c0   Linus Torvalds   reiserfs: run scr...
600
601
602
603
  		if (!strcmp(this_char, "new_hashed_relocation")) {
  			SET_OPTION(new_hashed_relocation);
  			continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604

bd4c625c0   Linus Torvalds   reiserfs: run scr...
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
  		if (!strcmp(this_char, "dirid_groups")) {
  			SET_OPTION(dirid_groups);
  			continue;
  		}
  		if (!strcmp(this_char, "oid_groups")) {
  			SET_OPTION(oid_groups);
  			continue;
  		}
  		if (!strcmp(this_char, "packing_groups")) {
  			SET_OPTION(packing_groups);
  			continue;
  		}
  		if (!strcmp(this_char, "hashed_formatted_nodes")) {
  			SET_OPTION(hashed_formatted_nodes);
  			continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621

bd4c625c0   Linus Torvalds   reiserfs: run scr...
622
623
624
625
  		if (!strcmp(this_char, "skip_busy")) {
  			SET_OPTION(skip_busy);
  			continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
626

bd4c625c0   Linus Torvalds   reiserfs: run scr...
627
628
629
630
  		if (!strcmp(this_char, "hundredth_slices")) {
  			SET_OPTION(hundredth_slices);
  			continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631

bd4c625c0   Linus Torvalds   reiserfs: run scr...
632
633
634
635
  		if (!strcmp(this_char, "old_way")) {
  			SET_OPTION(old_way);
  			continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636

bd4c625c0   Linus Torvalds   reiserfs: run scr...
637
638
639
640
  		if (!strcmp(this_char, "displace_based_on_dirid")) {
  			SET_OPTION(displace_based_on_dirid);
  			continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641

bd4c625c0   Linus Torvalds   reiserfs: run scr...
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
  		if (!strcmp(this_char, "preallocmin")) {
  			REISERFS_SB(s)->s_alloc_options.preallocmin =
  			    (value
  			     && *value) ? simple_strtoul(value, &value, 0) : 4;
  			continue;
  		}
  
  		if (!strcmp(this_char, "preallocsize")) {
  			REISERFS_SB(s)->s_alloc_options.preallocsize =
  			    (value
  			     && *value) ? simple_strtoul(value, &value,
  							 0) :
  			    PREALLOCATION_SIZE;
  			continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657

45b03d5e8   Jeff Mahoney   reiserfs: rework ...
658
659
  		reiserfs_warning(s, "zam-4001", "unknown option - %s",
  				 this_char);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
660
  		return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
  	}
1d889d995   Jeff Mahoney   reiserfs: make so...
662
663
  	reiserfs_info(s, "allocator options = [%08x]
  ", SB_ALLOC_OPTS(s));
bd4c625c0   Linus Torvalds   reiserfs: run scr...
664
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
666

c3aa07764   Jan Kara   reiserfs: Properl...
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
  static void print_sep(struct seq_file *seq, int *first)
  {
  	if (!*first)
  		seq_puts(seq, ":");
  	else
  		*first = 0;
  }
  
  void show_alloc_options(struct seq_file *seq, struct super_block *s)
  {
  	int first = 1;
  
  	if (SB_ALLOC_OPTS(s) == ((1 << _ALLOC_skip_busy) |
  		(1 << _ALLOC_dirid_groups) | (1 << _ALLOC_packing_groups)))
  		return;
  
  	seq_puts(seq, ",alloc=");
  
  	if (TEST_OPTION(concentrating_formatted_nodes, s)) {
  		print_sep(seq, &first);
  		if (REISERFS_SB(s)->s_alloc_options.border != 10) {
  			seq_printf(seq, "concentrating_formatted_nodes=%d",
  				100 / REISERFS_SB(s)->s_alloc_options.border);
  		} else
  			seq_puts(seq, "concentrating_formatted_nodes");
  	}
  	if (TEST_OPTION(displacing_large_files, s)) {
  		print_sep(seq, &first);
  		if (REISERFS_SB(s)->s_alloc_options.large_file_size != 16) {
  			seq_printf(seq, "displacing_large_files=%lu",
  			    REISERFS_SB(s)->s_alloc_options.large_file_size);
  		} else
  			seq_puts(seq, "displacing_large_files");
  	}
  	if (TEST_OPTION(displacing_new_packing_localities, s)) {
  		print_sep(seq, &first);
  		seq_puts(seq, "displacing_new_packing_localities");
  	}
  	if (TEST_OPTION(old_hashed_relocation, s)) {
  		print_sep(seq, &first);
  		seq_puts(seq, "old_hashed_relocation");
  	}
  	if (TEST_OPTION(new_hashed_relocation, s)) {
  		print_sep(seq, &first);
  		seq_puts(seq, "new_hashed_relocation");
  	}
  	if (TEST_OPTION(dirid_groups, s)) {
  		print_sep(seq, &first);
  		seq_puts(seq, "dirid_groups");
  	}
  	if (TEST_OPTION(oid_groups, s)) {
  		print_sep(seq, &first);
  		seq_puts(seq, "oid_groups");
  	}
  	if (TEST_OPTION(packing_groups, s)) {
  		print_sep(seq, &first);
  		seq_puts(seq, "packing_groups");
  	}
  	if (TEST_OPTION(hashed_formatted_nodes, s)) {
  		print_sep(seq, &first);
  		seq_puts(seq, "hashed_formatted_nodes");
  	}
  	if (TEST_OPTION(skip_busy, s)) {
  		print_sep(seq, &first);
  		seq_puts(seq, "skip_busy");
  	}
  	if (TEST_OPTION(hundredth_slices, s)) {
  		print_sep(seq, &first);
  		seq_puts(seq, "hundredth_slices");
  	}
  	if (TEST_OPTION(old_way, s)) {
  		print_sep(seq, &first);
  		seq_puts(seq, "old_way");
  	}
  	if (TEST_OPTION(displace_based_on_dirid, s)) {
  		print_sep(seq, &first);
  		seq_puts(seq, "displace_based_on_dirid");
  	}
  	if (REISERFS_SB(s)->s_alloc_options.preallocmin != 0) {
  		print_sep(seq, &first);
  		seq_printf(seq, "preallocmin=%d",
  				REISERFS_SB(s)->s_alloc_options.preallocmin);
  	}
  	if (REISERFS_SB(s)->s_alloc_options.preallocsize != 17) {
  		print_sep(seq, &first);
  		seq_printf(seq, "preallocsize=%d",
  				REISERFS_SB(s)->s_alloc_options.preallocsize);
  	}
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
756
  static inline void new_hashed_relocation(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
758
  	char *hash_in;
ae0a50aba   Fabian Frederick   fs/reiserfs/bitma...
759

bd4c625c0   Linus Torvalds   reiserfs: run scr...
760
761
762
763
  	if (hint->formatted_node) {
  		hash_in = (char *)&hint->key.k_dir_id;
  	} else {
  		if (!hint->inode) {
098297b27   Jeff Mahoney   reiserfs: cleanup...
764
  			/*hint->search_start = hint->beg;*/
bd4c625c0   Linus Torvalds   reiserfs: run scr...
765
766
767
768
769
770
771
772
  			hash_in = (char *)&hint->key.k_dir_id;
  		} else
  		    if (TEST_OPTION(displace_based_on_dirid, hint->th->t_super))
  			hash_in = (char *)(&INODE_PKEY(hint->inode)->k_dir_id);
  		else
  			hash_in =
  			    (char *)(&INODE_PKEY(hint->inode)->k_objectid);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773

bd4c625c0   Linus Torvalds   reiserfs: run scr...
774
775
  	hint->search_start =
  	    hint->beg + keyed_hash(hash_in, 4) % (hint->end - hint->beg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
777
778
779
  }
  
  /*
   * Relocation based on dirid, hashing them into a given bitmap block
c78bad11f   Joe Perches   fs/: Spelling fixes
780
   * files. Formatted nodes are unaffected, a separate policy covers them
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
   */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
782
  static void dirid_groups(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
784
785
786
787
  	unsigned long hash;
  	__u32 dirid = 0;
  	int bm = 0;
  	struct super_block *sb = hint->th->t_super;
ae0a50aba   Fabian Frederick   fs/reiserfs/bitma...
788

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789
  	if (hint->inode)
bd4c625c0   Linus Torvalds   reiserfs: run scr...
790
791
792
793
794
795
796
797
798
799
800
801
  		dirid = le32_to_cpu(INODE_PKEY(hint->inode)->k_dir_id);
  	else if (hint->formatted_node)
  		dirid = hint->key.k_dir_id;
  
  	if (dirid) {
  		bm = bmap_hash_id(sb, dirid);
  		hash = bm * (sb->s_blocksize << 3);
  		/* give a portion of the block group to metadata */
  		if (hint->inode)
  			hash += sb->s_blocksize / 2;
  		hint->search_start = hash;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
803
804
805
  }
  
  /*
   * Relocation based on oid, hashing them into a given bitmap block
c78bad11f   Joe Perches   fs/: Spelling fixes
806
   * files. Formatted nodes are unaffected, a separate policy covers them
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
   */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
808
  static void oid_groups(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
810
811
812
813
814
815
816
  	if (hint->inode) {
  		unsigned long hash;
  		__u32 oid;
  		__u32 dirid;
  		int bm;
  
  		dirid = le32_to_cpu(INODE_PKEY(hint->inode)->k_dir_id);
098297b27   Jeff Mahoney   reiserfs: cleanup...
817
818
  		/*
  		 * keep the root dir and it's first set of subdirs close to
bd4c625c0   Linus Torvalds   reiserfs: run scr...
819
820
821
822
823
824
825
826
827
828
  		 * the start of the disk
  		 */
  		if (dirid <= 2)
  			hash = (hint->inode->i_sb->s_blocksize << 3);
  		else {
  			oid = le32_to_cpu(INODE_PKEY(hint->inode)->k_objectid);
  			bm = bmap_hash_id(hint->inode->i_sb, oid);
  			hash = bm * (hint->inode->i_sb->s_blocksize << 3);
  		}
  		hint->search_start = hash;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
830
  }
098297b27   Jeff Mahoney   reiserfs: cleanup...
831
832
  /*
   * returns 1 if it finds an indirect item and gets valid hint info
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833
834
   * from it, otherwise 0
   */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
835
  static int get_left_neighbor(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
836
  {
fec6d055d   Josef "Jeff" Sipek   [PATCH] struct pa...
837
  	struct treepath *path;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
838
839
840
841
842
  	struct buffer_head *bh;
  	struct item_head *ih;
  	int pos_in_item;
  	__le32 *item;
  	int ret = 0;
098297b27   Jeff Mahoney   reiserfs: cleanup...
843
844
845
846
847
  	/*
  	 * reiserfs code can call this function w/o pointer to path
  	 * structure supplied; then we rely on supplied search_start
  	 */
  	if (!hint->path)
bd4c625c0   Linus Torvalds   reiserfs: run scr...
848
849
850
851
852
  		return 0;
  
  	path = hint->path;
  	bh = get_last_bh(path);
  	RFALSE(!bh, "green-4002: Illegal path specified to get_left_neighbor");
4cf5f7add   Jeff Mahoney   reiserfs: cleanup...
853
  	ih = tp_item_head(path);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
854
  	pos_in_item = path->pos_in_item;
4cf5f7add   Jeff Mahoney   reiserfs: cleanup...
855
  	item = tp_item_body(path);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
856
857
  
  	hint->search_start = bh->b_blocknr;
098297b27   Jeff Mahoney   reiserfs: cleanup...
858
859
860
861
  	/*
  	 * for indirect item: go to left and look for the first non-hole entry
  	 * in the indirect item
  	 */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
862
  	if (!hint->formatted_node && is_indirect_le_ih(ih)) {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
863
864
  		if (pos_in_item == I_UNFM_NUM(ih))
  			pos_in_item--;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
865
866
867
868
869
870
871
872
873
  		while (pos_in_item >= 0) {
  			int t = get_block_num(item, pos_in_item);
  			if (t) {
  				hint->search_start = t;
  				ret = 1;
  				break;
  			}
  			pos_in_item--;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875

bd4c625c0   Linus Torvalds   reiserfs: run scr...
876
877
  	/* does result value fit into specified region? */
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
878
  }
098297b27   Jeff Mahoney   reiserfs: cleanup...
879
880
881
882
883
884
  /*
   * should be, if formatted node, then try to put on first part of the device
   * specified as number of percent with mount option device, else try to put
   * on last of device.  This is not to say it is good code to do so,
   * but the effect should be measured.
   */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
885
886
  static inline void set_border_in_hint(struct super_block *s,
  				      reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
887
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
888
889
  	b_blocknr_t border =
  	    SB_BLOCK_COUNT(s) / REISERFS_SB(s)->s_alloc_options.border;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
890

bd4c625c0   Linus Torvalds   reiserfs: run scr...
891
892
893
894
  	if (hint->formatted_node)
  		hint->end = border - 1;
  	else
  		hint->beg = border;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
896
  static inline void displace_large_file(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
897
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
898
899
900
901
902
903
904
905
906
907
  	if (TEST_OPTION(displace_based_on_dirid, hint->th->t_super))
  		hint->search_start =
  		    hint->beg +
  		    keyed_hash((char *)(&INODE_PKEY(hint->inode)->k_dir_id),
  			       4) % (hint->end - hint->beg);
  	else
  		hint->search_start =
  		    hint->beg +
  		    keyed_hash((char *)(&INODE_PKEY(hint->inode)->k_objectid),
  			       4) % (hint->end - hint->beg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
909
  static inline void hash_formatted_node(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
910
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
911
  	char *hash_in;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912

bd4c625c0   Linus Torvalds   reiserfs: run scr...
913
914
915
916
917
918
  	if (!hint->inode)
  		hash_in = (char *)&hint->key.k_dir_id;
  	else if (TEST_OPTION(displace_based_on_dirid, hint->th->t_super))
  		hash_in = (char *)(&INODE_PKEY(hint->inode)->k_dir_id);
  	else
  		hash_in = (char *)(&INODE_PKEY(hint->inode)->k_objectid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
919

bd4c625c0   Linus Torvalds   reiserfs: run scr...
920
921
  	hint->search_start =
  	    hint->beg + keyed_hash(hash_in, 4) % (hint->end - hint->beg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
922
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
923
924
925
  static inline int
  this_blocknr_allocation_would_make_it_a_large_file(reiserfs_blocknr_hint_t *
  						   hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
926
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
927
928
  	return hint->block ==
  	    REISERFS_SB(hint->th->t_super)->s_alloc_options.large_file_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929
930
931
  }
  
  #ifdef DISPLACE_NEW_PACKING_LOCALITIES
bd4c625c0   Linus Torvalds   reiserfs: run scr...
932
  static inline void displace_new_packing_locality(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
933
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
934
  	struct in_core_key *key = &hint->key;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
935

bd4c625c0   Linus Torvalds   reiserfs: run scr...
936
937
938
939
  	hint->th->displace_new_blocks = 0;
  	hint->search_start =
  	    hint->beg + keyed_hash((char *)(&key->k_objectid),
  				   4) % (hint->end - hint->beg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
940
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
941
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
942

bd4c625c0   Linus Torvalds   reiserfs: run scr...
943
  static inline int old_hashed_relocation(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
944
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
945
946
  	b_blocknr_t border;
  	u32 hash_in;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947

bd4c625c0   Linus Torvalds   reiserfs: run scr...
948
949
950
  	if (hint->formatted_node || hint->inode == NULL) {
  		return 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
951

bd4c625c0   Linus Torvalds   reiserfs: run scr...
952
953
954
955
956
957
  	hash_in = le32_to_cpu((INODE_PKEY(hint->inode))->k_dir_id);
  	border =
  	    hint->beg + (u32) keyed_hash(((char *)(&hash_in)),
  					 4) % (hint->end - hint->beg - 1);
  	if (border > hint->search_start)
  		hint->search_start = border;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
958

bd4c625c0   Linus Torvalds   reiserfs: run scr...
959
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
961
  static inline int old_way(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
962
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
963
964
965
966
967
968
969
970
971
972
973
974
  	b_blocknr_t border;
  
  	if (hint->formatted_node || hint->inode == NULL) {
  		return 0;
  	}
  
  	border =
  	    hint->beg +
  	    le32_to_cpu(INODE_PKEY(hint->inode)->k_dir_id) % (hint->end -
  							      hint->beg);
  	if (border > hint->search_start)
  		hint->search_start = border;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
975

bd4c625c0   Linus Torvalds   reiserfs: run scr...
976
977
978
979
980
981
982
983
984
985
986
987
988
989
  	return 1;
  }
  
  static inline void hundredth_slices(reiserfs_blocknr_hint_t * hint)
  {
  	struct in_core_key *key = &hint->key;
  	b_blocknr_t slice_start;
  
  	slice_start =
  	    (keyed_hash((char *)(&key->k_dir_id), 4) % 100) * (hint->end / 100);
  	if (slice_start > hint->search_start
  	    || slice_start + (hint->end / 100) <= hint->search_start) {
  		hint->search_start = slice_start;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
990
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
991
992
993
  
  static void determine_search_start(reiserfs_blocknr_hint_t * hint,
  				   int amount_needed)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
994
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
995
996
  	struct super_block *s = hint->th->t_super;
  	int unfm_hint;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
997

bd4c625c0   Linus Torvalds   reiserfs: run scr...
998
999
  	hint->beg = 0;
  	hint->end = SB_BLOCK_COUNT(s) - 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1000

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1001
1002
1003
  	/* This is former border algorithm. Now with tunable border offset */
  	if (concentrating_formatted_nodes(s))
  		set_border_in_hint(s, hint);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1004
1005
  
  #ifdef DISPLACE_NEW_PACKING_LOCALITIES
098297b27   Jeff Mahoney   reiserfs: cleanup...
1006
1007
1008
1009
1010
  	/*
  	 * whenever we create a new directory, we displace it.  At first
  	 * we will hash for location, later we might look for a moderately
  	 * empty place for it
  	 */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1011
1012
1013
  	if (displacing_new_packing_localities(s)
  	    && hint->th->displace_new_blocks) {
  		displace_new_packing_locality(hint);
098297b27   Jeff Mahoney   reiserfs: cleanup...
1014
1015
1016
1017
  		/*
  		 * we do not continue determine_search_start,
  		 * if new packing locality is being displaced
  		 */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1018
1019
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1020
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1021

098297b27   Jeff Mahoney   reiserfs: cleanup...
1022
1023
1024
1025
  	/*
  	 * all persons should feel encouraged to add more special cases
  	 * here and test them
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1026

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1027
1028
1029
1030
1031
  	if (displacing_large_files(s) && !hint->formatted_node
  	    && this_blocknr_allocation_would_make_it_a_large_file(hint)) {
  		displace_large_file(hint);
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1032

098297b27   Jeff Mahoney   reiserfs: cleanup...
1033
1034
1035
1036
  	/*
  	 * if none of our special cases is relevant, use the left
  	 * neighbor in the tree order of the new node we are allocating for
  	 */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1037
1038
1039
1040
  	if (hint->formatted_node && TEST_OPTION(hashed_formatted_nodes, s)) {
  		hash_formatted_node(hint);
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1041

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1042
  	unfm_hint = get_left_neighbor(hint);
098297b27   Jeff Mahoney   reiserfs: cleanup...
1043
1044
1045
1046
1047
1048
1049
  	/*
  	 * Mimic old block allocator behaviour, that is if VFS allowed for
  	 * preallocation, new blocks are displaced based on directory ID.
  	 * Also, if suggested search_start is less than last preallocated
  	 * block, we start searching from it, assuming that HDD dataflow
  	 * is faster in forward direction
  	 */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
  	if (TEST_OPTION(old_way, s)) {
  		if (!hint->formatted_node) {
  			if (!reiserfs_hashed_relocation(s))
  				old_way(hint);
  			else if (!reiserfs_no_unhashed_relocation(s))
  				old_hashed_relocation(hint);
  
  			if (hint->inode
  			    && hint->search_start <
  			    REISERFS_I(hint->inode)->i_prealloc_block)
  				hint->search_start =
  				    REISERFS_I(hint->inode)->i_prealloc_block;
  		}
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1064
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1065

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1066
1067
1068
1069
1070
1071
  	/* This is an approach proposed by Hans */
  	if (TEST_OPTION(hundredth_slices, s)
  	    && !(displacing_large_files(s) && !hint->formatted_node)) {
  		hundredth_slices(hint);
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1072

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1073
1074
1075
1076
1077
  	/* old_hashed_relocation only works on unformatted */
  	if (!unfm_hint && !hint->formatted_node &&
  	    TEST_OPTION(old_hashed_relocation, s)) {
  		old_hashed_relocation(hint);
  	}
098297b27   Jeff Mahoney   reiserfs: cleanup...
1078

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1079
1080
1081
1082
1083
  	/* new_hashed_relocation works with both formatted/unformatted nodes */
  	if ((!unfm_hint || hint->formatted_node) &&
  	    TEST_OPTION(new_hashed_relocation, s)) {
  		new_hashed_relocation(hint);
  	}
098297b27   Jeff Mahoney   reiserfs: cleanup...
1084

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1085
1086
1087
1088
  	/* dirid grouping works only on unformatted nodes */
  	if (!unfm_hint && !hint->formatted_node && TEST_OPTION(dirid_groups, s)) {
  		dirid_groups(hint);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1089
  #ifdef DISPLACE_NEW_PACKING_LOCALITIES
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1090
1091
1092
  	if (hint->formatted_node && TEST_OPTION(dirid_groups, s)) {
  		dirid_groups(hint);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1093
  #endif
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1094
1095
1096
1097
1098
  	/* oid grouping works only on unformatted nodes */
  	if (!unfm_hint && !hint->formatted_node && TEST_OPTION(oid_groups, s)) {
  		oid_groups(hint);
  	}
  	return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1099
1100
1101
1102
  }
  
  static int determine_prealloc_size(reiserfs_blocknr_hint_t * hint)
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1103
1104
1105
1106
1107
1108
1109
  	/* make minimum size a mount option and benchmark both ways */
  	/* we preallocate blocks only for regular files, specific size */
  	/* benchmark preallocating always and see what happens */
  
  	hint->prealloc_size = 0;
  
  	if (!hint->formatted_node && hint->preallocate) {
54930dfeb   Jeff Mahoney   reiserfs: don't p...
1110
  		if (S_ISREG(hint->inode->i_mode) && !IS_PRIVATE(hint->inode)
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1111
1112
1113
1114
1115
1116
1117
1118
  		    && hint->inode->i_size >=
  		    REISERFS_SB(hint->th->t_super)->s_alloc_options.
  		    preallocmin * hint->inode->i_sb->s_blocksize)
  			hint->prealloc_size =
  			    REISERFS_SB(hint->th->t_super)->s_alloc_options.
  			    preallocsize - 1;
  	}
  	return CARRY_ON;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1119
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1120
1121
1122
1123
1124
1125
  static inline int 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)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1126
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
  	int rest = amount_needed;
  	int nr_allocated;
  
  	while (rest > 0 && start <= finish) {
  		nr_allocated = scan_bitmap(hint->th, &start, finish, min,
  					   rest + prealloc_size,
  					   !hint->formatted_node, hint->block);
  
  		if (nr_allocated == 0)	/* no new blocks allocated, return */
  			break;
  
  		/* fill free_blocknrs array first */
  		while (rest > 0 && nr_allocated > 0) {
  			*new_blocknrs++ = start++;
  			rest--;
  			nr_allocated--;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1144

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1145
1146
  		/* do we have something to fill prealloc. array also ? */
  		if (nr_allocated > 0) {
098297b27   Jeff Mahoney   reiserfs: cleanup...
1147
1148
1149
1150
  			/*
  			 * it means prealloc_size was greater that 0 and
  			 * we do preallocation
  			 */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1151
1152
1153
1154
1155
1156
1157
1158
  			list_add(&REISERFS_I(hint->inode)->i_prealloc_list,
  				 &SB_JOURNAL(hint->th->t_super)->
  				 j_prealloc_list);
  			REISERFS_I(hint->inode)->i_prealloc_block = start;
  			REISERFS_I(hint->inode)->i_prealloc_count =
  			    nr_allocated;
  			break;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1159
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1160

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1161
  	return (amount_needed - rest);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1162
1163
1164
  }
  
  static inline int blocknrs_and_prealloc_arrays_from_search_start
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1165
1166
1167
1168
1169
1170
1171
      (reiserfs_blocknr_hint_t * hint, b_blocknr_t * new_blocknrs,
       int amount_needed) {
  	struct super_block *s = hint->th->t_super;
  	b_blocknr_t start = hint->search_start;
  	b_blocknr_t finish = SB_BLOCK_COUNT(s) - 1;
  	int passno = 0;
  	int nr_allocated = 0;
d2d0395fd   Jeff Mahoney   reiserfs: locking...
1172
  	int depth;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1173
1174
1175
1176
  
  	determine_prealloc_size(hint);
  	if (!hint->formatted_node) {
  		int quota_ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1177
  #ifdef REISERQUOTA_DEBUG
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1178
1179
1180
  		reiserfs_debug(s, REISERFS_DEBUG_CODE,
  			       "reiserquota: allocating %d blocks id=%u",
  			       amount_needed, hint->inode->i_uid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1181
  #endif
d2d0395fd   Jeff Mahoney   reiserfs: locking...
1182
  		depth = reiserfs_write_unlock_nested(s);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1183
  		quota_ret =
5dd4056db   Christoph Hellwig   dquot: cleanup sp...
1184
  		    dquot_alloc_block_nodirty(hint->inode, amount_needed);
d2d0395fd   Jeff Mahoney   reiserfs: locking...
1185
1186
  		if (quota_ret) {	/* Quota exceeded? */
  			reiserfs_write_lock_nested(s, depth);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1187
  			return QUOTA_EXCEEDED;
d2d0395fd   Jeff Mahoney   reiserfs: locking...
1188
  		}
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1189
  		if (hint->preallocate && hint->prealloc_size) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1190
  #ifdef REISERQUOTA_DEBUG
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1191
1192
1193
  			reiserfs_debug(s, REISERFS_DEBUG_CODE,
  				       "reiserquota: allocating (prealloc) %d blocks id=%u",
  				       hint->prealloc_size, hint->inode->i_uid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1194
  #endif
5dd4056db   Christoph Hellwig   dquot: cleanup sp...
1195
  			quota_ret = dquot_prealloc_block_nodirty(hint->inode,
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1196
1197
1198
1199
1200
  							 hint->prealloc_size);
  			if (quota_ret)
  				hint->preallocate = hint->prealloc_size = 0;
  		}
  		/* for unformatted nodes, force large allocations */
d2d0395fd   Jeff Mahoney   reiserfs: locking...
1201
  		reiserfs_write_lock_nested(s, depth);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1202
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1203

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1204
  	do {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
  		switch (passno++) {
  		case 0:	/* Search from hint->search_start to end of disk */
  			start = hint->search_start;
  			finish = SB_BLOCK_COUNT(s) - 1;
  			break;
  		case 1:	/* Search from hint->beg to hint->search_start */
  			start = hint->beg;
  			finish = hint->search_start;
  			break;
  		case 2:	/* Last chance: Search from 0 to hint->beg */
  			start = 0;
  			finish = hint->beg;
  			break;
098297b27   Jeff Mahoney   reiserfs: cleanup...
1218
1219
  		default:
  			/* We've tried searching everywhere, not enough space */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1220
1221
  			/* Free the blocks */
  			if (!hint->formatted_node) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1222
  #ifdef REISERQUOTA_DEBUG
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1223
1224
1225
1226
1227
1228
  				reiserfs_debug(s, REISERFS_DEBUG_CODE,
  					       "reiserquota: freeing (nospace) %d blocks id=%u",
  					       amount_needed +
  					       hint->prealloc_size -
  					       nr_allocated,
  					       hint->inode->i_uid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1229
  #endif
77db4f25b   Jan Kara   reiserfs: Use low...
1230
  				/* Free not allocated blocks */
d2d0395fd   Jeff Mahoney   reiserfs: locking...
1231
  				depth = reiserfs_write_unlock_nested(s);
5dd4056db   Christoph Hellwig   dquot: cleanup sp...
1232
  				dquot_free_block_nodirty(hint->inode,
77db4f25b   Jan Kara   reiserfs: Use low...
1233
1234
  					amount_needed + hint->prealloc_size -
  					nr_allocated);
d2d0395fd   Jeff Mahoney   reiserfs: locking...
1235
  				reiserfs_write_lock_nested(s, depth);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
  			}
  			while (nr_allocated--)
  				reiserfs_free_block(hint->th, hint->inode,
  						    new_blocknrs[nr_allocated],
  						    !hint->formatted_node);
  
  			return NO_DISK_SPACE;
  		}
  	} while ((nr_allocated += allocate_without_wrapping_disk(hint,
  								 new_blocknrs +
  								 nr_allocated,
  								 start, finish,
9ea0f9499   Jeff Mahoney   [PATCH] reiserfs:...
1248
  								 1,
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1249
1250
1251
1252
1253
1254
1255
1256
1257
  								 amount_needed -
  								 nr_allocated,
  								 hint->
  								 prealloc_size))
  		 < amount_needed);
  	if (!hint->formatted_node &&
  	    amount_needed + hint->prealloc_size >
  	    nr_allocated + REISERFS_I(hint->inode)->i_prealloc_count) {
  		/* Some of preallocation blocks were not allocated */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1258
  #ifdef REISERQUOTA_DEBUG
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1259
1260
1261
1262
1263
1264
  		reiserfs_debug(s, REISERFS_DEBUG_CODE,
  			       "reiserquota: freeing (failed prealloc) %d blocks id=%u",
  			       amount_needed + hint->prealloc_size -
  			       nr_allocated -
  			       REISERFS_I(hint->inode)->i_prealloc_count,
  			       hint->inode->i_uid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1265
  #endif
d2d0395fd   Jeff Mahoney   reiserfs: locking...
1266
1267
  
  		depth = reiserfs_write_unlock_nested(s);
5dd4056db   Christoph Hellwig   dquot: cleanup sp...
1268
  		dquot_free_block_nodirty(hint->inode, amount_needed +
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1269
1270
1271
  					 hint->prealloc_size - nr_allocated -
  					 REISERFS_I(hint->inode)->
  					 i_prealloc_count);
d2d0395fd   Jeff Mahoney   reiserfs: locking...
1272
  		reiserfs_write_lock_nested(s, depth);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1273
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1274

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1275
  	return CARRY_ON;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1276
1277
1278
1279
  }
  
  /* grab new blocknrs from preallocated list */
  /* return amount still needed after using them */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1280
1281
1282
  static int use_preallocated_list_if_available(reiserfs_blocknr_hint_t * hint,
  					      b_blocknr_t * new_blocknrs,
  					      int amount_needed)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1283
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1284
  	struct inode *inode = hint->inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1285

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1286
1287
  	if (REISERFS_I(inode)->i_prealloc_count > 0) {
  		while (amount_needed) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1288

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1289
1290
  			*new_blocknrs++ = REISERFS_I(inode)->i_prealloc_block++;
  			REISERFS_I(inode)->i_prealloc_count--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1291

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1292
  			amount_needed--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1293

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1294
1295
1296
1297
1298
  			if (REISERFS_I(inode)->i_prealloc_count <= 0) {
  				list_del(&REISERFS_I(inode)->i_prealloc_list);
  				break;
  			}
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1299
  	}
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1300
1301
  	/* return amount still needed after using preallocated blocks */
  	return amount_needed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1302
  }
098297b27   Jeff Mahoney   reiserfs: cleanup...
1303
1304
1305
1306
1307
  int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *hint,
  			       b_blocknr_t *new_blocknrs,
  			       int amount_needed,
  			       /* Amount of blocks we have already reserved */
  			       int reserved_by_us)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1308
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
  	int initial_amount_needed = amount_needed;
  	int ret;
  	struct super_block *s = hint->th->t_super;
  
  	/* Check if there is enough space, taking into account reserved space */
  	if (SB_FREE_BLOCKS(s) - REISERFS_SB(s)->reserved_blocks <
  	    amount_needed - reserved_by_us)
  		return NO_DISK_SPACE;
  	/* should this be if !hint->inode &&  hint->preallocate? */
  	/* do you mean hint->formatted_node can be removed ? - Zam */
098297b27   Jeff Mahoney   reiserfs: cleanup...
1319
1320
1321
1322
1323
  	/*
  	 * hint->formatted_node cannot be removed because we try to access
  	 * inode information here, and there is often no inode associated with
  	 * metadata allocations - green
  	 */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1324
1325
1326
1327
  
  	if (!hint->formatted_node && hint->preallocate) {
  		amount_needed = use_preallocated_list_if_available
  		    (hint, new_blocknrs, amount_needed);
098297b27   Jeff Mahoney   reiserfs: cleanup...
1328
1329
1330
1331
1332
1333
  
  		/*
  		 * We have all the block numbers we need from the
  		 * prealloc list
  		 */
  		if (amount_needed == 0)
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
  			return CARRY_ON;
  		new_blocknrs += (initial_amount_needed - amount_needed);
  	}
  
  	/* find search start and save it in hint structure */
  	determine_search_start(hint, amount_needed);
  	if (hint->search_start >= SB_BLOCK_COUNT(s))
  		hint->search_start = SB_BLOCK_COUNT(s) - 1;
  
  	/* allocation itself; fill new_blocknrs and preallocation arrays */
  	ret = blocknrs_and_prealloc_arrays_from_search_start
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1345
  	    (hint, new_blocknrs, amount_needed);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1346

098297b27   Jeff Mahoney   reiserfs: cleanup...
1347
1348
1349
1350
1351
1352
  	/*
  	 * We used prealloc. list to fill (partially) new_blocknrs array.
  	 * If final allocation fails we need to return blocks back to
  	 * prealloc. list or just free them. -- Zam (I chose second
  	 * variant)
  	 */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1353
1354
1355
1356
1357
  	if (ret != CARRY_ON) {
  		while (amount_needed++ < initial_amount_needed) {
  			reiserfs_free_block(hint->th, hint->inode,
  					    *(--new_blocknrs), 1);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1358
  	}
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1359
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1360
  }
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1361
1362
1363
1364
1365
  void reiserfs_cache_bitmap_metadata(struct super_block *sb,
                                      struct buffer_head *bh,
                                      struct reiserfs_bitmap_info *info)
  {
  	unsigned long *cur = (unsigned long *)(bh->b_data + bh->b_size);
4d20851d3   Jeff Mahoney   reiserfs: remove ...
1366
  	/* The first bit must ALWAYS be 1 */
0030b6457   Jeff Mahoney   reiserfs: use rei...
1367
1368
1369
  	if (!reiserfs_test_le_bit(0, (unsigned long *)bh->b_data))
  		reiserfs_error(sb, "reiserfs-2025", "bitmap block %lu is "
  			       "corrupted: first bit must be 1", bh->b_blocknr);
4d20851d3   Jeff Mahoney   reiserfs: remove ...
1370
1371
  
  	info->free_count = 0;
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1372
1373
  
  	while (--cur >= (unsigned long *)bh->b_data) {
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1374
  		/* 0 and ~0 are special, we can optimize for them */
4d20851d3   Jeff Mahoney   reiserfs: remove ...
1375
  		if (*cur == 0)
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1376
  			info->free_count += BITS_PER_LONG;
4d20851d3   Jeff Mahoney   reiserfs: remove ...
1377
  		else if (*cur != ~0L)	/* A mix, investigate */
9d6bf5aa1   Akinobu Mita   reiserfs: use hwe...
1378
  			info->free_count += BITS_PER_LONG - hweight_long(*cur);
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1379
  	}
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1380
1381
1382
1383
1384
1385
  }
  
  struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb,
                                                 unsigned int bitmap)
  {
  	b_blocknr_t block = (sb->s_blocksize << 3) * bitmap;
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
1386
  	struct reiserfs_bitmap_info *info = SB_AP_BITMAP(sb) + bitmap;
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1387
  	struct buffer_head *bh;
098297b27   Jeff Mahoney   reiserfs: cleanup...
1388
1389
1390
1391
  	/*
  	 * Way old format filesystems had the bitmaps packed up front.
  	 * I doubt there are any of these left, but just in case...
  	 */
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1392
  	if (unlikely(test_bit(REISERFS_OLD_FORMAT,
a228bf8f0   Jeff Mahoney   reiserfs: cleanup...
1393
  			      &REISERFS_SB(sb)->s_properties)))
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1394
1395
1396
  		block = REISERFS_SB(sb)->s_sbh->b_blocknr + 1 + bitmap;
  	else if (bitmap == 0)
  		block = (REISERFS_DISK_OFFSET_IN_BYTES >> sb->s_blocksize_bits) + 1;
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
1397
1398
  	bh = sb_bread(sb, block);
  	if (bh == NULL)
00079e04f   Eric Eric Sesterhenn   [PATCH] reiserfs:...
1399
  		reiserfs_warning(sb, "sh-2029: %s: bitmap block (#%u) "
fbe5498b3   Harvey Harrison   reiserfs: replace...
1400
  		                 "reading failed", __func__, block);
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
1401
1402
  	else {
  		if (buffer_locked(bh)) {
278f6679f   Jeff Mahoney   reiserfs: locking...
1403
  			int depth;
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
1404
  			PROC_INFO_INC(sb, scan_bitmap.wait);
278f6679f   Jeff Mahoney   reiserfs: locking...
1405
  			depth = reiserfs_write_unlock_nested(sb);
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
1406
  			__wait_on_buffer(bh);
278f6679f   Jeff Mahoney   reiserfs: locking...
1407
  			reiserfs_write_lock_nested(sb, depth);
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
1408
1409
1410
  		}
  		BUG_ON(!buffer_uptodate(bh));
  		BUG_ON(atomic_read(&bh->b_count) == 0);
4d20851d3   Jeff Mahoney   reiserfs: remove ...
1411
  		if (info->free_count == UINT_MAX)
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
1412
1413
  			reiserfs_cache_bitmap_metadata(sb, bh, info);
  	}
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1414
1415
1416
1417
1418
1419
1420
  
  	return bh;
  }
  
  int reiserfs_init_bitmap_cache(struct super_block *sb)
  {
  	struct reiserfs_bitmap_info *bitmap;
cb680c1be   Jeff Mahoney   reiserfs: ignore ...
1421
  	unsigned int bmap_nr = reiserfs_bmap_count(sb);
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1422

cb680c1be   Jeff Mahoney   reiserfs: ignore ...
1423
  	bitmap = vmalloc(sizeof(*bitmap) * bmap_nr);
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1424
1425
  	if (bitmap == NULL)
  		return -ENOMEM;
cb680c1be   Jeff Mahoney   reiserfs: ignore ...
1426
  	memset(bitmap, 0xff, sizeof(*bitmap) * bmap_nr);
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1427

6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1428
1429
1430
1431
  	SB_AP_BITMAP(sb) = bitmap;
  
  	return 0;
  }
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
1432
1433
1434
1435
1436
1437
1438
1439
  
  void reiserfs_free_bitmap_cache(struct super_block *sb)
  {
  	if (SB_AP_BITMAP(sb)) {
  		vfree(SB_AP_BITMAP(sb));
  		SB_AP_BITMAP(sb) = NULL;
  	}
  }