151188Sbostic /* 251188Sbostic * Copyright (c) 1991 Regents of the University of California. 351188Sbostic * All rights reserved. 451188Sbostic * 551188Sbostic * %sccs.include.redist.c% 651188Sbostic * 7*55940Sbostic * @(#)lfs_segment.c 7.29 (Berkeley) 08/21/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 35*55940Sbostic #define MAX_ACTIVE 10 3651188Sbostic /* 3751860Sbostic * Determine if it's OK to start a partial in this segment, or if we need 3851860Sbostic * to go on to a new segment. 3951301Sbostic */ 4051860Sbostic #define LFS_PARTIAL_FITS(fs) \ 4151860Sbostic ((fs)->lfs_dbpseg - ((fs)->lfs_offset - (fs)->lfs_curseg) > \ 4251860Sbostic 1 << (fs)->lfs_fsbtodb) 4351188Sbostic 4453347Sbostic void lfs_callback __P((struct buf *)); 4552085Sbostic void lfs_gather __P((struct lfs *, struct segment *, 4652085Sbostic struct vnode *, int (*) __P((struct lfs *, struct buf *)))); 47*55940Sbostic int lfs_gatherblock __P((struct segment *, struct buf *, int *)); 4852085Sbostic void lfs_initseg __P((struct lfs *, struct segment *)); 4952085Sbostic void lfs_iset __P((struct inode *, daddr_t, time_t)); 5052085Sbostic int lfs_match_data __P((struct lfs *, struct buf *)); 5152085Sbostic int lfs_match_dindir __P((struct lfs *, struct buf *)); 5252085Sbostic int lfs_match_indir __P((struct lfs *, struct buf *)); 5352085Sbostic int lfs_match_tindir __P((struct lfs *, struct buf *)); 5452077Sbostic void lfs_newseg __P((struct lfs *)); 5552085Sbostic void lfs_shellsort __P((struct buf **, daddr_t *, register int)); 56*55940Sbostic void lfs_supercallback __P((struct buf *)); 57*55940Sbostic void lfs_updatemeta __P((struct segment *, struct vnode *)); 5852085Sbostic void lfs_writefile __P((struct lfs *, struct segment *, struct vnode *)); 5954264Sbostic int lfs_writeinode __P((struct lfs *, struct segment *, struct inode *)); 6054264Sbostic int lfs_writeseg __P((struct lfs *, struct segment *)); 6152085Sbostic void lfs_writesuper __P((struct lfs *, struct segment *)); 6254264Sbostic void lfs_writevnodes __P((struct lfs *fs, struct mount *mp, 6354264Sbostic struct segment *sp, int dirops)); 6451188Sbostic 6551860Sbostic int lfs_allclean_wakeup; /* Cleaner wakeup address. */ 6651860Sbostic 6752328Sbostic /* 6852328Sbostic * Ifile and meta data blocks are not marked busy, so segment writes MUST be 6952328Sbostic * single threaded. Currently, there are two paths into lfs_segwrite, sync() 7052328Sbostic * and getnewbuf(). They both mark the file system busy. Lfs_vflush() 7152328Sbostic * explicitly marks the file system busy. So lfs_segwrite is safe. I think. 7252328Sbostic */ 7352328Sbostic 7451188Sbostic int 7552328Sbostic lfs_vflush(vp) 7652328Sbostic struct vnode *vp; 7752328Sbostic { 7852328Sbostic struct inode *ip; 7952328Sbostic struct lfs *fs; 8052328Sbostic struct segment *sp; 8152328Sbostic int error, s; 8252328Sbostic 8354690Sbostic fs = VFSTOUFS(vp->v_mount)->um_lfs; 8454690Sbostic lfs_seglock(fs); 8552328Sbostic 8652328Sbostic /* 8752328Sbostic * Allocate a segment structure and enough space to hold pointers to 8852328Sbostic * the maximum possible number of buffers which can be described in a 8952328Sbostic * single summary block. 9052328Sbostic */ 9152328Sbostic sp = malloc(sizeof(struct segment), M_SEGMENT, M_WAITOK); 9252328Sbostic sp->bpp = malloc(((LFS_SUMMARY_SIZE - sizeof(SEGSUM)) / 9352328Sbostic sizeof(daddr_t) + 1) * sizeof(struct buf *), M_SEGMENT, M_WAITOK); 9452328Sbostic sp->seg_flags = SEGM_CKP; 9552328Sbostic 9652328Sbostic /* 9752328Sbostic * Keep a cumulative count of the outstanding I/O operations. If the 9852328Sbostic * disk drive catches up with us it could go to zero before we finish, 9952328Sbostic * so we artificially increment it by one until we've scheduled all of 10052328Sbostic * the writes we intend to do. 10152328Sbostic */ 10252328Sbostic s = splbio(); 10352688Sbostic ++fs->lfs_iocount; 10452328Sbostic splx(s); 10552328Sbostic 10652328Sbostic ip = VTOI(vp); 10755551Sbostic do { 10855803Sbostic lfs_initseg(fs, sp); 10955551Sbostic do { 11055551Sbostic if (vp->v_dirtyblkhd != NULL) 11155551Sbostic lfs_writefile(fs, sp, vp); 11255551Sbostic } while (lfs_writeinode(fs, sp, ip)); 11352328Sbostic 11455551Sbostic } while (lfs_writeseg(fs, sp) && ip->i_number == LFS_IFILE_INUM); 11552328Sbostic 11652328Sbostic /* 11752328Sbostic * If the I/O count is non-zero, sleep until it reaches zero. At the 11852328Sbostic * moment, the user's process hangs around so we can sleep. 11952328Sbostic */ 12052328Sbostic s = splbio(); 12152328Sbostic if (--fs->lfs_iocount && (error = 12252995Sbostic tsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs vflush", 0))) { 12352995Sbostic free(sp->bpp, M_SEGMENT); 12452995Sbostic free(sp, M_SEGMENT); 12552328Sbostic return (error); 12652995Sbostic } 12752328Sbostic splx(s); 12854690Sbostic lfs_segunlock(fs); 12952328Sbostic 13052995Sbostic /* 13152995Sbostic * XXX 13252995Sbostic * Should be writing a checkpoint? 13352995Sbostic */ 13452328Sbostic free(sp->bpp, M_SEGMENT); 13552328Sbostic free(sp, M_SEGMENT); 13652328Sbostic 13752328Sbostic return (0); 13852328Sbostic } 13952328Sbostic 14054264Sbostic void 14154264Sbostic lfs_writevnodes(fs, mp, sp, dirops) 14254264Sbostic struct lfs *fs; 14354264Sbostic struct mount *mp; 14454264Sbostic struct segment *sp; 14554264Sbostic int dirops; 14654264Sbostic { 14754264Sbostic struct inode *ip; 14854264Sbostic struct vnode *vp; 14954264Sbostic int error, s; 15054264Sbostic 15154264Sbostic loop: for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 15254264Sbostic /* 15354264Sbostic * If the vnode that we are about to sync is no longer 15454264Sbostic * associated with this mount point, start over. 15554264Sbostic */ 15654264Sbostic if (vp->v_mount != mp) 15754264Sbostic goto loop; 15854264Sbostic 15954264Sbostic if (dirops && !(vp->v_flag & VDIROP) || 16054264Sbostic !dirops && (vp->v_flag & VDIROP)) 16154264Sbostic continue; 16254264Sbostic /* 16354264Sbostic * XXX 16454264Sbostic * Up the ref count so we don't get tossed out of 16554264Sbostic * memory. 16654264Sbostic */ 16754264Sbostic VREF(vp); 16854264Sbostic 16954264Sbostic /* 17054264Sbostic * Write the inode/file if dirty and it's not the 17154264Sbostic * the IFILE. 17254264Sbostic */ 17354264Sbostic ip = VTOI(vp); 17454264Sbostic if ((ip->i_flag & (IMOD | IACC | IUPD | ICHG) || 17554264Sbostic vp->v_dirtyblkhd != NULL) && 17654264Sbostic ip->i_number != LFS_IFILE_INUM) { 17754264Sbostic if (vp->v_dirtyblkhd != NULL) 17854264Sbostic lfs_writefile(fs, sp, vp); 17954264Sbostic (void) lfs_writeinode(fs, sp, ip); 18054264Sbostic } 18154264Sbostic vp->v_flag &= ~VDIROP; 18254264Sbostic vrele(vp); 18354264Sbostic } 18454264Sbostic } 18554264Sbostic 18652328Sbostic int 18751215Sbostic lfs_segwrite(mp, do_ckp) 18852085Sbostic struct mount *mp; 18951860Sbostic int do_ckp; /* Do a checkpoint. */ 19051188Sbostic { 19155592Sbostic struct buf *bp; 19252085Sbostic struct inode *ip; 19351499Sbostic struct lfs *fs; 19452085Sbostic struct segment *sp; 19552085Sbostic struct vnode *vp; 19655592Sbostic SEGUSE *segusep; 19755592Sbostic daddr_t ibno; 198*55940Sbostic CLEANERINFO *cip; 199*55940Sbostic int clean, error, i, s; 20051188Sbostic 20152328Sbostic fs = VFSTOUFS(mp)->um_lfs; 202*55940Sbostic 203*55940Sbostic /* 204*55940Sbostic * If we have fewer than 2 clean segments, wait until cleaner 205*55940Sbostic * writes. 206*55940Sbostic */ 207*55940Sbostic do { 208*55940Sbostic LFS_CLEANERINFO(cip, fs, bp); 209*55940Sbostic clean = cip->clean; 210*55940Sbostic brelse(bp); 211*55940Sbostic if (clean <= 2) { 212*55940Sbostic printf ("segs clean: %d\n", clean); 213*55940Sbostic wakeup(&lfs_allclean_wakeup); 214*55940Sbostic if (error = tsleep(&fs->lfs_avail, PRIBIO + 1, 215*55940Sbostic "lfs writer", 0)) 216*55940Sbostic return (error); 217*55940Sbostic } 218*55940Sbostic } while (clean <= 2 ); 21954690Sbostic lfs_seglock(fs); 22052085Sbostic 22151860Sbostic /* 22252328Sbostic * Allocate a segment structure and enough space to hold pointers to 22352328Sbostic * the maximum possible number of buffers which can be described in a 22452328Sbostic * single summary block. 22552328Sbostic */ 226*55940Sbostic do_ckp = do_ckp || fs->lfs_nactive > MAX_ACTIVE; 22752328Sbostic sp = malloc(sizeof(struct segment), M_SEGMENT, M_WAITOK); 22852328Sbostic sp->bpp = malloc(((LFS_SUMMARY_SIZE - sizeof(SEGSUM)) / 22952328Sbostic sizeof(daddr_t) + 1) * sizeof(struct buf *), M_SEGMENT, M_WAITOK); 23052328Sbostic sp->seg_flags = do_ckp ? SEGM_CKP : 0; 23152328Sbostic lfs_initseg(fs, sp); 23252328Sbostic 23352328Sbostic /* 23452688Sbostic * Keep a cumulative count of the outstanding I/O operations. If the 23552688Sbostic * disk drive catches up with us it could go to zero before we finish, 23652688Sbostic * so we artificially increment it by one until we've scheduled all of 23752688Sbostic * the writes we intend to do. If not a checkpoint, we never do the 23852688Sbostic * final decrement, avoiding the wakeup in the callback routine. 23951860Sbostic */ 24052688Sbostic s = splbio(); 24155551Sbostic ++fs->lfs_iocount; 24252688Sbostic splx(s); 24351342Sbostic 24454264Sbostic lfs_writevnodes(fs, mp, sp, 0); 24554264Sbostic fs->lfs_writer = 1; 24654264Sbostic if (fs->lfs_dirops && (error = 24754264Sbostic tsleep(&fs->lfs_writer, PRIBIO + 1, "lfs writer", 0))) { 24854264Sbostic free(sp->bpp, M_SEGMENT); 24954264Sbostic free(sp, M_SEGMENT); 25054264Sbostic fs->lfs_writer = 0; 25155551Sbostic return (error); 25254264Sbostic } 25351860Sbostic 25454264Sbostic lfs_writevnodes(fs, mp, sp, 1); 25551860Sbostic 25654264Sbostic /* 25755592Sbostic * If we are doing a checkpoint, mark everything since the 25855592Sbostic * last checkpoint as no longer ACTIVE. 25954264Sbostic */ 26055592Sbostic if (do_ckp) 26155592Sbostic for (ibno = fs->lfs_cleansz + fs->lfs_segtabsz; 26255592Sbostic --ibno >= fs->lfs_cleansz; ) { 26355592Sbostic if (bread(fs->lfs_ivnode, ibno, fs->lfs_bsize, 26455592Sbostic NOCRED, &bp)) 26555592Sbostic 26655592Sbostic panic("lfs: ifile read"); 26755592Sbostic segusep = (SEGUSE *)bp->b_un.b_addr; 26855592Sbostic for (i = fs->lfs_sepb; i--; segusep++) 26955592Sbostic segusep->su_flags &= ~SEGUSE_ACTIVE; 27055592Sbostic 271*55940Sbostic error = VOP_BWRITE(bp); 27255592Sbostic } 27355592Sbostic 27454264Sbostic if (do_ckp || fs->lfs_doifile) { 27554264Sbostic vp = fs->lfs_ivnode; 27654264Sbostic while (vget(vp)); 27752328Sbostic ip = VTOI(vp); 27855592Sbostic if (vp->v_dirtyblkhd != NULL) 27955592Sbostic lfs_writefile(fs, sp, vp); 28055592Sbostic (void)lfs_writeinode(fs, sp, ip); 28152077Sbostic vput(vp); 28255592Sbostic /* 28355592Sbostic * This should never happen because we just guaranteed 28455592Sbostic * that all the segment usage table blocks are dirty, so 28555592Sbostic * no new ones should get written. 28655592Sbostic */ 28755592Sbostic if (lfs_writeseg(fs, sp) && do_ckp) 28855592Sbostic panic("lfs_segwrite: created dirty blocks on ckp"); 28954264Sbostic } else 29054264Sbostic (void) lfs_writeseg(fs, sp); 29151342Sbostic 29251215Sbostic /* 29351860Sbostic * If the I/O count is non-zero, sleep until it reaches zero. At the 29451860Sbostic * moment, the user's process hangs around so we can sleep. 29551215Sbostic */ 29654264Sbostic fs->lfs_writer = 0; 29754264Sbostic fs->lfs_doifile = 0; 29854264Sbostic wakeup(&fs->lfs_dirops); 29954264Sbostic 30055551Sbostic s = splbio(); 30155551Sbostic --fs->lfs_iocount; 30251860Sbostic if (do_ckp) { 30352688Sbostic if (fs->lfs_iocount && (error = 30452995Sbostic tsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs sync", 0))) { 30552995Sbostic free(sp->bpp, M_SEGMENT); 30652995Sbostic free(sp, M_SEGMENT); 30751915Sbostic return (error); 30852995Sbostic } 30951860Sbostic splx(s); 310*55940Sbostic fs->lfs_nactive = 0; 31151860Sbostic lfs_writesuper(fs, sp); 31252688Sbostic } else 31352688Sbostic splx(s); 31451215Sbostic 31554690Sbostic lfs_segunlock(fs); 31654690Sbostic 31751927Sbostic free(sp->bpp, M_SEGMENT); 31851927Sbostic free(sp, M_SEGMENT); 31951215Sbostic 32051860Sbostic return (0); 32151188Sbostic } 32251188Sbostic 32351860Sbostic /* 32451860Sbostic * Write the dirty blocks associated with a vnode. 32551860Sbostic */ 32652077Sbostic void 32751860Sbostic lfs_writefile(fs, sp, vp) 32851499Sbostic struct lfs *fs; 32952085Sbostic struct segment *sp; 33052085Sbostic struct vnode *vp; 33151188Sbostic { 33251860Sbostic struct buf *bp; 33352085Sbostic struct finfo *fip; 33451860Sbostic IFILE *ifp; 33551188Sbostic 33652085Sbostic if (sp->seg_bytes_left < fs->lfs_bsize || 33752085Sbostic sp->sum_bytes_left < sizeof(struct finfo)) { 33854264Sbostic (void) lfs_writeseg(fs, sp); 33952085Sbostic lfs_initseg(fs, sp); 34052085Sbostic } 34152085Sbostic sp->sum_bytes_left -= sizeof(struct finfo) - sizeof(daddr_t); 34251215Sbostic 34352085Sbostic fip = sp->fip; 34452085Sbostic fip->fi_nblocks = 0; 34552085Sbostic fip->fi_ino = VTOI(vp)->i_number; 34652085Sbostic LFS_IENTRY(ifp, fs, fip->fi_ino, bp); 34752085Sbostic fip->fi_version = ifp->if_version; 34852085Sbostic brelse(bp); 34951188Sbostic 35052085Sbostic /* 35152085Sbostic * It may not be necessary to write the meta-data blocks at this point, 35252085Sbostic * as the roll-forward recovery code should be able to reconstruct the 35352085Sbostic * list. 35452085Sbostic */ 35552085Sbostic lfs_gather(fs, sp, vp, lfs_match_data); 35652085Sbostic lfs_gather(fs, sp, vp, lfs_match_indir); 35752085Sbostic lfs_gather(fs, sp, vp, lfs_match_dindir); 35851860Sbostic #ifdef TRIPLE 35952085Sbostic lfs_gather(fs, sp, vp, lfs_match_tindir); 36051860Sbostic #endif 36151342Sbostic 36252085Sbostic fip = sp->fip; 36351860Sbostic #ifdef META 36452085Sbostic printf("lfs_writefile: adding %d blocks\n", fip->fi_nblocks); 36551860Sbostic #endif 36652085Sbostic if (fip->fi_nblocks != 0) { 36752085Sbostic ++((SEGSUM *)(sp->segsum))->ss_nfinfo; 36852085Sbostic sp->fip = 36952085Sbostic (struct finfo *)((caddr_t)fip + sizeof(struct finfo) + 37052085Sbostic sizeof(daddr_t) * (fip->fi_nblocks - 1)); 371*55940Sbostic sp->start_lbp = &sp->fip->fi_blocks[0]; 37252682Sstaelin } else 37352682Sstaelin sp->sum_bytes_left += sizeof(struct finfo) - sizeof(daddr_t); 37451215Sbostic } 37551215Sbostic 37654264Sbostic int 37751915Sbostic lfs_writeinode(fs, sp, ip) 37851915Sbostic struct lfs *fs; 37952085Sbostic struct segment *sp; 38052085Sbostic struct inode *ip; 38151915Sbostic { 38252085Sbostic struct buf *bp, *ibp; 38352077Sbostic IFILE *ifp; 38452682Sstaelin SEGUSE *sup; 38552682Sstaelin daddr_t daddr; 38652077Sbostic ino_t ino; 387*55940Sbostic int error, ndx; 38854264Sbostic int redo_ifile = 0; 38951915Sbostic 390*55940Sbostic if (!(ip->i_flag & (IMOD | IACC | IUPD | ICHG))) 391*55940Sbostic return; 392*55940Sbostic 39351915Sbostic /* Allocate a new inode block if necessary. */ 39451915Sbostic if (sp->ibp == NULL) { 39551915Sbostic /* Allocate a new segment if necessary. */ 39651915Sbostic if (sp->seg_bytes_left < fs->lfs_bsize || 39751915Sbostic sp->sum_bytes_left < sizeof(daddr_t)) { 39854264Sbostic (void) lfs_writeseg(fs, sp); 39951915Sbostic lfs_initseg(fs, sp); 40051915Sbostic } 40151915Sbostic 40251915Sbostic /* Get next inode block. */ 40352682Sstaelin daddr = fs->lfs_offset; 40451915Sbostic fs->lfs_offset += fsbtodb(fs, 1); 40551915Sbostic sp->ibp = *sp->cbpp++ = 406*55940Sbostic lfs_newbuf(fs->lfs_ivnode, daddr, fs->lfs_bsize); 407*55940Sbostic ++sp->start_bpp; 408*55940Sbostic fs->lfs_avail -= fsbtodb(fs, 1); 40952688Sbostic /* Set remaining space counters. */ 41051915Sbostic sp->seg_bytes_left -= fs->lfs_bsize; 41151915Sbostic sp->sum_bytes_left -= sizeof(daddr_t); 41252077Sbostic ndx = LFS_SUMMARY_SIZE / sizeof(daddr_t) - 41351915Sbostic sp->ninodes / INOPB(fs) - 1; 41452682Sstaelin ((daddr_t *)(sp->segsum))[ndx] = daddr; 41551915Sbostic } 41651915Sbostic 41752085Sbostic /* Update the inode times and copy the inode onto the inode page. */ 41852077Sbostic ITIMES(ip, &time, &time); 419*55940Sbostic ip->i_flag &= ~(IMOD | IACC | IUPD | ICHG); 420*55940Sbostic --fs->lfs_uinodes; 42151915Sbostic bp = sp->ibp; 42252085Sbostic bp->b_un.b_dino[sp->ninodes % INOPB(fs)] = ip->i_din; 42351915Sbostic /* Increment inode count in segment summary block. */ 42451915Sbostic ++((SEGSUM *)(sp->segsum))->ss_ninos; 42551915Sbostic 42651915Sbostic /* If this page is full, set flag to allocate a new page. */ 42751915Sbostic if (++sp->ninodes % INOPB(fs) == 0) 42851915Sbostic sp->ibp = NULL; 42951915Sbostic 43051915Sbostic /* 43152077Sbostic * If updating the ifile, update the super-block. Update the disk 43252077Sbostic * address and access times for this inode in the ifile. 43351915Sbostic */ 43452077Sbostic ino = ip->i_number; 43555696Sbostic if (ino == LFS_IFILE_INUM) { 43655696Sbostic daddr = fs->lfs_idaddr; 43751915Sbostic fs->lfs_idaddr = bp->b_blkno; 43855696Sbostic } else { 43955696Sbostic LFS_IENTRY(ifp, fs, ino, ibp); 44055696Sbostic daddr = ifp->if_daddr; 44155696Sbostic ifp->if_daddr = bp->b_blkno; 442*55940Sbostic error = VOP_BWRITE(ibp); 44355696Sbostic } 44452077Sbostic 44554264Sbostic /* 44654264Sbostic * No need to update segment usage if there was no former inode address 44754264Sbostic * or if the last inode address is in the current partial segment. 44854264Sbostic */ 44954264Sbostic if (daddr != LFS_UNUSED_DADDR && 45055803Sbostic !(daddr >= fs->lfs_lastpseg && daddr <= bp->b_blkno)) { 45152682Sstaelin LFS_SEGENTRY(sup, fs, datosn(fs, daddr), bp); 45252682Sstaelin #ifdef DIAGNOSTIC 45354264Sbostic if (sup->su_nbytes < sizeof(struct dinode)) { 45452819Sbostic /* XXX -- Change to a panic. */ 45552819Sbostic printf("lfs: negative bytes (segment %d)\n", 45652682Sstaelin datosn(fs, daddr)); 45754264Sbostic panic("negative bytes"); 45854264Sbostic } 45952682Sstaelin #endif 46052682Sstaelin sup->su_nbytes -= sizeof(struct dinode); 461*55940Sbostic error = VOP_BWRITE(bp); 46255696Sbostic redo_ifile = (ino == LFS_IFILE_INUM && !(bp->b_flags & B_GATHERED)); 46352682Sstaelin } 46455551Sbostic return (redo_ifile); 46551915Sbostic } 46651915Sbostic 467*55940Sbostic int 468*55940Sbostic lfs_gatherblock(sp, bp, sptr) 469*55940Sbostic struct segment *sp; 470*55940Sbostic struct buf *bp; 471*55940Sbostic int *sptr; 472*55940Sbostic { 473*55940Sbostic struct lfs *fs; 474*55940Sbostic int version; 475*55940Sbostic 476*55940Sbostic /* 477*55940Sbostic * If full, finish this segment. We may be doing I/O, so 478*55940Sbostic * release and reacquire the splbio(). 479*55940Sbostic */ 480*55940Sbostic fs = sp->fs; 481*55940Sbostic if (sp->sum_bytes_left < sizeof(daddr_t) || 482*55940Sbostic sp->seg_bytes_left < fs->lfs_bsize) { 483*55940Sbostic if (sptr) 484*55940Sbostic splx(*sptr); 485*55940Sbostic lfs_updatemeta(sp, bp->b_vp); 486*55940Sbostic 487*55940Sbostic /* Add the current file to the segment summary. */ 488*55940Sbostic ++((SEGSUM *)(sp->segsum))->ss_nfinfo; 489*55940Sbostic 490*55940Sbostic version = sp->fip->fi_version; 491*55940Sbostic (void) lfs_writeseg(fs, sp); 492*55940Sbostic lfs_initseg(fs, sp); 493*55940Sbostic 494*55940Sbostic sp->fip->fi_version = version; 495*55940Sbostic sp->fip->fi_ino = VTOI(bp->b_vp)->i_number; 496*55940Sbostic 497*55940Sbostic sp->sum_bytes_left -= 498*55940Sbostic sizeof(struct finfo) - sizeof(daddr_t); 499*55940Sbostic 500*55940Sbostic if (sptr) 501*55940Sbostic *sptr = splbio(); 502*55940Sbostic return(1); 503*55940Sbostic } 504*55940Sbostic 505*55940Sbostic /* Insert into the buffer list, update the FINFO block. */ 506*55940Sbostic bp->b_flags |= B_GATHERED; 507*55940Sbostic *sp->cbpp++ = bp; 508*55940Sbostic sp->fip->fi_blocks[sp->fip->fi_nblocks++] = bp->b_lblkno; 509*55940Sbostic 510*55940Sbostic sp->sum_bytes_left -= sizeof(daddr_t); 511*55940Sbostic sp->seg_bytes_left -= bp->b_bufsize; 512*55940Sbostic return(0); 513*55940Sbostic } 514*55940Sbostic 51552077Sbostic void 51651215Sbostic lfs_gather(fs, sp, vp, match) 51751499Sbostic struct lfs *fs; 51852085Sbostic struct segment *sp; 51952085Sbostic struct vnode *vp; 52052085Sbostic int (*match) __P((struct lfs *, struct buf *)); 52151215Sbostic { 522*55940Sbostic struct buf *bp; 52351342Sbostic int s; 52451215Sbostic 525*55940Sbostic s = splbio(); 526*55940Sbostic loop: for (bp = vp->v_dirtyblkhd; bp; bp = bp->b_blockf) { 52754264Sbostic if (bp->b_flags & B_BUSY || !match(fs, bp) || 52854264Sbostic bp->b_flags & B_GATHERED) 52951215Sbostic continue; 53051342Sbostic #ifdef DIAGNOSTIC 53151860Sbostic if (!(bp->b_flags & B_DELWRI)) 53251915Sbostic panic("lfs_gather: bp not B_DELWRI"); 53351860Sbostic if (!(bp->b_flags & B_LOCKED)) 53451915Sbostic panic("lfs_gather: bp not B_LOCKED"); 53551342Sbostic #endif 536*55940Sbostic if (lfs_gatherblock(sp, bp, &s)) 53753145Sstaelin goto loop; 53851188Sbostic } 53951215Sbostic splx(s); 540*55940Sbostic lfs_updatemeta(sp, vp); 54151188Sbostic } 54251188Sbostic 543*55940Sbostic 54451342Sbostic /* 54551342Sbostic * Update the metadata that points to the blocks listed in the FINFO 54651188Sbostic * array. 54751188Sbostic */ 54852077Sbostic void 549*55940Sbostic lfs_updatemeta(sp, vp) 55052085Sbostic struct segment *sp; 55152085Sbostic struct vnode *vp; 55251188Sbostic { 55351915Sbostic SEGUSE *sup; 55452085Sbostic struct buf *bp; 555*55940Sbostic struct lfs *fs; 55651860Sbostic INDIR a[NIADDR], *ap; 55752085Sbostic struct inode *ip; 55851915Sbostic daddr_t daddr, lbn, off; 559*55940Sbostic int db_per_fsb, error, i, nblocks, num; 56051188Sbostic 561*55940Sbostic nblocks = &sp->fip->fi_blocks[sp->fip->fi_nblocks] - sp->start_lbp; 562*55940Sbostic if (nblocks == 0) 56351215Sbostic return; 56451215Sbostic 56551915Sbostic /* Sort the blocks. */ 566*55940Sbostic if (!(sp->seg_flags & SEGM_CLEAN)) 567*55940Sbostic lfs_shellsort(sp->start_bpp, sp->start_lbp, nblocks); 56851215Sbostic 56951915Sbostic /* 57051915Sbostic * Assign disk addresses, and update references to the logical 57151915Sbostic * block and the segment usage information. 57251915Sbostic */ 573*55940Sbostic fs = sp->fs; 57451860Sbostic db_per_fsb = fsbtodb(fs, 1); 575*55940Sbostic for (i = nblocks; i--; ++sp->start_bpp) { 576*55940Sbostic lbn = *sp->start_lbp++; 577*55940Sbostic (*sp->start_bpp)->b_blkno = off = fs->lfs_offset; 57851860Sbostic fs->lfs_offset += db_per_fsb; 57951215Sbostic 58051860Sbostic if (error = lfs_bmaparray(vp, lbn, &daddr, a, &num)) 58152085Sbostic panic("lfs_updatemeta: lfs_bmaparray %d", error); 58251860Sbostic ip = VTOI(vp); 58351860Sbostic switch (num) { 58451860Sbostic case 0: 58551915Sbostic ip->i_db[lbn] = off; 58651860Sbostic break; 58751860Sbostic case 1: 58851915Sbostic ip->i_ib[a[0].in_off] = off; 58951860Sbostic break; 59051860Sbostic default: 59151860Sbostic ap = &a[num - 1]; 59251860Sbostic if (bread(vp, ap->in_lbn, fs->lfs_bsize, NOCRED, &bp)) 59351860Sbostic panic("lfs_updatemeta: bread bno %d", 59451860Sbostic ap->in_lbn); 59555458Sbostic /* 59655458Sbostic * Bread may create a new indirect block which needs 59755458Sbostic * to get counted for the inode. 59855458Sbostic */ 59955592Sbostic if (bp->b_blkno == -1 && !(bp->b_flags & B_CACHE)) { 600*55940Sbostic printf ("Updatemeta allocating indirect block: shouldn't happen\n"); 60155458Sbostic ip->i_blocks += btodb(fs->lfs_bsize); 60255592Sbostic fs->lfs_bfree -= btodb(fs->lfs_bsize); 60355592Sbostic } 60451915Sbostic bp->b_un.b_daddr[ap->in_off] = off; 60553530Sheideman VOP_BWRITE(bp); 60651188Sbostic } 60751915Sbostic 60851915Sbostic /* Update segment usage information. */ 60951915Sbostic if (daddr != UNASSIGNED) { 61051915Sbostic LFS_SEGENTRY(sup, fs, datosn(fs, daddr), bp); 61151915Sbostic #ifdef DIAGNOSTIC 61254264Sbostic if (sup->su_nbytes < fs->lfs_bsize) { 61352819Sbostic /* XXX -- Change to a panic. */ 61452819Sbostic printf("lfs: negative bytes (segment %d)\n", 61551915Sbostic datosn(fs, daddr)); 61654264Sbostic panic ("Negative Bytes"); 61754264Sbostic } 61851915Sbostic #endif 61951915Sbostic sup->su_nbytes -= fs->lfs_bsize; 620*55940Sbostic error = VOP_BWRITE(bp); 62151915Sbostic } 62251188Sbostic } 62351188Sbostic } 62451188Sbostic 62551915Sbostic /* 62651915Sbostic * Start a new segment. 62751915Sbostic */ 62852077Sbostic void 62951915Sbostic lfs_initseg(fs, sp) 63051499Sbostic struct lfs *fs; 63152085Sbostic struct segment *sp; 63251188Sbostic { 63351915Sbostic SEGUSE *sup; 63451915Sbostic SEGSUM *ssp; 63551915Sbostic struct buf *bp; 63651915Sbostic daddr_t lbn, *lbnp; 63751215Sbostic 63851915Sbostic /* Advance to the next segment. */ 63951927Sbostic if (!LFS_PARTIAL_FITS(fs)) { 64052682Sstaelin /* Wake up any cleaning procs waiting on this file system. */ 64152688Sbostic wakeup(&fs->lfs_nextseg); 64252688Sbostic wakeup(&lfs_allclean_wakeup); 64352682Sstaelin 64451927Sbostic lfs_newseg(fs); 64551927Sbostic fs->lfs_offset = fs->lfs_curseg; 64651915Sbostic sp->seg_number = datosn(fs, fs->lfs_curseg); 64751915Sbostic sp->seg_bytes_left = fs->lfs_dbpseg * DEV_BSIZE; 64851915Sbostic 64951915Sbostic /* 65051927Sbostic * If the segment contains a superblock, update the offset 65151927Sbostic * and summary address to skip over it. 65251915Sbostic */ 65352077Sbostic LFS_SEGENTRY(sup, fs, sp->seg_number, bp); 65451927Sbostic if (sup->su_flags & SEGUSE_SUPERBLOCK) { 65551915Sbostic fs->lfs_offset += LFS_SBPAD / DEV_BSIZE; 65651915Sbostic sp->seg_bytes_left -= LFS_SBPAD; 65751215Sbostic } 65852085Sbostic brelse(bp); 65951915Sbostic } else { 66051915Sbostic sp->seg_number = datosn(fs, fs->lfs_curseg); 66151915Sbostic sp->seg_bytes_left = (fs->lfs_dbpseg - 66251915Sbostic (fs->lfs_offset - fs->lfs_curseg)) * DEV_BSIZE; 66351915Sbostic } 66454264Sbostic fs->lfs_lastpseg = fs->lfs_offset; 66551342Sbostic 666*55940Sbostic sp->fs = fs; 66751915Sbostic sp->ibp = NULL; 66851915Sbostic sp->ninodes = 0; 66951342Sbostic 67051915Sbostic /* Get a new buffer for SEGSUM and enter it into the buffer list. */ 67151915Sbostic sp->cbpp = sp->bpp; 672*55940Sbostic *sp->cbpp = 673*55940Sbostic lfs_newbuf(fs->lfs_ivnode, fs->lfs_offset, LFS_SUMMARY_SIZE); 67451915Sbostic sp->segsum = (*sp->cbpp)->b_un.b_addr; 675*55940Sbostic sp->start_bpp = ++sp->cbpp; 67651915Sbostic fs->lfs_offset += LFS_SUMMARY_SIZE / DEV_BSIZE; 67751342Sbostic 67851915Sbostic /* Set point to SEGSUM, initialize it. */ 67951915Sbostic ssp = sp->segsum; 68051915Sbostic ssp->ss_next = fs->lfs_nextseg; 68151915Sbostic ssp->ss_nfinfo = ssp->ss_ninos = 0; 68251342Sbostic 68351915Sbostic /* Set pointer to first FINFO, initialize it. */ 68452085Sbostic sp->fip = (struct finfo *)(sp->segsum + sizeof(SEGSUM)); 68551915Sbostic sp->fip->fi_nblocks = 0; 686*55940Sbostic sp->start_lbp = &sp->fip->fi_blocks[0]; 68751342Sbostic 68851915Sbostic sp->seg_bytes_left -= LFS_SUMMARY_SIZE; 68951915Sbostic sp->sum_bytes_left = LFS_SUMMARY_SIZE - sizeof(SEGSUM); 69051915Sbostic } 69151342Sbostic 69251915Sbostic /* 69351915Sbostic * Return the next segment to write. 69451915Sbostic */ 69552077Sbostic void 69651915Sbostic lfs_newseg(fs) 69751915Sbostic struct lfs *fs; 69851915Sbostic { 69951927Sbostic CLEANERINFO *cip; 70051915Sbostic SEGUSE *sup; 70151915Sbostic struct buf *bp; 702*55940Sbostic int curseg, error, isdirty, sn; 70351915Sbostic 70455592Sbostic LFS_SEGENTRY(sup, fs, datosn(fs, fs->lfs_nextseg), bp); 70555592Sbostic sup->su_flags |= SEGUSE_DIRTY; 706*55940Sbostic (void) VOP_BWRITE(bp); 70751927Sbostic 70851927Sbostic LFS_CLEANERINFO(cip, fs, bp); 70951927Sbostic --cip->clean; 71051927Sbostic ++cip->dirty; 711*55940Sbostic (void) VOP_BWRITE(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 } 72555592Sbostic 726*55940Sbostic ++fs->lfs_nactive; 72751927Sbostic fs->lfs_nextseg = sntoda(fs, sn); 72851188Sbostic } 72951188Sbostic 73054264Sbostic int 73151188Sbostic lfs_writeseg(fs, sp) 73251499Sbostic struct lfs *fs; 73352085Sbostic struct segment *sp; 73451188Sbostic { 735*55940Sbostic extern int locked_queue_count; 73652688Sbostic struct buf **bpp, *bp, *cbp; 73751188Sbostic SEGUSE *sup; 73852085Sbostic SEGSUM *ssp; 73951860Sbostic dev_t i_dev; 74054264Sbostic size_t size; 74151860Sbostic u_long *datap, *dp; 742*55940Sbostic int ch_per_blk, do_again, error, i, nblocks, num, s; 74354264Sbostic int (*strategy)__P((struct vop_strategy_args *)); 74454690Sbostic struct vop_strategy_args vop_strategy_a; 74555592Sbostic u_short ninos; 74652688Sbostic char *p; 74751188Sbostic 748*55940Sbostic /* 749*55940Sbostic * If there are no buffers other than the segment summary to write 750*55940Sbostic * and it is not a checkpoint, don't do anything. On a checkpoint, 751*55940Sbostic * even if there aren't any buffers, you need to write the superblock. 752*55940Sbostic */ 753*55940Sbostic if ((nblocks = sp->cbpp - sp->bpp) == 1 && !(sp->seg_flags & SEGM_CKP)) 75455551Sbostic return (0); 75552085Sbostic 75651188Sbostic /* 75752085Sbostic * Compute checksum across data and then across summary; the first 75852085Sbostic * block (the summary block) is skipped. Set the create time here 75952085Sbostic * so that it's guaranteed to be later than the inode mod times. 76051860Sbostic * 76151860Sbostic * XXX 76251860Sbostic * Fix this to do it inline, instead of malloc/copy. 76351188Sbostic */ 76451860Sbostic datap = dp = malloc(nblocks * sizeof(u_long), M_SEGMENT, M_WAITOK); 76551915Sbostic for (bpp = sp->bpp, i = nblocks - 1; i--;) 76651915Sbostic *dp++ = (*++bpp)->b_un.b_words[0]; 76752085Sbostic ssp = (SEGSUM *)sp->segsum; 76852103Sbostic ssp->ss_create = time.tv_sec; 76955803Sbostic ssp->ss_datasum = cksum(datap, (nblocks - 1) * sizeof(u_long)); 77052085Sbostic ssp->ss_sumsum = 77152085Sbostic cksum(&ssp->ss_datasum, LFS_SUMMARY_SIZE - sizeof(ssp->ss_sumsum)); 77251927Sbostic free(datap, M_SEGMENT); 77351188Sbostic 77454264Sbostic /* Update the segment usage information. */ 77554264Sbostic LFS_SEGENTRY(sup, fs, sp->seg_number, bp); 77655592Sbostic ninos = (ssp->ss_ninos + INOPB(fs) - 1) / INOPB(fs); 77755592Sbostic sup->su_nbytes += nblocks - 1 - ninos << fs->lfs_bshift; 77854264Sbostic sup->su_nbytes += ssp->ss_ninos * sizeof(struct dinode); 77955803Sbostic sup->su_nbytes += LFS_SUMMARY_SIZE; 78054264Sbostic sup->su_lastmod = time.tv_sec; 78155592Sbostic sup->su_flags |= SEGUSE_ACTIVE; 78255592Sbostic sup->su_ninos += ninos; 78355592Sbostic ++sup->su_nsums; 784*55940Sbostic (void)VOP_BWRITE(bp); 78555592Sbostic fs->lfs_bfree -= (fsbtodb(fs, ninos) + LFS_SUMMARY_SIZE / DEV_BSIZE); 78654264Sbostic do_again = !(bp->b_flags & B_GATHERED); 78754264Sbostic 78851860Sbostic i_dev = VTOI(fs->lfs_ivnode)->i_dev; 78953574Sheideman strategy = VTOI(fs->lfs_ivnode)->i_devvp->v_op[VOFFSET(vop_strategy)]; 79051301Sbostic 79152688Sbostic /* 79252688Sbostic * When we simply write the blocks we lose a rotation for every block 79352688Sbostic * written. To avoid this problem, we allocate memory in chunks, copy 79452688Sbostic * the buffers into the chunk and write the chunk. 56K was chosen as 79552688Sbostic * some driver/controllers can't handle unsigned 16 bit transfers. 79652688Sbostic * When the data is copied to the chunk, turn off the the B_LOCKED bit 79752688Sbostic * and brelse the buffer (which will move them to the LRU list). Add 79852688Sbostic * the B_CALL flag to the buffer header so we can count I/O's for the 79952688Sbostic * checkpoints and so we can release the allocated memory. 80052688Sbostic * 80152688Sbostic * XXX 80252688Sbostic * This should be removed if the new virtual memory system allows us to 80352688Sbostic * easily make the buffers contiguous in kernel memory and if that's 80452688Sbostic * fast enough. 80552688Sbostic */ 80652688Sbostic #define LFS_CHUNKSIZE (56 * 1024) 80752688Sbostic ch_per_blk = LFS_CHUNKSIZE / fs->lfs_bsize; 80852688Sbostic for (bpp = sp->bpp, i = nblocks; i;) { 80952688Sbostic num = ch_per_blk; 81052688Sbostic if (num > i) 81152688Sbostic num = i; 81252688Sbostic i -= num; 81352688Sbostic size = num * fs->lfs_bsize; 81452688Sbostic 815*55940Sbostic cbp = lfs_newbuf(fs->lfs_ivnode, (*bpp)->b_blkno, size); 81652688Sbostic cbp->b_dev = i_dev; 817*55940Sbostic cbp->b_flags |= B_ASYNC | B_BUSY; 81852688Sbostic 81952688Sbostic s = splbio(); 82052688Sbostic ++fs->lfs_iocount; 82152688Sbostic for (p = cbp->b_un.b_addr; num--;) { 82252688Sbostic bp = *bpp++; 823*55940Sbostic /* 824*55940Sbostic * Fake buffers from the cleaner are marked as B_INVAL. 825*55940Sbostic * We need to copy the data from user space rather than 826*55940Sbostic * from the buffer indicated. 827*55940Sbostic * XXX == what do I do on an error? 828*55940Sbostic */ 829*55940Sbostic if (bp->b_flags & B_INVAL) { 830*55940Sbostic if (copyin(bp->b_saveaddr, p, bp->b_bcount)) 831*55940Sbostic panic("lfs_writeseg: copyin failed"); 832*55940Sbostic } else 833*55940Sbostic bcopy(bp->b_un.b_addr, p, bp->b_bcount); 83452688Sbostic p += bp->b_bcount; 835*55940Sbostic if (bp->b_flags & B_LOCKED) 836*55940Sbostic --locked_queue_count; 837*55940Sbostic bp->b_flags &= ~(B_ERROR | B_READ | B_DELWRI | 83854264Sbostic B_LOCKED | B_GATHERED); 839*55940Sbostic if (bp->b_flags & B_CALL) { 840*55940Sbostic /* if B_CALL, it was created with newbuf */ 841*55940Sbostic brelvp(bp); 842*55940Sbostic free(bp, M_SEGMENT); 843*55940Sbostic } else { 84452688Sbostic bremfree(bp); 84552688Sbostic reassignbuf(bp, bp->b_vp); 846*55940Sbostic brelse(bp); 84752688Sbostic } 84851860Sbostic } 84952688Sbostic splx(s); 85052688Sbostic cbp->b_bcount = p - cbp->b_un.b_addr; 85153574Sheideman vop_strategy_a.a_desc = VDESC(vop_strategy); 85253574Sheideman vop_strategy_a.a_bp = cbp; 85353574Sheideman (strategy)(&vop_strategy_a); 85451860Sbostic } 85555551Sbostic return (do_again); 85651188Sbostic } 85751188Sbostic 85852077Sbostic void 85951860Sbostic lfs_writesuper(fs, sp) 86051499Sbostic struct lfs *fs; 86152085Sbostic struct segment *sp; 86251301Sbostic { 86352085Sbostic struct buf *bp; 86451860Sbostic dev_t i_dev; 86553574Sheideman int (*strategy) __P((struct vop_strategy_args *)); 86654690Sbostic struct vop_strategy_args vop_strategy_a; 86751301Sbostic 86851860Sbostic i_dev = VTOI(fs->lfs_ivnode)->i_dev; 86953574Sheideman strategy = VTOI(fs->lfs_ivnode)->i_devvp->v_op[VOFFSET(vop_strategy)]; 87051356Sbostic 87151342Sbostic /* Checksum the superblock and copy it into a buffer. */ 87251499Sbostic fs->lfs_cksum = cksum(fs, sizeof(struct lfs) - sizeof(fs->lfs_cksum)); 873*55940Sbostic bp = lfs_newbuf(fs->lfs_ivnode, fs->lfs_sboffs[0], LFS_SBPAD); 87451860Sbostic *bp->b_un.b_lfs = *fs; 87551215Sbostic 87651356Sbostic /* Write the first superblock (wait). */ 87751860Sbostic bp->b_dev = i_dev; 87851915Sbostic bp->b_flags |= B_BUSY; 879*55940Sbostic bp->b_flags &= ~(B_DONE | B_CALL | B_ERROR | B_READ | B_DELWRI); 88053574Sheideman vop_strategy_a.a_desc = VDESC(vop_strategy); 88153574Sheideman vop_strategy_a.a_bp = bp; 88253574Sheideman (strategy)(&vop_strategy_a); 88351215Sbostic biowait(bp); 88451342Sbostic 88551356Sbostic /* Write the second superblock (don't wait). */ 88651215Sbostic bp->b_blkno = bp->b_lblkno = fs->lfs_sboffs[1]; 887*55940Sbostic bp->b_flags |= B_CALL | B_ASYNC | B_BUSY; 88851860Sbostic bp->b_flags &= ~(B_DONE | B_ERROR | B_READ | B_DELWRI); 889*55940Sbostic bp->b_iodone = lfs_supercallback; 89053574Sheideman (strategy)(&vop_strategy_a); 89151215Sbostic } 89251215Sbostic 89351342Sbostic /* 89451342Sbostic * Logical block number match routines used when traversing the dirty block 89551342Sbostic * chain. 89651342Sbostic */ 89752077Sbostic int 89852077Sbostic lfs_match_data(fs, bp) 89951860Sbostic struct lfs *fs; 90052085Sbostic struct buf *bp; 90151215Sbostic { 90251342Sbostic return (bp->b_lblkno >= 0); 90351215Sbostic } 90451215Sbostic 90552077Sbostic int 90652077Sbostic lfs_match_indir(fs, bp) 90751860Sbostic struct lfs *fs; 90852085Sbostic struct buf *bp; 90951215Sbostic { 91051860Sbostic int lbn; 91151860Sbostic 91251860Sbostic lbn = bp->b_lblkno; 91351860Sbostic return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 0); 91451215Sbostic } 91551215Sbostic 91652077Sbostic int 91752077Sbostic lfs_match_dindir(fs, bp) 91851860Sbostic struct lfs *fs; 91952085Sbostic struct buf *bp; 92051215Sbostic { 92151860Sbostic int lbn; 92251860Sbostic 92351860Sbostic lbn = bp->b_lblkno; 92451860Sbostic return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 1); 92551215Sbostic } 92651215Sbostic 92752077Sbostic int 92852077Sbostic lfs_match_tindir(fs, bp) 92951499Sbostic struct lfs *fs; 93052085Sbostic struct buf *bp; 93151342Sbostic { 93251860Sbostic int lbn; 93351342Sbostic 93451860Sbostic lbn = bp->b_lblkno; 93551860Sbostic return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 2); 93651860Sbostic } 93751342Sbostic 93851860Sbostic /* 93951860Sbostic * Allocate a new buffer header. 94051860Sbostic */ 94152085Sbostic struct buf * 942*55940Sbostic lfs_newbuf(vp, daddr, size) 943*55940Sbostic struct vnode *vp; 94451860Sbostic daddr_t daddr; 94551860Sbostic size_t size; 94651860Sbostic { 94752085Sbostic struct buf *bp; 948*55940Sbostic size_t nbytes; 94951342Sbostic 950*55940Sbostic nbytes = roundup(size, DEV_BSIZE); 951*55940Sbostic bp = malloc(sizeof(struct buf) + nbytes, M_SEGMENT, M_WAITOK); 952*55940Sbostic bzero(bp, sizeof(struct buf)); 953*55940Sbostic bgetvp(vp, bp); 954*55940Sbostic bp->b_un.b_addr = (caddr_t)(bp + 1); 955*55940Sbostic bp->b_bufsize = size; 956*55940Sbostic bp->b_bcount = size; 95751860Sbostic bp->b_lblkno = daddr; 95851860Sbostic bp->b_blkno = daddr; 95951860Sbostic bp->b_error = 0; 96051860Sbostic bp->b_resid = 0; 961*55940Sbostic bp->b_iodone = lfs_callback; 962*55940Sbostic bp->b_flags |= B_CALL | B_NOCACHE; 96351860Sbostic return (bp); 96451860Sbostic } 96551342Sbostic 96653347Sbostic void 96751860Sbostic lfs_callback(bp) 96852085Sbostic struct buf *bp; 96951860Sbostic { 97051860Sbostic struct lfs *fs; 97151342Sbostic 97251860Sbostic fs = VFSTOUFS(bp->b_vp->v_mount)->um_lfs; 97351860Sbostic #ifdef DIAGNOSTIC 97451860Sbostic if (fs->lfs_iocount == 0) 97551860Sbostic panic("lfs_callback: zero iocount\n"); 97651860Sbostic #endif 97751860Sbostic if (--fs->lfs_iocount == 0) 97852688Sbostic wakeup(&fs->lfs_iocount); 97951915Sbostic 980*55940Sbostic brelvp(bp); 981*55940Sbostic free(bp, M_SEGMENT); 98251860Sbostic } 98351342Sbostic 984*55940Sbostic void 985*55940Sbostic lfs_supercallback(bp) 986*55940Sbostic struct buf *bp; 987*55940Sbostic { 988*55940Sbostic brelvp(bp); 989*55940Sbostic free(bp, M_SEGMENT); 990*55940Sbostic } 991*55940Sbostic 99251215Sbostic /* 99351188Sbostic * Shellsort (diminishing increment sort) from Data Structures and 99451188Sbostic * Algorithms, Aho, Hopcraft and Ullman, 1983 Edition, page 290; 99551188Sbostic * see also Knuth Vol. 3, page 84. The increments are selected from 99651188Sbostic * formula (8), page 95. Roughly O(N^3/2). 99751188Sbostic */ 99851188Sbostic /* 99951188Sbostic * This is our own private copy of shellsort because we want to sort 100051188Sbostic * two parallel arrays (the array of buffer pointers and the array of 100151188Sbostic * logical block numbers) simultaneously. Note that we cast the array 100251188Sbostic * of logical block numbers to a unsigned in this routine so that the 100351188Sbostic * negative block numbers (meta data blocks) sort AFTER the data blocks. 100451188Sbostic */ 100552077Sbostic void 100652077Sbostic lfs_shellsort(bp_array, lb_array, nmemb) 100752085Sbostic struct buf **bp_array; 100851215Sbostic daddr_t *lb_array; 100951188Sbostic register int nmemb; 101051188Sbostic { 101151188Sbostic static int __rsshell_increments[] = { 4, 1, 0 }; 101251188Sbostic register int incr, *incrp, t1, t2; 101352085Sbostic struct buf *bp_temp; 101451188Sbostic u_long lb_temp; 101551188Sbostic 101651188Sbostic for (incrp = __rsshell_increments; incr = *incrp++;) 101751188Sbostic for (t1 = incr; t1 < nmemb; ++t1) 101851188Sbostic for (t2 = t1 - incr; t2 >= 0;) 101951188Sbostic if (lb_array[t2] > lb_array[t2 + incr]) { 102051188Sbostic lb_temp = lb_array[t2]; 102151188Sbostic lb_array[t2] = lb_array[t2 + incr]; 102251188Sbostic lb_array[t2 + incr] = lb_temp; 102351188Sbostic bp_temp = bp_array[t2]; 102451188Sbostic bp_array[t2] = bp_array[t2 + incr]; 102551188Sbostic bp_array[t2 + incr] = bp_temp; 102651188Sbostic t2 -= incr; 102751188Sbostic } else 102851188Sbostic break; 102951188Sbostic } 1030*55940Sbostic 1031