BACKPORT: FROMLIST: ovl: fix wrong use of impure dir cache in ovl_iterate()

Only upper dir can be impure, but if we are in the middle of
iterating a lower real dir, dir could be copied up and marked
impure. We only want the impure cache if we started iterating
a real upper dir to begin with.

Aditya Kali reported that the following reproducer hits the
WARN_ON(!cache->refcount) in ovl_get_cache():

 docker run --rm drupal:8.5.4-fpm-alpine \
    sh -c 'cd /var/www/html/vendor/symfony && \
           chown -R www-data:www-data . && ls -l .'

Reported-by: Aditya Kali <adityakali@xxxxxxxxxx>
Tested-by: Aditya Kali <adityakali@xxxxxxxxxx>
Fixes: 4edb83bb1041 ('ovl: constant d_ino for non-merge dirs')
Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx>

(am from https://www.spinics.net/lists/linux-unionfs/msg05418.html)

Conflicts:
	fs/overlayfs/readdir.c
(Dropped the "xino" related comment as it is not supported in
 our kernel)

BUG=b:111060505
TEST=trybots, manual testing using repro
Change-Id: Icc1e357c636d41365f325d078913b01be2ef72e1
Reviewed-on: https://chromium-review.googlesource.com/1149330
Commit-Ready: ChromeOS CL Exonerator Bot <[email protected]>
Tested-by: Aditya Kali <[email protected]>
Reviewed-by: Guenter Roeck <[email protected]>
(cherry picked from commit 0b4c9a7d4c4889a75f1dfdc3d2b15256704a8257)
Reviewed-on: https://chromium-review.googlesource.com/1162283
Commit-Queue: Aditya Kali <[email protected]>
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index 7fa7d68..1f97108 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -646,7 +646,13 @@ static int ovl_iterate_real(struct file *file, struct dir_context *ctx)
 		rdt.parent_ino = stat.ino;
 	}
 
-	if (ovl_test_flag(OVL_IMPURE, d_inode(dir))) {
+	/*
+	 * Only upper dir can be impure, but if we are in the middle of
+	 * iterating a lower real dir, dir could be copied up and marked
+	 * impure. We only want the impure cache if we started iterating
+	 * a real upper dir to begin with.
+	 */
+	if (od->is_upper && ovl_test_flag(OVL_IMPURE, d_inode(dir))) {
 		rdt.cache = ovl_cache_get_impure(&file->f_path);
 		if (IS_ERR(rdt.cache))
 			return PTR_ERR(rdt.cache);
@@ -671,13 +677,14 @@ static int ovl_iterate(struct file *file, struct dir_context *ctx)
 
 	if (od->is_real) {
 		/*
-		 * If parent is merge, then need to adjust d_ino for '..', if
-		 * dir is impure then need to adjust d_ino for copied up
-		 * entries.
+		 * If parent is merge, then need to adjust d_ino for '..'.
+		 * If dir is upper and impure then need to adjust d_ino for
+		 * copied up entries.
 		 */
 		if (ovl_same_sb(dentry->d_sb) &&
-		    (ovl_test_flag(OVL_IMPURE, d_inode(dentry)) ||
-		     OVL_TYPE_MERGE(ovl_path_type(dentry->d_parent)))) {
+		    (OVL_TYPE_MERGE(ovl_path_type(dentry->d_parent)) ||
+		     (od->is_upper &&
+		      ovl_test_flag(OVL_IMPURE, d_inode(dentry))))) {
 			return ovl_iterate_real(file, ctx);
 		}
 		return iterate_dir(od->realfile, ctx);