svn commit: r210043 - in projects/suj/7: sbin/dumpfs sbin/fsck_ffs
sbin/tunefs sys/sys sys/ufs/ffs sys/ufs/ufs
Jeff Roberson
jeff at FreeBSD.org
Wed Jul 14 01:55:25 UTC 2010
Author: jeff
Date: Wed Jul 14 01:55:24 2010
New Revision: 210043
URL: http://svn.freebsd.org/changeset/base/210043
Log:
- Update suj/7 with changes from recent head.
Modified:
projects/suj/7/sbin/dumpfs/dumpfs.c
projects/suj/7/sbin/fsck_ffs/fsck.h
projects/suj/7/sbin/fsck_ffs/main.c
projects/suj/7/sbin/fsck_ffs/pass1.c
projects/suj/7/sbin/fsck_ffs/pass2.c
projects/suj/7/sbin/fsck_ffs/pass4.c
projects/suj/7/sbin/fsck_ffs/suj.c
projects/suj/7/sbin/tunefs/tunefs.8
projects/suj/7/sbin/tunefs/tunefs.c
projects/suj/7/sys/sys/buf.h
projects/suj/7/sys/ufs/ffs/ffs_alloc.c
projects/suj/7/sys/ufs/ffs/ffs_extern.h
projects/suj/7/sys/ufs/ffs/ffs_inode.c
projects/suj/7/sys/ufs/ffs/ffs_snapshot.c
projects/suj/7/sys/ufs/ffs/ffs_softdep.c
projects/suj/7/sys/ufs/ffs/ffs_vfsops.c
projects/suj/7/sys/ufs/ffs/ffs_vnops.c
projects/suj/7/sys/ufs/ffs/fs.h
projects/suj/7/sys/ufs/ffs/softdep.h
projects/suj/7/sys/ufs/ufs/inode.h
projects/suj/7/sys/ufs/ufs/ufs_inode.c
projects/suj/7/sys/ufs/ufs/ufs_lookup.c
projects/suj/7/sys/ufs/ufs/ufs_vnops.c
Modified: projects/suj/7/sbin/dumpfs/dumpfs.c
==============================================================================
--- projects/suj/7/sbin/dumpfs/dumpfs.c Wed Jul 14 01:17:29 2010 (r210042)
+++ projects/suj/7/sbin/dumpfs/dumpfs.c Wed Jul 14 01:55:24 2010 (r210043)
@@ -238,7 +238,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)
@@ -252,7 +252,8 @@ 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_GJOURNAL | FS_FLAGS_UPDATED);
+ FS_ACLS | FS_MULTILABEL | FS_GJOURNAL | FS_FLAGS_UPDATED |
+ FS_SUJ);
if (fsflags != 0)
printf("unknown flags (%#x)", fsflags);
putchar('\n');
Modified: projects/suj/7/sbin/fsck_ffs/fsck.h
==============================================================================
--- projects/suj/7/sbin/fsck_ffs/fsck.h Wed Jul 14 01:17:29 2010 (r210042)
+++ projects/suj/7/sbin/fsck_ffs/fsck.h Wed Jul 14 01:55:24 2010 (r210043)
@@ -60,6 +60,9 @@
* $FreeBSD$
*/
+#ifndef _FSCK_H_
+#define _FSCK_H_
+
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
@@ -389,3 +392,5 @@ void setinodebuf(ino_t);
int setup(char *dev);
void gjournal_check(const char *filesys);
int suj_check(const char *filesys);
+
+#endif /* !_FSCK_H_ */
Modified: projects/suj/7/sbin/fsck_ffs/main.c
==============================================================================
--- projects/suj/7/sbin/fsck_ffs/main.c Wed Jul 14 01:17:29 2010 (r210042)
+++ projects/suj/7/sbin/fsck_ffs/main.c Wed Jul 14 01:55:24 2010 (r210043)
@@ -394,16 +394,18 @@ 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) {
- if (chkdoreload(mntp) == 0)
- exit(0);
- exit(4);
+ 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");
+ if (chkdoreload(mntp) == 0)
+ exit(0);
+ exit(4);
+ }
}
- /* suj_check failed, fall through. */
+ printf("** Skipping journal, falling through to full fsck\n\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.
@@ -433,7 +435,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/7/sbin/fsck_ffs/pass1.c
==============================================================================
--- projects/suj/7/sbin/fsck_ffs/pass1.c Wed Jul 14 01:17:29 2010 (r210042)
+++ projects/suj/7/sbin/fsck_ffs/pass1.c Wed Jul 14 01:55:24 2010 (r210043)
@@ -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/7/sbin/fsck_ffs/pass2.c
==============================================================================
--- projects/suj/7/sbin/fsck_ffs/pass2.c Wed Jul 14 01:17:29 2010 (r210042)
+++ projects/suj/7/sbin/fsck_ffs/pass2.c Wed Jul 14 01:55:24 2010 (r210043)
@@ -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/7/sbin/fsck_ffs/pass4.c
==============================================================================
--- projects/suj/7/sbin/fsck_ffs/pass4.c Wed Jul 14 01:17:29 2010 (r210042)
+++ projects/suj/7/sbin/fsck_ffs/pass4.c Wed Jul 14 01:55:24 2010 (r210043)
@@ -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/7/sbin/fsck_ffs/suj.c
==============================================================================
--- projects/suj/7/sbin/fsck_ffs/suj.c Wed Jul 14 01:17:29 2010 (r210042)
+++ projects/suj/7/sbin/fsck_ffs/suj.c Wed Jul 14 01:55:24 2010 (r210043)
@@ -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,
rec = (struct jsegrec *)((uintptr_t)rec + recsize)) {
recsize = DEV_BSIZE;
@@ -2545,7 +2638,7 @@ suj_find(ino_t ino, ufs_lbn_t lbn, ufs2_
return;
bytes = lfragtosize(fs, frags);
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-projects
mailing list