summaryrefslogtreecommitdiffstats
path: root/sbin
diff options
context:
space:
mode:
authormckusick <mckusick@FreeBSD.org>2010-01-11 20:05:38 +0000
committermckusick <mckusick@FreeBSD.org>2010-01-11 20:05:38 +0000
commita5ce2f4ff4e06311fdce45d9a7a2fdbf62be8a2a (patch)
treebfdf9a87dabead2b3de9547aa54e82afc86cd8f5 /sbin
parent25670cd155c4c56bcb69828cc33d068e0223b8a6 (diff)
downloadFreeBSD-src-a5ce2f4ff4e06311fdce45d9a7a2fdbf62be8a2a.zip
FreeBSD-src-a5ce2f4ff4e06311fdce45d9a7a2fdbf62be8a2a.tar.gz
This update utilizes new fsck sysctl commands that allow fsck running
in background mode to correct expected inconsistencies that arise during directory rename (see immediately previous update to this file for details). If run on a kernel without the new functionality, background fsck will simply ignore these inconsistencies rather than fail. Reported by: jeff
Diffstat (limited to 'sbin')
-rw-r--r--sbin/fsck_ffs/pass2.c89
1 files changed, 82 insertions, 7 deletions
diff --git a/sbin/fsck_ffs/pass2.c b/sbin/fsck_ffs/pass2.c
index ffe5fb7..35ab363 100644
--- a/sbin/fsck_ffs/pass2.c
+++ b/sbin/fsck_ffs/pass2.c
@@ -36,12 +36,14 @@ static const char sccsid[] = "@(#)pass2.c 8.9 (Berkeley) 4/28/95";
__FBSDID("$FreeBSD$");
#include <sys/param.h>
+#include <sys/sysctl.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ufs/dir.h>
#include <ufs/ffs/fs.h>
#include <err.h>
+#include <errno.h>
#include <stdint.h>
#include <string.h>
@@ -214,9 +216,48 @@ pass2(void)
inoinfo(inp->i_parent)->ino_linkcnt--;
continue;
}
- fileerror(inp->i_parent, inp->i_number,
- "BAD INODE NUMBER FOR '..'");
- if (reply("FIX") == 0)
+ /*
+ * Here we have:
+ * inp->i_number is directory with bad ".." in it.
+ * inp->i_dotdot is current value of "..".
+ * inp->i_parent is directory to which ".." should point.
+ */
+ getpathname(pathbuf, inp->i_parent, inp->i_number);
+ printf("BAD INODE NUMBER FOR '..' in DIR I=%d (%s)\n",
+ inp->i_number, pathbuf);
+ getpathname(pathbuf, inp->i_dotdot, inp->i_dotdot);
+ printf("CURRENTLY POINTS TO I=%d (%s), ", inp->i_dotdot,
+ pathbuf);
+ getpathname(pathbuf, inp->i_parent, inp->i_parent);
+ printf("SHOULD POINT TO I=%d (%s)", inp->i_parent, pathbuf);
+ if (cursnapshot != 0) {
+ /*
+ * We need to:
+ * setcwd(inp->i_number);
+ * setdotdot(inp->i_dotdot, inp->i_parent);
+ */
+ cmd.value = inp->i_number;
+ if (sysctlbyname("vfs.ffs.setcwd", 0, 0,
+ &cmd, sizeof cmd) == -1) {
+ /* kernel lacks support for these functions */
+ printf(" (IGNORED)\n");
+ continue;
+ }
+ cmd.value = inp->i_dotdot; /* verify same value */
+ cmd.size = inp->i_parent; /* new parent */
+ if (sysctlbyname("vfs.ffs.setdotdot", 0, 0,
+ &cmd, sizeof cmd) == -1) {
+ printf(" (FIX FAILED: %s)\n", strerror(errno));
+ continue;
+ }
+ printf(" (FIXED)\n");
+ inoinfo(inp->i_parent)->ino_linkcnt--;
+ inp->i_dotdot = inp->i_parent;
+ continue;
+ }
+ if (preen)
+ printf(" (FIXED)\n");
+ else if (reply("FIX") == 0)
continue;
inoinfo(inp->i_dotdot)->ino_linkcnt++;
inoinfo(inp->i_parent)->ino_linkcnt--;
@@ -450,6 +491,7 @@ again:
static int
fix_extraneous(struct inoinfo *inp, struct inodesc *idesc)
{
+ char *cp;
struct inodesc dotdesc;
char oldname[MAXPATHLEN + 1];
char newname[MAXPATHLEN + 1];
@@ -491,7 +533,7 @@ fix_extraneous(struct inoinfo *inp, struct inodesc *idesc)
strcat (newname, "/");
strcat(newname, idesc->id_dirp->d_name);
getpathname(oldname, inp->i_number, inp->i_number);
- pwarn("%s IS AN EXTRANEOUS HARD LINK TO DIRECTORY %s\n",
+ pwarn("%s IS AN EXTRANEOUS HARD LINK TO DIRECTORY %s",
newname, oldname);
if (cursnapshot != 0) {
/*
@@ -499,7 +541,21 @@ fix_extraneous(struct inoinfo *inp, struct inodesc *idesc)
* setcwd(idesc->id_number);
* unlink(idesc->id_dirp->d_name);
*/
- printf(" (IGNORED)\n");
+ cmd.value = idesc->id_number;
+ if (sysctlbyname("vfs.ffs.setcwd", 0, 0,
+ &cmd, sizeof cmd) == -1) {
+ printf(" (IGNORED)\n");
+ return (0);
+ }
+ cmd.value = (int)idesc->id_dirp->d_name;
+ cmd.size = inp->i_number; /* verify same name */
+ if (sysctlbyname("vfs.ffs.unlink", 0, 0,
+ &cmd, sizeof cmd) == -1) {
+ printf(" (UNLINK FAILED: %s)\n",
+ strerror(errno));
+ return (0);
+ }
+ printf(" (REMOVED)\n");
return (0);
}
if (preen) {
@@ -514,7 +570,7 @@ fix_extraneous(struct inoinfo *inp, struct inodesc *idesc)
*/
getpathname(oldname, inp->i_parent, inp->i_number);
getpathname(newname, inp->i_number, inp->i_number);
- pwarn("%s IS AN EXTRANEOUS HARD LINK TO DIRECTORY %s\n", oldname,
+ pwarn("%s IS AN EXTRANEOUS HARD LINK TO DIRECTORY %s", oldname,
newname);
if (cursnapshot != 0) {
/*
@@ -522,7 +578,26 @@ fix_extraneous(struct inoinfo *inp, struct inodesc *idesc)
* setcwd(inp->i_parent);
* unlink(last component of oldname pathname);
*/
- printf(" (IGNORED)\n");
+ cmd.value = inp->i_parent;
+ if (sysctlbyname("vfs.ffs.setcwd", 0, 0,
+ &cmd, sizeof cmd) == -1) {
+ printf(" (IGNORED)\n");
+ return (0);
+ }
+ if ((cp = rindex(oldname, '/')) == NULL) {
+ printf(" (IGNORED)\n");
+ return (0);
+ }
+ cmd.value = (int)(cp + 1);
+ cmd.size = inp->i_number; /* verify same name */
+ if (sysctlbyname("vfs.ffs.unlink", 0, 0,
+ &cmd, sizeof cmd) == -1) {
+ printf(" (UNLINK FAILED: %s)\n",
+ strerror(errno));
+ return (0);
+ }
+ printf(" (REMOVED)\n");
+ inp->i_parent = idesc->id_number; /* reparent to correct dir */
return (0);
}
if (!preen && !reply("REMOVE"))
OpenPOWER on IntegriCloud