Commit 7d94784293096c0a46897acdb83be5abd9278ece

Authored by J. Bruce Fields
1 parent 18608ad49c

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

... ... @@ -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;
... ... @@ -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)