diff options
Diffstat (limited to 'fs/nfs/write.c')
| -rw-r--r-- | fs/nfs/write.c | 44 |
1 files changed, 28 insertions, 16 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 53ff70e23993..de38d63aa920 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
| @@ -201,6 +201,7 @@ static int nfs_set_page_writeback(struct page *page) | |||
| 201 | struct inode *inode = page->mapping->host; | 201 | struct inode *inode = page->mapping->host; |
| 202 | struct nfs_server *nfss = NFS_SERVER(inode); | 202 | struct nfs_server *nfss = NFS_SERVER(inode); |
| 203 | 203 | ||
| 204 | page_cache_get(page); | ||
| 204 | if (atomic_long_inc_return(&nfss->writeback) > | 205 | if (atomic_long_inc_return(&nfss->writeback) > |
| 205 | NFS_CONGESTION_ON_THRESH) { | 206 | NFS_CONGESTION_ON_THRESH) { |
| 206 | set_bdi_congested(&nfss->backing_dev_info, | 207 | set_bdi_congested(&nfss->backing_dev_info, |
| @@ -216,6 +217,7 @@ static void nfs_end_page_writeback(struct page *page) | |||
| 216 | struct nfs_server *nfss = NFS_SERVER(inode); | 217 | struct nfs_server *nfss = NFS_SERVER(inode); |
| 217 | 218 | ||
| 218 | end_page_writeback(page); | 219 | end_page_writeback(page); |
| 220 | page_cache_release(page); | ||
| 219 | if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) | 221 | if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) |
| 220 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); | 222 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); |
| 221 | } | 223 | } |
| @@ -421,6 +423,7 @@ static void | |||
| 421 | nfs_mark_request_dirty(struct nfs_page *req) | 423 | nfs_mark_request_dirty(struct nfs_page *req) |
| 422 | { | 424 | { |
| 423 | __set_page_dirty_nobuffers(req->wb_page); | 425 | __set_page_dirty_nobuffers(req->wb_page); |
| 426 | __mark_inode_dirty(req->wb_page->mapping->host, I_DIRTY_DATASYNC); | ||
| 424 | } | 427 | } |
| 425 | 428 | ||
| 426 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 429 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
| @@ -660,9 +663,11 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page, | |||
| 660 | req = nfs_setup_write_request(ctx, page, offset, count); | 663 | req = nfs_setup_write_request(ctx, page, offset, count); |
| 661 | if (IS_ERR(req)) | 664 | if (IS_ERR(req)) |
| 662 | return PTR_ERR(req); | 665 | return PTR_ERR(req); |
| 666 | nfs_mark_request_dirty(req); | ||
| 663 | /* Update file length */ | 667 | /* Update file length */ |
| 664 | nfs_grow_file(page, offset, count); | 668 | nfs_grow_file(page, offset, count); |
| 665 | nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes); | 669 | nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes); |
| 670 | nfs_mark_request_dirty(req); | ||
| 666 | nfs_clear_page_tag_locked(req); | 671 | nfs_clear_page_tag_locked(req); |
| 667 | return 0; | 672 | return 0; |
| 668 | } | 673 | } |
| @@ -739,8 +744,6 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
| 739 | status = nfs_writepage_setup(ctx, page, offset, count); | 744 | status = nfs_writepage_setup(ctx, page, offset, count); |
| 740 | if (status < 0) | 745 | if (status < 0) |
| 741 | nfs_set_pageerror(page); | 746 | nfs_set_pageerror(page); |
| 742 | else | ||
| 743 | __set_page_dirty_nobuffers(page); | ||
| 744 | 747 | ||
| 745 | dprintk("NFS: nfs_updatepage returns %d (isize %lld)\n", | 748 | dprintk("NFS: nfs_updatepage returns %d (isize %lld)\n", |
| 746 | status, (long long)i_size_read(inode)); | 749 | status, (long long)i_size_read(inode)); |
| @@ -749,13 +752,12 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
| 749 | 752 | ||
| 750 | static void nfs_writepage_release(struct nfs_page *req) | 753 | static void nfs_writepage_release(struct nfs_page *req) |
| 751 | { | 754 | { |
| 755 | struct page *page = req->wb_page; | ||
| 752 | 756 | ||
| 753 | if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) { | 757 | if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) |
| 754 | nfs_end_page_writeback(req->wb_page); | ||
| 755 | nfs_inode_remove_request(req); | 758 | nfs_inode_remove_request(req); |
| 756 | } else | ||
| 757 | nfs_end_page_writeback(req->wb_page); | ||
| 758 | nfs_clear_page_tag_locked(req); | 759 | nfs_clear_page_tag_locked(req); |
| 760 | nfs_end_page_writeback(page); | ||
| 759 | } | 761 | } |
| 760 | 762 | ||
| 761 | static int flush_task_priority(int how) | 763 | static int flush_task_priority(int how) |
| @@ -779,7 +781,6 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
| 779 | int how) | 781 | int how) |
| 780 | { | 782 | { |
| 781 | struct inode *inode = req->wb_context->path.dentry->d_inode; | 783 | struct inode *inode = req->wb_context->path.dentry->d_inode; |
| 782 | int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
| 783 | int priority = flush_task_priority(how); | 784 | int priority = flush_task_priority(how); |
| 784 | struct rpc_task *task; | 785 | struct rpc_task *task; |
| 785 | struct rpc_message msg = { | 786 | struct rpc_message msg = { |
| @@ -794,9 +795,10 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
| 794 | .callback_ops = call_ops, | 795 | .callback_ops = call_ops, |
| 795 | .callback_data = data, | 796 | .callback_data = data, |
| 796 | .workqueue = nfsiod_workqueue, | 797 | .workqueue = nfsiod_workqueue, |
| 797 | .flags = flags, | 798 | .flags = RPC_TASK_ASYNC, |
| 798 | .priority = priority, | 799 | .priority = priority, |
| 799 | }; | 800 | }; |
| 801 | int ret = 0; | ||
| 800 | 802 | ||
| 801 | /* Set up the RPC argument and reply structs | 803 | /* Set up the RPC argument and reply structs |
| 802 | * NB: take care not to mess about with data->commit et al. */ | 804 | * NB: take care not to mess about with data->commit et al. */ |
| @@ -835,10 +837,18 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
| 835 | (unsigned long long)data->args.offset); | 837 | (unsigned long long)data->args.offset); |
| 836 | 838 | ||
| 837 | task = rpc_run_task(&task_setup_data); | 839 | task = rpc_run_task(&task_setup_data); |
| 838 | if (IS_ERR(task)) | 840 | if (IS_ERR(task)) { |
| 839 | return PTR_ERR(task); | 841 | ret = PTR_ERR(task); |
| 842 | goto out; | ||
| 843 | } | ||
| 844 | if (how & FLUSH_SYNC) { | ||
| 845 | ret = rpc_wait_for_completion_task(task); | ||
| 846 | if (ret == 0) | ||
| 847 | ret = task->tk_status; | ||
| 848 | } | ||
| 840 | rpc_put_task(task); | 849 | rpc_put_task(task); |
| 841 | return 0; | 850 | out: |
| 851 | return ret; | ||
| 842 | } | 852 | } |
| 843 | 853 | ||
| 844 | /* If a nfs_flush_* function fails, it should remove reqs from @head and | 854 | /* If a nfs_flush_* function fails, it should remove reqs from @head and |
| @@ -847,9 +857,11 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
| 847 | */ | 857 | */ |
| 848 | static void nfs_redirty_request(struct nfs_page *req) | 858 | static void nfs_redirty_request(struct nfs_page *req) |
| 849 | { | 859 | { |
| 860 | struct page *page = req->wb_page; | ||
| 861 | |||
| 850 | nfs_mark_request_dirty(req); | 862 | nfs_mark_request_dirty(req); |
| 851 | nfs_end_page_writeback(req->wb_page); | ||
| 852 | nfs_clear_page_tag_locked(req); | 863 | nfs_clear_page_tag_locked(req); |
| 864 | nfs_end_page_writeback(page); | ||
| 853 | } | 865 | } |
| 854 | 866 | ||
| 855 | /* | 867 | /* |
| @@ -1084,16 +1096,15 @@ static void nfs_writeback_release_full(void *calldata) | |||
| 1084 | if (nfs_write_need_commit(data)) { | 1096 | if (nfs_write_need_commit(data)) { |
| 1085 | memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); | 1097 | memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); |
| 1086 | nfs_mark_request_commit(req); | 1098 | nfs_mark_request_commit(req); |
| 1087 | nfs_end_page_writeback(page); | ||
| 1088 | dprintk(" marked for commit\n"); | 1099 | dprintk(" marked for commit\n"); |
| 1089 | goto next; | 1100 | goto next; |
| 1090 | } | 1101 | } |
| 1091 | dprintk(" OK\n"); | 1102 | dprintk(" OK\n"); |
| 1092 | remove_request: | 1103 | remove_request: |
| 1093 | nfs_end_page_writeback(page); | ||
| 1094 | nfs_inode_remove_request(req); | 1104 | nfs_inode_remove_request(req); |
| 1095 | next: | 1105 | next: |
| 1096 | nfs_clear_page_tag_locked(req); | 1106 | nfs_clear_page_tag_locked(req); |
| 1107 | nfs_end_page_writeback(page); | ||
| 1097 | } | 1108 | } |
| 1098 | nfs_writedata_release(calldata); | 1109 | nfs_writedata_release(calldata); |
| 1099 | } | 1110 | } |
| @@ -1207,7 +1218,6 @@ static int nfs_commit_rpcsetup(struct list_head *head, | |||
| 1207 | { | 1218 | { |
| 1208 | struct nfs_page *first = nfs_list_entry(head->next); | 1219 | struct nfs_page *first = nfs_list_entry(head->next); |
| 1209 | struct inode *inode = first->wb_context->path.dentry->d_inode; | 1220 | struct inode *inode = first->wb_context->path.dentry->d_inode; |
| 1210 | int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
| 1211 | int priority = flush_task_priority(how); | 1221 | int priority = flush_task_priority(how); |
| 1212 | struct rpc_task *task; | 1222 | struct rpc_task *task; |
| 1213 | struct rpc_message msg = { | 1223 | struct rpc_message msg = { |
| @@ -1222,7 +1232,7 @@ static int nfs_commit_rpcsetup(struct list_head *head, | |||
| 1222 | .callback_ops = &nfs_commit_ops, | 1232 | .callback_ops = &nfs_commit_ops, |
| 1223 | .callback_data = data, | 1233 | .callback_data = data, |
| 1224 | .workqueue = nfsiod_workqueue, | 1234 | .workqueue = nfsiod_workqueue, |
| 1225 | .flags = flags, | 1235 | .flags = RPC_TASK_ASYNC, |
| 1226 | .priority = priority, | 1236 | .priority = priority, |
| 1227 | }; | 1237 | }; |
| 1228 | 1238 | ||
| @@ -1252,6 +1262,8 @@ static int nfs_commit_rpcsetup(struct list_head *head, | |||
| 1252 | task = rpc_run_task(&task_setup_data); | 1262 | task = rpc_run_task(&task_setup_data); |
| 1253 | if (IS_ERR(task)) | 1263 | if (IS_ERR(task)) |
| 1254 | return PTR_ERR(task); | 1264 | return PTR_ERR(task); |
| 1265 | if (how & FLUSH_SYNC) | ||
| 1266 | rpc_wait_for_completion_task(task); | ||
| 1255 | rpc_put_task(task); | 1267 | rpc_put_task(task); |
| 1256 | return 0; | 1268 | return 0; |
| 1257 | } | 1269 | } |
