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