Blame view

fs/reiserfs/bitmap.c 36.9 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
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
41
  #include <linux/reiserfs_fs_sb.h>
  #include <linux/reiserfs_fs_i.h>
  #include <linux/quotaops.h>
  
  #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...
42
43
  	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
44
45
46
      } while(0)
  #define TEST_OPTION(optname, s) \
      test_bit(_ALLOC_ ## optname , &SB_ALLOC_OPTS(s))
bd4c625c0   Linus Torvalds   reiserfs: run scr...
47
  static inline void get_bit_address(struct super_block *s,
3ee166704   Jeff Mahoney   reiserfs: fix usa...
48
49
50
  				   b_blocknr_t block,
  				   unsigned int *bmap_nr,
  				   unsigned int *offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
52
53
  	/* 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:...
54
  	*bmap_nr = block >> (s->s_blocksize_bits + 3);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
55
56
  	/* 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
57
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
58
  int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
  {
3ee166704   Jeff Mahoney   reiserfs: fix usa...
60
  	unsigned int bmap, offset;
cb680c1be   Jeff Mahoney   reiserfs: ignore ...
61
  	unsigned int bmap_count = reiserfs_bmap_count(s);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62

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

e1fabd3cc   Jeff Mahoney   [PATCH] reiserfs:...
70
71
72
73
74
75
76
  	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 ...
77
78
  		if (block >= bmap1 &&
  		    block <= bmap1 + bmap_count) {
0030b6457   Jeff Mahoney   reiserfs: use rei...
79
80
81
  			reiserfs_error(s, "vs-4019", "bitmap block %lu(%u) "
  				       "can't be freed or reused",
  				       block, bmap_count);
e1fabd3cc   Jeff Mahoney   [PATCH] reiserfs:...
82
83
84
85
  			return 0;
  		}
  	} else {
  		if (offset == 0) {
0030b6457   Jeff Mahoney   reiserfs: use rei...
86
87
88
  			reiserfs_error(s, "vs-4020", "bitmap block %lu(%u) "
  				       "can't be freed or reused",
  				       block, bmap_count);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
89
90
  			return 0;
  		}
e1fabd3cc   Jeff Mahoney   [PATCH] reiserfs:...
91
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92

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

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

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

cb680c1be   Jeff Mahoney   reiserfs: ignore ...
144
145
  	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...
146
  	PROC_INFO_INC(s, scan_bitmap.bmap);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
149
150
  /* 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
151

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

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

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

3ad2f3fbb   Daniel Mack   tree-wide: Assort...
169
  		/* search for a first zero bit -- beginning of a window */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
170
  		*beg = reiserfs_find_next_zero_le_bit
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
171
  		    ((unsigned long *)(bh->b_data), boundary, *beg);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
172
173
174
  
  		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:...
175
  			brelse(bh);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
176
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178

bd4c625c0   Linus Torvalds   reiserfs: run scr...
179
180
181
182
183
  		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:...
184
  			    || reiserfs_test_le_bit(end, bh->b_data)) {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
185
186
187
188
189
190
191
192
  				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
193

bd4c625c0   Linus Torvalds   reiserfs: run scr...
194
195
196
197
  		/* 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:...
198
  			reiserfs_prepare_for_journal(s, bh, 1);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
199
200
201
202
  			/* 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:...
203
  				    (i, bh->b_data)) {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
204
205
206
207
208
209
210
211
212
213
  					/* 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...
214
  						reiserfs_clear_le_bit
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
215
216
  						    (i, bh->b_data);
  					reiserfs_restore_prepared_buffer(s, bh);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
217
218
219
220
221
222
  					*beg = org;
  					/* ... and search again in current block from beginning */
  					goto cont;
  				}
  			}
  			bi->free_count -= (end - *beg);
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
223
224
  			journal_mark_dirty(th, s, bh);
  			brelse(bh);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
225
226
227
228
229
230
231
232
233
234
235
  
  			/* 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
236
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
238
239
240
241
242
243
244
245
246
247
248
  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 ...
249
  		bm = hash % reiserfs_bmap_count(s);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
250
251
252
253
  		if (!bm)
  			bm = 1;
  	}
  	/* this can only be true when SB_BMAP_NR = 1 */
cb680c1be   Jeff Mahoney   reiserfs: ignore ...
254
  	if (bm >= reiserfs_bmap_count(s))
