Subject: Re: dump and nodump flag
To: None <tech-kern@netbsd.org>
From: Manuel Bouyer <bouyer@antioche.lip6.fr>
List: tech-kern
Date: 03/02/1999 11:32:13
On Mar 1, Manuel Bouyer wrote
> Hi,
> appened below is a patch against the 1.3.3 dump, which changes the handling
> [...]

Hum, there is a problem: directories should always be put in the usedinomap
unless they explicitely have the nodump flag. Using WANTTODUMP() for this
leads to propagation of false nodump attribute (gained just because a
directory didn't need dump with level > 0) and endless loop in pass 2.
Below is a corrected patch.

--
Manuel Bouyer, LIP6, Universite Paris VI.           Manuel.Bouyer@lip6.fr
--

Index: traverse.c
===================================================================
RCS file: /archive/cvs/cvsroot/NetBSD/src/sbin/dump/traverse.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 traverse.c
--- traverse.c	1997/12/15 16:38:51	1.1.1.1
+++ traverse.c	1999/03/02 10:28:14
@@ -79,9 +79,11 @@
 typedef	int32_t fsizeT;
 #endif
 
-static	int dirindir __P((ino_t ino, daddr_t blkno, int level, long *size));
+static	int dirindir __P((ino_t ino, daddr_t blkno, int level, long *size,
+    long *tapesize, int nodump));
 static	void dmpindir __P((ino_t ino, daddr_t blk, int level, fsizeT *size));
-static	int searchdir __P((ino_t ino, daddr_t blkno, long size, long filesize));
+static	int searchdir __P((ino_t ino, daddr_t blkno, long size, long filesize,
+    long *tapesize, int nodump));
 
 /*
  * This is an estimation of the number of TP_BSIZE blocks in the file.
@@ -151,9 +153,12 @@
 	dp = getino(ino);
 	if ((mode = (dp->di_mode & IFMT)) == 0)
 		return;
+	/*
+	 * Put all dirs in dumpdirmap, inodes that are to be dumped in the
+	 * used map. All inode but dirs who have the nodump attribute go
+	 * to the usedinomap.
+	 */
 	SETINO(ino, usedinomap);
-	if (mode == IFDIR)
-		SETINO(ino, dumpdirmap);
 	if (WANTTODUMP(dp)) {
 		SETINO(ino, dumpinomap);
 		if (mode != IFREG && mode != IFDIR && mode != IFLNK)
@@ -162,6 +167,13 @@
 			*tapesize += blockest(dp);
 		return;
 	}
+	if (mode == IFDIR) {
+		SETINO(ino, dumpdirmap);
+#ifdef UF_NODUMP
+		if (!nonodump && (dp->di_flags & UF_NODUMP))
+			CLRINO(ino, usedinomap);
+#endif
+	}
 	if (mode == IFDIR)
 		*dirskipped = 1;
 }
