Annotation of kernel/bsd/vfs/vfs_cluster.c, revision 1.1.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.