--- /dev/null
+From 8c5066aea7ef112b37ccce2cc0521124c4442abb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 20 Oct 2022 17:18:58 +0200
+Subject: fuse: fix readdir cache race
+
+From: Miklos Szeredi <mszeredi@redhat.com>
+
+[ Upstream commit 9fa248c65bdbf5af0a2f74dd38575acfc8dfd2bf ]
+
+There's a race in fuse's readdir cache that can result in an uninitilized
+page being read. The page lock is supposed to prevent this from happening
+but in the following case it doesn't:
+
+Two fuse_add_dirent_to_cache() start out and get the same parameters
+(size=0,offset=0). One of them wins the race to create and lock the page,
+after which it fills in data, sets rdc.size and unlocks the page.
+
+In the meantime the page gets evicted from the cache before the other
+instance gets to run. That one also creates the page, but finds the
+size to be mismatched, bails out and leaves the uninitialized page in the
+cache.
+
+Fix by marking a filled page uptodate and ignoring non-uptodate pages.
+
+Reported-by: Frank Sorenson <fsorenso@redhat.com>
+Fixes: 5d7bc7e8680c ("fuse: allow using readdir cache")
+Cc: <stable@vger.kernel.org> # v4.20
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/fuse/readdir.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c
+index bc267832310c..d5294e663df5 100644
+--- a/fs/fuse/readdir.c
++++ b/fs/fuse/readdir.c
+@@ -77,8 +77,10 @@ static void fuse_add_dirent_to_cache(struct file *file,
+ goto unlock;
+
+ addr = kmap_atomic(page);
+- if (!offset)
++ if (!offset) {
+ clear_page(addr);
++ SetPageUptodate(page);
++ }
+ memcpy(addr + offset, dirent, reclen);
+ kunmap_atomic(addr);
+ fi->rdc.size = (index << PAGE_SHIFT) + offset + reclen;
+@@ -516,6 +518,12 @@ static int fuse_readdir_cached(struct file *file, struct dir_context *ctx)
+
+ page = find_get_page_flags(file->f_mapping, index,
+ FGP_ACCESSED | FGP_LOCK);
++ /* Page gone missing, then re-added to cache, but not initialized? */
++ if (page && !PageUptodate(page)) {
++ unlock_page(page);
++ put_page(page);
++ page = NULL;
++ }
+ spin_lock(&fi->rdc.lock);
+ if (!page) {
+ /*
+--
+2.35.1
+