summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/fs/nfs/nfsport.h2
-rw-r--r--sys/fs/nfsclient/nfs_clrpcops.c22
-rw-r--r--sys/fs/nfsclient/nfs_clstate.c28
3 files changed, 42 insertions, 10 deletions
diff --git a/sys/fs/nfs/nfsport.h b/sys/fs/nfs/nfsport.h
index 8c43f3f..8bd0f9e 100644
--- a/sys/fs/nfs/nfsport.h
+++ b/sys/fs/nfs/nfsport.h
@@ -899,6 +899,7 @@ int newnfs_realign(struct mbuf **, int);
*/
#define NFSSTA_HASWRITEVERF 0x00040000 /* Has write verifier */
#define NFSSTA_GOTFSINFO 0x00100000 /* Got the fsinfo */
+#define NFSSTA_OPENMODE 0x00200000 /* Must use correct open mode */
#define NFSSTA_NOLAYOUTCOMMIT 0x04000000 /* Don't do LayoutCommit */
#define NFSSTA_SESSPERSIST 0x08000000 /* Has a persistent session */
#define NFSSTA_TIMEO 0x10000000 /* Experiencing a timeout */
@@ -929,6 +930,7 @@ int newnfs_realign(struct mbuf **, int);
#define NFSHASNOLAYOUTCOMMIT(n) ((n)->nm_state & NFSSTA_NOLAYOUTCOMMIT)
#define NFSHASSESSPERSIST(n) ((n)->nm_state & NFSSTA_SESSPERSIST)
#define NFSHASPNFS(n) ((n)->nm_state & NFSSTA_PNFS)
+#define NFSHASOPENMODE(n) ((n)->nm_state & NFSSTA_OPENMODE)
#define NFSHASONEOPENOWN(n) (((n)->nm_flag & NFSMNT_ONEOPENOWN) != 0 && \
(n)->nm_minorvers > 0)
diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index 32c6188..38d2f73 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -1134,6 +1134,11 @@ nfsrpc_setattr(vnode_t vp, struct vattr *vap, NFSACL_T *aclp,
else
error = nfsrpc_setaclrpc(vp, cred, p, aclp, &stateid,
stuff);
+ if (error == NFSERR_OPENMODE && mode == NFSV4OPEN_ACCESSREAD) {
+ NFSLOCKMNT(nmp);
+ nmp->nm_state |= NFSSTA_OPENMODE;
+ NFSUNLOCKMNT(nmp);
+ }
if (error == NFSERR_STALESTATEID)
nfscl_initiate_recovery(nmp->nm_clp);
if (lckp != NULL)
@@ -1154,7 +1159,9 @@ nfsrpc_setattr(vnode_t vp, struct vattr *vap, NFSACL_T *aclp,
error == NFSERR_BADSESSION ||
(error == NFSERR_OLDSTATEID && retrycnt < 20) ||
((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
- expireret == 0 && clidrev != 0 && retrycnt < 4));
+ expireret == 0 && clidrev != 0 && retrycnt < 4) ||
+ (error == NFSERR_OPENMODE && mode == NFSV4OPEN_ACCESSREAD &&
+ retrycnt < 4));
if (error && retrycnt >= 4)
error = EIO;
return (error);
@@ -1391,6 +1398,11 @@ nfsrpc_read(vnode_t vp, struct uio *uiop, struct ucred *cred,
&lckp);
error = nfsrpc_readrpc(vp, uiop, newcred, &stateid, p, nap,
attrflagp, stuff);
+ if (error == NFSERR_OPENMODE) {
+ NFSLOCKMNT(nmp);
+ nmp->nm_state |= NFSSTA_OPENMODE;
+ NFSUNLOCKMNT(nmp);
+ }
if (error == NFSERR_STALESTATEID)
nfscl_initiate_recovery(nmp->nm_clp);
if (lckp != NULL)
@@ -1409,7 +1421,8 @@ nfsrpc_read(vnode_t vp, struct uio *uiop, struct ucred *cred,
error == NFSERR_BADSESSION ||
(error == NFSERR_OLDSTATEID && retrycnt < 20) ||
((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
- expireret == 0 && clidrev != 0 && retrycnt < 4));
+ expireret == 0 && clidrev != 0 && retrycnt < 4) ||
+ (error == NFSERR_OPENMODE && retrycnt < 4));
if (error && retrycnt >= 4)
error = EIO;
if (NFSHASNFSV4(nmp))
@@ -5594,6 +5607,11 @@ nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
if (lastbyte > layp->nfsly_lastbyte)
layp->nfsly_lastbyte = lastbyte;
NFSUNLOCKCLSTATE();
+ } else if (error == NFSERR_OPENMODE &&
+ rwaccess == NFSV4OPEN_ACCESSREAD) {
+ NFSLOCKMNT(nmp);
+ nmp->nm_state |= NFSSTA_OPENMODE;
+ NFSUNLOCKMNT(nmp);
}
} else
error = EIO;
diff --git a/sys/fs/nfsclient/nfs_clstate.c b/sys/fs/nfsclient/nfs_clstate.c
index f12757d..0842e52 100644
--- a/sys/fs/nfsclient/nfs_clstate.c
+++ b/sys/fs/nfsclient/nfs_clstate.c
@@ -500,10 +500,11 @@ nfscl_getstateid(vnode_t vp, u_int8_t *nfhp, int fhlen, u_int32_t mode,
{
struct nfsclclient *clp;
struct nfsclowner *owp;
- struct nfsclopen *op = NULL;
+ struct nfsclopen *op = NULL, *top;
struct nfscllockowner *lp;
struct nfscldeleg *dp;
struct nfsnode *np;
+ struct nfsmount *nmp;
u_int8_t own[NFSV4CL_LOCKNAMELEN];
int error, done;
@@ -521,8 +522,9 @@ nfscl_getstateid(vnode_t vp, u_int8_t *nfhp, int fhlen, u_int32_t mode,
if (vnode_vtype(vp) != VREG)
return (EISDIR);
np = VTONFS(vp);
+ nmp = VFSTONFS(vnode_mount(vp));
NFSLOCKCLSTATE();
- clp = nfscl_findcl(VFSTONFS(vnode_mount(vp)));
+ clp = nfscl_findcl(nmp);
if (clp == NULL) {
NFSUNLOCKCLSTATE();
return (EACCES);
@@ -592,23 +594,33 @@ nfscl_getstateid(vnode_t vp, u_int8_t *nfhp, int fhlen, u_int32_t mode,
}
if (op == NULL) {
/* If not found, just look for any OpenOwner that will work. */
+ top = NULL;
done = 0;
owp = LIST_FIRST(&clp->nfsc_owner);
while (!done && owp != NULL) {
LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
if (op->nfso_fhlen == fhlen &&
- !NFSBCMP(op->nfso_fh, nfhp, fhlen) &&
- (mode & op->nfso_mode) == mode) {
- done = 1;
- break;
+ !NFSBCMP(op->nfso_fh, nfhp, fhlen)) {
+ if (top == NULL && (op->nfso_mode &
+ NFSV4OPEN_ACCESSWRITE) != 0 &&
+ (mode & NFSV4OPEN_ACCESSREAD) != 0)
+ top = op;
+ if ((mode & op->nfso_mode) == mode) {
+ done = 1;
+ break;
+ }
}
}
if (!done)
owp = LIST_NEXT(owp, nfsow_list);
}
if (!done) {
- NFSUNLOCKCLSTATE();
- return (ENOENT);
+ NFSCL_DEBUG(2, "openmode top=%p\n", top);
+ if (top == NULL || NFSHASOPENMODE(nmp)) {
+ NFSUNLOCKCLSTATE();
+ return (ENOENT);
+ } else
+ op = top;
}
/*
* For read aheads or write behinds, use the open cred.
OpenPOWER on IntegriCloud