diff options
author | Otto Moerbeek <otto@cvs.openbsd.org> | 2007-02-16 08:34:30 +0000 |
---|---|---|
committer | Otto Moerbeek <otto@cvs.openbsd.org> | 2007-02-16 08:34:30 +0000 |
commit | 5066e68b81c9309d61a1c3186a9aab6d328c512b (patch) | |
tree | b04a2fb33530c9abc2ae83727152591ffa37c18c /sbin/fsck_ffs/setup.c | |
parent | 3785927835d9a409f8e57c22fee8d3bd324c90b4 (diff) |
Fix a row of bugs in the code that computes the alternate superblock
locations based on the disklabel.
- unit bug: disklabel size is in sectors, but superblock
fs size is in fragments.
- The disklabel contains the maximum superblock size, not the actual
as used by newfs.
- problem is that mkfs reduces track/sector and secors/track to
make the cylindergroup fit in a fs block. In this case the values
in the disklabel do not predict what's in the superblock.
This fixes all these problems. It correctly predicts the location
of all superblocks on all my filesystems I have online (sized between
100MB and 1000GB). Also tested with filesystems with different
block and fragment sizes.
Written this with a goto to make the diff easier to read.
ok krw@ deraadt@
Diffstat (limited to 'sbin/fsck_ffs/setup.c')
-rw-r--r-- | sbin/fsck_ffs/setup.c | 26 |
1 files changed, 20 insertions, 6 deletions
diff --git a/sbin/fsck_ffs/setup.c b/sbin/fsck_ffs/setup.c index 44cfcafcb69..875237a010f 100644 --- a/sbin/fsck_ffs/setup.c +++ b/sbin/fsck_ffs/setup.c @@ -1,4 +1,4 @@ -/* $OpenBSD: setup.c,v 1.28 2007/02/13 15:56:22 otto Exp $ */ +/* $OpenBSD: setup.c,v 1.29 2007/02/16 08:34:29 otto Exp $ */ /* $NetBSD: setup.c,v 1.27 1996/09/27 22:45:19 christos Exp $ */ /* @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)setup.c 8.5 (Berkeley) 11/23/94"; #else -static const char rcsid[] = "$OpenBSD: setup.c,v 1.28 2007/02/13 15:56:22 otto Exp $"; +static const char rcsid[] = "$OpenBSD: setup.c,v 1.29 2007/02/16 08:34:29 otto Exp $"; #endif #endif /* not lint */ @@ -573,15 +573,19 @@ calcsb(char *dev, int devfd, struct fs *fs) memset(fs, 0, sizeof(struct fs)); fs->fs_fsize = pp->p_fsize; fs->fs_frag = pp->p_frag; + fs->fs_bsize = fs->fs_fsize * fs->fs_frag; fs->fs_cpg = pp->p_cpg; - fs->fs_size = pp->p_size; + fs->fs_nspf = fs->fs_fsize / lp->d_secsize; + /* unit for fs->fs_size is fragments, for pp->p_size it is sectors */ + fs->fs_size = pp->p_size / fs->fs_nspf; fs->fs_ntrak = lp->d_ntracks; fs->fs_nsect = lp->d_nsectors; fs->fs_spc = lp->d_secpercyl; - fs->fs_nspf = fs->fs_fsize / lp->d_secsize; + /* we can't use lp->d_sbsize, it is the max sb size */ fs->fs_sblkno = roundup( - howmany(lp->d_bbsize + lp->d_sbsize, fs->fs_fsize), + howmany(lp->d_bbsize + SBSIZE, fs->fs_fsize), fs->fs_frag); +again: fs->fs_cgmask = 0xffffffff; for (i = fs->fs_ntrak; i > 1; i >>= 1) fs->fs_cgmask <<= 1; @@ -590,9 +594,19 @@ calcsb(char *dev, int devfd, struct fs *fs) fs->fs_cgoffset = roundup( howmany(fs->fs_nsect, NSPF(fs)), fs->fs_frag); fs->fs_fpg = (fs->fs_cpg * fs->fs_spc) / NSPF(fs); - fs->fs_ncg = howmany(fs->fs_size / fs->fs_spc, fs->fs_cpg); + fs->fs_ncg = howmany(pp->p_size / fs->fs_spc, fs->fs_cpg); for (fs->fs_fsbtodb = 0, i = NSPF(fs); i > 1; i >>= 1) fs->fs_fsbtodb++; + /* + * Mimick what mkfs is doing to get an acceptable cgsize, + * not all fields used by CGSIZE() are filled in, but it's a best + * effort anyway. + */ + if (CGSIZE(fs) > fs->fs_bsize && fs->fs_ntrak > 1) { + fs->fs_ntrak >>= 1; + fs->fs_spc >>= 1; + goto again; + } dev_bsize = lp->d_secsize; return (1); } |