mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
Fix the case where fsck would not see sparse directories and the kernel would
panic. If such a thing is fixed fsck needs a rerun (and bugs the user to do so). Reviewed by: Kirk McKusick
This commit is contained in:
parent
0764dce2cb
commit
47ceb63687
16 changed files with 220 additions and 5 deletions
|
|
@ -94,7 +94,7 @@ Both the program and the interaction between the
|
|||
program and the operator are described.
|
||||
.sp 2
|
||||
.LP
|
||||
Revised July 16, 1985
|
||||
Revised October 7, 1996
|
||||
.AE
|
||||
.LP
|
||||
.bp
|
||||
|
|
|
|||
|
|
@ -344,6 +344,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
|
||||
|
|
|
|||
|
|
@ -249,6 +249,8 @@ File pointing to unallocated inode.
|
|||
.It
|
||||
Inode number out of range.
|
||||
.It
|
||||
Holes in directories.
|
||||
.It
|
||||
Dot or dot-dot not the first two entries of a directory
|
||||
or having the wrong inode number.
|
||||
.El
|
||||
|
|
|
|||
|
|
@ -180,6 +180,7 @@ 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 returntosingle; /* return to single user mode */
|
||||
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 */
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ ckinode(dp, idesc)
|
|||
struct dinode dino;
|
||||
quad_t remsize, sizepb;
|
||||
mode_t mode;
|
||||
char pathbuf[MAXPATHLEN + 1];
|
||||
|
||||
if (idesc->id_fix != IGNORE)
|
||||
idesc->id_fix = DONTKNOW;
|
||||
|
|
@ -78,8 +79,26 @@ 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);
|
||||
|
|
@ -97,6 +116,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;
|
||||
|
|
@ -116,6 +153,8 @@ iblock(idesc, ilevel, isize)
|
|||
int i, n, (*func)(), nif;
|
||||
quad_t sizepb;
|
||||
char buf[BUFSIZ];
|
||||
char pathbuf[MAXPATHLEN + 1];
|
||||
struct dinode *dp;
|
||||
|
||||
if (idesc->id_type == ADDR) {
|
||||
func = idesc->id_func;
|
||||
|
|
@ -158,6 +197,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -310,6 +310,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;
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ Both the program and the interaction between the
|
|||
program and the operator are described.
|
||||
.sp 2
|
||||
.LP
|
||||
Revised July 16, 1985
|
||||
Revised October 7, 1996
|
||||
.AE
|
||||
.LP
|
||||
.bp
|
||||
|
|
|
|||
|
|
@ -344,6 +344,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
|
||||
|
|
|
|||
|
|
@ -180,6 +180,7 @@ 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 returntosingle; /* return to single user mode */
|
||||
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 */
|
||||
|
|
|
|||
|
|
@ -249,6 +249,8 @@ File pointing to unallocated inode.
|
|||
.It
|
||||
Inode number out of range.
|
||||
.It
|
||||
Holes in directories.
|
||||
.It
|
||||
Dot or dot-dot not the first two entries of a directory
|
||||
or having the wrong inode number.
|
||||
.El
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ ckinode(dp, idesc)
|
|||
struct dinode dino;
|
||||
quad_t remsize, sizepb;
|
||||
mode_t mode;
|
||||
char pathbuf[MAXPATHLEN + 1];
|
||||
|
||||
if (idesc->id_fix != IGNORE)
|
||||
idesc->id_fix = DONTKNOW;
|
||||
|
|
@ -78,8 +79,26 @@ 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);
|
||||
|
|
@ -97,6 +116,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;
|
||||
|
|
@ -116,6 +153,8 @@ iblock(idesc, ilevel, isize)
|
|||
int i, n, (*func)(), nif;
|
||||
quad_t sizepb;
|
||||
char buf[BUFSIZ];
|
||||
char pathbuf[MAXPATHLEN + 1];
|
||||
struct dinode *dp;
|
||||
|
||||
if (idesc->id_type == ADDR) {
|
||||
func = idesc->id_func;
|
||||
|
|
@ -158,6 +197,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -310,6 +310,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;
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -180,6 +180,7 @@ 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 returntosingle; /* return to single user mode */
|
||||
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 */
|
||||
|
|
|
|||
|
|
@ -249,6 +249,8 @@ File pointing to unallocated inode.
|
|||
.It
|
||||
Inode number out of range.
|
||||
.It
|
||||
Holes in directories.
|
||||
.It
|
||||
Dot or dot-dot not the first two entries of a directory
|
||||
or having the wrong inode number.
|
||||
.El
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ ckinode(dp, idesc)
|
|||
struct dinode dino;
|
||||
quad_t remsize, sizepb;
|
||||
mode_t mode;
|
||||
char pathbuf[MAXPATHLEN + 1];
|
||||
|
||||
if (idesc->id_fix != IGNORE)
|
||||
idesc->id_fix = DONTKNOW;
|
||||
|
|
@ -78,8 +79,26 @@ 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);
|
||||
|
|
@ -97,6 +116,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;
|
||||
|
|
@ -116,6 +153,8 @@ iblock(idesc, ilevel, isize)
|
|||
int i, n, (*func)(), nif;
|
||||
quad_t sizepb;
|
||||
char buf[BUFSIZ];
|
||||
char pathbuf[MAXPATHLEN + 1];
|
||||
struct dinode *dp;
|
||||
|
||||
if (idesc->id_type == ADDR) {
|
||||
func = idesc->id_func;
|
||||
|
|
@ -158,6 +197,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -310,6 +310,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 a new issue