fuse: only reuse auxiliary request in fuse_writepage_in_flight()
authorMiklos Szeredi <mszeredi@redhat.com>
Wed, 16 Jan 2019 09:27:59 +0000 (10:27 +0100)
committerMiklos Szeredi <mszeredi@redhat.com>
Wed, 13 Feb 2019 12:15:12 +0000 (13:15 +0100)
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>
fs/fuse/file.c

index 8342df2..b0c32a7 100644 (file)
@@ -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;
                }