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