151188Sbostic /* 251188Sbostic * Copyright (c) 1991 Regents of the University of California. 351188Sbostic * All rights reserved. 451188Sbostic * 551188Sbostic * %sccs.include.redist.c% 651188Sbostic * 7*51215Sbostic * @(#)lfs_segment.c 5.2 (Berkeley) 10/02/91 851188Sbostic */ 951188Sbostic 10*51215Sbostic #ifdef LOGFS 1151188Sbostic #include "param.h" 1251188Sbostic #include "systm.h" 1351188Sbostic #include "namei.h" 1451188Sbostic #include "resourcevar.h" 1551188Sbostic #include "kernel.h" 1651188Sbostic #include "file.h" 1751188Sbostic #include "stat.h" 1851188Sbostic #include "buf.h" 1951188Sbostic #include "proc.h" 2051188Sbostic #include "conf.h" 2151188Sbostic #include "vnode.h" 2251188Sbostic #include "specdev.h" 2351188Sbostic #include "fifo.h" 2451188Sbostic #include "malloc.h" 2551188Sbostic #include "mount.h" 2651188Sbostic #include "../ufs/lockf.h" 2751188Sbostic #include "../ufs/quota.h" 2851188Sbostic #include "../ufs/inode.h" 2951188Sbostic #include "../ufs/dir.h" 3051188Sbostic #include "../ufs/ufsmount.h" 3151188Sbostic #include "lfs.h" 3251188Sbostic #include "lfs_extern.h" 3351188Sbostic 3451188Sbostic /* 35*51215Sbostic Add a check so that if the segment is empty, you don't write it. 36*51215Sbostic Write the code with lfs_ialloc to allocate a new page of inodes if you have to. 37*51215Sbostic Make an incoming sync wait until the previous one finishes. Keith 38*51215Sbostic will write this. When this happens, we no longer have to be 39*51215Sbostic able to chain superblocks together and handle multiple segments 40*51215Sbostic writing -- Seems like we can call biowait to wait for an io. 41*51215Sbostic However, I don't think we want to wait on the summary I/O 42*51215Sbostic necessarily, because if we've got lots of dirty buffers piling 43*51215Sbostic up, it would be nice to process them and get the segment all 44*51215Sbostic ready to write. Perhaps we can just wait before firing up the 45*51215Sbostic next set of writes, rather than waiting to start doing anything. 46*51215Sbostic Also -- my lfs_writesuper should wait until all the segment writes 47*51215Sbostic are done (I added a biowait, but we need to make sure that the SEGMENT 48*51215Sbostic structure hasn't been freed before we get there). 49*51215Sbostic Need to keep vnode v_numoutput up to date for pending writes? 50*51215Sbostic ???Could actually fire off the datablock writes before you finish. This 51*51215Sbostic would give them a chance to get started earlier... 5251188Sbostic */ 5351188Sbostic 5451188Sbostic static int lfs_biocallback __P((BUF *)); 5551188Sbostic static void lfs_endsum __P((LFS *, SEGMENT *, int)); 56*51215Sbostic static SEGMENT *lfs_gather 57*51215Sbostic __P((LFS *, SEGMENT *, VNODE *, int (*) __P((BUF *)))); 5851188Sbostic static BUF *lfs_newbuf __P((LFS *, daddr_t, size_t)); 5951188Sbostic static SEGMENT *lfs_newseg __P((LFS *)); 6051188Sbostic static void lfs_newsum __P((LFS *, SEGMENT *)); 6151188Sbostic static daddr_t lfs_nextseg __P((LFS *)); 62*51215Sbostic static void lfs_updatemeta __P((LFS *, SEGMENT *, INODE *, daddr_t *, 63*51215Sbostic BUF **, int)); 64*51215Sbostic static void lfs_writeckp __P((LFS *, SEGMENT *)); 65*51215Sbostic static SEGMENT *lfs_writefile __P((SEGMENT *, LFS *, VNODE *, int)); 66*51215Sbostic static SEGMENT *lfs_writeinode __P((LFS *, SEGMENT *, VNODE *)); 6751188Sbostic static void lfs_writeseg __P((LFS *, SEGMENT *)); 68*51215Sbostic static void lfs_writesuper __P((LFS *, SEGMENT *)); 69*51215Sbostic static int match_data __P((BUF *)); 70*51215Sbostic static int match_dindir __P((BUF *)); 71*51215Sbostic static int match_indir __P((BUF *)); 72*51215Sbostic static void shellsort __P((BUF **, daddr_t *, register int)); 7351188Sbostic 7451188Sbostic /* 7551188Sbostic * XXX -- when we add fragments in here, we will need to allocate a larger 7651188Sbostic * buffer pointer array (sp->bpp). 7751188Sbostic */ 7851188Sbostic int 79*51215Sbostic lfs_segwrite(mp, do_ckp) 8051188Sbostic MOUNT *mp; 81*51215Sbostic int do_ckp; /* do a checkpoint too */ 8251188Sbostic { 8351188Sbostic FINFO *fip; /* current file info structure */ 8451188Sbostic INODE *ip; 8551188Sbostic LFS *fs; 8651188Sbostic VNODE *vp; 8751188Sbostic SEGMENT *sp; 8851188Sbostic 8951188Sbostic fs = VFSTOUFS(mp)->um_lfs; 9051188Sbostic sp = lfs_newseg(fs); 9151188Sbostic loop: 9251188Sbostic for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 9351188Sbostic /* 9451188Sbostic * If the vnode that we are about to sync is no longer 9551188Sbostic * associated with this mount point, start over. 9651188Sbostic */ 9751188Sbostic if (vp->v_mount != mp) 9851188Sbostic goto loop; 9951188Sbostic if (VOP_ISLOCKED(vp)) 10051188Sbostic continue; 10151188Sbostic ip = VTOI(vp); 10251188Sbostic if (ip->i_number == LFS_IFILE_INUM) 10351188Sbostic continue; 10451188Sbostic if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0 && 10551188Sbostic vp->v_dirtyblkhd == NULL) 10651188Sbostic continue; 10751188Sbostic if (vget(vp)) 10851188Sbostic goto loop; 109*51215Sbostic sp = lfs_writefile(sp, fs, vp, do_ckp); 11051188Sbostic vput(vp); 11151188Sbostic } 112*51215Sbostic if (do_ckp) 113*51215Sbostic lfs_writeckp(fs, sp); 114*51215Sbostic else 115*51215Sbostic lfs_writeseg(fs, sp); 116*51215Sbostic #ifdef NOTLFS 117*51215Sbostic vflushbuf(ump->um_devvp, waitfor == MNT_WAIT ? B_SYNC : 0); 118*51215Sbostic #endif 11951188Sbostic return (0); 12051188Sbostic } 12151188Sbostic 12251188Sbostic static int 12351188Sbostic lfs_biocallback(bp) 12451188Sbostic BUF *bp; 12551188Sbostic { 12651188Sbostic LFS *fs; 12751188Sbostic SEGMENT *sp, *next_sp; 12851188Sbostic UFSMOUNT *ump; 12951188Sbostic VNODE *devvp; 13051188Sbostic 131*51215Sbostic /* 132*51215Sbostic * Grab the mount point for later (used to find the file system and 133*51215Sbostic * block device) and, if the contents are valid, move the buffer back 134*51215Sbostic * onto the clean list. 135*51215Sbostic */ 136*51215Sbostic printf("lfs_biocallback: buffer %x\n", bp, bp->b_lblkno); 13751188Sbostic ump = VFSTOUFS(bp->b_vp->v_mount); 138*51215Sbostic if (bp->b_flags & B_NOCACHE) 139*51215Sbostic bp->b_vp = NULL; 140*51215Sbostic else { 141*51215Sbostic bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI); 142*51215Sbostic reassignbuf(bp, bp->b_vp); 143*51215Sbostic } 144*51215Sbostic 14551188Sbostic fs = ump->um_lfs; 14651188Sbostic devvp = ump->um_devvp; 147*51215Sbostic brelse(bp); /* move up... XXX */ 148*51215Sbostic 149*51215Sbostic printf("\nlfs_biocallback: iocount %d\n", fs->lfs_iocount); 150*51215Sbostic if (fs->lfs_iocount == 0) { 151*51215Sbostic /* Wake up any other syncs waiting on this file system. */ 152*51215Sbostic return; 153*51215Sbostic } 154*51215Sbostic --fs->lfs_iocount; 155*51215Sbostic if (fs->lfs_iocount == 0) { 156*51215Sbostic printf("\nlfs_biocallback: doing summary write\n"); 15751188Sbostic /* Fire off summary writes */ 15851188Sbostic for (sp = fs->lfs_seglist; sp; sp = next_sp) { 15951188Sbostic next_sp = sp->nextp; 160*51215Sbostic #ifdef MOVETONEWBUF 161*51215Sbostic (*(sp->cbpp - 1))->b_dev = bp->b_dev; 162*51215Sbostic #endif 163*51215Sbostic (devvp->v_op->vop_strategy)(*(sp->cbpp - 1)); 16451188Sbostic free(sp->bpp, M_SEGMENT); 16551188Sbostic free(sp, M_SEGMENT); 16651188Sbostic } 16751188Sbostic } 16851188Sbostic } 16951188Sbostic 17051188Sbostic static void 17151188Sbostic lfs_endsum(fs, sp, calc_next) 17251188Sbostic LFS *fs; 17351188Sbostic SEGMENT *sp; 17451188Sbostic int calc_next; /* if 1, calculate next, else -1 */ 17551188Sbostic { 17651188Sbostic BUF *bp; 17751188Sbostic SEGSUM *ssp; 17851188Sbostic daddr_t next_addr; 179*51215Sbostic int npages, nseg_pages, nsums_per_blk; 18051188Sbostic 181*51215Sbostic /* printf("lfs_endsum\n"); /**/ 182*51215Sbostic if (sp->sbp == NULL) 183*51215Sbostic return; 184*51215Sbostic 18551188Sbostic ssp = sp->segsum; 18651188Sbostic if (!calc_next) 18751188Sbostic ssp->ss_nextsum = (daddr_t) -1; 188*51215Sbostic else 189*51215Sbostic ssp->ss_nextsum = sp->sum_addr - LFS_SUMMARY_SIZE / DEV_BSIZE; 19051188Sbostic 191*51215Sbostic if ((sp->sum_num % (fs->lfs_bsize / LFS_SUMMARY_SIZE)) == (nsums_per_blk - 1)) { 19251188Sbostic /* 193*51215Sbostic * This buffer is now full. Compute the next address if appropriate 194*51215Sbostic * and the checksum, and close the buffer by setting sp->sbp NULL. 19551188Sbostic */ 196*51215Sbostic if (calc_next) { 197*51215Sbostic nsums_per_blk = fs->lfs_bsize / LFS_SUMMARY_SIZE; 198*51215Sbostic nseg_pages = 1 + sp->sum_num / nsums_per_blk; 199*51215Sbostic npages = nseg_pages + (sp->ninodes + INOPB(fs) - 1) / INOPB(fs); 200*51215Sbostic next_addr = fs->lfs_sboffs[0] + 201*51215Sbostic (sp->seg_number + 1) * fsbtodb(fs, fs->lfs_ssize) 202*51215Sbostic - fsbtodb(fs, (npages - 1)) - LFS_SUMMARY_SIZE / DEV_BSIZE; 20351188Sbostic ssp->ss_nextsum = next_addr; 20451188Sbostic } 205*51215Sbostic ssp->ss_cksum = cksum(&ssp->ss_cksum, LFS_SUMMARY_SIZE - sizeof(ssp->ss_cksum)); 206*51215Sbostic sp->sbp = NULL; 207*51215Sbostic } else 20851188Sbostic /* Calculate cksum on previous segment summary */ 20951188Sbostic ssp->ss_cksum = cksum(&ssp->ss_cksum, 21051188Sbostic LFS_SUMMARY_SIZE - sizeof(ssp->ss_cksum)); 211*51215Sbostic } 212*51215Sbostic 213*51215Sbostic static SEGMENT * 214*51215Sbostic lfs_gather(fs, sp, vp, match) 215*51215Sbostic LFS *fs; 216*51215Sbostic SEGMENT *sp; 217*51215Sbostic VNODE *vp; 218*51215Sbostic int (*match) __P((BUF *)); 219*51215Sbostic { 220*51215Sbostic BUF **bpp, *bp, *nbp; 221*51215Sbostic FINFO *fip; 222*51215Sbostic INODE *ip; 223*51215Sbostic int count, s, version; 224*51215Sbostic daddr_t *lbp, *start_lbp; 225*51215Sbostic 226*51215Sbostic ip = VTOI(vp); 227*51215Sbostic bpp = sp->cbpp; 228*51215Sbostic fip = sp->fip; 229*51215Sbostic version = fip->fi_version; 230*51215Sbostic start_lbp = lbp = &fip->fi_blocks[fip->fi_nblocks]; 231*51215Sbostic count = 0; 232*51215Sbostic 233*51215Sbostic s = splbio(); 234*51215Sbostic for (bp = vp->v_dirtyblkhd; bp; bp = nbp) { 235*51215Sbostic nbp = bp->b_blockf; 236*51215Sbostic if ((bp->b_flags & B_BUSY)) 237*51215Sbostic continue; 238*51215Sbostic if ((bp->b_flags & B_DELWRI) == 0) 239*51215Sbostic panic("lfs_write: not dirty"); 240*51215Sbostic if (!match(bp)) 241*51215Sbostic continue; 242*51215Sbostic bremfree(bp); 243*51215Sbostic bp->b_flags |= B_BUSY | B_CALL; 244*51215Sbostic bp->b_dev = VTOI(fs->lfs_ivnode)->i_dev; 245*51215Sbostic bp->b_iodone = lfs_biocallback; 246*51215Sbostic 247*51215Sbostic *lbp++ = bp->b_lblkno; 248*51215Sbostic *sp->cbpp++ = bp; 249*51215Sbostic fip->fi_nblocks++; 250*51215Sbostic sp->sum_bytes_left -= sizeof(daddr_t); 251*51215Sbostic sp->seg_bytes_left -= bp->b_bufsize; 252*51215Sbostic if (sp->sum_bytes_left < sizeof(daddr_t) || 253*51215Sbostic sp->seg_bytes_left < fs->lfs_bsize) { 254*51215Sbostic /* 255*51215Sbostic * We are about to allocate a new summary block 256*51215Sbostic * and possibly a new segment. So, we need to 257*51215Sbostic * sort the blocks we've done so far, and assign 258*51215Sbostic * the disk addresses, so we can start a new block 259*51215Sbostic * correctly. We may be doing I/O so we need to 260*51215Sbostic * release the s lock before doing anything. 261*51215Sbostic */ 262*51215Sbostic splx(s); 263*51215Sbostic lfs_updatemeta(fs, sp, ip, start_lbp, bpp, 264*51215Sbostic lbp - start_lbp); 265*51215Sbostic 266*51215Sbostic /* Put this file in the segment summary */ 267*51215Sbostic ((SEGSUM *)(sp->segsum))->ss_nfinfo++; 268*51215Sbostic 269*51215Sbostic if (sp->seg_bytes_left < fs->lfs_bsize) { 270*51215Sbostic lfs_writeseg(fs, sp); 271*51215Sbostic sp = lfs_newseg(fs); 272*51215Sbostic } else if (sp->sum_bytes_left < sizeof(daddr_t)) 273*51215Sbostic lfs_newsum(fs, sp); 274*51215Sbostic fip = sp->fip; 275*51215Sbostic fip->fi_ino = ip->i_number; 276*51215Sbostic fip->fi_version = version; 277*51215Sbostic bpp = sp->cbpp; 278*51215Sbostic /* You know that you have a new FINFO either way */ 279*51215Sbostic start_lbp = lbp = fip->fi_blocks; 280*51215Sbostic s = splbio(); 281*51215Sbostic } 28251188Sbostic } 283*51215Sbostic splx(s); 284*51215Sbostic lfs_updatemeta(fs, sp, ip, start_lbp, bpp, lbp - start_lbp); 285*51215Sbostic 286*51215Sbostic return(sp); 28751188Sbostic } 28851188Sbostic 289*51215Sbostic 29051188Sbostic static BUF * 29151188Sbostic lfs_newbuf(fs, daddr, size) 29251188Sbostic LFS *fs; 29351188Sbostic daddr_t daddr; 29451188Sbostic size_t size; 29551188Sbostic { 29651188Sbostic BUF *bp; 29751188Sbostic VNODE *devvp; 29851188Sbostic 29951188Sbostic bp = getnewbuf(); 30051188Sbostic bremhash(bp); 30151188Sbostic 30251188Sbostic /* 30351188Sbostic * XXX 30451188Sbostic * Need a devvp, but this isn't a particularly clean way to get one. 305*51215Sbostic * devvp = VTOI(fs->lfs_ivnode)->i_devvp; 30651188Sbostic */ 307*51215Sbostic #ifdef NOTWORKING 308*51215Sbostic devvp = VFSTOUFS(fs->lfs_ivnode->v_mount)->um_devvp; 30951188Sbostic bgetvp(devvp, bp); 310*51215Sbostic #endif 311*51215Sbostic bp->b_vp = fs->lfs_ivnode; 312*51215Sbostic bp->b_dev = VTOI(fs->lfs_ivnode)->i_dev; 31351188Sbostic bp->b_bcount = 0; 314*51215Sbostic bp->b_blkno = bp->b_lblkno = daddr; 31551188Sbostic bp->b_error = 0; 31651188Sbostic bp->b_resid = 0; 317*51215Sbostic bp->b_flags |= B_CALL | B_DELWRI | B_NOCACHE | B_WRITE; 318*51215Sbostic bp->b_iodone = lfs_biocallback; 319*51215Sbostic #ifdef PROBABLYWRONG 32051188Sbostic binshash(bp, BUFHASH(devvp, daddr)); 321*51215Sbostic #endif 32251188Sbostic allocbuf(bp, size); 323*51215Sbostic #ifdef PROBABLYWRONG 324*51215Sbostic reassignbuf(bp, devvp); 325*51215Sbostic #endif 32651188Sbostic return (bp); 32751188Sbostic } 32851188Sbostic 32951188Sbostic 33051188Sbostic /* 33151188Sbostic * Start a new segment 33251188Sbostic */ 33351188Sbostic static SEGMENT * 33451188Sbostic lfs_newseg(fs) 33551188Sbostic LFS *fs; 33651188Sbostic { 33751188Sbostic SEGMENT *sp; 33851188Sbostic SEGUSE *sup; 33951188Sbostic 34051188Sbostic printf("lfs_newseg\n"); 34151188Sbostic /* Get buffer space to write out a segment */ 34251188Sbostic sp = malloc(sizeof(SEGMENT), M_SEGMENT, M_WAITOK); 343*51215Sbostic sp->ibp = NULL; 344*51215Sbostic sp->sbp = NULL; 34551188Sbostic sp->cbpp = sp->bpp = 34651188Sbostic malloc(fs->lfs_ssize * sizeof(BUF *), M_SEGMENT, M_WAITOK); 34751188Sbostic sp->nextp = NULL; 34851188Sbostic sp->sum_bytes_left = LFS_SUMMARY_SIZE; 34951188Sbostic sp->seg_bytes_left = (fs->lfs_segmask + 1) - LFS_SUMMARY_SIZE; 35051188Sbostic sp->saddr = fs->lfs_nextseg; 351*51215Sbostic printf("lfs_newseg: About to write segment %lx\n", sp->saddr); 35251188Sbostic sp->sum_addr = sp->saddr + sp->seg_bytes_left / DEV_BSIZE; 35351188Sbostic sp->ninodes = 0; 35451188Sbostic sp->sum_num = -1; 355*51215Sbostic sp->seg_number = 356*51215Sbostic (sp->saddr - fs->lfs_sboffs[0]) / fsbtodb(fs, fs->lfs_ssize); 35751188Sbostic 35851188Sbostic /* initialize segment summary info */ 35951188Sbostic lfs_newsum(fs, sp); 36051188Sbostic sup = fs->lfs_segtab + sp->seg_number; 36151188Sbostic 36251188Sbostic if (sup->su_nbytes != 0) { 36351188Sbostic /* This is a segment containing a super block */ 36451188Sbostic FINFO *fip; 36551188Sbostic daddr_t lbn, *lbnp; 366*51215Sbostic SEGSUM *ssp; 36751188Sbostic 368*51215Sbostic ssp = (SEGSUM *)sp->segsum; 369*51215Sbostic ssp->ss_nfinfo++; 37051188Sbostic fip = sp->fip; 37151188Sbostic fip->fi_nblocks = LFS_SBPAD >> fs->lfs_bshift; 37251188Sbostic fip->fi_version = 1; 37351188Sbostic fip->fi_ino = LFS_UNUSED_INUM; 37451188Sbostic sp->saddr += fsbtodb(fs, fip->fi_nblocks); 37551188Sbostic lbnp = fip->fi_blocks; 37651188Sbostic for (lbn = 0; lbn < fip->fi_nblocks; lbn++) 37751188Sbostic *lbnp++ = lbn; 37851188Sbostic sp->seg_bytes_left -= sup->su_nbytes; 37951188Sbostic sp->sum_bytes_left -= 38051188Sbostic sizeof(FINFO) + (fip->fi_nblocks - 1) * sizeof(daddr_t); 38151188Sbostic sp->fip = (FINFO *)lbnp; 38251188Sbostic } 38351188Sbostic return(sp); 38451188Sbostic } 38551188Sbostic 38651188Sbostic 38751188Sbostic static void 38851188Sbostic lfs_newsum(fs, sp) 38951188Sbostic LFS *fs; 39051188Sbostic SEGMENT *sp; 39151188Sbostic { 39251188Sbostic SEGSUM *ssp; 393*51215Sbostic int npages, nseg_pages, sums_per_blk; 39451188Sbostic 39551188Sbostic printf("lfs_newsum\n"); 396*51215Sbostic lfs_endsum(fs, sp, 1); 397*51215Sbostic ++sp->sum_num; 398*51215Sbostic if (sp->sbp == NULL) { 399*51215Sbostic /* Allocate a new buffer. */ 400*51215Sbostic if (sp->seg_bytes_left < fs->lfs_bsize) { 401*51215Sbostic lfs_writeseg(fs, sp); 402*51215Sbostic sp = lfs_newseg(fs); 403*51215Sbostic } 404*51215Sbostic sums_per_blk = fs->lfs_bsize / LFS_SUMMARY_SIZE; 405*51215Sbostic nseg_pages = 1 + sp->sum_num / sums_per_blk; 406*51215Sbostic npages = nseg_pages + (sp->ninodes + INOPB(fs) - 1) / INOPB(fs); 407*51215Sbostic sp->sum_addr = fs->lfs_sboffs[0] + 408*51215Sbostic (sp->seg_number + 1) * fsbtodb(fs, fs->lfs_ssize) 409*51215Sbostic - fsbtodb(fs, npages); 410*51215Sbostic sp->sbp = lfs_newbuf(fs, sp->sum_addr, fs->lfs_bsize); 411*51215Sbostic sp->bpp[fs->lfs_ssize - npages] = sp->sbp; 412*51215Sbostic printf("Inserting summary block, address %x at index %d\n", 413*51215Sbostic sp->sbp->b_lblkno, fs->lfs_ssize - npages); 414*51215Sbostic sp->seg_bytes_left -= fs->lfs_bsize; 415*51215Sbostic sp->segsum = sp->sbp->b_un.b_addr + fs->lfs_bsize - LFS_SUMMARY_SIZE; 416*51215Sbostic sp->sum_addr += (fs->lfs_bsize - LFS_SUMMARY_SIZE) / DEV_BSIZE; 41751188Sbostic } else { 418*51215Sbostic sp->segsum -= LFS_SUMMARY_SIZE; 419*51215Sbostic sp->sum_addr -= LFS_SUMMARY_SIZE / DEV_BSIZE; 42051188Sbostic } 42151188Sbostic 422*51215Sbostic ssp = sp->segsum; 423*51215Sbostic ssp->ss_next = fs->lfs_nextseg = lfs_nextseg(fs); 424*51215Sbostic ssp->ss_prev = fs->lfs_lastseg; 425*51215Sbostic 42651188Sbostic /* Initialize segment summary info. */ 42751188Sbostic sp->fip = (FINFO *)(sp->segsum + sizeof(SEGSUM)); 428*51215Sbostic sp->fip->fi_nblocks = 0; 42951188Sbostic ssp->ss_nextsum = (daddr_t)-1; 43051188Sbostic ssp->ss_create = time.tv_sec; 43151188Sbostic 43251188Sbostic ssp->ss_nfinfo = 0; 43351188Sbostic ssp->ss_ninos = 0; 43451188Sbostic sp->sum_bytes_left -= LFS_SUMMARY_SIZE; 43551188Sbostic sp->seg_bytes_left -= LFS_SUMMARY_SIZE; 43651188Sbostic } 43751188Sbostic 43851188Sbostic #define seginc(fs, sn) ((sn + 1) % fs->lfs_nseg) 43951188Sbostic static daddr_t 44051188Sbostic lfs_nextseg(fs) 44151188Sbostic LFS *fs; 44251188Sbostic { 44351188Sbostic int segnum, sn; 44451188Sbostic SEGUSE *sup; 44551188Sbostic 44651188Sbostic segnum = satosn(fs, fs->lfs_nextseg); 447*51215Sbostic for (sn = seginc(fs, segnum); sn != segnum; sn = seginc(fs, sn)) 448*51215Sbostic if (!(fs->lfs_segtab[sn].su_flags & SEGUSE_DIRTY)) 44951188Sbostic break; 450*51215Sbostic 45151188Sbostic if (sn == segnum) 45251188Sbostic panic("lfs_nextseg: file system full"); /* XXX */ 45351188Sbostic return(sntosa(fs, sn)); 45451188Sbostic } 45551188Sbostic 45651188Sbostic /* 45751188Sbostic * Update the metadata that points to the blocks listed in the FIP 45851188Sbostic * array. 45951188Sbostic */ 460*51215Sbostic static void 461*51215Sbostic lfs_updatemeta(fs, sp, ip, lbp, bpp, nblocks) 46251188Sbostic LFS *fs; 463*51215Sbostic SEGMENT *sp; 46451188Sbostic INODE *ip; 465*51215Sbostic daddr_t *lbp; 46651188Sbostic BUF **bpp; 467*51215Sbostic int nblocks; 46851188Sbostic { 46951188Sbostic SEGUSE *segup; 470*51215Sbostic BUF **lbpp, *bp, *mbp; 47151188Sbostic daddr_t da, iblkno; 472*51215Sbostic int db_per_fsb, error, i, oldsegnum; 473*51215Sbostic long lbn; 47451188Sbostic 475*51215Sbostic printf("lfs_updatemeta of %d blocks\n", nblocks); 476*51215Sbostic if ((nblocks == 0) && (ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0) 477*51215Sbostic return; 478*51215Sbostic 479*51215Sbostic /* First sort the blocks and add disk addresses */ 480*51215Sbostic shellsort(bpp, lbp, nblocks); 481*51215Sbostic 482*51215Sbostic db_per_fsb = 1 << fs->lfs_fsbtodb; 483*51215Sbostic for (lbpp = bpp, i = 0; i < nblocks; i++, lbpp++) { 484*51215Sbostic (*lbpp)->b_blkno = sp->saddr; 485*51215Sbostic sp->saddr += db_per_fsb; 486*51215Sbostic } 487*51215Sbostic 488*51215Sbostic for (lbpp = bpp, i = 0; i < nblocks; i++, lbpp++) { 489*51215Sbostic lbn = lbp[i]; 490*51215Sbostic printf("lfs_updatemeta: block %d\n", lbn); 49151188Sbostic if (error = lfs_bmap(ip, lbn, &da)) 492*51215Sbostic panic("lfs_updatemeta: lfs_bmap returned error"); 49351188Sbostic 49451188Sbostic if (da) { 495*51215Sbostic /* Update segment usage information */ 49651188Sbostic oldsegnum = (da - fs->lfs_sboffs[0]) / 49751188Sbostic fsbtodb(fs, fs->lfs_ssize); 49851188Sbostic segup = fs->lfs_segtab+oldsegnum; 49951188Sbostic segup->su_lastmod = time.tv_sec; 50051188Sbostic if ((segup->su_nbytes -= fs->lfs_bsize) < 0) 50151188Sbostic printf("lfs_updatemeta: negative bytes %s %d\n", 50251188Sbostic "in segment", oldsegnum); 50351188Sbostic } 50451188Sbostic 505*51215Sbostic /* 506*51215Sbostic * Now change whoever points to lbn. We could start with the 507*51215Sbostic * smallest (most negative) block number in these if clauses, 508*51215Sbostic * but we assume that indirect blocks are least common, and 509*51215Sbostic * handle them separately. 510*51215Sbostic */ 511*51215Sbostic bp = NULL; 512*51215Sbostic if (lbn < 0) { 513*51215Sbostic if (lbn < -NIADDR) { 514*51215Sbostic printf("lfs_updatemeta: changing indirect block %d\n", D_INDIR); 515*51215Sbostic if (error = bread(ITOV(ip), D_INDIR, 516*51215Sbostic fs->lfs_bsize, NOCRED, &bp)) 517*51215Sbostic panic("lfs_updatemeta: error on bread"); 518*51215Sbostic 519*51215Sbostic bp->b_un.b_daddr[-lbn % NINDIR(fs)] = 520*51215Sbostic (*lbpp)->b_blkno; 521*51215Sbostic } else 522*51215Sbostic ip->i_din.di_ib[-lbn-1] = (*lbpp)->b_blkno; 523*51215Sbostic 524*51215Sbostic } else if (lbn < NDADDR) 52551188Sbostic ip->i_din.di_db[lbn] = (*lbpp)->b_blkno; 52651188Sbostic else if ((lbn -= NDADDR) < NINDIR(fs)) { 52751188Sbostic printf("lfs_updatemeta: changing indirect block %d\n", S_INDIR); 528*51215Sbostic if (error = bread(ITOV(ip), S_INDIR, fs->lfs_bsize, 529*51215Sbostic NOCRED, &bp)) 530*51215Sbostic panic("lfs_updatemeta: bread returned error"); 531*51215Sbostic 53251188Sbostic bp->b_un.b_daddr[lbn] = (*lbpp)->b_blkno; 53351188Sbostic } else if ( (lbn = (lbn - NINDIR(fs)) / NINDIR(fs)) < 53451188Sbostic NINDIR(fs)) { 53551188Sbostic 53651188Sbostic iblkno = - (lbn + NIADDR + 1); 53751188Sbostic printf("lfs_updatemeta: changing indirect block %d\n", iblkno); 538*51215Sbostic if (error = bread(ITOV(ip), iblkno, fs->lfs_bsize, 539*51215Sbostic NOCRED, &bp)) 540*51215Sbostic panic("lfs_updatemeta: bread returned error"); 541*51215Sbostic 54251188Sbostic bp->b_un.b_daddr[lbn % NINDIR(fs)] = (*lbpp)->b_blkno; 54351188Sbostic } 54451188Sbostic else 545*51215Sbostic panic("lfs_updatemeta: logical block number too large"); 546*51215Sbostic if (bp) 547*51215Sbostic lfs_bwrite(bp); 54851188Sbostic } 54951188Sbostic } 55051188Sbostic 551*51215Sbostic static void 552*51215Sbostic lfs_writeckp(fs, sp) 553*51215Sbostic LFS *fs; 554*51215Sbostic SEGMENT *sp; 555*51215Sbostic { 556*51215Sbostic BUF *bp; 557*51215Sbostic FINFO *fip; 558*51215Sbostic INODE *ip; 559*51215Sbostic SEGUSE *sup; 560*51215Sbostic daddr_t *lbp; 561*51215Sbostic int bytes_needed, i; 562*51215Sbostic void *xp; 563*51215Sbostic 564*51215Sbostic printf("lfs_writeckp\n"); 565*51215Sbostic /* 566*51215Sbostic * This will write the dirty ifile blocks, but not the segusage 567*51215Sbostic * table nor the ifile inode. 568*51215Sbostic */ 569*51215Sbostic sp = lfs_writefile(sp, fs, fs->lfs_ivnode, 1); 570*51215Sbostic 571*51215Sbostic /* 572*51215Sbostic * Make sure that the segment usage table and the ifile inode will 573*51215Sbostic * fit in this segment. If they won't, put them in the next segment 574*51215Sbostic */ 575*51215Sbostic bytes_needed = fs->lfs_segtabsz << fs->lfs_bshift; 576*51215Sbostic if (sp->ninodes % INOPB(fs) == 0) 577*51215Sbostic bytes_needed += fs->lfs_bsize; 578*51215Sbostic 579*51215Sbostic if (sp->seg_bytes_left < bytes_needed) { 580*51215Sbostic lfs_writeseg(fs, sp); 581*51215Sbostic sp = lfs_newseg(fs); 582*51215Sbostic } else if (sp->sum_bytes_left < (fs->lfs_segtabsz * sizeof(daddr_t))) 583*51215Sbostic lfs_newsum(fs, sp); 584*51215Sbostic 585*51215Sbostic #ifdef DEBUG 586*51215Sbostic if (sp->seg_bytes_left < bytes_needed) 587*51215Sbostic panic("lfs_writeckp: unable to write checkpoint"); 588*51215Sbostic #endif 589*51215Sbostic 590*51215Sbostic /* 591*51215Sbostic * Now, update the segment usage information and the ifile inode and 592*51215Sbostic * and write it out 593*51215Sbostic */ 594*51215Sbostic 595*51215Sbostic sup = fs->lfs_segtab + sp->seg_number; 596*51215Sbostic sup->su_nbytes = (fs->lfs_segmask + 1) - sp->seg_bytes_left + 597*51215Sbostic bytes_needed; 598*51215Sbostic sup->su_lastmod = time.tv_sec; 599*51215Sbostic sup->su_flags = SEGUSE_DIRTY; 600*51215Sbostic 601*51215Sbostic /* Get buffers for the segusage table and write it out */ 602*51215Sbostic ip = VTOI(fs->lfs_ivnode); 603*51215Sbostic fip = sp->fip; 604*51215Sbostic lbp = &fip->fi_blocks[fip->fi_nblocks]; 605*51215Sbostic for (xp = fs->lfs_segtab, i = 0; i < fs->lfs_segtabsz; 606*51215Sbostic i++, xp += fs->lfs_bsize, lbp++) { 607*51215Sbostic bp = lfs_newbuf(fs, sp->saddr, fs->lfs_bsize); 608*51215Sbostic *sp->cbpp++ = bp; 609*51215Sbostic bcopy(xp, bp->b_un.b_words, fs->lfs_bsize); 610*51215Sbostic ip->i_din.di_db[i] = sp->saddr; 611*51215Sbostic sp->saddr += (1 << fs->lfs_fsbtodb); 612*51215Sbostic *lbp = i; 613*51215Sbostic fip->fi_nblocks++; 614*51215Sbostic } 615*51215Sbostic sp = lfs_writeinode(fs, sp, fs->lfs_ivnode); 616*51215Sbostic lfs_writeseg(fs, sp); 617*51215Sbostic lfs_writesuper(fs, sp); 618*51215Sbostic } 619*51215Sbostic 62051188Sbostic /* 62151188Sbostic * XXX -- I think we need to figure out what to do if we write 62251188Sbostic * the segment and find more dirty blocks when we're done. 62351188Sbostic */ 62451188Sbostic static SEGMENT * 625*51215Sbostic lfs_writefile(sp, fs, vp, do_ckp) 62651188Sbostic SEGMENT *sp; 62751188Sbostic LFS *fs; 62851188Sbostic VNODE *vp; 629*51215Sbostic int do_ckp; 63051188Sbostic { 63151188Sbostic FINFO *fip; 63251188Sbostic INODE *ip; 63351188Sbostic 63451188Sbostic /* initialize the FINFO structure */ 63551188Sbostic ip = VTOI(vp); 63651188Sbostic printf("lfs_writefile: node %d\n", ip->i_number); 63751188Sbostic loop: 638*51215Sbostic sp->fip->fi_nblocks = 0; 639*51215Sbostic sp->fip->fi_ino = ip->i_number; 640*51215Sbostic if (ip->i_number != LFS_IFILE_INUM) 641*51215Sbostic sp->fip->fi_version = lfs_getversion(fs, ip->i_number); 642*51215Sbostic else 643*51215Sbostic sp->fip->fi_version = 1; 64451188Sbostic 645*51215Sbostic sp = lfs_gather(fs, sp, vp, match_data); 646*51215Sbostic if (do_ckp) { 647*51215Sbostic sp = lfs_gather(fs, sp, vp, match_indir); 648*51215Sbostic sp = lfs_gather(fs, sp, vp, match_dindir); 649*51215Sbostic } 65051188Sbostic 651*51215Sbostic (void)printf("lfs_writefile: adding %d blocks to segment\n", 652*51215Sbostic sp->fip->fi_nblocks); 653*51215Sbostic /* 654*51215Sbostic * Update the inode for this file and reflect new inode 655*51215Sbostic * address in the ifile. If this is the ifile, don't update 656*51215Sbostic * the inode, because we're checkpointing and will update the 657*51215Sbostic * inode with the segment usage information (so we musn't 658*51215Sbostic * bump the finfo pointer either). 659*51215Sbostic */ 660*51215Sbostic if (ip->i_number != LFS_IFILE_INUM) { 661*51215Sbostic sp = lfs_writeinode(fs, sp, vp); 662*51215Sbostic fip = sp->fip; 663*51215Sbostic if (fip->fi_nblocks) { 66451188Sbostic ((SEGSUM *)(sp->segsum))->ss_nfinfo++; 665*51215Sbostic sp->fip = (FINFO *)((u_long)fip + sizeof(FINFO) + 666*51215Sbostic sizeof(u_long) * fip->fi_nblocks - 1); 66751188Sbostic } 66851188Sbostic } 66951188Sbostic return(sp); 67051188Sbostic } 67151188Sbostic 672*51215Sbostic static SEGMENT * 673*51215Sbostic lfs_writeinode(fs, sp, vp) 674*51215Sbostic LFS *fs; 675*51215Sbostic SEGMENT *sp; 676*51215Sbostic VNODE *vp; 67751188Sbostic { 678*51215Sbostic BUF *bp; 679*51215Sbostic INODE *ip; 680*51215Sbostic SEGSUM *ssp; 681*51215Sbostic daddr_t iaddr, next_addr; 682*51215Sbostic int npages, nseg_pages, sums_per_blk; 683*51215Sbostic struct dinode *dip; 684*51215Sbostic 685*51215Sbostic printf("lfs_writeinode\n"); 686*51215Sbostic sums_per_blk = fs->lfs_bsize / LFS_SUMMARY_SIZE; 687*51215Sbostic if (sp->ibp == NULL) { 688*51215Sbostic /* Allocate a new buffer. */ 689*51215Sbostic if (sp->seg_bytes_left < fs->lfs_bsize) { 690*51215Sbostic lfs_writeseg(fs, sp); 691*51215Sbostic sp = lfs_newseg(fs); 692*51215Sbostic } 693*51215Sbostic nseg_pages = (sp->sum_num + sums_per_blk) / sums_per_blk; 694*51215Sbostic npages = nseg_pages + (sp->ninodes + INOPB(fs)) / INOPB(fs); 695*51215Sbostic next_addr = fs->lfs_sboffs[0] + 696*51215Sbostic (sp->seg_number + 1) * fsbtodb(fs, fs->lfs_ssize) 697*51215Sbostic - fsbtodb(fs, npages); 698*51215Sbostic sp->ibp = lfs_newbuf(fs, next_addr, fs->lfs_bsize); 699*51215Sbostic sp->ibp->b_flags |= B_BUSY; 700*51215Sbostic sp->bpp[fs->lfs_ssize - npages] = sp->ibp; 701*51215Sbostic sp->seg_bytes_left -= fs->lfs_bsize; 702*51215Sbostic printf("alloc inode block @ daddr %x, bp = %x inserted at %d\n", 703*51215Sbostic next_addr, sp->ibp, fs->lfs_ssize - npages); 704*51215Sbostic } 705*51215Sbostic ip = VTOI(vp); 706*51215Sbostic bp = sp->ibp; 707*51215Sbostic dip = bp->b_un.b_dino + (sp->ninodes % INOPB(fs)); 708*51215Sbostic bcopy(&ip->i_din, dip, sizeof(struct dinode)); 709*51215Sbostic iaddr = bp->b_blkno; 710*51215Sbostic ++sp->ninodes; 711*51215Sbostic ssp = sp->segsum; 712*51215Sbostic ++ssp->ss_ninos; 713*51215Sbostic if (sp->ninodes % INOPB(fs) == 0) 714*51215Sbostic sp->ibp = NULL; 715*51215Sbostic if (ip->i_number == LFS_IFILE_INUM) 716*51215Sbostic fs->lfs_idaddr = iaddr; 717*51215Sbostic else 718*51215Sbostic lfs_iset(ip, iaddr, ip->i_atime); /* Update ifile */ 719*51215Sbostic ip->i_flags &= ~(IMOD|IACC|IUPD|ICHG); /* make inode clean */ 720*51215Sbostic return(sp); 72151188Sbostic } 72251188Sbostic 72351188Sbostic static void 72451188Sbostic lfs_writeseg(fs, sp) 72551188Sbostic LFS *fs; 72651188Sbostic SEGMENT *sp; 72751188Sbostic { 728*51215Sbostic BUF **bpp; 72951188Sbostic SEGSUM *ssp; 73051188Sbostic SEGUSE *sup; 73151188Sbostic VNODE *devvp; 73251188Sbostic int nblocks, nbuffers, ninode_blocks, nsegsums, nsum_pb; 73351188Sbostic int i, metaoff, nmeta; 734*51215Sbostic struct buf **xbp; int xi; 73551188Sbostic 73651188Sbostic printf("lfs_writeseg\n"); 737*51215Sbostic fs->lfs_lastseg = sntosa(fs, sp->seg_number); 738*51215Sbostic lfs_endsum(fs, sp, 0); 73951188Sbostic 740*51215Sbostic #ifdef HELLNO 74151188Sbostic /* Finish off any inodes */ 742*51215Sbostic if (sp->ibp) 743*51215Sbostic brelse(sp->ibp); 744*51215Sbostic #endif 74551188Sbostic 74651188Sbostic /* 74751188Sbostic * Copy inode and summary block buffer pointers down so they are 748*51215Sbostic * contiguous with the page buffer pointers. 74951188Sbostic */ 750*51215Sbostic ssp = sp->segsum; 751*51215Sbostic nsum_pb = fs->lfs_bsize / LFS_SUMMARY_SIZE; 752*51215Sbostic nbuffers = sp->cbpp - sp->bpp; 753*51215Sbostic nsegsums = 1 + sp->sum_num / nsum_pb; 754*51215Sbostic ninode_blocks = (sp->ninodes + INOPB(fs) - 1) / INOPB(fs); 755*51215Sbostic nmeta = ninode_blocks + nsegsums; 75651188Sbostic metaoff = fs->lfs_ssize - nmeta; 757*51215Sbostic nblocks = nbuffers + nmeta; 75851188Sbostic if (sp->bpp + metaoff != sp->cbpp) 759*51215Sbostic bcopy(sp->bpp + metaoff, sp->cbpp, sizeof(BUF *) * nmeta); 760*51215Sbostic sp->cbpp += nmeta; 76151188Sbostic 76251188Sbostic sup = fs->lfs_segtab + sp->seg_number; 76351188Sbostic sup->su_nbytes = nblocks << fs->lfs_bshift; 76451188Sbostic sup->su_lastmod = time.tv_sec; 76551188Sbostic sup->su_flags = SEGUSE_DIRTY; 76651188Sbostic 76751188Sbostic /* 768*51215Sbostic * Since we need to guarantee that the summary block gets written last, 76951188Sbostic * we issue the writes in two sets. The first n-1 buffers first, and 77051188Sbostic * then, after they've completed, the last 1 buffer. Only when that 771*51215Sbostic * final write completes is the segment valid. 77251188Sbostic */ 77351188Sbostic devvp = VFSTOUFS(fs->lfs_ivnode->v_mount)->um_devvp; 774*51215Sbostic /* 775*51215Sbostic * Since no writes are yet scheduled, no need to block here; if we 776*51215Sbostic * scheduled the writes at multiple points, we'd need an splbio() 777*51215Sbostic * here. 778*51215Sbostic */ 779*51215Sbostic fs->lfs_iocount = nblocks - 1; 78051188Sbostic sp->nextp = fs->lfs_seglist; 78151188Sbostic fs->lfs_seglist = sp; 782*51215Sbostic 783*51215Sbostic for (bpp = sp->bpp, i = 0; i < (nblocks - 1); i++, ++bpp) 784*51215Sbostic /* (*(devvp->v_op->vop_strategy)) */ sdstrategy(*bpp); 78551188Sbostic } 78651188Sbostic 787*51215Sbostic static void 788*51215Sbostic lfs_writesuper(fs, sp) 789*51215Sbostic LFS *fs; 790*51215Sbostic SEGMENT *sp; 791*51215Sbostic { 792*51215Sbostic BUF *bp; 793*51215Sbostic VNODE *devvp; 794*51215Sbostic 795*51215Sbostic printf("lfs_writesuper\n"); 796*51215Sbostic /* Wait for segment write to complete */ 797*51215Sbostic /* XXX probably should do this biowait(*(sp->cbpp - 1)); */ 798*51215Sbostic 799*51215Sbostic /* Get a buffer for the super block */ 800*51215Sbostic fs->lfs_cksum = cksum(fs, sizeof(LFS) - sizeof(fs->lfs_cksum)); 801*51215Sbostic bp = lfs_newbuf(fs, fs->lfs_sboffs[0], LFS_SBPAD); 802*51215Sbostic bp->b_flags &= ~B_CALL; 803*51215Sbostic bp->b_vp = NULL; 804*51215Sbostic bp->b_iodone = NULL; 805*51215Sbostic bcopy(fs, bp->b_un.b_lfs, sizeof(LFS)); 806*51215Sbostic 807*51215Sbostic /* Write the first superblock; wait. */ 808*51215Sbostic devvp = VFSTOUFS(fs->lfs_ivnode->v_mount)->um_devvp; 809*51215Sbostic #ifdef MOVETONEWBUF 810*51215Sbostic bp->b_dev = devvp->v_rdev; 811*51215Sbostic #endif 812*51215Sbostic (*devvp->v_op->vop_strategy)(bp); 813*51215Sbostic biowait(bp); 814*51215Sbostic 815*51215Sbostic /* Now, write the second one for which we don't have to wait */ 816*51215Sbostic bp->b_flags &= ~B_DONE; 817*51215Sbostic bp->b_blkno = bp->b_lblkno = fs->lfs_sboffs[1]; 818*51215Sbostic (*devvp->v_op->vop_strategy)(bp); 819*51215Sbostic brelse(bp); 820*51215Sbostic } 821*51215Sbostic 822*51215Sbostic /* Block match routines used when traversing the dirty block chain. */ 823*51215Sbostic match_data(bp) 824*51215Sbostic BUF *bp; 825*51215Sbostic { 826*51215Sbostic return(bp->b_lblkno >= 0); 827*51215Sbostic } 828*51215Sbostic 829*51215Sbostic 830*51215Sbostic match_dindir(bp) 831*51215Sbostic BUF *bp; 832*51215Sbostic { 833*51215Sbostic return(bp->b_lblkno == D_INDIR); 834*51215Sbostic } 835*51215Sbostic 83651188Sbostic /* 837*51215Sbostic * These are single indirect blocks. There are three types: 838*51215Sbostic * the one in the inode (address S_INDIR = -1). 839*51215Sbostic * the ones that hang off of D_INDIR the double indirect in the inode. 840*51215Sbostic * these all have addresses in the range -2NINDIR to -(3NINDIR-1) 841*51215Sbostic * the ones that hang off of double indirect that hang off of the 842*51215Sbostic * triple indirect. These all have addresses < -(NINDIR^2). 843*51215Sbostic * Since we currently don't support, triple indirect blocks, this gets simpler. 844*51215Sbostic * We just need to look for block numbers less than -NIADDR. 845*51215Sbostic */ 846*51215Sbostic match_indir(bp) 847*51215Sbostic BUF *bp; 848*51215Sbostic { 849*51215Sbostic return(bp->b_lblkno == S_INDIR || bp->b_lblkno < -NIADDR); 850*51215Sbostic } 851*51215Sbostic 852*51215Sbostic /* 85351188Sbostic * Shellsort (diminishing increment sort) from Data Structures and 85451188Sbostic * Algorithms, Aho, Hopcraft and Ullman, 1983 Edition, page 290; 85551188Sbostic * see also Knuth Vol. 3, page 84. The increments are selected from 85651188Sbostic * formula (8), page 95. Roughly O(N^3/2). 85751188Sbostic */ 85851188Sbostic /* 85951188Sbostic * This is our own private copy of shellsort because we want to sort 86051188Sbostic * two parallel arrays (the array of buffer pointers and the array of 86151188Sbostic * logical block numbers) simultaneously. Note that we cast the array 86251188Sbostic * of logical block numbers to a unsigned in this routine so that the 86351188Sbostic * negative block numbers (meta data blocks) sort AFTER the data blocks. 86451188Sbostic */ 86551188Sbostic static void 86651188Sbostic shellsort(bp_array, lb_array, nmemb) 86751188Sbostic BUF **bp_array; 868*51215Sbostic daddr_t *lb_array; 86951188Sbostic register int nmemb; 87051188Sbostic { 87151188Sbostic static int __rsshell_increments[] = { 4, 1, 0 }; 87251188Sbostic register int incr, *incrp, t1, t2; 87351188Sbostic BUF *bp_temp; 87451188Sbostic u_long lb_temp; 87551188Sbostic 87651188Sbostic for (incrp = __rsshell_increments; incr = *incrp++;) 87751188Sbostic for (t1 = incr; t1 < nmemb; ++t1) 87851188Sbostic for (t2 = t1 - incr; t2 >= 0;) 87951188Sbostic if (lb_array[t2] > lb_array[t2 + incr]) { 88051188Sbostic lb_temp = lb_array[t2]; 88151188Sbostic lb_array[t2] = lb_array[t2 + incr]; 88251188Sbostic lb_array[t2 + incr] = lb_temp; 88351188Sbostic bp_temp = bp_array[t2]; 88451188Sbostic bp_array[t2] = bp_array[t2 + incr]; 88551188Sbostic bp_array[t2 + incr] = bp_temp; 88651188Sbostic t2 -= incr; 88751188Sbostic } else 88851188Sbostic break; 88951188Sbostic } 890*51215Sbostic #endif /* LOGFS */ 891