bd4c625c0   Linus Torvalds   reiserfs: run scr...
255
256
  		bm = 0;
  	return bm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
258
259
260
261
262
  }
  
  /*
   * hashes the id and then returns > 0 if the block group for the
   * corresponding hash is full
   */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
263
264
  static inline int block_group_used(struct super_block *s, u32 id)
  {
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
265
266
267
268
269
  	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
270
  	 * to make a better decision. This favors long-term performance gain
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
271
272
  	 * 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 ...
273
  	if (info->free_count == UINT_MAX) {
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
274
275
276
277
278
  		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...
279
280
281
  		return 0;
  	}
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
284
285
286
  }
  
  /*
   * the packing is returned in disk byte order
   */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
287
  __le32 reiserfs_choose_packing(struct inode * dir)
3e8962be9   Al Viro   [PATCH] reiserfs ...
288
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
289
290
291
292
293
294
295
296
297
298
299
300
301
302
  	__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
303
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
304

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
306
  /* 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...
307
308
  static int scan_bitmap(struct reiserfs_transaction_handle *th,
  		       b_blocknr_t * start, b_blocknr_t finish,
3ee166704   Jeff Mahoney   reiserfs: fix usa...
309
  		       int min, int max, int unfm, sector_t file_block)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
311
312
313
314
  	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...
315
316
317
  	unsigned int bm, off;
  	unsigned int end_bm, end_off;
  	unsigned int off_max = s->s_blocksize << 3;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
318
319
320
321
322
323
324
325
326
  
  	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 ...
327
  	if (bm > reiserfs_bmap_count(s))
bd4c625c0   Linus Torvalds   reiserfs: run scr...
328
  		return 0;
cb680c1be   Jeff Mahoney   reiserfs: ignore ...
329
330
  	if (end_bm > reiserfs_bmap_count(s))
  		end_bm = reiserfs_bmap_count(s);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
331
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
  
  	/* 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
373
374
  
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
375
376
377
  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
378
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
379
380
  	struct super_block *s = th->t_super;
  	struct reiserfs_super_block *rs;
0b3dc17bc   Jeff Mahoney   [PATCH] reiserfs:...
381
  	struct buffer_head *sbh, *bmbh;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
382
  	struct reiserfs_bitmap_info *apbi;
3ee166704   Jeff Mahoney   reiserfs: fix usa...
383
  	unsigned int nr, offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384

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

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

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

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

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

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

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

bd4c625c0   Linus Torvalds   reiserfs: run scr...
496
497
498
499
  	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
500
  #ifdef CONFIG_REISERFS_CHECK
bd4c625c0   Linus Torvalds   reiserfs: run scr...
501
  		if (!ei->i_prealloc_count) {
0030b6457   Jeff Mahoney   reiserfs: use rei...
502
503
504
  			reiserfs_error(th->t_super, "zam-4001",
  				       "inode is in prealloc list but has "
  				       "no preallocated blocks.");
bd4c625c0   Linus Torvalds   reiserfs: run scr...
505
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
  #endif
bd4c625c0   Linus Torvalds   reiserfs: run scr...
507
508
  		__discard_prealloc(th, ei);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
510
  void reiserfs_init_alloc_options(struct super_block *s)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
512
513
514
  	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
515
516
517
  }
  
  /* block allocator related options are parsed here */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
518
  int reiserfs_parse_alloc_options(struct super_block *s, char *options)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
520
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
  	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
558

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

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

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

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

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

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

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

45b03d5e8   Jeff Mahoney   reiserfs: rework ...
617
618
  		reiserfs_warning(s, "zam-4001", "unknown option - %s",
  				 this_char);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
619
  		return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620
  	}
