151188Sbostic /* 251188Sbostic * Copyright (c) 1991 Regents of the University of California. 351188Sbostic * All rights reserved. 451188Sbostic * 551188Sbostic * %sccs.include.redist.c% 651188Sbostic * 7*51342Sbostic * @(#)lfs_segment.c 5.4 (Berkeley) 10/09/91 851188Sbostic */ 951188Sbostic 1051215Sbostic #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 /* 3551301Sbostic * Add a check so that if the segment is empty, you don't write it. 3651301Sbostic * 3751301Sbostic * Change lfs_ialloc to allocate a new page of inodes if you have to. 3851301Sbostic * 3951301Sbostic * Need to keep vnode v_numoutput up to date for pending writes? Could 4051301Sbostic * actually fire off the datablock writes before you finish. This would give 4151301Sbostic * them a chance to get started earlier. 4251301Sbostic */ 4351188Sbostic 4451188Sbostic static int lfs_biocallback __P((BUF *)); 4551188Sbostic static void lfs_endsum __P((LFS *, SEGMENT *, int)); 4651215Sbostic static SEGMENT *lfs_gather 4751215Sbostic __P((LFS *, SEGMENT *, VNODE *, int (*) __P((BUF *)))); 4851188Sbostic static BUF *lfs_newbuf __P((LFS *, daddr_t, size_t)); 4951188Sbostic static SEGMENT *lfs_newseg __P((LFS *)); 50*51342Sbostic static SEGMENT *lfs_newsum __P((LFS *, SEGMENT *)); 5151188Sbostic static daddr_t lfs_nextseg __P((LFS *)); 52*51342Sbostic static void lfs_updatemeta __P((LFS *, SEGMENT *, INODE *, daddr_t *, 5351215Sbostic BUF **, int)); 5451301Sbostic static SEGMENT *lfs_writeckp __P((LFS *, SEGMENT *)); 55*51342Sbostic static SEGMENT *lfs_writefile __P((LFS *, SEGMENT *, VNODE *, int)); 56*51342Sbostic static SEGMENT *lfs_writeinode __P((LFS *, SEGMENT *, INODE *)); 5751188Sbostic static void lfs_writeseg __P((LFS *, SEGMENT *)); 5851301Sbostic static void lfs_writesum __P((LFS *)); 59*51342Sbostic static void lfs_writesuper __P((LFS *)); 6051215Sbostic static int match_data __P((BUF *)); 6151215Sbostic static int match_dindir __P((BUF *)); 6251215Sbostic static int match_indir __P((BUF *)); 63*51342Sbostic static daddr_t next __P((LFS *, SEGMENT *, int *)); 6451215Sbostic static void shellsort __P((BUF **, daddr_t *, register int)); 6551188Sbostic 6651188Sbostic /* 6751188Sbostic * XXX -- when we add fragments in here, we will need to allocate a larger 6851188Sbostic * buffer pointer array (sp->bpp). 6951188Sbostic */ 7051188Sbostic int 7151215Sbostic lfs_segwrite(mp, do_ckp) 7251188Sbostic MOUNT *mp; 7351215Sbostic int do_ckp; /* do a checkpoint too */ 7451188Sbostic { 7551188Sbostic INODE *ip; 7651188Sbostic LFS *fs; 7751188Sbostic VNODE *vp; 7851188Sbostic SEGMENT *sp; 7951301Sbostic int s; 8051188Sbostic 8151188Sbostic fs = VFSTOUFS(mp)->um_lfs; 82*51342Sbostic 83*51342Sbostic #ifdef DIAGNOSTIC 84*51342Sbostic if (fs->lfs_seglist != NULL) 85*51342Sbostic panic("lfs_segwrite: seglist not NULL"); 86*51342Sbostic #endif 87*51342Sbostic 8851301Sbostic /* 8951301Sbostic * LFS requires that the summary blocks be written after the rest of 9051301Sbostic * the segment, and that the super blocks (on checkpoint) be written 9151301Sbostic * last of all. We keep a cumulative count of the outstanding blocks 9251301Sbostic * from all of the segments, and write these blocks when this count 9351301Sbostic * goes to zero. If the disk drive catches up with us it could go 9451301Sbostic * to zero before we finish, so we artificially increment it by one 9551301Sbostic * until we've scheduled all of the writes we intend to do. At the 9651301Sbostic * moment, the user's process hangs around so we can sleep; this should 9751301Sbostic * probably be redone using a kernel thread. 9851301Sbostic */ 9951301Sbostic s = splbio(); 10051301Sbostic fs->lfs_iocount = 1; 10151301Sbostic splx(s); 102*51342Sbostic 10351188Sbostic sp = lfs_newseg(fs); 10451188Sbostic loop: 10551188Sbostic for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 10651188Sbostic /* 10751188Sbostic * If the vnode that we are about to sync is no longer 10851188Sbostic * associated with this mount point, start over. 10951188Sbostic */ 11051188Sbostic if (vp->v_mount != mp) 11151188Sbostic goto loop; 11251188Sbostic if (VOP_ISLOCKED(vp)) 11351188Sbostic continue; 11451188Sbostic ip = VTOI(vp); 11551188Sbostic if (ip->i_number == LFS_IFILE_INUM) 11651188Sbostic continue; 117*51342Sbostic if ((ip->i_flag & (IMOD | IACC | IUPD | ICHG)) == 0 && 11851188Sbostic vp->v_dirtyblkhd == NULL) 11951188Sbostic continue; 12051188Sbostic if (vget(vp)) 12151188Sbostic goto loop; 122*51342Sbostic sp = lfs_writefile(fs, sp, vp, do_ckp); 12351188Sbostic vput(vp); 12451188Sbostic } 12551215Sbostic if (do_ckp) 12651301Sbostic sp = lfs_writeckp(fs, sp); 127*51342Sbostic lfs_writeseg(fs, sp); 128*51342Sbostic 12951301Sbostic s = splbio(); 13051301Sbostic if (--fs->lfs_iocount) 13151301Sbostic sleep(&fs->lfs_iocount, PRIBIO + 1); 13251301Sbostic splx(s); 13351301Sbostic lfs_writesum(fs); 13451301Sbostic if (do_ckp) 135*51342Sbostic lfs_writesuper(fs); 136*51342Sbostic printf("After writesuper returning\n"); 137*51342Sbostic 13851188Sbostic return (0); 13951188Sbostic } 14051188Sbostic 141*51342Sbostic static int /* XXX should be void */ 14251188Sbostic lfs_biocallback(bp) 14351188Sbostic BUF *bp; 14451188Sbostic { 14551188Sbostic LFS *fs; 14651188Sbostic 14751215Sbostic /* 14851301Sbostic * XXX 14951301Sbostic * Reset the flags (probably wrong). If the contents of the buffer 15051301Sbostic * are valid, move back onto the clean list. 15151215Sbostic */ 15251301Sbostic bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI); 15351301Sbostic fs = VFSTOUFS(bp->b_vp->v_mount)->um_lfs; 15451215Sbostic if (bp->b_flags & B_NOCACHE) 15551215Sbostic bp->b_vp = NULL; 15651301Sbostic else 15751215Sbostic reassignbuf(bp, bp->b_vp); 15851301Sbostic brelse(bp); 15951215Sbostic 16051301Sbostic printf("callback: buffer: %x iocount %d\n", bp, fs->lfs_iocount); 16151301Sbostic if (fs->lfs_iocount == 0) 16251301Sbostic panic("lfs_biocallback: zero iocount\n"); 16351215Sbostic 16451301Sbostic if (--fs->lfs_iocount == 0) 16551301Sbostic wakeup(&fs->lfs_iocount); 16651188Sbostic } 16751188Sbostic 168*51342Sbostic /* Finish up a summary block. */ 16951188Sbostic static void 17051188Sbostic lfs_endsum(fs, sp, calc_next) 17151188Sbostic LFS *fs; 17251188Sbostic SEGMENT *sp; 173*51342Sbostic int calc_next; 17451188Sbostic { 17551188Sbostic SEGSUM *ssp; 176*51342Sbostic int nsums_per_blk; 17751188Sbostic 17851215Sbostic if (sp->sbp == NULL) 17951215Sbostic return; 18051215Sbostic 18151188Sbostic ssp = sp->segsum; 18251188Sbostic 18351301Sbostic /* 184*51342Sbostic * Compute the address of the next summary block if calc_next is set, 185*51342Sbostic * otherwise end the chain. If the summary block is full, close it 186*51342Sbostic * by setting sp->sbp to NULL, so lfs_newsum will allocate a new one. 187*51342Sbostic * Calculate the checksum last. 18851301Sbostic */ 18951301Sbostic nsums_per_blk = fs->lfs_bsize / LFS_SUMMARY_SIZE; 190*51342Sbostic if (sp->nsums % nsums_per_blk == 0) { 191*51342Sbostic ssp->ss_nextsum = 192*51342Sbostic calc_next ? next(fs, sp, NULL) + 193*51342Sbostic (nsums_per_blk - 1) * LFS_SUMMARY_SIZE / DEV_BSIZE : 194*51342Sbostic (daddr_t)-1; 19551215Sbostic sp->sbp = NULL; 19651215Sbostic } else 197*51342Sbostic ssp->ss_nextsum = calc_next ? 198*51342Sbostic sp->sum_addr - LFS_SUMMARY_SIZE / DEV_BSIZE : (daddr_t)-1; 199*51342Sbostic 200*51342Sbostic ssp->ss_cksum = 201*51342Sbostic cksum(&ssp->ss_cksum, LFS_SUMMARY_SIZE - sizeof(ssp->ss_cksum)); 20251215Sbostic } 20351215Sbostic 20451215Sbostic static SEGMENT * 20551215Sbostic lfs_gather(fs, sp, vp, match) 20651215Sbostic LFS *fs; 20751215Sbostic SEGMENT *sp; 20851215Sbostic VNODE *vp; 20951215Sbostic int (*match) __P((BUF *)); 21051215Sbostic { 21151215Sbostic BUF **bpp, *bp, *nbp; 21251215Sbostic FINFO *fip; 21351215Sbostic INODE *ip; 21451215Sbostic daddr_t *lbp, *start_lbp; 215*51342Sbostic u_long version; 216*51342Sbostic int s; 21751215Sbostic 21851215Sbostic ip = VTOI(vp); 21951215Sbostic bpp = sp->cbpp; 22051215Sbostic fip = sp->fip; 22151215Sbostic start_lbp = lbp = &fip->fi_blocks[fip->fi_nblocks]; 22251215Sbostic 22351215Sbostic s = splbio(); 22451215Sbostic for (bp = vp->v_dirtyblkhd; bp; bp = nbp) { 22551215Sbostic nbp = bp->b_blockf; 226*51342Sbostic if (bp->b_flags & B_BUSY) 22751215Sbostic continue; 228*51342Sbostic #ifdef DIAGNOSTIC 22951215Sbostic if ((bp->b_flags & B_DELWRI) == 0) 230*51342Sbostic panic("lfs_gather: not dirty"); 231*51342Sbostic #endif 23251215Sbostic if (!match(bp)) 23351215Sbostic continue; 234*51342Sbostic 235*51342Sbostic /* Remove the buffer from the free lists, prepare it for I/O. */ 23651215Sbostic bremfree(bp); 23751215Sbostic bp->b_flags |= B_BUSY | B_CALL; 23851301Sbostic bp->b_iodone = lfs_biocallback; 23951215Sbostic bp->b_dev = VTOI(fs->lfs_ivnode)->i_dev; 24051215Sbostic 241*51342Sbostic /* Insert into the buffer list, update the FINFO block. */ 242*51342Sbostic *sp->cbpp++ = bp; 243*51342Sbostic ++fip->fi_nblocks; 24451215Sbostic *lbp++ = bp->b_lblkno; 245*51342Sbostic 24651215Sbostic sp->sum_bytes_left -= sizeof(daddr_t); 24751215Sbostic sp->seg_bytes_left -= bp->b_bufsize; 248*51342Sbostic 249*51342Sbostic /* 250*51342Sbostic * Allocate a new summary block (and, possibly, a new segment) 251*51342Sbostic * if necessary. In this case we sort the blocks we've done 252*51342Sbostic * so far and assign disk addresses so we can start the new 253*51342Sbostic * block correctly. We may be doing I/O, so we need to release 254*51342Sbostic * the splbio() before anything else. 255*51342Sbostic */ 256*51342Sbostic if (sp->sum_bytes_left < sizeof(daddr_t) || 25751215Sbostic sp->seg_bytes_left < fs->lfs_bsize) { 25851215Sbostic splx(s); 259*51342Sbostic lfs_updatemeta(fs, 260*51342Sbostic sp, ip, start_lbp, bpp, lbp - start_lbp); 26151215Sbostic 262*51342Sbostic /* Add the current file to the segment summary. */ 263*51342Sbostic ++((SEGSUM *)(sp->segsum))->ss_nfinfo; 26451215Sbostic 265*51342Sbostic version = fip->fi_version; 26651215Sbostic if (sp->seg_bytes_left < fs->lfs_bsize) { 26751215Sbostic lfs_writeseg(fs, sp); 26851215Sbostic sp = lfs_newseg(fs); 26951215Sbostic } else if (sp->sum_bytes_left < sizeof(daddr_t)) 270*51342Sbostic sp = lfs_newsum(fs, sp); 271*51342Sbostic 272*51342Sbostic /* A new FINFO either way. */ 27351215Sbostic fip = sp->fip; 274*51342Sbostic fip->fi_version = version; 27551215Sbostic fip->fi_ino = ip->i_number; 276*51342Sbostic start_lbp = lbp = fip->fi_blocks; 277*51342Sbostic 27851215Sbostic bpp = sp->cbpp; 27951215Sbostic s = splbio(); 28051215Sbostic } 28151188Sbostic } 28251215Sbostic splx(s); 28351215Sbostic lfs_updatemeta(fs, sp, ip, start_lbp, bpp, lbp - start_lbp); 284*51342Sbostic return (sp); 28551188Sbostic } 28651188Sbostic 287*51342Sbostic /* 288*51342Sbostic * Allocate a new buffer header. 289*51342Sbostic */ 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 29851188Sbostic bp = getnewbuf(); 29951188Sbostic bremhash(bp); 30051215Sbostic bp->b_vp = fs->lfs_ivnode; 30151188Sbostic bp->b_bcount = 0; 30251215Sbostic bp->b_blkno = bp->b_lblkno = daddr; 30351188Sbostic bp->b_error = 0; 30451188Sbostic bp->b_resid = 0; 30551301Sbostic bp->b_flags |= B_DELWRI | B_NOCACHE; 30651215Sbostic bp->b_iodone = lfs_biocallback; 30751301Sbostic bp->b_dev = VTOI(fs->lfs_ivnode)->i_dev; 30851188Sbostic allocbuf(bp, size); 30951188Sbostic return (bp); 31051188Sbostic } 31151188Sbostic 312*51342Sbostic /* 313*51342Sbostic * Start a new segment. 314*51342Sbostic */ 31551188Sbostic static SEGMENT * 31651188Sbostic lfs_newseg(fs) 31751188Sbostic LFS *fs; 31851188Sbostic { 319*51342Sbostic FINFO *fip; 32051188Sbostic SEGMENT *sp; 32151188Sbostic SEGUSE *sup; 322*51342Sbostic SEGSUM *ssp; 323*51342Sbostic daddr_t lbn, *lbnp; 32451188Sbostic 32551301Sbostic printf("lfs_newseg: new segment %x\n", fs->lfs_nextseg); 32651301Sbostic 32751188Sbostic sp = malloc(sizeof(SEGMENT), M_SEGMENT, M_WAITOK); 32851301Sbostic sp->nextp = NULL; 32951188Sbostic sp->cbpp = sp->bpp = 33051188Sbostic malloc(fs->lfs_ssize * sizeof(BUF *), M_SEGMENT, M_WAITOK); 33151301Sbostic sp->ibp = sp->sbp = NULL; 332*51342Sbostic sp->seg_bytes_left = (fs->lfs_segmask + 1); 33351188Sbostic sp->saddr = fs->lfs_nextseg; 33451188Sbostic sp->sum_addr = sp->saddr + sp->seg_bytes_left / DEV_BSIZE; 33551188Sbostic sp->ninodes = 0; 336*51342Sbostic sp->nsums = 0; 33751215Sbostic sp->seg_number = 33851215Sbostic (sp->saddr - fs->lfs_sboffs[0]) / fsbtodb(fs, fs->lfs_ssize); 33951188Sbostic 340*51342Sbostic /* Advance to the next segment. */ 34151301Sbostic fs->lfs_nextseg = lfs_nextseg(fs); 34251301Sbostic 343*51342Sbostic /* Initialize the summary block. */ 344*51342Sbostic sp = lfs_newsum(fs, sp); 345*51342Sbostic 346*51342Sbostic /* 347*51342Sbostic * If su_nbytes non-zero after the segment was cleaned, the segment 348*51342Sbostic * contains a super-block. Add segment summary information to not 349*51342Sbostic * allocate over it. 350*51342Sbostic */ 35151188Sbostic sup = fs->lfs_segtab + sp->seg_number; 35251188Sbostic if (sup->su_nbytes != 0) { 35351215Sbostic ssp = (SEGSUM *)sp->segsum; 354*51342Sbostic ++ssp->ss_nfinfo; 35551188Sbostic fip = sp->fip; 35651188Sbostic fip->fi_nblocks = LFS_SBPAD >> fs->lfs_bshift; 35751188Sbostic fip->fi_version = 1; 35851188Sbostic fip->fi_ino = LFS_UNUSED_INUM; 35951188Sbostic lbnp = fip->fi_blocks; 360*51342Sbostic for (lbn = 0; lbn < fip->fi_nblocks; ++lbn) 36151188Sbostic *lbnp++ = lbn; 362*51342Sbostic sp->saddr += fsbtodb(fs, fip->fi_nblocks); 36351188Sbostic sp->seg_bytes_left -= sup->su_nbytes; 364*51342Sbostic sp->sum_bytes_left -= 36551188Sbostic sizeof(FINFO) + (fip->fi_nblocks - 1) * sizeof(daddr_t); 36651188Sbostic sp->fip = (FINFO *)lbnp; 36751188Sbostic } 368*51342Sbostic return (sp); 36951188Sbostic } 37051188Sbostic 371*51342Sbostic static SEGMENT * 37251188Sbostic lfs_newsum(fs, sp) 37351188Sbostic LFS *fs; 37451188Sbostic SEGMENT *sp; 37551188Sbostic { 37651188Sbostic SEGSUM *ssp; 377*51342Sbostic int nblocks; 37851188Sbostic 37951188Sbostic printf("lfs_newsum\n"); 380*51342Sbostic 38151215Sbostic lfs_endsum(fs, sp, 1); 382*51342Sbostic 383*51342Sbostic /* Allocate a new buffer if necessary. */ 38451215Sbostic if (sp->sbp == NULL) { 385*51342Sbostic /* Allocate a new segment if necessary. */ 38651215Sbostic if (sp->seg_bytes_left < fs->lfs_bsize) { 38751215Sbostic lfs_writeseg(fs, sp); 38851215Sbostic sp = lfs_newseg(fs); 38951215Sbostic } 390*51342Sbostic 391*51342Sbostic /* Get the next summary block. */ 392*51342Sbostic sp->sum_addr = next(fs, sp, &nblocks); 393*51342Sbostic 394*51342Sbostic /* 395*51342Sbostic * Get a new buffer and enter into the buffer list from 396*51342Sbostic * the top of the list. 397*51342Sbostic */ 398*51342Sbostic sp->sbp = sp->bpp[fs->lfs_ssize - (nblocks + 1)] = 399*51342Sbostic lfs_newbuf(fs, sp->sum_addr, fs->lfs_bsize); 400*51342Sbostic 401*51342Sbostic sp->seg_bytes_left -= fs->lfs_bsize; 402*51342Sbostic 403*51342Sbostic /* 404*51342Sbostic * Do a callback for all but the very last summary block in 405*51342Sbostic * the segment, for which we wait. 406*51342Sbostic */ 407*51342Sbostic if (sp->nsums != 0) 40851301Sbostic sp->sbp->b_flags |= B_CALL; 409*51342Sbostic /* 410*51342Sbostic * Fill in the block from the end. The summary block is filled 411*51342Sbostic * in from the end to the beginning so that the last summary 412*51342Sbostic * is the last thing written, verifying the entire block. This 413*51342Sbostic * should go away when fragments are available. 414*51342Sbostic */ 41551301Sbostic sp->segsum = 41651301Sbostic sp->sbp->b_un.b_addr + fs->lfs_bsize - LFS_SUMMARY_SIZE; 41751215Sbostic sp->sum_addr += (fs->lfs_bsize - LFS_SUMMARY_SIZE) / DEV_BSIZE; 418*51342Sbostic 419*51342Sbostic printf("alloc summary: bp %x, lblkno %x, bp index %d\n", 420*51342Sbostic sp->sbp, sp->sbp->b_lblkno, fs->lfs_ssize - nblocks); 42151188Sbostic } else { 42251215Sbostic sp->segsum -= LFS_SUMMARY_SIZE; 42351215Sbostic sp->sum_addr -= LFS_SUMMARY_SIZE / DEV_BSIZE; 42451188Sbostic } 425*51342Sbostic ++sp->nsums; 42651188Sbostic 427*51342Sbostic /* Set point to SEGSUM, initialize it. */ 42851215Sbostic ssp = sp->segsum; 42951301Sbostic ssp->ss_next = fs->lfs_nextseg; 43051215Sbostic ssp->ss_prev = fs->lfs_lastseg; 43151188Sbostic ssp->ss_nextsum = (daddr_t)-1; 43251188Sbostic ssp->ss_create = time.tv_sec; 433*51342Sbostic ssp->ss_nfinfo = ssp->ss_ninos = 0; 43451188Sbostic 435*51342Sbostic /* Set pointer to first FINFO, initialize it. */ 436*51342Sbostic sp->fip = (FINFO *)(sp->segsum + sizeof(SEGSUM)); 437*51342Sbostic 438*51342Sbostic sp->sum_bytes_left = LFS_SUMMARY_SIZE - sizeof(SEGSUM); 439*51342Sbostic return (sp); 44051188Sbostic } 44151188Sbostic 442*51342Sbostic #define seginc(fs, sn) /* increment segment number */ \ 443*51342Sbostic (((sn) + 1) % (fs)->lfs_nseg) 444*51342Sbostic /* 445*51342Sbostic * Return the next segment to write. 446*51342Sbostic */ 44751188Sbostic static daddr_t 44851188Sbostic lfs_nextseg(fs) 44951188Sbostic LFS *fs; 45051188Sbostic { 45151188Sbostic int segnum, sn; 45251188Sbostic 453*51342Sbostic segnum = sn = datosn(fs, fs->lfs_nextseg); 454*51342Sbostic while ((sn = seginc(fs, sn)) != segnum && 455*51342Sbostic fs->lfs_segtab[sn].su_flags & SEGUSE_DIRTY); 45651215Sbostic 45751188Sbostic if (sn == segnum) 45851188Sbostic panic("lfs_nextseg: file system full"); /* XXX */ 459*51342Sbostic return (sntoda(fs, sn)); 46051188Sbostic } 46151188Sbostic 46251188Sbostic /* 463*51342Sbostic * Update the metadata that points to the blocks listed in the FINFO 46451188Sbostic * array. 46551188Sbostic */ 46651215Sbostic static void 46751215Sbostic lfs_updatemeta(fs, sp, ip, lbp, bpp, nblocks) 46851188Sbostic LFS *fs; 46951215Sbostic SEGMENT *sp; 47051188Sbostic INODE *ip; 47151215Sbostic daddr_t *lbp; 47251188Sbostic BUF **bpp; 47351215Sbostic int nblocks; 47451188Sbostic { 47551188Sbostic SEGUSE *segup; 476*51342Sbostic BUF **lbpp, *bp; 477*51342Sbostic daddr_t daddr, iblkno; 478*51342Sbostic int db_per_fsb, error, i; 47951215Sbostic long lbn; 48051188Sbostic 481*51342Sbostic if (nblocks == 0) 48251215Sbostic return; 483*51342Sbostic printf("lfs_updatemeta of %d blocks\n", nblocks); 48451215Sbostic 485*51342Sbostic /* Sort the blocks and add disk addresses */ 48651215Sbostic shellsort(bpp, lbp, nblocks); 48751215Sbostic 48851215Sbostic db_per_fsb = 1 << fs->lfs_fsbtodb; 489*51342Sbostic for (lbpp = bpp, i = 0; i < nblocks; ++i, ++lbpp) { 49051215Sbostic (*lbpp)->b_blkno = sp->saddr; 49151215Sbostic sp->saddr += db_per_fsb; 49251215Sbostic } 49351215Sbostic 494*51342Sbostic for (lbpp = bpp, i = 0; i < nblocks; ++i, ++lbpp) { 49551215Sbostic lbn = lbp[i]; 49651215Sbostic printf("lfs_updatemeta: block %d\n", lbn); 497*51342Sbostic if (error = lfs_bmap(ip, lbn, &daddr)) 498*51342Sbostic panic("lfs_updatemeta: lfs_bmap"); 49951188Sbostic 500*51342Sbostic /* Update in-core copy of old segment usage information. */ 501*51342Sbostic if (daddr != UNASSIGNED) { 502*51342Sbostic segup = fs->lfs_segtab + datosn(fs, daddr); 50351188Sbostic segup->su_lastmod = time.tv_sec; 504*51342Sbostic #ifdef DIAGNOSTIC 505*51342Sbostic if (segup->su_nbytes < fs->lfs_bsize) { 506*51342Sbostic printf("lfs: negative bytes (segment %d)\n", 507*51342Sbostic segup - fs->lfs_segtab); 508*51342Sbostic panic("lfs: negative bytes in segment\n"); 509*51342Sbostic } 510*51342Sbostic #endif 511*51342Sbostic segup->su_nbytes -= fs->lfs_bsize; 51251188Sbostic } 51351188Sbostic 51451215Sbostic /* 515*51342Sbostic * Now change whomever points to lbn. We could start with the 51651215Sbostic * smallest (most negative) block number in these if clauses, 51751215Sbostic * but we assume that indirect blocks are least common, and 518*51342Sbostic * handle them separately. The test for < 0 is correct and 519*51342Sbostic * minimizes the path in the common case. 52051215Sbostic */ 521*51342Sbostic #define BREAD(bno) \ 522*51342Sbostic if (error = bread(ITOV(ip), (bno), fs->lfs_bsize, NOCRED, &bp)) \ 523*51342Sbostic panic("lfs_updatemeta: bread"); 524*51342Sbostic 525*51342Sbostic if (lbn < 0) 52651215Sbostic if (lbn < -NIADDR) { 527*51342Sbostic printf("meta: update indirect block %d\n", 528*51342Sbostic D_INDIR); 529*51342Sbostic BREAD(D_INDIR); 530*51342Sbostic bp->b_un.b_daddr[-lbn % NINDIR(fs)] = 53151215Sbostic (*lbpp)->b_blkno; 532*51342Sbostic lfs_bwrite(bp); 533*51342Sbostic } else { 534*51342Sbostic ip->i_ib[-lbn-1] = (*lbpp)->b_blkno; 535*51342Sbostic } else if (lbn < NDADDR) { 536*51342Sbostic ip->i_db[lbn] = (*lbpp)->b_blkno; 537*51342Sbostic } else if ((lbn -= NDADDR) < NINDIR(fs)) { 538*51342Sbostic printf("meta: update indirect block %d\n", S_INDIR); 539*51342Sbostic BREAD(S_INDIR); 54051188Sbostic bp->b_un.b_daddr[lbn] = (*lbpp)->b_blkno; 541*51342Sbostic lfs_bwrite(bp); 542*51342Sbostic } else if ((lbn = 543*51342Sbostic (lbn - NINDIR(fs)) / NINDIR(fs)) < NINDIR(fs)) { 544*51342Sbostic iblkno = -(lbn + NIADDR + 1); 545*51342Sbostic printf("meta: update indirect block %d\n", iblkno); 546*51342Sbostic BREAD(iblkno); 54751188Sbostic bp->b_un.b_daddr[lbn % NINDIR(fs)] = (*lbpp)->b_blkno; 548*51342Sbostic lfs_bwrite(bp); 549*51342Sbostic } else 55051215Sbostic panic("lfs_updatemeta: logical block number too large"); 55151188Sbostic } 55251188Sbostic } 55351188Sbostic 55451301Sbostic static SEGMENT * 55551215Sbostic lfs_writeckp(fs, sp) 55651215Sbostic LFS *fs; 55751215Sbostic SEGMENT *sp; 55851215Sbostic { 55951215Sbostic BUF *bp; 56051215Sbostic FINFO *fip; 56151215Sbostic INODE *ip; 56251215Sbostic SEGUSE *sup; 56351301Sbostic void *xp; 56451215Sbostic daddr_t *lbp; 56551215Sbostic int bytes_needed, i; 56651215Sbostic 56751215Sbostic printf("lfs_writeckp\n"); 56851215Sbostic /* 56951215Sbostic * This will write the dirty ifile blocks, but not the segusage 57051215Sbostic * table nor the ifile inode. 57151215Sbostic */ 572*51342Sbostic sp = lfs_writefile(fs, sp, fs->lfs_ivnode, 1); 57351215Sbostic 57451215Sbostic /* 575*51342Sbostic * If the segment usage table and the ifile inode won't fit in this 576*51342Sbostic * segment, put them in the next one. 57751215Sbostic */ 57851215Sbostic bytes_needed = fs->lfs_segtabsz << fs->lfs_bshift; 57951215Sbostic if (sp->ninodes % INOPB(fs) == 0) 58051215Sbostic bytes_needed += fs->lfs_bsize; 58151215Sbostic 58251215Sbostic if (sp->seg_bytes_left < bytes_needed) { 58351215Sbostic lfs_writeseg(fs, sp); 58451215Sbostic sp = lfs_newseg(fs); 585*51342Sbostic ++((SEGSUM *)(sp->segsum))->ss_nfinfo; 586*51342Sbostic } else if (sp->sum_bytes_left < fs->lfs_segtabsz * sizeof(daddr_t)) { 587*51342Sbostic sp = lfs_newsum(fs, sp); 588*51342Sbostic ++((SEGSUM *)(sp->segsum))->ss_nfinfo; 589*51342Sbostic } 59051215Sbostic 59151215Sbostic #ifdef DEBUG 59251215Sbostic if (sp->seg_bytes_left < bytes_needed) 59351215Sbostic panic("lfs_writeckp: unable to write checkpoint"); 59451215Sbostic #endif 59551215Sbostic /* 59651301Sbostic * Update the segment usage information and the ifile inode 59751301Sbostic * and write it out. 59851215Sbostic */ 59951215Sbostic sup = fs->lfs_segtab + sp->seg_number; 60051301Sbostic sup->su_nbytes = 60151301Sbostic (fs->lfs_segmask + 1) - sp->seg_bytes_left + bytes_needed; 60251215Sbostic sup->su_lastmod = time.tv_sec; 60351215Sbostic sup->su_flags = SEGUSE_DIRTY; 60451215Sbostic 605*51342Sbostic /* 606*51342Sbostic * Get buffers for the segusage table and write it out. Don't 607*51342Sbostic * bother updating the FINFO pointer, it's not used after this. 608*51342Sbostic */ 60951215Sbostic ip = VTOI(fs->lfs_ivnode); 61051215Sbostic fip = sp->fip; 61151215Sbostic lbp = &fip->fi_blocks[fip->fi_nblocks]; 612*51342Sbostic for (xp = fs->lfs_segtab, i = 0; i < fs->lfs_segtabsz; 613*51342Sbostic xp += fs->lfs_bsize, ++i, ++lbp) { 61451301Sbostic *sp->cbpp++ = bp = lfs_newbuf(fs, sp->saddr, fs->lfs_bsize); 61551301Sbostic bp->b_flags |= B_CALL; 616*51342Sbostic bcopy(xp, bp->b_un.b_addr, fs->lfs_bsize); 617*51342Sbostic ip->i_db[i] = sp->saddr; 61851215Sbostic sp->saddr += (1 << fs->lfs_fsbtodb); 61951215Sbostic *lbp = i; 620*51342Sbostic ++fip->fi_nblocks; 62151215Sbostic } 622*51342Sbostic return (lfs_writeinode(fs, sp, VTOI(fs->lfs_ivnode))); 62351215Sbostic } 62451215Sbostic 62551188Sbostic /* 626*51342Sbostic * Write the dirty blocks associated with a vnode. 62751188Sbostic */ 62851188Sbostic static SEGMENT * 629*51342Sbostic lfs_writefile(fs, sp, vp, do_ckp) 630*51342Sbostic LFS *fs; 63151188Sbostic SEGMENT *sp; 63251188Sbostic VNODE *vp; 63351215Sbostic int do_ckp; 63451188Sbostic { 63551188Sbostic FINFO *fip; 63651301Sbostic ino_t inum; 63751188Sbostic 63851301Sbostic inum = VTOI(vp)->i_number; 639*51342Sbostic printf("lfs_writefile: node %d\n", inum); 64051188Sbostic 641*51342Sbostic if (vp->v_dirtyblkhd != NULL) { 642*51342Sbostic if (sp->seg_bytes_left < fs->lfs_bsize) { 643*51342Sbostic lfs_writeseg(fs, sp); 644*51342Sbostic sp = lfs_newseg(fs); 645*51342Sbostic } else if (sp->sum_bytes_left < sizeof(FINFO)) 646*51342Sbostic sp = lfs_newsum(fs, sp); 647*51342Sbostic sp->sum_bytes_left -= sizeof(FINFO) - sizeof(daddr_t); 64851188Sbostic 64951215Sbostic fip = sp->fip; 650*51342Sbostic fip->fi_nblocks = 0; 651*51342Sbostic fip->fi_version = 652*51342Sbostic inum == LFS_IFILE_INUM ? 1 : lfs_getversion(fs, inum); 653*51342Sbostic fip->fi_ino = inum; 654*51342Sbostic 655*51342Sbostic sp = lfs_gather(fs, sp, vp, match_data); 656*51342Sbostic if (do_ckp) { 657*51342Sbostic sp = lfs_gather(fs, sp, vp, match_indir); 658*51342Sbostic sp = lfs_gather(fs, sp, vp, match_dindir); 65951188Sbostic } 660*51342Sbostic 661*51342Sbostic fip = sp->fip; 662*51342Sbostic printf("lfs_writefile: adding %d blocks\n", fip->fi_nblocks); 663*51342Sbostic 664*51342Sbostic /* 665*51342Sbostic * If this is the ifile, always update the file count as we'll 666*51342Sbostic * be adding the segment usage information even if we didn't 667*51342Sbostic * write any blocks. Also, don't update the FINFO pointer for 668*51342Sbostic * the ifile as the segment usage information hasn't yet been 669*51342Sbostic * added. 670*51342Sbostic */ 671*51342Sbostic if (inum == LFS_IFILE_INUM) 672*51342Sbostic ++((SEGSUM *)(sp->segsum))->ss_nfinfo; 673*51342Sbostic else if (fip->fi_nblocks != 0) { 674*51342Sbostic ++((SEGSUM *)(sp->segsum))->ss_nfinfo; 675*51342Sbostic sp->fip = (FINFO *)((caddr_t)fip + sizeof(FINFO) + 676*51342Sbostic sizeof(daddr_t) * (fip->fi_nblocks - 1)); 677*51342Sbostic } 67851188Sbostic } 679*51342Sbostic 680*51342Sbostic /* If this isn't the ifile, update the inode. */ 681*51342Sbostic if (inum != LFS_IFILE_INUM) 682*51342Sbostic sp = lfs_writeinode(fs, sp, VTOI(vp)); 683*51342Sbostic return (sp); 68451188Sbostic } 68551188Sbostic 68651215Sbostic static SEGMENT * 687*51342Sbostic lfs_writeinode(fs, sp, ip) 68851215Sbostic LFS *fs; 68951215Sbostic SEGMENT *sp; 690*51342Sbostic INODE *ip; 69151188Sbostic { 69251215Sbostic BUF *bp; 693*51342Sbostic daddr_t next_addr; 694*51342Sbostic int nblocks; 69551215Sbostic 69651215Sbostic printf("lfs_writeinode\n"); 697*51342Sbostic /* Allocate a new inode block if necessary. */ 69851215Sbostic if (sp->ibp == NULL) { 699*51342Sbostic /* Allocate a new segment if necessary. */ 70051215Sbostic if (sp->seg_bytes_left < fs->lfs_bsize) { 70151215Sbostic lfs_writeseg(fs, sp); 70251215Sbostic sp = lfs_newseg(fs); 70351215Sbostic } 704*51342Sbostic 705*51342Sbostic /* Get next inode block. */ 706*51342Sbostic next_addr = next(fs, sp, &nblocks); 707*51342Sbostic 708*51342Sbostic /* 709*51342Sbostic * Get a new buffer and enter into the buffer list from 710*51342Sbostic * the top of the list. 711*51342Sbostic */ 712*51342Sbostic sp->ibp = sp->bpp[fs->lfs_ssize - (nblocks + 1)] = 713*51342Sbostic lfs_newbuf(fs, next_addr, fs->lfs_bsize); 71451301Sbostic sp->ibp->b_flags |= B_CALL; 715*51342Sbostic 716*51342Sbostic /* Set remaining space counter. */ 71751215Sbostic sp->seg_bytes_left -= fs->lfs_bsize; 718*51342Sbostic 719*51342Sbostic printf("alloc inode: bp %x, lblkno %x, bp index %d\n", 720*51342Sbostic sp->sbp, sp->sbp->b_lblkno, fs->lfs_ssize - nblocks); 72151215Sbostic } 722*51342Sbostic 723*51342Sbostic /* Copy the new inode onto the inode page. */ 72451215Sbostic bp = sp->ibp; 725*51342Sbostic bcopy(&ip->i_din, 726*51342Sbostic bp->b_un.b_dino + (sp->ninodes % INOPB(fs)), sizeof(DINODE)); 727*51342Sbostic 728*51342Sbostic /* Increment inode count in segment summary block. */ 729*51342Sbostic ++((SEGSUM *)(sp->segsum))->ss_ninos; 730*51342Sbostic 731*51342Sbostic /* If this page is full, set flag to allocate a new page. */ 732*51342Sbostic if (++sp->ninodes % INOPB(fs) == 0) 73351215Sbostic sp->ibp = NULL; 734*51342Sbostic 735*51342Sbostic /* 736*51342Sbostic * If updating the ifile, update the super-block; otherwise, update 737*51342Sbostic * the ifile itself. In either case, turn of inode update flags. 738*51342Sbostic */ 73951215Sbostic if (ip->i_number == LFS_IFILE_INUM) 740*51342Sbostic fs->lfs_idaddr = bp->b_blkno; 74151215Sbostic else 742*51342Sbostic lfs_iset(ip, bp->b_blkno, ip->i_atime); 743*51342Sbostic ip->i_flags &= ~(IMOD | IACC | IUPD | ICHG); 744*51342Sbostic return (sp); 74551188Sbostic } 74651188Sbostic 74751188Sbostic static void 74851188Sbostic lfs_writeseg(fs, sp) 74951188Sbostic LFS *fs; 75051188Sbostic SEGMENT *sp; 75151188Sbostic { 75251215Sbostic BUF **bpp; 75351188Sbostic SEGUSE *sup; 754*51342Sbostic int i, nblocks, s, (*strategy) __P((BUF *)); 755*51342Sbostic void *pmeta; 75651188Sbostic 75751188Sbostic printf("lfs_writeseg\n"); 758*51342Sbostic /* Update superblock segment address. */ 759*51342Sbostic fs->lfs_lastseg = sntoda(fs, sp->seg_number); 760*51342Sbostic 761*51342Sbostic /* Finish up any summary block. */ 76251215Sbostic lfs_endsum(fs, sp, 0); 76351188Sbostic 76451188Sbostic /* 76551188Sbostic * Copy inode and summary block buffer pointers down so they are 76651215Sbostic * contiguous with the page buffer pointers. 76751188Sbostic */ 768*51342Sbostic (void)next(fs, sp, &nblocks); 769*51342Sbostic pmeta = (sp->bpp + fs->lfs_ssize) - nblocks; 770*51342Sbostic if (pmeta != sp->cbpp) 771*51342Sbostic bcopy(pmeta, sp->cbpp, sizeof(BUF *) * nblocks); 772*51342Sbostic sp->cbpp += nblocks; 773*51342Sbostic nblocks = sp->cbpp - sp->bpp; 77451188Sbostic 77551188Sbostic sup = fs->lfs_segtab + sp->seg_number; 77651188Sbostic sup->su_nbytes = nblocks << fs->lfs_bshift; 77751188Sbostic sup->su_lastmod = time.tv_sec; 77851188Sbostic sup->su_flags = SEGUSE_DIRTY; 77951188Sbostic 78051188Sbostic /* 78151215Sbostic * Since we need to guarantee that the summary block gets written last, 78251188Sbostic * we issue the writes in two sets. The first n-1 buffers first, and 78351301Sbostic * then, after they've completed, the summary buffer. Only when that 78451215Sbostic * final write completes is the segment valid. 78551188Sbostic */ 786*51342Sbostic --nblocks; /* Don't count last summary block. */ 78751301Sbostic 78851188Sbostic sp->nextp = fs->lfs_seglist; 78951188Sbostic fs->lfs_seglist = sp; 79051215Sbostic 79151301Sbostic s = splbio(); 79251301Sbostic fs->lfs_iocount += nblocks; 79351301Sbostic splx(s); 794*51342Sbostic 795*51342Sbostic strategy = 796*51342Sbostic VFSTOUFS(fs->lfs_ivnode->v_mount)->um_devvp->v_op->vop_strategy; 79751301Sbostic for (bpp = sp->bpp, i = 0; i < nblocks; ++i, ++bpp) 798*51342Sbostic (strategy)(*bpp); 79951188Sbostic } 80051188Sbostic 80151215Sbostic static void 80251301Sbostic lfs_writesum(fs) 80351301Sbostic LFS *fs; 80451301Sbostic { 80551301Sbostic BUF *bp; 80651301Sbostic SEGMENT *next_sp, *sp; 807*51342Sbostic int (*strategy) __P((BUF *)); 80851301Sbostic 80951301Sbostic printf("lfs_writesum\n"); 810*51342Sbostic strategy = 811*51342Sbostic VFSTOUFS(fs->lfs_ivnode->v_mount)->um_devvp->v_op->vop_strategy; 81251301Sbostic for (sp = fs->lfs_seglist; sp; sp = next_sp) { 81351301Sbostic bp = *(sp->cbpp - 1); 814*51342Sbostic (strategy)(bp); 81551301Sbostic biowait(bp); 81651301Sbostic next_sp = sp->nextp; 81751301Sbostic free(sp->bpp, M_SEGMENT); 81851301Sbostic free(sp, M_SEGMENT); 81951301Sbostic } 820*51342Sbostic /* Segment list is done. */ 821*51342Sbostic fs->lfs_seglist = NULL; 82251301Sbostic } 82351301Sbostic 82451301Sbostic static void 825*51342Sbostic lfs_writesuper(fs) 82651215Sbostic LFS *fs; 82751215Sbostic { 82851215Sbostic BUF *bp; 829*51342Sbostic int (*strategy) __P((BUF *)); 83051215Sbostic 83151215Sbostic printf("lfs_writesuper\n"); 832*51342Sbostic /* Checksum the superblock and copy it into a buffer. */ 83351215Sbostic fs->lfs_cksum = cksum(fs, sizeof(LFS) - sizeof(fs->lfs_cksum)); 83451215Sbostic bp = lfs_newbuf(fs, fs->lfs_sboffs[0], LFS_SBPAD); 83551215Sbostic bcopy(fs, bp->b_un.b_lfs, sizeof(LFS)); 83651215Sbostic 837*51342Sbostic /* Write the first superblock. */ 838*51342Sbostic strategy = 839*51342Sbostic VFSTOUFS(fs->lfs_ivnode->v_mount)->um_devvp->v_op->vop_strategy; 840*51342Sbostic (strategy)(bp); 84151215Sbostic biowait(bp); 842*51342Sbostic 843*51342Sbostic /* Write the second superblock. */ 84451215Sbostic bp->b_flags &= ~B_DONE; 84551215Sbostic bp->b_blkno = bp->b_lblkno = fs->lfs_sboffs[1]; 846*51342Sbostic (strategy)(bp); 84751301Sbostic 84851301Sbostic bp->b_vp = NULL; /* No associated vnode. */ 849*51342Sbostic biowait(bp); 85051215Sbostic brelse(bp); 851*51342Sbostic printf("lfs_writesuper is returning\n"); 85251215Sbostic } 85351215Sbostic 854*51342Sbostic /* 855*51342Sbostic * Logical block number match routines used when traversing the dirty block 856*51342Sbostic * chain. 857*51342Sbostic */ 858*51342Sbostic int 85951215Sbostic match_data(bp) 86051215Sbostic BUF *bp; 86151215Sbostic { 862*51342Sbostic return (bp->b_lblkno >= 0); 86351215Sbostic } 86451215Sbostic 865*51342Sbostic int 86651215Sbostic match_dindir(bp) 86751215Sbostic BUF *bp; 86851215Sbostic { 869*51342Sbostic return (bp->b_lblkno == D_INDIR); 87051215Sbostic } 87151215Sbostic 87251188Sbostic /* 87351215Sbostic * These are single indirect blocks. There are three types: 874*51342Sbostic * 875*51342Sbostic * the one in the inode (lblkno == S_INDIR, or -1). 876*51342Sbostic * the ones that hang off of the double indirect in the inode (D_INDIR); 877*51342Sbostic * these all have addresses in the range -2NINDIR to -(3NINDIR-1). 878*51342Sbostic * the ones that hang off of the double indirect that hangs off of the 879*51342Sbostic * triple indirect. These all have addresses < -(NINDIR^2). 880*51342Sbostic * 881*51342Sbostic * Since we currently don't support triple indirect blocks, this gets 882*51342Sbostic * simpler, and we just look for block numbers less than -NIADDR. 88351215Sbostic */ 884*51342Sbostic int 88551215Sbostic match_indir(bp) 88651215Sbostic BUF *bp; 88751215Sbostic { 888*51342Sbostic return (bp->b_lblkno == S_INDIR || bp->b_lblkno < -NIADDR); 88951215Sbostic } 89051215Sbostic 891*51342Sbostic /* Get the next inode/summary block. */ 892*51342Sbostic static daddr_t 893*51342Sbostic next(fs, sp, nbp) 894*51342Sbostic LFS *fs; 895*51342Sbostic SEGMENT *sp; 896*51342Sbostic int *nbp; 897*51342Sbostic { 898*51342Sbostic int nblocks, nino_blocks, nseg_blocks, sums_per_block; 899*51342Sbostic 900*51342Sbostic /* Fs blocks allocated to summary blocks. */ 901*51342Sbostic sums_per_block = fs->lfs_bsize / LFS_SUMMARY_SIZE; 902*51342Sbostic nseg_blocks = (sp->nsums + sums_per_block - 1) / sums_per_block; 903*51342Sbostic 904*51342Sbostic /* Fs blocks allocated to inodes. */ 905*51342Sbostic nino_blocks = (sp->ninodes + INOPB(fs) - 1) / INOPB(fs); 906*51342Sbostic 907*51342Sbostic /* Total number of fs blocks allocated. */ 908*51342Sbostic nblocks = nseg_blocks + nino_blocks; 909*51342Sbostic 910*51342Sbostic if (nbp) 911*51342Sbostic *nbp = nblocks; 912*51342Sbostic 913*51342Sbostic /* 914*51342Sbostic * The disk address of the new inode/summary block is the address of 915*51342Sbostic * the start of the segment after this one minus the number of blocks 916*51342Sbostic * that we've already used. 917*51342Sbostic */ 918*51342Sbostic return (sntoda(fs, sp->seg_number + 1) - fsbtodb(fs, nblocks + 1)); 919*51342Sbostic } 920*51342Sbostic 92151215Sbostic /* 92251188Sbostic * Shellsort (diminishing increment sort) from Data Structures and 92351188Sbostic * Algorithms, Aho, Hopcraft and Ullman, 1983 Edition, page 290; 92451188Sbostic * see also Knuth Vol. 3, page 84. The increments are selected from 92551188Sbostic * formula (8), page 95. Roughly O(N^3/2). 92651188Sbostic */ 92751188Sbostic /* 92851188Sbostic * This is our own private copy of shellsort because we want to sort 92951188Sbostic * two parallel arrays (the array of buffer pointers and the array of 93051188Sbostic * logical block numbers) simultaneously. Note that we cast the array 93151188Sbostic * of logical block numbers to a unsigned in this routine so that the 93251188Sbostic * negative block numbers (meta data blocks) sort AFTER the data blocks. 93351188Sbostic */ 93451188Sbostic static void 93551188Sbostic shellsort(bp_array, lb_array, nmemb) 93651188Sbostic BUF **bp_array; 93751215Sbostic daddr_t *lb_array; 93851188Sbostic register int nmemb; 93951188Sbostic { 94051188Sbostic static int __rsshell_increments[] = { 4, 1, 0 }; 94151188Sbostic register int incr, *incrp, t1, t2; 94251188Sbostic BUF *bp_temp; 94351188Sbostic u_long lb_temp; 94451188Sbostic 94551188Sbostic for (incrp = __rsshell_increments; incr = *incrp++;) 94651188Sbostic for (t1 = incr; t1 < nmemb; ++t1) 94751188Sbostic for (t2 = t1 - incr; t2 >= 0;) 94851188Sbostic if (lb_array[t2] > lb_array[t2 + incr]) { 94951188Sbostic lb_temp = lb_array[t2]; 95051188Sbostic lb_array[t2] = lb_array[t2 + incr]; 95151188Sbostic lb_array[t2 + incr] = lb_temp; 95251188Sbostic bp_temp = bp_array[t2]; 95351188Sbostic bp_array[t2] = bp_array[t2 + incr]; 95451188Sbostic bp_array[t2 + incr] = bp_temp; 95551188Sbostic t2 -= incr; 95651188Sbostic } else 95751188Sbostic break; 95851188Sbostic } 95951215Sbostic #endif /* LOGFS */ 960