diff options
Diffstat (limited to 'fs/nfs/write.c')
-rw-r--r-- | fs/nfs/write.c | 150 |
1 files changed, 62 insertions, 88 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 175d5d073ccf..12493846a2d3 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -49,6 +49,9 @@ static const struct nfs_rw_ops nfs_rw_write_ops; | |||
49 | static void nfs_clear_request_commit(struct nfs_page *req); | 49 | static void nfs_clear_request_commit(struct nfs_page *req); |
50 | static void nfs_init_cinfo_from_inode(struct nfs_commit_info *cinfo, | 50 | static void nfs_init_cinfo_from_inode(struct nfs_commit_info *cinfo, |
51 | struct inode *inode); | 51 | struct inode *inode); |
52 | static struct nfs_page * | ||
53 | nfs_page_search_commits_for_head_request_locked(struct nfs_inode *nfsi, | ||
54 | struct page *page); | ||
52 | 55 | ||
53 | static struct kmem_cache *nfs_wdata_cachep; | 56 | static struct kmem_cache *nfs_wdata_cachep; |
54 | static mempool_t *nfs_wdata_mempool; | 57 | static mempool_t *nfs_wdata_mempool; |
@@ -95,38 +98,6 @@ static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error) | |||
95 | } | 98 | } |
96 | 99 | ||
97 | /* | 100 | /* |
98 | * nfs_page_search_commits_for_head_request_locked | ||
99 | * | ||
100 | * Search through commit lists on @inode for the head request for @page. | ||
101 | * Must be called while holding the inode (which is cinfo) lock. | ||
102 | * | ||
103 | * Returns the head request if found, or NULL if not found. | ||
104 | */ | ||
105 | static struct nfs_page * | ||
106 | nfs_page_search_commits_for_head_request_locked(struct nfs_inode *nfsi, | ||
107 | struct page *page) | ||
108 | { | ||
109 | struct nfs_page *freq, *t; | ||
110 | struct nfs_commit_info cinfo; | ||
111 | struct inode *inode = &nfsi->vfs_inode; | ||
112 | |||
113 | nfs_init_cinfo_from_inode(&cinfo, inode); | ||
114 | |||
115 | /* search through pnfs commit lists */ | ||
116 | freq = pnfs_search_commit_reqs(inode, &cinfo, page); | ||
117 | if (freq) | ||
118 | return freq->wb_head; | ||
119 | |||
120 | /* Linearly search the commit list for the correct request */ | ||
121 | list_for_each_entry_safe(freq, t, &cinfo.mds->list, wb_list) { | ||
122 | if (freq->wb_page == page) | ||
123 | return freq->wb_head; | ||
124 | } | ||
125 | |||
126 | return NULL; | ||
127 | } | ||
128 | |||
129 | /* | ||
130 | * nfs_page_find_head_request_locked - find head request associated with @page | 101 | * nfs_page_find_head_request_locked - find head request associated with @page |
131 | * | 102 | * |
132 | * must be called while holding the inode lock. | 103 | * must be called while holding the inode lock. |
@@ -271,11 +242,14 @@ static void nfs_mark_uptodate(struct nfs_page *req) | |||
271 | 242 | ||
272 | static int wb_priority(struct writeback_control *wbc) | 243 | static int wb_priority(struct writeback_control *wbc) |
273 | { | 244 | { |
245 | int ret = 0; | ||
274 | if (wbc->for_reclaim) | 246 | if (wbc->for_reclaim) |
275 | return FLUSH_HIGHPRI | FLUSH_STABLE; | 247 | return FLUSH_HIGHPRI | FLUSH_STABLE; |
248 | if (wbc->sync_mode == WB_SYNC_ALL) | ||
249 | ret = FLUSH_COND_STABLE; | ||
276 | if (wbc->for_kupdate || wbc->for_background) | 250 | if (wbc->for_kupdate || wbc->for_background) |
277 | return FLUSH_LOWPRI | FLUSH_COND_STABLE; | 251 | ret |= FLUSH_LOWPRI; |
278 | return FLUSH_COND_STABLE; | 252 | return ret; |
279 | } | 253 | } |
280 | 254 | ||
281 | /* | 255 | /* |
@@ -731,6 +705,8 @@ static void nfs_inode_remove_request(struct nfs_page *req) | |||
731 | if (likely(!PageSwapCache(head->wb_page))) { | 705 | if (likely(!PageSwapCache(head->wb_page))) { |
732 | set_page_private(head->wb_page, 0); | 706 | set_page_private(head->wb_page, 0); |
733 | ClearPagePrivate(head->wb_page); | 707 | ClearPagePrivate(head->wb_page); |
708 | smp_mb__after_atomic(); | ||
709 | wake_up_page(head->wb_page, PG_private); | ||
734 | clear_bit(PG_MAPPED, &head->wb_flags); | 710 | clear_bit(PG_MAPPED, &head->wb_flags); |
735 | } | 711 | } |
736 | nfsi->npages--; | 712 | nfsi->npages--; |
@@ -749,7 +725,38 @@ nfs_mark_request_dirty(struct nfs_page *req) | |||
749 | __set_page_dirty_nobuffers(req->wb_page); | 725 | __set_page_dirty_nobuffers(req->wb_page); |
750 | } | 726 | } |
751 | 727 | ||
752 | #if IS_ENABLED(CONFIG_NFS_V3) || IS_ENABLED(CONFIG_NFS_V4) | 728 | /* |
729 | * nfs_page_search_commits_for_head_request_locked | ||
730 | * | ||
731 | * Search through commit lists on @inode for the head request for @page. | ||
732 | * Must be called while holding the inode (which is cinfo) lock. | ||
733 | * | ||
734 | * Returns the head request if found, or NULL if not found. | ||
735 | */ | ||
736 | static struct nfs_page * | ||
737 | nfs_page_search_commits_for_head_request_locked(struct nfs_inode *nfsi, | ||
738 | struct page *page) | ||
739 | { | ||
740 | struct nfs_page *freq, *t; | ||
741 | struct nfs_commit_info cinfo; | ||
742 | struct inode *inode = &nfsi->vfs_inode; | ||
743 | |||
744 | nfs_init_cinfo_from_inode(&cinfo, inode); | ||
745 | |||
746 | /* search through pnfs commit lists */ | ||
747 | freq = pnfs_search_commit_reqs(inode, &cinfo, page); | ||
748 | if (freq) | ||
749 | return freq->wb_head; | ||
750 | |||
751 | /* Linearly search the commit list for the correct request */ | ||
752 | list_for_each_entry_safe(freq, t, &cinfo.mds->list, wb_list) { | ||
753 | if (freq->wb_page == page) | ||
754 | return freq->wb_head; | ||
755 | } | ||
756 | |||
757 | return NULL; | ||
758 | } | ||
759 | |||
753 | /** | 760 | /** |
754 | * nfs_request_add_commit_list - add request to a commit list | 761 | * nfs_request_add_commit_list - add request to a commit list |
755 | * @req: pointer to a struct nfs_page | 762 | * @req: pointer to a struct nfs_page |
@@ -867,36 +874,6 @@ int nfs_write_need_commit(struct nfs_pgio_header *hdr) | |||
867 | return hdr->verf.committed != NFS_FILE_SYNC; | 874 | return hdr->verf.committed != NFS_FILE_SYNC; |
868 | } | 875 | } |
869 | 876 | ||
870 | #else | ||
871 | static void nfs_init_cinfo_from_inode(struct nfs_commit_info *cinfo, | ||
872 | struct inode *inode) | ||
873 | { | ||
874 | } | ||
875 | |||
876 | void nfs_init_cinfo(struct nfs_commit_info *cinfo, | ||
877 | struct inode *inode, | ||
878 | struct nfs_direct_req *dreq) | ||
879 | { | ||
880 | } | ||
881 | |||
882 | void | ||
883 | nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg, | ||
884 | struct nfs_commit_info *cinfo) | ||
885 | { | ||
886 | } | ||
887 | |||
888 | static void | ||
889 | nfs_clear_request_commit(struct nfs_page *req) | ||
890 | { | ||
891 | } | ||
892 | |||
893 | int nfs_write_need_commit(struct nfs_pgio_header *hdr) | ||
894 | { | ||
895 | return 0; | ||
896 | } | ||
897 | |||
898 | #endif | ||
899 | |||
900 | static void nfs_write_completion(struct nfs_pgio_header *hdr) | 877 | static void nfs_write_completion(struct nfs_pgio_header *hdr) |
901 | { | 878 | { |
902 | struct nfs_commit_info cinfo; | 879 | struct nfs_commit_info cinfo; |
@@ -932,7 +909,6 @@ out: | |||
932 | hdr->release(hdr); | 909 | hdr->release(hdr); |
933 | } | 910 | } |
934 | 911 | ||
935 | #if IS_ENABLED(CONFIG_NFS_V3) || IS_ENABLED(CONFIG_NFS_V4) | ||
936 | unsigned long | 912 | unsigned long |
937 | nfs_reqs_to_commit(struct nfs_commit_info *cinfo) | 913 | nfs_reqs_to_commit(struct nfs_commit_info *cinfo) |
938 | { | 914 | { |
@@ -989,19 +965,6 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst, | |||
989 | return ret; | 965 | return ret; |
990 | } | 966 | } |
991 | 967 | ||
992 | #else | ||
993 | unsigned long nfs_reqs_to_commit(struct nfs_commit_info *cinfo) | ||
994 | { | ||
995 | return 0; | ||
996 | } | ||
997 | |||
998 | int nfs_scan_commit(struct inode *inode, struct list_head *dst, | ||
999 | struct nfs_commit_info *cinfo) | ||
1000 | { | ||
1001 | return 0; | ||
1002 | } | ||
1003 | #endif | ||
1004 | |||
1005 | /* | 968 | /* |
1006 | * Search for an existing write request, and attempt to update | 969 | * Search for an existing write request, and attempt to update |
1007 | * it to reflect a new dirty region on a given page. | 970 | * it to reflect a new dirty region on a given page. |
@@ -1394,7 +1357,6 @@ static int nfs_writeback_done(struct rpc_task *task, | |||
1394 | return status; | 1357 | return status; |
1395 | nfs_add_stats(inode, NFSIOS_SERVERWRITTENBYTES, hdr->res.count); | 1358 | nfs_add_stats(inode, NFSIOS_SERVERWRITTENBYTES, hdr->res.count); |
1396 | 1359 | ||
1397 | #if IS_ENABLED(CONFIG_NFS_V3) || IS_ENABLED(CONFIG_NFS_V4) | ||
1398 | if (hdr->res.verf->committed < hdr->args.stable && | 1360 | if (hdr->res.verf->committed < hdr->args.stable && |
1399 | task->tk_status >= 0) { | 1361 | task->tk_status >= 0) { |
1400 | /* We tried a write call, but the server did not | 1362 | /* We tried a write call, but the server did not |
@@ -1416,7 +1378,6 @@ static int nfs_writeback_done(struct rpc_task *task, | |||
1416 | complain = jiffies + 300 * HZ; | 1378 | complain = jiffies + 300 * HZ; |
1417 | } | 1379 | } |
1418 | } | 1380 | } |
1419 | #endif | ||
1420 | 1381 | ||
1421 | /* Deal with the suid/sgid bit corner case */ | 1382 | /* Deal with the suid/sgid bit corner case */ |
1422 | if (nfs_should_remove_suid(inode)) | 1383 | if (nfs_should_remove_suid(inode)) |
@@ -1469,7 +1430,6 @@ static void nfs_writeback_result(struct rpc_task *task, | |||
1469 | } | 1430 | } |
1470 | 1431 | ||
1471 | 1432 | ||
1472 | #if IS_ENABLED(CONFIG_NFS_V3) || IS_ENABLED(CONFIG_NFS_V4) | ||
1473 | static int nfs_commit_set_lock(struct nfs_inode *nfsi, int may_wait) | 1433 | static int nfs_commit_set_lock(struct nfs_inode *nfsi, int may_wait) |
1474 | { | 1434 | { |
1475 | int ret; | 1435 | int ret; |
@@ -1538,6 +1498,18 @@ int nfs_initiate_commit(struct rpc_clnt *clnt, struct nfs_commit_data *data, | |||
1538 | } | 1498 | } |
1539 | EXPORT_SYMBOL_GPL(nfs_initiate_commit); | 1499 | EXPORT_SYMBOL_GPL(nfs_initiate_commit); |
1540 | 1500 | ||
1501 | static loff_t nfs_get_lwb(struct list_head *head) | ||
1502 | { | ||
1503 | loff_t lwb = 0; | ||
1504 | struct nfs_page *req; | ||
1505 | |||
1506 | list_for_each_entry(req, head, wb_list) | ||
1507 | if (lwb < (req_offset(req) + req->wb_bytes)) | ||
1508 | lwb = req_offset(req) + req->wb_bytes; | ||
1509 | |||
1510 | return lwb; | ||
1511 | } | ||
1512 | |||
1541 | /* | 1513 | /* |
1542 | * Set up the argument/result storage required for the RPC call. | 1514 | * Set up the argument/result storage required for the RPC call. |
1543 | */ | 1515 | */ |
@@ -1557,6 +1529,9 @@ void nfs_init_commit(struct nfs_commit_data *data, | |||
1557 | data->inode = inode; | 1529 | data->inode = inode; |
1558 | data->cred = first->wb_context->cred; | 1530 | data->cred = first->wb_context->cred; |
1559 | data->lseg = lseg; /* reference transferred */ | 1531 | data->lseg = lseg; /* reference transferred */ |
1532 | /* only set lwb for pnfs commit */ | ||
1533 | if (lseg) | ||
1534 | data->lwb = nfs_get_lwb(&data->pages); | ||
1560 | data->mds_ops = &nfs_commit_ops; | 1535 | data->mds_ops = &nfs_commit_ops; |
1561 | data->completion_ops = cinfo->completion_ops; | 1536 | data->completion_ops = cinfo->completion_ops; |
1562 | data->dreq = cinfo->dreq; | 1537 | data->dreq = cinfo->dreq; |
@@ -1636,6 +1611,7 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data) | |||
1636 | struct nfs_page *req; | 1611 | struct nfs_page *req; |
1637 | int status = data->task.tk_status; | 1612 | int status = data->task.tk_status; |
1638 | struct nfs_commit_info cinfo; | 1613 | struct nfs_commit_info cinfo; |
1614 | struct nfs_server *nfss; | ||
1639 | 1615 | ||
1640 | while (!list_empty(&data->pages)) { | 1616 | while (!list_empty(&data->pages)) { |
1641 | req = nfs_list_entry(data->pages.next); | 1617 | req = nfs_list_entry(data->pages.next); |
@@ -1669,6 +1645,10 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data) | |||
1669 | next: | 1645 | next: |
1670 | nfs_unlock_and_release_request(req); | 1646 | nfs_unlock_and_release_request(req); |
1671 | } | 1647 | } |
1648 | nfss = NFS_SERVER(data->inode); | ||
1649 | if (atomic_long_read(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) | ||
1650 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); | ||
1651 | |||
1672 | nfs_init_cinfo(&cinfo, data->inode, data->dreq); | 1652 | nfs_init_cinfo(&cinfo, data->inode, data->dreq); |
1673 | if (atomic_dec_and_test(&cinfo.mds->rpcs_out)) | 1653 | if (atomic_dec_and_test(&cinfo.mds->rpcs_out)) |
1674 | nfs_commit_clear_lock(NFS_I(data->inode)); | 1654 | nfs_commit_clear_lock(NFS_I(data->inode)); |
@@ -1778,12 +1758,6 @@ out_mark_dirty: | |||
1778 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); | 1758 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); |
1779 | return ret; | 1759 | return ret; |
1780 | } | 1760 | } |
1781 | #else | ||
1782 | static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_control *wbc) | ||
1783 | { | ||
1784 | return 0; | ||
1785 | } | ||
1786 | #endif | ||
1787 | 1761 | ||
1788 | int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) | 1762 | int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) |
1789 | { | 1763 | { |