151188Sbostic /* 251188Sbostic * Copyright (c) 1991 Regents of the University of California. 351188Sbostic * All rights reserved. 451188Sbostic * 551188Sbostic * %sccs.include.redist.c% 651188Sbostic * 7*55551Sbostic * @(#)lfs_segment.c 7.24 (Berkeley) 07/22/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/malloc.h> 2251490Sbostic #include <sys/mount.h> 2351188Sbostic 2455033Smckusick #include <miscfs/specfs/specdev.h> 2555033Smckusick #include <miscfs/fifofs/fifo.h> 2655033Smckusick 2751499Sbostic #include <ufs/ufs/quota.h> 2851499Sbostic #include <ufs/ufs/inode.h> 2951499Sbostic #include <ufs/ufs/dir.h> 3051499Sbostic #include <ufs/ufs/ufsmount.h> 3151490Sbostic 3251499Sbostic #include <ufs/lfs/lfs.h> 3351499Sbostic #include <ufs/lfs/lfs_extern.h> 3451490Sbostic 3551860Sbostic /* In-memory description of a segment about to be written. */ 3651860Sbostic struct segment { 3752085Sbostic struct buf **bpp; /* pointer to buffer array */ 3852085Sbostic struct buf **cbpp; /* pointer to next available bp */ 3952085Sbostic struct buf *ibp; /* buffer pointer to inode page */ 4052085Sbostic struct finfo *fip; /* current fileinfo pointer */ 4151860Sbostic void *segsum; /* segment summary info */ 4251860Sbostic u_long ninodes; /* number of inodes in this segment */ 4351860Sbostic u_long seg_bytes_left; /* bytes left in segment */ 4451860Sbostic u_long sum_bytes_left; /* bytes left in summary block */ 4551860Sbostic u_long seg_number; /* number of this segment */ 4651860Sbostic #define SEGM_CKP 0x01 /* doing a checkpoint */ 4751860Sbostic u_long seg_flags; /* run-time flags for this segment */ 4851860Sbostic }; 4951860Sbostic 5051188Sbostic /* 5151860Sbostic * Determine if it's OK to start a partial in this segment, or if we need 5251860Sbostic * to go on to a new segment. 5351301Sbostic */ 5451860Sbostic #define LFS_PARTIAL_FITS(fs) \ 5551860Sbostic ((fs)->lfs_dbpseg - ((fs)->lfs_offset - (fs)->lfs_curseg) > \ 5651860Sbostic 1 << (fs)->lfs_fsbtodb) 5751188Sbostic 5853347Sbostic void lfs_callback __P((struct buf *)); 5952085Sbostic void lfs_gather __P((struct lfs *, struct segment *, 6052085Sbostic struct vnode *, int (*) __P((struct lfs *, struct buf *)))); 6152085Sbostic void lfs_initseg __P((struct lfs *, struct segment *)); 6252085Sbostic void lfs_iset __P((struct inode *, daddr_t, time_t)); 6352085Sbostic int lfs_match_data __P((struct lfs *, struct buf *)); 6452085Sbostic int lfs_match_dindir __P((struct lfs *, struct buf *)); 6552085Sbostic int lfs_match_indir __P((struct lfs *, struct buf *)); 6652085Sbostic int lfs_match_tindir __P((struct lfs *, struct buf *)); 6752085Sbostic struct buf * 6852688Sbostic lfs_newbuf __P((struct lfs *, daddr_t, size_t)); 6952077Sbostic void lfs_newseg __P((struct lfs *)); 7052085Sbostic void lfs_shellsort __P((struct buf **, daddr_t *, register int)); 7152077Sbostic void lfs_updatemeta __P((struct lfs *, 7252085Sbostic struct segment *, struct vnode *, daddr_t *, struct buf **, int)); 7352085Sbostic void lfs_writefile __P((struct lfs *, struct segment *, struct vnode *)); 7454264Sbostic int lfs_writeinode __P((struct lfs *, struct segment *, struct inode *)); 7554264Sbostic int lfs_writeseg __P((struct lfs *, struct segment *)); 7652085Sbostic void lfs_writesuper __P((struct lfs *, struct segment *)); 7754264Sbostic void lfs_writevnodes __P((struct lfs *fs, struct mount *mp, 7854264Sbostic struct segment *sp, int dirops)); 7951188Sbostic 8051860Sbostic int lfs_allclean_wakeup; /* Cleaner wakeup address. */ 8151860Sbostic 8252328Sbostic /* 8352328Sbostic * Ifile and meta data blocks are not marked busy, so segment writes MUST be 8452328Sbostic * single threaded. Currently, there are two paths into lfs_segwrite, sync() 8552328Sbostic * and getnewbuf(). They both mark the file system busy. Lfs_vflush() 8652328Sbostic * explicitly marks the file system busy. So lfs_segwrite is safe. I think. 8752328Sbostic */ 8852328Sbostic 8951188Sbostic int 9052328Sbostic lfs_vflush(vp) 9152328Sbostic struct vnode *vp; 9252328Sbostic { 9352328Sbostic struct inode *ip; 9452328Sbostic struct lfs *fs; 9552328Sbostic struct segment *sp; 9652328Sbostic int error, s; 9752328Sbostic 9852328Sbostic #ifdef VERBOSE 9952328Sbostic printf("lfs_vflush\n"); 10052328Sbostic #endif 10154690Sbostic fs = VFSTOUFS(vp->v_mount)->um_lfs; 10254690Sbostic lfs_seglock(fs); 10352328Sbostic 10452328Sbostic /* 10552328Sbostic * Allocate a segment structure and enough space to hold pointers to 10652328Sbostic * the maximum possible number of buffers which can be described in a 10752328Sbostic * single summary block. 10852328Sbostic */ 10952328Sbostic sp = malloc(sizeof(struct segment), M_SEGMENT, M_WAITOK); 11052328Sbostic sp->bpp = malloc(((LFS_SUMMARY_SIZE - sizeof(SEGSUM)) / 11152328Sbostic sizeof(daddr_t) + 1) * sizeof(struct buf *), M_SEGMENT, M_WAITOK); 11252328Sbostic sp->seg_flags = SEGM_CKP; 11352328Sbostic lfs_initseg(fs, sp); 11452328Sbostic 11552328Sbostic /* 11652328Sbostic * Keep a cumulative count of the outstanding I/O operations. If the 11752328Sbostic * disk drive catches up with us it could go to zero before we finish, 11852328Sbostic * so we artificially increment it by one until we've scheduled all of 11952328Sbostic * the writes we intend to do. 12052328Sbostic */ 12152328Sbostic s = splbio(); 12252688Sbostic ++fs->lfs_iocount; 12352328Sbostic splx(s); 12452328Sbostic 12552328Sbostic ip = VTOI(vp); 126*55551Sbostic do { 127*55551Sbostic do { 128*55551Sbostic if (vp->v_dirtyblkhd != NULL) 129*55551Sbostic lfs_writefile(fs, sp, vp); 130*55551Sbostic } while (lfs_writeinode(fs, sp, ip)); 131*55551Sbostic ip->i_flags &= ~(IMOD | IACC | IUPD | ICHG); 13252328Sbostic 133*55551Sbostic } while (lfs_writeseg(fs, sp) && ip->i_number == LFS_IFILE_INUM); 13452328Sbostic 13552328Sbostic /* 13652328Sbostic * If the I/O count is non-zero, sleep until it reaches zero. At the 13752328Sbostic * moment, the user's process hangs around so we can sleep. 13852328Sbostic */ 13952328Sbostic s = splbio(); 14052328Sbostic if (--fs->lfs_iocount && (error = 14152995Sbostic tsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs vflush", 0))) { 14252995Sbostic free(sp->bpp, M_SEGMENT); 14352995Sbostic free(sp, M_SEGMENT); 14452328Sbostic return (error); 14552995Sbostic } 14652328Sbostic splx(s); 14754690Sbostic lfs_segunlock(fs); 14852328Sbostic 14952995Sbostic /* 15052995Sbostic * XXX 15152995Sbostic * Should be writing a checkpoint? 15252995Sbostic */ 15352328Sbostic free(sp->bpp, M_SEGMENT); 15452328Sbostic free(sp, M_SEGMENT); 15552328Sbostic 15652328Sbostic return (0); 15752328Sbostic } 15852328Sbostic 15954264Sbostic void 16054264Sbostic lfs_writevnodes(fs, mp, sp, dirops) 16154264Sbostic struct lfs *fs; 16254264Sbostic struct mount *mp; 16354264Sbostic struct segment *sp; 16454264Sbostic int dirops; 16554264Sbostic { 16654264Sbostic struct inode *ip; 16754264Sbostic struct vnode *vp; 16854264Sbostic int error, s; 16954264Sbostic 17054264Sbostic loop: for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 17154264Sbostic /* 17254264Sbostic * If the vnode that we are about to sync is no longer 17354264Sbostic * associated with this mount point, start over. 17454264Sbostic */ 17554264Sbostic if (vp->v_mount != mp) 17654264Sbostic goto loop; 17754264Sbostic 17854264Sbostic if (dirops && !(vp->v_flag & VDIROP) || 17954264Sbostic !dirops && (vp->v_flag & VDIROP)) 18054264Sbostic continue; 18154264Sbostic /* 18254264Sbostic * XXX 18354264Sbostic * Up the ref count so we don't get tossed out of 18454264Sbostic * memory. 18554264Sbostic */ 18654264Sbostic VREF(vp); 18754264Sbostic 18854264Sbostic /* 18954264Sbostic * Write the inode/file if dirty and it's not the 19054264Sbostic * the IFILE. 19154264Sbostic */ 19254264Sbostic ip = VTOI(vp); 19354264Sbostic if ((ip->i_flag & (IMOD | IACC | IUPD | ICHG) || 19454264Sbostic vp->v_dirtyblkhd != NULL) && 19554264Sbostic ip->i_number != LFS_IFILE_INUM) { 19654264Sbostic if (vp->v_dirtyblkhd != NULL) 19754264Sbostic lfs_writefile(fs, sp, vp); 19854264Sbostic (void) lfs_writeinode(fs, sp, ip); 19954264Sbostic ip->i_flags &= ~(IMOD | IACC | IUPD | ICHG); 20054264Sbostic } 20154264Sbostic vp->v_flag &= ~VDIROP; 20254264Sbostic vrele(vp); 20354264Sbostic } 20454264Sbostic } 20554264Sbostic 20652328Sbostic int 20751215Sbostic lfs_segwrite(mp, do_ckp) 20852085Sbostic struct mount *mp; 20951860Sbostic int do_ckp; /* Do a checkpoint. */ 21051188Sbostic { 21152085Sbostic struct inode *ip; 21251499Sbostic struct lfs *fs; 21352085Sbostic struct segment *sp; 21452085Sbostic struct vnode *vp; 21554264Sbostic int error, s; 21651188Sbostic 21751860Sbostic #ifdef VERBOSE 21851860Sbostic printf("lfs_segwrite\n"); 21951860Sbostic #endif 22052328Sbostic fs = VFSTOUFS(mp)->um_lfs; 22154690Sbostic lfs_seglock(fs); 22252085Sbostic 22351860Sbostic /* 22452328Sbostic * Allocate a segment structure and enough space to hold pointers to 22552328Sbostic * the maximum possible number of buffers which can be described in a 22652328Sbostic * single summary block. 22752328Sbostic */ 22852328Sbostic sp = malloc(sizeof(struct segment), M_SEGMENT, M_WAITOK); 22952328Sbostic sp->bpp = malloc(((LFS_SUMMARY_SIZE - sizeof(SEGSUM)) / 23052328Sbostic sizeof(daddr_t) + 1) * sizeof(struct buf *), M_SEGMENT, M_WAITOK); 23152328Sbostic sp->seg_flags = do_ckp ? SEGM_CKP : 0; 23252328Sbostic lfs_initseg(fs, sp); 23352328Sbostic 23452328Sbostic /* 23552688Sbostic * Keep a cumulative count of the outstanding I/O operations. If the 23652688Sbostic * disk drive catches up with us it could go to zero before we finish, 23752688Sbostic * so we artificially increment it by one until we've scheduled all of 23852688Sbostic * the writes we intend to do. If not a checkpoint, we never do the 23952688Sbostic * final decrement, avoiding the wakeup in the callback routine. 24051860Sbostic */ 24152688Sbostic s = splbio(); 242*55551Sbostic ++fs->lfs_iocount; 24352688Sbostic splx(s); 24451342Sbostic 24554264Sbostic lfs_writevnodes(fs, mp, sp, 0); 24654264Sbostic fs->lfs_writer = 1; 24754264Sbostic if (fs->lfs_dirops && (error = 24854264Sbostic tsleep(&fs->lfs_writer, PRIBIO + 1, "lfs writer", 0))) { 24954264Sbostic free(sp->bpp, M_SEGMENT); 25054264Sbostic free(sp, M_SEGMENT); 25154264Sbostic fs->lfs_writer = 0; 252*55551Sbostic return (error); 25354264Sbostic } 25451860Sbostic 25554264Sbostic lfs_writevnodes(fs, mp, sp, 1); 25651860Sbostic 25754264Sbostic /* 25854264Sbostic * If this is a checkpoint, we need to loop on both the ifile and 25954264Sbostic * the writeseg to make sure that we don't end up with any dirty 26054264Sbostic * buffers left when this is all over. 26154264Sbostic */ 26254264Sbostic if (do_ckp || fs->lfs_doifile) { 26354264Sbostic redo: 26454264Sbostic vp = fs->lfs_ivnode; 26554264Sbostic while (vget(vp)); 26652328Sbostic ip = VTOI(vp); 26754264Sbostic do { 26852328Sbostic if (vp->v_dirtyblkhd != NULL) 26952328Sbostic lfs_writefile(fs, sp, vp); 27054264Sbostic } while (lfs_writeinode(fs, sp, ip) && do_ckp); 27152077Sbostic ip->i_flags &= ~(IMOD | IACC | IUPD | ICHG); 27252077Sbostic vput(vp); 27354264Sbostic if (lfs_writeseg(fs, sp) && do_ckp) { 27454264Sbostic lfs_initseg(fs, sp); 27554264Sbostic goto redo; 27654264Sbostic } 27754264Sbostic } else 27854264Sbostic (void) lfs_writeseg(fs, sp); 27951342Sbostic 28051215Sbostic /* 28151860Sbostic * If the I/O count is non-zero, sleep until it reaches zero. At the 28251860Sbostic * moment, the user's process hangs around so we can sleep. 28351215Sbostic */ 28454264Sbostic fs->lfs_writer = 0; 28554264Sbostic fs->lfs_doifile = 0; 28654264Sbostic wakeup(&fs->lfs_dirops); 28754264Sbostic 288*55551Sbostic s = splbio(); 289*55551Sbostic --fs->lfs_iocount; 29051860Sbostic if (do_ckp) { 29152688Sbostic if (fs->lfs_iocount && (error = 29252995Sbostic tsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs sync", 0))) { 29352995Sbostic free(sp->bpp, M_SEGMENT); 29452995Sbostic free(sp, M_SEGMENT); 29551915Sbostic return (error); 29652995Sbostic } 29751860Sbostic splx(s); 29851860Sbostic lfs_writesuper(fs, sp); 29952688Sbostic } else 30052688Sbostic splx(s); 30151215Sbostic 30254690Sbostic lfs_segunlock(fs); 30354690Sbostic 30451927Sbostic free(sp->bpp, M_SEGMENT); 30551927Sbostic free(sp, M_SEGMENT); 30651215Sbostic 30751860Sbostic return (0); 30851188Sbostic } 30951188Sbostic 31051860Sbostic /* 31151860Sbostic * Write the dirty blocks associated with a vnode. 31251860Sbostic */ 31352077Sbostic void 31451860Sbostic lfs_writefile(fs, sp, vp) 31551499Sbostic struct lfs *fs; 31652085Sbostic struct segment *sp; 31752085Sbostic struct vnode *vp; 31851188Sbostic { 31951860Sbostic struct buf *bp; 32052085Sbostic struct finfo *fip; 32151860Sbostic IFILE *ifp; 32251188Sbostic 32351860Sbostic #ifdef VERBOSE 32451860Sbostic printf("lfs_writefile\n"); 32551860Sbostic #endif 32652085Sbostic if (sp->seg_bytes_left < fs->lfs_bsize || 32752085Sbostic sp->sum_bytes_left < sizeof(struct finfo)) { 32854264Sbostic (void) lfs_writeseg(fs, sp); 32952085Sbostic lfs_initseg(fs, sp); 33052085Sbostic } 33152085Sbostic sp->sum_bytes_left -= sizeof(struct finfo) - sizeof(daddr_t); 33251215Sbostic 33352085Sbostic fip = sp->fip; 33452085Sbostic fip->fi_nblocks = 0; 33552085Sbostic fip->fi_ino = VTOI(vp)->i_number; 33652085Sbostic LFS_IENTRY(ifp, fs, fip->fi_ino, bp); 33752085Sbostic fip->fi_version = ifp->if_version; 33852085Sbostic brelse(bp); 33951188Sbostic 34052085Sbostic /* 34152085Sbostic * It may not be necessary to write the meta-data blocks at this point, 34252085Sbostic * as the roll-forward recovery code should be able to reconstruct the 34352085Sbostic * list. 34452085Sbostic */ 34552085Sbostic lfs_gather(fs, sp, vp, lfs_match_data); 34652085Sbostic lfs_gather(fs, sp, vp, lfs_match_indir); 34752085Sbostic lfs_gather(fs, sp, vp, lfs_match_dindir); 34851860Sbostic #ifdef TRIPLE 34952085Sbostic lfs_gather(fs, sp, vp, lfs_match_tindir); 35051860Sbostic #endif 35151342Sbostic 35252085Sbostic fip = sp->fip; 35351860Sbostic #ifdef META 35452085Sbostic printf("lfs_writefile: adding %d blocks\n", fip->fi_nblocks); 35551860Sbostic #endif 35652085Sbostic if (fip->fi_nblocks != 0) { 35752085Sbostic ++((SEGSUM *)(sp->segsum))->ss_nfinfo; 35852085Sbostic sp->fip = 35952085Sbostic (struct finfo *)((caddr_t)fip + sizeof(struct finfo) + 36052085Sbostic sizeof(daddr_t) * (fip->fi_nblocks - 1)); 36152682Sstaelin } else 36252682Sstaelin sp->sum_bytes_left += sizeof(struct finfo) - sizeof(daddr_t); 36351215Sbostic } 36451215Sbostic 36554264Sbostic int 36651915Sbostic lfs_writeinode(fs, sp, ip) 36751915Sbostic struct lfs *fs; 36852085Sbostic struct segment *sp; 36952085Sbostic struct inode *ip; 37051915Sbostic { 37152085Sbostic struct buf *bp, *ibp; 37252077Sbostic IFILE *ifp; 37352682Sstaelin SEGUSE *sup; 37452682Sstaelin daddr_t daddr; 37552077Sbostic ino_t ino; 37651915Sbostic int ndx; 37754264Sbostic int redo_ifile = 0; 37851915Sbostic 37951915Sbostic #ifdef VERBOSE 38051915Sbostic printf("lfs_writeinode\n"); 38151915Sbostic #endif 38251915Sbostic /* Allocate a new inode block if necessary. */ 38351915Sbostic if (sp->ibp == NULL) { 38451915Sbostic /* Allocate a new segment if necessary. */ 38551915Sbostic if (sp->seg_bytes_left < fs->lfs_bsize || 38651915Sbostic sp->sum_bytes_left < sizeof(daddr_t)) { 38754264Sbostic (void) lfs_writeseg(fs, sp); 38851915Sbostic lfs_initseg(fs, sp); 38951915Sbostic } 39051915Sbostic 39151915Sbostic /* Get next inode block. */ 39252682Sstaelin daddr = fs->lfs_offset; 39351915Sbostic fs->lfs_offset += fsbtodb(fs, 1); 39451915Sbostic sp->ibp = *sp->cbpp++ = 39552688Sbostic lfs_newbuf(fs, daddr, fs->lfs_bsize); 39651915Sbostic 39752688Sbostic /* Set remaining space counters. */ 39851915Sbostic sp->seg_bytes_left -= fs->lfs_bsize; 39951915Sbostic sp->sum_bytes_left -= sizeof(daddr_t); 40052077Sbostic ndx = LFS_SUMMARY_SIZE / sizeof(daddr_t) - 40151915Sbostic sp->ninodes / INOPB(fs) - 1; 40252682Sstaelin ((daddr_t *)(sp->segsum))[ndx] = daddr; 40351915Sbostic } 40451915Sbostic 40552085Sbostic /* Update the inode times and copy the inode onto the inode page. */ 40652077Sbostic ITIMES(ip, &time, &time); 40751915Sbostic bp = sp->ibp; 40852085Sbostic bp->b_un.b_dino[sp->ninodes % INOPB(fs)] = ip->i_din; 40951915Sbostic 41051915Sbostic /* Increment inode count in segment summary block. */ 41151915Sbostic ++((SEGSUM *)(sp->segsum))->ss_ninos; 41251915Sbostic 41351915Sbostic /* If this page is full, set flag to allocate a new page. */ 41451915Sbostic if (++sp->ninodes % INOPB(fs) == 0) 41551915Sbostic sp->ibp = NULL; 41651915Sbostic 41751915Sbostic /* 41852077Sbostic * If updating the ifile, update the super-block. Update the disk 41952077Sbostic * address and access times for this inode in the ifile. 42051915Sbostic */ 42152077Sbostic ino = ip->i_number; 42252077Sbostic if (ino == LFS_IFILE_INUM) 42351915Sbostic fs->lfs_idaddr = bp->b_blkno; 42452077Sbostic 42552077Sbostic LFS_IENTRY(ifp, fs, ino, ibp); 42652682Sstaelin daddr = ifp->if_daddr; 42752077Sbostic ifp->if_daddr = bp->b_blkno; 42852085Sbostic LFS_UBWRITE(ibp); 42954264Sbostic redo_ifile = (ino == LFS_IFILE_INUM && !(ibp->b_flags & B_GATHERED)); 43052682Sstaelin 43154264Sbostic /* 43254264Sbostic * No need to update segment usage if there was no former inode address 43354264Sbostic * or if the last inode address is in the current partial segment. 43454264Sbostic */ 43554264Sbostic if (daddr != LFS_UNUSED_DADDR && 43654264Sbostic !(daddr >= fs->lfs_curseg && daddr <= ifp->if_daddr) ) { 43752682Sstaelin LFS_SEGENTRY(sup, fs, datosn(fs, daddr), bp); 43852682Sstaelin #ifdef DIAGNOSTIC 43954264Sbostic if (sup->su_nbytes < sizeof(struct dinode)) { 44052819Sbostic /* XXX -- Change to a panic. */ 44152819Sbostic printf("lfs: negative bytes (segment %d)\n", 44252682Sstaelin datosn(fs, daddr)); 44354264Sbostic panic("negative bytes"); 44454264Sbostic } 44552682Sstaelin #endif 44652682Sstaelin sup->su_nbytes -= sizeof(struct dinode); 44752682Sstaelin LFS_UBWRITE(bp); 44854264Sbostic redo_ifile |= 44954264Sbostic (ino == LFS_IFILE_INUM && !(bp->b_flags & B_GATHERED)); 45052682Sstaelin } 451*55551Sbostic return (redo_ifile); 45251915Sbostic } 45351915Sbostic 45452077Sbostic void 45551215Sbostic lfs_gather(fs, sp, vp, match) 45651499Sbostic struct lfs *fs; 45752085Sbostic struct segment *sp; 45852085Sbostic struct vnode *vp; 45952085Sbostic int (*match) __P((struct lfs *, struct buf *)); 46051215Sbostic { 46154264Sbostic struct buf **bpp, *bp; 46254264Sbostic struct buf *lastbp; 46352085Sbostic struct finfo *fip; 46452085Sbostic struct inode *ip; 46551215Sbostic daddr_t *lbp, *start_lbp; 46651342Sbostic u_long version; 46751342Sbostic int s; 46851215Sbostic 46951860Sbostic #ifdef VERBOSE 47051860Sbostic printf("lfs_gather\n"); 47151860Sbostic #endif 47251215Sbostic ip = VTOI(vp); 47351215Sbostic bpp = sp->cbpp; 47451215Sbostic fip = sp->fip; 47551215Sbostic start_lbp = lbp = &fip->fi_blocks[fip->fi_nblocks]; 47651215Sbostic 47753145Sstaelin loop: s = splbio(); 47854264Sbostic lastbp = NULL; 47954264Sbostic for (bp = vp->v_dirtyblkhd; bp; lastbp = bp, bp = bp->b_blockf) { 48054264Sbostic if (bp->b_flags & B_BUSY || !match(fs, bp) || 48154264Sbostic bp->b_flags & B_GATHERED) 48251215Sbostic continue; 48351342Sbostic #ifdef DIAGNOSTIC 48451860Sbostic if (!(bp->b_flags & B_DELWRI)) 48551915Sbostic panic("lfs_gather: bp not B_DELWRI"); 48651860Sbostic if (!(bp->b_flags & B_LOCKED)) 48751915Sbostic panic("lfs_gather: bp not B_LOCKED"); 48851342Sbostic #endif 48951860Sbostic /* 49051860Sbostic * If full, finish this segment. We may be doing I/O, so 49151860Sbostic * release and reacquire the splbio(). 49251860Sbostic */ 49351342Sbostic if (sp->sum_bytes_left < sizeof(daddr_t) || 49451215Sbostic sp->seg_bytes_left < fs->lfs_bsize) { 49551215Sbostic splx(s); 49651342Sbostic lfs_updatemeta(fs, 49751860Sbostic sp, vp, start_lbp, bpp, lbp - start_lbp); 49851215Sbostic 49951342Sbostic /* Add the current file to the segment summary. */ 50051342Sbostic ++((SEGSUM *)(sp->segsum))->ss_nfinfo; 50151215Sbostic 50251342Sbostic version = fip->fi_version; 50354264Sbostic (void) lfs_writeseg(fs, sp); 50451915Sbostic lfs_initseg(fs, sp); 50551342Sbostic 50651215Sbostic fip = sp->fip; 50751342Sbostic fip->fi_version = version; 50851215Sbostic fip->fi_ino = ip->i_number; 50951342Sbostic start_lbp = lbp = fip->fi_blocks; 51051342Sbostic 51152682Sstaelin sp->sum_bytes_left -= 51252682Sstaelin sizeof(struct finfo) - sizeof(daddr_t); 51352682Sstaelin 51451215Sbostic bpp = sp->cbpp; 51553145Sstaelin goto loop; 51651215Sbostic } 51752682Sstaelin 51852682Sstaelin /* Insert into the buffer list, update the FINFO block. */ 51954264Sbostic bp->b_flags |= B_GATHERED; 52052682Sstaelin *sp->cbpp++ = bp; 52152682Sstaelin ++fip->fi_nblocks; 52252682Sstaelin *lbp++ = bp->b_lblkno; 52352682Sstaelin 52452682Sstaelin sp->sum_bytes_left -= sizeof(daddr_t); 52552682Sstaelin sp->seg_bytes_left -= bp->b_bufsize; 52651188Sbostic } 52751215Sbostic splx(s); 52851860Sbostic lfs_updatemeta(fs, sp, vp, start_lbp, bpp, lbp - start_lbp); 52951188Sbostic } 53051188Sbostic 53151342Sbostic /* 53251342Sbostic * Update the metadata that points to the blocks listed in the FINFO 53351188Sbostic * array. 53451188Sbostic */ 53552077Sbostic void 53651860Sbostic lfs_updatemeta(fs, sp, vp, lbp, bpp, nblocks) 53751499Sbostic struct lfs *fs; 53852085Sbostic struct segment *sp; 53952085Sbostic struct vnode *vp; 54051215Sbostic daddr_t *lbp; 54152085Sbostic struct buf **bpp; 54251215Sbostic int nblocks; 54351188Sbostic { 54451915Sbostic SEGUSE *sup; 54552085Sbostic struct buf *bp; 54651860Sbostic INDIR a[NIADDR], *ap; 54752085Sbostic struct inode *ip; 54851915Sbostic daddr_t daddr, lbn, off; 54951860Sbostic int db_per_fsb, error, i, num; 55051188Sbostic 55151860Sbostic #ifdef VERBOSE 55251860Sbostic printf("lfs_updatemeta\n"); 55351860Sbostic #endif 55451342Sbostic if (nblocks == 0) 55551215Sbostic return; 55651215Sbostic 55751915Sbostic /* Sort the blocks. */ 55852077Sbostic lfs_shellsort(bpp, lbp, nblocks); 55951215Sbostic 56051915Sbostic /* 56151915Sbostic * Assign disk addresses, and update references to the logical 56251915Sbostic * block and the segment usage information. 56351915Sbostic */ 56451860Sbostic db_per_fsb = fsbtodb(fs, 1); 56551915Sbostic for (i = nblocks; i--; ++bpp) { 56651915Sbostic lbn = *lbp++; 56751915Sbostic (*bpp)->b_blkno = off = fs->lfs_offset; 56851860Sbostic fs->lfs_offset += db_per_fsb; 56951215Sbostic 57051860Sbostic if (error = lfs_bmaparray(vp, lbn, &daddr, a, &num)) 57152085Sbostic panic("lfs_updatemeta: lfs_bmaparray %d", error); 57251860Sbostic ip = VTOI(vp); 57351860Sbostic switch (num) { 57451860Sbostic case 0: 57551915Sbostic ip->i_db[lbn] = off; 57651860Sbostic break; 57751860Sbostic case 1: 57851915Sbostic ip->i_ib[a[0].in_off] = off; 57951860Sbostic break; 58051860Sbostic default: 58151860Sbostic ap = &a[num - 1]; 58251860Sbostic if (bread(vp, ap->in_lbn, fs->lfs_bsize, NOCRED, &bp)) 58351860Sbostic panic("lfs_updatemeta: bread bno %d", 58451860Sbostic ap->in_lbn); 58555458Sbostic /* 58655458Sbostic * Bread may create a new indirect block which needs 58755458Sbostic * to get counted for the inode. 58855458Sbostic */ 58955458Sbostic if (bp->b_blkno == -1 && !(bp->b_flags & B_CACHE)) 59055458Sbostic ip->i_blocks += btodb(fs->lfs_bsize); 59151915Sbostic bp->b_un.b_daddr[ap->in_off] = off; 59253530Sheideman VOP_BWRITE(bp); 59351188Sbostic } 59451915Sbostic 59551915Sbostic /* Update segment usage information. */ 59651915Sbostic if (daddr != UNASSIGNED) { 59751915Sbostic LFS_SEGENTRY(sup, fs, datosn(fs, daddr), bp); 59851915Sbostic #ifdef DIAGNOSTIC 59954264Sbostic if (sup->su_nbytes < fs->lfs_bsize) { 60052819Sbostic /* XXX -- Change to a panic. */ 60152819Sbostic printf("lfs: negative bytes (segment %d)\n", 60251915Sbostic datosn(fs, daddr)); 60354264Sbostic panic ("Negative Bytes"); 60454264Sbostic } 60551915Sbostic #endif 60651915Sbostic sup->su_nbytes -= fs->lfs_bsize; 60752085Sbostic LFS_UBWRITE(bp); 60851915Sbostic } 60951188Sbostic } 61051188Sbostic } 61151188Sbostic 61251915Sbostic /* 61351915Sbostic * Start a new segment. 61451915Sbostic */ 61552077Sbostic void 61651915Sbostic lfs_initseg(fs, sp) 61751499Sbostic struct lfs *fs; 61852085Sbostic struct segment *sp; 61951188Sbostic { 62051915Sbostic SEGUSE *sup; 62151915Sbostic SEGSUM *ssp; 62251915Sbostic struct buf *bp; 62351915Sbostic daddr_t lbn, *lbnp; 62451215Sbostic 62551860Sbostic #ifdef VERBOSE 62651915Sbostic printf("lfs_initseg\n"); 62751860Sbostic #endif 62851915Sbostic /* Advance to the next segment. */ 62951927Sbostic if (!LFS_PARTIAL_FITS(fs)) { 63052682Sstaelin /* Wake up any cleaning procs waiting on this file system. */ 63152688Sbostic wakeup(&fs->lfs_nextseg); 63252688Sbostic wakeup(&lfs_allclean_wakeup); 63352682Sstaelin 63451927Sbostic lfs_newseg(fs); 63551927Sbostic fs->lfs_offset = fs->lfs_curseg; 63651915Sbostic sp->seg_number = datosn(fs, fs->lfs_curseg); 63751915Sbostic sp->seg_bytes_left = fs->lfs_dbpseg * DEV_BSIZE; 63851915Sbostic 63951915Sbostic /* 64051927Sbostic * If the segment contains a superblock, update the offset 64151927Sbostic * and summary address to skip over it. 64251915Sbostic */ 64352077Sbostic LFS_SEGENTRY(sup, fs, sp->seg_number, bp); 64451927Sbostic if (sup->su_flags & SEGUSE_SUPERBLOCK) { 64551915Sbostic fs->lfs_offset += LFS_SBPAD / DEV_BSIZE; 64651915Sbostic sp->seg_bytes_left -= LFS_SBPAD; 64751215Sbostic } 64852085Sbostic brelse(bp); 64951915Sbostic } else { 65051915Sbostic sp->seg_number = datosn(fs, fs->lfs_curseg); 65151915Sbostic sp->seg_bytes_left = (fs->lfs_dbpseg - 65251915Sbostic (fs->lfs_offset - fs->lfs_curseg)) * DEV_BSIZE; 65351915Sbostic } 65454264Sbostic fs->lfs_lastpseg = fs->lfs_offset; 65551342Sbostic 65651915Sbostic sp->ibp = NULL; 65751915Sbostic sp->ninodes = 0; 65851342Sbostic 65951915Sbostic /* Get a new buffer for SEGSUM and enter it into the buffer list. */ 66051915Sbostic sp->cbpp = sp->bpp; 66152688Sbostic *sp->cbpp = lfs_newbuf(fs, fs->lfs_offset, LFS_SUMMARY_SIZE); 66251915Sbostic sp->segsum = (*sp->cbpp)->b_un.b_addr; 66351915Sbostic ++sp->cbpp; 66451915Sbostic fs->lfs_offset += LFS_SUMMARY_SIZE / DEV_BSIZE; 66551342Sbostic 66651915Sbostic /* Set point to SEGSUM, initialize it. */ 66751915Sbostic ssp = sp->segsum; 66851915Sbostic ssp->ss_next = fs->lfs_nextseg; 66951915Sbostic ssp->ss_nfinfo = ssp->ss_ninos = 0; 67051342Sbostic 67151915Sbostic /* Set pointer to first FINFO, initialize it. */ 67252085Sbostic sp->fip = (struct finfo *)(sp->segsum + sizeof(SEGSUM)); 67351915Sbostic sp->fip->fi_nblocks = 0; 67451342Sbostic 67551915Sbostic sp->seg_bytes_left -= LFS_SUMMARY_SIZE; 67651915Sbostic sp->sum_bytes_left = LFS_SUMMARY_SIZE - sizeof(SEGSUM); 67751915Sbostic } 67851342Sbostic 67951915Sbostic /* 68051915Sbostic * Return the next segment to write. 68151915Sbostic */ 68252077Sbostic void 68351915Sbostic lfs_newseg(fs) 68451915Sbostic struct lfs *fs; 68551915Sbostic { 68651927Sbostic CLEANERINFO *cip; 68751915Sbostic SEGUSE *sup; 68851915Sbostic struct buf *bp; 68951927Sbostic int curseg, isdirty, sn; 69051915Sbostic 69151915Sbostic #ifdef VERBOSE 69251915Sbostic printf("lfs_newseg\n"); 69351915Sbostic #endif 69451927Sbostic /* 69551927Sbostic * Turn off the active bit for the current segment, turn on the 69651927Sbostic * active and dirty bits for the next segment, update the cleaner 69751927Sbostic * info. Set the current segment to the next segment, get a new 69851927Sbostic * next segment. 69951927Sbostic */ 70051927Sbostic LFS_SEGENTRY(sup, fs, datosn(fs, fs->lfs_curseg), bp); 70151927Sbostic sup->su_flags &= ~SEGUSE_ACTIVE; 70252085Sbostic LFS_UBWRITE(bp); 70351927Sbostic 70451927Sbostic LFS_SEGENTRY(sup, fs, datosn(fs, fs->lfs_nextseg), bp); 70554264Sbostic sup->su_flags |= SEGUSE_ACTIVE | SEGUSE_DIRTY | SEGUSE_LIVELOG; 70652085Sbostic LFS_UBWRITE(bp); 70751927Sbostic 70851927Sbostic LFS_CLEANERINFO(cip, fs, bp); 70951927Sbostic --cip->clean; 71051927Sbostic ++cip->dirty; 71152085Sbostic LFS_UBWRITE(bp); 71251927Sbostic 71351927Sbostic fs->lfs_lastseg = fs->lfs_curseg; 71451927Sbostic fs->lfs_curseg = fs->lfs_nextseg; 71551927Sbostic for (sn = curseg = datosn(fs, fs->lfs_curseg);;) { 71651915Sbostic sn = (sn + 1) % fs->lfs_nseg; 71751927Sbostic if (sn == curseg) 71851915Sbostic panic("lfs_nextseg: no clean segments"); 71951915Sbostic LFS_SEGENTRY(sup, fs, sn, bp); 72051915Sbostic isdirty = sup->su_flags & SEGUSE_DIRTY; 72152085Sbostic brelse(bp); 72251915Sbostic if (!isdirty) 72351915Sbostic break; 72451915Sbostic } 72551927Sbostic fs->lfs_nextseg = sntoda(fs, sn); 72651188Sbostic } 72751188Sbostic 72854264Sbostic int 72951188Sbostic lfs_writeseg(fs, sp) 73051499Sbostic struct lfs *fs; 73152085Sbostic struct segment *sp; 73251188Sbostic { 73352688Sbostic struct buf **bpp, *bp, *cbp; 73451188Sbostic SEGUSE *sup; 73552085Sbostic SEGSUM *ssp; 73651860Sbostic dev_t i_dev; 73754264Sbostic size_t size; 73851860Sbostic u_long *datap, *dp; 73954264Sbostic int ch_per_blk, do_again, i, nblocks, num, s; 74054264Sbostic int (*strategy)__P((struct vop_strategy_args *)); 74154690Sbostic struct vop_strategy_args vop_strategy_a; 74252688Sbostic char *p; 74351188Sbostic 74451860Sbostic #ifdef VERBOSE 74551860Sbostic printf("lfs_writeseg\n"); 74651860Sbostic #endif 74754264Sbostic /* Checkpoint always writes superblock, even if no data blocks. */ 74854264Sbostic if ((nblocks = sp->cbpp - sp->bpp) == 0 && !(sp->seg_flags & SEGM_CKP)) 749*55551Sbostic return (0); 75052085Sbostic 75151188Sbostic /* 75252085Sbostic * Compute checksum across data and then across summary; the first 75352085Sbostic * block (the summary block) is skipped. Set the create time here 75452085Sbostic * so that it's guaranteed to be later than the inode mod times. 75551860Sbostic * 75651860Sbostic * XXX 75751860Sbostic * Fix this to do it inline, instead of malloc/copy. 75851188Sbostic */ 75951860Sbostic datap = dp = malloc(nblocks * sizeof(u_long), M_SEGMENT, M_WAITOK); 76051915Sbostic for (bpp = sp->bpp, i = nblocks - 1; i--;) 76151915Sbostic *dp++ = (*++bpp)->b_un.b_words[0]; 76252085Sbostic ssp = (SEGSUM *)sp->segsum; 76352103Sbostic ssp->ss_create = time.tv_sec; 76452085Sbostic ssp->ss_datasum = cksum(datap, nblocks * sizeof(u_long)); 76552085Sbostic ssp->ss_sumsum = 76652085Sbostic cksum(&ssp->ss_datasum, LFS_SUMMARY_SIZE - sizeof(ssp->ss_sumsum)); 76751927Sbostic free(datap, M_SEGMENT); 76851188Sbostic 76954264Sbostic /* Update the segment usage information. */ 77054264Sbostic LFS_SEGENTRY(sup, fs, sp->seg_number, bp); 77154264Sbostic sup->su_nbytes += nblocks - 1 - 77254264Sbostic (ssp->ss_ninos + INOPB(fs) - 1) / INOPB(fs) << fs->lfs_bshift; 77354264Sbostic sup->su_nbytes += ssp->ss_ninos * sizeof(struct dinode); 77454264Sbostic sup->su_lastmod = time.tv_sec; 77554264Sbostic LFS_UBWRITE(bp); 77654264Sbostic do_again = !(bp->b_flags & B_GATHERED); 77754264Sbostic 77851860Sbostic i_dev = VTOI(fs->lfs_ivnode)->i_dev; 77953574Sheideman strategy = VTOI(fs->lfs_ivnode)->i_devvp->v_op[VOFFSET(vop_strategy)]; 78051301Sbostic 78152688Sbostic /* 78252688Sbostic * When we simply write the blocks we lose a rotation for every block 78352688Sbostic * written. To avoid this problem, we allocate memory in chunks, copy 78452688Sbostic * the buffers into the chunk and write the chunk. 56K was chosen as 78552688Sbostic * some driver/controllers can't handle unsigned 16 bit transfers. 78652688Sbostic * When the data is copied to the chunk, turn off the the B_LOCKED bit 78752688Sbostic * and brelse the buffer (which will move them to the LRU list). Add 78852688Sbostic * the B_CALL flag to the buffer header so we can count I/O's for the 78952688Sbostic * checkpoints and so we can release the allocated memory. 79052688Sbostic * 79152688Sbostic * XXX 79252688Sbostic * This should be removed if the new virtual memory system allows us to 79352688Sbostic * easily make the buffers contiguous in kernel memory and if that's 79452688Sbostic * fast enough. 79552688Sbostic */ 79652688Sbostic #define LFS_CHUNKSIZE (56 * 1024) 79752688Sbostic ch_per_blk = LFS_CHUNKSIZE / fs->lfs_bsize; 79852688Sbostic for (bpp = sp->bpp, i = nblocks; i;) { 79952688Sbostic num = ch_per_blk; 80052688Sbostic if (num > i) 80152688Sbostic num = i; 80252688Sbostic i -= num; 80352688Sbostic size = num * fs->lfs_bsize; 80452688Sbostic 80552688Sbostic cbp = lfs_newbuf(fs, (*bpp)->b_blkno, 0); 80652688Sbostic cbp->b_dev = i_dev; 80752688Sbostic cbp->b_flags = B_ASYNC | B_BUSY | B_CALL; 80852688Sbostic cbp->b_iodone = lfs_callback; 80952688Sbostic cbp->b_saveaddr = cbp->b_un.b_addr; 81052688Sbostic cbp->b_un.b_addr = malloc(size, M_SEGMENT, M_WAITOK); 81152688Sbostic 81252688Sbostic s = splbio(); 81352688Sbostic ++fs->lfs_iocount; 81452688Sbostic for (p = cbp->b_un.b_addr; num--;) { 81552688Sbostic bp = *bpp++; 81652688Sbostic bcopy(bp->b_un.b_addr, p, bp->b_bcount); 81752688Sbostic p += bp->b_bcount; 81854264Sbostic bp->b_flags &= ~(B_DONE | B_ERROR | B_READ | B_DELWRI | 81954264Sbostic B_LOCKED | B_GATHERED); 82054264Sbostic if (!(bp->b_flags & (B_NOCACHE | B_INVAL))) { 82152688Sbostic bremfree(bp); 82252688Sbostic reassignbuf(bp, bp->b_vp); 82352688Sbostic } 82452688Sbostic brelse(bp); 82551860Sbostic } 82652688Sbostic splx(s); 82752688Sbostic cbp->b_bcount = p - cbp->b_un.b_addr; 82853574Sheideman vop_strategy_a.a_desc = VDESC(vop_strategy); 82953574Sheideman vop_strategy_a.a_bp = cbp; 83053574Sheideman (strategy)(&vop_strategy_a); 83151860Sbostic } 832*55551Sbostic return (do_again); 83351188Sbostic } 83451188Sbostic 83552077Sbostic void 83651860Sbostic lfs_writesuper(fs, sp) 83751499Sbostic struct lfs *fs; 83852085Sbostic struct segment *sp; 83951301Sbostic { 84052085Sbostic struct buf *bp; 84151860Sbostic dev_t i_dev; 84253574Sheideman int (*strategy) __P((struct vop_strategy_args *)); 84354690Sbostic struct vop_strategy_args vop_strategy_a; 84451301Sbostic 84551860Sbostic #ifdef VERBOSE 84651860Sbostic printf("lfs_writesuper\n"); 84751860Sbostic #endif 84851860Sbostic i_dev = VTOI(fs->lfs_ivnode)->i_dev; 84953574Sheideman strategy = VTOI(fs->lfs_ivnode)->i_devvp->v_op[VOFFSET(vop_strategy)]; 85051356Sbostic 85151342Sbostic /* Checksum the superblock and copy it into a buffer. */ 85251499Sbostic fs->lfs_cksum = cksum(fs, sizeof(struct lfs) - sizeof(fs->lfs_cksum)); 85352688Sbostic bp = lfs_newbuf(fs, fs->lfs_sboffs[0], LFS_SBPAD); 85451860Sbostic *bp->b_un.b_lfs = *fs; 85551215Sbostic 85651356Sbostic /* Write the first superblock (wait). */ 85751860Sbostic bp->b_dev = i_dev; 85851915Sbostic bp->b_flags |= B_BUSY; 85951860Sbostic bp->b_flags &= ~(B_DONE | B_ERROR | B_READ | B_DELWRI); 86053574Sheideman vop_strategy_a.a_desc = VDESC(vop_strategy); 86153574Sheideman vop_strategy_a.a_bp = bp; 86253574Sheideman (strategy)(&vop_strategy_a); 86351215Sbostic biowait(bp); 86451342Sbostic 86551356Sbostic /* Write the second superblock (don't wait). */ 86651215Sbostic bp->b_blkno = bp->b_lblkno = fs->lfs_sboffs[1]; 86751915Sbostic bp->b_flags |= B_ASYNC | B_BUSY; 86851860Sbostic bp->b_flags &= ~(B_DONE | B_ERROR | B_READ | B_DELWRI); 86953574Sheideman (strategy)(&vop_strategy_a); 87051215Sbostic } 87151215Sbostic 87251342Sbostic /* 87351342Sbostic * Logical block number match routines used when traversing the dirty block 87451342Sbostic * chain. 87551342Sbostic */ 87652077Sbostic int 87752077Sbostic lfs_match_data(fs, bp) 87851860Sbostic struct lfs *fs; 87952085Sbostic struct buf *bp; 88051215Sbostic { 88151342Sbostic return (bp->b_lblkno >= 0); 88251215Sbostic } 88351215Sbostic 88452077Sbostic int 88552077Sbostic lfs_match_indir(fs, bp) 88651860Sbostic struct lfs *fs; 88752085Sbostic struct buf *bp; 88851215Sbostic { 88951860Sbostic int lbn; 89051860Sbostic 89151860Sbostic lbn = bp->b_lblkno; 89251860Sbostic return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 0); 89351215Sbostic } 89451215Sbostic 89552077Sbostic int 89652077Sbostic lfs_match_dindir(fs, bp) 89751860Sbostic struct lfs *fs; 89852085Sbostic struct buf *bp; 89951215Sbostic { 90051860Sbostic int lbn; 90151860Sbostic 90251860Sbostic lbn = bp->b_lblkno; 90351860Sbostic return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 1); 90451215Sbostic } 90551215Sbostic 90652077Sbostic int 90752077Sbostic lfs_match_tindir(fs, bp) 90851499Sbostic struct lfs *fs; 90952085Sbostic struct buf *bp; 91051342Sbostic { 91151860Sbostic int lbn; 91251342Sbostic 91351860Sbostic lbn = bp->b_lblkno; 91451860Sbostic return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 2); 91551860Sbostic } 91651342Sbostic 91751860Sbostic /* 91851860Sbostic * Allocate a new buffer header. 91951860Sbostic */ 92052085Sbostic struct buf * 92152688Sbostic lfs_newbuf(fs, daddr, size) 92251860Sbostic struct lfs *fs; 92351860Sbostic daddr_t daddr; 92451860Sbostic size_t size; 92551860Sbostic { 92652085Sbostic struct buf *bp; 92751342Sbostic 92851860Sbostic #ifdef VERBOSE 92951860Sbostic printf("lfs_newbuf\n"); 93051860Sbostic #endif 93151860Sbostic bp = getnewbuf(); 93251860Sbostic bremhash(bp); 93351860Sbostic bgetvp(fs->lfs_ivnode, bp); 93451860Sbostic bp->b_bcount = 0; 93551860Sbostic bp->b_lblkno = daddr; 93651860Sbostic bp->b_blkno = daddr; 93751860Sbostic bp->b_error = 0; 93851860Sbostic bp->b_resid = 0; 93952688Sbostic if (size) 94052688Sbostic allocbuf(bp, size); 94151860Sbostic bp->b_flags |= B_NOCACHE; 94252688Sbostic bp->b_saveaddr = NULL; 94351915Sbostic binshash(bp, &bfreelist[BQ_AGE]); 94451860Sbostic return (bp); 94551860Sbostic } 94651342Sbostic 94753347Sbostic void 94851860Sbostic lfs_callback(bp) 94952085Sbostic struct buf *bp; 95051860Sbostic { 95151860Sbostic struct lfs *fs; 95251342Sbostic 95351860Sbostic fs = VFSTOUFS(bp->b_vp->v_mount)->um_lfs; 95451860Sbostic #ifdef DIAGNOSTIC 95551860Sbostic if (fs->lfs_iocount == 0) 95651860Sbostic panic("lfs_callback: zero iocount\n"); 95751860Sbostic #endif 95851860Sbostic if (--fs->lfs_iocount == 0) 95952688Sbostic wakeup(&fs->lfs_iocount); 96051915Sbostic 96152688Sbostic if (bp->b_saveaddr) { 96252688Sbostic free(bp->b_un.b_addr, M_SEGMENT); 96352688Sbostic bp->b_un.b_addr = bp->b_saveaddr; 96452819Sbostic bp->b_saveaddr = NULL; 96552688Sbostic } 96651860Sbostic brelse(bp); 96751860Sbostic } 96851342Sbostic 96951215Sbostic /* 97051188Sbostic * Shellsort (diminishing increment sort) from Data Structures and 97151188Sbostic * Algorithms, Aho, Hopcraft and Ullman, 1983 Edition, page 290; 97251188Sbostic * see also Knuth Vol. 3, page 84. The increments are selected from 97351188Sbostic * formula (8), page 95. Roughly O(N^3/2). 97451188Sbostic */ 97551188Sbostic /* 97651188Sbostic * This is our own private copy of shellsort because we want to sort 97751188Sbostic * two parallel arrays (the array of buffer pointers and the array of 97851188Sbostic * logical block numbers) simultaneously. Note that we cast the array 97951188Sbostic * of logical block numbers to a unsigned in this routine so that the 98051188Sbostic * negative block numbers (meta data blocks) sort AFTER the data blocks. 98151188Sbostic */ 98252077Sbostic void 98352077Sbostic lfs_shellsort(bp_array, lb_array, nmemb) 98452085Sbostic struct buf **bp_array; 98551215Sbostic daddr_t *lb_array; 98651188Sbostic register int nmemb; 98751188Sbostic { 98851188Sbostic static int __rsshell_increments[] = { 4, 1, 0 }; 98951188Sbostic register int incr, *incrp, t1, t2; 99052085Sbostic struct buf *bp_temp; 99151188Sbostic u_long lb_temp; 99251188Sbostic 99351188Sbostic for (incrp = __rsshell_increments; incr = *incrp++;) 99451188Sbostic for (t1 = incr; t1 < nmemb; ++t1) 99551188Sbostic for (t2 = t1 - incr; t2 >= 0;) 99651188Sbostic if (lb_array[t2] > lb_array[t2 + incr]) { 99751188Sbostic lb_temp = lb_array[t2]; 99851188Sbostic lb_array[t2] = lb_array[t2 + incr]; 99951188Sbostic lb_array[t2 + incr] = lb_temp; 100051188Sbostic bp_temp = bp_array[t2]; 100151188Sbostic bp_array[t2] = bp_array[t2 + incr]; 100251188Sbostic bp_array[t2 + incr] = bp_temp; 100351188Sbostic t2 -= incr; 100451188Sbostic } else 100551188Sbostic break; 100651188Sbostic } 1007