diff mbox series

[RFC,v21,2/7] NFSD: add support for share reservation conflict to courteous server

Message ID 1650739455-26096-3-git-send-email-dai.ngo@oracle.com (mailing list archive)
State New, archived
Headers show
Series NFSD: Initial implementation of NFSv4 Courteous Server | expand

Commit Message

Dai Ngo April 23, 2022, 6:44 p.m. UTC
This patch allows expired client with open state to be in COURTESY
state. Share/access conflict with COURTESY client is resolved by
setting COURTESY client to EXPIRABLE state, schedule laundromat
to run and returning nfserr_jukebox to the request client.

Signed-off-by: Dai Ngo <dai.ngo@oracle.com>
---
 fs/nfsd/nfs4state.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 105 insertions(+), 6 deletions(-)

Comments

Chuck Lever April 25, 2022, 1:15 p.m. UTC | #1
> On Apr 23, 2022, at 2:44 PM, Dai Ngo <dai.ngo@oracle.com> wrote:
> 
> This patch allows expired client with open state to be in COURTESY
> state. Share/access conflict with COURTESY client is resolved by
> setting COURTESY client to EXPIRABLE state, schedule laundromat
> to run and returning nfserr_jukebox to the request client.
> 
> Signed-off-by: Dai Ngo <dai.ngo@oracle.com>
> ---
> fs/nfsd/nfs4state.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++---
> 1 file changed, 105 insertions(+), 6 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index fea5e24e7d94..b08c132648b9 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -700,6 +700,57 @@ run_laundromat(struct nfsd_net *nn, bool wait)
> 		flush_workqueue(laundry_wq);
> }
> 
> +/*
> + * Check if courtesy clients have conflicting access and resolve it if possible
> + *
> + * access:  is op_share_access if share_access is true.
> + *	    Check if access mode, op_share_access, would conflict with
> + *	    the current deny mode of the file 'fp'.
> + * access:  is op_share_deny if share_access is false.
> + *	    Check if the deny mode, op_share_deny, would conflict with
> + *	    current access of the file 'fp'.
> + * stp:     skip checking this entry.
> + * new_stp: normal open, not open upgrade.
> + *
> + * Function returns:
> + *	false - access/deny mode conflict with normal client.
> + *	true  - no conflict or conflict with courtesy client(s) is resolved.
> + */
> +static bool
> +nfs4_resolve_deny_conflicts_locked(struct nfs4_file *fp, bool new_stp,
> +		struct nfs4_ol_stateid *stp, u32 access, bool share_access)
> +{
> +	struct nfs4_ol_stateid *st;
> +	bool conflict = true;
> +	unsigned char bmap;
> +	struct nfsd_net *nn;
> +	struct nfs4_client *clp;
> +
> +	lockdep_assert_held(&fp->fi_lock);
> +	list_for_each_entry(st, &fp->fi_stateids, st_perfile) {
> +		/* ignore lock stateid */
> +		if (st->st_openstp)
> +			continue;
> +		if (st == stp && new_stp)
> +			continue;
> +		/* check file access against deny mode or vice versa */
> +		bmap = share_access ? st->st_deny_bmap : st->st_access_bmap;
> +		if (!(access & bmap_to_share_mode(bmap)))
> +			continue;
> +		clp = st->st_stid.sc_client;
> +		if (try_to_expire_client(clp))
> +			continue;
> +		conflict = false;
> +		break;
> +	}
> +	if (conflict) {
> +		clp = stp->st_stid.sc_client;
> +		nn = net_generic(clp->net, nfsd_net_id);
> +		run_laundromat(nn, false);
> +	}
> +	return conflict;
> +}
> +
> static void
> __nfs4_file_get_access(struct nfs4_file *fp, u32 access)
> {
> @@ -4995,13 +5046,14 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
> 
> static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
> 		struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp,
> -		struct nfsd4_open *open)
> +		struct nfsd4_open *open, bool new_stp)
> {
> 	struct nfsd_file *nf = NULL;
> 	__be32 status;
> 	int oflag = nfs4_access_to_omode(open->op_share_access);
> 	int access = nfs4_access_to_access(open->op_share_access);
> 	unsigned char old_access_bmap, old_deny_bmap;
> +	struct nfs4_client *clp;
> 
> 	spin_lock(&fp->fi_lock);
> 
> @@ -5011,6 +5063,14 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
> 	 */
> 	status = nfs4_file_check_deny(fp, open->op_share_deny);
> 	if (status != nfs_ok) {
> +		if (status != nfserr_share_denied) {
> +			spin_unlock(&fp->fi_lock);
> +			goto out;
> +		}
> +		clp = stp->st_stid.sc_client;

@clp is set here, but the value is never used in this function,
even in later patches. Possibly left over from the previous
revision of this series?


> +		if (nfs4_resolve_deny_conflicts_locked(fp, new_stp,
> +				stp, open->op_share_deny, false))
> +			status = nfserr_jukebox;
> 		spin_unlock(&fp->fi_lock);
> 		goto out;
> 	}
> @@ -5018,6 +5078,14 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
> 	/* set access to the file */
> 	status = nfs4_file_get_access(fp, open->op_share_access);
> 	if (status != nfs_ok) {
> +		if (status != nfserr_share_denied) {
> +			spin_unlock(&fp->fi_lock);
> +			goto out;
> +		}
> +		clp = stp->st_stid.sc_client;

Ditto.


> +		if (nfs4_resolve_deny_conflicts_locked(fp, new_stp,
> +				stp, open->op_share_access, true))
> +			status = nfserr_jukebox;
> 		spin_unlock(&fp->fi_lock);
> 		goto out;
> 	}
> @@ -5064,21 +5132,29 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
> }
> 
> static __be32
> -nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, struct nfsd4_open *open)
> +nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp,
> +		struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp,
> +		struct nfsd4_open *open)
> {
> 	__be32 status;
> 	unsigned char old_deny_bmap = stp->st_deny_bmap;
> 
> 	if (!test_access(open->op_share_access, stp))
> -		return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open);
> +		return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open, false);
> 
> 	/* test and set deny mode */
> 	spin_lock(&fp->fi_lock);
> 	status = nfs4_file_check_deny(fp, open->op_share_deny);
> 	if (status == nfs_ok) {
> -		set_deny(open->op_share_deny, stp);
> -		fp->fi_share_deny |=
> +		if (status != nfserr_share_denied) {
> +			set_deny(open->op_share_deny, stp);
> +			fp->fi_share_deny |=
> 				(open->op_share_deny & NFS4_SHARE_DENY_BOTH);
> +		} else {
> +			if (nfs4_resolve_deny_conflicts_locked(fp, false,
> +					stp, open->op_share_deny, false))
> +				status = nfserr_jukebox;
> +		}
> 	}
> 	spin_unlock(&fp->fi_lock);
> 
> @@ -5419,7 +5495,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
> 			goto out;
> 		}
> 	} else {
> -		status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open);
> +		status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open, true);
> 		if (status) {
> 			stp->st_stid.sc_type = NFS4_CLOSED_STID;
> 			release_open_stateid(stp);
> @@ -5653,12 +5729,35 @@ static void nfsd4_ssc_expire_umount(struct nfsd_net *nn)
> }
> #endif
> 
> +static bool
> +nfs4_has_any_locks(struct nfs4_client *clp)
> +{
> +	int i;
> +	struct nfs4_stateowner *so;
> +
> +	spin_lock(&clp->cl_lock);
> +	for (i = 0; i < OWNER_HASH_SIZE; i++) {
> +		list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[i],
> +				so_strhash) {
> +			if (so->so_is_open_owner)
> +				continue;
> +			spin_unlock(&clp->cl_lock);
> +			return true;
> +		}
> +	}
> +	spin_unlock(&clp->cl_lock);
> +	return false;
> +}
> +
> /*
>  * place holder for now, no check for lock blockers yet
>  */
> static bool
> nfs4_anylock_blockers(struct nfs4_client *clp)
> {
> +	/* not allow locks yet */
> +	if (nfs4_has_any_locks(clp))
> +		return true;
> 	/*
> 	 * don't want to check for delegation conflict here since
> 	 * we need the state_lock for it. The laundromat willexpire
> -- 
> 2.9.5
> 

--
Chuck Lever
Dai Ngo April 25, 2022, 3:08 p.m. UTC | #2
On 4/25/22 6:15 AM, Chuck Lever III wrote:
>
>> On Apr 23, 2022, at 2:44 PM, Dai Ngo <dai.ngo@oracle.com> wrote:
>>
>> This patch allows expired client with open state to be in COURTESY
>> state. Share/access conflict with COURTESY client is resolved by
>> setting COURTESY client to EXPIRABLE state, schedule laundromat
>> to run and returning nfserr_jukebox to the request client.
>>
>> Signed-off-by: Dai Ngo <dai.ngo@oracle.com>
>> ---
>> fs/nfsd/nfs4state.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++---
>> 1 file changed, 105 insertions(+), 6 deletions(-)
>>
>> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
>> index fea5e24e7d94..b08c132648b9 100644
>> --- a/fs/nfsd/nfs4state.c
>> +++ b/fs/nfsd/nfs4state.c
>> @@ -700,6 +700,57 @@ run_laundromat(struct nfsd_net *nn, bool wait)
>> 		flush_workqueue(laundry_wq);
>> }
>>
>> +/*
>> + * Check if courtesy clients have conflicting access and resolve it if possible
>> + *
>> + * access:  is op_share_access if share_access is true.
>> + *	    Check if access mode, op_share_access, would conflict with
>> + *	    the current deny mode of the file 'fp'.
>> + * access:  is op_share_deny if share_access is false.
>> + *	    Check if the deny mode, op_share_deny, would conflict with
>> + *	    current access of the file 'fp'.
>> + * stp:     skip checking this entry.
>> + * new_stp: normal open, not open upgrade.
>> + *
>> + * Function returns:
>> + *	false - access/deny mode conflict with normal client.
>> + *	true  - no conflict or conflict with courtesy client(s) is resolved.
>> + */
>> +static bool
>> +nfs4_resolve_deny_conflicts_locked(struct nfs4_file *fp, bool new_stp,
>> +		struct nfs4_ol_stateid *stp, u32 access, bool share_access)
>> +{
>> +	struct nfs4_ol_stateid *st;
>> +	bool conflict = true;
>> +	unsigned char bmap;
>> +	struct nfsd_net *nn;
>> +	struct nfs4_client *clp;
>> +
>> +	lockdep_assert_held(&fp->fi_lock);
>> +	list_for_each_entry(st, &fp->fi_stateids, st_perfile) {
>> +		/* ignore lock stateid */
>> +		if (st->st_openstp)
>> +			continue;
>> +		if (st == stp && new_stp)
>> +			continue;
>> +		/* check file access against deny mode or vice versa */
>> +		bmap = share_access ? st->st_deny_bmap : st->st_access_bmap;
>> +		if (!(access & bmap_to_share_mode(bmap)))
>> +			continue;
>> +		clp = st->st_stid.sc_client;
>> +		if (try_to_expire_client(clp))
>> +			continue;
>> +		conflict = false;
>> +		break;
>> +	}
>> +	if (conflict) {
>> +		clp = stp->st_stid.sc_client;
>> +		nn = net_generic(clp->net, nfsd_net_id);
>> +		run_laundromat(nn, false);
>> +	}
>> +	return conflict;
>> +}
>> +
>> static void
>> __nfs4_file_get_access(struct nfs4_file *fp, u32 access)
>> {
>> @@ -4995,13 +5046,14 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
>>
>> static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
>> 		struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp,
>> -		struct nfsd4_open *open)
>> +		struct nfsd4_open *open, bool new_stp)
>> {
>> 	struct nfsd_file *nf = NULL;
>> 	__be32 status;
>> 	int oflag = nfs4_access_to_omode(open->op_share_access);
>> 	int access = nfs4_access_to_access(open->op_share_access);
>> 	unsigned char old_access_bmap, old_deny_bmap;
>> +	struct nfs4_client *clp;
>>
>> 	spin_lock(&fp->fi_lock);
>>
>> @@ -5011,6 +5063,14 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
>> 	 */
>> 	status = nfs4_file_check_deny(fp, open->op_share_deny);
>> 	if (status != nfs_ok) {
>> +		if (status != nfserr_share_denied) {
>> +			spin_unlock(&fp->fi_lock);
>> +			goto out;
>> +		}
>> +		clp = stp->st_stid.sc_client;
> @clp is set here, but the value is never used in this function,
> even in later patches. Possibly left over from the previous
> revision of this series?

Thanks Chuck, will fix in v22.
Kernel test robot also reported the problem.

-Dai

>
>
>> +		if (nfs4_resolve_deny_conflicts_locked(fp, new_stp,
>> +				stp, open->op_share_deny, false))
>> +			status = nfserr_jukebox;
>> 		spin_unlock(&fp->fi_lock);
>> 		goto out;
>> 	}
>> @@ -5018,6 +5078,14 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
>> 	/* set access to the file */
>> 	status = nfs4_file_get_access(fp, open->op_share_access);
>> 	if (status != nfs_ok) {
>> +		if (status != nfserr_share_denied) {
>> +			spin_unlock(&fp->fi_lock);
>> +			goto out;
>> +		}
>> +		clp = stp->st_stid.sc_client;
> Ditto.
>
>
>> +		if (nfs4_resolve_deny_conflicts_locked(fp, new_stp,
>> +				stp, open->op_share_access, true))
>> +			status = nfserr_jukebox;
>> 		spin_unlock(&fp->fi_lock);
>> 		goto out;
>> 	}
>> @@ -5064,21 +5132,29 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
>> }
>>
>> static __be32
>> -nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, struct nfsd4_open *open)
>> +nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp,
>> +		struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp,
>> +		struct nfsd4_open *open)
>> {
>> 	__be32 status;
>> 	unsigned char old_deny_bmap = stp->st_deny_bmap;
>>
>> 	if (!test_access(open->op_share_access, stp))
>> -		return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open);
>> +		return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open, false);
>>
>> 	/* test and set deny mode */
>> 	spin_lock(&fp->fi_lock);
>> 	status = nfs4_file_check_deny(fp, open->op_share_deny);
>> 	if (status == nfs_ok) {
>> -		set_deny(open->op_share_deny, stp);
>> -		fp->fi_share_deny |=
>> +		if (status != nfserr_share_denied) {
>> +			set_deny(open->op_share_deny, stp);
>> +			fp->fi_share_deny |=
>> 				(open->op_share_deny & NFS4_SHARE_DENY_BOTH);
>> +		} else {
>> +			if (nfs4_resolve_deny_conflicts_locked(fp, false,
>> +					stp, open->op_share_deny, false))
>> +				status = nfserr_jukebox;
>> +		}
>> 	}
>> 	spin_unlock(&fp->fi_lock);
>>
>> @@ -5419,7 +5495,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
>> 			goto out;
>> 		}
>> 	} else {
>> -		status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open);
>> +		status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open, true);
>> 		if (status) {
>> 			stp->st_stid.sc_type = NFS4_CLOSED_STID;
>> 			release_open_stateid(stp);
>> @@ -5653,12 +5729,35 @@ static void nfsd4_ssc_expire_umount(struct nfsd_net *nn)
>> }
>> #endif
>>
>> +static bool
>> +nfs4_has_any_locks(struct nfs4_client *clp)
>> +{
>> +	int i;
>> +	struct nfs4_stateowner *so;
>> +
>> +	spin_lock(&clp->cl_lock);
>> +	for (i = 0; i < OWNER_HASH_SIZE; i++) {
>> +		list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[i],
>> +				so_strhash) {
>> +			if (so->so_is_open_owner)
>> +				continue;
>> +			spin_unlock(&clp->cl_lock);
>> +			return true;
>> +		}
>> +	}
>> +	spin_unlock(&clp->cl_lock);
>> +	return false;
>> +}
>> +
>> /*
>>   * place holder for now, no check for lock blockers yet
>>   */
>> static bool
>> nfs4_anylock_blockers(struct nfs4_client *clp)
>> {
>> +	/* not allow locks yet */
>> +	if (nfs4_has_any_locks(clp))
>> +		return true;
>> 	/*
>> 	 * don't want to check for delegation conflict here since
>> 	 * we need the state_lock for it. The laundromat willexpire
>> -- 
>> 2.9.5
>>
> --
> Chuck Lever
>
>
>
diff mbox series

Patch

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index fea5e24e7d94..b08c132648b9 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -700,6 +700,57 @@  run_laundromat(struct nfsd_net *nn, bool wait)
 		flush_workqueue(laundry_wq);
 }
 
+/*
+ * Check if courtesy clients have conflicting access and resolve it if possible
+ *
+ * access:  is op_share_access if share_access is true.
+ *	    Check if access mode, op_share_access, would conflict with
+ *	    the current deny mode of the file 'fp'.
+ * access:  is op_share_deny if share_access is false.
+ *	    Check if the deny mode, op_share_deny, would conflict with
+ *	    current access of the file 'fp'.
+ * stp:     skip checking this entry.
+ * new_stp: normal open, not open upgrade.
+ *
+ * Function returns:
+ *	false - access/deny mode conflict with normal client.
+ *	true  - no conflict or conflict with courtesy client(s) is resolved.
+ */
+static bool
+nfs4_resolve_deny_conflicts_locked(struct nfs4_file *fp, bool new_stp,
+		struct nfs4_ol_stateid *stp, u32 access, bool share_access)
+{
+	struct nfs4_ol_stateid *st;
+	bool conflict = true;
+	unsigned char bmap;
+	struct nfsd_net *nn;
+	struct nfs4_client *clp;
+
+	lockdep_assert_held(&fp->fi_lock);
+	list_for_each_entry(st, &fp->fi_stateids, st_perfile) {
+		/* ignore lock stateid */
+		if (st->st_openstp)
+			continue;
+		if (st == stp && new_stp)
+			continue;
+		/* check file access against deny mode or vice versa */
+		bmap = share_access ? st->st_deny_bmap : st->st_access_bmap;
+		if (!(access & bmap_to_share_mode(bmap)))
+			continue;
+		clp = st->st_stid.sc_client;
+		if (try_to_expire_client(clp))
+			continue;
+		conflict = false;
+		break;
+	}
+	if (conflict) {
+		clp = stp->st_stid.sc_client;
+		nn = net_generic(clp->net, nfsd_net_id);
+		run_laundromat(nn, false);
+	}
+	return conflict;
+}
+
 static void
 __nfs4_file_get_access(struct nfs4_file *fp, u32 access)
 {
@@ -4995,13 +5046,14 @@  nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
 
 static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
 		struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp,
-		struct nfsd4_open *open)
+		struct nfsd4_open *open, bool new_stp)
 {
 	struct nfsd_file *nf = NULL;
 	__be32 status;
 	int oflag = nfs4_access_to_omode(open->op_share_access);
 	int access = nfs4_access_to_access(open->op_share_access);
 	unsigned char old_access_bmap, old_deny_bmap;
+	struct nfs4_client *clp;
 
 	spin_lock(&fp->fi_lock);
 
@@ -5011,6 +5063,14 @@  static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
 	 */
 	status = nfs4_file_check_deny(fp, open->op_share_deny);
 	if (status != nfs_ok) {
+		if (status != nfserr_share_denied) {
+			spin_unlock(&fp->fi_lock);
+			goto out;
+		}
+		clp = stp->st_stid.sc_client;
+		if (nfs4_resolve_deny_conflicts_locked(fp, new_stp,
+				stp, open->op_share_deny, false))
+			status = nfserr_jukebox;
 		spin_unlock(&fp->fi_lock);
 		goto out;
 	}
@@ -5018,6 +5078,14 @@  static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
 	/* set access to the file */
 	status = nfs4_file_get_access(fp, open->op_share_access);
 	if (status != nfs_ok) {
+		if (status != nfserr_share_denied) {
+			spin_unlock(&fp->fi_lock);
+			goto out;
+		}
+		clp = stp->st_stid.sc_client;
+		if (nfs4_resolve_deny_conflicts_locked(fp, new_stp,
+				stp, open->op_share_access, true))
+			status = nfserr_jukebox;
 		spin_unlock(&fp->fi_lock);
 		goto out;
 	}
@@ -5064,21 +5132,29 @@  static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
 }
 
 static __be32
-nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, struct nfsd4_open *open)
+nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp,
+		struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp,
+		struct nfsd4_open *open)
 {
 	__be32 status;
 	unsigned char old_deny_bmap = stp->st_deny_bmap;
 
 	if (!test_access(open->op_share_access, stp))
-		return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open);
+		return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open, false);
 
 	/* test and set deny mode */
 	spin_lock(&fp->fi_lock);
 	status = nfs4_file_check_deny(fp, open->op_share_deny);
 	if (status == nfs_ok) {
-		set_deny(open->op_share_deny, stp);
-		fp->fi_share_deny |=
+		if (status != nfserr_share_denied) {
+			set_deny(open->op_share_deny, stp);
+			fp->fi_share_deny |=
 				(open->op_share_deny & NFS4_SHARE_DENY_BOTH);
+		} else {
+			if (nfs4_resolve_deny_conflicts_locked(fp, false,
+					stp, open->op_share_deny, false))
+				status = nfserr_jukebox;
+		}
 	}
 	spin_unlock(&fp->fi_lock);
 
@@ -5419,7 +5495,7 @@  nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
 			goto out;
 		}
 	} else {
-		status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open);
+		status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open, true);
 		if (status) {
 			stp->st_stid.sc_type = NFS4_CLOSED_STID;
 			release_open_stateid(stp);
@@ -5653,12 +5729,35 @@  static void nfsd4_ssc_expire_umount(struct nfsd_net *nn)
 }
 #endif
 
+static bool
+nfs4_has_any_locks(struct nfs4_client *clp)
+{
+	int i;
+	struct nfs4_stateowner *so;
+
+	spin_lock(&clp->cl_lock);
+	for (i = 0; i < OWNER_HASH_SIZE; i++) {
+		list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[i],
+				so_strhash) {
+			if (so->so_is_open_owner)
+				continue;
+			spin_unlock(&clp->cl_lock);
+			return true;
+		}
+	}
+	spin_unlock(&clp->cl_lock);
+	return false;
+}
+
 /*
  * place holder for now, no check for lock blockers yet
  */
 static bool
 nfs4_anylock_blockers(struct nfs4_client *clp)
 {
+	/* not allow locks yet */
+	if (nfs4_has_any_locks(clp))
+		return true;
 	/*
 	 * don't want to check for delegation conflict here since
 	 * we need the state_lock for it. The laundromat willexpire