Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 14 Jul 2010 08:48:54 +0000 (UTC)
From:      Jeff Roberson <jeff@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r210049 - in projects/suj/6: sbin/dumpfs sbin/fsck_ffs sbin/tunefs sys/kern sys/sys sys/ufs/ffs sys/ufs/ufs
Message-ID:  <201007140848.o6E8ms9h011452@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jeff
Date: Wed Jul 14 08:48:53 2010
New Revision: 210049
URL: http://svn.freebsd.org/changeset/base/210049

Log:
   - Bring in suj fixes from head to suj/6.

Modified:
  projects/suj/6/sbin/dumpfs/dumpfs.c
  projects/suj/6/sbin/fsck_ffs/main.c
  projects/suj/6/sbin/fsck_ffs/pass1.c
  projects/suj/6/sbin/fsck_ffs/pass2.c
  projects/suj/6/sbin/fsck_ffs/pass4.c
  projects/suj/6/sbin/fsck_ffs/suj.c
  projects/suj/6/sbin/tunefs/tunefs.8
  projects/suj/6/sbin/tunefs/tunefs.c
  projects/suj/6/sys/kern/vfs_vnops.c
  projects/suj/6/sys/sys/buf.h
  projects/suj/6/sys/sys/mount.h
  projects/suj/6/sys/ufs/ffs/ffs_alloc.c
  projects/suj/6/sys/ufs/ffs/ffs_extern.h
  projects/suj/6/sys/ufs/ffs/ffs_inode.c
  projects/suj/6/sys/ufs/ffs/ffs_snapshot.c
  projects/suj/6/sys/ufs/ffs/ffs_softdep.c
  projects/suj/6/sys/ufs/ffs/ffs_vfsops.c
  projects/suj/6/sys/ufs/ffs/ffs_vnops.c
  projects/suj/6/sys/ufs/ffs/fs.h
  projects/suj/6/sys/ufs/ffs/softdep.h
  projects/suj/6/sys/ufs/ufs/inode.h
  projects/suj/6/sys/ufs/ufs/ufs_inode.c
  projects/suj/6/sys/ufs/ufs/ufs_lookup.c
  projects/suj/6/sys/ufs/ufs/ufs_vnops.c

Modified: projects/suj/6/sbin/dumpfs/dumpfs.c
==============================================================================
--- projects/suj/6/sbin/dumpfs/dumpfs.c	Wed Jul 14 08:47:19 2010	(r210048)
+++ projects/suj/6/sbin/dumpfs/dumpfs.c	Wed Jul 14 08:48:53 2010	(r210049)
@@ -219,7 +219,7 @@ dumpfs(const char *name)
 	if (fsflags & FS_UNCLEAN)
 		printf("unclean ");
 	if (fsflags & FS_DOSOFTDEP)
-		printf("soft-updates ");
+		printf("soft-updates%s ", (fsflags & FS_SUJ) ? "+journal" : "");
 	if (fsflags & FS_NEEDSFSCK)
 		printf("needs fsck run ");
 	if (fsflags & FS_INDEXDIRS)
@@ -231,7 +231,7 @@ dumpfs(const char *name)
 	if (fsflags & FS_FLAGS_UPDATED)
 		printf("fs_flags expanded ");
 	fsflags &= ~(FS_UNCLEAN | FS_DOSOFTDEP | FS_NEEDSFSCK | FS_INDEXDIRS |
-		     FS_ACLS | FS_MULTILABEL | FS_FLAGS_UPDATED);
+		     FS_ACLS | FS_MULTILABEL | FS_FLAGS_UPDATED | FS_SUJ);
 	if (fsflags != 0)
 		printf("unknown flags (%#x)", fsflags);
 	putchar('\n');

Modified: projects/suj/6/sbin/fsck_ffs/main.c
==============================================================================
--- projects/suj/6/sbin/fsck_ffs/main.c	Wed Jul 14 08:47:19 2010	(r210048)
+++ projects/suj/6/sbin/fsck_ffs/main.c	Wed Jul 14 08:48:53 2010	(r210049)
@@ -242,26 +242,6 @@ checkfilesys(char *filesys)
 			exit(7);	/* Filesystem clean, report it now */
 		exit(0);
 	}
-	if (ckclean && skipclean) {
-		/*
-		 * If file system is su+j, check it here.
-		 */
-		if ((fsreadfd = open(filesys, O_RDONLY)) < 0 || readsb(0) == 0)
-			exit(3);	/* Cannot read superblock */
-		close(fsreadfd);
-#if 0
-		if ((sblock.fs_flags & FS_SUJ) != 0) {
-			if (sblock.fs_clean == 1) {
-				pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n");
-				exit(0);
-			}
-			suj_check(filesys);
-			if (chkdoreload(mntp) == 0)
-				exit(0);
-			exit(4);
-		}
-#endif
-	}
 	/*
 	 * If we are to do a background check:
 	 *	Get the mount point information of the file system
@@ -364,13 +344,17 @@ checkfilesys(char *filesys)
 	/*
 	 * Determine if we can and should do journal recovery.
 	 */
