aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2007-07-08 14:11:36 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2007-07-10 23:40:43 -0400
commit6ee412689027dc7954453aed392ab5c7599c0f73 (patch)
tree71f09219acaf905e779f9cecf2d0256ba34d6526
parentaac00a8d0a53097063da532cbdf0b8775a4dcd53 (diff)
NFSv4: Don't call OPEN if we already have an open stateid for a file
If we already have a stateid with the correct open mode for a given file, then we can reuse that stateid instead of re-issuing an OPEN call without violating the close-to-open caching semantics. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/nfs4proc.c49
1 files changed, 41 insertions, 8 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index ea332e831d75..1de076619253 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -324,6 +324,24 @@ static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task)
324 return ret; 324 return ret;
325} 325}
326 326
327static int can_open_cached(struct nfs4_state *state, int mode)
328{
329 int ret = 0;
330 switch (mode & (FMODE_READ|FMODE_WRITE|O_EXCL)) {
331 case FMODE_READ:
332 ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0;
333 ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0;
334 break;
335 case FMODE_WRITE:
336 ret |= test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0;
337 ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0;
338 break;
339 case FMODE_READ|FMODE_WRITE:
340 ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0;
341 }
342 return ret;
343}
344
327static int can_open_delegated(struct nfs_delegation *delegation, mode_t open_flags) 345static int can_open_delegated(struct nfs_delegation *delegation, mode_t open_flags)
328{ 346{
329 if ((delegation->type & open_flags) != open_flags) 347 if ((delegation->type & open_flags) != open_flags)
@@ -407,7 +425,7 @@ static void nfs4_return_incompatible_delegation(struct inode *inode, mode_t open
407 nfs_inode_return_delegation(inode); 425 nfs_inode_return_delegation(inode);
408} 426}
409 427
410static struct nfs4_state *nfs4_try_open_delegated(struct nfs4_opendata *opendata) 428static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
411{ 429{
412 struct nfs4_state *state = opendata->state; 430 struct nfs4_state *state = opendata->state;
413 struct nfs_inode *nfsi = NFS_I(state->inode); 431 struct nfs_inode *nfsi = NFS_I(state->inode);
@@ -418,9 +436,19 @@ static struct nfs4_state *nfs4_try_open_delegated(struct nfs4_opendata *opendata
418 436
419 rcu_read_lock(); 437 rcu_read_lock();
420 delegation = rcu_dereference(nfsi->delegation); 438 delegation = rcu_dereference(nfsi->delegation);
421 if (delegation == NULL)
422 goto out_unlock;
423 for (;;) { 439 for (;;) {
440 if (can_open_cached(state, open_mode)) {
441 spin_lock(&state->owner->so_lock);
442 if (can_open_cached(state, open_mode)) {
443 update_open_stateflags(state, open_mode);
444 spin_unlock(&state->owner->so_lock);
445 rcu_read_unlock();
446 goto out_return_state;
447 }
448 spin_unlock(&state->owner->so_lock);
449 }
450 if (delegation == NULL)
451 break;
424 if (!can_open_delegated(delegation, open_mode)) 452 if (!can_open_delegated(delegation, open_mode))
425 break; 453 break;
426 /* Save the delegation */ 454 /* Save the delegation */
@@ -434,8 +462,9 @@ static struct nfs4_state *nfs4_try_open_delegated(struct nfs4_opendata *opendata
434 ret = -EAGAIN; 462 ret = -EAGAIN;
435 rcu_read_lock(); 463 rcu_read_lock();
436 delegation = rcu_dereference(nfsi->delegation); 464 delegation = rcu_dereference(nfsi->delegation);
465 /* If no delegation, try a cached open */
437 if (delegation == NULL) 466 if (delegation == NULL)
438 break; 467 continue;
439 /* Is the delegation still valid? */ 468 /* Is the delegation still valid? */
440 if (memcmp(stateid.data, delegation->stateid.data, sizeof(stateid.data)) != 0) 469 if (memcmp(stateid.data, delegation->stateid.data, sizeof(stateid.data)) != 0)
441 continue; 470 continue;
@@ -443,7 +472,6 @@ static struct nfs4_state *nfs4_try_open_delegated(struct nfs4_opendata *opendata
443 update_open_stateid(state, NULL, &stateid, open_mode); 472 update_open_stateid(state, NULL, &stateid, open_mode);
444 goto out_return_state; 473 goto out_return_state;
445 } 474 }
446out_unlock:
447 rcu_read_unlock(); 475 rcu_read_unlock();
448out: 476out:
449 return ERR_PTR(ret); 477 return ERR_PTR(ret);
@@ -461,7 +489,7 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data
461 int ret; 489 int ret;
462 490
463 if (!data->rpc_done) { 491 if (!data->rpc_done) {
464 state = nfs4_try_open_delegated(data); 492 state = nfs4_try_open_cached(data);
465 goto out; 493 goto out;
466 } 494 }
467 495
@@ -775,13 +803,14 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
775 if (data->state != NULL) { 803 if (data->state != NULL) {
776 struct nfs_delegation *delegation; 804 struct nfs_delegation *delegation;
777 805
806 if (can_open_cached(data->state, data->o_arg.open_flags & (FMODE_READ|FMODE_WRITE|O_EXCL)))
807 goto out_no_action;
778 rcu_read_lock(); 808 rcu_read_lock();
779 delegation = rcu_dereference(NFS_I(data->state->inode)->delegation); 809 delegation = rcu_dereference(NFS_I(data->state->inode)->delegation);
780 if (delegation != NULL && 810 if (delegation != NULL &&
781 (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0) { 811 (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0) {
782 rcu_read_unlock(); 812 rcu_read_unlock();
783 task->tk_action = NULL; 813 goto out_no_action;
784 return;
785 } 814 }
786 rcu_read_unlock(); 815 rcu_read_unlock();
787 } 816 }
@@ -792,6 +821,10 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
792 msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; 821 msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
793 data->timestamp = jiffies; 822 data->timestamp = jiffies;
794 rpc_call_setup(task, &msg, 0); 823 rpc_call_setup(task, &msg, 0);
824 return;
825out_no_action:
826 task->tk_action = NULL;
827
795} 828}
796 829
797static void nfs4_open_done(struct rpc_task *task, void *calldata) 830static void nfs4_open_done(struct rpc_task *task, void *calldata)