|
|
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: /* $NetBSD: lfs_segment.c,v 1.3 1994/08/21 03:15:32 cgd Exp $ */ ! 26: ! 27: /* ! 28: * Copyright (c) 1991, 1993 ! 29: * The Regents of the University of California. All rights reserved. ! 30: * ! 31: * Redistribution and use in source and binary forms, with or without ! 32: * modification, are permitted provided that the following conditions ! 33: * are met: ! 34: * 1. Redistributions of source code must retain the above copyright ! 35: * notice, this list of conditions and the following disclaimer. ! 36: * 2. Redistributions in binary form must reproduce the above copyright ! 37: * notice, this list of conditions and the following disclaimer in the ! 38: * documentation and/or other materials provided with the distribution. ! 39: * 3. All advertising materials mentioning features or use of this software ! 40: * must display the following acknowledgement: ! 41: * This product includes software developed by the University of ! 42: * California, Berkeley and its contributors. ! 43: * 4. Neither the name of the University nor the names of its contributors ! 44: * may be used to endorse or promote products derived from this software ! 45: * without specific prior written permission. ! 46: * ! 47: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 48: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 49: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 50: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 51: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 52: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 53: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 54: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 55: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 56: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 57: * SUCH DAMAGE. ! 58: * ! 59: * @(#)lfs_segment.c 8.5 (Berkeley) 1/4/94 ! 60: */ ! 61: ! 62: #include <sys/param.h> ! 63: #include <sys/systm.h> ! 64: #include <sys/namei.h> ! 65: #include <sys/kernel.h> ! 66: #include <sys/resourcevar.h> ! 67: #include <sys/file.h> ! 68: #include <sys/stat.h> ! 69: #include <sys/buf.h> ! 70: #include <sys/proc.h> ! 71: #include <sys/conf.h> ! 72: #include <sys/vnode.h> ! 73: #include <sys/malloc.h> ! 74: #include <sys/mount.h> ! 75: ! 76: #include <miscfs/specfs/specdev.h> ! 77: #include <miscfs/fifofs/fifo.h> ! 78: ! 79: #include <ufs/ufs/quota.h> ! 80: #include <ufs/ufs/inode.h> ! 81: #include <ufs/ufs/dir.h> ! 82: #include <ufs/ufs/ufsmount.h> ! 83: #include <ufs/ufs/ufs_extern.h> ! 84: ! 85: #include <ufs/lfs/lfs.h> ! 86: #include <ufs/lfs/lfs_extern.h> ! 87: ! 88: extern int count_lock_queue __P((void)); ! 89: ! 90: #define MAX_ACTIVE 10 ! 91: /* ! 92: * Determine if it's OK to start a partial in this segment, or if we need ! 93: * to go on to a new segment. ! 94: */ ! 95: #define LFS_PARTIAL_FITS(fs) \ ! 96: ((fs)->lfs_dbpseg - ((fs)->lfs_offset - (fs)->lfs_curseg) > \ ! 97: 1 << (fs)->lfs_fsbtodb) ! 98: ! 99: void lfs_callback __P((struct buf *)); ! 100: void lfs_gather __P((struct lfs *, struct segment *, ! 101: struct vnode *, int (*) __P((struct lfs *, struct buf *)))); ! 102: int lfs_gatherblock __P((struct segment *, struct buf *, int *)); ! 103: void lfs_iset __P((struct inode *, daddr_t, time_t)); ! 104: int lfs_match_data __P((struct lfs *, struct buf *)); ! 105: int lfs_match_dindir __P((struct lfs *, struct buf *)); ! 106: int lfs_match_indir __P((struct lfs *, struct buf *)); ! 107: int lfs_match_tindir __P((struct lfs *, struct buf *)); ! 108: void lfs_newseg __P((struct lfs *)); ! 109: void lfs_shellsort __P((struct buf **, daddr_t *, register int)); ! 110: void lfs_supercallback __P((struct buf *)); ! 111: void lfs_updatemeta __P((struct segment *)); ! 112: int lfs_vref __P((struct vnode *)); ! 113: void lfs_vunref __P((struct vnode *)); ! 114: void lfs_writefile __P((struct lfs *, struct segment *, struct vnode *)); ! 115: int lfs_writeinode __P((struct lfs *, struct segment *, struct inode *)); ! 116: int lfs_writeseg __P((struct lfs *, struct segment *)); ! 117: void lfs_writesuper __P((struct lfs *)); ! 118: void lfs_writevnodes __P((struct lfs *fs, struct mount *mp, ! 119: struct segment *sp, int dirops)); ! 120: ! 121: int lfs_allclean_wakeup; /* Cleaner wakeup address. */ ! 122: ! 123: /* Statistics Counters */ ! 124: #define DOSTATS ! 125: struct lfs_stats lfs_stats; ! 126: ! 127: /* op values to lfs_writevnodes */ ! 128: #define VN_REG 0 ! 129: #define VN_DIROP 1 ! 130: #define VN_EMPTY 2 ! 131: ! 132: /* ! 133: * Ifile and meta data blocks are not marked busy, so segment writes MUST be ! 134: * single threaded. Currently, there are two paths into lfs_segwrite, sync() ! 135: * and getnewbuf(). They both mark the file system busy. Lfs_vflush() ! 136: * explicitly marks the file system busy. So lfs_segwrite is safe. I think. ! 137: */ ! 138: ! 139: int ! 140: lfs_vflush(vp) ! 141: struct vnode *vp; ! 142: { ! 143: struct inode *ip; ! 144: struct lfs *fs; ! 145: struct segment *sp; ! 146: ! 147: fs = VFSTOUFS(vp->v_mount)->um_lfs; ! 148: if (fs->lfs_nactive > MAX_ACTIVE) ! 149: return(lfs_segwrite(vp->v_mount, SEGM_SYNC|SEGM_CKP)); ! 150: lfs_seglock(fs, SEGM_SYNC); ! 151: sp = fs->lfs_sp; ! 152: ! 153: ! 154: ip = VTOI(vp); ! 155: if (vp->v_dirtyblkhd.lh_first == NULL) ! 156: lfs_writevnodes(fs, vp->v_mount, sp, VN_EMPTY); ! 157: ! 158: do { ! 159: do { ! 160: if (vp->v_dirtyblkhd.lh_first != NULL) ! 161: lfs_writefile(fs, sp, vp); ! 162: } while (lfs_writeinode(fs, sp, ip)); ! 163: ! 164: } while (lfs_writeseg(fs, sp) && ip->i_number == LFS_IFILE_INUM); ! 165: ! 166: #ifdef DOSTATS ! 167: ++lfs_stats.nwrites; ! 168: if (sp->seg_flags & SEGM_SYNC) ! 169: ++lfs_stats.nsync_writes; ! 170: if (sp->seg_flags & SEGM_CKP) ! 171: ++lfs_stats.ncheckpoints; ! 172: #endif ! 173: lfs_segunlock(fs); ! 174: return (0); ! 175: } ! 176: ! 177: void ! 178: lfs_writevnodes(fs, mp, sp, op) ! 179: struct lfs *fs; ! 180: struct mount *mp; ! 181: struct segment *sp; ! 182: int op; ! 183: { ! 184: struct inode *ip; ! 185: struct vnode *vp; ! 186: ! 187: loop: ! 188: for (vp = mp->mnt_vnodelist.lh_first; ! 189: vp != NULL; ! 190: vp = vp->v_mntvnodes.le_next) { ! 191: /* ! 192: * If the vnode that we are about to sync is no longer ! 193: * associated with this mount point, start over. ! 194: */ ! 195: if (vp->v_mount != mp) ! 196: goto loop; ! 197: ! 198: /* XXX ignore dirops for now ! 199: if (op == VN_DIROP && !(vp->v_flag & VDIROP) || ! 200: op != VN_DIROP && (vp->v_flag & VDIROP)) ! 201: continue; ! 202: */ ! 203: ! 204: if (op == VN_EMPTY && vp->v_dirtyblkhd.lh_first) ! 205: continue; ! 206: ! 207: if (vp->v_type == VNON) ! 208: continue; ! 209: ! 210: if (lfs_vref(vp)) ! 211: continue; ! 212: ! 213: /* ! 214: * Write the inode/file if dirty and it's not the ! 215: * the IFILE. ! 216: */ ! 217: ip = VTOI(vp); ! 218: if ((ip->i_flag & ! 219: (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE) || ! 220: vp->v_dirtyblkhd.lh_first != NULL) && ! 221: ip->i_number != LFS_IFILE_INUM) { ! 222: if (vp->v_dirtyblkhd.lh_first != NULL) ! 223: lfs_writefile(fs, sp, vp); ! 224: (void) lfs_writeinode(fs, sp, ip); ! 225: } ! 226: vp->v_flag &= ~VDIROP; ! 227: lfs_vunref(vp); ! 228: } ! 229: } ! 230: ! 231: int ! 232: lfs_segwrite(mp, flags) ! 233: struct mount *mp; ! 234: int flags; /* Do a checkpoint. */ ! 235: { ! 236: struct buf *bp; ! 237: struct inode *ip; ! 238: struct lfs *fs; ! 239: struct segment *sp; ! 240: struct vnode *vp; ! 241: SEGUSE *segusep; ! 242: daddr_t ibno; ! 243: CLEANERINFO *cip; ! 244: int clean, do_ckp, error, i; ! 245: ! 246: fs = VFSTOUFS(mp)->um_lfs; ! 247: ! 248: /* ! 249: * If we have fewer than 2 clean segments, wait until cleaner ! 250: * writes. ! 251: */ ! 252: do { ! 253: LFS_CLEANERINFO(cip, fs, bp); ! 254: clean = cip->clean; ! 255: brelse(bp); ! 256: if (clean <= 2) { ! 257: printf ("segs clean: %d\n", clean); ! 258: wakeup(&lfs_allclean_wakeup); ! 259: if (error = tsleep(&fs->lfs_avail, PRIBIO + 1, ! 260: "lfs writer", 0)) ! 261: return (error); ! 262: } ! 263: } while (clean <= 2 ); ! 264: ! 265: /* ! 266: * Allocate a segment structure and enough space to hold pointers to ! 267: * the maximum possible number of buffers which can be described in a ! 268: * single summary block. ! 269: */ ! 270: do_ckp = flags & SEGM_CKP || fs->lfs_nactive > MAX_ACTIVE; ! 271: lfs_seglock(fs, flags | (do_ckp ? SEGM_CKP : 0)); ! 272: sp = fs->lfs_sp; ! 273: ! 274: lfs_writevnodes(fs, mp, sp, VN_REG); ! 275: ! 276: /* XXX ignore ordering of dirops for now */ ! 277: /* XXX ! 278: fs->lfs_writer = 1; ! 279: if (fs->lfs_dirops && (error = ! 280: tsleep(&fs->lfs_writer, PRIBIO + 1, "lfs writer", 0))) { ! 281: free(sp->bpp, M_SEGMENT); ! 282: free(sp, M_SEGMENT); ! 283: fs->lfs_writer = 0; ! 284: return (error); ! 285: } ! 286: ! 287: lfs_writevnodes(fs, mp, sp, VN_DIROP); ! 288: */ ! 289: ! 290: /* ! 291: * If we are doing a checkpoint, mark everything since the ! 292: * last checkpoint as no longer ACTIVE. ! 293: */ ! 294: if (do_ckp) ! 295: for (ibno = fs->lfs_cleansz + fs->lfs_segtabsz; ! 296: --ibno >= fs->lfs_cleansz; ) { ! 297: if (bread(fs->lfs_ivnode, ibno, fs->lfs_bsize, ! 298: NOCRED, &bp)) ! 299: ! 300: panic("lfs: ifile read"); ! 301: segusep = (SEGUSE *)bp->b_data; ! 302: for (i = fs->lfs_sepb; i--; segusep++) ! 303: segusep->su_flags &= ~SEGUSE_ACTIVE; ! 304: ! 305: error = VOP_BWRITE(bp); ! 306: } ! 307: ! 308: if (do_ckp || fs->lfs_doifile) { ! 309: redo: ! 310: vp = fs->lfs_ivnode; ! 311: while (vget(vp, 1)); ! 312: ip = VTOI(vp); ! 313: if (vp->v_dirtyblkhd.lh_first != NULL) ! 314: lfs_writefile(fs, sp, vp); ! 315: (void)lfs_writeinode(fs, sp, ip); ! 316: vput(vp); ! 317: if (lfs_writeseg(fs, sp) && do_ckp) ! 318: goto redo; ! 319: } else ! 320: (void) lfs_writeseg(fs, sp); ! 321: ! 322: /* ! 323: * If the I/O count is non-zero, sleep until it reaches zero. At the ! 324: * moment, the user's process hangs around so we can sleep. ! 325: */ ! 326: /* XXX ignore dirops for now ! 327: fs->lfs_writer = 0; ! 328: fs->lfs_doifile = 0; ! 329: wakeup(&fs->lfs_dirops); ! 330: */ ! 331: ! 332: #ifdef DOSTATS ! 333: ++lfs_stats.nwrites; ! 334: if (sp->seg_flags & SEGM_SYNC) ! 335: ++lfs_stats.nsync_writes; ! 336: if (sp->seg_flags & SEGM_CKP) ! 337: ++lfs_stats.ncheckpoints; ! 338: #endif ! 339: lfs_segunlock(fs); ! 340: return (0); ! 341: } ! 342: ! 343: /* ! 344: * Write the dirty blocks associated with a vnode. ! 345: */ ! 346: void ! 347: lfs_writefile(fs, sp, vp) ! 348: struct lfs *fs; ! 349: struct segment *sp; ! 350: struct vnode *vp; ! 351: { ! 352: struct buf *bp; ! 353: struct finfo *fip; ! 354: IFILE *ifp; ! 355: ! 356: if (sp->seg_bytes_left < fs->lfs_bsize || ! 357: sp->sum_bytes_left < sizeof(struct finfo)) ! 358: (void) lfs_writeseg(fs, sp); ! 359: ! 360: sp->sum_bytes_left -= sizeof(struct finfo) - sizeof(daddr_t); ! 361: ++((SEGSUM *)(sp->segsum))->ss_nfinfo; ! 362: ! 363: fip = sp->fip; ! 364: fip->fi_nblocks = 0; ! 365: fip->fi_ino = VTOI(vp)->i_number; ! 366: LFS_IENTRY(ifp, fs, fip->fi_ino, bp); ! 367: fip->fi_version = ifp->if_version; ! 368: brelse(bp); ! 369: ! 370: /* ! 371: * It may not be necessary to write the meta-data blocks at this point, ! 372: * as the roll-forward recovery code should be able to reconstruct the ! 373: * list. ! 374: */ ! 375: lfs_gather(fs, sp, vp, lfs_match_data); ! 376: lfs_gather(fs, sp, vp, lfs_match_indir); ! 377: lfs_gather(fs, sp, vp, lfs_match_dindir); ! 378: #ifdef TRIPLE ! 379: lfs_gather(fs, sp, vp, lfs_match_tindir); ! 380: #endif ! 381: ! 382: fip = sp->fip; ! 383: if (fip->fi_nblocks != 0) { ! 384: sp->fip = ! 385: (struct finfo *)((caddr_t)fip + sizeof(struct finfo) + ! 386: sizeof(daddr_t) * (fip->fi_nblocks - 1)); ! 387: sp->start_lbp = &sp->fip->fi_blocks[0]; ! 388: } else { ! 389: sp->sum_bytes_left += sizeof(struct finfo) - sizeof(daddr_t); ! 390: --((SEGSUM *)(sp->segsum))->ss_nfinfo; ! 391: } ! 392: } ! 393: ! 394: int ! 395: lfs_writeinode(fs, sp, ip) ! 396: struct lfs *fs; ! 397: struct segment *sp; ! 398: struct inode *ip; ! 399: { ! 400: struct buf *bp, *ibp; ! 401: IFILE *ifp; ! 402: SEGUSE *sup; ! 403: daddr_t daddr; ! 404: ino_t ino; ! 405: int error, i, ndx; ! 406: int redo_ifile = 0; ! 407: ! 408: if (!(ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE))) ! 409: return(0); ! 410: ! 411: /* Allocate a new inode block if necessary. */ ! 412: if (sp->ibp == NULL) { ! 413: /* Allocate a new segment if necessary. */ ! 414: if (sp->seg_bytes_left < fs->lfs_bsize || ! 415: sp->sum_bytes_left < sizeof(daddr_t)) ! 416: (void) lfs_writeseg(fs, sp); ! 417: ! 418: /* Get next inode block. */ ! 419: daddr = fs->lfs_offset; ! 420: fs->lfs_offset += fsbtodb(fs, 1); ! 421: sp->ibp = *sp->cbpp++ = ! 422: lfs_newbuf(VTOI(fs->lfs_ivnode)->i_devvp, daddr, ! 423: fs->lfs_bsize); ! 424: /* Zero out inode numbers */ ! 425: for (i = 0; i < INOPB(fs); ++i) ! 426: ((struct dinode *)sp->ibp->b_data)[i].di_inumber = 0; ! 427: ++sp->start_bpp; ! 428: fs->lfs_avail -= fsbtodb(fs, 1); ! 429: /* Set remaining space counters. */ ! 430: sp->seg_bytes_left -= fs->lfs_bsize; ! 431: sp->sum_bytes_left -= sizeof(daddr_t); ! 432: ndx = LFS_SUMMARY_SIZE / sizeof(daddr_t) - ! 433: sp->ninodes / INOPB(fs) - 1; ! 434: ((daddr_t *)(sp->segsum))[ndx] = daddr; ! 435: } ! 436: ! 437: /* Update the inode times and copy the inode onto the inode page. */ ! 438: if (ip->i_flag & IN_MODIFIED) ! 439: --fs->lfs_uinodes; ! 440: ITIMES(ip, &time, &time); ! 441: ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE); ! 442: bp = sp->ibp; ! 443: ((struct dinode *)bp->b_data)[sp->ninodes % INOPB(fs)] = ip->i_din; ! 444: /* Increment inode count in segment summary block. */ ! 445: ++((SEGSUM *)(sp->segsum))->ss_ninos; ! 446: ! 447: /* If this page is full, set flag to allocate a new page. */ ! 448: if (++sp->ninodes % INOPB(fs) == 0) ! 449: sp->ibp = NULL; ! 450: ! 451: /* ! 452: * If updating the ifile, update the super-block. Update the disk ! 453: * address and access times for this inode in the ifile. ! 454: */ ! 455: ino = ip->i_number; ! 456: if (ino == LFS_IFILE_INUM) { ! 457: daddr = fs->lfs_idaddr; ! 458: fs->lfs_idaddr = bp->b_blkno; ! 459: } else { ! 460: LFS_IENTRY(ifp, fs, ino, ibp); ! 461: daddr = ifp->if_daddr; ! 462: ifp->if_daddr = bp->b_blkno; ! 463: error = VOP_BWRITE(ibp); ! 464: } ! 465: ! 466: /* ! 467: * No need to update segment usage if there was no former inode address ! 468: * or if the last inode address is in the current partial segment. ! 469: */ ! 470: if (daddr != LFS_UNUSED_DADDR && ! 471: !(daddr >= fs->lfs_lastpseg && daddr <= bp->b_blkno)) { ! 472: LFS_SEGENTRY(sup, fs, datosn(fs, daddr), bp); ! 473: #if DIAGNOSTIC ! 474: if (sup->su_nbytes < sizeof(struct dinode)) { ! 475: /* XXX -- Change to a panic. */ ! 476: printf("lfs: negative bytes (segment %d)\n", ! 477: datosn(fs, daddr)); ! 478: panic("negative bytes"); ! 479: } ! 480: #endif ! 481: sup->su_nbytes -= sizeof(struct dinode); ! 482: redo_ifile = ! 483: (ino == LFS_IFILE_INUM && !(bp->b_flags & B_GATHERED)); ! 484: error = VOP_BWRITE(bp); ! 485: } ! 486: return (redo_ifile); ! 487: } ! 488: ! 489: int ! 490: lfs_gatherblock(sp, bp, sptr) ! 491: struct segment *sp; ! 492: struct buf *bp; ! 493: int *sptr; ! 494: { ! 495: struct lfs *fs; ! 496: int version; ! 497: ! 498: /* ! 499: * If full, finish this segment. We may be doing I/O, so ! 500: * release and reacquire the splbio(). ! 501: */ ! 502: #if DIAGNOSTIC ! 503: if (sp->vp == NULL) ! 504: panic ("lfs_gatherblock: Null vp in segment"); ! 505: #endif ! 506: fs = sp->fs; ! 507: if (sp->sum_bytes_left < sizeof(daddr_t) || ! 508: sp->seg_bytes_left < fs->lfs_bsize) { ! 509: if (sptr) ! 510: splx(*sptr); ! 511: lfs_updatemeta(sp); ! 512: ! 513: version = sp->fip->fi_version; ! 514: (void) lfs_writeseg(fs, sp); ! 515: ! 516: sp->fip->fi_version = version; ! 517: sp->fip->fi_ino = VTOI(sp->vp)->i_number; ! 518: /* Add the current file to the segment summary. */ ! 519: ++((SEGSUM *)(sp->segsum))->ss_nfinfo; ! 520: sp->sum_bytes_left -= ! 521: sizeof(struct finfo) - sizeof(daddr_t); ! 522: ! 523: if (sptr) ! 524: *sptr = splbio(); ! 525: return(1); ! 526: } ! 527: ! 528: /* Insert into the buffer list, update the FINFO block. */ ! 529: bp->b_flags |= B_GATHERED; ! 530: *sp->cbpp++ = bp; ! 531: sp->fip->fi_blocks[sp->fip->fi_nblocks++] = bp->b_lblkno; ! 532: ! 533: sp->sum_bytes_left -= sizeof(daddr_t); ! 534: sp->seg_bytes_left -= fs->lfs_bsize; ! 535: return(0); ! 536: } ! 537: ! 538: void ! 539: lfs_gather(fs, sp, vp, match) ! 540: struct lfs *fs; ! 541: struct segment *sp; ! 542: struct vnode *vp; ! 543: int (*match) __P((struct lfs *, struct buf *)); ! 544: { ! 545: struct buf *bp; ! 546: int s; ! 547: ! 548: sp->vp = vp; ! 549: s = splbio(); ! 550: loop: for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = bp->b_vnbufs.le_next) { ! 551: if (bp->b_flags & B_BUSY || !match(fs, bp) || ! 552: bp->b_flags & B_GATHERED) ! 553: continue; ! 554: #if DIAGNOSTIC ! 555: if (!(bp->b_flags & B_DELWRI)) ! 556: panic("lfs_gather: bp not B_DELWRI"); ! 557: if (!(bp->b_flags & B_LOCKED)) ! 558: panic("lfs_gather: bp not B_LOCKED"); ! 559: #endif ! 560: if (lfs_gatherblock(sp, bp, &s)) ! 561: goto loop; ! 562: } ! 563: splx(s); ! 564: lfs_updatemeta(sp); ! 565: sp->vp = NULL; ! 566: } ! 567: ! 568: ! 569: /* ! 570: * Update the metadata that points to the blocks listed in the FINFO ! 571: * array. ! 572: */ ! 573: void ! 574: lfs_updatemeta(sp) ! 575: struct segment *sp; ! 576: { ! 577: SEGUSE *sup; ! 578: struct buf *bp; ! 579: struct lfs *fs; ! 580: struct vnode *vp; ! 581: struct indir a[NIADDR + 2], *ap; ! 582: struct inode *ip; ! 583: daddr_t daddr, lbn, off; ! 584: int db_per_fsb, error, i, nblocks, num; ! 585: ! 586: vp = sp->vp; ! 587: nblocks = &sp->fip->fi_blocks[sp->fip->fi_nblocks] - sp->start_lbp; ! 588: if (vp == NULL || nblocks == 0) ! 589: return; ! 590: ! 591: /* Sort the blocks. */ ! 592: if (!(sp->seg_flags & SEGM_CLEAN)) ! 593: lfs_shellsort(sp->start_bpp, sp->start_lbp, nblocks); ! 594: ! 595: /* ! 596: * Assign disk addresses, and update references to the logical ! 597: * block and the segment usage information. ! 598: */ ! 599: fs = sp->fs; ! 600: db_per_fsb = fsbtodb(fs, 1); ! 601: for (i = nblocks; i--; ++sp->start_bpp) { ! 602: lbn = *sp->start_lbp++; ! 603: (*sp->start_bpp)->b_blkno = off = fs->lfs_offset; ! 604: fs->lfs_offset += db_per_fsb; ! 605: ! 606: if (error = ufs_bmaparray(vp, lbn, &daddr, a, &num, NULL)) ! 607: panic("lfs_updatemeta: ufs_bmaparray %d", error); ! 608: ip = VTOI(vp); ! 609: switch (num) { ! 610: case 0: ! 611: ip->i_db[lbn] = off; ! 612: break; ! 613: case 1: ! 614: ip->i_ib[a[0].in_off] = off; ! 615: break; ! 616: default: ! 617: ap = &a[num - 1]; ! 618: if (bread(vp, ap->in_lbn, fs->lfs_bsize, NOCRED, &bp)) ! 619: panic("lfs_updatemeta: bread bno %d", ! 620: ap->in_lbn); ! 621: /* ! 622: * Bread may create a new indirect block which needs ! 623: * to get counted for the inode. ! 624: */ ! 625: if (bp->b_blkno == -1 && !(bp->b_flags & B_CACHE)) { ! 626: printf ("Updatemeta allocating indirect block: shouldn't happen\n"); ! 627: ip->i_blocks += btodb(fs->lfs_bsize); ! 628: fs->lfs_bfree -= btodb(fs->lfs_bsize); ! 629: } ! 630: ((daddr_t *)bp->b_data)[ap->in_off] = off; ! 631: VOP_BWRITE(bp); ! 632: } ! 633: ! 634: /* Update segment usage information. */ ! 635: if (daddr != UNASSIGNED && ! 636: !(daddr >= fs->lfs_lastpseg && daddr <= off)) { ! 637: LFS_SEGENTRY(sup, fs, datosn(fs, daddr), bp); ! 638: #if DIAGNOSTIC ! 639: if (sup->su_nbytes < fs->lfs_bsize) { ! 640: /* XXX -- Change to a panic. */ ! 641: printf("lfs: negative bytes (segment %d)\n", ! 642: datosn(fs, daddr)); ! 643: panic ("Negative Bytes"); ! 644: } ! 645: #endif ! 646: sup->su_nbytes -= fs->lfs_bsize; ! 647: error = VOP_BWRITE(bp); ! 648: } ! 649: } ! 650: } ! 651: ! 652: /* ! 653: * Start a new segment. ! 654: */ ! 655: int ! 656: lfs_initseg(fs) ! 657: struct lfs *fs; ! 658: { ! 659: struct segment *sp; ! 660: SEGUSE *sup; ! 661: SEGSUM *ssp; ! 662: struct buf *bp; ! 663: int repeat; ! 664: ! 665: sp = fs->lfs_sp; ! 666: ! 667: repeat = 0; ! 668: /* Advance to the next segment. */ ! 669: if (!LFS_PARTIAL_FITS(fs)) { ! 670: /* Wake up any cleaning procs waiting on this file system. */ ! 671: wakeup(&lfs_allclean_wakeup); ! 672: ! 673: lfs_newseg(fs); ! 674: repeat = 1; ! 675: fs->lfs_offset = fs->lfs_curseg; ! 676: sp->seg_number = datosn(fs, fs->lfs_curseg); ! 677: sp->seg_bytes_left = fs->lfs_dbpseg * DEV_BSIZE; ! 678: ! 679: /* ! 680: * If the segment contains a superblock, update the offset ! 681: * and summary address to skip over it. ! 682: */ ! 683: LFS_SEGENTRY(sup, fs, sp->seg_number, bp); ! 684: if (sup->su_flags & SEGUSE_SUPERBLOCK) { ! 685: fs->lfs_offset += LFS_SBPAD / DEV_BSIZE; ! 686: sp->seg_bytes_left -= LFS_SBPAD; ! 687: } ! 688: brelse(bp); ! 689: } else { ! 690: sp->seg_number = datosn(fs, fs->lfs_curseg); ! 691: sp->seg_bytes_left = (fs->lfs_dbpseg - ! 692: (fs->lfs_offset - fs->lfs_curseg)) * DEV_BSIZE; ! 693: } ! 694: fs->lfs_lastpseg = fs->lfs_offset; ! 695: ! 696: sp->fs = fs; ! 697: sp->ibp = NULL; ! 698: sp->ninodes = 0; ! 699: ! 700: /* Get a new buffer for SEGSUM and enter it into the buffer list. */ ! 701: sp->cbpp = sp->bpp; ! 702: *sp->cbpp = lfs_newbuf(VTOI(fs->lfs_ivnode)->i_devvp, fs->lfs_offset, ! 703: LFS_SUMMARY_SIZE); ! 704: sp->segsum = (*sp->cbpp)->b_data; ! 705: bzero(sp->segsum, LFS_SUMMARY_SIZE); ! 706: sp->start_bpp = ++sp->cbpp; ! 707: fs->lfs_offset += LFS_SUMMARY_SIZE / DEV_BSIZE; ! 708: ! 709: /* Set point to SEGSUM, initialize it. */ ! 710: ssp = sp->segsum; ! 711: ssp->ss_next = fs->lfs_nextseg; ! 712: ssp->ss_nfinfo = ssp->ss_ninos = 0; ! 713: ! 714: /* Set pointer to first FINFO, initialize it. */ ! 715: sp->fip = (struct finfo *)((caddr_t)sp->segsum + sizeof(SEGSUM)); ! 716: sp->fip->fi_nblocks = 0; ! 717: sp->start_lbp = &sp->fip->fi_blocks[0]; ! 718: ! 719: sp->seg_bytes_left -= LFS_SUMMARY_SIZE; ! 720: sp->sum_bytes_left = LFS_SUMMARY_SIZE - sizeof(SEGSUM); ! 721: ! 722: return(repeat); ! 723: } ! 724: ! 725: /* ! 726: * Return the next segment to write. ! 727: */ ! 728: void ! 729: lfs_newseg(fs) ! 730: struct lfs *fs; ! 731: { ! 732: CLEANERINFO *cip; ! 733: SEGUSE *sup; ! 734: struct buf *bp; ! 735: int curseg, isdirty, sn; ! 736: ! 737: LFS_SEGENTRY(sup, fs, datosn(fs, fs->lfs_nextseg), bp); ! 738: sup->su_flags |= SEGUSE_DIRTY | SEGUSE_ACTIVE; ! 739: sup->su_nbytes = 0; ! 740: sup->su_nsums = 0; ! 741: sup->su_ninos = 0; ! 742: (void) VOP_BWRITE(bp); ! 743: ! 744: LFS_CLEANERINFO(cip, fs, bp); ! 745: --cip->clean; ! 746: ++cip->dirty; ! 747: (void) VOP_BWRITE(bp); ! 748: ! 749: fs->lfs_lastseg = fs->lfs_curseg; ! 750: fs->lfs_curseg = fs->lfs_nextseg; ! 751: for (sn = curseg = datosn(fs, fs->lfs_curseg);;) { ! 752: sn = (sn + 1) % fs->lfs_nseg; ! 753: if (sn == curseg) ! 754: panic("lfs_nextseg: no clean segments"); ! 755: LFS_SEGENTRY(sup, fs, sn, bp); ! 756: isdirty = sup->su_flags & SEGUSE_DIRTY; ! 757: brelse(bp); ! 758: if (!isdirty) ! 759: break; ! 760: } ! 761: ! 762: ++fs->lfs_nactive; ! 763: fs->lfs_nextseg = sntoda(fs, sn); ! 764: #ifdef DOSTATS ! 765: ++lfs_stats.segsused; ! 766: #endif ! 767: } ! 768: ! 769: int ! 770: lfs_writeseg(fs, sp) ! 771: struct lfs *fs; ! 772: struct segment *sp; ! 773: { ! 774: extern int locked_queue_count; ! 775: struct buf **bpp, *bp, *cbp; ! 776: SEGUSE *sup; ! 777: SEGSUM *ssp; ! 778: dev_t i_dev; ! 779: size_t size; ! 780: u_long *datap, *dp; ! 781: int ch_per_blk, do_again, i, nblocks, num, s; ! 782: int (*strategy)__P((struct vop_strategy_args *)); ! 783: struct vop_strategy_args vop_strategy_a; ! 784: u_short ninos; ! 785: char *p; ! 786: ! 787: /* ! 788: * If there are no buffers other than the segment summary to write ! 789: * and it is not a checkpoint, don't do anything. On a checkpoint, ! 790: * even if there aren't any buffers, you need to write the superblock. ! 791: */ ! 792: if ((nblocks = sp->cbpp - sp->bpp) == 1) ! 793: return (0); ! 794: ! 795: ssp = (SEGSUM *)sp->segsum; ! 796: ! 797: /* Update the segment usage information. */ ! 798: LFS_SEGENTRY(sup, fs, sp->seg_number, bp); ! 799: ninos = (ssp->ss_ninos + INOPB(fs) - 1) / INOPB(fs); ! 800: sup->su_nbytes += nblocks - 1 - ninos << fs->lfs_bshift; ! 801: sup->su_nbytes += ssp->ss_ninos * sizeof(struct dinode); ! 802: sup->su_nbytes += LFS_SUMMARY_SIZE; ! 803: sup->su_lastmod = time.tv_sec; ! 804: sup->su_ninos += ninos; ! 805: ++sup->su_nsums; ! 806: do_again = !(bp->b_flags & B_GATHERED); ! 807: (void)VOP_BWRITE(bp); ! 808: /* ! 809: * Compute checksum across data and then across summary; the first ! 810: * block (the summary block) is skipped. Set the create time here ! 811: * so that it's guaranteed to be later than the inode mod times. ! 812: * ! 813: * XXX ! 814: * Fix this to do it inline, instead of malloc/copy. ! 815: */ ! 816: // datap = dp = malloc(nblocks * sizeof(u_long), M_SEGMENT, M_WAITOK); ! 817: MALLOC(dp, caddr_t, nblocks * sizeof(u_long), M_SEGMENT, M_WAITOK); ! 818: datap = dp; ! 819: for (bpp = sp->bpp, i = nblocks - 1; i--;) { ! 820: if ((*++bpp)->b_flags & B_INVAL) { ! 821: if (copyin((*bpp)->b_saveaddr, dp++, sizeof(u_long))) ! 822: panic("lfs_writeseg: copyin failed"); ! 823: } else ! 824: *dp++ = ((u_long *)(*bpp)->b_data)[0]; ! 825: } ! 826: ssp->ss_create = time.tv_sec; ! 827: ssp->ss_datasum = cksum(datap, (nblocks - 1) * sizeof(u_long)); ! 828: ssp->ss_sumsum = ! 829: cksum(&ssp->ss_datasum, LFS_SUMMARY_SIZE - sizeof(ssp->ss_sumsum)); ! 830: free(datap, M_SEGMENT); ! 831: #if DIAGNOSTIC ! 832: if (fs->lfs_bfree < fsbtodb(fs, ninos) + LFS_SUMMARY_SIZE / DEV_BSIZE) ! 833: panic("lfs_writeseg: No diskspace for summary"); ! 834: #endif ! 835: fs->lfs_bfree -= (fsbtodb(fs, ninos) + LFS_SUMMARY_SIZE / DEV_BSIZE); ! 836: ! 837: i_dev = VTOI(fs->lfs_ivnode)->i_dev; ! 838: strategy = VTOI(fs->lfs_ivnode)->i_devvp->v_op[VOFFSET(vop_strategy)]; ! 839: ! 840: /* ! 841: * When we simply write the blocks we lose a rotation for every block ! 842: * written. To avoid this problem, we allocate memory in chunks, copy ! 843: * the buffers into the chunk and write the chunk. MAXPHYS is the ! 844: * largest size I/O devices can handle. ! 845: * When the data is copied to the chunk, turn off the the B_LOCKED bit ! 846: * and brelse the buffer (which will move them to the LRU list). Add ! 847: * the B_CALL flag to the buffer header so we can count I/O's for the ! 848: * checkpoints and so we can release the allocated memory. ! 849: * ! 850: * XXX ! 851: * This should be removed if the new virtual memory system allows us to ! 852: * easily make the buffers contiguous in kernel memory and if that's ! 853: * fast enough. ! 854: */ ! 855: ch_per_blk = MAXPHYS / fs->lfs_bsize; ! 856: for (bpp = sp->bpp, i = nblocks; i;) { ! 857: num = ch_per_blk; ! 858: if (num > i) ! 859: num = i; ! 860: i -= num; ! 861: size = num * fs->lfs_bsize; ! 862: ! 863: cbp = lfs_newbuf(VTOI(fs->lfs_ivnode)->i_devvp, ! 864: (*bpp)->b_blkno, size); ! 865: cbp->b_dev = i_dev; ! 866: cbp->b_flags |= B_ASYNC | B_BUSY; ! 867: ! 868: s = splbio(); ! 869: ++fs->lfs_iocount; ! 870: for (p = cbp->b_data; num--;) { ! 871: bp = *bpp++; ! 872: /* ! 873: * Fake buffers from the cleaner are marked as B_INVAL. ! 874: * We need to copy the data from user space rather than ! 875: * from the buffer indicated. ! 876: * XXX == what do I do on an error? ! 877: */ ! 878: if (bp->b_flags & B_INVAL) { ! 879: if (copyin(bp->b_saveaddr, p, bp->b_bcount)) ! 880: panic("lfs_writeseg: copyin failed"); ! 881: } else ! 882: bcopy(bp->b_data, p, bp->b_bcount); ! 883: p += bp->b_bcount; ! 884: if (bp->b_flags & B_LOCKED) ! 885: --locked_queue_count; ! 886: bp->b_flags &= ~(B_ERROR | B_READ | B_DELWRI | ! 887: B_LOCKED | B_GATHERED); ! 888: if (bp->b_flags & B_CALL) { ! 889: /* if B_CALL, it was created with newbuf */ ! 890: brelvp(bp); ! 891: if (!(bp->b_flags & B_INVAL)) ! 892: free(bp->b_data, M_SEGMENT); ! 893: free(bp, M_SEGMENT); ! 894: } else { ! 895: bremfree(bp); ! 896: bp->b_flags |= B_DONE; ! 897: reassignbuf(bp, bp->b_vp); ! 898: brelse(bp); ! 899: } ! 900: } ! 901: ++cbp->b_vp->v_numoutput; ! 902: splx(s); ! 903: cbp->b_bcount = p - (char *)cbp->b_data; ! 904: /* ! 905: * XXXX This is a gross and disgusting hack. Since these ! 906: * buffers are physically addressed, they hang off the ! 907: * device vnode (devvp). As a result, they have no way ! 908: * of getting to the LFS superblock or lfs structure to ! 909: * keep track of the number of I/O's pending. So, I am ! 910: * going to stuff the fs into the saveaddr field of ! 911: * the buffer (yuk). ! 912: */ ! 913: cbp->b_saveaddr = (caddr_t)fs; ! 914: vop_strategy_a.a_desc = VDESC(vop_strategy); ! 915: vop_strategy_a.a_bp = cbp; ! 916: (strategy)(&vop_strategy_a); ! 917: } ! 918: /* ! 919: * XXX ! 920: * Vinvalbuf can move locked buffers off the locked queue ! 921: * and we have no way of knowing about this. So, after ! 922: * doing a big write, we recalculate how many bufers are ! 923: * really still left on the locked queue. ! 924: */ ! 925: locked_queue_count = count_lock_queue(); ! 926: wakeup(&locked_queue_count); ! 927: #ifdef DOSTATS ! 928: ++lfs_stats.psegwrites; ! 929: lfs_stats.blocktot += nblocks - 1; ! 930: if (fs->lfs_sp->seg_flags & SEGM_SYNC) ! 931: ++lfs_stats.psyncwrites; ! 932: if (fs->lfs_sp->seg_flags & SEGM_CLEAN) { ! 933: ++lfs_stats.pcleanwrites; ! 934: lfs_stats.cleanblocks += nblocks - 1; ! 935: } ! 936: #endif ! 937: return (lfs_initseg(fs) || do_again); ! 938: } ! 939: ! 940: void ! 941: lfs_writesuper(fs) ! 942: struct lfs *fs; ! 943: { ! 944: struct buf *bp; ! 945: dev_t i_dev; ! 946: int (*strategy) __P((struct vop_strategy_args *)); ! 947: int s; ! 948: struct vop_strategy_args vop_strategy_a; ! 949: ! 950: i_dev = VTOI(fs->lfs_ivnode)->i_dev; ! 951: strategy = VTOI(fs->lfs_ivnode)->i_devvp->v_op[VOFFSET(vop_strategy)]; ! 952: ! 953: /* Checksum the superblock and copy it into a buffer. */ ! 954: fs->lfs_cksum = cksum(fs, sizeof(struct lfs) - sizeof(fs->lfs_cksum)); ! 955: bp = lfs_newbuf(VTOI(fs->lfs_ivnode)->i_devvp, fs->lfs_sboffs[0], ! 956: LFS_SBPAD); ! 957: *(struct lfs *)bp->b_data = *fs; ! 958: ! 959: /* XXX Toggle between first two superblocks; for now just write first */ ! 960: bp->b_dev = i_dev; ! 961: bp->b_flags |= B_BUSY | B_CALL | B_ASYNC; ! 962: bp->b_flags &= ~(B_DONE | B_ERROR | B_READ | B_DELWRI); ! 963: bp->b_iodone = lfs_supercallback; ! 964: vop_strategy_a.a_desc = VDESC(vop_strategy); ! 965: vop_strategy_a.a_bp = bp; ! 966: s = splbio(); ! 967: ++bp->b_vp->v_numoutput; ! 968: splx(s); ! 969: (strategy)(&vop_strategy_a); ! 970: } ! 971: ! 972: /* ! 973: * Logical block number match routines used when traversing the dirty block ! 974: * chain. ! 975: */ ! 976: int ! 977: lfs_match_data(fs, bp) ! 978: struct lfs *fs; ! 979: struct buf *bp; ! 980: { ! 981: return (bp->b_lblkno >= 0); ! 982: } ! 983: ! 984: int ! 985: lfs_match_indir(fs, bp) ! 986: struct lfs *fs; ! 987: struct buf *bp; ! 988: { ! 989: int lbn; ! 990: ! 991: lbn = bp->b_lblkno; ! 992: return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 0); ! 993: } ! 994: ! 995: int ! 996: lfs_match_dindir(fs, bp) ! 997: struct lfs *fs; ! 998: struct buf *bp; ! 999: { ! 1000: int lbn; ! 1001: ! 1002: lbn = bp->b_lblkno; ! 1003: return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 1); ! 1004: } ! 1005: ! 1006: int ! 1007: lfs_match_tindir(fs, bp) ! 1008: struct lfs *fs; ! 1009: struct buf *bp; ! 1010: { ! 1011: int lbn; ! 1012: ! 1013: lbn = bp->b_lblkno; ! 1014: return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 2); ! 1015: } ! 1016: ! 1017: /* ! 1018: * Allocate a new buffer header. ! 1019: */ ! 1020: struct buf * ! 1021: lfs_newbuf(vp, daddr, size) ! 1022: struct vnode *vp; ! 1023: daddr_t daddr; ! 1024: size_t size; ! 1025: { ! 1026: struct buf *bp; ! 1027: size_t nbytes; ! 1028: ! 1029: nbytes = roundup(size, DEV_BSIZE); ! 1030: // bp = malloc(sizeof(struct buf), M_SEGMENT, M_WAITOK); ! 1031: MALLOC(bp, struct buf *, sizeof(struct buf), M_SEGMENT, M_WAITOK); ! 1032: bzero(bp, sizeof(struct buf)); ! 1033: if (nbytes) ! 1034: // bp->b_data = malloc(nbytes, M_SEGMENT, M_WAITOK); ! 1035: MALLOC(bp->d_data, caddr_t, nbytes, M_SEGMENT, M_WAITOK); ! 1036: bgetvp(vp, bp); ! 1037: bp->b_bufsize = size; ! 1038: bp->b_bcount = size; ! 1039: bp->b_lblkno = daddr; ! 1040: bp->b_blkno = daddr; ! 1041: bp->b_error = 0; ! 1042: bp->b_resid = 0; ! 1043: bp->b_iodone = lfs_callback; ! 1044: bp->b_flags |= B_BUSY | B_CALL | B_NOCACHE; ! 1045: return (bp); ! 1046: } ! 1047: ! 1048: void ! 1049: lfs_callback(bp) ! 1050: struct buf *bp; ! 1051: { ! 1052: struct lfs *fs; ! 1053: ! 1054: fs = (struct lfs *)bp->b_saveaddr; ! 1055: #if DIAGNOSTIC ! 1056: if (fs->lfs_iocount == 0) ! 1057: panic("lfs_callback: zero iocount\n"); ! 1058: #endif ! 1059: if (--fs->lfs_iocount == 0) ! 1060: wakeup(&fs->lfs_iocount); ! 1061: ! 1062: brelvp(bp); ! 1063: free(bp->b_data, M_SEGMENT); ! 1064: free(bp, M_SEGMENT); ! 1065: } ! 1066: ! 1067: void ! 1068: lfs_supercallback(bp) ! 1069: struct buf *bp; ! 1070: { ! 1071: brelvp(bp); ! 1072: free(bp->b_data, M_SEGMENT); ! 1073: free(bp, M_SEGMENT); ! 1074: } ! 1075: ! 1076: /* ! 1077: * Shellsort (diminishing increment sort) from Data Structures and ! 1078: * Algorithms, Aho, Hopcraft and Ullman, 1983 Edition, page 290; ! 1079: * see also Knuth Vol. 3, page 84. The increments are selected from ! 1080: * formula (8), page 95. Roughly O(N^3/2). ! 1081: */ ! 1082: /* ! 1083: * This is our own private copy of shellsort because we want to sort ! 1084: * two parallel arrays (the array of buffer pointers and the array of ! 1085: * logical block numbers) simultaneously. Note that we cast the array ! 1086: * of logical block numbers to a unsigned in this routine so that the ! 1087: * negative block numbers (meta data blocks) sort AFTER the data blocks. ! 1088: */ ! 1089: void ! 1090: lfs_shellsort(bp_array, lb_array, nmemb) ! 1091: struct buf **bp_array; ! 1092: daddr_t *lb_array; ! 1093: register int nmemb; ! 1094: { ! 1095: static int __rsshell_increments[] = { 4, 1, 0 }; ! 1096: register int incr, *incrp, t1, t2; ! 1097: struct buf *bp_temp; ! 1098: u_long lb_temp; ! 1099: ! 1100: for (incrp = __rsshell_increments; incr = *incrp++;) ! 1101: for (t1 = incr; t1 < nmemb; ++t1) ! 1102: for (t2 = t1 - incr; t2 >= 0;) ! 1103: if (lb_array[t2] > lb_array[t2 + incr]) { ! 1104: lb_temp = lb_array[t2]; ! 1105: lb_array[t2] = lb_array[t2 + incr]; ! 1106: lb_array[t2 + incr] = lb_temp; ! 1107: bp_temp = bp_array[t2]; ! 1108: bp_array[t2] = bp_array[t2 + incr]; ! 1109: bp_array[t2 + incr] = bp_temp; ! 1110: t2 -= incr; ! 1111: } else ! 1112: break; ! 1113: } ! 1114: ! 1115: /* ! 1116: * Check VXLOCK. Return 1 if the vnode is locked. Otherwise, vget it. ! 1117: */ ! 1118: lfs_vref(vp) ! 1119: register struct vnode *vp; ! 1120: { ! 1121: ! 1122: if (vp->v_flag & VXLOCK) ! 1123: return(1); ! 1124: return (vget(vp, 0)); ! 1125: } ! 1126: ! 1127: void ! 1128: lfs_vunref(vp) ! 1129: register struct vnode *vp; ! 1130: { ! 1131: extern int lfs_no_inactive; ! 1132: ! 1133: /* ! 1134: * This is vrele except that we do not want to VOP_INACTIVE ! 1135: * this vnode. Rather than inline vrele here, we use a global ! 1136: * flag to tell lfs_inactive not to run. Yes, its gross. ! 1137: */ ! 1138: lfs_no_inactive = 1; ! 1139: vrele(vp); ! 1140: lfs_no_inactive = 0; ! 1141: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.