+ clp = st->st_stid.sc_client;
+ if (nfsd4_expire_courtesy_clnt(clp))
+ continue;
+ conflict = false;
+ break;
+ }
+ return conflict;
+}
+
static __be32
-nfs4_file_get_access(struct nfs4_file *fp, u32 access)
+nfs4_file_get_access(struct nfs4_file *fp, u32 access,
+ struct nfs4_ol_stateid *stp, bool new_stp)
{
+
lockdep_assert_held(&fp->fi_lock);
/* Does this access mode make sense? */
@@ -711,15 +758,21 @@ nfs4_file_get_access(struct nfs4_file *fp, u32 access)
return nfserr_inval;
/* Does it conflict with a deny mode already set? */
- if ((access & fp->fi_share_deny) != 0)
- return nfserr_share_denied;
+ if ((access & fp->fi_share_deny) != 0) {
+ if (!nfs4_resolve_deny_conflicts_locked(fp, new_stp,
+ stp, access, true))
+ return nfserr_share_denied;
+ }
__nfs4_file_get_access(fp, access);
return nfs_ok;
}
-static __be32 nfs4_file_check_deny(struct nfs4_file *fp, u32 deny)
+static __be32 nfs4_file_check_deny(struct nfs4_file *fp, u32 deny,
+ struct nfs4_ol_stateid *stp, bool new_stp)
{
+ __be32 rc = nfs_ok;
+
/* Common case is that there is no deny mode. */
if (deny) {
/* Does this deny mode make sense? */
@@ -728,13 +781,19 @@ static __be32 nfs4_file_check_deny(struct nfs4_file *fp, u32 deny)
if ((deny & NFS4_SHARE_DENY_READ) &&
atomic_read(&fp->fi_access[O_RDONLY]))
- return nfserr_share_denied;
+ rc = nfserr_share_denied;
if ((deny & NFS4_SHARE_DENY_WRITE) &&
atomic_read(&fp->fi_access[O_WRONLY]))
- return nfserr_share_denied;
+ rc = nfserr_share_denied;
+
+ if (rc == nfserr_share_denied) {
+ if (nfs4_resolve_deny_conflicts_locked(fp, new_stp,
+ stp, deny, false))
+ rc = nfs_ok;
+ }
}
- return nfs_ok;
+ return rc;
}
static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
@@ -4952,7 +5011,7 @@ 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;
@@ -4966,14 +5025,14 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
* Are we trying to set a deny mode that would conflict with
* current access?
*/
- status = nfs4_file_check_deny(fp, open->op_share_deny);
+ status = nfs4_file_check_deny(fp, open->op_share_deny, stp, new_stp);
if (status != nfs_ok) {
spin_unlock(&fp->fi_lock);
goto out;
}
/* set access to the file */
- status = nfs4_file_get_access(fp, open->op_share_access);
+ status = nfs4_file_get_access(fp, open->op_share_access, stp, new_stp);
if (status != nfs_ok) {
spin_unlock(&fp->fi_lock);
goto out;
@@ -5027,11 +5086,11 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *c
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);
+ status = nfs4_file_check_deny(fp, open->op_share_deny, stp, false);
if (status == nfs_ok) {
set_deny(open->op_share_deny, stp);
fp->fi_share_deny |=
@@ -5376,7 +5435,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);
--
2.9.5