Annotation of XNU/bsd/ufs/lfs/lfs_segment.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*     $NetBSD: lfs_segment.c,v 1.3 1994/08/21 03:15:32 cgd Exp $      */
        !            23: 
        !            24: /*
        !            25:  * Copyright (c) 1991, 1993
        !            26:  *     The Regents of the University of California.  All rights reserved.
        !            27:  *
        !            28:  * Redistribution and use in source and binary forms, with or without
        !            29:  * modification, are permitted provided that the following conditions
        !            30:  * are met:
        !            31:  * 1. Redistributions of source code must retain the above copyright
        !            32:  *    notice, this list of conditions and the following disclaimer.
        !            33:  * 2. Redistributions in binary form must reproduce the above copyright
        !            34:  *    notice, this list of conditions and the following disclaimer in the
        !            35:  *    documentation and/or other materials provided with the distribution.
        !            36:  * 3. All advertising materials mentioning features or use of this software
        !            37:  *    must display the following acknowledgement:
        !            38:  *     This product includes software developed by the University of
        !            39:  *     California, Berkeley and its contributors.
        !            40:  * 4. Neither the name of the University nor the names of its contributors
        !            41:  *    may be used to endorse or promote products derived from this software
        !            42:  *    without specific prior written permission.
        !            43:  *
        !            44:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            45:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            46:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            47:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            48:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            49:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            50:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            51:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            52:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            53:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            54:  * SUCH DAMAGE.
        !            55:  *
        !            56:  *     @(#)lfs_segment.c       8.5 (Berkeley) 1/4/94
        !            57:  */
        !            58: 
        !            59: #include <sys/param.h>
        !            60: #include <sys/systm.h>
        !            61: #include <sys/namei.h>
        !            62: #include <sys/kernel.h>
        !            63: #include <sys/resourcevar.h>
        !            64: #include <sys/file.h>
        !            65: #include <sys/stat.h>
        !            66: #include <sys/buf.h>
        !            67: #include <sys/proc.h>
        !            68: #include <sys/conf.h>
        !            69: #include <sys/vnode.h>
        !            70: #include <sys/malloc.h>
        !            71: #include <sys/mount.h>
        !            72: 
        !            73: #include <miscfs/specfs/specdev.h>
        !            74: #include <miscfs/fifofs/fifo.h>
        !            75: 
        !            76: #include <ufs/ufs/quota.h>
        !            77: #include <ufs/ufs/inode.h>
        !            78: #include <ufs/ufs/dir.h>
        !            79: #include <ufs/ufs/ufsmount.h>
        !            80: #include <ufs/ufs/ufs_extern.h>
        !            81: 
        !            82: #include <ufs/lfs/lfs.h>
        !            83: #include <ufs/lfs/lfs_extern.h>
        !            84: 
        !            85: extern int count_lock_queue __P((void));
        !            86: 
        !            87: #define MAX_ACTIVE     10
        !            88: /*
        !            89:  * Determine if it's OK to start a partial in this segment, or if we need
        !            90:  * to go on to a new segment.
        !            91:  */
        !            92: #define        LFS_PARTIAL_FITS(fs) \
        !            93:        ((fs)->lfs_dbpseg - ((fs)->lfs_offset - (fs)->lfs_curseg) > \
        !            94:        1 << (fs)->lfs_fsbtodb)
        !            95: 
        !            96: void    lfs_callback __P((struct buf *));
        !            97: void    lfs_gather __P((struct lfs *, struct segment *,
        !            98:             struct vnode *, int (*) __P((struct lfs *, struct buf *))));
        !            99: int     lfs_gatherblock __P((struct segment *, struct buf *, int *));
        !           100: void    lfs_iset __P((struct inode *, daddr_t, time_t));
        !           101: int     lfs_match_data __P((struct lfs *, struct buf *));
        !           102: int     lfs_match_dindir __P((struct lfs *, struct buf *));
        !           103: int     lfs_match_indir __P((struct lfs *, struct buf *));
        !           104: int     lfs_match_tindir __P((struct lfs *, struct buf *));
        !           105: void    lfs_newseg __P((struct lfs *));
        !           106: void    lfs_shellsort __P((struct buf **, daddr_t *, register int));
        !           107: void    lfs_supercallback __P((struct buf *));
        !           108: void    lfs_updatemeta __P((struct segment *));
        !           109: int     lfs_vref __P((struct vnode *));
        !           110: void    lfs_vunref __P((struct vnode *));
        !           111: void    lfs_writefile __P((struct lfs *, struct segment *, struct vnode *));
        !           112: int     lfs_writeinode __P((struct lfs *, struct segment *, struct inode *));
        !           113: int     lfs_writeseg __P((struct lfs *, struct segment *));
        !           114: void    lfs_writesuper __P((struct lfs *));
        !           115: void    lfs_writevnodes __P((struct lfs *fs, struct mount *mp,
        !           116:            struct segment *sp, int dirops));
        !           117: 
        !           118: int    lfs_allclean_wakeup;            /* Cleaner wakeup address. */
        !           119: 
        !           120: /* Statistics Counters */
        !           121: #define DOSTATS
        !           122: struct lfs_stats lfs_stats;
        !           123: 
        !           124: /* op values to lfs_writevnodes */
        !           125: #define        VN_REG  0
        !           126: #define        VN_DIROP        1
        !           127: #define        VN_EMPTY        2
        !           128: 
        !           129: /*
        !           130:  * Ifile and meta data blocks are not marked busy, so segment writes MUST be
        !           131:  * single threaded.  Currently, there are two paths into lfs_segwrite, sync()
        !           132:  * and getnewbuf().  They both mark the file system busy.  Lfs_vflush()
        !           133:  * explicitly marks the file system busy.  So lfs_segwrite is safe.  I think.
        !           134:  */
        !           135: 
        !           136: int
        !           137: lfs_vflush(vp)
        !           138:        struct vnode *vp;
        !           139: {
        !           140:        struct inode *ip;
        !           141:        struct lfs *fs;
        !           142:        struct segment *sp;
        !           143: 
        !           144:        fs = VFSTOUFS(vp->v_mount)->um_lfs;
        !           145:        if (fs->lfs_nactive > MAX_ACTIVE)
        !           146:                return(lfs_segwrite(vp->v_mount, SEGM_SYNC|SEGM_CKP));
        !           147:        lfs_seglock(fs, SEGM_SYNC);
        !           148:        sp = fs->lfs_sp;
        !           149: 
        !           150: 
        !           151:        ip = VTOI(vp);
        !           152:        if (vp->v_dirtyblkhd.lh_first == NULL)
        !           153:                lfs_writevnodes(fs, vp->v_mount, sp, VN_EMPTY);
        !           154: 
        !           155:        do {
        !           156:                do {
        !           157:                        if (vp->v_dirtyblkhd.lh_first != NULL)
        !           158:                                lfs_writefile(fs, sp, vp);
        !           159:                } while (lfs_writeinode(fs, sp, ip));
        !           160: 
        !           161:        } while (lfs_writeseg(fs, sp) && ip->i_number == LFS_IFILE_INUM);
        !           162: 
        !           163: #ifdef DOSTATS
        !           164:        ++lfs_stats.nwrites;
        !           165:        if (sp->seg_flags & SEGM_SYNC)
        !           166:                ++lfs_stats.nsync_writes;
        !           167:        if (sp->seg_flags & SEGM_CKP)
        !           168:                ++lfs_stats.ncheckpoints;
        !           169: #endif
        !           170:        lfs_segunlock(fs);
        !           171:        return (0);
        !           172: }
        !           173: 
        !           174: void
        !           175: lfs_writevnodes(fs, mp, sp, op)
        !           176:        struct lfs *fs;
        !           177:        struct mount *mp;
        !           178:        struct segment *sp;
        !           179:        int op;
        !           180: {
        !           181:        struct inode *ip;
        !           182:        struct vnode *vp;
        !           183: 
        !           184: loop:
        !           185:        for (vp = mp->mnt_vnodelist.lh_first;
        !           186:             vp != NULL;
        !           187:             vp = vp->v_mntvnodes.le_next) {
        !           188:                /*
        !           189:                 * If the vnode that we are about to sync is no longer
        !           190:                 * associated with this mount point, start over.
        !           191:                 */
        !           192:                if (vp->v_mount != mp)
        !           193:                        goto loop;
        !           194: 
        !           195:                /* XXX ignore dirops for now
        !           196:                if (op == VN_DIROP && !(vp->v_flag & VDIROP) ||
        !           197:                    op != VN_DIROP && (vp->v_flag & VDIROP))
        !           198:                        continue;
        !           199:                */
        !           200: 
        !           201:                if (op == VN_EMPTY && vp->v_dirtyblkhd.lh_first)
        !           202:                        continue;
        !           203: 
        !           204:                if (vp->v_type == VNON)
        !           205:                        continue;
        !           206: 
        !           207:                if (lfs_vref(vp))
        !           208:                        continue;
        !           209: 
        !           210:                /*
        !           211:                 * Write the inode/file if dirty and it's not the
        !           212:                 * the IFILE.
        !           213:                 */
        !           214:                ip = VTOI(vp);
        !           215:                if ((ip->i_flag &
        !           216:                    (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE) ||
        !           217:                    vp->v_dirtyblkhd.lh_first != NULL) &&
        !           218:                    ip->i_number != LFS_IFILE_INUM) {
        !           219:                        if (vp->v_dirtyblkhd.lh_first != NULL)
        !           220:                                lfs_writefile(fs, sp, vp);
        !           221:                        (void) lfs_writeinode(fs, sp, ip);
        !           222:                }
        !           223:                vp->v_flag &= ~VDIROP;
        !           224:                lfs_vunref(vp);
        !           225:        }
        !           226: }
        !           227: 
        !           228: int
        !           229: lfs_segwrite(mp, flags)
        !           230:        struct mount *mp;
        !           231:        int flags;                      /* Do a checkpoint. */
        !           232: {
        !           233:        struct buf *bp;
        !           234:        struct inode *ip;
        !           235:        struct lfs *fs;
        !           236:        struct segment *sp;
        !           237:        struct vnode *vp;
        !           238:        SEGUSE *segusep;
        !           239:        daddr_t ibno;
        !           240:        CLEANERINFO *cip;
        !           241:        int clean, do_ckp, error, i;
        !           242: 
        !           243:        fs = VFSTOUFS(mp)->um_lfs;
        !           244: 
        !           245:        /*
        !           246:         * If we have fewer than 2 clean segments, wait until cleaner
        !           247:         * writes.
        !           248:         */
        !           249:        do {
        !           250:                LFS_CLEANERINFO(cip, fs, bp);
        !           251:                clean = cip->clean;
        !           252:                brelse(bp);
        !           253:                if (clean <= 2) {
        !           254:                        printf ("segs clean: %d\n", clean);
        !           255:                        wakeup(&lfs_allclean_wakeup);
        !           256:                        if (error = tsleep(&fs->lfs_avail, PRIBIO + 1,
        !           257:                            "lfs writer", 0))
        !           258:                                return (error);
        !           259:                }
        !           260:        } while (clean <= 2 );
        !           261: 
        !           262:        /*
        !           263:         * Allocate a segment structure and enough space to hold pointers to
        !           264:         * the maximum possible number of buffers which can be described in a
        !           265:         * single summary block.
        !           266:         */
        !           267:        do_ckp = flags & SEGM_CKP || fs->lfs_nactive > MAX_ACTIVE;
        !           268:        lfs_seglock(fs, flags | (do_ckp ? SEGM_CKP : 0));
        !           269:        sp = fs->lfs_sp;
        !           270: 
        !           271:        lfs_writevnodes(fs, mp, sp, VN_REG);
        !           272: 
        !           273:        /* XXX ignore ordering of dirops for now */
        !           274:        /* XXX
        !           275:        fs->lfs_writer = 1;
        !           276:        if (fs->lfs_dirops && (error =
        !           277:            tsleep(&fs->lfs_writer, PRIBIO + 1, "lfs writer", 0))) {
        !           278:                free(sp->bpp, M_SEGMENT);
        !           279:                free(sp, M_SEGMENT); 
        !           280:                fs->lfs_writer = 0;
        !           281:                return (error);
        !           282:        }
        !           283: 
        !           284:        lfs_writevnodes(fs, mp, sp, VN_DIROP);
        !           285:        */
        !           286: 
        !           287:        /*
        !           288:         * If we are doing a checkpoint, mark everything since the
        !           289:         * last checkpoint as no longer ACTIVE.
        !           290:         */
        !           291:        if (do_ckp)
        !           292:                for (ibno = fs->lfs_cleansz + fs->lfs_segtabsz;
        !           293:                     --ibno >= fs->lfs_cleansz; ) {
        !           294:                        if (bread(fs->lfs_ivnode, ibno, fs->lfs_bsize,
        !           295:                            NOCRED, &bp))
        !           296: 
        !           297:                                panic("lfs: ifile read");
        !           298:                        segusep = (SEGUSE *)bp->b_data;
        !           299:                        for (i = fs->lfs_sepb; i--; segusep++)
        !           300:                                segusep->su_flags &= ~SEGUSE_ACTIVE;
        !           301:                                
        !           302:                        error = VOP_BWRITE(bp);
        !           303:                }
        !           304: 
        !           305:        if (do_ckp || fs->lfs_doifile) {
        !           306: redo:
        !           307:                vp = fs->lfs_ivnode;
        !           308:                while (vget(vp, 1));
        !           309:                ip = VTOI(vp);
        !           310:                if (vp->v_dirtyblkhd.lh_first != NULL)
        !           311:                        lfs_writefile(fs, sp, vp);
        !           312:                (void)lfs_writeinode(fs, sp, ip);
        !           313:                vput(vp);
        !           314:                if (lfs_writeseg(fs, sp) && do_ckp)
        !           315:                        goto redo;
        !           316:        } else
        !           317:                (void) lfs_writeseg(fs, sp);
        !           318: 
        !           319:        /*
        !           320:         * If the I/O count is non-zero, sleep until it reaches zero.  At the
        !           321:         * moment, the user's process hangs around so we can sleep.
        !           322:         */
        !           323:        /* XXX ignore dirops for now
        !           324:        fs->lfs_writer = 0;
        !           325:        fs->lfs_doifile = 0;
        !           326:        wakeup(&fs->lfs_dirops);
        !           327:        */
        !           328: 
        !           329: #ifdef DOSTATS
        !           330:        ++lfs_stats.nwrites;
        !           331:        if (sp->seg_flags & SEGM_SYNC)
        !           332:                ++lfs_stats.nsync_writes;
        !           333:        if (sp->seg_flags & SEGM_CKP)
        !           334:                ++lfs_stats.ncheckpoints;
        !           335: #endif
        !           336:        lfs_segunlock(fs);
        !           337:        return (0);
        !           338: }
        !           339: 
        !           340: /*
        !           341:  * Write the dirty blocks associated with a vnode.
        !           342:  */
        !           343: void
        !           344: lfs_writefile(fs, sp, vp)
        !           345:        struct lfs *fs;
        !           346:        struct segment *sp;
        !           347:        struct vnode *vp;
        !           348: {
        !           349:        struct buf *bp;
        !           350:        struct finfo *fip;
        !           351:        IFILE *ifp;
        !           352: 
        !           353:        if (sp->seg_bytes_left < fs->lfs_bsize ||
        !           354:            sp->sum_bytes_left < sizeof(struct finfo))
        !           355:                (void) lfs_writeseg(fs, sp);
        !           356: 
        !           357:        sp->sum_bytes_left -= sizeof(struct finfo) - sizeof(daddr_t);
        !           358:        ++((SEGSUM *)(sp->segsum))->ss_nfinfo;
        !           359: 
        !           360:        fip = sp->fip;
        !           361:        fip->fi_nblocks = 0;
        !           362:        fip->fi_ino = VTOI(vp)->i_number;
        !           363:        LFS_IENTRY(ifp, fs, fip->fi_ino, bp);
        !           364:        fip->fi_version = ifp->if_version;
        !           365:        brelse(bp);
        !           366: 
        !           367:        /*
        !           368:         * It may not be necessary to write the meta-data blocks at this point,
        !           369:         * as the roll-forward recovery code should be able to reconstruct the
        !           370:         * list.
        !           371:         */
        !           372:        lfs_gather(fs, sp, vp, lfs_match_data);
        !           373:        lfs_gather(fs, sp, vp, lfs_match_indir);
        !           374:        lfs_gather(fs, sp, vp, lfs_match_dindir);
        !           375: #ifdef TRIPLE
        !           376:        lfs_gather(fs, sp, vp, lfs_match_tindir);
        !           377: #endif
        !           378: 
        !           379:        fip = sp->fip;
        !           380:        if (fip->fi_nblocks != 0) {
        !           381:                sp->fip =
        !           382:                    (struct finfo *)((caddr_t)fip + sizeof(struct finfo) +
        !           383:                    sizeof(daddr_t) * (fip->fi_nblocks - 1));
        !           384:                sp->start_lbp = &sp->fip->fi_blocks[0];
        !           385:        } else {
        !           386:                sp->sum_bytes_left += sizeof(struct finfo) - sizeof(daddr_t);
        !           387:                --((SEGSUM *)(sp->segsum))->ss_nfinfo;
        !           388:        }
        !           389: }
        !           390: 
        !           391: int
        !           392: lfs_writeinode(fs, sp, ip)
        !           393:        struct lfs *fs;
        !           394:        struct segment *sp;
        !           395:        struct inode *ip;
        !           396: {
        !           397:        struct buf *bp, *ibp;
        !           398:        IFILE *ifp;
        !           399:        SEGUSE *sup;
        !           400:        daddr_t daddr;
        !           401:        ino_t ino;
        !           402:        int error, i, ndx;
        !           403:        int redo_ifile = 0;
        !           404: 
        !           405:        if (!(ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)))
        !           406:                return(0);
        !           407: 
        !           408:        /* Allocate a new inode block if necessary. */
        !           409:        if (sp->ibp == NULL) {
        !           410:                /* Allocate a new segment if necessary. */
        !           411:                if (sp->seg_bytes_left < fs->lfs_bsize ||
        !           412:                    sp->sum_bytes_left < sizeof(daddr_t))
        !           413:                        (void) lfs_writeseg(fs, sp);
        !           414: 
        !           415:                /* Get next inode block. */
        !           416:                daddr = fs->lfs_offset;
        !           417:                fs->lfs_offset += fsbtodb(fs, 1);
        !           418:                sp->ibp = *sp->cbpp++ =
        !           419:                    lfs_newbuf(VTOI(fs->lfs_ivnode)->i_devvp, daddr,
        !           420:                    fs->lfs_bsize);
        !           421:                /* Zero out inode numbers */
        !           422:                for (i = 0; i < INOPB(fs); ++i)
        !           423:                        ((struct dinode *)sp->ibp->b_data)[i].di_inumber = 0;
        !           424:                ++sp->start_bpp;
        !           425:                fs->lfs_avail -= fsbtodb(fs, 1);
        !           426:                /* Set remaining space counters. */
        !           427:                sp->seg_bytes_left -= fs->lfs_bsize;
        !           428:                sp->sum_bytes_left -= sizeof(daddr_t);
        !           429:                ndx = LFS_SUMMARY_SIZE / sizeof(daddr_t) -
        !           430:                    sp->ninodes / INOPB(fs) - 1;
        !           431:                ((daddr_t *)(sp->segsum))[ndx] = daddr;
        !           432:        }
        !           433: 
        !           434:        /* Update the inode times and copy the inode onto the inode page. */
        !           435:        if (ip->i_flag & IN_MODIFIED)
        !           436:                --fs->lfs_uinodes;
        !           437:        ITIMES(ip, &time, &time);
        !           438:        ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
        !           439:        bp = sp->ibp;
        !           440:        ((struct dinode *)bp->b_data)[sp->ninodes % INOPB(fs)] = ip->i_din;
        !           441:        /* Increment inode count in segment summary block. */
        !           442:        ++((SEGSUM *)(sp->segsum))->ss_ninos;
        !           443: 
        !           444:        /* If this page is full, set flag to allocate a new page. */
        !           445:        if (++sp->ninodes % INOPB(fs) == 0)
        !           446:                sp->ibp = NULL;
        !           447: 
        !           448:        /*
        !           449:         * If updating the ifile, update the super-block.  Update the disk
        !           450:         * address and access times for this inode in the ifile.
        !           451:         */
        !           452:        ino = ip->i_number;
        !           453:        if (ino == LFS_IFILE_INUM) {
        !           454:                daddr = fs->lfs_idaddr;
        !           455:                fs->lfs_idaddr = bp->b_blkno;
        !           456:        } else {
        !           457:                LFS_IENTRY(ifp, fs, ino, ibp);
        !           458:                daddr = ifp->if_daddr;
        !           459:                ifp->if_daddr = bp->b_blkno;
        !           460:                error = VOP_BWRITE(ibp);
        !           461:        }
        !           462: 
        !           463:        /*
        !           464:         * No need to update segment usage if there was no former inode address
        !           465:         * or if the last inode address is in the current partial segment.
        !           466:         */
        !           467:        if (daddr != LFS_UNUSED_DADDR && 
        !           468:            !(daddr >= fs->lfs_lastpseg && daddr <= bp->b_blkno)) {
        !           469:                LFS_SEGENTRY(sup, fs, datosn(fs, daddr), bp);
        !           470: #if DIAGNOSTIC
        !           471:                if (sup->su_nbytes < sizeof(struct dinode)) {
        !           472:                        /* XXX -- Change to a panic. */
        !           473:                        printf("lfs: negative bytes (segment %d)\n",
        !           474:                            datosn(fs, daddr));
        !           475:                        panic("negative bytes");
        !           476:                }
        !           477: #endif
        !           478:                sup->su_nbytes -= sizeof(struct dinode);
        !           479:                redo_ifile =
        !           480:                    (ino == LFS_IFILE_INUM && !(bp->b_flags & B_GATHERED));
        !           481:                error = VOP_BWRITE(bp);
        !           482:        }
        !           483:        return (redo_ifile);
        !           484: }
        !           485: 
        !           486: int
        !           487: lfs_gatherblock(sp, bp, sptr)
        !           488:        struct segment *sp;
        !           489:        struct buf *bp;
        !           490:        int *sptr;
        !           491: {
        !           492:        struct lfs *fs;
        !           493:        int version;
        !           494: 
        !           495:        /*
        !           496:         * If full, finish this segment.  We may be doing I/O, so
        !           497:         * release and reacquire the splbio().
        !           498:         */
        !           499: #if DIAGNOSTIC
        !           500:        if (sp->vp == NULL)
        !           501:                panic ("lfs_gatherblock: Null vp in segment");
        !           502: #endif
        !           503:        fs = sp->fs;
        !           504:        if (sp->sum_bytes_left < sizeof(daddr_t) ||
        !           505:            sp->seg_bytes_left < fs->lfs_bsize) {
        !           506:                if (sptr)
        !           507:                        splx(*sptr);
        !           508:                lfs_updatemeta(sp);
        !           509: 
        !           510:                version = sp->fip->fi_version;
        !           511:                (void) lfs_writeseg(fs, sp);
        !           512: 
        !           513:                sp->fip->fi_version = version;
        !           514:                sp->fip->fi_ino = VTOI(sp->vp)->i_number;
        !           515:                /* Add the current file to the segment summary. */
        !           516:                ++((SEGSUM *)(sp->segsum))->ss_nfinfo;
        !           517:                sp->sum_bytes_left -= 
        !           518:                    sizeof(struct finfo) - sizeof(daddr_t);
        !           519: 
        !           520:                if (sptr)
        !           521:                        *sptr = splbio();
        !           522:                return(1);
        !           523:        }
        !           524: 
        !           525:        /* Insert into the buffer list, update the FINFO block. */
        !           526:        bp->b_flags |= B_GATHERED;
        !           527:        *sp->cbpp++ = bp;
        !           528:        sp->fip->fi_blocks[sp->fip->fi_nblocks++] = bp->b_lblkno;
        !           529: 
        !           530:        sp->sum_bytes_left -= sizeof(daddr_t);
        !           531:        sp->seg_bytes_left -= fs->lfs_bsize;
        !           532:        return(0);
        !           533: }
        !           534: 
        !           535: void
        !           536: lfs_gather(fs, sp, vp, match)
        !           537:        struct lfs *fs;
        !           538:        struct segment *sp;
        !           539:        struct vnode *vp;
        !           540:        int (*match) __P((struct lfs *, struct buf *));
        !           541: {
        !           542:        struct buf *bp;
        !           543:        int s;
        !           544: 
        !           545:        sp->vp = vp;
        !           546:        s = splbio();
        !           547: loop:  for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = bp->b_vnbufs.le_next) {
        !           548:                if (bp->b_flags & B_BUSY || !match(fs, bp) ||
        !           549:                    bp->b_flags & B_GATHERED)
        !           550:                        continue;
        !           551: #if DIAGNOSTIC
        !           552:                if (!(bp->b_flags & B_DELWRI))
        !           553:                        panic("lfs_gather: bp not B_DELWRI");
        !           554:                if (!(bp->b_flags & B_LOCKED))
        !           555:                        panic("lfs_gather: bp not B_LOCKED");
        !           556: #endif
        !           557:                if (lfs_gatherblock(sp, bp, &s))
        !           558:                        goto loop;
        !           559:        }
        !           560:        splx(s);
        !           561:        lfs_updatemeta(sp);
        !           562:        sp->vp = NULL;
        !           563: }
        !           564: 
        !           565: 
        !           566: /*
        !           567:  * Update the metadata that points to the blocks listed in the FINFO
        !           568:  * array.
        !           569:  */
        !           570: void
        !           571: lfs_updatemeta(sp)
        !           572:        struct segment *sp;
        !           573: {
        !           574:        SEGUSE *sup;
        !           575:        struct buf *bp;
        !           576:        struct lfs *fs;
        !           577:        struct vnode *vp;
        !           578:        struct indir a[NIADDR + 2], *ap;
        !           579:        struct inode *ip;
        !           580:        daddr_t daddr, lbn, off;
        !           581:        int db_per_fsb, error, i, nblocks, num;
        !           582: 
        !           583:        vp = sp->vp;
        !           584:        nblocks = &sp->fip->fi_blocks[sp->fip->fi_nblocks] - sp->start_lbp;
        !           585:        if (vp == NULL || nblocks == 0) 
        !           586:                return;
        !           587: 
        !           588:        /* Sort the blocks. */
        !           589:        if (!(sp->seg_flags & SEGM_CLEAN))
        !           590:                lfs_shellsort(sp->start_bpp, sp->start_lbp, nblocks);
        !           591: 
        !           592:        /*
        !           593:         * Assign disk addresses, and update references to the logical
        !           594:         * block and the segment usage information.
        !           595:         */
        !           596:        fs = sp->fs;
        !           597:        db_per_fsb = fsbtodb(fs, 1);
        !           598:        for (i = nblocks; i--; ++sp->start_bpp) {
        !           599:                lbn = *sp->start_lbp++;
        !           600:                (*sp->start_bpp)->b_blkno = off = fs->lfs_offset;
        !           601:                fs->lfs_offset += db_per_fsb;
        !           602: 
        !           603:                if (error = ufs_bmaparray(vp, lbn, &daddr, a, &num, NULL))
        !           604:                        panic("lfs_updatemeta: ufs_bmaparray %d", error);
        !           605:                ip = VTOI(vp);
        !           606:                switch (num) {
        !           607:                case 0:
        !           608:                        ip->i_db[lbn] = off;
        !           609:                        break;
        !           610:                case 1:
        !           611:                        ip->i_ib[a[0].in_off] = off;
        !           612:                        break;
        !           613:                default:
        !           614:                        ap = &a[num - 1];
        !           615:                        if (bread(vp, ap->in_lbn, fs->lfs_bsize, NOCRED, &bp))
        !           616:                                panic("lfs_updatemeta: bread bno %d",
        !           617:                                    ap->in_lbn);
        !           618:                        /*
        !           619:                         * Bread may create a new indirect block which needs
        !           620:                         * to get counted for the inode.
        !           621:                         */
        !           622:                        if (bp->b_blkno == -1 && !(bp->b_flags & B_CACHE)) {
        !           623: printf ("Updatemeta allocating indirect block: shouldn't happen\n");
        !           624:                                ip->i_blocks += btodb(fs->lfs_bsize);
        !           625:                                fs->lfs_bfree -= btodb(fs->lfs_bsize);
        !           626:                        }
        !           627:                        ((daddr_t *)bp->b_data)[ap->in_off] = off;
        !           628:                        VOP_BWRITE(bp);
        !           629:                }
        !           630: 
        !           631:                /* Update segment usage information. */
        !           632:                if (daddr != UNASSIGNED &&
        !           633:                    !(daddr >= fs->lfs_lastpseg && daddr <= off)) {
        !           634:                        LFS_SEGENTRY(sup, fs, datosn(fs, daddr), bp);
        !           635: #if DIAGNOSTIC
        !           636:                        if (sup->su_nbytes < fs->lfs_bsize) {
        !           637:                                /* XXX -- Change to a panic. */
        !           638:                                printf("lfs: negative bytes (segment %d)\n",
        !           639:                                    datosn(fs, daddr));
        !           640:                                panic ("Negative Bytes");
        !           641:                        }
        !           642: #endif
        !           643:                        sup->su_nbytes -= fs->lfs_bsize;
        !           644:                        error = VOP_BWRITE(bp);
        !           645:                }
        !           646:        }
        !           647: }
        !           648: 
        !           649: /*
        !           650:  * Start a new segment.
        !           651:  */
        !           652: int
        !           653: lfs_initseg(fs)
        !           654:        struct lfs *fs;
        !           655: {
        !           656:        struct segment *sp;
        !           657:        SEGUSE *sup;
        !           658:        SEGSUM *ssp;
        !           659:        struct buf *bp;
        !           660:        int repeat;
        !           661: 
        !           662:        sp = fs->lfs_sp;
        !           663: 
        !           664:        repeat = 0;
        !           665:        /* Advance to the next segment. */
        !           666:        if (!LFS_PARTIAL_FITS(fs)) {
        !           667:                /* Wake up any cleaning procs waiting on this file system. */
        !           668:                wakeup(&lfs_allclean_wakeup);
        !           669: 
        !           670:                lfs_newseg(fs);
        !           671:                repeat = 1;
        !           672:                fs->lfs_offset = fs->lfs_curseg;
        !           673:                sp->seg_number = datosn(fs, fs->lfs_curseg);
        !           674:                sp->seg_bytes_left = fs->lfs_dbpseg * DEV_BSIZE;
        !           675: 
        !           676:                /*
        !           677:                 * If the segment contains a superblock, update the offset
        !           678:                 * and summary address to skip over it.
        !           679:                 */
        !           680:                LFS_SEGENTRY(sup, fs, sp->seg_number, bp);
        !           681:                if (sup->su_flags & SEGUSE_SUPERBLOCK) {
        !           682:                        fs->lfs_offset += LFS_SBPAD / DEV_BSIZE;
        !           683:                        sp->seg_bytes_left -= LFS_SBPAD;
        !           684:                }
        !           685:                brelse(bp);
        !           686:        } else {
        !           687:                sp->seg_number = datosn(fs, fs->lfs_curseg);
        !           688:                sp->seg_bytes_left = (fs->lfs_dbpseg -
        !           689:                    (fs->lfs_offset - fs->lfs_curseg)) * DEV_BSIZE;
        !           690:        }
        !           691:        fs->lfs_lastpseg = fs->lfs_offset;
        !           692: 
        !           693:        sp->fs = fs;
        !           694:        sp->ibp = NULL;
        !           695:        sp->ninodes = 0;
        !           696: 
        !           697:        /* Get a new buffer for SEGSUM and enter it into the buffer list. */
        !           698:        sp->cbpp = sp->bpp;
        !           699:        *sp->cbpp = lfs_newbuf(VTOI(fs->lfs_ivnode)->i_devvp, fs->lfs_offset,
        !           700:             LFS_SUMMARY_SIZE);
        !           701:        sp->segsum = (*sp->cbpp)->b_data;
        !           702:        bzero(sp->segsum, LFS_SUMMARY_SIZE);
        !           703:        sp->start_bpp = ++sp->cbpp;
        !           704:        fs->lfs_offset += LFS_SUMMARY_SIZE / DEV_BSIZE;
        !           705: 
        !           706:        /* Set point to SEGSUM, initialize it. */
        !           707:        ssp = sp->segsum;
        !           708:        ssp->ss_next = fs->lfs_nextseg;
        !           709:        ssp->ss_nfinfo = ssp->ss_ninos = 0;
        !           710: 
        !           711:        /* Set pointer to first FINFO, initialize it. */
        !           712:        sp->fip = (struct finfo *)((caddr_t)sp->segsum + sizeof(SEGSUM));
        !           713:        sp->fip->fi_nblocks = 0;
        !           714:        sp->start_lbp = &sp->fip->fi_blocks[0];
        !           715: 
        !           716:        sp->seg_bytes_left -= LFS_SUMMARY_SIZE;
        !           717:        sp->sum_bytes_left = LFS_SUMMARY_SIZE - sizeof(SEGSUM);
        !           718: 
        !           719:        return(repeat);
        !           720: }
        !           721: 
        !           722: /*
        !           723:  * Return the next segment to write.
        !           724:  */
        !           725: void
        !           726: lfs_newseg(fs)
        !           727:        struct lfs *fs;
        !           728: {
        !           729:        CLEANERINFO *cip;
        !           730:        SEGUSE *sup;
        !           731:        struct buf *bp;
        !           732:        int curseg, isdirty, sn;
        !           733: 
        !           734:         LFS_SEGENTRY(sup, fs, datosn(fs, fs->lfs_nextseg), bp);
        !           735:         sup->su_flags |= SEGUSE_DIRTY | SEGUSE_ACTIVE;
        !           736:        sup->su_nbytes = 0;
        !           737:        sup->su_nsums = 0;
        !           738:        sup->su_ninos = 0;
        !           739:         (void) VOP_BWRITE(bp);
        !           740: 
        !           741:        LFS_CLEANERINFO(cip, fs, bp);
        !           742:        --cip->clean;
        !           743:        ++cip->dirty;
        !           744:        (void) VOP_BWRITE(bp);
        !           745: 
        !           746:        fs->lfs_lastseg = fs->lfs_curseg;
        !           747:        fs->lfs_curseg = fs->lfs_nextseg;
        !           748:        for (sn = curseg = datosn(fs, fs->lfs_curseg);;) {
        !           749:                sn = (sn + 1) % fs->lfs_nseg;
        !           750:                if (sn == curseg)
        !           751:                        panic("lfs_nextseg: no clean segments");
        !           752:                LFS_SEGENTRY(sup, fs, sn, bp);
        !           753:                isdirty = sup->su_flags & SEGUSE_DIRTY;
        !           754:                brelse(bp);
        !           755:                if (!isdirty)
        !           756:                        break;
        !           757:        }
        !           758: 
        !           759:        ++fs->lfs_nactive;
        !           760:        fs->lfs_nextseg = sntoda(fs, sn);
        !           761: #ifdef DOSTATS
        !           762:        ++lfs_stats.segsused;
        !           763: #endif
        !           764: }
        !           765: 
        !           766: int
        !           767: lfs_writeseg(fs, sp)
        !           768:        struct lfs *fs;
        !           769:        struct segment *sp;
        !           770: {
        !           771:        extern int locked_queue_count;
        !           772:        struct buf **bpp, *bp, *cbp;
        !           773:        SEGUSE *sup;
        !           774:        SEGSUM *ssp;
        !           775:        dev_t i_dev;
        !           776:        size_t size;
        !           777:        u_long *datap, *dp;
        !           778:        int ch_per_blk, do_again, i, nblocks, num, s;
        !           779:        int (*strategy)__P((struct vop_strategy_args *));
        !           780:        struct vop_strategy_args vop_strategy_a;
        !           781:        u_short ninos;
        !           782:        char *p;
        !           783: 
        !           784:        /*
        !           785:         * If there are no buffers other than the segment summary to write
        !           786:         * and it is not a checkpoint, don't do anything.  On a checkpoint,
        !           787:         * even if there aren't any buffers, you need to write the superblock.
        !           788:         */
        !           789:        if ((nblocks = sp->cbpp - sp->bpp) == 1)
        !           790:                return (0);
        !           791: 
        !           792:        ssp = (SEGSUM *)sp->segsum;
        !           793: 
        !           794:        /* Update the segment usage information. */
        !           795:        LFS_SEGENTRY(sup, fs, sp->seg_number, bp);
        !           796:        ninos = (ssp->ss_ninos + INOPB(fs) - 1) / INOPB(fs);
        !           797:        sup->su_nbytes += nblocks - 1 - ninos << fs->lfs_bshift;
        !           798:        sup->su_nbytes += ssp->ss_ninos * sizeof(struct dinode);
        !           799:        sup->su_nbytes += LFS_SUMMARY_SIZE;
        !           800:        sup->su_lastmod = time.tv_sec;
        !           801:        sup->su_ninos += ninos;
        !           802:        ++sup->su_nsums;
        !           803:        do_again = !(bp->b_flags & B_GATHERED);
        !           804:        (void)VOP_BWRITE(bp);
        !           805:        /*
        !           806:         * Compute checksum across data and then across summary; the first
        !           807:         * block (the summary block) is skipped.  Set the create time here
        !           808:         * so that it's guaranteed to be later than the inode mod times.
        !           809:         *
        !           810:         * XXX
        !           811:         * Fix this to do it inline, instead of malloc/copy.
        !           812:         */
        !           813: //     datap = dp = malloc(nblocks * sizeof(u_long), M_SEGMENT, M_WAITOK);
        !           814:        MALLOC(dp, caddr_t, nblocks * sizeof(u_long), M_SEGMENT, M_WAITOK);
        !           815:        datap = dp;
        !           816:        for (bpp = sp->bpp, i = nblocks - 1; i--;) {
        !           817:                if ((*++bpp)->b_flags & B_INVAL) {
        !           818:                        if (copyin((*bpp)->b_saveaddr, dp++, sizeof(u_long)))
        !           819:                                panic("lfs_writeseg: copyin failed");
        !           820:                } else
        !           821:                        *dp++ = ((u_long *)(*bpp)->b_data)[0];
        !           822:        }
        !           823:        ssp->ss_create = time.tv_sec;
        !           824:        ssp->ss_datasum = cksum(datap, (nblocks - 1) * sizeof(u_long));
        !           825:        ssp->ss_sumsum =
        !           826:            cksum(&ssp->ss_datasum, LFS_SUMMARY_SIZE - sizeof(ssp->ss_sumsum));
        !           827:        free(datap, M_SEGMENT);
        !           828: #if DIAGNOSTIC
        !           829:        if (fs->lfs_bfree < fsbtodb(fs, ninos) + LFS_SUMMARY_SIZE / DEV_BSIZE)
        !           830:                panic("lfs_writeseg: No diskspace for summary");
        !           831: #endif
        !           832:        fs->lfs_bfree -= (fsbtodb(fs, ninos) + LFS_SUMMARY_SIZE / DEV_BSIZE);
        !           833: 
        !           834:        i_dev = VTOI(fs->lfs_ivnode)->i_dev;
        !           835:        strategy = VTOI(fs->lfs_ivnode)->i_devvp->v_op[VOFFSET(vop_strategy)];
        !           836: 
        !           837:        /*
        !           838:         * When we simply write the blocks we lose a rotation for every block
        !           839:         * written.  To avoid this problem, we allocate memory in chunks, copy
        !           840:         * the buffers into the chunk and write the chunk.  MAXPHYS is the
        !           841:         * largest size I/O devices can handle.
        !           842:         * When the data is copied to the chunk, turn off the the B_LOCKED bit
        !           843:         * and brelse the buffer (which will move them to the LRU list).  Add
        !           844:         * the B_CALL flag to the buffer header so we can count I/O's for the
        !           845:         * checkpoints and so we can release the allocated memory.
        !           846:         *
        !           847:         * XXX
        !           848:         * This should be removed if the new virtual memory system allows us to
        !           849:         * easily make the buffers contiguous in kernel memory and if that's
        !           850:         * fast enough.
        !           851:         */
        !           852:        ch_per_blk = MAXPHYS / fs->lfs_bsize;
        !           853:        for (bpp = sp->bpp, i = nblocks; i;) {
        !           854:                num = ch_per_blk;
        !           855:                if (num > i)
        !           856:                        num = i;
        !           857:                i -= num;
        !           858:                size = num * fs->lfs_bsize;
        !           859: 
        !           860:                cbp = lfs_newbuf(VTOI(fs->lfs_ivnode)->i_devvp,
        !           861:                    (*bpp)->b_blkno, size);
        !           862:                cbp->b_dev = i_dev;
        !           863:                cbp->b_flags |= B_ASYNC | B_BUSY;
        !           864: 
        !           865:                s = splbio();
        !           866:                ++fs->lfs_iocount;
        !           867:                for (p = cbp->b_data; num--;) {
        !           868:                        bp = *bpp++;
        !           869:                        /*
        !           870:                         * Fake buffers from the cleaner are marked as B_INVAL.
        !           871:                         * We need to copy the data from user space rather than
        !           872:                         * from the buffer indicated.
        !           873:                         * XXX == what do I do on an error?
        !           874:                         */
        !           875:                        if (bp->b_flags & B_INVAL) {
        !           876:                                if (copyin(bp->b_saveaddr, p, bp->b_bcount))
        !           877:                                        panic("lfs_writeseg: copyin failed");
        !           878:                        } else
        !           879:                                bcopy(bp->b_data, p, bp->b_bcount);
        !           880:                        p += bp->b_bcount;
        !           881:                        if (bp->b_flags & B_LOCKED)
        !           882:                                --locked_queue_count;
        !           883:                        bp->b_flags &= ~(B_ERROR | B_READ | B_DELWRI |
        !           884:                             B_LOCKED | B_GATHERED);
        !           885:                        if (bp->b_flags & B_CALL) {
        !           886:                                /* if B_CALL, it was created with newbuf */
        !           887:                                brelvp(bp);
        !           888:                                if (!(bp->b_flags & B_INVAL))
        !           889:                                        free(bp->b_data, M_SEGMENT);
        !           890:                                free(bp, M_SEGMENT);
        !           891:                        } else {
        !           892:                                bremfree(bp);
        !           893:                                bp->b_flags |= B_DONE;
        !           894:                                reassignbuf(bp, bp->b_vp);
        !           895:                                brelse(bp);
        !           896:                        }
        !           897:                }
        !           898:                ++cbp->b_vp->v_numoutput;
        !           899:                splx(s);
        !           900:                cbp->b_bcount = p - (char *)cbp->b_data;
        !           901:                /*
        !           902:                 * XXXX This is a gross and disgusting hack.  Since these
        !           903:                 * buffers are physically addressed, they hang off the
        !           904:                 * device vnode (devvp).  As a result, they have no way
        !           905:                 * of getting to the LFS superblock or lfs structure to
        !           906:                 * keep track of the number of I/O's pending.  So, I am
        !           907:                 * going to stuff the fs into the saveaddr field of
        !           908:                 * the buffer (yuk).
        !           909:                 */
        !           910:                cbp->b_saveaddr = (caddr_t)fs;
        !           911:                vop_strategy_a.a_desc = VDESC(vop_strategy);
        !           912:                vop_strategy_a.a_bp = cbp;
        !           913:                (strategy)(&vop_strategy_a);
        !           914:        }
        !           915:        /*
        !           916:         * XXX
        !           917:         * Vinvalbuf can move locked buffers off the locked queue
        !           918:         * and we have no way of knowing about this.  So, after
        !           919:         * doing a big write, we recalculate how many bufers are
        !           920:         * really still left on the locked queue.
        !           921:         */
        !           922:        locked_queue_count = count_lock_queue();
        !           923:        wakeup(&locked_queue_count);
        !           924: #ifdef DOSTATS
        !           925:        ++lfs_stats.psegwrites;
        !           926:        lfs_stats.blocktot += nblocks - 1;
        !           927:        if (fs->lfs_sp->seg_flags & SEGM_SYNC)
        !           928:                ++lfs_stats.psyncwrites;
        !           929:        if (fs->lfs_sp->seg_flags & SEGM_CLEAN) {
        !           930:                ++lfs_stats.pcleanwrites;
        !           931:                lfs_stats.cleanblocks += nblocks - 1;
        !           932:        }
        !           933: #endif
        !           934:        return (lfs_initseg(fs) || do_again);
        !           935: }
        !           936: 
        !           937: void
        !           938: lfs_writesuper(fs)
        !           939:        struct lfs *fs;
        !           940: {
        !           941:        struct buf *bp;
        !           942:        dev_t i_dev;
        !           943:        int (*strategy) __P((struct vop_strategy_args *));
        !           944:        int s;
        !           945:        struct vop_strategy_args vop_strategy_a;
        !           946: 
        !           947:        i_dev = VTOI(fs->lfs_ivnode)->i_dev;
        !           948:        strategy = VTOI(fs->lfs_ivnode)->i_devvp->v_op[VOFFSET(vop_strategy)];
        !           949: 
        !           950:        /* Checksum the superblock and copy it into a buffer. */
        !           951:        fs->lfs_cksum = cksum(fs, sizeof(struct lfs) - sizeof(fs->lfs_cksum));
        !           952:        bp = lfs_newbuf(VTOI(fs->lfs_ivnode)->i_devvp, fs->lfs_sboffs[0],
        !           953:            LFS_SBPAD);
        !           954:        *(struct lfs *)bp->b_data = *fs;
        !           955: 
        !           956:        /* XXX Toggle between first two superblocks; for now just write first */
        !           957:        bp->b_dev = i_dev;
        !           958:        bp->b_flags |= B_BUSY | B_CALL | B_ASYNC;
        !           959:        bp->b_flags &= ~(B_DONE | B_ERROR | B_READ | B_DELWRI);
        !           960:        bp->b_iodone = lfs_supercallback;
        !           961:        vop_strategy_a.a_desc = VDESC(vop_strategy);
        !           962:        vop_strategy_a.a_bp = bp;
        !           963:        s = splbio();
        !           964:        ++bp->b_vp->v_numoutput;
        !           965:        splx(s);
        !           966:        (strategy)(&vop_strategy_a);
        !           967: }
        !           968: 
        !           969: /*
        !           970:  * Logical block number match routines used when traversing the dirty block
        !           971:  * chain.
        !           972:  */
        !           973: int
        !           974: lfs_match_data(fs, bp)
        !           975:        struct lfs *fs;
        !           976:        struct buf *bp;
        !           977: {
        !           978:        return (bp->b_lblkno >= 0);
        !           979: }
        !           980: 
        !           981: int
        !           982: lfs_match_indir(fs, bp)
        !           983:        struct lfs *fs;
        !           984:        struct buf *bp;
        !           985: {
        !           986:        int lbn;
        !           987: 
        !           988:        lbn = bp->b_lblkno;
        !           989:        return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 0);
        !           990: }
        !           991: 
        !           992: int
        !           993: lfs_match_dindir(fs, bp)
        !           994:        struct lfs *fs;
        !           995:        struct buf *bp;
        !           996: {
        !           997:        int lbn;
        !           998: 
        !           999:        lbn = bp->b_lblkno;
        !          1000:        return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 1);
        !          1001: }
        !          1002: 
        !          1003: int
        !          1004: lfs_match_tindir(fs, bp)
        !          1005:        struct lfs *fs;
        !          1006:        struct buf *bp;
        !          1007: {
        !          1008:        int lbn;
        !          1009: 
        !          1010:        lbn = bp->b_lblkno;
        !          1011:        return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 2);
        !          1012: }
        !          1013: 
        !          1014: /*
        !          1015:  * Allocate a new buffer header.
        !          1016:  */
        !          1017: struct buf *
        !          1018: lfs_newbuf(vp, daddr, size)
        !          1019:        struct vnode *vp;
        !          1020:        daddr_t daddr;
        !          1021:        size_t size;
        !          1022: {
        !          1023:        struct buf *bp;
        !          1024:        size_t nbytes;
        !          1025: 
        !          1026:        nbytes = roundup(size, DEV_BSIZE);
        !          1027: //     bp = malloc(sizeof(struct buf), M_SEGMENT, M_WAITOK);
        !          1028:        MALLOC(bp, struct buf *, sizeof(struct buf), M_SEGMENT, M_WAITOK);
        !          1029:        bzero(bp, sizeof(struct buf));
        !          1030:        if (nbytes)
        !          1031: //             bp->b_data = malloc(nbytes, M_SEGMENT, M_WAITOK);
        !          1032:                MALLOC(bp->d_data, caddr_t, nbytes, M_SEGMENT, M_WAITOK);
        !          1033:        bgetvp(vp, bp);
        !          1034:        bp->b_bufsize = size;
        !          1035:        bp->b_bcount = size;
        !          1036:        bp->b_lblkno = daddr;
        !          1037:        bp->b_blkno = daddr;
        !          1038:        bp->b_error = 0;
        !          1039:        bp->b_resid = 0;
        !          1040:        bp->b_iodone = lfs_callback;
        !          1041:        bp->b_flags |= B_BUSY | B_CALL | B_NOCACHE;
        !          1042:        return (bp);
        !          1043: }
        !          1044: 
        !          1045: void
        !          1046: lfs_callback(bp)
        !          1047:        struct buf *bp;
        !          1048: {
        !          1049:        struct lfs *fs;
        !          1050: 
        !          1051:        fs = (struct lfs *)bp->b_saveaddr;
        !          1052: #if DIAGNOSTIC
        !          1053:        if (fs->lfs_iocount == 0)
        !          1054:                panic("lfs_callback: zero iocount\n");
        !          1055: #endif
        !          1056:        if (--fs->lfs_iocount == 0)
        !          1057:                wakeup(&fs->lfs_iocount);
        !          1058: 
        !          1059:        brelvp(bp);
        !          1060:        free(bp->b_data, M_SEGMENT);
        !          1061:        free(bp, M_SEGMENT);
        !          1062: }
        !          1063: 
        !          1064: void
        !          1065: lfs_supercallback(bp)
        !          1066:        struct buf *bp;
        !          1067: {
        !          1068:        brelvp(bp);
        !          1069:        free(bp->b_data, M_SEGMENT);
        !          1070:        free(bp, M_SEGMENT);
        !          1071: }
        !          1072: 
        !          1073: /*
        !          1074:  * Shellsort (diminishing increment sort) from Data Structures and
        !          1075:  * Algorithms, Aho, Hopcraft and Ullman, 1983 Edition, page 290;
        !          1076:  * see also Knuth Vol. 3, page 84.  The increments are selected from
        !          1077:  * formula (8), page 95.  Roughly O(N^3/2).
        !          1078:  */
        !          1079: /*
        !          1080:  * This is our own private copy of shellsort because we want to sort
        !          1081:  * two parallel arrays (the array of buffer pointers and the array of
        !          1082:  * logical block numbers) simultaneously.  Note that we cast the array
        !          1083:  * of logical block numbers to a unsigned in this routine so that the
        !          1084:  * negative block numbers (meta data blocks) sort AFTER the data blocks.
        !          1085:  */
        !          1086: void
        !          1087: lfs_shellsort(bp_array, lb_array, nmemb)
        !          1088:        struct buf **bp_array;
        !          1089:        daddr_t *lb_array;
        !          1090:        register int nmemb;
        !          1091: {
        !          1092:        static int __rsshell_increments[] = { 4, 1, 0 };
        !          1093:        register int incr, *incrp, t1, t2;
        !          1094:        struct buf *bp_temp;
        !          1095:        u_long lb_temp;
        !          1096: 
        !          1097:        for (incrp = __rsshell_increments; incr = *incrp++;)
        !          1098:                for (t1 = incr; t1 < nmemb; ++t1)
        !          1099:                        for (t2 = t1 - incr; t2 >= 0;)
        !          1100:                                if (lb_array[t2] > lb_array[t2 + incr]) {
        !          1101:                                        lb_temp = lb_array[t2];
        !          1102:                                        lb_array[t2] = lb_array[t2 + incr];
        !          1103:                                        lb_array[t2 + incr] = lb_temp;
        !          1104:                                        bp_temp = bp_array[t2];
        !          1105:                                        bp_array[t2] = bp_array[t2 + incr];
        !          1106:                                        bp_array[t2 + incr] = bp_temp;
        !          1107:                                        t2 -= incr;
        !          1108:                                } else
        !          1109:                                        break;
        !          1110: }
        !          1111: 
        !          1112: /*
        !          1113:  * Check VXLOCK.  Return 1 if the vnode is locked.  Otherwise, vget it.
        !          1114:  */
        !          1115: lfs_vref(vp)
        !          1116:        register struct vnode *vp;
        !          1117: {
        !          1118: 
        !          1119:        if (vp->v_flag & VXLOCK)
        !          1120:                return(1);
        !          1121:        return (vget(vp, 0));
        !          1122: }
        !          1123: 
        !          1124: void
        !          1125: lfs_vunref(vp)
        !          1126:        register struct vnode *vp;
        !          1127: {
        !          1128:        extern int lfs_no_inactive;
        !          1129: 
        !          1130:        /*
        !          1131:         * This is vrele except that we do not want to VOP_INACTIVE
        !          1132:         * this vnode. Rather than inline vrele here, we use a global
        !          1133:         * flag to tell lfs_inactive not to run. Yes, its gross.
        !          1134:         */
        !          1135:        lfs_no_inactive = 1;
        !          1136:        vrele(vp);
        !          1137:        lfs_no_inactive = 0;
        !          1138: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.