diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-03-20 13:44:27 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-03-20 13:44:27 -0500 |
commit | 788e7a89a03e364855583c0ab4649b94925efbb9 (patch) | |
tree | 4434c93af133a92f550ba0ecc8d3254cb222e72d | |
parent | 7117bf3dfb10b534a017260d9fc643bc1d0afd2a (diff) |
NFS: Cleanup of NFS write code in preparation for asynchronous o_direct
This patch inverts the callback hierarchy for NFS write calls.
Instead of having the NFSv2/v3/v4-specific code set up the RPC callback
ops, we allow the original caller to do so. This allows for more
flexibility w.r.t. how to set up and tear down the nfs_write_data
structure while still allowing the NFSv3/v4 code to perform error
handling.
The greater flexibility is needed by the asynchronous O_DIRECT code, which
wants to be able to hold on to the original nfs_write_data structures after
the WRITE RPC call has completed in order to be able to replay them if the
COMMIT call determines that the server has rebooted.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | fs/nfs/nfs3proc.c | 66 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 54 | ||||
-rw-r--r-- | fs/nfs/proc.c | 24 | ||||
-rw-r--r-- | fs/nfs/write.c | 92 | ||||
-rw-r--r-- | include/linux/nfs_fs.h | 7 | ||||
-rw-r--r-- | include/linux/nfs_xdr.h | 3 |
6 files changed, 103 insertions, 143 deletions
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 740f8b1ab04d..c4f7de8830e9 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
@@ -849,29 +849,17 @@ nfs3_proc_read_setup(struct nfs_read_data *data) | |||
849 | rpc_call_setup(task, &msg, 0); | 849 | rpc_call_setup(task, &msg, 0); |
850 | } | 850 | } |
851 | 851 | ||
852 | static void nfs3_write_done(struct rpc_task *task, void *calldata) | 852 | static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data) |
853 | { | 853 | { |
854 | struct nfs_write_data *data = calldata; | ||
855 | |||
856 | if (nfs3_async_handle_jukebox(task, data->inode)) | 854 | if (nfs3_async_handle_jukebox(task, data->inode)) |
857 | return; | 855 | return -EAGAIN; |
858 | if (task->tk_status >= 0) | 856 | if (task->tk_status >= 0) |
859 | nfs_post_op_update_inode(data->inode, data->res.fattr); | 857 | nfs_post_op_update_inode(data->inode, data->res.fattr); |
860 | nfs_writeback_done(task, calldata); | 858 | return 0; |
861 | } | 859 | } |
862 | 860 | ||
863 | static const struct rpc_call_ops nfs3_write_ops = { | 861 | static void nfs3_proc_write_setup(struct nfs_write_data *data, int how) |
864 | .rpc_call_done = nfs3_write_done, | ||
865 | .rpc_release = nfs_writedata_release, | ||
866 | }; | ||
867 | |||
868 | static void | ||
869 | nfs3_proc_write_setup(struct nfs_write_data *data, int how) | ||
870 | { | 862 | { |
871 | struct rpc_task *task = &data->task; | ||
872 | struct inode *inode = data->inode; | ||
873 | int stable; | ||
874 | int flags; | ||
875 | struct rpc_message msg = { | 863 | struct rpc_message msg = { |
876 | .rpc_proc = &nfs3_procedures[NFS3PROC_WRITE], | 864 | .rpc_proc = &nfs3_procedures[NFS3PROC_WRITE], |
877 | .rpc_argp = &data->args, | 865 | .rpc_argp = &data->args, |
@@ -879,45 +867,28 @@ nfs3_proc_write_setup(struct nfs_write_data *data, int how) | |||
879 | .rpc_cred = data->cred, | 867 | .rpc_cred = data->cred, |
880 | }; | 868 | }; |
881 | 869 | ||
870 | data->args.stable = NFS_UNSTABLE; | ||
882 | if (how & FLUSH_STABLE) { | 871 | if (how & FLUSH_STABLE) { |
883 | if (!NFS_I(inode)->ncommit) | 872 | data->args.stable = NFS_FILE_SYNC; |
884 | stable = NFS_FILE_SYNC; | 873 | if (NFS_I(data->inode)->ncommit) |
885 | else | 874 | data->args.stable = NFS_DATA_SYNC; |
886 | stable = NFS_DATA_SYNC; | 875 | } |
887 | } else | ||
888 | stable = NFS_UNSTABLE; | ||
889 | data->args.stable = stable; | ||
890 | |||
891 | /* Set the initial flags for the task. */ | ||
892 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
893 | 876 | ||
894 | /* Finalize the task. */ | 877 | /* Finalize the task. */ |
895 | rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs3_write_ops, data); | 878 | rpc_call_setup(&data->task, &msg, 0); |
896 | rpc_call_setup(task, &msg, 0); | ||
897 | } | 879 | } |
898 | 880 | ||
899 | static void nfs3_commit_done(struct rpc_task *task, void *calldata) | 881 | static int nfs3_commit_done(struct rpc_task *task, struct nfs_write_data *data) |
900 | { | 882 | { |
901 | struct nfs_write_data *data = calldata; | ||
902 | |||
903 | if (nfs3_async_handle_jukebox(task, data->inode)) | 883 | if (nfs3_async_handle_jukebox(task, data->inode)) |
904 | return; | 884 | return -EAGAIN; |
905 | if (task->tk_status >= 0) | 885 | if (task->tk_status >= 0) |
906 | nfs_post_op_update_inode(data->inode, data->res.fattr); | 886 | nfs_post_op_update_inode(data->inode, data->res.fattr); |
907 | nfs_commit_done(task, calldata); | 887 | return 0; |
908 | } | 888 | } |
909 | 889 | ||
910 | static const struct rpc_call_ops nfs3_commit_ops = { | 890 | static void nfs3_proc_commit_setup(struct nfs_write_data *data, int how) |
911 | .rpc_call_done = nfs3_commit_done, | ||
912 | .rpc_release = nfs_commit_release, | ||
913 | }; | ||
914 | |||
915 | static void | ||
916 | nfs3_proc_commit_setup(struct nfs_write_data *data, int how) | ||
917 | { | 891 | { |
918 | struct rpc_task *task = &data->task; | ||
919 | struct inode *inode = data->inode; | ||
920 | int flags; | ||
921 | struct rpc_message msg = { | 892 | struct rpc_message msg = { |
922 | .rpc_proc = &nfs3_procedures[NFS3PROC_COMMIT], | 893 | .rpc_proc = &nfs3_procedures[NFS3PROC_COMMIT], |
923 | .rpc_argp = &data->args, | 894 | .rpc_argp = &data->args, |
@@ -925,12 +896,7 @@ nfs3_proc_commit_setup(struct nfs_write_data *data, int how) | |||
925 | .rpc_cred = data->cred, | 896 | .rpc_cred = data->cred, |
926 | }; | 897 | }; |
927 | 898 | ||
928 | /* Set the initial flags for the task. */ | 899 | rpc_call_setup(&data->task, &msg, 0); |
929 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
930 | |||
931 | /* Finalize the task. */ | ||
932 | rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs3_commit_ops, data); | ||
933 | rpc_call_setup(task, &msg, 0); | ||
934 | } | 900 | } |
935 | 901 | ||
936 | static int | 902 | static int |
@@ -970,7 +936,9 @@ struct nfs_rpc_ops nfs_v3_clientops = { | |||
970 | .decode_dirent = nfs3_decode_dirent, | 936 | .decode_dirent = nfs3_decode_dirent, |
971 | .read_setup = nfs3_proc_read_setup, | 937 | .read_setup = nfs3_proc_read_setup, |
972 | .write_setup = nfs3_proc_write_setup, | 938 | .write_setup = nfs3_proc_write_setup, |
939 | .write_done = nfs3_write_done, | ||
973 | .commit_setup = nfs3_proc_commit_setup, | 940 | .commit_setup = nfs3_proc_commit_setup, |
941 | .commit_done = nfs3_commit_done, | ||
974 | .file_open = nfs_open, | 942 | .file_open = nfs_open, |
975 | .file_release = nfs_release, | 943 | .file_release = nfs_release, |
976 | .lock = nfs3_proc_lock, | 944 | .lock = nfs3_proc_lock, |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index f1ff4fa6cce5..ef4dc315ecc2 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -2388,32 +2388,23 @@ nfs4_proc_read_setup(struct nfs_read_data *data) | |||
2388 | rpc_call_setup(task, &msg, 0); | 2388 | rpc_call_setup(task, &msg, 0); |
2389 | } | 2389 | } |
2390 | 2390 | ||
2391 | static void nfs4_write_done(struct rpc_task *task, void *calldata) | 2391 | static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) |
2392 | { | 2392 | { |
2393 | struct nfs_write_data *data = calldata; | ||
2394 | struct inode *inode = data->inode; | 2393 | struct inode *inode = data->inode; |
2395 | 2394 | ||
2396 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { | 2395 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { |
2397 | rpc_restart_call(task); | 2396 | rpc_restart_call(task); |
2398 | return; | 2397 | return -EAGAIN; |
2399 | } | 2398 | } |
2400 | if (task->tk_status >= 0) { | 2399 | if (task->tk_status >= 0) { |
2401 | renew_lease(NFS_SERVER(inode), data->timestamp); | 2400 | renew_lease(NFS_SERVER(inode), data->timestamp); |
2402 | nfs_post_op_update_inode(inode, data->res.fattr); | 2401 | nfs_post_op_update_inode(inode, data->res.fattr); |
2403 | } | 2402 | } |
2404 | /* Call back common NFS writeback processing */ | 2403 | return 0; |
2405 | nfs_writeback_done(task, calldata); | ||
2406 | } | 2404 | } |
2407 | 2405 | ||
2408 | static const struct rpc_call_ops nfs4_write_ops = { | 2406 | static void nfs4_proc_write_setup(struct nfs_write_data *data, int how) |
2409 | .rpc_call_done = nfs4_write_done, | ||
2410 | .rpc_release = nfs_writedata_release, | ||
2411 | }; | ||
2412 | |||
2413 | static void | ||
2414 | nfs4_proc_write_setup(struct nfs_write_data *data, int how) | ||
2415 | { | 2407 | { |
2416 | struct rpc_task *task = &data->task; | ||
2417 | struct rpc_message msg = { | 2408 | struct rpc_message msg = { |
2418 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE], | 2409 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE], |
2419 | .rpc_argp = &data->args, | 2410 | .rpc_argp = &data->args, |
@@ -2423,7 +2414,6 @@ nfs4_proc_write_setup(struct nfs_write_data *data, int how) | |||
2423 | struct inode *inode = data->inode; | 2414 | struct inode *inode = data->inode; |
2424 | struct nfs_server *server = NFS_SERVER(inode); | 2415 | struct nfs_server *server = NFS_SERVER(inode); |
2425 | int stable; | 2416 | int stable; |
2426 | int flags; | ||
2427 | 2417 | ||
2428 | if (how & FLUSH_STABLE) { | 2418 | if (how & FLUSH_STABLE) { |
2429 | if (!NFS_I(inode)->ncommit) | 2419 | if (!NFS_I(inode)->ncommit) |
@@ -2438,57 +2428,37 @@ nfs4_proc_write_setup(struct nfs_write_data *data, int how) | |||
2438 | 2428 | ||
2439 | data->timestamp = jiffies; | 2429 | data->timestamp = jiffies; |
2440 | 2430 | ||
2441 | /* Set the initial flags for the task. */ | ||
2442 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
2443 | |||
2444 | /* Finalize the task. */ | 2431 | /* Finalize the task. */ |
2445 | rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs4_write_ops, data); | 2432 | rpc_call_setup(&data->task, &msg, 0); |
2446 | rpc_call_setup(task, &msg, 0); | ||
2447 | } | 2433 | } |
2448 | 2434 | ||
2449 | static void nfs4_commit_done(struct rpc_task *task, void *calldata) | 2435 | static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) |
2450 | { | 2436 | { |
2451 | struct nfs_write_data *data = calldata; | ||
2452 | struct inode *inode = data->inode; | 2437 | struct inode *inode = data->inode; |
2453 | 2438 | ||
2454 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { | 2439 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { |
2455 | rpc_restart_call(task); | 2440 | rpc_restart_call(task); |
2456 | return; | 2441 | return -EAGAIN; |
2457 | } | 2442 | } |
2458 | if (task->tk_status >= 0) | 2443 | if (task->tk_status >= 0) |
2459 | nfs_post_op_update_inode(inode, data->res.fattr); | 2444 | nfs_post_op_update_inode(inode, data->res.fattr); |
2460 | /* Call back common NFS writeback processing */ | 2445 | return 0; |
2461 | nfs_commit_done(task, calldata); | ||
2462 | } | 2446 | } |
2463 | 2447 | ||
2464 | static const struct rpc_call_ops nfs4_commit_ops = { | 2448 | static void nfs4_proc_commit_setup(struct nfs_write_data *data, int how) |
2465 | .rpc_call_done = nfs4_commit_done, | ||
2466 | .rpc_release = nfs_commit_release, | ||
2467 | }; | ||
2468 | |||
2469 | static void | ||
2470 | nfs4_proc_commit_setup(struct nfs_write_data *data, int how) | ||
2471 | { | 2449 | { |
2472 | struct rpc_task *task = &data->task; | ||
2473 | struct rpc_message msg = { | 2450 | struct rpc_message msg = { |
2474 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT], | 2451 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT], |
2475 | .rpc_argp = &data->args, | 2452 | .rpc_argp = &data->args, |
2476 | .rpc_resp = &data->res, | 2453 | .rpc_resp = &data->res, |
2477 | .rpc_cred = data->cred, | 2454 | .rpc_cred = data->cred, |
2478 | }; | 2455 | }; |
2479 | struct inode *inode = data->inode; | 2456 | struct nfs_server *server = NFS_SERVER(data->inode); |
2480 | struct nfs_server *server = NFS_SERVER(inode); | ||
2481 | int flags; | ||
2482 | 2457 | ||
2483 | data->args.bitmask = server->attr_bitmask; | 2458 | data->args.bitmask = server->attr_bitmask; |
2484 | data->res.server = server; | 2459 | data->res.server = server; |
2485 | 2460 | ||
2486 | /* Set the initial flags for the task. */ | 2461 | rpc_call_setup(&data->task, &msg, 0); |
2487 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
2488 | |||
2489 | /* Finalize the task. */ | ||
2490 | rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs4_commit_ops, data); | ||
2491 | rpc_call_setup(task, &msg, 0); | ||
2492 | } | 2462 | } |
2493 | 2463 | ||
2494 | /* | 2464 | /* |
@@ -3648,7 +3618,9 @@ struct nfs_rpc_ops nfs_v4_clientops = { | |||
3648 | .decode_dirent = nfs4_decode_dirent, | 3618 | .decode_dirent = nfs4_decode_dirent, |
3649 | .read_setup = nfs4_proc_read_setup, | 3619 | .read_setup = nfs4_proc_read_setup, |
3650 | .write_setup = nfs4_proc_write_setup, | 3620 | .write_setup = nfs4_proc_write_setup, |
3621 | .write_done = nfs4_write_done, | ||
3651 | .commit_setup = nfs4_proc_commit_setup, | 3622 | .commit_setup = nfs4_proc_commit_setup, |
3623 | .commit_done = nfs4_commit_done, | ||
3652 | .file_open = nfs_open, | 3624 | .file_open = nfs_open, |
3653 | .file_release = nfs_release, | 3625 | .file_release = nfs_release, |
3654 | .lock = nfs4_proc_lock, | 3626 | .lock = nfs4_proc_lock, |
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 2b051ab8bea8..608aa5932a1d 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
@@ -654,26 +654,15 @@ nfs_proc_read_setup(struct nfs_read_data *data) | |||
654 | rpc_call_setup(task, &msg, 0); | 654 | rpc_call_setup(task, &msg, 0); |
655 | } | 655 | } |
656 | 656 | ||
657 | static void nfs_write_done(struct rpc_task *task, void *calldata) | 657 | static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data) |
658 | { | 658 | { |
659 | struct nfs_write_data *data = calldata; | ||
660 | |||
661 | if (task->tk_status >= 0) | 659 | if (task->tk_status >= 0) |
662 | nfs_post_op_update_inode(data->inode, data->res.fattr); | 660 | nfs_post_op_update_inode(data->inode, data->res.fattr); |
663 | nfs_writeback_done(task, calldata); | 661 | return 0; |
664 | } | 662 | } |
665 | 663 | ||
666 | static const struct rpc_call_ops nfs_write_ops = { | 664 | static void nfs_proc_write_setup(struct nfs_write_data *data, int how) |
667 | .rpc_call_done = nfs_write_done, | ||
668 | .rpc_release = nfs_writedata_release, | ||
669 | }; | ||
670 | |||
671 | static void | ||
672 | nfs_proc_write_setup(struct nfs_write_data *data, int how) | ||
673 | { | 665 | { |
674 | struct rpc_task *task = &data->task; | ||
675 | struct inode *inode = data->inode; | ||
676 | int flags; | ||
677 | struct rpc_message msg = { | 666 | struct rpc_message msg = { |
678 | .rpc_proc = &nfs_procedures[NFSPROC_WRITE], | 667 | .rpc_proc = &nfs_procedures[NFSPROC_WRITE], |
679 | .rpc_argp = &data->args, | 668 | .rpc_argp = &data->args, |
@@ -684,12 +673,8 @@ nfs_proc_write_setup(struct nfs_write_data *data, int how) | |||
684 | /* Note: NFSv2 ignores @stable and always uses NFS_FILE_SYNC */ | 673 | /* Note: NFSv2 ignores @stable and always uses NFS_FILE_SYNC */ |
685 | data->args.stable = NFS_FILE_SYNC; | 674 | data->args.stable = NFS_FILE_SYNC; |
686 | 675 | ||
687 | /* Set the initial flags for the task. */ | ||
688 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
689 | |||
690 | /* Finalize the task. */ | 676 | /* Finalize the task. */ |
691 | rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs_write_ops, data); | 677 | rpc_call_setup(&data->task, &msg, 0); |
692 | rpc_call_setup(task, &msg, 0); | ||
693 | } | 678 | } |
694 | 679 | ||
695 | static void | 680 | static void |
@@ -736,6 +721,7 @@ struct nfs_rpc_ops nfs_v2_clientops = { | |||
736 | .decode_dirent = nfs_decode_dirent, | 721 | .decode_dirent = nfs_decode_dirent, |
737 | .read_setup = nfs_proc_read_setup, | 722 | .read_setup = nfs_proc_read_setup, |
738 | .write_setup = nfs_proc_write_setup, | 723 | .write_setup = nfs_proc_write_setup, |
724 | .write_done = nfs_write_done, | ||
739 | .commit_setup = nfs_proc_commit_setup, | 725 | .commit_setup = nfs_proc_commit_setup, |
740 | .file_open = nfs_open, | 726 | .file_open = nfs_open, |
741 | .file_release = nfs_release, | 727 | .file_release = nfs_release, |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index e7c8361cf201..5912274ff1a1 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -77,12 +77,14 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context*, | |||
77 | struct inode *, | 77 | struct inode *, |
78 | struct page *, | 78 | struct page *, |
79 | unsigned int, unsigned int); | 79 | unsigned int, unsigned int); |
80 | static void nfs_writeback_done_partial(struct nfs_write_data *, int); | 80 | static int nfs_writeback_done(struct rpc_task *, struct nfs_write_data *); |
81 | static void nfs_writeback_done_full(struct nfs_write_data *, int); | ||
82 | static int nfs_wait_on_write_congestion(struct address_space *, int); | 81 | static int nfs_wait_on_write_congestion(struct address_space *, int); |
83 | static int nfs_wait_on_requests(struct inode *, unsigned long, unsigned int); | 82 | static int nfs_wait_on_requests(struct inode *, unsigned long, unsigned int); |
84 | static int nfs_flush_inode(struct inode *inode, unsigned long idx_start, | 83 | static int nfs_flush_inode(struct inode *inode, unsigned long idx_start, |
85 | unsigned int npages, int how); | 84 | unsigned int npages, int how); |
85 | static const struct rpc_call_ops nfs_write_partial_ops; | ||
86 | static const struct rpc_call_ops nfs_write_full_ops; | ||
87 | static const struct rpc_call_ops nfs_commit_ops; | ||
86 | 88 | ||
87 | static kmem_cache_t *nfs_wdata_cachep; | 89 | static kmem_cache_t *nfs_wdata_cachep; |
88 | mempool_t *nfs_wdata_mempool; | 90 | mempool_t *nfs_wdata_mempool; |
@@ -872,10 +874,12 @@ static inline int flush_task_priority(int how) | |||
872 | */ | 874 | */ |
873 | static void nfs_write_rpcsetup(struct nfs_page *req, | 875 | static void nfs_write_rpcsetup(struct nfs_page *req, |
874 | struct nfs_write_data *data, | 876 | struct nfs_write_data *data, |
877 | const struct rpc_call_ops *call_ops, | ||
875 | unsigned int count, unsigned int offset, | 878 | unsigned int count, unsigned int offset, |
876 | int how) | 879 | int how) |
877 | { | 880 | { |
878 | struct inode *inode; | 881 | struct inode *inode; |
882 | int flags; | ||
879 | 883 | ||
880 | /* Set up the RPC argument and reply structs | 884 | /* Set up the RPC argument and reply structs |
881 | * NB: take care not to mess about with data->commit et al. */ | 885 | * NB: take care not to mess about with data->commit et al. */ |
@@ -896,6 +900,9 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
896 | data->res.verf = &data->verf; | 900 | data->res.verf = &data->verf; |
897 | nfs_fattr_init(&data->fattr); | 901 | nfs_fattr_init(&data->fattr); |
898 | 902 | ||
903 | /* Set up the initial task struct. */ | ||
904 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
905 | rpc_init_task(&data->task, NFS_CLIENT(inode), flags, call_ops, data); | ||
899 | NFS_PROTO(inode)->write_setup(data, how); | 906 | NFS_PROTO(inode)->write_setup(data, how); |
900 | 907 | ||
901 | data->task.tk_priority = flush_task_priority(how); | 908 | data->task.tk_priority = flush_task_priority(how); |
@@ -959,14 +966,15 @@ static int nfs_flush_multi(struct list_head *head, struct inode *inode, int how) | |||
959 | list_del_init(&data->pages); | 966 | list_del_init(&data->pages); |
960 | 967 | ||
961 | data->pagevec[0] = page; | 968 | data->pagevec[0] = page; |
962 | data->complete = nfs_writeback_done_partial; | ||
963 | 969 | ||
964 | if (nbytes > wsize) { | 970 | if (nbytes > wsize) { |
965 | nfs_write_rpcsetup(req, data, wsize, offset, how); | 971 | nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, |
972 | wsize, offset, how); | ||
966 | offset += wsize; | 973 | offset += wsize; |
967 | nbytes -= wsize; | 974 | nbytes -= wsize; |
968 | } else { | 975 | } else { |
969 | nfs_write_rpcsetup(req, data, nbytes, offset, how); | 976 | nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, |
977 | nbytes, offset, how); | ||
970 | nbytes = 0; | 978 | nbytes = 0; |
971 | } | 979 | } |
972 | nfs_execute_write(data); | 980 | nfs_execute_write(data); |
@@ -1020,9 +1028,8 @@ static int nfs_flush_one(struct list_head *head, struct inode *inode, int how) | |||
1020 | } | 1028 | } |
1021 | req = nfs_list_entry(data->pages.next); | 1029 | req = nfs_list_entry(data->pages.next); |
1022 | 1030 | ||
1023 | data->complete = nfs_writeback_done_full; | ||
1024 | /* Set up the argument struct */ | 1031 | /* Set up the argument struct */ |
1025 | nfs_write_rpcsetup(req, data, count, 0, how); | 1032 | nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how); |
1026 | 1033 | ||
1027 | nfs_execute_write(data); | 1034 | nfs_execute_write(data); |
1028 | return 0; | 1035 | return 0; |
@@ -1066,8 +1073,9 @@ nfs_flush_list(struct list_head *head, int wpages, int how) | |||
1066 | /* | 1073 | /* |
1067 | * Handle a write reply that flushed part of a page. | 1074 | * Handle a write reply that flushed part of a page. |
1068 | */ | 1075 | */ |
1069 | static void nfs_writeback_done_partial(struct nfs_write_data *data, int status) | 1076 | static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) |
1070 | { | 1077 | { |
1078 | struct nfs_write_data *data = calldata; | ||
1071 | struct nfs_page *req = data->req; | 1079 | struct nfs_page *req = data->req; |
1072 | struct page *page = req->wb_page; | 1080 | struct page *page = req->wb_page; |
1073 | 1081 | ||
@@ -1077,11 +1085,14 @@ static void nfs_writeback_done_partial(struct nfs_write_data *data, int status) | |||
1077 | req->wb_bytes, | 1085 | req->wb_bytes, |
1078 | (long long)req_offset(req)); | 1086 | (long long)req_offset(req)); |
1079 | 1087 | ||
1080 | if (status < 0) { | 1088 | if (nfs_writeback_done(task, data) != 0) |
1089 | return; | ||
1090 | |||
1091 | if (task->tk_status < 0) { | ||
1081 | ClearPageUptodate(page); | 1092 | ClearPageUptodate(page); |
1082 | SetPageError(page); | 1093 | SetPageError(page); |
1083 | req->wb_context->error = status; | 1094 | req->wb_context->error = task->tk_status; |
1084 | dprintk(", error = %d\n", status); | 1095 | dprintk(", error = %d\n", task->tk_status); |
1085 | } else { | 1096 | } else { |
1086 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1097 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
1087 | if (data->verf.committed < NFS_FILE_SYNC) { | 1098 | if (data->verf.committed < NFS_FILE_SYNC) { |
@@ -1102,6 +1113,11 @@ static void nfs_writeback_done_partial(struct nfs_write_data *data, int status) | |||
1102 | nfs_writepage_release(req); | 1113 | nfs_writepage_release(req); |
1103 | } | 1114 | } |
1104 | 1115 | ||
1116 | static const struct rpc_call_ops nfs_write_partial_ops = { | ||
1117 | .rpc_call_done = nfs_writeback_done_partial, | ||
1118 | .rpc_release = nfs_writedata_release, | ||
1119 | }; | ||
1120 | |||
1105 | /* | 1121 | /* |
1106 | * Handle a write reply that flushes a whole page. | 1122 | * Handle a write reply that flushes a whole page. |
1107 | * | 1123 | * |
@@ -1109,11 +1125,15 @@ static void nfs_writeback_done_partial(struct nfs_write_data *data, int status) | |||
1109 | * writebacks since the page->count is kept > 1 for as long | 1125 | * writebacks since the page->count is kept > 1 for as long |
1110 | * as the page has a write request pending. | 1126 | * as the page has a write request pending. |
1111 | */ | 1127 | */ |
1112 | static void nfs_writeback_done_full(struct nfs_write_data *data, int status) | 1128 | static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) |
1113 | { | 1129 | { |
1130 | struct nfs_write_data *data = calldata; | ||
1114 | struct nfs_page *req; | 1131 | struct nfs_page *req; |
1115 | struct page *page; | 1132 | struct page *page; |
1116 | 1133 | ||
1134 | if (nfs_writeback_done(task, data) != 0) | ||
1135 | return; | ||
1136 | |||
1117 | /* Update attributes as result of writeback. */ | 1137 | /* Update attributes as result of writeback. */ |
1118 | while (!list_empty(&data->pages)) { | 1138 | while (!list_empty(&data->pages)) { |
1119 | req = nfs_list_entry(data->pages.next); | 1139 | req = nfs_list_entry(data->pages.next); |
@@ -1126,13 +1146,13 @@ static void nfs_writeback_done_full(struct nfs_write_data *data, int status) | |||
1126 | req->wb_bytes, | 1146 | req->wb_bytes, |
1127 | (long long)req_offset(req)); | 1147 | (long long)req_offset(req)); |
1128 | 1148 | ||
1129 | if (status < 0) { | 1149 | if (task->tk_status < 0) { |
1130 | ClearPageUptodate(page); | 1150 | ClearPageUptodate(page); |
1131 | SetPageError(page); | 1151 | SetPageError(page); |
1132 | req->wb_context->error = status; | 1152 | req->wb_context->error = task->tk_status; |
1133 | end_page_writeback(page); | 1153 | end_page_writeback(page); |
1134 | nfs_inode_remove_request(req); | 1154 | nfs_inode_remove_request(req); |
1135 | dprintk(", error = %d\n", status); | 1155 | dprintk(", error = %d\n", task->tk_status); |
1136 | goto next; | 1156 | goto next; |
1137 | } | 1157 | } |
1138 | end_page_writeback(page); | 1158 | end_page_writeback(page); |
@@ -1154,18 +1174,28 @@ static void nfs_writeback_done_full(struct nfs_write_data *data, int status) | |||
1154 | } | 1174 | } |
1155 | } | 1175 | } |
1156 | 1176 | ||
1177 | static const struct rpc_call_ops nfs_write_full_ops = { | ||
1178 | .rpc_call_done = nfs_writeback_done_full, | ||
1179 | .rpc_release = nfs_writedata_release, | ||
1180 | }; | ||
1181 | |||
1182 | |||
1157 | /* | 1183 | /* |
1158 | * This function is called when the WRITE call is complete. | 1184 | * This function is called when the WRITE call is complete. |
1159 | */ | 1185 | */ |
1160 | void nfs_writeback_done(struct rpc_task *task, void *calldata) | 1186 | static int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) |
1161 | { | 1187 | { |
1162 | struct nfs_write_data *data = calldata; | ||
1163 | struct nfs_writeargs *argp = &data->args; | 1188 | struct nfs_writeargs *argp = &data->args; |
1164 | struct nfs_writeres *resp = &data->res; | 1189 | struct nfs_writeres *resp = &data->res; |
1190 | int status; | ||
1165 | 1191 | ||
1166 | dprintk("NFS: %4d nfs_writeback_done (status %d)\n", | 1192 | dprintk("NFS: %4d nfs_writeback_done (status %d)\n", |
1167 | task->tk_pid, task->tk_status); | 1193 | task->tk_pid, task->tk_status); |
1168 | 1194 | ||
1195 | /* Call the NFS version-specific code */ | ||
1196 | status = NFS_PROTO(data->inode)->write_done(task, data); | ||
1197 | if (status != 0) | ||
1198 | return status; | ||
1169 | nfs_add_stats(data->inode, NFSIOS_SERVERWRITTENBYTES, resp->count); | 1199 | nfs_add_stats(data->inode, NFSIOS_SERVERWRITTENBYTES, resp->count); |
1170 | 1200 | ||
1171 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1201 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
@@ -1210,7 +1240,7 @@ void nfs_writeback_done(struct rpc_task *task, void *calldata) | |||
1210 | argp->stable = NFS_FILE_SYNC; | 1240 | argp->stable = NFS_FILE_SYNC; |
1211 | } | 1241 | } |
1212 | rpc_restart_call(task); | 1242 | rpc_restart_call(task); |
1213 | return; | 1243 | return -EAGAIN; |
1214 | } | 1244 | } |
1215 | if (time_before(complain, jiffies)) { | 1245 | if (time_before(complain, jiffies)) { |
1216 | printk(KERN_WARNING | 1246 | printk(KERN_WARNING |
@@ -1221,11 +1251,7 @@ void nfs_writeback_done(struct rpc_task *task, void *calldata) | |||
1221 | /* Can't do anything about it except throw an error. */ | 1251 | /* Can't do anything about it except throw an error. */ |
1222 | task->tk_status = -EIO; | 1252 | task->tk_status = -EIO; |
1223 | } | 1253 | } |
1224 | 1254 | return 0; | |
1225 | /* | ||
1226 | * Process the nfs_page list | ||
1227 | */ | ||
1228 | data->complete(data, task->tk_status); | ||
1229 | } | 1255 | } |
1230 | 1256 | ||
1231 | 1257 | ||
@@ -1239,10 +1265,12 @@ void nfs_commit_release(void *wdata) | |||
1239 | * Set up the argument/result storage required for the RPC call. | 1265 | * Set up the argument/result storage required for the RPC call. |
1240 | */ | 1266 | */ |
1241 | static void nfs_commit_rpcsetup(struct list_head *head, | 1267 | static void nfs_commit_rpcsetup(struct list_head *head, |
1242 | struct nfs_write_data *data, int how) | 1268 | struct nfs_write_data *data, |
1269 | int how) | ||
1243 | { | 1270 | { |
1244 | struct nfs_page *first; | 1271 | struct nfs_page *first; |
1245 | struct inode *inode; | 1272 | struct inode *inode; |
1273 | int flags; | ||
1246 | 1274 | ||
1247 | /* Set up the RPC argument and reply structs | 1275 | /* Set up the RPC argument and reply structs |
1248 | * NB: take care not to mess about with data->commit et al. */ | 1276 | * NB: take care not to mess about with data->commit et al. */ |
@@ -1262,7 +1290,10 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1262 | data->res.fattr = &data->fattr; | 1290 | data->res.fattr = &data->fattr; |
1263 | data->res.verf = &data->verf; | 1291 | data->res.verf = &data->verf; |
1264 | nfs_fattr_init(&data->fattr); | 1292 | nfs_fattr_init(&data->fattr); |
1265 | 1293 | ||
1294 | /* Set up the initial task struct. */ | ||
1295 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
1296 | rpc_init_task(&data->task, NFS_CLIENT(inode), flags, &nfs_commit_ops, data); | ||
1266 | NFS_PROTO(inode)->commit_setup(data, how); | 1297 | NFS_PROTO(inode)->commit_setup(data, how); |
1267 | 1298 | ||
1268 | data->task.tk_priority = flush_task_priority(how); | 1299 | data->task.tk_priority = flush_task_priority(how); |
@@ -1303,7 +1334,7 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how) | |||
1303 | /* | 1334 | /* |
1304 | * COMMIT call returned | 1335 | * COMMIT call returned |
1305 | */ | 1336 | */ |
1306 | void nfs_commit_done(struct rpc_task *task, void *calldata) | 1337 | static void nfs_commit_done(struct rpc_task *task, void *calldata) |
1307 | { | 1338 | { |
1308 | struct nfs_write_data *data = calldata; | 1339 | struct nfs_write_data *data = calldata; |
1309 | struct nfs_page *req; | 1340 | struct nfs_page *req; |
@@ -1312,6 +1343,10 @@ void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
1312 | dprintk("NFS: %4d nfs_commit_done (status %d)\n", | 1343 | dprintk("NFS: %4d nfs_commit_done (status %d)\n", |
1313 | task->tk_pid, task->tk_status); | 1344 | task->tk_pid, task->tk_status); |
1314 | 1345 | ||
1346 | /* Call the NFS version-specific code */ | ||
1347 | if (NFS_PROTO(data->inode)->commit_done(task, data) != 0) | ||
1348 | return; | ||
1349 | |||
1315 | while (!list_empty(&data->pages)) { | 1350 | while (!list_empty(&data->pages)) { |
1316 | req = nfs_list_entry(data->pages.next); | 1351 | req = nfs_list_entry(data->pages.next); |
1317 | nfs_list_remove_request(req); | 1352 | nfs_list_remove_request(req); |
@@ -1345,6 +1380,11 @@ void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
1345 | } | 1380 | } |
1346 | sub_page_state(nr_unstable,res); | 1381 | sub_page_state(nr_unstable,res); |
1347 | } | 1382 | } |
1383 | |||
1384 | static const struct rpc_call_ops nfs_commit_ops = { | ||
1385 | .rpc_call_done = nfs_commit_done, | ||
1386 | .rpc_release = nfs_commit_release, | ||
1387 | }; | ||
1348 | #endif | 1388 | #endif |
1349 | 1389 | ||
1350 | static int nfs_flush_inode(struct inode *inode, unsigned long idx_start, | 1390 | static int nfs_flush_inode(struct inode *inode, unsigned long idx_start, |
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index b71da4d4b137..782e59765696 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
@@ -407,13 +407,6 @@ extern int nfs_writepage(struct page *page, struct writeback_control *wbc); | |||
407 | extern int nfs_writepages(struct address_space *, struct writeback_control *); | 407 | extern int nfs_writepages(struct address_space *, struct writeback_control *); |
408 | extern int nfs_flush_incompatible(struct file *file, struct page *page); | 408 | extern int nfs_flush_incompatible(struct file *file, struct page *page); |
409 | extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int); | 409 | extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int); |
410 | extern void nfs_writeback_done(struct rpc_task *task, void *data); | ||
411 | extern void nfs_writedata_release(void *data); | ||
412 | |||
413 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | ||
414 | extern void nfs_commit_done(struct rpc_task *, void *data); | ||
415 | extern void nfs_commit_release(void *data); | ||
416 | #endif | ||
417 | 410 | ||
418 | /* | 411 | /* |
419 | * Try to write back everything synchronously (but check the | 412 | * Try to write back everything synchronously (but check the |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 6d6f69ec5675..277750cc70c0 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
@@ -714,7 +714,6 @@ struct nfs_write_data { | |||
714 | #ifdef CONFIG_NFS_V4 | 714 | #ifdef CONFIG_NFS_V4 |
715 | unsigned long timestamp; /* For lease renewal */ | 715 | unsigned long timestamp; /* For lease renewal */ |
716 | #endif | 716 | #endif |
717 | void (*complete) (struct nfs_write_data *, int); | ||
718 | struct page *page_array[NFS_PAGEVEC_SIZE + 1]; | 717 | struct page *page_array[NFS_PAGEVEC_SIZE + 1]; |
719 | }; | 718 | }; |
720 | 719 | ||
@@ -770,7 +769,9 @@ struct nfs_rpc_ops { | |||
770 | u32 * (*decode_dirent)(u32 *, struct nfs_entry *, int plus); | 769 | u32 * (*decode_dirent)(u32 *, struct nfs_entry *, int plus); |
771 | void (*read_setup) (struct nfs_read_data *); | 770 | void (*read_setup) (struct nfs_read_data *); |
772 | void (*write_setup) (struct nfs_write_data *, int how); | 771 | void (*write_setup) (struct nfs_write_data *, int how); |
772 | int (*write_done) (struct rpc_task *, struct nfs_write_data *); | ||
773 | void (*commit_setup) (struct nfs_write_data *, int how); | 773 | void (*commit_setup) (struct nfs_write_data *, int how); |
774 | int (*commit_done) (struct rpc_task *, struct nfs_write_data *); | ||
774 | int (*file_open) (struct inode *, struct file *); | 775 | int (*file_open) (struct inode *, struct file *); |
775 | int (*file_release) (struct inode *, struct file *); | 776 | int (*file_release) (struct inode *, struct file *); |
776 | int (*lock)(struct file *, int, struct file_lock *); | 777 | int (*lock)(struct file *, int, struct file_lock *); |