Incorporate fix by iedowse @ FreeBSD to allow disks with large numbers of

cylinder groups to work correctly, with minor modifications by me to work
with our FFS_EI code.  From the FreeBSD commit message:

	The ffs superblock includes a 128-byte region for use by temporary
	in-core pointers to summary information. An array in this region
	(fs_csp) could overflow on filesystems with a very large number of
	cylinder groups (~16000 on i386 with 8k blocks). When this happens,
	other fields in the superblock get corrupted, and fsck refuses to
	check the filesystem.

	Solve this problem by replacing the fs_csp array in 'struct fs'
	with a single pointer, and add padding to keep the length of the
	128-byte region fixed. Update the kernel and userland utilities
	to use just this single pointer.

	With this change, the kernel no longer makes use of the superblock
	fields 'fs_csshift' and 'fs_csmask'. Add a comment to newfs/mkfs.c
	to indicate that these fields must be calculated for compatibility
	with older kernels.

	Reviewed by:    mckusick
This commit is contained in:
lukem 2001-09-02 01:58:30 +00:00
parent 2102cef10c
commit e3ba61f9f3
6 changed files with 74 additions and 97 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: setup.c,v 1.45 2001/08/17 02:18:47 lukem Exp $ */
/* $NetBSD: setup.c,v 1.46 2001/09/02 01:58:31 lukem Exp $ */
/*
* Copyright (c) 1980, 1986, 1993
@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "@(#)setup.c 8.10 (Berkeley) 5/9/95";
#else
__RCSID("$NetBSD: setup.c,v 1.45 2001/08/17 02:18:47 lukem Exp $");
__RCSID("$NetBSD: setup.c,v 1.46 2001/09/02 01:58:31 lukem Exp $");
#endif
#endif /* not lint */
@ -90,6 +90,7 @@ setup(dev)
struct fs proto;
int doskipclean;
u_int64_t maxfilesize;
struct csum *ccsp;
havesb = 0;
fswritefd = -1;
@ -349,11 +350,12 @@ setup(dev)
* read in the summary info.
*/
asked = 0;
sblock->fs_csp = (struct csum *)calloc(1, sblock->fs_cssize);
for (i = 0, j = 0; i < sblock->fs_cssize; i += sblock->fs_bsize, j++) {
size = sblock->fs_cssize - i < sblock->fs_bsize ?
sblock->fs_cssize - i : sblock->fs_bsize;
sblock->fs_csp[j] = (struct csum *)calloc(1, (unsigned)size);
if (bread(fsreadfd, (char *)sblock->fs_csp[j],
ccsp = (struct csum *)((char *)sblock->fs_csp + i);
if (bread(fsreadfd, (char *)ccsp,
fsbtodb(sblock, sblock->fs_csaddr + j * sblock->fs_frag),
size) != 0 && !asked) {
pfatal("BAD SUMMARY INFORMATION");
@ -363,28 +365,15 @@ setup(dev)
}
asked++;
}
/*
* The following assumes that struct csum is made of
* u_int32_t
*/
if (doswap) {
int k;
u_int32_t *cd = (u_int32_t *)sblock->fs_csp[j];
for (k = 0; k < size / sizeof(u_int32_t); k++)
cd[k] = bswap32(cd[k]);
bwrite(fswritefd, (char *)sblock->fs_csp[j],
ffs_csum_swap(ccsp, ccsp, size);
bwrite(fswritefd, (char *)ccsp,
fsbtodb(sblock,
sblock->fs_csaddr + j * sblock->fs_frag),
size);
}
if (needswap) {
int k;
u_int32_t *cd = (u_int32_t *)sblock->fs_csp[j];
for (k = 0; k < size / sizeof(u_int32_t); k++)
cd[k] = bswap32(cd[k]);
}
if (needswap)
ffs_csum_swap(ccsp, ccsp, size);
}
/*
* allocate and initialize the necessary maps
@ -603,7 +592,8 @@ cmpsblks(const struct fs *sb, struct fs *asb)
asb->fs_optim = sb->fs_optim;
asb->fs_rotdelay = sb->fs_rotdelay;
asb->fs_maxbpg = sb->fs_maxbpg;
memmove(asb->fs_csp, sb->fs_csp, sizeof sb->fs_csp);
memmove(asb->fs_ocsp, sb->fs_ocsp, sizeof sb->fs_ocsp);
asb->fs_csp = sb->fs_csp;
asb->fs_maxcluster = sb->fs_maxcluster;
memmove(asb->fs_fsmnt, sb->fs_fsmnt, sizeof sb->fs_fsmnt);
memmove(asb->fs_sparecon,

View File

@ -1,4 +1,4 @@
/* $NetBSD: utilities.c,v 1.31 2001/08/15 03:54:53 lukem Exp $ */
/* $NetBSD: utilities.c,v 1.32 2001/09/02 01:58:31 lukem Exp $ */
/*
* Copyright (c) 1980, 1986, 1993
@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "@(#)utilities.c 8.6 (Berkeley) 5/19/95";
#else
__RCSID("$NetBSD: utilities.c,v 1.31 2001/08/15 03:54:53 lukem Exp $");
__RCSID("$NetBSD: utilities.c,v 1.32 2001/09/02 01:58:31 lukem Exp $");
#endif
#endif /* not lint */
@ -222,6 +222,7 @@ flush(fd, bp)
struct bufarea *bp;
{
int i, j;
struct csum *ccsp;
if (!bp->b_dirty)
return;
@ -237,27 +238,14 @@ flush(fd, bp)
for (i = 0, j = 0; i < sblock->fs_cssize; i += sblock->fs_bsize, j++) {
int size = sblock->fs_cssize - i < sblock->fs_bsize ?
sblock->fs_cssize - i : sblock->fs_bsize;
/*
* The following routines assumes that struct csum is made of
* u_int32_t's
*/
if (needswap) {
int k;
u_int32_t *cd = (u_int32_t *)sblock->fs_csp[j];
for (k = 0; k < size / sizeof(u_int32_t); k++)
cd[k] = bswap32(cd[k]);
}
bwrite(fswritefd, (char *)sblock->fs_csp[j],
ccsp = (struct csum *)((char *)sblock->fs_csp + i);
if (needswap)
ffs_csum_swap(ccsp, ccsp, size);
bwrite(fswritefd, (char *)ccsp,
fsbtodb(sblock, sblock->fs_csaddr + j * sblock->fs_frag),
size);
if (needswap) {
int k;
u_int32_t *cd = (u_int32_t *)sblock->fs_csp[j];
for (k = 0; k < size / sizeof(u_int32_t); k++)
cd[k] = bswap32(cd[k]);
}
if (needswap)
ffs_csum_swap(ccsp, ccsp, size);
}
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: mkfs.c,v 1.53 2001/08/30 14:37:26 lukem Exp $ */
/* $NetBSD: mkfs.c,v 1.54 2001/09/02 01:58:32 lukem Exp $ */
/*
* Copyright (c) 1980, 1989, 1993
@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "@(#)mkfs.c 8.11 (Berkeley) 5/3/95";
#else
__RCSID("$NetBSD: mkfs.c,v 1.53 2001/08/30 14:37:26 lukem Exp $");
__RCSID("$NetBSD: mkfs.c,v 1.54 2001/09/02 01:58:32 lukem Exp $");
#endif
#endif /* not lint */
@ -523,14 +523,11 @@ next:
sblock.fs_csaddr = cgdmin(&sblock, 0);
sblock.fs_cssize =
fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum));
if (sblock.fs_cssize / sblock.fs_bsize > MAXCSBUFS) {
printf("With %d cylinder groups, "
"%d cylinder group summary areas are needed.\n",
sblock.fs_ncg, sblock.fs_cssize / sblock.fs_bsize);
printf("Only %ld are available. Reduce the number of cylinder "
"groups.\n", (long)MAXCSBUFS);
exit(38);
}
/*
* The superblock fields 'fs_csmask' and 'fs_csshift' are no
* longer used. However, we still initialise them so that the
* filesystem remains compatible with old kernels.
*/
i = sblock.fs_bsize / sizeof(struct csum);
sblock.fs_csmask = ~(i - 1);
for (sblock.fs_csshift = 0; i > 1; i >>= 1)

View File

@ -1,4 +1,4 @@
/* $NetBSD: ffs_vfsops.c,v 1.83 2001/08/17 02:18:48 lukem Exp $ */
/* $NetBSD: ffs_vfsops.c,v 1.84 2001/09/02 01:58:30 lukem Exp $ */
/*
* Copyright (c) 1989, 1991, 1993, 1994
@ -394,6 +394,7 @@ ffs_reload(mountp, cred, p)
{
struct vnode *vp, *nvp, *devvp;
struct inode *ip;
void *space;
struct buf *bp;
struct fs *fs, *newfs;
struct partinfo dpart;
@ -444,7 +445,7 @@ ffs_reload(mountp, cred, p)
* new superblock. These should really be in the ufsmount. XXX
* Note that important parameters (eg fs_ncg) are unchanged.
*/
memcpy(&newfs->fs_csp[0], &fs->fs_csp[0], sizeof(fs->fs_csp));
newfs->fs_csp = fs->fs_csp;
newfs->fs_maxcluster = fs->fs_maxcluster;
newfs->fs_ronly = fs->fs_ronly;
memcpy(fs, newfs, (u_int)fs->fs_sbsize);
@ -459,6 +460,7 @@ ffs_reload(mountp, cred, p)
* Step 3: re-read summary information from disk.
*/
blks = howmany(fs->fs_cssize, fs->fs_fsize);
space = fs->fs_csp;
for (i = 0; i < blks; i += fs->fs_frag) {
size = fs->fs_bsize;
if (i + fs->fs_frag > blks)
@ -471,12 +473,12 @@ ffs_reload(mountp, cred, p)
}
#ifdef FFS_EI
if (UFS_FSNEEDSWAP(fs))
ffs_csum_swap((struct csum*)bp->b_data,
(struct csum*)fs->fs_csp[fragstoblks(fs, i)], size);
ffs_csum_swap((struct csum *)bp->b_data,
(struct csum *)space, size);
else
#endif
memcpy(fs->fs_csp[fragstoblks(fs, i)], bp->b_data,
(size_t)size);
memcpy(space, bp->b_data, (size_t)size);
space = (char *)space + size;
brelse(bp);
}
if ((fs->fs_flags & FS_DOSOFTDEP))
@ -555,7 +557,7 @@ ffs_mountfs(devvp, mp, p)
struct fs *fs;
dev_t dev;
struct partinfo dpart;
caddr_t base, space;
void *space;
int blks;
int error, i, size, ronly;
#ifdef FFS_EI
@ -661,7 +663,8 @@ ffs_mountfs(devvp, mp, p)
blks = howmany(size, fs->fs_fsize);
if (fs->fs_contigsumsize > 0)
size += fs->fs_ncg * sizeof(int32_t);
base = space = malloc((u_long)size, M_UFSMNT, M_WAITOK);
space = malloc((u_long)size, M_UFSMNT, M_WAITOK);
fs->fs_csp = space;
for (i = 0; i < blks; i += fs->fs_frag) {
size = fs->fs_bsize;
if (i + fs->fs_frag > blks)
@ -669,19 +672,18 @@ ffs_mountfs(devvp, mp, p)
error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
cred, &bp);
if (error) {
free(base, M_UFSMNT);
free(fs->fs_csp, M_UFSMNT);
goto out2;
}
#ifdef FFS_EI
if (needswap)
ffs_csum_swap((struct csum*)bp->b_data,
(struct csum*)space, size);
ffs_csum_swap((struct csum *)bp->b_data,
(struct csum *)space, size);
else
#endif
memcpy(space, bp->b_data, (u_int)size);
fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
space += size;
space = (char *)space + size;
brelse(bp);
bp = NULL;
}
@ -718,7 +720,7 @@ ffs_mountfs(devvp, mp, p)
if (ronly == 0 && (fs->fs_flags & FS_DOSOFTDEP)) {
error = softdep_mount(devvp, mp, fs, cred);
if (error) {
free(base, M_UFSMNT);
free(fs->fs_csp, M_UFSMNT);
goto out;
}
}
@ -807,7 +809,7 @@ ffs_unmount(mp, mntflags, p)
error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE,
NOCRED, p);
vput(ump->um_devvp);
free(fs->fs_csp[0], M_UFSMNT);
free(fs->fs_csp, M_UFSMNT);
free(fs, M_UFSMNT);
free(ump, M_UFSMNT);
mp->mnt_data = (qaddr_t)0;
@ -1293,12 +1295,12 @@ ffs_cgupdate(mp, waitfor)
struct fs *fs = mp->um_fs;
struct buf *bp;
int blks;
caddr_t space;
void *space;
int i, size, error = 0, allerror = 0;
allerror = ffs_sbupdate(mp, waitfor);
blks = howmany(fs->fs_cssize, fs->fs_fsize);
space = (caddr_t)fs->fs_csp[0];
space = fs->fs_csp;
for (i = 0; i < blks; i += fs->fs_frag) {
size = fs->fs_bsize;
if (i + fs->fs_frag > blks)
@ -1312,7 +1314,7 @@ ffs_cgupdate(mp, waitfor)
else
#endif
memcpy(bp->b_data, space, (u_int)size);
space += size;
space = (char *)space + size;
if (waitfor == MNT_WAIT)
error = bwrite(bp);
else

View File

@ -1,4 +1,4 @@
/* $NetBSD: fs.h,v 1.17 2001/08/31 03:15:45 lukem Exp $ */
/* $NetBSD: fs.h,v 1.18 2001/09/02 01:58:31 lukem Exp $ */
/*
* Copyright (c) 1982, 1986, 1993
@ -109,14 +109,17 @@
#define MAXMNTLEN 512
/*
* The limit on the amount of summary information per file system
* is defined by MAXCSBUFS. It is currently parameterized for a
* size of 128 bytes (2 million cylinder groups on machines with
* 32-bit pointers, and 1 million on 64-bit machines). One pointer
* is taken away to point to an array of cluster sizes that is
* computed as cylinder groups are inspected.
* There is a 128-byte region in the superblock reserved for in-core
* pointers to summary information. Originally this included an array
* of pointers to blocks of struct csum; now there are just two
* pointers and the remaining space is padded with fs_ocsp[].
*
* NOCSPTRS determines the size of this padding. One pointer (fs_csp)
* is taken away to point to a contiguous array of struct csum for
* all cylinder groups; a second (fs_maxcluster) points to an array
* of cluster sizes that is computed as cylinder groups are inspected.
*/
#define MAXCSBUFS ((128 / sizeof(void *)) - 1)
#define NOCSPTRS ((128 / sizeof(void *)) - 2)
/*
* A summary of contiguous blocks of various sizes is maintained
@ -146,9 +149,6 @@
* from first cylinder group data blocks. These blocks have to be
* read in from fs_csaddr (size fs_cssize) in addition to the
* super block.
*
* N.B. sizeof(struct csum) must be a power of two in order for
* the ``fs_cs'' macro to work (see below).
*/
struct csum {
int32_t cs_ndir; /* number of directories */
@ -192,8 +192,8 @@ struct fs {
int32_t fs_fragshift; /* block to frag shift */
int32_t fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */
int32_t fs_sbsize; /* actual size of super block */
int32_t fs_csmask; /* csum block offset */
int32_t fs_csshift; /* csum block number */
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 */
@ -229,8 +229,9 @@ struct fs {
u_char fs_fsmnt[MAXMNTLEN]; /* name mounted on */
/* these fields retain the current block allocation info */
int32_t fs_cgrotor; /* last cg searched */
struct csum *fs_csp[MAXCSBUFS];/* list of fs_cs info buffers */
int32_t *fs_maxcluster; /* max cluster in each cyl group */
void *fs_ocsp[NOCSPTRS]; /* padding; was list of fs_cs buffers */
struct csum *fs_csp; /* cg summary info buffer for fs_cs */
int32_t *fs_maxcluster; /* max cluster in each cyl group */
int32_t fs_cpc; /* cyl per cycle in postbl */
int16_t fs_opostbl[16][8]; /* old rotation block list head */
int32_t fs_sparecon[49]; /* reserved for future constants */
@ -239,8 +240,8 @@ struct fs {
int32_t fs_maxsymlinklen; /* max length of an internal symlink */
int32_t fs_inodefmt; /* format of on-disk inodes */
u_int64_t fs_maxfilesize; /* maximum representable file size */
int64_t fs_qbmask; /* ~fs_bmask - for use with quad size */
int64_t fs_qfmask; /* ~fs_fmask - for use with quad size */
int64_t fs_qbmask; /* ~fs_bmask for use with 64-bit size */
int64_t fs_qfmask; /* ~fs_fmask for use with 64-bit size */
int32_t fs_state; /* validate fs_clean field (UNUSED) */
int32_t fs_postblformat; /* format of positional layout tables */
int32_t fs_nrpos; /* number of rotational positions */
@ -320,11 +321,8 @@ struct fs {
/*
* Convert cylinder group to base address of its global summary info.
*
* N.B. This macro assumes that sizeof(struct csum) is a power of two.
*/
#define fs_cs(fs, indx) \
fs_csp[(indx) >> (fs)->fs_csshift][(indx) & ~(fs)->fs_csmask]
#define fs_cs(fs, indx) fs_csp[indx]
/*
* Cylinder group block for a file system.

View File

@ -1,4 +1,4 @@
/* $NetBSD: dumpfs.c,v 1.28 2001/08/30 14:37:27 lukem Exp $ */
/* $NetBSD: dumpfs.c,v 1.29 2001/09/02 01:58:32 lukem Exp $ */
/*
* Copyright (c) 1983, 1992, 1993
@ -43,7 +43,7 @@ __COPYRIGHT("@(#) Copyright (c) 1983, 1992, 1993\n\
#if 0
static char sccsid[] = "@(#)dumpfs.c 8.5 (Berkeley) 4/29/95";
#else
__RCSID("$NetBSD: dumpfs.c,v 1.28 2001/08/30 14:37:27 lukem Exp $");
__RCSID("$NetBSD: dumpfs.c,v 1.29 2001/09/02 01:58:32 lukem Exp $");
#endif
#endif /* not lint */
@ -119,6 +119,7 @@ dumpfs(const char *name)
{
int fd, c, i, j, k, size;
time_t t;
struct csum *ccsp;
if ((fd = open(name, O_RDONLY, 0)) < 0)
goto err;
@ -227,18 +228,19 @@ dumpfs(const char *name)
}
}
printf("\ncs[].cs_(nbfree,ndir,nifree,nffree):\n\t");
afs.fs_csp = calloc(1, afs.fs_cssize);
for (i = 0, j = 0; i < afs.fs_cssize; i += afs.fs_bsize, j++) {
size = afs.fs_cssize - i < afs.fs_bsize ?
afs.fs_cssize - i : afs.fs_bsize;
afs.fs_csp[j] = calloc(1, size);
ccsp = (struct csum *)((char *)afs.fs_csp + i);
if (lseek(fd,
(off_t)(fsbtodb(&afs, (afs.fs_csaddr + j * afs.fs_frag))) *
dev_bsize, SEEK_SET) == (off_t)-1)
goto err;
if (read(fd, afs.fs_csp[j], size) != size)
if (read(fd, ccsp, size) != size)
goto err;
if (needswap)
ffs_csum_swap(afs.fs_csp[j], afs.fs_csp[j], size);
ffs_csum_swap(ccsp, ccsp, size);
}
for (i = 0; i < afs.fs_ncg; i++) {
struct csum *cs = &afs.fs_cs(&afs, i);