Blame view

fs/reiserfs/bitmap.c 39.3 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
6
7
8
9
10
  #include <linux/time.h>
  #include <linux/reiserfs_fs.h>
  #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
13
14
  #include <linux/reiserfs_fs_sb.h>
  #include <linux/reiserfs_fs_i.h>
  #include <linux/quotaops.h>
c3aa07764   Jan Kara   reiserfs: Properl...
15
  #include <linux/seq_file.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
41
42
  
  #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...
43
44
  	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
45
46
47
      } while(0)
  #define TEST_OPTION(optname, s) \
      test_bit(_ALLOC_ ## optname , &SB_ALLOC_OPTS(s))
bd4c625c0   Linus Torvalds   reiserfs: run scr...
48
  static inline void get_bit_address(struct super_block *s,
3ee166704   Jeff Mahoney   reiserfs: fix usa...
49
50
51
  				   b_blocknr_t block,
  				   unsigned int *bmap_nr,
  				   unsigned int *offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
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
72
73
74
75
76
77
  	get_bit_address(s, block, &bmap, &offset);
  
  	/* Old format filesystem? Unlikely, but the bitmaps are all up front so
  	 * we need to account for it. */
  	if (unlikely(test_bit(REISERFS_OLD_FORMAT,
  			      &(REISERFS_SB(s)->s_properties)))) {
  		b_blocknr_t bmap1 = REISERFS_SB(s)->s_sbh->b_blocknr + 1;
cb680c1be   Jeff Mahoney   reiserfs: ignore ...
78
79
  		if (block >= bmap1 &&
  		    block <= bmap1 + bmap_count) {
0030b6457   Jeff Mahoney   reiserfs: use rei...
80
81
82
  			reiserfs_error(s, "vs-4019", "bitmap block %lu(%u) "
  				       "can't be freed or reused",
  				       block, bmap_count);
e1fabd3cc   Jeff Mahoney   [PATCH] reiserfs:...
83
84
85
86
  			return 0;
  		}
  	} else {
  		if (offset == 0) {
0030b6457   Jeff Mahoney   reiserfs: use rei...
87
88
89
  			reiserfs_error(s, "vs-4020", "bitmap block %lu(%u) "
  				       "can't be freed or reused",
  				       block, bmap_count);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
90
91
  			return 0;
  		}
e1fabd3cc   Jeff Mahoney   [PATCH] reiserfs:...
92
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93

cb680c1be   Jeff Mahoney   reiserfs: ignore ...
94
  	if (bmap >= bmap_count) {
0030b6457   Jeff Mahoney   reiserfs: use rei...
95
96
97
  		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...
98
99
  		return 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100

bd4c625c0   Linus Torvalds   reiserfs: run scr...
101
  	if (bit_value == 0 && block == SB_ROOT_BLOCK(s)) {
0030b6457   Jeff Mahoney   reiserfs: use rei...
102
103
  		reiserfs_error(s, "vs-4050", "this is root block (%u), "
  			       "it must be busy", SB_ROOT_BLOCK(s));
bd4c625c0   Linus Torvalds   reiserfs: run scr...
104
105
106
107
  		return 0;
  	}
  
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
110
111
  
  /* 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...
112
113
  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
114
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
115
116
117
118
119
120
121
122
123
124
125
126
  	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 {
  			(*next) = off + 1;	/* inc offset to avoid looping. */
  			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
127
  	}
bd4c625c0   Linus Torvalds   reiserfs: run scr...
128
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
130
131
132
  }
  
  /* it searches for a window of zero bits with given minimum and maximum lengths in one bitmap
   * block; */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
133
  static int scan_bitmap_block(struct reiserfs_transaction_handle *th,
3ee166704   Jeff Mahoney   reiserfs: fix usa...
134
135
  			     unsigned int bmap_n, int *beg, int boundary,
  			     int min, int max, int unfm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
137
138
  	struct super_block *s = th->t_super;
  	struct reiserfs_bitmap_info *bi = &SB_AP_BITMAP(s)[bmap_n];
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
139
  	struct buffer_head *bh;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
140
141
  	int end, next;
  	int org = *beg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142

bd4c625c0   Linus Torvalds   reiserfs: run scr...
143
  	BUG_ON(!th->t_trans_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144

cb680c1be   Jeff Mahoney   reiserfs: ignore ...
145
146
  	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...
147
  	PROC_INFO_INC(s, scan_bitmap.bmap);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
149
150
151
  /* this is unclear and lacks comments, explain how journal bitmaps
     work here for the reader.  Convey a sense of the design here. What
     is a window? */
  /* - I mean `a window of zero bits' as in description of this function - Zam. */
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
164
  	while (1) {
  	      cont:
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
165
166
  		if (bi->free_count < min) {
  			brelse(bh);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
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
174
175
  
  		if (*beg + min > boundary) {	/* search for a zero bit fails or the rest of bitmap block
  						 * cannot contain a zero window of minimum size */
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
176
  			brelse(bh);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
177
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179

bd4c625c0   Linus Torvalds   reiserfs: run scr...
180
181
182
183
184
  		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:...
185
  			    || reiserfs_test_le_bit(end, bh->b_data)) {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
186
187
188
189
190
191
192
193
  				next = end;
  				break;
  			}
  			/* finding the other end of zero bit window requires looking into journal structures (in
  			 * case of searching for free blocks for unformatted nodes) */
  			if (unfm && is_block_in_journal(s, bmap_n, end, &next))
  				break;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
307
  /* 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...
308
309
  static int scan_bitmap(struct reiserfs_transaction_handle *th,
  		       b_blocknr_t * start, b_blocknr_t finish,
3ee166704   Jeff Mahoney   reiserfs: fix usa...
310
  		       int min, int max, int unfm, sector_t file_block)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
312
313
314
315
  	int nr_allocated = 0;
  	struct super_block *s = th->t_super;
  	/* find every bm and bmap and bmap_nr in this file, and change them all to bitmap_blocknr
  	 * - Hans, it is not a block number - Zam. */
3ee166704   Jeff Mahoney   reiserfs: fix usa...
316
317
318
  	unsigned int bm, off;
  	unsigned int end_bm, end_off;
  	unsigned int off_max = s->s_blocksize << 3;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
319
320
321
322
323
324
325
326
327
  
  	BUG_ON(!th->t_trans_id);
  
  	PROC_INFO_INC(s, scan_bitmap.call);
  	if (SB_FREE_BLOCKS(s) <= 0)
  		return 0;	// No point in looking for more free blocks
  
  	get_bit_address(s, *start, &bm, &off);
  	get_bit_address(s, finish, &end_bm, &end_off);
cb680c1be   Jeff Mahoney   reiserfs: ignore ...
328
  	if (bm > reiserfs_bmap_count(s))
bd4c625c0   Linus Torvalds   reiserfs: run scr...
329
  		return 0;
cb680c1be   Jeff Mahoney   reiserfs: ignore ...
330
331
  	if (end_bm > reiserfs_bmap_count(s))
  		end_bm = reiserfs_bmap_count(s);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
  
  	/* When the bitmap is more than 10% free, anyone can allocate.
  	 * 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);
  
        ret:
  	*start = bm * off_max + off;
  	return nr_allocated;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
375
  
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
376
377
378
  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
379
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
380
381
  	struct super_block *s = th->t_super;
  	struct reiserfs_super_block *rs;
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
382
  	struct buffer_head *sbh, *bmbh;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
383
  	struct reiserfs_bitmap_info *apbi;
3ee166704   Jeff Mahoney   reiserfs: fix usa...
384
  	unsigned int nr, offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385

bd4c625c0   Linus Torvalds   reiserfs: run scr...
386
  	BUG_ON(!th->t_trans_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387

bd4c625c0   Linus Torvalds   reiserfs: run scr...
388
  	PROC_INFO_INC(s, free_block);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389

bd4c625c0   Linus Torvalds   reiserfs: run scr...
390
391
392
  	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
393

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

cb680c1be   Jeff Mahoney   reiserfs: ignore ...
396
  	if (nr >= reiserfs_bmap_count(s)) {
0030b6457   Jeff Mahoney   reiserfs: use rei...
397
398
  		reiserfs_error(s, "vs-4075", "block %lu is out of range",
  			       block);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
399
400
  		return;
  	}
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
401
402
403
  	bmbh = reiserfs_read_bitmap_block(s, nr);
  	if (!bmbh)
  		return;
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
404
405
  
  	reiserfs_prepare_for_journal(s, bmbh, 1);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
406
407
  
  	/* clear bit for the given block in bit map */
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
408
  	if (!reiserfs_test_and_clear_le_bit(offset, bmbh->b_data)) {
0030b6457   Jeff Mahoney   reiserfs: use rei...
409
410
  		reiserfs_error(s, "vs-4080",
  			       "block %lu: bit already cleared", block);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
411
412
  	}
  	apbi[nr].free_count++;
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
413
414
  	journal_mark_dirty(th, s, bmbh);
  	brelse(bmbh);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
415
416
417
418
419
420
421
  
  	reiserfs_prepare_for_journal(s, sbh, 1);
  	/* update super block */
  	set_sb_free_blocks(rs, sb_free_blocks(rs) + 1);
  
  	journal_mark_dirty(th, s, sbh);
  	if (for_unformatted)
5dd4056db   Christoph Hellwig   dquot: cleanup sp...
422
  		dquot_free_block_nodirty(inode, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
424
425
426
  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
427
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
428
  	struct super_block *s = th->t_super;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
429
  	BUG_ON(!th->t_trans_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430

bd4c625c0   Linus Torvalds   reiserfs: run scr...
431
  	RFALSE(!s, "vs-4061: trying to free block on nonexistent device");
d4c3d19d0   Jeff Mahoney   reiserfs: use is_...
432
433
434
435
  	if (!is_reusable(s, block, 1))
  		return;
  
  	if (block > sb_block_count(REISERFS_SB(s)->s_rs)) {
0030b6457   Jeff Mahoney   reiserfs: use rei...
436
  		reiserfs_error(th->t_super, "bitmap-4072",
d4c3d19d0   Jeff Mahoney   reiserfs: use is_...
437
438
439
440
441
  			       "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...
442
443
444
  	/* 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
445
446
447
  }
  
  /* preallocated blocks don't need to be run through journal_mark_freed */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
448
449
450
  static void reiserfs_free_prealloc_block(struct reiserfs_transaction_handle *th,
  					 struct inode *inode, b_blocknr_t block)
  {
d4c3d19d0   Jeff Mahoney   reiserfs: use is_...
451
  	BUG_ON(!th->t_trans_id);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
452
453
  	RFALSE(!th->t_super,
  	       "vs-4060: trying to free block on nonexistent device");
d4c3d19d0   Jeff Mahoney   reiserfs: use is_...
454
455
  	if (!is_reusable(th->t_super, block, 1))
  		return;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
456
  	_reiserfs_free_block(th, inode, block, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
458
459
  static void __discard_prealloc(struct reiserfs_transaction_handle *th,
  			       struct reiserfs_inode_info *ei)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
461
462
463
464
  	unsigned long save = ei->i_prealloc_block;
  	int dirty = 0;
  	struct inode *inode = &ei->vfs_inode;
  	BUG_ON(!th->t_trans_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
  #ifdef CONFIG_REISERFS_CHECK
bd4c625c0   Linus Torvalds   reiserfs: run scr...
466
  	if (ei->i_prealloc_count < 0)
0030b6457   Jeff Mahoney   reiserfs: use rei...
467
468
  		reiserfs_error(th->t_super, "zam-4001",
  			       "inode has negative prealloc blocks count.");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
  #endif
bd4c625c0   Linus Torvalds   reiserfs: run scr...
470
471
472
473
474
475
476
477
478
479
  	while (ei->i_prealloc_count > 0) {
  		reiserfs_free_prealloc_block(th, inode, ei->i_prealloc_block);
  		ei->i_prealloc_block++;
  		ei->i_prealloc_count--;
  		dirty = 1;
  	}
  	if (dirty)
  		reiserfs_update_sd(th, inode);
  	ei->i_prealloc_block = save;
  	list_del_init(&(ei->i_prealloc_list));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
481
482
  }
  
  /* FIXME: It should be inline function */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
483
484
  void reiserfs_discard_prealloc(struct reiserfs_transaction_handle *th,
  			       struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
486
487
488
489
  	struct reiserfs_inode_info *ei = REISERFS_I(inode);
  	BUG_ON(!th->t_trans_id);
  	if (ei->i_prealloc_count)
  		__discard_prealloc(th, ei);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
491
  void reiserfs_discard_all_prealloc(struct reiserfs_transaction_handle *th)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
493
  	struct list_head *plist = &SB_JOURNAL(th->t_super)->j_prealloc_list;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494

bd4c625c0   Linus Torvalds   reiserfs: run scr...
495
  	BUG_ON(!th->t_trans_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496

bd4c625c0   Linus Torvalds   reiserfs: run scr...
497
498
499
500
  	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
501
  #ifdef CONFIG_REISERFS_CHECK
bd4c625c0   Linus Torvalds   reiserfs: run scr...
502
  		if (!ei->i_prealloc_count) {
0030b6457   Jeff Mahoney   reiserfs: use rei...
503
504
505
  			reiserfs_error(th->t_super, "zam-4001",
  				       "inode is in prealloc list but has "
  				       "no preallocated blocks.");
bd4c625c0   Linus Torvalds   reiserfs: run scr...
506
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
  #endif
bd4c625c0   Linus Torvalds   reiserfs: run scr...
508
509
  		__discard_prealloc(th, ei);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
511
  void reiserfs_init_alloc_options(struct super_block *s)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
513
514
515
  	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
516
517
518
  }
  
  /* block allocator related options are parsed here */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
519
  int reiserfs_parse_alloc_options(struct super_block *s, char *options)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
  	char *this_char, *value;
  
  	REISERFS_SB(s)->s_alloc_options.bits = 0;	/* clear default settings */
  
  	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;
  		};
  
  		if (!strcmp(this_char, "old_hashed_relocation")) {
  			SET_OPTION(old_hashed_relocation);
  			continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559

bd4c625c0   Linus Torvalds   reiserfs: run scr...
560
561
562
563
  		if (!strcmp(this_char, "new_hashed_relocation")) {
  			SET_OPTION(new_hashed_relocation);
  			continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564

bd4c625c0   Linus Torvalds   reiserfs: run scr...
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
  		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
581

bd4c625c0   Linus Torvalds   reiserfs: run scr...
582
583
584
585
  		if (!strcmp(this_char, "skip_busy")) {
  			SET_OPTION(skip_busy);
  			continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586

bd4c625c0   Linus Torvalds   reiserfs: run scr...
587
588
589
590
  		if (!strcmp(this_char, "hundredth_slices")) {
  			SET_OPTION(hundredth_slices);
  			continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591

bd4c625c0   Linus Torvalds   reiserfs: run scr...
592
593
594
595
  		if (!strcmp(this_char, "old_way")) {
  			SET_OPTION(old_way);
  			continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
596

bd4c625c0   Linus Torvalds   reiserfs: run scr...
597
598
599
600
  		if (!strcmp(this_char, "displace_based_on_dirid")) {
  			SET_OPTION(displace_based_on_dirid);
  			continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601

bd4c625c0   Linus Torvalds   reiserfs: run scr...
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
  		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
617

45b03d5e8   Jeff Mahoney   reiserfs: rework ...
618
619
  		reiserfs_warning(s, "zam-4001", "unknown option - %s",
  				 this_char);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
620
  		return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
  	}
1d889d995   Jeff Mahoney   reiserfs: make so...
622
623
  	reiserfs_info(s, "allocator options = [%08x]
  ", SB_ALLOC_OPTS(s));
bd4c625c0   Linus Torvalds   reiserfs: run scr...
624
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
626

c3aa07764   Jan Kara   reiserfs: Properl...
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
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
  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...
716
  static inline void new_hashed_relocation(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
717
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
718
719
720
721
722
723
724
725
726
727
728
729
730
731
  	char *hash_in;
  	if (hint->formatted_node) {
  		hash_in = (char *)&hint->key.k_dir_id;
  	} else {
  		if (!hint->inode) {
  			//hint->search_start = hint->beg;
  			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
732

bd4c625c0   Linus Torvalds   reiserfs: run scr...
733
734
  	hint->search_start =
  	    hint->beg + keyed_hash(hash_in, 4) % (hint->end - hint->beg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
735
736
737
738
  }
  
  /*
   * Relocation based on dirid, hashing them into a given bitmap block
c78bad11f   Joe Perches   fs/: Spelling fixes
739
   * files. Formatted nodes are unaffected, a separate policy covers them
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
   */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
741
  static void dirid_groups(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
743
744
745
746
  	unsigned long hash;
  	__u32 dirid = 0;
  	int bm = 0;
  	struct super_block *sb = hint->th->t_super;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
  	if (hint->inode)
bd4c625c0   Linus Torvalds   reiserfs: run scr...
748
749
750
751
752
753
754
755
756
757
758
759
  		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
760
761
762
763
  }
  
  /*
   * Relocation based on oid, hashing them into a given bitmap block
c78bad11f   Joe Perches   fs/: Spelling fixes
764
   * files. Formatted nodes are unaffected, a separate policy covers them
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
   */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
766
  static void oid_groups(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
  	if (hint->inode) {
  		unsigned long hash;
  		__u32 oid;
  		__u32 dirid;
  		int bm;
  
  		dirid = le32_to_cpu(INODE_PKEY(hint->inode)->k_dir_id);
  
  		/* keep the root dir and it's first set of subdirs close to
  		 * 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
787
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788
789
790
791
792
  }
  
  /* returns 1 if it finds an indirect item and gets valid hint info
   * from it, otherwise 0
   */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
793
  static int get_left_neighbor(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
  {
fec6d055d   Josef "Jeff" Sipek   [PATCH] struct pa...
795
  	struct treepath *path;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
796
797
798
799
800
801
802
  	struct buffer_head *bh;
  	struct item_head *ih;
  	int pos_in_item;
  	__le32 *item;
  	int ret = 0;
  
  	if (!hint->path)	/* reiserfs code can call this function w/o pointer to path
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
803
  				 * structure supplied; then we rely on supplied search_start */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
  		return 0;
  
  	path = hint->path;
  	bh = get_last_bh(path);
  	RFALSE(!bh, "green-4002: Illegal path specified to get_left_neighbor");
  	ih = get_ih(path);
  	pos_in_item = path->pos_in_item;
  	item = get_item(path);
  
  	hint->search_start = bh->b_blocknr;
  
  	if (!hint->formatted_node && is_indirect_le_ih(ih)) {
  		/* for indirect item: go to left and look for the first non-hole entry
  		   in the indirect item */
  		if (pos_in_item == I_UNFM_NUM(ih))
  			pos_in_item--;
  //          pos_in_item = I_UNFM_NUM (ih) - 1;
  		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
830
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831

bd4c625c0   Linus Torvalds   reiserfs: run scr...
832
833
  	/* does result value fit into specified region? */
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
834
835
836
837
838
839
  }
  
  /* 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...
840
841
  static inline void set_border_in_hint(struct super_block *s,
  				      reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
842
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
843
844
  	b_blocknr_t border =
  	    SB_BLOCK_COUNT(s) / REISERFS_SB(s)->s_alloc_options.border;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845

bd4c625c0   Linus Torvalds   reiserfs: run scr...
846
847
848
849
  	if (hint->formatted_node)
  		hint->end = border - 1;
  	else
  		hint->beg = border;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
850
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
851
  static inline void displace_large_file(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
853
854
855
856
857
858
859
860
861
862
  	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
863
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
864
  static inline void hash_formatted_node(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
865
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
866
  	char *hash_in;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867

bd4c625c0   Linus Torvalds   reiserfs: run scr...
868
869
870
871
872
873
  	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
874

bd4c625c0   Linus Torvalds   reiserfs: run scr...
875
876
  	hint->search_start =
  	    hint->beg + keyed_hash(hash_in, 4) % (hint->end - hint->beg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
877
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
878
879
880
  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
881
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
882
883
  	return hint->block ==
  	    REISERFS_SB(hint->th->t_super)->s_alloc_options.large_file_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
884
885
886
  }
  
  #ifdef DISPLACE_NEW_PACKING_LOCALITIES
bd4c625c0   Linus Torvalds   reiserfs: run scr...
887
  static inline void displace_new_packing_locality(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
889
  	struct in_core_key *key = &hint->key;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
890

bd4c625c0   Linus Torvalds   reiserfs: run scr...
891
892
893
894
  	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
895
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
896
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
897

bd4c625c0   Linus Torvalds   reiserfs: run scr...
898
  static inline int old_hashed_relocation(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
899
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
900
901
  	b_blocknr_t border;
  	u32 hash_in;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
902

bd4c625c0   Linus Torvalds   reiserfs: run scr...
903
904
905
  	if (hint->formatted_node || hint->inode == NULL) {
  		return 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906

bd4c625c0   Linus Torvalds   reiserfs: run scr...
907
908
909
910
911
912
  	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
913

bd4c625c0   Linus Torvalds   reiserfs: run scr...
914
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
915
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
916
  static inline int old_way(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
918
919
920
921
922
923
924
925
926
927
928
929
  	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
930

bd4c625c0   Linus Torvalds   reiserfs: run scr...
931
932
933
934
935
936
937
938
939
940
941
942
943
944
  	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
945
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
946
947
948
  
  static void determine_search_start(reiserfs_blocknr_hint_t * hint,
  				   int amount_needed)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
949
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
950
951
  	struct super_block *s = hint->th->t_super;
  	int unfm_hint;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952

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

bd4c625c0   Linus Torvalds   reiserfs: run scr...
956
957
958
  	/* 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
959
960
  
  #ifdef DISPLACE_NEW_PACKING_LOCALITIES
bd4c625c0   Linus Torvalds   reiserfs: run scr...
961
962
963
964
965
966
967
968
969
970
971
  	/* 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 */
  	if (displacing_new_packing_localities(s)
  	    && hint->th->displace_new_blocks) {
  		displace_new_packing_locality(hint);
  
  		/* we do not continue determine_search_start,
  		 * if new packing locality is being displaced */
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
972
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
973

bd4c625c0   Linus Torvalds   reiserfs: run scr...
974
975
  	/* all persons should feel encouraged to add more special cases here and
  	 * test them */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
976

bd4c625c0   Linus Torvalds   reiserfs: run scr...
977
978
979
980
981
  	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
982

bd4c625c0   Linus Torvalds   reiserfs: run scr...
983
984
985
986
987
988
  	/* if none of our special cases is relevant, use the left neighbor in the
  	   tree order of the new node we are allocating for */
  	if (hint->formatted_node && TEST_OPTION(hashed_formatted_nodes, s)) {
  		hash_formatted_node(hint);
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
989

bd4c625c0   Linus Torvalds   reiserfs: run scr...
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
  	unfm_hint = get_left_neighbor(hint);
  
  	/* 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 */
  	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
1010
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1011

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1012
1013
1014
1015
1016
1017
  	/* 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
1018

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
  	/* old_hashed_relocation only works on unformatted */
  	if (!unfm_hint && !hint->formatted_node &&
  	    TEST_OPTION(old_hashed_relocation, s)) {
  		old_hashed_relocation(hint);
  	}
  	/* 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);
  	}
  	/* 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
1033
  #ifdef DISPLACE_NEW_PACKING_LOCALITIES
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1034
1035
1036
  	if (hint->formatted_node && TEST_OPTION(dirid_groups, s)) {
  		dirid_groups(hint);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1037
  #endif
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1038
1039
1040
1041
1042
  	/* 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
1043
1044
1045
1046
  }
  
  static int determine_prealloc_size(reiserfs_blocknr_hint_t * hint)
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
  	/* 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) {
  		if (S_ISREG(hint->inode->i_mode)
  		    && 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
1063
1064
1065
1066
  }
  
  /* XXX I know it could be merged with upper-level function;
     but may be result function would be too complex. */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1067
1068
1069
1070
1071
1072
  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
1073
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
  	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
1091

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
  		/* do we have something to fill prealloc. array also ? */
  		if (nr_allocated > 0) {
  			/* it means prealloc_size was greater that 0 and we do preallocation */
  			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
1103
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1104

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1105
  	return (amount_needed - rest);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1106
1107
1108
  }
  
  static inline int blocknrs_and_prealloc_arrays_from_search_start
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1109
1110
1111
1112
1113
1114
1115
      (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;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1116
1117
1118
1119
  
  	determine_prealloc_size(hint);
  	if (!hint->formatted_node) {
  		int quota_ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1120
  #ifdef REISERQUOTA_DEBUG
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1121
1122
1123
  		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
1124
  #endif
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1125
  		quota_ret =
5dd4056db   Christoph Hellwig   dquot: cleanup sp...
1126
  		    dquot_alloc_block_nodirty(hint->inode, amount_needed);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1127
1128
1129
  		if (quota_ret)	/* Quota exceeded? */
  			return QUOTA_EXCEEDED;
  		if (hint->preallocate && hint->prealloc_size) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1130
  #ifdef REISERQUOTA_DEBUG
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1131
1132
1133
  			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
1134
  #endif
5dd4056db   Christoph Hellwig   dquot: cleanup sp...
1135
  			quota_ret = dquot_prealloc_block_nodirty(hint->inode,
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1136
1137
1138
1139
1140
  							 hint->prealloc_size);
  			if (quota_ret)
  				hint->preallocate = hint->prealloc_size = 0;
  		}
  		/* for unformatted nodes, force large allocations */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1141
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1142

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1143
  	do {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
  		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;
  		default:	/* We've tried searching everywhere, not enough space */
  			/* Free the blocks */
  			if (!hint->formatted_node) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1160
  #ifdef REISERQUOTA_DEBUG
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1161
1162
1163
1164
1165
1166
  				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
1167
  #endif
77db4f25b   Jan Kara   reiserfs: Use low...
1168
  				/* Free not allocated blocks */
5dd4056db   Christoph Hellwig   dquot: cleanup sp...
1169
  				dquot_free_block_nodirty(hint->inode,
77db4f25b   Jan Kara   reiserfs: Use low...
1170
1171
  					amount_needed + hint->prealloc_size -
  					nr_allocated);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
  			}
  			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:...
1184
  								 1,
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1185
1186
1187
1188
1189
1190
1191
1192
1193
  								 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
1194
  #ifdef REISERQUOTA_DEBUG
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1195
1196
1197
1198
1199
1200
  		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
1201
  #endif
5dd4056db   Christoph Hellwig   dquot: cleanup sp...
1202
  		dquot_free_block_nodirty(hint->inode, amount_needed +
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1203
1204
1205
1206
  					 hint->prealloc_size - nr_allocated -
  					 REISERFS_I(hint->inode)->
  					 i_prealloc_count);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1207

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1208
  	return CARRY_ON;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1209
1210
1211
1212
  }
  
  /* grab new blocknrs from preallocated list */
  /* return amount still needed after using them */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1213
1214
1215
  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
1216
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1217
  	struct inode *inode = hint->inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1218

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

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

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

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1227
1228
1229
1230
1231
  			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
1232
  	}
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1233
1234
  	/* return amount still needed after using preallocated blocks */
  	return amount_needed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1235
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1236
1237
  int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t * hint, b_blocknr_t * new_blocknrs, int amount_needed, int reserved_by_us	/* Amount of blocks we have
  																	   already reserved */ )
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1238
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
  	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 */
  	/* hint->formatted_node cannot be removed because we try to access
  	   inode information here, and there is often no inode assotiated with
  	   metadata allocations - green */
  
  	if (!hint->formatted_node && hint->preallocate) {
  		amount_needed = use_preallocated_list_if_available
  		    (hint, new_blocknrs, amount_needed);
  		if (amount_needed == 0)	/* all blocknrs we need we got from
  					   prealloc. list */
  			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
1269
  	    (hint, new_blocknrs, amount_needed);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
  
  	/* 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) */
  
  	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
1280
  	}
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1281
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1282
  }
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1283
1284
1285
1286
1287
  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 ...
1288
  	/* The first bit must ALWAYS be 1 */
0030b6457   Jeff Mahoney   reiserfs: use rei...
1289
1290
1291
  	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 ...
1292
1293
  
  	info->free_count = 0;
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1294
1295
  
  	while (--cur >= (unsigned long *)bh->b_data) {
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1296
  		/* 0 and ~0 are special, we can optimize for them */
4d20851d3   Jeff Mahoney   reiserfs: remove ...
1297
  		if (*cur == 0)
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1298
  			info->free_count += BITS_PER_LONG;
4d20851d3   Jeff Mahoney   reiserfs: remove ...
1299
  		else if (*cur != ~0L)	/* A mix, investigate */
9d6bf5aa1   Akinobu Mita   reiserfs: use hwe...
1300
  			info->free_count += BITS_PER_LONG - hweight_long(*cur);
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1301
  	}
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1302
1303
1304
1305
1306
1307
  }
  
  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:...
1308
  	struct reiserfs_bitmap_info *info = SB_AP_BITMAP(sb) + bitmap;
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1309
1310
1311
1312
1313
1314
1315
1316
1317
  	struct buffer_head *bh;
  
  	/* Way old format filesystems had the bitmaps packed up front.
  	 * I doubt there are any of these left, but just in case... */
  	if (unlikely(test_bit(REISERFS_OLD_FORMAT,
  	                      &(REISERFS_SB(sb)->s_properties))))
  		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;
4c5eface5   Frederic Weisbecker   kill-the-BKL/reis...
1318
  	reiserfs_write_unlock(sb);
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
1319
  	bh = sb_bread(sb, block);
4c5eface5   Frederic Weisbecker   kill-the-BKL/reis...
1320
  	reiserfs_write_lock(sb);
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
1321
  	if (bh == NULL)
00079e04f   Eric Eric Sesterhenn   [PATCH] reiserfs:...
1322
  		reiserfs_warning(sb, "sh-2029: %s: bitmap block (#%u) "
fbe5498b3   Harvey Harrison   reiserfs: replace...
1323
  		                 "reading failed", __func__, block);
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
1324
1325
1326
  	else {
  		if (buffer_locked(bh)) {
  			PROC_INFO_INC(sb, scan_bitmap.wait);
8ebc42323   Frederic Weisbecker   reiserfs: kill-th...
1327
  			reiserfs_write_unlock(sb);
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
1328
  			__wait_on_buffer(bh);
8ebc42323   Frederic Weisbecker   reiserfs: kill-th...
1329
  			reiserfs_write_lock(sb);
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
1330
1331
1332
  		}
  		BUG_ON(!buffer_uptodate(bh));
  		BUG_ON(atomic_read(&bh->b_count) == 0);
4d20851d3   Jeff Mahoney   reiserfs: remove ...
1333
  		if (info->free_count == UINT_MAX)
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
1334
1335
  			reiserfs_cache_bitmap_metadata(sb, bh, info);
  	}
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1336
1337
1338
1339
1340
1341
1342
  
  	return bh;
  }
  
  int reiserfs_init_bitmap_cache(struct super_block *sb)
  {
  	struct reiserfs_bitmap_info *bitmap;
cb680c1be   Jeff Mahoney   reiserfs: ignore ...
1343
  	unsigned int bmap_nr = reiserfs_bmap_count(sb);
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1344

cb680c1be   Jeff Mahoney   reiserfs: ignore ...
1345
  	bitmap = vmalloc(sizeof(*bitmap) * bmap_nr);
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1346
1347
  	if (bitmap == NULL)
  		return -ENOMEM;
cb680c1be   Jeff Mahoney   reiserfs: ignore ...
1348
  	memset(bitmap, 0xff, sizeof(*bitmap) * bmap_nr);
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1349

6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1350
1351
1352
1353
  	SB_AP_BITMAP(sb) = bitmap;
  
  	return 0;
  }
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
1354
1355
1356
1357
1358
1359
1360
1361
  
  void reiserfs_free_bitmap_cache(struct super_block *sb)
  {
  	if (SB_AP_BITMAP(sb)) {
  		vfree(SB_AP_BITMAP(sb));
  		SB_AP_BITMAP(sb) = NULL;
  	}
  }