151188Sbostic /* 251188Sbostic * Copyright (c) 1991 Regents of the University of California. 351188Sbostic * All rights reserved. 451188Sbostic * 551188Sbostic * %sccs.include.redist.c% 651188Sbostic * 7*54264Sbostic * @(#)lfs_segment.c 7.20 (Berkeley) 06/23/92 851188Sbostic */ 951188Sbostic 1051490Sbostic #include <sys/param.h> 1151490Sbostic #include <sys/systm.h> 1251490Sbostic #include <sys/namei.h> 1352085Sbostic #include <sys/kernel.h> 1451490Sbostic #include <sys/resourcevar.h> 1551490Sbostic #include <sys/file.h> 1651490Sbostic #include <sys/stat.h> 1751490Sbostic #include <sys/buf.h> 1851490Sbostic #include <sys/proc.h> 1951490Sbostic #include <sys/conf.h> 2051490Sbostic #include <sys/vnode.h> 2151490Sbostic #include <sys/specdev.h> 2251490Sbostic #include <sys/fifo.h> 2351490Sbostic #include <sys/malloc.h> 2451490Sbostic #include <sys/mount.h> 2551188Sbostic 2651499Sbostic #include <ufs/ufs/quota.h> 2751499Sbostic #include <ufs/ufs/inode.h> 2851499Sbostic #include <ufs/ufs/dir.h> 2951499Sbostic #include <ufs/ufs/ufsmount.h> 3051490Sbostic 3151499Sbostic #include <ufs/lfs/lfs.h> 3251499Sbostic #include <ufs/lfs/lfs_extern.h> 3351490Sbostic 3451860Sbostic /* In-memory description of a segment about to be written. */ 3551860Sbostic struct segment { 3652085Sbostic struct buf **bpp; /* pointer to buffer array */ 3752085Sbostic struct buf **cbpp; /* pointer to next available bp */ 3852085Sbostic struct buf *ibp; /* buffer pointer to inode page */ 3952085Sbostic struct finfo *fip; /* current fileinfo pointer */ 4051860Sbostic void *segsum; /* segment summary info */ 4151860Sbostic u_long ninodes; /* number of inodes in this segment */ 4251860Sbostic u_long seg_bytes_left; /* bytes left in segment */ 4351860Sbostic u_long sum_bytes_left; /* bytes left in summary block */ 4451860Sbostic u_long seg_number; /* number of this segment */ 4551860Sbostic #define SEGM_CKP 0x01 /* doing a checkpoint */ 4651860Sbostic u_long seg_flags; /* run-time flags for this segment */ 4751860Sbostic }; 4851860Sbostic 4951188Sbostic /* 5051860Sbostic * Determine if it's OK to start a partial in this segment, or if we need 5151860Sbostic * to go on to a new segment. 5251301Sbostic */ 5351860Sbostic #define LFS_PARTIAL_FITS(fs) \ 5451860Sbostic ((fs)->lfs_dbpseg - ((fs)->lfs_offset - (fs)->lfs_curseg) > \ 5551860Sbostic 1 << (fs)->lfs_fsbtodb) 5651188Sbostic 5753347Sbostic void lfs_callback __P((struct buf *)); 5852085Sbostic void lfs_gather __P((struct lfs *, struct segment *, 5952085Sbostic struct vnode *, int (*) __P((struct lfs *, struct buf *)))); 6052085Sbostic void lfs_initseg __P((struct lfs *, struct segment *)); 6152085Sbostic void lfs_iset __P((struct inode *, daddr_t, time_t)); 6252085Sbostic int lfs_match_data __P((struct lfs *, struct buf *)); 6352085Sbostic int lfs_match_dindir __P((struct lfs *, struct buf *)); 6452085Sbostic int lfs_match_indir __P((struct lfs *, struct buf *)); 6552085Sbostic int lfs_match_tindir __P((struct lfs *, struct buf *)); 6652085Sbostic struct buf * 6752688Sbostic lfs_newbuf __P((struct lfs *, daddr_t, size_t)); 6852077Sbostic void lfs_newseg __P((struct lfs *)); 6952085Sbostic void lfs_shellsort __P((struct buf **, daddr_t *, register int)); 7052077Sbostic void lfs_updatemeta __P((struct lfs *, 7152085Sbostic struct segment *, struct vnode *, daddr_t *, struct buf **, int)); 7252085Sbostic void lfs_writefile __P((struct lfs *, struct segment *, struct vnode *)); 73*54264Sbostic int lfs_writeinode __P((struct lfs *, struct segment *, struct inode *)); 74*54264Sbostic int lfs_writeseg __P((struct lfs *, struct segment *)); 7552085Sbostic void lfs_writesuper __P((struct lfs *, struct segment *)); 76*54264Sbostic void lfs_writevnodes __P((struct lfs *fs, struct mount *mp, 77*54264Sbostic struct segment *sp, int dirops)); 7851188Sbostic 7951860Sbostic int lfs_allclean_wakeup; /* Cleaner wakeup address. */ 8051860Sbostic 8152328Sbostic /* 8252328Sbostic * Ifile and meta data blocks are not marked busy, so segment writes MUST be 8352328Sbostic * single threaded. Currently, there are two paths into lfs_segwrite, sync() 8452328Sbostic * and getnewbuf(). They both mark the file system busy. Lfs_vflush() 8552328Sbostic * explicitly marks the file system busy. So lfs_segwrite is safe. I think. 8652328Sbostic */ 8752328Sbostic 8851188Sbostic int 8952328Sbostic lfs_vflush(vp) 9052328Sbostic struct vnode *vp; 9152328Sbostic { 9252328Sbostic struct inode *ip; 9352328Sbostic struct lfs *fs; 9452328Sbostic struct mount *mp; 9552328Sbostic struct segment *sp; 9652328Sbostic int error, s; 9752328Sbostic 9852328Sbostic #ifdef VERBOSE 9952328Sbostic printf("lfs_vflush\n"); 10052328Sbostic #endif 10152328Sbostic mp = vp->v_mount; 10252328Sbostic fs = VFSTOUFS(mp)->um_lfs; 10352328Sbostic 10452328Sbostic /* 10552328Sbostic * XXX 10652328Sbostic * check flags? 10752328Sbostic * mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY) || 10852328Sbostic */ 10952328Sbostic if (vfs_busy(mp)) 11052328Sbostic return (0); 11152328Sbostic 11252328Sbostic /* 11352328Sbostic * Allocate a segment structure and enough space to hold pointers to 11452328Sbostic * the maximum possible number of buffers which can be described in a 11552328Sbostic * single summary block. 11652328Sbostic */ 11752328Sbostic sp = malloc(sizeof(struct segment), M_SEGMENT, M_WAITOK); 11852328Sbostic sp->bpp = malloc(((LFS_SUMMARY_SIZE - sizeof(SEGSUM)) / 11952328Sbostic sizeof(daddr_t) + 1) * sizeof(struct buf *), M_SEGMENT, M_WAITOK); 12052328Sbostic sp->seg_flags = SEGM_CKP; 12152328Sbostic lfs_initseg(fs, sp); 12252328Sbostic 12352328Sbostic /* 12452328Sbostic * Keep a cumulative count of the outstanding I/O operations. If the 12552328Sbostic * disk drive catches up with us it could go to zero before we finish, 12652328Sbostic * so we artificially increment it by one until we've scheduled all of 12752328Sbostic * the writes we intend to do. 12852328Sbostic */ 12952328Sbostic s = splbio(); 13052688Sbostic ++fs->lfs_iocount; 13152328Sbostic splx(s); 13252328Sbostic 13352328Sbostic if (vp->v_dirtyblkhd != NULL) 13452328Sbostic lfs_writefile(fs, sp, vp); 13552328Sbostic ip = VTOI(vp); 136*54264Sbostic (void) lfs_writeinode(fs, sp, ip); 13752328Sbostic ip->i_flags &= ~(IMOD | IACC | IUPD | ICHG); 13852328Sbostic 139*54264Sbostic (void) lfs_writeseg(fs, sp); 14052328Sbostic 14152328Sbostic /* 14252328Sbostic * If the I/O count is non-zero, sleep until it reaches zero. At the 14352328Sbostic * moment, the user's process hangs around so we can sleep. 14452328Sbostic */ 14552328Sbostic s = splbio(); 14652328Sbostic if (--fs->lfs_iocount && (error = 14752995Sbostic tsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs vflush", 0))) { 14852995Sbostic free(sp->bpp, M_SEGMENT); 14952995Sbostic free(sp, M_SEGMENT); 15052328Sbostic return (error); 15152995Sbostic } 15252328Sbostic splx(s); 15352328Sbostic vfs_unbusy(mp); 15452328Sbostic 15552995Sbostic /* 15652995Sbostic * XXX 15752995Sbostic * Should be writing a checkpoint? 15852995Sbostic */ 15952328Sbostic free(sp->bpp, M_SEGMENT); 16052328Sbostic free(sp, M_SEGMENT); 16152328Sbostic 16252328Sbostic return (0); 16352328Sbostic } 16452328Sbostic 165*54264Sbostic void 166*54264Sbostic lfs_writevnodes(fs, mp, sp, dirops) 167*54264Sbostic struct lfs *fs; 168*54264Sbostic struct mount *mp; 169*54264Sbostic struct segment *sp; 170*54264Sbostic int dirops; 171*54264Sbostic { 172*54264Sbostic struct inode *ip; 173*54264Sbostic struct vnode *vp; 174*54264Sbostic int error, s; 175*54264Sbostic 176*54264Sbostic loop: for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 177*54264Sbostic /* 178*54264Sbostic * If the vnode that we are about to sync is no longer 179*54264Sbostic * associated with this mount point, start over. 180*54264Sbostic */ 181*54264Sbostic if (vp->v_mount != mp) 182*54264Sbostic goto loop; 183*54264Sbostic 184*54264Sbostic if (dirops && !(vp->v_flag & VDIROP) || 185*54264Sbostic !dirops && (vp->v_flag & VDIROP)) 186*54264Sbostic continue; 187*54264Sbostic /* 188*54264Sbostic * XXX 189*54264Sbostic * Up the ref count so we don't get tossed out of 190*54264Sbostic * memory. 191*54264Sbostic */ 192*54264Sbostic VREF(vp); 193*54264Sbostic 194*54264Sbostic /* 195*54264Sbostic * Write the inode/file if dirty and it's not the 196*54264Sbostic * the IFILE. 197*54264Sbostic */ 198*54264Sbostic ip = VTOI(vp); 199*54264Sbostic if ((ip->i_flag & (IMOD | IACC | IUPD | ICHG) || 200*54264Sbostic vp->v_dirtyblkhd != NULL) && 201*54264Sbostic ip->i_number != LFS_IFILE_INUM) { 202*54264Sbostic if (vp->v_dirtyblkhd != NULL) 203*54264Sbostic lfs_writefile(fs, sp, vp); 204*54264Sbostic (void) lfs_writeinode(fs, sp, ip); 205*54264Sbostic ip->i_flags &= ~(IMOD | IACC | IUPD | ICHG); 206*54264Sbostic } 207*54264Sbostic vp->v_flag &= ~VDIROP; 208*54264Sbostic vrele(vp); 209*54264Sbostic } 210*54264Sbostic } 211*54264Sbostic 21252328Sbostic int 21351215Sbostic lfs_segwrite(mp, do_ckp) 21452085Sbostic struct mount *mp; 21551860Sbostic int do_ckp; /* Do a checkpoint. */ 21651188Sbostic { 21753530Sheideman USES_VOP_ISLOCKED; 21852085Sbostic struct inode *ip; 21951499Sbostic struct lfs *fs; 22052085Sbostic struct segment *sp; 22152085Sbostic struct vnode *vp; 222*54264Sbostic int error, s; 22351188Sbostic 22451860Sbostic #ifdef VERBOSE 22551860Sbostic printf("lfs_segwrite\n"); 22651860Sbostic #endif 22752328Sbostic fs = VFSTOUFS(mp)->um_lfs; 22852085Sbostic 22951860Sbostic /* 23052328Sbostic * Allocate a segment structure and enough space to hold pointers to 23152328Sbostic * the maximum possible number of buffers which can be described in a 23252328Sbostic * single summary block. 23352328Sbostic */ 23452328Sbostic sp = malloc(sizeof(struct segment), M_SEGMENT, M_WAITOK); 23552328Sbostic sp->bpp = malloc(((LFS_SUMMARY_SIZE - sizeof(SEGSUM)) / 23652328Sbostic sizeof(daddr_t) + 1) * sizeof(struct buf *), M_SEGMENT, M_WAITOK); 23752328Sbostic sp->seg_flags = do_ckp ? SEGM_CKP : 0; 23852328Sbostic lfs_initseg(fs, sp); 23952328Sbostic 24052328Sbostic /* 24152688Sbostic * Keep a cumulative count of the outstanding I/O operations. If the 24252688Sbostic * disk drive catches up with us it could go to zero before we finish, 24352688Sbostic * so we artificially increment it by one until we've scheduled all of 24452688Sbostic * the writes we intend to do. If not a checkpoint, we never do the 24552688Sbostic * final decrement, avoiding the wakeup in the callback routine. 24651860Sbostic */ 24752688Sbostic s = splbio(); 248*54264Sbostic fs->lfs_iocount++; 24952688Sbostic splx(s); 25051342Sbostic 251*54264Sbostic lfs_writevnodes(fs, mp, sp, 0); 252*54264Sbostic s = splbio(); 253*54264Sbostic fs->lfs_writer = 1; 254*54264Sbostic if (fs->lfs_dirops && (error = 255*54264Sbostic tsleep(&fs->lfs_writer, PRIBIO + 1, "lfs writer", 0))) { 256*54264Sbostic free(sp->bpp, M_SEGMENT); 257*54264Sbostic free(sp, M_SEGMENT); 258*54264Sbostic fs->lfs_writer = 0; 259*54264Sbostic splx(s); 260*54264Sbostic return(error); 261*54264Sbostic } 262*54264Sbostic splx(s); 26351860Sbostic 264*54264Sbostic lfs_writevnodes(fs, mp, sp, 1); 26551860Sbostic 266*54264Sbostic /* 267*54264Sbostic * If this is a checkpoint, we need to loop on both the ifile and 268*54264Sbostic * the writeseg to make sure that we don't end up with any dirty 269*54264Sbostic * buffers left when this is all over. 270*54264Sbostic */ 271*54264Sbostic if (do_ckp || fs->lfs_doifile) { 272*54264Sbostic redo: 273*54264Sbostic vp = fs->lfs_ivnode; 274*54264Sbostic while (vget(vp)); 27552328Sbostic ip = VTOI(vp); 276*54264Sbostic do { 27752328Sbostic if (vp->v_dirtyblkhd != NULL) 27852328Sbostic lfs_writefile(fs, sp, vp); 279*54264Sbostic } while (lfs_writeinode(fs, sp, ip) && do_ckp); 28052077Sbostic ip->i_flags &= ~(IMOD | IACC | IUPD | ICHG); 28152077Sbostic vput(vp); 282*54264Sbostic if (lfs_writeseg(fs, sp) && do_ckp) { 283*54264Sbostic lfs_initseg(fs, sp); 284*54264Sbostic goto redo; 285*54264Sbostic } 286*54264Sbostic } else 287*54264Sbostic (void) lfs_writeseg(fs, sp); 28851342Sbostic 28951215Sbostic /* 29051860Sbostic * If the I/O count is non-zero, sleep until it reaches zero. At the 29151860Sbostic * moment, the user's process hangs around so we can sleep. 29251215Sbostic */ 29352688Sbostic s = splbio(); 29452688Sbostic --fs->lfs_iocount; 295*54264Sbostic fs->lfs_writer = 0; 296*54264Sbostic fs->lfs_doifile = 0; 297*54264Sbostic wakeup(&fs->lfs_dirops); 298*54264Sbostic 29951860Sbostic if (do_ckp) { 30052688Sbostic if (fs->lfs_iocount && (error = 30152995Sbostic tsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs sync", 0))) { 30252995Sbostic free(sp->bpp, M_SEGMENT); 30352995Sbostic free(sp, M_SEGMENT); 30451915Sbostic return (error); 30552995Sbostic } 30651860Sbostic splx(s); 30751860Sbostic lfs_writesuper(fs, sp); 30852688Sbostic } else 30952688Sbostic splx(s); 31051215Sbostic 31151927Sbostic free(sp->bpp, M_SEGMENT); 31251927Sbostic free(sp, M_SEGMENT); 31351215Sbostic 31451860Sbostic return (0); 31551188Sbostic } 31651188Sbostic 31751860Sbostic /* 31851860Sbostic * Write the dirty blocks associated with a vnode. 31951860Sbostic */ 32052077Sbostic void 32151860Sbostic lfs_writefile(fs, sp, vp) 32251499Sbostic struct lfs *fs; 32352085Sbostic struct segment *sp; 32452085Sbostic struct vnode *vp; 32551188Sbostic { 32651860Sbostic struct buf *bp; 32752085Sbostic struct finfo *fip; 32851860Sbostic IFILE *ifp; 32951188Sbostic 33051860Sbostic #ifdef VERBOSE 33151860Sbostic printf("lfs_writefile\n"); 33251860Sbostic #endif 33352085Sbostic if (sp->seg_bytes_left < fs->lfs_bsize || 33452085Sbostic sp->sum_bytes_left < sizeof(struct finfo)) { 335*54264Sbostic (void) lfs_writeseg(fs, sp); 33652085Sbostic lfs_initseg(fs, sp); 33752085Sbostic } 33852085Sbostic sp->sum_bytes_left -= sizeof(struct finfo) - sizeof(daddr_t); 33951215Sbostic 34052085Sbostic fip = sp->fip; 34152085Sbostic fip->fi_nblocks = 0; 34252085Sbostic fip->fi_ino = VTOI(vp)->i_number; 34352085Sbostic LFS_IENTRY(ifp, fs, fip->fi_ino, bp); 34452085Sbostic fip->fi_version = ifp->if_version; 34552085Sbostic brelse(bp); 34651188Sbostic 34752085Sbostic /* 34852085Sbostic * It may not be necessary to write the meta-data blocks at this point, 34952085Sbostic * as the roll-forward recovery code should be able to reconstruct the 35052085Sbostic * list. 35152085Sbostic */ 35252085Sbostic lfs_gather(fs, sp, vp, lfs_match_data); 35352085Sbostic lfs_gather(fs, sp, vp, lfs_match_indir); 35452085Sbostic lfs_gather(fs, sp, vp, lfs_match_dindir); 35551860Sbostic #ifdef TRIPLE 35652085Sbostic lfs_gather(fs, sp, vp, lfs_match_tindir); 35751860Sbostic #endif 35851342Sbostic 35952085Sbostic fip = sp->fip; 36051860Sbostic #ifdef META 36152085Sbostic printf("lfs_writefile: adding %d blocks\n", fip->fi_nblocks); 36251860Sbostic #endif 36352085Sbostic if (fip->fi_nblocks != 0) { 36452085Sbostic ++((SEGSUM *)(sp->segsum))->ss_nfinfo; 36552085Sbostic sp->fip = 36652085Sbostic (struct finfo *)((caddr_t)fip + sizeof(struct finfo) + 36752085Sbostic sizeof(daddr_t) * (fip->fi_nblocks - 1)); 36852682Sstaelin } else 36952682Sstaelin sp->sum_bytes_left += sizeof(struct finfo) - sizeof(daddr_t); 37051215Sbostic } 37151215Sbostic 372*54264Sbostic int 37351915Sbostic lfs_writeinode(fs, sp, ip) 37451915Sbostic struct lfs *fs; 37552085Sbostic struct segment *sp; 37652085Sbostic struct inode *ip; 37751915Sbostic { 37852085Sbostic struct buf *bp, *ibp; 37952077Sbostic IFILE *ifp; 38052682Sstaelin SEGUSE *sup; 38152682Sstaelin daddr_t daddr; 38252077Sbostic ino_t ino; 38351915Sbostic int ndx; 384*54264Sbostic int redo_ifile = 0; 38551915Sbostic 38651915Sbostic #ifdef VERBOSE 38751915Sbostic printf("lfs_writeinode\n"); 38851915Sbostic #endif 38951915Sbostic /* Allocate a new inode block if necessary. */ 39051915Sbostic if (sp->ibp == NULL) { 39151915Sbostic /* Allocate a new segment if necessary. */ 39251915Sbostic if (sp->seg_bytes_left < fs->lfs_bsize || 39351915Sbostic sp->sum_bytes_left < sizeof(daddr_t)) { 394*54264Sbostic (void) lfs_writeseg(fs, sp); 39551915Sbostic lfs_initseg(fs, sp); 39651915Sbostic } 39751915Sbostic 39851915Sbostic /* Get next inode block. */ 39952682Sstaelin daddr = fs->lfs_offset; 40051915Sbostic fs->lfs_offset += fsbtodb(fs, 1); 40151915Sbostic sp->ibp = *sp->cbpp++ = 40252688Sbostic lfs_newbuf(fs, daddr, fs->lfs_bsize); 40351915Sbostic 40452688Sbostic /* Set remaining space counters. */ 40551915Sbostic sp->seg_bytes_left -= fs->lfs_bsize; 40651915Sbostic sp->sum_bytes_left -= sizeof(daddr_t); 40752077Sbostic ndx = LFS_SUMMARY_SIZE / sizeof(daddr_t) - 40851915Sbostic sp->ninodes / INOPB(fs) - 1; 40952682Sstaelin ((daddr_t *)(sp->segsum))[ndx] = daddr; 41051915Sbostic } 41151915Sbostic 41252085Sbostic /* Update the inode times and copy the inode onto the inode page. */ 41352077Sbostic ITIMES(ip, &time, &time); 41451915Sbostic bp = sp->ibp; 41552085Sbostic bp->b_un.b_dino[sp->ninodes % INOPB(fs)] = ip->i_din; 41651915Sbostic 41751915Sbostic /* Increment inode count in segment summary block. */ 41851915Sbostic ++((SEGSUM *)(sp->segsum))->ss_ninos; 41951915Sbostic 42051915Sbostic /* If this page is full, set flag to allocate a new page. */ 42151915Sbostic if (++sp->ninodes % INOPB(fs) == 0) 42251915Sbostic sp->ibp = NULL; 42351915Sbostic 42451915Sbostic /* 42552077Sbostic * If updating the ifile, update the super-block. Update the disk 42652077Sbostic * address and access times for this inode in the ifile. 42751915Sbostic */ 42852077Sbostic ino = ip->i_number; 42952077Sbostic if (ino == LFS_IFILE_INUM) 43051915Sbostic fs->lfs_idaddr = bp->b_blkno; 43152077Sbostic 43252077Sbostic LFS_IENTRY(ifp, fs, ino, ibp); 43352682Sstaelin daddr = ifp->if_daddr; 43452077Sbostic ifp->if_daddr = bp->b_blkno; 43552085Sbostic LFS_UBWRITE(ibp); 436*54264Sbostic redo_ifile = (ino == LFS_IFILE_INUM && !(ibp->b_flags & B_GATHERED)); 43752682Sstaelin 438*54264Sbostic /* 439*54264Sbostic * No need to update segment usage if there was no former inode address 440*54264Sbostic * or if the last inode address is in the current partial segment. 441*54264Sbostic */ 442*54264Sbostic if (daddr != LFS_UNUSED_DADDR && 443*54264Sbostic !(daddr >= fs->lfs_curseg && daddr <= ifp->if_daddr) ) { 44452682Sstaelin LFS_SEGENTRY(sup, fs, datosn(fs, daddr), bp); 44552682Sstaelin #ifdef DIAGNOSTIC 446*54264Sbostic if (sup->su_nbytes < sizeof(struct dinode)) { 44752819Sbostic /* XXX -- Change to a panic. */ 44852819Sbostic printf("lfs: negative bytes (segment %d)\n", 44952682Sstaelin datosn(fs, daddr)); 450*54264Sbostic panic("negative bytes"); 451*54264Sbostic } 45252682Sstaelin #endif 45352682Sstaelin sup->su_nbytes -= sizeof(struct dinode); 45452682Sstaelin LFS_UBWRITE(bp); 455*54264Sbostic redo_ifile |= 456*54264Sbostic (ino == LFS_IFILE_INUM && !(bp->b_flags & B_GATHERED)); 45752682Sstaelin } 458*54264Sbostic return(redo_ifile); 45951915Sbostic } 46051915Sbostic 46152077Sbostic void 46251215Sbostic lfs_gather(fs, sp, vp, match) 46351499Sbostic struct lfs *fs; 46452085Sbostic struct segment *sp; 46552085Sbostic struct vnode *vp; 46652085Sbostic int (*match) __P((struct lfs *, struct buf *)); 46751215Sbostic { 468*54264Sbostic struct buf **bpp, *bp; 469*54264Sbostic struct buf *lastbp; 47052085Sbostic struct finfo *fip; 47152085Sbostic struct inode *ip; 47251215Sbostic daddr_t *lbp, *start_lbp; 47351342Sbostic u_long version; 47451342Sbostic int s; 47551215Sbostic 47651860Sbostic #ifdef VERBOSE 47751860Sbostic printf("lfs_gather\n"); 47851860Sbostic #endif 47951215Sbostic ip = VTOI(vp); 48051215Sbostic bpp = sp->cbpp; 48151215Sbostic fip = sp->fip; 48251215Sbostic start_lbp = lbp = &fip->fi_blocks[fip->fi_nblocks]; 48351215Sbostic 48453145Sstaelin loop: s = splbio(); 485*54264Sbostic lastbp = NULL; 486*54264Sbostic for (bp = vp->v_dirtyblkhd; bp; lastbp = bp, bp = bp->b_blockf) { 487*54264Sbostic if (bp->b_flags & B_BUSY || !match(fs, bp) || 488*54264Sbostic bp->b_flags & B_GATHERED) 48951215Sbostic continue; 49051342Sbostic #ifdef DIAGNOSTIC 49151860Sbostic if (!(bp->b_flags & B_DELWRI)) 49251915Sbostic panic("lfs_gather: bp not B_DELWRI"); 49351860Sbostic if (!(bp->b_flags & B_LOCKED)) 49451915Sbostic panic("lfs_gather: bp not B_LOCKED"); 49551342Sbostic #endif 49651860Sbostic /* 49751860Sbostic * If full, finish this segment. We may be doing I/O, so 49851860Sbostic * release and reacquire the splbio(). 49951860Sbostic */ 50051342Sbostic if (sp->sum_bytes_left < sizeof(daddr_t) || 50151215Sbostic sp->seg_bytes_left < fs->lfs_bsize) { 50251215Sbostic splx(s); 50351342Sbostic lfs_updatemeta(fs, 50451860Sbostic sp, vp, start_lbp, bpp, lbp - start_lbp); 50551215Sbostic 50651342Sbostic /* Add the current file to the segment summary. */ 50751342Sbostic ++((SEGSUM *)(sp->segsum))->ss_nfinfo; 50851215Sbostic 50951342Sbostic version = fip->fi_version; 510*54264Sbostic (void) lfs_writeseg(fs, sp); 51151915Sbostic lfs_initseg(fs, sp); 51251342Sbostic 51351215Sbostic fip = sp->fip; 51451342Sbostic fip->fi_version = version; 51551215Sbostic fip->fi_ino = ip->i_number; 51651342Sbostic start_lbp = lbp = fip->fi_blocks; 51751342Sbostic 51852682Sstaelin sp->sum_bytes_left -= 51952682Sstaelin sizeof(struct finfo) - sizeof(daddr_t); 52052682Sstaelin 52151215Sbostic bpp = sp->cbpp; 52253145Sstaelin goto loop; 52351215Sbostic } 52452682Sstaelin 52552682Sstaelin /* Insert into the buffer list, update the FINFO block. */ 526*54264Sbostic bp->b_flags |= B_GATHERED; 52752682Sstaelin *sp->cbpp++ = bp; 52852682Sstaelin ++fip->fi_nblocks; 52952682Sstaelin *lbp++ = bp->b_lblkno; 53052682Sstaelin 53152682Sstaelin sp->sum_bytes_left -= sizeof(daddr_t); 53252682Sstaelin sp->seg_bytes_left -= bp->b_bufsize; 53351188Sbostic } 53451215Sbostic splx(s); 53551860Sbostic lfs_updatemeta(fs, sp, vp, start_lbp, bpp, lbp - start_lbp); 53651188Sbostic } 53751188Sbostic 53851342Sbostic /* 53951342Sbostic * Update the metadata that points to the blocks listed in the FINFO 54051188Sbostic * array. 54151188Sbostic */ 54252077Sbostic void 54351860Sbostic lfs_updatemeta(fs, sp, vp, lbp, bpp, nblocks) 54451499Sbostic struct lfs *fs; 54552085Sbostic struct segment *sp; 54652085Sbostic struct vnode *vp; 54751215Sbostic daddr_t *lbp; 54852085Sbostic struct buf **bpp; 54951215Sbostic int nblocks; 55051188Sbostic { 55153530Sheideman USES_VOP_BWRITE; 55251915Sbostic SEGUSE *sup; 55352085Sbostic struct buf *bp; 55451860Sbostic INDIR a[NIADDR], *ap; 55552085Sbostic struct inode *ip; 55651915Sbostic daddr_t daddr, lbn, off; 55751860Sbostic int db_per_fsb, error, i, num; 55851188Sbostic 55951860Sbostic #ifdef VERBOSE 56051860Sbostic printf("lfs_updatemeta\n"); 56151860Sbostic #endif 56251342Sbostic if (nblocks == 0) 56351215Sbostic return; 56451215Sbostic 56551915Sbostic /* Sort the blocks. */ 56652077Sbostic lfs_shellsort(bpp, lbp, nblocks); 56751215Sbostic 56851915Sbostic /* 56951915Sbostic * Assign disk addresses, and update references to the logical 57051915Sbostic * block and the segment usage information. 57151915Sbostic */ 57251860Sbostic db_per_fsb = fsbtodb(fs, 1); 57351915Sbostic for (i = nblocks; i--; ++bpp) { 57451915Sbostic lbn = *lbp++; 57551915Sbostic (*bpp)->b_blkno = off = fs->lfs_offset; 57651860Sbostic fs->lfs_offset += db_per_fsb; 57751215Sbostic 57851860Sbostic if (error = lfs_bmaparray(vp, lbn, &daddr, a, &num)) 57952085Sbostic panic("lfs_updatemeta: lfs_bmaparray %d", error); 58051860Sbostic ip = VTOI(vp); 58151860Sbostic switch (num) { 58251860Sbostic case 0: 58351915Sbostic ip->i_db[lbn] = off; 58451860Sbostic break; 58551860Sbostic case 1: 58651915Sbostic ip->i_ib[a[0].in_off] = off; 58751860Sbostic break; 58851860Sbostic default: 58951860Sbostic ap = &a[num - 1]; 59051860Sbostic if (bread(vp, ap->in_lbn, fs->lfs_bsize, NOCRED, &bp)) 59151860Sbostic panic("lfs_updatemeta: bread bno %d", 59251860Sbostic ap->in_lbn); 59351915Sbostic bp->b_un.b_daddr[ap->in_off] = off; 59453530Sheideman VOP_BWRITE(bp); 59551188Sbostic } 59651915Sbostic 59751915Sbostic /* Update segment usage information. */ 59851915Sbostic if (daddr != UNASSIGNED) { 59951915Sbostic LFS_SEGENTRY(sup, fs, datosn(fs, daddr), bp); 60051915Sbostic #ifdef DIAGNOSTIC 601*54264Sbostic if (sup->su_nbytes < fs->lfs_bsize) { 60252819Sbostic /* XXX -- Change to a panic. */ 60352819Sbostic printf("lfs: negative bytes (segment %d)\n", 60451915Sbostic datosn(fs, daddr)); 605*54264Sbostic panic ("Negative Bytes"); 606*54264Sbostic } 60751915Sbostic #endif 60851915Sbostic sup->su_nbytes -= fs->lfs_bsize; 60952085Sbostic LFS_UBWRITE(bp); 61051915Sbostic } 61151188Sbostic } 61251188Sbostic } 61351188Sbostic 61451915Sbostic /* 61551915Sbostic * Start a new segment. 61651915Sbostic */ 61752077Sbostic void 61851915Sbostic lfs_initseg(fs, sp) 61951499Sbostic struct lfs *fs; 62052085Sbostic struct segment *sp; 62151188Sbostic { 62251915Sbostic SEGUSE *sup; 62351915Sbostic SEGSUM *ssp; 62451915Sbostic struct buf *bp; 62551915Sbostic daddr_t lbn, *lbnp; 62651215Sbostic 62751860Sbostic #ifdef VERBOSE 62851915Sbostic printf("lfs_initseg\n"); 62951860Sbostic #endif 63051915Sbostic /* Advance to the next segment. */ 63151927Sbostic if (!LFS_PARTIAL_FITS(fs)) { 63252682Sstaelin /* Wake up any cleaning procs waiting on this file system. */ 63352688Sbostic wakeup(&fs->lfs_nextseg); 63452688Sbostic wakeup(&lfs_allclean_wakeup); 63552682Sstaelin 63651927Sbostic lfs_newseg(fs); 63751927Sbostic fs->lfs_offset = fs->lfs_curseg; 63851915Sbostic sp->seg_number = datosn(fs, fs->lfs_curseg); 63951915Sbostic sp->seg_bytes_left = fs->lfs_dbpseg * DEV_BSIZE; 64051915Sbostic 64151915Sbostic /* 64251927Sbostic * If the segment contains a superblock, update the offset 64351927Sbostic * and summary address to skip over it. 64451915Sbostic */ 64552077Sbostic LFS_SEGENTRY(sup, fs, sp->seg_number, bp); 64651927Sbostic if (sup->su_flags & SEGUSE_SUPERBLOCK) { 64751915Sbostic fs->lfs_offset += LFS_SBPAD / DEV_BSIZE; 64851915Sbostic sp->seg_bytes_left -= LFS_SBPAD; 64951215Sbostic } 65052085Sbostic brelse(bp); 65151915Sbostic } else { 65251915Sbostic sp->seg_number = datosn(fs, fs->lfs_curseg); 65351915Sbostic sp->seg_bytes_left = (fs->lfs_dbpseg - 65451915Sbostic (fs->lfs_offset - fs->lfs_curseg)) * DEV_BSIZE; 65551915Sbostic } 656*54264Sbostic fs->lfs_lastpseg = fs->lfs_offset; 65751342Sbostic 65851915Sbostic sp->ibp = NULL; 65951915Sbostic sp->ninodes = 0; 66051342Sbostic 66151915Sbostic /* Get a new buffer for SEGSUM and enter it into the buffer list. */ 66251915Sbostic sp->cbpp = sp->bpp; 66352688Sbostic *sp->cbpp = lfs_newbuf(fs, fs->lfs_offset, LFS_SUMMARY_SIZE); 66451915Sbostic sp->segsum = (*sp->cbpp)->b_un.b_addr; 66551915Sbostic ++sp->cbpp; 66651915Sbostic fs->lfs_offset += LFS_SUMMARY_SIZE / DEV_BSIZE; 66751342Sbostic 66851915Sbostic /* Set point to SEGSUM, initialize it. */ 66951915Sbostic ssp = sp->segsum; 67051915Sbostic ssp->ss_next = fs->lfs_nextseg; 67151915Sbostic ssp->ss_nfinfo = ssp->ss_ninos = 0; 67251342Sbostic 67351915Sbostic /* Set pointer to first FINFO, initialize it. */ 67452085Sbostic sp->fip = (struct finfo *)(sp->segsum + sizeof(SEGSUM)); 67551915Sbostic sp->fip->fi_nblocks = 0; 67651342Sbostic 67751915Sbostic sp->seg_bytes_left -= LFS_SUMMARY_SIZE; 67851915Sbostic sp->sum_bytes_left = LFS_SUMMARY_SIZE - sizeof(SEGSUM); 67951915Sbostic } 68051342Sbostic 68151915Sbostic /* 68251915Sbostic * Return the next segment to write. 68351915Sbostic */ 68452077Sbostic void 68551915Sbostic lfs_newseg(fs) 68651915Sbostic struct lfs *fs; 68751915Sbostic { 68851927Sbostic CLEANERINFO *cip; 68951915Sbostic SEGUSE *sup; 69051915Sbostic struct buf *bp; 69151927Sbostic int curseg, isdirty, sn; 69251915Sbostic 69351915Sbostic #ifdef VERBOSE 69451915Sbostic printf("lfs_newseg\n"); 69551915Sbostic #endif 69651927Sbostic /* 69751927Sbostic * Turn off the active bit for the current segment, turn on the 69851927Sbostic * active and dirty bits for the next segment, update the cleaner 69951927Sbostic * info. Set the current segment to the next segment, get a new 70051927Sbostic * next segment. 70151927Sbostic */ 70251927Sbostic LFS_SEGENTRY(sup, fs, datosn(fs, fs->lfs_curseg), bp); 70351927Sbostic sup->su_flags &= ~SEGUSE_ACTIVE; 70452085Sbostic LFS_UBWRITE(bp); 70551927Sbostic 70651927Sbostic LFS_SEGENTRY(sup, fs, datosn(fs, fs->lfs_nextseg), bp); 707*54264Sbostic sup->su_flags |= SEGUSE_ACTIVE | SEGUSE_DIRTY | SEGUSE_LIVELOG; 70852085Sbostic LFS_UBWRITE(bp); 70951927Sbostic 71051927Sbostic LFS_CLEANERINFO(cip, fs, bp); 71151927Sbostic --cip->clean; 71251927Sbostic ++cip->dirty; 71352085Sbostic LFS_UBWRITE(bp); 71451927Sbostic 71551927Sbostic fs->lfs_lastseg = fs->lfs_curseg; 71651927Sbostic fs->lfs_curseg = fs->lfs_nextseg; 71751927Sbostic for (sn = curseg = datosn(fs, fs->lfs_curseg);;) { 71851915Sbostic sn = (sn + 1) % fs->lfs_nseg; 71951927Sbostic if (sn == curseg) 72051915Sbostic panic("lfs_nextseg: no clean segments"); 72151915Sbostic LFS_SEGENTRY(sup, fs, sn, bp); 72251915Sbostic isdirty = sup->su_flags & SEGUSE_DIRTY; 72352085Sbostic brelse(bp); 72451915Sbostic if (!isdirty) 72551915Sbostic break; 72651915Sbostic } 72751927Sbostic fs->lfs_nextseg = sntoda(fs, sn); 72851188Sbostic } 72951188Sbostic 730*54264Sbostic int 73151188Sbostic lfs_writeseg(fs, sp) 73251499Sbostic struct lfs *fs; 73352085Sbostic struct segment *sp; 73451188Sbostic { 73553574Sheideman USES_VOP_STRATEGY; 73652688Sbostic struct buf **bpp, *bp, *cbp; 73751188Sbostic SEGUSE *sup; 73852085Sbostic SEGSUM *ssp; 73951860Sbostic dev_t i_dev; 740*54264Sbostic size_t size; 74151860Sbostic u_long *datap, *dp; 742*54264Sbostic int ch_per_blk, do_again, i, nblocks, num, s; 743*54264Sbostic int (*strategy)__P((struct vop_strategy_args *)); 74452688Sbostic char *p; 74551188Sbostic 74651860Sbostic #ifdef VERBOSE 74751860Sbostic printf("lfs_writeseg\n"); 74851860Sbostic #endif 749*54264Sbostic /* Checkpoint always writes superblock, even if no data blocks. */ 750*54264Sbostic if ((nblocks = sp->cbpp - sp->bpp) == 0 && !(sp->seg_flags & SEGM_CKP)) 75152085Sbostic return; 75252085Sbostic 75351188Sbostic /* 75452085Sbostic * Compute checksum across data and then across summary; the first 75552085Sbostic * block (the summary block) is skipped. Set the create time here 75652085Sbostic * so that it's guaranteed to be later than the inode mod times. 75751860Sbostic * 75851860Sbostic * XXX 75951860Sbostic * Fix this to do it inline, instead of malloc/copy. 76051188Sbostic */ 76151860Sbostic datap = dp = malloc(nblocks * sizeof(u_long), M_SEGMENT, M_WAITOK); 76251915Sbostic for (bpp = sp->bpp, i = nblocks - 1; i--;) 76351915Sbostic *dp++ = (*++bpp)->b_un.b_words[0]; 76452085Sbostic ssp = (SEGSUM *)sp->segsum; 76552103Sbostic ssp->ss_create = time.tv_sec; 76652085Sbostic ssp->ss_datasum = cksum(datap, nblocks * sizeof(u_long)); 76752085Sbostic ssp->ss_sumsum = 76852085Sbostic cksum(&ssp->ss_datasum, LFS_SUMMARY_SIZE - sizeof(ssp->ss_sumsum)); 76951927Sbostic free(datap, M_SEGMENT); 77051188Sbostic 771*54264Sbostic /* Update the segment usage information. */ 772*54264Sbostic LFS_SEGENTRY(sup, fs, sp->seg_number, bp); 773*54264Sbostic sup->su_nbytes += nblocks - 1 - 774*54264Sbostic (ssp->ss_ninos + INOPB(fs) - 1) / INOPB(fs) << fs->lfs_bshift; 775*54264Sbostic sup->su_nbytes += ssp->ss_ninos * sizeof(struct dinode); 776*54264Sbostic sup->su_lastmod = time.tv_sec; 777*54264Sbostic LFS_UBWRITE(bp); 778*54264Sbostic do_again = !(bp->b_flags & B_GATHERED); 779*54264Sbostic 78051860Sbostic i_dev = VTOI(fs->lfs_ivnode)->i_dev; 78153574Sheideman strategy = VTOI(fs->lfs_ivnode)->i_devvp->v_op[VOFFSET(vop_strategy)]; 78251301Sbostic 78352688Sbostic /* 78452688Sbostic * When we simply write the blocks we lose a rotation for every block 78552688Sbostic * written. To avoid this problem, we allocate memory in chunks, copy 78652688Sbostic * the buffers into the chunk and write the chunk. 56K was chosen as 78752688Sbostic * some driver/controllers can't handle unsigned 16 bit transfers. 78852688Sbostic * When the data is copied to the chunk, turn off the the B_LOCKED bit 78952688Sbostic * and brelse the buffer (which will move them to the LRU list). Add 79052688Sbostic * the B_CALL flag to the buffer header so we can count I/O's for the 79152688Sbostic * checkpoints and so we can release the allocated memory. 79252688Sbostic * 79352688Sbostic * XXX 79452688Sbostic * This should be removed if the new virtual memory system allows us to 79552688Sbostic * easily make the buffers contiguous in kernel memory and if that's 79652688Sbostic * fast enough. 79752688Sbostic */ 79852688Sbostic #define LFS_CHUNKSIZE (56 * 1024) 79952688Sbostic ch_per_blk = LFS_CHUNKSIZE / fs->lfs_bsize; 80052688Sbostic for (bpp = sp->bpp, i = nblocks; i;) { 80152688Sbostic num = ch_per_blk; 80252688Sbostic if (num > i) 80352688Sbostic num = i; 80452688Sbostic i -= num; 80552688Sbostic size = num * fs->lfs_bsize; 80652688Sbostic 80752688Sbostic cbp = lfs_newbuf(fs, (*bpp)->b_blkno, 0); 80852688Sbostic cbp->b_dev = i_dev; 80952688Sbostic cbp->b_flags = B_ASYNC | B_BUSY | B_CALL; 81052688Sbostic cbp->b_iodone = lfs_callback; 81152688Sbostic cbp->b_saveaddr = cbp->b_un.b_addr; 81252688Sbostic cbp->b_un.b_addr = malloc(size, M_SEGMENT, M_WAITOK); 81352688Sbostic 81452688Sbostic s = splbio(); 81552688Sbostic ++fs->lfs_iocount; 81652688Sbostic for (p = cbp->b_un.b_addr; num--;) { 81752688Sbostic bp = *bpp++; 81852688Sbostic bcopy(bp->b_un.b_addr, p, bp->b_bcount); 81952688Sbostic p += bp->b_bcount; 820*54264Sbostic bp->b_flags &= ~(B_DONE | B_ERROR | B_READ | B_DELWRI | 821*54264Sbostic B_LOCKED | B_GATHERED); 822*54264Sbostic if (!(bp->b_flags & (B_NOCACHE | B_INVAL))) { 82352688Sbostic bremfree(bp); 82452688Sbostic reassignbuf(bp, bp->b_vp); 82552688Sbostic } 82652688Sbostic brelse(bp); 82751860Sbostic } 82852688Sbostic splx(s); 82952688Sbostic cbp->b_bcount = p - cbp->b_un.b_addr; 83053574Sheideman vop_strategy_a.a_desc = VDESC(vop_strategy); 83153574Sheideman vop_strategy_a.a_bp = cbp; 83253574Sheideman (strategy)(&vop_strategy_a); 83351860Sbostic } 834*54264Sbostic return(do_again); 83551188Sbostic } 83651188Sbostic 83752077Sbostic void 83851860Sbostic lfs_writesuper(fs, sp) 83951499Sbostic struct lfs *fs; 84052085Sbostic struct segment *sp; 84151301Sbostic { 84253574Sheideman USES_VOP_STRATEGY; 84352085Sbostic struct buf *bp; 84451860Sbostic dev_t i_dev; 84553574Sheideman int (*strategy) __P((struct vop_strategy_args *)); 84651301Sbostic 84751860Sbostic #ifdef VERBOSE 84851860Sbostic printf("lfs_writesuper\n"); 84951860Sbostic #endif 85051860Sbostic i_dev = VTOI(fs->lfs_ivnode)->i_dev; 85153574Sheideman strategy = VTOI(fs->lfs_ivnode)->i_devvp->v_op[VOFFSET(vop_strategy)]; 85251356Sbostic 85351342Sbostic /* Checksum the superblock and copy it into a buffer. */ 85451499Sbostic fs->lfs_cksum = cksum(fs, sizeof(struct lfs) - sizeof(fs->lfs_cksum)); 85552688Sbostic bp = lfs_newbuf(fs, fs->lfs_sboffs[0], LFS_SBPAD); 85651860Sbostic *bp->b_un.b_lfs = *fs; 85751215Sbostic 85851356Sbostic /* Write the first superblock (wait). */ 85951860Sbostic bp->b_dev = i_dev; 86051915Sbostic bp->b_flags |= B_BUSY; 86151860Sbostic bp->b_flags &= ~(B_DONE | B_ERROR | B_READ | B_DELWRI); 86253574Sheideman vop_strategy_a.a_desc = VDESC(vop_strategy); 86353574Sheideman vop_strategy_a.a_bp = bp; 86453574Sheideman (strategy)(&vop_strategy_a); 86551215Sbostic biowait(bp); 86651342Sbostic 86751356Sbostic /* Write the second superblock (don't wait). */ 86851215Sbostic bp->b_blkno = bp->b_lblkno = fs->lfs_sboffs[1]; 86951915Sbostic bp->b_flags |= B_ASYNC | B_BUSY; 87051860Sbostic bp->b_flags &= ~(B_DONE | B_ERROR | B_READ | B_DELWRI); 87153574Sheideman (strategy)(&vop_strategy_a); 87251215Sbostic } 87351215Sbostic 87451342Sbostic /* 87551342Sbostic * Logical block number match routines used when traversing the dirty block 87651342Sbostic * chain. 87751342Sbostic */ 87852077Sbostic int 87952077Sbostic lfs_match_data(fs, bp) 88051860Sbostic struct lfs *fs; 88152085Sbostic struct buf *bp; 88251215Sbostic { 88351342Sbostic return (bp->b_lblkno >= 0); 88451215Sbostic } 88551215Sbostic 88652077Sbostic int 88752077Sbostic lfs_match_indir(fs, bp) 88851860Sbostic struct lfs *fs; 88952085Sbostic struct buf *bp; 89051215Sbostic { 89151860Sbostic int lbn; 89251860Sbostic 89351860Sbostic lbn = bp->b_lblkno; 89451860Sbostic return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 0); 89551215Sbostic } 89651215Sbostic 89752077Sbostic int 89852077Sbostic lfs_match_dindir(fs, bp) 89951860Sbostic struct lfs *fs; 90052085Sbostic struct buf *bp; 90151215Sbostic { 90251860Sbostic int lbn; 90351860Sbostic 90451860Sbostic lbn = bp->b_lblkno; 90551860Sbostic return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 1); 90651215Sbostic } 90751215Sbostic 90852077Sbostic int 90952077Sbostic lfs_match_tindir(fs, bp) 91051499Sbostic struct lfs *fs; 91152085Sbostic struct buf *bp; 91251342Sbostic { 91351860Sbostic int lbn; 91451342Sbostic 91551860Sbostic lbn = bp->b_lblkno; 91651860Sbostic return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 2); 91751860Sbostic } 91851342Sbostic 91951860Sbostic /* 92051860Sbostic * Allocate a new buffer header. 92151860Sbostic */ 92252085Sbostic struct buf * 92352688Sbostic lfs_newbuf(fs, daddr, size) 92451860Sbostic struct lfs *fs; 92551860Sbostic daddr_t daddr; 92651860Sbostic size_t size; 92751860Sbostic { 92852085Sbostic struct buf *bp; 92951342Sbostic 93051860Sbostic #ifdef VERBOSE 93151860Sbostic printf("lfs_newbuf\n"); 93251860Sbostic #endif 93351860Sbostic bp = getnewbuf(); 93451860Sbostic bremhash(bp); 93551860Sbostic bgetvp(fs->lfs_ivnode, bp); 93651860Sbostic bp->b_bcount = 0; 93751860Sbostic bp->b_lblkno = daddr; 93851860Sbostic bp->b_blkno = daddr; 93951860Sbostic bp->b_error = 0; 94051860Sbostic bp->b_resid = 0; 94152688Sbostic if (size) 94252688Sbostic allocbuf(bp, size); 94351860Sbostic bp->b_flags |= B_NOCACHE; 94452688Sbostic bp->b_saveaddr = NULL; 94551915Sbostic binshash(bp, &bfreelist[BQ_AGE]); 94651860Sbostic return (bp); 94751860Sbostic } 94851342Sbostic 94953347Sbostic void 95051860Sbostic lfs_callback(bp) 95152085Sbostic struct buf *bp; 95251860Sbostic { 95351860Sbostic struct lfs *fs; 95451342Sbostic 95551860Sbostic fs = VFSTOUFS(bp->b_vp->v_mount)->um_lfs; 95651860Sbostic #ifdef DIAGNOSTIC 95751860Sbostic if (fs->lfs_iocount == 0) 95851860Sbostic panic("lfs_callback: zero iocount\n"); 95951860Sbostic #endif 96051860Sbostic if (--fs->lfs_iocount == 0) 96152688Sbostic wakeup(&fs->lfs_iocount); 96251915Sbostic 96352688Sbostic if (bp->b_saveaddr) { 96452688Sbostic free(bp->b_un.b_addr, M_SEGMENT); 96552688Sbostic bp->b_un.b_addr = bp->b_saveaddr; 96652819Sbostic bp->b_saveaddr = NULL; 96752688Sbostic } 96851860Sbostic brelse(bp); 96951860Sbostic } 97051342Sbostic 97151215Sbostic /* 97251188Sbostic * Shellsort (diminishing increment sort) from Data Structures and 97351188Sbostic * Algorithms, Aho, Hopcraft and Ullman, 1983 Edition, page 290; 97451188Sbostic * see also Knuth Vol. 3, page 84. The increments are selected from 97551188Sbostic * formula (8), page 95. Roughly O(N^3/2). 97651188Sbostic */ 97751188Sbostic /* 97851188Sbostic * This is our own private copy of shellsort because we want to sort 97951188Sbostic * two parallel arrays (the array of buffer pointers and the array of 98051188Sbostic * logical block numbers) simultaneously. Note that we cast the array 98151188Sbostic * of logical block numbers to a unsigned in this routine so that the 98251188Sbostic * negative block numbers (meta data blocks) sort AFTER the data blocks. 98351188Sbostic */ 98452077Sbostic void 98552077Sbostic lfs_shellsort(bp_array, lb_array, nmemb) 98652085Sbostic struct buf **bp_array; 98751215Sbostic daddr_t *lb_array; 98851188Sbostic register int nmemb; 98951188Sbostic { 99051188Sbostic static int __rsshell_increments[] = { 4, 1, 0 }; 99151188Sbostic register int incr, *incrp, t1, t2; 99252085Sbostic struct buf *bp_temp; 99351188Sbostic u_long lb_temp; 99451188Sbostic 99551188Sbostic for (incrp = __rsshell_increments; incr = *incrp++;) 99651188Sbostic for (t1 = incr; t1 < nmemb; ++t1) 99751188Sbostic for (t2 = t1 - incr; t2 >= 0;) 99851188Sbostic if (lb_array[t2] > lb_array[t2 + incr]) { 99951188Sbostic lb_temp = lb_array[t2]; 100051188Sbostic lb_array[t2] = lb_array[t2 + incr]; 100151188Sbostic lb_array[t2 + incr] = lb_temp; 100251188Sbostic bp_temp = bp_array[t2]; 100351188Sbostic bp_array[t2] = bp_array[t2 + incr]; 100451188Sbostic bp_array[t2 + incr] = bp_temp; 100551188Sbostic t2 -= incr; 100651188Sbostic } else 100751188Sbostic break; 100851188Sbostic } 1009