Commit 7d94784293096c0a46897acdb83be5abd9278ece
1 parent
18608ad49c
Exists in
master
and in
4 other branches
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>
Showing 2 changed files with 21 additions and 16 deletions Side-by-side Diff
fs/nfsd/nfs4state.c
... | ... | @@ -2450,14 +2450,13 @@ |
2450 | 2450 | static __be32 |
2451 | 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 | 2455 | __be32 status; |
2455 | 2456 | |
2456 | - set_access(&new_access, stp->st_access_bmap); | |
2457 | - new_access = (~new_access) & open->op_share_access & ~NFS4_SHARE_WANT_MASK; | |
2458 | - | |
2457 | + new_access = !test_bit(op_share_access, &stp->st_access_bmap); | |
2459 | 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 | 2460 | if (status) |
2462 | 2461 | return status; |
2463 | 2462 | } |
... | ... | @@ -2470,7 +2469,6 @@ |
2470 | 2469 | return status; |
2471 | 2470 | } |
2472 | 2471 | /* remember the open */ |
2473 | - op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK; | |
2474 | 2472 | __set_bit(op_share_access, &stp->st_access_bmap); |
2475 | 2473 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); |
2476 | 2474 | |
... | ... | @@ -3560,7 +3558,8 @@ |
3560 | 3558 | struct nfs4_stateowner *open_sop = NULL; |
3561 | 3559 | struct nfs4_stateowner *lock_sop = NULL; |
3562 | 3560 | struct nfs4_stateid *lock_stp; |
3563 | - struct file *filp; | |
3561 | + struct nfs4_file *fp; | |
3562 | + struct file *filp = NULL; | |
3564 | 3563 | struct file_lock file_lock; |
3565 | 3564 | struct file_lock conflock; |
3566 | 3565 | __be32 status = 0; |
... | ... | @@ -3590,7 +3589,6 @@ |
3590 | 3589 | * lock stateid. |
3591 | 3590 | */ |
3592 | 3591 | struct nfs4_stateid *open_stp = NULL; |
3593 | - struct nfs4_file *fp; | |
3594 | 3592 | |
3595 | 3593 | status = nfserr_stale_clientid; |
3596 | 3594 | if (!nfsd4_has_session(cstate) && |
... | ... | @@ -3633,6 +3631,7 @@ |
3633 | 3631 | if (status) |
3634 | 3632 | goto out; |
3635 | 3633 | lock_sop = lock->lk_replay_owner; |
3634 | + fp = lock_stp->st_file; | |
3636 | 3635 | } |
3637 | 3636 | /* lock->lk_replay_owner and lock_stp have been created or found */ |
3638 | 3637 | |
3639 | 3638 | |
... | ... | @@ -3647,13 +3646,19 @@ |
3647 | 3646 | switch (lock->lk_type) { |
3648 | 3647 | case NFS4_READ_LT: |
3649 | 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 | 3653 | file_lock.fl_type = F_RDLCK; |
3652 | 3654 | cmd = F_SETLK; |
3653 | 3655 | break; |
3654 | 3656 | case NFS4_WRITE_LT: |
3655 | 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 | 3662 | file_lock.fl_type = F_WRLCK; |
3658 | 3663 | cmd = F_SETLK; |
3659 | 3664 | break; |
fs/nfsd/state.h
... | ... | @@ -363,16 +363,16 @@ |
363 | 363 | * at all? */ |
364 | 364 | static inline struct file *find_writeable_file(struct nfs4_file *f) |
365 | 365 | { |
366 | - if (f->fi_fds[O_RDWR]) | |
367 | - return f->fi_fds[O_RDWR]; | |
368 | - return f->fi_fds[O_WRONLY]; | |
366 | + if (f->fi_fds[O_WRONLY]) | |
367 | + return f->fi_fds[O_WRONLY]; | |
368 | + return f->fi_fds[O_RDWR]; | |
369 | 369 | } |
370 | 370 | |
371 | 371 | static inline struct file *find_readable_file(struct nfs4_file *f) |
372 | 372 | { |
373 | - if (f->fi_fds[O_RDWR]) | |
374 | - return f->fi_fds[O_RDWR]; | |
375 | - return f->fi_fds[O_RDONLY]; | |
373 | + if (f->fi_fds[O_RDONLY]) | |
374 | + return f->fi_fds[O_RDONLY]; | |
375 | + return f->fi_fds[O_RDWR]; | |
376 | 376 | } |
377 | 377 | |
378 | 378 | static inline struct file *find_any_file(struct nfs4_file *f) |