xref: /dragonfly/sys/vfs/hpfs/hpfs_alsubr.c (revision 49781055)
1 /*-
2  * Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD: src/sys/fs/hpfs/hpfs_alsubr.c,v 1.1 1999/12/09 19:09:58 semenu Exp $
27  * $DragonFly: src/sys/vfs/hpfs/hpfs_alsubr.c,v 1.6 2006/01/13 21:09:27 swildner Exp $
28  */
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/proc.h>
34 #include <sys/time.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <sys/vnode.h>
38 #include <sys/mount.h>
39 #include <sys/namei.h>
40 #include <sys/malloc.h>
41 #include <sys/buf.h>
42 
43 #include "hpfs.h"
44 #include "hpfs_subr.h"
45 
46 #define	AE_DONE		0		/* Nothing to change */
47 #define	AE_SPLIT	2		/* Split was done, ranp is valid */
48 
49 int		hpfs_addextentr (struct hpfsmount *, lsn_t, alleaf_t *,
50 			         alnode_t *, u_long *);
51 int		hpfs_allocalsec (struct hpfsmount *, lsn_t, struct buf **);
52 int		hpfs_alblk2alsec (struct hpfsmount *, alblk_t *, alsec_t **,
53 				  struct buf **);
54 int		hpfs_splitalsec (struct hpfsmount *, alsec_t *, alsec_t **,
55 				 struct buf **);
56 int		hpfs_concatalsec (struct hpfsmount *, alsec_t *, alsec_t *,
57 				  alnode_t *);
58 
59 /*
60  * Map file offset to disk offset. hpfsnode have to be locked.
61  */
62 int
63 hpfs_hpbmap(struct hpfsnode *hp, daddr_t bn, daddr_t *bnp, int *runp)
64 {
65 	struct buf *bp;
66 	alblk_t * abp;
67 	alleaf_t *alp;
68 	alnode_t *anp;
69 	int error, i;
70 
71 	dprintf(("hpfs_hpbmap(0x%x, 0x%x): ",hp->h_no, bn));
72 
73 	bp = NULL;
74 	abp = &hp->h_fn.fn_ab;
75 	alp = (alleaf_t *)&hp->h_fn.fn_abd;
76 	anp = (alnode_t *)&hp->h_fn.fn_abd;
77 
78 dive:
79 	if (abp->ab_flag & AB_NODES) {
80 		for (i=0; i<abp->ab_busycnt; i++, anp++) {
81 			dprintf(("[0x%x,0x%x] ",anp->an_nextoff,anp->an_lsn));
82 			if (bn < anp->an_nextoff) {
83 				alsec_t *asp;
84 
85 				dprintf(("< found | "));
86 
87 				if (bp)
88 					brelse(bp);
89 				error = bread(hp->h_devvp, anp->an_lsn,
90 					      DEV_BSIZE, &bp);
91 				if (error) {
92 					printf("hpfs_hpbmap: bread error\n");
93 					brelse(bp);
94 					return (error);
95 				}
96 
97 				asp = (alsec_t *) bp->b_data;
98 				if (asp->as_magic != AS_MAGIC) {
99 					brelse(bp);
100 					printf("hpfs_hpbmap: "
101 					       "MAGIC DOESN'T MATCH");
102 					return (EINVAL);
103 				}
104 
105 				abp = &asp->as_ab;
106 				alp = (alleaf_t *)&asp->as_abd;
107 				anp = (alnode_t *)&asp->as_abd;
108 
109 				goto dive;
110 			}
111 		}
112 	} else {
113 		for (i=0; i<abp->ab_busycnt; i++, alp++) {
114 			dprintf(("[0x%x,0x%x,0x%x] ",
115 				 alp->al_off,alp->al_len,alp->al_lsn));
116 
117 			if ((bn >= alp->al_off) &&
118 			    (!alp->al_len || (bn < alp->al_off + alp->al_len))) {
119 				dprintf(("found, "));
120 
121 				*bnp = bn - alp->al_off + alp->al_lsn;
122 
123 				dprintf((" 0x%x ", *bnp));
124 
125 				if (runp != NULL) {
126 					if (alp->al_len)
127 						*runp = alp->al_off - 1 +
128 							alp->al_len - bn;
129 					else
130 						*runp = 3; /* XXX */
131 
132 					dprintf((" 0x%x cont", *runp));
133 				}
134 
135 				if (bp)
136 					brelse(bp);
137 
138 				dprintf(("\n"));
139 				return (0);
140 			}
141 		}
142 	}
143 
144 	dprintf(("END, notfound\n"));
145 	if (bp)
146 		brelse(bp);
147 
148 	dprintf(("hpfs_hpbmap: offset too big\n"));
149 
150 	return (EFBIG);
151 }
152 
153 /*
154  * Find place and preinitialize AlSec structure
155  * AlBlk is initialized to contain AlLeafs.
156  */
157 int
158 hpfs_allocalsec(struct hpfsmount *hpmp, lsn_t parlsn, struct buf **bpp)
159 {
160 	alsec_t * asp;
161 	struct buf * bp;
162 	lsn_t lsn;
163 	int error;
164 
165 	*bpp = NULL;
166 
167 	error = hpfs_bmfblookup(hpmp, &lsn);
168 	if (error) {
169 		printf("hpfs_allocalsec: CAN'T ALLOC SPACE FOR AlSec\n");
170 		return (error);
171 	}
172 
173 	error = hpfs_bmmarkbusy(hpmp, lsn, 1);
174 	if (error)
175 		return (error);
176 
177 	bp = getblk(hpmp->hpm_devvp, lsn, DEV_BSIZE, 0, 0);
178 	clrbuf(bp);
179 
180 	/* Fill AlSec info */
181 	asp = (alsec_t *) bp->b_data;
182 	asp->as_magic = AS_MAGIC;
183 	asp->as_self = lsn;
184 	asp->as_parent = parlsn;
185 
186 	/* Fill AlBlk */
187 	asp->as_ab.ab_flag = 0;
188 	asp->as_ab.ab_busycnt = 0;
189 	asp->as_ab.ab_freecnt = 0x28;
190 	asp->as_ab.ab_freeoff = sizeof(alblk_t);
191 
192 	*bpp = bp;
193 
194 	return (0);
195 }
196 
197 /*
198  * Split AlSec structure into new allocated:
199  * allocate new AlSec; then move second half of asp's entries in
200  * into it; set proper flags.
201  *
202  * IF AlSec CONTAINS AlNodes, THEN YOU ALMOST EVERYTIME HAVE TO
203  * FIX LAST AlNode in OLD AlSec (NEXTOFF TO BE 0xFFFFFFFF).
204  * TOGETHER WITH FIXING ALL CHILDREN'S AlSecs (THEY HAVE GOT NEW PARENT).
205  */
206 int
207 hpfs_splitalsec(struct hpfsmount *hpmp, alsec_t *asp, alsec_t **naspp,
208 		struct buf **nbpp)
209 {
210 	alsec_t *nasp;
211 	struct buf *nbp;
212 	alblk_t *abp;
213 	alblk_t *nabp;
214 	int error, n1, n2, sz;
215 
216 	error = hpfs_allocalsec(hpmp, asp->as_parent, &nbp);
217 	if (error)
218 		return (error);
219 
220 	nasp = (alsec_t *)nbp->b_data;
221 	nabp = &nasp->as_ab;
222 	abp = &asp->as_ab;
223 
224 	n1 = (abp->ab_busycnt + 1) / 2;
225 	n2 = (abp->ab_busycnt - n1);
226 	sz = (abp->ab_flag & AB_NODES) ? sizeof(alnode_t) : sizeof(alleaf_t);
227 
228 	bcopy((caddr_t)abp + sizeof(alblk_t) + n1 * sz,
229 	      (caddr_t)nabp + sizeof(alblk_t), n2 * sz);
230 
231 	nabp->ab_flag = abp->ab_flag;
232 	nabp->ab_busycnt = n2;
233 	nabp->ab_freecnt = (0x1e0 / sz - n2);
234 	nabp->ab_freeoff += n2 * sz;
235 
236 	abp->ab_busycnt -= n1;
237 	abp->ab_freecnt += n1;
238 	abp->ab_freeoff -= n1 * sz;
239 
240 	*naspp = nasp;
241 	*nbpp = nbp;
242 
243 	return (0);
244 }
245 
246 /*
247  * Try to concatenate two AlSec's
248  *
249  * Moves all entries from AlSec corresponding (as1p, aanp[1]) into
250  * corresponding aanp[0] one. If not enought space, then return ENOSPC.
251  *
252  * WARNING! YOU HAVE TO FIX aanp VALUES YOURSELF LATER:
253  * aanp[0].an_nextoff = aanp[1].an_nextoff;
254  */
255 int
256 hpfs_concatalsec(struct hpfsmount *hpmp, alsec_t *as0p, alsec_t *as1p,
257 		 alnode_t *aanp)
258 {
259 	alblk_t *ab0p;
260 	alblk_t *ab1p;
261 	int sz;
262 
263 	dprintf(("hpfs_concatalsec: AlSecs at 0x%x and 0x%x \n",
264 		as0p->as_self,as1p->as_self));
265 
266 	ab0p = &as0p->as_ab;
267 	ab1p = &as1p->as_ab;
268 	sz = (ab0p->ab_flag & AB_NODES) ? sizeof(alnode_t) : sizeof(alleaf_t);
269 
270 	if (ab0p->ab_freecnt > ab1p->ab_busycnt) {
271 		/*
272 		 * Concatenate AlSecs
273 		 */
274 		if (ab0p->ab_flag & AB_NODES)
275 			AB_LASTANP(ab0p)->an_nextoff = aanp[0].an_nextoff;
276 
277 		bcopy (AB_ALNODE(ab1p), AB_FREEANP(ab0p),
278 			 ab1p->ab_busycnt * sz);
279 
280 		AB_ADDNREC(ab0p, sz, ab1p->ab_busycnt);
281 
282 		return (0);
283 	} else {
284 		/* Not enought space to concatenate */
285 		return (ENOSPC);
286 	}
287 }
288 
289 /*
290  * Transform AlBlk structure into new allocated
291  * AlSec.
292  *
293  * DOESN'T SET AlSec'S PARENT LSN.
294  */
295 int
296 hpfs_alblk2alsec(struct hpfsmount *hpmp, alblk_t *abp, alsec_t **naspp,
297 		 struct buf **nbpp)
298 {
299 	alsec_t *nasp;
300 	alblk_t *nabp;
301 	struct buf *nbp;
302 	int error, sz;
303 
304 	error = hpfs_allocalsec(hpmp, 0, &nbp);
305 	if (error)
306 		return (error);
307 
308 	nasp = (alsec_t *)nbp->b_data;
309 	nabp = &nasp->as_ab;
310 
311 	sz = (abp->ab_flag & AB_NODES) ? sizeof(alnode_t) : sizeof(alleaf_t);
312 
313 	bcopy (abp, nabp, sizeof(alblk_t) + sz * abp->ab_busycnt);
314 
315 	nabp->ab_freecnt = 0x1e0 / sz - nabp->ab_busycnt;
316 
317 	*naspp = nasp;
318 	*nbpp = nbp;
319 
320 	return (0);
321 }
322 
323 /*
324  * Allocate len blocks and concatenate them to file.
325  * If we hadn't found contignous run of len blocks, concatenate
326  * as much as we can, and return.
327  *
328  */
329 int
330 hpfs_addextent(struct hpfsmount *hpmp, struct hpfsnode *hp, u_long len)
331 {
332 	alblk_t *rabp;
333 	alnode_t ranp[2];
334 	alleaf_t al;
335 	int error;
336 	u_long pf;
337 
338 	/*
339 	 * We don't know for now start lsn of block
340 	 */
341 	al.al_lsn = ~0;
342 	al.al_len = len;
343 	al.al_off = (hp->h_fn.fn_size + DEV_BSIZE - 1) >> DEV_BSHIFT;
344 
345 	rabp = &hp->h_fn.fn_ab;
346 
347 	/* Init AlBlk if this is first extent */
348 	if (al.al_off == 0) {
349 		lsn_t nlsn;
350 		u_long nlen;
351 
352 		dprintf(("hpfs_addextent: init AlBlk in root\n"));
353 
354 		rabp->ab_busycnt = 0;
355 		rabp->ab_freecnt = 0x8;
356 		rabp->ab_freeoff = sizeof(alblk_t);
357 		rabp->ab_flag = 0;
358 
359 		error = hpfs_bmlookup (hpmp, 0, hp->h_no + 1, al.al_len, &nlsn, &nlen);
360 		if (error)
361 			return (error);
362 
363 		error = hpfs_bmmarkbusy(hpmp, nlsn, nlen);
364 		if (error)
365 			return (error);
366 
367 		dprintf(("hpfs_addextent: new: 0x%x 0x%lx, ", nlsn, nlen));
368 
369 		AL_SET(AB_FREEALP(rabp), al.al_off, nlen, nlsn);
370 		AB_ADDAL(rabp);
371 
372 		al.al_off += nlen;
373 		al.al_len -= nlen;
374 	}
375 
376 retry:
377 	dprintf(("hpfs_addextent: AlBlk: [0x%x, 0x%x, 0x%x] need: 0x%x\n",
378 		 rabp->ab_freecnt, rabp->ab_busycnt, rabp->ab_flag, al.al_len));
379 
380 	while ((al.al_len) && (rabp->ab_freecnt > 0)) {
381 		if (rabp->ab_flag & AB_NODES) {
382 			alnode_t *anp;
383 			/*
384 			 * This is level containing AlNodes, so try to
385 			 * insert recursively into last entry.
386 			 */
387 			anp = AB_LASTANP(rabp);
388 			dprintf(("hpfs_addextent: AlNode: [0x%x,0x%x] \n",
389 				 anp->an_nextoff,anp->an_lsn));
390 
391 			/*
392 			 * Try to insert...
393 			 */
394 			error = hpfs_addextentr (hpmp, anp->an_lsn, &al, ranp, &pf);
395 			if (error) {
396 				printf("hpfs_addextent: FAILED %d\n",error);
397 				return (error);
398 			}
399 
400 			switch (pf) {
401 			case AE_SPLIT:
402 				dprintf(("hpfs_addextent: successful (split)\n"));
403 				/*
404 				 * Then hpfs_addextentr has split tree below, now
405 				 * we need to fix this level. Particulary:
406 				 * fix last AlNode and add another one.
407 				 */
408 
409 				bcopy(ranp, AB_LASTANP(rabp), sizeof(alnode_t) * 2);
410 				AB_ADDAN(rabp);
411 				break;
412 
413 			default:
414 			case AE_DONE:
415 				dprintf(("hpfs_addextent: successful\n"));
416 				break;
417 			}
418 		} else {
419 			alleaf_t *alp;
420 
421 			alp = AB_LASTALP(rabp);
422 			dprintf(("hpfs_addextent: AlLeaf: [0x%x,0x%x,0x%x] \n",
423 				 alp->al_off,alp->al_len,alp->al_lsn));
424 
425 			/* Check if we trying to add in right place */
426 			if (alp->al_off + alp->al_len == al.al_off) {
427 				lsn_t nlsn;
428 				u_long nlen;
429 
430 				/*
431 				 * Search bitmap for block begining from
432 				 * alp->al_lsn + alp->al_len and long of ralp->al_len
433 				 */
434 				error = hpfs_bmlookup (hpmp, 0,
435 					alp->al_lsn + alp->al_len, al.al_len, &nlsn, &nlen);
436 				if (error)
437 					return (error);
438 
439 				error = hpfs_bmmarkbusy(hpmp, nlsn, nlen);
440 				if (error)
441 					return (error);
442 
443 				dprintf(("hpfs_addextent: new: 0x%x 0x%lx, ", nlsn, nlen));
444 
445 				if (alp->al_lsn + alp->al_len == nlsn) {
446 					dprintf(("extended existed leaf\n"));
447 
448 					alp->al_len += nlen;
449 				} else {
450 					dprintf(("created new leaf\n"));
451 					AL_SET(AB_FREEALP(rabp), al.al_off, nlen, nlsn);
452 					AB_ADDAL(rabp);
453 				}
454 				al.al_off += nlen;
455 				al.al_len -= nlen;
456 			} else {
457 				printf("hpfs_addextent: INTERNAL INCONSISTENCE\n");
458 				return (EINVAL);
459 			}
460 		}
461 	}
462 
463 	/*
464 	 * Move AlBlk contain to new AlSec (it will fit more
465 	 * entries) if overflowed (no more free entries).
466 	 */
467 	if (rabp->ab_freecnt <= 0) {
468 		struct buf *nbp;
469 		alsec_t * nrasp;
470 
471 		dprintf(("hpfs_addextent: overflow, convt\n"));
472 
473 		/*
474 		 * Convert AlBlk to new AlSec, it will set
475 		 * AB_FNPARENT also.
476 		 */
477 		rabp->ab_flag |= AB_FNPARENT;
478 		error = hpfs_alblk2alsec (hpmp, rabp, &nrasp, &nbp);
479 		if (error) {
480 			printf("hpfs_addextent: CAN'T CONVT\n");
481 			return (error);
482 		}
483 		nrasp->as_parent = hp->h_no;
484 
485 		/*
486 		 * Scan all childrens (if exist), set new parent and
487 		 * clean their AB_FNPARENT flag.
488 		 */
489 		if (rabp->ab_flag & AB_NODES) {
490 			int i;
491 			alsec_t * asp;
492 			alnode_t * anp;
493 			struct buf * bp;
494 
495 			anp = AB_ALNODE(rabp);
496 			for (i=0; i<rabp->ab_busycnt; i++) {
497 				error = hpfs_breadalsec(hpmp, anp->an_lsn, &bp);
498 				if (error)
499 					return (error);
500 
501 				asp = (alsec_t *)bp->b_data;
502 				asp->as_ab.ab_flag &= ~AB_FNPARENT;
503 				asp->as_parent = nrasp->as_self;
504 
505 				bdwrite(bp);
506 				anp ++;
507 			}
508 		}
509 
510 		/* Convert AlBlk to contain AlNodes */
511 		rabp->ab_flag = AB_NODES;
512 		rabp->ab_busycnt = 0;
513 		rabp->ab_freecnt = 0xC;
514 		rabp->ab_freeoff = sizeof(alblk_t);
515 
516 		/* Add AlNode for new allocated AlSec */
517 		AN_SET(AB_FREEANP(rabp), ~0, nrasp->as_self);
518 		AB_ADDAN(rabp);
519 
520 		bdwrite(nbp);
521 	}
522 
523 	if (al.al_len) {
524 		dprintf(("hpfs_addextent: root retry\n"));
525 		goto retry;
526 	}
527 
528 	return (0);
529 }
530 
531 /*
532  * Descent down to the end of tree, then search for
533  * ralp->len contignous run begining from last run's end and
534  * concatenate new block! If we can't find one, then...
535  *
536  * Parameters:
537  *	hpmp:	Mix info
538  *	rlsn:	LSN containing AlSec
539  *	ralp:	AlLeaf to insert
540  *	ranp:	New AlNodes' values
541  *	resp:	Mix returning info
542  */
543 int
544 hpfs_addextentr(struct hpfsmount *hpmp, lsn_t rlsn, alleaf_t *ralp,
545 		alnode_t *ranp, u_long *resp)
546 {
547 	struct buf *rbp;
548 	alsec_t *rasp;
549 	alblk_t *rabp;
550 	alleaf_t *alp;
551 	alnode_t *anp;
552 	int error;
553 	u_long pf;
554 	u_long wb;
555 
556 	*resp = 0;
557 
558 	dprintf(("hpfs_addextentr: AlSec at 0x%x\n", rlsn));
559 
560 	error = hpfs_breadalsec(hpmp, rlsn, &rbp);
561 	if (error)
562 		return (error);
563 
564 	rasp = (alsec_t *)rbp->b_data;
565 	rabp = &rasp->as_ab;
566 	wb = 0;
567 
568 	dprintf(("hpfs_addextentr: AlBlk: [0x%x, 0x%x, 0x%x]\n",
569 		 rabp->ab_freecnt, rabp->ab_busycnt, rabp->ab_flag));
570 
571 	while ((ralp->al_len) && (rabp->ab_freecnt > 0)) {
572 		if (rabp->ab_flag & AB_NODES) {
573 			/*
574 			 * This is level containing AlNodes, so try to
575 			 * insert recursively into last entry.
576 			 */
577 			anp = AB_LASTANP(rabp);
578 			dprintf(("hpfs_addextentr: AlNode: [0x%x,0x%x] \n",
579 				 anp->an_nextoff,anp->an_lsn));
580 
581 			/*
582 			 * Try to insert...
583 			 */
584 			error = hpfs_addextentr (hpmp, anp->an_lsn, ralp, ranp, &pf);
585 			if (error) {
586 				printf("hpfs_addextentr: FAILED %d\n",error);
587 				goto fail;
588 			}
589 
590 			switch (pf) {
591 			case AE_SPLIT:
592 				dprintf(("hpfs_addextentr: successful (split)\n"));
593 				/*
594 				 * Then hpfs_addextentr has split tree below, now
595 				 * we need to fix this level. Particulary:
596 				 * fix last AlNode and add another one.
597 				 */
598 				bcopy(ranp, AB_LASTANP(rabp), sizeof(alnode_t) * 2);
599 				AB_ADDAN(rabp);
600 				wb = 1;
601 				break;
602 
603 			default:
604 			case AE_DONE:
605 				dprintf(("hpfs_addextentr: successful\n"));
606 				break;
607 			}
608 		} else {
609 			alp = AB_LASTALP(rabp);
610 			dprintf(("hpfs_addextentr: AlLeaf: [0x%x,0x%x,0x%x] \n",
611 				 alp->al_off,alp->al_len,alp->al_lsn));
612 
613 			/* Check if we trying to add in right place */
614 			if (alp->al_off + alp->al_len == ralp->al_off) {
615 				lsn_t nlsn;
616 				u_long nlen;
617 				/*
618 				 * Search bitmap for block begining from
619 				 * alp->al_lsn + alp->al_len and long of ralp->al_len
620 				 */
621 				error = hpfs_bmlookup (hpmp, 0,
622 					alp->al_lsn + alp->al_len, ralp->al_len, &nlsn, &nlen);
623 				if (error)
624 					goto fail;
625 
626 				error = hpfs_bmmarkbusy(hpmp, nlsn, nlen);
627 				if (error)
628 					goto fail;
629 
630 				dprintf(("hpfs_addextentr: new: 0x%x 0x%lx, ", nlsn, nlen));
631 
632 				/*
633 				 * If ending of existed entry fits the
634 				 * begining of the extent being added,
635 				 * then we add concatenate two extents.
636 				 */
637 				if (alp->al_lsn + alp->al_len == nlsn) {
638 					dprintf(("concat\n"));
639 					alp->al_len += nlen;
640 				} else {
641 					dprintf(("created new leaf\n"));
642 					AL_SET(AB_FREEALP(rabp), ralp->al_off, nlen, nlsn);
643 					AB_ADDAL(rabp);
644 				}
645 
646 				ralp->al_len -= nlen;
647 				ralp->al_off += nlen;
648 			} else {
649 				printf("hpfs_addextentr: INTERNAL INCONSISTENCE\n");
650 				error = (EINVAL);
651 				goto fail;
652 			}
653 		}
654 	}
655 
656 	/*
657 	 * Split AlBlk if overflowed.
658 	 */
659 	if (rabp->ab_freecnt <= 0) {
660 		struct buf *nbp;
661 		alsec_t * nrasp;
662 
663 		dprintf(("hpfs_addextentr: overflow, split\n"));
664 
665 		error = hpfs_splitalsec (hpmp, rasp, &nrasp, &nbp);
666 		if (error) {
667 			printf("hpfs_addextent: CAN'T SPLIT\n");
668 			goto fail;
669 		}
670 
671 		if (rabp->ab_flag & AB_NODES) {
672 			int i;
673 			alsec_t * asp;
674 			alnode_t * anp;
675 			struct buf * bp;
676 
677 			ranp[0].an_nextoff =
678 				AB_LASTANP(&rasp->as_ab)->an_nextoff;
679 
680 			/* We need to set left subtree's last entry
681 			 * offset to 0xFFFFFFFF for OS/2 to be able
682 			 * to read our files. It treats absence  of
683 			 * 0xFFFFFFFF as error.
684 			 */
685 			AB_LASTANP(&rasp->as_ab)->an_nextoff = ~0;
686 
687 			/* We need to fix new allocated AlSec's
688 			 * children, becouse their parent has changed.
689 			 */
690 			anp = AB_ALNODE(&nrasp->as_ab);
691 			for (i=0; i<nrasp->as_ab.ab_busycnt; i++) {
692 				error = hpfs_breadalsec(hpmp, anp->an_lsn, &bp);
693 				if (error) {
694 					brelse(nbp);
695 					goto fail;
696 				}
697 
698 				asp = (alsec_t *)bp->b_data;
699 				asp->as_parent = nrasp->as_self;
700 
701 				bdwrite(bp);
702 				anp ++;
703 			}
704 		} else {
705 			ranp[0].an_nextoff =
706 				AB_ALLEAF(&nrasp->as_ab)->al_off;
707 		}
708 
709 		ranp[0].an_lsn = rasp->as_self;
710 		ranp[1].an_nextoff = ~0;
711 		ranp[1].an_lsn = nrasp->as_self;
712 
713 		bdwrite(nbp);
714 
715 		*resp = AE_SPLIT;
716 		wb = 1;
717 	}
718 
719 	if (wb)
720 		bdwrite (rbp);
721 	else
722 		brelse(rbp);
723 
724 	return (0);
725 
726 fail:
727 	brelse(rbp);
728 
729 	return (error);
730 }
731 
732 /*
733  * Recursive routine walking down the b-tree and deallocating all
734  * extents above bn. Returns *resp != 0 if alblk was totally
735  * deallocated and may be freed. Tries to keep b-tree.
736  *
737  * (XXXX) NOTE! THIS ROUTINE WILL NEVER DECREMENT DEPTH OF
738  * THE TREE.
739  */
740 int
741 hpfs_truncatealblk(struct hpfsmount *hpmp, alblk_t *abp, lsn_t bn, int *resp)
742 {
743 	int error;
744 	alleaf_t *alp;
745 	alnode_t *anp;
746 	alsec_t *asp;
747 	struct buf *bp;
748 
749 	dprintf(("hpfs_truncatealblk: AlBlk: [0x%x,0x%x, 0x%x]\n",
750 		 abp->ab_freecnt, abp->ab_busycnt, abp->ab_flag));
751 
752 	if (abp->ab_flag & AB_NODES) {
753 		/*
754 		 * Scan array of AlNodes backward,
755 		 * diving in recursion if needed
756 		 */
757 		anp = AB_LASTANP(abp);
758 
759 		while (abp->ab_busycnt && (bn <= anp->an_nextoff)) {
760 			dprintf(("hpfs_truncatealblk: AlNode: [0x%x,0x%x] \n",
761 				anp->an_nextoff,anp->an_lsn));
762 
763 			error = hpfs_breadalsec(hpmp, anp->an_lsn, &bp);
764 			if (error)
765 				return (error);
766 
767 			asp = (alsec_t *)bp->b_data;
768 
769 			error = hpfs_truncatealblk (hpmp,
770 					&asp->as_ab, bn, resp);
771 			if (error) {
772 				brelse(bp);
773 				return (error);
774 			}
775 
776 			if (*resp) {
777 				brelse (bp);
778 
779 				error = hpfs_bmmarkfree(hpmp,
780 						anp->an_lsn, 1);
781 				if (error)
782 					return (error);
783 
784 				AB_RMAN(abp);
785 				anp --;
786 			} else {
787 				/*
788 				 * We have deallocated some entries, some space
789 				 * migth been freed, then try to concat two
790 				 * last AlSec.
791 				 */
792 				anp->an_nextoff = ~0;
793 				if (abp->ab_busycnt >= 2) {
794 					alsec_t *as0p;
795 					struct buf *b0p;
796 
797 					error = hpfs_breadalsec(hpmp,
798 							(anp-1)->an_lsn, &b0p);
799 					if (error)
800 						return (error);
801 
802 					as0p = (alsec_t *)b0p->b_data;
803 					error = hpfs_concatalsec(hpmp,
804 							as0p, asp, anp - 1);
805 					if (error == ENOSPC) {
806 						/* Not enought space */
807 						brelse (b0p);
808 						bdwrite (bp);
809 					} else if (error == 0) {
810 						/* All OK  */
811 						(anp-1)->an_nextoff = anp->an_nextoff;
812 
813 						bdwrite (b0p);
814 						brelse (bp);
815 
816 						error = hpfs_bmmarkfree(hpmp,
817 								anp->an_lsn, 1);
818 						if (error)
819 							return (error);
820 
821 						AB_RMAN(abp);
822 					} else {
823 						/* True error */
824 						brelse (b0p);
825 						brelse (bp);
826 						return (error);
827 					}
828 				} else {
829 					/* Nowhere to concatenate */
830 					bdwrite (bp);
831 				}
832 
833 				/* There can not be any more entries
834 				 * over greater bn, becouse last AlSec
835 				 * wasn't freed totally. So go out.
836 				 */
837 				break;
838 			}
839 		}
840 
841 		if (abp->ab_busycnt == 0)
842 			*resp = 1;
843 		else
844 			*resp = 0;
845 	} else {
846 		/*
847 		 * Scan array of AlLeafs backward,
848 		 * free all above bn.
849 		 */
850 		alp = AB_LASTALP(abp);
851 
852 		while (abp->ab_busycnt && (bn < alp->al_off + alp->al_len)){
853 			dprintf(("hpfs_truncatealblk: AlLeaf: [0x%x,0x%x,0x%x] \n",
854 				 alp->al_off,alp->al_len,alp->al_lsn));
855 
856 			if (bn <= alp->al_off) {
857 				error = hpfs_bmmarkfree(hpmp, alp->al_lsn,
858 						alp->al_len);
859 				if (error)
860 					return (error);
861 
862 				AB_RMAL(abp);
863 				alp --;
864 			} else if ((bn > alp->al_off) &&
865 			    	   (bn < alp->al_off + alp->al_len)){
866 				error = hpfs_bmmarkfree(hpmp,
867 						alp->al_lsn + bn - alp->al_off,
868 						alp->al_len - bn + alp->al_off);
869 				if (error)
870 					return (error);
871 
872 				alp->al_len = bn - alp->al_off;
873 
874 				break;
875 			} else
876 				break;
877 		}
878 	}
879 
880 	/* Signal parent deallocation, if need */
881 	if (abp->ab_busycnt == 0)
882 		*resp = 1;
883 	else
884 		*resp = 0;
885 
886 	return (0);
887 }
888