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