1 /*
2 * linux/fs/hfs/balloc.c
3 *
4 * Copyright (C) 1995-1997 Paul H. Hargrove
5 * This file may be distributed under the terms of the GNU General Public License.
6 *
7 * hfs_bnode_alloc() and hfs_bnode_bitop() are based on GPLed code
8 * Copyright (C) 1995 Michael Dreher
9 *
10 * This file contains the code to create and destroy nodes
11 * in the B-tree structure.
12 *
13 * "XXX" in a comment is a note to myself to consider changing something.
14 *
15 * In function preconditions the term "valid" applied to a pointer to
16 * a structure means that the pointer is non-NULL and the structure it
17 * points to has all fields initialized to consistent values.
18 *
19 * The code in this file initializes some structures which contain
20 * pointers by calling memset(&foo, 0, sizeof(foo)).
21 * This produces the desired behavior only due to the non-ANSI
22 * assumption that the machine representation of NULL is all zeros.
23 */
24
25 #include "hfs_btree.h"
26
27 /*================ File-local functions ================*/
28
29 /*
30 * get_new_node()
31 *
32 * Get a buffer for a new node with out reading it from disk.
33 */
get_new_node(struct hfs_btree * tree,hfs_u32 node)34 static hfs_buffer get_new_node(struct hfs_btree *tree, hfs_u32 node)
35 {
36 int tmp;
37 hfs_buffer retval = HFS_BAD_BUFFER;
38
39 tmp = hfs_extent_map(&tree->entry.u.file.data_fork, node, 0);
40 if (tmp) {
41 retval = hfs_buffer_get(tree->sys_mdb, tmp, 0);
42 }
43 return retval;
44 }
45
46 /*
47 * hfs_bnode_init()
48 *
49 * Description:
50 * Initialize a newly allocated bnode.
51 * Input Variable(s):
52 * struct hfs_btree *tree: Pointer to a B-tree
53 * hfs_u32 node: the node number to allocate
54 * Output Variable(s):
55 * NONE
56 * Returns:
57 * struct hfs_bnode_ref for the new node
58 * Preconditions:
59 * 'tree' points to a "valid" (struct hfs_btree)
60 * 'node' exists and has been allocated in the bitmap of bnodes.
61 * Postconditions:
62 * On success:
63 * The node is not read from disk, nor added to the bnode cache.
64 * The 'sticky' and locking-related fields are all zero/NULL.
65 * The bnode's nd{[FB]Link, Type, NHeight} fields are uninitialized.
66 * The bnode's ndNRecs field and offsets table indicate an empty bnode.
67 * On failure:
68 * The node is deallocated.
69 */
hfs_bnode_init(struct hfs_btree * tree,hfs_u32 node)70 static struct hfs_bnode_ref hfs_bnode_init(struct hfs_btree * tree,
71 hfs_u32 node)
72 {
73 #if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
74 extern int bnode_count;
75 #endif
76 struct hfs_bnode_ref retval;
77
78 retval.lock_type = HFS_LOCK_NONE;
79 if (!HFS_NEW(retval.bn)) {
80 hfs_warn("hfs_bnode_init: out of memory.\n");
81 goto bail2;
82 }
83
84 /* Partially initialize the in-core structure */
85 memset(retval.bn, 0, sizeof(*retval.bn));
86 retval.bn->magic = HFS_BNODE_MAGIC;
87 retval.bn->tree = tree;
88 retval.bn->node = node;
89 hfs_init_waitqueue(&retval.bn->wqueue);
90 hfs_init_waitqueue(&retval.bn->rqueue);
91 hfs_bnode_lock(&retval, HFS_LOCK_WRITE);
92
93 retval.bn->buf = get_new_node(tree, node);
94 if (!hfs_buffer_ok(retval.bn->buf)) {
95 goto bail1;
96 }
97
98 #if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
99 ++bnode_count;
100 #endif
101
102 /* Partially initialize the on-disk structure */
103 memset(hfs_buffer_data(retval.bn->buf), 0, HFS_SECTOR_SIZE);
104 hfs_put_hs(sizeof(struct NodeDescriptor), RECTBL(retval.bn, 1));
105
106 return retval;
107
108 bail1:
109 HFS_DELETE(retval.bn);
110 bail2:
111 /* clear the bit in the bitmap */
112 hfs_bnode_bitop(tree, node, 0);
113 return retval;
114 }
115
116 /*
117 * init_mapnode()
118 *
119 * Description:
120 * Initializes a given node as a mapnode in the given tree.
121 * Input Variable(s):
122 * struct hfs_bnode *bn: the node to add the mapnode after.
123 * hfs_u32: the node to use as a mapnode.
124 * Output Variable(s):
125 * NONE
126 * Returns:
127 * struct hfs_bnode *: the new mapnode or NULL
128 * Preconditions:
129 * 'tree' is a valid (struct hfs_btree).
130 * 'node' is the number of the first node in 'tree' that is not
131 * represented by a bit in the existing mapnodes.
132 * Postconditions:
133 * On failure 'tree' is unchanged and NULL is returned.
134 * On success the node given by 'node' has been added to the linked
135 * list of mapnodes attached to 'tree', and has been initialized as
136 * a valid mapnode with its first bit set to indicate itself as
137 * allocated.
138 */
init_mapnode(struct hfs_bnode * bn,hfs_u32 node)139 static struct hfs_bnode *init_mapnode(struct hfs_bnode *bn, hfs_u32 node)
140 {
141 #if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
142 extern int bnode_count;
143 #endif
144 struct hfs_bnode *retval;
145
146 if (!HFS_NEW(retval)) {
147 hfs_warn("hfs_bnode_add: out of memory.\n");
148 return NULL;
149 }
150
151 memset(retval, 0, sizeof(*retval));
152 retval->magic = HFS_BNODE_MAGIC;
153 retval->tree = bn->tree;
154 retval->node = node;
155 retval->sticky = HFS_STICKY;
156 retval->buf = get_new_node(bn->tree, node);
157 if (!hfs_buffer_ok(retval->buf)) {
158 HFS_DELETE(retval);
159 return NULL;
160 }
161
162 #if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
163 ++bnode_count;
164 #endif
165
166 /* Initialize the bnode data structure */
167 memset(hfs_buffer_data(retval->buf), 0, HFS_SECTOR_SIZE);
168 retval->ndFLink = 0;
169 retval->ndBLink = bn->node;
170 retval->ndType = ndMapNode;
171 retval->ndNHeight = 0;
172 retval->ndNRecs = 1;
173 hfs_put_hs(sizeof(struct NodeDescriptor), RECTBL(retval, 1));
174 hfs_put_hs(0x1fa, RECTBL(retval, 2));
175 *((hfs_u8 *)bnode_key(retval, 1)) = 0x80; /* set first bit of bitmap */
176 retval->prev = bn;
177 hfs_bnode_commit(retval);
178
179 bn->ndFLink = node;
180 bn->next = retval;
181 hfs_bnode_commit(bn);
182
183 return retval;
184 }
185
186 /*================ Global functions ================*/
187
188 /*
189 * hfs_bnode_bitop()
190 *
191 * Description:
192 * Allocate/free the requested node of a B-tree of the hfs filesystem
193 * by setting/clearing the corresponding bit in the B-tree bitmap.
194 * The size of the B-tree will not be changed.
195 * Input Variable(s):
196 * struct hfs_btree *tree: Pointer to a B-tree
197 * hfs_u32 bitnr: The node number to free
198 * int set: 0 to clear the bit, non-zero to set it.
199 * Output Variable(s):
200 * None
201 * Returns:
202 * 0: no error
203 * -1: The node was already allocated/free, nothing has been done.
204 * -2: The node is out of range of the B-tree.
205 * -4: not enough map nodes to hold all the bits
206 * Preconditions:
207 * 'tree' points to a "valid" (struct hfs_btree)
208 * 'bitnr' is a node number within the range of the btree, which is
209 * currently free/allocated.
210 * Postconditions:
211 * The bit number 'bitnr' of the node bitmap is set/cleared and the
212 * number of free nodes in the btree is decremented/incremented by one.
213 */
hfs_bnode_bitop(struct hfs_btree * tree,hfs_u32 bitnr,int set)214 int hfs_bnode_bitop(struct hfs_btree *tree, hfs_u32 bitnr, int set)
215 {
216 struct hfs_bnode *bn; /* the current bnode */
217 hfs_u16 start; /* the start (in bits) of the bitmap in node */
218 hfs_u16 len; /* the len (in bits) of the bitmap in node */
219 hfs_u32 *u32; /* address of the u32 containing the bit */
220
221 if (bitnr >= tree->bthNNodes) {
222 hfs_warn("hfs_bnode_bitop: node number out of range.\n");
223 return -2;
224 }
225
226 bn = &tree->head;
227 for (;;) {
228 start = bnode_offset(bn, bn->ndNRecs) << 3;
229 len = (bnode_offset(bn, bn->ndNRecs + 1) << 3) - start;
230
231 if (bitnr < len) {
232 break;
233 }
234
235 /* continue on to next map node if available */
236 if (!(bn = bn->next)) {
237 hfs_warn("hfs_bnode_bitop: too few map nodes.\n");
238 return -4;
239 }
240 bitnr -= len;
241 }
242
243 /* Change the correct bit */
244 bitnr += start;
245 u32 = (hfs_u32 *)hfs_buffer_data(bn->buf) + (bitnr >> 5);
246 bitnr %= 32;
247 if ((set && hfs_set_bit(bitnr, u32)) ||
248 (!set && !hfs_clear_bit(bitnr, u32))) {
249 hfs_warn("hfs_bnode_bitop: bitmap corruption.\n");
250 return -1;
251 }
252 hfs_buffer_dirty(bn->buf);
253
254 /* adjust the free count */
255 tree->bthFree += (set ? -1 : 1);
256 tree->dirt = 1;
257
258 return 0;
259 }
260
261 /*
262 * hfs_bnode_alloc()
263 *
264 * Description:
265 * Find a cleared bit in the B-tree node bitmap of the hfs filesystem,
266 * set it and return the corresponding bnode, with its contents zeroed.
267 * When there is no free bnode in the tree, an error is returned, no
268 * new nodes will be added by this function!
269 * Input Variable(s):
270 * struct hfs_btree *tree: Pointer to a B-tree
271 * Output Variable(s):
272 * NONE
273 * Returns:
274 * struct hfs_bnode_ref for the new bnode
275 * Preconditions:
276 * 'tree' points to a "valid" (struct hfs_btree)
277 * There is at least one free bnode.
278 * Postconditions:
279 * On success:
280 * The corresponding bit in the btree bitmap is set.
281 * The number of free nodes in the btree is decremented by one.
282 * The node is not read from disk, nor added to the bnode cache.
283 * The 'sticky' field is uninitialized.
284 */
hfs_bnode_alloc(struct hfs_btree * tree)285 struct hfs_bnode_ref hfs_bnode_alloc(struct hfs_btree *tree)
286 {
287 struct hfs_bnode *bn; /* the current bnode */
288 hfs_u32 bitnr = 0; /* which bit are we examining */
289 hfs_u16 first; /* the first clear bit in this bnode */
290 hfs_u16 start; /* the start (in bits) of the bitmap in node */
291 hfs_u16 end; /* the end (in bits) of the bitmap in node */
292 hfs_u32 *data; /* address of the data in this bnode */
293
294 bn = &tree->head;
295 for (;;) {
296 start = bnode_offset(bn, bn->ndNRecs) << 3;
297 end = bnode_offset(bn, bn->ndNRecs + 1) << 3;
298 data = (hfs_u32 *)hfs_buffer_data(bn->buf);
299
300 /* search the current node */
301 first = hfs_find_zero_bit(data, end, start);
302 if (first < end) {
303 break;
304 }
305
306 /* continue search in next map node */
307 bn = bn->next;
308
309 if (!bn) {
310 hfs_warn("hfs_bnode_alloc: too few map nodes.\n");
311 goto bail;
312 }
313 bitnr += (end - start);
314 }
315
316 if ((bitnr += (first - start)) >= tree->bthNNodes) {
317 hfs_warn("hfs_bnode_alloc: no free nodes found, "
318 "count wrong?\n");
319 goto bail;
320 }
321
322 if (hfs_set_bit(first % 32, data + (first>>5))) {
323 hfs_warn("hfs_bnode_alloc: bitmap corruption.\n");
324 goto bail;
325 }
326 hfs_buffer_dirty(bn->buf);
327
328 /* decrement the free count */
329 --tree->bthFree;
330 tree->dirt = 1;
331
332 return hfs_bnode_init(tree, bitnr);
333
334 bail:
335 return (struct hfs_bnode_ref){NULL, HFS_LOCK_NONE};
336 }
337
338 /*
339 * hfs_btree_extend()
340 *
341 * Description:
342 * Adds nodes to a B*-tree if possible.
343 * Input Variable(s):
344 * struct hfs_btree *tree: the btree to add nodes to.
345 * Output Variable(s):
346 * NONE
347 * Returns:
348 * void
349 * Preconditions:
350 * 'tree' is a valid (struct hfs_btree *).
351 * Postconditions:
352 * If possible the number of nodes indicated by the tree's clumpsize
353 * have been added to the tree, updating all in-core and on-disk
354 * allocation information.
355 * If insufficient disk-space was available then fewer nodes may have
356 * been added than would be expected based on the clumpsize.
357 * In the case of the extents B*-tree this function will add fewer
358 * nodes than expected if adding more would result in an extent
359 * record for the extents tree being added to the extents tree.
360 * The situation could be dealt with, but doing so confuses Macs.
361 */
hfs_btree_extend(struct hfs_btree * tree)362 void hfs_btree_extend(struct hfs_btree *tree)
363 {
364 struct hfs_bnode_ref head;
365 struct hfs_bnode *bn, *tmp;
366 struct hfs_cat_entry *entry = &tree->entry;
367 struct hfs_mdb *mdb = entry->mdb;
368 hfs_u32 old_nodes, new_nodes, total_nodes, new_mapnodes, seen;
369
370 old_nodes = entry->u.file.data_fork.psize;
371
372 entry->u.file.data_fork.lsize += 1; /* rounded up to clumpsize */
373 hfs_extent_adj(&entry->u.file.data_fork);
374
375 total_nodes = entry->u.file.data_fork.psize;
376 entry->u.file.data_fork.lsize = total_nodes << HFS_SECTOR_SIZE_BITS;
377 new_nodes = total_nodes - old_nodes;
378 if (!new_nodes) {
379 return;
380 }
381
382 head = hfs_bnode_find(tree, 0, HFS_LOCK_WRITE);
383 if (!(bn = head.bn)) {
384 hfs_warn("hfs_btree_extend: header node not found.\n");
385 return;
386 }
387
388 seen = 0;
389 new_mapnodes = 0;
390 for (;;) {
391 seen += bnode_rsize(bn, bn->ndNRecs) << 3;
392
393 if (seen >= total_nodes) {
394 break;
395 }
396
397 if (!bn->next) {
398 tmp = init_mapnode(bn, seen);
399 if (!tmp) {
400 hfs_warn("hfs_btree_extend: "
401 "can't build mapnode.\n");
402 hfs_bnode_relse(&head);
403 return;
404 }
405 ++new_mapnodes;
406 }
407 bn = bn->next;
408 }
409 hfs_bnode_relse(&head);
410
411 tree->bthNNodes = total_nodes;
412 tree->bthFree += (new_nodes - new_mapnodes);
413 tree->dirt = 1;
414
415 /* write the backup MDB, not returning until it is written */
416 hfs_mdb_commit(mdb, 1);
417
418 return;
419 }
420
421 /*
422 * hfs_bnode_free()
423 *
424 * Remove a node from the cache and mark it free in the bitmap.
425 */
hfs_bnode_free(struct hfs_bnode_ref * bnr)426 int hfs_bnode_free(struct hfs_bnode_ref *bnr)
427 {
428 hfs_u32 node = bnr->bn->node;
429 struct hfs_btree *tree = bnr->bn->tree;
430
431 if (bnr->bn->count != 1) {
432 hfs_warn("hfs_bnode_free: count != 1.\n");
433 return -EIO;
434 }
435
436 hfs_bnode_relse(bnr);
437 hfs_bnode_bitop(tree, node, 0);
438 return 0;
439 }
440