Annotation of XNU/bsd/vfs/vfs_cluster.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: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
        !            23: /*
        !            24:  * Copyright (c) 1993
        !            25:  *     The Regents of the University of California.  All rights reserved.
        !            26:  *
        !            27:  * Redistribution and use in source and binary forms, with or without
        !            28:  * modification, are permitted provided that the following conditions
        !            29:  * are met:
        !            30:  * 1. Redistributions of source code must retain the above copyright
        !            31:  *    notice, this list of conditions and the following disclaimer.
        !            32:  * 2. Redistributions in binary form must reproduce the above copyright
        !            33:  *    notice, this list of conditions and the following disclaimer in the
        !            34:  *    documentation and/or other materials provided with the distribution.
        !            35:  * 3. All advertising materials mentioning features or use of this software
        !            36:  *    must display the following acknowledgement:
        !            37:  *     This product includes software developed by the University of
        !            38:  *     California, Berkeley and its contributors.
        !            39:  * 4. Neither the name of the University nor the names of its contributors
        !            40:  *    may be used to endorse or promote products derived from this software
        !            41:  *    without specific prior written permission.
        !            42:  *
        !            43:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            44:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            45:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            46:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            47:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            48:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            49:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            50:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            51:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            52:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            53:  * SUCH DAMAGE.
        !            54:  *
        !            55:  *     @(#)vfs_cluster.c       8.10 (Berkeley) 3/28/95
        !            56:  */
        !            57: 
        !            58: #include <sys/param.h>
        !            59: #include <sys/proc.h>
        !            60: #include <sys/buf.h>
        !            61: #include <sys/vnode.h>
        !            62: #include <sys/mount.h>
        !            63: #include <sys/trace.h>
        !            64: #include <sys/malloc.h>
        !            65: #include <sys/resourcevar.h>
        !            66: #include <libkern/libkern.h>
        !            67: #include <kern/mapfs.h>
        !            68: 
        !            69: #include <sys/kdebug.h>
        !            70: 
        !            71: /*
        !            72:  * Local declarations
        !            73:  */
        !            74: struct buf *cluster_rbuild __P((struct vnode *, u_quad_t, struct buf *,
        !            75:            daddr_t, daddr_t, long, int, long, long));
        !            76: struct buf *cluster_create __P((struct vnode *, struct buf *, daddr_t, daddr_t, long,
        !            77:            int, long, daddr_t *, int));
        !            78: int         cluster_block __P((struct vnode *, u_quad_t, struct buf *, long, long));
        !            79: void       cluster_wbuild __P((struct vnode *, struct buf *, long,
        !            80:            daddr_t, int, daddr_t, long, int));
        !            81: struct cluster_save *cluster_collectbufs __P((struct vnode *, struct buf *));
        !            82: 
        !            83: #if DIAGNOSTIC
        !            84: /*
        !            85:  * Set to 1 if reads of block zero should cause readahead to be done.
        !            86:  * Set to 0 treats a read of block zero as a non-sequential read.
        !            87:  *
        !            88:  * Setting to one assumes that most reads of block zero of files are due to
        !            89:  * sequential passes over the files (e.g. cat, sum) where additional blocks
        !            90:  * will soon be needed.  Setting to zero assumes that the majority are
        !            91:  * surgical strikes to get particular info (e.g. size, file) where readahead
        !            92:  * blocks will not be used and, in fact, push out other potentially useful
        !            93:  * blocks from the cache.  The former seems intuitive, but some quick tests
        !            94:  * showed that the latter performed better from a system-wide point of view.
        !            95:  */
        !            96: int    doclusterraz = 0;
        !            97: #define ISSEQREAD(vp, blk) \
        !            98:        (((blk) != 0 || doclusterraz) && \
        !            99:         ((blk) == (vp)->v_lastr + 1 || (blk) == (vp)->v_lastr))
        !           100: #else
        !           101: #define ISSEQREAD(vp, blk) \
        !           102:        ((blk) != 0 && ((blk) == (vp)->v_lastr + 1 || (blk) == (vp)->v_lastr))
        !           103: #endif
        !           104: 
        !           105: /*
        !           106:  * This replaces bread.  If this is a bread at the beginning of a file and
        !           107:  * lastr is 0, we assume this is the first read and we'll read up to two
        !           108:  * blocks if they are sequential.  After that, we'll do regular read ahead
        !           109:  * in clustered chunks.
        !           110:  *
        !           111:  * There are 4 or 5 cases depending on how you count:
        !           112:  *     Desired block is in the cache:
        !           113:  *         1 Not sequential access (0 I/Os).
        !           114:  *         2 Access is sequential, do read-ahead (1 ASYNC).
        !           115:  *     Desired block is not in cache:
        !           116:  *         3 Not sequential access (1 SYNC).
        !           117:  *         4 Sequential access, next block is contiguous (1 SYNC).
        !           118:  *         5 Sequential access, next block is not contiguous (1 SYNC, 1 ASYNC)
        !           119:  *
        !           120:  * There are potentially two buffers that require I/O.
        !           121:  *     bp is the block requested.
        !           122:  *     rbp is the read-ahead block.
        !           123:  *     If either is NULL, then you don't have to do the I/O.
        !           124:  */
        !           125: 
        !           126: cluster_read(vp, filesize, lblkno, size, cred, bpp, secsize, 
        !           127:                         firstpass, resid, fp_sequential)
        !           128:        struct vnode *vp;
        !           129:        u_quad_t filesize;
        !           130:        daddr_t lblkno;
        !           131:        long size;
        !           132:        struct ucred *cred;
        !           133:        struct buf **bpp;
        !           134:        long secsize;
        !           135:        int firstpass;
        !           136:        long resid;
        !           137:        int *fp_sequential;
        !           138: {
        !           139:        struct buf *bp, *rbp, *cbp;
        !           140:        daddr_t blkno, ioblkno;
        !           141:        long flags;
        !           142:        int error, num_ra, alreadyincore;
        !           143:        long num;
        !           144:        int sequential, case4;
        !           145:        int l_maxra;
        !           146:        int l_ralen;
        !           147:        int l_lastr;
        !           148: 
        !           149: #if DIAGNOSTIC
        !           150:        if (size == 0)
        !           151:                panic("cluster_read: size = 0");
        !           152: #endif
        !           153: 
        !           154:        KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 11)) | DBG_FUNC_START,
        !           155:                                           lblkno,
        !           156:                                           resid,
        !           157:                                           firstpass,
        !           158:                                           vp,
        !           159:                                           0);
        !           160:        error = 0;
        !           161:        flags = B_READ;
        !           162:        *bpp = bp = getblk(vp, lblkno, size, 0, 0);
        !           163: 
        !           164:        if (resid == PAGE_SIZE && lblkno && !ISSEQREAD(vp, lblkno) &&
        !           165:            (vp->v_mount->mnt_stat.f_iosize & (PAGE_SIZE - 1)) == 0) {
        !           166:                if (bp->b_flags & B_CACHE) {
        !           167: 
        !           168:                        KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 11)) | DBG_FUNC_END,
        !           169:                                   lblkno,
        !           170:                                   size,
        !           171:                                   -1,
        !           172:                                   0,
        !           173:                                   0);
        !           174: 
        !           175:                        vp->v_consumed += (bp->b_bcount/size);
        !           176:                        return (0);
        !           177:                }
        !           178:                bp->b_flags |= B_READ;
        !           179: 
        !           180:                if (cluster_block(vp, filesize, bp, size, secsize)) {
        !           181: 
        !           182:                        error = biowait(bp);
        !           183: 
        !           184:                        KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 11)) | DBG_FUNC_END,
        !           185:                                   bp,
        !           186:                                   0,
        !           187:                                   0,
        !           188:                                   0,
        !           189:                                   0);
        !           190: 
        !           191:                        return(error);
        !           192:                }
        !           193:        }
        !           194:        l_maxra = vp->v_maxra;
        !           195:        l_ralen = vp->v_ralen;
        !           196:        l_lastr = vp->v_lastr;
        !           197: 
        !           198:        /* round up resid count to nearest block size */
        !           199:        if ( resid  > size )
        !           200:                resid += size - 1;
        !           201: 
        !           202:        if (bp->b_flags & B_CACHE) {
        !           203:                /*
        !           204:                 * Desired block is in cache; do any readahead ASYNC.
        !           205:                 * Case 1, 2.
        !           206:                 */
        !           207:                trace(TR_BREADHIT, pack(vp, size), lblkno);
        !           208:                flags |= B_ASYNC;
        !           209:                if (resid > size)
        !           210:                        resid -= size;
        !           211: 
        !           212:                ioblkno = lblkno + (l_ralen ? l_ralen : 1);
        !           213:                alreadyincore = incore(vp, ioblkno) != NULL;
        !           214: 
        !           215:                /*
        !           216:                 * treat this as a hit for purposes of speculative I/O around paging activity
        !           217:                 */
        !           218:                vp->v_consumed += (bp->b_bcount/size);
        !           219: 
        !           220:                bp = NULL;
        !           221:        } else {
        !           222:                /* Block wasn't in cache, case 3, 4, 5. */
        !           223:                trace(TR_BREADMISS, pack(vp, size), lblkno);
        !           224:                bp->b_flags |= B_READ;
        !           225:                ioblkno = lblkno;
        !           226:                alreadyincore = 0;
        !           227:                current_proc()->p_stats->p_ru.ru_inblock++;             /* XXX */
        !           228:        }
        !           229:        /*
        !           230:         * XXX
        !           231:         * Replace 1 with a window size based on some permutation of
        !           232:         * maxcontig and rot_delay.  This will let you figure out how
        !           233:         * many blocks you should read-ahead (case 2, 4, 5).
        !           234:         *
        !           235:         * If the access isn't sequential, reset the window to 1.
        !           236:         * Note that a read to the same block is considered sequential.
        !           237:         * This catches the case where the file is being read sequentially,
        !           238:         * but at smaller than the filesystem block size.
        !           239:         */
        !           240:        rbp = NULL;
        !           241:        cbp = NULL;
        !           242:        case4 = 0;
        !           243: 
        !           244:        if (!ISSEQREAD(vp, lblkno)) {
        !           245:                l_ralen = 0;
        !           246:                l_maxra = lblkno;
        !           247:                sequential = 0;
        !           248:        }
        !           249:        else
        !           250:                sequential = 1;
        !           251: 
        !           252:        /* On first pass set the sequential state.
        !           253:         * Otherwise, just use the value passed in.
        !           254:         */
        !           255:        if (firstpass)
        !           256:                *fp_sequential = sequential;
        !           257: 
        !           258:        if (resid > size || *fp_sequential) {
        !           259:          if (((u_quad_t)(ioblkno + 1)) * (u_quad_t)size <= filesize && !alreadyincore &&
        !           260:            !(error = VOP_BMAP(vp, ioblkno, NULL, &blkno, &num_ra)) &&
        !           261:            blkno != -1) {
        !           262:                /*
        !           263:                 * Reading sequentially, and the next block is not in the
        !           264:                 * cache.  We are going to try reading ahead.
        !           265:                 */
        !           266:                if (num_ra) {
        !           267:                        /*
        !           268:                         * If our desired readahead block had been read
        !           269:                         * in a previous readahead but is no longer in
        !           270:                         * core, then we may be reading ahead too far
        !           271:                         * or are not using our readahead very rapidly.
        !           272:                         * In this case we scale back the window.
        !           273:                         */
        !           274:                        if (*fp_sequential) {
        !           275:                                if (!alreadyincore && ioblkno <= l_maxra)
        !           276:                                        l_ralen = max(l_ralen >> 1, 1);
        !           277:                                /*
        !           278:                                 * There are more sequential blocks than our current
        !           279:                                 * window allows, scale up.  Ideally we want to get
        !           280:                                 * in sync with the filesystem maxcontig value.
        !           281:                                 */
        !           282:                                else if (num_ra > l_ralen && lblkno != l_lastr)
        !           283:                                        l_ralen = l_ralen ?
        !           284:                                        min(num_ra, l_ralen << 1) : 1;
        !           285:                        }
        !           286:                        num = max((resid/size)-1, l_ralen);
        !           287:                        num_ra = min(num, num_ra);
        !           288:                }
        !           289: 
        !           290:                if (num_ra) {                           /* case 2, 4 */
        !           291:                        cbp = cluster_rbuild(vp, filesize,
        !           292:                                             bp, ioblkno, blkno, size, num_ra, flags, secsize);
        !           293: 
        !           294:                        if (cbp) {
        !           295:                                if ( !(cbp->b_flags & B_CALL)) {
        !           296:                                        if ((rbp = cbp) == bp)
        !           297:                                                rbp = NULL;
        !           298:                                        cbp = NULL;
        !           299:                                } else
        !           300:                                        case4 = 1;
        !           301:                        }
        !           302:                } else if (ioblkno == lblkno) {
        !           303:                        bp->b_blkno = blkno;
        !           304:                        /* Case 5: check how many blocks to read ahead */
        !           305:                        ++ioblkno;
        !           306:                        if (((u_quad_t)(ioblkno + 1)) * (u_quad_t)size > filesize ||
        !           307:                            incore(vp, ioblkno) || (error = VOP_BMAP(vp,
        !           308:                             ioblkno, NULL, &blkno, &num_ra)) || blkno == -1)
        !           309:                                goto skip_readahead;
        !           310:                        /*
        !           311:                         * Adjust readahead as above.
        !           312:                         * Don't check alreadyincore, we know it is 0 from
        !           313:                         * the previous conditional.
        !           314:                         */
        !           315:                        if (num_ra) {
        !           316:                          if (*fp_sequential) {
        !           317:                                if (ioblkno <= l_maxra)
        !           318:                                        l_ralen = max(l_ralen >> 1, 1);
        !           319:                                else if (num_ra > l_ralen && lblkno != l_lastr)
        !           320:                                        l_ralen = l_ralen ?
        !           321:                                                min(num_ra, l_ralen<<1) : 1;
        !           322:                          }
        !           323:                          num = max((resid/size)-1, l_ralen);
        !           324:                          num_ra = min(num, num_ra);
        !           325:                        }
        !           326:                        flags |= B_ASYNC;
        !           327: 
        !           328:                        if (num_ra) {
        !           329:                                cbp = cluster_rbuild(vp, filesize,
        !           330:                                    NULL, ioblkno, blkno, size, num_ra, flags,
        !           331:                                                     secsize);
        !           332:                                if (cbp) {
        !           333:                                        if ( !(cbp->b_flags & B_CALL)) {
        !           334:                                                rbp = cbp;
        !           335:                                                cbp = NULL;
        !           336:                                        }
        !           337:                                }
        !           338:                        } else {
        !           339:                                rbp = getblk(vp, ioblkno, size, 0, 0);
        !           340:                                rbp->b_flags |= flags;
        !           341:                                rbp->b_blkno = blkno;
        !           342:                        }
        !           343:                } else {
        !           344:                        /* case 2; read ahead single block */
        !           345:                        rbp = getblk(vp, ioblkno, size, 0, 0);
        !           346:                        rbp->b_flags |= flags;
        !           347:                        rbp->b_blkno = blkno;
        !           348:                }
        !           349:                if (cbp || rbp) {                       /* case 2, 5 */
        !           350:                        trace(TR_BREADMISSRA,
        !           351:                            pack(vp, (num_ra + 1) * size), ioblkno);
        !           352:                        current_proc()->p_stats->p_ru.ru_inblock++;     /* XXX */
        !           353:                }
        !           354:          }
        !           355:        }
        !           356: 
        !           357: skip_readahead:
        !           358:        if (bp && !case4) {
        !           359:                if (bp->b_flags & (B_DONE | B_DELWRI))
        !           360:                        panic("cluster_read: DONE bp");
        !           361:                else {
        !           362:                        /*
        !           363:                         * issue the BMAP here if needed due to the block device's
        !           364:                         * lack of a BMAP call in the strategy routine.... when being
        !           365:                         * used by the filesystem/mount code, the blockno's being worked
        !           366:                         * with are always physical so the strategy routine doesn't bother.
        !           367:                         * Now that we are calling cluster read/write from spec_read/spec_write
        !           368:                         * we have to use real logical blockno's in order to properly trigger
        !           369:                         * the read-ahead and write-coalescing.
        !           370:                         */
        !           371:                        if (bp->b_lblkno == bp->b_blkno) {
        !           372:                                VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL);
        !           373:                                
        !           374:                                if ((long)bp->b_blkno == -1)
        !           375:                                        clrbuf(bp);
        !           376:                        }
        !           377:                        error = VOP_STRATEGY(bp);
        !           378: 
        !           379:                        KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 11)) | DBG_FUNC_NONE,
        !           380:                                           bp->b_lblkno,
        !           381:                                           bp->b_bcount,
        !           382:                                           vp,
        !           383:                                           0xaaaaaaaa, 0 );
        !           384:                }
        !           385:        }
        !           386:        if (rbp) {
        !           387:                if (error || rbp->b_flags & (B_DONE | B_DELWRI)) {
        !           388:                        rbp->b_flags &= ~(B_ASYNC | B_READ);
        !           389:                        brelse(rbp);
        !           390:                } else {
        !           391:                        /*
        !           392:                         * issue the BMAP here if needed due to the block device's
        !           393:                         * lack of a BMAP call in the strategy routine.... when being
        !           394:                         * used by the filesystem/mount code, the blockno's being worked
        !           395:                         * with are always physical so the strategy routine doesn't bother.
        !           396:                         * Now that we are calling cluster read/write from spec_read/spec_write
        !           397:                         * we have to use real logical blockno's in order to properly trigger
        !           398:                         * the read-ahead and write-coalescing.
        !           399:                         */
        !           400:                        if (rbp->b_lblkno == rbp->b_blkno) {
        !           401:                                VOP_BMAP(vp, rbp->b_lblkno, NULL, &rbp->b_blkno, NULL);
        !           402: 
        !           403:                                if ((long)rbp->b_blkno == -1)
        !           404:                                        clrbuf(rbp);
        !           405:                        }
        !           406:                        (void) VOP_STRATEGY(rbp);
        !           407: 
        !           408:                        KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 11)) | DBG_FUNC_NONE,
        !           409:                                           rbp->b_lblkno,
        !           410:                                           rbp->b_bcount,
        !           411:                                           vp,
        !           412:                                           0xaaaaaabb, 0 );
        !           413:                }
        !           414:        }
        !           415:        if (cbp) {
        !           416:                (void) VOP_STRATEGY(cbp);
        !           417: 
        !           418:                KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 11)) | DBG_FUNC_NONE,
        !           419:                                           cbp->b_lblkno,
        !           420:                                           cbp->b_bcount,
        !           421:                                           vp,
        !           422:                                           0xaaaaaacc, 0 );
        !           423:        }
        !           424:        /*
        !           425:         * Recalculate our maximum readahead
        !           426:         */
        !           427:        if (rbp == NULL) {
        !           428:                if (cbp)
        !           429:                        rbp = cbp;
        !           430:                else
        !           431:                        rbp = bp;
        !           432:        }
        !           433:        if (rbp)
        !           434:                vp->v_maxra = rbp->b_lblkno + (rbp->b_bcount / size) - 1;
        !           435:        else
        !           436:                vp->v_maxra = l_maxra;
        !           437:        vp->v_ralen = l_ralen;
        !           438: 
        !           439:        if (bp)
        !           440:                error = biowait(bp);
        !           441: 
        !           442:        KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 11)) | DBG_FUNC_END,
        !           443:                                           bp,
        !           444:                                           rbp,
        !           445:                                           cbp,
        !           446:                                           vp->v_maxra,
        !           447:                                           0);
        !           448:        return(error);
        !           449: }
        !           450: 
        !           451: struct pent {
        !           452:   int mask;
        !           453:   int num;
        !           454: } pent[7] = {
        !           455:   {0,0},
        !           456:   {0,0},
        !           457:   {~0,1},
        !           458:   {~1,2},
        !           459:   {~3,4},
        !           460:   {~7,8},
        !           461:   {~15,16}};
        !           462: 
        !           463: 
        !           464: int cluster_block(vp, filesize, bp, size, secsize)
        !           465:        struct vnode *vp;
        !           466:        u_quad_t filesize;
        !           467:        struct buf *bp;
        !           468:        long size;
        !           469:        long secsize;
        !           470: {
        !           471:        struct buf *cbp;
        !           472:        daddr_t lblkno, blkno, ioblkno, lbn;
        !           473:        int num_io, num;
        !           474:        unsigned ratio;
        !           475: 
        !           476: #if 0 /* FIXED READS */
        !           477:        /* calculate maximum number of blocks to read in */
        !           478: 
        !           479:        lblkno = bp->b_lblkno & ~0x07;     /* put us on a 32k (8 page boundary) boundary */
        !           480:        num    = 8;
        !           481:        num_io = 0;
        !           482: #else /* ADAPTIVE READS */
        !           483:        if (vp->v_bread > vp->v_trigger) {
        !           484:                ratio = (vp->v_consumed*100) / vp->v_bread;
        !           485: 
        !           486:                if (ratio < 50 && vp->v_power > 2) {
        !           487:                        vp->v_power--;
        !           488:                        vp->v_trigger = vp->v_bread + (16 * pent[vp->v_power].num);
        !           489:                } else if (ratio > 75 && vp->v_power < 6) {
        !           490:                        vp->v_power++;
        !           491:                        vp->v_trigger = vp->v_bread + (16 * pent[vp->v_power].num);
        !           492:                }
        !           493:        }
        !           494:        if ((num = pent[vp->v_power].num) == 1)
        !           495:                return (0);
        !           496:        lblkno = bp->b_lblkno & pent[vp->v_power].mask;
        !           497:        num_io = 0;
        !           498: #endif
        !           499: 
        !           500:        KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 14)) | DBG_FUNC_START,
        !           501:                                           lblkno,
        !           502:                                           num,
        !           503:                                           vp->v_flag,
        !           504:                                           vp,
        !           505:                                           0 );
        !           506: 
        !           507:        for (lbn = bp->b_lblkno; lbn > lblkno; lbn--) {
        !           508:                if (incore(vp, lbn - 1))
        !           509:                        break;
        !           510:        }
        !           511:        num -= (lbn - lblkno);
        !           512: 
        !           513:        for (;;) {
        !           514:                if (VOP_BMAP(vp, lbn, NULL, &blkno, &num_io) || blkno == -1 || num_io == 0) {
        !           515:                        if (lbn == bp->b_lblkno) {
        !           516:                                KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 14)) | DBG_FUNC_END,
        !           517:                                             -1,
        !           518:                                             lbn,
        !           519:                                             blkno,
        !           520:                                             num_io,
        !           521:                                             0);
        !           522:                                return (0);
        !           523:                        }
        !           524:                }
        !           525:                if ((lbn + num_io) >= bp->b_lblkno)
        !           526:                        break;
        !           527:                lbn++;
        !           528:                num--;
        !           529:        }
        !           530:        if ((num_io = min(num, num_io + 1)) == 1)
        !           531:                return (0);
        !           532: 
        !           533:        if ((u_quad_t)size * ((u_quad_t)(lbn + num_io)) > filesize)
        !           534:                num_io = (filesize - ((u_quad_t)size * (u_quad_t)lbn)) / size;
        !           535: 
        !           536:        cbp = cluster_create(vp, bp, lbn, blkno, size, num_io, secsize, &ioblkno, B_AGE);
        !           537: 
        !           538:        if (cbp) {
        !           539:                (void) VOP_STRATEGY(cbp);
        !           540:                vp->v_bread += (cbp->b_bcount / size);
        !           541:                KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 14)) | DBG_FUNC_END,
        !           542:                             cbp->b_lblkno,
        !           543:                             cbp->b_bcount,
        !           544:                             vp,
        !           545:                             0xaaaaaadd,
        !           546:                             0 );
        !           547: 
        !           548:                return (1);
        !           549:        }
        !           550:        KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 14)) | DBG_FUNC_END,
        !           551:                     0,
        !           552:                     0,
        !           553:                     0,
        !           554:                     0,
        !           555:                     0);
        !           556:        return (0);
        !           557: }
        !           558: 
        !           559: 
        !           560: /*
        !           561:  * generate advisory I/O in as big of chunks as possible
        !           562:  * and then parcel them up into logical blocks in the buffer hash table.
        !           563:  */
        !           564: advisory_read(vp, filesize, lblkno, size, runt_size, io_size, secsize)
        !           565:        struct vnode *vp;
        !           566:        u_quad_t filesize;
        !           567:        daddr_t lblkno;
        !           568:        long size;
        !           569:        long runt_size;
        !           570:        long io_size;
        !           571:        long secsize;
        !           572: {
        !           573:        struct buf *bp, *cbp;
        !           574:        daddr_t blkno, ioblkno;
        !           575:        int error, num_io;
        !           576:        long num;
        !           577: 
        !           578:        error = 0;
        !           579: 
        !           580:        /* calculate maximum number of blocks to read in */
        !           581: 
        !           582:        num = (io_size + (size - 1)) / size;
        !           583: 
        !           584:        if ((u_quad_t)size * ((u_quad_t)(lblkno + num)) > filesize) {
        !           585:                if (((u_quad_t)size * (u_quad_t)lblkno) >= filesize)
        !           586:                        return(EFBIG);
        !           587:                io_size = filesize - ((u_quad_t)size * (u_quad_t)lblkno);
        !           588: 
        !           589:                num = io_size / size;
        !           590:        } else
        !           591:                io_size = num * size;
        !           592: 
        !           593:        KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 13)) | DBG_FUNC_START,
        !           594:                                           lblkno,
        !           595:                                           io_size,
        !           596:                                           num,
        !           597:                                           vp,
        !           598:                                           0 );
        !           599: 
        !           600:        while (num) {
        !           601:                if (error = VOP_BMAP(vp, lblkno, NULL, &blkno, &num_io))
        !           602:                        break;
        !           603:                    
        !           604:                if (blkno == -1) {
        !           605:                        lblkno++;
        !           606:                        num--;
        !           607:                        io_size -= size;
        !           608:                        continue;
        !           609:                }
        !           610:                num_io = min(num, num_io + 1);
        !           611: 
        !           612:                cbp = cluster_create(vp, NULL, lblkno, blkno, size, num_io, secsize, &ioblkno, 0);
        !           613: 
        !           614:                if (cbp) {
        !           615:                        KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 13)) | DBG_FUNC_NONE,
        !           616:                                     cbp->b_blkno,
        !           617:                                     cbp->b_bcount,
        !           618:                                     vp,
        !           619:                                     0xaaaaaaee,
        !           620:                                     0 );
        !           621: 
        !           622:                        (void) VOP_STRATEGY(cbp);
        !           623:                } else {
        !           624:                        if (ioblkno == lblkno) {
        !           625:                                error = ENOMEM;
        !           626:                                break;
        !           627:                        }
        !           628:                }
        !           629:                io_size -= ((ioblkno - lblkno) * size);
        !           630:                num -= ioblkno - lblkno;
        !           631:                lblkno = ioblkno;
        !           632:        }
        !           633:        if (io_size && !error) {
        !           634:                bp = getblk(vp, lblkno, runt_size, 0, 0);
        !           635: 
        !           636:                if (bp->b_flags & (B_DONE | B_DELWRI))
        !           637:                        brelse(bp);
        !           638:                else {
        !           639:                        bp->b_flags |= (B_READ | B_ASYNC);
        !           640: 
        !           641:                        (void) VOP_STRATEGY(bp);
        !           642: 
        !           643:                        KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 13)) | DBG_FUNC_NONE,
        !           644:                                   bp->b_blkno,
        !           645:                                   bp->b_bcount,
        !           646:                                   vp,
        !           647:                                   0xaaaaaaff,
        !           648:                                   0 );
        !           649:                }
        !           650:                io_size -= runt_size;
        !           651:        }
        !           652: 
        !           653:        KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 13)) | DBG_FUNC_END,
        !           654:                                           lblkno,
        !           655:                                           io_size,
        !           656:                                           num,
        !           657:                                           error,
        !           658:                                           0);
        !           659:        return(error);
        !           660: }
        !           661: 
        !           662: 
        !           663: /*
        !           664:  * If blocks are contiguous on disk, use this to provide clustered
        !           665:  * read ahead.  We will read as many blocks as possible sequentially
        !           666:  * and then parcel them up into logical blocks in the buffer hash table.
        !           667:  */
        !           668: struct buf *
        !           669: cluster_rbuild(vp, filesize, bp, lbn, blkno, size, run, flags, secsize)
        !           670:        struct vnode *vp;
        !           671:        u_quad_t filesize;
        !           672:        struct buf *bp;
        !           673:        daddr_t lbn;
        !           674:        daddr_t blkno;
        !           675:        long size;
        !           676:        int run;
        !           677:        long flags;
        !           678:        long secsize;
        !           679: {
        !           680:        struct cluster_save *b_save;
        !           681:        struct buf *tbp, *cbp;
        !           682:        caddr_t cp;
        !           683:        daddr_t bn;
        !           684:        int i, inc;
        !           685: 
        !           686: #if DIAGNOSTIC
        !           687:        if (size != vp->v_mount->mnt_stat.f_iosize)
        !           688:                panic("cluster_rbuild: size %d != filesize %d\n",
        !           689:                        size, vp->v_mount->mnt_stat.f_iosize);
        !           690: #endif
        !           691:        if ((u_quad_t)size * ((u_quad_t)(lbn + run + 1)) > filesize)
        !           692:                --run;
        !           693:        if (run == 0) {
        !           694:                if (!bp) {
        !           695:                        bp = getblk(vp, lbn, size, 0, 0);
        !           696:                        bp->b_blkno = blkno;
        !           697:                        bp->b_flags |= flags;
        !           698:                }
        !           699:                return(bp);
        !           700:        }       
        !           701:        b_save = _MALLOC(sizeof(struct buf *) * (run + 1) + sizeof(struct cluster_save),
        !           702:            M_SEGMENT, M_NOWAIT);
        !           703: 
        !           704:        if (b_save)
        !           705:                cbp = alloc_io_buf(vp);
        !           706:        else
        !           707:                cbp = NULL;
        !           708: 
        !           709:        if (b_save == NULL || cbp == NULL) {
        !           710:                if (b_save)
        !           711:                        _FREE(b_save, M_SEGMENT);
        !           712:                if (cbp)
        !           713:                        free_io_buf(cbp);
        !           714:                return (bp);
        !           715:        }
        !           716:        b_save->bs_bufsize = size;
        !           717:        b_save->bs_nchildren = 0;
        !           718:        b_save->bs_children = (struct buf **)(b_save + 1);
        !           719: 
        !           720:        cbp->b_saveaddr = (caddr_t)b_save;
        !           721:        cbp->b_iodone = cluster_callback;
        !           722:        cbp->b_blkno = blkno;
        !           723:        cbp->b_lblkno = lbn;
        !           724:        cbp->b_flags |= flags | B_CALL;
        !           725: 
        !           726:        inc = btodb(size, secsize);
        !           727:        cp = (char *)cbp->b_data;
        !           728:        tbp = bp;
        !           729: 
        !           730:        for (bn = blkno, i = 0; i <= run; ++i, bn += inc) {
        !           731:                if (tbp == NULL) {
        !           732:                        if (incore(vp, lbn + i))
        !           733:                                /*
        !           734:                                 * A component of the cluster is already in core,
        !           735:                                 * terminate the cluster early.
        !           736:                                 */
        !           737:                                break;
        !           738:                        tbp = getblk(vp, lbn + i, size, 0, 0);
        !           739:                }
        !           740:                pagemove(tbp->b_data, cp, size);
        !           741:                cbp->b_bcount += size;
        !           742:                cbp->b_bufsize += size;
        !           743:                cp += size;
        !           744: 
        !           745:                if (bp != tbp)
        !           746:                        tbp->b_flags |= flags | B_READ | B_ASYNC;
        !           747:                tbp->b_bufsize -= size;
        !           748:                tbp->b_blkno = bn;
        !           749: 
        !           750:                b_save->bs_children[i] = tbp;
        !           751:                b_save->bs_nchildren++;
        !           752: 
        !           753:                tbp = NULL;
        !           754:        }
        !           755:        /*
        !           756:         * The cluster may have been terminated early
        !           757:         * If no cluster could be formed, deallocate the cluster save info.
        !           758:         */
        !           759:        if (i == 0) {
        !           760:                _FREE(b_save, M_SEGMENT);
        !           761:                free_io_buf(cbp);
        !           762:                return(bp);
        !           763:        }
        !           764:        return(cbp);
        !           765: }
        !           766: 
        !           767: 
        !           768: 
        !           769: struct buf *
        !           770: cluster_create(vp, bp, lbn, blkno, size, run, secsize, ioblkno, flags)
        !           771:        struct vnode *vp;
        !           772:        struct buf *bp;
        !           773:        daddr_t lbn;
        !           774:        daddr_t blkno;
        !           775:        long size;
        !           776:        int run;
        !           777:        long secsize;
        !           778:        daddr_t *ioblkno;
        !           779:        int flags;
        !           780: {
        !           781:        struct cluster_save *b_save;
        !           782:        struct buf *tbp, *cbp;
        !           783:        caddr_t cp;
        !           784:        daddr_t bn;
        !           785:        int i, inc;
        !           786: 
        !           787:        inc = btodb(size, secsize);
        !           788: 
        !           789:        if (bp == NULL) {
        !           790:                while (run && (tbp = incore(vp, lbn))) {
        !           791:                        /*
        !           792:                         * if a block is already in core
        !           793:                         * and is not busy
        !           794:                         * then get and release to freshen it in the LRU
        !           795:                         */
        !           796:                        if ( !(tbp->b_flags & B_BUSY)) {
        !           797:                                tbp = getblk(vp, lbn, size, 0, 0);
        !           798:                                brelse(tbp);
        !           799:                        }
        !           800:                        lbn++;
        !           801:                        run--;
        !           802:                        blkno += inc;
        !           803:                }
        !           804:                if (run == 0) {
        !           805:                        *ioblkno = lbn;
        !           806:                        return (NULL);
        !           807:                }
        !           808:        }
        !           809:        b_save = _MALLOC((sizeof(struct buf *) * run) + sizeof(struct cluster_save), M_SEGMENT, M_NOWAIT);
        !           810: 
        !           811:        if (b_save)
        !           812:                cbp = alloc_io_buf(vp);
        !           813:        else
        !           814:                cbp = NULL;
        !           815: 
        !           816:        if (b_save == NULL || cbp == NULL) {
        !           817:                if (b_save)
        !           818:                        _FREE(b_save, M_SEGMENT);
        !           819:                if (cbp)
        !           820:                        free_io_buf(cbp);
        !           821:                *ioblkno = lbn;
        !           822:                
        !           823:                return (NULL);
        !           824:        }
        !           825:        b_save->bs_bufsize = size;
        !           826:        b_save->bs_nchildren = 0;
        !           827:        b_save->bs_children = (struct buf **)(b_save + 1);
        !           828: 
        !           829:        cbp->b_saveaddr = (caddr_t)b_save;
        !           830:        cbp->b_iodone = cluster_callback;
        !           831:        cbp->b_blkno = blkno;
        !           832:        cbp->b_lblkno = lbn;
        !           833:        cbp->b_flags |= (B_READ | B_ASYNC | B_CALL);
        !           834: 
        !           835:        cp = (char *)cbp->b_data;
        !           836: 
        !           837:        for (bn = blkno, i = 0; i < run; ++i, bn += inc, ++lbn) {
        !           838:                if (bp && bp->b_lblkno == lbn)
        !           839:                        tbp = bp;
        !           840:                else {
        !           841:                        if (tbp = incore(vp, lbn)) {
        !           842:                                /*
        !           843:                                 * A component of the cluster is already in core,
        !           844:                                 * terminate the cluster early.
        !           845:                                 * if its not busy then also
        !           846:                                 * get and release to freshen it in the LRU
        !           847:                                 */
        !           848:                                if ( !(tbp->b_flags & B_BUSY)) {
        !           849:                                        tbp = getblk(vp, lbn, size, 0, 0);
        !           850:                                        brelse(tbp);
        !           851:                                }
        !           852:                                break;
        !           853:                        }
        !           854:                        tbp = getblk(vp, lbn, size, 0, 0);
        !           855:                }
        !           856:                pagemove(tbp->b_data, cp, size);
        !           857: 
        !           858:                tbp->b_bufsize -= size;
        !           859:                tbp->b_blkno = bn;
        !           860:                cbp->b_bcount += size;
        !           861:                cbp->b_bufsize += size;
        !           862:                cp += size;
        !           863: 
        !           864:                if (tbp != bp)
        !           865:                        tbp->b_flags |= (B_READ | B_ASYNC | flags);
        !           866:                b_save->bs_children[i] = tbp;
        !           867:                b_save->bs_nchildren++;
        !           868:        }
        !           869:        *ioblkno = lbn;
        !           870:        /*
        !           871:         * The cluster may have been terminated early
        !           872:         * If no cluster could be formed, deallocate the cluster save info.
        !           873:         */
        !           874:        if (cbp->b_bcount == 0) {
        !           875:                _FREE(b_save, M_SEGMENT);
        !           876:                free_io_buf(cbp);
        !           877:                return(NULL);
        !           878:        }
        !           879:        return(cbp);
        !           880: }
        !           881: 
        !           882: 
        !           883: /*
        !           884:  * Cleanup after a clustered read or write.
        !           885:  * This is complicated by the fact that any of the buffers might have
        !           886:  * extra memory (if there were no empty buffer headers at allocbuf time)
        !           887:  * that we will need to shift around.
        !           888:  */
        !           889: void
        !           890: cluster_callback(bp)
        !           891:        struct buf *bp;
        !           892: {
        !           893:        struct cluster_save *b_save;
        !           894:        struct buf **bpp, *tbp;
        !           895:        long bsize;
        !           896:        int  xsize;
        !           897:        int  n;
        !           898:        caddr_t cp;
        !           899:        int error = 0;
        !           900: 
        !           901:        /*
        !           902:         * Must propogate errors to all the components.
        !           903:         */
        !           904:        if (bp->b_flags & B_ERROR)
        !           905:                error = bp->b_error;
        !           906:        b_save = (struct cluster_save *)(bp->b_saveaddr);
        !           907: 
        !           908:        bsize = b_save->bs_bufsize;
        !           909:        xsize = bp->b_bcount - bp->b_resid;
        !           910:        cp = (char *)bp->b_data;
        !           911:        /*
        !           912:         * Move memory from the large cluster buffer into the component
        !           913:         * buffers and mark IO as done on these.
        !           914:         */
        !           915:        for (bpp = b_save->bs_children; b_save->bs_nchildren--; ++bpp) {
        !           916:                tbp = *bpp;
        !           917:                pagemove(cp, tbp->b_data, bsize);
        !           918:                tbp->b_bufsize += bsize;
        !           919: 
        !           920:                n = min(bsize, xsize);
        !           921:                xsize -= n;
        !           922: 
        !           923:                if ((tbp->b_bcount = n) == 0)
        !           924:                        tbp->b_flags |= B_INVAL;
        !           925:                tbp->b_resid = bsize - n;
        !           926: 
        !           927:                if (error) {
        !           928:                        tbp->b_flags |= B_ERROR;
        !           929:                        tbp->b_error = error;
        !           930:                }
        !           931:                biodone(tbp);
        !           932:                bp->b_bufsize -= bsize;
        !           933:                cp += bsize;
        !           934:        }
        !           935:        _FREE(b_save, M_SEGMENT);
        !           936: 
        !           937:        free_io_buf(bp);
        !           938: }
        !           939: 
        !           940: 
        !           941: /*
        !           942:  * on close, flush out any remaining cluster
        !           943:  *
        !           944:  */
        !           945: cluster_close(vp, bsize, secsize)
        !           946:         struct vnode *vp;
        !           947:        int  bsize;
        !           948:        long secsize;
        !           949: {
        !           950:         int cursize;
        !           951: 
        !           952:        if (vp->v_clen) {
        !           953:                cursize = vp->v_lastw - vp->v_cstart + 1;
        !           954: 
        !           955:                cluster_wbuild(vp, NULL, bsize, vp->v_cstart, cursize, -1, secsize, 0);
        !           956: 
        !           957:                vp->v_lasta = vp->v_clen = vp->v_cstart = vp->v_lastw = 0;
        !           958:        }
        !           959: }
        !           960: 
        !           961: 
        !           962: /*
        !           963:  * Do clustered write for FFS.
        !           964:  *
        !           965:  * Three cases:
        !           966:  *     1. Write is not sequential (write asynchronously)
        !           967:  *     Write is sequential:
        !           968:  *     2.      beginning of cluster - begin cluster
        !           969:  *     3.      middle of a cluster - add to cluster
        !           970:  *     4.      end of a cluster - asynchronously write cluster
        !           971:  */
        !           972: 
        !           973: cluster_write(bp, filesize, secsize)
        !           974:         struct buf *bp;
        !           975:        u_quad_t filesize;
        !           976:        long secsize;
        !           977: {
        !           978:         struct vnode *vp;
        !           979:         daddr_t lbn;
        !           980:         daddr_t bn;
        !           981:         int cursize;
        !           982:        int need_commit;
        !           983:        int need_sync;
        !           984:        int bsize;
        !           985:        int error = 0;
        !           986: 
        !           987:        need_commit = (bp->b_flags & B_CLUST_COMMIT);
        !           988:        need_sync   = (bp->b_flags & B_CLUST_SYNC);
        !           989:        bp->b_flags &= ~(B_CLUST_COMMIT | B_CLUST_SYNC);
        !           990:        
        !           991:         vp = bp->b_vp;
        !           992:        bn = bp->b_blkno;
        !           993:         lbn = bp->b_lblkno;
        !           994:        bsize = bp->b_bcount;
        !           995: 
        !           996:        if ((bsize & (PAGE_SIZE - 1)) || bsize > MAXBSIZE) {
        !           997:                bp->b_flags |= B_AGE;
        !           998:                bawrite(bp);
        !           999: 
        !          1000:                return (error);
        !          1001:        }
        !          1002:        /* Initialize vnode to beginning of file. */
        !          1003:        if (lbn == 0)
        !          1004:                vp->v_lasta = vp->v_clen = vp->v_cstart = vp->v_lastw = 0;
        !          1005: 
        !          1006: 
        !          1007:        KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_START,
        !          1008:                                           bp->b_lblkno,
        !          1009:                                           bp->b_bcount,
        !          1010:                                           vp,
        !          1011:                                           0,
        !          1012:                                           0);
        !          1013:        
        !          1014:         if (vp->v_clen == 0 || lbn != vp->v_lastw + 1 || (bn != vp->v_lasta + btodb(bsize, secsize)))
        !          1015:        {
        !          1016:                if (vp->v_clen) {
        !          1017:                        /*
        !          1018:                         * Current block is neither logically or physically sequential to last written
        !          1019:                         *
        !          1020:                         * If we are not writing at the end of file, or the process
        !          1021:                         * seeked to another point in the file since its
        !          1022:                         * last write, then push the previous cluster.
        !          1023:                         * Otherwise try reallocating to make it sequential.
        !          1024:                         */
        !          1025:                        cursize = vp->v_lastw - vp->v_cstart + 1;
        !          1026: 
        !          1027:                        if (((u_quad_t)(lbn + 1)) * (u_quad_t)bsize != filesize || lbn != vp->v_lastw + 1) {
        !          1028:                                cluster_wbuild(vp, NULL, bsize,
        !          1029:                                               vp->v_cstart, cursize, lbn, secsize, need_sync);
        !          1030:                        } else {
        !          1031:                                struct buf **bpp, **endbp;
        !          1032:                                struct cluster_save *buflist;
        !          1033: 
        !          1034:                                buflist = cluster_collectbufs(vp, bp);
        !          1035: 
        !          1036:                                if (buflist == NULL) {
        !          1037:                                        cluster_wbuild(vp, NULL, bsize,
        !          1038:                                                       vp->v_cstart, cursize, lbn, secsize, need_sync);
        !          1039:                                } else {
        !          1040: 
        !          1041:                                        endbp = &buflist->bs_children
        !          1042:                                                [buflist->bs_nchildren - 1];
        !          1043:                                        if (VOP_REALLOCBLKS(vp, buflist)) {
        !          1044:                                                /*
        !          1045:                                                 * Failed, push the previous cluster.
        !          1046:                                                 */
        !          1047:                                                for (bpp = buflist->bs_children;
        !          1048:                                                     bpp < endbp; bpp++)
        !          1049:                                                        brelse(*bpp);
        !          1050:                                                _FREE(buflist, M_SEGMENT);
        !          1051: 
        !          1052:                                                cluster_wbuild(vp, NULL, bsize,
        !          1053:                                                               vp->v_cstart, cursize, lbn, secsize, need_sync);
        !          1054:                                        } else {
        !          1055:                                                /*
        !          1056:                                                 * Succeeded, keep building cluster.
        !          1057:                                                 * don't bdwrite the last bp, we'll 
        !          1058:                                                 * first check to see if we now have a full
        !          1059:                                                 * cluster, or the caller has requested a SYNC write
        !          1060:                                                 */
        !          1061:                                                for (bpp = buflist->bs_children;
        !          1062:                                                     bpp < endbp; bpp++)
        !          1063:                                                        bdwrite(*bpp);
        !          1064:                                                _FREE(buflist, M_SEGMENT);
        !          1065:                                                /*
        !          1066:                                                 * update the physical block number because,
        !          1067:                                                 * VOP_REALLOCBLKS will have changed it
        !          1068:                                                 */
        !          1069:                                                bn = bp->b_blkno;
        !          1070:                                                goto chk_cluster_full;
        !          1071:                                        }
        !          1072:                                }
        !          1073:                        }
        !          1074:                }
        !          1075:                 if (need_commit) {       /* we're being asked to do IO_SYNC and this is the last */
        !          1076:                        vp->v_clen = 0;  /* chunk of the I/O request, so we can't start a new cluster yet */
        !          1077: 
        !          1078:                        if (need_sync)
        !          1079:                                bwrite(bp);
        !          1080:                        else
        !          1081:                                bawrite(bp);
        !          1082: 
        !          1083:                        KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_END,
        !          1084:                                           bp->b_lblkno,
        !          1085:                                           bp->b_blkno,
        !          1086:                                           bp->b_bcount,
        !          1087:                                           2,
        !          1088:                                           0 );
        !          1089:                 } else {
        !          1090:                        /*
        !          1091:                         * begin a new cluster... limiting the size to MAXPHYSIO
        !          1092:                         */
        !          1093:                        vp->v_cstart = lbn;
        !          1094:                        vp->v_clen = (MAXPHYSIO / bsize) - 1;
        !          1095: 
        !          1096:                         bdwrite(bp);
        !          1097: 
        !          1098:                        KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_END,
        !          1099:                                           bp->b_lblkno,
        !          1100:                                           bp->b_blkno,
        !          1101:                                           bp->b_bcount,
        !          1102:                                           3,
        !          1103:                                           0 );
        !          1104:                }
        !          1105:                goto check_for_commit;
        !          1106:        }
        !          1107: chk_cluster_full:
        !          1108:        if ((lbn == vp->v_cstart + vp->v_clen) || need_commit) {
        !          1109:                /*
        !          1110:                 * At end of cluster, write it out.
        !          1111:                 */
        !          1112:                cluster_wbuild(vp, bp, bsize, vp->v_cstart,
        !          1113:                               (lbn - vp->v_cstart) + 1, lbn, secsize, need_sync);
        !          1114: 
        !          1115:                KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_END,
        !          1116:                                           vp->v_cstart,
        !          1117:                                           vp->v_clen + 1,
        !          1118:                                           lbn,
        !          1119:                                           4,
        !          1120:                                           0 );
        !          1121:                vp->v_clen = 0;
        !          1122:        } else {
        !          1123:                /*
        !          1124:                 * In the middle of a cluster, so just delay the
        !          1125:                 * I/O for now.
        !          1126:                 */
        !          1127:                bdwrite(bp);
        !          1128: 
        !          1129:                KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_END,
        !          1130:                                           bp->b_lblkno,
        !          1131:                                           bp->b_blkno,
        !          1132:                                           vp->v_cstart,
        !          1133:                                           5,
        !          1134:                                           0);
        !          1135:        }
        !          1136: check_for_commit:
        !          1137:        vp->v_lastw = lbn;
        !          1138:        vp->v_lasta = bn;
        !          1139: 
        !          1140:         if (need_commit) {
        !          1141:                bp = getblk(vp, lbn, bsize, 0, 0);
        !          1142: 
        !          1143:                if (bp->b_flags & B_ERROR)
        !          1144:                        error = (bp->b_error ? bp->b_error : EIO);
        !          1145:                brelse(bp);
        !          1146:        }
        !          1147:        return (error);
        !          1148: }
        !          1149: 
        !          1150: 
        !          1151: /*
        !          1152:  * This is an awful lot like cluster_rbuild...wish they could be combined.
        !          1153:  * The last lbn argument is the current block on which I/O is being
        !          1154:  * performed.  Check to see that it doesn't fall in the middle of
        !          1155:  * the current block (if last_bp == NULL).
        !          1156:  */
        !          1157: void
        !          1158: cluster_wbuild(vp, last_bp, size, start_lbn, len, lbn, secsize, need_sync)
        !          1159:        struct vnode *vp;
        !          1160:        struct buf *last_bp;
        !          1161:        long size;
        !          1162:        daddr_t start_lbn;
        !          1163:        int len;
        !          1164:        daddr_t lbn;
        !          1165:        long secsize;
        !          1166:        int need_sync;
        !          1167: {
        !          1168:        struct cluster_save *b_save;
        !          1169:        struct buf *bp, *tbp;
        !          1170:        caddr_t cp;
        !          1171:        int i, s;
        !          1172: 
        !          1173: #if DIAGNOSTIC
        !          1174:        if (size != vp->v_mount->mnt_stat.f_iosize)
        !          1175:                panic("cluster_wbuild: size %d != filesize %d\n",
        !          1176:                        size, vp->v_mount->mnt_stat.f_iosize);
        !          1177: #endif
        !          1178: redo:
        !          1179:         while ((!incore(vp, start_lbn) || start_lbn == lbn) && len) {
        !          1180:                ++start_lbn;
        !          1181:                --len;
        !          1182:        }
        !          1183:        /* Get more memory for current buffer */
        !          1184:        if (len <= 1) {
        !          1185:                if (last_bp) {
        !          1186:                        KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_NONE,
        !          1187:                                           last_bp->b_lblkno,
        !          1188:                                           last_bp->b_blkno,
        !          1189:                                           last_bp->b_bcount,
        !          1190:                                           10,
        !          1191:                                           0 );
        !          1192:                        if (need_sync)
        !          1193:                                bwrite(last_bp);
        !          1194:                        else
        !          1195:                                bawrite(last_bp);
        !          1196:                } else if (len) {
        !          1197:                        bp = getblk(vp, start_lbn, size, 0, 0);
        !          1198: 
        !          1199:                        KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_NONE,
        !          1200:                                           bp->b_lblkno,
        !          1201:                                           bp->b_blkno,
        !          1202:                                           bp->b_bcount,
        !          1203:                                           11,
        !          1204:                                           0 );
        !          1205:                        if (bp->b_flags & B_DELWRI) {
        !          1206:                                if (need_sync)
        !          1207:                                        bwrite(bp);
        !          1208:                                else
        !          1209:                                        bawrite(bp);
        !          1210:                        } else
        !          1211:                                brelse(bp);
        !          1212:                }
        !          1213:                return;
        !          1214:        }
        !          1215:        b_save = _MALLOC(sizeof(struct buf *) * len + sizeof(struct cluster_save),
        !          1216:                         M_SEGMENT, M_NOWAIT);
        !          1217:        if (b_save)
        !          1218:                bp = alloc_io_buf(vp);
        !          1219:        else
        !          1220:                bp = NULL;
        !          1221: 
        !          1222:        if (b_save == NULL || bp == NULL) {
        !          1223:                if (bp)
        !          1224:                        free_io_buf(bp);
        !          1225:                if (b_save)
        !          1226:                        _FREE(b_save, M_SEGMENT);
        !          1227: 
        !          1228:                for (i = 0; i < len; ++i, ++start_lbn) {
        !          1229:                        if (!incore(vp, start_lbn))
        !          1230:                                continue;
        !          1231:                        if (last_bp == NULL || start_lbn != lbn) {
        !          1232:                                tbp = getblk(vp, start_lbn, size, 0, 0);
        !          1233: 
        !          1234:                                if (tbp->b_flags & B_DELWRI) {
        !          1235:                                        KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_NONE,
        !          1236:                                                     tbp->b_lblkno,
        !          1237:                                                     tbp->b_blkno,
        !          1238:                                                     tbp->b_bcount,
        !          1239:                                                     12,
        !          1240:                                                     0 );
        !          1241: 
        !          1242:                                        if (need_sync)
        !          1243:                                                bwrite(tbp);
        !          1244:                                        else
        !          1245:                                                bawrite(tbp);
        !          1246:                                } else
        !          1247:                                        brelse(tbp);
        !          1248:                        }
        !          1249:                }
        !          1250:                if (last_bp) {
        !          1251:                        KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_NONE,
        !          1252:                                           last_bp->b_lblkno,
        !          1253:                                           last_bp->b_blkno,
        !          1254:                                           last_bp->b_bcount,
        !          1255:                                           13,
        !          1256:                                           0 );
        !          1257:                        if (need_sync)
        !          1258:                                bwrite(last_bp);
        !          1259:                        else
        !          1260:                                bawrite(last_bp);
        !          1261:                }
        !          1262:                return;
        !          1263:        }
        !          1264:        b_save->bs_bufsize = size;
        !          1265:        b_save->bs_nchildren = 0;
        !          1266:        b_save->bs_children = (struct buf **)(b_save + 1);
        !          1267: 
        !          1268:        bp->b_saveaddr = (caddr_t)b_save;
        !          1269:        bp->b_iodone = cluster_callback;
        !          1270:         bp->b_flags |= (B_WRITEINPROG | B_CALL | B_ASYNC);
        !          1271: 
        !          1272:        cp = (char *)bp->b_data;
        !          1273: 
        !          1274:        for (start_lbn, i = 0; i < len; ++i, ++start_lbn) {
        !          1275:                /*
        !          1276:                 * Block is not in core or the non-sequential block
        !          1277:                 * ending our cluster was part of the cluster (in which
        !          1278:                 * case we don't want to write it twice).
        !          1279:                 */
        !          1280:                if (!incore(vp, start_lbn) ||
        !          1281:                    (last_bp == NULL && start_lbn == lbn))
        !          1282:                        break;
        !          1283: 
        !          1284:                /*
        !          1285:                 * Get the desired block buffer (unless it is the final
        !          1286:                 * sequential block whose buffer was passed in explictly
        !          1287:                 * as last_bp).
        !          1288:                 */
        !          1289:                if (last_bp == NULL || start_lbn != lbn) {
        !          1290:                        tbp = getblk(vp, start_lbn, size, 0, 0);
        !          1291:                        if (!(tbp->b_flags & B_DELWRI)) {
        !          1292:                                brelse(tbp);
        !          1293:                                break;
        !          1294:                        }
        !          1295:                } else
        !          1296:                        tbp = last_bp;
        !          1297: 
        !          1298:                if (i == 0) {
        !          1299:                        bp->b_blkno = tbp->b_blkno;
        !          1300:                        bp->b_lblkno= tbp->b_lblkno;
        !          1301:                } else {
        !          1302:                        if (tbp->b_blkno != (bp->b_blkno + btodb(bp->b_bufsize, secsize))) {
        !          1303:                                brelse(tbp);
        !          1304:                                break;
        !          1305:                        }
        !          1306:                }
        !          1307:                /* Move memory from children to parent */
        !          1308:                pagemove(tbp->b_data, cp, size);
        !          1309:                bp->b_bcount += size;
        !          1310:                bp->b_bufsize += size;
        !          1311:                cp += size;
        !          1312: 
        !          1313:                tbp->b_bufsize -= size;
        !          1314:                tbp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI);
        !          1315:                tbp->b_flags |= (B_ASYNC | B_AGE);
        !          1316: 
        !          1317:                s = splbio();
        !          1318:                reassignbuf(tbp, tbp->b_vp);            /* put on clean list */
        !          1319:                ++tbp->b_vp->v_numoutput;
        !          1320:                splx(s);
        !          1321:  
        !          1322:                b_save->bs_children[i] = tbp;
        !          1323:                b_save->bs_nchildren++;
        !          1324:        }
        !          1325: 
        !          1326:        if (i == 0) {
        !          1327:                /* None to cluster */
        !          1328:                free_io_buf(bp);
        !          1329:                _FREE(b_save, M_SEGMENT);
        !          1330:        } else {
        !          1331:                if (bp->b_bcount > MAXPHYSIO)
        !          1332:                        panic("cluster_wbuild: bp->b_bcount = %x\n", bp->b_bcount);
        !          1333: 
        !          1334:                KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_NONE,
        !          1335:                                           bp->b_lblkno,
        !          1336:                                           bp->b_bcount,
        !          1337:                                           vp,
        !          1338:                                           0xbbbbbbaa,
        !          1339:                                           0 );
        !          1340:                VOP_STRATEGY(bp);
        !          1341:        }
        !          1342:        if (i < len) {
        !          1343:                len -= i + 1;
        !          1344:                start_lbn += 1;
        !          1345:                goto redo;
        !          1346:        }
        !          1347: }
        !          1348: 
        !          1349: /*
        !          1350:  * Collect together all the buffers in a cluster.
        !          1351:  * Plus add one additional buffer.
        !          1352:  */
        !          1353: struct cluster_save *
        !          1354: cluster_collectbufs(vp, last_bp)
        !          1355:        struct vnode *vp;
        !          1356:        struct buf *last_bp;
        !          1357: {
        !          1358:        struct cluster_save *buflist;
        !          1359:        daddr_t lbn;
        !          1360:        int i, j, len;
        !          1361: 
        !          1362:        len = vp->v_lastw - vp->v_cstart + 1;
        !          1363:        buflist = _MALLOC(sizeof(struct buf *) * (len + 1) + sizeof(*buflist),
        !          1364:            M_SEGMENT, M_NOWAIT);
        !          1365: 
        !          1366:        if (buflist == NULL)
        !          1367:                return (NULL);
        !          1368: 
        !          1369:        buflist->bs_nchildren = 0;
        !          1370:        buflist->bs_children = (struct buf **)(buflist + 1);
        !          1371:        for (lbn = vp->v_cstart, i = 0; i < len; lbn++, i++) {
        !          1372:                    (void)bread(vp, lbn, last_bp->b_bcount, NOCRED,
        !          1373:                        &buflist->bs_children[i]);
        !          1374:                    if(!(buflist->bs_children[i]->b_flags & B_DELWRI)) {
        !          1375:                      for (j=0; j<=i; j++)
        !          1376:                        brelse(buflist->bs_children[j]);
        !          1377:                      _FREE(buflist, M_SEGMENT);
        !          1378:                      return(NULL);
        !          1379:                    }
        !          1380:        }
        !          1381:        buflist->bs_children[i] = last_bp;
        !          1382:        buflist->bs_nchildren = i + 1;
        !          1383:        return (buflist);
        !          1384: }

unix.superglobalmegacorp.com

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