Subject: sector size != DEV_BSIZE -- revised patches
To: None <tech-kern@netbsd.org>
From: Trevin Beattie <trevin@xmission.com>
List: tech-kern
Date: 06/08/2002 19:29:07
--Boundary_(ID_EuO+FP843wYApWVDCvIRvw)
Content-type: text/plain; charset=us-ascii
Content-transfer-encoding: 7BIT

After taking everybody's suggestions into account, I've made some more
changes to the ffs.  In particular, I've retracted my previous changes to
newfs/mkfs, so that certain fields remain in terms of physical sector size
and *not* DEV_BSIZE.  And I've carefully checked the ffs driver to make
sure it only used physical parameters where appropriate, and using the
correct fields in the super block to convert those to byte offsets.

With the patches, I have managed to create a new file system on a virtual
disk using 2048 bytes per sector, mount it, and write some files.  Then,
just for fun, I tried reconfiguring the virtual disk for 512 bytes per
sector and mounted it again.  It still worked!  I wasn't sure whether it
would, because the disk label still reads 2048 B/s.

Note that some of the patches are mostly additions to or changes in
comments, which I put in to clarify (for me) what the code was / should be
doing.  Feel free to accept or ignore those changes.

Still haven't tried this out on a real MO disk yet.

The significant code changes are:

In arch/i386/i386/disksubr.c, fixed partition boundary checking

In ufs/ffs/ffs_vfsops.c, make sure super-block is read from the correct
(byte) offset

** In ufs/ffs/fs.h, changed the macros fsbtodb() and dbtofsb() to convert
to/from DEV_BSHIFT units instead of sectors.  This change needs more
careful examination, because I have no idea whether any external programs
use them.  Also, I have only audited their use in the ffs file system; I
have not checked lfs, ext2fs, mfs, or whatever other file systems may use
them.

In sbin/newfs/mkfs.c, use NSPF() instead of fsbtodb()

In sbin/newfs/newfs.c, read the file system size in bytes instead of
sectors until after the options have been parsed and the sector size is known.

--Boundary_(ID_EuO+FP843wYApWVDCvIRvw)
Content-type: text/plain; charset=iso-8859-1; NAME=ffs-patch
Content-transfer-encoding: 7BIT
Content-disposition: attachment; filename=ffs-patch

diff -u /usr/src/sys/arch/i386/i386/disksubr.c /home/trevin/src/sys/arch/i386/i386/disksubr.c
--- /usr/src/sys/arch/i386/i386/disksubr.c	Wed Feb 20 04:10:35 2002
+++ /home/trevin/src/sys/arch/i386/i386/disksubr.c	Fri May 31 12:31:00 2002
@@ -140,6 +140,7 @@
 	struct disklabel *dlp;
 	char *msg = NULL;
 	int dospartoff, cyl, i, *ip;
+	int sectodbs = lp->d_secsize / DEV_BSIZE;
 
 	/* minimal requirements for archtypal disk label */
 	if (lp->d_secsize == 0)
@@ -170,13 +171,13 @@
 
 	/* do dos partitions in the process of getting disklabel? */
 	dospartoff = 0;
-	cyl = LABELSECTOR / lp->d_secpercyl;
+	cyl = LABELSECTOR / (lp->d_secpercyl * sectodbs);
 	if (!osdep)
 		goto nombrpart;
 	dp = osdep->dosparts;
 
 	/* read master boot record */
-	bp->b_blkno = MBR_BBSECTOR;
+	bp->b_blkno = MBR_BBSECTOR * sectodbs;
 	bp->b_bcount = lp->d_secsize;
 	bp->b_flags |= B_READ;
 	bp->b_cylinder = MBR_BBSECTOR / lp->d_secpercyl;
@@ -244,7 +245,7 @@
 
 nombrpart:
 	/* next, dig out disk label */
-	bp->b_blkno = dospartoff + LABELSECTOR;
+	bp->b_blkno = dospartoff * sectodbs + LABELSECTOR;
 	bp->b_cylinder = cyl;
 	bp->b_bcount = lp->d_secsize;
 	bp->b_flags &= ~(B_DONE);
@@ -388,6 +389,7 @@
 	struct buf *bp;
 	struct disklabel *dlp;
 	int error, dospartoff, cyl;
+	int sectodbs = lp->d_secsize / DEV_BSIZE;
 
 	/* get a buffer and initialize it */
 	bp = geteblk((int)lp->d_secsize);
@@ -395,13 +397,13 @@
 
 	/* do dos partitions in the process of getting disklabel? */
 	dospartoff = 0;
-	cyl = LABELSECTOR / lp->d_secpercyl;
+	cyl = LABELSECTOR / (lp->d_secpercyl * sectodbs);
 	if (!osdep)
 		goto nombrpart;
 	dp = osdep->dosparts;
 
 	/* read master boot record */
-	bp->b_blkno = MBR_BBSECTOR;
+	bp->b_blkno = MBR_BBSECTOR * sectodbs;
 	bp->b_bcount = lp->d_secsize;
 	bp->b_flags |= B_READ;
 	bp->b_cylinder = MBR_BBSECTOR / lp->d_secpercyl;
