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