xref: /csrg-svn/sys/ufs/lfs/lfs_segment.c (revision 51499)
151188Sbostic /*
251188Sbostic  * Copyright (c) 1991 Regents of the University of California.
351188Sbostic  * All rights reserved.
451188Sbostic  *
551188Sbostic  * %sccs.include.redist.c%
651188Sbostic  *
7*51499Sbostic  *	@(#)lfs_segment.c	7.1 (Berkeley) 11/01/91
851188Sbostic  */
951188Sbostic 
1051490Sbostic #include <sys/param.h>
1151490Sbostic #include <sys/systm.h>
1251490Sbostic #include <sys/namei.h>
1351490Sbostic #include <sys/resourcevar.h>
1451490Sbostic #include <sys/kernel.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/specdev.h>
2251490Sbostic #include <sys/fifo.h>
2351490Sbostic #include <sys/malloc.h>
2451490Sbostic #include <sys/mount.h>
2551188Sbostic 
26*51499Sbostic #include <ufs/ufs/quota.h>
27*51499Sbostic #include <ufs/ufs/inode.h>
28*51499Sbostic #include <ufs/ufs/dir.h>
29*51499Sbostic #include <ufs/ufs/ufsmount.h>
3051490Sbostic 
31*51499Sbostic #include <ufs/lfs/lfs.h>
32*51499Sbostic #include <ufs/lfs/lfs_extern.h>
3351490Sbostic 
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 *));
45*51499Sbostic static void	 lfs_endsum __P((struct lfs *, SEGMENT *, int));
46*51499Sbostic static SEGMENT	*lfs_gather __P((struct lfs *,
47*51499Sbostic 		     SEGMENT *, VNODE *, int (*) __P((BUF *))));
48*51499Sbostic static BUF	*lfs_newbuf __P((struct lfs *, daddr_t, size_t));
49*51499Sbostic static SEGMENT	*lfs_newseg __P((struct lfs *));
50*51499Sbostic static SEGMENT	*lfs_newsum __P((struct lfs *, SEGMENT *));
51*51499Sbostic static daddr_t	 lfs_nextseg __P((struct lfs *));
52*51499Sbostic static void	 lfs_updatemeta __P((struct lfs *,
53*51499Sbostic 		     SEGMENT *, INODE *, daddr_t *, BUF **, int));
54*51499Sbostic static SEGMENT	*lfs_writeckp __P((struct lfs *, SEGMENT *));
55*51499Sbostic static SEGMENT	*lfs_writefile __P((struct lfs *, SEGMENT *, VNODE *, int));
56*51499Sbostic static SEGMENT	*lfs_writeinode __P((struct lfs *, SEGMENT *, INODE *));
57*51499Sbostic static void	 lfs_writeseg __P((struct lfs *, SEGMENT *));
58*51499Sbostic static void	 lfs_writesum __P((struct lfs *));
59*51499Sbostic static void	 lfs_writesuper __P((struct lfs *));
6051215Sbostic static int	 match_data __P((BUF *));
6151215Sbostic static int	 match_dindir __P((BUF *));
6251215Sbostic static int	 match_indir __P((BUF *));
63*51499Sbostic static daddr_t	 next __P((struct 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;
76*51499Sbostic 	struct lfs *fs;
7751188Sbostic 	VNODE *vp;
7851188Sbostic 	SEGMENT *sp;
7951301Sbostic 	int s;
8051188Sbostic 
8151188Sbostic 	fs = VFSTOUFS(mp)->um_lfs;
8251342Sbostic 
8351342Sbostic #ifdef DIAGNOSTIC
8451342Sbostic 	if (fs->lfs_seglist != NULL)
8551342Sbostic 		panic("lfs_segwrite: seglist not NULL");
8651342Sbostic #endif
8751342Sbostic 
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);
10251342Sbostic 
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;
11751342Sbostic 		if ((ip->i_flag & (IMOD | IACC | IUPD | ICHG)) == 0 &&
11851188Sbostic 		    vp->v_dirtyblkhd == NULL)
11951188Sbostic 			continue;
12051188Sbostic 		if (vget(vp))
12151188Sbostic 			goto loop;
12251342Sbostic 		sp = lfs_writefile(fs, sp, vp, do_ckp);
12351188Sbostic 		vput(vp);
12451188Sbostic 	}
12551215Sbostic 	if (do_ckp)
12651301Sbostic 		sp = lfs_writeckp(fs, sp);
12751342Sbostic 	lfs_writeseg(fs, sp);
12851342Sbostic 
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)
13551342Sbostic 		lfs_writesuper(fs);
13651188Sbostic 	return (0);
13751188Sbostic }
13851188Sbostic 
13951342Sbostic static int					/* XXX should be void */
14051188Sbostic lfs_biocallback(bp)
14151188Sbostic 	BUF *bp;
14251188Sbostic {
143*51499Sbostic 	struct lfs *fs;
14451188Sbostic 
14551215Sbostic 	/*
14651301Sbostic 	 * XXX
14751301Sbostic 	 * Reset the flags (probably wrong).  If the contents of the buffer
14851301Sbostic 	 * are valid, move back onto the clean list.
14951215Sbostic 	 */
15051301Sbostic 	bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI);
15151301Sbostic 	fs = VFSTOUFS(bp->b_vp->v_mount)->um_lfs;
15251215Sbostic 	if (bp->b_flags & B_NOCACHE)
15351215Sbostic 		bp->b_vp = NULL;
15451301Sbostic 	else
15551215Sbostic 		reassignbuf(bp, bp->b_vp);
15651301Sbostic 	brelse(bp);
15751215Sbostic 
15851356Sbostic #ifdef SEGWRITE
15951301Sbostic printf("callback: buffer: %x iocount %d\n", bp, fs->lfs_iocount);
16051356Sbostic #endif
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 
16851342Sbostic /* Finish up a summary block. */
16951188Sbostic static void
17051188Sbostic lfs_endsum(fs, sp, calc_next)
171*51499Sbostic 	struct lfs *fs;
17251188Sbostic 	SEGMENT *sp;
17351342Sbostic 	int calc_next;
17451188Sbostic {
17551188Sbostic 	SEGSUM *ssp;
17651342Sbostic 	int nsums_per_blk;
17751188Sbostic 
17851215Sbostic 	if (sp->sbp == NULL)
17951215Sbostic 		return;
18051215Sbostic 
18151188Sbostic 	ssp = sp->segsum;
18251188Sbostic 
18351301Sbostic 	/*
18451342Sbostic 	 * Compute the address of the next summary block if calc_next is set,
18551342Sbostic 	 * otherwise end the chain.  If the summary block is full, close it
18651342Sbostic 	 * by setting sp->sbp to NULL, so lfs_newsum will allocate a new one.
18751342Sbostic 	 * Calculate the checksum last.
18851301Sbostic 	 */
18951301Sbostic 	nsums_per_blk = fs->lfs_bsize / LFS_SUMMARY_SIZE;
19051342Sbostic 	if (sp->nsums % nsums_per_blk == 0) {
19151342Sbostic 		ssp->ss_nextsum =
19251342Sbostic 		    calc_next ? next(fs, sp, NULL) +
19351342Sbostic 		    (nsums_per_blk - 1) * LFS_SUMMARY_SIZE / DEV_BSIZE :
19451342Sbostic 		    (daddr_t)-1;
19551215Sbostic 		sp->sbp = NULL;
19651215Sbostic 	} else
19751342Sbostic 		ssp->ss_nextsum = calc_next ?
19851342Sbostic 		    sp->sum_addr - LFS_SUMMARY_SIZE / DEV_BSIZE : (daddr_t)-1;
19951342Sbostic 
20051342Sbostic 	ssp->ss_cksum =
20151342Sbostic 	    cksum(&ssp->ss_cksum, LFS_SUMMARY_SIZE - sizeof(ssp->ss_cksum));
20251215Sbostic }
20351215Sbostic 
20451215Sbostic static SEGMENT *
20551215Sbostic lfs_gather(fs, sp, vp, match)
206*51499Sbostic 	struct 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;
21551342Sbostic 	u_long version;
21651342Sbostic 	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;
22651342Sbostic 		if (bp->b_flags & B_BUSY)
22751215Sbostic 			continue;
22851342Sbostic #ifdef DIAGNOSTIC
22951215Sbostic 		if ((bp->b_flags & B_DELWRI) == 0)
23051342Sbostic 			panic("lfs_gather: not dirty");
23151342Sbostic #endif
23251215Sbostic 		if (!match(bp))
23351215Sbostic 			continue;
23451342Sbostic 
23551342Sbostic 		/* 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 
24151342Sbostic 		/* Insert into the buffer list, update the FINFO block. */
24251342Sbostic 		*sp->cbpp++ = bp;
24351342Sbostic 		++fip->fi_nblocks;
24451215Sbostic 		*lbp++ = bp->b_lblkno;
24551342Sbostic 
24651215Sbostic 		sp->sum_bytes_left -= sizeof(daddr_t);
24751215Sbostic 		sp->seg_bytes_left -= bp->b_bufsize;
24851342Sbostic 
24951342Sbostic 		/*
25051342Sbostic 		 * Allocate a new summary block (and, possibly, a new segment)
25151342Sbostic 		 * if necessary.  In this case we sort the blocks we've done
25251342Sbostic 		 * so far and assign disk addresses so we can start the new
25351342Sbostic 		 * block correctly.  We may be doing I/O, so we need to release
25451342Sbostic 		 * the splbio() before anything else.
25551342Sbostic 		 */
25651342Sbostic 		if (sp->sum_bytes_left < sizeof(daddr_t) ||
25751215Sbostic 		    sp->seg_bytes_left < fs->lfs_bsize) {
25851215Sbostic 			splx(s);
25951342Sbostic 			lfs_updatemeta(fs,
26051342Sbostic 			    sp, ip, start_lbp, bpp, lbp - start_lbp);
26151215Sbostic 
26251342Sbostic 			/* Add the current file to the segment summary. */
26351342Sbostic 			++((SEGSUM *)(sp->segsum))->ss_nfinfo;
26451215Sbostic 
26551342Sbostic 			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))
27051342Sbostic 				sp = lfs_newsum(fs, sp);
27151342Sbostic 
27251342Sbostic 			/* A new FINFO either way. */
27351215Sbostic 			fip = sp->fip;
27451342Sbostic 			fip->fi_version = version;
27551215Sbostic 			fip->fi_ino = ip->i_number;
27651342Sbostic 			start_lbp = lbp = fip->fi_blocks;
27751342Sbostic 
27851215Sbostic 			bpp = sp->cbpp;
27951215Sbostic 			s = splbio();
28051215Sbostic 		}
28151188Sbostic 	}
28251215Sbostic 	splx(s);
28351215Sbostic 	lfs_updatemeta(fs, sp, ip, start_lbp, bpp, lbp - start_lbp);
28451342Sbostic 	return (sp);
28551188Sbostic }
28651188Sbostic 
28751342Sbostic /*
28851342Sbostic  * Allocate a new buffer header.
28951342Sbostic  */
29051188Sbostic static BUF *
29151188Sbostic lfs_newbuf(fs, daddr, size)
292*51499Sbostic 	struct 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 
31251342Sbostic /*
31351342Sbostic  * Start a new segment.
31451342Sbostic  */
31551188Sbostic static SEGMENT *
31651188Sbostic lfs_newseg(fs)
317*51499Sbostic 	struct lfs *fs;
31851188Sbostic {
31951342Sbostic 	FINFO *fip;
32051188Sbostic 	SEGMENT *sp;
32151188Sbostic 	SEGUSE *sup;
32251342Sbostic 	SEGSUM *ssp;
32351342Sbostic 	daddr_t lbn, *lbnp;
32451188Sbostic 
32551188Sbostic 	sp = malloc(sizeof(SEGMENT), M_SEGMENT, M_WAITOK);
32651301Sbostic 	sp->nextp = NULL;
32751188Sbostic 	sp->cbpp = sp->bpp =
32851188Sbostic 	    malloc(fs->lfs_ssize * sizeof(BUF *), M_SEGMENT, M_WAITOK);
32951301Sbostic 	sp->ibp = sp->sbp = NULL;
33051342Sbostic 	sp->seg_bytes_left = (fs->lfs_segmask + 1);
33151188Sbostic 	sp->saddr = fs->lfs_nextseg;
33251188Sbostic 	sp->sum_addr = sp->saddr + sp->seg_bytes_left / DEV_BSIZE;
33351188Sbostic 	sp->ninodes = 0;
33451342Sbostic 	sp->nsums = 0;
33551215Sbostic 	sp->seg_number =
33651215Sbostic 	    (sp->saddr - fs->lfs_sboffs[0]) / fsbtodb(fs, fs->lfs_ssize);
33751188Sbostic 
33851342Sbostic 	/* Advance to the next segment. */
33951301Sbostic 	fs->lfs_nextseg = lfs_nextseg(fs);
34051301Sbostic 
34151342Sbostic 	/* Initialize the summary block. */
34251342Sbostic 	sp = lfs_newsum(fs, sp);
34351342Sbostic 
34451342Sbostic 	/*
34551342Sbostic 	 * If su_nbytes non-zero after the segment was cleaned, the segment
34651342Sbostic 	 * contains a super-block.  Add segment summary information to not
34751342Sbostic 	 * allocate over it.
34851342Sbostic 	 */
34951188Sbostic 	sup = fs->lfs_segtab + sp->seg_number;
35051188Sbostic 	if (sup->su_nbytes != 0) {
35151215Sbostic 		ssp = (SEGSUM *)sp->segsum;
35251342Sbostic 		++ssp->ss_nfinfo;
35351188Sbostic 		fip = sp->fip;
35451188Sbostic 		fip->fi_nblocks = LFS_SBPAD >> fs->lfs_bshift;
35551188Sbostic 		fip->fi_version = 1;
35651188Sbostic 		fip->fi_ino = LFS_UNUSED_INUM;
35751188Sbostic 		lbnp = fip->fi_blocks;
35851342Sbostic 		for (lbn = 0; lbn < fip->fi_nblocks; ++lbn)
35951188Sbostic 			*lbnp++ = lbn;
36051342Sbostic 		sp->saddr += fsbtodb(fs, fip->fi_nblocks);
36151188Sbostic 		sp->seg_bytes_left -= sup->su_nbytes;
36251342Sbostic 		sp->sum_bytes_left -=
36351188Sbostic 		    sizeof(FINFO) + (fip->fi_nblocks - 1) * sizeof(daddr_t);
36451188Sbostic 		sp->fip = (FINFO *)lbnp;
36551188Sbostic 	}
36651342Sbostic 	return (sp);
36751188Sbostic }
36851188Sbostic 
36951342Sbostic static SEGMENT *
37051188Sbostic lfs_newsum(fs, sp)
371*51499Sbostic 	struct lfs *fs;
37251188Sbostic 	SEGMENT *sp;
37351188Sbostic {
37451188Sbostic 	SEGSUM *ssp;
37551342Sbostic 	int nblocks;
37651188Sbostic 
37751215Sbostic 	lfs_endsum(fs, sp, 1);
37851342Sbostic 
37951342Sbostic 	/* Allocate a new buffer if necessary. */
38051215Sbostic 	if (sp->sbp == NULL) {
38151342Sbostic 		/* Allocate a new segment if necessary. */
38251215Sbostic 		if (sp->seg_bytes_left < fs->lfs_bsize) {
38351215Sbostic 			lfs_writeseg(fs, sp);
38451215Sbostic 			sp = lfs_newseg(fs);
38551215Sbostic 		}
38651342Sbostic 
38751342Sbostic 		/* Get the next summary block. */
38851342Sbostic 		sp->sum_addr = next(fs, sp, &nblocks);
38951342Sbostic 
39051342Sbostic 		/*
39151342Sbostic 		 * Get a new buffer and enter into the buffer list from
39251342Sbostic 		 * the top of the list.
39351342Sbostic 		 */
39451342Sbostic 		sp->sbp = sp->bpp[fs->lfs_ssize - (nblocks + 1)] =
39551342Sbostic 		    lfs_newbuf(fs, sp->sum_addr, fs->lfs_bsize);
39651342Sbostic 
39751342Sbostic 		sp->seg_bytes_left -= fs->lfs_bsize;
39851342Sbostic 
39951342Sbostic 		/*
40051342Sbostic 		 * Do a callback for all but the very last summary block in
40151342Sbostic 		 * the segment, for which we wait.
40251342Sbostic 		 */
40351342Sbostic 		if (sp->nsums != 0)
40451301Sbostic 			sp->sbp->b_flags |= B_CALL;
40551342Sbostic 		/*
40651342Sbostic 		 * Fill in the block from the end.  The summary block is filled
40751342Sbostic 		 * in from the end to the beginning so that the last summary
40851342Sbostic 		 * is the last thing written, verifying the entire block.  This
40951342Sbostic 		 * should go away when fragments are available.
41051342Sbostic 		 */
41151301Sbostic 		sp->segsum =
41251301Sbostic 		    sp->sbp->b_un.b_addr + fs->lfs_bsize - LFS_SUMMARY_SIZE;
41351215Sbostic 		sp->sum_addr += (fs->lfs_bsize - LFS_SUMMARY_SIZE) / DEV_BSIZE;
41451342Sbostic 
41551356Sbostic #ifdef SEGWRITE
41651342Sbostic 		printf("alloc summary: bp %x, lblkno %x, bp index %d\n",
41751342Sbostic 		    sp->sbp, sp->sbp->b_lblkno, fs->lfs_ssize - nblocks);
41851356Sbostic #endif
41951188Sbostic 	} else {
42051215Sbostic 		sp->segsum -= LFS_SUMMARY_SIZE;
42151215Sbostic 		sp->sum_addr -= LFS_SUMMARY_SIZE / DEV_BSIZE;
42251188Sbostic 	}
42351342Sbostic 	++sp->nsums;
42451188Sbostic 
42551342Sbostic 	/* Set point to SEGSUM, initialize it. */
42651215Sbostic 	ssp = sp->segsum;
42751301Sbostic 	ssp->ss_next = fs->lfs_nextseg;
42851215Sbostic 	ssp->ss_prev = fs->lfs_lastseg;
42951188Sbostic 	ssp->ss_nextsum = (daddr_t)-1;
43051188Sbostic 	ssp->ss_create = time.tv_sec;
43151342Sbostic 	ssp->ss_nfinfo = ssp->ss_ninos = 0;
43251188Sbostic 
43351342Sbostic 	/* Set pointer to first FINFO, initialize it. */
43451342Sbostic 	sp->fip = (FINFO *)(sp->segsum + sizeof(SEGSUM));
43551342Sbostic 
43651342Sbostic 	sp->sum_bytes_left = LFS_SUMMARY_SIZE - sizeof(SEGSUM);
43751342Sbostic 	return (sp);
43851188Sbostic }
43951188Sbostic 
44051342Sbostic #define seginc(fs, sn)		/* increment segment number */ \
44151342Sbostic 	(((sn) + 1) % (fs)->lfs_nseg)
44251342Sbostic /*
44351342Sbostic  * Return the next segment to write.
44451342Sbostic  */
44551188Sbostic static daddr_t
44651188Sbostic lfs_nextseg(fs)
447*51499Sbostic 	struct lfs *fs;
44851188Sbostic {
44951188Sbostic 	int segnum, sn;
45051188Sbostic 
45151342Sbostic 	segnum = sn = datosn(fs, fs->lfs_nextseg);
45251342Sbostic 	while ((sn = seginc(fs, sn)) != segnum &&
45351342Sbostic 	    fs->lfs_segtab[sn].su_flags & SEGUSE_DIRTY);
45451215Sbostic 
45551188Sbostic 	if (sn == segnum)
45651188Sbostic 		panic("lfs_nextseg: file system full");		/* XXX */
45751342Sbostic 	return (sntoda(fs, sn));
45851188Sbostic }
45951188Sbostic 
46051188Sbostic /*
46151342Sbostic  * Update the metadata that points to the blocks listed in the FINFO
46251188Sbostic  * array.
46351188Sbostic  */
46451215Sbostic static void
46551215Sbostic lfs_updatemeta(fs, sp, ip, lbp, bpp, nblocks)
466*51499Sbostic 	struct lfs *fs;
46751215Sbostic 	SEGMENT *sp;
46851188Sbostic 	INODE *ip;
46951215Sbostic 	daddr_t *lbp;
47051188Sbostic 	BUF **bpp;
47151215Sbostic 	int nblocks;
47251188Sbostic {
47351188Sbostic 	SEGUSE *segup;
47451342Sbostic 	BUF **lbpp, *bp;
47551342Sbostic 	daddr_t daddr, iblkno;
47651342Sbostic 	int db_per_fsb, error, i;
47751215Sbostic 	long lbn;
47851188Sbostic 
47951342Sbostic 	if (nblocks == 0)
48051215Sbostic 		return;
48151215Sbostic 
48251342Sbostic 	/* Sort the blocks and add disk addresses */
48351215Sbostic 	shellsort(bpp, lbp, nblocks);
48451215Sbostic 
48551215Sbostic 	db_per_fsb = 1 << fs->lfs_fsbtodb;
48651342Sbostic 	for (lbpp = bpp, i = 0; i < nblocks; ++i, ++lbpp) {
48751215Sbostic 		(*lbpp)->b_blkno = sp->saddr;
48851215Sbostic 		sp->saddr += db_per_fsb;
48951215Sbostic 	}
49051215Sbostic 
49151342Sbostic 	for (lbpp = bpp, i = 0; i < nblocks; ++i, ++lbpp) {
49251215Sbostic 		lbn = lbp[i];
49351342Sbostic 		if (error = lfs_bmap(ip, lbn, &daddr))
49451342Sbostic 			panic("lfs_updatemeta: lfs_bmap");
49551188Sbostic 
49651342Sbostic 		/* Update in-core copy of old segment usage information. */
49751342Sbostic 		if (daddr != UNASSIGNED) {
49851342Sbostic 			segup = fs->lfs_segtab + datosn(fs, daddr);
49951188Sbostic 			segup->su_lastmod = time.tv_sec;
50051342Sbostic #ifdef DIAGNOSTIC
50151356Sbostic 			if (segup->su_nbytes < fs->lfs_bsize)
50251356Sbostic 				panic("lfs: negative bytes (segment %d)\n",
50351342Sbostic 				    segup - fs->lfs_segtab);
50451342Sbostic #endif
50551342Sbostic 			segup->su_nbytes -= fs->lfs_bsize;
50651188Sbostic 		}
50751188Sbostic 
50851215Sbostic 		/*
50951342Sbostic 		 * Now change whomever points to lbn.  We could start with the
51051215Sbostic 		 * smallest (most negative) block number in these if clauses,
51151215Sbostic 		 * but we assume that indirect blocks are least common, and
51251342Sbostic 		 * handle them separately.  The test for < 0 is correct and
51351342Sbostic 		 * minimizes the path in the common case.
51451215Sbostic 		 */
51551342Sbostic #define	BREAD(bno) \
51651342Sbostic 	if (error = bread(ITOV(ip), (bno), fs->lfs_bsize, NOCRED, &bp)) \
51751342Sbostic 		panic("lfs_updatemeta: bread");
51851342Sbostic 
51951342Sbostic 		if (lbn < 0)
52051215Sbostic 			if (lbn < -NIADDR) {
52151356Sbostic #ifdef META
52251342Sbostic 				printf("meta: update indirect block %d\n",
52351342Sbostic 				    D_INDIR);
52451356Sbostic #endif
52551342Sbostic 				BREAD(D_INDIR);
52651342Sbostic 				bp->b_un.b_daddr[-lbn % NINDIR(fs)] =
52751215Sbostic 				    (*lbpp)->b_blkno;
52851342Sbostic 				lfs_bwrite(bp);
52951342Sbostic 			} else {
53051342Sbostic 				ip->i_ib[-lbn-1] = (*lbpp)->b_blkno;
53151342Sbostic 		} else if (lbn < NDADDR) {
53251342Sbostic 			ip->i_db[lbn] = (*lbpp)->b_blkno;
53351342Sbostic 		} else if ((lbn -= NDADDR) < NINDIR(fs)) {
53451356Sbostic #ifdef META
53551342Sbostic 			printf("meta: update indirect block %d\n", S_INDIR);
53651356Sbostic #endif
53751342Sbostic 			BREAD(S_INDIR);
53851188Sbostic 			bp->b_un.b_daddr[lbn] = (*lbpp)->b_blkno;
53951342Sbostic 			lfs_bwrite(bp);
54051342Sbostic 		} else if ((lbn =
54151342Sbostic 		    (lbn - NINDIR(fs)) / NINDIR(fs)) < NINDIR(fs)) {
54251342Sbostic 			iblkno = -(lbn + NIADDR + 1);
54351356Sbostic #ifdef META
54451342Sbostic 			printf("meta: update indirect block %d\n", iblkno);
54551356Sbostic #endif
54651342Sbostic 			BREAD(iblkno);
54751188Sbostic 			bp->b_un.b_daddr[lbn % NINDIR(fs)] = (*lbpp)->b_blkno;
54851342Sbostic 			lfs_bwrite(bp);
54951342Sbostic 		} else
55051215Sbostic 			panic("lfs_updatemeta: logical block number too large");
55151188Sbostic 	}
55251188Sbostic }
55351188Sbostic 
55451301Sbostic static SEGMENT *
55551215Sbostic lfs_writeckp(fs, sp)
556*51499Sbostic 	struct 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 	/*
56851215Sbostic 	 * This will write the dirty ifile blocks, but not the segusage
56951215Sbostic 	 * table nor the ifile inode.
57051215Sbostic 	 */
57151342Sbostic 	sp = lfs_writefile(fs, sp, fs->lfs_ivnode, 1);
57251215Sbostic 
57351215Sbostic 	/*
57451342Sbostic 	 * If the segment usage table and the ifile inode won't fit in this
57551342Sbostic 	 * segment, put them in the next one.
57651215Sbostic 	 */
57751215Sbostic 	bytes_needed = fs->lfs_segtabsz << fs->lfs_bshift;
57851215Sbostic 	if (sp->ninodes % INOPB(fs) == 0)
57951215Sbostic 		bytes_needed += fs->lfs_bsize;
58051215Sbostic 
58151215Sbostic 	if (sp->seg_bytes_left < bytes_needed) {
58251215Sbostic 		lfs_writeseg(fs, sp);
58351215Sbostic 		sp = lfs_newseg(fs);
58451342Sbostic 		++((SEGSUM *)(sp->segsum))->ss_nfinfo;
58551342Sbostic 	} else if (sp->sum_bytes_left < fs->lfs_segtabsz * sizeof(daddr_t)) {
58651342Sbostic 		sp = lfs_newsum(fs, sp);
58751342Sbostic 		++((SEGSUM *)(sp->segsum))->ss_nfinfo;
58851342Sbostic 	}
58951215Sbostic 
59051215Sbostic #ifdef DEBUG
59151215Sbostic 	if (sp->seg_bytes_left < bytes_needed)
59251215Sbostic 		panic("lfs_writeckp: unable to write checkpoint");
59351215Sbostic #endif
59451215Sbostic 	/*
59551301Sbostic 	 * Update the segment usage information and the ifile inode
59651301Sbostic 	 * and write it out.
59751215Sbostic 	 */
59851215Sbostic 	sup = fs->lfs_segtab + sp->seg_number;
59951301Sbostic 	sup->su_nbytes =
60051301Sbostic 	    (fs->lfs_segmask + 1) - sp->seg_bytes_left + bytes_needed;
60151215Sbostic 	sup->su_lastmod = time.tv_sec;
60251215Sbostic 	sup->su_flags = SEGUSE_DIRTY;
60351215Sbostic 
60451342Sbostic 	/*
60551342Sbostic 	 * Get buffers for the segusage table and write it out.  Don't
60651342Sbostic 	 * bother updating the FINFO pointer, it's not used after this.
60751342Sbostic 	 */
60851215Sbostic 	ip = VTOI(fs->lfs_ivnode);
60951215Sbostic 	fip = sp->fip;
61051215Sbostic 	lbp = &fip->fi_blocks[fip->fi_nblocks];
61151342Sbostic 	for (xp = fs->lfs_segtab, i = 0; i < fs->lfs_segtabsz;
61251342Sbostic 	    xp += fs->lfs_bsize, ++i, ++lbp) {
61351301Sbostic 		*sp->cbpp++ = bp = lfs_newbuf(fs, sp->saddr, fs->lfs_bsize);
61451301Sbostic 		bp->b_flags |= B_CALL;
61551342Sbostic 		bcopy(xp, bp->b_un.b_addr, fs->lfs_bsize);
61651342Sbostic 		ip->i_db[i] = sp->saddr;
61751215Sbostic 		sp->saddr += (1 << fs->lfs_fsbtodb);
61851215Sbostic 		*lbp = i;
61951342Sbostic 		++fip->fi_nblocks;
62051215Sbostic 	}
62151342Sbostic 	return (lfs_writeinode(fs, sp, VTOI(fs->lfs_ivnode)));
62251215Sbostic }
62351215Sbostic 
62451188Sbostic /*
62551342Sbostic  * Write the dirty blocks associated with a vnode.
62651188Sbostic  */
62751188Sbostic static SEGMENT *
62851342Sbostic lfs_writefile(fs, sp, vp, do_ckp)
629*51499Sbostic 	struct lfs *fs;
63051188Sbostic 	SEGMENT *sp;
63151188Sbostic 	VNODE *vp;
63251215Sbostic 	int do_ckp;
63351188Sbostic {
63451188Sbostic 	FINFO *fip;
63551301Sbostic 	ino_t inum;
63651188Sbostic 
63751301Sbostic 	inum = VTOI(vp)->i_number;
63851188Sbostic 
63951342Sbostic 	if (vp->v_dirtyblkhd != NULL) {
64051342Sbostic 		if (sp->seg_bytes_left < fs->lfs_bsize) {
64151342Sbostic 			lfs_writeseg(fs, sp);
64251342Sbostic 			sp = lfs_newseg(fs);
64351342Sbostic 		} else if (sp->sum_bytes_left < sizeof(FINFO))
64451342Sbostic 			sp = lfs_newsum(fs, sp);
64551342Sbostic 		sp->sum_bytes_left -= sizeof(FINFO) - sizeof(daddr_t);
64651188Sbostic 
64751215Sbostic 		fip = sp->fip;
64851342Sbostic 		fip->fi_nblocks = 0;
64951342Sbostic 		fip->fi_version =
65051342Sbostic 		    inum == LFS_IFILE_INUM ? 1 : lfs_getversion(fs, inum);
65151342Sbostic 		fip->fi_ino = inum;
65251342Sbostic 
65351342Sbostic 		sp = lfs_gather(fs, sp, vp, match_data);
65451342Sbostic 		if (do_ckp) {
65551342Sbostic 			sp = lfs_gather(fs, sp, vp, match_indir);
65651342Sbostic 			sp = lfs_gather(fs, sp, vp, match_dindir);
65751188Sbostic 		}
65851342Sbostic 
65951342Sbostic 		fip = sp->fip;
66051356Sbostic 
66151356Sbostic #ifdef META
66251342Sbostic 		printf("lfs_writefile: adding %d blocks\n", fip->fi_nblocks);
66351356Sbostic #endif
66451342Sbostic 		/*
66551342Sbostic 		 * If this is the ifile, always update the file count as we'll
66651342Sbostic 		 * be adding the segment usage information even if we didn't
66751342Sbostic 		 * write any blocks.  Also, don't update the FINFO pointer for
66851342Sbostic 		 * the ifile as the segment usage information hasn't yet been
66951342Sbostic 		 * added.
67051342Sbostic 		 */
67151342Sbostic 		if (inum == LFS_IFILE_INUM)
67251342Sbostic 			++((SEGSUM *)(sp->segsum))->ss_nfinfo;
67351342Sbostic 		else if (fip->fi_nblocks != 0) {
67451342Sbostic 			++((SEGSUM *)(sp->segsum))->ss_nfinfo;
67551342Sbostic 			sp->fip = (FINFO *)((caddr_t)fip + sizeof(FINFO) +
67651342Sbostic 			    sizeof(daddr_t) * (fip->fi_nblocks - 1));
67751342Sbostic 		}
67851188Sbostic 	}
67951342Sbostic 
68051342Sbostic 	/* If this isn't the ifile, update the inode. */
68151342Sbostic 	if (inum != LFS_IFILE_INUM)
68251342Sbostic 		sp = lfs_writeinode(fs, sp, VTOI(vp));
68351342Sbostic 	return (sp);
68451188Sbostic }
68551188Sbostic 
68651215Sbostic static SEGMENT *
68751342Sbostic lfs_writeinode(fs, sp, ip)
688*51499Sbostic 	struct lfs *fs;
68951215Sbostic 	SEGMENT *sp;
69051342Sbostic 	INODE *ip;
69151188Sbostic {
69251215Sbostic 	BUF *bp;
69351342Sbostic 	daddr_t next_addr;
69451342Sbostic 	int nblocks;
69551215Sbostic 
69651342Sbostic 	/* Allocate a new inode block if necessary. */
69751215Sbostic 	if (sp->ibp == NULL) {
69851342Sbostic 		/* Allocate a new segment if necessary. */
69951215Sbostic 		if (sp->seg_bytes_left < fs->lfs_bsize) {
70051215Sbostic 			lfs_writeseg(fs, sp);
70151215Sbostic 			sp = lfs_newseg(fs);
70251215Sbostic 		}
70351342Sbostic 
70451342Sbostic 		/* Get next inode block. */
70551342Sbostic 		next_addr = next(fs, sp, &nblocks);
70651342Sbostic 
70751342Sbostic 		/*
70851342Sbostic 		 * Get a new buffer and enter into the buffer list from
70951342Sbostic 		 * the top of the list.
71051342Sbostic 		 */
71151342Sbostic 		sp->ibp = sp->bpp[fs->lfs_ssize - (nblocks + 1)] =
71251342Sbostic 		    lfs_newbuf(fs, next_addr, fs->lfs_bsize);
71351301Sbostic 		sp->ibp->b_flags |= B_CALL;
71451342Sbostic 
71551342Sbostic 		/* Set remaining space counter. */
71651215Sbostic 		sp->seg_bytes_left -= fs->lfs_bsize;
71751215Sbostic 	}
71851342Sbostic 
71951342Sbostic 	/* Copy the new inode onto the inode page. */
72051215Sbostic 	bp = sp->ibp;
72151342Sbostic 	bcopy(&ip->i_din,
72251342Sbostic 	    bp->b_un.b_dino + (sp->ninodes % INOPB(fs)), sizeof(DINODE));
72351342Sbostic 
72451342Sbostic 	/* Increment inode count in segment summary block. */
72551342Sbostic 	++((SEGSUM *)(sp->segsum))->ss_ninos;
72651342Sbostic 
72751342Sbostic 	/* If this page is full, set flag to allocate a new page. */
72851342Sbostic 	if (++sp->ninodes % INOPB(fs) == 0)
72951215Sbostic 		sp->ibp = NULL;
73051342Sbostic 
73151342Sbostic 	/*
73251342Sbostic 	 * If updating the ifile, update the super-block; otherwise, update
73351342Sbostic 	 * the ifile itself.  In either case, turn of inode update flags.
73451342Sbostic 	 */
73551215Sbostic 	if (ip->i_number == LFS_IFILE_INUM)
73651342Sbostic 		fs->lfs_idaddr = bp->b_blkno;
73751215Sbostic 	else
73851342Sbostic 		lfs_iset(ip, bp->b_blkno, ip->i_atime);
73951342Sbostic 	ip->i_flags &= ~(IMOD | IACC | IUPD | ICHG);
74051342Sbostic 	return (sp);
74151188Sbostic }
74251188Sbostic 
74351188Sbostic static void
74451188Sbostic lfs_writeseg(fs, sp)
745*51499Sbostic 	struct lfs *fs;
74651188Sbostic 	SEGMENT *sp;
74751188Sbostic {
74851215Sbostic 	BUF **bpp;
74951188Sbostic 	SEGUSE *sup;
75051342Sbostic 	int i, nblocks, s, (*strategy) __P((BUF *));
75151342Sbostic 	void *pmeta;
75251188Sbostic 
75351342Sbostic 	/* Update superblock segment address. */
75451342Sbostic 	fs->lfs_lastseg = sntoda(fs, sp->seg_number);
75551342Sbostic 
75651342Sbostic 	/* Finish up any summary block. */
75751215Sbostic 	lfs_endsum(fs, sp, 0);
75851188Sbostic 
75951188Sbostic 	/*
76051188Sbostic 	 * Copy inode and summary block buffer pointers down so they are
76151215Sbostic 	 * contiguous with the page buffer pointers.
76251188Sbostic 	 */
76351342Sbostic 	(void)next(fs, sp, &nblocks);
76451342Sbostic 	pmeta = (sp->bpp + fs->lfs_ssize) - nblocks;
76551342Sbostic 	if (pmeta != sp->cbpp)
76651342Sbostic 		bcopy(pmeta, sp->cbpp, sizeof(BUF *) * nblocks);
76751342Sbostic 	sp->cbpp += nblocks;
76851342Sbostic 	nblocks = sp->cbpp - sp->bpp;
76951188Sbostic 
77051188Sbostic 	sup = fs->lfs_segtab + sp->seg_number;
77151188Sbostic 	sup->su_nbytes = nblocks << fs->lfs_bshift;
77251188Sbostic 	sup->su_lastmod = time.tv_sec;
77351188Sbostic 	sup->su_flags = SEGUSE_DIRTY;
77451188Sbostic 
77551188Sbostic 	/*
77651215Sbostic 	 * Since we need to guarantee that the summary block gets written last,
77751188Sbostic 	 * we issue the writes in two sets.  The first n-1 buffers first, and
77851301Sbostic 	 * then, after they've completed, the summary buffer.  Only when that
77951215Sbostic 	 * final write completes is the segment valid.
78051188Sbostic 	 */
78151342Sbostic 	--nblocks;			/* Don't count last summary block. */
78251301Sbostic 
78351188Sbostic 	sp->nextp = fs->lfs_seglist;
78451188Sbostic 	fs->lfs_seglist = sp;
78551215Sbostic 
78651301Sbostic 	s = splbio();
78751301Sbostic 	fs->lfs_iocount += nblocks;
78851301Sbostic 	splx(s);
78951342Sbostic 
79051342Sbostic 	strategy =
79151342Sbostic 	    VFSTOUFS(fs->lfs_ivnode->v_mount)->um_devvp->v_op->vop_strategy;
79251301Sbostic 	for (bpp = sp->bpp, i = 0; i < nblocks; ++i, ++bpp)
79351342Sbostic 		(strategy)(*bpp);
79451188Sbostic }
79551188Sbostic 
79651215Sbostic static void
79751301Sbostic lfs_writesum(fs)
798*51499Sbostic 	struct lfs *fs;
79951301Sbostic {
80051301Sbostic 	BUF *bp;
80151301Sbostic 	SEGMENT *next_sp, *sp;
80251342Sbostic 	int (*strategy) __P((BUF *));
80351301Sbostic 
80451342Sbostic 	strategy =
80551342Sbostic 	    VFSTOUFS(fs->lfs_ivnode->v_mount)->um_devvp->v_op->vop_strategy;
80651301Sbostic 	for (sp = fs->lfs_seglist; sp; sp = next_sp) {
80751301Sbostic 		bp = *(sp->cbpp - 1);
80851342Sbostic 		(strategy)(bp);
80951301Sbostic 		biowait(bp);
81051356Sbostic 		bp->b_vp = NULL;		/* No associated vnode. */
81151356Sbostic 		brelse(bp);
81251356Sbostic 
81351301Sbostic 		next_sp = sp->nextp;
81451301Sbostic 		free(sp->bpp, M_SEGMENT);
81551301Sbostic 		free(sp, M_SEGMENT);
81651301Sbostic 	}
81751342Sbostic 	/* Segment list is done. */
81851342Sbostic 	fs->lfs_seglist = NULL;
81951301Sbostic }
82051301Sbostic 
82151301Sbostic static void
82251342Sbostic lfs_writesuper(fs)
823*51499Sbostic 	struct lfs *fs;
82451215Sbostic {
82551215Sbostic 	BUF *bp;
82651342Sbostic 	int (*strategy) __P((BUF *));
82751215Sbostic 
82851356Sbostic 	strategy =
82951356Sbostic 	    VFSTOUFS(fs->lfs_ivnode->v_mount)->um_devvp->v_op->vop_strategy;
83051356Sbostic 
83151342Sbostic 	/* Checksum the superblock and copy it into a buffer. */
832*51499Sbostic 	fs->lfs_cksum = cksum(fs, sizeof(struct lfs) - sizeof(fs->lfs_cksum));
83351215Sbostic 	bp = lfs_newbuf(fs, fs->lfs_sboffs[0], LFS_SBPAD);
834*51499Sbostic 	bcopy(fs, bp->b_un.b_lfs, sizeof(struct lfs));
83551215Sbostic 
83651356Sbostic 	/* Write the first superblock (wait). */
83751342Sbostic 	(strategy)(bp);
83851215Sbostic 	biowait(bp);
83951342Sbostic 
84051356Sbostic 	/* Write the second superblock (don't wait). */
84151215Sbostic 	bp->b_flags &= ~B_DONE;
84251356Sbostic 	bp->b_flags |= B_ASYNC;
84351356Sbostic 	bp->b_vp = NULL;			/* No associated vnode. */
84451215Sbostic 	bp->b_blkno = bp->b_lblkno = fs->lfs_sboffs[1];
84551342Sbostic 	(strategy)(bp);
84651215Sbostic }
84751215Sbostic 
84851342Sbostic /*
84951342Sbostic  * Logical block number match routines used when traversing the dirty block
85051342Sbostic  * chain.
85151342Sbostic  */
85251490Sbostic static int
85351215Sbostic match_data(bp)
85451215Sbostic 	BUF *bp;
85551215Sbostic {
85651342Sbostic 	return (bp->b_lblkno >= 0);
85751215Sbostic }
85851215Sbostic 
85951490Sbostic static int
86051215Sbostic match_dindir(bp)
86151215Sbostic 	BUF *bp;
86251215Sbostic {
86351342Sbostic 	return (bp->b_lblkno == D_INDIR);
86451215Sbostic }
86551215Sbostic 
86651188Sbostic /*
86751215Sbostic  * These are single indirect blocks.  There are three types:
86851342Sbostic  *
86951342Sbostic  * the one in the inode (lblkno == S_INDIR, or -1).
87051342Sbostic  * the ones that hang off of the double indirect in the inode (D_INDIR);
87151342Sbostic  *    these all have addresses in the range -2NINDIR to -(3NINDIR-1).
87251342Sbostic  * the ones that hang off of the double indirect that hangs off of the
87351342Sbostic  *    triple indirect.  These all have addresses < -(NINDIR^2).
87451342Sbostic  *
87551342Sbostic  * Since we currently don't support triple indirect blocks, this gets
87651342Sbostic  * simpler, and we just look for block numbers less than -NIADDR.
87751215Sbostic  */
87851490Sbostic static int
87951215Sbostic match_indir(bp)
88051215Sbostic 	BUF *bp;
88151215Sbostic {
88251342Sbostic 	return (bp->b_lblkno == S_INDIR || bp->b_lblkno < -NIADDR);
88351215Sbostic }
88451215Sbostic 
88551342Sbostic /* Get the next inode/summary block. */
88651342Sbostic static daddr_t
88751342Sbostic next(fs, sp, nbp)
888*51499Sbostic 	struct lfs *fs;
88951342Sbostic 	SEGMENT *sp;
89051342Sbostic 	int *nbp;
89151342Sbostic {
89251342Sbostic 	int nblocks, nino_blocks, nseg_blocks, sums_per_block;
89351342Sbostic 
89451342Sbostic 	/* Fs blocks allocated to summary blocks. */
89551342Sbostic 	sums_per_block = fs->lfs_bsize / LFS_SUMMARY_SIZE;
89651342Sbostic 	nseg_blocks = (sp->nsums + sums_per_block - 1) / sums_per_block;
89751342Sbostic 
89851342Sbostic 	/* Fs blocks allocated to inodes. */
89951342Sbostic 	nino_blocks = (sp->ninodes + INOPB(fs) - 1) / INOPB(fs);
90051342Sbostic 
90151342Sbostic 	/* Total number of fs blocks allocated. */
90251342Sbostic 	nblocks = nseg_blocks + nino_blocks;
90351342Sbostic 
90451342Sbostic 	if (nbp)
90551342Sbostic 		*nbp = nblocks;
90651342Sbostic 
90751342Sbostic 	/*
90851342Sbostic 	 * The disk address of the new inode/summary block is the address of
90951342Sbostic 	 * the start of the segment after this one minus the number of blocks
91051342Sbostic 	 * that we've already used.
91151342Sbostic 	 */
91251342Sbostic 	return (sntoda(fs, sp->seg_number + 1) - fsbtodb(fs, nblocks + 1));
91351342Sbostic }
91451342Sbostic 
91551215Sbostic /*
91651188Sbostic  * Shellsort (diminishing increment sort) from Data Structures and
91751188Sbostic  * Algorithms, Aho, Hopcraft and Ullman, 1983 Edition, page 290;
91851188Sbostic  * see also Knuth Vol. 3, page 84.  The increments are selected from
91951188Sbostic  * formula (8), page 95.  Roughly O(N^3/2).
92051188Sbostic  */
92151188Sbostic /*
92251188Sbostic  * This is our own private copy of shellsort because we want to sort
92351188Sbostic  * two parallel arrays (the array of buffer pointers and the array of
92451188Sbostic  * logical block numbers) simultaneously.  Note that we cast the array
92551188Sbostic  * of logical block numbers to a unsigned in this routine so that the
92651188Sbostic  * negative block numbers (meta data blocks) sort AFTER the data blocks.
92751188Sbostic  */
92851188Sbostic static void
92951188Sbostic shellsort(bp_array, lb_array, nmemb)
93051188Sbostic 	BUF **bp_array;
93151215Sbostic 	daddr_t *lb_array;
93251188Sbostic 	register int nmemb;
93351188Sbostic {
93451188Sbostic 	static int __rsshell_increments[] = { 4, 1, 0 };
93551188Sbostic 	register int incr, *incrp, t1, t2;
93651188Sbostic 	BUF *bp_temp;
93751188Sbostic 	u_long lb_temp;
93851188Sbostic 
93951188Sbostic 	for (incrp = __rsshell_increments; incr = *incrp++;)
94051188Sbostic 		for (t1 = incr; t1 < nmemb; ++t1)
94151188Sbostic 			for (t2 = t1 - incr; t2 >= 0;)
94251188Sbostic 				if (lb_array[t2] > lb_array[t2 + incr]) {
94351188Sbostic 					lb_temp = lb_array[t2];
94451188Sbostic 					lb_array[t2] = lb_array[t2 + incr];
94551188Sbostic 					lb_array[t2 + incr] = lb_temp;
94651188Sbostic 					bp_temp = bp_array[t2];
94751188Sbostic 					bp_array[t2] = bp_array[t2 + incr];
94851188Sbostic 					bp_array[t2 + incr] = bp_temp;
94951188Sbostic 					t2 -= incr;
95051188Sbostic 				} else
95151188Sbostic 					break;
95251188Sbostic }
953