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); }