summaryrefslogtreecommitdiff
path: root/fs/fuse/file.c
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2019-01-16 10:27:59 +0100
committerMiklos Szeredi <mszeredi@redhat.com>2019-02-13 13:15:12 +0100
commit419234d5958b8ec4f5e2ba8ed2e77916f844ded1 (patch)
tree5a51921ecdd67b542c8cc49653c3adb7e835596c /fs/fuse/file.c
parent7f305ca1928d8b7db69f428b10988a3aa3e81053 (diff)
fuse: only reuse auxiliary request in fuse_writepage_in_flight()
Don't reuse the queued request, even if it only contains a single page. This is needed because previous locking changes (spliting out fiq->waitq.lock from fc->lock) broke the assumption that request will remain in FR_PENDING at least until the new page contents are copied. This fix removes a slight optimization for a rare corner case, so we really shoudln't care. Reported-by: Kirill Tkhai <ktkhai@virtuozzo.com> Fixes: fd22d62ed0c3 ("fuse: no fc->lock for iqueue parts") Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to 'fs/fuse/file.c')
-rw-r--r--fs/fuse/file.c13
1 files changed, 7 insertions, 6 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 8342df29815d..b0c32a74082f 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1746,9 +1746,9 @@ static void fuse_writepages_send(struct fuse_fill_wb_data *data)
/*
* First recheck under fi->lock if the offending offset is still under
- * writeback. If yes, then iterate write requests, to see if there's one
- * already added for a page at this offset. If there's none, then insert this
- * new request onto the auxiliary list, otherwise reuse the existing one by
+ * writeback. If yes, then iterate auxiliary write requests, to see if there's
+ * one already added for a page at this offset. If there's none, then insert
+ * this new request onto the auxiliary list, otherwise reuse the existing one by
* copying the new page contents over to the old temporary page.
*/
static bool fuse_writepage_in_flight(struct fuse_req *new_req,
@@ -1771,13 +1771,14 @@ static bool fuse_writepage_in_flight(struct fuse_req *new_req,
}
new_req->num_pages = 1;
- for (tmp = old_req; tmp != NULL; tmp = tmp->misc.write.next) {
+ for (tmp = old_req->misc.write.next; tmp; tmp = tmp->misc.write.next) {
pgoff_t curr_index;
WARN_ON(tmp->inode != new_req->inode);
curr_index = tmp->misc.write.in.offset >> PAGE_SHIFT;
- if (tmp->num_pages == 1 && curr_index == page->index &&
- test_bit(FR_PENDING, &tmp->flags)) {
+ if (curr_index == page->index) {
+ WARN_ON(tmp->num_pages != 1);
+ WARN_ON(!test_bit(FR_PENDING, &tmp->flags));
copy_highpage(tmp->pages[0], page);
break;
}