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