-	if ((sblock.fs_flags & (FS_SUJ | FS_NEEDSFSCK)) == FS_SUJ) {
-		if (preen || reply("USE JOURNAL?")) {
-			if (suj_check(filesys) == 0)
-				goto out;
-			/* suj_check failed, fall through. */
+	if ((sblock.fs_flags & FS_SUJ) == FS_SUJ) {
+		if ((sblock.fs_flags & FS_NEEDSFSCK) != FS_NEEDSFSCK && skipclean) {
+			if (preen || reply("USE JOURNAL?")) {
+				if (suj_check(filesys) == 0) {
++                                       printf("\n***** FILE SYSTEM MARKED CLEAN *****\n");
+					goto out;
+				}
+				/* suj_check failed, fall through. */
+			}
+			printf("** Skipping journal, falling through to full fsck\n");
 		}
-		printf("** Skipping journal, falling through to full fsck\n");
 		/*
 		 * Write the superblock so we don't try to recover the
 		 * journal on another pass.
@@ -400,7 +384,10 @@ checkfilesys(char *filesys)
 	 */
 	if (duplist) {
 		if (preen || usedsoftdep)
-			pfatal("INTERNAL ERROR: dups with -p");
+			pfatal("INTERNAL ERROR: dups with %s%s%s",
+			    preen ? "-p" : "",
+			    (preen && usedsoftdep) ? " and " : "",
+			    usedsoftdep ? "softupdates" : "");
 		printf("** Phase 1b - Rescan For More DUPS\n");
 		pass1b();
 	}

Modified: projects/suj/6/sbin/fsck_ffs/pass1.c
==============================================================================
--- projects/suj/6/sbin/fsck_ffs/pass1.c	Wed Jul 14 08:47:19 2010	(r210048)
+++ projects/suj/6/sbin/fsck_ffs/pass1.c	Wed Jul 14 08:48:53 2010	(r210049)
@@ -95,10 +95,16 @@ pass1(void)
 		getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize);
 		if (sblock.fs_magic == FS_UFS2_MAGIC) {
 			inosused = cgrp.cg_initediblk;
-			if (inosused > sblock.fs_ipg)
+			if (inosused > sblock.fs_ipg) {
+				pfatal("%s (%d > %d) %s %d\nReset to %d\n",
+				    "Too many initialized inodes", inosused,
+				    sblock.fs_ipg, "in cylinder group", c,
+				    sblock.fs_ipg);
 				inosused = sblock.fs_ipg;
-		} else
+			}
+		} else {
 			inosused = sblock.fs_ipg;
+		}
 		if (got_siginfo) {
 			printf("%s: phase 1: cyl group %d of %d (%d%%)\n",
 			    cdevname, c, sblock.fs_ncg,

Modified: projects/suj/6/sbin/fsck_ffs/pass2.c
==============================================================================
--- projects/suj/6/sbin/fsck_ffs/pass2.c	Wed Jul 14 08:47:19 2010	(r210048)
+++ projects/suj/6/sbin/fsck_ffs/pass2.c	Wed Jul 14 08:48:53 2010	(r210049)
@@ -36,12 +36,14 @@ static const char sccsid[] = "@(#)pass2.
 __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>
 
@@ -49,6 +51,8 @@ __FBSDID("$FreeBSD$");
 
 #define MINDIRSIZE	(sizeof (struct dirtemplate))
 
+static int fix_extraneous(struct inoinfo *, struct inodesc *);
+static int deleteentry(struct inodesc *);
 static int blksort(const void *, const void *);
 static int pass2check(struct inodesc *);
 
@@ -212,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--;
@@ -231,13 +274,12 @@ static int
 pass2check(struct inodesc *idesc)
 {
 	struct direct *dirp = idesc->id_dirp;
+	char dirname[MAXPATHLEN + 1];
 	struct inoinfo *inp;
 	int n, entrysize, ret = 0;
 	union dinode *dp;
 	const char *errmsg;
 	struct direct proto;
-	char namebuf[MAXPATHLEN + 1];
-	char pathbuf[MAXPATHLEN + 1];
 
 	/*
 	 * check for "."
@@ -393,9 +435,37 @@ again:
 				errmsg = "DUP/BAD";
 			else if (!preen && !usedsoftdep)
 				errmsg = "ZERO LENGTH DIRECTORY";
-			else {
+			else if (cursnapshot == 0) {
 				n = 1;
 				break;
+			} else {
+				getpathname(dirname, idesc->id_number,
+				    dirp->d_ino);
+				pwarn("ZERO LENGTH DIRECTORY %s I=%d",
+					dirname, dirp->d_ino);
+				/*
+				 * We need to:
+				 *    setcwd(idesc->id_parent);
+				 *    rmdir(dirp->d_name);
+				 */
+				cmd.value = idesc->id_number;
+				if (sysctlbyname("vfs.ffs.setcwd", 0, 0,
+				    &cmd, sizeof cmd) == -1) {
+					/* kernel lacks support */
+					printf(" (IGNORED)\n");
+					n = 1;
+					break;
+				}
+				if (rmdir(dirp->d_name) == -1) {
+					printf(" (REMOVAL FAILED: %s)\n",
+					    strerror(errno));
+					n = 1;
+					break;
+				}
+				/* ".." reference to parent is removed */
+				inoinfo(idesc->id_number)->ino_linkcnt--;
+				printf(" (REMOVED)\n");
+				break;
 			}
 			fileerror(idesc->id_number, dirp->d_ino, errmsg);
 			if ((n = reply("REMOVE")) == 1)
@@ -414,27 +484,12 @@ again:
 
 		case DFOUND:
 			inp = getinoinfo(dirp->d_ino);
-			if (inp->i_parent != 0 && idesc->id_entryno > 2) {
-				getpathname(pathbuf, idesc->id_number,
-				    idesc->id_number);
-				getpathname(namebuf, dirp->d_ino, dirp->d_ino);
-				pwarn("%s%s%s %s %s\n", pathbuf,
-				    (strcmp(pathbuf, "/") == 0 ? "" : "/"),
-				    dirp->d_name,
-				    "IS AN EXTRANEOUS HARD LINK TO DIRECTORY",
-				    namebuf);
-				if (cursnapshot != 0)
-					break;
-				if (preen) {
-					printf(" (REMOVED)\n");
-					n = 1;
-					break;
-				}
-				if ((n = reply("REMOVE")) == 1)
+			if (idesc->id_entryno > 2) {
+				if (inp->i_parent == 0)
+					inp->i_parent = idesc->id_number;
+				else if ((n = fix_extraneous(inp, idesc)) == 1)
 					break;
 			}
-			if (idesc->id_entryno > 2)
-				inp->i_parent = idesc->id_number;
 			/* FALLTHROUGH */
 
 		case FSTATE:
@@ -460,6 +515,143 @@ again:
 	return (ret|KEEPON|ALTERED);
 }
 
+static int
+fix_extraneous(struct inoinfo *inp, struct inodesc *idesc)
+{
+	char *cp;
+	struct inodesc dotdesc;
+	char oldname[MAXPATHLEN + 1];
+	char newname[MAXPATHLEN + 1];
+	
+	/*
+	 * If we have not yet found "..", look it up now so we know
+	 * which inode the directory itself believes is its parent.
+	 */
+	if (inp->i_dotdot == 0) {
+		memset(&dotdesc, 0, sizeof(struct inodesc));
+		dotdesc.id_type = DATA;
+		dotdesc.id_number = idesc->id_dirp->d_ino;
+		dotdesc.id_func = findino;
+		dotdesc.id_name = strdup("..");
+		if ((ckinode(ginode(dotdesc.id_number), &dotdesc) & FOUND))
+			inp->i_dotdot = dotdesc.id_parent;
+	}
+	/*
+	 * We have the previously found old name (inp->i_parent) and the
+	 * just found new name (idesc->id_number). We have five cases:
+	 * 1)  ".." is missing - can remove either name, choose to delete
+	 *     new one and let fsck create ".." pointing to old name.
+	 * 2) Both new and old are in same directory, choose to delete
+	 *    the new name and let fsck fix ".." if it is wrong.
+	 * 3) ".." does not point to the new name, so delete it and let
+	 *    fsck fix ".." to point to the old one if it is wrong.
+	 * 4) ".." points to the old name only, so delete the new one.
+	 * 5) ".." points to the new name only, so delete the old one.
+	 *
+	 * For cases 1-4 we eliminate the new name;
+	 * for case 5 we eliminate the old name.
+	 */
+	if (inp->i_dotdot == 0 ||		    /* Case 1 */
+	    idesc->id_number == inp->i_parent ||    /* Case 2 */
+	    inp->i_dotdot != idesc->id_number ||    /* Case 3 */
+	    inp->i_dotdot == inp->i_parent) {	    /* Case 4 */
+		getpathname(newname, idesc->id_number, idesc->id_number);
+		if (strcmp(newname, "/") != 0)
+			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",
+		    newname, oldname);
+		if (cursnapshot != 0) {
+			/*
+			 * We need to
+			 *    setcwd(idesc->id_number);
+			 *    unlink(idesc->id_dirp->d_name);
+			 */
+			cmd.value = idesc->id_number;
+			if (sysctlbyname("vfs.ffs.setcwd", 0, 0,
+			    &cmd, sizeof cmd) == -1) {
+				printf(" (IGNORED)\n");
+				return (0);
+			}
+			cmd.value = (intptr_t)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) {
+			printf(" (REMOVED)\n");
+			return (1);
+		}
+		return (reply("REMOVE"));
+	}
+	/*
+	 * None of the first four cases above, so must be case (5).
+	 * Eliminate the old name and make the new the name the parent.
+	 */
+	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", oldname,
+	    newname);
+	if (cursnapshot != 0) {
+		/*
+		 * We need to
+		 *    setcwd(inp->i_parent);
+		 *    unlink(last component of oldname pathname);
+		 */
+		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 = (intptr_t)(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"))
+		return (0);
+	memset(&dotdesc, 0, sizeof(struct inodesc));
+	dotdesc.id_type = DATA;
+	dotdesc.id_number = inp->i_parent; /* directory in which name appears */
+	dotdesc.id_parent = inp->i_number; /* inode number in entry to delete */
+	dotdesc.id_func = deleteentry;
+	if ((ckinode(ginode(dotdesc.id_number), &dotdesc) & FOUND) && preen)
+		printf(" (REMOVED)\n");
+	inp->i_parent = idesc->id_number;  /* reparent to correct directory */
+	inoinfo(inp->i_number)->ino_linkcnt++; /* name gone, return reference */
+	return (0);
+}
+
+static int
+deleteentry(struct inodesc *idesc)
+{
+	struct direct *dirp = idesc->id_dirp;
+
+	if (idesc->id_entryno++ < 2 || dirp->d_ino != idesc->id_parent)
+		return (KEEPON);
+	dirp->d_ino = 0;
+	return (ALTERED|STOP|FOUND);
+}
+
 /*
  * Routine to sort disk blocks.
  */

Modified: projects/suj/6/sbin/fsck_ffs/pass4.c
==============================================================================
--- projects/suj/6/sbin/fsck_ffs/pass4.c	Wed Jul 14 08:47:19 2010	(r210048)
+++ projects/suj/6/sbin/fsck_ffs/pass4.c	Wed Jul 14 08:48:53 2010	(r210049)
@@ -97,6 +97,9 @@ pass4(void)
 				break;
 
 			case DCLEAR:
+				/* if on snapshot, already cleared */
+				if (cursnapshot != 0)
+					break;
 				dp = ginode(inumber);
 				if (DIP(dp, di_size) == 0) {
 					clri(&idesc, "ZERO LENGTH", 1);

Modified: projects/suj/6/sbin/fsck_ffs/suj.c
==============================================================================
--- projects/suj/6/sbin/fsck_ffs/suj.c	Wed Jul 14 08:47:19 2010	(r210048)
+++ projects/suj/6/sbin/fsck_ffs/suj.c	Wed Jul 14 08:48:53 2010	(r210049)
@@ -37,12 +37,15 @@ __FBSDID("$FreeBSD$");
 #include <ufs/ufs/dir.h>
 #include <ufs/ffs/fs.h>
 
+#include <setjmp.h>
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
 #include <libufs.h>
 #include <string.h>
 #include <strings.h>
+#include <sysexits.h>
 #include <err.h>
 #include <assert.h>
 
@@ -141,7 +144,10 @@ uint64_t freedir;
 uint64_t jbytes;
 uint64_t jrecs;
 
+static jmp_buf	jmpbuf;
+
 typedef void (*ino_visitor)(ino_t, ufs_lbn_t, ufs2_daddr_t, int);
+static void err_suj(const char *, ...) __dead2;
 static void ino_trunc(ino_t, off_t);
 static void ino_decr(ino_t);
 static void ino_adjust(struct suj_ino *);
@@ -155,11 +161,30 @@ errmalloc(size_t n)
 
 	a = malloc(n);
 	if (a == NULL)
-		errx(1, "malloc(%zu)", n);
+		err(EX_OSERR, "malloc(%zu)", n);
 	return (a);
 }
 
 /*
+ * When hit a fatal error in journalling check, print out
+ * the error and then offer to fallback to normal fsck.
+ */
+static void
+err_suj(const char * restrict fmt, ...)
+{
+	va_list ap;
+
+	if (preen)
+		(void)fprintf(stdout, "%s: ", cdevname);
+
+	va_start(ap, fmt);
+	(void)vfprintf(stdout, fmt, ap);
+	va_end(ap);
+
+	longjmp(jmpbuf, -1);
+}
+
+/*
  * Open the given provider, load superblock.
  */
 static void
@@ -169,9 +194,9 @@ opendisk(const char *devnam)
 		return;
 	disk = malloc(sizeof(*disk));
 	if (disk == NULL)
-		errx(1, "malloc(%zu)", sizeof(*disk));
+		err(EX_OSERR, "malloc(%zu)", sizeof(*disk));
 	if (ufs_disk_fillout(disk, devnam) == -1) {
-		err(1, "ufs_disk_fillout(%s) failed: %s", devnam,
+		err(EX_OSERR, "ufs_disk_fillout(%s) failed: %s", devnam,
 		    disk->d_error);
 	}
 	fs = &disk->d_fs;
@@ -203,9 +228,9 @@ closedisk(const char *devnam)
 	fs->fs_time = time(NULL);
 	fs->fs_mtime = time(NULL);
 	if (sbwrite(disk, 0) == -1)
-		err(1, "sbwrite(%s)", devnam);
+		err(EX_OSERR, "sbwrite(%s)", devnam);
 	if (ufs_disk_close(disk) == -1)
-		err(1, "ufs_disk_close(%s)", devnam);
+		err(EX_OSERR, "ufs_disk_close(%s)", devnam);
 	free(disk);
 	disk = NULL;
 	fs = NULL;
@@ -221,10 +246,8 @@ cg_lookup(int cgx)
 	struct cghd *hd;
 	struct suj_cg *sc;
 
-	if (cgx < 0 || cgx >= fs->fs_ncg) {
-		abort();
-		errx(1, "Bad cg number %d", cgx);
-	}
+	if (cgx < 0 || cgx >= fs->fs_ncg)
+		err_suj("Bad cg number %d\n", cgx);
 	if (lastcg && lastcg->sc_cgx == cgx)
 		return (lastcg);
 	hd = &cghash[SUJ_HASH(cgx)];
@@ -241,7 +264,7 @@ cg_lookup(int cgx)
 	LIST_INSERT_HEAD(hd, sc, sc_next);
 	if (bread(disk, fsbtodb(fs, cgtod(fs, sc->sc_cgx)), sc->sc_cgbuf,
 	    fs->fs_bsize) == -1)
-		err(1, "Unable to read cylinder group %d", sc->sc_cgx);
+		err_suj("Unable to read cylinder group %d\n", sc->sc_cgx);
 
 	return (sc);
 }
@@ -344,7 +367,7 @@ dblk_read(ufs2_daddr_t blk, int size)
 		dblk->db_buf = errmalloc(size);
 		dblk->db_size = size;
 		if (bread(disk, fsbtodb(fs, blk), dblk->db_buf, size) == -1)
-			err(1, "Failed to read data block %jd", blk);
+			err_suj("Failed to read data block %jd\n", blk);
 	}
 	return (dblk->db_buf);
 }
@@ -370,7 +393,7 @@ dblk_write(void)
 				continue;
 			if (bwrite(disk, fsbtodb(fs, dblk->db_blk),
 			    dblk->db_buf, dblk->db_size) == -1)
-				err(1, "Unable to write block %jd",
+				err_suj("Unable to write block %jd\n",
 				    dblk->db_blk);
 		}
 	}
