fuse: clean up 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)
Restructure the function to better separate the locked and the unlocked
parts.  Use the "old_req" local variable to mean only the queued request,
and not any auxiliary requests added onto its misc.write.next list.  These
changes are in preparation for the following patch.

Also turn BUG_ON instances into WARN_ON and add a header comment explaining
what the function does.

Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/fuse/file.c

index 927d40d..8342df2 100644 (file)
@@ -1744,6 +1744,13 @@ static void fuse_writepages_send(struct fuse_fill_wb_data *data)
                end_page_writeback(data->orig_pages[i]);
 }
 
+/*
+ * 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
+ * copying the new page contents over to the old temporary page.
+ */
 static bool fuse_writepage_in_flight(struct fuse_req *new_req,
                                     struct page *page)
 {
@@ -1751,9 +1758,8 @@ static bool fuse_writepage_in_flight(struct fuse_req *new_req,
        struct fuse_inode *fi = get_fuse_inode(new_req->inode);
        struct fuse_req *tmp;
        struct fuse_req *old_req;
-       pgoff_t curr_index;
 
-       BUG_ON(new_req->num_pages != 0);
+       WARN_ON(new_req->num_pages != 0);
 
        spin_lock(&fc->lock);
        list_del(&new_req->writepages_entry);
@@ -1766,32 +1772,34 @@ 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) {
-               BUG_ON(tmp->inode != new_req->inode);
+               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) {
-                       old_req = tmp;
+               if (tmp->num_pages == 1 && curr_index == page->index &&
+                   test_bit(FR_PENDING, &tmp->flags)) {
+                       copy_highpage(tmp->pages[0], page);
+                       break;
                }
        }
 
-       if (old_req->num_pages == 1 && test_bit(FR_PENDING, &old_req->flags)) {
-               struct backing_dev_info *bdi = inode_to_bdi(page->mapping->host);
+       if (!tmp) {
+               new_req->misc.write.next = old_req->misc.write.next;
+               old_req->misc.write.next = new_req;
+       }
 
-               copy_highpage(old_req->pages[0], page);
-               spin_unlock(&fc->lock);
+       spin_unlock(&fc->lock);
+
+       if (tmp) {
+               struct backing_dev_info *bdi = inode_to_bdi(new_req->inode);
 
                dec_wb_stat(&bdi->wb, WB_WRITEBACK);
                dec_node_page_state(new_req->pages[0], NR_WRITEBACK_TEMP);
                wb_writeout_inc(&bdi->wb);
                fuse_writepage_free(fc, new_req);
                fuse_request_free(new_req);
-               goto out;
-       } else {
-               new_req->misc.write.next = old_req->misc.write.next;
-               old_req->misc.write.next = new_req;
        }
-       spin_unlock(&fc->lock);
-out:
+
        return true;
 }