diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-07-08 14:11:36 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-07-10 23:40:43 -0400 |
commit | 6ee412689027dc7954453aed392ab5c7599c0f73 (patch) | |
tree | 71f09219acaf905e779f9cecf2d0256ba34d6526 /fs | |
parent | aac00a8d0a53097063da532cbdf0b8775a4dcd53 (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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/nfs4proc.c | 49 |
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 | ||
327 | static 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 | |||
327 | static int can_open_delegated(struct nfs_delegation *delegation, mode_t open_flags) | 345 | static 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 | ||
410 | static struct nfs4_state *nfs4_try_open_delegated(struct nfs4_opendata *opendata) | 428 | static 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 | } |
446 | out_unlock: | ||
447 | rcu_read_unlock(); | 475 | rcu_read_unlock(); |
448 | out: | 476 | out: |
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; | ||
825 | out_no_action: | ||
826 | task->tk_action = NULL; | ||
827 | |||
795 | } | 828 | } |
796 | 829 | ||
797 | static void nfs4_open_done(struct rpc_task *task, void *calldata) | 830 | static void nfs4_open_done(struct rpc_task *task, void *calldata) |