git: a8d7958cef10 - stable/13 - Properly handle the replacement of a partially allocated root directory.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 11 Dec 2022 00:38:20 UTC
The branch stable/13 has been updated by mckusick:
URL: https://cgit.FreeBSD.org/src/commit/?id=a8d7958cef1031a2860c7f1f41a4b4ae09d78b23
commit a8d7958cef1031a2860c7f1f41a4b4ae09d78b23
Author: Kirk McKusick <mckusick@FreeBSD.org>
AuthorDate: 2022-09-03 21:46:50 +0000
Commit: Kirk McKusick <mckusick@FreeBSD.org>
CommitDate: 2022-12-11 00:37:17 +0000
Properly handle the replacement of a partially allocated root directory.
(cherry picked from commit f4fc3895243b9a8ae0577e731a3e450377071196)
(cherry picked from commit 2aa6ed881d22e4ed095d04ecb8a11f178274a644)
(cherry picked from commit 2567b60f62534bf5b243972f85b4921bba837439)
Sponsored by: The FreeBSD Foundation
---
sbin/fsck_ffs/dir.c | 18 +++++++++++++-----
sbin/fsck_ffs/fsck.h | 8 +++++++-
sbin/fsck_ffs/inode.c | 7 +++++--
3 files changed, 25 insertions(+), 8 deletions(-)
diff --git a/sbin/fsck_ffs/dir.c b/sbin/fsck_ffs/dir.c
index 42ecf4112253..ba286a965513 100644
--- a/sbin/fsck_ffs/dir.c
+++ b/sbin/fsck_ffs/dir.c
@@ -474,6 +474,7 @@ linkup(ino_t orphan, ino_t parentdir, char *name)
union dinode *dp;
int lostdir;
ino_t oldlfdir;
+ struct inoinfo *inp;
struct inodesc idesc;
char tempname[BUFSIZ];
@@ -581,10 +582,13 @@ linkup(ino_t orphan, ino_t parentdir, char *name)
inodirty(&ip);
inoinfo(lfdir)->ino_linkcnt++;
pwarn("DIR I=%lu CONNECTED. ", (u_long)orphan);
- if (parentdir != (ino_t)-1) {
+ inp = getinoinfo(parentdir);
+ if (parentdir != (ino_t)-1 && inp != NULL &&
+ (inp->i_flags & INFO_NEW) == 0) {
printf("PARENT WAS I=%lu\n", (u_long)parentdir);
/*
- * The parent directory, because of the ordering
+ * If the parent directory did not have to
+ * be replaced then because of the ordering
* guarantees, has had the link count incremented
* for the child, but no entry was made. This
* fixes the parent link count so that fsck does
@@ -823,7 +827,12 @@ allocdir(ino_t parent, ino_t request, int mode)
inodirty(&ip);
if (ino == UFS_ROOTINO) {
inoinfo(ino)->ino_linkcnt = DIP(dp, di_nlink);
- cacheino(dp, ino);
+ if ((inp = getinoinfo(ino)) == NULL)
+ inp = cacheino(dp, ino);
+ else
+ inp->i_flags = INFO_NEW;
+ inp->i_parent = parent;
+ inp->i_dotdot = parent;
irelse(&ip);
return(ino);
}
@@ -832,8 +841,7 @@ allocdir(ino_t parent, ino_t request, int mode)
irelse(&ip);
return (0);
}
- cacheino(dp, ino);
- inp = getinoinfo(ino);
+ inp = cacheino(dp, ino);
inp->i_parent = parent;
inp->i_dotdot = parent;
inoinfo(ino)->ino_state = inoinfo(parent)->ino_state;
diff --git a/sbin/fsck_ffs/fsck.h b/sbin/fsck_ffs/fsck.h
index 1fb0df0c5124..1d3f9b7943ec 100644
--- a/sbin/fsck_ffs/fsck.h
+++ b/sbin/fsck_ffs/fsck.h
@@ -311,9 +311,15 @@ extern struct inoinfo {
ino_t i_parent; /* inode number of parent */
ino_t i_dotdot; /* inode number of `..' */
size_t i_isize; /* size of inode */
+ u_int i_flags; /* flags, see below */
u_int i_numblks; /* size of block array in bytes */
ufs2_daddr_t i_blks[1]; /* actually longer */
} **inphead, **inpsort;
+/*
+ * flags for struct inoinfo
+ */
+#define INFO_NEW 0x0000001 /* replaced broken directory */
+
extern long dirhash, inplast;
extern unsigned long numdirs, listmax;
extern long countdirs; /* number of directories we actually found */
@@ -447,7 +453,7 @@ 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);
+struct inoinfo *cacheino(union dinode *dp, ino_t inumber);
void catch(int);
void catchquit(int);
void cgdirty(struct bufarea *);
diff --git a/sbin/fsck_ffs/inode.c b/sbin/fsck_ffs/inode.c
index f0699aabe349..c9b4a80b50fb 100644
--- a/sbin/fsck_ffs/inode.c
+++ b/sbin/fsck_ffs/inode.c
@@ -698,12 +698,15 @@ freeinodebuf(void)
*
* Enter inodes into the cache.
*/
-void
+struct inoinfo *
cacheino(union dinode *dp, ino_t inumber)
{
struct inoinfo *inp, **inpp;
int i, blks;
+ if (getinoinfo(inumber) != NULL)
+ pfatal("cacheino: duplicate entry for ino %ld\n",
+ (intmax_t)inumber);
if (howmany(DIP(dp, di_size), sblock.fs_bsize) > UFS_NDADDR)
blks = UFS_NDADDR + UFS_NIADDR;
else if (DIP(dp, di_size) > 0)
@@ -735,6 +738,7 @@ cacheino(union dinode *dp, ino_t inumber)
errx(EEXIT, "cannot increase directory list");
}
inpsort[inplast++] = inp;
+ return (inp);
}
/*
@@ -750,7 +754,6 @@ getinoinfo(ino_t inumber)
continue;
return (inp);
}
- errx(EEXIT, "cannot find inode %ju", (uintmax_t)inumber);
return ((struct inoinfo *)0);
}