diff options
author | semenu <semenu@FreeBSD.org> | 1999-12-09 19:10:13 +0000 |
---|---|---|
committer | semenu <semenu@FreeBSD.org> | 1999-12-09 19:10:13 +0000 |
commit | d230d55c6a76b5a3528898567115e4434c5d5885 (patch) | |
tree | 5d7427b5398caa08bf403312440238a6226bb8d4 /sys/fs/hpfs/hpfs_alsubr.c | |
parent | dd77f5d4fb9ad73450c3c19665c2c0841b74ba62 (diff) | |
download | FreeBSD-src-d230d55c6a76b5a3528898567115e4434c5d5885.zip FreeBSD-src-d230d55c6a76b5a3528898567115e4434c5d5885.tar.gz |
First version of HPFS stuff.
Diffstat (limited to 'sys/fs/hpfs/hpfs_alsubr.c')
-rw-r--r-- | sys/fs/hpfs/hpfs_alsubr.c | 906 |
1 files changed, 906 insertions, 0 deletions
diff --git a/sys/fs/hpfs/hpfs_alsubr.c b/sys/fs/hpfs/hpfs_alsubr.c new file mode 100644 index 0000000..52ca645 --- /dev/null +++ b/sys/fs/hpfs/hpfs_alsubr.c @@ -0,0 +1,906 @@ +/*- + * Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/proc.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/vnode.h> +#include <sys/mount.h> +#include <sys/namei.h> +#include <sys/malloc.h> +#include <sys/buf.h> + +#include <fs/hpfs/hpfs.h> +#include <fs/hpfs/hpfs_subr.h> + +#define AE_DONE 0 /* Nothing to change */ +#define AE_SPLIT 2 /* Split was done, ranp is valid */ + +int hpfs_addextentr (struct hpfsmount *, lsn_t, alleaf_t *, + alnode_t *, u_long *); +int hpfs_allocalsec (struct hpfsmount *, lsn_t, struct buf **); +int hpfs_alblk2alsec (struct hpfsmount *, alblk_t *, alsec_t **, + struct buf **); +int hpfs_splitalsec (struct hpfsmount *, alsec_t *, alsec_t **, + struct buf **); +int hpfs_concatalsec (struct hpfsmount *, alsec_t *, alsec_t *, + alnode_t *); + +/* + * Map file offset to disk offset. hpfsnode have to be locked. + */ +int +hpfs_hpbmap(hp, bn, bnp, runp) + struct hpfsnode *hp; + daddr_t bn; + daddr_t *bnp; + int *runp; +{ + struct buf *bp; + alblk_t * abp; + alleaf_t *alp; + alnode_t *anp; + int error, i; + + dprintf(("hpfs_hpbmap(0x%x, 0x%x): ",hp->h_no, bn)); + + bp = NULL; + abp = &hp->h_fn.fn_ab; + alp = (alleaf_t *)&hp->h_fn.fn_abd; + anp = (alnode_t *)&hp->h_fn.fn_abd; + +dive: + if (abp->ab_flag & AB_NODES) { + for (i=0; i<abp->ab_busycnt; i++, anp++) { + dprintf(("[0x%x,0x%x] ",anp->an_nextoff,anp->an_lsn)); + if (bn < anp->an_nextoff) { + alsec_t *asp; + + dprintf(("< found | ")); + + if (bp) + brelse(bp); + error = bread(hp->h_devvp, anp->an_lsn, + DEV_BSIZE, NOCRED, &bp); + if (error) { + printf("hpfs_hpbmap: bread error\n"); + brelse(bp); + return (error); + } + + asp = (alsec_t *) bp->b_data; + if (asp->as_magic != AS_MAGIC) { + brelse(bp); + printf("hpfs_hpbmap: " + "MAGIC DOESN'T MATCH"); + return (EINVAL); + } + + abp = &asp->as_ab; + alp = (alleaf_t *)&asp->as_abd; + anp = (alnode_t *)&asp->as_abd; + + goto dive; + } + } + } else { + for (i=0; i<abp->ab_busycnt; i++, alp++) { + dprintf(("[0x%x,0x%x,0x%x] ", + alp->al_off,alp->al_len,alp->al_lsn)); + + if ((bn >= alp->al_off) && + (!alp->al_len || (bn < alp->al_off + alp->al_len))) { + dprintf(("found, ")); + + *bnp = bn - alp->al_off + alp->al_lsn; + + dprintf((" 0x%x ", *bnp)); + + if (runp != NULL) { + if (alp->al_len) + *runp = alp->al_off - 1 + + alp->al_len - bn; + else + *runp = 3; /* XXX */ + + dprintf((" 0x%x cont", *runp)); + } + + if (bp) + brelse(bp); + + dprintf(("\n")); + return (0); + } + } + } + + dprintf(("END, notfound\n")); + if (bp) + brelse(bp); + + dprintf(("hpfs_hpbmap: offset too big\n")); + + return (EFBIG); +} + +/* + * Find place and preinitialize AlSec structure + * AlBlk is initialized to contain AlLeafs. + */ +int +hpfs_allocalsec ( + struct hpfsmount *hpmp, + lsn_t parlsn, + struct buf **bpp) +{ + alsec_t * asp; + struct buf * bp; + lsn_t lsn; + int error; + + *bpp = NULL; + + error = hpfs_bmfblookup(hpmp, &lsn); + if (error) { + printf("hpfs_allocalsec: CAN'T ALLOC SPACE FOR AlSec\n"); + return (error); + } + + error = hpfs_bmmarkbusy(hpmp, lsn, 1); + if (error) + return (error); + + bp = getblk(hpmp->hpm_devvp, lsn, DEV_BSIZE, 0, 0); + clrbuf(bp); + + /* Fill AlSec info */ + asp = (alsec_t *) bp->b_data; + asp->as_magic = AS_MAGIC; + asp->as_self = lsn; + asp->as_parent = parlsn; + + /* Fill AlBlk */ + asp->as_ab.ab_flag = 0; + asp->as_ab.ab_busycnt = 0; + asp->as_ab.ab_freecnt = 0x28; + asp->as_ab.ab_freeoff = sizeof(alblk_t); + + *bpp = bp; + + return (0); +} + +/* + * Split AlSec structure into new allocated: + * allocate new AlSec; then move second half of asp's entries in + * into it; set proper flags. + * + * IF AlSec CONTAINS AlNodes, THEN YOU ALMOST EVERYTIME HAVE TO + * FIX LAST AlNode in OLD AlSec (NEXTOFF TO BE 0xFFFFFFFF). + * TOGETHER WITH FIXING ALL CHILDREN'S AlSecs (THEY HAVE GOT NEW PARENT). + */ +int +hpfs_splitalsec ( + struct hpfsmount *hpmp, + alsec_t *asp, + alsec_t **naspp, + struct buf **nbpp) +{ + alsec_t *nasp; + struct buf *nbp; + alblk_t *abp; + alblk_t *nabp; + int error, n1, n2, sz; + + error = hpfs_allocalsec(hpmp, asp->as_parent, &nbp); + if (error) + return (error); + + nasp = (alsec_t *)nbp->b_data; + nabp = &nasp->as_ab; + abp = &asp->as_ab; + + n1 = (abp->ab_busycnt + 1) / 2; + n2 = (abp->ab_busycnt - n1); + sz = (abp->ab_flag & AB_NODES) ? sizeof(alnode_t) : sizeof(alleaf_t); + + bcopy((caddr_t)abp + sizeof(alblk_t) + n1 * sz, + (caddr_t)nabp + sizeof(alblk_t), n2 * sz); + + nabp->ab_flag = abp->ab_flag; + nabp->ab_busycnt = n2; + nabp->ab_freecnt = (0x1e0 / sz - n2); + nabp->ab_freeoff += n2 * sz; + + abp->ab_busycnt -= n1; + abp->ab_freecnt += n1; + abp->ab_freeoff -= n1 * sz; + + *naspp = nasp; + *nbpp = nbp; + + return (0); +} + +/* + * Try to concatenate two AlSec's + * + * Moves all entries from AlSec corresponding (as1p, aanp[1]) into + * corresponding aanp[0] one. If not enought space, then return ENOSPC. + * + * WARNING! YOU HAVE TO FIX aanp VALUES YOURSELF LATER: + * aanp[0].an_nextoff = aanp[1].an_nextoff; + */ +int +hpfs_concatalsec ( + struct hpfsmount *hpmp, + alsec_t *as0p, + alsec_t *as1p, + alnode_t *aanp) +{ + alblk_t *ab0p; + alblk_t *ab1p; + int sz; + + dprintf(("hpfs_concatalsec: AlSecs at 0x%x and 0x%x \n", + as0p->as_self,as1p->as_self)); + + ab0p = &as0p->as_ab; + ab1p = &as1p->as_ab; + sz = (ab0p->ab_flag & AB_NODES) ? sizeof(alnode_t) : sizeof(alleaf_t); + + if (ab0p->ab_freecnt > ab1p->ab_busycnt) { + /* + * Concatenate AlSecs + */ + if (ab0p->ab_flag & AB_NODES) + AB_LASTANP(ab0p)->an_nextoff = aanp[0].an_nextoff; + + bcopy (AB_ALNODE(ab1p), AB_FREEANP(ab0p), + ab1p->ab_busycnt * sz); + + AB_ADDNREC(ab0p, sz, ab1p->ab_busycnt); + + return (0); + } else { + /* Not enought space to concatenate */ + return (ENOSPC); + } +} + +/* + * Transform AlBlk structure into new allocated + * AlSec. + * + * DOESN'T SET AlSec'S PARENT LSN. + */ +int +hpfs_alblk2alsec ( + struct hpfsmount *hpmp, + alblk_t *abp, + alsec_t **naspp, + struct buf **nbpp) +{ + alsec_t *nasp; + alblk_t *nabp; + struct buf *nbp; + int error, sz; + + error = hpfs_allocalsec(hpmp, 0, &nbp); + if (error) + return (error); + + nasp = (alsec_t *)nbp->b_data; + nabp = &nasp->as_ab; + + sz = (abp->ab_flag & AB_NODES) ? sizeof(alnode_t) : sizeof(alleaf_t); + + bcopy (abp, nabp, sizeof(alblk_t) + sz * abp->ab_busycnt); + + nabp->ab_freecnt = 0x1e0 / sz - nabp->ab_busycnt; + + *naspp = nasp; + *nbpp = nbp; + + return (0); +} + +/* + * Allocate len blocks and concatenate them to file. + * If we hadn't found contignous run of len blocks, concatenate + * as much as we can, and return. + * + */ +int +hpfs_addextent ( + struct hpfsmount *hpmp, + struct hpfsnode *hp, + u_long len) +{ + alblk_t *rabp; + alnode_t ranp[2]; + alleaf_t al; + int error; + u_long pf; + + /* + * We don't know for now start lsn of block + */ + al.al_lsn = ~0; + al.al_len = len; + al.al_off = (hp->h_fn.fn_size + DEV_BSIZE - 1) >> DEV_BSHIFT; + + rabp = &hp->h_fn.fn_ab; + + /* Init AlBlk if this is first extent */ + if (al.al_off == 0) { + lsn_t nlsn; + u_long nlen; + + dprintf(("hpfs_addextent: init AlBlk in root\n")); + + rabp->ab_busycnt = 0; + rabp->ab_freecnt = 0x8; + rabp->ab_freeoff = sizeof(alblk_t); + rabp->ab_flag = 0; + + error = hpfs_bmlookup (hpmp, 0, hp->h_no + 1, al.al_len, &nlsn, &nlen); + if (error) + return (error); + + error = hpfs_bmmarkbusy(hpmp, nlsn, nlen); + if (error) + return (error); + + dprintf(("hpfs_addextent: new: 0x%x 0x%lx, ", nlsn, nlen)); + + AL_SET(AB_FREEALP(rabp), al.al_off, nlen, nlsn); + AB_ADDAL(rabp); + + al.al_off += nlen; + al.al_len -= nlen; + } + +retry: + dprintf(("hpfs_addextent: AlBlk: [0x%x, 0x%x, 0x%x] need: 0x%x\n", + rabp->ab_freecnt, rabp->ab_busycnt, rabp->ab_flag, al.al_len)); + + while ((al.al_len) && (rabp->ab_freecnt > 0)) { + if (rabp->ab_flag & AB_NODES) { + alnode_t *anp; + /* + * This is level containing AlNodes, so try to + * insert recursively into last entry. + */ + anp = AB_LASTANP(rabp); + dprintf(("hpfs_addextent: AlNode: [0x%x,0x%x] \n", + anp->an_nextoff,anp->an_lsn)); + + /* + * Try to insert... + */ + error = hpfs_addextentr (hpmp, anp->an_lsn, &al, ranp, &pf); + if (error) { + printf("hpfs_addextent: FAILED %d\n",error); + return (error); + } + + switch (pf) { + case AE_SPLIT: + dprintf(("hpfs_addextent: successful (split)\n")); + /* + * Then hpfs_addextentr has split tree below, now + * we need to fix this level. Particulary: + * fix last AlNode and add another one. + */ + + bcopy(ranp, AB_LASTANP(rabp), sizeof(alnode_t) * 2); + AB_ADDAN(rabp); + break; + + default: + case AE_DONE: + dprintf(("hpfs_addextent: successful\n")); + break; + } + } else { + alleaf_t *alp; + + alp = AB_LASTALP(rabp); + dprintf(("hpfs_addextent: AlLeaf: [0x%x,0x%x,0x%x] \n", + alp->al_off,alp->al_len,alp->al_lsn)); + + /* Check if we trying to add in right place */ + if (alp->al_off + alp->al_len == al.al_off) { + lsn_t nlsn; + u_long nlen; + + /* + * Search bitmap for block begining from + * alp->al_lsn + alp->al_len and long of ralp->al_len + */ + error = hpfs_bmlookup (hpmp, 0, + alp->al_lsn + alp->al_len, al.al_len, &nlsn, &nlen); + if (error) + return (error); + + error = hpfs_bmmarkbusy(hpmp, nlsn, nlen); + if (error) + return (error); + + dprintf(("hpfs_addextent: new: 0x%x 0x%lx, ", nlsn, nlen)); + + if (alp->al_lsn + alp->al_len == nlsn) { + dprintf(("extended existed leaf\n")); + + alp->al_len += nlen; + } else { + dprintf(("created new leaf\n")); + AL_SET(AB_FREEALP(rabp), al.al_off, nlen, nlsn); + AB_ADDAL(rabp); + } + al.al_off += nlen; + al.al_len -= nlen; + } else { + printf("hpfs_addextent: INTERNAL INCONSISTENCE\n"); + return (EINVAL); + } + } + } + + /* + * Move AlBlk contain to new AlSec (it will fit more + * entries) if overflowed (no more free entries). + */ + if (rabp->ab_freecnt <= 0) { + struct buf *nbp; + alsec_t * nrasp; + + dprintf(("hpfs_addextent: overflow, convt\n")); + + /* + * Convert AlBlk to new AlSec, it will set + * AB_FNPARENT also. + */ + rabp->ab_flag |= AB_FNPARENT; + error = hpfs_alblk2alsec (hpmp, rabp, &nrasp, &nbp); + if (error) { + printf("hpfs_addextent: CAN'T CONVT\n"); + return (error); + } + nrasp->as_parent = hp->h_no; + + /* + * Scan all childrens (if exist), set new parent and + * clean their AB_FNPARENT flag. + */ + if (rabp->ab_flag & AB_NODES) { + int i; + alsec_t * asp; + alnode_t * anp; + struct buf * bp; + + anp = AB_ALNODE(rabp); + for (i=0; i<rabp->ab_busycnt; i++) { + error = hpfs_breadalsec(hpmp, anp->an_lsn, &bp); + if (error) + return (error); + + asp = (alsec_t *)bp->b_data; + asp->as_ab.ab_flag &= ~AB_FNPARENT; + asp->as_parent = nrasp->as_self; + + bdwrite(bp); + anp ++; + } + } + + /* Convert AlBlk to contain AlNodes */ + rabp->ab_flag = AB_NODES; + rabp->ab_busycnt = 0; + rabp->ab_freecnt = 0xC; + rabp->ab_freeoff = sizeof(alblk_t); + + /* Add AlNode for new allocated AlSec */ + AN_SET(AB_FREEANP(rabp), ~0, nrasp->as_self); + AB_ADDAN(rabp); + + bdwrite(nbp); + } + + if (al.al_len) { + dprintf(("hpfs_addextent: root retry\n")); + goto retry; + } + + return (0); +} + +/* + * Descent down to the end of tree, then search for + * ralp->len contignous run begining from last run's end and + * concatenate new block! If we can't find one, then... + */ +int +hpfs_addextentr ( + struct hpfsmount *hpmp, /* Mix info */ + lsn_t rlsn, /* LSN containing AlSec */ + alleaf_t *ralp, /* AlLeaf to insert */ + alnode_t *ranp, /* New AlNodes' values */ + u_long *resp) /* Mix returning info */ +{ + struct buf *rbp; + alsec_t *rasp; + alblk_t *rabp; + alleaf_t *alp; + alnode_t *anp; + int error; + u_long pf; + u_long wb; + + *resp = 0; + + dprintf(("hpfs_addextentr: AlSec at 0x%x\n", rlsn)); + + error = hpfs_breadalsec(hpmp, rlsn, &rbp); + if (error) + return (error); + + rasp = (alsec_t *)rbp->b_data; + rabp = &rasp->as_ab; + wb = 0; + + dprintf(("hpfs_addextentr: AlBlk: [0x%x, 0x%x, 0x%x]\n", + rabp->ab_freecnt, rabp->ab_busycnt, rabp->ab_flag)); + + while ((ralp->al_len) && (rabp->ab_freecnt > 0)) { + if (rabp->ab_flag & AB_NODES) { + /* + * This is level containing AlNodes, so try to + * insert recursively into last entry. + */ + anp = AB_LASTANP(rabp); + dprintf(("hpfs_addextentr: AlNode: [0x%x,0x%x] \n", + anp->an_nextoff,anp->an_lsn)); + + /* + * Try to insert... + */ + error = hpfs_addextentr (hpmp, anp->an_lsn, ralp, ranp, &pf); + if (error) { + printf("hpfs_addextentr: FAILED %d\n",error); + goto fail; + } + + switch (pf) { + case AE_SPLIT: + dprintf(("hpfs_addextentr: successful (split)\n")); + /* + * Then hpfs_addextentr has split tree below, now + * we need to fix this level. Particulary: + * fix last AlNode and add another one. + */ + bcopy(ranp, AB_LASTANP(rabp), sizeof(alnode_t) * 2); + AB_ADDAN(rabp); + wb = 1; + break; + + default: + case AE_DONE: + dprintf(("hpfs_addextentr: successful\n")); + break; + } + } else { + alp = AB_LASTALP(rabp); + dprintf(("hpfs_addextentr: AlLeaf: [0x%x,0x%x,0x%x] \n", + alp->al_off,alp->al_len,alp->al_lsn)); + + /* Check if we trying to add in right place */ + if (alp->al_off + alp->al_len == ralp->al_off) { + lsn_t nlsn; + u_long nlen; + /* + * Search bitmap for block begining from + * alp->al_lsn + alp->al_len and long of ralp->al_len + */ + error = hpfs_bmlookup (hpmp, 0, + alp->al_lsn + alp->al_len, ralp->al_len, &nlsn, &nlen); + if (error) + goto fail; + + error = hpfs_bmmarkbusy(hpmp, nlsn, nlen); + if (error) + goto fail; + + dprintf(("hpfs_addextentr: new: 0x%x 0x%lx, ", nlsn, nlen)); + + /* + * If ending of existed entry fits the + * begining of the extent being added, + * then we add concatenate two extents. + */ + if (alp->al_lsn + alp->al_len == nlsn) { + dprintf(("concat\n")); + alp->al_len += nlen; + } else { + dprintf(("created new leaf\n")); + AL_SET(AB_FREEALP(rabp), ralp->al_off, nlen, nlsn); + AB_ADDAL(rabp); + } + + ralp->al_len -= nlen; + ralp->al_off += nlen; + } else { + printf("hpfs_addextentr: INTERNAL INCONSISTENCE\n"); + error = (EINVAL); + goto fail; + } + } + } + + /* + * Split AlBlk if overflowed. + */ + if (rabp->ab_freecnt <= 0) { + struct buf *nbp; + alsec_t * nrasp; + + dprintf(("hpfs_addextentr: overflow, split\n")); + + error = hpfs_splitalsec (hpmp, rasp, &nrasp, &nbp); + if (error) { + printf("hpfs_addextent: CAN'T SPLIT\n"); + goto fail; + } + + if (rabp->ab_flag & AB_NODES) { + int i; + alsec_t * asp; + alnode_t * anp; + struct buf * bp; + + ranp[0].an_nextoff = + AB_LASTANP(&rasp->as_ab)->an_nextoff; + + /* We need to set left subtree's last entry + * offset to 0xFFFFFFFF for OS/2 to be able + * to read our files. It treats absence of + * 0xFFFFFFFF as error. + */ + AB_LASTANP(&rasp->as_ab)->an_nextoff = ~0; + + /* We need to fix new allocated AlSec's + * children, becouse their parent has changed. + */ + anp = AB_ALNODE(&nrasp->as_ab); + for (i=0; i<nrasp->as_ab.ab_busycnt; i++) { + error = hpfs_breadalsec(hpmp, anp->an_lsn, &bp); + if (error) { + brelse(nbp); + goto fail; + } + + asp = (alsec_t *)bp->b_data; + asp->as_parent = nrasp->as_self; + + bdwrite(bp); + anp ++; + } + } else { + ranp[0].an_nextoff = + AB_ALLEAF(&nrasp->as_ab)->al_off; + } + + ranp[0].an_lsn = rasp->as_self; + ranp[1].an_nextoff = ~0; + ranp[1].an_lsn = nrasp->as_self; + + bdwrite(nbp); + + *resp = AE_SPLIT; + wb = 1; + } + + if (wb) + bdwrite (rbp); + else + brelse(rbp); + + return (0); + +fail: + brelse(rbp); + + return (error); +} + +/* + * Recursive routine walking down the b-tree and deallocating all + * extents above bn. Returns *resp != 0 if alblk was totally + * deallocated and may be freed. Tries to keep b-tree. + * + * (XXXX) NOTE! THIS ROUTINE WILL NEVER DECREMENT DEPTH OF + * THE TREE. + */ +int +hpfs_truncatealblk ( + struct hpfsmount *hpmp, + alblk_t *abp, + lsn_t bn, + int *resp) +{ + int error; + alleaf_t *alp; + alnode_t *anp; + alsec_t *asp; + struct buf *bp; + + dprintf(("hpfs_truncatealblk: AlBlk: [0x%x,0x%x, 0x%x]\n", + abp->ab_freecnt, abp->ab_busycnt, abp->ab_flag)); + + if (abp->ab_flag & AB_NODES) { + /* + * Scan array of AlNodes backward, + * diving in recursion if needed + */ + anp = AB_LASTANP(abp); + + while (abp->ab_busycnt && (bn <= anp->an_nextoff)) { + dprintf(("hpfs_truncatealblk: AlNode: [0x%x,0x%x] \n", + anp->an_nextoff,anp->an_lsn)); + + error = hpfs_breadalsec(hpmp, anp->an_lsn, &bp); + if (error) + return (error); + + asp = (alsec_t *)bp->b_data; + + error = hpfs_truncatealblk (hpmp, + &asp->as_ab, bn, resp); + if (error) { + brelse(bp); + return (error); + } + + if (*resp) { + brelse (bp); + + error = hpfs_bmmarkfree(hpmp, + anp->an_lsn, 1); + if (error) + return (error); + + AB_RMAN(abp); + anp --; + } else { + /* + * We have deallocated some entries, some space + * migth been freed, then try to concat two + * last AlSec. + */ + anp->an_nextoff = ~0; + if (abp->ab_busycnt >= 2) { + alsec_t *as0p; + struct buf *b0p; + + error = hpfs_breadalsec(hpmp, + (anp-1)->an_lsn, &b0p); + if (error) + return (error); + + as0p = (alsec_t *)b0p->b_data; + error = hpfs_concatalsec(hpmp, + as0p, asp, anp - 1); + if (error == ENOSPC) { + /* Not enought space */ + brelse (b0p); + bdwrite (bp); + } else if (error == 0) { + /* All OK */ + (anp-1)->an_nextoff = anp->an_nextoff; + + bdwrite (b0p); + brelse (bp); + + error = hpfs_bmmarkfree(hpmp, + anp->an_lsn, 1); + if (error) + return (error); + + AB_RMAN(abp); + } else { + /* True error */ + brelse (b0p); + brelse (bp); + return (error); + } + } else { + /* Nowhere to concatenate */ + bdwrite (bp); + } + + /* There can not be any more entries + * over greater bn, becouse last AlSec + * wasn't freed totally. So go out. + */ + break; + } + } + + if (abp->ab_busycnt == 0) + *resp = 1; + else + *resp = 0; + } else { + /* + * Scan array of AlLeafs backward, + * free all above bn. + */ + alp = AB_LASTALP(abp); + + while (abp->ab_busycnt && (bn < alp->al_off + alp->al_len)){ + dprintf(("hpfs_truncatealblk: AlLeaf: [0x%x,0x%x,0x%x] \n", + alp->al_off,alp->al_len,alp->al_lsn)); + + if (bn <= alp->al_off) { + error = hpfs_bmmarkfree(hpmp, alp->al_lsn, + alp->al_len); + if (error) + return (error); + + AB_RMAL(abp); + alp --; + } else if ((bn > alp->al_off) && + (bn < alp->al_off + alp->al_len)){ + error = hpfs_bmmarkfree(hpmp, + alp->al_lsn + bn - alp->al_off, + alp->al_len - bn + alp->al_off); + if (error) + return (error); + + alp->al_len = bn - alp->al_off; + + break; + } else + break; + } + } + + /* Signal parent deallocation, if need */ + if (abp->ab_busycnt == 0) + *resp = 1; + else + *resp = 0; + + return (0); +} |