The branch stable/13 has been updated by mckusick:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=a8d7958cef1031a2860c7f1f41a4b4ae09d78b23

commit a8d7958cef1031a2860c7f1f41a4b4ae09d78b23
Author:     Kirk McKusick <[email protected]>
AuthorDate: 2022-09-03 21:46:50 +0000
Commit:     Kirk McKusick <[email protected]>
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);
 }
 

Reply via email to