diff options
author | J. Bruce Fields <bfields@redhat.com> | 2010-08-20 18:09:31 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2010-08-26 13:22:02 -0400 |
commit | 7d94784293096c0a46897acdb83be5abd9278ece (patch) | |
tree | da2bc54b7d2527b465833610d80ec0285b90c8a7 | |
parent | 18608ad49cffa430cfd0b4e027dedfe3114f916e (diff) |
nfsd4: fix downgrade/lock logic
If we already had a RW open for a file, and get a readonly open, we were
piggybacking on the existing RW open. That's inconsistent with the
downgrade logic which blows away the RW open assuming you'll still have
a readonly open.
Also, make sure there is a readonly or writeonly open available for
locking, again to prevent bad behavior in downgrade cases when any RW
open may be lost.
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r-- | fs/nfsd/nfs4state.c | 25 | ||||
-rw-r--r-- | fs/nfsd/state.h | 12 |
2 files changed, 21 insertions, 16 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index b990eadb799c..69b266db7f5c 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -2450,14 +2450,13 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, | |||
2450 | static __be32 | 2450 | static __be32 |
2451 | nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open) | 2451 | nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open) |
2452 | { | 2452 | { |
2453 | u32 op_share_access, new_access; | 2453 | u32 op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK; |
2454 | bool new_access; | ||
2454 | __be32 status; | 2455 | __be32 status; |
2455 | 2456 | ||
2456 | set_access(&new_access, stp->st_access_bmap); | 2457 | new_access = !test_bit(op_share_access, &stp->st_access_bmap); |
2457 | new_access = (~new_access) & open->op_share_access & ~NFS4_SHARE_WANT_MASK; | ||
2458 | |||
2459 | if (new_access) { | 2458 | if (new_access) { |
2460 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, new_access); | 2459 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, op_share_access); |
2461 | if (status) | 2460 | if (status) |
2462 | return status; | 2461 | return status; |
2463 | } | 2462 | } |
@@ -2470,7 +2469,6 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *c | |||
2470 | return status; | 2469 | return status; |
2471 | } | 2470 | } |
2472 | /* remember the open */ | 2471 | /* remember the open */ |
2473 | op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK; | ||
2474 | __set_bit(op_share_access, &stp->st_access_bmap); | 2472 | __set_bit(op_share_access, &stp->st_access_bmap); |
2475 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); | 2473 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); |
2476 | 2474 | ||
@@ -3560,7 +3558,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3560 | struct nfs4_stateowner *open_sop = NULL; | 3558 | struct nfs4_stateowner *open_sop = NULL; |
3561 | struct nfs4_stateowner *lock_sop = NULL; | 3559 | struct nfs4_stateowner *lock_sop = NULL; |
3562 | struct nfs4_stateid *lock_stp; | 3560 | struct nfs4_stateid *lock_stp; |
3563 | struct file *filp; | 3561 | struct nfs4_file *fp; |
3562 | struct file *filp = NULL; | ||
3564 | struct file_lock file_lock; | 3563 | struct file_lock file_lock; |
3565 | struct file_lock conflock; | 3564 | struct file_lock conflock; |
3566 | __be32 status = 0; | 3565 | __be32 status = 0; |
@@ -3590,7 +3589,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3590 | * lock stateid. | 3589 | * lock stateid. |
3591 | */ | 3590 | */ |
3592 | struct nfs4_stateid *open_stp = NULL; | 3591 | struct nfs4_stateid *open_stp = NULL; |
3593 | struct nfs4_file *fp; | ||
3594 | 3592 | ||
3595 | status = nfserr_stale_clientid; | 3593 | status = nfserr_stale_clientid; |
3596 | if (!nfsd4_has_session(cstate) && | 3594 | if (!nfsd4_has_session(cstate) && |
@@ -3633,6 +3631,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3633 | if (status) | 3631 | if (status) |
3634 | goto out; | 3632 | goto out; |
3635 | lock_sop = lock->lk_replay_owner; | 3633 | lock_sop = lock->lk_replay_owner; |
3634 | fp = lock_stp->st_file; | ||
3636 | } | 3635 | } |
3637 | /* lock->lk_replay_owner and lock_stp have been created or found */ | 3636 | /* lock->lk_replay_owner and lock_stp have been created or found */ |
3638 | 3637 | ||
@@ -3647,13 +3646,19 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3647 | switch (lock->lk_type) { | 3646 | switch (lock->lk_type) { |
3648 | case NFS4_READ_LT: | 3647 | case NFS4_READ_LT: |
3649 | case NFS4_READW_LT: | 3648 | case NFS4_READW_LT: |
3650 | filp = find_readable_file(lock_stp->st_file); | 3649 | if (find_readable_file(lock_stp->st_file)) { |
3650 | nfs4_get_vfs_file(rqstp, fp, &cstate->current_fh, NFS4_SHARE_ACCESS_READ); | ||
3651 | filp = find_readable_file(lock_stp->st_file); | ||
3652 | } | ||
3651 | file_lock.fl_type = F_RDLCK; | 3653 | file_lock.fl_type = F_RDLCK; |
3652 | cmd = F_SETLK; | 3654 | cmd = F_SETLK; |
3653 | break; | 3655 | break; |
3654 | case NFS4_WRITE_LT: | 3656 | case NFS4_WRITE_LT: |
3655 | case NFS4_WRITEW_LT: | 3657 | case NFS4_WRITEW_LT: |
3656 | filp = find_writeable_file(lock_stp->st_file); | 3658 | if (find_writeable_file(lock_stp->st_file)) { |
3659 | nfs4_get_vfs_file(rqstp, fp, &cstate->current_fh, NFS4_SHARE_ACCESS_WRITE); | ||
3660 | filp = find_writeable_file(lock_stp->st_file); | ||
3661 | } | ||
3657 | file_lock.fl_type = F_WRLCK; | 3662 | file_lock.fl_type = F_WRLCK; |
3658 | cmd = F_SETLK; | 3663 | cmd = F_SETLK; |
3659 | break; | 3664 | break; |
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 84579c86b13d..322518c88e4b 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -363,16 +363,16 @@ struct nfs4_file { | |||
363 | * at all? */ | 363 | * at all? */ |
364 | static inline struct file *find_writeable_file(struct nfs4_file *f) | 364 | static inline struct file *find_writeable_file(struct nfs4_file *f) |
365 | { | 365 | { |
366 | if (f->fi_fds[O_RDWR]) | 366 | if (f->fi_fds[O_WRONLY]) |
367 | return f->fi_fds[O_RDWR]; | 367 | return f->fi_fds[O_WRONLY]; |
368 | return f->fi_fds[O_WRONLY]; | 368 | return f->fi_fds[O_RDWR]; |
369 | } | 369 | } |
370 | 370 | ||
371 | static inline struct file *find_readable_file(struct nfs4_file *f) | 371 | static inline struct file *find_readable_file(struct nfs4_file *f) |
372 | { | 372 | { |
373 | if (f->fi_fds[O_RDWR]) | 373 | if (f->fi_fds[O_RDONLY]) |
374 | return f->fi_fds[O_RDWR]; | 374 | return f->fi_fds[O_RDONLY]; |
375 | return f->fi_fds[O_RDONLY]; | 375 | return f->fi_fds[O_RDWR]; |
376 | } | 376 | } |
377 | 377 | ||
378 | static inline struct file *find_any_file(struct nfs4_file *f) | 378 | static inline struct file *find_any_file(struct nfs4_file *f) |