Subject: Re: ffs fs_flags superblock update sign extension bug
To: Manuel Bouyer <bouyer@antioche.eu.org>
From: Darrin B. Jewell <dbj@NetBSD.org>
List: tech-kern
Date: 10/07/2003 10:19:16
--=-=-=
Manuel Bouyer <bouyer@antioche.eu.org> writes:
> On Sun, Sep 28, 2003 at 06:20:30PM -0400, Darrin B. Jewell wrote:
> >
> > Filesystems that were upgraded by -current kernels in the intermediate
> > time will have bad values of fs_flags which will cause a problem which
> > will not be exhibited until some future date when those flag fields
> > are used. If desired, I can post a simple program which can go in and
> > unset these flags. Since the lifespan of the incorrect code was
> > small, I do not recommend implementing compatibility in the kernel.
>
> Yes, please. And maybe add a warning in the kernel until 2.0 is branched.
The following program will check for and correct this problem in the
superblock. Once this email makes the archives, I'll add a warning
in the kernel that points to this message and plan to remove that warning
when we get closer to branching for the release.
Darrin
--=-=-=
Content-Disposition: attachment; filename=fixufsflags.c
Content-Description: program to fix fs_flags in superblock
/*
* This program fixes a bug introduced in ffs filesystems whose
* superblock was updated by a netbsd-current kernel in sept 2003.
* For more information see mail to tech-kern@netbsd.org
* Message ID: <200309282220.h8SMKUN03670@marcela.zlz.net>
* Archive URL:
* http://mail-index.netbsd.org/tech-kern/2003/09/28/0003.html
*
* THIS PROGRAM MODIFIES YOUR FILESYSTEM SUPERBLOCK. RUN WITH CARE
*
* To compile:
* cc -o fixufsflags fixufsflags.c -lutil
*
* Example invocation:
* fixufsflags wd0a
*
* Darrin B. Jewell <dbj@netbsd.org> 2003-10-03
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <unistd.h>
#include <fcntl.h>
#include <fstab.h>
#include <err.h>
#include <util.h> /* For opendisk. compile this with -lutil */
#include <sys/param.h>
#include <sys/time.h>
#include <ufs/ffs/fs.h>
int fixfs(struct fs *fs);
int
main(int argc, char *argv[])
{
char devfname[MAXPATHLEN] = "unknown";
u_int8_t sbbuf[SBLOCKSIZE] = { 0 };
int r;
int fd;
off_t off;
ssize_t sz;
int ret;
setprogname(argv[0]);
if (argc != 2)
errx(EXIT_FAILURE,"usage: %s device",getprogname());
fd = opendisk(argv[1],O_RDWR|O_SYNC|O_RSYNC,devfname,MAXPATHLEN,0);
if (fd == -1)
err(EXIT_FAILURE,"Unable to open disk %s as %s",argv[1],devfname);
off = lseek(fd, SBLOCK_UFS1, SEEK_SET);
if (off == -1)
err(EXIT_FAILURE,"unable to seek to offset %d",SBLOCK_UFS1);
assert(off == SBLOCK_UFS1);
sz = read(fd, sbbuf, SBLOCKSIZE);
if (sz == -1)
err(EXIT_FAILURE,"unable to read %d bytes at offset %d",SBLOCKSIZE,SBLOCK_UFS1);
if (sz != SBLOCKSIZE)
warnx("unable to read superblock, only read %d bytes at offset %d",sz,SBLOCK_UFS1);
printf("Successfully read %"PRIdMAX" bytes at offset %"PRIdMAX" from %s\n",
(intmax_t)sz,(intmax_t)off,devfname);
ret = fixfs((struct fs *)sbbuf);
if ((ret == 1) && (sz == SBLOCKSIZE)) {
off = lseek(fd, SBLOCK_UFS1, SEEK_SET);
if (off == -1)
err(EXIT_FAILURE,"unable to seek to offset %d",SBLOCK_UFS1);
assert(off == SBLOCK_UFS1);
sz = write(fd, sbbuf, SBLOCKSIZE);
if (sz == -1)
err(EXIT_FAILURE,"unable to write %d bytes at offset %d",SBLOCKSIZE,SBLOCK_UFS1);
if (sz != SBLOCKSIZE)
warnx("unable to write superblock, only wrote %d bytes at offset %d",sz,SBLOCK_UFS1);
printf("Successfully wrote %"PRIdMAX" bytes at offset %"PRIdMAX" from %s\n",
(intmax_t)sz,(intmax_t)off,devfname);
printf("Superblock updated\n");
}
r = close(fd);
if (r == -1)
err(EXIT_FAILURE,"close");
assert(r == 0);
if (ret == -1)
return EXIT_FAILURE;
return EXIT_SUCCESS;
}
int
fixfs(struct fs *fs)
{
int swapped;
swapped = fs->fs_magic == FS_UFS1_MAGIC_SWAPPED;
if (!swapped && fs->fs_magic != FS_UFS1_MAGIC) {
warnx("Magic number does not indicate ffs filesystem");
return -1;
}
if (swapped) {
warnx("Swapped ffs filesystems not supported");
return -1;
}
if (fs->fs_bsize != fs->fs_maxbsize) {
warnx("Does not appear to be upgraded ffs filesystem");
return -1;
}
if (fs->fs_flags & 0xffffff00) {
printf("Unknown bits set in fs_flags: 0x%08x\n",fs->fs_flags);
if ((fs->fs_flags & 0x7fffff00) == 0x7fffff00) {
printf("Stripping incorrect bits from fs_flags\n");
fs->fs_flags &= 0x7f;
return 1;
}
} else {
printf("fs_flags bits appear to be clean\n");
}
return 0;
}
--=-=-=--