Annotation of kernel/bsd/vfs/vfs_cluster.c, revision 1.1

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

unix.superglobalmegacorp.com

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