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:
parent
f22ea83247
commit
2402aaa614
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user