1d889d995   Jeff Mahoney   reiserfs: make so...
621
622
  	reiserfs_info(s, "allocator options = [%08x]
  ", SB_ALLOC_OPTS(s));
bd4c625c0   Linus Torvalds   reiserfs: run scr...
623
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
625
626
  
  static inline void new_hashed_relocation(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
627
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
628
629
630
631
632
633
634
635
636
637
638
639
640
641
  	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
642

bd4c625c0   Linus Torvalds   reiserfs: run scr...
643
644
  	hint->search_start =
  	    hint->beg + keyed_hash(hash_in, 4) % (hint->end - hint->beg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645
646
647
648
  }
  
  /*
   * Relocation based on dirid, hashing them into a given bitmap block
c78bad11f   Joe Perches   fs/: Spelling fixes
649
   * files. Formatted nodes are unaffected, a separate policy covers them
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
   */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
651
  static void dirid_groups(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
652
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
653
654
655
656
  	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
657
  	if (hint->inode)
bd4c625c0   Linus Torvalds   reiserfs: run scr...
658
659
660
661
662
663
664
665
666
667
668
669
  		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
670
671
672
673
  }
  
  /*
   * Relocation based on oid, hashing them into a given bitmap block
c78bad11f   Joe Perches   fs/: Spelling fixes
674
   * files. Formatted nodes are unaffected, a separate policy covers them
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
   */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
676
  static void oid_groups(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
  	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
697
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
699
700
701
702
  }
  
  /* returns 1 if it finds an indirect item and gets valid hint info
   * from it, otherwise 0
   */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
703
  static int get_left_neighbor(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704
  {
fec6d055d   Josef "Jeff" Sipek   [PATCH] struct pa...
705
  	struct treepath *path;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
706
707
708
709
710
711
712
  	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
713
  				 * structure supplied; then we rely on supplied search_start */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
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
  		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
740
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741

bd4c625c0   Linus Torvalds   reiserfs: run scr...
742
743
  	/* does result value fit into specified region? */
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744
745
746
747
748
749
  }
  
  /* 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...
750
751
  static inline void set_border_in_hint(struct super_block *s,
  				      reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
753
754
  	b_blocknr_t border =
  	    SB_BLOCK_COUNT(s) / REISERFS_SB(s)->s_alloc_options.border;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755

bd4c625c0   Linus Torvalds   reiserfs: run scr...
756
757
758
759
  	if (hint->formatted_node)
  		hint->end = border - 1;
  	else
  		hint->beg = border;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
761
  static inline void displace_large_file(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
763
764
765
766
767
768
769
770
771
772
  	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
773
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
774
  static inline void hash_formatted_node(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
776
  	char *hash_in;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777

bd4c625c0   Linus Torvalds   reiserfs: run scr...
778
779
780
781
782
783
  	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
784

bd4c625c0   Linus Torvalds   reiserfs: run scr...
785
786
  	hint->search_start =
  	    hint->beg + keyed_hash(hash_in, 4) % (hint->end - hint->beg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
787
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
788
789
790
  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
791
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
792
793
  	return hint->block ==
  	    REISERFS_SB(hint->th->t_super)->s_alloc_options.large_file_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
795
796
  }
  
  #ifdef DISPLACE_NEW_PACKING_LOCALITIES
bd4c625c0   Linus Torvalds   reiserfs: run scr...
797
  static inline void displace_new_packing_locality(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
799
  	struct in_core_key *key = &hint->key;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800

bd4c625c0   Linus Torvalds   reiserfs: run scr...
801
802
803
804
  	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
805
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
806
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807

bd4c625c0   Linus Torvalds   reiserfs: run scr...
808
  static inline int old_hashed_relocation(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
810
811
  	b_blocknr_t border;
  	u32 hash_in;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
812

bd4c625c0   Linus Torvalds   reiserfs: run scr...
813
814
815
  	if (hint->formatted_node || hint->inode == NULL) {
  		return 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
816

bd4c625c0   Linus Torvalds   reiserfs: run scr...
817
818
819
820
821
822
  	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
823

bd4c625c0   Linus Torvalds   reiserfs: run scr...
824
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
826
  static inline int old_way(reiserfs_blocknr_hint_t * hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
828
829
830
831
832
833
834
835
836
837
838
839
  	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
840

bd4c625c0   Linus Torvalds   reiserfs: run scr...
841
842
843
844
845
846
847
848
849
850
851
852
853
854
  	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
855
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
856
857
858
  
  static void determine_search_start(reiserfs_blocknr_hint_t * hint,
  				   int amount_needed)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
860
861
  	struct super_block *s = hint->th->t_super;
  	int unfm_hint;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
862

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

bd4c625c0   Linus Torvalds   reiserfs: run scr...
866
867
868
  	/* 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
869
870
  
  #ifdef DISPLACE_NEW_PACKING_LOCALITIES
bd4c625c0   Linus Torvalds   reiserfs: run scr...
871
872
873
874
875
876
877
878
879
880
881
  	/* 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
882
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
883

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

bd4c625c0   Linus Torvalds   reiserfs: run scr...
887
888
889
890
891
  	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
892

bd4c625c0   Linus Torvalds   reiserfs: run scr...
893
894
895
896
897
898
  	/* 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
899

bd4c625c0   Linus Torvalds   reiserfs: run scr...
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
  	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
920
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
921

bd4c625c0   Linus Torvalds   reiserfs: run scr...
922
923
924
925
926
927
  	/* 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
928

bd4c625c0   Linus Torvalds   reiserfs: run scr...
929
930
931
932
933
934
935
936
937
938
939
940
941
942
  	/* 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
943
  #ifdef DISPLACE_NEW_PACKING_LOCALITIES
bd4c625c0   Linus Torvalds   reiserfs: run scr...
944
945
946
  	if (hint->formatted_node && TEST_OPTION(dirid_groups, s)) {
  		dirid_groups(hint);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947
  #endif
bd4c625c0   Linus Torvalds   reiserfs: run scr...
948
949
950
951
952
  	/* 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
953
954
955
956
  }
  
  static int determine_prealloc_size(reiserfs_blocknr_hint_t * hint)
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
  	/* 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
973
974
975
976
  }
  
  /* 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...
977
978
979
980
981
982
  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
983
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
  	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
1001

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
  		/* 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
1013
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1014

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1015
  	return (amount_needed - rest);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1016
1017
1018
  }
  
  static inline int blocknrs_and_prealloc_arrays_from_search_start
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1019
1020
1021
1022
1023
1024
1025
      (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...
1026
1027
1028
1029
  
  	determine_prealloc_size(hint);
  	if (!hint->formatted_node) {
  		int quota_ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1030
  #ifdef REISERQUOTA_DEBUG
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1031
1032
1033
  		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
1034
  #endif
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1035
  		quota_ret =
5dd4056db   Christoph Hellwig   dquot: cleanup sp...
1036
  		    dquot_alloc_block_nodirty(hint->inode, amount_needed);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1037
1038
1039
  		if (quota_ret)	/* Quota exceeded? */
  			return QUOTA_EXCEEDED;
  		if (hint->preallocate && hint->prealloc_size) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1040
  #ifdef REISERQUOTA_DEBUG
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1041
1042
1043
  			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
1044
  #endif
5dd4056db   Christoph Hellwig   dquot: cleanup sp...
1045
  			quota_ret = dquot_prealloc_block_nodirty(hint->inode,
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1046
1047
1048
1049
1050
  							 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
1051
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1052

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1053
  	do {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
  		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
1070
  #ifdef REISERQUOTA_DEBUG
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1071
1072
1073
1074
1075
1076
  				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
1077
  #endif
77db4f25b   Jan Kara   reiserfs: Use low...
1078
  				/* Free not allocated blocks */
5dd4056db   Christoph Hellwig   dquot: cleanup sp...
1079
  				dquot_free_block_nodirty(hint->inode,
77db4f25b   Jan Kara   reiserfs: Use low...
1080
1081
  					amount_needed + hint->prealloc_size -
  					nr_allocated);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
  			}
  			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:...
1094
  								 1,
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1095
1096
1097
1098
1099
1100
1101
1102
1103
  								 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
1104
  #ifdef REISERQUOTA_DEBUG
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1105
1106
1107
1108
1109
1110
  		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
1111
  #endif
5dd4056db   Christoph Hellwig   dquot: cleanup sp...
1112
  		dquot_free_block_nodirty(hint->inode, amount_needed +
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1113
1114
1115
1116
  					 hint->prealloc_size - nr_allocated -
  					 REISERFS_I(hint->inode)->
  					 i_prealloc_count);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1117

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1118
  	return CARRY_ON;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1119
1120
1121
1122
  }
  
  /* grab new blocknrs from preallocated list */
  /* return amount still needed after using them */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1123
1124
1125
  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
1126
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1127
  	struct inode *inode = hint->inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1128

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

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

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

bd4c625c0   Linus Torvalds   reiserfs: run scr...
1137
1138
1139
1140
1141
  			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
1142
  	}
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1143
1144
  	/* return amount still needed after using preallocated blocks */
  	return amount_needed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1145
  }
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1146
1147
  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
1148
  {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
  	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
1179
  	    (hint, new_blocknrs, amount_needed);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
  
  	/* 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
1190
  	}
bd4c625c0   Linus Torvalds   reiserfs: run scr...
1191
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1192
  }
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1193
1194
1195
1196
1197
  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 ...
1198
  	/* The first bit must ALWAYS be 1 */
0030b6457   Jeff Mahoney   reiserfs: use rei...
1199
1200
1201
  	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 ...
1202
1203
  
  	info->free_count = 0;
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1204
1205
  
  	while (--cur >= (unsigned long *)bh->b_data) {
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1206
  		/* 0 and ~0 are special, we can optimize for them */
4d20851d3   Jeff Mahoney   reiserfs: remove ...
1207
  		if (*cur == 0)
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1208
  			info->free_count += BITS_PER_LONG;
4d20851d3   Jeff Mahoney   reiserfs: remove ...
1209
  		else if (*cur != ~0L)	/* A mix, investigate */
9d6bf5aa1   Akinobu Mita   reiserfs: use hwe...
1210
  			info->free_count += BITS_PER_LONG - hweight_long(*cur);
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1211
  	}
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1212
1213
1214
1215
1216
1217
  }
  
  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:...
1218
  	struct reiserfs_bitmap_info *info = SB_AP_BITMAP(sb) + bitmap;
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1219
1220
1221
1222
1223
1224
1225
1226
1227
  	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...
1228
  	reiserfs_write_unlock(sb);
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
1229
  	bh = sb_bread(sb, block);
4c5eface5   Frederic Weisbecker   kill-the-BKL/reis...
1230
  	reiserfs_write_lock(sb);
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
1231
  	if (bh == NULL)
00079e04f   Eric Eric Sesterhenn   [PATCH] reiserfs:...
1232
  		reiserfs_warning(sb, "sh-2029: %s: bitmap block (#%u) "
fbe5498b3   Harvey Harrison   reiserfs: replace...
1233
  		                 "reading failed", __func__, block);
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
1234
1235
1236
  	else {
  		if (buffer_locked(bh)) {
  			PROC_INFO_INC(sb, scan_bitmap.wait);
8ebc42323   Frederic Weisbecker   reiserfs: kill-th...
1237
  			reiserfs_write_unlock(sb);
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
1238
  			__wait_on_buffer(bh);
8ebc42323   Frederic Weisbecker   reiserfs: kill-th...
1239
  			reiserfs_write_lock(sb);
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
1240
1241
1242
  		}
  		BUG_ON(!buffer_uptodate(bh));
  		BUG_ON(atomic_read(&bh->b_count) == 0);
4d20851d3   Jeff Mahoney   reiserfs: remove ...
1243
  		if (info->free_count == UINT_MAX)
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
1244
1245
  			reiserfs_cache_bitmap_metadata(sb, bh, info);
  	}
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1246
1247
1248
1249
1250
1251
1252
  
  	return bh;
  }
  
  int reiserfs_init_bitmap_cache(struct super_block *sb)
  {
  	struct reiserfs_bitmap_info *bitmap;
cb680c1be   Jeff Mahoney   reiserfs: ignore ...
1253
  	unsigned int bmap_nr = reiserfs_bmap_count(sb);
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1254

500f5a0bf   Frederic Weisbecker   reiserfs: Fix pos...
1255
1256
  	/* Avoid lock recursion in fault case */
  	reiserfs_write_unlock(sb);
cb680c1be   Jeff Mahoney   reiserfs: ignore ...
1257
  	bitmap = vmalloc(sizeof(*bitmap) * bmap_nr);
500f5a0bf   Frederic Weisbecker   reiserfs: Fix pos...
1258
  	reiserfs_write_lock(sb);
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1259
1260
  	if (bitmap == NULL)
  		return -ENOMEM;
cb680c1be   Jeff Mahoney   reiserfs: ignore ...
1261
  	memset(bitmap, 0xff, sizeof(*bitmap) * bmap_nr);
6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1262

6f01046b3   Jeff Mahoney   [PATCH] reiserfs:...
1263
1264
1265
1266
  	SB_AP_BITMAP(sb) = bitmap;
  
  	return 0;
  }
5065227b4   Jeff Mahoney   [PATCH] reiserfs:...
1267
1268
1269
1270
1271
1272
1273
1274
  
  void reiserfs_free_bitmap_cache(struct super_block *sb)
  {
  	if (SB_AP_BITMAP(sb)) {
  		vfree(SB_AP_BITMAP(sb));
  		SB_AP_BITMAP(sb) = NULL;
  	}
  }