aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4proc.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2005-10-18 17:20:12 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2005-10-18 17:20:12 -0400
commitcee54fc944422c44e476736c045a9e8053cb0644 (patch)
tree95f4728b3ffa8a2456727b10cd3a68f2a3065415 /fs/nfs/nfs4proc.c
parent5e5ce5be6f0161d2a069a4f8a1154fe639c5c02f (diff)
NFSv4: Add functions to order RPC calls
NFSv4 file state-changing functions such as OPEN, CLOSE, LOCK,... are all labelled with "sequence identifiers" in order to prevent the server from reordering RPC requests, as this could cause its file state to become out of sync with the client. Currently the NFS client code enforces this ordering locally using semaphores to restrict access to structures until the RPC call is done. This, of course, only works with synchronous RPC calls, since the user process must first grab the semaphore. By dropping semaphores, and instead teaching the RPC engine to hold the RPC calls until they are ready to be sent, we can extend this process to work nicely with asynchronous RPC calls too. This patch adds a new list called "rpc_sequence" that defines the order of the RPC calls to be sent. We add one such list for each state_owner. When an RPC call is ready to be sent, it checks if it is top of the rpc_sequence list. If so, it proceeds. If not, it goes back to sleep, and loops until it hits top of the list. Once the RPC call has completed, it can then bump the sequence id counter, and remove itself from the rpc_sequence list, and then wake up the next sleeper. Note that the state_owner sequence ids and lock_owner sequence ids are all indexed to the same rpc_sequence list, so OPEN, LOCK,... requests are all ordered w.r.t. each other. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r--fs/nfs/nfs4proc.c111
1 files changed, 73 insertions, 38 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 9701ca8c9428..9ba89e7cdd28 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -218,7 +218,6 @@ static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *st
218 struct nfs_delegation *delegation = NFS_I(inode)->delegation; 218 struct nfs_delegation *delegation = NFS_I(inode)->delegation;
219 struct nfs_openargs o_arg = { 219 struct nfs_openargs o_arg = {
220 .fh = NFS_FH(inode), 220 .fh = NFS_FH(inode),
221 .seqid = sp->so_seqid,
222 .id = sp->so_id, 221 .id = sp->so_id,
223 .open_flags = state->state, 222 .open_flags = state->state,
224 .clientid = server->nfs4_state->cl_clientid, 223 .clientid = server->nfs4_state->cl_clientid,
@@ -245,8 +244,13 @@ static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *st
245 } 244 }
246 o_arg.u.delegation_type = delegation->type; 245 o_arg.u.delegation_type = delegation->type;
247 } 246 }
247 o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid);
248 if (o_arg.seqid == NULL)
249 return -ENOMEM;
248 status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); 250 status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR);
249 nfs4_increment_seqid(status, sp); 251 /* Confirm the sequence as being established */
252 nfs_confirm_seqid(&sp->so_seqid, status);
253 nfs_increment_open_seqid(status, o_arg.seqid);
250 if (status == 0) { 254 if (status == 0) {
251 memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid)); 255 memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid));
252 if (o_res.delegation_type != 0) { 256 if (o_res.delegation_type != 0) {
@@ -256,6 +260,7 @@ static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *st
256 nfs_async_inode_return_delegation(inode, &o_res.stateid); 260 nfs_async_inode_return_delegation(inode, &o_res.stateid);
257 } 261 }
258 } 262 }
263 nfs_free_seqid(o_arg.seqid);
259 clear_bit(NFS_DELEGATED_STATE, &state->flags); 264 clear_bit(NFS_DELEGATED_STATE, &state->flags);
260 /* Ensure we update the inode attributes */ 265 /* Ensure we update the inode attributes */
261 NFS_CACHEINV(inode); 266 NFS_CACHEINV(inode);
@@ -307,16 +312,20 @@ static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state
307 goto out; 312 goto out;
308 if (state->state == 0) 313 if (state->state == 0)
309 goto out; 314 goto out;
310 arg.seqid = sp->so_seqid; 315 arg.seqid = nfs_alloc_seqid(&sp->so_seqid);
316 status = -ENOMEM;
317 if (arg.seqid == NULL)
318 goto out;
311 arg.open_flags = state->state; 319 arg.open_flags = state->state;
312 memcpy(arg.u.delegation.data, state->stateid.data, sizeof(arg.u.delegation.data)); 320 memcpy(arg.u.delegation.data, state->stateid.data, sizeof(arg.u.delegation.data));
313 status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); 321 status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR);
314 nfs4_increment_seqid(status, sp); 322 nfs_increment_open_seqid(status, arg.seqid);
315 if (status >= 0) { 323 if (status >= 0) {
316 memcpy(state->stateid.data, res.stateid.data, 324 memcpy(state->stateid.data, res.stateid.data,
317 sizeof(state->stateid.data)); 325 sizeof(state->stateid.data));
318 clear_bit(NFS_DELEGATED_STATE, &state->flags); 326 clear_bit(NFS_DELEGATED_STATE, &state->flags);
319 } 327 }
328 nfs_free_seqid(arg.seqid);
320out: 329out:
321 up(&sp->so_sema); 330 up(&sp->so_sema);
322 dput(parent); 331 dput(parent);
@@ -345,11 +354,11 @@ int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state)
345 return err; 354 return err;
346} 355}
347 356
348static inline int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid) 357static inline int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid, struct nfs_seqid *seqid)
349{ 358{
350 struct nfs_open_confirmargs arg = { 359 struct nfs_open_confirmargs arg = {
351 .fh = fh, 360 .fh = fh,
352 .seqid = sp->so_seqid, 361 .seqid = seqid,
353 .stateid = *stateid, 362 .stateid = *stateid,
354 }; 363 };
355 struct nfs_open_confirmres res; 364 struct nfs_open_confirmres res;
@@ -362,7 +371,9 @@ static inline int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nf
362 int status; 371 int status;
363 372
364 status = rpc_call_sync(clnt, &msg, RPC_TASK_NOINTR); 373 status = rpc_call_sync(clnt, &msg, RPC_TASK_NOINTR);
365 nfs4_increment_seqid(status, sp); 374 /* Confirm the sequence as being established */
375 nfs_confirm_seqid(&sp->so_seqid, status);
376 nfs_increment_open_seqid(status, seqid);
366 if (status >= 0) 377 if (status >= 0)
367 memcpy(stateid, &res.stateid, sizeof(*stateid)); 378 memcpy(stateid, &res.stateid, sizeof(*stateid));
368 return status; 379 return status;
@@ -380,21 +391,21 @@ static int _nfs4_proc_open(struct inode *dir, struct nfs4_state_owner *sp, stru
380 int status; 391 int status;
381 392
382 /* Update sequence id. The caller must serialize! */ 393 /* Update sequence id. The caller must serialize! */
383 o_arg->seqid = sp->so_seqid;
384 o_arg->id = sp->so_id; 394 o_arg->id = sp->so_id;
385 o_arg->clientid = sp->so_client->cl_clientid; 395 o_arg->clientid = sp->so_client->cl_clientid;
386 396
387 status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); 397 status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR);
388 nfs4_increment_seqid(status, sp); 398 nfs_increment_open_seqid(status, o_arg->seqid);
389 if (status != 0) 399 if (status != 0)
390 goto out; 400 goto out;
391 update_changeattr(dir, &o_res->cinfo); 401 update_changeattr(dir, &o_res->cinfo);
392 if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { 402 if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
393 status = _nfs4_proc_open_confirm(server->client, &o_res->fh, 403 status = _nfs4_proc_open_confirm(server->client, &o_res->fh,
394 sp, &o_res->stateid); 404 sp, &o_res->stateid, o_arg->seqid);
395 if (status != 0) 405 if (status != 0)
396 goto out; 406 goto out;
397 } 407 }
408 nfs_confirm_seqid(&sp->so_seqid, 0);
398 if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) 409 if (!(o_res->f_attr->valid & NFS_ATTR_FATTR))
399 status = server->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr); 410 status = server->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr);
400out: 411out:
@@ -465,6 +476,10 @@ static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
465 set_bit(NFS_DELEGATED_STATE, &state->flags); 476 set_bit(NFS_DELEGATED_STATE, &state->flags);
466 goto out; 477 goto out;
467 } 478 }
479 o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid);
480 status = -ENOMEM;
481 if (o_arg.seqid == NULL)
482 goto out;
468 status = _nfs4_proc_open(dir, sp, &o_arg, &o_res); 483 status = _nfs4_proc_open(dir, sp, &o_arg, &o_res);
469 if (status != 0) 484 if (status != 0)
470 goto out_nodeleg; 485 goto out_nodeleg;
@@ -490,6 +505,7 @@ static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
490 nfs_inode_reclaim_delegation(inode, sp->so_cred, &o_res); 505 nfs_inode_reclaim_delegation(inode, sp->so_cred, &o_res);
491 } 506 }
492out_nodeleg: 507out_nodeleg:
508 nfs_free_seqid(o_arg.seqid);
493 clear_bit(NFS_DELEGATED_STATE, &state->flags); 509 clear_bit(NFS_DELEGATED_STATE, &state->flags);
494out: 510out:
495 dput(parent); 511 dput(parent);
@@ -667,6 +683,9 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st
667 /* Serialization for the sequence id */ 683 /* Serialization for the sequence id */
668 down(&sp->so_sema); 684 down(&sp->so_sema);
669 685
686 o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid);
687 if (o_arg.seqid == NULL)
688 return -ENOMEM;
670 status = _nfs4_proc_open(dir, sp, &o_arg, &o_res); 689 status = _nfs4_proc_open(dir, sp, &o_arg, &o_res);
671 if (status != 0) 690 if (status != 0)
672 goto out_err; 691 goto out_err;
@@ -681,6 +700,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st
681 update_open_stateid(state, &o_res.stateid, flags); 700 update_open_stateid(state, &o_res.stateid, flags);
682 if (o_res.delegation_type != 0) 701 if (o_res.delegation_type != 0)
683 nfs_inode_set_delegation(inode, cred, &o_res); 702 nfs_inode_set_delegation(inode, cred, &o_res);
703 nfs_free_seqid(o_arg.seqid);
684 up(&sp->so_sema); 704 up(&sp->so_sema);
685 nfs4_put_state_owner(sp); 705 nfs4_put_state_owner(sp);
686 up_read(&clp->cl_sem); 706 up_read(&clp->cl_sem);
@@ -690,6 +710,7 @@ out_err:
690 if (sp != NULL) { 710 if (sp != NULL) {
691 if (state != NULL) 711 if (state != NULL)
692 nfs4_put_open_state(state); 712 nfs4_put_open_state(state);
713 nfs_free_seqid(o_arg.seqid);
693 up(&sp->so_sema); 714 up(&sp->so_sema);
694 nfs4_put_state_owner(sp); 715 nfs4_put_state_owner(sp);
695 } 716 }
@@ -718,7 +739,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry,
718 * It is actually a sign of a bug on the client or on the server. 739 * It is actually a sign of a bug on the client or on the server.
719 * 740 *
720 * If we receive a BAD_SEQID error in the particular case of 741 * If we receive a BAD_SEQID error in the particular case of
721 * doing an OPEN, we assume that nfs4_increment_seqid() will 742 * doing an OPEN, we assume that nfs_increment_open_seqid() will
722 * have unhashed the old state_owner for us, and that we can 743 * have unhashed the old state_owner for us, and that we can
723 * therefore safely retry using a new one. We should still warn 744 * therefore safely retry using a new one. We should still warn
724 * the user though... 745 * the user though...
@@ -799,7 +820,7 @@ static void nfs4_close_done(struct rpc_task *task)
799 /* hmm. we are done with the inode, and in the process of freeing 820 /* hmm. we are done with the inode, and in the process of freeing
800 * the state_owner. we keep this around to process errors 821 * the state_owner. we keep this around to process errors
801 */ 822 */
802 nfs4_increment_seqid(task->tk_status, sp); 823 nfs_increment_open_seqid(task->tk_status, calldata->arg.seqid);
803 switch (task->tk_status) { 824 switch (task->tk_status) {
804 case 0: 825 case 0:
805 memcpy(&state->stateid, &calldata->res.stateid, 826 memcpy(&state->stateid, &calldata->res.stateid,
@@ -818,6 +839,7 @@ static void nfs4_close_done(struct rpc_task *task)
818 } 839 }
819 state->state = calldata->arg.open_flags; 840 state->state = calldata->arg.open_flags;
820 nfs4_put_open_state(state); 841 nfs4_put_open_state(state);
842 nfs_free_seqid(calldata->arg.seqid);
821 up(&sp->so_sema); 843 up(&sp->so_sema);
822 nfs4_put_state_owner(sp); 844 nfs4_put_state_owner(sp);
823 up_read(&server->nfs4_state->cl_sem); 845 up_read(&server->nfs4_state->cl_sem);
@@ -865,7 +887,11 @@ int nfs4_do_close(struct inode *inode, struct nfs4_state *state, mode_t mode)
865 calldata->state = state; 887 calldata->state = state;
866 calldata->arg.fh = NFS_FH(inode); 888 calldata->arg.fh = NFS_FH(inode);
867 /* Serialization for the sequence id */ 889 /* Serialization for the sequence id */
868 calldata->arg.seqid = state->owner->so_seqid; 890 calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid);
891 if (calldata->arg.seqid == NULL) {
892 kfree(calldata);
893 return -ENOMEM;
894 }
869 calldata->arg.open_flags = mode; 895 calldata->arg.open_flags = mode;
870 memcpy(&calldata->arg.stateid, &state->stateid, 896 memcpy(&calldata->arg.stateid, &state->stateid,
871 sizeof(calldata->arg.stateid)); 897 sizeof(calldata->arg.stateid));
@@ -2729,15 +2755,19 @@ static int _nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock
2729 /* We might have lost the locks! */ 2755 /* We might have lost the locks! */
2730 if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) 2756 if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0)
2731 goto out; 2757 goto out;
2732 luargs.seqid = lsp->ls_seqid; 2758 luargs.seqid = nfs_alloc_seqid(&lsp->ls_seqid);
2733 memcpy(&luargs.stateid, &lsp->ls_stateid, sizeof(luargs.stateid)); 2759 status = -ENOMEM;
2760 if (luargs.seqid == NULL)
2761 goto out;
2762 memcpy(luargs.stateid.data, lsp->ls_stateid.data, sizeof(luargs.stateid.data));
2734 arg.u.locku = &luargs; 2763 arg.u.locku = &luargs;
2735 status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); 2764 status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR);
2736 nfs4_increment_lock_seqid(status, lsp); 2765 nfs_increment_lock_seqid(status, luargs.seqid);
2737 2766
2738 if (status == 0) 2767 if (status == 0)
2739 memcpy(&lsp->ls_stateid, &res.u.stateid, 2768 memcpy(lsp->ls_stateid.data, res.u.stateid.data,
2740 sizeof(lsp->ls_stateid)); 2769 sizeof(lsp->ls_stateid.data));
2770 nfs_free_seqid(luargs.seqid);
2741out: 2771out:
2742 up(&state->lock_sema); 2772 up(&state->lock_sema);
2743 if (status == 0) 2773 if (status == 0)
@@ -2783,9 +2813,13 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r
2783 .reclaim = reclaim, 2813 .reclaim = reclaim,
2784 .new_lock_owner = 0, 2814 .new_lock_owner = 0,
2785 }; 2815 };
2786 int status; 2816 struct nfs_seqid *lock_seqid;
2817 int status = -ENOMEM;
2787 2818
2788 if (!(lsp->ls_flags & NFS_LOCK_INITIALIZED)) { 2819 lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid);
2820 if (lock_seqid == NULL)
2821 return -ENOMEM;
2822 if (!(lsp->ls_seqid.flags & NFS_SEQID_CONFIRMED)) {
2789 struct nfs4_state_owner *owner = state->owner; 2823 struct nfs4_state_owner *owner = state->owner;
2790 struct nfs_open_to_lock otl = { 2824 struct nfs_open_to_lock otl = {
2791 .lock_owner = { 2825 .lock_owner = {
@@ -2793,39 +2827,40 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r
2793 }, 2827 },
2794 }; 2828 };
2795 2829
2796 otl.lock_seqid = lsp->ls_seqid; 2830 otl.lock_seqid = lock_seqid;
2797 otl.lock_owner.id = lsp->ls_id; 2831 otl.lock_owner.id = lsp->ls_id;
2798 memcpy(&otl.open_stateid, &state->stateid, sizeof(otl.open_stateid)); 2832 memcpy(&otl.open_stateid, &state->stateid, sizeof(otl.open_stateid));
2799 largs.u.open_lock = &otl; 2833 largs.u.open_lock = &otl;
2800 largs.new_lock_owner = 1; 2834 largs.new_lock_owner = 1;
2801 arg.u.lock = &largs; 2835 arg.u.lock = &largs;
2802 down(&owner->so_sema); 2836 down(&owner->so_sema);
2803 otl.open_seqid = owner->so_seqid; 2837 otl.open_seqid = nfs_alloc_seqid(&owner->so_seqid);
2804 status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); 2838 if (otl.open_seqid != NULL) {
2805 /* increment open_owner seqid on success, and 2839 status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR);
2806 * seqid mutating errors */ 2840 /* increment seqid on success, and seqid mutating errors */
2807 nfs4_increment_seqid(status, owner); 2841 nfs_increment_open_seqid(status, otl.open_seqid);
2808 up(&owner->so_sema); 2842 nfs_free_seqid(otl.open_seqid);
2809 if (status == 0) {
2810 lsp->ls_flags |= NFS_LOCK_INITIALIZED;
2811 lsp->ls_seqid++;
2812 } 2843 }
2844 up(&owner->so_sema);
2845 if (status == 0)
2846 nfs_confirm_seqid(&lsp->ls_seqid, 0);
2813 } else { 2847 } else {
2814 struct nfs_exist_lock el = { 2848 struct nfs_exist_lock el;
2815 .seqid = lsp->ls_seqid,
2816 };
2817 memcpy(&el.stateid, &lsp->ls_stateid, sizeof(el.stateid)); 2849 memcpy(&el.stateid, &lsp->ls_stateid, sizeof(el.stateid));
2818 largs.u.exist_lock = &el; 2850 largs.u.exist_lock = &el;
2819 arg.u.lock = &largs; 2851 arg.u.lock = &largs;
2852 el.seqid = lock_seqid;
2820 status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); 2853 status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR);
2821 /* increment seqid on success, and * seqid mutating errors*/
2822 nfs4_increment_lock_seqid(status, lsp);
2823 } 2854 }
2855 /* increment seqid on success, and seqid mutating errors*/
2856 nfs_increment_lock_seqid(status, lock_seqid);
2824 /* save the returned stateid. */ 2857 /* save the returned stateid. */
2825 if (status == 0) 2858 if (status == 0) {
2826 memcpy(&lsp->ls_stateid, &res.u.stateid, sizeof(nfs4_stateid)); 2859 memcpy(lsp->ls_stateid.data, res.u.stateid.data, sizeof(lsp->ls_stateid.data));
2827 else if (status == -NFS4ERR_DENIED) 2860 lsp->ls_flags |= NFS_LOCK_INITIALIZED;
2861 } else if (status == -NFS4ERR_DENIED)
2828 status = -EAGAIN; 2862 status = -EAGAIN;
2863 nfs_free_seqid(lock_seqid);
2829 return status; 2864 return status;
2830} 2865}
2831 2866