@@ -433,7 +435,7 @@
 #endif
 
 	/* next, dig out disk label */
-	bp->b_blkno = dospartoff + LABELSECTOR;
+	bp->b_blkno = dospartoff * sectodbs + LABELSECTOR;
 	bp->b_cylinder = cyl;
 	bp->b_bcount = lp->d_secsize;
 	bp->b_flags &= ~(B_DONE);
@@ -475,13 +477,14 @@
 	int wlabel;
 {
 	struct partition *p = lp->d_partitions + DISKPART(bp->b_dev);
-	int labelsector = lp->d_partitions[2].p_offset + LABELSECTOR;
+	int sectodbs = lp->d_secsize / DEV_BSIZE;
+	int labelblock = lp->d_partitions[2].p_offset * sectodbs + LABELSECTOR;
 	int sz;
 
-	sz = howmany(bp->b_bcount, lp->d_secsize);
+	sz = howmany(bp->b_bcount, DEV_BSIZE);
 
-	if (bp->b_blkno + sz > p->p_size) {
-		sz = p->p_size - bp->b_blkno;
+	if (bp->b_blkno + sz > p->p_size * sectodbs) {
+		sz = p->p_size * sectodbs - bp->b_blkno;
 		if (sz == 0) {
 			/* If exactly at end of disk, return EOF. */
 			bp->b_resid = bp->b_bcount;
@@ -497,9 +500,9 @@
 	}
 
 	/* Overwriting disk label? */
-	if (bp->b_blkno + p->p_offset <= labelsector &&
+	if (bp->b_blkno + p->p_offset * sectodbs <= labelblock &&
 #if LABELSECTOR != 0
-	    bp->b_blkno + p->p_offset + sz > labelsector &&
+	    bp->b_blkno + p->p_offset * sectodbs + sz > labelblock &&
 #endif
 	    (bp->b_flags & B_READ) == 0 && !wlabel) {
 		bp->b_error = EROFS;
@@ -507,8 +510,8 @@
 	}
 
 	/* calculate cylinder for disksort to order transfers with */
-	bp->b_cylinder = (bp->b_blkno + p->p_offset) /
-	    (lp->d_secsize / DEV_BSIZE) / lp->d_secpercyl;
+	bp->b_cylinder = (bp->b_blkno / sectodbs + p->p_offset)
+		/ lp->d_secpercyl;
 	return (1);
 
 bad:
diff -u /usr/src/sys/ufs/ffs/ffs_vfsops.c /home/trevin/src/sys/ufs/ffs/ffs_vfsops.c
--- /usr/src/sys/ufs/ffs/ffs_vfsops.c	Wed Apr 10 04:38:14 2002
+++ /home/trevin/src/sys/ufs/ffs/ffs_vfsops.c	Fri Jun  7 17:15:22 2002
@@ -441,7 +441,6 @@
 	void *space;
 	struct buf *bp;
 	struct fs *fs, *newfs;
-	struct partinfo dpart;
 	int i, blks, size, error;
 	int32_t *lp;
 	caddr_t cp;
@@ -460,11 +459,8 @@
 	/*
 	 * Step 2: re-read superblock from disk.
 	 */
-	if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
-		size = DEV_BSIZE;
-	else
-		size = dpart.disklab->d_secsize;
-	error = bread(devvp, (ufs_daddr_t)(SBOFF / size), SBSIZE, NOCRED, &bp);
+	error = bread(devvp, (ufs_daddr_t)(SBOFF / DEV_BSIZE), SBSIZE,
+		      NOCRED, &bp);
 	if (error) {
 		brelse(bp);
 		return (error);
@@ -611,7 +607,6 @@
 	struct buf *bp;
 	struct fs *fs;
 	dev_t dev;
-	struct partinfo dpart;
 	void *space;
 	int blks;
 	int error, i, size, ronly;
@@ -645,14 +640,10 @@
 	error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
 	if (error)
 		return (error);
-	if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0)
-		size = DEV_BSIZE;
-	else
-		size = dpart.disklab->d_secsize;
-
 	bp = NULL;
 	ump = NULL;
-	error = bread(devvp, (ufs_daddr_t)(SBOFF / size), SBSIZE, cred, &bp);
+	error = bread(devvp, (ufs_daddr_t)(SBOFF / DEV_BSIZE), SBSIZE,
+		      cred, &bp);
 	if (error)
 		goto out;
 
@@ -793,7 +784,7 @@
 	ump->um_devvp = devvp;
 	ump->um_nindir = fs->fs_nindir;
 	ump->um_lognindir = ffs(fs->fs_nindir) - 1;
-	ump->um_bptrtodb = fs->fs_fsbtodb;
+	ump->um_bptrtodb = fs->fs_fshift - DEV_BSHIFT;
 	ump->um_seqinc = fs->fs_frag;
 	for (i = 0; i < MAXQUOTAS; i++)
 		ump->um_quotas[i] = NULLVP;
@@ -1367,7 +1358,7 @@
 	}							/* XXX */
 	fs->fs_maxfilesize = mp->um_savedmaxfilesize;	/* XXX */
 
-	bp = getblk(mp->um_devvp, SBOFF >> (fs->fs_fshift - fs->fs_fsbtodb),
+	bp = getblk(mp->um_devvp, SBOFF >> DEV_BSHIFT,
 	    (int)fs->fs_sbsize, 0, 0);
 	saveflag = fs->fs_flags & FS_INTERNAL;
 	fs->fs_flags &= ~FS_INTERNAL;
diff -u /usr/src/sys/ufs/ffs/fs.h /home/trevin/src/sys/ufs/ffs/fs.h
--- /usr/src/sys/ufs/ffs/fs.h	Thu Apr 11 04:37:24 2002
+++ /home/trevin/src/sys/ufs/ffs/fs.h	Thu Jun  6 16:58:00 2002
@@ -174,12 +174,12 @@
 struct fs {
 	int32_t	 fs_firstfield;		/* historic file system linked list, */
 	int32_t	 fs_unused_1;		/*     used for incore super blocks */
-	ufs_daddr_t fs_sblkno;		/* addr of super-block in filesys */
-	ufs_daddr_t fs_cblkno;		/* offset of cyl-block in filesys */
-	ufs_daddr_t fs_iblkno;		/* offset of inode-blocks in filesys */
-	ufs_daddr_t fs_dblkno;		/* offset of first data after cg */
+	ufs_daddr_t fs_sblkno;		/* offset of dup super-block in cg */
+	ufs_daddr_t fs_cblkno;		/* offset of cyl-block in cyl grp */
+	ufs_daddr_t fs_iblkno;		/* offset of inode-blocks in cyl grp */
+	ufs_daddr_t fs_dblkno;		/* offset of first data block in cg */
 	int32_t	 fs_cgoffset;		/* cylinder group offset in cylinder */
-	int32_t	 fs_cgmask;		/* used to calc mod fs_ntrak */
+	int32_t	 fs_cgmask;		/* used to calc start of cg block */
 	int32_t	 fs_time;		/* last time written */
 	int32_t	 fs_size;		/* number of blocks in fs */
 	int32_t	 fs_dsize;		/* number of data blocks in fs */
@@ -201,13 +201,14 @@
 	int32_t	 fs_maxbpg;		/* max number of blks per cyl group */
 /* these fields can be computed from the others */
 	int32_t	 fs_fragshift;		/* block to frag shift */
-	int32_t	 fs_fsbtodb;		/* fsbtodb and dbtofsb shift constant */
+	int32_t	 fs_fsbtodb;		/* frag to sector shift (don't use
+					 * unless you REALLY want sectors!) */
 	int32_t	 fs_sbsize;		/* actual size of super block */
 	int32_t	 fs_csmask;		/* csum block offset (now unused) */
 	int32_t	 fs_csshift;		/* csum block number (now unused) */
-	int32_t	 fs_nindir;		/* value of NINDIR */
-	int32_t	 fs_inopb;		/* value of INOPB */
-	int32_t	 fs_nspf;		/* value of NSPF */
+	int32_t	 fs_nindir;		/* number of indirects in a block */
+	int32_t	 fs_inopb;		/* number of inodes per block */
+	int32_t	 fs_nspf;		/* number of sectors per fragment */
 /* yet another configuration parameter */
 	int32_t	 fs_optim;		/* optimization preference, see below */
 /* these fields are derived from the hardware */
@@ -229,7 +230,7 @@
 /* these fields can be computed from the others */
 	int32_t	 fs_cpg;		/* cylinders per group */
 	int32_t	 fs_ipg;		/* inodes per group */
-	int32_t	 fs_fpg;		/* blocks per group * fs_frag */
+	int32_t	 fs_fpg;		/* frags per group */
 /* this data must be re-computed after crashes */
 	struct	csum fs_cstotal;	/* cylinder summary information */
 /* these fields are cleared at mount time */
@@ -431,15 +432,16 @@
 };
 
 /*
- * Turn file system block numbers into disk block addresses.
- * This maps file system blocks to device size blocks.
+ * Turn file system block numbers into logical block addresses.
+ * This maps file system blocks to DEV_BSIZE blocks.
  */
-#define	fsbtodb(fs, b)	((b) << (fs)->fs_fsbtodb)
-#define	dbtofsb(fs, b)	((b) >> (fs)->fs_fsbtodb)
+#define	fsbtodb(fs, b)	((b) << ((fs)->fs_fshift - DEV_BSHIFT))
+#define	dbtofsb(fs, b)	((b) >> ((fs)->fs_fshift - DEV_BSHIFT))
 
 /*
  * Cylinder group macros to locate things in cylinder groups.
  * They calc file system addresses of cylinder group data structures.
+ * All values are fragment numbers within the filesystem.
  */
 #define	cgbase(fs, c)	((ufs_daddr_t)((fs)->fs_fpg * (c)))
 #define	cgdmin(fs, c)	(cgstart(fs, c) + (fs)->fs_dblkno)	/* 1st data */
@@ -470,10 +472,12 @@
 
 /*
  * Extract the bits for a block from a map.
- * Compute the cylinder and rotational position of a cyl block addr.
  */
 #define	blkmap(fs, map, loc) \
     (((map)[(loc) / NBBY] >> ((loc) % NBBY)) & (0xff >> (NBBY - (fs)->fs_frag)))
+/*
+ * Compute the cylinder and rotational position of a DEV_BSIZE block addr.
+ */
 #define	cbtocylno(fs, bno) \
     (fsbtodb(fs, bno) / (fs)->fs_spc)
 #define	cbtorpos(fs, bno) \
@@ -532,8 +536,7 @@
 	    : (fragroundup(fs, blkoff(fs, (dip)->di_size))))
 
 /*
- * Number of disk sectors per block/fragment; assumes DEV_BSIZE byte
- * sector size.
+ * Number of physical disk sectors per block/fragment.
  */
 #define	NSPB(fs)	((fs)->fs_nspf << (fs)->fs_fragshift)
 #define	NSPF(fs)	((fs)->fs_nspf)
diff -u /usr/src/sbin/newfs/mkfs.c /home/trevin/src/sbin/newfs/mkfs.c
--- /usr/src/sbin/newfs/mkfs.c	Thu Apr 11 04:17:30 2002
+++ /home/trevin/src/sbin/newfs/mkfs.c	Fri Jun  7 16:57:42 2002
@@ -240,21 +240,41 @@
 	sblock.fs_nrpos = nrpos;
 	sblock.fs_nindir = sblock.fs_bsize / sizeof(daddr_t);
 	sblock.fs_inopb = sblock.fs_bsize / DINODE_SIZE;
+	/* Number of sectors per fragment and fragment -> sector shift const */
 	sblock.fs_nspf = sblock.fs_fsize / sectorsize;
 	for (sblock.fs_fsbtodb = 0, i = NSPF(&sblock); i > 1; i >>= 1)
 		sblock.fs_fsbtodb++;
+	/* The backup super block follows the boot block and primary sb. */
 	sblock.fs_sblkno =
 	    roundup(howmany(bbsize + sbsize, sblock.fs_fsize), sblock.fs_frag);
+	/* The cylinder group block follows the backup super block. */
 	sblock.fs_cblkno = (daddr_t)(sblock.fs_sblkno +
 	    roundup(howmany(sbsize, sblock.fs_fsize), sblock.fs_frag));
+	/* The first inode block follows the cylinder group block. */
 	sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag;
+	/*
+	 * Set the cylinder group offset to the number of frags per track,
+	 * rounded up to the next full block boundary.  This skews the cg
+	 * block by approximately one track per group.
+	 */
 	sblock.fs_cgoffset = roundup(
 	    howmany(sblock.fs_nsect, NSPF(&sblock)), sblock.fs_frag);
+	/*
+	 * Set the cylinder group mask to the number of tracks
+	 * rounded up to the next power of 2, negated.  The
+	 * cgstart() macro uses ~this to wrap the cg block back
+	 * to the first cylinder in the group after fs_cgoffset
+	 * takes it through all of the platters.
+	 */
 	for (sblock.fs_cgmask = 0xffffffff, i = sblock.fs_ntrak; i > 1; i >>= 1)
 		sblock.fs_cgmask <<= 1;
 	if (!POWEROF2(sblock.fs_ntrak))
 		sblock.fs_cgmask <<= 1;
 	sblock.fs_maxfilesize = sblock.fs_bsize * NDADDR - 1;
+	/*
+	 * Each indirect block addresses NINDIR^N * fs_bsize bytes,
+	 * where N is the indirect block number + 1.
+	 */
 	for (sizepb = sblock.fs_bsize, i = 0; i < NIADDR; i++) {
 		sizepb *= NINDIR(&sblock);
 		sblock.fs_maxfilesize += sizepb;
@@ -264,15 +284,26 @@
 	 * and calculate minimum cylinders per group.
 	 */
 	sblock.fs_spc = secpercyl;
+	/*
+	 * cylinders per cycle == number of cylinders required to align
+	 * the first sector in a cylinder on a block boundary.
+	 */
 	for (sblock.fs_cpc = NSPB(&sblock), i = sblock.fs_spc;
 	     sblock.fs_cpc > 1 && (i & 1) == 0;
 	     sblock.fs_cpc >>= 1, i >>= 1)
 		/* void */;
 	mincpc = sblock.fs_cpc;
+	/* Bytes per cylinder */
 	bpcg = sblock.fs_spc * sectorsize;
+	/* Number of inodes that will fit on one cylinder */
 	inospercg = roundup(bpcg / DINODE_SIZE, INOPB(&sblock));
+	/* Cap the result at 1/3 the number of bits in a fs block */
 	if (inospercg > MAXIPG(&sblock))
 		inospercg = MAXIPG(&sblock);
+	/*
+	 * Calculate the number of sectors used in a cylinder
+	 * group by the super block, cylinder block, and inode blocks.
+	 */
 	used = (sblock.fs_iblkno + inospercg / INOPF(&sblock)) * NSPF(&sblock);
 	mincpgcnt = howmany(sblock.fs_cgoffset * (~sblock.fs_cgmask) + used,
 	    sblock.fs_spc);
@@ -396,7 +427,7 @@
 	}
 	sblock.fs_fpg = (sblock.fs_cpg * sblock.fs_spc) / NSPF(&sblock);
 	if ((sblock.fs_cpg * sblock.fs_spc) % NSPB(&sblock) != 0) {
-		printf("panic (fs_cpg * fs_spc) %% NSPF != 0");
+		printf("panic (fs_cpg * fs_spc) %% NSPB != 0");
 		exit(24);
 	}
 	if (sblock.fs_cpg < mincpg) {
@@ -411,7 +442,7 @@
 		else if (mapcramped)
 			printf("Block size restricts");
 		else
-			printf("Bytes per inode restrict");
+			printf("Bytes per inode restricts");
 		printf(" cylinders per group to %d.\n", sblock.fs_cpg);
 		exit(27);
 	}
@@ -419,8 +450,10 @@
 	/*
 	 * Now have size for file system and nsect and ntrak.
 	 * Determine number of cylinders and blocks in the file system.
+	 * ATTENTION: At this point, the units of fssize changes
+	 *	      from sectors to fragments.
 	 */
-	sblock.fs_size = fssize = dbtofsb(&sblock, fssize);
+	sblock.fs_size = fssize = fssize / NSPF(&sblock);
 	sblock.fs_ncyl = fssize * NSPF(&sblock) / sblock.fs_spc;
 	if (fssize * NSPF(&sblock) > sblock.fs_ncyl * sblock.fs_spc) {
 		sblock.fs_ncyl++;
@@ -501,6 +534,9 @@
 	sblock.fs_ncg = sblock.fs_ncyl / sblock.fs_cpg;
 	if (sblock.fs_ncyl % sblock.fs_cpg)
 		sblock.fs_ncg++;
+	/*
+	 * The first data block follows the inode blocks in a cylinder.
+	 */
 	sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock);
 	i = MIN(~sblock.fs_cgmask, sblock.fs_ncg - 1);
 	if (cgdmin(&sblock, i) - cgbase(&sblock, i) >= sblock.fs_fpg) {
@@ -595,14 +631,14 @@
 	 * subwindows in sysinst.
 	 */
 	printcolwidth = count_digits(
-			fsbtodb(&sblock, cgsblock(&sblock, sblock.fs_ncg -1)));
+			cgsblock(&sblock, sblock.fs_ncg -1) * NSPF(&sblock));
 	nprintcols = 76 / (printcolwidth + 2);
 	/*
 	 * Now build the cylinders group blocks and
-	 * then print out indices of cylinder groups.
+	 * then print out sector indices of cylinder groups.
 	 */
 	if (!mfs)
-		printf("super-block backups (for fsck -b #) at:");
+		printf("super-block backups (for fsck -b #) at sector:");
 	for (cylno = 0; cylno < sblock.fs_ncg; cylno++) {
 		initcg(cylno, utime);
 		if (mfs)
@@ -610,7 +646,7 @@
 		if (cylno % nprintcols == 0)
 			printf("\n");
 		printf(" %*d,", printcolwidth,
-				fsbtodb(&sblock, cgsblock(&sblock, cylno)));
+				cgsblock(&sblock, cylno) * NSPF(&sblock));
 		fflush(stdout);
 	}
 	if (!mfs)
@@ -632,7 +668,7 @@
 	 * Write out the duplicate super blocks
 	 */
 	for (cylno = 0; cylno < sblock.fs_ncg; cylno++)
-		wtfs(fsbtodb(&sblock, cgsblock(&sblock, cylno)),
+		wtfs(cgsblock(&sblock, cylno) * NSPF(&sblock),
 		    sbsize, writebuf);
 
 	/*
@@ -647,7 +683,7 @@
 		writebuf2 = (char *)fscs;
 
 	for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize)
-		wtfs(fsbtodb(&sblock, sblock.fs_csaddr + numfrags(&sblock, i)),
+		wtfs((sblock.fs_csaddr + numfrags(&sblock, i)) * NSPF(&sblock),
 			sblock.fs_cssize - i < sblock.fs_bsize ?
 			    sblock.fs_cssize - i : sblock.fs_bsize,
 			((char *)writebuf2) + i);
@@ -730,7 +766,7 @@
 			acg.cg_cs.cs_nifree--;
 		}
 	for (i = 0; i < sblock.fs_ipg / INOPF(&sblock); i += sblock.fs_frag)
-		wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i),
+		wtfs((cgimin(&sblock, cylno) + i) * NSPF(&sblock),
 		    sblock.fs_bsize, (char *)zino);
 	if (cylno > 0) {
 		/*
@@ -814,7 +850,7 @@
 	memcpy(writebuf, &acg, sblock.fs_bsize);
 	if (needswap)
 		swap_cg(&acg, (struct cg*)writebuf);
-	wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)),
+	wtfs(cgtod(&sblock, cylno) * NSPF(&sblock),
 		sblock.fs_bsize, writebuf);
 }
 
@@ -899,7 +935,7 @@
 	node.di_blocks = btodb(fragroundup(&sblock, node.di_size));
 	node.di_uid = geteuid();
 	node.di_gid = getegid();
-	wtfs(fsbtodb(&sblock, node.di_db[0]), node.di_size, buf);
+	wtfs(node.di_db[0] * NSPF(&sblock), node.di_size, buf);
 	iput(&node, LOSTFOUNDINO);
 #endif
 	/*
@@ -923,7 +959,7 @@
 	if (node.di_db[0] == 0)
 		return (0);
 	node.di_blocks = btodb(fragroundup(&sblock, node.di_size));
-	wtfs(fsbtodb(&sblock, node.di_db[0]), sblock.fs_fsize, buf);
+	wtfs(node.di_db[0] * NSPF(&sblock), sblock.fs_fsize, buf);
 	iput(&node, ROOTINO);
 	return (1);
 }
@@ -959,7 +995,7 @@
 	int i, frag;
 	daddr_t d, blkno;
 
-	rdfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize, &acg);
+	rdfs(cgtod(&sblock, 0) * NSPF(&sblock), sblock.fs_cgsize, &acg);
 	/* fs -> host byte order */
 	if (needswap)
 		swap_cg(&acg, &acg);
@@ -1004,7 +1040,7 @@
 	/* host -> fs byte order */
 	if (needswap)
 		swap_cg(&acg, &acg);
-	wtfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize,
+	wtfs(cgtod(&sblock, 0) * NSPF(&sblock), sblock.fs_cgsize,
 	    (char *)&acg);
 	return (d);
 }
@@ -1056,7 +1092,7 @@
 	int c, i;
 
 	c = ino_to_cg(&sblock, ino);
-	rdfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize, &acg);
+	rdfs(cgtod(&sblock, 0) * NSPF(&sblock), sblock.fs_cgsize, &acg);
 	/* fs -> host byte order */
 	if (needswap)
 		swap_cg(&acg, &acg);
@@ -1069,7 +1105,7 @@
 	/* host -> fs byte order */
 	if (needswap)
 		swap_cg(&acg, &acg);
-	wtfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize,
+	wtfs(cgtod(&sblock, 0) * NSPF(&sblock), sblock.fs_cgsize,
 	    (char *)&acg);
 	sblock.fs_cstotal.cs_nifree--;
 	fscs[0].cs_nifree--;
@@ -1077,7 +1113,7 @@
 		printf("fsinit: inode value out of range (%d).\n", ino);
 		exit(32);
 	}
