summaryrefslogtreecommitdiff
path: root/fs/fuse
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2019-01-16 12:27:59 +0300
committerMiklos Szeredi <mszeredi@redhat.com>2019-02-13 15:15:12 +0300
commit7f305ca1928d8b7db69f428b10988a3aa3e81053 (patch)
tree1bf72aa67967f9282c4e51b0babb1c3383475f93 /fs/fuse
parent2fe93bd43264242e4568763d1b183b1cc58066ff (diff)
downloadlinux-7f305ca1928d8b7db69f428b10988a3aa3e81053.tar.xz
fuse: clean up fuse_writepage_in_flight()
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>
Diffstat (limited to 'fs/fuse')
-rw-r--r--fs/fuse/file.c40
1 files changed, 24 insertions, 16 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 927d40dec376..8342df29815d 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -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;
}