diff options
Diffstat (limited to 'fs/nfs/write.c')
-rw-r--r-- | fs/nfs/write.c | 207 |
1 files changed, 119 insertions, 88 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index bed63416a55b..1ade11d1ba07 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -48,7 +48,7 @@ static struct kmem_cache *nfs_wdata_cachep; | |||
48 | static mempool_t *nfs_wdata_mempool; | 48 | static mempool_t *nfs_wdata_mempool; |
49 | static mempool_t *nfs_commit_mempool; | 49 | static mempool_t *nfs_commit_mempool; |
50 | 50 | ||
51 | struct nfs_write_data *nfs_commit_alloc(void) | 51 | struct nfs_write_data *nfs_commitdata_alloc(void) |
52 | { | 52 | { |
53 | struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, GFP_NOFS); | 53 | struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, GFP_NOFS); |
54 | 54 | ||
@@ -59,19 +59,13 @@ struct nfs_write_data *nfs_commit_alloc(void) | |||
59 | return p; | 59 | return p; |
60 | } | 60 | } |
61 | 61 | ||
62 | static void nfs_commit_rcu_free(struct rcu_head *head) | 62 | void nfs_commit_free(struct nfs_write_data *p) |
63 | { | 63 | { |
64 | struct nfs_write_data *p = container_of(head, struct nfs_write_data, task.u.tk_rcu); | ||
65 | if (p && (p->pagevec != &p->page_array[0])) | 64 | if (p && (p->pagevec != &p->page_array[0])) |
66 | kfree(p->pagevec); | 65 | kfree(p->pagevec); |
67 | mempool_free(p, nfs_commit_mempool); | 66 | mempool_free(p, nfs_commit_mempool); |
68 | } | 67 | } |
69 | 68 | ||
70 | void nfs_commit_free(struct nfs_write_data *wdata) | ||
71 | { | ||
72 | call_rcu_bh(&wdata->task.u.tk_rcu, nfs_commit_rcu_free); | ||
73 | } | ||
74 | |||
75 | struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) | 69 | struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) |
76 | { | 70 | { |
77 | struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS); | 71 | struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS); |
@@ -93,21 +87,18 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) | |||
93 | return p; | 87 | return p; |
94 | } | 88 | } |
95 | 89 | ||
96 | static void nfs_writedata_rcu_free(struct rcu_head *head) | 90 | static void nfs_writedata_free(struct nfs_write_data *p) |
97 | { | 91 | { |
98 | struct nfs_write_data *p = container_of(head, struct nfs_write_data, task.u.tk_rcu); | ||
99 | if (p && (p->pagevec != &p->page_array[0])) | 92 | if (p && (p->pagevec != &p->page_array[0])) |
100 | kfree(p->pagevec); | 93 | kfree(p->pagevec); |
101 | mempool_free(p, nfs_wdata_mempool); | 94 | mempool_free(p, nfs_wdata_mempool); |
102 | } | 95 | } |
103 | 96 | ||
104 | static void nfs_writedata_free(struct nfs_write_data *wdata) | 97 | void nfs_writedata_release(void *data) |
105 | { | 98 | { |
106 | call_rcu_bh(&wdata->task.u.tk_rcu, nfs_writedata_rcu_free); | 99 | struct nfs_write_data *wdata = data; |
107 | } | ||
108 | 100 | ||
109 | void nfs_writedata_release(void *wdata) | 101 | put_nfs_open_context(wdata->args.context); |
110 | { | ||
111 | nfs_writedata_free(wdata); | 102 | nfs_writedata_free(wdata); |
112 | } | 103 | } |
113 | 104 | ||
@@ -291,8 +282,6 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | |||
291 | spin_unlock(&inode->i_lock); | 282 | spin_unlock(&inode->i_lock); |
292 | if (!nfs_pageio_add_request(pgio, req)) { | 283 | if (!nfs_pageio_add_request(pgio, req)) { |
293 | nfs_redirty_request(req); | 284 | nfs_redirty_request(req); |
294 | nfs_end_page_writeback(page); | ||
295 | nfs_clear_page_tag_locked(req); | ||
296 | return pgio->pg_error; | 285 | return pgio->pg_error; |
297 | } | 286 | } |
298 | return 0; | 287 | return 0; |
@@ -366,15 +355,13 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) | |||
366 | /* | 355 | /* |
367 | * Insert a write request into an inode | 356 | * Insert a write request into an inode |
368 | */ | 357 | */ |
369 | static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | 358 | static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req) |
370 | { | 359 | { |
371 | struct nfs_inode *nfsi = NFS_I(inode); | 360 | struct nfs_inode *nfsi = NFS_I(inode); |
372 | int error; | 361 | int error; |
373 | 362 | ||
374 | error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req); | 363 | error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req); |
375 | BUG_ON(error == -EEXIST); | 364 | BUG_ON(error); |
376 | if (error) | ||
377 | return error; | ||
378 | if (!nfsi->npages) { | 365 | if (!nfsi->npages) { |
379 | igrab(inode); | 366 | igrab(inode); |
380 | if (nfs_have_delegation(inode, FMODE_WRITE)) | 367 | if (nfs_have_delegation(inode, FMODE_WRITE)) |
@@ -384,8 +371,8 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | |||
384 | set_page_private(req->wb_page, (unsigned long)req); | 371 | set_page_private(req->wb_page, (unsigned long)req); |
385 | nfsi->npages++; | 372 | nfsi->npages++; |
386 | kref_get(&req->wb_kref); | 373 | kref_get(&req->wb_kref); |
387 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); | 374 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, |
388 | return 0; | 375 | NFS_PAGE_TAG_LOCKED); |
389 | } | 376 | } |
390 | 377 | ||
391 | /* | 378 | /* |
@@ -413,7 +400,7 @@ static void nfs_inode_remove_request(struct nfs_page *req) | |||
413 | } | 400 | } |
414 | 401 | ||
415 | static void | 402 | static void |
416 | nfs_redirty_request(struct nfs_page *req) | 403 | nfs_mark_request_dirty(struct nfs_page *req) |
417 | { | 404 | { |
418 | __set_page_dirty_nobuffers(req->wb_page); | 405 | __set_page_dirty_nobuffers(req->wb_page); |
419 | } | 406 | } |
@@ -467,7 +454,7 @@ int nfs_reschedule_unstable_write(struct nfs_page *req) | |||
467 | return 1; | 454 | return 1; |
468 | } | 455 | } |
469 | if (test_and_clear_bit(PG_NEED_RESCHED, &req->wb_flags)) { | 456 | if (test_and_clear_bit(PG_NEED_RESCHED, &req->wb_flags)) { |
470 | nfs_redirty_request(req); | 457 | nfs_mark_request_dirty(req); |
471 | return 1; | 458 | return 1; |
472 | } | 459 | } |
473 | return 0; | 460 | return 0; |
@@ -597,6 +584,13 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | |||
597 | /* Loop over all inode entries and see if we find | 584 | /* Loop over all inode entries and see if we find |
598 | * A request for the page we wish to update | 585 | * A request for the page we wish to update |
599 | */ | 586 | */ |
587 | if (new) { | ||
588 | if (radix_tree_preload(GFP_NOFS)) { | ||
589 | nfs_release_request(new); | ||
590 | return ERR_PTR(-ENOMEM); | ||
591 | } | ||
592 | } | ||
593 | |||
600 | spin_lock(&inode->i_lock); | 594 | spin_lock(&inode->i_lock); |
601 | req = nfs_page_find_request_locked(page); | 595 | req = nfs_page_find_request_locked(page); |
602 | if (req) { | 596 | if (req) { |
@@ -607,28 +601,27 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | |||
607 | error = nfs_wait_on_request(req); | 601 | error = nfs_wait_on_request(req); |
608 | nfs_release_request(req); | 602 | nfs_release_request(req); |
609 | if (error < 0) { | 603 | if (error < 0) { |
610 | if (new) | 604 | if (new) { |
605 | radix_tree_preload_end(); | ||
611 | nfs_release_request(new); | 606 | nfs_release_request(new); |
607 | } | ||
612 | return ERR_PTR(error); | 608 | return ERR_PTR(error); |
613 | } | 609 | } |
614 | continue; | 610 | continue; |
615 | } | 611 | } |
616 | spin_unlock(&inode->i_lock); | 612 | spin_unlock(&inode->i_lock); |
617 | if (new) | 613 | if (new) { |
614 | radix_tree_preload_end(); | ||
618 | nfs_release_request(new); | 615 | nfs_release_request(new); |
616 | } | ||
619 | break; | 617 | break; |
620 | } | 618 | } |
621 | 619 | ||
622 | if (new) { | 620 | if (new) { |
623 | int error; | ||
624 | nfs_lock_request_dontget(new); | 621 | nfs_lock_request_dontget(new); |
625 | error = nfs_inode_add_request(inode, new); | 622 | nfs_inode_add_request(inode, new); |
626 | if (error) { | ||
627 | spin_unlock(&inode->i_lock); | ||
628 | nfs_unlock_request(new); | ||
629 | return ERR_PTR(error); | ||
630 | } | ||
631 | spin_unlock(&inode->i_lock); | 623 | spin_unlock(&inode->i_lock); |
624 | radix_tree_preload_end(); | ||
632 | req = new; | 625 | req = new; |
633 | goto zero_page; | 626 | goto zero_page; |
634 | } | 627 | } |
@@ -785,7 +778,7 @@ static int flush_task_priority(int how) | |||
785 | /* | 778 | /* |
786 | * Set up the argument/result storage required for the RPC call. | 779 | * Set up the argument/result storage required for the RPC call. |
787 | */ | 780 | */ |
788 | static void nfs_write_rpcsetup(struct nfs_page *req, | 781 | static int nfs_write_rpcsetup(struct nfs_page *req, |
789 | struct nfs_write_data *data, | 782 | struct nfs_write_data *data, |
790 | const struct rpc_call_ops *call_ops, | 783 | const struct rpc_call_ops *call_ops, |
791 | unsigned int count, unsigned int offset, | 784 | unsigned int count, unsigned int offset, |
@@ -806,6 +799,7 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
806 | .rpc_message = &msg, | 799 | .rpc_message = &msg, |
807 | .callback_ops = call_ops, | 800 | .callback_ops = call_ops, |
808 | .callback_data = data, | 801 | .callback_data = data, |
802 | .workqueue = nfsiod_workqueue, | ||
809 | .flags = flags, | 803 | .flags = flags, |
810 | .priority = priority, | 804 | .priority = priority, |
811 | }; | 805 | }; |
@@ -822,7 +816,7 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
822 | data->args.pgbase = req->wb_pgbase + offset; | 816 | data->args.pgbase = req->wb_pgbase + offset; |
823 | data->args.pages = data->pagevec; | 817 | data->args.pages = data->pagevec; |
824 | data->args.count = count; | 818 | data->args.count = count; |
825 | data->args.context = req->wb_context; | 819 | data->args.context = get_nfs_open_context(req->wb_context); |
826 | data->args.stable = NFS_UNSTABLE; | 820 | data->args.stable = NFS_UNSTABLE; |
827 | if (how & FLUSH_STABLE) { | 821 | if (how & FLUSH_STABLE) { |
828 | data->args.stable = NFS_DATA_SYNC; | 822 | data->args.stable = NFS_DATA_SYNC; |
@@ -847,8 +841,21 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
847 | (unsigned long long)data->args.offset); | 841 | (unsigned long long)data->args.offset); |
848 | 842 | ||
849 | task = rpc_run_task(&task_setup_data); | 843 | task = rpc_run_task(&task_setup_data); |
850 | if (!IS_ERR(task)) | 844 | if (IS_ERR(task)) |
851 | rpc_put_task(task); | 845 | return PTR_ERR(task); |
846 | rpc_put_task(task); | ||
847 | return 0; | ||
848 | } | ||
849 | |||
850 | /* If a nfs_flush_* function fails, it should remove reqs from @head and | ||
851 | * call this on each, which will prepare them to be retried on next | ||
852 | * writeback using standard nfs. | ||
853 | */ | ||
854 | static void nfs_redirty_request(struct nfs_page *req) | ||
855 | { | ||
856 | nfs_mark_request_dirty(req); | ||
857 | nfs_end_page_writeback(req->wb_page); | ||
858 | nfs_clear_page_tag_locked(req); | ||
852 | } | 859 | } |
853 | 860 | ||
854 | /* | 861 | /* |
@@ -863,6 +870,7 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned | |||
863 | size_t wsize = NFS_SERVER(inode)->wsize, nbytes; | 870 | size_t wsize = NFS_SERVER(inode)->wsize, nbytes; |
864 | unsigned int offset; | 871 | unsigned int offset; |
865 | int requests = 0; | 872 | int requests = 0; |
873 | int ret = 0; | ||
866 | LIST_HEAD(list); | 874 | LIST_HEAD(list); |
867 | 875 | ||
868 | nfs_list_remove_request(req); | 876 | nfs_list_remove_request(req); |
@@ -884,6 +892,8 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned | |||
884 | offset = 0; | 892 | offset = 0; |
885 | nbytes = count; | 893 | nbytes = count; |
886 | do { | 894 | do { |
895 | int ret2; | ||
896 | |||
887 | data = list_entry(list.next, struct nfs_write_data, pages); | 897 | data = list_entry(list.next, struct nfs_write_data, pages); |
888 | list_del_init(&data->pages); | 898 | list_del_init(&data->pages); |
889 | 899 | ||
@@ -891,13 +901,15 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned | |||
891 | 901 | ||
892 | if (nbytes < wsize) | 902 | if (nbytes < wsize) |
893 | wsize = nbytes; | 903 | wsize = nbytes; |
894 | nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, | 904 | ret2 = nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, |
895 | wsize, offset, how); | 905 | wsize, offset, how); |
906 | if (ret == 0) | ||
907 | ret = ret2; | ||
896 | offset += wsize; | 908 | offset += wsize; |
897 | nbytes -= wsize; | 909 | nbytes -= wsize; |
898 | } while (nbytes != 0); | 910 | } while (nbytes != 0); |
899 | 911 | ||
900 | return 0; | 912 | return ret; |
901 | 913 | ||
902 | out_bad: | 914 | out_bad: |
903 | while (!list_empty(&list)) { | 915 | while (!list_empty(&list)) { |
@@ -906,8 +918,6 @@ out_bad: | |||
906 | nfs_writedata_release(data); | 918 | nfs_writedata_release(data); |
907 | } | 919 | } |
908 | nfs_redirty_request(req); | 920 | nfs_redirty_request(req); |
909 | nfs_end_page_writeback(req->wb_page); | ||
910 | nfs_clear_page_tag_locked(req); | ||
911 | return -ENOMEM; | 921 | return -ENOMEM; |
912 | } | 922 | } |
913 | 923 | ||
@@ -940,16 +950,12 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned i | |||
940 | req = nfs_list_entry(data->pages.next); | 950 | req = nfs_list_entry(data->pages.next); |
941 | 951 | ||
942 | /* Set up the argument struct */ | 952 | /* Set up the argument struct */ |
943 | nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how); | 953 | return nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how); |
944 | |||
945 | return 0; | ||
946 | out_bad: | 954 | out_bad: |
947 | while (!list_empty(head)) { | 955 | while (!list_empty(head)) { |
948 | req = nfs_list_entry(head->next); | 956 | req = nfs_list_entry(head->next); |
949 | nfs_list_remove_request(req); | 957 | nfs_list_remove_request(req); |
950 | nfs_redirty_request(req); | 958 | nfs_redirty_request(req); |
951 | nfs_end_page_writeback(req->wb_page); | ||
952 | nfs_clear_page_tag_locked(req); | ||
953 | } | 959 | } |
954 | return -ENOMEM; | 960 | return -ENOMEM; |
955 | } | 961 | } |
@@ -972,7 +978,6 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) | |||
972 | { | 978 | { |
973 | struct nfs_write_data *data = calldata; | 979 | struct nfs_write_data *data = calldata; |
974 | struct nfs_page *req = data->req; | 980 | struct nfs_page *req = data->req; |
975 | struct page *page = req->wb_page; | ||
976 | 981 | ||
977 | dprintk("NFS: write (%s/%Ld %d@%Ld)", | 982 | dprintk("NFS: write (%s/%Ld %d@%Ld)", |
978 | req->wb_context->path.dentry->d_inode->i_sb->s_id, | 983 | req->wb_context->path.dentry->d_inode->i_sb->s_id, |
@@ -980,13 +985,20 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) | |||
980 | req->wb_bytes, | 985 | req->wb_bytes, |
981 | (long long)req_offset(req)); | 986 | (long long)req_offset(req)); |
982 | 987 | ||
983 | if (nfs_writeback_done(task, data) != 0) | 988 | nfs_writeback_done(task, data); |
984 | return; | 989 | } |
985 | 990 | ||
986 | if (task->tk_status < 0) { | 991 | static void nfs_writeback_release_partial(void *calldata) |
992 | { | ||
993 | struct nfs_write_data *data = calldata; | ||
994 | struct nfs_page *req = data->req; | ||
995 | struct page *page = req->wb_page; | ||
996 | int status = data->task.tk_status; | ||
997 | |||
998 | if (status < 0) { | ||
987 | nfs_set_pageerror(page); | 999 | nfs_set_pageerror(page); |
988 | nfs_context_set_write_error(req->wb_context, task->tk_status); | 1000 | nfs_context_set_write_error(req->wb_context, status); |
989 | dprintk(", error = %d\n", task->tk_status); | 1001 | dprintk(", error = %d\n", status); |
990 | goto out; | 1002 | goto out; |
991 | } | 1003 | } |
992 | 1004 | ||
@@ -1011,11 +1023,12 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) | |||
1011 | out: | 1023 | out: |
1012 | if (atomic_dec_and_test(&req->wb_complete)) | 1024 | if (atomic_dec_and_test(&req->wb_complete)) |
1013 | nfs_writepage_release(req); | 1025 | nfs_writepage_release(req); |
1026 | nfs_writedata_release(calldata); | ||
1014 | } | 1027 | } |
1015 | 1028 | ||
1016 | static const struct rpc_call_ops nfs_write_partial_ops = { | 1029 | static const struct rpc_call_ops nfs_write_partial_ops = { |
1017 | .rpc_call_done = nfs_writeback_done_partial, | 1030 | .rpc_call_done = nfs_writeback_done_partial, |
1018 | .rpc_release = nfs_writedata_release, | 1031 | .rpc_release = nfs_writeback_release_partial, |
1019 | }; | 1032 | }; |
1020 | 1033 | ||
1021 | /* | 1034 | /* |
@@ -1028,17 +1041,21 @@ static const struct rpc_call_ops nfs_write_partial_ops = { | |||
1028 | static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) | 1041 | static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) |
1029 | { | 1042 | { |
1030 | struct nfs_write_data *data = calldata; | 1043 | struct nfs_write_data *data = calldata; |
1031 | struct nfs_page *req; | ||
1032 | struct page *page; | ||
1033 | 1044 | ||
1034 | if (nfs_writeback_done(task, data) != 0) | 1045 | nfs_writeback_done(task, data); |
1035 | return; | 1046 | } |
1047 | |||
1048 | static void nfs_writeback_release_full(void *calldata) | ||
1049 | { | ||
1050 | struct nfs_write_data *data = calldata; | ||
1051 | int status = data->task.tk_status; | ||
1036 | 1052 | ||
1037 | /* Update attributes as result of writeback. */ | 1053 | /* Update attributes as result of writeback. */ |
1038 | while (!list_empty(&data->pages)) { | 1054 | while (!list_empty(&data->pages)) { |
1039 | req = nfs_list_entry(data->pages.next); | 1055 | struct nfs_page *req = nfs_list_entry(data->pages.next); |
1056 | struct page *page = req->wb_page; | ||
1057 | |||
1040 | nfs_list_remove_request(req); | 1058 | nfs_list_remove_request(req); |
1041 | page = req->wb_page; | ||
1042 | 1059 | ||
1043 | dprintk("NFS: write (%s/%Ld %d@%Ld)", | 1060 | dprintk("NFS: write (%s/%Ld %d@%Ld)", |
1044 | req->wb_context->path.dentry->d_inode->i_sb->s_id, | 1061 | req->wb_context->path.dentry->d_inode->i_sb->s_id, |
@@ -1046,10 +1063,10 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) | |||
1046 | req->wb_bytes, | 1063 | req->wb_bytes, |
1047 | (long long)req_offset(req)); | 1064 | (long long)req_offset(req)); |
1048 | 1065 | ||
1049 | if (task->tk_status < 0) { | 1066 | if (status < 0) { |
1050 | nfs_set_pageerror(page); | 1067 | nfs_set_pageerror(page); |
1051 | nfs_context_set_write_error(req->wb_context, task->tk_status); | 1068 | nfs_context_set_write_error(req->wb_context, status); |
1052 | dprintk(", error = %d\n", task->tk_status); | 1069 | dprintk(", error = %d\n", status); |
1053 | goto remove_request; | 1070 | goto remove_request; |
1054 | } | 1071 | } |
1055 | 1072 | ||
@@ -1069,11 +1086,12 @@ remove_request: | |||
1069 | next: | 1086 | next: |
1070 | nfs_clear_page_tag_locked(req); | 1087 | nfs_clear_page_tag_locked(req); |
1071 | } | 1088 | } |
1089 | nfs_writedata_release(calldata); | ||
1072 | } | 1090 | } |
1073 | 1091 | ||
1074 | static const struct rpc_call_ops nfs_write_full_ops = { | 1092 | static const struct rpc_call_ops nfs_write_full_ops = { |
1075 | .rpc_call_done = nfs_writeback_done_full, | 1093 | .rpc_call_done = nfs_writeback_done_full, |
1076 | .rpc_release = nfs_writedata_release, | 1094 | .rpc_release = nfs_writeback_release_full, |
1077 | }; | 1095 | }; |
1078 | 1096 | ||
1079 | 1097 | ||
@@ -1159,15 +1177,18 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1159 | 1177 | ||
1160 | 1178 | ||
1161 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1179 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
1162 | void nfs_commit_release(void *wdata) | 1180 | void nfs_commitdata_release(void *data) |
1163 | { | 1181 | { |
1182 | struct nfs_write_data *wdata = data; | ||
1183 | |||
1184 | put_nfs_open_context(wdata->args.context); | ||
1164 | nfs_commit_free(wdata); | 1185 | nfs_commit_free(wdata); |
1165 | } | 1186 | } |
1166 | 1187 | ||
1167 | /* | 1188 | /* |
1168 | * Set up the argument/result storage required for the RPC call. | 1189 | * Set up the argument/result storage required for the RPC call. |
1169 | */ | 1190 | */ |
1170 | static void nfs_commit_rpcsetup(struct list_head *head, | 1191 | static int nfs_commit_rpcsetup(struct list_head *head, |
1171 | struct nfs_write_data *data, | 1192 | struct nfs_write_data *data, |
1172 | int how) | 1193 | int how) |
1173 | { | 1194 | { |
@@ -1187,6 +1208,7 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1187 | .rpc_message = &msg, | 1208 | .rpc_message = &msg, |
1188 | .callback_ops = &nfs_commit_ops, | 1209 | .callback_ops = &nfs_commit_ops, |
1189 | .callback_data = data, | 1210 | .callback_data = data, |
1211 | .workqueue = nfsiod_workqueue, | ||
1190 | .flags = flags, | 1212 | .flags = flags, |
1191 | .priority = priority, | 1213 | .priority = priority, |
1192 | }; | 1214 | }; |
@@ -1203,6 +1225,7 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1203 | /* Note: we always request a commit of the entire inode */ | 1225 | /* Note: we always request a commit of the entire inode */ |
1204 | data->args.offset = 0; | 1226 | data->args.offset = 0; |
1205 | data->args.count = 0; | 1227 | data->args.count = 0; |
1228 | data->args.context = get_nfs_open_context(first->wb_context); | ||
1206 | data->res.count = 0; | 1229 | data->res.count = 0; |
1207 | data->res.fattr = &data->fattr; | 1230 | data->res.fattr = &data->fattr; |
1208 | data->res.verf = &data->verf; | 1231 | data->res.verf = &data->verf; |
@@ -1214,8 +1237,10 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1214 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); | 1237 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); |
1215 | 1238 | ||
1216 | task = rpc_run_task(&task_setup_data); | 1239 | task = rpc_run_task(&task_setup_data); |
1217 | if (!IS_ERR(task)) | 1240 | if (IS_ERR(task)) |
1218 | rpc_put_task(task); | 1241 | return PTR_ERR(task); |
1242 | rpc_put_task(task); | ||
1243 | return 0; | ||
1219 | } | 1244 | } |
1220 | 1245 | ||
1221 | /* | 1246 | /* |
@@ -1227,15 +1252,13 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how) | |||
1227 | struct nfs_write_data *data; | 1252 | struct nfs_write_data *data; |
1228 | struct nfs_page *req; | 1253 | struct nfs_page *req; |
1229 | 1254 | ||
1230 | data = nfs_commit_alloc(); | 1255 | data = nfs_commitdata_alloc(); |
1231 | 1256 | ||
1232 | if (!data) | 1257 | if (!data) |
1233 | goto out_bad; | 1258 | goto out_bad; |
1234 | 1259 | ||
1235 | /* Set up the argument struct */ | 1260 | /* Set up the argument struct */ |
1236 | nfs_commit_rpcsetup(head, data, how); | 1261 | return nfs_commit_rpcsetup(head, data, how); |
1237 | |||
1238 | return 0; | ||
1239 | out_bad: | 1262 | out_bad: |
1240 | while (!list_empty(head)) { | 1263 | while (!list_empty(head)) { |
1241 | req = nfs_list_entry(head->next); | 1264 | req = nfs_list_entry(head->next); |
@@ -1255,7 +1278,6 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how) | |||
1255 | static void nfs_commit_done(struct rpc_task *task, void *calldata) | 1278 | static void nfs_commit_done(struct rpc_task *task, void *calldata) |
1256 | { | 1279 | { |
1257 | struct nfs_write_data *data = calldata; | 1280 | struct nfs_write_data *data = calldata; |
1258 | struct nfs_page *req; | ||
1259 | 1281 | ||
1260 | dprintk("NFS: %5u nfs_commit_done (status %d)\n", | 1282 | dprintk("NFS: %5u nfs_commit_done (status %d)\n", |
1261 | task->tk_pid, task->tk_status); | 1283 | task->tk_pid, task->tk_status); |
@@ -1263,6 +1285,13 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
1263 | /* Call the NFS version-specific code */ | 1285 | /* Call the NFS version-specific code */ |
1264 | if (NFS_PROTO(data->inode)->commit_done(task, data) != 0) | 1286 | if (NFS_PROTO(data->inode)->commit_done(task, data) != 0) |
1265 | return; | 1287 | return; |
1288 | } | ||
1289 | |||
1290 | static void nfs_commit_release(void *calldata) | ||
1291 | { | ||
1292 | struct nfs_write_data *data = calldata; | ||
1293 | struct nfs_page *req; | ||
1294 | int status = data->task.tk_status; | ||
1266 | 1295 | ||
1267 | while (!list_empty(&data->pages)) { | 1296 | while (!list_empty(&data->pages)) { |
1268 | req = nfs_list_entry(data->pages.next); | 1297 | req = nfs_list_entry(data->pages.next); |
@@ -1277,10 +1306,10 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
1277 | (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), | 1306 | (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), |
1278 | req->wb_bytes, | 1307 | req->wb_bytes, |
1279 | (long long)req_offset(req)); | 1308 | (long long)req_offset(req)); |
1280 | if (task->tk_status < 0) { | 1309 | if (status < 0) { |
1281 | nfs_context_set_write_error(req->wb_context, task->tk_status); | 1310 | nfs_context_set_write_error(req->wb_context, status); |
1282 | nfs_inode_remove_request(req); | 1311 | nfs_inode_remove_request(req); |
1283 | dprintk(", error = %d\n", task->tk_status); | 1312 | dprintk(", error = %d\n", status); |
1284 | goto next; | 1313 | goto next; |
1285 | } | 1314 | } |
1286 | 1315 | ||
@@ -1297,10 +1326,11 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
1297 | } | 1326 | } |
1298 | /* We have a mismatch. Write the page again */ | 1327 | /* We have a mismatch. Write the page again */ |
1299 | dprintk(" mismatch\n"); | 1328 | dprintk(" mismatch\n"); |
1300 | nfs_redirty_request(req); | 1329 | nfs_mark_request_dirty(req); |
1301 | next: | 1330 | next: |
1302 | nfs_clear_page_tag_locked(req); | 1331 | nfs_clear_page_tag_locked(req); |
1303 | } | 1332 | } |
1333 | nfs_commitdata_release(calldata); | ||
1304 | } | 1334 | } |
1305 | 1335 | ||
1306 | static const struct rpc_call_ops nfs_commit_ops = { | 1336 | static const struct rpc_call_ops nfs_commit_ops = { |
@@ -1487,18 +1517,19 @@ static int nfs_wb_page_priority(struct inode *inode, struct page *page, | |||
1487 | }; | 1517 | }; |
1488 | int ret; | 1518 | int ret; |
1489 | 1519 | ||
1490 | BUG_ON(!PageLocked(page)); | 1520 | do { |
1491 | if (clear_page_dirty_for_io(page)) { | 1521 | if (clear_page_dirty_for_io(page)) { |
1492 | ret = nfs_writepage_locked(page, &wbc); | 1522 | ret = nfs_writepage_locked(page, &wbc); |
1523 | if (ret < 0) | ||
1524 | goto out_error; | ||
1525 | } else if (!PagePrivate(page)) | ||
1526 | break; | ||
1527 | ret = nfs_sync_mapping_wait(page->mapping, &wbc, how); | ||
1493 | if (ret < 0) | 1528 | if (ret < 0) |
1494 | goto out; | 1529 | goto out_error; |
1495 | } | 1530 | } while (PagePrivate(page)); |
1496 | if (!PagePrivate(page)) | 1531 | return 0; |
1497 | return 0; | 1532 | out_error: |
1498 | ret = nfs_sync_mapping_wait(page->mapping, &wbc, how); | ||
1499 | if (ret >= 0) | ||
1500 | return 0; | ||
1501 | out: | ||
1502 | __mark_inode_dirty(inode, I_DIRTY_PAGES); | 1533 | __mark_inode_dirty(inode, I_DIRTY_PAGES); |
1503 | return ret; | 1534 | return ret; |
1504 | } | 1535 | } |