Import 2.3.26pre2
[davej-history.git] / fs / hfs / bitmap.c
blob4fcec675fe5cad3f5690037875e7d42c055026cb
1 /*
2 * linux/fs/hfs/bitmap.c
4 * Copyright (C) 1996-1997 Paul H. Hargrove
5 * This file may be distributed under the terms of the GNU Public License.
7 * Based on GPLed code Copyright (C) 1995 Michael Dreher
9 * This file contains the code to modify the volume bitmap:
10 * search/set/clear bits.
12 * "XXX" in a comment is a note to myself to consider changing something.
14 * In function preconditions the term "valid" applied to a pointer to
15 * a structure means that the pointer is non-NULL and the structure it
16 * points to has all fields initialized to consistent values.
19 #include "hfs.h"
21 /*================ Global functions ================*/
24 * hfs_vbm_count_free()
26 * Description:
27 * Count the number of consecutive cleared bits in the bitmap blocks of
28 * the hfs MDB starting at bit number 'start'. 'mdb' had better
29 * be locked or the indicated number of blocks may be no longer free,
30 * when this functions returns!
31 * Input Variable(s):
32 * struct hfs_mdb *mdb: Pointer to the hfs MDB
33 * hfs_u16 start: bit number to start at
34 * Output Variable(s):
35 * NONE
36 * Returns:
37 * The number of consecutive cleared bits starting at bit 'start'
38 * Preconditions:
39 * 'mdb' points to a "valid" (struct hfs_mdb).
40 * Postconditions:
41 * NONE
43 hfs_u16 hfs_vbm_count_free(const struct hfs_mdb *mdb, hfs_u16 start)
45 hfs_u16 block_nr; /* index of the current bitmap block */
46 hfs_u16 bit_nr; /* index of the current bit in block */
47 hfs_u16 count; /* number of bits found so far */
48 hfs_u16 len; /* number of bits found in this block */
49 hfs_u16 max_block; /* index of last bitmap block */
50 hfs_u16 max_bits; /* index of last bit in block */
52 /* is this a valid HFS MDB? */
53 if (!mdb) {
54 return 0;
57 block_nr = start / HFS_BM_BPB;
58 bit_nr = start % HFS_BM_BPB;
59 max_block = (mdb->fs_ablocks + HFS_BM_BPB - 1) / HFS_BM_BPB - 1;
61 count = 0;
62 while (block_nr <= max_block) {
63 if (block_nr != max_block) {
64 max_bits = HFS_BM_BPB;
65 } else {
66 max_bits = mdb->fs_ablocks % HFS_BM_BPB;
69 len=hfs_count_zero_bits(hfs_buffer_data(mdb->bitmap[block_nr]),
70 max_bits, bit_nr);
71 count += len;
73 /* see if we fell short of the end of this block */
74 if ((len + bit_nr) < max_bits) {
75 break;
78 ++block_nr;
79 bit_nr = 0;
81 return count;
85 * hfs_vbm_search_free()
87 * Description:
88 * Search for 'num_bits' consecutive cleared bits in the bitmap blocks of
89 * the hfs MDB. 'mdb' had better be locked or the returned range
90 * may be no longer free, when this functions returns!
91 * XXX Currently the search starts from bit 0, but it should start with
92 * the bit number stored in 's_alloc_ptr' of the MDB.
93 * Input Variable(s):
94 * struct hfs_mdb *mdb: Pointer to the hfs MDB
95 * hfs_u16 *num_bits: Pointer to the number of cleared bits
96 * to search for
97 * Output Variable(s):
98 * hfs_u16 *num_bits: The number of consecutive clear bits of the
99 * returned range. If the bitmap is fragmented, this will be less than
100 * requested and it will be zero, when the disk is full.
101 * Returns:
102 * The number of the first bit of the range of cleared bits which has been
103 * found. When 'num_bits' is zero, this is invalid!
104 * Preconditions:
105 * 'mdb' points to a "valid" (struct hfs_mdb).
106 * 'num_bits' points to a variable of type (hfs_u16), which contains
107 * the number of cleared bits to find.
108 * Postconditions:
109 * 'num_bits' is set to the length of the found sequence.
111 hfs_u16 hfs_vbm_search_free(const struct hfs_mdb *mdb, hfs_u16 *num_bits)
113 hfs_u16 block_nr; /* index of the current bitmap block */
115 /* position and length of current portion of a run */
116 hfs_u16 cur_pos, cur_len;
118 /* position and length of current complete run */
119 hfs_u16 pos=0, len=0;
121 /* position and length of longest complete run */
122 hfs_u16 longest_pos=0, longest_len=0;
124 void *bitmap; /* contents of the current bitmap block */
125 hfs_u16 max_block; /* upper limit of outer loop */
126 hfs_u16 max_bits; /* upper limit of inner loop */
128 /* is this a valid HFS MDB? */
129 if (!mdb) {
130 *num_bits = 0;
131 hfs_warn("hfs_vbm_search_free: not a valid MDB\n");
132 return 0;
135 /* make sure we have actual work to perform */
136 if (!(*num_bits)) {
137 return 0;
140 max_block = (mdb->fs_ablocks+HFS_BM_BPB-1) / HFS_BM_BPB - 1;
142 /* search all bitmap blocks */
143 for (block_nr = 0; block_nr <= max_block; block_nr++) {
144 bitmap = hfs_buffer_data(mdb->bitmap[block_nr]);
146 if (block_nr != max_block) {
147 max_bits = HFS_BM_BPB;
148 } else {
149 max_bits = mdb->fs_ablocks % HFS_BM_BPB;
152 cur_pos = 0;
153 do {
154 cur_len = hfs_count_zero_bits(bitmap, max_bits,
155 cur_pos);
156 len += cur_len;
157 if (len > longest_len) {
158 longest_pos = pos;
159 longest_len = len;
160 if (len >= *num_bits) {
161 goto search_end;
164 if ((cur_pos + cur_len) == max_bits) {
165 break; /* zeros may continue into next block */
168 /* find start of next run of zeros */
169 cur_pos = hfs_find_zero_bit(bitmap, max_bits,
170 cur_pos + cur_len);
171 pos = cur_pos + HFS_BM_BPB*block_nr;
172 len = 0;
173 } while (cur_pos < max_bits);
176 search_end:
177 *num_bits = longest_len;
178 return longest_pos;
183 * hfs_set_vbm_bits()
185 * Description:
186 * Set the requested bits in the volume bitmap of the hfs filesystem
187 * Input Variable(s):
188 * struct hfs_mdb *mdb: Pointer to the hfs MDB
189 * hfs_u16 start: The offset of the first bit
190 * hfs_u16 count: The number of bits
191 * Output Variable(s):
192 * None
193 * Returns:
194 * 0: no error
195 * -1: One of the bits was already set. This is a strange
196 * error and when it happens, the filesystem must be repaired!
197 * -2: One or more of the bits are out of range of the bitmap.
198 * -3: The 's_magic' field of the MDB does not match
199 * Preconditions:
200 * 'mdb' points to a "valid" (struct hfs_mdb).
201 * Postconditions:
202 * Starting with bit number 'start', 'count' bits in the volume bitmap
203 * are set. The affected bitmap blocks are marked "dirty", the free
204 * block count of the MDB is updated and the MDB is marked dirty.
206 int hfs_set_vbm_bits(struct hfs_mdb *mdb, hfs_u16 start, hfs_u16 count)
208 hfs_u16 block_nr; /* index of the current bitmap block */
209 hfs_u16 u32_nr; /* index of the current hfs_u32 in block */
210 hfs_u16 bit_nr; /* index of the current bit in hfs_u32 */
211 hfs_u16 left = count; /* number of bits left to be set */
212 hfs_u32 *bitmap; /* the current bitmap block's contents */
214 /* is this a valid HFS MDB? */
215 if (!mdb) {
216 return -3;
219 /* is there any actual work to be done? */
220 if (!count) {
221 return 0;
224 /* are all of the bits in range? */
225 if ((start + count) > mdb->fs_ablocks) {
226 return -2;
229 block_nr = start / HFS_BM_BPB;
230 u32_nr = (start % HFS_BM_BPB) / 32;
231 bit_nr = start % 32;
233 /* bitmap is always on a 32-bit boundary */
234 bitmap = (hfs_u32 *)hfs_buffer_data(mdb->bitmap[block_nr]);
236 /* do any partial hfs_u32 at the start */
237 if (bit_nr != 0) {
238 while ((bit_nr < 32) && left) {
239 if (hfs_set_bit(bit_nr, bitmap + u32_nr)) {
240 hfs_buffer_dirty(mdb->bitmap[block_nr]);
241 return -1;
243 ++bit_nr;
244 --left;
246 bit_nr=0;
248 /* advance u32_nr and check for end of this block */
249 if (++u32_nr > 127) {
250 u32_nr = 0;
251 hfs_buffer_dirty(mdb->bitmap[block_nr]);
252 ++block_nr;
253 /* bitmap is always on a 32-bit boundary */
254 bitmap = (hfs_u32 *)
255 hfs_buffer_data(mdb->bitmap[block_nr]);
259 /* do full hfs_u32s */
260 while (left > 31) {
261 if (bitmap[u32_nr] != ((hfs_u32)0)) {
262 hfs_buffer_dirty(mdb->bitmap[block_nr]);
263 return -1;
265 bitmap[u32_nr] = ~((hfs_u32)0);
266 left -= 32;
268 /* advance u32_nr and check for end of this block */
269 if (++u32_nr > 127) {
270 u32_nr = 0;
271 hfs_buffer_dirty(mdb->bitmap[block_nr]);
272 ++block_nr;
273 /* bitmap is always on a 32-bit boundary */
274 bitmap = (hfs_u32 *)
275 hfs_buffer_data(mdb->bitmap[block_nr]);
280 /* do any partial hfs_u32 at end */
281 while (left) {
282 if (hfs_set_bit(bit_nr, bitmap + u32_nr)) {
283 hfs_buffer_dirty(mdb->bitmap[block_nr]);
284 return -1;
286 ++bit_nr;
287 --left;
290 hfs_buffer_dirty(mdb->bitmap[block_nr]);
291 mdb->free_ablocks -= count;
293 /* successful completion */
294 hfs_mdb_dirty(mdb->sys_mdb);
295 return 0;
299 * hfs_clear_vbm_bits()
301 * Description:
302 * Clear the requested bits in the volume bitmap of the hfs filesystem
303 * Input Variable(s):
304 * struct hfs_mdb *mdb: Pointer to the hfs MDB
305 * hfs_u16 start: The offset of the first bit
306 * hfs_u16 count: The number of bits
307 * Output Variable(s):
308 * None
309 * Returns:
310 * 0: no error
311 * -1: One of the bits was already clear. This is a strange
312 * error and when it happens, the filesystem must be repaired!
313 * -2: One or more of the bits are out of range of the bitmap.
314 * -3: The 's_magic' field of the MDB does not match
315 * Preconditions:
316 * 'mdb' points to a "valid" (struct hfs_mdb).
317 * Postconditions:
318 * Starting with bit number 'start', 'count' bits in the volume bitmap
319 * are cleared. The affected bitmap blocks are marked "dirty", the free
320 * block count of the MDB is updated and the MDB is marked dirty.
322 int hfs_clear_vbm_bits(struct hfs_mdb *mdb, hfs_u16 start, hfs_u16 count)
324 hfs_u16 block_nr; /* index of the current bitmap block */
325 hfs_u16 u32_nr; /* index of the current hfs_u32 in block */
326 hfs_u16 bit_nr; /* index of the current bit in hfs_u32 */
327 hfs_u16 left = count; /* number of bits left to be set */
328 hfs_u32 *bitmap; /* the current bitmap block's contents */
330 /* is this a valid HFS MDB? */
331 if (!mdb) {
332 return -3;
335 /* is there any actual work to be done? */
336 if (!count) {
337 return 0;
340 /* are all of the bits in range? */
341 if ((start + count) > mdb->fs_ablocks) {
342 return -2;
345 block_nr = start / HFS_BM_BPB;
346 u32_nr = (start % HFS_BM_BPB) / 32;
347 bit_nr = start % 32;
349 /* bitmap is always on a 32-bit boundary */
350 bitmap = (hfs_u32 *)hfs_buffer_data(mdb->bitmap[block_nr]);
352 /* do any partial hfs_u32 at the start */
353 if (bit_nr != 0) {
354 while ((bit_nr < 32) && left) {
355 if (!hfs_clear_bit(bit_nr, bitmap + u32_nr)) {
356 hfs_buffer_dirty(mdb->bitmap[block_nr]);
357 return -1;
359 ++bit_nr;
360 --left;
362 bit_nr=0;
364 /* advance u32_nr and check for end of this block */
365 if (++u32_nr > 127) {
366 u32_nr = 0;
367 hfs_buffer_dirty(mdb->bitmap[block_nr]);
368 ++block_nr;
369 /* bitmap is always on a 32-bit boundary */
370 bitmap = (hfs_u32 *)
371 hfs_buffer_data(mdb->bitmap[block_nr]);
375 /* do full hfs_u32s */
376 while (left > 31) {
377 if (bitmap[u32_nr] != ~((hfs_u32)0)) {
378 hfs_buffer_dirty(mdb->bitmap[block_nr]);
379 return -1;
381 bitmap[u32_nr] = ((hfs_u32)0);
382 left -= 32;
384 /* advance u32_nr and check for end of this block */
385 if (++u32_nr > 127) {
386 u32_nr = 0;
387 hfs_buffer_dirty(mdb->bitmap[block_nr]);
388 ++block_nr;
389 /* bitmap is always on a 32-bit boundary */
390 bitmap = (hfs_u32 *)
391 hfs_buffer_data(mdb->bitmap[block_nr]);
396 /* do any partial hfs_u32 at end */
397 while (left) {
398 if (!hfs_clear_bit(bit_nr, bitmap + u32_nr)) {
399 hfs_buffer_dirty(mdb->bitmap[block_nr]);
400 return -1;
402 ++bit_nr;
403 --left;
406 hfs_buffer_dirty(mdb->bitmap[block_nr]);
407 mdb->free_ablocks += count;
409 /* successful completion */
410 hfs_mdb_dirty(mdb->sys_mdb);
411 return 0;