Author: rmacklem
Date: Sun Apr 23 21:51:28 2017
New Revision: 317345
URL: https://svnweb.freebsd.org/changeset/base/317345

Log:
  Make the NFSv4 client to use a write open for reading if allowed by the 
server.
  
  An NFSv4 server has the option of allowing a Read to be done using a Write
  Open. If this is not allowed, the server will return NFSERR_OPENMODE.
  This patch attempts the read with a write open and then disables this
  if the server replies NFSERR_OPENMODE.
  This change will avoid some uses of the special stateids. This will be
  useful for pNFS/DS Reads, since they cannot use special stateids.
  It will also be useful for any NFSv4 server that does not support reading
  via the special stateids. It has been tested against both types of NFSv4 
server.
  
  MFC after:    2 weeks

Modified:
  head/sys/fs/nfs/nfsport.h
  head/sys/fs/nfsclient/nfs_clrpcops.c
  head/sys/fs/nfsclient/nfs_clstate.c

Modified: head/sys/fs/nfs/nfsport.h
==============================================================================
--- head/sys/fs/nfs/nfsport.h   Sun Apr 23 21:36:32 2017        (r317344)
+++ head/sys/fs/nfs/nfsport.h   Sun Apr 23 21:51:28 2017        (r317345)
@@ -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)
 

Modified: head/sys/fs/nfsclient/nfs_clrpcops.c
==============================================================================
--- head/sys/fs/nfsclient/nfs_clrpcops.c        Sun Apr 23 21:36:32 2017        
(r317344)
+++ head/sys/fs/nfsclient/nfs_clrpcops.c        Sun Apr 23 21:51:28 2017        
(r317345)
@@ -1134,6 +1134,11 @@ nfsrpc_setattr(vnode_t vp, struct vattr 
                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 
            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
                            &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
            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 *uio
                                        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;

Modified: head/sys/fs/nfsclient/nfs_clstate.c
==============================================================================
--- head/sys/fs/nfsclient/nfs_clstate.c Sun Apr 23 21:36:32 2017        
(r317344)
+++ head/sys/fs/nfsclient/nfs_clstate.c Sun Apr 23 21:51:28 2017        
(r317345)
@@ -500,10 +500,11 @@ nfscl_getstateid(vnode_t vp, u_int8_t *n
 {
        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 *n
        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 *n
        }
        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.
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to