-	d = fsbtodb(&sblock, ino_to_fsba(&sblock, ino));
+	d = ino_to_fsba(&sblock, ino) * NSPF(&sblock);
 	rdfs(d, sblock.fs_bsize, ibuf);
 	if (needswap) {
 		ffs_dinode_swap(ip, &ibuf[ino_to_fsbo(&sblock, ino)]);
@@ -1094,28 +1130,28 @@
  * read a block from the file system
  */
 void
-rdfs(daddr_t bno, int size, void *bf)
+rdfs(daddr_t secnum, int size, void *bf)
 {
 	int n;
 	off_t offset;
 
 #ifdef MFS
 	if (mfs) {
-		memmove(bf, membase + bno * sectorsize, size);
+		memmove(bf, membase + secnum * sectorsize, size);
 		return;
 	}
 #endif
-	offset = bno;
+	offset = secnum;
 	offset *= sectorsize;
 	if (lseek(fsi, offset, SEEK_SET) < 0) {
 		printf("rdfs: seek error for sector %d: %s\n",
-		    bno, strerror(errno));
+		    secnum, strerror(errno));
 		exit(33);
 	}
 	n = read(fsi, bf, size);
 	if (n != size) {
 		printf("rdfs: read error for sector %d: %s\n",
-		    bno, strerror(errno));
+		    secnum, strerror(errno));
 		exit(34);
 	}
 }
