151188Sbostic /* 251188Sbostic * Copyright (c) 1991 Regents of the University of California. 351188Sbostic * All rights reserved. 451188Sbostic * 551188Sbostic * %sccs.include.redist.c% 651188Sbostic * 7*55803Sbostic * @(#)lfs_segment.c 7.27 (Berkeley) 08/01/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 11452328Sbostic /* 11552328Sbostic * Keep a cumulative count of the outstanding I/O operations. If the 11652328Sbostic * disk drive catches up with us it could go to zero before we finish, 11752328Sbostic * so we artificially increment it by one until we've scheduled all of 11852328Sbostic * the writes we intend to do. 11952328Sbostic */ 12052328Sbostic s = splbio(); 12152688Sbostic ++fs->lfs_iocount; 12252328Sbostic splx(s); 12352328Sbostic 12452328Sbostic ip = VTOI(vp); 12555551Sbostic do { 126*55803Sbostic lfs_initseg(fs, sp); 12755551Sbostic do { 12855551Sbostic if (vp->v_dirtyblkhd != NULL) 12955551Sbostic lfs_writefile(fs, sp, vp); 13055551Sbostic } while (lfs_writeinode(fs, sp, ip)); 13155551Sbostic ip->i_flags &= ~(IMOD | IACC | IUPD | ICHG); 13252328Sbostic 13355551Sbostic } 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 { 21155592Sbostic struct buf *bp; 21252085Sbostic struct inode *ip; 21351499Sbostic struct lfs *fs; 21452085Sbostic struct segment *sp; 21552085Sbostic struct vnode *vp; 21655592Sbostic SEGUSE *segusep; 21755592Sbostic daddr_t ibno; 21855592Sbostic int error, i, s; 21951188Sbostic 22051860Sbostic #ifdef VERBOSE 22151860Sbostic printf("lfs_segwrite\n"); 22251860Sbostic #endif 22352328Sbostic fs = VFSTOUFS(mp)->um_lfs; 22454690Sbostic lfs_seglock(fs); 22552085Sbostic 22651860Sbostic /* 22752328Sbostic * Allocate a segment structure and enough space to hold pointers to 22852328Sbostic * the maximum possible number of buffers which can be described in a 22952328Sbostic * single summary block. 23052328Sbostic */ 23152328Sbostic sp = malloc(sizeof(struct segment), M_SEGMENT, M_WAITOK); 23252328Sbostic sp->bpp = malloc(((LFS_SUMMARY_SIZE - sizeof(SEGSUM)) / 23352328Sbostic sizeof(daddr_t) + 1) * sizeof(struct buf *), M_SEGMENT, M_WAITOK); 23452328Sbostic sp->seg_flags = do_ckp ? SEGM_CKP : 0; 23552328Sbostic lfs_initseg(fs, sp); 23652328Sbostic 23752328Sbostic /* 23852688Sbostic * Keep a cumulative count of the outstanding I/O operations. If the 23952688Sbostic * disk drive catches up with us it could go to zero before we finish, 24052688Sbostic * so we artificially increment it by one until we've scheduled all of 24152688Sbostic * the writes we intend to do. If not a checkpoint, we never do the 24252688Sbostic * final decrement, avoiding the wakeup in the callback routine. 24351860Sbostic */ 24452688Sbostic s = splbio(); 24555551Sbostic ++fs->lfs_iocount; 24652688Sbostic splx(s); 24751342Sbostic 24854264Sbostic lfs_writevnodes(fs, mp, sp, 0); 24954264Sbostic fs->lfs_writer = 1; 25054264Sbostic if (fs->lfs_dirops && (error = 25154264Sbostic tsleep(&fs->lfs_writer, PRIBIO + 1, "lfs writer", 0))) { 25254264Sbostic free(sp->bpp, M_SEGMENT); 25354264Sbostic free(sp, M_SEGMENT); 25454264Sbostic fs->lfs_writer = 0; 25555551Sbostic return (error); 25654264Sbostic } 25751860Sbostic 25854264Sbostic lfs_writevnodes(fs, mp, sp, 1); 25951860Sbostic 26054264Sbostic /* 26155592Sbostic * If we are doing a checkpoint, mark everything since the 26255592Sbostic * last checkpoint as no longer ACTIVE. 26354264Sbostic */ 26455592Sbostic if (do_ckp) 26555592Sbostic for (ibno = fs->lfs_cleansz + fs->lfs_segtabsz; 26655592Sbostic --ibno >= fs->lfs_cleansz; ) { 26755592Sbostic if (bread(fs->lfs_ivnode, ibno, fs->lfs_bsize, 26855592Sbostic NOCRED, &bp)) 26955592Sbostic 27055592Sbostic panic("lfs: ifile read"); 27155592Sbostic segusep = (SEGUSE *)bp->b_un.b_addr; 27255592Sbostic for (i = fs->lfs_sepb; i--; segusep++) 27355592Sbostic segusep->su_flags &= ~SEGUSE_ACTIVE; 27455592Sbostic 27555592Sbostic LFS_UBWRITE(bp); 27655592Sbostic } 27755592Sbostic 27854264Sbostic if (do_ckp || fs->lfs_doifile) { 27954264Sbostic vp = fs->lfs_ivnode; 28054264Sbostic while (vget(vp)); 28152328Sbostic ip = VTOI(vp); 28255592Sbostic if (vp->v_dirtyblkhd != NULL) 28355592Sbostic lfs_writefile(fs, sp, vp); 28455592Sbostic (void)lfs_writeinode(fs, sp, ip); 28552077Sbostic ip->i_flags &= ~(IMOD | IACC | IUPD | ICHG); 28652077Sbostic vput(vp); 28755592Sbostic /* 28855592Sbostic * This should never happen because we just guaranteed 28955592Sbostic * that all the segment usage table blocks are dirty, so 29055592Sbostic * no new ones should get written. 29155592Sbostic */ 29255592Sbostic if (lfs_writeseg(fs, sp) && do_ckp) 29355592Sbostic panic("lfs_segwrite: created dirty blocks on ckp"); 29454264Sbostic } else 29554264Sbostic (void) lfs_writeseg(fs, sp); 29651342Sbostic 29751215Sbostic /* 29851860Sbostic * If the I/O count is non-zero, sleep until it reaches zero. At the 29951860Sbostic * moment, the user's process hangs around so we can sleep. 30051215Sbostic */ 30154264Sbostic fs->lfs_writer = 0; 30254264Sbostic fs->lfs_doifile = 0; 30354264Sbostic wakeup(&fs->lfs_dirops); 30454264Sbostic 30555551Sbostic s = splbio(); 30655551Sbostic --fs->lfs_iocount; 30751860Sbostic if (do_ckp) { 30852688Sbostic if (fs->lfs_iocount && (error = 30952995Sbostic tsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs sync", 0))) { 31052995Sbostic free(sp->bpp, M_SEGMENT); 31152995Sbostic free(sp, M_SEGMENT); 31251915Sbostic return (error); 31352995Sbostic } 31451860Sbostic splx(s); 31551860Sbostic lfs_writesuper(fs, sp); 31652688Sbostic } else 31752688Sbostic splx(s); 31851215Sbostic 31954690Sbostic lfs_segunlock(fs); 32054690Sbostic 32151927Sbostic free(sp->bpp, M_SEGMENT); 32251927Sbostic free(sp, M_SEGMENT); 32351215Sbostic 32451860Sbostic return (0); 32551188Sbostic } 32651188Sbostic 32751860Sbostic /* 32851860Sbostic * Write the dirty blocks associated with a vnode. 32951860Sbostic */ 33052077Sbostic void 33151860Sbostic lfs_writefile(fs, sp, vp) 33251499Sbostic struct lfs *fs; 33352085Sbostic struct segment *sp; 33452085Sbostic struct vnode *vp; 33551188Sbostic { 33651860Sbostic struct buf *bp; 33752085Sbostic struct finfo *fip; 33851860Sbostic IFILE *ifp; 33951188Sbostic 34051860Sbostic #ifdef VERBOSE 34151860Sbostic printf("lfs_writefile\n"); 34251860Sbostic #endif 34352085Sbostic if (sp->seg_bytes_left < fs->lfs_bsize || 34452085Sbostic sp->sum_bytes_left < sizeof(struct finfo)) { 34554264Sbostic (void) lfs_writeseg(fs, sp); 34652085Sbostic lfs_initseg(fs, sp); 34752085Sbostic } 34852085Sbostic sp->sum_bytes_left -= sizeof(struct finfo) - sizeof(daddr_t); 34951215Sbostic 35052085Sbostic fip = sp->fip; 35152085Sbostic fip->fi_nblocks = 0; 35252085Sbostic fip->fi_ino = VTOI(vp)->i_number; 35352085Sbostic LFS_IENTRY(ifp, fs, fip->fi_ino, bp); 35452085Sbostic fip->fi_version = ifp->if_version; 35552085Sbostic brelse(bp); 35651188Sbostic 35752085Sbostic /* 35852085Sbostic * It may not be necessary to write the meta-data blocks at this point, 35952085Sbostic * as the roll-forward recovery code should be able to reconstruct the 36052085Sbostic * list. 36152085Sbostic */ 36252085Sbostic lfs_gather(fs, sp, vp, lfs_match_data); 36352085Sbostic lfs_gather(fs, sp, vp, lfs_match_indir); 36452085Sbostic lfs_gather(fs, sp, vp, lfs_match_dindir); 36551860Sbostic #ifdef TRIPLE 36652085Sbostic lfs_gather(fs, sp, vp, lfs_match_tindir); 36751860Sbostic #endif 36851342Sbostic 36952085Sbostic fip = sp->fip; 37051860Sbostic #ifdef META 37152085Sbostic printf("lfs_writefile: adding %d blocks\n", fip->fi_nblocks); 37251860Sbostic #endif 37352085Sbostic if (fip->fi_nblocks != 0) { 37452085Sbostic ++((SEGSUM *)(sp->segsum))->ss_nfinfo; 37552085Sbostic sp->fip = 37652085Sbostic (struct finfo *)((caddr_t)fip + sizeof(struct finfo) + 37752085Sbostic sizeof(daddr_t) * (fip->fi_nblocks - 1)); 37852682Sstaelin } else 37952682Sstaelin sp->sum_bytes_left += sizeof(struct finfo) - sizeof(daddr_t); 38051215Sbostic } 38151215Sbostic 38254264Sbostic int 38351915Sbostic lfs_writeinode(fs, sp, ip) 38451915Sbostic struct lfs *fs; 38552085Sbostic struct segment *sp; 38652085Sbostic struct inode *ip; 38751915Sbostic { 38852085Sbostic struct buf *bp, *ibp; 38952077Sbostic IFILE *ifp; 39052682Sstaelin SEGUSE *sup; 39152682Sstaelin daddr_t daddr; 39252077Sbostic ino_t ino; 39351915Sbostic int ndx; 39454264Sbostic int redo_ifile = 0; 39551915Sbostic 39651915Sbostic #ifdef VERBOSE 39751915Sbostic printf("lfs_writeinode\n"); 39851915Sbostic #endif 39951915Sbostic /* Allocate a new inode block if necessary. */ 40051915Sbostic if (sp->ibp == NULL) { 40151915Sbostic /* Allocate a new segment if necessary. */ 40251915Sbostic if (sp->seg_bytes_left < fs->lfs_bsize || 40351915Sbostic sp->sum_bytes_left < sizeof(daddr_t)) { 40454264Sbostic (void) lfs_writeseg(fs, sp); 40551915Sbostic lfs_initseg(fs, sp); 40651915Sbostic } 40751915Sbostic 40851915Sbostic /* Get next inode block. */ 40952682Sstaelin daddr = fs->lfs_offset; 41051915Sbostic fs->lfs_offset += fsbtodb(fs, 1); 41151915Sbostic sp->ibp = *sp->cbpp++ = 41252688Sbostic lfs_newbuf(fs, daddr, fs->lfs_bsize); 41351915Sbostic 41452688Sbostic /* Set remaining space counters. */ 41551915Sbostic sp->seg_bytes_left -= fs->lfs_bsize; 41651915Sbostic sp->sum_bytes_left -= sizeof(daddr_t); 41752077Sbostic ndx = LFS_SUMMARY_SIZE / sizeof(daddr_t) - 41851915Sbostic sp->ninodes / INOPB(fs) - 1; 41952682Sstaelin ((daddr_t *)(sp->segsum))[ndx] = daddr; 42051915Sbostic } 42151915Sbostic 42252085Sbostic /* Update the inode times and copy the inode onto the inode page. */ 42352077Sbostic ITIMES(ip, &time, &time); 42451915Sbostic bp = sp->ibp; 42552085Sbostic bp->b_un.b_dino[sp->ninodes % INOPB(fs)] = ip->i_din; 42651915Sbostic 42751915Sbostic /* Increment inode count in segment summary block. */ 42851915Sbostic ++((SEGSUM *)(sp->segsum))->ss_ninos; 42951915Sbostic 43051915Sbostic /* If this page is full, set flag to allocate a new page. */ 43151915Sbostic if (++sp->ninodes % INOPB(fs) == 0) 43251915Sbostic sp->ibp = NULL; 43351915Sbostic 43451915Sbostic /* 43552077Sbostic * If updating the ifile, update the super-block. Update the disk 43652077Sbostic * address and access times for this inode in the ifile. 43751915Sbostic */ 43852077Sbostic ino = ip->i_number; 43955696Sbostic if (ino == LFS_IFILE_INUM) { 44055696Sbostic daddr = fs->lfs_idaddr; 44151915Sbostic fs->lfs_idaddr = bp->b_blkno; 44255696Sbostic } else { 44355696Sbostic LFS_IENTRY(ifp, fs, ino, ibp); 44455696Sbostic daddr = ifp->if_daddr; 44555696Sbostic ifp->if_daddr = bp->b_blkno; 44655696Sbostic LFS_UBWRITE(ibp); 44755696Sbostic } 44852077Sbostic 44954264Sbostic /* 45054264Sbostic * No need to update segment usage if there was no former inode address 45154264Sbostic * or if the last inode address is in the current partial segment. 45254264Sbostic */ 45354264Sbostic if (daddr != LFS_UNUSED_DADDR && 454*55803Sbostic !(daddr >= fs->lfs_lastpseg && daddr <= bp->b_blkno)) { 45552682Sstaelin LFS_SEGENTRY(sup, fs, datosn(fs, daddr), bp); 45652682Sstaelin #ifdef DIAGNOSTIC 45754264Sbostic if (sup->su_nbytes < sizeof(struct dinode)) { 45852819Sbostic /* XXX -- Change to a panic. */ 45952819Sbostic printf("lfs: negative bytes (segment %d)\n", 46052682Sstaelin datosn(fs, daddr)); 46154264Sbostic panic("negative bytes"); 46254264Sbostic } 46352682Sstaelin #endif 46452682Sstaelin sup->su_nbytes -= sizeof(struct dinode); 46552682Sstaelin LFS_UBWRITE(bp); 46655696Sbostic redo_ifile = (ino == LFS_IFILE_INUM && !(bp->b_flags & B_GATHERED)); 46752682Sstaelin } 46855551Sbostic return (redo_ifile); 46951915Sbostic } 47051915Sbostic 47152077Sbostic void 47251215Sbostic lfs_gather(fs, sp, vp, match) 47351499Sbostic struct lfs *fs; 47452085Sbostic struct segment *sp; 47552085Sbostic struct vnode *vp; 47652085Sbostic int (*match) __P((struct lfs *, struct buf *)); 47751215Sbostic { 47854264Sbostic struct buf **bpp, *bp; 47954264Sbostic struct buf *lastbp; 48052085Sbostic struct finfo *fip; 48152085Sbostic struct inode *ip; 48251215Sbostic daddr_t *lbp, *start_lbp; 48351342Sbostic u_long version; 48451342Sbostic int s; 48551215Sbostic 48651860Sbostic #ifdef VERBOSE 48751860Sbostic printf("lfs_gather\n"); 48851860Sbostic #endif 48951215Sbostic ip = VTOI(vp); 49051215Sbostic bpp = sp->cbpp; 49151215Sbostic fip = sp->fip; 49251215Sbostic start_lbp = lbp = &fip->fi_blocks[fip->fi_nblocks]; 49351215Sbostic 49453145Sstaelin loop: s = splbio(); 49554264Sbostic lastbp = NULL; 49654264Sbostic for (bp = vp->v_dirtyblkhd; bp; lastbp = bp, bp = bp->b_blockf) { 49754264Sbostic if (bp->b_flags & B_BUSY || !match(fs, bp) || 49854264Sbostic bp->b_flags & B_GATHERED) 49951215Sbostic continue; 50051342Sbostic #ifdef DIAGNOSTIC 50151860Sbostic if (!(bp->b_flags & B_DELWRI)) 50251915Sbostic panic("lfs_gather: bp not B_DELWRI"); 50351860Sbostic if (!(bp->b_flags & B_LOCKED)) 50451915Sbostic panic("lfs_gather: bp not B_LOCKED"); 50551342Sbostic #endif 50651860Sbostic /* 50751860Sbostic * If full, finish this segment. We may be doing I/O, so 50851860Sbostic * release and reacquire the splbio(). 50951860Sbostic */ 51051342Sbostic if (sp->sum_bytes_left < sizeof(daddr_t) || 51151215Sbostic sp->seg_bytes_left < fs->lfs_bsize) { 51251215Sbostic splx(s); 51351342Sbostic lfs_updatemeta(fs, 51451860Sbostic sp, vp, start_lbp, bpp, lbp - start_lbp); 51551215Sbostic 51651342Sbostic /* Add the current file to the segment summary. */ 51751342Sbostic ++((SEGSUM *)(sp->segsum))->ss_nfinfo; 51851215Sbostic 51951342Sbostic version = fip->fi_version; 52054264Sbostic (void) lfs_writeseg(fs, sp); 52151915Sbostic lfs_initseg(fs, sp); 52251342Sbostic 52351215Sbostic fip = sp->fip; 52451342Sbostic fip->fi_version = version; 52551215Sbostic fip->fi_ino = ip->i_number; 52651342Sbostic start_lbp = lbp = fip->fi_blocks; 52751342Sbostic 52852682Sstaelin sp->sum_bytes_left -= 52952682Sstaelin sizeof(struct finfo) - sizeof(daddr_t); 53052682Sstaelin 53151215Sbostic bpp = sp->cbpp; 53253145Sstaelin goto loop; 53351215Sbostic } 53452682Sstaelin 53552682Sstaelin /* Insert into the buffer list, update the FINFO block. */ 53654264Sbostic bp->b_flags |= B_GATHERED; 53752682Sstaelin *sp->cbpp++ = bp; 53852682Sstaelin ++fip->fi_nblocks; 53952682Sstaelin *lbp++ = bp->b_lblkno; 54052682Sstaelin 54152682Sstaelin sp->sum_bytes_left -= sizeof(daddr_t); 54252682Sstaelin sp->seg_bytes_left -= bp->b_bufsize; 54351188Sbostic } 54451215Sbostic splx(s); 54551860Sbostic lfs_updatemeta(fs, sp, vp, start_lbp, bpp, lbp - start_lbp); 54651188Sbostic } 54751188Sbostic 54851342Sbostic /* 54951342Sbostic * Update the metadata that points to the blocks listed in the FINFO 55051188Sbostic * array. 55151188Sbostic */ 55252077Sbostic void 55351860Sbostic lfs_updatemeta(fs, sp, vp, lbp, bpp, nblocks) 55451499Sbostic struct lfs *fs; 55552085Sbostic struct segment *sp; 55652085Sbostic struct vnode *vp; 55751215Sbostic daddr_t *lbp; 55852085Sbostic struct buf **bpp; 55951215Sbostic int nblocks; 56051188Sbostic { 56151915Sbostic SEGUSE *sup; 56252085Sbostic struct buf *bp; 56351860Sbostic INDIR a[NIADDR], *ap; 56452085Sbostic struct inode *ip; 56551915Sbostic daddr_t daddr, lbn, off; 56651860Sbostic int db_per_fsb, error, i, num; 56751188Sbostic 56851860Sbostic #ifdef VERBOSE 56951860Sbostic printf("lfs_updatemeta\n"); 57051860Sbostic #endif 57151342Sbostic if (nblocks == 0) 57251215Sbostic return; 57351215Sbostic 57451915Sbostic /* Sort the blocks. */ 57552077Sbostic lfs_shellsort(bpp, lbp, nblocks); 57651215Sbostic 57751915Sbostic /* 57851915Sbostic * Assign disk addresses, and update references to the logical 57951915Sbostic * block and the segment usage information. 58051915Sbostic */ 58151860Sbostic db_per_fsb = fsbtodb(fs, 1); 58251915Sbostic for (i = nblocks; i--; ++bpp) { 58351915Sbostic lbn = *lbp++; 58451915Sbostic (*bpp)->b_blkno = off = fs->lfs_offset; 58551860Sbostic fs->lfs_offset += db_per_fsb; 58651215Sbostic 58751860Sbostic if (error = lfs_bmaparray(vp, lbn, &daddr, a, &num)) 58852085Sbostic panic("lfs_updatemeta: lfs_bmaparray %d", error); 58951860Sbostic ip = VTOI(vp); 59051860Sbostic switch (num) { 59151860Sbostic case 0: 59251915Sbostic ip->i_db[lbn] = off; 59351860Sbostic break; 59451860Sbostic case 1: 59551915Sbostic ip->i_ib[a[0].in_off] = off; 59651860Sbostic break; 59751860Sbostic default: 59851860Sbostic ap = &a[num - 1]; 59951860Sbostic if (bread(vp, ap->in_lbn, fs->lfs_bsize, NOCRED, &bp)) 60051860Sbostic panic("lfs_updatemeta: bread bno %d", 60151860Sbostic ap->in_lbn); 60255458Sbostic /* 60355458Sbostic * Bread may create a new indirect block which needs 60455458Sbostic * to get counted for the inode. 60555458Sbostic */ 60655592Sbostic if (bp->b_blkno == -1 && !(bp->b_flags & B_CACHE)) { 60755458Sbostic ip->i_blocks += btodb(fs->lfs_bsize); 60855592Sbostic fs->lfs_bfree -= btodb(fs->lfs_bsize); 60955592Sbostic } 61051915Sbostic bp->b_un.b_daddr[ap->in_off] = off; 61153530Sheideman VOP_BWRITE(bp); 61251188Sbostic } 61351915Sbostic 61451915Sbostic /* Update segment usage information. */ 61551915Sbostic if (daddr != UNASSIGNED) { 61651915Sbostic LFS_SEGENTRY(sup, fs, datosn(fs, daddr), bp); 61751915Sbostic #ifdef DIAGNOSTIC 61854264Sbostic if (sup->su_nbytes < fs->lfs_bsize) { 61952819Sbostic /* XXX -- Change to a panic. */ 62052819Sbostic printf("lfs: negative bytes (segment %d)\n", 62151915Sbostic datosn(fs, daddr)); 62254264Sbostic panic ("Negative Bytes"); 62354264Sbostic } 62451915Sbostic #endif 62551915Sbostic sup->su_nbytes -= fs->lfs_bsize; 62652085Sbostic LFS_UBWRITE(bp); 62751915Sbostic } 62851188Sbostic } 62951188Sbostic } 63051188Sbostic 63151915Sbostic /* 63251915Sbostic * Start a new segment. 63351915Sbostic */ 63452077Sbostic void 63551915Sbostic lfs_initseg(fs, sp) 63651499Sbostic struct lfs *fs; 63752085Sbostic struct segment *sp; 63851188Sbostic { 63951915Sbostic SEGUSE *sup; 64051915Sbostic SEGSUM *ssp; 64151915Sbostic struct buf *bp; 64251915Sbostic daddr_t lbn, *lbnp; 64351215Sbostic 64451860Sbostic #ifdef VERBOSE 64551915Sbostic printf("lfs_initseg\n"); 64651860Sbostic #endif 64751915Sbostic /* Advance to the next segment. */ 64851927Sbostic if (!LFS_PARTIAL_FITS(fs)) { 64952682Sstaelin /* Wake up any cleaning procs waiting on this file system. */ 65052688Sbostic wakeup(&fs->lfs_nextseg); 65152688Sbostic wakeup(&lfs_allclean_wakeup); 65252682Sstaelin 65351927Sbostic lfs_newseg(fs); 65451927Sbostic fs->lfs_offset = fs->lfs_curseg; 65551915Sbostic sp->seg_number = datosn(fs, fs->lfs_curseg); 65651915Sbostic sp->seg_bytes_left = fs->lfs_dbpseg * DEV_BSIZE; 65751915Sbostic 65851915Sbostic /* 65951927Sbostic * If the segment contains a superblock, update the offset 66051927Sbostic * and summary address to skip over it. 66151915Sbostic */ 66252077Sbostic LFS_SEGENTRY(sup, fs, sp->seg_number, bp); 66351927Sbostic if (sup->su_flags & SEGUSE_SUPERBLOCK) { 66451915Sbostic fs->lfs_offset += LFS_SBPAD / DEV_BSIZE; 66551915Sbostic sp->seg_bytes_left -= LFS_SBPAD; 66651215Sbostic } 66752085Sbostic brelse(bp); 66851915Sbostic } else { 66951915Sbostic sp->seg_number = datosn(fs, fs->lfs_curseg); 67051915Sbostic sp->seg_bytes_left = (fs->lfs_dbpseg - 67151915Sbostic (fs->lfs_offset - fs->lfs_curseg)) * DEV_BSIZE; 67251915Sbostic } 67354264Sbostic fs->lfs_lastpseg = fs->lfs_offset; 67451342Sbostic 67551915Sbostic sp->ibp = NULL; 67651915Sbostic sp->ninodes = 0; 67751342Sbostic 67851915Sbostic /* Get a new buffer for SEGSUM and enter it into the buffer list. */ 67951915Sbostic sp->cbpp = sp->bpp; 68052688Sbostic *sp->cbpp = lfs_newbuf(fs, fs->lfs_offset, LFS_SUMMARY_SIZE); 68151915Sbostic sp->segsum = (*sp->cbpp)->b_un.b_addr; 68251915Sbostic ++sp->cbpp; 68351915Sbostic fs->lfs_offset += LFS_SUMMARY_SIZE / DEV_BSIZE; 68451342Sbostic 68551915Sbostic /* Set point to SEGSUM, initialize it. */ 68651915Sbostic ssp = sp->segsum; 68751915Sbostic ssp->ss_next = fs->lfs_nextseg; 68851915Sbostic ssp->ss_nfinfo = ssp->ss_ninos = 0; 68951342Sbostic 69051915Sbostic /* Set pointer to first FINFO, initialize it. */ 69152085Sbostic sp->fip = (struct finfo *)(sp->segsum + sizeof(SEGSUM)); 69251915Sbostic sp->fip->fi_nblocks = 0; 69351342Sbostic 69451915Sbostic sp->seg_bytes_left -= LFS_SUMMARY_SIZE; 69551915Sbostic sp->sum_bytes_left = LFS_SUMMARY_SIZE - sizeof(SEGSUM); 69651915Sbostic } 69751342Sbostic 69851915Sbostic /* 69951915Sbostic * Return the next segment to write. 70051915Sbostic */ 70152077Sbostic void 70251915Sbostic lfs_newseg(fs) 70351915Sbostic struct lfs *fs; 70451915Sbostic { 70551927Sbostic CLEANERINFO *cip; 70651915Sbostic SEGUSE *sup; 70751915Sbostic struct buf *bp; 70851927Sbostic int curseg, isdirty, sn; 70951915Sbostic 71051915Sbostic #ifdef VERBOSE 71151915Sbostic printf("lfs_newseg\n"); 71251915Sbostic #endif 71355592Sbostic LFS_SEGENTRY(sup, fs, datosn(fs, fs->lfs_nextseg), bp); 71455592Sbostic sup->su_flags |= SEGUSE_DIRTY; 71555592Sbostic LFS_UBWRITE(bp); 71651927Sbostic 71751927Sbostic LFS_CLEANERINFO(cip, fs, bp); 71851927Sbostic --cip->clean; 71951927Sbostic ++cip->dirty; 72052085Sbostic LFS_UBWRITE(bp); 72151927Sbostic 72251927Sbostic fs->lfs_lastseg = fs->lfs_curseg; 72351927Sbostic fs->lfs_curseg = fs->lfs_nextseg; 72451927Sbostic for (sn = curseg = datosn(fs, fs->lfs_curseg);;) { 72551915Sbostic sn = (sn + 1) % fs->lfs_nseg; 72651927Sbostic if (sn == curseg) 72751915Sbostic panic("lfs_nextseg: no clean segments"); 72851915Sbostic LFS_SEGENTRY(sup, fs, sn, bp); 72951915Sbostic isdirty = sup->su_flags & SEGUSE_DIRTY; 73052085Sbostic brelse(bp); 73151915Sbostic if (!isdirty) 73251915Sbostic break; 73351915Sbostic } 73455592Sbostic 73551927Sbostic fs->lfs_nextseg = sntoda(fs, sn); 73651188Sbostic } 73751188Sbostic 73854264Sbostic int 73951188Sbostic lfs_writeseg(fs, sp) 74051499Sbostic struct lfs *fs; 74152085Sbostic struct segment *sp; 74251188Sbostic { 74352688Sbostic struct buf **bpp, *bp, *cbp; 74451188Sbostic SEGUSE *sup; 74552085Sbostic SEGSUM *ssp; 74651860Sbostic dev_t i_dev; 74754264Sbostic size_t size; 74851860Sbostic u_long *datap, *dp; 74954264Sbostic int ch_per_blk, do_again, i, nblocks, num, s; 75054264Sbostic int (*strategy)__P((struct vop_strategy_args *)); 75154690Sbostic struct vop_strategy_args vop_strategy_a; 75255592Sbostic u_short ninos; 75352688Sbostic char *p; 75451188Sbostic 75551860Sbostic #ifdef VERBOSE 75651860Sbostic printf("lfs_writeseg\n"); 75751860Sbostic #endif 75854264Sbostic /* Checkpoint always writes superblock, even if no data blocks. */ 75954264Sbostic if ((nblocks = sp->cbpp - sp->bpp) == 0 && !(sp->seg_flags & SEGM_CKP)) 76055551Sbostic return (0); 76152085Sbostic 76251188Sbostic /* 76352085Sbostic * Compute checksum across data and then across summary; the first 76452085Sbostic * block (the summary block) is skipped. Set the create time here 76552085Sbostic * so that it's guaranteed to be later than the inode mod times. 76651860Sbostic * 76751860Sbostic * XXX 76851860Sbostic * Fix this to do it inline, instead of malloc/copy. 76951188Sbostic */ 77051860Sbostic datap = dp = malloc(nblocks * sizeof(u_long), M_SEGMENT, M_WAITOK); 77151915Sbostic for (bpp = sp->bpp, i = nblocks - 1; i--;) 77251915Sbostic *dp++ = (*++bpp)->b_un.b_words[0]; 77352085Sbostic ssp = (SEGSUM *)sp->segsum; 77452103Sbostic ssp->ss_create = time.tv_sec; 775*55803Sbostic ssp->ss_datasum = cksum(datap, (nblocks - 1) * sizeof(u_long)); 77652085Sbostic ssp->ss_sumsum = 77752085Sbostic cksum(&ssp->ss_datasum, LFS_SUMMARY_SIZE - sizeof(ssp->ss_sumsum)); 77851927Sbostic free(datap, M_SEGMENT); 77951188Sbostic 78054264Sbostic /* Update the segment usage information. */ 78154264Sbostic LFS_SEGENTRY(sup, fs, sp->seg_number, bp); 78255592Sbostic ninos = (ssp->ss_ninos + INOPB(fs) - 1) / INOPB(fs); 78355592Sbostic sup->su_nbytes += nblocks - 1 - ninos << fs->lfs_bshift; 78454264Sbostic sup->su_nbytes += ssp->ss_ninos * sizeof(struct dinode); 785*55803Sbostic sup->su_nbytes += LFS_SUMMARY_SIZE; 78654264Sbostic sup->su_lastmod = time.tv_sec; 78755592Sbostic sup->su_flags |= SEGUSE_ACTIVE; 78855592Sbostic sup->su_ninos += ninos; 78955592Sbostic ++sup->su_nsums; 79054264Sbostic LFS_UBWRITE(bp); 79155592Sbostic fs->lfs_bfree -= (fsbtodb(fs, ninos) + LFS_SUMMARY_SIZE / DEV_BSIZE); 79254264Sbostic do_again = !(bp->b_flags & B_GATHERED); 79354264Sbostic 79451860Sbostic i_dev = VTOI(fs->lfs_ivnode)->i_dev; 79553574Sheideman strategy = VTOI(fs->lfs_ivnode)->i_devvp->v_op[VOFFSET(vop_strategy)]; 79651301Sbostic 79752688Sbostic /* 79852688Sbostic * When we simply write the blocks we lose a rotation for every block 79952688Sbostic * written. To avoid this problem, we allocate memory in chunks, copy 80052688Sbostic * the buffers into the chunk and write the chunk. 56K was chosen as 80152688Sbostic * some driver/controllers can't handle unsigned 16 bit transfers. 80252688Sbostic * When the data is copied to the chunk, turn off the the B_LOCKED bit 80352688Sbostic * and brelse the buffer (which will move them to the LRU list). Add 80452688Sbostic * the B_CALL flag to the buffer header so we can count I/O's for the 80552688Sbostic * checkpoints and so we can release the allocated memory. 80652688Sbostic * 80752688Sbostic * XXX 80852688Sbostic * This should be removed if the new virtual memory system allows us to 80952688Sbostic * easily make the buffers contiguous in kernel memory and if that's 81052688Sbostic * fast enough. 81152688Sbostic */ 81252688Sbostic #define LFS_CHUNKSIZE (56 * 1024) 81352688Sbostic ch_per_blk = LFS_CHUNKSIZE / fs->lfs_bsize; 81452688Sbostic for (bpp = sp->bpp, i = nblocks; i;) { 81552688Sbostic num = ch_per_blk; 81652688Sbostic if (num > i) 81752688Sbostic num = i; 81852688Sbostic i -= num; 81952688Sbostic size = num * fs->lfs_bsize; 82052688Sbostic 82152688Sbostic cbp = lfs_newbuf(fs, (*bpp)->b_blkno, 0); 82252688Sbostic cbp->b_dev = i_dev; 82352688Sbostic cbp->b_flags = B_ASYNC | B_BUSY | B_CALL; 82452688Sbostic cbp->b_iodone = lfs_callback; 82552688Sbostic cbp->b_saveaddr = cbp->b_un.b_addr; 82652688Sbostic cbp->b_un.b_addr = malloc(size, M_SEGMENT, M_WAITOK); 82752688Sbostic 82852688Sbostic s = splbio(); 82952688Sbostic ++fs->lfs_iocount; 83052688Sbostic for (p = cbp->b_un.b_addr; num--;) { 83152688Sbostic bp = *bpp++; 83252688Sbostic bcopy(bp->b_un.b_addr, p, bp->b_bcount); 83352688Sbostic p += bp->b_bcount; 83454264Sbostic bp->b_flags &= ~(B_DONE | B_ERROR | B_READ | B_DELWRI | 83554264Sbostic B_LOCKED | B_GATHERED); 83654264Sbostic if (!(bp->b_flags & (B_NOCACHE | B_INVAL))) { 83752688Sbostic bremfree(bp); 83852688Sbostic reassignbuf(bp, bp->b_vp); 83952688Sbostic } 84052688Sbostic brelse(bp); 84151860Sbostic } 84252688Sbostic splx(s); 84352688Sbostic cbp->b_bcount = p - cbp->b_un.b_addr; 84453574Sheideman vop_strategy_a.a_desc = VDESC(vop_strategy); 84553574Sheideman vop_strategy_a.a_bp = cbp; 84653574Sheideman (strategy)(&vop_strategy_a); 84751860Sbostic } 84855551Sbostic return (do_again); 84951188Sbostic } 85051188Sbostic 85152077Sbostic void 85251860Sbostic lfs_writesuper(fs, sp) 85351499Sbostic struct lfs *fs; 85452085Sbostic struct segment *sp; 85551301Sbostic { 85652085Sbostic struct buf *bp; 85751860Sbostic dev_t i_dev; 85853574Sheideman int (*strategy) __P((struct vop_strategy_args *)); 85954690Sbostic struct vop_strategy_args vop_strategy_a; 86051301Sbostic 86151860Sbostic #ifdef VERBOSE 86251860Sbostic printf("lfs_writesuper\n"); 86351860Sbostic #endif 86451860Sbostic i_dev = VTOI(fs->lfs_ivnode)->i_dev; 86553574Sheideman strategy = VTOI(fs->lfs_ivnode)->i_devvp->v_op[VOFFSET(vop_strategy)]; 86651356Sbostic 86751342Sbostic /* Checksum the superblock and copy it into a buffer. */ 86851499Sbostic fs->lfs_cksum = cksum(fs, sizeof(struct lfs) - sizeof(fs->lfs_cksum)); 86952688Sbostic bp = lfs_newbuf(fs, fs->lfs_sboffs[0], LFS_SBPAD); 87051860Sbostic *bp->b_un.b_lfs = *fs; 87151215Sbostic 87251356Sbostic /* Write the first superblock (wait). */ 87351860Sbostic bp->b_dev = i_dev; 87451915Sbostic bp->b_flags |= B_BUSY; 87551860Sbostic bp->b_flags &= ~(B_DONE | B_ERROR | B_READ | B_DELWRI); 87653574Sheideman vop_strategy_a.a_desc = VDESC(vop_strategy); 87753574Sheideman vop_strategy_a.a_bp = bp; 87853574Sheideman (strategy)(&vop_strategy_a); 87951215Sbostic biowait(bp); 88051342Sbostic 88151356Sbostic /* Write the second superblock (don't wait). */ 88251215Sbostic bp->b_blkno = bp->b_lblkno = fs->lfs_sboffs[1]; 88351915Sbostic bp->b_flags |= B_ASYNC | B_BUSY; 88451860Sbostic bp->b_flags &= ~(B_DONE | B_ERROR | B_READ | B_DELWRI); 88553574Sheideman (strategy)(&vop_strategy_a); 88651215Sbostic } 88751215Sbostic 88851342Sbostic /* 88951342Sbostic * Logical block number match routines used when traversing the dirty block 89051342Sbostic * chain. 89151342Sbostic */ 89252077Sbostic int 89352077Sbostic lfs_match_data(fs, bp) 89451860Sbostic struct lfs *fs; 89552085Sbostic struct buf *bp; 89651215Sbostic { 89751342Sbostic return (bp->b_lblkno >= 0); 89851215Sbostic } 89951215Sbostic 90052077Sbostic int 90152077Sbostic lfs_match_indir(fs, bp) 90251860Sbostic struct lfs *fs; 90352085Sbostic struct buf *bp; 90451215Sbostic { 90551860Sbostic int lbn; 90651860Sbostic 90751860Sbostic lbn = bp->b_lblkno; 90851860Sbostic return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 0); 90951215Sbostic } 91051215Sbostic 91152077Sbostic int 91252077Sbostic lfs_match_dindir(fs, bp) 91351860Sbostic struct lfs *fs; 91452085Sbostic struct buf *bp; 91551215Sbostic { 91651860Sbostic int lbn; 91751860Sbostic 91851860Sbostic lbn = bp->b_lblkno; 91951860Sbostic return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 1); 92051215Sbostic } 92151215Sbostic 92252077Sbostic int 92352077Sbostic lfs_match_tindir(fs, bp) 92451499Sbostic struct lfs *fs; 92552085Sbostic struct buf *bp; 92651342Sbostic { 92751860Sbostic int lbn; 92851342Sbostic 92951860Sbostic lbn = bp->b_lblkno; 93051860Sbostic return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 2); 93151860Sbostic } 93251342Sbostic 93351860Sbostic /* 93451860Sbostic * Allocate a new buffer header. 93551860Sbostic */ 93652085Sbostic struct buf * 93752688Sbostic lfs_newbuf(fs, daddr, size) 93851860Sbostic struct lfs *fs; 93951860Sbostic daddr_t daddr; 94051860Sbostic size_t size; 94151860Sbostic { 94252085Sbostic struct buf *bp; 94351342Sbostic 94451860Sbostic #ifdef VERBOSE 94551860Sbostic printf("lfs_newbuf\n"); 94651860Sbostic #endif 94751860Sbostic bp = getnewbuf(); 94851860Sbostic bremhash(bp); 94951860Sbostic bgetvp(fs->lfs_ivnode, bp); 95051860Sbostic bp->b_bcount = 0; 95151860Sbostic bp->b_lblkno = daddr; 95251860Sbostic bp->b_blkno = daddr; 95351860Sbostic bp->b_error = 0; 95451860Sbostic bp->b_resid = 0; 95552688Sbostic if (size) 95652688Sbostic allocbuf(bp, size); 95751860Sbostic bp->b_flags |= B_NOCACHE; 95852688Sbostic bp->b_saveaddr = NULL; 95951915Sbostic binshash(bp, &bfreelist[BQ_AGE]); 96051860Sbostic return (bp); 96151860Sbostic } 96251342Sbostic 96353347Sbostic void 96451860Sbostic lfs_callback(bp) 96552085Sbostic struct buf *bp; 96651860Sbostic { 96751860Sbostic struct lfs *fs; 96851342Sbostic 96951860Sbostic fs = VFSTOUFS(bp->b_vp->v_mount)->um_lfs; 97051860Sbostic #ifdef DIAGNOSTIC 97151860Sbostic if (fs->lfs_iocount == 0) 97251860Sbostic panic("lfs_callback: zero iocount\n"); 97351860Sbostic #endif 97451860Sbostic if (--fs->lfs_iocount == 0) 97552688Sbostic wakeup(&fs->lfs_iocount); 97651915Sbostic 97752688Sbostic if (bp->b_saveaddr) { 97852688Sbostic free(bp->b_un.b_addr, M_SEGMENT); 97952688Sbostic bp->b_un.b_addr = bp->b_saveaddr; 98052819Sbostic bp->b_saveaddr = NULL; 98152688Sbostic } 98251860Sbostic brelse(bp); 98351860Sbostic } 98451342Sbostic 98551215Sbostic /* 98651188Sbostic * Shellsort (diminishing increment sort) from Data Structures and 98751188Sbostic * Algorithms, Aho, Hopcraft and Ullman, 1983 Edition, page 290; 98851188Sbostic * see also Knuth Vol. 3, page 84. The increments are selected from 98951188Sbostic * formula (8), page 95. Roughly O(N^3/2). 99051188Sbostic */ 99151188Sbostic /* 99251188Sbostic * This is our own private copy of shellsort because we want to sort 99351188Sbostic * two parallel arrays (the array of buffer pointers and the array of 99451188Sbostic * logical block numbers) simultaneously. Note that we cast the array 99551188Sbostic * of logical block numbers to a unsigned in this routine so that the 99651188Sbostic * negative block numbers (meta data blocks) sort AFTER the data blocks. 99751188Sbostic */ 99852077Sbostic void 99952077Sbostic lfs_shellsort(bp_array, lb_array, nmemb) 100052085Sbostic struct buf **bp_array; 100151215Sbostic daddr_t *lb_array; 100251188Sbostic register int nmemb; 100351188Sbostic { 100451188Sbostic static int __rsshell_increments[] = { 4, 1, 0 }; 100551188Sbostic register int incr, *incrp, t1, t2; 100652085Sbostic struct buf *bp_temp; 100751188Sbostic u_long lb_temp; 100851188Sbostic 100951188Sbostic for (incrp = __rsshell_increments; incr = *incrp++;) 101051188Sbostic for (t1 = incr; t1 < nmemb; ++t1) 101151188Sbostic for (t2 = t1 - incr; t2 >= 0;) 101251188Sbostic if (lb_array[t2] > lb_array[t2 + incr]) { 101351188Sbostic lb_temp = lb_array[t2]; 101451188Sbostic lb_array[t2] = lb_array[t2 + incr]; 101551188Sbostic lb_array[t2 + incr] = lb_temp; 101651188Sbostic bp_temp = bp_array[t2]; 101751188Sbostic bp_array[t2] = bp_array[t2 + incr]; 101851188Sbostic bp_array[t2 + incr] = bp_temp; 101951188Sbostic t2 -= incr; 102051188Sbostic } else 102151188Sbostic break; 102251188Sbostic } 1023