aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/fuse/file.c100
-rw-r--r--fs/fuse/fuse_i.h1
2 files changed, 91 insertions, 10 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index bf765cf7b112..f8ff019cc6ec 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1414,7 +1414,9 @@ static void fuse_writepage_free(struct fuse_conn *fc, struct fuse_req *req)
1414 1414
1415 for (i = 0; i < req->num_pages; i++) 1415 for (i = 0; i < req->num_pages; i++)
1416 __free_page(req->pages[i]); 1416 __free_page(req->pages[i]);
1417 fuse_file_put(req->ff, false); 1417
1418 if (req->ff)
1419 fuse_file_put(req->ff, false);
1418} 1420}
1419 1421
1420static void fuse_writepage_finish(struct fuse_conn *fc, struct fuse_req *req) 1422static void fuse_writepage_finish(struct fuse_conn *fc, struct fuse_req *req)
@@ -1496,6 +1498,14 @@ static void fuse_writepage_end(struct fuse_conn *fc, struct fuse_req *req)
1496 1498
1497 mapping_set_error(inode->i_mapping, req->out.h.error); 1499 mapping_set_error(inode->i_mapping, req->out.h.error);
1498 spin_lock(&fc->lock); 1500 spin_lock(&fc->lock);
1501 while (req->misc.write.next) {
1502 struct fuse_req *next = req->misc.write.next;
1503 req->misc.write.next = next->misc.write.next;
1504 next->misc.write.next = NULL;
1505 list_add(&next->writepages_entry, &fi->writepages);
1506 list_add_tail(&next->list, &fi->queued_writes);
1507 fuse_flush_writepages(inode);
1508 }
1499 fi->writectr--; 1509 fi->writectr--;
1500 fuse_writepage_finish(fc, req); 1510 fuse_writepage_finish(fc, req);
1501 spin_unlock(&fc->lock); 1511 spin_unlock(&fc->lock);
@@ -1548,6 +1558,7 @@ static int fuse_writepage_locked(struct page *page)
1548 1558
1549 copy_highpage(tmp_page, page); 1559 copy_highpage(tmp_page, page);
1550 req->misc.write.in.write_flags |= FUSE_WRITE_CACHE; 1560 req->misc.write.in.write_flags |= FUSE_WRITE_CACHE;
1561 req->misc.write.next = NULL;
1551 req->in.argpages = 1; 1562 req->in.argpages = 1;
1552 req->num_pages = 1; 1563 req->num_pages = 1;
1553 req->pages[0] = tmp_page; 1564 req->pages[0] = tmp_page;
@@ -1612,6 +1623,62 @@ static void fuse_writepages_send(struct fuse_fill_wb_data *data)
1612 end_page_writeback(data->orig_pages[i]); 1623 end_page_writeback(data->orig_pages[i]);
1613} 1624}
1614 1625
1626static bool fuse_writepage_in_flight(struct fuse_req *new_req,
1627 struct page *page)
1628{
1629 struct fuse_conn *fc = get_fuse_conn(new_req->inode);
1630 struct fuse_inode *fi = get_fuse_inode(new_req->inode);
1631 struct fuse_req *tmp;
1632 struct fuse_req *old_req;
1633 bool found = false;
1634 pgoff_t curr_index;
1635
1636 BUG_ON(new_req->num_pages != 0);
1637
1638 spin_lock(&fc->lock);
1639 list_del(&new_req->writepages_entry);
1640 new_req->num_pages = 1;
1641 list_for_each_entry(old_req, &fi->writepages, writepages_entry) {
1642 BUG_ON(old_req->inode != new_req->inode);
1643 curr_index = old_req->misc.write.in.offset >> PAGE_CACHE_SHIFT;
1644 if (curr_index <= page->index &&
1645 page->index < curr_index + old_req->num_pages) {
1646 found = true;
1647 break;
1648 }
1649 }
1650 if (!found)
1651 goto out_unlock;
1652
1653 for (tmp = old_req; tmp != NULL; tmp = tmp->misc.write.next) {
1654 BUG_ON(tmp->inode != new_req->inode);
1655 curr_index = tmp->misc.write.in.offset >> PAGE_CACHE_SHIFT;
1656 if (tmp->num_pages == 1 &&
1657 curr_index == page->index) {
1658 old_req = tmp;
1659 }
1660 }
1661
1662 if (old_req->num_pages == 1 && (old_req->state == FUSE_REQ_INIT ||
1663 old_req->state == FUSE_REQ_PENDING)) {
1664 copy_highpage(old_req->pages[0], page);
1665 spin_unlock(&fc->lock);
1666
1667 dec_bdi_stat(page->mapping->backing_dev_info, BDI_WRITEBACK);
1668 dec_zone_page_state(page, NR_WRITEBACK_TEMP);
1669 fuse_writepage_free(fc, new_req);
1670 fuse_request_free(new_req);
1671 goto out;
1672 } else {
1673 new_req->misc.write.next = old_req->misc.write.next;
1674 old_req->misc.write.next = new_req;
1675 }
1676out_unlock:
1677 spin_unlock(&fc->lock);
1678out:
1679 return found;
1680}
1681
1615static int fuse_writepages_fill(struct page *page, 1682static int fuse_writepages_fill(struct page *page,
1616 struct writeback_control *wbc, void *_data) 1683 struct writeback_control *wbc, void *_data)
1617{ 1684{
@@ -1620,6 +1687,7 @@ static int fuse_writepages_fill(struct page *page,
1620 struct inode *inode = data->inode; 1687 struct inode *inode = data->inode;
1621 struct fuse_conn *fc = get_fuse_conn(inode); 1688 struct fuse_conn *fc = get_fuse_conn(inode);
1622 struct page *tmp_page; 1689 struct page *tmp_page;
1690 bool is_writeback;
1623 int err; 1691 int err;
1624 1692
1625 if (!data->ff) { 1693 if (!data->ff) {
@@ -1629,15 +1697,20 @@ static int fuse_writepages_fill(struct page *page,
1629 goto out_unlock; 1697 goto out_unlock;
1630 } 1698 }
1631 1699
1632 if (req) { 1700 /*
1633 BUG_ON(!req->num_pages); 1701 * Being under writeback is unlikely but possible. For example direct
1634 if (req->num_pages == FUSE_MAX_PAGES_PER_REQ || 1702 * read to an mmaped fuse file will set the page dirty twice; once when
1635 (req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_write || 1703 * the pages are faulted with get_user_pages(), and then after the read
1636 data->orig_pages[req->num_pages - 1]->index + 1 != page->index) { 1704 * completed.
1705 */
1706 is_writeback = fuse_page_is_writeback(inode, page->index);
1637 1707
1638 fuse_writepages_send(data); 1708 if (req && req->num_pages &&
1639 data->req = NULL; 1709 (is_writeback || req->num_pages == FUSE_MAX_PAGES_PER_REQ ||
1640 } 1710 (req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_write ||
1711 data->orig_pages[req->num_pages - 1]->index + 1 != page->index)) {
1712 fuse_writepages_send(data);
1713 data->req = NULL;
1641 } 1714 }
1642 err = -ENOMEM; 1715 err = -ENOMEM;
1643 tmp_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM); 1716 tmp_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
@@ -1669,6 +1742,7 @@ static int fuse_writepages_fill(struct page *page,
1669 1742
1670 fuse_write_fill(req, data->ff, page_offset(page), 0); 1743 fuse_write_fill(req, data->ff, page_offset(page), 0);
1671 req->misc.write.in.write_flags |= FUSE_WRITE_CACHE; 1744 req->misc.write.in.write_flags |= FUSE_WRITE_CACHE;
1745 req->misc.write.next = NULL;
1672 req->in.argpages = 1; 1746 req->in.argpages = 1;
1673 req->background = 1; 1747 req->background = 1;
1674 req->num_pages = 0; 1748 req->num_pages = 0;
@@ -1690,6 +1764,13 @@ static int fuse_writepages_fill(struct page *page,
1690 1764
1691 inc_bdi_stat(page->mapping->backing_dev_info, BDI_WRITEBACK); 1765 inc_bdi_stat(page->mapping->backing_dev_info, BDI_WRITEBACK);
1692 inc_zone_page_state(tmp_page, NR_WRITEBACK_TEMP); 1766 inc_zone_page_state(tmp_page, NR_WRITEBACK_TEMP);
1767
1768 err = 0;
1769 if (is_writeback && fuse_writepage_in_flight(req, page)) {
1770 end_page_writeback(page);
1771 data->req = NULL;
1772 goto out_unlock;
1773 }
1693 data->orig_pages[req->num_pages] = page; 1774 data->orig_pages[req->num_pages] = page;
1694 1775
1695 /* 1776 /*
@@ -1700,7 +1781,6 @@ static int fuse_writepages_fill(struct page *page,
1700 req->num_pages++; 1781 req->num_pages++;
1701 spin_unlock(&fc->lock); 1782 spin_unlock(&fc->lock);
1702 1783
1703 err = 0;
1704out_unlock: 1784out_unlock:
1705 unlock_page(page); 1785 unlock_page(page);
1706 1786
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 5b9e6f3b6aef..643274852c8b 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -321,6 +321,7 @@ struct fuse_req {
321 struct { 321 struct {
322 struct fuse_write_in in; 322 struct fuse_write_in in;
323 struct fuse_write_out out; 323 struct fuse_write_out out;
324 struct fuse_req *next;
324 } write; 325 } write;
325 struct fuse_notify_retrieve_in retrieve_in; 326 struct fuse_notify_retrieve_in retrieve_in;
326 struct fuse_lk_in lk_in; 327 struct fuse_lk_in lk_in;