The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/nfsclient/nfs_clport.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-3-Clause
    3  *
    4  * Copyright (c) 1989, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * This code is derived from software contributed to Berkeley by
    8  * Rick Macklem at The University of Guelph.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. Neither the name of the University nor the names of its contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  *
   34  */
   35 
   36 #include <sys/cdefs.h>
   37 __FBSDID("$FreeBSD$");
   38 
   39 #include "opt_inet.h"
   40 #include "opt_inet6.h"
   41 
   42 #include <sys/capsicum.h>
   43 
   44 /*
   45  * generally, I don't like #includes inside .h files, but it seems to
   46  * be the easiest way to handle the port.
   47  */
   48 #include <sys/fail.h>
   49 #include <sys/hash.h>
   50 #include <sys/sysctl.h>
   51 #include <fs/nfs/nfsport.h>
   52 #include <netinet/in_fib.h>
   53 #include <netinet/if_ether.h>
   54 #include <netinet6/ip6_var.h>
   55 #include <net/if_types.h>
   56 #include <net/route/nhop.h>
   57 
   58 #include <fs/nfsclient/nfs_kdtrace.h>
   59 
   60 #ifdef KDTRACE_HOOKS
   61 dtrace_nfsclient_attrcache_flush_probe_func_t
   62                 dtrace_nfscl_attrcache_flush_done_probe;
   63 uint32_t        nfscl_attrcache_flush_done_id;
   64 
   65 dtrace_nfsclient_attrcache_get_hit_probe_func_t
   66                 dtrace_nfscl_attrcache_get_hit_probe;
   67 uint32_t        nfscl_attrcache_get_hit_id;
   68 
   69 dtrace_nfsclient_attrcache_get_miss_probe_func_t
   70                 dtrace_nfscl_attrcache_get_miss_probe;
   71 uint32_t        nfscl_attrcache_get_miss_id;
   72 
   73 dtrace_nfsclient_attrcache_load_probe_func_t
   74                 dtrace_nfscl_attrcache_load_done_probe;
   75 uint32_t        nfscl_attrcache_load_done_id;
   76 #endif /* !KDTRACE_HOOKS */
   77 
   78 extern u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
   79 extern struct vop_vector newnfs_vnodeops;
   80 extern struct vop_vector newnfs_fifoops;
   81 extern uma_zone_t newnfsnode_zone;
   82 extern struct buf_ops buf_ops_newnfs;
   83 extern uma_zone_t ncl_pbuf_zone;
   84 extern short nfsv4_cbport;
   85 extern int nfscl_enablecallb;
   86 extern int nfs_numnfscbd;
   87 extern int nfscl_inited;
   88 struct mtx ncl_iod_mutex;
   89 NFSDLOCKMUTEX;
   90 extern struct mtx nfsrv_dslock_mtx;
   91 
   92 extern void (*ncl_call_invalcaches)(struct vnode *);
   93 
   94 SYSCTL_DECL(_vfs_nfs);
   95 static int ncl_fileid_maxwarnings = 10;
   96 SYSCTL_INT(_vfs_nfs, OID_AUTO, fileid_maxwarnings, CTLFLAG_RWTUN,
   97     &ncl_fileid_maxwarnings, 0,
   98     "Limit fileid corruption warnings; 0 is off; -1 is unlimited");
   99 static volatile int ncl_fileid_nwarnings;
  100 
  101 static void nfscl_warn_fileid(struct nfsmount *, struct nfsvattr *,
  102     struct nfsvattr *);
  103 
  104 /*
  105  * Comparison function for vfs_hash functions.
  106  */
  107 int
  108 newnfs_vncmpf(struct vnode *vp, void *arg)
  109 {
  110         struct nfsfh *nfhp = (struct nfsfh *)arg;
  111         struct nfsnode *np = VTONFS(vp);
  112 
  113         if (np->n_fhp->nfh_len != nfhp->nfh_len ||
  114             NFSBCMP(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len))
  115                 return (1);
  116         return (0);
  117 }
  118 
  119 /*
  120  * Look up a vnode/nfsnode by file handle.
  121  * Callers must check for mount points!!
  122  * In all cases, a pointer to a
  123  * nfsnode structure is returned.
  124  * This variant takes a "struct nfsfh *" as second argument and uses
  125  * that structure up, either by hanging off the nfsnode or FREEing it.
  126  */
  127 int
  128 nfscl_nget(struct mount *mntp, struct vnode *dvp, struct nfsfh *nfhp,
  129     struct componentname *cnp, struct thread *td, struct nfsnode **npp,
  130     void *stuff, int lkflags)
  131 {
  132         struct nfsnode *np, *dnp;
  133         struct vnode *vp, *nvp;
  134         struct nfsv4node *newd, *oldd;
  135         int error;
  136         u_int hash;
  137         struct nfsmount *nmp;
  138 
  139         nmp = VFSTONFS(mntp);
  140         dnp = VTONFS(dvp);
  141         *npp = NULL;
  142 
  143         hash = fnv_32_buf(nfhp->nfh_fh, nfhp->nfh_len, FNV1_32_INIT);
  144 
  145         error = vfs_hash_get(mntp, hash, lkflags,
  146             td, &nvp, newnfs_vncmpf, nfhp);
  147         if (error == 0 && nvp != NULL) {
  148                 /*
  149                  * I believe there is a slight chance that vgonel() could
  150                  * get called on this vnode between when NFSVOPLOCK() drops
  151                  * the VI_LOCK() and vget() acquires it again, so that it
  152                  * hasn't yet had v_usecount incremented. If this were to
  153                  * happen, the VIRF_DOOMED flag would be set, so check for
  154                  * that here. Since we now have the v_usecount incremented,
  155                  * we should be ok until we vrele() it, if the VIRF_DOOMED
  156                  * flag isn't set now.
  157                  */
  158                 VI_LOCK(nvp);
  159                 if (VN_IS_DOOMED(nvp)) {
  160                         VI_UNLOCK(nvp);
  161                         vrele(nvp);
  162                         error = ENOENT;
  163                 } else {
  164                         VI_UNLOCK(nvp);
  165                 }
  166         }
  167         if (error) {
  168                 free(nfhp, M_NFSFH);
  169                 return (error);
  170         }
  171         if (nvp != NULL) {
  172                 np = VTONFS(nvp);
  173                 /*
  174                  * For NFSv4, check to see if it is the same name and
  175                  * replace the name, if it is different.
  176                  */
  177                 oldd = newd = NULL;
  178                 if ((nmp->nm_flag & NFSMNT_NFSV4) && np->n_v4 != NULL &&
  179                     nvp->v_type == VREG &&
  180                     (np->n_v4->n4_namelen != cnp->cn_namelen ||
  181                      NFSBCMP(cnp->cn_nameptr, NFS4NODENAME(np->n_v4),
  182                      cnp->cn_namelen) ||
  183                      dnp->n_fhp->nfh_len != np->n_v4->n4_fhlen ||
  184                      NFSBCMP(dnp->n_fhp->nfh_fh, np->n_v4->n4_data,
  185                      dnp->n_fhp->nfh_len))) {
  186                     newd = malloc(
  187                         sizeof (struct nfsv4node) + dnp->n_fhp->nfh_len +
  188                         + cnp->cn_namelen - 1, M_NFSV4NODE, M_WAITOK);
  189                     NFSLOCKNODE(np);
  190                     if (newd != NULL && np->n_v4 != NULL && nvp->v_type == VREG
  191                         && (np->n_v4->n4_namelen != cnp->cn_namelen ||
  192                          NFSBCMP(cnp->cn_nameptr, NFS4NODENAME(np->n_v4),
  193                          cnp->cn_namelen) ||
  194                          dnp->n_fhp->nfh_len != np->n_v4->n4_fhlen ||
  195                          NFSBCMP(dnp->n_fhp->nfh_fh, np->n_v4->n4_data,
  196                          dnp->n_fhp->nfh_len))) {
  197                         oldd = np->n_v4;
  198                         np->n_v4 = newd;
  199                         newd = NULL;
  200                         np->n_v4->n4_fhlen = dnp->n_fhp->nfh_len;
  201                         np->n_v4->n4_namelen = cnp->cn_namelen;
  202                         NFSBCOPY(dnp->n_fhp->nfh_fh, np->n_v4->n4_data,
  203                             dnp->n_fhp->nfh_len);
  204                         NFSBCOPY(cnp->cn_nameptr, NFS4NODENAME(np->n_v4),
  205                             cnp->cn_namelen);
  206                     }
  207                     NFSUNLOCKNODE(np);
  208                 }
  209                 if (newd != NULL)
  210                         free(newd, M_NFSV4NODE);
  211                 if (oldd != NULL)
  212                         free(oldd, M_NFSV4NODE);
  213                 *npp = np;
  214                 free(nfhp, M_NFSFH);
  215                 return (0);
  216         }
  217         np = uma_zalloc(newnfsnode_zone, M_WAITOK | M_ZERO);
  218 
  219         error = getnewvnode(nfs_vnode_tag, mntp, &newnfs_vnodeops, &nvp);
  220         if (error) {
  221                 uma_zfree(newnfsnode_zone, np);
  222                 free(nfhp, M_NFSFH);
  223                 return (error);
  224         }
  225         vp = nvp;
  226         KASSERT(vp->v_bufobj.bo_bsize != 0, ("nfscl_nget: bo_bsize == 0"));
  227         vp->v_bufobj.bo_ops = &buf_ops_newnfs;
  228         vp->v_data = np;
  229         np->n_vnode = vp;
  230         /* 
  231          * Initialize the mutex even if the vnode is going to be a loser.
  232          * This simplifies the logic in reclaim, which can then unconditionally
  233          * destroy the mutex (in the case of the loser, or if hash_insert
  234          * happened to return an error no special casing is needed).
  235          */
  236         mtx_init(&np->n_mtx, "NEWNFSnode lock", NULL, MTX_DEF | MTX_DUPOK);
  237         lockinit(&np->n_excl, PVFS, "nfsupg", VLKTIMEOUT, LK_NOSHARE |
  238             LK_CANRECURSE);
  239 
  240         /* 
  241          * Are we getting the root? If so, make sure the vnode flags
  242          * are correct 
  243          */
  244         if ((nfhp->nfh_len == nmp->nm_fhsize) &&
  245             !bcmp(nfhp->nfh_fh, nmp->nm_fh, nfhp->nfh_len)) {
  246                 if (vp->v_type == VNON)
  247                         vp->v_type = VDIR;
  248                 vp->v_vflag |= VV_ROOT;
  249         }
  250 
  251         vp->v_vflag |= VV_VMSIZEVNLOCK;
  252 
  253         np->n_fhp = nfhp;
  254         /*
  255          * For NFSv4, we have to attach the directory file handle and
  256          * file name, so that Open Ops can be done later.
  257          */
  258         if (nmp->nm_flag & NFSMNT_NFSV4) {
  259                 np->n_v4 = malloc(sizeof (struct nfsv4node)
  260                     + dnp->n_fhp->nfh_len + cnp->cn_namelen - 1, M_NFSV4NODE,
  261                     M_WAITOK);
  262                 np->n_v4->n4_fhlen = dnp->n_fhp->nfh_len;
  263                 np->n_v4->n4_namelen = cnp->cn_namelen;
  264                 NFSBCOPY(dnp->n_fhp->nfh_fh, np->n_v4->n4_data,
  265                     dnp->n_fhp->nfh_len);
  266                 NFSBCOPY(cnp->cn_nameptr, NFS4NODENAME(np->n_v4),
  267                     cnp->cn_namelen);
  268         } else {
  269                 np->n_v4 = NULL;
  270         }
  271 
  272         /*
  273          * NFS supports recursive and shared locking.
  274          */
  275         lockmgr(vp->v_vnlock, LK_EXCLUSIVE | LK_NOWITNESS, NULL);
  276         VN_LOCK_AREC(vp);
  277         VN_LOCK_ASHARE(vp);
  278         error = insmntque(vp, mntp);
  279         if (error != 0) {
  280                 *npp = NULL;
  281                 mtx_destroy(&np->n_mtx);
  282                 lockdestroy(&np->n_excl);
  283                 free(nfhp, M_NFSFH);
  284                 if (np->n_v4 != NULL)
  285                         free(np->n_v4, M_NFSV4NODE);
  286                 uma_zfree(newnfsnode_zone, np);
  287                 return (error);
  288         }
  289         error = vfs_hash_insert(vp, hash, lkflags, 
  290             td, &nvp, newnfs_vncmpf, nfhp);
  291         if (error)
  292                 return (error);
  293         if (nvp != NULL) {
  294                 *npp = VTONFS(nvp);
  295                 /* vfs_hash_insert() vput()'s the losing vnode */
  296                 return (0);
  297         }
  298         *npp = np;
  299 
  300         return (0);
  301 }
  302 
  303 /*
  304  * Another variant of nfs_nget(). This one is only used by reopen. It
  305  * takes almost the same args as nfs_nget(), but only succeeds if an entry
  306  * exists in the cache. (Since files should already be "open" with a
  307  * vnode ref cnt on the node when reopen calls this, it should always
  308  * succeed.)
  309  * Also, don't get a vnode lock, since it may already be locked by some
  310  * other process that is handling it. This is ok, since all other threads
  311  * on the client are blocked by the nfsc_lock being exclusively held by the
  312  * caller of this function.
  313  */
  314 int
  315 nfscl_ngetreopen(struct mount *mntp, u_int8_t *fhp, int fhsize,
  316     struct thread *td, struct nfsnode **npp)
  317 {
  318         struct vnode *nvp;
  319         u_int hash;
  320         struct nfsfh *nfhp;
  321         int error;
  322 
  323         *npp = NULL;
  324         /* For forced dismounts, just return error. */
  325         if (NFSCL_FORCEDISM(mntp))
  326                 return (EINTR);
  327         nfhp = malloc(sizeof (struct nfsfh) + fhsize,
  328             M_NFSFH, M_WAITOK);
  329         bcopy(fhp, &nfhp->nfh_fh[0], fhsize);
  330         nfhp->nfh_len = fhsize;
  331 
  332         hash = fnv_32_buf(fhp, fhsize, FNV1_32_INIT);
  333 
  334         /*
  335          * First, try to get the vnode locked, but don't block for the lock.
  336          */
  337         error = vfs_hash_get(mntp, hash, (LK_EXCLUSIVE | LK_NOWAIT), td, &nvp,
  338             newnfs_vncmpf, nfhp);
  339         if (error == 0 && nvp != NULL) {
  340                 NFSVOPUNLOCK(nvp);
  341         } else if (error == EBUSY) {
  342                 /*
  343                  * It is safe so long as a vflush() with
  344                  * FORCECLOSE has not been done. Since the Renew thread is
  345                  * stopped and the MNTK_UNMOUNTF flag is set before doing
  346                  * a vflush() with FORCECLOSE, we should be ok here.
  347                  */
  348                 if (NFSCL_FORCEDISM(mntp))
  349                         error = EINTR;
  350                 else {
  351                         vfs_hash_ref(mntp, hash, td, &nvp, newnfs_vncmpf, nfhp);
  352                         if (nvp == NULL) {
  353                                 error = ENOENT;
  354                         } else if (VN_IS_DOOMED(nvp)) {
  355                                 error = ENOENT;
  356                                 vrele(nvp);
  357                         } else {
  358                                 error = 0;
  359                         }
  360                 }
  361         }
  362         free(nfhp, M_NFSFH);
  363         if (error)
  364                 return (error);
  365         if (nvp != NULL) {
  366                 *npp = VTONFS(nvp);
  367                 return (0);
  368         }
  369         return (EINVAL);
  370 }
  371 
  372 static void
  373 nfscl_warn_fileid(struct nfsmount *nmp, struct nfsvattr *oldnap,
  374     struct nfsvattr *newnap)
  375 {
  376         int off;
  377 
  378         if (ncl_fileid_maxwarnings >= 0 &&
  379             ncl_fileid_nwarnings >= ncl_fileid_maxwarnings)
  380                 return;
  381         off = 0;
  382         if (ncl_fileid_maxwarnings >= 0) {
  383                 if (++ncl_fileid_nwarnings >= ncl_fileid_maxwarnings)
  384                         off = 1;
  385         }
  386 
  387         printf("newnfs: server '%s' error: fileid changed. "
  388             "fsid %jx:%jx: expected fileid %#jx, got %#jx. "
  389             "(BROKEN NFS SERVER OR MIDDLEWARE)\n",
  390             nmp->nm_com.nmcom_hostname,
  391             (uintmax_t)nmp->nm_fsid[0],
  392             (uintmax_t)nmp->nm_fsid[1],
  393             (uintmax_t)oldnap->na_fileid,
  394             (uintmax_t)newnap->na_fileid);
  395 
  396         if (off)
  397                 printf("newnfs: Logged %d times about fileid corruption; "
  398                     "going quiet to avoid spamming logs excessively. (Limit "
  399                     "is: %d).\n", ncl_fileid_nwarnings,
  400                     ncl_fileid_maxwarnings);
  401 }
  402 
  403 /*
  404  * Load the attribute cache (that lives in the nfsnode entry) with
  405  * the attributes of the second argument and
  406  * Iff vaper not NULL
  407  *    copy the attributes to *vaper
  408  * Similar to nfs_loadattrcache(), except the attributes are passed in
  409  * instead of being parsed out of the mbuf list.
  410  */
  411 int
  412 nfscl_loadattrcache(struct vnode **vpp, struct nfsvattr *nap, void *nvaper,
  413     void *stuff, int writeattr, int dontshrink)
  414 {
  415         struct vnode *vp = *vpp;
  416         struct vattr *vap, *nvap = &nap->na_vattr, *vaper = nvaper;
  417         struct nfsnode *np;
  418         struct nfsmount *nmp;
  419         struct timespec mtime_save;
  420         int error, force_fid_err;
  421 
  422         error = 0;
  423 
  424         /*
  425          * If v_type == VNON it is a new node, so fill in the v_type,
  426          * n_mtime fields. Check to see if it represents a special 
  427          * device, and if so, check for a possible alias. Once the
  428          * correct vnode has been obtained, fill in the rest of the
  429          * information.
  430          */
  431         np = VTONFS(vp);
  432         NFSLOCKNODE(np);
  433         if (vp->v_type != nvap->va_type) {
  434                 vp->v_type = nvap->va_type;
  435                 if (vp->v_type == VFIFO)
  436                         vp->v_op = &newnfs_fifoops;
  437                 np->n_mtime = nvap->va_mtime;
  438         }
  439         nmp = VFSTONFS(vp->v_mount);
  440         vap = &np->n_vattr.na_vattr;
  441         mtime_save = vap->va_mtime;
  442         if (writeattr) {
  443                 np->n_vattr.na_filerev = nap->na_filerev;
  444                 np->n_vattr.na_size = nap->na_size;
  445                 np->n_vattr.na_mtime = nap->na_mtime;
  446                 np->n_vattr.na_ctime = nap->na_ctime;
  447                 np->n_vattr.na_fsid = nap->na_fsid;
  448                 np->n_vattr.na_mode = nap->na_mode;
  449         } else {
  450                 force_fid_err = 0;
  451                 KFAIL_POINT_ERROR(DEBUG_FP, nfscl_force_fileid_warning,
  452                     force_fid_err);
  453                 /*
  454                  * BROKEN NFS SERVER OR MIDDLEWARE
  455                  *
  456                  * Certain NFS servers (certain old proprietary filers ca.
  457                  * 2006) or broken middleboxes (e.g. WAN accelerator products)
  458                  * will respond to GETATTR requests with results for a
  459                  * different fileid.
  460                  *
  461                  * The WAN accelerator we've observed not only serves stale
  462                  * cache results for a given file, it also occasionally serves
  463                  * results for wholly different files.  This causes surprising
  464                  * problems; for example the cached size attribute of a file
  465                  * may truncate down and then back up, resulting in zero
  466                  * regions in file contents read by applications.  We observed
  467                  * this reliably with Clang and .c files during parallel build.
  468                  * A pcap revealed packet fragmentation and GETATTR RPC
  469                  * responses with wholly wrong fileids.
  470                  */
  471                 if ((np->n_vattr.na_fileid != 0 &&
  472                      np->n_vattr.na_fileid != nap->na_fileid) ||
  473                     force_fid_err) {
  474                         nfscl_warn_fileid(nmp, &np->n_vattr, nap);
  475                         error = EIDRM;
  476                         goto out;
  477                 }
  478                 NFSBCOPY((caddr_t)nap, (caddr_t)&np->n_vattr,
  479                     sizeof (struct nfsvattr));
  480         }
  481 
  482         /*
  483          * For NFSv4, if the node's fsid is not equal to the mount point's
  484          * fsid, return the low order 32bits of the node's fsid. This
  485          * allows getcwd(3) to work. There is a chance that the fsid might
  486          * be the same as a local fs, but since this is in an NFS mount
  487          * point, I don't think that will cause any problems?
  488          */
  489         if (NFSHASNFSV4(nmp) && NFSHASHASSETFSID(nmp) &&
  490             (nmp->nm_fsid[0] != np->n_vattr.na_filesid[0] ||
  491              nmp->nm_fsid[1] != np->n_vattr.na_filesid[1])) {
  492                 /*
  493                  * va_fsid needs to be set to some value derived from
  494                  * np->n_vattr.na_filesid that is not equal
  495                  * vp->v_mount->mnt_stat.f_fsid[0], so that it changes
  496                  * from the value used for the top level server volume
  497                  * in the mounted subtree.
  498                  */
  499                 vn_fsid(vp, vap);
  500                 if ((uint32_t)vap->va_fsid == np->n_vattr.na_filesid[0])
  501                         vap->va_fsid = hash32_buf(
  502                             np->n_vattr.na_filesid, 2 * sizeof(uint64_t), 0);
  503         } else
  504                 vn_fsid(vp, vap);
  505         np->n_attrstamp = time_second;
  506         if (vap->va_size != np->n_size) {
  507                 if (vap->va_type == VREG) {
  508                         if (dontshrink && vap->va_size < np->n_size) {
  509                                 /*
  510                                  * We've been told not to shrink the file;
  511                                  * zero np->n_attrstamp to indicate that
  512                                  * the attributes are stale.
  513                                  */
  514                                 vap->va_size = np->n_size;
  515                                 np->n_attrstamp = 0;
  516                                 KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
  517                         } else if (np->n_flag & NMODIFIED) {
  518                                 /*
  519                                  * We've modified the file: Use the larger
  520                                  * of our size, and the server's size.
  521                                  */
  522                                 if (vap->va_size < np->n_size) {
  523                                         vap->va_size = np->n_size;
  524                                 } else {
  525                                         np->n_size = vap->va_size;
  526                                         np->n_flag |= NSIZECHANGED;
  527                                 }
  528                         } else {
  529                                 np->n_size = vap->va_size;
  530                                 np->n_flag |= NSIZECHANGED;
  531                         }
  532                 } else {
  533                         np->n_size = vap->va_size;
  534                 }
  535         }
  536         /*
  537          * The following checks are added to prevent a race between (say)
  538          * a READDIR+ and a WRITE. 
  539          * READDIR+, WRITE requests sent out.
  540          * READDIR+ resp, WRITE resp received on client.
  541          * However, the WRITE resp was handled before the READDIR+ resp
  542          * causing the post op attrs from the write to be loaded first
  543          * and the attrs from the READDIR+ to be loaded later. If this 
  544          * happens, we have stale attrs loaded into the attrcache.
  545          * We detect this by for the mtime moving back. We invalidate the 
  546          * attrcache when this happens.
  547          */
  548         if (timespeccmp(&mtime_save, &vap->va_mtime, >)) {
  549                 /* Size changed or mtime went backwards */
  550                 np->n_attrstamp = 0;
  551                 KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
  552         }
  553         if (vaper != NULL) {
  554                 NFSBCOPY((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
  555                 if (np->n_flag & NCHG) {
  556                         if (np->n_flag & NACC)
  557                                 vaper->va_atime = np->n_atim;
  558                         if (np->n_flag & NUPD)
  559                                 vaper->va_mtime = np->n_mtim;
  560                 }
  561         }
  562 
  563 out:
  564 #ifdef KDTRACE_HOOKS
  565         if (np->n_attrstamp != 0)
  566                 KDTRACE_NFS_ATTRCACHE_LOAD_DONE(vp, vap, error);
  567 #endif
  568         (void)ncl_pager_setsize(vp, NULL);
  569         return (error);
  570 }
  571 
  572 /*
  573  * Call vnode_pager_setsize() if the size of the node changed, as
  574  * recorded in nfsnode vs. v_object, or delay the call if notifying
  575  * the pager is not possible at the moment.
  576  *
  577  * If nsizep is non-NULL, the call is delayed and the new node size is
  578  * provided.  Caller should itself call vnode_pager_setsize() if
  579  * function returned true.  If nsizep is NULL, function tries to call
  580  * vnode_pager_setsize() itself if needed and possible, and the nfs
  581  * node is unlocked unconditionally, the return value is not useful.
  582  */
  583 bool
  584 ncl_pager_setsize(struct vnode *vp, u_quad_t *nsizep)
  585 {
  586         struct nfsnode *np;
  587         vm_object_t object;
  588         struct vattr *vap;
  589         u_quad_t nsize;
  590         bool setnsize;
  591 
  592         np = VTONFS(vp);
  593         NFSASSERTNODE(np);
  594 
  595         vap = &np->n_vattr.na_vattr;
  596         nsize = vap->va_size;
  597         object = vp->v_object;
  598         setnsize = false;
  599 
  600         if (object != NULL && nsize != object->un_pager.vnp.vnp_size) {
  601                 if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE &&
  602                     (curthread->td_pflags2 & TDP2_SBPAGES) == 0)
  603                         setnsize = true;
  604                 else
  605                         np->n_flag |= NVNSETSZSKIP;
  606         }
  607         if (nsizep == NULL) {
  608                 NFSUNLOCKNODE(np);
  609                 if (setnsize)
  610                         vnode_pager_setsize(vp, nsize);
  611                 setnsize = false;
  612         } else {
  613                 *nsizep = nsize;
  614         }
  615         return (setnsize);
  616 }
  617 
  618 /*
  619  * Fill in the client id name. For these bytes:
  620  * 1 - they must be unique
  621  * 2 - they should be persistent across client reboots
  622  * 1 is more critical than 2
  623  * Use the mount point's unique id plus either the uuid or, if that
  624  * isn't set, random junk.
  625  */
  626 void
  627 nfscl_fillclid(u_int64_t clval, char *uuid, u_int8_t *cp, u_int16_t idlen)
  628 {
  629         int uuidlen;
  630 
  631         /*
  632          * First, put in the 64bit mount point identifier.
  633          */
  634         if (idlen >= sizeof (u_int64_t)) {
  635                 NFSBCOPY((caddr_t)&clval, cp, sizeof (u_int64_t));
  636                 cp += sizeof (u_int64_t);
  637                 idlen -= sizeof (u_int64_t);
  638         }
  639 
  640         /*
  641          * If uuid is non-zero length, use it.
  642          */
  643         uuidlen = strlen(uuid);
  644         if (uuidlen > 0 && idlen >= uuidlen) {
  645                 NFSBCOPY(uuid, cp, uuidlen);
  646                 cp += uuidlen;
  647                 idlen -= uuidlen;
  648         }
  649 
  650         /*
  651          * This only normally happens if the uuid isn't set.
  652          */
  653         while (idlen > 0) {
  654                 *cp++ = (u_int8_t)(arc4random() % 256);
  655                 idlen--;
  656         }
  657 }
  658 
  659 /*
  660  * Fill in a lock owner name. For now, pid + the process's creation time.
  661  */
  662 void
  663 nfscl_filllockowner(void *id, u_int8_t *cp, int flags)
  664 {
  665         union {
  666                 u_int32_t       lval;
  667                 u_int8_t        cval[4];
  668         } tl;
  669         struct proc *p;
  670 
  671         if (id == NULL) {
  672                 /* Return the single open_owner of all 0 bytes. */
  673                 bzero(cp, NFSV4CL_LOCKNAMELEN);
  674                 return;
  675         }
  676         if ((flags & F_POSIX) != 0) {
  677                 p = (struct proc *)id;
  678                 tl.lval = p->p_pid;
  679                 *cp++ = tl.cval[0];
  680                 *cp++ = tl.cval[1];
  681                 *cp++ = tl.cval[2];
  682                 *cp++ = tl.cval[3];
  683                 tl.lval = p->p_stats->p_start.tv_sec;
  684                 *cp++ = tl.cval[0];
  685                 *cp++ = tl.cval[1];
  686                 *cp++ = tl.cval[2];
  687                 *cp++ = tl.cval[3];
  688                 tl.lval = p->p_stats->p_start.tv_usec;
  689                 *cp++ = tl.cval[0];
  690                 *cp++ = tl.cval[1];
  691                 *cp++ = tl.cval[2];
  692                 *cp = tl.cval[3];
  693         } else if ((flags & F_FLOCK) != 0) {
  694                 bcopy(&id, cp, sizeof(id));
  695                 bzero(&cp[sizeof(id)], NFSV4CL_LOCKNAMELEN - sizeof(id));
  696         } else {
  697                 printf("nfscl_filllockowner: not F_POSIX or F_FLOCK\n");
  698                 bzero(cp, NFSV4CL_LOCKNAMELEN);
  699         }
  700 }
  701 
  702 /*
  703  * Find the parent process for the thread passed in as an argument.
  704  * If none exists, return NULL, otherwise return a thread for the parent.
  705  * (Can be any of the threads, since it is only used for td->td_proc.)
  706  */
  707 NFSPROC_T *
  708 nfscl_getparent(struct thread *td)
  709 {
  710         struct proc *p;
  711         struct thread *ptd;
  712 
  713         if (td == NULL)
  714                 return (NULL);
  715         p = td->td_proc;
  716         if (p->p_pid == 0)
  717                 return (NULL);
  718         p = p->p_pptr;
  719         if (p == NULL)
  720                 return (NULL);
  721         ptd = TAILQ_FIRST(&p->p_threads);
  722         return (ptd);
  723 }
  724 
  725 /*
  726  * Start up the renew kernel thread.
  727  */
  728 static void
  729 start_nfscl(void *arg)
  730 {
  731         struct nfsclclient *clp;
  732         struct thread *td;
  733 
  734         clp = (struct nfsclclient *)arg;
  735         td = TAILQ_FIRST(&clp->nfsc_renewthread->p_threads);
  736         nfscl_renewthread(clp, td);
  737         kproc_exit(0);
  738 }
  739 
  740 void
  741 nfscl_start_renewthread(struct nfsclclient *clp)
  742 {
  743 
  744         kproc_create(start_nfscl, (void *)clp, &clp->nfsc_renewthread, 0, 0,
  745             "nfscl");
  746 }
  747 
  748 /*
  749  * Handle wcc_data.
  750  * For NFSv4, it assumes that nfsv4_wccattr() was used to set up the getattr
  751  * as the first Op after PutFH.
  752  * (For NFSv4, the postop attributes are after the Op, so they can't be
  753  *  parsed here. A separate call to nfscl_postop_attr() is required.)
  754  */
  755 int
  756 nfscl_wcc_data(struct nfsrv_descript *nd, struct vnode *vp,
  757     struct nfsvattr *nap, int *flagp, int *wccflagp, void *stuff)
  758 {
  759         u_int32_t *tl;
  760         struct nfsnode *np = VTONFS(vp);
  761         struct nfsvattr nfsva;
  762         int error = 0;
  763 
  764         if (wccflagp != NULL)
  765                 *wccflagp = 0;
  766         if (nd->nd_flag & ND_NFSV3) {
  767                 *flagp = 0;
  768                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
  769                 if (*tl == newnfs_true) {
  770                         NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
  771                         if (wccflagp != NULL) {
  772                                 NFSLOCKNODE(np);
  773                                 *wccflagp = (np->n_mtime.tv_sec ==
  774                                     fxdr_unsigned(u_int32_t, *(tl + 2)) &&
  775                                     np->n_mtime.tv_nsec ==
  776                                     fxdr_unsigned(u_int32_t, *(tl + 3)));
  777                                 NFSUNLOCKNODE(np);
  778                         }
  779                 }
  780                 error = nfscl_postop_attr(nd, nap, flagp, stuff);
  781                 if (wccflagp != NULL && *flagp == 0)
  782                         *wccflagp = 0;
  783         } else if ((nd->nd_flag & (ND_NOMOREDATA | ND_NFSV4 | ND_V4WCCATTR))
  784             == (ND_NFSV4 | ND_V4WCCATTR)) {
  785                 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
  786                     NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
  787                     NULL, NULL, NULL, NULL, NULL);
  788                 if (error)
  789                         return (error);
  790                 /*
  791                  * Get rid of Op# and status for next op.
  792                  */
  793                 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
  794                 if (*++tl)
  795                         nd->nd_flag |= ND_NOMOREDATA;
  796                 if (wccflagp != NULL &&
  797                     nfsva.na_vattr.va_mtime.tv_sec != 0) {
  798                         NFSLOCKNODE(np);
  799                         *wccflagp = (np->n_mtime.tv_sec ==
  800                             nfsva.na_vattr.va_mtime.tv_sec &&
  801                             np->n_mtime.tv_nsec ==
  802                             nfsva.na_vattr.va_mtime.tv_sec);
  803                         NFSUNLOCKNODE(np);
  804                 }
  805         }
  806 nfsmout:
  807         return (error);
  808 }
  809 
  810 /*
  811  * Get postop attributes.
  812  */
  813 int
  814 nfscl_postop_attr(struct nfsrv_descript *nd, struct nfsvattr *nap, int *retp,
  815     void *stuff)
  816 {
  817         u_int32_t *tl;
  818         int error = 0;
  819 
  820         *retp = 0;
  821         if (nd->nd_flag & ND_NOMOREDATA)
  822                 return (error);
  823         if (nd->nd_flag & ND_NFSV3) {
  824                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
  825                 *retp = fxdr_unsigned(int, *tl);
  826         } else if (nd->nd_flag & ND_NFSV4) {
  827                 /*
  828                  * For NFSv4, the postop attr are at the end, so no point
  829                  * in looking if nd_repstat != 0.
  830                  */
  831                 if (!nd->nd_repstat) {
  832                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
  833                         if (*(tl + 1))
  834                                 /* should never happen since nd_repstat != 0 */
  835                                 nd->nd_flag |= ND_NOMOREDATA;
  836                         else
  837                                 *retp = 1;
  838                 }
  839         } else if (!nd->nd_repstat) {
  840                 /* For NFSv2, the attributes are here iff nd_repstat == 0 */
  841                 *retp = 1;
  842         }
  843         if (*retp) {
  844                 error = nfsm_loadattr(nd, nap);
  845                 if (error)
  846                         *retp = 0;
  847         }
  848 nfsmout:
  849         return (error);
  850 }
  851 
  852 /*
  853  * nfscl_request() - mostly a wrapper for newnfs_request().
  854  */
  855 int
  856 nfscl_request(struct nfsrv_descript *nd, struct vnode *vp, NFSPROC_T *p,
  857     struct ucred *cred, void *stuff)
  858 {
  859         int ret, vers;
  860         struct nfsmount *nmp;
  861 
  862         nmp = VFSTONFS(vp->v_mount);
  863         if (nd->nd_flag & ND_NFSV4)
  864                 vers = NFS_VER4;
  865         else if (nd->nd_flag & ND_NFSV3)
  866                 vers = NFS_VER3;
  867         else
  868                 vers = NFS_VER2;
  869         ret = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
  870                 NFS_PROG, vers, NULL, 1, NULL, NULL);
  871         return (ret);
  872 }
  873 
  874 /*
  875  * fill in this bsden's variant of statfs using nfsstatfs.
  876  */
  877 void
  878 nfscl_loadsbinfo(struct nfsmount *nmp, struct nfsstatfs *sfp, void *statfs)
  879 {
  880         struct statfs *sbp = (struct statfs *)statfs;
  881 
  882         if (nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) {
  883                 sbp->f_bsize = NFS_FABLKSIZE;
  884                 sbp->f_blocks = sfp->sf_tbytes / NFS_FABLKSIZE;
  885                 sbp->f_bfree = sfp->sf_fbytes / NFS_FABLKSIZE;
  886                 /*
  887                  * Although sf_abytes is uint64_t and f_bavail is int64_t,
  888                  * the value after dividing by NFS_FABLKSIZE is small
  889                  * enough that it will fit in 63bits, so it is ok to
  890                  * assign it to f_bavail without fear that it will become
  891                  * negative.
  892                  */
  893                 sbp->f_bavail = sfp->sf_abytes / NFS_FABLKSIZE;
  894                 sbp->f_files = sfp->sf_tfiles;
  895                 /* Since f_ffree is int64_t, clip it to 63bits. */
  896                 if (sfp->sf_ffiles > INT64_MAX)
  897                         sbp->f_ffree = INT64_MAX;
  898                 else
  899                         sbp->f_ffree = sfp->sf_ffiles;
  900         } else if ((nmp->nm_flag & NFSMNT_NFSV4) == 0) {
  901                 /*
  902                  * The type casts to (int32_t) ensure that this code is
  903                  * compatible with the old NFS client, in that it will
  904                  * propagate bit31 to the high order bits. This may or may
  905                  * not be correct for NFSv2, but since it is a legacy
  906                  * environment, I'd rather retain backwards compatibility.
  907                  */
  908                 sbp->f_bsize = (int32_t)sfp->sf_bsize;
  909                 sbp->f_blocks = (int32_t)sfp->sf_blocks;
  910                 sbp->f_bfree = (int32_t)sfp->sf_bfree;
  911                 sbp->f_bavail = (int32_t)sfp->sf_bavail;
  912                 sbp->f_files = 0;
  913                 sbp->f_ffree = 0;
  914         }
  915 }
  916 
  917 /*
  918  * Use the fsinfo stuff to update the mount point.
  919  */
  920 void
  921 nfscl_loadfsinfo(struct nfsmount *nmp, struct nfsfsinfo *fsp)
  922 {
  923 
  924         if ((nmp->nm_wsize == 0 || fsp->fs_wtpref < nmp->nm_wsize) &&
  925             fsp->fs_wtpref >= NFS_FABLKSIZE)
  926                 nmp->nm_wsize = (fsp->fs_wtpref + NFS_FABLKSIZE - 1) &
  927                     ~(NFS_FABLKSIZE - 1);
  928         if (fsp->fs_wtmax < nmp->nm_wsize && fsp->fs_wtmax > 0) {
  929                 nmp->nm_wsize = fsp->fs_wtmax & ~(NFS_FABLKSIZE - 1);
  930                 if (nmp->nm_wsize == 0)
  931                         nmp->nm_wsize = fsp->fs_wtmax;
  932         }
  933         if (nmp->nm_wsize < NFS_FABLKSIZE)
  934                 nmp->nm_wsize = NFS_FABLKSIZE;
  935         if ((nmp->nm_rsize == 0 || fsp->fs_rtpref < nmp->nm_rsize) &&
  936             fsp->fs_rtpref >= NFS_FABLKSIZE)
  937                 nmp->nm_rsize = (fsp->fs_rtpref + NFS_FABLKSIZE - 1) &
  938                     ~(NFS_FABLKSIZE - 1);
  939         if (fsp->fs_rtmax < nmp->nm_rsize && fsp->fs_rtmax > 0) {
  940                 nmp->nm_rsize = fsp->fs_rtmax & ~(NFS_FABLKSIZE - 1);
  941                 if (nmp->nm_rsize == 0)
  942                         nmp->nm_rsize = fsp->fs_rtmax;
  943         }
  944         if (nmp->nm_rsize < NFS_FABLKSIZE)
  945                 nmp->nm_rsize = NFS_FABLKSIZE;
  946         if ((nmp->nm_readdirsize == 0 || fsp->fs_dtpref < nmp->nm_readdirsize)
  947             && fsp->fs_dtpref >= NFS_DIRBLKSIZ)
  948                 nmp->nm_readdirsize = (fsp->fs_dtpref + NFS_DIRBLKSIZ - 1) &
  949                     ~(NFS_DIRBLKSIZ - 1);
  950         if (fsp->fs_rtmax < nmp->nm_readdirsize && fsp->fs_rtmax > 0) {
  951                 nmp->nm_readdirsize = fsp->fs_rtmax & ~(NFS_DIRBLKSIZ - 1);
  952                 if (nmp->nm_readdirsize == 0)
  953                         nmp->nm_readdirsize = fsp->fs_rtmax;
  954         }
  955         if (nmp->nm_readdirsize < NFS_DIRBLKSIZ)
  956                 nmp->nm_readdirsize = NFS_DIRBLKSIZ;
  957         if (fsp->fs_maxfilesize > 0 &&
  958             fsp->fs_maxfilesize < nmp->nm_maxfilesize)
  959                 nmp->nm_maxfilesize = fsp->fs_maxfilesize;
  960         nmp->nm_mountp->mnt_stat.f_iosize = newnfs_iosize(nmp);
  961         nmp->nm_state |= NFSSTA_GOTFSINFO;
  962 }
  963 
  964 /*
  965  * Lookups source address which should be used to communicate with
  966  * @nmp and stores it inside @pdst.
  967  *
  968  * Returns 0 on success.
  969  */
  970 u_int8_t *
  971 nfscl_getmyip(struct nfsmount *nmp, struct in6_addr *paddr, int *isinet6p)
  972 {
  973 #if defined(INET6) || defined(INET)
  974         int fibnum;
  975 
  976         fibnum = curthread->td_proc->p_fibnum;
  977 #endif
  978 #ifdef INET
  979         if (nmp->nm_nam->sa_family == AF_INET) {
  980                 struct epoch_tracker et;
  981                 struct nhop_object *nh;
  982                 struct sockaddr_in *sin;
  983                 struct in_addr addr = {};
  984 
  985                 sin = (struct sockaddr_in *)nmp->nm_nam;
  986                 NET_EPOCH_ENTER(et);
  987                 CURVNET_SET(CRED_TO_VNET(nmp->nm_sockreq.nr_cred));
  988                 nh = fib4_lookup(fibnum, sin->sin_addr, 0, NHR_NONE, 0);
  989                 CURVNET_RESTORE();
  990                 if (nh != NULL)
  991                         addr = IA_SIN(ifatoia(nh->nh_ifa))->sin_addr;
  992                 NET_EPOCH_EXIT(et);
  993                 if (nh == NULL)
  994                         return (NULL);
  995 
  996                 if (IN_LOOPBACK(ntohl(addr.s_addr))) {
  997                         /* Ignore loopback addresses */
  998                         return (NULL);
  999                 }
 1000 
 1001                 *isinet6p = 0;
 1002                 *((struct in_addr *)paddr) = addr;
 1003 
 1004                 return (u_int8_t *)paddr;
 1005         }
 1006 #endif
 1007 #ifdef INET6
 1008         if (nmp->nm_nam->sa_family == AF_INET6) {
 1009                 struct sockaddr_in6 *sin6;
 1010                 int error;
 1011 
 1012                 sin6 = (struct sockaddr_in6 *)nmp->nm_nam;
 1013 
 1014                 CURVNET_SET(CRED_TO_VNET(nmp->nm_sockreq.nr_cred));
 1015                 error = in6_selectsrc_addr(fibnum, &sin6->sin6_addr,
 1016                     sin6->sin6_scope_id, NULL, paddr, NULL);
 1017                 CURVNET_RESTORE();
 1018                 if (error != 0)
 1019                         return (NULL);
 1020 
 1021                 if (IN6_IS_ADDR_LOOPBACK(paddr))
 1022                         return (NULL);
 1023 
 1024                 /* Scope is embedded in */
 1025                 *isinet6p = 1;
 1026 
 1027                 return (u_int8_t *)paddr;
 1028         }
 1029 #endif
 1030         return (NULL);
 1031 }
 1032 
 1033 /*
 1034  * Copy NFS uid, gids from the cred structure.
 1035  */
 1036 void
 1037 newnfs_copyincred(struct ucred *cr, struct nfscred *nfscr)
 1038 {
 1039         int i;
 1040 
 1041         KASSERT(cr->cr_ngroups >= 0,
 1042             ("newnfs_copyincred: negative cr_ngroups"));
 1043         nfscr->nfsc_uid = cr->cr_uid;
 1044         nfscr->nfsc_ngroups = MIN(cr->cr_ngroups, NFS_MAXGRPS + 1);
 1045         for (i = 0; i < nfscr->nfsc_ngroups; i++)
 1046                 nfscr->nfsc_groups[i] = cr->cr_groups[i];
 1047 }
 1048 
 1049 /*
 1050  * Do any client specific initialization.
 1051  */
 1052 void
 1053 nfscl_init(void)
 1054 {
 1055         static int inited = 0;
 1056 
 1057         if (inited)
 1058                 return;
 1059         inited = 1;
 1060         nfscl_inited = 1;
 1061         ncl_pbuf_zone = pbuf_zsecond_create("nfspbuf", nswbuf / 2);
 1062 }
 1063 
 1064 /*
 1065  * Check each of the attributes to be set, to ensure they aren't already
 1066  * the correct value. Disable setting ones already correct.
 1067  */
 1068 int
 1069 nfscl_checksattr(struct vattr *vap, struct nfsvattr *nvap)
 1070 {
 1071 
 1072         if (vap->va_mode != (mode_t)VNOVAL) {
 1073                 if (vap->va_mode == nvap->na_mode)
 1074                         vap->va_mode = (mode_t)VNOVAL;
 1075         }
 1076         if (vap->va_uid != (uid_t)VNOVAL) {
 1077                 if (vap->va_uid == nvap->na_uid)
 1078                         vap->va_uid = (uid_t)VNOVAL;
 1079         }
 1080         if (vap->va_gid != (gid_t)VNOVAL) {
 1081                 if (vap->va_gid == nvap->na_gid)
 1082                         vap->va_gid = (gid_t)VNOVAL;
 1083         }
 1084         if (vap->va_size != VNOVAL) {
 1085                 if (vap->va_size == nvap->na_size)
 1086                         vap->va_size = VNOVAL;
 1087         }
 1088 
 1089         /*
 1090          * We are normally called with only a partially initialized
 1091          * VAP.  Since the NFSv3 spec says that server may use the
 1092          * file attributes to store the verifier, the spec requires
 1093          * us to do a SETATTR RPC. FreeBSD servers store the verifier
 1094          * in atime, but we can't really assume that all servers will
 1095          * so we ensure that our SETATTR sets both atime and mtime.
 1096          * Set the VA_UTIMES_NULL flag for this case, so that
 1097          * the server's time will be used.  This is needed to
 1098          * work around a bug in some Solaris servers, where
 1099          * setting the time TOCLIENT causes the Setattr RPC
 1100          * to return NFS_OK, but not set va_mode.
 1101          */
 1102         if (vap->va_mtime.tv_sec == VNOVAL) {
 1103                 vfs_timestamp(&vap->va_mtime);
 1104                 vap->va_vaflags |= VA_UTIMES_NULL;
 1105         }
 1106         if (vap->va_atime.tv_sec == VNOVAL)
 1107                 vap->va_atime = vap->va_mtime;
 1108         return (1);
 1109 }
 1110 
 1111 /*
 1112  * Map nfsv4 errors to errno.h errors.
 1113  * The uid and gid arguments are only used for NFSERR_BADOWNER and that
 1114  * error should only be returned for the Open, Create and Setattr Ops.
 1115  * As such, most calls can just pass in 0 for those arguments.
 1116  */
 1117 int
 1118 nfscl_maperr(struct thread *td, int error, uid_t uid, gid_t gid)
 1119 {
 1120         struct proc *p;
 1121 
 1122         if (error < 10000 || error >= NFSERR_STALEWRITEVERF)
 1123                 return (error);
 1124         if (td != NULL)
 1125                 p = td->td_proc;
 1126         else
 1127                 p = NULL;
 1128         switch (error) {
 1129         case NFSERR_BADOWNER:
 1130                 tprintf(p, LOG_INFO,
 1131                     "No name and/or group mapping for uid,gid:(%d,%d)\n",
 1132                     uid, gid);
 1133                 return (EPERM);
 1134         case NFSERR_BADNAME:
 1135         case NFSERR_BADCHAR:
 1136                 printf("nfsv4 char/name not handled by server\n");
 1137                 return (ENOENT);
 1138         case NFSERR_STALECLIENTID:
 1139         case NFSERR_STALESTATEID:
 1140         case NFSERR_EXPIRED:
 1141         case NFSERR_BADSTATEID:
 1142         case NFSERR_BADSESSION:
 1143                 printf("nfsv4 recover err returned %d\n", error);
 1144                 return (EIO);
 1145         case NFSERR_BADHANDLE:
 1146         case NFSERR_SERVERFAULT:
 1147         case NFSERR_BADTYPE:
 1148         case NFSERR_FHEXPIRED:
 1149         case NFSERR_RESOURCE:
 1150         case NFSERR_MOVED:
 1151         case NFSERR_NOFILEHANDLE:
 1152         case NFSERR_MINORVERMISMATCH:
 1153         case NFSERR_OLDSTATEID:
 1154         case NFSERR_BADSEQID:
 1155         case NFSERR_LEASEMOVED:
 1156         case NFSERR_RECLAIMBAD:
 1157         case NFSERR_BADXDR:
 1158         case NFSERR_OPILLEGAL:
 1159                 printf("nfsv4 client/server protocol prob err=%d\n",
 1160                     error);
 1161                 return (EIO);
 1162         default:
 1163                 tprintf(p, LOG_INFO, "nfsv4 err=%d\n", error);
 1164                 return (EIO);
 1165         };
 1166 }
 1167 
 1168 /*
 1169  * Check to see if the process for this owner exists. Return 1 if it doesn't
 1170  * and 0 otherwise.
 1171  */
 1172 int
 1173 nfscl_procdoesntexist(u_int8_t *own)
 1174 {
 1175         union {
 1176                 u_int32_t       lval;
 1177                 u_int8_t        cval[4];
 1178         } tl;
 1179         struct proc *p;
 1180         pid_t pid;
 1181         int i, ret = 0;
 1182 
 1183         /* For the single open_owner of all 0 bytes, just return 0. */
 1184         for (i = 0; i < NFSV4CL_LOCKNAMELEN; i++)
 1185                 if (own[i] != 0)
 1186                         break;
 1187         if (i == NFSV4CL_LOCKNAMELEN)
 1188                 return (0);
 1189 
 1190         tl.cval[0] = *own++;
 1191         tl.cval[1] = *own++;
 1192         tl.cval[2] = *own++;
 1193         tl.cval[3] = *own++;
 1194         pid = tl.lval;
 1195         p = pfind_any_locked(pid);
 1196         if (p == NULL)
 1197                 return (1);
 1198         if (p->p_stats == NULL) {
 1199                 PROC_UNLOCK(p);
 1200                 return (0);
 1201         }
 1202         tl.cval[0] = *own++;
 1203         tl.cval[1] = *own++;
 1204         tl.cval[2] = *own++;
 1205         tl.cval[3] = *own++;
 1206         if (tl.lval != p->p_stats->p_start.tv_sec) {
 1207                 ret = 1;
 1208         } else {
 1209                 tl.cval[0] = *own++;
 1210                 tl.cval[1] = *own++;
 1211                 tl.cval[2] = *own++;
 1212                 tl.cval[3] = *own;
 1213                 if (tl.lval != p->p_stats->p_start.tv_usec)
 1214                         ret = 1;
 1215         }
 1216         PROC_UNLOCK(p);
 1217         return (ret);
 1218 }
 1219 
 1220 /*
 1221  * - nfs pseudo system call for the client
 1222  */
 1223 /*
 1224  * MPSAFE
 1225  */
 1226 static int
 1227 nfssvc_nfscl(struct thread *td, struct nfssvc_args *uap)
 1228 {
 1229         struct file *fp;
 1230         struct nfscbd_args nfscbdarg;
 1231         struct nfsd_nfscbd_args nfscbdarg2;
 1232         struct nameidata nd;
 1233         struct nfscl_dumpmntopts dumpmntopts;
 1234         cap_rights_t rights;
 1235         char *buf;
 1236         int error;
 1237         struct mount *mp;
 1238         struct nfsmount *nmp;
 1239 
 1240         if (uap->flag & NFSSVC_CBADDSOCK) {
 1241                 error = copyin(uap->argp, (caddr_t)&nfscbdarg, sizeof(nfscbdarg));
 1242                 if (error)
 1243                         return (error);
 1244                 /*
 1245                  * Since we don't know what rights might be required,
 1246                  * pretend that we need them all. It is better to be too
 1247                  * careful than too reckless.
 1248                  */
 1249                 error = fget(td, nfscbdarg.sock,
 1250                     cap_rights_init_one(&rights, CAP_SOCK_CLIENT), &fp);
 1251                 if (error)
 1252                         return (error);
 1253                 if (fp->f_type != DTYPE_SOCKET) {
 1254                         fdrop(fp, td);
 1255                         return (EPERM);
 1256                 }
 1257                 error = nfscbd_addsock(fp);
 1258                 fdrop(fp, td);
 1259                 if (!error && nfscl_enablecallb == 0) {
 1260                         nfsv4_cbport = nfscbdarg.port;
 1261                         nfscl_enablecallb = 1;
 1262                 }
 1263         } else if (uap->flag & NFSSVC_NFSCBD) {
 1264                 if (uap->argp == NULL) 
 1265                         return (EINVAL);
 1266                 error = copyin(uap->argp, (caddr_t)&nfscbdarg2,
 1267                     sizeof(nfscbdarg2));
 1268                 if (error)
 1269                         return (error);
 1270                 error = nfscbd_nfsd(td, &nfscbdarg2);
 1271         } else if (uap->flag & NFSSVC_DUMPMNTOPTS) {
 1272                 error = copyin(uap->argp, &dumpmntopts, sizeof(dumpmntopts));
 1273                 if (error == 0 && (dumpmntopts.ndmnt_blen < 256 ||
 1274                     dumpmntopts.ndmnt_blen > 1024))
 1275                         error = EINVAL;
 1276                 if (error == 0)
 1277                         error = nfsrv_lookupfilename(&nd,
 1278                             dumpmntopts.ndmnt_fname, td);
 1279                 if (error == 0 && strcmp(nd.ni_vp->v_mount->mnt_vfc->vfc_name,
 1280                     "nfs") != 0) {
 1281                         vput(nd.ni_vp);
 1282                         error = EINVAL;
 1283                 }
 1284                 if (error == 0) {
 1285                         buf = malloc(dumpmntopts.ndmnt_blen, M_TEMP, M_WAITOK);
 1286                         nfscl_retopts(VFSTONFS(nd.ni_vp->v_mount), buf,
 1287                             dumpmntopts.ndmnt_blen);
 1288                         vput(nd.ni_vp);
 1289                         error = copyout(buf, dumpmntopts.ndmnt_buf,
 1290                             dumpmntopts.ndmnt_blen);
 1291                         free(buf, M_TEMP);
 1292                 }
 1293         } else if (uap->flag & NFSSVC_FORCEDISM) {
 1294                 buf = malloc(MNAMELEN + 1, M_TEMP, M_WAITOK);
 1295                 error = copyinstr(uap->argp, buf, MNAMELEN + 1, NULL);
 1296                 if (error == 0) {
 1297                         nmp = NULL;
 1298                         mtx_lock(&mountlist_mtx);
 1299                         TAILQ_FOREACH(mp, &mountlist, mnt_list) {
 1300                                 if (strcmp(mp->mnt_stat.f_mntonname, buf) ==
 1301                                     0 && strcmp(mp->mnt_stat.f_fstypename,
 1302                                     "nfs") == 0 && mp->mnt_data != NULL) {
 1303                                         nmp = VFSTONFS(mp);
 1304                                         NFSDDSLOCK();
 1305                                         if (nfsv4_findmirror(nmp) != NULL) {
 1306                                                 NFSDDSUNLOCK();
 1307                                                 error = ENXIO;
 1308                                                 nmp = NULL;
 1309                                                 break;
 1310                                         }
 1311                                         mtx_lock(&nmp->nm_mtx);
 1312                                         if ((nmp->nm_privflag &
 1313                                             NFSMNTP_FORCEDISM) == 0) {
 1314                                                 nmp->nm_privflag |= 
 1315                                                    (NFSMNTP_FORCEDISM |
 1316                                                     NFSMNTP_CANCELRPCS);
 1317                                                 mtx_unlock(&nmp->nm_mtx);
 1318                                         } else {
 1319                                                 mtx_unlock(&nmp->nm_mtx);
 1320                                                 nmp = NULL;
 1321                                         }
 1322                                         NFSDDSUNLOCK();
 1323                                         break;
 1324                                 }
 1325                         }
 1326                         mtx_unlock(&mountlist_mtx);
 1327 
 1328                         if (nmp != NULL) {
 1329                                 /*
 1330                                  * Call newnfs_nmcancelreqs() to cause
 1331                                  * any RPCs in progress on the mount point to
 1332                                  * fail.
 1333                                  * This will cause any process waiting for an
 1334                                  * RPC to complete while holding a vnode lock
 1335                                  * on the mounted-on vnode (such as "df" or
 1336                                  * a non-forced "umount") to fail.
 1337                                  * This will unlock the mounted-on vnode so
 1338                                  * a forced dismount can succeed.
 1339                                  * Then clear NFSMNTP_CANCELRPCS and wakeup(),
 1340                                  * so that nfs_unmount() can complete.
 1341                                  */
 1342                                 newnfs_nmcancelreqs(nmp);
 1343                                 mtx_lock(&nmp->nm_mtx);
 1344                                 nmp->nm_privflag &= ~NFSMNTP_CANCELRPCS;
 1345                                 wakeup(nmp);
 1346                                 mtx_unlock(&nmp->nm_mtx);
 1347                         } else if (error == 0)
 1348                                 error = EINVAL;
 1349                 }
 1350                 free(buf, M_TEMP);
 1351         } else {
 1352                 error = EINVAL;
 1353         }
 1354         return (error);
 1355 }
 1356 
 1357 extern int (*nfsd_call_nfscl)(struct thread *, struct nfssvc_args *);
 1358 
 1359 /*
 1360  * Called once to initialize data structures...
 1361  */
 1362 static int
 1363 nfscl_modevent(module_t mod, int type, void *data)
 1364 {
 1365         int error = 0;
 1366         static int loaded = 0;
 1367 
 1368         switch (type) {
 1369         case MOD_LOAD:
 1370                 if (loaded)
 1371                         return (0);
 1372                 newnfs_portinit();
 1373                 mtx_init(&ncl_iod_mutex, "ncl_iod_mutex", NULL, MTX_DEF);
 1374                 nfscl_init();
 1375                 NFSD_LOCK();
 1376                 nfsrvd_cbinit(0);
 1377                 NFSD_UNLOCK();
 1378                 ncl_call_invalcaches = ncl_invalcaches;
 1379                 nfsd_call_nfscl = nfssvc_nfscl;
 1380                 loaded = 1;
 1381                 break;
 1382 
 1383         case MOD_UNLOAD:
 1384                 if (nfs_numnfscbd != 0) {
 1385                         error = EBUSY;
 1386                         break;
 1387                 }
 1388 
 1389                 /*
 1390                  * XXX: Unloading of nfscl module is unsupported.
 1391                  */
 1392 #if 0
 1393                 ncl_call_invalcaches = NULL;
 1394                 nfsd_call_nfscl = NULL;
 1395                 uma_zdestroy(ncl_pbuf_zone);
 1396                 /* and get rid of the mutexes */
 1397                 mtx_destroy(&ncl_iod_mutex);
 1398                 loaded = 0;
 1399                 break;
 1400 #else
 1401                 /* FALLTHROUGH */
 1402 #endif
 1403         default:
 1404                 error = EOPNOTSUPP;
 1405                 break;
 1406         }
 1407         return error;
 1408 }
 1409 static moduledata_t nfscl_mod = {
 1410         "nfscl",
 1411         nfscl_modevent,
 1412         NULL,
 1413 };
 1414 DECLARE_MODULE(nfscl, nfscl_mod, SI_SUB_VFS, SI_ORDER_FIRST);
 1415 
 1416 /* So that loader and kldload(2) can find us, wherever we are.. */
 1417 MODULE_VERSION(nfscl, 1);
 1418 MODULE_DEPEND(nfscl, nfscommon, 1, 1, 1);
 1419 MODULE_DEPEND(nfscl, krpc, 1, 1, 1);
 1420 MODULE_DEPEND(nfscl, nfssvc, 1, 1, 1);

Cache object: 403dbb6e1497a748cf66bdb8f2737130


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.