Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 19 Oct 2002 17:49:49 +1000 (EST)
From:      Bruce Evans <bde@zeta.org.au>
To:        BOUWSMA Beery <freebsd-misuser@ipv6.netscum.dyndns.dk>
Cc:        freebsd-fs@FreeBSD.ORG
Subject:   Re: UFS2 panic (and other issues) at mount with unusual `newfs' values
Message-ID:  <20021019165432.W2104-100000@gamplex.bde.org>
In-Reply-To: <200210121522.g9CFMMt00455@MAIL.NetScum.DynDNS.dK>

next in thread | previous in thread | raw e-mail | index | archive | help
On Sat, 12 Oct 2002, BOUWSMA Beery wrote:

> [IPv6-only address above; strip the obvious for IPv4-only mail]
>
> About three months ago, I bothered both this list and -current with
> a message, and I've finally gotten around to taking a closer look at
> it, keeping it in -fs this time.  I wrote:
>
> > It seems that any -f fsize value larger than 8192 given to `newfs'
> > creates a UFS2 filesystem that causes a panic when mounted, even
>
> > #15 0xc0297772 in ffs_mount (mp=0xc1918400, path=0xc1922180 "/mnt", data=---Can'
> > t read userspace from dump, or kernel process---
>
> Adding some debuggery makes it appear that the real crash occurs
> in sys/ufs/ffs/ffs_vfsops.c in ffs_mountfs() right here:
>
>         /* XXX DEBUG */ printf("ffs_mountfs: checkpoint 9\n");
>         bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize);
>         /* XXX DEBUG */ printf("ffs_mountfs: checkpoint 10\n");
>
> This should be line 690, plus or minus a few, in 14.Sep 1.190
> revision of this (last one I tried to build).

The panic is just because we have allocated a buffer of size SBLOCKSIZE
using bread(), but here we bcopy an amount potentially larger than
SBLOCKSIZE into the buffer.  Your patch that was recently committed to
newfs/mkfs.c stops mkfs creating filesystems with such a larger
fs_sbsize.

I use the following patches which would have turned the panic into a
mount failure.  The original version of these was to try to get
MAXBSIZE = DEV_BSIZE working so that the block size could be the
same as the fragment size even when the fragment size is DEV_BSIZE.
This doesn't quite work due to problems with fs_sbsize being small
instead of large.  IIRC, sizeof(struct fs) is slightly less than
1536 and things fail unless fs_bsize is larger than this (it must
be at least 2048 after rounding).

%%%
Index: ffs_vfsops.c
===================================================================
RCS file: /home/ncvs/src/sys/ufs/ffs/ffs_vfsops.c,v
retrieving revision 1.194
diff -u -2 -r1.194 ffs_vfsops.c
--- ffs_vfsops.c	15 Oct 2002 20:00:06 -0000	1.194
+++ ffs_vfsops.c	16 Oct 2002 12:47:01 -0000
@@ -429,8 +425,17 @@
 	     newfs->fs_magic != FS_UFS2_MAGIC) ||
 	    newfs->fs_bsize > MAXBSIZE ||
-	    newfs->fs_bsize < sizeof(struct fs)) {
-			brelse(bp);
-			return (EIO);		/* XXX needs translation */
+	    newfs->fs_sbsize > SBLOCKSIZE) {
+		bp->b_flags |= B_INVAL | B_NOCACHE;
+		brelse(bp);
+		return (EIO);		/* XXX needs translation */
 	}