@@ -1124,30 +1160,30 @@
  * write a block to the file system
  */
 void
-wtfs(daddr_t bno, int size, void *bf)
+wtfs(daddr_t secnum, int size, void *bf)
 {
 	int n;
 	off_t offset;
 
 #ifdef MFS
 	if (mfs) {
-		memmove(membase + bno * sectorsize, bf, size);
+		memmove(membase + secnum * sectorsize, bf, size);
 		return;
 	}
 #endif
 	if (Nflag)
 		return;
-	offset = bno;
+	offset = secnum;
 	offset *= sectorsize;
 	if (lseek(fso, offset, SEEK_SET) < 0) {
 		printf("wtfs: seek error for sector %d: %s\n",
-		    bno, strerror(errno));
+		    secnum, strerror(errno));
 		exit(35);
 	}
 	n = write(fso, bf, size);
 	if (n != size) {
 		printf("wtfs: write error for sector %d: %s\n",
-		    bno, strerror(errno));
+		    secnum, strerror(errno));
 		exit(36);
 	}
 }
@@ -1276,7 +1312,7 @@
 	for (i=0; i < MAXFRAG; i++)
 		n->cg_frsum[i] = bswap32(o->cg_frsum[i]);
 
-	/* alays new format */
+	/* alay's new format */
 	if (n->cg_magic == CG_MAGIC) {
 		btotsize = n->cg_boff - n->cg_btotoff;
 		fbsize = n->cg_iusedoff - n->cg_boff;
diff -u /usr/src/sbin/newfs/newfs.c /home/trevin/src/sbin/newfs/newfs.c
--- /usr/src/sbin/newfs/newfs.c	Wed Feb 20 04:01:03 2002
+++ /home/trevin/src/sbin/newfs/newfs.c	Fri Jun  7 17:00:42 2002
@@ -100,6 +100,8 @@
 
 #define	COMPAT			/* allow non-labeled disks */
 
+#define	POWEROF2(num)	(((num) & ((num) - 1)) == 0)
+
 /*
  * The following two constants set the default block and fragment sizes.
  * Both constants must be a power of 2 and meet the following constraints:
@@ -112,10 +114,10 @@
  * otherwise if less than MEDIUM_FSSIZE use M_DFL_*, otherwise use
  * L_DFL_*.
  */
-#define	SMALL_FSSIZE	(20*1024*2)
+#define	SMALL_FSSIZE	(20*1024*1024)
 #define	S_DFL_FRAGSIZE	512
 #define	S_DFL_BLKSIZE	4096
-#define	MEDIUM_FSSIZE	(1000*1024*2)
+#define	MEDIUM_FSSIZE	(1000*1024*1024)
 #define	M_DFL_FRAGSIZE	1024
 #define	M_DFL_BLKSIZE	8192
 #define	L_DFL_FRAGSIZE	2048
@@ -171,7 +173,7 @@
 int	mfs;			/* run as the memory based filesystem */
 int	Nflag;			/* run without writing file system */
 int	Oflag;			/* format as an 4.3BSD file system */
-int	fssize;			/* file system size */
+int	fssize;			/* file system size in sectors */
 int	ntracks;		/* # tracks/cylinder */
 int	nsectors;		/* # sectors/track */
 int	nphyssectors;		/* # sectors/track including spares */
@@ -219,7 +221,7 @@
 	int ch, fsi, fso, len, maxpartitions, n, Fflag, Iflag, Zflag;
 	char *cp, *endp, *s1, *s2, *special;
 	const char *opstring;
-	long long llsize;
+	long long llsize = 0;
 	int dfl_fragsize, dfl_blksize;
 #ifdef MFS
 	char mountfromname[100];
@@ -278,6 +280,12 @@
 		case 'S':
 			sectorsize = strsuftoi("sector size",
 			    optarg, 1, INT_MAX);
+			if (sectorsize % DEV_BSIZE)
+				errx(1,
+			    "sector size must be a multiple of %d bytes.",
+				    DEV_BSIZE);
+			if (!POWEROF2(sectorsize))
+				errx(1, "Sector size must be a power of 2.");
 			break;
 #ifdef COMPAT
 		case 'T':
@@ -374,41 +382,39 @@
 			    optarg, 1, INT_MAX);
 			break;
 		case 's':
