Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7d947842 authored by J. Bruce Fields's avatar J. Bruce Fields
Browse files

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: default avatarJ. Bruce Fields <bfields@redhat.com>
parent 18608ad4
Loading
Loading
Loading
Loading
+15 −10
Original line number Original line Diff line number Diff line
@@ -2450,14 +2450,13 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
static __be32
static __be32
nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open)
nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open)
{
{
	u32 op_share_access, new_access;
	u32 op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK;
	bool new_access;
	__be32 status;
	__be32 status;


	set_access(&new_access, stp->st_access_bmap);
	new_access = !test_bit(op_share_access, &stp->st_access_bmap);
	new_access = (~new_access) & open->op_share_access & ~NFS4_SHARE_WANT_MASK;

	if (new_access) {
	if (new_access) {
		status = nfs4_get_vfs_file(rqstp, fp, cur_fh, new_access);
		status = nfs4_get_vfs_file(rqstp, fp, cur_fh, op_share_access);
		if (status)
		if (status)
			return status;
			return status;
	}
	}
@@ -2470,7 +2469,6 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *c
		return status;
		return status;
	}
	}
	/* remember the open */
	/* remember the open */
	op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK;
	__set_bit(op_share_access, &stp->st_access_bmap);
	__set_bit(op_share_access, &stp->st_access_bmap);
	__set_bit(open->op_share_deny, &stp->st_deny_bmap);
	__set_bit(open->op_share_deny, &stp->st_deny_bmap);


@@ -3560,7 +3558,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	struct nfs4_stateowner *open_sop = NULL;
	struct nfs4_stateowner *open_sop = NULL;
	struct nfs4_stateowner *lock_sop = NULL;
	struct nfs4_stateowner *lock_sop = NULL;
	struct nfs4_stateid *lock_stp;
	struct nfs4_stateid *lock_stp;
	struct file *filp;
	struct nfs4_file *fp;
	struct file *filp = NULL;
	struct file_lock file_lock;
	struct file_lock file_lock;
	struct file_lock conflock;
	struct file_lock conflock;
	__be32 status = 0;
	__be32 status = 0;
@@ -3590,7 +3589,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
		 * lock stateid.
		 * lock stateid.
		 */
		 */
		struct nfs4_stateid *open_stp = NULL;
		struct nfs4_stateid *open_stp = NULL;
		struct nfs4_file *fp;
		
		
		status = nfserr_stale_clientid;
		status = nfserr_stale_clientid;
		if (!nfsd4_has_session(cstate) &&
		if (!nfsd4_has_session(cstate) &&
@@ -3633,6 +3631,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
		if (status)
		if (status)
			goto out;
			goto out;
		lock_sop = lock->lk_replay_owner;
		lock_sop = lock->lk_replay_owner;
		fp = lock_stp->st_file;
	}
	}
	/* lock->lk_replay_owner and lock_stp have been created or found */
	/* lock->lk_replay_owner and lock_stp have been created or found */


@@ -3647,13 +3646,19 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	switch (lock->lk_type) {
	switch (lock->lk_type) {
		case NFS4_READ_LT:
		case NFS4_READ_LT:
		case NFS4_READW_LT:
		case NFS4_READW_LT:
			if (find_readable_file(lock_stp->st_file)) {
				nfs4_get_vfs_file(rqstp, fp, &cstate->current_fh, NFS4_SHARE_ACCESS_READ);
				filp = find_readable_file(lock_stp->st_file);
				filp = find_readable_file(lock_stp->st_file);
			}
			file_lock.fl_type = F_RDLCK;
			file_lock.fl_type = F_RDLCK;
			cmd = F_SETLK;
			cmd = F_SETLK;
		break;
		break;
		case NFS4_WRITE_LT:
		case NFS4_WRITE_LT:
		case NFS4_WRITEW_LT:
		case NFS4_WRITEW_LT:
			if (find_writeable_file(lock_stp->st_file)) {
				nfs4_get_vfs_file(rqstp, fp, &cstate->current_fh, NFS4_SHARE_ACCESS_WRITE);
				filp = find_writeable_file(lock_stp->st_file);
				filp = find_writeable_file(lock_stp->st_file);
			}
			file_lock.fl_type = F_WRLCK;
			file_lock.fl_type = F_WRLCK;
			cmd = F_SETLK;
			cmd = F_SETLK;
		break;
		break;
+6 −6
Original line number Original line Diff line number Diff line
@@ -363,16 +363,16 @@ struct nfs4_file {
 * at all? */
 * at all? */
static inline struct file *find_writeable_file(struct nfs4_file *f)
static inline struct file *find_writeable_file(struct nfs4_file *f)
{
{
	if (f->fi_fds[O_RDWR])
	if (f->fi_fds[O_WRONLY])
		return f->fi_fds[O_RDWR];
		return f->fi_fds[O_WRONLY];
		return f->fi_fds[O_WRONLY];
	return f->fi_fds[O_RDWR];
}
}


static inline struct file *find_readable_file(struct nfs4_file *f)
static inline struct file *find_readable_file(struct nfs4_file *f)
{
{
	if (f->fi_fds[O_RDWR])
	if (f->fi_fds[O_RDONLY])
		return f->fi_fds[O_RDWR];
		return f->fi_fds[O_RDONLY];
		return f->fi_fds[O_RDONLY];
	return f->fi_fds[O_RDWR];
}
}


static inline struct file *find_any_file(struct nfs4_file *f)
static inline struct file *find_any_file(struct nfs4_file *f)