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