diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/nfs4proc.c | 110 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 6 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 14 |
3 files changed, 86 insertions, 44 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 9ba89e7cdd28..5154ddf6d9a5 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -189,6 +189,21 @@ static void update_changeattr(struct inode *inode, struct nfs4_change_info *cinf | |||
189 | nfsi->change_attr = cinfo->after; | 189 | nfsi->change_attr = cinfo->after; |
190 | } | 190 | } |
191 | 191 | ||
192 | /* Helper for asynchronous RPC calls */ | ||
193 | static int nfs4_call_async(struct rpc_clnt *clnt, rpc_action tk_begin, | ||
194 | rpc_action tk_exit, void *calldata) | ||
195 | { | ||
196 | struct rpc_task *task; | ||
197 | |||
198 | if (!(task = rpc_new_task(clnt, tk_exit, RPC_TASK_ASYNC))) | ||
199 | return -ENOMEM; | ||
200 | |||
201 | task->tk_calldata = calldata; | ||
202 | task->tk_action = tk_begin; | ||
203 | rpc_execute(task); | ||
204 | return 0; | ||
205 | } | ||
206 | |||
192 | static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) | 207 | static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) |
193 | { | 208 | { |
194 | struct inode *inode = state->inode; | 209 | struct inode *inode = state->inode; |
@@ -810,11 +825,24 @@ struct nfs4_closedata { | |||
810 | struct nfs_closeres res; | 825 | struct nfs_closeres res; |
811 | }; | 826 | }; |
812 | 827 | ||
828 | static void nfs4_free_closedata(struct nfs4_closedata *calldata) | ||
829 | { | ||
830 | struct nfs4_state *state = calldata->state; | ||
831 | struct nfs4_state_owner *sp = state->owner; | ||
832 | struct nfs_server *server = NFS_SERVER(calldata->inode); | ||
833 | |||
834 | nfs4_put_open_state(calldata->state); | ||
835 | nfs_free_seqid(calldata->arg.seqid); | ||
836 | up(&sp->so_sema); | ||
837 | nfs4_put_state_owner(sp); | ||
838 | up_read(&server->nfs4_state->cl_sem); | ||
839 | kfree(calldata); | ||
840 | } | ||
841 | |||
813 | static void nfs4_close_done(struct rpc_task *task) | 842 | static void nfs4_close_done(struct rpc_task *task) |
814 | { | 843 | { |
815 | struct nfs4_closedata *calldata = (struct nfs4_closedata *)task->tk_calldata; | 844 | struct nfs4_closedata *calldata = (struct nfs4_closedata *)task->tk_calldata; |
816 | struct nfs4_state *state = calldata->state; | 845 | struct nfs4_state *state = calldata->state; |
817 | struct nfs4_state_owner *sp = state->owner; | ||
818 | struct nfs_server *server = NFS_SERVER(calldata->inode); | 846 | struct nfs_server *server = NFS_SERVER(calldata->inode); |
819 | 847 | ||
820 | /* hmm. we are done with the inode, and in the process of freeing | 848 | /* hmm. we are done with the inode, and in the process of freeing |
@@ -838,25 +866,46 @@ static void nfs4_close_done(struct rpc_task *task) | |||
838 | } | 866 | } |
839 | } | 867 | } |
840 | state->state = calldata->arg.open_flags; | 868 | state->state = calldata->arg.open_flags; |
841 | nfs4_put_open_state(state); | 869 | nfs4_free_closedata(calldata); |
842 | nfs_free_seqid(calldata->arg.seqid); | ||
843 | up(&sp->so_sema); | ||
844 | nfs4_put_state_owner(sp); | ||
845 | up_read(&server->nfs4_state->cl_sem); | ||
846 | kfree(calldata); | ||
847 | } | 870 | } |
848 | 871 | ||
849 | static inline int nfs4_close_call(struct rpc_clnt *clnt, struct nfs4_closedata *calldata) | 872 | static void nfs4_close_begin(struct rpc_task *task) |
850 | { | 873 | { |
874 | struct nfs4_closedata *calldata = (struct nfs4_closedata *)task->tk_calldata; | ||
875 | struct nfs4_state *state = calldata->state; | ||
851 | struct rpc_message msg = { | 876 | struct rpc_message msg = { |
852 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE], | 877 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE], |
853 | .rpc_argp = &calldata->arg, | 878 | .rpc_argp = &calldata->arg, |
854 | .rpc_resp = &calldata->res, | 879 | .rpc_resp = &calldata->res, |
855 | .rpc_cred = calldata->state->owner->so_cred, | 880 | .rpc_cred = state->owner->so_cred, |
856 | }; | 881 | }; |
857 | if (calldata->arg.open_flags != 0) | 882 | int mode = 0; |
883 | int status; | ||
884 | |||
885 | status = nfs_wait_on_sequence(calldata->arg.seqid, task); | ||
886 | if (status != 0) | ||
887 | return; | ||
888 | /* Don't reorder reads */ | ||
889 | smp_rmb(); | ||
890 | /* Recalculate the new open mode in case someone reopened the file | ||
891 | * while we were waiting in line to be scheduled. | ||
892 | */ | ||
893 | if (state->nreaders != 0) | ||
894 | mode |= FMODE_READ; | ||
895 | if (state->nwriters != 0) | ||
896 | mode |= FMODE_WRITE; | ||
897 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) | ||
898 | state->state = mode; | ||
899 | if (mode == state->state) { | ||
900 | nfs4_free_closedata(calldata); | ||
901 | task->tk_exit = NULL; | ||
902 | rpc_exit(task, 0); | ||
903 | return; | ||
904 | } | ||
905 | if (mode != 0) | ||
858 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; | 906 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; |
859 | return rpc_call_async(clnt, &msg, 0, nfs4_close_done, calldata); | 907 | calldata->arg.open_flags = mode; |
908 | rpc_call_setup(task, &msg, 0); | ||
860 | } | 909 | } |
861 | 910 | ||
862 | /* | 911 | /* |
@@ -873,35 +922,30 @@ static inline int nfs4_close_call(struct rpc_clnt *clnt, struct nfs4_closedata * | |||
873 | int nfs4_do_close(struct inode *inode, struct nfs4_state *state, mode_t mode) | 922 | int nfs4_do_close(struct inode *inode, struct nfs4_state *state, mode_t mode) |
874 | { | 923 | { |
875 | struct nfs4_closedata *calldata; | 924 | struct nfs4_closedata *calldata; |
876 | int status; | 925 | int status = -ENOMEM; |
877 | 926 | ||
878 | /* Tell caller we're done */ | 927 | calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); |
879 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { | ||
880 | state->state = mode; | ||
881 | return 0; | ||
882 | } | ||
883 | calldata = (struct nfs4_closedata *)kmalloc(sizeof(*calldata), GFP_KERNEL); | ||
884 | if (calldata == NULL) | 928 | if (calldata == NULL) |
885 | return -ENOMEM; | 929 | goto out; |
886 | calldata->inode = inode; | 930 | calldata->inode = inode; |
887 | calldata->state = state; | 931 | calldata->state = state; |
888 | calldata->arg.fh = NFS_FH(inode); | 932 | calldata->arg.fh = NFS_FH(inode); |
933 | calldata->arg.stateid = &state->stateid; | ||
889 | /* Serialization for the sequence id */ | 934 | /* Serialization for the sequence id */ |
890 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); | 935 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); |
891 | if (calldata->arg.seqid == NULL) { | 936 | if (calldata->arg.seqid == NULL) |
892 | kfree(calldata); | 937 | goto out_free_calldata; |
893 | return -ENOMEM; | 938 | |
894 | } | 939 | status = nfs4_call_async(NFS_SERVER(inode)->client, nfs4_close_begin, |
895 | calldata->arg.open_flags = mode; | 940 | nfs4_close_done, calldata); |
896 | memcpy(&calldata->arg.stateid, &state->stateid, | 941 | if (status == 0) |
897 | sizeof(calldata->arg.stateid)); | 942 | goto out; |
898 | status = nfs4_close_call(NFS_SERVER(inode)->client, calldata); | 943 | |
899 | /* | 944 | nfs_free_seqid(calldata->arg.seqid); |
900 | * Return -EINPROGRESS on success in order to indicate to the | 945 | out_free_calldata: |
901 | * caller that an asynchronous RPC call has been launched, and | 946 | kfree(calldata); |
902 | * that it will release the semaphores on completion. | 947 | out: |
903 | */ | 948 | return status; |
904 | return (status == 0) ? -EINPROGRESS : status; | ||
905 | } | 949 | } |
906 | 950 | ||
907 | struct inode * | 951 | struct inode * |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index f535c219cf3a..59c93f37e1b2 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -518,7 +518,11 @@ void nfs4_close_state(struct nfs4_state *state, mode_t mode) | |||
518 | newstate |= FMODE_WRITE; | 518 | newstate |= FMODE_WRITE; |
519 | if (state->state == newstate) | 519 | if (state->state == newstate) |
520 | goto out; | 520 | goto out; |
521 | if (nfs4_do_close(inode, state, newstate) == -EINPROGRESS) | 521 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { |
522 | state->state = newstate; | ||
523 | goto out; | ||
524 | } | ||
525 | if (nfs4_do_close(inode, state, newstate) == 0) | ||
522 | return; | 526 | return; |
523 | } | 527 | } |
524 | out: | 528 | out: |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index fcd28a29a2f8..934ec50ea6bf 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -602,10 +602,10 @@ static int encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg) | |||
602 | { | 602 | { |
603 | uint32_t *p; | 603 | uint32_t *p; |
604 | 604 | ||
605 | RESERVE_SPACE(8+sizeof(arg->stateid.data)); | 605 | RESERVE_SPACE(8+sizeof(arg->stateid->data)); |
606 | WRITE32(OP_CLOSE); | 606 | WRITE32(OP_CLOSE); |
607 | WRITE32(arg->seqid->sequence->counter); | 607 | WRITE32(arg->seqid->sequence->counter); |
608 | WRITEMEM(arg->stateid.data, sizeof(arg->stateid.data)); | 608 | WRITEMEM(arg->stateid->data, sizeof(arg->stateid->data)); |
609 | 609 | ||
610 | return 0; | 610 | return 0; |
611 | } | 611 | } |
@@ -950,9 +950,9 @@ static int encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closea | |||
950 | { | 950 | { |
951 | uint32_t *p; | 951 | uint32_t *p; |
952 | 952 | ||
953 | RESERVE_SPACE(8+sizeof(arg->stateid.data)); | 953 | RESERVE_SPACE(8+sizeof(arg->stateid->data)); |
954 | WRITE32(OP_OPEN_DOWNGRADE); | 954 | WRITE32(OP_OPEN_DOWNGRADE); |
955 | WRITEMEM(arg->stateid.data, sizeof(arg->stateid.data)); | 955 | WRITEMEM(arg->stateid->data, sizeof(arg->stateid->data)); |
956 | WRITE32(arg->seqid->sequence->counter); | 956 | WRITE32(arg->seqid->sequence->counter); |
957 | encode_share_access(xdr, arg->open_flags); | 957 | encode_share_access(xdr, arg->open_flags); |
958 | return 0; | 958 | return 0; |
@@ -1416,9 +1416,6 @@ static int nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_clos | |||
1416 | }; | 1416 | }; |
1417 | int status; | 1417 | int status; |
1418 | 1418 | ||
1419 | status = nfs_wait_on_sequence(args->seqid, req->rq_task); | ||
1420 | if (status != 0) | ||
1421 | goto out; | ||
1422 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1419 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1423 | encode_compound_hdr(&xdr, &hdr); | 1420 | encode_compound_hdr(&xdr, &hdr); |
1424 | status = encode_putfh(&xdr, args->fh); | 1421 | status = encode_putfh(&xdr, args->fh); |
@@ -1518,9 +1515,6 @@ static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct | |||
1518 | }; | 1515 | }; |
1519 | int status; | 1516 | int status; |
1520 | 1517 | ||
1521 | status = nfs_wait_on_sequence(args->seqid, req->rq_task); | ||
1522 | if (status != 0) | ||
1523 | goto out; | ||
1524 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1518 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1525 | encode_compound_hdr(&xdr, &hdr); | 1519 | encode_compound_hdr(&xdr, &hdr); |
1526 | status = encode_putfh(&xdr, args->fh); | 1520 | status = encode_putfh(&xdr, args->fh); |