aboutsummaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
Diffstat (limited to 'sbin')
-rw-r--r--sbin/fsck_ffs/dir.c139
-rw-r--r--sbin/fsck_ffs/ea.c1
-rw-r--r--sbin/fsck_ffs/fsck.h81
-rw-r--r--sbin/fsck_ffs/fsutil.c424
-rw-r--r--sbin/fsck_ffs/gjournal.c411
-rw-r--r--sbin/fsck_ffs/globs.c9
-rw-r--r--sbin/fsck_ffs/inode.c368
-rw-r--r--sbin/fsck_ffs/main.c16
-rw-r--r--sbin/fsck_ffs/pass1.c61
-rw-r--r--sbin/fsck_ffs/pass1b.c14
-rw-r--r--sbin/fsck_ffs/pass2.c35
-rw-r--r--sbin/fsck_ffs/pass3.c7
-rw-r--r--sbin/fsck_ffs/pass4.c11
-rw-r--r--sbin/fsck_ffs/setup.c18
-rw-r--r--sbin/fsck_ffs/suj.c914
-rw-r--r--sbin/fsdb/fsdb.c89
-rw-r--r--sbin/fsdb/fsdb.h1
17 files changed, 1215 insertions, 1384 deletions
diff --git a/sbin/fsck_ffs/dir.c b/sbin/fsck_ffs/dir.c
index a86d65a9f183..e88d1650ce5a 100644
--- a/sbin/fsck_ffs/dir.c
+++ b/sbin/fsck_ffs/dir.c
@@ -62,7 +62,7 @@ static struct dirtemplate dirhead = {
static int chgino(struct inodesc *);
static int dircheck(struct inodesc *, struct bufarea *, struct direct *);
-static int expanddir(union dinode *dp, char *name);
+static int expanddir(struct inode *ip, char *name);
static void freedir(ino_t ino, ino_t parent);
static struct direct *fsck_readdir(struct inodesc *);
static struct bufarea *getdirblk(ufs2_daddr_t blkno, long size);
@@ -126,6 +126,8 @@ dirscan(struct inodesc *idesc)
idesc->id_dirp = (struct direct *)dbuf;
if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
bp = getdirblk(idesc->id_blkno, blksiz);
+ if (bp->b_errs != 0)
+ return (STOP);
memmove(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf,
(size_t)dsize);
dirty(bp);
@@ -155,6 +157,8 @@ fsck_readdir(struct inodesc *idesc)
if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
return (NULL);
bp = getdirblk(idesc->id_blkno, blksiz);
+ if (bp->b_errs != 0)
+ return (NULL);
dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
/*
* Only need to check current entry if it is the first in the
@@ -330,6 +334,7 @@ direrror(ino_t ino, const char *errmesg)
void
fileerror(ino_t cwd, ino_t ino, const char *errmesg)
{
+ struct inode ip;
union dinode *dp;
char pathbuf[MAXPATHLEN + 1];
@@ -338,8 +343,9 @@ fileerror(ino_t cwd, ino_t ino, const char *errmesg)
pfatal("out-of-range inode number %ju", (uintmax_t)ino);
return;
}
- dp = ginode(ino);
- prtinode(ino, dp);
+ ginode(ino, &ip);
+ dp = ip.i_dp;
+ prtinode(&ip);
printf("\n");
getpathname(pathbuf, cwd, ino);
if (ftypeok(dp))
@@ -348,15 +354,18 @@ fileerror(ino_t cwd, ino_t ino, const char *errmesg)
pathbuf);
else
pfatal("NAME=%s\n", pathbuf);
+ irelse(&ip);
}
void
adjust(struct inodesc *idesc, int lcnt)
{
+ struct inode ip;
union dinode *dp;
int saveresolved;
- dp = ginode(idesc->id_number);
+ ginode(idesc->id_number, &ip);
+ dp = ip.i_dp;
if (DIP(dp, di_nlink) == lcnt) {
/*
* If we have not hit any unresolved problems, are running
@@ -365,6 +374,7 @@ adjust(struct inodesc *idesc, int lcnt)
*/
if (resolved && (preen || bkgrdflag) && usedsoftdep) {
clri(idesc, "UNREF", 1);
+ irelse(&ip);
return;
} else {
/*
@@ -377,19 +387,19 @@ adjust(struct inodesc *idesc, int lcnt)
if (linkup(idesc->id_number, (ino_t)0, NULL) == 0) {
resolved = saveresolved;
clri(idesc, "UNREF", 0);
+ irelse(&ip);
return;
}
/*
* Account for the new reference created by linkup().
*/
- dp = ginode(idesc->id_number);
lcnt--;
}
}
if (lcnt != 0) {
pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname :
((DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE"));
- prtinode(idesc->id_number, dp);
+ prtinode(&ip);
printf(" COUNT %d SHOULD BE %d",
DIP(dp, di_nlink), DIP(dp, di_nlink) - lcnt);
if (preen || usedsoftdep) {
@@ -403,7 +413,7 @@ adjust(struct inodesc *idesc, int lcnt)
if (preen || reply("ADJUST") == 1) {
if (bkgrdflag == 0) {
DIP_SET(dp, di_nlink, DIP(dp, di_nlink) - lcnt);
- inodirty(dp);
+ inodirty(&ip);
} else {
cmd.value = idesc->id_number;
cmd.size = -lcnt;
@@ -417,6 +427,7 @@ adjust(struct inodesc *idesc, int lcnt)
}
}
}
+ irelse(&ip);
}
static int
@@ -460,6 +471,7 @@ chgino(struct inodesc *idesc)
int
linkup(ino_t orphan, ino_t parentdir, char *name)
{
+ struct inode ip;
union dinode *dp;
int lostdir;
ino_t oldlfdir;
@@ -467,29 +479,32 @@ linkup(ino_t orphan, ino_t parentdir, char *name)
char tempname[BUFSIZ];
memset(&idesc, 0, sizeof(struct inodesc));
- dp = ginode(orphan);
+ ginode(orphan, &ip);
+ dp = ip.i_dp;
lostdir = (DIP(dp, di_mode) & IFMT) == IFDIR;
pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
- prtinode(orphan, dp);
+ prtinode(&ip);
printf("\n");
- if (preen && DIP(dp, di_size) == 0)
+ if (preen && DIP(dp, di_size) == 0) {
+ irelse(&ip);
return (0);
+ }
+ irelse(&ip);
if (cursnapshot != 0) {
pfatal("FILE LINKUP IN SNAPSHOT");
return (0);
}
if (preen)
printf(" (RECONNECTED)\n");
- else
- if (reply("RECONNECT") == 0)
- return (0);
+ else if (reply("RECONNECT") == 0)
+ return (0);
if (lfdir == 0) {
- dp = ginode(UFS_ROOTINO);
+ ginode(UFS_ROOTINO, &ip);
idesc.id_name = strdup(lfname);
idesc.id_type = DATA;
idesc.id_func = findino;
idesc.id_number = UFS_ROOTINO;
- if ((ckinode(dp, &idesc) & FOUND) != 0) {
+ if ((ckinode(ip.i_dp, &idesc) & FOUND) != 0) {
lfdir = idesc.id_parent;
} else {
pwarn("NO lost+found DIRECTORY");
@@ -510,42 +525,52 @@ linkup(ino_t orphan, ino_t parentdir, char *name)
}
}
}
+ irelse(&ip);
if (lfdir == 0) {
pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY");
printf("\n\n");
return (0);
}
}
- dp = ginode(lfdir);
+ ginode(lfdir, &ip);
+ dp = ip.i_dp;
if ((DIP(dp, di_mode) & IFMT) != IFDIR) {
pfatal("lost+found IS NOT A DIRECTORY");
- if (reply("REALLOCATE") == 0)
+ if (reply("REALLOCATE") == 0) {
+ irelse(&ip);
return (0);
+ }
oldlfdir = lfdir;
if ((lfdir = allocdir(UFS_ROOTINO, (ino_t)0, lfmode)) == 0) {
pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
+ irelse(&ip);
return (0);
}
if ((changeino(UFS_ROOTINO, lfname, lfdir) & ALTERED) == 0) {
pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
+ irelse(&ip);
return (0);
}
- inodirty(dp);
- idesc.id_type = ADDR;
+ idesc.id_type = inoinfo(oldlfdir)->ino_idtype;
idesc.id_func = freeblock;
idesc.id_number = oldlfdir;
adjust(&idesc, inoinfo(oldlfdir)->ino_linkcnt + 1);
inoinfo(oldlfdir)->ino_linkcnt = 0;
- dp = ginode(lfdir);
+ inodirty(&ip);
+ irelse(&ip);
+ ginode(lfdir, &ip);
+ dp = ip.i_dp;
}
if (inoinfo(lfdir)->ino_state != DFOUND) {
pfatal("SORRY. NO lost+found DIRECTORY\n\n");
+ irelse(&ip);
return (0);
}
(void)lftempname(tempname, orphan);
if (makeentry(lfdir, orphan, (name ? name : tempname)) == 0) {
pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
printf("\n\n");
+ irelse(&ip);
return (0);
}
inoinfo(orphan)->ino_linkcnt--;
@@ -553,9 +578,8 @@ linkup(ino_t orphan, ino_t parentdir, char *name)
if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 &&
parentdir != (ino_t)-1)
(void)makeentry(orphan, lfdir, "..");
- dp = ginode(lfdir);
DIP_SET(dp, di_nlink, DIP(dp, di_nlink) + 1);
- inodirty(dp);
+ inodirty(&ip);
inoinfo(lfdir)->ino_linkcnt++;
pwarn("DIR I=%lu CONNECTED. ", (u_long)orphan);
if (parentdir != (ino_t)-1) {
@@ -572,6 +596,7 @@ linkup(ino_t orphan, ino_t parentdir, char *name)
if (preen == 0)
printf("\n");
}
+ irelse(&ip);
return (1);
}
@@ -582,6 +607,8 @@ int
changeino(ino_t dir, const char *name, ino_t newnum)
{
struct inodesc idesc;
+ struct inode ip;
+ int error;
memset(&idesc, 0, sizeof(struct inodesc));
idesc.id_type = DATA;
@@ -590,7 +617,10 @@ changeino(ino_t dir, const char *name, ino_t newnum)
idesc.id_fix = DONTKNOW;
idesc.id_name = strdup(name);
idesc.id_parent = newnum; /* new value for name */
- return (ckinode(ginode(dir), &idesc));
+ ginode(dir, &ip);
+ error = ckinode(ip.i_dp, &idesc);
+ irelse(&ip);
+ return (error);
}
/*
@@ -599,8 +629,10 @@ changeino(ino_t dir, const char *name, ino_t newnum)
int
makeentry(ino_t parent, ino_t ino, const char *name)
{
+ struct inode ip;
union dinode *dp;
struct inodesc idesc;
+ int retval;
char pathbuf[MAXPATHLEN + 1];
if (parent < UFS_ROOTINO || parent >= maxino ||
@@ -613,30 +645,37 @@ makeentry(ino_t parent, ino_t ino, const char *name)
idesc.id_parent = ino; /* this is the inode to enter */
idesc.id_fix = DONTKNOW;
idesc.id_name = strdup(name);
- dp = ginode(parent);
+ ginode(parent, &ip);
+ dp = ip.i_dp;
if (DIP(dp, di_size) % DIRBLKSIZ) {
DIP_SET(dp, di_size, roundup(DIP(dp, di_size), DIRBLKSIZ));
- inodirty(dp);
+ inodirty(&ip);
}
- if ((ckinode(dp, &idesc) & ALTERED) != 0)
+ if ((ckinode(dp, &idesc) & ALTERED) != 0) {
+ irelse(&ip);
return (1);
+ }
getpathname(pathbuf, parent, parent);
- dp = ginode(parent);
- if (expanddir(dp, pathbuf) == 0)
+ if (expanddir(&ip, pathbuf) == 0) {
+ irelse(&ip);
return (0);
- return (ckinode(dp, &idesc) & ALTERED);
+ }
+ retval = ckinode(dp, &idesc) & ALTERED;
+ irelse(&ip);
+ return (retval);
}
/*
* Attempt to expand the size of a directory
*/
static int
-expanddir(union dinode *dp, char *name)
+expanddir(struct inode *ip, char *name)
{
ufs2_daddr_t lastlbn, oldblk, newblk, indirblk;
size_t filesize, lastlbnsize;
struct bufarea *bp, *nbp;
struct inodesc idesc;
+ union dinode *dp;
int indiralloced;
char *cp;
@@ -645,6 +684,7 @@ expanddir(union dinode *dp, char *name)
pwarn("NO SPACE LEFT IN %s", name);
if (!preen && reply("EXPAND") == 0)
return (0);
+ dp = ip->i_dp;
filesize = DIP(dp, di_size);
lastlbn = lblkno(&sblock, filesize);
/*
@@ -671,7 +711,7 @@ expanddir(union dinode *dp, char *name)
DIP_SET(dp, di_size, filesize + sblock.fs_bsize - lastlbnsize);
DIP_SET(dp, di_blocks, DIP(dp, di_blocks) +
btodb(sblock.fs_bsize - lastlbnsize));
- inodirty(dp);
+ inodirty(ip);
memmove(nbp->b_un.b_buf, bp->b_un.b_buf, lastlbnsize);
memset(&nbp->b_un.b_buf[lastlbnsize], 0,
sblock.fs_bsize - lastlbnsize);
@@ -680,10 +720,12 @@ expanddir(union dinode *dp, char *name)
cp += DIRBLKSIZ)
memmove(cp, &emptydir, sizeof emptydir);
dirty(nbp);
- nbp->b_flags &= ~B_INUSE;
+ brelse(nbp);
idesc.id_blkno = oldblk;
idesc.id_numfrags = numfrags(&sblock, lastlbnsize);
(void)freeblock(&idesc);
+ if (preen)
+ printf(" (EXPANDED)\n");
return (1);
}
if ((newblk = allocblk(sblock.fs_frag)) == 0)
@@ -719,18 +761,18 @@ expanddir(union dinode *dp, char *name)
}
IBLK_SET(nbp, lastlbn - UFS_NDADDR, newblk);
dirty(nbp);
- nbp->b_flags &= ~B_INUSE;
+ brelse(nbp);
}
DIP_SET(dp, di_size, filesize + sblock.fs_bsize);
DIP_SET(dp, di_blocks, DIP(dp, di_blocks) + btodb(sblock.fs_bsize));
- inodirty(dp);
+ inodirty(ip);
if (preen)
printf(" (EXPANDED)\n");
return (1);
bad:
pfatal(" (EXPANSION FAILED)\n");
if (nbp != NULL)
- nbp->b_flags &= ~B_INUSE;
+ brelse(nbp);
if (newblk != 0) {
idesc.id_blkno = newblk;
idesc.id_numfrags = sblock.fs_frag;
@@ -752,6 +794,7 @@ allocdir(ino_t parent, ino_t request, int mode)
{
ino_t ino;
char *cp;
+ struct inode ip;
union dinode *dp;
struct bufarea *bp;
struct inoinfo *inp;
@@ -761,10 +804,12 @@ allocdir(ino_t parent, ino_t request, int mode)
dirp = &dirhead;
dirp->dot_ino = ino;
dirp->dotdot_ino = parent;
- dp = ginode(ino);
+ ginode(ino, &ip);
+ dp = ip.i_dp;
bp = getdirblk(DIP(dp, di_db[0]), sblock.fs_fsize);
if (bp->b_errs) {
freeino(ino);
+ irelse(&ip);
return (0);
}
memmove(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate));
@@ -774,14 +819,16 @@ allocdir(ino_t parent, ino_t request, int mode)
memmove(cp, &emptydir, sizeof emptydir);
dirty(bp);
DIP_SET(dp, di_nlink, 2);
- inodirty(dp);
+ inodirty(&ip);
if (ino == UFS_ROOTINO) {
inoinfo(ino)->ino_linkcnt = DIP(dp, di_nlink);
cacheino(dp, ino);
+ irelse(&ip);
return(ino);
}
if (!INO_IS_DVALID(parent)) {
freeino(ino);
+ irelse(&ip);
return (0);
}
cacheino(dp, ino);
@@ -793,9 +840,12 @@ allocdir(ino_t parent, ino_t request, int mode)
inoinfo(ino)->ino_linkcnt = DIP(dp, di_nlink);
inoinfo(parent)->ino_linkcnt++;
}
- dp = ginode(parent);
+ irelse(&ip);
+ ginode(parent, &ip);
+ dp = ip.i_dp;
DIP_SET(dp, di_nlink, DIP(dp, di_nlink) + 1);
- inodirty(dp);
+ inodirty(&ip);
+ irelse(&ip);
return (ino);
}
@@ -805,12 +855,15 @@ allocdir(ino_t parent, ino_t request, int mode)
static void
freedir(ino_t ino, ino_t parent)
{
+ struct inode ip;
union dinode *dp;
if (ino != parent) {
- dp = ginode(parent);
+ ginode(parent, &ip);
+ dp = ip.i_dp;
DIP_SET(dp, di_nlink, DIP(dp, di_nlink) - 1);
- inodirty(dp);
+ inodirty(&ip);
+ irelse(&ip);
}
freeino(ino);
}
@@ -847,8 +900,8 @@ static struct bufarea *
getdirblk(ufs2_daddr_t blkno, long size)
{
- if (pdirbp != NULL)
- pdirbp->b_flags &= ~B_INUSE;
+ if (pdirbp != NULL && pdirbp->b_errs == 0)
+ brelse(pdirbp);
pdirbp = getdatablk(blkno, size, BT_DIRDATA);
return (pdirbp);
}
diff --git a/sbin/fsck_ffs/ea.c b/sbin/fsck_ffs/ea.c
index 29e5f46d7651..7cf20196dfae 100644
--- a/sbin/fsck_ffs/ea.c
+++ b/sbin/fsck_ffs/ea.c
@@ -82,6 +82,7 @@ eascan(struct inodesc *idesc, struct ufs2_dinode *dp)
if ((n & 31) == 31)
printf("\n");
}
+ brelse(bp);
return (STOP);
#endif
}
diff --git a/sbin/fsck_ffs/fsck.h b/sbin/fsck_ffs/fsck.h
index a471d1979438..676350b75767 100644
--- a/sbin/fsck_ffs/fsck.h
+++ b/sbin/fsck_ffs/fsck.h
@@ -73,8 +73,7 @@
#define MAXDUP 10 /* limit on dup blks (per inode) */
#define MAXBAD 10 /* limit on bad blks (per inode) */
-#define MINBUFS 10 /* minimum number of buffers required */
-#define MAXBUFS 40 /* maximum space to allocate to buffers */
+#define MINBUFS 100 /* minimum number of buffers required */
#define INOBUFSIZE 64*1024 /* size of buffer to read inodes in pass1 */
#define ZEROBUFSIZE (dev_bsize * 128) /* size of zero buffer used by -Z */
@@ -101,9 +100,10 @@ union dinode {
* have its link count adjusted by the value remaining in ino_linkcnt.
*/
struct inostat {
- char ino_state; /* state of inode, see below */
- char ino_type; /* type of inode */
- short ino_linkcnt; /* number of links not found */
+ u_char ino_state; /* state of inode, see below */
+ u_char ino_type:4; /* type of inode */
+ u_char ino_idtype:4; /* idesc id_type, SNAP or ADDR */
+ u_short ino_linkcnt; /* number of links not found */
};
/*
* Inode states.
@@ -133,15 +133,34 @@ extern struct inostatlist {
} *inostathead;
/*
+ * Structure to reference a dinode.
+ */
+struct inode {
+ struct bufarea *i_bp; /* buffer containing the dinode */
+ union dinode *i_dp; /* pointer to dinode in buffer */
+ ino_t i_number; /* inode number */
+};
+
+/*
+ * Size of hash tables
+ */
+#define HASHSIZE 2048
+#define HASH(x) ((x * 2654435761) & (HASHSIZE - 1))
+
+/*
* buffer cache structure.
*/
struct bufarea {
- TAILQ_ENTRY(bufarea) b_list; /* buffer list */
+ TAILQ_ENTRY(bufarea) b_list; /* LRU buffer queue */
+ LIST_ENTRY(bufarea) b_hash; /* hash list */
ufs2_daddr_t b_bno; /* disk block number */
int b_size; /* size of I/O */
int b_errs; /* I/O error */
int b_flags; /* B_ flags below */
int b_type; /* BT_ type below */
+ int b_refcnt; /* ref count of users */
+ int b_index; /* for BT_LEVEL, ptr index */
+ /* for BT_INODES, first inum */
union {
char *b_buf; /* buffer space */
ufs1_daddr_t *b_indir1; /* UFS1 indirect block */
@@ -151,7 +170,6 @@ struct bufarea {
struct ufs1_dinode *b_dinode1; /* UFS1 inode block */
struct ufs2_dinode *b_dinode2; /* UFS2 inode block */
} b_un;
- char b_dirty;
};
#define IBLK(bp, i) \
@@ -168,7 +186,7 @@ struct bufarea {
/*
* Buffer flags
*/
-#define B_INUSE 0x00000001 /* Buffer is in use */
+#define B_DIRTY 0x00000001 /* Buffer is dirty */
/*
* Type of data in buffer
*/
@@ -182,7 +200,8 @@ struct bufarea {
#define BT_INODES 7 /* Buffer holds inodes */
#define BT_DIRDATA 8 /* Buffer holds directory data */
#define BT_DATA 9 /* Buffer holds user data */
-#define BT_NUMBUFTYPES 10
+#define BT_EMPTY 10 /* Buffer allocated but not filled */
+#define BT_NUMBUFTYPES 11
#define BT_NAMES { \
"unknown", \
"Superblock", \
@@ -193,27 +212,33 @@ struct bufarea {
"External Attribute", \
"Inode Block", \
"Directory Contents", \
- "User Data" }
+ "User Data", \
+ "Allocated but not filled" }
+extern char *buftype[];
+#define BT_BUFTYPE(type) \
+ type < BT_NUMBUFTYPES ? buftype[type] : buftype[BT_UNKNOWN]
extern long readcnt[BT_NUMBUFTYPES];
extern long totalreadcnt[BT_NUMBUFTYPES];
extern struct timespec readtime[BT_NUMBUFTYPES];
extern struct timespec totalreadtime[BT_NUMBUFTYPES];
extern struct timespec startprog;
+extern struct bufarea *icachebp; /* inode cache buffer */
extern struct bufarea sblk; /* file system superblock */
extern struct bufarea *pdirbp; /* current directory contents */
-extern struct bufarea *pbp; /* current inode block */
+extern int sujrecovery; /* 1 => doing check using the journal */
#define dirty(bp) do { \
if (fswritefd < 0) \
pfatal("SETTING DIRTY FLAG IN READ_ONLY MODE\n"); \
else \
- (bp)->b_dirty = 1; \
+ (bp)->b_flags |= B_DIRTY; \
} while (0)
#define initbarea(bp, type) do { \
- (bp)->b_dirty = 0; \
(bp)->b_bno = (ufs2_daddr_t)-1; \
(bp)->b_flags = 0; \
+ (bp)->b_refcnt = 0; \
+ (bp)->b_index = 0; \
(bp)->b_type = type; \
} while (0)
@@ -227,6 +252,8 @@ struct inodesc {
enum fixstate id_fix; /* policy on fixing errors */
int (*id_func)(struct inodesc *);
/* function to be applied to blocks of inode */
+ struct bufarea *id_bp; /* ckinode: buffer with indirect pointers */
+ union dinode *id_dp; /* ckinode: dinode being traversed */
ino_t id_number; /* inode number described */
ino_t id_parent; /* for DATA nodes, their parent */
ufs_lbn_t id_lbn; /* logical block number of current block */
@@ -239,7 +266,7 @@ struct inodesc {
int id_loc; /* for DATA nodes, current location in dir */
struct direct *id_dirp; /* for DATA nodes, ptr to current entry */
char *id_name; /* for DATA nodes, name to find or enter */
- char id_type; /* type of descriptor, DATA or ADDR */
+ char id_type; /* type of descriptor, DATA, ADDR, or SNAP */
};
/* file types */
#define DATA 1 /* a directory */
@@ -332,7 +359,6 @@ extern char skipclean; /* skip clean file systems if preening */
extern int fsmodified; /* 1 => write done to file system */
extern int fsreadfd; /* file descriptor for reading file system */
extern int fswritefd; /* file descriptor for writing file system */
-extern struct uufsd disk; /* libufs user-ufs disk structure */
extern int surrender; /* Give up if reads fail */
extern int wantrestart; /* Restart fsck on early termination */
@@ -352,12 +378,11 @@ extern volatile sig_atomic_t got_sigalarm; /* received a SIGALRM */
#define clearinode(dp) \
if (sblock.fs_magic == FS_UFS1_MAGIC) { \
- (dp)->dp1 = ufs1_zino; \
+ (dp)->dp1 = zino.dp1; \
} else { \
- (dp)->dp2 = ufs2_zino; \
+ (dp)->dp2 = zino.dp2; \
}
-extern struct ufs1_dinode ufs1_zino;
-extern struct ufs2_dinode ufs2_zino;
+extern union dinode zino;
#define setbmap(blkno) setbit(blockmap, blkno)
#define testbmap(blkno) isset(blockmap, blkno)
@@ -408,6 +433,7 @@ struct fstab;
void adjust(struct inodesc *, int lcnt);
+void alarmhandler(int sig);
ufs2_daddr_t allocblk(long frags);
ino_t allocdir(ino_t parent, ino_t request, int mode);
ino_t allocino(ino_t request, int type);
@@ -418,12 +444,14 @@ void bufinit(void);
void blwrite(int fd, char *buf, ufs2_daddr_t blk, ssize_t size);
void blerase(int fd, ufs2_daddr_t blk, long size);
void blzero(int fd, ufs2_daddr_t blk, long size);
+void brelse(struct bufarea *);
void cacheino(union dinode *dp, ino_t inumber);
void catch(int);
void catchquit(int);
void cgdirty(struct bufarea *);
+struct bufarea *cglookup(int cg);
int changeino(ino_t dir, const char *name, ino_t newnum);
-int check_cgmagic(int cg, struct bufarea *cgbp);
+int check_cgmagic(int cg, struct bufarea *cgbp, int requestrebuild);
int chkrange(ufs2_daddr_t blk, int cnt);
void ckfini(int markclean);
int ckinode(union dinode *dp, struct inodesc *);
@@ -444,16 +472,17 @@ void freeinodebuf(void);
void fsutilinit(void);
int ftypeok(union dinode *dp);
void getblk(struct bufarea *bp, ufs2_daddr_t blk, long size);
-struct bufarea *cglookup(int cg);
struct bufarea *getdatablk(ufs2_daddr_t blkno, long size, int type);
struct inoinfo *getinoinfo(ino_t inumber);
union dinode *getnextinode(ino_t inumber, int rebuildcg);
void getpathname(char *namebuf, ino_t curdir, ino_t ino);
-union dinode *ginode(ino_t inumber);
+void ginode(ino_t, struct inode *);
void infohandler(int sig);
-void alarmhandler(int sig);
+void irelse(struct inode *);
+ufs2_daddr_t ino_blkatoff(union dinode *, ino_t, ufs_lbn_t, int *,
+ struct bufarea **);
void inocleanup(void);
-void inodirty(union dinode *);
+void inodirty(struct inode *);
struct inostat *inoinfo(ino_t inum);
void IOstats(char *what);
int linkup(ino_t orphan, ino_t parentdir, char *name);
@@ -468,13 +497,13 @@ void pass4(void);
void pass5(void);
void pfatal(const char *fmt, ...) __printflike(1, 2);
void propagate(void);
-void prtinode(ino_t ino, union dinode *dp);
+void prtinode(struct inode *);
void pwarn(const char *fmt, ...) __printflike(1, 2);
int readsb(int listerr);
int reply(const char *question);
void rwerror(const char *mesg, ufs2_daddr_t blk);
void sblock_init(void);
-void setinodebuf(ino_t);
+void setinodebuf(int, ino_t);
int setup(char *dev);
void gjournal_check(const char *filesys);
int suj_check(const char *filesys);
diff --git a/sbin/fsck_ffs/fsutil.c b/sbin/fsck_ffs/fsutil.c
index 11d2ebd598fd..64c4701d9b7f 100644
--- a/sbin/fsck_ffs/fsutil.c
+++ b/sbin/fsck_ffs/fsutil.c
@@ -64,9 +64,14 @@ __FBSDID("$FreeBSD$");
#include "fsck.h"
+int sujrecovery = 0;
+
+static struct bufarea *allocbuf(const char *);
+static void cg_write(struct bufarea *);
static void slowio_start(void);
static void slowio_end(void);
static void printIOstats(void);
+static void prtbuf(const char *, struct bufarea *);
static long diskreads, totaldiskreads, totalreads; /* Disk cache statistics */
static struct timespec startpass, finishpass;
@@ -74,12 +79,16 @@ struct timeval slowio_starttime;
int slowio_delay_usec = 10000; /* Initial IO delay for background fsck */
int slowio_pollcnt;
static struct bufarea cgblk; /* backup buffer for cylinder group blocks */
-static TAILQ_HEAD(buflist, bufarea) bufhead; /* head of buffer cache list */
+static TAILQ_HEAD(bufqueue, bufarea) bufqueuehd; /* head of buffer cache LRU */
+static LIST_HEAD(bufhash, bufarea) bufhashhd[HASHSIZE]; /* buffer hash list */
static int numbufs; /* size of buffer cache */
-static char *buftype[BT_NUMBUFTYPES] = BT_NAMES;
+static int cachelookups; /* number of cache lookups */
+static int cachereads; /* number of cache reads */
static struct bufarea *cgbufs; /* header for cylinder group cache */
static int flushtries; /* number of tries to reclaim memory */
+char *buftype[BT_NUMBUFTYPES] = BT_NAMES;
+
void
fsutilinit(void)
{
@@ -89,11 +98,6 @@ fsutilinit(void)
bzero(&slowio_starttime, sizeof(struct timeval));
slowio_delay_usec = 10000;
slowio_pollcnt = 0;
- bzero(&cgblk, sizeof(struct bufarea));
- TAILQ_INIT(&bufhead);
- numbufs = 0;
- /* buftype ? */
- cgbufs = NULL;
flushtries = 0;
}
@@ -181,33 +185,19 @@ inoinfo(ino_t inum)
void
bufinit(void)
{
- struct bufarea *bp;
- long bufcnt, i;
- char *bufp;
+ int i;
- pbp = pdirbp = (struct bufarea *)0;
- bufp = Malloc((unsigned int)sblock.fs_bsize);
- if (bufp == NULL)
- errx(EEXIT, "cannot allocate buffer pool");
- cgblk.b_un.b_buf = bufp;
+ pdirbp = (struct bufarea *)0;
+ bzero(&cgblk, sizeof(struct bufarea));
+ cgblk.b_un.b_buf = Malloc((unsigned int)sblock.fs_bsize);
+ if (cgblk.b_un.b_buf == NULL)
+ errx(EEXIT, "Initial malloc(%d) failed", sblock.fs_bsize);
initbarea(&cgblk, BT_CYLGRP);
- TAILQ_INIT(&bufhead);
- bufcnt = MAXBUFS;
- if (bufcnt < MINBUFS)
- bufcnt = MINBUFS;
- for (i = 0; i < bufcnt; i++) {
- bp = (struct bufarea *)Malloc(sizeof(struct bufarea));
- bufp = Malloc((unsigned int)sblock.fs_bsize);
- if (bp == NULL || bufp == NULL) {
- if (i >= MINBUFS)
- break;
- errx(EEXIT, "cannot allocate buffer pool");
- }
- bp->b_un.b_buf = bufp;
- TAILQ_INSERT_HEAD(&bufhead, bp, b_list);
- initbarea(bp, BT_UNKNOWN);
- }
- numbufs = i; /* save number of buffers */
+ cgbufs = NULL;
+ numbufs = cachelookups = cachereads = 0;
+ TAILQ_INIT(&bufqueuehd);
+ for (i = 0; i < HASHSIZE; i++)
+ LIST_INIT(&bufhashhd[i]);
for (i = 0; i < BT_NUMBUFTYPES; i++) {
readtime[i].tv_sec = totalreadtime[i].tv_sec = 0;
readtime[i].tv_nsec = totalreadtime[i].tv_nsec = 0;
@@ -215,6 +205,25 @@ bufinit(void)
}
}
+static struct bufarea *
+allocbuf(const char *failreason)
+{
+ struct bufarea *bp;
+ char *bufp;
+
+ bp = (struct bufarea *)Malloc(sizeof(struct bufarea));
+ bufp = Malloc((unsigned int)sblock.fs_bsize);
+ if (bp == NULL || bufp == NULL) {
+ errx(EEXIT, "%s", failreason);
+ /* NOTREACHED */
+ }
+ numbufs++;
+ bp->b_un.b_buf = bufp;
+ TAILQ_INSERT_HEAD(&bufqueuehd, bp, b_list);
+ initbarea(bp, BT_UNKNOWN);
+ return (bp);
+}
+
/*
* Manage cylinder group buffers.
*
@@ -230,18 +239,22 @@ cglookup(int cg)
struct bufarea *cgbp;
struct cg *cgp;
+ if ((unsigned) cg >= sblock.fs_ncg)
+ errx(EEXIT, "cglookup: out of range cylinder group %d", cg);
if (cgbufs == NULL) {
cgbufs = calloc(sblock.fs_ncg, sizeof(struct bufarea));
if (cgbufs == NULL)
- errx(EEXIT, "cannot allocate cylinder group buffers");
+ errx(EEXIT, "Cannot allocate cylinder group buffers");
}
cgbp = &cgbufs[cg];
if (cgbp->b_un.b_cg != NULL)
return (cgbp);
cgp = NULL;
if (flushtries == 0)
- cgp = malloc((unsigned int)sblock.fs_cgsize);
+ cgp = Malloc((unsigned int)sblock.fs_cgsize);
if (cgp == NULL) {
+ if (sujrecovery)
+ errx(EEXIT,"Ran out of memory during journal recovery");
getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
return (&cgblk);
}
@@ -278,7 +291,7 @@ flushentry(void)
{
struct bufarea *cgbp;
- if (flushtries == sblock.fs_ncg || cgbufs == NULL)
+ if (sujrecovery || flushtries == sblock.fs_ncg || cgbufs == NULL)
return (0);
cgbp = &cgbufs[flushtries++];
if (cgbp->b_un.b_cg == NULL)
@@ -296,25 +309,84 @@ struct bufarea *
getdatablk(ufs2_daddr_t blkno, long size, int type)
{
struct bufarea *bp;
+ struct bufhash *bhdp;
- TAILQ_FOREACH(bp, &bufhead, b_list)
- if (bp->b_bno == fsbtodb(&sblock, blkno))
+ cachelookups++;
+ /* If out of range, return empty buffer with b_err == -1 */
+ if (type != BT_INODES && chkrange(blkno, size / sblock.fs_fsize)) {
+ blkno = -1;
+ type = BT_EMPTY;
+ }
+ bhdp = &bufhashhd[HASH(blkno)];
+ LIST_FOREACH(bp, bhdp, b_hash)
+ if (bp->b_bno == fsbtodb(&sblock, blkno)) {
+ if (debug && bp->b_size != size) {
+ prtbuf("getdatablk: size mismatch", bp);
+ pfatal("getdatablk: b_size %d != size %ld\n",
+ bp->b_size, size);
+ }
goto foundit;
- TAILQ_FOREACH_REVERSE(bp, &bufhead, buflist, b_list)
- if ((bp->b_flags & B_INUSE) == 0)
- break;
- if (bp == NULL)
- errx(EEXIT, "deadlocked buffer pool");
+ }
+ /*
+ * Move long-term busy buffer back to the front of the LRU so we
+ * do not endless inspect them for recycling.
+ */
+ bp = TAILQ_LAST(&bufqueuehd, bufqueue);
+ if (bp != NULL && bp->b_refcnt != 0) {
+ TAILQ_REMOVE(&bufqueuehd, bp, b_list);
+ TAILQ_INSERT_HEAD(&bufqueuehd, bp, b_list);
+ }
+ /*
+ * Allocate up to the minimum number of buffers before
+ * considering recycling any of them.
+ */
+ if (size > sblock.fs_bsize)
+ errx(EEXIT, "Excessive buffer size %ld > %d\n", size,
+ sblock.fs_bsize);
+ if (numbufs < MINBUFS) {
+ bp = allocbuf("cannot create minimal buffer pool");
+ } else if (sujrecovery) {
+ /*
+ * SUJ recovery does not want anything written until it
+ * has successfully completed (so it can fail back to
+ * full fsck). Thus, we can only recycle clean buffers.
+ */
+ TAILQ_FOREACH_REVERSE(bp, &bufqueuehd, bufqueue, b_list)
+ if ((bp->b_flags & B_DIRTY) == 0 && bp->b_refcnt == 0)
+ break;
+ if (bp == NULL)
+ bp = allocbuf("Ran out of memory during "
+ "journal recovery");
+ else
+ LIST_REMOVE(bp, b_hash);
+ } else {
+ /*
+ * Recycle oldest non-busy buffer.
+ */
+ TAILQ_FOREACH_REVERSE(bp, &bufqueuehd, bufqueue, b_list)
+ if (bp->b_refcnt == 0)
+ break;
+ if (bp == NULL)
+ bp = allocbuf("Ran out of memory for buffers");
+ else
+ LIST_REMOVE(bp, b_hash);
+ }
+ flush(fswritefd, bp);
bp->b_type = type;
+ LIST_INSERT_HEAD(bhdp, bp, b_hash);
getblk(bp, blkno, size);
+ cachereads++;
/* fall through */
foundit:
- if (debug && bp->b_type != type)
- printf("Buffer type changed from %s to %s\n",
- buftype[bp->b_type], buftype[type]);
- TAILQ_REMOVE(&bufhead, bp, b_list);
- TAILQ_INSERT_HEAD(&bufhead, bp, b_list);
- bp->b_flags |= B_INUSE;
+ if (debug && bp->b_type != type) {
+ printf("getdatablk: buffer type changed to %s",
+ BT_BUFTYPE(type));
+ prtbuf("", bp);
+ }
+ TAILQ_REMOVE(&bufqueuehd, bp, b_list);
+ TAILQ_INSERT_HEAD(&bufqueuehd, bp, b_list);
+ if (bp->b_errs == 0)
+ bp->b_refcnt++;
return (bp);
}
@@ -328,12 +400,15 @@ getblk(struct bufarea *bp, ufs2_daddr_t blk, long size)
if (bp->b_bno == dblk) {
totalreads++;
} else {
- flush(fswritefd, bp);
if (debug) {
readcnt[bp->b_type]++;
clock_gettime(CLOCK_REALTIME_PRECISE, &start);
}
- bp->b_errs = blread(fsreadfd, bp->b_un.b_buf, dblk, size);
+ if (bp->b_type != BT_EMPTY)
+ bp->b_errs =
+ blread(fsreadfd, bp->b_un.b_buf, dblk, size);
+ else
+ bp->b_errs = -1;
if (debug) {
clock_gettime(CLOCK_REALTIME_PRECISE, &finish);
timespecsub(&finish, &start, &finish);
@@ -346,12 +421,22 @@ getblk(struct bufarea *bp, ufs2_daddr_t blk, long size)
}
void
+brelse(struct bufarea *bp)
+{
+
+ if (bp->b_refcnt <= 0)
+ prtbuf("brelse: buffer with negative reference count", bp);
+ bp->b_refcnt--;
+}
+
+void
flush(int fd, struct bufarea *bp)
{
+ struct inode ip;
- if (!bp->b_dirty)
+ if ((bp->b_flags & B_DIRTY) == 0)
return;
- bp->b_dirty = 0;
+ bp->b_flags &= ~B_DIRTY;
if (fswritefd < 0) {
pfatal("WRITING IN READ_ONLY MODE.\n");
return;
@@ -373,15 +458,90 @@ flush(int fd, struct bufarea *bp)
fsmodified = 1;
break;
case BT_CYLGRP:
+ if (sujrecovery)
+ cg_write(bp);
if (cgput(fswritefd, &sblock, bp->b_un.b_cg) == 0)
fsmodified = 1;
break;
+ case BT_INODES:
+ if (debug && sblock.fs_magic == FS_UFS2_MAGIC) {
+ struct ufs2_dinode *dp = bp->b_un.b_dinode2;
+ int i;
+
+ for (i = 0; i < INOPB(&sblock); dp++, i++) {
+ if (ffs_verify_dinode_ckhash(&sblock, dp) == 0)
+ continue;
+ pwarn("flush: INODE CHECK-HASH FAILED");
+ ip.i_bp = bp;
+ ip.i_dp = (union dinode *)dp;
+ ip.i_number = bp->b_index + i;
+ prtinode(&ip);
+ if (preen || reply("FIX") != 0) {
+ if (preen)
+ printf(" (FIXED)\n");
+ ffs_update_dinode_ckhash(&sblock, dp);
+ inodirty(&ip);
+ }
+ }
+ }
+ /* FALLTHROUGH */
default:
blwrite(fd, bp->b_un.b_buf, bp->b_bno, bp->b_size);
break;
}
}
+/*
+ * Journaled soft updates does not maintain cylinder group summary
+ * information during cleanup, so this routine recalculates the summary
+ * information and updates the superblock summary in preparation for
+ * writing out the cylinder group.
+ */
+static void
+cg_write(struct bufarea *bp)
+{
+ ufs1_daddr_t fragno, cgbno, maxbno;
+ u_int8_t *blksfree;
+ struct cg *cgp;
+ int blk;
+ int i;
+
+ /*
+ * Fix the frag and cluster summary.
+ */
+ cgp = bp->b_un.b_cg;
+ cgp->cg_cs.cs_nbfree = 0;
+ cgp->cg_cs.cs_nffree = 0;
+ bzero(&cgp->cg_frsum, sizeof(cgp->cg_frsum));
+ maxbno = fragstoblks(&sblock, sblock.fs_fpg);
+ if (sblock.fs_contigsumsize > 0) {
+ for (i = 1; i <= sblock.fs_contigsumsize; i++)
+ cg_clustersum(cgp)[i] = 0;
+ bzero(cg_clustersfree(cgp), howmany(maxbno, CHAR_BIT));
+ }
+ blksfree = cg_blksfree(cgp);
+ for (cgbno = 0; cgbno < maxbno; cgbno++) {
+ if (ffs_isfreeblock(&sblock, blksfree, cgbno))
+ continue;
+ if (ffs_isblock(&sblock, blksfree, cgbno)) {
+ ffs_clusteracct(&sblock, cgp, cgbno, 1);
+ cgp->cg_cs.cs_nbfree++;
+ continue;
+ }
+ fragno = blkstofrags(&sblock, cgbno);
+ blk = blkmap(&sblock, blksfree, fragno);
+ ffs_fragacct(&sblock, blk, cgp->cg_frsum, 1);
+ for (i = 0; i < sblock.fs_frag; i++)
+ if (isset(blksfree, fragno + i))
+ cgp->cg_cs.cs_nffree++;
+ }
+ /*
+ * Update the superblock cg summary from our now correct values
+ * before writing the block.
+ */
+ sblock.fs_cs(&sblock, cgp->cg_cgx) = cgp->cg_cs;
+}
+
void
rwerror(const char *mesg, ufs2_daddr_t blk)
{
@@ -421,28 +581,91 @@ ckfini(int markclean)
}
}
if (debug && totalreads > 0)
- printf("cache with %d buffers missed %ld of %ld (%d%%)\n",
- numbufs, totaldiskreads, totalreads,
- (int)(totaldiskreads * 100 / totalreads));
+ printf("cache with %d buffers missed %d of %d (%d%%)\n",
+ numbufs, cachereads, cachelookups,
+ (int)(cachereads * 100 / cachelookups));
if (fswritefd < 0) {
(void)close(fsreadfd);
return;
}
- flush(fswritefd, &sblk);
- if (havesb && cursnapshot == 0 && sblock.fs_magic == FS_UFS2_MAGIC &&
- sblk.b_bno != sblock.fs_sblockloc / dev_bsize &&
- !preen && reply("UPDATE STANDARD SUPERBLOCK")) {
- /* Change the write destination to standard superblock */
- sblock.fs_sblockactualloc = sblock.fs_sblockloc;
- sblk.b_bno = sblock.fs_sblockloc / dev_bsize;
- sbdirty();
- flush(fswritefd, &sblk);
+ /*
+ * To remain idempotent with partial truncations the buffers
+ * must be flushed in this order:
+ * 1) cylinder groups (bitmaps)
+ * 2) indirect, directory, external attribute, and data blocks
+ * 3) inode blocks
+ * 4) superblock
+ * This ordering preserves access to the modified pointers
+ * until they are freed.
+ */
+ /* Step 1: cylinder groups */
+ if (debug)
+ printf("Flush Cylinder groups\n");
+ if (cgbufs != NULL) {
+ for (cnt = 0; cnt < sblock.fs_ncg; cnt++) {
+ if (cgbufs[cnt].b_un.b_cg == NULL)
+ continue;
+ flush(fswritefd, &cgbufs[cnt]);
+ free(cgbufs[cnt].b_un.b_cg);
+ }
+ free(cgbufs);
}
flush(fswritefd, &cgblk);
free(cgblk.b_un.b_buf);
cnt = 0;
- TAILQ_FOREACH_REVERSE_SAFE(bp, &bufhead, buflist, b_list, nbp) {
- TAILQ_REMOVE(&bufhead, bp, b_list);
+ /* Step 2: indirect, directory, external attribute, and data blocks */
+ if (debug)
+ printf("Flush indirect, directory, external attribute, "
+ "and data blocks\n");
+ if (pdirbp != NULL)
+ brelse(pdirbp);
+ TAILQ_FOREACH_REVERSE_SAFE(bp, &bufqueuehd, bufqueue, b_list, nbp) {
+ switch (bp->b_type) {
+ /* These should not be in the buffer cache list */
+ case BT_UNKNOWN:
+ case BT_SUPERBLK:
+ case BT_CYLGRP:
+ default:
+ prtbuf("ckfini: improper buffer type on cache list",bp);
+ continue;
+ /* These are the ones to flush in this step */
+ case BT_EMPTY:
+ if (bp->b_bno >= 0)
+ pfatal("Unused BT_EMPTY buffer for block %jd\n",
+ (intmax_t)bp->b_bno);
+ /* FALLTHROUGH */
+ case BT_LEVEL1:
+ case BT_LEVEL2:
+ case BT_LEVEL3:
+ case BT_EXTATTR:
+ case BT_DIRDATA:
+ case BT_DATA:
+ break;
+ /* These are the ones to flush in the next step */
+ case BT_INODES:
+ continue;
+ }
+ if (debug && bp->b_refcnt != 0) {
+ prtbuf("ckfini: clearing in-use buffer", bp);
+ pfatal("ckfini: clearing in-use buffer\n");
+ }
+ TAILQ_REMOVE(&bufqueuehd, bp, b_list);
+ cnt++;
+ flush(fswritefd, bp);
+ free(bp->b_un.b_buf);
+ free((char *)bp);
+ }
+ /* Step 3: inode blocks */
+ if (debug)
+ printf("Flush inode blocks\n");
+ if (icachebp != NULL)
+ brelse(icachebp);
+ TAILQ_FOREACH_REVERSE_SAFE(bp, &bufqueuehd, bufqueue, b_list, nbp) {
+ if (debug && bp->b_refcnt != 0) {
+ prtbuf("ckfini: clearing in-use buffer", bp);
+ pfatal("ckfini: clearing in-use buffer\n");
+ }
+ TAILQ_REMOVE(&bufqueuehd, bp, b_list);
cnt++;
flush(fswritefd, bp);
free(bp->b_un.b_buf);
@@ -450,16 +673,20 @@ ckfini(int markclean)
}
if (numbufs != cnt)
errx(EEXIT, "panic: lost %d buffers", numbufs - cnt);
- if (cgbufs != NULL) {
- for (cnt = 0; cnt < sblock.fs_ncg; cnt++) {
- if (cgbufs[cnt].b_un.b_cg == NULL)
- continue;
- flush(fswritefd, &cgbufs[cnt]);
- free(cgbufs[cnt].b_un.b_cg);
- }
- free(cgbufs);
+ /* Step 4: superblock */
+ if (debug)
+ printf("Flush the superblock\n");
+ flush(fswritefd, &sblk);
+ if (havesb && cursnapshot == 0 && sblock.fs_magic == FS_UFS2_MAGIC &&
+ sblk.b_bno != sblock.fs_sblockloc / dev_bsize &&
+ !preen && reply("UPDATE STANDARD SUPERBLOCK")) {
+ /* Change the write destination to standard superblock */
+ sblock.fs_sblockactualloc = sblock.fs_sblockloc;
+ sblk.b_bno = sblock.fs_sblockloc / dev_bsize;
+ sbdirty();
+ flush(fswritefd, &sblk);
}
- pbp = pdirbp = (struct bufarea *)0;
+ pdirbp = (struct bufarea *)0;
if (cursnapshot == 0 && sblock.fs_clean != markclean) {
if ((sblock.fs_clean = markclean) != 0) {
sblock.fs_flags &= ~(FS_UNCLEAN | FS_NEEDSFSCK);
@@ -484,6 +711,7 @@ ckfini(int markclean)
rerun = 1;
}
}
+ finalIOstats();
(void)close(fsreadfd);
(void)close(fswritefd);
}
@@ -689,14 +917,24 @@ blzero(int fd, ufs2_daddr_t blk, long size)
* test fails, offer an option to rebuild the whole cylinder group.
*/
int
-check_cgmagic(int cg, struct bufarea *cgbp)
+check_cgmagic(int cg, struct bufarea *cgbp, int request_rebuild)
{
struct cg *cgp = cgbp->b_un.b_cg;
+ uint32_t cghash, calchash;
/*
* Extended cylinder group checks.
*/
- if (cg_chkmagic(cgp) &&
+ calchash = cgp->cg_ckhash;
+ if ((sblock.fs_metackhash & CK_CYLGRP) != 0) {
+ cghash = cgp->cg_ckhash;
+ cgp->cg_ckhash = 0;
+ calchash = calculate_crc32c(~0L, (void *)cgp, sblock.fs_cgsize);
+ cgp->cg_ckhash = cghash;
+ }
+ if (cgp->cg_ckhash == calchash &&
+ cg_chkmagic(cgp) &&
+ cgp->cg_cgx == cg &&
((sblock.fs_magic == FS_UFS1_MAGIC &&
cgp->cg_old_niblk == sblock.fs_ipg &&
cgp->cg_ndblk <= sblock.fs_fpg &&
@@ -707,7 +945,9 @@ check_cgmagic(int cg, struct bufarea *cgbp)
cgp->cg_initediblk <= sblock.fs_ipg))) {
return (1);
}
- pfatal("CYLINDER GROUP %d: BAD MAGIC NUMBER", cg);
+ pfatal("CYLINDER GROUP %d: INTEGRITY CHECK FAILED", cg);
+ if (!request_rebuild)
+ return (0);
if (!reply("REBUILD CYLINDER GROUP")) {
printf("YOU WILL NEED TO RERUN FSCK.\n");
rerun = 1;
@@ -780,7 +1020,7 @@ allocblk(long frags)
cg = dtog(&sblock, i + j);
cgbp = cglookup(cg);
cgp = cgbp->b_un.b_cg;
- if (!check_cgmagic(cg, cgbp))
+ if (!check_cgmagic(cg, cgbp, 0))
return (0);
baseblk = dtogd(&sblock, i + j);
for (k = 0; k < frags; k++) {
@@ -844,6 +1084,7 @@ getpathname(char *namebuf, ino_t curdir, ino_t ino)
{
int len;
char *cp;
+ struct inode ip;
struct inodesc idesc;
static int busy = 0;
@@ -869,15 +1110,23 @@ getpathname(char *namebuf, ino_t curdir, ino_t ino)
idesc.id_number = ino;
idesc.id_func = findino;
idesc.id_name = strdup("..");
- if ((ckinode(ginode(ino), &idesc) & FOUND) == 0)
+ ginode(ino, &ip);
+ if ((ckinode(ip.i_dp, &idesc) & FOUND) == 0) {
+ irelse(&ip);
break;
+ }
+ irelse(&ip);
namelookup:
idesc.id_number = idesc.id_parent;
idesc.id_parent = ino;
idesc.id_func = findname;
idesc.id_name = namebuf;
- if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0)
+ ginode(idesc.id_number, &ip);
+ if ((ckinode(ip.i_dp, &idesc) & FOUND) == 0) {
+ irelse(&ip);
break;
+ }
+ irelse(&ip);
len = strlen(namebuf);
cp -= len;
memmove(cp, namebuf, (size_t)len);
@@ -956,6 +1205,19 @@ dofix(struct inodesc *idesc, const char *msg)
#include <stdarg.h>
/*
+ * Print details about a buffer.
+ */
+static void
+prtbuf(const char *msg, struct bufarea *bp)
+{
+
+ printf("%s: bp %p, type %s, bno %ld, size %d, refcnt %d, flags %s, "
+ "index %d\n", msg, bp, BT_BUFTYPE(bp->b_type), bp->b_bno,
+ bp->b_size, bp->b_refcnt, bp->b_flags & B_DIRTY ? "dirty" : "clean",
+ bp->b_index);
+}
+
+/*
* An unexpected inconsistency occurred.
* Die if preening or file system is running with soft dependency protocol,
* otherwise just print message and continue.
diff --git a/sbin/fsck_ffs/gjournal.c b/sbin/fsck_ffs/gjournal.c
index 6e3dbd2da41e..b65589b5bd08 100644
--- a/sbin/fsck_ffs/gjournal.c
+++ b/sbin/fsck_ffs/gjournal.c
@@ -56,354 +56,30 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <sys/param.h>
-#include <sys/disklabel.h>
-#include <sys/mount.h>
+#include <string.h>
#include <sys/stat.h>
-
-#include <ufs/ufs/ufsmount.h>
-#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <libufs.h>
-#include <strings.h>
-#include <err.h>
-#include <assert.h>
-
#include "fsck.h"
-struct cgchain {
- union {
- struct cg cgcu_cg;
- char cgcu_buf[MAXBSIZE];
- } cgc_union;
- int cgc_busy;
- int cgc_dirty;
- LIST_ENTRY(cgchain) cgc_next;
-};
-#define cgc_cg cgc_union.cgcu_cg
-
-#define MAX_CACHED_CGS 1024
-static unsigned ncgs = 0;
-static LIST_HEAD(, cgchain) cglist = LIST_HEAD_INITIALIZER(cglist);
-
-static const char *devnam;
-static struct uufsd *diskp = NULL;
-static struct fs *fs = NULL;
-
-static void putcgs(void);
-
-/*
- * Return cylinder group from the cache or load it if it is not in the
- * cache yet.
- * Don't cache more than MAX_CACHED_CGS cylinder groups.
- */
-static struct cgchain *
-getcg(int cg)
-{
- struct cgchain *cgc;
-
- assert(diskp != NULL && fs != NULL);
- LIST_FOREACH(cgc, &cglist, cgc_next) {
- if (cgc->cgc_cg.cg_cgx == cg) {
- //printf("%s: Found cg=%d\n", __func__, cg);
- return (cgc);
- }
- }
- /*
- * Our cache is full? Let's clean it up.
- */
- if (ncgs >= MAX_CACHED_CGS) {
- //printf("%s: Flushing CGs.\n", __func__);
- putcgs();
- }
- cgc = malloc(sizeof(*cgc));
- if (cgc == NULL) {
- /*
- * Cannot allocate memory?
- * Let's put all currently loaded and not busy cylinder groups
- * on disk and try again.
- */
- //printf("%s: No memory, flushing CGs.\n", __func__);
- putcgs();
- cgc = malloc(sizeof(*cgc));
- if (cgc == NULL)
- err(1, "malloc(%zu)", sizeof(*cgc));
- }
- if (cgget(fsreadfd, fs, cg, &cgc->cgc_cg) == -1)
- err(1, "cgget(%d)", cg);
- cgc->cgc_busy = 0;
- cgc->cgc_dirty = 0;
- LIST_INSERT_HEAD(&cglist, cgc, cgc_next);
- ncgs++;
- //printf("%s: Read cg=%d\n", __func__, cg);
- return (cgc);
-}
-
-/*
- * Mark cylinder group as dirty - it will be written back on putcgs().
- */
-static void
-dirtycg(struct cgchain *cgc)
-{
-
- cgc->cgc_dirty = 1;
-}
-
-/*
- * Mark cylinder group as busy - it will not be freed on putcgs().
- */
-static void
-busycg(struct cgchain *cgc)
-{
-
- cgc->cgc_busy = 1;
-}
-
-/*
- * Unmark the given cylinder group as busy.
- */
-static void
-unbusycg(struct cgchain *cgc)
-{
-
- cgc->cgc_busy = 0;
-}
-
-/*
- * Write back all dirty cylinder groups.
- * Free all non-busy cylinder groups.
- */
-static void
-putcgs(void)
-{
- struct cgchain *cgc, *cgc2;
-
- assert(diskp != NULL && fs != NULL);
- LIST_FOREACH_SAFE(cgc, &cglist, cgc_next, cgc2) {
- if (cgc->cgc_busy)
- continue;
- LIST_REMOVE(cgc, cgc_next);
- ncgs--;
- if (cgc->cgc_dirty) {
- if (cgput(fswritefd, fs, &cgc->cgc_cg) == -1)
- err(1, "cgput(%d)", cgc->cgc_cg.cg_cgx);
- //printf("%s: Wrote cg=%d\n", __func__,
- // cgc->cgc_cg.cg_cgx);
- }
- free(cgc);
- }
-}
-
-#if 0
-/*
- * Free all non-busy cylinder groups without storing the dirty ones.
- */
-static void
-cancelcgs(void)
-{
- struct cgchain *cgc;
-
- assert(diskp != NULL && fs != NULL);
- while ((cgc = LIST_FIRST(&cglist)) != NULL) {
- if (cgc->cgc_busy)
- continue;
- LIST_REMOVE(cgc, cgc_next);
- //printf("%s: Canceled cg=%d\n", __func__, cgc->cgc_cg.cg_cgx);
- free(cgc);
- }
-}
-#endif
-
-/*
- * Open the given provider, load superblock.
- */
-static void
-opendisk(void)
-{
- if (diskp != NULL)
- return;
- diskp = &disk;
- if (ufs_disk_fillout(diskp, devnam) == -1) {
- err(1, "ufs_disk_fillout(%s) failed: %s", devnam,
- diskp->d_error);
- }
- fs = &diskp->d_fs;
-}
-
-/*
- * Mark file system as clean, write the super-block back, close the disk.
- */
-static void
-closedisk(void)
-{
-
- fs->fs_clean = 1;
- if (sbwrite(diskp, 0) == -1)
- err(1, "sbwrite(%s)", devnam);
- if (ufs_disk_close(diskp) == -1)
- err(1, "ufs_disk_close(%s)", devnam);
- free(diskp);
- diskp = NULL;
- fs = NULL;
-}
-
-static void
-blkfree(ufs2_daddr_t bno, long size)
-{
- struct cgchain *cgc;
- struct cg *cgp;
- ufs1_daddr_t fragno, cgbno;
- int i, cg, blk, frags, bbase;
- u_int8_t *blksfree;
-
- cg = dtog(fs, bno);
- cgc = getcg(cg);
- dirtycg(cgc);
- cgp = &cgc->cgc_cg;
- cgbno = dtogd(fs, bno);
- blksfree = cg_blksfree(cgp);
- if (size == fs->fs_bsize) {
- fragno = fragstoblks(fs, cgbno);
- if (!ffs_isfreeblock(fs, blksfree, fragno))
- assert(!"blkfree: freeing free block");
- ffs_setblock(fs, blksfree, fragno);
- ffs_clusteracct(fs, cgp, fragno, 1);
- cgp->cg_cs.cs_nbfree++;
- fs->fs_cstotal.cs_nbfree++;
- fs->fs_cs(fs, cg).cs_nbfree++;
- } else {
- bbase = cgbno - fragnum(fs, cgbno);
- /*
- * decrement the counts associated with the old frags
- */
- blk = blkmap(fs, blksfree, bbase);
- ffs_fragacct(fs, blk, cgp->cg_frsum, -1);
- /*
- * deallocate the fragment
- */
- frags = numfrags(fs, size);
- for (i = 0; i < frags; i++) {
- if (isset(blksfree, cgbno + i))
- assert(!"blkfree: freeing free frag");
- setbit(blksfree, cgbno + i);
- }
- cgp->cg_cs.cs_nffree += i;
- fs->fs_cstotal.cs_nffree += i;
- fs->fs_cs(fs, cg).cs_nffree += i;
- /*
- * add back in counts associated with the new frags
- */
- blk = blkmap(fs, blksfree, bbase);
- ffs_fragacct(fs, blk, cgp->cg_frsum, 1);
- /*
- * if a complete block has been reassembled, account for it
- */
- fragno = fragstoblks(fs, bbase);
- if (ffs_isblock(fs, blksfree, fragno)) {
- cgp->cg_cs.cs_nffree -= fs->fs_frag;
- fs->fs_cstotal.cs_nffree -= fs->fs_frag;
- fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag;
- ffs_clusteracct(fs, cgp, fragno, 1);
- cgp->cg_cs.cs_nbfree++;
- fs->fs_cstotal.cs_nbfree++;
- fs->fs_cs(fs, cg).cs_nbfree++;
- }
- }
-}
-
-/*
- * Recursively free all indirect blocks.
- */
-static void
-freeindir(ufs2_daddr_t blk, int level)
-{
- char sblks[MAXBSIZE];
- ufs2_daddr_t *blks;
- int i;
-
- if (bread(diskp, fsbtodb(fs, blk), (void *)&sblks, (size_t)fs->fs_bsize) == -1)
- err(1, "bread: %s", diskp->d_error);
- blks = (ufs2_daddr_t *)&sblks;
- for (i = 0; i < NINDIR(fs); i++) {
- if (blks[i] == 0)
- break;
- if (level == 0)
- blkfree(blks[i], fs->fs_bsize);
- else
- freeindir(blks[i], level - 1);
- }
- blkfree(blk, fs->fs_bsize);
-}
-
-#define dblksize(fs, dino, lbn) \
- ((dino)->di_size >= smalllblktosize(fs, (lbn) + 1) \
- ? (fs)->fs_bsize \
- : fragroundup(fs, blkoff(fs, (dino)->di_size)))
-
-/*
- * Free all blocks associated with the given inode.
- */
-static void
-clear_inode(struct ufs2_dinode *dino)
-{
- ufs2_daddr_t bn;
- int extblocks, i, level;
- off_t osize;
- long bsize;
-
- extblocks = 0;
- if (fs->fs_magic == FS_UFS2_MAGIC && dino->di_extsize > 0)
- extblocks = btodb(fragroundup(fs, dino->di_extsize));
- /* deallocate external attributes blocks */
- if (extblocks > 0) {
- osize = dino->di_extsize;
- dino->di_blocks -= extblocks;
- dino->di_extsize = 0;
- for (i = 0; i < UFS_NXADDR; i++) {
- if (dino->di_extb[i] == 0)
- continue;
- blkfree(dino->di_extb[i], sblksize(fs, osize, i));
- }
- }
-#define SINGLE 0 /* index of single indirect block */
-#define DOUBLE 1 /* index of double indirect block */
-#define TRIPLE 2 /* index of triple indirect block */
- /* deallocate indirect blocks */
- for (level = SINGLE; level <= TRIPLE; level++) {
- if (dino->di_ib[level] == 0)
- break;
- freeindir(dino->di_ib[level], level);
- }
- /* deallocate direct blocks and fragments */
- for (i = 0; i < UFS_NDADDR; i++) {
- bn = dino->di_db[i];
- if (bn == 0)
- continue;
- bsize = dblksize(fs, dino, i);
- blkfree(bn, bsize);
- }
-}
-
void
gjournal_check(const char *filesys)
{
- union dinodep dp;
- struct cgchain *cgc;
+ struct fs *fs;
+ struct inode ip;
+ union dinode *dp;
+ struct bufarea *cgbp;
struct cg *cgp;
+ struct inodesc idesc;
uint8_t *inosused;
ino_t cino, ino;
int cg;
- devnam = filesys;
- opendisk();
+ fs = &sblock;
/* Are there any unreferenced inodes in this file system? */
if (fs->fs_unrefs == 0) {
//printf("No unreferenced inodes.\n");
- closedisk();
+ sbdirty();
+ ckfini(1);
return;
}
@@ -419,77 +95,67 @@ gjournal_check(const char *filesys)
cg * 100 / fs->fs_ncg);
got_sigalarm = 0;
}
- cgc = getcg(cg);
- cgp = &cgc->cgc_cg;
+ cgbp = cglookup(cg);
+ cgp = cgbp->b_un.b_cg;
+ if (!check_cgmagic(cg, cgbp, 0)) {
+ rerun = 1;
+ ckfini(0);
+ return;
+ }
/* Are there any unreferenced inodes in this cylinder group? */
if (cgp->cg_unrefs == 0)
continue;
//printf("Analizing cylinder group %d (count=%d)\n", cg, cgp->cg_unrefs);
/*
- * We are going to modify this cylinder group, so we want it to
- * be written back.
- */
- dirtycg(cgc);
- /* We don't want it to be freed in the meantime. */
- busycg(cgc);
- inosused = cg_inosused(cgp);
- /*
* Now go through the list of all inodes in this cylinder group
* to find unreferenced ones.
*/
+ inosused = cg_inosused(cgp);
for (cino = 0; cino < fs->fs_ipg; cino++) {
ino = fs->fs_ipg * cg + cino;
/* Unallocated? Skip it. */
if (isclr(inosused, cino))
continue;
- if (getinode(diskp, &dp, ino) == -1)
- err(1, "getinode (cg=%d ino=%ju) %s",
- cg, (uintmax_t)ino, diskp->d_error);
+ ginode(ino, &ip);
+ dp = ip.i_dp;
/* Not a regular file nor directory? Skip it. */
- if (!S_ISREG(dp.dp2->di_mode) &&
- !S_ISDIR(dp.dp2->di_mode))
+ if (!S_ISREG(dp->dp2.di_mode) &&
+ !S_ISDIR(dp->dp2.di_mode)) {
+ irelse(&ip);
continue;
+ }
/* Has reference(s)? Skip it. */
- if (dp.dp2->di_nlink > 0)
+ if (dp->dp2.di_nlink > 0) {
+ irelse(&ip);
continue;
+ }
/* printf("Clearing inode=%d (size=%jd)\n", ino,
- (intmax_t)dp.dp2->di_size); */
- /* Free inode's blocks. */
- clear_inode(dp.dp2);
+ (intmax_t)dp->dp2->di_size); */
/* Deallocate it. */
+ memset(&idesc, 0, sizeof(struct inodesc));
+ idesc.id_type = ADDR;
+ idesc.id_func = freeblock;
+ idesc.id_number = ino;
+ clri(&idesc, "UNREF", 1);
clrbit(inosused, cino);
/* Update position of last used inode. */
if (ino < cgp->cg_irotor)
cgp->cg_irotor = ino;
/* Update statistics. */
- cgp->cg_cs.cs_nifree++;
- fs->fs_cs(fs, cg).cs_nifree++;
- fs->fs_cstotal.cs_nifree++;
cgp->cg_unrefs--;
fs->fs_unrefs--;
- /* If this is directory, update related statistics. */
- if (S_ISDIR(dp.dp2->di_mode)) {
- cgp->cg_cs.cs_ndir--;
- fs->fs_cs(fs, cg).cs_ndir--;
- fs->fs_cstotal.cs_ndir--;
- }
/* Zero-fill the inode. */
- *dp.dp2 = ufs2_zino;
+ dp->dp2 = zino.dp2;
/* Write the inode back. */
- if (putinode(diskp) == -1)
- err(1, "putinode (cg=%d ino=%ju) %s",
- cg, (uintmax_t)ino, diskp->d_error);
+ inodirty(&ip);
+ irelse(&ip);
+ cgdirty(cgbp);
if (cgp->cg_unrefs == 0) {
//printf("No more unreferenced inodes in cg=%d.\n", cg);
break;
}
}
/*
- * We don't need this cylinder group anymore, so feel free to
- * free it if needed.
- */
- unbusycg(cgc);
- /*
* If there are no more unreferenced inodes, there is no need to
* check other cylinder groups.
*/
@@ -499,8 +165,7 @@ gjournal_check(const char *filesys)
break;
}
}
- /* Write back modified cylinder groups. */
- putcgs();
/* Write back updated statistics and super-block. */
- closedisk();
+ sbdirty();
+ ckfini(1);
}
diff --git a/sbin/fsck_ffs/globs.c b/sbin/fsck_ffs/globs.c
index 9324133bf544..45d6b80d8fe8 100644
--- a/sbin/fsck_ffs/globs.c
+++ b/sbin/fsck_ffs/globs.c
@@ -56,7 +56,6 @@ struct timespec totalreadtime[BT_NUMBUFTYPES];
struct timespec startprog;
struct bufarea sblk; /* file system superblock */
struct bufarea *pdirbp; /* current directory contents */
-struct bufarea *pbp; /* current inode block */
ino_t cursnapshot;
long dirhash, inplast;
unsigned long numdirs, listmax;
@@ -114,8 +113,7 @@ ufs2_daddr_t n_blks; /* number of blocks in use */
ino_t n_files; /* number of files in use */
volatile sig_atomic_t got_siginfo; /* received a SIGINFO */
volatile sig_atomic_t got_sigalarm; /* received a SIGALRM */
-struct ufs1_dinode ufs1_zino;
-struct ufs2_dinode ufs2_zino;
+union dinode zino;
struct dups *duplist;
struct dups *muldup;
@@ -131,7 +129,6 @@ fsckinit(void)
bzero(&startprog, sizeof(struct timespec));
bzero(&sblk, sizeof(struct bufarea));
pdirbp = NULL;
- pbp = NULL;
cursnapshot = 0;
listmax = numdirs = dirhash = inplast = 0;
countdirs = 0;
@@ -171,6 +168,6 @@ fsckinit(void)
n_files = 0;
got_siginfo = 0;
got_sigalarm = 0;
- bzero(&ufs1_zino, sizeof(struct ufs1_dinode));
- bzero(&ufs2_zino, sizeof(struct ufs2_dinode));
+ bzero(&zino.dp1, sizeof(struct ufs1_dinode));
+ bzero(&zino.dp2, sizeof(struct ufs2_dinode));
}
diff --git a/sbin/fsck_ffs/inode.c b/sbin/fsck_ffs/inode.c
index 2fcc6414918b..18a015f8187e 100644
--- a/sbin/fsck_ffs/inode.c
+++ b/sbin/fsck_ffs/inode.c
@@ -53,15 +53,18 @@ __FBSDID("$FreeBSD$");
#include "fsck.h"
-static ino_t startinum;
+struct bufarea *icachebp; /* inode cache buffer */
static int iblock(struct inodesc *, off_t isize, int type);
+static ufs2_daddr_t indir_blkatoff(ufs2_daddr_t, ino_t, ufs_lbn_t, ufs_lbn_t,
+ struct bufarea **);
int
ckinode(union dinode *dp, struct inodesc *idesc)
{
off_t remsize, sizepb;
int i, offset, ret;
+ struct inode ip;
union dinode dino;
ufs2_daddr_t ndb;
mode_t mode;
@@ -69,6 +72,7 @@ ckinode(union dinode *dp, struct inodesc *idesc)
if (idesc->id_fix != IGNORE)
idesc->id_fix = DONTKNOW;
+ idesc->id_dp = dp;
idesc->id_lbn = -1;
idesc->id_lballoc = -1;
idesc->id_level = 0;
@@ -99,14 +103,14 @@ ckinode(union dinode *dp, struct inodesc *idesc)
pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
pathbuf);
if (reply("ADJUST LENGTH") == 1) {
- dp = ginode(idesc->id_number);
- DIP_SET(dp, di_size,
+ ginode(idesc->id_number, &ip);
+ DIP_SET(ip.i_dp, di_size,
i * sblock.fs_bsize);
printf(
"YOU MUST RERUN FSCK AFTERWARDS\n");
rerun = 1;
- inodirty(dp);
-
+ inodirty(&ip);
+ irelse(&ip);
}
}
continue;
@@ -139,14 +143,15 @@ ckinode(union dinode *dp, struct inodesc *idesc)
pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
pathbuf);
if (reply("ADJUST LENGTH") == 1) {
- dp = ginode(idesc->id_number);
- DIP_SET(dp, di_size,
- DIP(dp, di_size) - remsize);
+ ginode(idesc->id_number, &ip);
+ DIP_SET(ip.i_dp, di_size,
+ DIP(ip.i_dp, di_size) - remsize);
remsize = 0;
printf(
"YOU MUST RERUN FSCK AFTERWARDS\n");
rerun = 1;
- inodirty(dp);
+ inodirty(&ip);
+ irelse(&ip);
break;
}
}
@@ -159,12 +164,12 @@ ckinode(union dinode *dp, struct inodesc *idesc)
static int
iblock(struct inodesc *idesc, off_t isize, int type)
{
+ struct inode ip;
struct bufarea *bp;
int i, n, (*func)(struct inodesc *), nif;
off_t sizepb;
char buf[BUFSIZ];
char pathbuf[MAXPATHLEN + 1];
- union dinode *dp;
if (idesc->id_type != DATA) {
func = idesc->id_func;
@@ -172,9 +177,12 @@ iblock(struct inodesc *idesc, off_t isize, int type)
return (n);
} else
func = dirscan;
- if (chkrange(idesc->id_blkno, idesc->id_numfrags))
- return (SKIP);
bp = getdatablk(idesc->id_blkno, sblock.fs_bsize, type);
+ if (bp->b_errs != 0) {
+ brelse(bp);
+ return (SKIP);
+ }
+ idesc->id_bp = bp;
idesc->id_level--;
for (sizepb = sblock.fs_bsize, i = 0; i < idesc->id_level; i++)
sizepb *= NINDIR(&sblock);
@@ -200,6 +208,7 @@ iblock(struct inodesc *idesc, off_t isize, int type)
for (i = 0; i < nif; i++) {
if (IBLK(bp, i)) {
idesc->id_blkno = IBLK(bp, i);
+ bp->b_index = i;
if (idesc->id_level == 0) {
idesc->id_lbn++;
n = (*func)(idesc);
@@ -208,7 +217,7 @@ iblock(struct inodesc *idesc, off_t isize, int type)
idesc->id_level++;
}
if (n & STOP) {
- bp->b_flags &= ~B_INUSE;
+ brelse(bp);
return (n);
}
} else {
@@ -220,26 +229,142 @@ iblock(struct inodesc *idesc, off_t isize, int type)
pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
pathbuf);
if (reply("ADJUST LENGTH") == 1) {
- dp = ginode(idesc->id_number);
- DIP_SET(dp, di_size,
- DIP(dp, di_size) - isize);
+ ginode(idesc->id_number, &ip);
+ DIP_SET(ip.i_dp, di_size,
+ DIP(ip.i_dp, di_size) - isize);
isize = 0;
printf(
"YOU MUST RERUN FSCK AFTERWARDS\n");
rerun = 1;
- inodirty(dp);
- bp->b_flags &= ~B_INUSE;
+ inodirty(&ip);
+ brelse(bp);
return(STOP);
}
}
}
isize -= sizepb;
}
- bp->b_flags &= ~B_INUSE;
+ brelse(bp);
return (KEEPON);
}
/*
+ * Finds the disk block address at the specified lbn within the inode
+ * specified by dp. This follows the whole tree and honors di_size and
+ * di_extsize so it is a true test of reachability. The lbn may be
+ * negative if an extattr or indirect block is requested.
+ */
+ufs2_daddr_t
+ino_blkatoff(union dinode *dp, ino_t ino, ufs_lbn_t lbn, int *frags,
+ struct bufarea **bpp)
+{
+ ufs_lbn_t tmpval;
+ ufs_lbn_t cur;
+ ufs_lbn_t next;
+ int i;
+
+ *frags = 0;
+ /*
+ * Handle extattr blocks first.
+ */
+ if (lbn < 0 && lbn >= -UFS_NXADDR) {
+ lbn = -1 - lbn;
+ if (lbn > lblkno(&sblock, dp->dp2.di_extsize - 1))
+ return (0);
+ *frags = numfrags(&sblock,
+ sblksize(&sblock, dp->dp2.di_extsize, lbn));
+ return (dp->dp2.di_extb[lbn]);
+ }
+ /*
+ * Now direct and indirect.
+ */
+ if (DIP(dp, di_mode) == IFLNK &&
+ DIP(dp, di_size) < sblock.fs_maxsymlinklen)
+ return (0);
+ if (lbn >= 0 && lbn < UFS_NDADDR) {
+ *frags = numfrags(&sblock,
+ sblksize(&sblock, DIP(dp, di_size), lbn));
+ return (DIP(dp, di_db[lbn]));
+ }
+ *frags = sblock.fs_frag;
+
+ for (i = 0, tmpval = NINDIR(&sblock), cur = UFS_NDADDR; i < UFS_NIADDR;
+ i++, tmpval *= NINDIR(&sblock), cur = next) {
+ next = cur + tmpval;
+ if (lbn == -cur - i)
+ return (DIP(dp, di_ib[i]));
+ /*
+ * Determine whether the lbn in question is within this tree.
+ */
+ if (lbn < 0 && -lbn >= next)
+ continue;
+ if (lbn > 0 && lbn >= next)
+ continue;
+ return (indir_blkatoff(DIP(dp, di_ib[i]), ino, -cur - i, lbn,
+ bpp));
+ }
+ pfatal("lbn %jd not in ino %ju\n", lbn, (uintmax_t)ino);
+ return (0);
+}
+
+/*
+ * Fetch an indirect block to find the block at a given lbn. The lbn
+ * may be negative to fetch a specific indirect block pointer or positive
+ * to fetch a specific block.
+ */
+static ufs2_daddr_t
+indir_blkatoff(ufs2_daddr_t blk, ino_t ino, ufs_lbn_t cur, ufs_lbn_t lbn,
+ struct bufarea **bpp)
+{
+ struct bufarea *bp;
+ ufs_lbn_t lbnadd;
+ ufs_lbn_t base;
+ int i, level;
+
+ if (blk == 0)
+ return (0);
+ level = lbn_level(cur);
+ if (level == -1)
+ pfatal("Invalid indir lbn %jd in ino %ju\n",
+ lbn, (uintmax_t)ino);
+ if (level == 0 && lbn < 0)
+ pfatal("Invalid lbn %jd in ino %ju\n",
+ lbn, (uintmax_t)ino);
+ lbnadd = 1;
+ base = -(cur + level);
+ for (i = level; i > 0; i--)
+ lbnadd *= NINDIR(&sblock);
+ if (lbn > 0)
+ i = (lbn - base) / lbnadd;
+ else
+ i = (-lbn - base) / lbnadd;
+ if (i < 0 || i >= NINDIR(&sblock)) {
+ pfatal("Invalid indirect index %d produced by lbn %jd "
+ "in ino %ju\n", i, lbn, (uintmax_t)ino);
+ return (0);
+ }
+ if (level == 0)
+ cur = base + (i * lbnadd);
+ else
+ cur = -(base + (i * lbnadd)) - (level - 1);
+ bp = getdatablk(blk, sblock.fs_bsize, BT_LEVEL1 + level);
+ if (bp->b_errs != 0)
+ return (0);
+ blk = IBLK(bp, i);
+ bp->b_index = i;
+ if (bpp != NULL)
+ *bpp = bp;
+ else
+ brelse(bp);
+ if (cur == lbn)
+ return (blk);
+ if (level == 0)
+ pfatal("Invalid lbn %jd at level 0 for ino %ju\n", lbn,
+ (uintmax_t)ino);
+ return (indir_blkatoff(blk, ino, cur, lbn, bpp));
+}
+
+/*
* Check that a block in a legal block number.
* Return 0 if in range, 1 if out of range.
*/
@@ -287,39 +412,68 @@ chkrange(ufs2_daddr_t blk, int cnt)
/*
* General purpose interface for reading inodes.
*/
-union dinode *
-ginode(ino_t inumber)
+void
+ginode(ino_t inumber, struct inode *ip)
{
ufs2_daddr_t iblk;
- union dinode *dp;
+ static ino_t startinum = -1;
if (inumber < UFS_ROOTINO || inumber > maxino)
errx(EEXIT, "bad inode number %ju to ginode",
(uintmax_t)inumber);
- if (startinum == 0 ||
- inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
+ ip->i_number = inumber;
+ if (startinum != -1 &&
+ inumber >= startinum && inumber < startinum + INOPB(&sblock)) {
+ /* take an additional reference for the returned inode */
+ icachebp->b_refcnt++;
+ } else {
iblk = ino_to_fsba(&sblock, inumber);
- if (pbp != NULL)
- pbp->b_flags &= ~B_INUSE;
- pbp = getdatablk(iblk, sblock.fs_bsize, BT_INODES);
+ /* release our cache-hold reference on old icachebp */
+ if (icachebp != NULL)
+ brelse(icachebp);
+ icachebp = getdatablk(iblk, sblock.fs_bsize, BT_INODES);
+ if (icachebp->b_errs != 0) {
+ ip->i_bp = NULL;
+ ip->i_dp = &zino;
+ return;
+ }
startinum = rounddown(inumber, INOPB(&sblock));
+ /* take a cache-hold reference on new icachebp */
+ icachebp->b_refcnt++;
+ icachebp->b_index = startinum;
}
- if (sblock.fs_magic == FS_UFS1_MAGIC)
- return ((union dinode *)
- &pbp->b_un.b_dinode1[inumber % INOPB(&sblock)]);
- dp = (union dinode *)&pbp->b_un.b_dinode2[inumber % INOPB(&sblock)];
- if (ffs_verify_dinode_ckhash(&sblock, (struct ufs2_dinode *)dp) != 0) {
+ ip->i_bp = icachebp;
+ if (sblock.fs_magic == FS_UFS1_MAGIC) {
+ ip->i_dp = (union dinode *)
+ &icachebp->b_un.b_dinode1[inumber % INOPB(&sblock)];
+ return;
+ }
+ ip->i_dp = (union dinode *)
+ &icachebp->b_un.b_dinode2[inumber % INOPB(&sblock)];
+ if (ffs_verify_dinode_ckhash(&sblock, (struct ufs2_dinode *)ip->i_dp)) {
pwarn("INODE CHECK-HASH FAILED");
- prtinode(inumber, dp);
+ prtinode(ip);
if (preen || reply("FIX") != 0) {
if (preen)
printf(" (FIXED)\n");
ffs_update_dinode_ckhash(&sblock,
- (struct ufs2_dinode *)dp);
- inodirty(dp);
+ (struct ufs2_dinode *)ip->i_dp);
+ inodirty(ip);
}
}
- return (dp);
+}
+
+/*
+ * Release a held inode.
+ */
+void
+irelse(struct inode *ip)
+{
+
+ if (ip->i_bp->b_refcnt <= 0)
+ pfatal("irelse: releasing unreferenced ino %ju\n",
+ (uintmax_t) ip->i_number);
+ brelse(ip->i_bp);
}
/*
@@ -338,6 +492,7 @@ getnextinode(ino_t inumber, int rebuildcg)
mode_t mode;
ufs2_daddr_t ndb, blk;
union dinode *dp;
+ struct inode ip;
static caddr_t nextinop;
if (inumber != nextino++ || inumber > lastvalidinum)
@@ -373,7 +528,10 @@ getnextinode(ino_t inumber, int rebuildcg)
}
if (ffs_verify_dinode_ckhash(&sblock, (struct ufs2_dinode *)dp) != 0) {
pwarn("INODE CHECK-HASH FAILED");
- prtinode(inumber, dp);
+ ip.i_bp = NULL;
+ ip.i_dp = dp;
+ ip.i_number = inumber;
+ prtinode(&ip);
if (preen || reply("FIX") != 0) {
if (preen)
printf(" (FIXED)\n");
@@ -389,9 +547,9 @@ getnextinode(ino_t inumber, int rebuildcg)
*/
mode = DIP(dp, di_mode) & IFMT;
if (mode == 0) {
- if (memcmp(dp->dp2.di_db, ufs2_zino.di_db,
+ if (memcmp(dp->dp2.di_db, zino.dp2.di_db,
UFS_NDADDR * sizeof(ufs2_daddr_t)) ||
- memcmp(dp->dp2.di_ib, ufs2_zino.di_ib,
+ memcmp(dp->dp2.di_ib, zino.dp2.di_ib,
UFS_NIADDR * sizeof(ufs2_daddr_t)) ||
dp->dp2.di_mode || dp->dp2.di_size)
return (NULL);
@@ -433,24 +591,26 @@ getnextinode(ino_t inumber, int rebuildcg)
}
void
-setinodebuf(ino_t inum)
+setinodebuf(int cg, ino_t inosused)
{
+ ino_t inum;
- if (inum % sblock.fs_ipg != 0)
- errx(EEXIT, "bad inode number %ju to setinodebuf",
- (uintmax_t)inum);
- lastvalidinum = inum + sblock.fs_ipg - 1;
- startinum = 0;
+ inum = cg * sblock.fs_ipg;
+ lastvalidinum = inum + inosused - 1;
nextino = inum;
lastinum = inum;
readcount = 0;
- if (inobuf.b_un.b_buf != NULL)
- return;
- inobufsize = blkroundup(&sblock, INOBUFSIZE);
+ if (inobuf.b_un.b_buf == NULL) {
+ inobufsize = blkroundup(&sblock,
+ MAX(INOBUFSIZE, sblock.fs_bsize));
+ initbarea(&inobuf, BT_INODES);
+ if ((inobuf.b_un.b_buf = Malloc((unsigned)inobufsize)) == NULL)
+ errx(EEXIT, "cannot allocate space for inode buffer");
+ }
fullcnt = inobufsize / ((sblock.fs_magic == FS_UFS1_MAGIC) ?
sizeof(struct ufs1_dinode) : sizeof(struct ufs2_dinode));
- readpercg = sblock.fs_ipg / fullcnt;
- partialcnt = sblock.fs_ipg % fullcnt;
+ readpercg = inosused / fullcnt;
+ partialcnt = inosused % fullcnt;
partialsize = partialcnt * ((sblock.fs_magic == FS_UFS1_MAGIC) ?
sizeof(struct ufs1_dinode) : sizeof(struct ufs2_dinode));
if (partialcnt != 0) {
@@ -459,9 +619,37 @@ setinodebuf(ino_t inum)
partialcnt = fullcnt;
partialsize = inobufsize;
}
- initbarea(&inobuf, BT_INODES);
- if ((inobuf.b_un.b_buf = Malloc((unsigned)inobufsize)) == NULL)
- errx(EEXIT, "cannot allocate space for inode buffer");
+}
+
+int
+freeblock(struct inodesc *idesc)
+{
+ struct dups *dlp;
+ ufs2_daddr_t blkno;
+ long nfrags, res;
+
+ res = KEEPON;
+ blkno = idesc->id_blkno;
+ for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
+ if (chkrange(blkno, 1)) {
+ res = SKIP;
+ } else if (testbmap(blkno)) {
+ for (dlp = duplist; dlp; dlp = dlp->next) {
+ if (dlp->dup != blkno)
+ continue;
+ dlp->dup = duplist->dup;
+ dlp = duplist;
+ duplist = duplist->next;
+ free((char *)dlp);
+ break;
+ }
+ if (dlp == NULL) {
+ clrbmap(blkno);
+ n_blks--;
+ }
+ }
+ }
+ return (res);
}
void
@@ -558,24 +746,27 @@ inocleanup(void)
}
void
-inodirty(union dinode *dp)
+inodirty(struct inode *ip)
{
if (sblock.fs_magic == FS_UFS2_MAGIC)
- ffs_update_dinode_ckhash(&sblock, (struct ufs2_dinode *)dp);
- dirty(pbp);
+ ffs_update_dinode_ckhash(&sblock,
+ (struct ufs2_dinode *)ip->i_dp);
+ dirty(ip->i_bp);
}
void
clri(struct inodesc *idesc, const char *type, int flag)
{
union dinode *dp;
+ struct inode ip;
- dp = ginode(idesc->id_number);
+ ginode(idesc->id_number, &ip);
+ dp = ip.i_dp;
if (flag == 1) {
pwarn("%s %s", type,
(DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE");
- prtinode(idesc->id_number, dp);
+ prtinode(&ip);
printf("\n");
}
if (preen || reply("CLEAR") == 1) {
@@ -586,7 +777,7 @@ clri(struct inodesc *idesc, const char *type, int flag)
(void)ckinode(dp, idesc);
inoinfo(idesc->id_number)->ino_state = USTATE;
clearinode(dp);
- inodirty(dp);
+ inodirty(&ip);
} else {
cmd.value = idesc->id_number;
cmd.size = -DIP(dp, di_nlink);
@@ -598,6 +789,7 @@ clri(struct inodesc *idesc, const char *type, int flag)
rwerror("ADJUST INODE", cmd.value);
}
}
+ irelse(&ip);
}
int
@@ -641,46 +833,17 @@ clearentry(struct inodesc *idesc)
return (STOP|FOUND|ALTERED);
}
-int
-freeblock(struct inodesc *idesc)
-{
- struct dups *dlp;
- ufs2_daddr_t blkno;
- long nfrags, res;
-
- res = KEEPON;
- blkno = idesc->id_blkno;
- for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
- if (chkrange(blkno, 1)) {
- res = SKIP;
- } else if (testbmap(blkno)) {
- for (dlp = duplist; dlp; dlp = dlp->next) {
- if (dlp->dup != blkno)
- continue;
- dlp->dup = duplist->dup;
- dlp = duplist;
- duplist = duplist->next;
- free((char *)dlp);
- break;
- }
- if (dlp == NULL) {
- clrbmap(blkno);
- n_blks--;
- }
- }
- }
- return (res);
-}
-
void
-prtinode(ino_t ino, union dinode *dp)
+prtinode(struct inode *ip)
{
char *p;
+ union dinode *dp;
struct passwd *pw;
time_t t;
- printf(" I=%lu ", (u_long)ino);
- if (ino < UFS_ROOTINO || ino > maxino)
+ dp = ip->i_dp;
+ printf(" I=%lu ", (u_long)ip->i_number);
+ if (ip->i_number < UFS_ROOTINO || ip->i_number > maxino)
return;
printf(" OWNER=");
if ((pw = getpwuid((int)DIP(dp, di_uid))) != NULL)
@@ -731,6 +894,7 @@ ino_t
allocino(ino_t request, int type)
{
ino_t ino;
+ struct inode ip;
union dinode *dp;
struct bufarea *cgbp;
struct cg *cgp;
@@ -748,7 +912,7 @@ allocino(ino_t request, int type)
cg = ino_to_cg(&sblock, ino);
cgbp = cglookup(cg);
cgp = cgbp->b_un.b_cg;
- if (!check_cgmagic(cg, cgbp))
+ if (!check_cgmagic(cg, cgbp, 0))
return (0);
setbit(cg_inosused(cgp), ino % sblock.fs_ipg);
cgp->cg_cs.cs_nifree--;
@@ -765,10 +929,12 @@ allocino(ino_t request, int type)
return (0);
}
cgdirty(cgbp);
- dp = ginode(ino);
+ ginode(ino, &ip);
+ dp = ip.i_dp;
DIP_SET(dp, di_db[0], allocblk((long)1));
if (DIP(dp, di_db[0]) == 0) {
inoinfo(ino)->ino_state = USTATE;
+ irelse(&ip);
return (0);
}
DIP_SET(dp, di_mode, type);
@@ -782,7 +948,8 @@ allocino(ino_t request, int type)
DIP_SET(dp, di_size, sblock.fs_fsize);
DIP_SET(dp, di_blocks, btodb(sblock.fs_fsize));
n_files++;
- inodirty(dp);
+ inodirty(&ip);
+ irelse(&ip);
inoinfo(ino)->ino_type = IFTODT(type);
return (ino);
}
@@ -795,15 +962,18 @@ freeino(ino_t ino)
{
struct inodesc idesc;
union dinode *dp;
+ struct inode ip;
memset(&idesc, 0, sizeof(struct inodesc));
- idesc.id_type = ADDR;
+ idesc.id_type = inoinfo(ino)->ino_idtype;
idesc.id_func = freeblock;
idesc.id_number = ino;
- dp = ginode(ino);
+ ginode(ino, &ip);
+ dp = ip.i_dp;
(void)ckinode(dp, &idesc);
clearinode(dp);
- inodirty(dp);
+ inodirty(&ip);
+ irelse(&ip);
inoinfo(ino)->ino_state = USTATE;
n_files--;
}
diff --git a/sbin/fsck_ffs/main.c b/sbin/fsck_ffs/main.c
index 6a67bbe3feb1..65cee9b7b8c6 100644
--- a/sbin/fsck_ffs/main.c
+++ b/sbin/fsck_ffs/main.c
@@ -70,7 +70,7 @@ __FBSDID("$FreeBSD$");
#include "fsck.h"
-int restarts;
+static int restarts;
static void usage(void) __dead2;
static intmax_t argtoimax(int flag, const char *req, const char *str, int base);
@@ -296,7 +296,12 @@ checkfilesys(char *filesys)
*/
if ((fsreadfd = open(filesys, O_RDONLY)) < 0 || readsb(0) == 0)
exit(3); /* Cannot read superblock */
- close(fsreadfd);
+ if (nflag || (fswritefd = open(filesys, O_WRONLY)) < 0) {
+ fswritefd = -1;
+ if (preen)
+ pfatal("NO WRITE ACCESS");
+ printf(" (NO WRITE)");
+ }
if ((sblock.fs_flags & FS_GJOURNAL) != 0) {
//printf("GJournaled file system detected on %s.\n",
// filesys);
@@ -312,6 +317,8 @@ checkfilesys(char *filesys)
} else {
pfatal(
"UNEXPECTED INCONSISTENCY, CANNOT RUN FAST FSCK\n");
+ close(fsreadfd);
+ close(fswritefd);
}
}
}
@@ -424,12 +431,14 @@ checkfilesys(char *filesys)
*/
if ((sblock.fs_flags & FS_SUJ) == FS_SUJ) {
if ((sblock.fs_flags & FS_NEEDSFSCK) != FS_NEEDSFSCK && skipclean) {
+ sujrecovery = 1;
if (suj_check(filesys) == 0) {
printf("\n***** FILE SYSTEM MARKED CLEAN *****\n");
if (chkdoreload(mntp) == 0)
exit(0);
exit(4);
}
+ sujrecovery = 0;
printf("** Skipping journal, falling through to full fsck\n\n");
}
/*
@@ -601,7 +610,7 @@ checkfilesys(char *filesys)
sblock.fs_time = time(NULL);
sbdirty();
}
- if (cvtlevel && sblk.b_dirty) {
+ if (cvtlevel && (sblk.b_flags & B_DIRTY) != 0) {
/*
* Write out the duplicate super blocks
*/
@@ -610,7 +619,6 @@ checkfilesys(char *filesys)
}
if (rerun)
resolved = 0;
- finalIOstats();
/*
* Check to see if the file system is mounted read-write.
diff --git a/sbin/fsck_ffs/pass1.c b/sbin/fsck_ffs/pass1.c
index 0e9a232c76fb..c1f1b1ec04f5 100644
--- a/sbin/fsck_ffs/pass1.c
+++ b/sbin/fsck_ffs/pass1.c
@@ -97,19 +97,18 @@ pass1(void)
n_files = n_blks = 0;
for (c = 0; c < sblock.fs_ncg; c++) {
inumber = c * sblock.fs_ipg;
- setinodebuf(inumber);
cgbp = cglookup(c);
cgp = cgbp->b_un.b_cg;
rebuildcg = 0;
- if (!check_cgmagic(c, cgbp))
+ if (!check_cgmagic(c, cgbp, 1))
rebuildcg = 1;
if (!rebuildcg && sblock.fs_magic == FS_UFS2_MAGIC) {
inosused = cgp->cg_initediblk;
if (inosused > sblock.fs_ipg) {
- pfatal(
-"Too many initialized inodes (%ju > %d) in cylinder group %d\nReset to %d\n",
- (uintmax_t)inosused,
- sblock.fs_ipg, c, sblock.fs_ipg);
+ pfatal("Too many initialized inodes (%ju > %d) "
+ "in cylinder group %d\nReset to %d\n",
+ (uintmax_t)inosused, sblock.fs_ipg, c,
+ sblock.fs_ipg);
inosused = sblock.fs_ipg;
}
} else {
@@ -167,6 +166,7 @@ pass1(void)
/*
* Scan the allocated inodes.
*/
+ setinodebuf(c, inosused);
for (i = 0; i < inosused; i++, inumber++) {
if (inumber < UFS_ROOTINO) {
(void)getnextinode(inumber, rebuildcg);
@@ -243,6 +243,7 @@ pass1(void)
static int
checkinode(ino_t inumber, struct inodesc *idesc, int rebuildcg)
{
+ struct inode ip;
union dinode *dp;
off_t kernmaxfilesize;
ufs2_daddr_t ndb;
@@ -255,23 +256,24 @@ checkinode(ino_t inumber, struct inodesc *idesc, int rebuildcg)
mode = DIP(dp, di_mode) & IFMT;
if (mode == 0) {
if ((sblock.fs_magic == FS_UFS1_MAGIC &&
- (memcmp(dp->dp1.di_db, ufs1_zino.di_db,
+ (memcmp(dp->dp1.di_db, zino.dp1.di_db,
UFS_NDADDR * sizeof(ufs1_daddr_t)) ||
- memcmp(dp->dp1.di_ib, ufs1_zino.di_ib,
+ memcmp(dp->dp1.di_ib, zino.dp1.di_ib,
UFS_NIADDR * sizeof(ufs1_daddr_t)) ||
dp->dp1.di_mode || dp->dp1.di_size)) ||
(sblock.fs_magic == FS_UFS2_MAGIC &&
- (memcmp(dp->dp2.di_db, ufs2_zino.di_db,
+ (memcmp(dp->dp2.di_db, zino.dp2.di_db,
UFS_NDADDR * sizeof(ufs2_daddr_t)) ||
- memcmp(dp->dp2.di_ib, ufs2_zino.di_ib,
+ memcmp(dp->dp2.di_ib, zino.dp2.di_ib,
UFS_NIADDR * sizeof(ufs2_daddr_t)) ||
dp->dp2.di_mode || dp->dp2.di_size))) {
pfatal("PARTIALLY ALLOCATED INODE I=%lu",
(u_long)inumber);
if (reply("CLEAR") == 1) {
- dp = ginode(inumber);
- clearinode(dp);
- inodirty(dp);
+ ginode(inumber, &ip);
+ clearinode(ip.i_dp);
+ inodirty(&ip);
+ irelse(&ip);
}
}
inoinfo(inumber)->ino_state = USTATE;
@@ -291,10 +293,12 @@ checkinode(ino_t inumber, struct inodesc *idesc, int rebuildcg)
goto unknown;
}
if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) {
- dp = ginode(inumber);
+ ginode(inumber, &ip);
+ dp = ip.i_dp;
DIP_SET(dp, di_size, sblock.fs_fsize);
DIP_SET(dp, di_mode, IFREG|0600);
- inodirty(dp);
+ inodirty(&ip);
+ irelse(&ip);
}
if ((mode == IFBLK || mode == IFCHR || mode == IFIFO ||
mode == IFSOCK) && DIP(dp, di_size) != 0) {
@@ -375,12 +379,12 @@ checkinode(ino_t inumber, struct inodesc *idesc, int rebuildcg)
badblk = dupblk = 0;
idesc->id_number = inumber;
if (DIP(dp, di_flags) & SF_SNAPSHOT)
- idesc->id_type = SNAP;
+ inoinfo(inumber)->ino_idtype = SNAP;
else
- idesc->id_type = ADDR;
+ inoinfo(inumber)->ino_idtype = ADDR;
+ idesc->id_type = inoinfo(inumber)->ino_idtype;
(void)ckinode(dp, idesc);
if (sblock.fs_magic == FS_UFS2_MAGIC && dp->dp2.di_extsize > 0) {
- idesc->id_type = ADDR;
ndb = howmany(dp->dp2.di_extsize, sblock.fs_bsize);
for (j = 0; j < UFS_NXADDR; j++) {
if (--ndb == 0 &&
@@ -409,9 +413,10 @@ checkinode(ino_t inumber, struct inodesc *idesc, int rebuildcg)
else if (reply("CORRECT") == 0)
return (1);
if (bkgrdflag == 0) {
- dp = ginode(inumber);
- DIP_SET(dp, di_blocks, idesc->id_entryno);
- inodirty(dp);
+ ginode(inumber, &ip);
+ DIP_SET(ip.i_dp, di_blocks, idesc->id_entryno);
+ inodirty(&ip);
+ irelse(&ip);
} else {
cmd.value = idesc->id_number;
cmd.size = idesc->id_entryno - DIP(dp, di_blocks);
@@ -448,9 +453,10 @@ checkinode(ino_t inumber, struct inodesc *idesc, int rebuildcg)
else if (reply("ADJUST") == 0)
return (1);
if (bkgrdflag == 0) {
- dp = ginode(inumber);
- DIP_SET(dp, di_size, fixsize);
- inodirty(dp);
+ ginode(inumber, &ip);
+ DIP_SET(ip.i_dp, di_size, fixsize);
+ inodirty(&ip);
+ irelse(&ip);
} else {
cmd.value = idesc->id_number;
cmd.size = fixsize;
@@ -469,9 +475,10 @@ unknown:
inoinfo(inumber)->ino_state = FCLEAR;
if (reply("CLEAR") == 1) {
inoinfo(inumber)->ino_state = USTATE;
- dp = ginode(inumber);
- clearinode(dp);
- inodirty(dp);
+ ginode(inumber, &ip);
+ clearinode(ip.i_dp);
+ inodirty(&ip);
+ irelse(&ip);
}
return (1);
}
diff --git a/sbin/fsck_ffs/pass1b.c b/sbin/fsck_ffs/pass1b.c
index 4db754371b0b..8c09ef36acad 100644
--- a/sbin/fsck_ffs/pass1b.c
+++ b/sbin/fsck_ffs/pass1b.c
@@ -55,10 +55,9 @@ pass1b(void)
int c, i;
union dinode *dp;
struct inodesc idesc;
- ino_t inumber;
+ ino_t inumber, inosused;
memset(&idesc, 0, sizeof(struct inodesc));
- idesc.id_type = ADDR;
idesc.id_func = pass1bcheck;
duphead = duplist;
inumber = 0;
@@ -74,13 +73,16 @@ pass1b(void)
c * 100 / sblock.fs_ncg);
got_sigalarm = 0;
}
- for (i = 0; i < sblock.fs_ipg; i++, inumber++) {
+ inosused = inostathead[c].il_numalloced;
+ if (inosused == 0)
+ continue;
+ setinodebuf(c, inosused);
+ for (i = 0; i < inosused; i++, inumber++) {
if (inumber < UFS_ROOTINO)
continue;
- dp = ginode(inumber);
- if (dp == NULL)
- continue;
+ dp = getnextinode(inumber, 0);
idesc.id_number = inumber;
+ idesc.id_type = inoinfo(inumber)->ino_idtype;
if (inoinfo(inumber)->ino_state != USTATE &&
(ckinode(dp, &idesc) & STOP)) {
rerun = 1;
diff --git a/sbin/fsck_ffs/pass2.c b/sbin/fsck_ffs/pass2.c
index f0e1321afcfe..8632cf4878b1 100644
--- a/sbin/fsck_ffs/pass2.c
+++ b/sbin/fsck_ffs/pass2.c
@@ -61,6 +61,7 @@ static int pass2check(struct inodesc *);
void
pass2(void)
{
+ struct inode ip;
union dinode *dp;
struct inoinfo **inpp, *inp;
struct inoinfo **inpend;
@@ -111,10 +112,12 @@ pass2(void)
ckfini(0);
exit(EEXIT);
}
- dp = ginode(UFS_ROOTINO);
+ ginode(UFS_ROOTINO, &ip);
+ dp = ip.i_dp;
DIP_SET(dp, di_mode, DIP(dp, di_mode) & ~IFMT);
DIP_SET(dp, di_mode, DIP(dp, di_mode) | IFDIR);
- inodirty(dp);
+ inodirty(&ip);
+ irelse(&ip);
break;
case DSTATE:
@@ -158,9 +161,10 @@ pass2(void)
direrror(inp->i_number, "DIRECTORY TOO SHORT");
inp->i_isize = roundup(MINDIRSIZE, DIRBLKSIZ);
if (reply("FIX") == 1) {
- dp = ginode(inp->i_number);
- DIP_SET(dp, di_size, inp->i_isize);
- inodirty(dp);
+ ginode(inp->i_number, &ip);
+ DIP_SET(ip.i_dp, di_size, inp->i_isize);
+ inodirty(&ip);
+ irelse(&ip);
}
} else if ((inp->i_isize & (DIRBLKSIZ - 1)) != 0) {
getpathname(pathbuf, inp->i_number, inp->i_number);
@@ -176,10 +180,11 @@ pass2(void)
printf(" (ADJUSTED)\n");
inp->i_isize = roundup(inp->i_isize, DIRBLKSIZ);
if (preen || reply("ADJUST") == 1) {
- dp = ginode(inp->i_number);
- DIP_SET(dp, di_size,
+ ginode(inp->i_number, &ip);
+ DIP_SET(ip.i_dp, di_size,
roundup(inp->i_isize, DIRBLKSIZ));
- inodirty(dp);
+ inodirty(&ip);
+ irelse(&ip);
}
}
dp = &dino;
@@ -281,6 +286,7 @@ pass2check(struct inodesc *idesc)
char dirname[MAXPATHLEN + 1];
struct inoinfo *inp;
int n, entrysize, ret = 0;
+ struct inode ip;
union dinode *dp;
const char *errmsg;
struct direct proto;
@@ -476,10 +482,12 @@ again:
fileerror(idesc->id_number, dirp->d_ino, errmsg);
if ((n = reply("REMOVE")) == 1)
break;
- dp = ginode(dirp->d_ino);
+ ginode(dirp->d_ino, &ip);
+ dp = ip.i_dp;
inoinfo(dirp->d_ino)->ino_state =
(DIP(dp, di_mode) & IFMT) == IFDIR ? DSTATE : FSTATE;
inoinfo(dirp->d_ino)->ino_linkcnt = DIP(dp, di_nlink);
+ irelse(&ip);
goto again;
case DSTATE:
@@ -526,6 +534,7 @@ static int
fix_extraneous(struct inoinfo *inp, struct inodesc *idesc)
{
char *cp;
+ struct inode ip;
struct inodesc dotdesc;
char oldname[MAXPATHLEN + 1];
char newname[MAXPATHLEN + 1];
@@ -540,8 +549,10 @@ fix_extraneous(struct inoinfo *inp, struct inodesc *idesc)
dotdesc.id_number = idesc->id_dirp->d_ino;
dotdesc.id_func = findino;
dotdesc.id_name = strdup("..");
- if ((ckinode(ginode(dotdesc.id_number), &dotdesc) & FOUND))
+ ginode(dotdesc.id_number, &ip);
+ if ((ckinode(ip.i_dp, &dotdesc) & FOUND))
inp->i_dotdot = dotdesc.id_parent;
+ irelse(&ip);
}
/*
* We have the previously found old name (inp->i_parent) and the
@@ -641,8 +652,10 @@ fix_extraneous(struct inoinfo *inp, struct inodesc *idesc)
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)
+ ginode(dotdesc.id_number, &ip);
+ if ((ckinode(ip.i_dp, &dotdesc) & FOUND) && preen)
printf(" (REMOVED)\n");
+ irelse(&ip);
inp->i_parent = idesc->id_number; /* reparent to correct directory */
inoinfo(inp->i_number)->ino_linkcnt++; /* name gone, return reference */
return (0);
diff --git a/sbin/fsck_ffs/pass3.c b/sbin/fsck_ffs/pass3.c
index 38eb9a4cdfc6..22cb0393905b 100644
--- a/sbin/fsck_ffs/pass3.c
+++ b/sbin/fsck_ffs/pass3.c
@@ -53,6 +53,7 @@ pass3(void)
struct inoinfo *inp;
int loopcnt, inpindex, state;
ino_t orphan;
+ struct inode ip;
struct inodesc idesc;
char namebuf[UFS_MAXNAMLEN+1];
@@ -114,15 +115,17 @@ pass3(void)
idesc.id_parent = orphan;
idesc.id_func = findname;
idesc.id_name = namebuf;
- if ((ckinode(ginode(inp->i_parent), &idesc) & FOUND) == 0)
+ ginode(inp->i_parent, &ip);
+ if ((ckinode(ip.i_dp, &idesc) & FOUND) == 0)
pfatal("COULD NOT FIND NAME IN PARENT DIRECTORY");
if (linkup(orphan, inp->i_parent, namebuf)) {
idesc.id_func = clearentry;
- if (ckinode(ginode(inp->i_parent), &idesc) & FOUND)
+ if (ckinode(ip.i_dp, &idesc) & FOUND)
inoinfo(orphan)->ino_linkcnt++;
inp->i_parent = inp->i_dotdot = lfdir;
inoinfo(lfdir)->ino_linkcnt--;
}
+ irelse(&ip);
inoinfo(orphan)->ino_state = DFOUND;
propagate();
}
diff --git a/sbin/fsck_ffs/pass4.c b/sbin/fsck_ffs/pass4.c
index 925be9f4fb4a..cfcd36296887 100644
--- a/sbin/fsck_ffs/pass4.c
+++ b/sbin/fsck_ffs/pass4.c
@@ -38,6 +38,7 @@ static const char sccsid[] = "@(#)pass4.c 8.4 (Berkeley) 4/28/95";
__FBSDID("$FreeBSD$");
#include <sys/param.h>
+#include <sys/stat.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
@@ -52,12 +53,11 @@ void
pass4(void)
{
ino_t inumber;
- union dinode *dp;
+ struct inode ip;
struct inodesc idesc;
int i, n, cg;
memset(&idesc, 0, sizeof(struct inodesc));
- idesc.id_type = ADDR;
idesc.id_func = freeblock;
for (cg = 0; cg < sblock.fs_ncg; cg++) {
if (got_siginfo) {
@@ -76,6 +76,7 @@ pass4(void)
if (inumber < UFS_ROOTINO)
continue;
idesc.id_number = inumber;
+ idesc.id_type = inoinfo(inumber)->ino_idtype;
switch (inoinfo(inumber)->ino_state) {
case FZLINK:
@@ -103,11 +104,13 @@ pass4(void)
/* if on snapshot, already cleared */
if (cursnapshot != 0)
break;
- dp = ginode(inumber);
- if (DIP(dp, di_size) == 0) {
+ ginode(inumber, &ip);
+ if (DIP(ip.i_dp, di_size) == 0) {
clri(&idesc, "ZERO LENGTH", 1);
+ irelse(&ip);
break;
}
+ irelse(&ip);
/* fall through */
case FCLEAR:
clri(&idesc, "BAD/DUP", 1);
diff --git a/sbin/fsck_ffs/setup.c b/sbin/fsck_ffs/setup.c
index deb920e00e7c..0ae7f1bbb28f 100644
--- a/sbin/fsck_ffs/setup.c
+++ b/sbin/fsck_ffs/setup.c
@@ -58,9 +58,8 @@ __FBSDID("$FreeBSD$");
#include "fsck.h"
-struct inoinfo **inphead, **inpsort;
+struct inoinfo **inphead, **inpsort; /* info about all inodes */
-struct uufsd disk;
struct bufarea asblk;
#define altsblock (*asblk.b_un.b_fs)
#define POWEROF2(num) (((num) & ((num) - 1)) == 0)
@@ -128,8 +127,7 @@ setup(char *dev)
}
}
}
- if ((fsreadfd = open(dev, O_RDONLY)) < 0 ||
- ufs_disk_fillout_blank(&disk, dev) < 0) {
+ if ((fsreadfd = open(dev, O_RDONLY)) < 0) {
if (bkgrdflag) {
unlink(snapname);
bkgrdflag = 0;
@@ -174,8 +172,7 @@ setup(char *dev)
if (preen == 0)
printf("** %s", dev);
if (bkgrdflag == 0 &&
- (nflag || ufs_disk_write(&disk) < 0 ||
- (fswritefd = dup(disk.d_fd)) < 0)) {
+ (nflag || (fswritefd = open(dev, O_WRONLY)) < 0)) {
fswritefd = -1;
if (preen)
pfatal("NO WRITE ACCESS");
@@ -211,13 +208,6 @@ setup(char *dev)
pwarn("USING ALTERNATE SUPERBLOCK AT %jd\n", bflag);
bflag = 0;
}
- /* Save copy of things needed by libufs */
- memcpy(&disk.d_fs, &sblock, sblock.fs_sbsize);
- disk.d_ufs = (sblock.fs_magic == FS_UFS1_MAGIC) ? 1 : 2;
- disk.d_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
- disk.d_sblock = sblock.fs_sblockloc / disk.d_bsize;
- disk.d_si = sblock.fs_si;
-
if (skipclean && ckclean && sblock.fs_clean) {
pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n");
return (-1);
@@ -249,7 +239,7 @@ setup(char *dev)
pfatal("from before 2002 with the command ``fsck -c 2''\n");
exit(EEXIT);
}
- if (asblk.b_dirty && !bflag) {
+ if ((asblk.b_flags & B_DIRTY) != 0 && !bflag) {
memmove(&altsblock, &sblock, (size_t)sblock.fs_sbsize);
flush(fswritefd, &asblk);
}
diff --git a/sbin/fsck_ffs/suj.c b/sbin/fsck_ffs/suj.c
index 8ecd1f686ea7..aa2085e2fa77 100644
--- a/sbin/fsck_ffs/suj.c
+++ b/sbin/fsck_ffs/suj.c
@@ -56,9 +56,6 @@ __FBSDID("$FreeBSD$");
#include "fsck.h"
#define DOTDOT_OFFSET DIRECTSIZ(1)
-#define SUJ_HASHSIZE 2048
-#define SUJ_HASHMASK (SUJ_HASHSIZE - 1)
-#define SUJ_HASH(x) ((x * 2654435761) & SUJ_HASHMASK)
struct suj_seg {
TAILQ_ENTRY(suj_seg) ss_next;
@@ -97,41 +94,20 @@ struct suj_blk {
};
LIST_HEAD(blkhd, suj_blk);
-struct data_blk {
- LIST_ENTRY(data_blk) db_next;
- uint8_t *db_buf;
- ufs2_daddr_t db_blk;
- int db_size;
- int db_dirty;
-};
-
-struct ino_blk {
- LIST_ENTRY(ino_blk) ib_next;
- uint8_t *ib_buf;
- int ib_dirty;
- ino_t ib_startinginum;
- ufs2_daddr_t ib_blk;
-};
-LIST_HEAD(iblkhd, ino_blk);
-
struct suj_cg {
LIST_ENTRY(suj_cg) sc_next;
- struct blkhd sc_blkhash[SUJ_HASHSIZE];
- struct inohd sc_inohash[SUJ_HASHSIZE];
- struct iblkhd sc_iblkhash[SUJ_HASHSIZE];
+ struct blkhd sc_blkhash[HASHSIZE];
+ struct inohd sc_inohash[HASHSIZE];
struct ino_blk *sc_lastiblk;
struct suj_ino *sc_lastino;
struct suj_blk *sc_lastblk;
- uint8_t *sc_cgbuf;
+ struct bufarea *sc_cgbp;
struct cg *sc_cgp;
- int sc_dirty;
int sc_cgx;
};
-static LIST_HEAD(cghd, suj_cg) cghash[SUJ_HASHSIZE];
-static LIST_HEAD(dblkhd, data_blk) dbhash[SUJ_HASHSIZE];
+static LIST_HEAD(cghd, suj_cg) cghash[HASHSIZE];
static struct suj_cg *lastcg;
-static struct data_blk *lastblk;
static TAILQ_HEAD(seghd, suj_seg) allsegs;
static uint64_t oldseq;
@@ -158,7 +134,6 @@ static void ino_adjust(struct suj_ino *);
static void ino_build(struct suj_ino *);
static int blk_isfree(ufs2_daddr_t);
static void initsuj(void);
-static void ino_dirty(ino_t);
static void *
errmalloc(size_t n)
@@ -191,38 +166,6 @@ err_suj(const char * restrict fmt, ...)
}
/*
- * Mark file system as clean, write the super-block back, close the disk.
- */
-static void
-closedisk(const char *devnam)
-{
- struct csum *cgsum;
- uint32_t i;
-
- /*
- * Recompute the fs summary info from correct cs summaries.
- */
- bzero(&fs->fs_cstotal, sizeof(struct csum_total));
- for (i = 0; i < fs->fs_ncg; i++) {
- cgsum = &fs->fs_cs(fs, i);
- fs->fs_cstotal.cs_nffree += cgsum->cs_nffree;
- fs->fs_cstotal.cs_nbfree += cgsum->cs_nbfree;
- fs->fs_cstotal.cs_nifree += cgsum->cs_nifree;
- fs->fs_cstotal.cs_ndir += cgsum->cs_ndir;
- }
- fs->fs_pendinginodes = 0;
- fs->fs_pendingblocks = 0;
- fs->fs_clean = 1;
- fs->fs_time = time(NULL);
- fs->fs_mtime = time(NULL);
- if (sbput(disk.d_fd, fs, 0) == -1)
- err(EX_OSERR, "sbput(%s)", devnam);
- if (ufs_disk_close(&disk) == -1)
- err(EX_OSERR, "ufs_disk_close(%s)", devnam);
- fs = NULL;
-}
-
-/*
* Lookup a cg by number in the hash so we can keep track of which cgs
* need stats rebuilt.
*/
@@ -231,31 +174,29 @@ cg_lookup(int cgx)
{
struct cghd *hd;
struct suj_cg *sc;
+ struct bufarea *cgbp;
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)];
+ cgbp = cglookup(cgx);
+ if (!check_cgmagic(cgx, cgbp, 0))
+ err_suj("UNABLE TO REBUILD CYLINDER GROUP %d", cgx);
+ hd = &cghash[HASH(cgx)];
LIST_FOREACH(sc, hd, sc_next)
if (sc->sc_cgx == cgx) {
+ sc->sc_cgbp = cgbp;
+ sc->sc_cgp = sc->sc_cgbp->b_un.b_cg;
lastcg = sc;
return (sc);
}
sc = errmalloc(sizeof(*sc));
bzero(sc, sizeof(*sc));
- sc->sc_cgbuf = errmalloc(fs->fs_bsize);
- sc->sc_cgp = (struct cg *)sc->sc_cgbuf;
+ sc->sc_cgbp = cgbp;
+ sc->sc_cgp = sc->sc_cgbp->b_un.b_cg;
sc->sc_cgx = cgx;
LIST_INSERT_HEAD(hd, sc, sc_next);
- /*
- * Use bread() here rather than cgget() because the cylinder group
- * may be corrupted but we want it anyway so we can fix it.
- */
- if (bread(&disk, fsbtodb(fs, cgtod(fs, sc->sc_cgx)), sc->sc_cgbuf,
- fs->fs_bsize) == -1)
- err_suj("Unable to read cylinder group %d\n", sc->sc_cgx);
-
return (sc);
}
@@ -273,7 +214,7 @@ ino_lookup(ino_t ino, int creat)
sc = cg_lookup(ino_to_cg(fs, ino));
if (sc->sc_lastino && sc->sc_lastino->si_ino == ino)
return (sc->sc_lastino);
- hd = &sc->sc_inohash[SUJ_HASH(ino)];
+ hd = &sc->sc_inohash[HASH(ino)];
LIST_FOREACH(sino, hd, si_next)
if (sino->si_ino == ino)
return (sino);
@@ -304,7 +245,7 @@ blk_lookup(ufs2_daddr_t blk, int creat)
sc = cg_lookup(dtog(fs, blk));
if (sc->sc_lastblk && sc->sc_lastblk->sb_blk == blk)
return (sc->sc_lastblk);
- hd = &sc->sc_blkhash[SUJ_HASH(fragstoblks(fs, blk))];
+ hd = &sc->sc_blkhash[HASH(fragstoblks(fs, blk))];
LIST_FOREACH(sblk, hd, sb_next)
if (sblk->sb_blk == blk)
return (sblk);
@@ -319,189 +260,6 @@ blk_lookup(ufs2_daddr_t blk, int creat)
return (sblk);
}
-static struct data_blk *
-dblk_lookup(ufs2_daddr_t blk)
-{
- struct data_blk *dblk;
- struct dblkhd *hd;
-
- hd = &dbhash[SUJ_HASH(fragstoblks(fs, blk))];
- if (lastblk && lastblk->db_blk == blk)
- return (lastblk);
- LIST_FOREACH(dblk, hd, db_next)
- if (dblk->db_blk == blk)
- return (dblk);
- /*
- * The inode block wasn't located, allocate a new one.
- */
- dblk = errmalloc(sizeof(*dblk));
- bzero(dblk, sizeof(*dblk));
- LIST_INSERT_HEAD(hd, dblk, db_next);
- dblk->db_blk = blk;
- return (dblk);
-}
-
-static uint8_t *
-dblk_read(ufs2_daddr_t blk, int size)
-{
- struct data_blk *dblk;
-
- dblk = dblk_lookup(blk);
- /*
- * I doubt size mismatches can happen in practice but it is trivial
- * to handle.
- */
- if (size != dblk->db_size) {
- if (dblk->db_buf)
- free(dblk->db_buf);
- dblk->db_buf = errmalloc(size);
- dblk->db_size = size;
- if (bread(&disk, fsbtodb(fs, blk), dblk->db_buf, size) == -1)
- err_suj("Failed to read data block %jd\n", blk);
- }
- return (dblk->db_buf);
-}
-
-static void
-dblk_dirty(ufs2_daddr_t blk)
-{
- struct data_blk *dblk;
-
- dblk = dblk_lookup(blk);
- dblk->db_dirty = 1;
-}
-
-static void
-dblk_write(void)
-{
- struct data_blk *dblk;
- int i;
-
- for (i = 0; i < SUJ_HASHSIZE; i++) {
- LIST_FOREACH(dblk, &dbhash[i], db_next) {
- if (dblk->db_dirty == 0 || dblk->db_size == 0)
- continue;
- if (bwrite(&disk, fsbtodb(fs, dblk->db_blk),
- dblk->db_buf, dblk->db_size) == -1)
- err_suj("Unable to write block %jd\n",
- dblk->db_blk);
- }
- }
-}
-
-static union dinode *
-ino_read(ino_t ino)
-{
- struct ino_blk *iblk;
- struct iblkhd *hd;
- struct suj_cg *sc;
- ufs2_daddr_t blk;
- union dinode *dp;
- int off;
-
- blk = ino_to_fsba(fs, ino);
- sc = cg_lookup(ino_to_cg(fs, ino));
- iblk = sc->sc_lastiblk;
- if (iblk && iblk->ib_blk == blk)
- goto found;
- hd = &sc->sc_iblkhash[SUJ_HASH(fragstoblks(fs, blk))];
- LIST_FOREACH(iblk, hd, ib_next)
- if (iblk->ib_blk == blk)
- goto found;
- /*
- * The inode block wasn't located, allocate a new one.
- */
- iblk = errmalloc(sizeof(*iblk));
- bzero(iblk, sizeof(*iblk));
- iblk->ib_buf = errmalloc(fs->fs_bsize);
- iblk->ib_blk = blk;
- iblk->ib_startinginum = rounddown(ino, INOPB(fs));
- LIST_INSERT_HEAD(hd, iblk, ib_next);
- if (bread(&disk, fsbtodb(fs, blk), iblk->ib_buf, fs->fs_bsize) == -1)
- err_suj("Failed to read inode block %jd\n", blk);
-found:
- sc->sc_lastiblk = iblk;
- off = ino_to_fsbo(fs, ino);
- if (fs->fs_magic == FS_UFS1_MAGIC)
- return (union dinode *)&((struct ufs1_dinode *)iblk->ib_buf)[off];
- dp = (union dinode *)&((struct ufs2_dinode *)iblk->ib_buf)[off];
- if (debug &&
- ffs_verify_dinode_ckhash(fs, (struct ufs2_dinode *)dp) != 0) {
- pwarn("ino_read: INODE CHECK-HASH FAILED");
- prtinode(ino, dp);
- if (preen || reply("FIX") != 0) {
- if (preen)
- printf(" (FIXED)\n");
- ino_dirty(ino);
- }
- }
- return (dp);
-}
-
-static void
-ino_dirty(ino_t ino)
-{
- struct ino_blk *iblk;
- struct iblkhd *hd;
- struct suj_cg *sc;
- ufs2_daddr_t blk;
- int off;
-
- blk = ino_to_fsba(fs, ino);
- sc = cg_lookup(ino_to_cg(fs, ino));
- iblk = sc->sc_lastiblk;
- if (iblk && iblk->ib_blk == blk) {
- if (fs->fs_magic == FS_UFS2_MAGIC) {
- off = ino_to_fsbo(fs, ino);
- ffs_update_dinode_ckhash(fs,
- &((struct ufs2_dinode *)iblk->ib_buf)[off]);
- }
- iblk->ib_dirty = 1;
- return;
- }
- hd = &sc->sc_iblkhash[SUJ_HASH(fragstoblks(fs, blk))];
- LIST_FOREACH(iblk, hd, ib_next) {
- if (iblk->ib_blk == blk) {
- if (fs->fs_magic == FS_UFS2_MAGIC) {
- off = ino_to_fsbo(fs, ino);
- ffs_update_dinode_ckhash(fs,
- &((struct ufs2_dinode *)iblk->ib_buf)[off]);
- }
- iblk->ib_dirty = 1;
- return;
- }
- }
- ino_read(ino);
- ino_dirty(ino);
-}
-
-static void
-iblk_write(struct ino_blk *iblk)
-{
- struct ufs2_dinode *dp;
- int i;
-
- if (iblk->ib_dirty == 0)
- return;
- if (debug && fs->fs_magic == FS_UFS2_MAGIC) {
- dp = (struct ufs2_dinode *)iblk->ib_buf;
- for (i = 0; i < INOPB(fs); dp++, i++) {
- if (ffs_verify_dinode_ckhash(fs, dp) == 0)
- continue;
- pwarn("iblk_write: INODE CHECK-HASH FAILED");
- prtinode(iblk->ib_startinginum + i, (union dinode *)dp);
- if (preen || reply("FIX") != 0) {
- if (preen)
- printf(" (FIXED)\n");
- ino_dirty(iblk->ib_startinginum + i);
- }
- }
- }
- if (bwrite(&disk, fsbtodb(fs, iblk->ib_blk), iblk->ib_buf,
- fs->fs_bsize) == -1)
- err_suj("Failed to write inode block %jd\n", iblk->ib_blk);
-}
-
static int
blk_overlaps(struct jblkrec *brec, ufs2_daddr_t start, int frags)
{
@@ -650,7 +408,7 @@ ino_free(ino_t ino, int mode)
freedir++;
cgp->cg_cs.cs_ndir--;
}
- sc->sc_dirty = 1;
+ cgdirty(sc->sc_cgbp);
return (1);
}
@@ -696,7 +454,7 @@ blk_free(ufs2_daddr_t bno, int mask, int frags)
setbit(blksfree, cgbno + i);
}
}
- sc->sc_dirty = 1;
+ cgdirty(sc->sc_cgbp);
}
/*
@@ -713,110 +471,6 @@ blk_isfree(ufs2_daddr_t bno)
}
/*
- * Fetch an indirect block to find the block at a given lbn. The lbn
- * may be negative to fetch a specific indirect block pointer or positive
- * to fetch a specific block.
- */
-static ufs2_daddr_t
-indir_blkatoff(ufs2_daddr_t blk, ino_t ino, ufs_lbn_t cur, ufs_lbn_t lbn)
-{
- ufs2_daddr_t *bap2;
- ufs2_daddr_t *bap1;
- ufs_lbn_t lbnadd;
- ufs_lbn_t base;
- int level;
- int i;
-
- if (blk == 0)
- return (0);
- level = lbn_level(cur);
- if (level == -1)
- err_suj("Invalid indir lbn %jd\n", lbn);
- if (level == 0 && lbn < 0)
- err_suj("Invalid lbn %jd\n", lbn);
- bap2 = (void *)dblk_read(blk, fs->fs_bsize);
- bap1 = (void *)bap2;
- lbnadd = 1;
- base = -(cur + level);
- for (i = level; i > 0; i--)
- lbnadd *= NINDIR(fs);
- if (lbn > 0)
- i = (lbn - base) / lbnadd;
- else
- i = (-lbn - base) / lbnadd;
- if (i < 0 || i >= NINDIR(fs))
- err_suj("Invalid indirect index %d produced by lbn %jd\n",
- i, lbn);
- if (level == 0)
- cur = base + (i * lbnadd);
- else
- cur = -(base + (i * lbnadd)) - (level - 1);
- if (fs->fs_magic == FS_UFS1_MAGIC)
- blk = bap1[i];
- else
- blk = bap2[i];
- if (cur == lbn)
- return (blk);
- if (level == 0)
- err_suj("Invalid lbn %jd at level 0\n", lbn);
- return indir_blkatoff(blk, ino, cur, lbn);
-}
-
-/*
- * Finds the disk block address at the specified lbn within the inode
- * specified by ip. This follows the whole tree and honors di_size and
- * di_extsize so it is a true test of reachability. The lbn may be
- * negative if an extattr or indirect block is requested.
- */
-static ufs2_daddr_t
-ino_blkatoff(union dinode *ip, ino_t ino, ufs_lbn_t lbn, int *frags)
-{
- ufs_lbn_t tmpval;
- ufs_lbn_t cur;
- ufs_lbn_t next;
- int i;
-
- /*
- * Handle extattr blocks first.
- */
- if (lbn < 0 && lbn >= -UFS_NXADDR) {
- lbn = -1 - lbn;
- if (lbn > lblkno(fs, ip->dp2.di_extsize - 1))
- return (0);
- *frags = numfrags(fs, sblksize(fs, ip->dp2.di_extsize, lbn));
- return (ip->dp2.di_extb[lbn]);
- }
- /*
- * Now direct and indirect.
- */
- if (DIP(ip, di_mode) == IFLNK &&
- DIP(ip, di_size) < fs->fs_maxsymlinklen)
- return (0);
- if (lbn >= 0 && lbn < UFS_NDADDR) {
- *frags = numfrags(fs, sblksize(fs, DIP(ip, di_size), lbn));
- return (DIP(ip, di_db[lbn]));
- }
- *frags = fs->fs_frag;
-
- for (i = 0, tmpval = NINDIR(fs), cur = UFS_NDADDR; i < UFS_NIADDR; i++,
- tmpval *= NINDIR(fs), cur = next) {
- next = cur + tmpval;
- if (lbn == -cur - i)
- return (DIP(ip, di_ib[i]));
- /*
- * Determine whether the lbn in question is within this tree.
- */
- if (lbn < 0 && -lbn >= next)
- continue;
- if (lbn > 0 && lbn >= next)
- continue;
- return indir_blkatoff(DIP(ip, di_ib[i]), ino, -cur - i, lbn);
- }
- err_suj("lbn %jd not in ino\n", lbn);
- /* NOTREACHED */
-}
-
-/*
* Determine whether a block exists at a particular lbn in an inode.
* Returns 1 if found, 0 if not. lbn may be negative for indirects
* or ext blocks.
@@ -824,15 +478,18 @@ ino_blkatoff(union dinode *ip, ino_t ino, ufs_lbn_t lbn, int *frags)
static int
blk_isat(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, int *frags)
{
- union dinode *ip;
+ struct inode ip;
+ union dinode *dp;
ufs2_daddr_t nblk;
- ip = ino_read(ino);
-
- if (DIP(ip, di_nlink) == 0 || DIP(ip, di_mode) == 0)
+ ginode(ino, &ip);
+ dp = ip.i_dp;
+ if (DIP(dp, di_nlink) == 0 || DIP(dp, di_mode) == 0) {
+ irelse(&ip);
return (0);
- nblk = ino_blkatoff(ip, ino, lbn, frags);
-
+ }
+ nblk = ino_blkatoff(dp, ino, lbn, frags, NULL);
+ irelse(&ip);
return (nblk == blk);
}
@@ -845,8 +502,9 @@ ino_clrat(ino_t parent, off_t diroff, ino_t child)
{
union dinode *dip;
struct direct *dp;
+ struct inode ip;
ufs2_daddr_t blk;
- uint8_t *block;
+ struct bufarea *bp;
ufs_lbn_t lbn;
int blksize;
int frags;
@@ -858,16 +516,21 @@ ino_clrat(ino_t parent, off_t diroff, ino_t child)
lbn = lblkno(fs, diroff);
doff = blkoff(fs, diroff);
- dip = ino_read(parent);
- blk = ino_blkatoff(dip, parent, lbn, &frags);
+ ginode(parent, &ip);
+ dip = ip.i_dp;
+ blk = ino_blkatoff(dip, parent, lbn, &frags, NULL);
blksize = sblksize(fs, DIP(dip, di_size), lbn);
- block = dblk_read(blk, blksize);
- dp = (struct direct *)&block[doff];
+ irelse(&ip);
+ bp = getdatablk(blk, blksize, BT_DIRDATA);
+ if (bp->b_errs != 0)
+ err_suj("ino_clrat: UNRECOVERABLE I/O ERROR");
+ dp = (struct direct *)&bp->b_un.b_buf[doff];
if (dp->d_ino != child)
errx(1, "Inode %ju does not exist in %ju at %jd",
(uintmax_t)child, (uintmax_t)parent, diroff);
dp->d_ino = 0;
- dblk_dirty(blk);
+ dirty(bp);
+ brelse(bp);
/*
* The actual .. reference count will already have been removed
* from the parent by the .. remref record.
@@ -881,10 +544,11 @@ ino_clrat(ino_t parent, off_t diroff, ino_t child)
static int
ino_isat(ino_t parent, off_t diroff, ino_t child, int *mode, int *isdot)
{
+ struct inode ip;
union dinode *dip;
+ struct bufarea *bp;
struct direct *dp;
ufs2_daddr_t blk;
- uint8_t *block;
ufs_lbn_t lbn;
int blksize;
int frags;
@@ -892,7 +556,8 @@ ino_isat(ino_t parent, off_t diroff, ino_t child, int *mode, int *isdot)
int doff;
*isdot = 0;
- dip = ino_read(parent);
+ ginode(parent, &ip);
+ dip = ip.i_dp;
*mode = DIP(dip, di_mode);
if ((*mode & IFMT) != IFDIR) {
if (debug) {
@@ -907,6 +572,7 @@ ino_isat(ino_t parent, off_t diroff, ino_t child, int *mode, int *isdot)
printf("Directory %ju has zero mode\n",
(uintmax_t)parent);
}
+ irelse(&ip);
return (0);
}
lbn = lblkno(fs, diroff);
@@ -918,15 +584,19 @@ ino_isat(ino_t parent, off_t diroff, ino_t child, int *mode, int *isdot)
" exceeding size %jd\n",
(uintmax_t)child, (uintmax_t)parent, diroff,
DIP(dip, di_size));
+ irelse(&ip);
return (0);
}
- blk = ino_blkatoff(dip, parent, lbn, &frags);
+ blk = ino_blkatoff(dip, parent, lbn, &frags, NULL);
+ irelse(&ip);
if (blk <= 0) {
if (debug)
printf("Sparse directory %ju", (uintmax_t)parent);
return (0);
}
- block = dblk_read(blk, blksize);
+ bp = getdatablk(blk, blksize, BT_DIRDATA);
+ if (bp->b_errs != 0)
+ err_suj("ino_isat: UNRECOVERABLE I/O ERROR");
/*
* Walk through the records from the start of the block to be
* certain we hit a valid record and not some junk in the middle
@@ -934,7 +604,7 @@ ino_isat(ino_t parent, off_t diroff, ino_t child, int *mode, int *isdot)
*/
dpoff = rounddown(doff, DIRBLKSIZ);
do {
- dp = (struct direct *)&block[dpoff];
+ dp = (struct direct *)&bp->b_un.b_buf[dpoff];
if (dpoff == doff)
break;
if (dp->d_reclen == 0)
@@ -949,6 +619,7 @@ ino_isat(ino_t parent, off_t diroff, ino_t child, int *mode, int *isdot)
if (debug)
printf("ino %ju not found in %ju, lbn %jd, dpoff %d\n",
(uintmax_t)child, (uintmax_t)parent, lbn, dpoff);
+ brelse(bp);
return (0);
}
/*
@@ -962,11 +633,13 @@ ino_isat(ino_t parent, off_t diroff, ino_t child, int *mode, int *isdot)
dp->d_name[0] == '.' && dp->d_name[1] == '.')
*isdot = 1;
*mode = DTTOIF(dp->d_type);
+ brelse(bp);
return (1);
}
if (debug)
printf("ino %ju doesn't match dirent ino %ju in parent %ju\n",
(uintmax_t)child, (uintmax_t)dp->d_ino, (uintmax_t)parent);
+ brelse(bp);
return (0);
}
@@ -981,8 +654,7 @@ static void
indir_visit(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, uint64_t *frags,
ino_visitor visitor, int flags)
{
- ufs2_daddr_t *bap2;
- ufs1_daddr_t *bap1;
+ struct bufarea *bp;
ufs_lbn_t lbnadd;
ufs2_daddr_t nblk;
ufs_lbn_t nlbn;
@@ -1009,14 +681,11 @@ indir_visit(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, uint64_t *frags,
lbnadd = 1;
for (i = level; i > 0; i--)
lbnadd *= NINDIR(fs);
- bap1 = (void *)dblk_read(blk, fs->fs_bsize);
- bap2 = (void *)bap1;
+ bp = getdatablk(blk, fs->fs_bsize, BT_LEVEL1 + level);
+ if (bp->b_errs != 0)
+ err_suj("indir_visit: UNRECOVERABLE I/O ERROR");
for (i = 0; i < NINDIR(fs); i++) {
- if (fs->fs_magic == FS_UFS1_MAGIC)
- nblk = *bap1++;
- else
- nblk = *bap2++;
- if (nblk == 0)
+ if ((nblk = IBLK(bp, i)) == 0)
continue;
if (level == 0) {
nlbn = -lbn + i * lbnadd;
@@ -1027,6 +696,7 @@ indir_visit(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, uint64_t *frags,
indir_visit(ino, nlbn, nblk, frags, visitor, flags);
}
}
+ brelse(bp);
out:
if (flags & VISIT_INDIR) {
(*frags) += fs->fs_frag;
@@ -1042,7 +712,7 @@ out:
* the correct di_blocks for a file.
*/
static uint64_t
-ino_visit(union dinode *ip, ino_t ino, ino_visitor visitor, int flags)
+ino_visit(union dinode *dp, ino_t ino, ino_visitor visitor, int flags)
{
ufs_lbn_t nextlbn;
ufs_lbn_t tmpval;
@@ -1053,18 +723,18 @@ ino_visit(union dinode *ip, ino_t ino, ino_visitor visitor, int flags)
int frags;
int i;
- size = DIP(ip, di_size);
- mode = DIP(ip, di_mode) & IFMT;
+ size = DIP(dp, di_size);
+ mode = DIP(dp, di_mode) & IFMT;
fragcnt = 0;
if ((flags & VISIT_EXT) &&
- fs->fs_magic == FS_UFS2_MAGIC && ip->dp2.di_extsize) {
+ fs->fs_magic == FS_UFS2_MAGIC && dp->dp2.di_extsize) {
for (i = 0; i < UFS_NXADDR; i++) {
- if (ip->dp2.di_extb[i] == 0)
+ if (dp->dp2.di_extb[i] == 0)
continue;
- frags = sblksize(fs, ip->dp2.di_extsize, i);
+ frags = sblksize(fs, dp->dp2.di_extsize, i);
frags = numfrags(fs, frags);
fragcnt += frags;
- visitor(ino, -1 - i, ip->dp2.di_extb[i], frags);
+ visitor(ino, -1 - i, dp->dp2.di_extb[i], frags);
}
}
/* Skip datablocks for short links and devices. */
@@ -1072,12 +742,12 @@ ino_visit(union dinode *ip, ino_t ino, ino_visitor visitor, int flags)
(mode == IFLNK && size < fs->fs_maxsymlinklen))
return (fragcnt);
for (i = 0; i < UFS_NDADDR; i++) {
- if (DIP(ip, di_db[i]) == 0)
+ if (DIP(dp, di_db[i]) == 0)
continue;
frags = sblksize(fs, size, i);
frags = numfrags(fs, frags);
fragcnt += frags;
- visitor(ino, i, DIP(ip, di_db[i]), frags);
+ visitor(ino, i, DIP(dp, di_db[i]), frags);
}
/*
* We know the following indirects are real as we're following
@@ -1088,9 +758,9 @@ ino_visit(union dinode *ip, ino_t ino, ino_visitor visitor, int flags)
lbn = nextlbn) {
nextlbn = lbn + tmpval;
tmpval *= NINDIR(fs);
- if (DIP(ip, di_ib[i]) == 0)
+ if (DIP(dp, di_ib[i]) == 0)
continue;
- indir_visit(ino, -lbn - i, DIP(ip, di_ib[i]), &fragcnt, visitor,
+ indir_visit(ino, -lbn - i, DIP(dp, di_ib[i]), &fragcnt, visitor,
flags);
}
return (fragcnt);
@@ -1117,7 +787,8 @@ null_visit(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, int frags)
static void
ino_adjblks(struct suj_ino *sino)
{
- union dinode *ip;
+ struct inode ip;
+ union dinode *dp;
uint64_t blocks;
uint64_t frags;
off_t isize;
@@ -1125,10 +796,13 @@ ino_adjblks(struct suj_ino *sino)
ino_t ino;
ino = sino->si_ino;
- ip = ino_read(ino);
+ ginode(ino, &ip);
+ dp = ip.i_dp;
/* No need to adjust zero'd inodes. */
- if (DIP(ip, di_mode) == 0)
+ if (DIP(dp, di_mode) == 0) {
+ irelse(&ip);
return;
+ }
/*
* Visit all blocks and count them as well as recording the last
* valid lbn in the file. If the file size doesn't agree with the
@@ -1136,7 +810,7 @@ ino_adjblks(struct suj_ino *sino)
* the blocks count.
*/
visitlbn = 0;
- frags = ino_visit(ip, ino, null_visit, VISIT_INDIR | VISIT_EXT);
+ frags = ino_visit(dp, ino, null_visit, VISIT_INDIR | VISIT_EXT);
blocks = fsbtodb(fs, frags);
/*
* We assume the size and direct block list is kept coherent by
@@ -1145,21 +819,25 @@ ino_adjblks(struct suj_ino *sino)
* populated indirects.
*/
if (visitlbn >= UFS_NDADDR) {
- isize = DIP(ip, di_size);
+ isize = DIP(dp, di_size);
size = lblktosize(fs, visitlbn + 1);
if (isize > size)
isize = size;
/* Always truncate to free any unpopulated indirects. */
- ino_trunc(sino->si_ino, isize);
+ ino_trunc(ino, isize);
+ irelse(&ip);
return;
}
- if (blocks == DIP(ip, di_blocks))
+ if (blocks == DIP(dp, di_blocks)) {
+ irelse(&ip);
return;
+ }
if (debug)
printf("ino %ju adjusting block count from %jd to %jd\n",
- (uintmax_t)ino, DIP(ip, di_blocks), blocks);
- DIP_SET(ip, di_blocks, blocks);
- ino_dirty(ino);
+ (uintmax_t)ino, DIP(dp, di_blocks), blocks);
+ DIP_SET(dp, di_blocks, blocks);
+ inodirty(&ip);
+ irelse(&ip);
}
static void
@@ -1229,6 +907,9 @@ ino_remref(ino_t parent, ino_t child, uint64_t diroff, int isdotdot)
* directory it will be discarded.
*/
if (sino->si_linkadj) {
+ if (sino->si_nlink == 0)
+ err_suj("ino_remref: ino %ld mode 0%o about to go "
+ "negative\n", sino->si_ino, sino->si_mode);
sino->si_nlink--;
if (isdotdot)
sino->si_dotlinks--;
@@ -1256,9 +937,9 @@ static void
ino_free_children(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, int frags)
{
struct suj_ino *sino;
+ struct bufarea *bp;
struct direct *dp;
off_t diroff;
- uint8_t *block;
int skipparent;
int isdotdot;
int dpoff;
@@ -1270,10 +951,12 @@ ino_free_children(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, int frags)
else
skipparent = 0;
size = lfragtosize(fs, frags);
- block = dblk_read(blk, size);
- dp = (struct direct *)&block[0];
+ bp = getdatablk(blk, size, BT_DIRDATA);
+ if (bp->b_errs != 0)
+ err_suj("ino_free_children: UNRECOVERABLE I/O ERROR");
+ dp = (struct direct *)&bp->b_un.b_buf[0];
for (dpoff = 0; dpoff < size && dp->d_reclen; dpoff += dp->d_reclen) {
- dp = (struct direct *)&block[dpoff];
+ dp = (struct direct *)&bp->b_un.b_buf[dpoff];
if (dp->d_ino == 0 || dp->d_ino == UFS_WINO)
continue;
if (dp->d_namlen == 1 && dp->d_name[0] == '.')
@@ -1288,6 +971,7 @@ ino_free_children(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, int frags)
diroff = lblktosize(fs, lbn) + dpoff;
ino_remref(ino, dp->d_ino, diroff, isdotdot);
}
+ brelse(bp);
}
/*
@@ -1295,29 +979,31 @@ ino_free_children(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, int frags)
* link counts. Free the inode back to the cg.
*/
static void
-ino_reclaim(union dinode *ip, ino_t ino, int mode)
+ino_reclaim(struct inode *ip, ino_t ino, int mode)
{
+ union dinode *dp;
uint32_t gen;
+ dp = ip->i_dp;
if (ino == UFS_ROOTINO)
err_suj("Attempting to free UFS_ROOTINO\n");
if (debug)
printf("Truncating and freeing ino %ju, nlink %d, mode %o\n",
- (uintmax_t)ino, DIP(ip, di_nlink), DIP(ip, di_mode));
+ (uintmax_t)ino, DIP(dp, di_nlink), DIP(dp, di_mode));
/* We are freeing an inode or directory. */
- if ((DIP(ip, di_mode) & IFMT) == IFDIR)
- ino_visit(ip, ino, ino_free_children, 0);
- DIP_SET(ip, di_nlink, 0);
- ino_visit(ip, ino, blk_free_visit, VISIT_EXT | VISIT_INDIR);
+ if ((DIP(dp, di_mode) & IFMT) == IFDIR)
+ ino_visit(dp, ino, ino_free_children, 0);
+ DIP_SET(dp, di_nlink, 0);
+ ino_visit(dp, ino, blk_free_visit, VISIT_EXT | VISIT_INDIR);
/* Here we have to clear the inode and release any blocks it holds. */
- gen = DIP(ip, di_gen);
+ gen = DIP(dp, di_gen);
if (fs->fs_magic == FS_UFS1_MAGIC)
- bzero(ip, sizeof(struct ufs1_dinode));
+ bzero(dp, sizeof(struct ufs1_dinode));
else
- bzero(ip, sizeof(struct ufs2_dinode));
- DIP_SET(ip, di_gen, gen);
- ino_dirty(ino);
+ bzero(dp, sizeof(struct ufs2_dinode));
+ DIP_SET(dp, di_gen, gen);
+ inodirty(ip);
ino_free(ino, mode);
return;
}
@@ -1328,14 +1014,16 @@ ino_reclaim(union dinode *ip, ino_t ino, int mode)
static void
ino_decr(ino_t ino)
{
- union dinode *ip;
+ struct inode ip;
+ union dinode *dp;
int reqlink;
int nlink;
int mode;
- ip = ino_read(ino);
- nlink = DIP(ip, di_nlink);
- mode = DIP(ip, di_mode);
+ ginode(ino, &ip);
+ dp = ip.i_dp;
+ nlink = DIP(dp, di_nlink);
+ mode = DIP(dp, di_mode);
if (nlink < 1)
err_suj("Inode %d link count %d invalid\n", ino, nlink);
if (mode == 0)
@@ -1349,11 +1037,13 @@ ino_decr(ino_t ino)
if (debug)
printf("ino %ju not enough links to live %d < %d\n",
(uintmax_t)ino, nlink, reqlink);
- ino_reclaim(ip, ino, mode);
+ ino_reclaim(&ip, ino, mode);
+ irelse(&ip);
return;
}
- DIP_SET(ip, di_nlink, nlink);
- ino_dirty(ino);
+ DIP_SET(dp, di_nlink, nlink);
+ inodirty(&ip);
+ irelse(&ip);
}
/*
@@ -1366,7 +1056,8 @@ ino_adjust(struct suj_ino *sino)
struct jrefrec *rrec;
struct suj_rec *srec;
struct suj_ino *stmp;
- union dinode *ip;
+ union dinode *dp;
+ struct inode ip;
nlink_t nlink;
nlink_t reqlink;
int recmode;
@@ -1414,20 +1105,22 @@ ino_adjust(struct suj_ino *sino)
}
}
}
- ip = ino_read(ino);
- mode = DIP(ip, di_mode) & IFMT;
+ ginode(ino, &ip);
+ dp = ip.i_dp;
+ mode = DIP(dp, di_mode) & IFMT;
if (nlink > UFS_LINK_MAX)
err_suj("ino %ju nlink manipulation error, new %ju, old %d\n",
- (uintmax_t)ino, (uintmax_t)nlink, DIP(ip, di_nlink));
+ (uintmax_t)ino, (uintmax_t)nlink, DIP(dp, di_nlink));
if (debug)
printf("Adjusting ino %ju, nlink %ju, old link %d lastmode %o\n",
- (uintmax_t)ino, (uintmax_t)nlink, DIP(ip, di_nlink),
+ (uintmax_t)ino, (uintmax_t)nlink, DIP(dp, di_nlink),
sino->si_mode);
if (mode == 0) {
if (debug)
printf("ino %ju, zero inode freeing bitmap\n",
(uintmax_t)ino);
ino_free(ino, sino->si_mode);
+ irelse(&ip);
return;
}
/* XXX Should be an assert? */
@@ -1444,18 +1137,21 @@ ino_adjust(struct suj_ino *sino)
printf("ino %ju not enough links to live %ju < %ju\n",
(uintmax_t)ino, (uintmax_t)nlink,
(uintmax_t)reqlink);
- ino_reclaim(ip, ino, mode);
+ ino_reclaim(&ip, ino, mode);
+ irelse(&ip);
return;
}
/* If required write the updated link count. */
- if (DIP(ip, di_nlink) == nlink) {
+ if (DIP(dp, di_nlink) == nlink) {
if (debug)
printf("ino %ju, link matches, skipping.\n",
(uintmax_t)ino);
+ irelse(&ip);
return;
}
- DIP_SET(ip, di_nlink, nlink);
- ino_dirty(ino);
+ DIP_SET(dp, di_nlink, nlink);
+ inodirty(&ip);
+ irelse(&ip);
}
/*
@@ -1463,35 +1159,32 @@ ino_adjust(struct suj_ino *sino)
* and zeroing the indirect.
*/
static void
-indir_trunc(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, ufs_lbn_t lastlbn)
+indir_trunc(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, ufs_lbn_t lastlbn,
+ union dinode *dp)
{
- ufs2_daddr_t *bap2;
- ufs1_daddr_t *bap1;
+ struct bufarea *bp;
ufs_lbn_t lbnadd;
ufs2_daddr_t nblk;
ufs_lbn_t next;
ufs_lbn_t nlbn;
- int dirty;
+ int isdirty;
int level;
int i;
if (blk == 0)
return;
- dirty = 0;
+ isdirty = 0;
level = lbn_level(lbn);
if (level == -1)
err_suj("Invalid level for lbn %jd\n", lbn);
lbnadd = 1;
for (i = level; i > 0; i--)
lbnadd *= NINDIR(fs);
- bap1 = (void *)dblk_read(blk, fs->fs_bsize);
- bap2 = (void *)bap1;
+ bp = getdatablk(blk, fs->fs_bsize, BT_LEVEL1 + level);
+ if (bp->b_errs != 0)
+ err_suj("indir_trunc: UNRECOVERABLE I/O ERROR");
for (i = 0; i < NINDIR(fs); i++) {
- if (fs->fs_magic == FS_UFS1_MAGIC)
- nblk = *bap1++;
- else
- nblk = *bap2++;
- if (nblk == 0)
+ if ((nblk = IBLK(bp, i)) == 0)
continue;
if (level != 0) {
nlbn = (lbn + 1) - (i * lbnadd);
@@ -1503,7 +1196,7 @@ indir_trunc(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, ufs_lbn_t lastlbn)
next = -(lbn + level) + ((i+1) * lbnadd);
if (next <= lastlbn)
continue;
- indir_trunc(ino, nlbn, nblk, lastlbn);
+ indir_trunc(ino, nlbn, nblk, lastlbn, dp);
/* If all of this indirect was reclaimed, free it. */
nlbn = next - lbnadd;
if (nlbn < lastlbn)
@@ -1513,15 +1206,13 @@ indir_trunc(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, ufs_lbn_t lastlbn)
if (nlbn < lastlbn)
continue;
}
- dirty = 1;
+ isdirty = 1;
blk_free(nblk, 0, fs->fs_frag);
- if (fs->fs_magic == FS_UFS1_MAGIC)
- *(bap1 - 1) = 0;
- else
- *(bap2 - 1) = 0;
+ IBLK_SET(bp, i, 0);
}
- if (dirty)
- dblk_dirty(blk);
+ if (isdirty)
+ dirty(bp);
+ brelse(bp);
}
/*
@@ -1533,7 +1224,9 @@ indir_trunc(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, ufs_lbn_t lastlbn)
static void
ino_trunc(ino_t ino, off_t size)
{
- union dinode *ip;
+ struct inode ip;
+ union dinode *dp;
+ struct bufarea *bp;
ufs2_daddr_t bn;
uint64_t totalfrags;
ufs_lbn_t nextlbn;
@@ -1541,33 +1234,42 @@ ino_trunc(ino_t ino, off_t size)
ufs_lbn_t tmpval;
ufs_lbn_t lbn;
ufs_lbn_t i;
- int frags;
+ int blksize, frags;
off_t cursize;
off_t off;
int mode;
- ip = ino_read(ino);
- mode = DIP(ip, di_mode) & IFMT;
- cursize = DIP(ip, di_size);
+ ginode(ino, &ip);
+ dp = ip.i_dp;
+ mode = DIP(dp, di_mode) & IFMT;
+ cursize = DIP(dp, di_size);
if (debug)
printf("Truncating ino %ju, mode %o to size %jd from size %jd\n",
(uintmax_t)ino, mode, size, cursize);
/* Skip datablocks for short links and devices. */
if (mode == 0 || mode == IFBLK || mode == IFCHR ||
- (mode == IFLNK && cursize < fs->fs_maxsymlinklen))
+ (mode == IFLNK && cursize < fs->fs_maxsymlinklen)) {
+ irelse(&ip);
return;
+ }
/* Don't extend. */
- if (size > cursize)
- size = cursize;
+ if (size > cursize) {
+ irelse(&ip);
+ return;
+ }
+ if ((DIP(dp, di_flags) & SF_SNAPSHOT) != 0) {
+ if (size > 0)
+ err_suj("Partial truncation of ino %ju snapshot file\n",
+ (uintmax_t)ino);
+ }
lastlbn = lblkno(fs, blkroundup(fs, size));
for (i = lastlbn; i < UFS_NDADDR; i++) {
- if (DIP(ip, di_db[i]) == 0)
+ if ((bn = DIP(dp, di_db[i])) == 0)
continue;
- frags = sblksize(fs, cursize, i);
- frags = numfrags(fs, frags);
- blk_free(DIP(ip, di_db[i]), 0, frags);
- DIP_SET(ip, di_db[i], 0);
+ blksize = sblksize(fs, cursize, i);
+ blk_free(bn, 0, numfrags(fs, blksize));
+ DIP_SET(dp, di_db[i], 0);
}
/*
* Follow indirect blocks, freeing anything required.
@@ -1579,16 +1281,15 @@ ino_trunc(ino_t ino, off_t size)
/* If we're not freeing any in this indirect range skip it. */
if (lastlbn >= nextlbn)
continue;
- if (DIP(ip, di_ib[i]) == 0)
+ if (DIP(dp, di_ib[i]) == 0)
continue;
- indir_trunc(ino, -lbn - i, DIP(ip, di_ib[i]), lastlbn);
+ indir_trunc(ino, -lbn - i, DIP(dp, di_ib[i]), lastlbn, dp);
/* If we freed everything in this indirect free the indir. */
if (lastlbn > lbn)
continue;
- blk_free(DIP(ip, di_ib[i]), 0, fs->fs_frag);
- DIP_SET(ip, di_ib[i], 0);
+ blk_free(DIP(dp, di_ib[i]), 0, fs->fs_frag);
+ DIP_SET(dp, di_ib[i], 0);
}
- ino_dirty(ino);
/*
* Now that we've freed any whole blocks that exceed the desired
* truncation size, figure out how many blocks remain and what the
@@ -1597,7 +1298,7 @@ ino_trunc(ino_t ino, off_t size)
* would've done. This is consistent with normal fsck behavior.
*/
visitlbn = 0;
- totalfrags = ino_visit(ip, ino, null_visit, VISIT_INDIR | VISIT_EXT);
+ totalfrags = ino_visit(dp, ino, null_visit, VISIT_INDIR | VISIT_EXT);
if (size > lblktosize(fs, visitlbn + 1))
size = lblktosize(fs, visitlbn + 1);
/*
@@ -1607,7 +1308,7 @@ ino_trunc(ino_t ino, off_t size)
if (visitlbn < UFS_NDADDR && totalfrags) {
long oldspace, newspace;
- bn = DIP(ip, di_db[visitlbn]);
+ bn = DIP(dp, di_db[visitlbn]);
if (bn == 0)
err_suj("Bad blk at ino %ju lbn %jd\n",
(uintmax_t)ino, visitlbn);
@@ -1620,30 +1321,32 @@ ino_trunc(ino_t ino, off_t size)
totalfrags -= frags;
}
}
- DIP_SET(ip, di_blocks, fsbtodb(fs, totalfrags));
- DIP_SET(ip, di_size, size);
- ino_dirty(ino);
+ DIP_SET(dp, di_blocks, fsbtodb(fs, totalfrags));
+ DIP_SET(dp, di_size, size);
+ inodirty(&ip);
/*
* If we've truncated into the middle of a block or frag we have
* to zero it here. Otherwise the file could extend into
* uninitialized space later.
*/
off = blkoff(fs, size);
- if (off && DIP(ip, di_mode) != IFDIR) {
- uint8_t *buf;
+ if (off && DIP(dp, di_mode) != IFDIR) {
long clrsize;
- bn = ino_blkatoff(ip, ino, visitlbn, &frags);
+ bn = ino_blkatoff(dp, ino, visitlbn, &frags, NULL);
if (bn == 0)
err_suj("Block missing from ino %ju at lbn %jd\n",
(uintmax_t)ino, visitlbn);
clrsize = frags * fs->fs_fsize;
- buf = dblk_read(bn, clrsize);
+ bp = getdatablk(bn, clrsize, BT_DATA);
+ if (bp->b_errs != 0)
+ err_suj("ino_trunc: UNRECOVERABLE I/O ERROR");
clrsize -= off;
- buf += off;
- bzero(buf, clrsize);
- dblk_dirty(bn);
+ bzero(&bp->b_un.b_buf[off], clrsize);
+ dirty(bp);
+ brelse(bp);
}
+ irelse(&ip);
return;
}
@@ -1789,7 +1492,7 @@ cg_build(struct suj_cg *sc)
struct suj_ino *sino;
int i;
- for (i = 0; i < SUJ_HASHSIZE; i++)
+ for (i = 0; i < HASHSIZE; i++)
LIST_FOREACH(sino, &sc->sc_inohash[i], si_next)
ino_build(sino);
}
@@ -1804,7 +1507,7 @@ cg_trunc(struct suj_cg *sc)
struct suj_ino *sino;
int i;
- for (i = 0; i < SUJ_HASHSIZE; i++) {
+ for (i = 0; i < HASHSIZE; i++) {
LIST_FOREACH(sino, &sc->sc_inohash[i], si_next) {
if (sino->si_trunc) {
ino_trunc(sino->si_ino,
@@ -1824,7 +1527,7 @@ cg_adj_blk(struct suj_cg *sc)
struct suj_ino *sino;
int i;
- for (i = 0; i < SUJ_HASHSIZE; i++) {
+ for (i = 0; i < HASHSIZE; i++) {
LIST_FOREACH(sino, &sc->sc_inohash[i], si_next) {
if (sino->si_blkadj)
ino_adjblks(sino);
@@ -1843,7 +1546,7 @@ cg_check_blk(struct suj_cg *sc)
int i;
- for (i = 0; i < SUJ_HASHSIZE; i++)
+ for (i = 0; i < HASHSIZE; i++)
LIST_FOREACH(sblk, &sc->sc_blkhash[i], sb_next)
blk_check(sblk);
}
@@ -1858,86 +1561,18 @@ cg_check_ino(struct suj_cg *sc)
struct suj_ino *sino;
int i;
- for (i = 0; i < SUJ_HASHSIZE; i++)
+ for (i = 0; i < HASHSIZE; i++)
LIST_FOREACH(sino, &sc->sc_inohash[i], si_next)
ino_check(sino);
}
-/*
- * Write a potentially dirty cg. Recalculate the summary information and
- * update the superblock summary.
- */
-static void
-cg_write(struct suj_cg *sc)
-{
- ufs1_daddr_t fragno, cgbno, maxbno;
- u_int8_t *blksfree;
- struct cg *cgp;
- int blk;
- int i;
-
- if (sc->sc_dirty == 0)
- return;
- /*
- * Fix the frag and cluster summary.
- */
- cgp = sc->sc_cgp;
- cgp->cg_cs.cs_nbfree = 0;
- cgp->cg_cs.cs_nffree = 0;
- bzero(&cgp->cg_frsum, sizeof(cgp->cg_frsum));
- maxbno = fragstoblks(fs, fs->fs_fpg);
- if (fs->fs_contigsumsize > 0) {
- for (i = 1; i <= fs->fs_contigsumsize; i++)
- cg_clustersum(cgp)[i] = 0;
- bzero(cg_clustersfree(cgp), howmany(maxbno, CHAR_BIT));
- }
- blksfree = cg_blksfree(cgp);
- for (cgbno = 0; cgbno < maxbno; cgbno++) {
- if (ffs_isfreeblock(fs, blksfree, cgbno))
- continue;
- if (ffs_isblock(fs, blksfree, cgbno)) {
- ffs_clusteracct(fs, cgp, cgbno, 1);
- cgp->cg_cs.cs_nbfree++;
- continue;
- }
- fragno = blkstofrags(fs, cgbno);
- blk = blkmap(fs, blksfree, fragno);
- ffs_fragacct(fs, blk, cgp->cg_frsum, 1);
- for (i = 0; i < fs->fs_frag; i++)
- if (isset(blksfree, fragno + i))
- cgp->cg_cs.cs_nffree++;
- }
- /*
- * Update the superblock cg summary from our now correct values
- * before writing the block.
- */
- fs->fs_cs(fs, sc->sc_cgx) = cgp->cg_cs;
- if (cgput(fswritefd, fs, cgp) == -1)
- err_suj("Unable to write cylinder group %d\n", sc->sc_cgx);
-}
-
-/*
- * Write out any modified inodes.
- */
-static void
-cg_write_inos(struct suj_cg *sc)
-{
- struct ino_blk *iblk;
- int i;
-
- for (i = 0; i < SUJ_HASHSIZE; i++)
- LIST_FOREACH(iblk, &sc->sc_iblkhash[i], ib_next)
- if (iblk->ib_dirty)
- iblk_write(iblk);
-}
-
static void
cg_apply(void (*apply)(struct suj_cg *))
{
struct suj_cg *scg;
int i;
- for (i = 0; i < SUJ_HASHSIZE; i++)
+ for (i = 0; i < HASHSIZE; i++)
LIST_FOREACH(scg, &cghash[i], sc_next)
apply(scg);
}
@@ -1948,7 +1583,8 @@ cg_apply(void (*apply)(struct suj_cg *))
static void
ino_unlinked(void)
{
- union dinode *ip;
+ struct inode ip;
+ union dinode *dp;
uint16_t mode;
ino_t inon;
ino_t ino;
@@ -1956,23 +1592,25 @@ ino_unlinked(void)
ino = fs->fs_sujfree;
fs->fs_sujfree = 0;
while (ino != 0) {
- ip = ino_read(ino);
- mode = DIP(ip, di_mode) & IFMT;
- inon = DIP(ip, di_freelink);
- DIP_SET(ip, di_freelink, 0);
- ino_dirty(ino);
+ ginode(ino, &ip);
+ dp = ip.i_dp;
+ mode = DIP(dp, di_mode) & IFMT;
+ inon = DIP(dp, di_freelink);
+ DIP_SET(dp, di_freelink, 0);
+ inodirty(&ip);
/*
* XXX Should this be an errx?
*/
- if (DIP(ip, di_nlink) == 0) {
+ if (DIP(dp, di_nlink) == 0) {
if (debug)
printf("Freeing unlinked ino %ju mode %o\n",
(uintmax_t)ino, mode);
- ino_reclaim(ip, ino, mode);
+ ino_reclaim(&ip, ino, mode);
} else if (debug)
printf("Skipping ino %ju mode %o with link %d\n",
- (uintmax_t)ino, mode, DIP(ip, di_nlink));
+ (uintmax_t)ino, mode, DIP(dp, di_nlink));
ino = inon;
+ irelse(&ip);
}
}
@@ -2398,35 +2036,35 @@ suj_prune(void)
* Verify the journal inode before attempting to read records.
*/
static int
-suj_verifyino(union dinode *ip)
+suj_verifyino(union dinode *dp)
{
- if (DIP(ip, di_nlink) != 1) {
+ if (DIP(dp, di_nlink) != 1) {
printf("Invalid link count %d for journal inode %ju\n",
- DIP(ip, di_nlink), (uintmax_t)sujino);
+ DIP(dp, di_nlink), (uintmax_t)sujino);
return (-1);
}
- if ((DIP(ip, di_flags) & (SF_IMMUTABLE | SF_NOUNLINK)) !=
+ if ((DIP(dp, di_flags) & (SF_IMMUTABLE | SF_NOUNLINK)) !=
(SF_IMMUTABLE | SF_NOUNLINK)) {
printf("Invalid flags 0x%X for journal inode %ju\n",
- DIP(ip, di_flags), (uintmax_t)sujino);
+ DIP(dp, di_flags), (uintmax_t)sujino);
return (-1);
}
- if (DIP(ip, di_mode) != (IFREG | IREAD)) {
+ if (DIP(dp, di_mode) != (IFREG | IREAD)) {
printf("Invalid mode %o for journal inode %ju\n",
- DIP(ip, di_mode), (uintmax_t)sujino);
+ DIP(dp, di_mode), (uintmax_t)sujino);
return (-1);
}
- if (DIP(ip, di_size) < SUJ_MIN) {
+ if (DIP(dp, di_size) < SUJ_MIN) {
printf("Invalid size %jd for journal inode %ju\n",
- DIP(ip, di_size), (uintmax_t)sujino);
+ DIP(dp, di_size), (uintmax_t)sujino);
return (-1);
}
- if (DIP(ip, di_modrev) != fs->fs_mtime) {
+ if (DIP(dp, di_modrev) != fs->fs_mtime) {
printf("Journal timestamp does not match fs mount time\n");
return (-1);
}
@@ -2478,7 +2116,7 @@ jblocks_next(struct jblocks *jblocks, int bytes, int *actual)
int freecnt;
int blocks;
- blocks = bytes / disk.d_bsize;
+ blocks = btodb(bytes);
jext = &jblocks->jb_extent[jblocks->jb_head];
freecnt = jext->je_blocks - jblocks->jb_off;
if (freecnt == 0) {
@@ -2490,7 +2128,7 @@ jblocks_next(struct jblocks *jblocks, int bytes, int *actual)
}
if (freecnt > blocks)
freecnt = blocks;
- *actual = freecnt * disk.d_bsize;
+ *actual = dbtob(freecnt);
daddr = jext->je_daddr + jblocks->jb_off;
return (daddr);
@@ -2504,7 +2142,7 @@ static void
jblocks_advance(struct jblocks *jblocks, int bytes)
{
- jblocks->jb_off += bytes / disk.d_bsize;
+ jblocks->jb_off += btodb(bytes);
}
static void
@@ -2595,7 +2233,7 @@ restart:
/*
* Read 1MB at a time and scan for records within this block.
*/
- if (bread(&disk, blk, &block, size) == -1) {
+ if (pread(fsreadfd, &block, size, dbtob(blk)) != size) {
err_suj("Error reading journal block %jd\n",
(intmax_t)blk);
}
@@ -2603,9 +2241,11 @@ restart:
rec = (struct jsegrec *)((uintptr_t)rec + recsize)) {
recsize = real_dev_bsize;
if (rec->jsr_time != fs->fs_mtime) {
+#ifdef notdef
if (debug)
printf("Rec time %jd != fs mtime %jd\n",
rec->jsr_time, fs->fs_mtime);
+#endif
jblocks_advance(suj_jblocks, recsize);
continue;
}
@@ -2663,53 +2303,23 @@ restart:
}
/*
- * Search a directory block for the SUJ_FILE.
- */
-static void
-suj_find(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, int frags)
-{
- char block[MAXBSIZE];
- struct direct *dp;
- int bytes;
- int off;
-
- if (sujino)
- return;
- bytes = lfragtosize(fs, frags);
- if (bread(&disk, fsbtodb(fs, blk), block, bytes) <= 0)
- err_suj("Failed to read UFS_ROOTINO directory block %jd\n",
- blk);
- for (off = 0; off < bytes; off += dp->d_reclen) {
- dp = (struct direct *)&block[off];
- if (dp->d_reclen == 0)
- break;
- if (dp->d_ino == 0)
- continue;
- if (dp->d_namlen != strlen(SUJ_FILE))
- continue;
- if (bcmp(dp->d_name, SUJ_FILE, dp->d_namlen) != 0)
- continue;
- sujino = dp->d_ino;
- return;
- }
-}
-
-/*
* Orchestrate the verification of a filesystem via the softupdates journal.
*/
int
suj_check(const char *filesys)
{
+ struct inodesc idesc;
+ struct csum *cgsum;
union dinode *jip;
- union dinode *ip;
+ struct inode ip;
uint64_t blocks;
- int retval;
+ int i, retval;
struct suj_seg *seg;
struct suj_seg *segn;
initsuj();
fs = &sblock;
- if (real_dev_bsize == 0 && ioctl(disk.d_fd, DIOCGSECTORSIZE,
+ if (real_dev_bsize == 0 && ioctl(fsreadfd, DIOCGSECTORSIZE,
&real_dev_bsize) == -1)
real_dev_bsize = secsize;
if (debug)
@@ -2734,26 +2344,34 @@ suj_check(const char *filesys)
}
/*
- * Find the journal inode.
+ * Search the root directory for the SUJ_FILE.
*/
- ip = ino_read(UFS_ROOTINO);
- sujino = 0;
- ino_visit(ip, UFS_ROOTINO, suj_find, 0);
- if (sujino == 0) {
+ idesc.id_type = DATA;
+ idesc.id_fix = IGNORE;
+ idesc.id_number = UFS_ROOTINO;
+ idesc.id_func = findino;
+ idesc.id_name = SUJ_FILE;
+ ginode(UFS_ROOTINO, &ip);
+ if ((ckinode(ip.i_dp, &idesc) & FOUND) == FOUND) {
+ sujino = idesc.id_parent;
+ irelse(&ip);
+ } else {
printf("Journal inode removed. Use tunefs to re-create.\n");
sblock.fs_flags &= ~FS_SUJ;
sblock.fs_sujfree = 0;
+ irelse(&ip);
return (-1);
}
/*
* Fetch the journal inode and verify it.
*/
- jip = ino_read(sujino);
+ ginode(sujino, &ip);
+ jip = ip.i_dp;
printf("** SU+J Recovering %s\n", filesys);
- if (suj_verifyino(jip) != 0)
- return (-1);
- if (!preen && !reply("USE JOURNAL"))
+ if (suj_verifyino(jip) != 0 || (!preen && !reply("USE JOURNAL"))) {
+ irelse(&ip);
return (-1);
+ }
/*
* Build a list of journal blocks in jblocks before parsing the
* available journal blocks in with suj_read().
@@ -2764,8 +2382,10 @@ suj_check(const char *filesys)
blocks = ino_visit(jip, sujino, suj_add_block, 0);
if (blocks != numfrags(fs, DIP(jip, di_size))) {
printf("Sparse journal inode %ju.\n", (uintmax_t)sujino);
+ irelse(&ip);
return (-1);
}
+ irelse(&ip);
suj_read();
jblocks_destroy(suj_jblocks);
suj_jblocks = NULL;
@@ -2785,16 +2405,23 @@ suj_check(const char *filesys)
if (preen == 0 && (jrecs > 0 || jbytes > 0) && reply("WRITE CHANGES") == 0)
return (0);
/*
- * To remain idempotent with partial truncations the free bitmaps
- * must be written followed by indirect blocks and lastly inode
- * blocks. This preserves access to the modified pointers until
- * they are freed.
+ * Recompute the fs summary info from correct cs summaries.
*/
- cg_apply(cg_write);
- dblk_write();
- cg_apply(cg_write_inos);
- /* Write back superblock. */
- closedisk(filesys);
+ bzero(&fs->fs_cstotal, sizeof(struct csum_total));
+ for (i = 0; i < fs->fs_ncg; i++) {
+ cgsum = &fs->fs_cs(fs, i);
+ fs->fs_cstotal.cs_nffree += cgsum->cs_nffree;
+ fs->fs_cstotal.cs_nbfree += cgsum->cs_nbfree;
+ fs->fs_cstotal.cs_nifree += cgsum->cs_nifree;
+ fs->fs_cstotal.cs_ndir += cgsum->cs_ndir;
+ }
+ fs->fs_pendinginodes = 0;
+ fs->fs_pendingblocks = 0;
+ fs->fs_clean = 1;
+ fs->fs_time = time(NULL);
+ fs->fs_mtime = time(NULL);
+ sbdirty();
+ ckfini(1);
if (jrecs > 0 || jbytes > 0) {
printf("** %jd journal records in %jd bytes for %.2f%% utilization\n",
jrecs, jbytes, ((float)jrecs / (float)(jbytes / JREC_SIZE)) * 100);
@@ -2810,12 +2437,9 @@ initsuj(void)
{
int i;
- for (i = 0; i < SUJ_HASHSIZE; i++) {
+ for (i = 0; i < HASHSIZE; i++)
LIST_INIT(&cghash[i]);
- LIST_INIT(&dbhash[i]);
- }
lastcg = NULL;
- lastblk = NULL;
TAILQ_INIT(&allsegs);
oldseq = 0;
fs = NULL;
diff --git a/sbin/fsdb/fsdb.c b/sbin/fsdb/fsdb.c
index ffffa389a206..785aeb2b5a75 100644
--- a/sbin/fsdb/fsdb.c
+++ b/sbin/fsdb/fsdb.c
@@ -63,6 +63,10 @@ static int find_blks64(uint64_t *buf, int size, uint64_t *blknum);
static int find_indirblks32(uint32_t blk, int ind_level, uint32_t *blknum);
static int find_indirblks64(uint64_t blk, int ind_level, uint64_t *blknum);
+struct inode curip;
+union dinode *curinode;
+ino_t curinum, ocurrent;
+
static void
usage(void)
{
@@ -120,7 +124,7 @@ main(int argc, char *argv[])
ckfini(0);
printf("*** FILE SYSTEM MARKED DIRTY\n");
printf("*** BE SURE TO RUN FSCK TO CLEAN UP ANY DAMAGE\n");
- printf("*** IF IT WAS MOUNTED, RE-MOUNT WITH -u -o reload\n");
+ printf("*** IF IT IS MOUNTED, RE-MOUNT WITH -u -o reload\n");
}
exit(rval);
}
@@ -220,6 +224,16 @@ prompt(EditLine *el)
return pstring;
}
+static void
+setcurinode(ino_t inum)
+{
+
+ if (curip.i_number != 0)
+ irelse(&curip);
+ ginode(inum, &curip);
+ curinode = curip.i_dp;
+ curinum = inum;
+}
int
cmdloop(void)
@@ -234,8 +248,7 @@ cmdloop(void)
EditLine *elptr;
HistEvent he;
- curinode = ginode(UFS_ROOTINO);
- curinum = UFS_ROOTINO;
+ setcurinode(UFS_ROOTINO);
printactive(0);
hist = history_init();
@@ -287,20 +300,20 @@ cmdloop(void)
} else
rval = 0;
free(line);
- if (rval < 0)
+ if (rval < 0) {
/* user typed "quit" */
+ irelse(&curip);
return 0;
+ }
if (rval)
warnx("rval was %d", rval);
}
el_end(elptr);
history_end(hist);
+ irelse(&curip);
return rval;
}
-union dinode *curinode;
-ino_t curinum, ocurrent;
-
#define GETINUM(ac,inum) inum = strtoul(argv[ac], &cp, 0); \
if (inum < UFS_ROOTINO || inum > maxino || cp == argv[ac] || *cp != '\0' ) { \
printf("inode %ju out of range; range is [%ju,%ju]\n", \
@@ -317,33 +330,30 @@ CMDFUNCSTART(focus)
char *cp;
GETINUM(1,inum);
- curinode = ginode(inum);
ocurrent = curinum;
- curinum = inum;
+ setcurinode(inum);
printactive(0);
return 0;
}
CMDFUNCSTART(back)
{
- curinum = ocurrent;
- curinode = ginode(curinum);
+ setcurinode(ocurrent);
printactive(0);
return 0;
}
CMDFUNCSTART(zapi)
{
+ struct inode ip;
ino_t inum;
- union dinode *dp;
char *cp;
GETINUM(1,inum);
- dp = ginode(inum);
- clearinode(dp);
- inodirty(dp);
- if (curinode) /* re-set after potential change */
- curinode = ginode(curinum);
+ ginode(inum, &ip);
+ clearinode(ip.i_dp);
+ inodirty(&ip);
+ irelse(&ip);
return 0;
}
@@ -371,7 +381,7 @@ CMDFUNCSTART(uplink)
DIP_SET(curinode, di_nlink, DIP(curinode, di_nlink) + 1);
printf("inode %ju link count now %d\n",
(uintmax_t)curinum, DIP(curinode, di_nlink));
- inodirty(curinode);
+ inodirty(&curip);
return 0;
}
@@ -382,7 +392,7 @@ CMDFUNCSTART(downlink)
DIP_SET(curinode, di_nlink, DIP(curinode, di_nlink) - 1);
printf("inode %ju link count now %d\n",
(uintmax_t)curinum, DIP(curinode, di_nlink));
- inodirty(curinode);
+ inodirty(&curip);
return 0;
}
@@ -431,7 +441,6 @@ CMDFUNCSTART(ls)
idesc.id_type = DATA;
idesc.id_fix = IGNORE;
ckinode(curinode, &idesc);
- curinode = ginode(curinum);
return 0;
}
@@ -511,8 +520,7 @@ CMDFUNCSTART(findblk)
goto end;
}
/* Get on-disk inode aka dinode. */
- curinum = inum;
- curinode = ginode(inum);
+ setcurinode(inum);
/* Find IFLNK dinode with allocated data blocks. */
switch (DIP(curinode, di_mode) & IFMT) {
case IFDIR:
@@ -564,8 +572,7 @@ CMDFUNCSTART(findblk)
}
}
end:
- curinum = ocurrent;
- curinode = ginode(curinum);
+ setcurinode(ocurrent);
if (is_ufs2)
free(wantedblk64);
else
@@ -713,8 +720,7 @@ dolookup(char *name)
idesc.id_type = DATA;
idesc.id_fix = IGNORE;
if (ckinode(curinode, &idesc) & FOUND) {
- curinum = idesc.id_parent;
- curinode = ginode(curinum);
+ setcurinode(idesc.id_parent);
printactive(0);
return 1;
} else {
@@ -733,8 +739,7 @@ CMDFUNCSTART(focusname)
ocurrent = curinum;
if (argv[1][0] == '/') {
- curinum = UFS_ROOTINO;
- curinode = ginode(UFS_ROOTINO);
+ setcurinode(UFS_ROOTINO);
} else {
if (!checkactivedir())
return 1;
@@ -745,7 +750,6 @@ CMDFUNCSTART(focusname)
printf("component `%s': ", val);
fflush(stdout);
if (!dolookup(val)) {
- curinode = ginode(curinum);
return(1);
}
}
@@ -768,7 +772,6 @@ CMDFUNCSTART(ln)
printf("Ino %ju entered as `%s'\n", (uintmax_t)inum, argv[2]);
else
printf("could not enter name? weird.\n");
- curinode = ginode(curinum);
return rval;
}
@@ -920,7 +923,7 @@ CMDFUNCSTART(newtype)
}
DIP_SET(curinode, di_mode, DIP(curinode, di_mode) & ~IFMT);
DIP_SET(curinode, di_mode, DIP(curinode, di_mode) | type);
- inodirty(curinode);
+ inodirty(&curip);
printactive(0);
return 0;
}
@@ -941,7 +944,7 @@ CMDFUNCSTART(chlen)
}
DIP_SET(curinode, di_size, len);
- inodirty(curinode);
+ inodirty(&curip);
printactive(0);
return rval;
}
@@ -963,7 +966,7 @@ CMDFUNCSTART(chmode)
DIP_SET(curinode, di_mode, DIP(curinode, di_mode) & ~07777);
DIP_SET(curinode, di_mode, DIP(curinode, di_mode) | modebits);
- inodirty(curinode);
+ inodirty(&curip);
printactive(0);
return rval;
}
@@ -988,7 +991,7 @@ CMDFUNCSTART(chaflags)
return(1);
}
DIP_SET(curinode, di_flags, flags);
- inodirty(curinode);
+ inodirty(&curip);
printactive(0);
return rval;
}
@@ -1013,7 +1016,7 @@ CMDFUNCSTART(chgen)
return(1);
}
DIP_SET(curinode, di_gen, gen);
- inodirty(curinode);
+ inodirty(&curip);
printactive(0);
return rval;
}
@@ -1038,7 +1041,7 @@ CMDFUNCSTART(chsize)
return(1);
}
DIP_SET(curinode, di_size, size);
- inodirty(curinode);
+ inodirty(&curip);
printactive(0);
return rval;
}
@@ -1063,7 +1066,7 @@ CMDFUNCSTART(linkcount)
}
DIP_SET(curinode, di_nlink, lcnt);
- inodirty(curinode);
+ inodirty(&curip);
printactive(0);
return rval;
}
@@ -1090,7 +1093,7 @@ CMDFUNCSTART(chowner)
}
DIP_SET(curinode, di_uid, uid);
- inodirty(curinode);
+ inodirty(&curip);
printactive(0);
return rval;
}
@@ -1116,7 +1119,7 @@ CMDFUNCSTART(chgroup)
}
DIP_SET(curinode, di_gid, gid);
- inodirty(curinode);
+ inodirty(&curip);
printactive(0);
return rval;
}
@@ -1185,7 +1188,7 @@ CMDFUNCSTART(chbtime)
return 1;
curinode->dp2.di_birthtime = _time_to_time64(secs);
curinode->dp2.di_birthnsec = nsecs;
- inodirty(curinode);
+ inodirty(&curip);
printactive(0);
return 0;
}
@@ -1202,7 +1205,7 @@ CMDFUNCSTART(chmtime)
else
curinode->dp2.di_mtime = _time_to_time64(secs);
DIP_SET(curinode, di_mtimensec, nsecs);
- inodirty(curinode);
+ inodirty(&curip);
printactive(0);
return 0;
}
@@ -1219,7 +1222,7 @@ CMDFUNCSTART(chatime)
else
curinode->dp2.di_atime = _time_to_time64(secs);
DIP_SET(curinode, di_atimensec, nsecs);
- inodirty(curinode);
+ inodirty(&curip);
printactive(0);
return 0;
}
@@ -1236,7 +1239,7 @@ CMDFUNCSTART(chctime)
else
curinode->dp2.di_ctime = _time_to_time64(secs);
DIP_SET(curinode, di_ctimensec, nsecs);
- inodirty(curinode);
+ inodirty(&curip);
printactive(0);
return 0;
}
diff --git a/sbin/fsdb/fsdb.h b/sbin/fsdb/fsdb.h
index b8dc1e0a2dd6..fee35886f675 100644
--- a/sbin/fsdb/fsdb.h
+++ b/sbin/fsdb/fsdb.h
@@ -52,6 +52,7 @@ struct cmdtable {
#define FL_ST 0x0002 /* resplit final string if argc > maxargc */
int (*handler)(int argc, char *argv[]);
};
+extern struct inode curip;
extern union dinode *curinode;
extern ino_t curinum;