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 <[email protected]>
---
 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 1bbad4798f0b..28e6b3c1aa06 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1242,6 +1242,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]);
@@ -1254,7 +1259,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;
@@ -1262,7 +1266,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;
 
        /*
@@ -1274,19 +1285,15 @@ static void fuse_readpages_end(struct fuse_mount *fm, 
struct fuse_args *args,
        for (i = 0; i < ap->num_pages; i++) {
                struct folio *folio = page_folio(ap->pages[i]);
 
-               if (likely(!killed))
+               if (likely(!args->killed))
                        folio_end_read(folio, !err);
                folio_put(folio);
        }
        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)

_______________________________________________
Devel mailing list
[email protected]
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to