[BACK]Return to vfs_cluster.c CVS log [TXT][DIR] Up to [local] / sys / kern

Annotation of sys/kern/vfs_cluster.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: vfs_cluster.c,v 1.37 2007/05/26 20:26:51 pedro Exp $  */
        !             2: /*     $NetBSD: vfs_cluster.c,v 1.12 1996/04/22 01:39:05 christos Exp $        */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1993
        !             6:  *     The Regents of the University of California.  All rights reserved.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer.
        !            13:  * 2. Redistributions in binary form must reproduce the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer in the
        !            15:  *    documentation and/or other materials provided with the distribution.
        !            16:  * 3. Neither the name of the University nor the names of its contributors
        !            17:  *    may be used to endorse or promote products derived from this software
        !            18:  *    without specific prior written permission.
        !            19:  *
        !            20:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            30:  * SUCH DAMAGE.
        !            31:  *
        !            32:  *     @(#)vfs_cluster.c       8.8 (Berkeley) 7/28/94
        !            33:  */
        !            34:
        !            35: #include <sys/param.h>
        !            36: #include <sys/proc.h>
        !            37: #include <sys/buf.h>
        !            38: #include <sys/vnode.h>
        !            39: #include <sys/mount.h>
        !            40: #include <sys/malloc.h>
        !            41: #include <sys/systm.h>
        !            42: #include <sys/resourcevar.h>
        !            43:
        !            44: #include <uvm/uvm_extern.h>
        !            45:
        !            46: void cluster_wbuild(struct vnode *, struct buf *, long, daddr64_t, int,
        !            47:     daddr64_t);
        !            48: struct cluster_save *cluster_collectbufs(struct vnode *, struct cluster_info *,
        !            49:     struct buf *);
        !            50:
        !            51: /*
        !            52:  * Do clustered write for FFS.
        !            53:  *
        !            54:  * Three cases:
        !            55:  *     1. Write is not sequential (write asynchronously)
        !            56:  *     Write is sequential:
        !            57:  *     2.      beginning of cluster - begin cluster
        !            58:  *     3.      middle of a cluster - add to cluster
        !            59:  *     4.      end of a cluster - asynchronously write cluster
        !            60:  */
        !            61: void
        !            62: cluster_write(struct buf *bp, struct cluster_info *ci, u_quad_t filesize)
        !            63: {
        !            64:        struct vnode *vp;
        !            65:        daddr64_t lbn;
        !            66:        int maxclen, cursize;
        !            67:
        !            68:        vp = bp->b_vp;
        !            69:        lbn = bp->b_lblkno;
        !            70:
        !            71:        /* Initialize vnode to beginning of file. */
        !            72:        if (lbn == 0)
        !            73:                ci->ci_lasta = ci->ci_clen = ci->ci_cstart = ci->ci_lastw = 0;
        !            74:
        !            75:        if (ci->ci_clen == 0 || lbn != ci->ci_lastw + 1 ||
        !            76:            (bp->b_blkno != ci->ci_lasta + btodb(bp->b_bcount))) {
        !            77:                maxclen = MAXBSIZE / vp->v_mount->mnt_stat.f_iosize - 1;
        !            78:                if (ci->ci_clen != 0) {
        !            79:                        /*
        !            80:                         * Next block is not sequential.
        !            81:                         *
        !            82:                         * If we are not writing at end of file, the process
        !            83:                         * seeked to another point in the file since its
        !            84:                         * last write, or we have reached our maximum
        !            85:                         * cluster size, then push the previous cluster.
        !            86:                         * Otherwise try reallocating to make it sequential.
        !            87:                         */
        !            88:                        cursize = ci->ci_lastw - ci->ci_cstart + 1;
        !            89:                        if (((u_quad_t)(lbn + 1)) * bp->b_bcount != filesize ||
        !            90:                            lbn != ci->ci_lastw + 1 || ci->ci_clen <= cursize) {
        !            91:                                cluster_wbuild(vp, NULL, bp->b_bcount,
        !            92:                                    ci->ci_cstart, cursize, lbn);
        !            93:                        } else {
        !            94:                                struct buf **bpp, **endbp;
        !            95:                                struct cluster_save *buflist;
        !            96:
        !            97:                                buflist = cluster_collectbufs(vp, ci, bp);
        !            98:                                endbp = &buflist->bs_children
        !            99:                                    [buflist->bs_nchildren - 1];
        !           100:                                if (VOP_REALLOCBLKS(vp, buflist)) {
        !           101:                                        /*
        !           102:                                         * Failed, push the previous cluster.
        !           103:                                         */
        !           104:                                        for (bpp = buflist->bs_children;
        !           105:                                            bpp < endbp; bpp++)
        !           106:                                                brelse(*bpp);
        !           107:                                        free(buflist, M_VCLUSTER);
        !           108:                                        cluster_wbuild(vp, NULL, bp->b_bcount,
        !           109:                                            ci->ci_cstart, cursize, lbn);
        !           110:                                } else {
        !           111:                                        /*
        !           112:                                         * Succeeded, keep building cluster.
        !           113:                                         */
        !           114:                                        for (bpp = buflist->bs_children;
        !           115:                                            bpp <= endbp; bpp++)
        !           116:                                                bdwrite(*bpp);
        !           117:                                        free(buflist, M_VCLUSTER);
        !           118:                                        ci->ci_lastw = lbn;
        !           119:                                        ci->ci_lasta = bp->b_blkno;
        !           120:                                        return;
        !           121:                                }
        !           122:                        }
        !           123:                }
        !           124:                /*
        !           125:                 * Consider beginning a cluster.
        !           126:                 * If at end of file, make cluster as large as possible,
        !           127:                 * otherwise find size of existing cluster.
        !           128:                 */
        !           129:                if ((u_quad_t)(lbn + 1) * (u_quad_t)bp->b_bcount != filesize &&
        !           130:                    (VOP_BMAP(vp, lbn, NULL, &bp->b_blkno, &maxclen) ||
        !           131:                    bp->b_blkno == -1)) {
        !           132:                        bawrite(bp);
        !           133:                        ci->ci_clen = 0;
        !           134:                        ci->ci_lasta = bp->b_blkno;
        !           135:                        ci->ci_cstart = lbn + 1;
        !           136:                        ci->ci_lastw = lbn;
        !           137:                        return;
        !           138:                }
        !           139:                ci->ci_clen = maxclen;
        !           140:                if (maxclen == 0) {             /* I/O not contiguous */
        !           141:                        ci->ci_cstart = lbn + 1;
        !           142:                        bawrite(bp);
        !           143:                } else {                        /* Wait for rest of cluster */
        !           144:                        ci->ci_cstart = lbn;
        !           145:                        bdwrite(bp);
        !           146:                }
        !           147:        } else if (lbn == ci->ci_cstart + ci->ci_clen) {
        !           148:                /*
        !           149:                 * At end of cluster, write it out.
        !           150:                 */
        !           151:                cluster_wbuild(vp, bp, bp->b_bcount, ci->ci_cstart,
        !           152:                    ci->ci_clen + 1, lbn);
        !           153:                ci->ci_clen = 0;
        !           154:                ci->ci_cstart = lbn + 1;
        !           155:        } else
        !           156:                /*
        !           157:                 * In the middle of a cluster, so just delay the
        !           158:                 * I/O for now.
        !           159:                 */
        !           160:                bdwrite(bp);
        !           161:        ci->ci_lastw = lbn;
        !           162:        ci->ci_lasta = bp->b_blkno;
        !           163: }
        !           164:
        !           165: /*
        !           166:  * The last lbn argument is the current block on which I/O is being
        !           167:  * performed.  Check to see that it doesn't fall in the middle of
        !           168:  * the current block (if last_bp == NULL).
        !           169:  */
        !           170: void
        !           171: cluster_wbuild(struct vnode *vp, struct buf *last_bp, long size,
        !           172:     daddr64_t start_lbn, int len, daddr64_t lbn)
        !           173: {
        !           174:        struct buf *bp;
        !           175:
        !           176: #ifdef DIAGNOSTIC
        !           177:        if (size != vp->v_mount->mnt_stat.f_iosize)
        !           178:                panic("cluster_wbuild: size %ld != filesize %ld",
        !           179:                        size, vp->v_mount->mnt_stat.f_iosize);
        !           180: #endif
        !           181: redo:
        !           182:        while ((!incore(vp, start_lbn) || start_lbn == lbn) && len) {
        !           183:                ++start_lbn;
        !           184:                --len;
        !           185:        }
        !           186:
        !           187:        /* Get more memory for current buffer */
        !           188:        if (len <= 1) {
        !           189:                if (last_bp) {
        !           190:                        bawrite(last_bp);
        !           191:                } else if (len) {
        !           192:                        bp = getblk(vp, start_lbn, size, 0, 0);
        !           193:                        /*
        !           194:                         * The buffer could have already been flushed out of
        !           195:                         * the cache. If that has happened, we'll get a new
        !           196:                         * buffer here with random data, just drop it.
        !           197:                         */
        !           198:                        if ((bp->b_flags & B_DELWRI) == 0)
        !           199:                                brelse(bp);
        !           200:                        else
        !           201:                                bawrite(bp);
        !           202:                }
        !           203:                return;
        !           204:        }
        !           205:
        !           206:        bp = getblk(vp, start_lbn, size, 0, 0);
        !           207:        if (!(bp->b_flags & B_DELWRI)) {
        !           208:                ++start_lbn;
        !           209:                --len;
        !           210:                brelse(bp);
        !           211:                goto redo;
        !           212:        }
        !           213:
        !           214:        ++start_lbn;
        !           215:        --len;
        !           216:        bawrite(bp);
        !           217:        goto redo;
        !           218: }
        !           219:
        !           220: /*
        !           221:  * Collect together all the buffers in a cluster.
        !           222:  * Plus add one additional buffer.
        !           223:  */
        !           224: struct cluster_save *
        !           225: cluster_collectbufs(struct vnode *vp, struct cluster_info *ci,
        !           226:     struct buf *last_bp)
        !           227: {
        !           228:        struct cluster_save *buflist;
        !           229:        daddr64_t lbn;
        !           230:        int i, len;
        !           231:
        !           232:        len = ci->ci_lastw - ci->ci_cstart + 1;
        !           233:        buflist = malloc(sizeof(struct buf *) * (len + 1) + sizeof(*buflist),
        !           234:            M_VCLUSTER, M_WAITOK);
        !           235:        buflist->bs_nchildren = 0;
        !           236:        buflist->bs_children = (struct buf **)(buflist + 1);
        !           237:        for (lbn = ci->ci_cstart, i = 0; i < len; lbn++, i++)
        !           238:                (void)bread(vp, lbn, last_bp->b_bcount, NOCRED,
        !           239:                    &buflist->bs_children[i]);
        !           240:        buflist->bs_children[i] = last_bp;
        !           241:        buflist->bs_nchildren = i + 1;
        !           242:        return (buflist);
        !           243: }

CVSweb