[Devel] [PATCH VZ9 1/2] fs/fuse kio: remove request from revoke list before unlocking pages

Liu Kui kui.liu at virtuozzo.com
Tue Dec 16 12:25:44 MSK 2025


The read request must be removed from the revoke list before unlocking
the pages. Otherwise, fuse_invalidate_file() could incorrectly unlock
the pages if another process has locked them in the meantime.

Also add a sanity check in fuse_revoke_readpages() to catch unexpected
conditions.

https://virtuozzo.atlassian.net/browse/VSTOR-120919

Signed-off-by: Liu Kui <kui.liu at virtuozzo.com>
---
 fs/fuse/file.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index baefef99df32..b59dacd29a6a 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1220,6 +1220,11 @@ void fuse_revoke_readpages(struct fuse_file *ff)
 	spin_lock(&ff->lock);
 	/* revoke all pending read issued from page cache */
 	list_for_each_entry(ia, &ff->revoke_list, revoke_entry) {
+		/* this should never happen unless userspace misbehaves */
+		if (unlikely(ia->ap.args.killed)) {
+			WARN_ON_ONCE(1);
+			continue;
+		}
 		ia->ap.args.killed = 1;
 		for (i = 0; i < ia->ap.num_pages; i++)
 			unlock_page(ia->ap.pages[i]);
@@ -1232,7 +1237,6 @@ static void fuse_readpages_end(struct fuse_mount *fm, struct fuse_args *args,
 			       int err)
 {
 	int i;
-	bool killed = args->killed;
 	struct fuse_io_args *ia = container_of(args, typeof(*ia), ap.args);
 	struct fuse_args_pages *ap = &ia->ap;
 	size_t count = ia->read.in.size;
@@ -1240,7 +1244,14 @@ static void fuse_readpages_end(struct fuse_mount *fm, struct fuse_args *args,
 	struct inode *inode = args->io_inode;
 	struct fuse_file *ff = ia->ff;
 
-	if (unlikely(killed))
+	/* remove request from revoke list first */
+	if (ff) {
+		spin_lock(&ff->lock);
+		list_del(&ia->revoke_entry);
+		spin_unlock(&ff->lock);
+	}
+
+	if (unlikely(args->killed))
 		err = -EIO;
 
 	/*
@@ -1252,7 +1263,7 @@ static void fuse_readpages_end(struct fuse_mount *fm, struct fuse_args *args,
 	for (i = 0; i < ap->num_pages; i++) {
 		struct page *page = ap->pages[i];
 
-		if (likely(!killed)) {
+		if (likely(!args->killed)) {
 			if (!err)
 				SetPageUptodate(page);
 			else
@@ -1263,13 +1274,9 @@ static void fuse_readpages_end(struct fuse_mount *fm, struct fuse_args *args,
 	}
 	fuse_invalidate_atime(inode);
 
-	if (ff) {
-		spin_lock(&ff->lock);
-		list_del(&ia->revoke_entry);
-		spin_unlock(&ff->lock);
-
+	if (ff)
 		fuse_release_ff(inode, ff);
-	}
+
 	fuse_io_free(ia);
 }
 
-- 
2.39.5 (Apple Git-154)



More information about the Devel mailing list