+	if (newfs->fs_bsize < sizeof(struct fs))
+		printf("newfs->fs_bsize < sizeof(struct fs) (%lu <= %lu)\n",
+		    (u_long)newfs->fs_bsize, (u_long)sizeof(struct fs));
+	if (newfs->fs_sbsize != fragroundup(newfs, sizeof(struct fs)))
+		printf(
+    "newfs->fs_sbsize != fragroundup(newfs, sizeof(struct fs)) (%lu != %lu)\n",
+		    (u_long)newfs->fs_sbsize,
+		    (u_long)fragroundup(newfs, sizeof(struct fs)));
 	/*
 	 * Copy pointer fields back into superblock before copying in	XXX
@@ -625,6 +623,7 @@
 		      fs->fs_sblockloc == sblockloc)) &&
 		    fs->fs_bsize <= MAXBSIZE &&
-		    fs->fs_bsize >= sizeof(struct fs))
+		    fs->fs_sbsize <= SBLOCKSIZE)
 			break;
+		bp->b_flags |= B_INVAL | B_NOCACHE;
 		brelse(bp);
 		bp = NULL;
@@ -685,5 +690,5 @@
 	ump->um_vfree = ffs_vfree;
 	bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize);
-	if (fs->fs_sbsize < SBLOCKSIZE)
+	if (fs->fs_sbsize != fs->fs_bsize)
 		bp->b_flags |= B_INVAL | B_NOCACHE;
 	brelse(bp);
%%%

Notes on the above patch:

%%%
% Index: ffs_vfsops.c
% ===================================================================
% RCS file: /home/ncvs/src/sys/ufs/ffs/ffs_vfsops.c,v
% retrieving revision 1.194
% diff -u -2 -r1.194 ffs_vfsops.c
% --- ffs_vfsops.c	15 Oct 2002 20:00:06 -0000	1.194
% +++ ffs_vfsops.c	16 Oct 2002 12:47:01 -0000
% @@ -429,8 +425,17 @@
%  	     newfs->fs_magic != FS_UFS2_MAGIC) ||
%  	    newfs->fs_bsize > MAXBSIZE ||
% -	    newfs->fs_bsize < sizeof(struct fs)) {
% -			brelse(bp);
% -			return (EIO);		/* XXX needs translation */
% +	    newfs->fs_sbsize > SBLOCKSIZE) {

Don't reject filesystems with a small blocksize, since these can work.
Reject filesystems with a too-large fs_sbsize instead.

% +		bp->b_flags |= B_INVAL | B_NOCACHE;

Discard the buffer immediately since we are certain we don't want it,
and keeping buffers of unusual sizes around can be dangerous.  The usual
size is fs_bsize for a valid filesystems, and here we don't even have
a valid filesystem.

% +		brelse(bp);
% +		return (EIO);		/* XXX needs translation */

Fix indentation.

%  	}
% +	if (newfs->fs_bsize < sizeof(struct fs))
% +		printf("newfs->fs_bsize < sizeof(struct fs) (%lu <= %lu)\n",
% +		    (u_long)newfs->fs_bsize, (u_long)sizeof(struct fs));
% +	if (newfs->fs_sbsize != fragroundup(newfs, sizeof(struct fs)))
% +		printf(
% +    "newfs->fs_sbsize != fragroundup(newfs, sizeof(struct fs)) (%lu != %lu)\n",
% +		    (u_long)newfs->fs_sbsize,
% +		    (u_long)fragroundup(newfs, sizeof(struct fs)));
%  	/*
%  	 * Copy pointer fields back into superblock before copying in	XXX

Debugging code.  newfs->fs_bsize can be smaller than sizeof(struct fs)
when MAXBSIZE < 4096.  Some of these cases worked for me and I think all
should work provided the blocking is done carefully.

% @@ -625,6 +623,7 @@
%  		      fs->fs_sblockloc == sblockloc)) &&
%  		    fs->fs_bsize <= MAXBSIZE &&
% -		    fs->fs_bsize >= sizeof(struct fs))
% +		    fs->fs_sbsize <= SBLOCKSIZE)
%  			break;
% +		bp->b_flags |= B_INVAL | B_NOCACHE;
%  		brelse(bp);
%  		bp = NULL;

As above (above is for the reload case; this is the main case).
Invalidating the buffer is more useful here, since we bread() with size
SBLOCKSIZE here but only want to keep a buffer of size fs_sbsize.

% @@ -685,5 +690,5 @@
%  	ump->um_vfree = ffs_vfree;
%  	bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize);
% -	if (fs->fs_sbsize < SBLOCKSIZE)
% +	if (fs->fs_sbsize != fs->fs_bsize)
%  		bp->b_flags |= B_INVAL | B_NOCACHE;
%  	brelse(bp);

More superstition about keeping odd-size buffers.  I think both of the
conditions are wrong.  Only buffers of size fs_sbsize are useful.
%%%

> First question:  with UFS2, what should the values for sbsize
> be, so I know if the above line is at fault, or if the numbers
> I give below indicate a problem elsewhere, like in newfs or
> something?

I believe fs_sbsize is now just sizeof(struct fs) rounded up a little
now that there is no rotational info at the end of it.  It must be
rounded to a multiple of DEV_BSIZE.  Further rounding to a multiple
of fs_bsize or SBLOCKSIZE isn't essential although it might simplify
blocking.

Bruce


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-fs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20021019165432.W2104-100000>