svn commit: r346185 - head/sbin/fsck_ffs

Kirk McKusick mckusick at FreeBSD.org
Sat Apr 13 13:31:08 UTC 2019


Author: mckusick
Date: Sat Apr 13 13:31:06 2019
New Revision: 346185
URL: https://svnweb.freebsd.org/changeset/base/346185

Log:
  Followup to -r344552 in which fsck_ffs checks for a size past the
  last allocated block of the file and if that is found, shortens the
  file to reference the last allocated block thus avoiding having it
  reference a hole at its end.
  
  This update corrects an error where fsck_ffs miscalculated the last
  logical block of the file when the file contained a large hole.
  
  Reported by:  Jamie Landeg-Jones
  Tested by:    Peter Holm
  MFC after:    2 weeks
  Sponsored by: Netflix

Modified:
  head/sbin/fsck_ffs/fsck.h
  head/sbin/fsck_ffs/inode.c
  head/sbin/fsck_ffs/pass1.c

Modified: head/sbin/fsck_ffs/fsck.h
==============================================================================
--- head/sbin/fsck_ffs/fsck.h	Sat Apr 13 12:50:47 2019	(r346184)
+++ head/sbin/fsck_ffs/fsck.h	Sat Apr 13 13:31:06 2019	(r346185)
@@ -231,6 +231,7 @@ struct inodesc {
 	ino_t id_parent;	/* for DATA nodes, their parent */
 	ufs_lbn_t id_lbn;	/* logical block number of current block */
 	ufs2_daddr_t id_blkno;	/* current block number being examined */
+	int id_level;		/* level of indirection of this block */
 	int id_numfrags;	/* number of frags contained in block */
 	ufs_lbn_t id_lballoc;	/* pass1: last LBN that is allocated */
 	off_t id_filesize;	/* for DATA nodes, the size of the directory */

Modified: head/sbin/fsck_ffs/inode.c
==============================================================================
--- head/sbin/fsck_ffs/inode.c	Sat Apr 13 12:50:47 2019	(r346184)
+++ head/sbin/fsck_ffs/inode.c	Sat Apr 13 13:31:06 2019	(r346185)
@@ -55,7 +55,7 @@ __FBSDID("$FreeBSD$");
 
 static ino_t startinum;
 
-static int iblock(struct inodesc *, long ilevel, off_t isize, int type);
+static int iblock(struct inodesc *, off_t isize, int type);
 
 int
 ckinode(union dinode *dp, struct inodesc *idesc)
@@ -70,6 +70,8 @@ ckinode(union dinode *dp, struct inodesc *idesc)
 	if (idesc->id_fix != IGNORE)
 		idesc->id_fix = DONTKNOW;
 	idesc->id_lbn = -1;
+	idesc->id_lballoc = -1;
+	idesc->id_level = 0;
 	idesc->id_entryno = 0;
 	idesc->id_filesize = DIP(dp, di_size);
 	mode = DIP(dp, di_mode) & IFMT;
@@ -122,9 +124,10 @@ ckinode(union dinode *dp, struct inodesc *idesc)
 	sizepb = sblock.fs_bsize;
 	for (i = 0; i < UFS_NIADDR; i++) {
 		sizepb *= NINDIR(&sblock);
+		idesc->id_level = i + 1;
 		if (DIP(&dino, di_ib[i])) {
 			idesc->id_blkno = DIP(&dino, di_ib[i]);
-			ret = iblock(idesc, i + 1, remsize, BT_LEVEL1 + i);
+			ret = iblock(idesc, remsize, BT_LEVEL1 + i);
 			if (ret & STOP)
 				return (ret);
 		} else if (remsize > 0) {
@@ -154,7 +157,7 @@ ckinode(union dinode *dp, struct inodesc *idesc)
 }
 
 static int
-iblock(struct inodesc *idesc, long ilevel, off_t isize, int type)
+iblock(struct inodesc *idesc, off_t isize, int type)
 {
 	struct bufarea *bp;
 	int i, n, (*func)(struct inodesc *), nif;
@@ -172,8 +175,8 @@ iblock(struct inodesc *idesc, long ilevel, off_t isize
 	if (chkrange(idesc->id_blkno, idesc->id_numfrags))
 		return (SKIP);
 	bp = getdatablk(idesc->id_blkno, sblock.fs_bsize, type);
-	ilevel--;
-	for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
+	idesc->id_level--;
+	for (sizepb = sblock.fs_bsize, i = 0; i < idesc->id_level; i++)
 		sizepb *= NINDIR(&sblock);
 	if (howmany(isize, sizepb) > NINDIR(&sblock))
 		nif = NINDIR(&sblock);
@@ -195,19 +198,21 @@ iblock(struct inodesc *idesc, long ilevel, off_t isize
 		flush(fswritefd, bp);
 	}
 	for (i = 0; i < nif; i++) {
-		if (ilevel == 0)
-			idesc->id_lbn++;
 		if (IBLK(bp, i)) {
 			idesc->id_blkno = IBLK(bp, i);
-			if (ilevel == 0)
+			if (idesc->id_level == 0) {
+				idesc->id_lbn++;
 				n = (*func)(idesc);
-			else
-				n = iblock(idesc, ilevel, isize, type);
+			} else {
+				n = iblock(idesc, isize, type);
+				idesc->id_level++;
+			}
 			if (n & STOP) {
 				bp->b_flags &= ~B_INUSE;
 				return (n);
 			}
 		} else {
+			idesc->id_lbn += sizepb / sblock.fs_bsize;
 			if (idesc->id_type == DATA && isize > 0) {
 				/* An empty block in a directory XXX */
 				getpathname(pathbuf, idesc->id_number,

Modified: head/sbin/fsck_ffs/pass1.c
==============================================================================
--- head/sbin/fsck_ffs/pass1.c	Sat Apr 13 12:50:47 2019	(r346184)
+++ head/sbin/fsck_ffs/pass1.c	Sat Apr 13 13:31:06 2019	(r346185)
@@ -378,7 +378,6 @@ checkinode(ino_t inumber, struct inodesc *idesc, int r
 		idesc->id_type = SNAP;
 	else
 		idesc->id_type = ADDR;
-	idesc->id_lballoc = -1;
 	(void)ckinode(dp, idesc);
 	if (sblock.fs_magic == FS_UFS2_MAGIC && dp->dp2.di_extsize > 0) {
 		idesc->id_type = ADDR;
@@ -565,7 +564,7 @@ pass1check(struct inodesc *idesc)
 		 */
 		idesc->id_entryno++;
 	}
-	if (idesc->id_lballoc == -1 || idesc->id_lballoc < idesc->id_lbn)
+	if (idesc->id_level == 0 && idesc->id_lballoc < idesc->id_lbn)
 		idesc->id_lballoc = idesc->id_lbn;
 	return (res);
 }


More information about the svn-src-head mailing list