diff options
Diffstat (limited to 'fs/nfs/write.c')
-rw-r--r-- | fs/nfs/write.c | 133 |
1 files changed, 81 insertions, 52 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 7b9316406930..ce43cd6d88c6 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -21,6 +21,8 @@ | |||
21 | #include <linux/nfs_page.h> | 21 | #include <linux/nfs_page.h> |
22 | #include <linux/backing-dev.h> | 22 | #include <linux/backing-dev.h> |
23 | #include <linux/export.h> | 23 | #include <linux/export.h> |
24 | #include <linux/freezer.h> | ||
25 | #include <linux/wait.h> | ||
24 | 26 | ||
25 | #include <asm/uaccess.h> | 27 | #include <asm/uaccess.h> |
26 | 28 | ||
@@ -244,11 +246,9 @@ static int wb_priority(struct writeback_control *wbc) | |||
244 | { | 246 | { |
245 | int ret = 0; | 247 | int ret = 0; |
246 | if (wbc->for_reclaim) | 248 | if (wbc->for_reclaim) |
247 | return FLUSH_HIGHPRI | FLUSH_STABLE; | 249 | return FLUSH_HIGHPRI | FLUSH_COND_STABLE; |
248 | if (wbc->sync_mode == WB_SYNC_ALL) | 250 | if (wbc->sync_mode == WB_SYNC_ALL) |
249 | ret = FLUSH_COND_STABLE; | 251 | ret = FLUSH_COND_STABLE; |
250 | if (wbc->for_kupdate || wbc->for_background) | ||
251 | ret |= FLUSH_LOWPRI; | ||
252 | return ret; | 252 | return ret; |
253 | } | 253 | } |
254 | 254 | ||
@@ -545,12 +545,22 @@ try_again: | |||
545 | return head; | 545 | return head; |
546 | } | 546 | } |
547 | 547 | ||
548 | static void nfs_write_error_remove_page(struct nfs_page *req) | ||
549 | { | ||
550 | nfs_unlock_request(req); | ||
551 | nfs_end_page_writeback(req); | ||
552 | nfs_release_request(req); | ||
553 | generic_error_remove_page(page_file_mapping(req->wb_page), | ||
554 | req->wb_page); | ||
555 | } | ||
556 | |||
548 | /* | 557 | /* |
549 | * Find an associated nfs write request, and prepare to flush it out | 558 | * Find an associated nfs write request, and prepare to flush it out |
550 | * May return an error if the user signalled nfs_wait_on_request(). | 559 | * May return an error if the user signalled nfs_wait_on_request(). |
551 | */ | 560 | */ |
552 | static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | 561 | static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, |
553 | struct page *page, bool nonblock) | 562 | struct page *page, bool nonblock, |
563 | bool launder) | ||
554 | { | 564 | { |
555 | struct nfs_page *req; | 565 | struct nfs_page *req; |
556 | int ret = 0; | 566 | int ret = 0; |
@@ -567,8 +577,21 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | |||
567 | 577 | ||
568 | ret = 0; | 578 | ret = 0; |
569 | if (!nfs_pageio_add_request(pgio, req)) { | 579 | if (!nfs_pageio_add_request(pgio, req)) { |
570 | nfs_redirty_request(req); | ||
571 | ret = pgio->pg_error; | 580 | ret = pgio->pg_error; |
581 | /* | ||
582 | * Remove the problematic req upon fatal errors | ||
583 | * in launder case, while other dirty pages can | ||
584 | * still be around until they get flushed. | ||
585 | */ | ||
586 | if (nfs_error_is_fatal(ret)) { | ||
587 | nfs_context_set_write_error(req->wb_context, ret); | ||
588 | if (launder) { | ||
589 | nfs_write_error_remove_page(req); | ||
590 | goto out; | ||
591 | } | ||
592 | } | ||
593 | nfs_redirty_request(req); | ||
594 | ret = -EAGAIN; | ||
572 | } else | 595 | } else |
573 | nfs_add_stats(page_file_mapping(page)->host, | 596 | nfs_add_stats(page_file_mapping(page)->host, |
574 | NFSIOS_WRITEPAGES, 1); | 597 | NFSIOS_WRITEPAGES, 1); |
@@ -576,12 +599,14 @@ out: | |||
576 | return ret; | 599 | return ret; |
577 | } | 600 | } |
578 | 601 | ||
579 | static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio) | 602 | static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, |
603 | struct nfs_pageio_descriptor *pgio, bool launder) | ||
580 | { | 604 | { |
581 | int ret; | 605 | int ret; |
582 | 606 | ||
583 | nfs_pageio_cond_complete(pgio, page_file_index(page)); | 607 | nfs_pageio_cond_complete(pgio, page_file_index(page)); |
584 | ret = nfs_page_async_flush(pgio, page, wbc->sync_mode == WB_SYNC_NONE); | 608 | ret = nfs_page_async_flush(pgio, page, wbc->sync_mode == WB_SYNC_NONE, |
609 | launder); | ||
585 | if (ret == -EAGAIN) { | 610 | if (ret == -EAGAIN) { |
586 | redirty_page_for_writepage(wbc, page); | 611 | redirty_page_for_writepage(wbc, page); |
587 | ret = 0; | 612 | ret = 0; |
@@ -592,7 +617,9 @@ static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, st | |||
592 | /* | 617 | /* |
593 | * Write an mmapped page to the server. | 618 | * Write an mmapped page to the server. |
594 | */ | 619 | */ |
595 | static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc) | 620 | static int nfs_writepage_locked(struct page *page, |
621 | struct writeback_control *wbc, | ||
622 | bool launder) | ||
596 | { | 623 | { |
597 | struct nfs_pageio_descriptor pgio; | 624 | struct nfs_pageio_descriptor pgio; |
598 | struct inode *inode = page_file_mapping(page)->host; | 625 | struct inode *inode = page_file_mapping(page)->host; |
@@ -601,7 +628,7 @@ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc | |||
601 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); | 628 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); |
602 | nfs_pageio_init_write(&pgio, inode, wb_priority(wbc), | 629 | nfs_pageio_init_write(&pgio, inode, wb_priority(wbc), |
603 | false, &nfs_async_write_completion_ops); | 630 | false, &nfs_async_write_completion_ops); |
604 | err = nfs_do_writepage(page, wbc, &pgio); | 631 | err = nfs_do_writepage(page, wbc, &pgio, launder); |
605 | nfs_pageio_complete(&pgio); | 632 | nfs_pageio_complete(&pgio); |
606 | if (err < 0) | 633 | if (err < 0) |
607 | return err; | 634 | return err; |
@@ -614,7 +641,7 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc) | |||
614 | { | 641 | { |
615 | int ret; | 642 | int ret; |
616 | 643 | ||
617 | ret = nfs_writepage_locked(page, wbc); | 644 | ret = nfs_writepage_locked(page, wbc, false); |
618 | unlock_page(page); | 645 | unlock_page(page); |
619 | return ret; | 646 | return ret; |
620 | } | 647 | } |
@@ -623,7 +650,7 @@ static int nfs_writepages_callback(struct page *page, struct writeback_control * | |||
623 | { | 650 | { |
624 | int ret; | 651 | int ret; |
625 | 652 | ||
626 | ret = nfs_do_writepage(page, wbc, data); | 653 | ret = nfs_do_writepage(page, wbc, data, false); |
627 | unlock_page(page); | 654 | unlock_page(page); |
628 | return ret; | 655 | return ret; |
629 | } | 656 | } |
@@ -1128,7 +1155,8 @@ int nfs_flush_incompatible(struct file *file, struct page *page) | |||
1128 | if (req == NULL) | 1155 | if (req == NULL) |
1129 | return 0; | 1156 | return 0; |
1130 | l_ctx = req->wb_lock_context; | 1157 | l_ctx = req->wb_lock_context; |
1131 | do_flush = req->wb_page != page || req->wb_context != ctx; | 1158 | do_flush = req->wb_page != page || |
1159 | !nfs_match_open_context(req->wb_context, ctx); | ||
1132 | /* for now, flush if more than 1 request in page_group */ | 1160 | /* for now, flush if more than 1 request in page_group */ |
1133 | do_flush |= req->wb_this_page != req; | 1161 | do_flush |= req->wb_this_page != req; |
1134 | if (l_ctx && flctx && | 1162 | if (l_ctx && flctx && |
@@ -1326,9 +1354,15 @@ static void nfs_async_write_error(struct list_head *head) | |||
1326 | } | 1354 | } |
1327 | } | 1355 | } |
1328 | 1356 | ||
1357 | static void nfs_async_write_reschedule_io(struct nfs_pgio_header *hdr) | ||
1358 | { | ||
1359 | nfs_async_write_error(&hdr->pages); | ||
1360 | } | ||
1361 | |||
1329 | static const struct nfs_pgio_completion_ops nfs_async_write_completion_ops = { | 1362 | static const struct nfs_pgio_completion_ops nfs_async_write_completion_ops = { |
1330 | .error_cleanup = nfs_async_write_error, | 1363 | .error_cleanup = nfs_async_write_error, |
1331 | .completion = nfs_write_completion, | 1364 | .completion = nfs_write_completion, |
1365 | .reschedule_io = nfs_async_write_reschedule_io, | ||
1332 | }; | 1366 | }; |
1333 | 1367 | ||
1334 | void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, | 1368 | void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, |
@@ -1529,27 +1563,21 @@ static void nfs_writeback_result(struct rpc_task *task, | |||
1529 | } | 1563 | } |
1530 | } | 1564 | } |
1531 | 1565 | ||
1532 | 1566 | static int wait_on_commit(struct nfs_mds_commit_info *cinfo) | |
1533 | static int nfs_commit_set_lock(struct nfs_inode *nfsi, int may_wait) | ||
1534 | { | 1567 | { |
1535 | int ret; | 1568 | return wait_on_atomic_t(&cinfo->rpcs_out, |
1569 | nfs_wait_atomic_killable, TASK_KILLABLE); | ||
1570 | } | ||
1536 | 1571 | ||
1537 | if (!test_and_set_bit(NFS_INO_COMMIT, &nfsi->flags)) | 1572 | static void nfs_commit_begin(struct nfs_mds_commit_info *cinfo) |
1538 | return 1; | 1573 | { |
1539 | if (!may_wait) | 1574 | atomic_inc(&cinfo->rpcs_out); |
1540 | return 0; | ||
1541 | ret = out_of_line_wait_on_bit_lock(&nfsi->flags, | ||
1542 | NFS_INO_COMMIT, | ||
1543 | nfs_wait_bit_killable, | ||
1544 | TASK_KILLABLE); | ||
1545 | return (ret < 0) ? ret : 1; | ||
1546 | } | 1575 | } |
1547 | 1576 | ||
1548 | static void nfs_commit_clear_lock(struct nfs_inode *nfsi) | 1577 | static void nfs_commit_end(struct nfs_mds_commit_info *cinfo) |
1549 | { | 1578 | { |
1550 | clear_bit(NFS_INO_COMMIT, &nfsi->flags); | 1579 | if (atomic_dec_and_test(&cinfo->rpcs_out)) |
1551 | smp_mb__after_atomic(); | 1580 | wake_up_atomic_t(&cinfo->rpcs_out); |
1552 | wake_up_bit(&nfsi->flags, NFS_INO_COMMIT); | ||
1553 | } | 1581 | } |
1554 | 1582 | ||
1555 | void nfs_commitdata_release(struct nfs_commit_data *data) | 1583 | void nfs_commitdata_release(struct nfs_commit_data *data) |
@@ -1666,6 +1694,13 @@ void nfs_retry_commit(struct list_head *page_list, | |||
1666 | } | 1694 | } |
1667 | EXPORT_SYMBOL_GPL(nfs_retry_commit); | 1695 | EXPORT_SYMBOL_GPL(nfs_retry_commit); |
1668 | 1696 | ||
1697 | static void | ||
1698 | nfs_commit_resched_write(struct nfs_commit_info *cinfo, | ||
1699 | struct nfs_page *req) | ||
1700 | { | ||
1701 | __set_page_dirty_nobuffers(req->wb_page); | ||
1702 | } | ||
1703 | |||
1669 | /* | 1704 | /* |
1670 | * Commit dirty pages | 1705 | * Commit dirty pages |
1671 | */ | 1706 | */ |
@@ -1687,7 +1722,6 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how, | |||
1687 | data->mds_ops, how, 0); | 1722 | data->mds_ops, how, 0); |
1688 | out_bad: | 1723 | out_bad: |
1689 | nfs_retry_commit(head, NULL, cinfo, 0); | 1724 | nfs_retry_commit(head, NULL, cinfo, 0); |
1690 | cinfo->completion_ops->error_cleanup(NFS_I(inode)); | ||
1691 | return -ENOMEM; | 1725 | return -ENOMEM; |
1692 | } | 1726 | } |
1693 | 1727 | ||
@@ -1749,8 +1783,7 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data) | |||
1749 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); | 1783 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); |
1750 | 1784 | ||
1751 | nfs_init_cinfo(&cinfo, data->inode, data->dreq); | 1785 | nfs_init_cinfo(&cinfo, data->inode, data->dreq); |
1752 | if (atomic_dec_and_test(&cinfo.mds->rpcs_out)) | 1786 | nfs_commit_end(cinfo.mds); |
1753 | nfs_commit_clear_lock(NFS_I(data->inode)); | ||
1754 | } | 1787 | } |
1755 | 1788 | ||
1756 | static void nfs_commit_release(void *calldata) | 1789 | static void nfs_commit_release(void *calldata) |
@@ -1769,7 +1802,7 @@ static const struct rpc_call_ops nfs_commit_ops = { | |||
1769 | 1802 | ||
1770 | static const struct nfs_commit_completion_ops nfs_commit_completion_ops = { | 1803 | static const struct nfs_commit_completion_ops nfs_commit_completion_ops = { |
1771 | .completion = nfs_commit_release_pages, | 1804 | .completion = nfs_commit_release_pages, |
1772 | .error_cleanup = nfs_commit_clear_lock, | 1805 | .resched_write = nfs_commit_resched_write, |
1773 | }; | 1806 | }; |
1774 | 1807 | ||
1775 | int nfs_generic_commit_list(struct inode *inode, struct list_head *head, | 1808 | int nfs_generic_commit_list(struct inode *inode, struct list_head *head, |
@@ -1788,30 +1821,25 @@ int nfs_commit_inode(struct inode *inode, int how) | |||
1788 | LIST_HEAD(head); | 1821 | LIST_HEAD(head); |
1789 | struct nfs_commit_info cinfo; | 1822 | struct nfs_commit_info cinfo; |
1790 | int may_wait = how & FLUSH_SYNC; | 1823 | int may_wait = how & FLUSH_SYNC; |
1824 | int error = 0; | ||
1791 | int res; | 1825 | int res; |
1792 | 1826 | ||
1793 | res = nfs_commit_set_lock(NFS_I(inode), may_wait); | ||
1794 | if (res <= 0) | ||
1795 | goto out_mark_dirty; | ||
1796 | nfs_init_cinfo_from_inode(&cinfo, inode); | 1827 | nfs_init_cinfo_from_inode(&cinfo, inode); |
1828 | nfs_commit_begin(cinfo.mds); | ||
1797 | res = nfs_scan_commit(inode, &head, &cinfo); | 1829 | res = nfs_scan_commit(inode, &head, &cinfo); |
1798 | if (res) { | 1830 | if (res) |
1799 | int error; | ||
1800 | |||
1801 | error = nfs_generic_commit_list(inode, &head, how, &cinfo); | 1831 | error = nfs_generic_commit_list(inode, &head, how, &cinfo); |
1802 | if (error < 0) | 1832 | nfs_commit_end(cinfo.mds); |
1803 | return error; | 1833 | if (error < 0) |
1804 | if (!may_wait) | 1834 | goto out_error; |
1805 | goto out_mark_dirty; | 1835 | if (!may_wait) |
1806 | error = wait_on_bit_action(&NFS_I(inode)->flags, | 1836 | goto out_mark_dirty; |
1807 | NFS_INO_COMMIT, | 1837 | error = wait_on_commit(cinfo.mds); |
1808 | nfs_wait_bit_killable, | 1838 | if (error < 0) |
1809 | TASK_KILLABLE); | 1839 | return error; |
1810 | if (error < 0) | ||
1811 | return error; | ||
1812 | } else | ||
1813 | nfs_commit_clear_lock(NFS_I(inode)); | ||
1814 | return res; | 1840 | return res; |
1841 | out_error: | ||
1842 | res = error; | ||
1815 | /* Note: If we exit without ensuring that the commit is complete, | 1843 | /* Note: If we exit without ensuring that the commit is complete, |
1816 | * we must mark the inode as dirty. Otherwise, future calls to | 1844 | * we must mark the inode as dirty. Otherwise, future calls to |
1817 | * sync_inode() with the WB_SYNC_ALL flag set will fail to ensure | 1845 | * sync_inode() with the WB_SYNC_ALL flag set will fail to ensure |
@@ -1821,6 +1849,7 @@ out_mark_dirty: | |||
1821 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); | 1849 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); |
1822 | return res; | 1850 | return res; |
1823 | } | 1851 | } |
1852 | EXPORT_SYMBOL_GPL(nfs_commit_inode); | ||
1824 | 1853 | ||
1825 | int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) | 1854 | int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) |
1826 | { | 1855 | { |
@@ -1911,7 +1940,7 @@ int nfs_wb_page_cancel(struct inode *inode, struct page *page) | |||
1911 | /* | 1940 | /* |
1912 | * Write back all requests on one page - we do this before reading it. | 1941 | * Write back all requests on one page - we do this before reading it. |
1913 | */ | 1942 | */ |
1914 | int nfs_wb_page(struct inode *inode, struct page *page) | 1943 | int nfs_wb_single_page(struct inode *inode, struct page *page, bool launder) |
1915 | { | 1944 | { |
1916 | loff_t range_start = page_file_offset(page); | 1945 | loff_t range_start = page_file_offset(page); |
1917 | loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); | 1946 | loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); |
@@ -1928,7 +1957,7 @@ int nfs_wb_page(struct inode *inode, struct page *page) | |||
1928 | for (;;) { | 1957 | for (;;) { |
1929 | wait_on_page_writeback(page); | 1958 | wait_on_page_writeback(page); |
1930 | if (clear_page_dirty_for_io(page)) { | 1959 | if (clear_page_dirty_for_io(page)) { |
1931 | ret = nfs_writepage_locked(page, &wbc); | 1960 | ret = nfs_writepage_locked(page, &wbc, launder); |
1932 | if (ret < 0) | 1961 | if (ret < 0) |
1933 | goto out_error; | 1962 | goto out_error; |
1934 | continue; | 1963 | continue; |