blob: 995472de92a0633db29a6e4b55155e2cbc03960f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/fs/hpfs/alloc.c
3 *
4 * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999
5 *
6 * HPFS bitmap operations
7 */
8
9#include "hpfs_fn.h"
10
Linus Torvalds1da177e2005-04-16 15:20:36 -070011/*
12 * Check if a sector is allocated in bitmap
13 * This is really slow. Turned on only if chk==2
14 */
15
16static int chk_if_allocated(struct super_block *s, secno sec, char *msg)
17{
18 struct quad_buffer_head qbh;
19 unsigned *bmp;
20 if (!(bmp = hpfs_map_bitmap(s, sec >> 14, &qbh, "chk"))) goto fail;
21 if ((bmp[(sec & 0x3fff) >> 5] >> (sec & 0x1f)) & 1) {
22 hpfs_error(s, "sector '%s' - %08x not allocated in bitmap", msg, sec);
23 goto fail1;
24 }
25 hpfs_brelse4(&qbh);
26 if (sec >= hpfs_sb(s)->sb_dirband_start && sec < hpfs_sb(s)->sb_dirband_start + hpfs_sb(s)->sb_dirband_size) {
27 unsigned ssec = (sec - hpfs_sb(s)->sb_dirband_start) / 4;
28 if (!(bmp = hpfs_map_dnode_bitmap(s, &qbh))) goto fail;
29 if ((bmp[ssec >> 5] >> (ssec & 0x1f)) & 1) {
30 hpfs_error(s, "sector '%s' - %08x not allocated in directory bitmap", msg, sec);
31 goto fail1;
32 }
33 hpfs_brelse4(&qbh);
34 }
35 return 0;
36 fail1:
37 hpfs_brelse4(&qbh);
38 fail:
39 return 1;
40}
41
42/*
43 * Check if sector(s) have proper number and additionally check if they're
44 * allocated in bitmap.
45 */
46
47int hpfs_chk_sectors(struct super_block *s, secno start, int len, char *msg)
48{
49 if (start + len < start || start < 0x12 ||
50 start + len > hpfs_sb(s)->sb_fs_size) {
51 hpfs_error(s, "sector(s) '%s' badly placed at %08x", msg, start);
52 return 1;
53 }
54 if (hpfs_sb(s)->sb_chk>=2) {
55 int i;
56 for (i = 0; i < len; i++)
57 if (chk_if_allocated(s, start + i, msg)) return 1;
58 }
59 return 0;
60}
61
62static secno alloc_in_bmp(struct super_block *s, secno near, unsigned n, unsigned forward)
63{
64 struct quad_buffer_head qbh;
65 unsigned *bmp;
66 unsigned bs = near & ~0x3fff;
67 unsigned nr = (near & 0x3fff) & ~(n - 1);
68 /*unsigned mnr;*/
69 unsigned i, q;
70 int a, b;
71 secno ret = 0;
72 if (n != 1 && n != 4) {
73 hpfs_error(s, "Bad allocation size: %d", n);
74 return 0;
75 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 if (bs != ~0x3fff) {
77 if (!(bmp = hpfs_map_bitmap(s, near >> 14, &qbh, "aib"))) goto uls;
78 } else {
79 if (!(bmp = hpfs_map_dnode_bitmap(s, &qbh))) goto uls;
80 }
81 if (!tstbits(bmp, nr, n + forward)) {
82 ret = bs + nr;
83 goto rt;
84 }
85 /*if (!tstbits(bmp, nr + n, n + forward)) {
86 ret = bs + nr + n;
87 goto rt;
88 }*/
89 q = nr + n; b = 0;
90 while ((a = tstbits(bmp, q, n + forward)) != 0) {
91 q += a;
92 if (n != 1) q = ((q-1)&~(n-1))+n;
93 if (!b) {
94 if (q>>5 != nr>>5) {
95 b = 1;
96 q = nr & 0x1f;
97 }
98 } else if (q > nr) break;
99 }
100 if (!a) {
101 ret = bs + q;
102 goto rt;
103 }
104 nr >>= 5;
105 /*for (i = nr + 1; i != nr; i++, i &= 0x1ff) {*/
106 i = nr;
107 do {
108 if (!bmp[i]) goto cont;
109 if (n + forward >= 0x3f && bmp[i] != -1) goto cont;
110 q = i<<5;
111 if (i > 0) {
112 unsigned k = bmp[i-1];
113 while (k & 0x80000000) {
114 q--; k <<= 1;
115 }
116 }
117 if (n != 1) q = ((q-1)&~(n-1))+n;
118 while ((a = tstbits(bmp, q, n + forward)) != 0) {
119 q += a;
120 if (n != 1) q = ((q-1)&~(n-1))+n;
121 if (q>>5 > i) break;
122 }
123 if (!a) {
124 ret = bs + q;
125 goto rt;
126 }
127 cont:
128 i++, i &= 0x1ff;
129 } while (i != nr);
130 rt:
131 if (ret) {
132 if (hpfs_sb(s)->sb_chk && ((ret >> 14) != (bs >> 14) || (bmp[(ret & 0x3fff) >> 5] | ~(((1 << n) - 1) << (ret & 0x1f))) != 0xffffffff)) {
133 hpfs_error(s, "Allocation doesn't work! Wanted %d, allocated at %08x", n, ret);
134 ret = 0;
135 goto b;
136 }
137 bmp[(ret & 0x3fff) >> 5] &= ~(((1 << n) - 1) << (ret & 0x1f));
138 hpfs_mark_4buffers_dirty(&qbh);
139 }
140 b:
141 hpfs_brelse4(&qbh);
142 uls:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 return ret;
144}
145
146/*
147 * Allocation strategy: 1) search place near the sector specified
148 * 2) search bitmap where free sectors last found
149 * 3) search all bitmaps
150 * 4) search all bitmaps ignoring number of pre-allocated
151 * sectors
152 */
153
Mikulas Patocka7d23ce32011-05-08 20:43:06 +0200154secno hpfs_alloc_sector(struct super_block *s, secno near, unsigned n, int forward)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155{
156 secno sec;
157 int i;
158 unsigned n_bmps;
159 struct hpfs_sb_info *sbi = hpfs_sb(s);
160 int f_p = 0;
161 int near_bmp;
162 if (forward < 0) {
163 forward = -forward;
164 f_p = 1;
165 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 n_bmps = (sbi->sb_fs_size + 0x4000 - 1) >> 14;
167 if (near && near < sbi->sb_fs_size) {
168 if ((sec = alloc_in_bmp(s, near, n, f_p ? forward : forward/4))) goto ret;
169 near_bmp = near >> 14;
170 } else near_bmp = n_bmps / 2;
171 /*
172 if (b != -1) {
173 if ((sec = alloc_in_bmp(s, b<<14, n, f_p ? forward : forward/2))) {
174 b &= 0x0fffffff;
175 goto ret;
176 }
177 if (b > 0x10000000) if ((sec = alloc_in_bmp(s, (b&0xfffffff)<<14, n, f_p ? forward : 0))) goto ret;
178 */
179 if (!f_p) if (forward > sbi->sb_max_fwd_alloc) forward = sbi->sb_max_fwd_alloc;
180 less_fwd:
181 for (i = 0; i < n_bmps; i++) {
182 if (near_bmp+i < n_bmps && ((sec = alloc_in_bmp(s, (near_bmp+i) << 14, n, forward)))) {
183 sbi->sb_c_bitmap = near_bmp+i;
184 goto ret;
185 }
186 if (!forward) {
187 if (near_bmp-i-1 >= 0 && ((sec = alloc_in_bmp(s, (near_bmp-i-1) << 14, n, forward)))) {
188 sbi->sb_c_bitmap = near_bmp-i-1;
189 goto ret;
190 }
191 } else {
192 if (near_bmp+i >= n_bmps && ((sec = alloc_in_bmp(s, (near_bmp+i-n_bmps) << 14, n, forward)))) {
193 sbi->sb_c_bitmap = near_bmp+i-n_bmps;
194 goto ret;
195 }
196 }
197 if (i == 1 && sbi->sb_c_bitmap != -1 && ((sec = alloc_in_bmp(s, (sbi->sb_c_bitmap) << 14, n, forward)))) {
198 goto ret;
199 }
200 }
201 if (!f_p) {
202 if (forward) {
203 sbi->sb_max_fwd_alloc = forward * 3 / 4;
204 forward /= 2;
205 goto less_fwd;
206 }
207 }
208 sec = 0;
209 ret:
210 if (sec && f_p) {
211 for (i = 0; i < forward; i++) {
Mikulas Patocka7d23ce32011-05-08 20:43:06 +0200212 if (!hpfs_alloc_if_possible(s, sec + i + 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 hpfs_error(s, "Prealloc doesn't work! Wanted %d, allocated at %08x, can't allocate %d", forward, sec, i);
214 sec = 0;
215 break;
216 }
217 }
218 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 return sec;
220}
221
Mikulas Patocka7d23ce32011-05-08 20:43:06 +0200222static secno alloc_in_dirband(struct super_block *s, secno near)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223{
224 unsigned nr = near;
225 secno sec;
226 struct hpfs_sb_info *sbi = hpfs_sb(s);
227 if (nr < sbi->sb_dirband_start)
228 nr = sbi->sb_dirband_start;
229 if (nr >= sbi->sb_dirband_start + sbi->sb_dirband_size)
230 nr = sbi->sb_dirband_start + sbi->sb_dirband_size - 4;
231 nr -= sbi->sb_dirband_start;
232 nr >>= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 sec = alloc_in_bmp(s, (~0x3fff) | nr, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 if (!sec) return 0;
235 return ((sec & 0x3fff) << 2) + sbi->sb_dirband_start;
236}
237
238/* Alloc sector if it's free */
239
Mikulas Patocka7d23ce32011-05-08 20:43:06 +0200240int hpfs_alloc_if_possible(struct super_block *s, secno sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241{
242 struct quad_buffer_head qbh;
243 unsigned *bmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 if (!(bmp = hpfs_map_bitmap(s, sec >> 14, &qbh, "aip"))) goto end;
245 if (bmp[(sec & 0x3fff) >> 5] & (1 << (sec & 0x1f))) {
246 bmp[(sec & 0x3fff) >> 5] &= ~(1 << (sec & 0x1f));
247 hpfs_mark_4buffers_dirty(&qbh);
248 hpfs_brelse4(&qbh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 return 1;
250 }
251 hpfs_brelse4(&qbh);
252 end:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 return 0;
254}
255
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256/* Free sectors in bitmaps */
257
258void hpfs_free_sectors(struct super_block *s, secno sec, unsigned n)
259{
260 struct quad_buffer_head qbh;
261 unsigned *bmp;
262 struct hpfs_sb_info *sbi = hpfs_sb(s);
263 /*printk("2 - ");*/
264 if (!n) return;
265 if (sec < 0x12) {
266 hpfs_error(s, "Trying to free reserved sector %08x", sec);
267 return;
268 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 sbi->sb_max_fwd_alloc += n > 0xffff ? 0xffff : n;
270 if (sbi->sb_max_fwd_alloc > 0xffffff) sbi->sb_max_fwd_alloc = 0xffffff;
271 new_map:
272 if (!(bmp = hpfs_map_bitmap(s, sec >> 14, &qbh, "free"))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 return;
274 }
275 new_tst:
276 if ((bmp[(sec & 0x3fff) >> 5] >> (sec & 0x1f) & 1)) {
277 hpfs_error(s, "sector %08x not allocated", sec);
278 hpfs_brelse4(&qbh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 return;
280 }
281 bmp[(sec & 0x3fff) >> 5] |= 1 << (sec & 0x1f);
282 if (!--n) {
283 hpfs_mark_4buffers_dirty(&qbh);
284 hpfs_brelse4(&qbh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 return;
286 }
287 if (!(++sec & 0x3fff)) {
288 hpfs_mark_4buffers_dirty(&qbh);
289 hpfs_brelse4(&qbh);
290 goto new_map;
291 }
292 goto new_tst;
293}
294
295/*
296 * Check if there are at least n free dnodes on the filesystem.
297 * Called before adding to dnode. If we run out of space while
298 * splitting dnodes, it would corrupt dnode tree.
299 */
300
301int hpfs_check_free_dnodes(struct super_block *s, int n)
302{
303 int n_bmps = (hpfs_sb(s)->sb_fs_size + 0x4000 - 1) >> 14;
304 int b = hpfs_sb(s)->sb_c_bitmap & 0x0fffffff;
305 int i, j;
306 unsigned *bmp;
307 struct quad_buffer_head qbh;
308 if ((bmp = hpfs_map_dnode_bitmap(s, &qbh))) {
309 for (j = 0; j < 512; j++) {
310 unsigned k;
311 if (!bmp[j]) continue;
312 for (k = bmp[j]; k; k >>= 1) if (k & 1) if (!--n) {
313 hpfs_brelse4(&qbh);
314 return 0;
315 }
316 }
317 }
318 hpfs_brelse4(&qbh);
319 i = 0;
320 if (hpfs_sb(s)->sb_c_bitmap != -1) {
321 bmp = hpfs_map_bitmap(s, b, &qbh, "chkdn1");
322 goto chk_bmp;
323 }
324 chk_next:
325 if (i == b) i++;
326 if (i >= n_bmps) return 1;
327 bmp = hpfs_map_bitmap(s, i, &qbh, "chkdn2");
328 chk_bmp:
329 if (bmp) {
330 for (j = 0; j < 512; j++) {
331 unsigned k;
332 if (!bmp[j]) continue;
333 for (k = 0xf; k; k <<= 4)
334 if ((bmp[j] & k) == k) {
335 if (!--n) {
336 hpfs_brelse4(&qbh);
337 return 0;
338 }
339 }
340 }
341 hpfs_brelse4(&qbh);
342 }
343 i++;
344 goto chk_next;
345}
346
347void hpfs_free_dnode(struct super_block *s, dnode_secno dno)
348{
349 if (hpfs_sb(s)->sb_chk) if (dno & 3) {
350 hpfs_error(s, "hpfs_free_dnode: dnode %08x not aligned", dno);
351 return;
352 }
353 if (dno < hpfs_sb(s)->sb_dirband_start ||
354 dno >= hpfs_sb(s)->sb_dirband_start + hpfs_sb(s)->sb_dirband_size) {
355 hpfs_free_sectors(s, dno, 4);
356 } else {
357 struct quad_buffer_head qbh;
358 unsigned *bmp;
359 unsigned ssec = (dno - hpfs_sb(s)->sb_dirband_start) / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 if (!(bmp = hpfs_map_dnode_bitmap(s, &qbh))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 return;
362 }
363 bmp[ssec >> 5] |= 1 << (ssec & 0x1f);
364 hpfs_mark_4buffers_dirty(&qbh);
365 hpfs_brelse4(&qbh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 }
367}
368
369struct dnode *hpfs_alloc_dnode(struct super_block *s, secno near,
Mikulas Patocka7d23ce32011-05-08 20:43:06 +0200370 dnode_secno *dno, struct quad_buffer_head *qbh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371{
372 struct dnode *d;
373 if (hpfs_count_one_bitmap(s, hpfs_sb(s)->sb_dmap) > FREE_DNODES_ADD) {
Mikulas Patocka7d23ce32011-05-08 20:43:06 +0200374 if (!(*dno = alloc_in_dirband(s, near)))
375 if (!(*dno = hpfs_alloc_sector(s, near, 4, 0))) return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 } else {
Mikulas Patocka7d23ce32011-05-08 20:43:06 +0200377 if (!(*dno = hpfs_alloc_sector(s, near, 4, 0)))
378 if (!(*dno = alloc_in_dirband(s, near))) return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 }
380 if (!(d = hpfs_get_4sectors(s, *dno, qbh))) {
381 hpfs_free_dnode(s, *dno);
382 return NULL;
383 }
384 memset(d, 0, 2048);
385 d->magic = DNODE_MAGIC;
386 d->first_free = 52;
387 d->dirent[0] = 32;
388 d->dirent[2] = 8;
389 d->dirent[30] = 1;
390 d->dirent[31] = 255;
391 d->self = *dno;
392 return d;
393}
394
395struct fnode *hpfs_alloc_fnode(struct super_block *s, secno near, fnode_secno *fno,
396 struct buffer_head **bh)
397{
398 struct fnode *f;
Mikulas Patocka7d23ce32011-05-08 20:43:06 +0200399 if (!(*fno = hpfs_alloc_sector(s, near, 1, FNODE_ALLOC_FWD))) return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 if (!(f = hpfs_get_sector(s, *fno, bh))) {
401 hpfs_free_sectors(s, *fno, 1);
402 return NULL;
403 }
404 memset(f, 0, 512);
405 f->magic = FNODE_MAGIC;
406 f->ea_offs = 0xc4;
407 f->btree.n_free_nodes = 8;
408 f->btree.first_free = 8;
409 return f;
410}
411
412struct anode *hpfs_alloc_anode(struct super_block *s, secno near, anode_secno *ano,
413 struct buffer_head **bh)
414{
415 struct anode *a;
Mikulas Patocka7d23ce32011-05-08 20:43:06 +0200416 if (!(*ano = hpfs_alloc_sector(s, near, 1, ANODE_ALLOC_FWD))) return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 if (!(a = hpfs_get_sector(s, *ano, bh))) {
418 hpfs_free_sectors(s, *ano, 1);
419 return NULL;
420 }
421 memset(a, 0, 512);
422 a->magic = ANODE_MAGIC;
423 a->self = *ano;
424 a->btree.n_free_nodes = 40;
425 a->btree.n_used_nodes = 0;
426 a->btree.first_free = 8;
427 return a;
428}