Bug fix from Kirk McKusick <mckusick@McKusick.COM>:

Fix a bug in fsck_ffs where if a directory somehow develops a hole
(that is a block pointer that has a value of zero), fsck would give the
filesystem a clean bill of health, but the kernel would panic when
accessing the directory with the hole. Fsck now checks for holes
in directories.  If found in preen mode, fsck fails.  In manual
mode, it can be directed to shorten the directory to the beginning of
the hole. A  more complete solution would be to allocate a block to fill
the hole. However, this is a lot more work for a `cannot happen' error,
so the extra effort seems unwarranted.
This commit is contained in:
thorpej 1996-10-11 20:15:46 +00:00
parent f22ea83247
commit 2402aaa614
4 changed files with 80 additions and 7 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: 3.t,v 1.3 1996/04/05 01:45:45 cgd Exp $
.\" $NetBSD: 3.t,v 1.4 1996/10/11 20:15:49 thorpej Exp $
.\"
.\" Copyright (c) 1982, 1993
.\" The Regents of the University of California. All rights reserved.
@ -346,6 +346,19 @@ will remove that directory entry.
Again,
this condition can only arise when there has been a hardware failure.
.PP
.I Fsck
also checks for directories with unallocated blocks (holes).
Such directories should never be created.
When found,
.I fsck
will prompt the user to adjust the length of the offending directory
which is done by shortening the size of the directory to the end of the
last allocated block preceeding the hole.
Unfortunately, this means that another Phase 1 run has to be done.
.I Fsck
will remind the user to rerun fsck after repairing a
directory containing an unallocated block.
.PP
If a directory entry inode number references
outside the inode list, then
.I fsck_ffs

View File

@ -1,4 +1,4 @@
/* $NetBSD: fsck.h,v 1.12 1996/09/23 16:18:33 christos Exp $ */
/* $NetBSD: fsck.h,v 1.13 1996/10/11 20:15:46 thorpej Exp $ */
/*
* Copyright (c) 1980, 1986, 1993
@ -181,6 +181,7 @@ char skipclean; /* skip clean file systems if preening */
int fsmodified; /* 1 => write done to file system */
int fsreadfd; /* file descriptor for reading file system */
int fswritefd; /* file descriptor for writing file system */
int rerun; /* rerun fsck. Only used in non-preen mode */
daddr_t maxfsblock; /* number of blocks in the file system */
char *blockmap; /* ptr to primary blk allocation map */

View File

@ -1,4 +1,4 @@
/* $NetBSD: inode.c,v 1.22 1996/09/27 22:45:13 christos Exp $ */
/* $NetBSD: inode.c,v 1.23 1996/10/11 20:15:47 thorpej Exp $ */
/*
* Copyright (c) 1980, 1986, 1993
@ -37,7 +37,7 @@
#if 0
static char sccsid[] = "@(#)inode.c 8.5 (Berkeley) 2/8/95";
#else
static char rcsid[] = "$NetBSD: inode.c,v 1.22 1996/09/27 22:45:13 christos Exp $";
static char rcsid[] = "$NetBSD: inode.c,v 1.23 1996/10/11 20:15:47 thorpej Exp $";
#endif
#endif /* not lint */
@ -71,6 +71,7 @@ ckinode(dp, idesc)
struct dinode dino;
u_int64_t remsize, sizepb;
mode_t mode;
char pathbuf[MAXPATHLEN + 1];
if (idesc->id_fix != IGNORE)
idesc->id_fix = DONTKNOW;
@ -89,8 +90,25 @@ ckinode(dp, idesc)
numfrags(&sblock, fragroundup(&sblock, offset));
else
idesc->id_numfrags = sblock.fs_frag;
if (*ap == 0)
if (*ap == 0) {
if (idesc->id_type == DATA && ndb >= 0) {
/* An empty block in a directory XXX */
getpathname(pathbuf, idesc->id_number,
idesc->id_number);
pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
pathbuf);
if (reply("ADJUST LENGTH") == 1) {
dp = ginode(idesc->id_number);
dp->di_size = (ap - &dino.di_db[0]) *
sblock.fs_bsize;
printf(
"YOU MUST RERUN FSCK AFTERWARDS\n");
rerun = 1;
inodirty();
}
}
continue;
}
idesc->id_blkno = *ap;
if (idesc->id_type == ADDR)
ret = (*idesc->id_func)(idesc);
@ -108,6 +126,24 @@ ckinode(dp, idesc)
ret = iblock(idesc, n, remsize);
if (ret & STOP)
return (ret);
} else {
if (idesc->id_type == DATA && remsize > 0) {
/* An empty block in a directory XXX */
getpathname(pathbuf, idesc->id_number,
idesc->id_number);
pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
pathbuf);
if (reply("ADJUST LENGTH") == 1) {
dp = ginode(idesc->id_number);
dp->di_size -= remsize;
remsize = 0;
printf(
"YOU MUST RERUN FSCK AFTERWARDS\n");
rerun = 1;
inodirty();
break;
}
}
}
sizepb *= NINDIR(&sblock);
remsize -= sizepb;
@ -127,6 +163,8 @@ iblock(idesc, ilevel, isize)
int i, n, (*func) __P((struct inodesc *)), nif;
u_int64_t sizepb;
char buf[BUFSIZ];
char pathbuf[MAXPATHLEN + 1];
struct dinode *dp;
if (idesc->id_type == ADDR) {
func = idesc->id_func;
@ -170,6 +208,25 @@ iblock(idesc, ilevel, isize)
bp->b_flags &= ~B_INUSE;
return (n);
}
} else {
if (idesc->id_type == DATA && isize > 0) {
/* An empty block in a directory XXX */
getpathname(pathbuf, idesc->id_number,
idesc->id_number);
pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
pathbuf);
if (reply("ADJUST LENGTH") == 1) {
dp = ginode(idesc->id_number);
dp->di_size -= isize;
isize = 0;
printf(
"YOU MUST RERUN FSCK AFTERWARDS\n");
rerun = 1;
inodirty();
bp->b_flags &= ~B_INUSE;
return(STOP);
}
}
}
isize -= sizepb;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: main.c,v 1.21 1996/09/27 22:45:14 christos Exp $ */
/* $NetBSD: main.c,v 1.22 1996/10/11 20:15:48 thorpej Exp $ */
/*
* Copyright (c) 1980, 1986, 1993
@ -43,7 +43,7 @@ static char copyright[] =
#if 0
static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 1/23/94";
#else
static char rcsid[] = "$NetBSD: main.c,v 1.21 1996/09/27 22:45:14 christos Exp $";
static char rcsid[] = "$NetBSD: main.c,v 1.22 1996/10/11 20:15:48 thorpej Exp $";
#endif
#endif /* not lint */
@ -311,6 +311,8 @@ checkfilesys(filesys, mntpt, auxdata, child)
return (0);
if (!preen)
printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
if (rerun)
printf("\n***** PLEASE RERUN FSCK *****\n");
if (hotroot()) {
struct statfs stfs_buf;
/*