@@ -403,7 +426,7 @@ ino_read(ino_t ino)
 	iblk->ib_blk = blk;
 	LIST_INSERT_HEAD(hd, iblk, ib_next);
 	if (bread(disk, fsbtodb(fs, blk), iblk->ib_buf, fs->fs_bsize) == -1)
-		err(1, "Failed to read inode block %jd", blk);
+		err_suj("Failed to read inode block %jd\n", blk);
 found:
 	sc->sc_lastiblk = iblk;
 	off = ino_to_fsbo(fs, ino);
@@ -447,7 +470,7 @@ iblk_write(struct ino_blk *iblk)
 		return;
 	if (bwrite(disk, fsbtodb(fs, iblk->ib_blk), iblk->ib_buf,
 	    fs->fs_bsize) == -1)
-		err(1, "Failed to write inode block %jd", iblk->ib_blk);
+		err_suj("Failed to write inode block %jd\n", iblk->ib_blk);
 }
 
 static int
@@ -679,9 +702,9 @@ indir_blkatoff(ufs2_daddr_t blk, ino_t i
 		return (0);
 	level = lbn_level(cur);
 	if (level == -1)
-		errx(1, "Invalid indir lbn %jd", lbn);
+		err_suj("Invalid indir lbn %jd\n", lbn);
 	if (level == 0 && lbn < 0)
-		errx(1, "Invalid lbn %jd", lbn);
+		err_suj("Invalid lbn %jd\n", lbn);
 	bap2 = (void *)dblk_read(blk, fs->fs_bsize);
 	bap1 = (void *)bap2;
 	lbnadd = 1;
@@ -693,7 +716,7 @@ indir_blkatoff(ufs2_daddr_t blk, ino_t i
 	else
 		i = (-lbn - base) / lbnadd;
 	if (i < 0 || i >= NINDIR(fs))
-		errx(1, "Invalid indirect index %d produced by lbn %jd",
+		err_suj("Invalid indirect index %d produced by lbn %jd\n",
 		    i, lbn);
 	if (level == 0)
 		cur = base + (i * lbnadd);
@@ -705,10 +728,8 @@ indir_blkatoff(ufs2_daddr_t blk, ino_t i
 		blk = bap2[i];
 	if (cur == lbn)
 		return (blk);
-	if (level == 0) {
-		abort();
-		errx(1, "Invalid lbn %jd at level 0", lbn);
-	}
+	if (level == 0)
+		err_suj("Invalid lbn %jd at level 0\n", lbn);
 	return indir_blkatoff(blk, ino, cur, lbn);
 }
 
@@ -762,7 +783,8 @@ ino_blkatoff(union dinode *ip, ino_t ino
 			continue;
 		return indir_blkatoff(DIP(ip, di_ib[i]), ino, -cur - i, lbn);
 	}
-	errx(1, "lbn %jd not in ino", lbn);
+	err_suj("lbn %jd not in ino\n", lbn);
+	/* NOTREACHED */
 }
 
 /*
@@ -786,6 +808,44 @@ blk_isat(ino_t ino, ufs_lbn_t lbn, ufs2_
 }
 
 /*
+ * Clear the directory entry at diroff that should point to child.  Minimal
+ * checking is done and it is assumed that this path was verified with isat.
+ */
+static void
+ino_clrat(ino_t parent, off_t diroff, ino_t child)
+{
+	union dinode *dip;
+	struct direct *dp;
+	ufs2_daddr_t blk;
+	uint8_t *block;
+	ufs_lbn_t lbn;
+	int blksize;
+	int frags;
+	int doff;
+
+	if (debug)
+		printf("Clearing inode %d from parent %d at offset %jd\n",
+		    child, parent, diroff);
+
+	lbn = lblkno(fs, diroff);
+	doff = blkoff(fs, diroff);
+	dip = ino_read(parent);
+	blk = ino_blkatoff(dip, parent, lbn, &frags);
+	blksize = sblksize(fs, DIP(dip, di_size), lbn);
+	block = dblk_read(blk, blksize);
+	dp = (struct direct *)&block[doff];
+	if (dp->d_ino != child)
+		errx(1, "Inode %d does not exist in %d at %jd",
+		    child, parent, diroff);
+	dp->d_ino = 0;
+	dblk_dirty(blk);
+	/*
+	 * The actual .. reference count will already have been removed
+	 * from the parent by the .. remref record.
+	 */
+}
+
+/*
  * Determines whether a pointer to an inode exists within a directory
  * at a specified offset.  Returns the mode of the found entry.
  */
@@ -851,7 +911,7 @@ ino_isat(ino_t parent, off_t diroff, ino
 		dpoff += dp->d_reclen;
 	} while (dpoff <= doff);
 	if (dpoff > fs->fs_bsize)
-		errx(1, "Corrupt directory block in dir ino %d", parent);
+		err_suj("Corrupt directory block in dir ino %d\n", parent);
 	/* Not found. */
 	if (dpoff != doff) {
 		if (debug)
@@ -907,7 +967,7 @@ indir_visit(ino_t ino, ufs_lbn_t lbn, uf
 		return;
 	level = lbn_level(lbn);
 	if (level == -1)
-		errx(1, "Invalid level for lbn %jd", lbn);
+		err_suj("Invalid level for lbn %jd\n", lbn);
 	if ((flags & VISIT_ROOT) == 0 && blk_isindir(blk, ino, lbn) == 0) {
 		if (debug)
 			printf("blk %jd ino %d lbn %jd(%d) is not indir.\n",
@@ -1055,7 +1115,6 @@ ino_adjblks(struct suj_ino *sino)
 	if (visitlbn >= NDADDR) {
 		isize = DIP(ip, di_size);
 		size = lblktosize(fs, visitlbn + 1);
-		printf("ino %d isize %jd size %jd\n", ino, isize, size);
 		if (isize > size)
 			isize = size;
 		/* Always truncate to free any unpopulated indirects. */
@@ -1113,6 +1172,57 @@ ino_setskip(struct suj_ino *sino, ino_t 
 		sino->si_skipparent = 1;
 }
 
+static void
+ino_remref(ino_t parent, ino_t child, uint64_t diroff, int isdotdot)
+{
+	struct suj_ino *sino;
+	struct suj_rec *srec;
+	struct jrefrec *rrec;
+
+	/*
+	 * Lookup this inode to see if we have a record for it.
+	 */
+	sino = ino_lookup(child, 0);
+	/*
+	 * Tell any child directories we've already removed their
+	 * parent link cnt.  Don't try to adjust our link down again.
+	 */
+	if (sino != NULL && isdotdot == 0)
+		ino_setskip(sino, parent);
+	/*
+	 * No valid record for this inode.  Just drop the on-disk
+	 * link by one.
+	 */
+	if (sino == NULL || sino->si_hasrecs == 0) {
+		ino_decr(child);
+		return;
+	}
+	/*
+	 * Use ino_adjust() if ino_check() has already processed this
+	 * child.  If we lose the last non-dot reference to a
+	 * directory it will be discarded.
+	 */
+	if (sino->si_linkadj) {
+		sino->si_nlink--;
+		if (isdotdot)
+			sino->si_dotlinks--;
+		ino_adjust(sino);
+		return;
+	}
+	/*
+	 * If we haven't yet processed this inode we need to make
+	 * sure we will successfully discover the lost path.  If not
+	 * use nlinkadj to remember.
+	 */
+	TAILQ_FOREACH(srec, &sino->si_recs, sr_next) {
+		rrec = (struct jrefrec *)srec->sr_rec;
+		if (rrec->jr_parent == parent &&
+		    rrec->jr_diroff == diroff)
+			return;
+	}
+	sino->si_nlinkadj++;
+}
+
 /*
  * Free the children of a directory when the directory is discarded.
  */
@@ -1120,13 +1230,11 @@ static void
 ino_free_children(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, int frags)
 {
 	struct suj_ino *sino;
-	struct suj_rec *srec;
-	struct jrefrec *rrec;
 	struct direct *dp;
 	off_t diroff;
 	uint8_t *block;
 	int skipparent;
-	int isparent;
+	int isdotdot;
 	int dpoff;
 	int size;
 
@@ -1144,53 +1252,15 @@ ino_free_children(ino_t ino, ufs_lbn_t l
 			continue;
 		if (dp->d_namlen == 1 && dp->d_name[0] == '.')
 			continue;
-		isparent = dp->d_namlen == 2 && dp->d_name[0] == '.' &&
+		isdotdot = dp->d_namlen == 2 && dp->d_name[0] == '.' &&
 		    dp->d_name[1] == '.';
-		if (isparent && skipparent == 1)
+		if (isdotdot && skipparent == 1)
 			continue;
 		if (debug)
 			printf("Directory %d removing ino %d name %s\n",
 			    ino, dp->d_ino, dp->d_name);
-		/*
-		 * Lookup this inode to see if we have a record for it.
-		 * If not, we've already adjusted it assuming this path
-		 * was valid and we have to adjust once more.
-		 */
-		sino = ino_lookup(dp->d_ino, 0);
-		if (sino == NULL || sino->si_hasrecs == 0) {
-			ino_decr(ino);
-			continue;
-		}
-		/*
-		 * Use ino_adjust() so if we lose the last non-dot reference
-		 * to a directory it can be discarded.
-		 */
-		if (sino->si_linkadj) {
-			sino->si_nlink--;
-			if (isparent)
-				sino->si_dotlinks--;
-			ino_adjust(sino);
-		}
-		/*
-		 * Tell any child directories we've already removed their
-		 * parent.  Don't try to adjust our link down again.
-		 */
-		if (isparent == 0)
-			ino_setskip(sino, ino);
-		/*
-		 * If we haven't yet processed this inode we need to make
-		 * sure we will successfully discover the lost path.  If not
-		 * use nlinkadj to remember.
-		 */
 		diroff = lblktosize(fs, lbn) + dpoff;
-		TAILQ_FOREACH(srec, &sino->si_recs, sr_next) {
-			rrec = (struct jrefrec *)srec->sr_rec;
-			if (rrec->jr_parent == ino &&
-			    rrec->jr_diroff == diroff)
-				break;
-		}
-		if (srec == NULL)
-			sino->si_nlinkadj++;
+		ino_remref(ino, dp->d_ino, diroff, isdotdot);
 	}
 }
 
@@ -1204,7 +1274,7 @@ ino_reclaim(union dinode *ip, ino_t ino,
 	uint32_t gen;
 
 	if (ino == ROOTINO)
-		errx(1, "Attempting to free ROOTINO");
+		err_suj("Attempting to free ROOTINO\n");
 	if (debug)
 		printf("Truncating and freeing ino %d, nlink %d, mode %o\n",
 		    ino, DIP(ip, di_nlink), DIP(ip, di_mode));
@@ -1241,9 +1311,9 @@ ino_decr(ino_t ino)
 	nlink = DIP(ip, di_nlink);
 	mode = DIP(ip, di_mode);
 	if (nlink < 1)
-		errx(1, "Inode %d link count %d invalid", ino, nlink);
+		err_suj("Inode %d link count %d invalid\n", ino, nlink);
 	if (mode == 0)
-		errx(1, "Inode %d has a link of %d with 0 mode.", ino, nlink);
+		err_suj("Inode %d has a link of %d with 0 mode\n", ino, nlink);
 	nlink--;
 	if ((mode & IFMT) == IFDIR)
 		reqlink = 2;
@@ -1272,18 +1342,38 @@ ino_adjust(struct suj_ino *sino)
 	struct suj_ino *stmp;
 	union dinode *ip;
 	nlink_t nlink;
+	int recmode;
 	int reqlink;
+	int isdot;
 	int mode;
 	ino_t ino;
 
 	nlink = sino->si_nlink;
 	ino = sino->si_ino;
+	mode = sino->si_mode & IFMT;
+	/*
+	 * If it's a directory with no dot links, it was truncated before
+	 * the name was cleared.  We need to clear the dirent that
+	 * points at it.
+	 */
+	if (mode == IFDIR && nlink == 1 && sino->si_dotlinks == 0) {
+		sino->si_nlink = nlink = 0;
+		TAILQ_FOREACH(srec, &sino->si_recs, sr_next) {
+			rrec = (struct jrefrec *)srec->sr_rec;
+			if (ino_isat(rrec->jr_parent, rrec->jr_diroff, ino,
+			    &recmode, &isdot) == 0)
+				continue;
+			ino_clrat(rrec->jr_parent, rrec->jr_diroff, ino);
+			break;
+		}
+		if (srec == NULL)
+			errx(1, "Directory %d name not found", ino);
+	}
 	/*
 	 * If it's a directory with no real names pointing to it go ahead
 	 * and truncate it.  This will free any children.
 	 */
-	if ((sino->si_mode & IFMT) == IFDIR &&
-	    nlink - sino->si_dotlinks == 0) {
+	if (mode == IFDIR && nlink - sino->si_dotlinks == 0) {
 		sino->si_nlink = nlink = 0;
 		/*
 		 * Mark any .. links so they know not to free this inode
@@ -1301,8 +1391,8 @@ ino_adjust(struct suj_ino *sino)
 	ip = ino_read(ino);
 	mode = DIP(ip, di_mode) & IFMT;
 	if (nlink > LINK_MAX)
-		errx(1,
-		    "ino %d nlink manipulation error, new link %d, old link %d",
+		err_suj(
+		    "ino %d nlink manipulation error, new link %d, old link %d\n",
 		    ino, nlink, DIP(ip, di_nlink));
 	if (debug)
 		printf("Adjusting ino %d, nlink %d, old link %d lastmode %o\n",
@@ -1360,7 +1450,7 @@ indir_trunc(ino_t ino, ufs_lbn_t lbn, uf
 	dirty = 0;
 	level = lbn_level(lbn);
 	if (level == -1)
-		errx(1, "Invalid level for lbn %jd", lbn);
+		err_suj("Invalid level for lbn %jd\n", lbn);
 	lbnadd = 1;
 	for (i = level; i > 0; i--)
 		lbnadd *= NINDIR(fs);
@@ -1489,7 +1579,7 @@ ino_trunc(ino_t ino, off_t size)
 
 		bn = DIP(ip, di_db[visitlbn]);
 		if (bn == 0)
-			errx(1, "Bad blk at ino %d lbn %jd\n", ino, visitlbn);
+			err_suj("Bad blk at ino %d lbn %jd\n", ino, visitlbn);
 		oldspace = sblksize(fs, cursize, visitlbn);
 		newspace = sblksize(fs, size, visitlbn);
 		if (oldspace != newspace) {
@@ -1513,7 +1603,7 @@ ino_trunc(ino_t ino, off_t size)
 
 		bn = ino_blkatoff(ip, ino, visitlbn, &frags);
 		if (bn == 0)
-			errx(1, "Block missing from ino %d at lbn %jd\n",
+			err_suj("Block missing from ino %d at lbn %jd\n",
 			    ino, visitlbn);
 		clrsize = frags * fs->fs_fsize;
 		buf = dblk_read(bn, clrsize);
@@ -1556,7 +1646,7 @@ ino_check(struct suj_ino *sino)
 		isat = ino_isat(rrec->jr_parent, rrec->jr_diroff, 
 		    rrec->jr_ino, &mode, &isdot);
 		if (isat && (mode & IFMT) != (rrec->jr_mode & IFMT))
-			errx(1, "Inode mode/directory type mismatch %o != %o",
+			err_suj("Inode mode/directory type mismatch %o != %o\n",
 			    mode, rrec->jr_mode);
 		if (debug)
 			printf("jrefrec: op %d ino %d, nlink %d, parent %d, "
@@ -1779,7 +1869,7 @@ cg_write(struct suj_cg *sc)
 	fs->fs_cs(fs, sc->sc_cgx) = cgp->cg_cs;
 	if (bwrite(disk, fsbtodb(fs, cgtod(fs, sc->sc_cgx)), sc->sc_cgbuf,
 	    fs->fs_bsize) == -1)
-		err(1, "Unable to write cylinder group %d", sc->sc_cgx);
+		err_suj("Unable to write cylinder group %d\n", sc->sc_cgx);
 }
 
 /*
@@ -1971,6 +2061,7 @@ ino_build_ref(struct suj_ino *sino, stru
 				continue;
 			diroff = mvrec->jm_oldoff;
 			TAILQ_REMOVE(&sino->si_movs, srn, sr_next);
+			free(srn);
 			ino_dup_ref(sino, refrec, diroff);
 		}
 	}
@@ -2027,7 +2118,7 @@ ino_build_ref(struct suj_ino *sino, stru
 			TAILQ_REMOVE(&sino->si_newrecs, srn, sr_next);
 			break;
 		default:
-			errx(1, "ino_build_ref: Unknown op %d",
+			err_suj("ino_build_ref: Unknown op %d\n",
 			    srn->sr_rec->rec_jrefrec.jr_op);
 		}
 	}
@@ -2057,7 +2148,7 @@ ino_build(struct suj_ino *sino)
 			TAILQ_INSERT_TAIL(&sino->si_movs, srec, sr_next);
 			break;
 		default:
-			errx(1, "ino_build: Unknown op %d",
+			err_suj("ino_build: Unknown op %d\n",
 			    srec->sr_rec->rec_jrefrec.jr_op);
 		}
 	}
@@ -2108,7 +2199,7 @@ blk_build(struct jblkrec *blkrec)
 	blkrec->jb_blkno -= frag;
 	blkrec->jb_oldfrags = frag;
 	if (blkrec->jb_oldfrags + blkrec->jb_frags > fs->fs_frag)
-		errx(1, "Invalid fragment count %d oldfrags %d",
+		err_suj("Invalid fragment count %d oldfrags %d\n",
 		    blkrec->jb_frags, frag);
 	/*
 	 * Detect dups.  If we detect a dup we always discard the oldest
@@ -2186,7 +2277,7 @@ suj_build(void)
 				ino_build_trunc((struct jtrncrec *)rec);
 				break;
 			default:
-				errx(1, "Unknown journal operation %d (%d)",
+				err_suj("Unknown journal operation %d (%d)\n",
 				    rec->rec_jrefrec.jr_op, off);
 			}
 			i++;
@@ -2234,9 +2325,10 @@ suj_prune(void)
 		newseq = seg->ss_rec.jsr_seq;
 		
 	}
-	if (newseq != oldseq)
-		errx(1, "Journal file sequence mismatch %jd != %jd",
+	if (newseq != oldseq) {
+		err_suj("Journal file sequence mismatch %jd != %jd\n",
 		    newseq, oldseq);
+	}
 	/*
 	 * The kernel may asynchronously write segments which can create
 	 * gaps in the sequence space.  Throw away any segments after the
@@ -2464,9 +2556,10 @@ restart:
 		/*
 		 * Read 1MB at a time and scan for records within this block.
 		 */
-		if (bread(disk, blk, &block, size) == -1)
-			err(1, "Error reading journal block %jd",
+		if (bread(disk, blk, &block, size) == -1) {
+			err_suj("Error reading journal block %jd\n",
 			    (intmax_t)blk);
+		}
 		for (rec = (void *)block; size; size -= recsize,

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201007140848.o6E8ms9h011452>