aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/nfs4proc.c110
-rw-r--r--fs/nfs/nfs4state.c6
-rw-r--r--fs/nfs/nfs4xdr.c14
-rw-r--r--include/linux/nfs_xdr.h2
4 files changed, 87 insertions, 45 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 */
193static 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
192static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) 207static 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
828static 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
813static void nfs4_close_done(struct rpc_task *task) 842static 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
849static inline int nfs4_close_call(struct rpc_clnt *clnt, struct nfs4_closedata *calldata) 872static 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 *
873int nfs4_do_close(struct inode *inode, struct nfs4_state *state, mode_t mode) 922int 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 945out_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. 947out:
903 */ 948 return status;
904 return (status == 0) ? -EINPROGRESS : status;
905} 949}
906 950
907struct inode * 951struct 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 }
524out: 528out:
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);
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index d578912bf9a9..cac0df950c66 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -149,7 +149,7 @@ struct nfs_open_confirmres {
149 */ 149 */
150struct nfs_closeargs { 150struct nfs_closeargs {
151 struct nfs_fh * fh; 151 struct nfs_fh * fh;
152 nfs4_stateid stateid; 152 nfs4_stateid * stateid;
153 struct nfs_seqid * seqid; 153 struct nfs_seqid * seqid;
154 int open_flags; 154 int open_flags;
155}; 155};