@@ -281,8 +293,8 @@
 	ino_t maxino;
 	long *tapesize;
 {
-	struct	dinode *dp;
-	int i, isdir;
+	struct	dinode *dp, di;
+	int i, isdir, nodump;
 	char *map;
 	ino_t ino;
 	long filesize;
@@ -294,24 +306,36 @@
 			isdir = *map++;
 		else
 			isdir >>= 1;
-		if ((isdir & 1) == 0 || TSTINO(ino, dumpinomap))
+		/*
+		 * If dir has been removed from the used map, it's either
+		 * because it had the nodump flag, or it herited it from
+		 * its parent. A directory can't be in dumpinomap if
+		 * not in usedinomap, but we have to go throuh it anyway
+		 * to propagate the nodump attribute.
+		 */
+		nodump = (TSTINO(ino, usedinomap) == 0);
+		if ((isdir & 1) == 0 ||
+		    (TSTINO(ino, dumpinomap) && nodump == 0))
 			continue;
+
 		dp = getino(ino);
-		filesize = dp->di_size;
+		di = *dp; /* inode buf may be changed in searchdir */
+		filesize = di.di_size;
 		for (ret = 0, i = 0; filesize > 0 && i < NDADDR; i++) {
-			if (dp->di_db[i] != 0)
-				ret |= searchdir(ino, dp->di_db[i],
+			if (di.di_db[i] != 0)
+				ret |= searchdir(ino, di.di_db[i],
 					(long)dblksize(sblock, dp, i),
-					filesize);
+					filesize, tapesize, nodump);
 			if (ret & HASDUMPEDFILE)
 				filesize = 0;
 			else
 				filesize -= sblock->fs_bsize;
 		}
 		for (i = 0; filesize > 0 && i < NIADDR; i++) {
-			if (dp->di_ib[i] == 0)
+			if (di.di_ib[i] == 0)
 				continue;
-			ret |= dirindir(ino, dp->di_ib[i], i, &filesize);
+			ret |= dirindir(ino, di.di_ib[i], i, &filesize,
+			    tapesize, nodump);
 		}
 		if (ret & HASDUMPEDFILE) {
 			SETINO(ino, dumpinomap);
@@ -319,7 +343,11 @@
 			change = 1;
 			continue;
 		}
-		if ((ret & HASSUBDIRS) == 0) {
+		if (nodump) {
+			if (ret & HASSUBDIRS)
+				change = 1; /* subdirs have inherited nodump */
+			CLRINO(ino, dumpdirmap);
+		} else if ((ret & HASSUBDIRS) == 0) {
 			if (!TSTINO(ino, dumpinomap)) {
 				CLRINO(ino, dumpdirmap);
 				change = 1;
@@ -335,11 +363,13 @@
  * require the directory to be dumped.
  */
 static int
-dirindir(ino, blkno, ind_level, filesize)
+dirindir(ino, blkno, ind_level, filesize, tapesize, nodump)
 	ino_t ino;
 	daddr_t blkno;
 	int ind_level;
 	long *filesize;
+	long *tapesize;
+	int nodump;
 {
 	int ret = 0;
 	int i;
@@ -351,7 +381,7 @@
 			blkno = idblk[i];
 			if (blkno != 0)
 				ret |= searchdir(ino, blkno, sblock->fs_bsize,
-					*filesize);
+					*filesize, tapesize, nodump);
 			if (ret & HASDUMPEDFILE)
 				*filesize = 0;
 			else
@@ -363,7 +393,8 @@
 	for (i = 0; *filesize > 0 && i < NINDIR(sblock); i++) {
 		blkno = idblk[i];
 		if (blkno != 0)
-			ret |= dirindir(ino, blkno, ind_level, filesize);
+			ret |= dirindir(ino, blkno, ind_level, filesize,
+			    tapesize, nodump);
 	}
 	return (ret);
 }
@@ -374,13 +405,16 @@
  * contains any subdirectories.
  */
 static int
-searchdir(ino, blkno, size, filesize)
+searchdir(ino, blkno, size, filesize, tapesize, nodump)
 	ino_t ino;
 	daddr_t blkno;
 	long size;
 	long filesize;
+	long *tapesize;
+	int nodump;
 {
 	struct direct *dp;
+	struct dinode *ip;
 	long loc, ret = 0;
 	char dblk[MAXBSIZE];
 
@@ -401,16 +435,30 @@
 				continue;
 			if (dp->d_name[1] == '.' && dp->d_name[2] == '\0')
 				continue;
-		}
-		if (TSTINO(dp->d_ino, dumpinomap)) {
-			ret |= HASDUMPEDFILE;
-			if (ret & HASSUBDIRS)
-				break;
 		}
-		if (TSTINO(dp->d_ino, dumpdirmap)) {
-			ret |= HASSUBDIRS;
-			if (ret & HASDUMPEDFILE)
-				break;
+		if (nodump) {
+			ip = getino(dp->d_ino);
+			if (TSTINO(dp->d_ino, dumpinomap)) {
+				CLRINO(dp->d_ino, dumpinomap);
+				CLRINO(dp->d_ino, usedinomap);
+				*tapesize -= blockest(ip);
+			}
+			/* Add dir back to the dir map, to propagate nodump */
+			if ((ip->di_mode & IFMT) == IFDIR) {
+				SETINO(dp->d_ino, dumpdirmap);
+				ret |= HASSUBDIRS;
+			}
+		} else {
+			if (TSTINO(dp->d_ino, dumpinomap)) {
+				ret |= HASDUMPEDFILE;
+				if (ret & HASSUBDIRS)
+					break;
+			}
+			if (TSTINO(dp->d_ino, dumpdirmap)) {
+				ret |= HASSUBDIRS;
+				if (ret & HASDUMPEDFILE)
+					break;
+			}
 		}
 	}
 	return (ret);