xref: /csrg-svn/sys/ufs/lfs/lfs_segment.c (revision 51215)
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