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 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) _______________________________________________ Devel mailing list [email protected] https://lists.openvz.org/mailman/listinfo/devel