+			fssize = 0;
 			llsize = strtoll(optarg, &endp, 10);
 			if (endp[0] != '\0' && endp[1] != '\0')
 				llsize = -1;
 			else {
-				int	ssiz;
-
-				ssiz = (sectorsize ? sectorsize : DFL_SECSIZE);
 				switch (tolower((unsigned char)endp[0])) {
 				case 'b':
-					llsize /= ssiz;
 					break;
 				case 'k':
-					llsize *= 1024 / ssiz;
+					llsize *= 1024;
 					break;
 				case 'm':
-					llsize *= 1024 * 1024 / ssiz;
+					llsize *= 1024 * 1024;
 					break;
 				case 'g':
-					llsize *= 1024 * 1024 * 1024 / ssiz;
+					llsize *= 1024 * 1024 * 1024;
 					break;
 				case '\0':
 				case 's':
+					if (llsize > INT_MAX)
+					    errx(1, "file system size `%s'"
+						 " is too large.", optarg);
+					fssize = llsize;
+					llsize = 0;
 					break;
 				default:
 					llsize = -1;
 				}
 			}
-			if (llsize > INT_MAX)
-				errx(1, "file system size `%s' is too large.",
-				    optarg);
-			if (llsize <= 0)
+			if (llsize <= 0 && !fssize)
 				errx(1,
 			    "`%s' is not a valid number for file system size.",
 				    optarg);
