Mass of debugging printks
diff --git a/fs/namei.c b/fs/namei.c
index 6128593..e2dba6f 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1276,6 +1276,8 @@
 	unsigned i, layers = parent.dentry->d_sb->s_union_count;
 	int err;
 
+	printk("UNION: __lookup %s\n", name->name);
+
 	if (!topmost->dentry->d_inode) {
 		if (d_is_whiteout(topmost->dentry))
 			return 0;
@@ -1289,6 +1291,8 @@
 	    !S_ISDIR(topmost->dentry->d_inode->i_mode))
 		return 0;
 
+	printk("UNION: __lookup 2\n");
+
 	/* At this point we have either a negative fallthru dentry or we have a
 	 * positive directory dentry.
 	 *
@@ -1342,6 +1346,8 @@
 			goto out_found_lower_file;
 		}
 
+		printk("UNION: is dir\n");
+
 		/* Mountpoints and automount points on a lowerfs just confuse
 		 * everything, so refuse to handle them for the moment.
 		 */
@@ -1358,6 +1364,7 @@
 		 * directory.
 		 */
 		if (!topmost->dentry->d_inode) {
+			printk("UNION: create top\n");
 			err = union_create_topmost_dir(&parent, name, topmost,
 						       &lower);
 			if (err)
@@ -1371,6 +1378,7 @@
 	return 0;
 
 out_found_lower_file:
+	printk("UNION: __lookup found lower file\n");
 	dput(topmost->dentry);
 	*topmost = lower;
 	return 0;
@@ -1439,6 +1447,8 @@
 	struct inode *dir = parent->d_inode;
 	int err;
 
+	printk("UNION: lookup %s\n", name->name);
+
 	mutex_lock(&dir->i_mutex);
 	err = lookup_union_locked(nd, name, topmost);
 	mutex_unlock(&dir->i_mutex);
@@ -1487,6 +1497,8 @@
 	if (!IS_DIR_UNIONED(parent))
 		return true;
 
+	printk("UNION: Dir is unioned (RCU)\n");
+
 	/* If it's positive then no further lookup is needed: the file or
 	 * directory has been copied up and the user gets to play with that.
 	 */
@@ -1504,8 +1516,10 @@
 	 * the top layer of the union (copied up) immediately, that will
 	 * require a mutex.
 	 */
-	if (nd->flags & LOOKUP_COPY_UP)
+	if (nd->flags & LOOKUP_COPY_UP) {
+		printk("Must copy up %s\n", dentry->d_name.name);
 		return false;
+	}
 
 	/* At this point we have a negative dentry in the unionmount that may
 	 * be overlaying a non-directory file in a lower filesystem, so we loop
@@ -1557,8 +1571,10 @@
 		/* If the lower dentry is a directory then it will need copying
 		 * up before we can make use of it.
 		 */
-		if (S_ISDIR((*inode)->i_mode))
+		if (S_ISDIR((*inode)->i_mode)) {
+			printk("UNION: Need copyup\n");
 			return false;
+		}
 
 		/* There is a file in a lower fs that we can use */
 		if (read_seqcount_retry(&lower_dir->d_seq, ldseq) ||
@@ -1667,6 +1683,9 @@
 	int status = 1;
 	int err;
 
+	if (IS_DIR_UNIONED(parent))
+		printk("UNION: --> lookup_fast(%s)\n", nd->last.name);
+
 	/*
 	 * Rename seqlock is not required here because in the off chance
 	 * of a false negative due to a concurrent rename, we're going to
@@ -1716,9 +1735,13 @@
 			goto unlazy;
 		return 0;
 unlazy:
+		if (IS_DIR_UNIONED(parent))
+			printk("UNION: unlazy\n");
 		if (unlazy_walk(nd, dentry))
 			return -ECHILD;
 	} else {
+		if (IS_DIR_UNIONED(parent))
+			printk("UNION: !RCU\n");
 		dentry = __d_lookup(parent, &nd->last);
 	}
 
@@ -1749,7 +1772,9 @@
 		nd->flags |= LOOKUP_JUMPED;
 
 	if (needs_lookup_union(nd, &nd->path, path)) {
-		int err = lookup_union(nd, &nd->last, path);
+		int err;
+		printk("UNION: Fast need lookup\n");
+		err = lookup_union(nd, &nd->last, path);
 		if (err < 0)
 			return err;
 	}
@@ -1758,6 +1783,8 @@
 	return 0;
 
 need_lookup:
+	if (IS_DIR_UNIONED(parent))
+		printk("UNION: need_lookup\n");
 	return 1;
 }
 
@@ -1770,9 +1797,16 @@
 	parent = nd->path.dentry;
 	BUG_ON(nd->inode != parent->d_inode);
 
+	if (IS_DIR_UNIONED(parent))
+		printk("UNION: --> lookup_slow(%s)\n", nd->last.name);
+
 	mutex_lock(&parent->d_inode->i_mutex);
 	dentry = __lookup_hash(&nd->last, parent, nd->flags);
 	mutex_unlock(&parent->d_inode->i_mutex);
+
+	if (IS_DIR_UNIONED(parent))
+		printk("UNION: --> slow: __lookup_hash() = %p\n", dentry);
+
 	if (IS_ERR(dentry))
 		return PTR_ERR(dentry);
 	path->mnt = nd->path.mnt;
@@ -1785,6 +1819,7 @@
 	if (err)
 		nd->flags |= LOOKUP_JUMPED;
 	if (needs_lookup_union(nd, &nd->path, path)) {
+		printk("UNION: Slow need lookup\n");
 		err = lookup_union(nd, &nd->last, path);
 		if (err < 0) {
 			path_put_conditional(path, nd);
@@ -1855,6 +1890,10 @@
 {
 	struct inode *inode;
 	int err;
+
+	if (IS_DIR_UNIONED(nd->path.dentry))
+		printk("UNION: --> walk_component(%s)\n", nd->last.name);
+
 	/*
 	 * "." and ".." are special - ".." especially so because it has
 	 * to be able to know about the current root directory and
@@ -1873,6 +1912,9 @@
 
 		inode = path->dentry->d_inode;
 	}
+
+	if (IS_DIR_UNIONED(nd->path.dentry))
+		printk("UNION: --> walk: looked up\n");
 	err = -ENOENT;
 	if (!inode)
 		goto out_path_put;
@@ -2265,6 +2307,9 @@
 	struct inode *inode;
 	int err;
 
+	if (IS_DIR_UNIONED(nd->path.dentry))
+		printk("UNION: --> walk_last_component(%s)\n", nd->last.name);
+
 	/* "." and ".." are special - ".." especially so because it has
 	 * to be able to know about the current root directory and
 	 * parent relationships.
@@ -2281,6 +2326,15 @@
 		inode = path->dentry->d_inode;
 	}
 
+	if (IS_MNT_UNION(nd->path.mnt))
+		printk("UNION: walk_last_comp: nd->path.mnt UPPER\n");
+	if (IS_MNT_LOWER(nd->path.mnt))
+		printk("UNION: walk_last_comp: nd->path.mnt LOWER\n");
+	if (IS_MNT_UNION(path->mnt))
+		printk("UNION: walk_last_comp: path->mnt UPPER\n");
+	if (IS_MNT_LOWER(path->mnt))
+		printk("UNION: walk_last_comp: path->mnt LOWER\n");
+
 	err = -ENOENT;
 	if (!inode)
 		goto out_path_put;
@@ -2298,6 +2352,7 @@
 
 	if (nd->flags & LOOKUP_COPY_UP && IS_MNT_LOWER(path->mnt)) {
 		BUG_ON(S_ISDIR(inode->i_mode));
+		printk("UNION: walk_last_comp: Need to copy up\n");
 		if (nd->flags & LOOKUP_RCU &&
 		    unlikely(unlazy_walk(nd, path->dentry))) {
 			err = -ECHILD;
@@ -2315,6 +2370,12 @@
 		if (err)
 			goto out_path_put;
 
+		if (path->mnt != nd->path.mnt)
+			printk("UNION: !!! mnt not changed by copyup\n");
+
+		printk("UNION: walk_last_comp: copied up lower\n");
+		BUG_ON(path->mnt != nd->path.mnt);
+
 		inode = path->dentry->d_inode;
 		err = -ENOENT;
 		if (!inode)
@@ -2391,6 +2452,17 @@
 			err = lookup_last(nd, &terminal_symlink);
 			put_link(nd, &link, cookie);
 		}
+
+		if (!err) {
+			if (!nd)
+				printk("UNION: path_lookupat: !nd\n");
+			else if (!nd->path.mnt)
+				printk("UNION: path_lookupat: !nd->path.mnt\n");
+			else if (IS_MNT_UNION(nd->path.mnt))
+				printk("UNION: path_lookupat: nd->path.mnt UPPER\n");
+			else if (IS_MNT_LOWER(nd->path.mnt))
+				printk("UNION: path_lookupat: nd->path.mnt LOWER\n");
+		}
 	}
 
 	if (!err)
@@ -3100,6 +3172,11 @@
 
 	BUG_ON(dentry->d_inode);
 
+	if (IS_DIR_UNIONED(nd->path.dentry))
+		printk("UNION: --> atomic_open(%s)\n", nd->last.name);
+	if (IS_MNT_UNION(nd->path.mnt))
+		printk("UNION: --> atomic_open(UNIONED)\n");
+
 	/* Don't create child dentry for a dead directory. */
 	if (unlikely(IS_DEADDIR(dir))) {
 		error = -ENOENT;
@@ -3261,11 +3338,22 @@
 	int error;
 	bool need_lookup;
 
+	if (IS_DIR_UNIONED(dir))
+		printk("UNION: --> lookup_open(%s)\n", nd->last.name);
+	if (IS_MNT_UNION(nd->path.mnt))
+		printk("UNION: --> lookup_open(UNIONED)\n");
+	if (IS_MNT_LOWER(nd->path.mnt))
+		printk("UNION: --> lookup_open(LOWER)\n");
+
 	*opened &= ~FILE_CREATED;
 	dentry = lookup_dcache(&nd->last, dir, nd->flags, &need_lookup);
 	if (IS_ERR(dentry))
 		return PTR_ERR(dentry);
 
+	if (IS_DIR_UNIONED(dir))
+		printk("UNION: lookup_dcache() = %p [%p]\n",
+		       dentry, dentry ? dentry->d_inode : NULL);
+
 	/* Cached positive dentry: will open in f_op->open */
 	if (!need_lookup && dentry->d_inode)
 		goto out_no_open;
@@ -3275,14 +3363,21 @@
 	 */
 	if ((nd->flags & LOOKUP_OPEN) && dir_inode->i_op->atomic_open &&
 	    !(IS_MNT_UNION(nd->path.mnt) &&
-	      op->acc_mode & (MAY_WRITE | MAY_APPEND)))
+	      op->acc_mode & (MAY_WRITE | MAY_APPEND))) {
+		if (IS_DIR_UNIONED(dir))
+			printk("UNION: open atomic\n");
 		return atomic_open(nd, dentry, path, file, op, got_write,
 				   need_lookup, opened);
+	}
 
+	if (IS_DIR_UNIONED(dir))
+		printk("UNION: don't open atomic\n");
 	if (need_lookup) {
 		BUG_ON(dentry->d_inode);
 
 		dentry = lookup_real(dir_inode, dentry, nd->flags);
+		if (IS_DIR_UNIONED(dir))
+			printk("UNION: lookup_real() = %p\n", dentry);
 		if (IS_ERR(dentry))
 			return PTR_ERR(dentry);
 	}
@@ -3327,6 +3422,10 @@
 		if (IS_MNT_UNION(nd->path.mnt)) {
 			struct path topmost;
 
+			printk("UNION: %p/%p\n", dir->d_sb, dentry->d_sb);
+
+			printk("UNION: deal with O_CREAT\n");
+
 			if (d_is_whiteout(dentry) ||
 			    (IS_OPAQUE(dir_inode) && !d_is_fallthru(dentry)))
 				goto just_create; /* Lower is blocked off */
@@ -3344,9 +3443,11 @@
 
 			if (topmost.mnt != nd->path.mnt) {
 				/* Moved down. */
+				printk("UNION: found lower (ignore O_CREAT)\n");
 				BUG_ON(!IS_MNT_LOWER(topmost.mnt));
 				BUG_ON(!topmost.dentry->d_inode);
 				*path = topmost;
+				printk("UNION: looked up lower (O_CREAT ignored)\n");
 				return 1;
 			}
 			BUG_ON(topmost.dentry != dentry);
@@ -3365,6 +3466,8 @@
 		/* The file does not exist in the top layer of a union - but it
 		 * might exist in a lower layer.
 		 */
+		printk("UNION: %p/%p\n", dir->d_sb, dentry->d_sb);
+
 		if (d_is_whiteout(dentry) ||
 		    (IS_OPAQUE(dir_inode) && !d_is_fallthru(dentry)))
 			goto out_no_open; /* Lower is blocked off */
@@ -3375,10 +3478,14 @@
 		error = __lookup_union(nd, &dentry->d_name, path);
 		if (error)
 			goto out_dput;
+
+		printk("UNION: looked up lower\n");
 		return 1;
 	}
 
 out_no_open:
+	if (IS_DIR_UNIONED(dir))
+		printk("UNION: out_no_open\n");
 	path->dentry = dentry;
 	path->mnt = nd->path.mnt;
 	return 1;
@@ -3406,6 +3513,13 @@
 	bool retried = false;
 	int error;
 
+	if (IS_DIR_UNIONED(dir))
+		printk("UNION: --> do_last()\n");
+	if (IS_MNT_LOWER(nd->path.mnt))
+		printk("UNION: do_last: nd->path.mnt at lower\n");
+	else if (IS_MNT_UNION(nd->path.mnt))
+		printk("UNION: do_last: nd->path.mnt at union\n");
+
 	nd->flags &= ~LOOKUP_PARENT;
 	nd->flags |= op->intent;
 
@@ -3423,8 +3537,13 @@
 			symlink_ok = true;
 		/* we _can_ be in RCU mode here */
 		error = lookup_fast(nd, path, &inode);
-		if (likely(!error))
+		if (likely(!error)) {
+			if (IS_MNT_LOWER(path->mnt))
+				printk("lookup_fast -> at lower\n");
+			if (IS_DIR_UNIONED(nd->path.dentry))
+				printk("UNION: --> do_last: goto finish_lookup\n");
 			goto finish_lookup;
+		}
 
 		if (error < 0)
 			goto out;
@@ -3451,8 +3570,11 @@
 retry_lookup:
 	if (op->open_flag & (O_CREAT | O_TRUNC | O_WRONLY | O_RDWR)) {
 		error = mnt_want_write(nd->path.mnt);
-		if (!error)
+		if (!error) {
+			if (IS_DIR_UNIONED(nd->path.dentry))
+				printk("UNION: got_write = true\n");
 			got_write = true;
+		}
 		/*
 		 * do _not_ fail yet - we might not need that or fail with
 		 * a different error; let lookup_open() decide; we'll be
@@ -3463,6 +3585,8 @@
 	error = lookup_open(nd, path, file, op, got_write, opened);
 	mutex_unlock(&dir->d_inode->i_mutex);
 
+	if (IS_DIR_UNIONED(nd->path.dentry))
+		printk("UNION: lookup_open() = %d\n", error);
 	if (error <= 0) {
 		if (error)
 			goto out;
@@ -3510,8 +3634,11 @@
 	}
 
 	error = -EEXIST;
-	if ((open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT))
+	if ((open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT)) {
+		if (IS_DIR_UNIONED(nd->path.dentry))
+			printk("UNION: created, but O_EXCL\n");
 		goto exit_dput;
+	}
 
 	if (IS_MNT_LOWER(path->mnt) && d_managed(path->dentry)) {
 		error = -EREMOTE;
@@ -3519,8 +3646,11 @@
 	}
 
 	error = follow_managed(path, nd->flags);
-	if (error < 0)
+	if (error < 0) {
+		if (IS_DIR_UNIONED(nd->path.dentry))
+			printk("UNION: follow_managed() = %d\n", error);
 		goto exit_dput;
+	}
 
 	if (error)
 		nd->flags |= LOOKUP_JUMPED;
@@ -3528,6 +3658,14 @@
 	BUG_ON(nd->flags & LOOKUP_RCU);
 	inode = path->dentry->d_inode;
 finish_lookup:
+	if (IS_MNT_LOWER(path->mnt))
+		printk("UNION: do_last: finish_lookup: at lower\n");
+	if (IS_MNT_UNION(path->mnt))
+		printk("UNION: do_last: finish_lookup: at upper\n");
+	if (IS_MNT_LOWER(nd->path.mnt))
+		printk("UNION: do_last: nd->path.mnt at lower\n");
+	else if (IS_MNT_UNION(nd->path.mnt))
+		printk("UNION: do_last: nd->path.mnt at upper\n");
 	/* we _can_ be in RCU mode here */
 	BUG_ON(IS_MNT_LOWER(path->mnt) &&
 	       (d_is_whiteout(path->dentry) ||
@@ -3540,6 +3678,8 @@
 	}
 
 	if (should_follow_link(inode, !symlink_ok)) {
+		if (IS_DIR_UNIONED(dir))
+			printk("UNION: should_follow_link() -> true\n");
 		if (nd->flags & LOOKUP_RCU) {
 			if (unlikely(unlazy_walk(nd, path->dentry))) {
 				error = -ECHILD;
@@ -3555,6 +3695,7 @@
 	if (IS_MNT_LOWER(path->mnt) &&
 	    nd->flags & LOOKUP_COPY_UP &&
 	    S_ISREG(inode->i_mode)) {
+		printk("UNION: Need to copy up\n");
 		if (nd->flags & LOOKUP_RCU &&
 		    unlikely(unlazy_walk(nd, path->dentry))) {
 			path_to_nameidata(path, nd);
@@ -3577,6 +3718,10 @@
 		if (error)
 			goto exit_dput;
 
+		if (path->mnt != nd->path.mnt)
+			printk("UNION: !!! mnt not changed by copyup\n");
+
+		printk("UNION: copied up lower\n");
 		BUG_ON(path->mnt != nd->path.mnt);
 
 		inode = path->dentry->d_inode;
@@ -3592,8 +3737,16 @@
 	}
 
 	if ((nd->flags & LOOKUP_RCU) || nd->path.mnt != path->mnt) {
+		if (IS_DIR_UNIONED(dir)) {
+			if (nd->flags & LOOKUP_RCU)
+				printk("UNION: in rcu mode\n");
+			if (nd->path.mnt != path->mnt)
+				printk("UNION: nd->path.mnt != path->mnt\n");
+		}
 		path_to_nameidata(path, nd);
 	} else {
+		if (IS_DIR_UNIONED(dir))
+			printk("UNION: not in rcu mode\n");
 		save_parent.dentry = nd->path.dentry;
 		save_parent.mnt = mntget(path->mnt);
 		nd->path.dentry = path->dentry;
@@ -3602,7 +3755,11 @@
 	nd->inode = inode;
 	/* Why this, you ask?  _Now_ we might have grown LOOKUP_JUMPED... */
 finish_open:
+	if (IS_DIR_UNIONED(dir))
+		printk("UNION: --> complete_walk()\n");
 	error = complete_walk(nd);
+	if (IS_DIR_UNIONED(dir))
+		printk("UNION: <-- complete_walk()\n");
 	if (error) {
 		path_put(&save_parent);
 		return error;
diff --git a/fs/namespace.c b/fs/namespace.c
index 47888e6..8915d2a 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1686,6 +1686,8 @@
 	if (d_unlinked(mntpnt->dentry))
 		return -ENOENT;
 
+	printk("UNION: prepare\n");
+
 	err = check_topmost_union_mnt(topmost_mnt, topmost_mnt->mnt.mnt_flags);
 	if (err)
 		return err;
@@ -1697,6 +1699,8 @@
 	err = build_root_union(topmost_mnt);
 	if (err)
 		goto out;
+
+	printk("UNION: prepared\n");
 	return 0;
 
 out:
diff --git a/fs/open.c b/fs/open.c
index dcdf292..c03de97 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -71,6 +71,15 @@
 
 	inode = path->dentry->d_inode;
 
+	if (IS_MNT_LOWER(path->mnt))
+		printk("UNION: truncate: path.mnt: at lower\n");
+	if (IS_MNT_UNION(path->mnt))
+		printk("UNION: truncate: path.mnt: at upper\n");
+	if (parent && IS_MNT_LOWER(parent->mnt))
+		printk("UNION: truncate: parent.mnt at lower\n");
+	if (parent && IS_MNT_UNION(parent->mnt))
+		printk("UNION: truncate: parent.mnt at upper\n");
+
 	/* For directories it's -EISDIR, for other non-regulars - -EINVAL */
 	if (S_ISDIR(inode->i_mode))
 		return -EISDIR;
diff --git a/fs/union.c b/fs/union.c
index 888c475..cfeb65f 100644
--- a/fs/union.c
+++ b/fs/union.c
@@ -569,6 +569,9 @@
 	struct path to;
 	int error;
 
+	printk("-->union_copyup_file(,%s,%s,%zu)\n",
+	       lower->dentry->d_name.name, dentry->d_name.name, len);
+
 	BUG_ON(!mutex_is_locked(&parent->dentry->d_inode->i_mutex));
 
 	override_cred = prepare_kernel_cred(NULL);
@@ -605,6 +608,7 @@
 out:
 	revert_creds(saved_cred);
 	put_cred(override_cred);
+	printk("<--union_copyup_file() = %d\n", error);
 	return error;
 }
 
diff --git a/fs/union.h b/fs/union.h
index beef9b6..3ff82ae 100644
--- a/fs/union.h
+++ b/fs/union.h
@@ -90,6 +90,8 @@
 	if (!IS_DIR_UNIONED(parent_path->dentry))
 		return false;
 
+	printk("UNION: is unioned\n");
+
 	/* Either already built or crossed a mountpoint to not-unioned mnt */
 	/* XXX are bind mounts root? think not */
 	if (IS_ROOT(path->dentry))