-			fssize = (int)llsize;
 			break;
 		case 't':
 			ntracks = strsuftoi("total tracks",
@@ -446,8 +452,15 @@
 			sectorsize = DFL_SECSIZE;
 
 		if (Fflag && !Nflag) {	/* creating image in a regular file */
-			if (fssize == 0)
+			if (fssize == 0) {
+			    if (llsize == 0)
 				errx(1, "need to specify size when using -F");
+			    llsize /= sectorsize;
+			    if (llsize > INT_MAX)
+				errx(1, "file system size `%s' is too large.",
+				    optarg);
+			    fssize = llsize;
+			}
 			fso = open(special, O_RDWR | O_CREAT | O_TRUNC, 0777);
 			if (fso == -1)
 				err(1, "can't open file %s", special);
@@ -562,11 +575,6 @@
 			errx(1, "`%c' partition type is not `4.2BSD'", *cp);
 	}	/* !Fflag && !mfs */
 
-	if (fssize == 0)
-		fssize = pp->p_size;
-	if (fssize > pp->p_size && !mfs && !Fflag)
-		errx(1, "maximum file system size on the `%c' partition is %d",
-		    *cp, pp->p_size);
 	if (rpm == 0) {
 		rpm = lp->d_rpm;
 		if (rpm <= 0)
@@ -587,6 +595,21 @@
 		if (sectorsize <= 0)
 			errx(1, "no default sector size");
 	}
+	if (fssize == 0) {
+		if (llsize == 0)
+			fssize = pp->p_size;
+		else {
+			llsize /= sectorsize;
+			if (llsize > INT_MAX)
+				errx(1, "file system size `%s' is too large.",
+				     optarg);
+			fssize = llsize;
+		}
+	}
+	if (fssize > pp->p_size && !mfs && !Fflag)
+		errx(1, "maximum file system size on the `%c' partition is %d"
+		     " sectors (%gMB)", *cp, pp->p_size,
+		     (double) pp->p_size * sectorsize / (1024 * 1024));
 	if (trackskew == -1) {
 		trackskew = lp->d_trackskew;
 		if (trackskew < 0)
@@ -598,10 +621,10 @@
 			interleave = 1;
 	}
 
-	if (fssize < SMALL_FSSIZE) {
+	if (fssize < SMALL_FSSIZE / sectorsize) {
 		dfl_fragsize = S_DFL_FRAGSIZE;
 		dfl_blksize = S_DFL_BLKSIZE;
-	} else if (fssize < MEDIUM_FSSIZE) {
+	} else if (fssize < MEDIUM_FSSIZE / sectorsize) {
 		dfl_fragsize = M_DFL_FRAGSIZE;
 		dfl_blksize = M_DFL_BLKSIZE;
 	} else {
diff -u /usr/src/sbin/newfs/newfs.8 /home/trevin/src/sbin/newfs/newfs.8
--- /usr/src/sbin/newfs/newfs.8	Tue Apr  9 04:22:20 2002
+++ /home/trevin/src/sbin/newfs/newfs.8	Tue May 14 23:38:23 2002
@@ -149,9 +149,9 @@
 .Ar block-size
 .It \&\*[Lt] 20 MB
 4 KB
-.It \&\*[Lt] 1024 MB
+.It \&\*[Lt] 1000 MB
 8 KB
-.It \&\*[Gt]\&= 1024 MB
+.It \&\*[Gt]\&= 1000 MB
 16 KB
 .El
 .It Fl c Ar cpg
@@ -179,7 +179,7 @@
 The fragment size of the file system in bytes.
 It must be a power of two ranging in value between
 .Ar block-size Ns /8
-and
+(or the sector size, whichever is greater) and
 .Ar block-size .
 The optimal
 .Ar block-size Ns : Ns Ar frag-size
@@ -193,9 +193,9 @@
 .Ar frag-size
 .It \&\*[Lt] 20 MB
 0.5 KB
-.It \&\*[Lt] 1024 MB
+.It \&\*[Lt] 1000 MB
 1 KB
-.It \&\*[Gt]\&= 1024 MB
+.It \&\*[Gt]\&= 1000 MB
 2 KB
 .El
 .It Fl g Ar avgfilesize
@@ -215,9 +215,9 @@
 .Ar bytes-per-inode
 .It \&\*[Lt] 20 MB
 2 KB
-.It \&\*[Lt] 1024 MB
+.It \&\*[Lt] 1000 MB
 4 KB
-.It \&\*[Gt]\&= 1024 MB
+.It \&\*[Gt]\&= 1000 MB
 8 KB
 .El
 .It Fl m Ar free-space
@@ -245,7 +245,7 @@
 .Xr tunefs 8
 for more details on how to set this option.
 .It Fl s Ar size
-The size of the file system in sectors.
+The size of the file system.
 An
 .Sq s
 suffix will be interpreted as the number of sectors (the default).
@@ -269,8 +269,8 @@
 to find the alternative superblocks if the standard superblock is lost.
 .Bl -tag -width Fl
 .It Fl S Ar sector-size
-The size of a sector in bytes (almost never anything but 512).
-Defaults to 512.
+The size of a sector in bytes.
+Defaults to the sector size read from the disk label.
 .It Fl k Ar skew
 Sector \&0 skew, per track.
 Used to describe perturbations in the media format to compensate for
@@ -297,8 +297,8 @@
 The speed of the disk in revolutions per minute.
 .ne 1i
 .It Fl t Ar ntracks
-The number of tracks per cylinder available for data allocation by the file
-system.
+The number of tracks per cylinder (heads) available for data
+allocation by the file system.
 .It Fl u Ar nsectors
 The number of sectors per track available for data allocation by the file
 system.

--Boundary_(ID_EuO+FP843wYApWVDCvIRvw)
Content-type: text/plain; charset=us-ascii
Content-transfer-encoding: 7BIT


-----------------------
Trevin Beattie          "Do not meddle in the affairs of wizards,
trevin@xmission.com     for you are crunchy and good with ketchup."
      {:->                                     --unknown

--Boundary_(ID_EuO+FP843wYApWVDCvIRvw)--