]> CyberLeo.Net >> Repos - FreeBSD/releng/9.3.git/blob - sys/fs/nfsclient/nfs_clvfsops.c
Copy stable/9 to releng/9.3 as part of the 9.3-RELEASE cycle.
[FreeBSD/releng/9.3.git] / sys / fs / nfsclient / nfs_clvfsops.c
1 /*-
2  * Copyright (c) 1989, 1993, 1995
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Rick Macklem at The University of Guelph.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 4. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  *      from nfs_vfsops.c       8.12 (Berkeley) 5/20/95
33  */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38
39 #include "opt_bootp.h"
40 #include "opt_nfsroot.h"
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/bio.h>
46 #include <sys/buf.h>
47 #include <sys/clock.h>
48 #include <sys/jail.h>
49 #include <sys/limits.h>
50 #include <sys/lock.h>
51 #include <sys/malloc.h>
52 #include <sys/mbuf.h>
53 #include <sys/module.h>
54 #include <sys/mount.h>
55 #include <sys/proc.h>
56 #include <sys/socket.h>
57 #include <sys/socketvar.h>
58 #include <sys/sockio.h>
59 #include <sys/sysctl.h>
60 #include <sys/vnode.h>
61 #include <sys/signalvar.h>
62
63 #include <vm/vm.h>
64 #include <vm/vm_extern.h>
65 #include <vm/uma.h>
66
67 #include <net/if.h>
68 #include <net/route.h>
69 #include <netinet/in.h>
70
71 #include <fs/nfs/nfsport.h>
72 #include <fs/nfsclient/nfsnode.h>
73 #include <fs/nfsclient/nfsmount.h>
74 #include <fs/nfsclient/nfs.h>
75 #include <nfs/nfsdiskless.h>
76
77 FEATURE(nfscl, "NFSv4 client");
78
79 extern int nfscl_ticks;
80 extern struct timeval nfsboottime;
81 extern struct nfsstats  newnfsstats;
82 extern int nfsrv_useacl;
83 extern enum nfsiod_state ncl_iodwant[NFS_MAXASYNCDAEMON];
84 extern struct nfsmount *ncl_iodmount[NFS_MAXASYNCDAEMON];
85 extern struct mtx ncl_iod_mutex;
86
87 MALLOC_DEFINE(M_NEWNFSREQ, "newnfsclient_req", "New NFS request header");
88 MALLOC_DEFINE(M_NEWNFSMNT, "newnfsmnt", "New NFS mount struct");
89
90 SYSCTL_DECL(_vfs_nfs);
91 static int nfs_ip_paranoia = 1;
92 SYSCTL_INT(_vfs_nfs, OID_AUTO, nfs_ip_paranoia, CTLFLAG_RW,
93     &nfs_ip_paranoia, 0, "");
94 static int nfs_tprintf_initial_delay = NFS_TPRINTF_INITIAL_DELAY;
95 SYSCTL_INT(_vfs_nfs, NFS_TPRINTF_INITIAL_DELAY,
96         downdelayinitial, CTLFLAG_RW, &nfs_tprintf_initial_delay, 0, "");
97 /* how long between console messages "nfs server foo not responding" */
98 static int nfs_tprintf_delay = NFS_TPRINTF_DELAY;
99 SYSCTL_INT(_vfs_nfs, NFS_TPRINTF_DELAY,
100         downdelayinterval, CTLFLAG_RW, &nfs_tprintf_delay, 0, "");
101
102 static int      nfs_mountroot(struct mount *);
103 static void     nfs_sec_name(char *, int *);
104 static void     nfs_decode_args(struct mount *mp, struct nfsmount *nmp,
105                     struct nfs_args *argp, const char *, struct ucred *,
106                     struct thread *);
107 static int      mountnfs(struct nfs_args *, struct mount *,
108                     struct sockaddr *, char *, u_char *, int, u_char *, int,
109                     u_char *, int, struct vnode **, struct ucred *,
110                     struct thread *, int, int);
111 static void     nfs_getnlminfo(struct vnode *, uint8_t *, size_t *,
112                     struct sockaddr_storage *, int *, off_t *,
113                     struct timeval *);
114 static vfs_mount_t nfs_mount;
115 static vfs_cmount_t nfs_cmount;
116 static vfs_unmount_t nfs_unmount;
117 static vfs_root_t nfs_root;
118 static vfs_statfs_t nfs_statfs;
119 static vfs_sync_t nfs_sync;
120 static vfs_sysctl_t nfs_sysctl;
121
122 /*
123  * nfs vfs operations.
124  */
125 static struct vfsops nfs_vfsops = {
126         .vfs_init =             ncl_init,
127         .vfs_mount =            nfs_mount,
128         .vfs_cmount =           nfs_cmount,
129         .vfs_root =             nfs_root,
130         .vfs_statfs =           nfs_statfs,
131         .vfs_sync =             nfs_sync,
132         .vfs_uninit =           ncl_uninit,
133         .vfs_unmount =          nfs_unmount,
134         .vfs_sysctl =           nfs_sysctl,
135 };
136 VFS_SET(nfs_vfsops, nfs, VFCF_NETWORK | VFCF_SBDRY);
137
138 /* So that loader and kldload(2) can find us, wherever we are.. */
139 MODULE_VERSION(nfs, 1);
140 MODULE_DEPEND(nfs, nfscommon, 1, 1, 1);
141 MODULE_DEPEND(nfs, krpc, 1, 1, 1);
142 MODULE_DEPEND(nfs, nfssvc, 1, 1, 1);
143 MODULE_DEPEND(nfs, nfslock, 1, 1, 1);
144
145 /*
146  * This structure is now defined in sys/nfs/nfs_diskless.c so that it
147  * can be shared by both NFS clients. It is declared here so that it
148  * will be defined for kernels built without NFS_ROOT, although it
149  * isn't used in that case.
150  */
151 #if !defined(NFS_ROOT) && !defined(NFSCLIENT)
152 struct nfs_diskless     nfs_diskless = { { { 0 } } };
153 struct nfsv3_diskless   nfsv3_diskless = { { { 0 } } };
154 int                     nfs_diskless_valid = 0;
155 #endif
156
157 SYSCTL_INT(_vfs_nfs, OID_AUTO, diskless_valid, CTLFLAG_RD,
158     &nfs_diskless_valid, 0,
159     "Has the diskless struct been filled correctly");
160
161 SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD,
162     nfsv3_diskless.root_hostnam, 0, "Path to nfs root");
163
164 SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD,
165     &nfsv3_diskless.root_saddr, sizeof(nfsv3_diskless.root_saddr),
166     "%Ssockaddr_in", "Diskless root nfs address");
167
168
169 void            newnfsargs_ntoh(struct nfs_args *);
170 static int      nfs_mountdiskless(char *,
171                     struct sockaddr_in *, struct nfs_args *,
172                     struct thread *, struct vnode **, struct mount *);
173 static void     nfs_convert_diskless(void);
174 static void     nfs_convert_oargs(struct nfs_args *args,
175                     struct onfs_args *oargs);
176
177 int
178 newnfs_iosize(struct nfsmount *nmp)
179 {
180         int iosize, maxio;
181
182         /* First, set the upper limit for iosize */
183         if (nmp->nm_flag & NFSMNT_NFSV4) {
184                 maxio = NFS_MAXBSIZE;
185         } else if (nmp->nm_flag & NFSMNT_NFSV3) {
186                 if (nmp->nm_sotype == SOCK_DGRAM)
187                         maxio = NFS_MAXDGRAMDATA;
188                 else
189                         maxio = NFS_MAXBSIZE;
190         } else {
191                 maxio = NFS_V2MAXDATA;
192         }
193         if (nmp->nm_rsize > maxio || nmp->nm_rsize == 0)
194                 nmp->nm_rsize = maxio;
195         if (nmp->nm_rsize > MAXBSIZE)
196                 nmp->nm_rsize = MAXBSIZE;
197         if (nmp->nm_readdirsize > maxio || nmp->nm_readdirsize == 0)
198                 nmp->nm_readdirsize = maxio;
199         if (nmp->nm_readdirsize > nmp->nm_rsize)
200                 nmp->nm_readdirsize = nmp->nm_rsize;
201         if (nmp->nm_wsize > maxio || nmp->nm_wsize == 0)
202                 nmp->nm_wsize = maxio;
203         if (nmp->nm_wsize > MAXBSIZE)
204                 nmp->nm_wsize = MAXBSIZE;
205
206         /*
207          * Calculate the size used for io buffers.  Use the larger
208          * of the two sizes to minimise nfs requests but make sure
209          * that it is at least one VM page to avoid wasting buffer
210          * space.
211          */
212         iosize = imax(nmp->nm_rsize, nmp->nm_wsize);
213         iosize = imax(iosize, PAGE_SIZE);
214         nmp->nm_mountp->mnt_stat.f_iosize = iosize;
215         return (iosize);
216 }
217
218 static void
219 nfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs)
220 {
221
222         args->version = NFS_ARGSVERSION;
223         args->addr = oargs->addr;
224         args->addrlen = oargs->addrlen;
225         args->sotype = oargs->sotype;
226         args->proto = oargs->proto;
227         args->fh = oargs->fh;
228         args->fhsize = oargs->fhsize;
229         args->flags = oargs->flags;
230         args->wsize = oargs->wsize;
231         args->rsize = oargs->rsize;
232         args->readdirsize = oargs->readdirsize;
233         args->timeo = oargs->timeo;
234         args->retrans = oargs->retrans;
235         args->readahead = oargs->readahead;
236         args->hostname = oargs->hostname;
237 }
238
239 static void
240 nfs_convert_diskless(void)
241 {
242
243         bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif,
244                 sizeof(struct ifaliasreq));
245         bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway,
246                 sizeof(struct sockaddr_in));
247         nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args);
248         if (nfsv3_diskless.root_args.flags & NFSMNT_NFSV3) {
249                 nfsv3_diskless.root_fhsize = NFSX_MYFH;
250                 bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_MYFH);
251         } else {
252                 nfsv3_diskless.root_fhsize = NFSX_V2FH;
253                 bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_V2FH);
254         }
255         bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr,
256                 sizeof(struct sockaddr_in));
257         bcopy(nfs_diskless.root_hostnam, nfsv3_diskless.root_hostnam, MNAMELEN);
258         nfsv3_diskless.root_time = nfs_diskless.root_time;
259         bcopy(nfs_diskless.my_hostnam, nfsv3_diskless.my_hostnam,
260                 MAXHOSTNAMELEN);
261         nfs_diskless_valid = 3;
262 }
263
264 /*
265  * nfs statfs call
266  */
267 static int
268 nfs_statfs(struct mount *mp, struct statfs *sbp)
269 {
270         struct vnode *vp;
271         struct thread *td;
272         struct nfsmount *nmp = VFSTONFS(mp);
273         struct nfsvattr nfsva;
274         struct nfsfsinfo fs;
275         struct nfsstatfs sb;
276         int error = 0, attrflag, gotfsinfo = 0, ret;
277         struct nfsnode *np;
278
279         td = curthread;
280
281         error = vfs_busy(mp, MBF_NOWAIT);
282         if (error)
283                 return (error);
284         error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, LK_EXCLUSIVE);
285         if (error) {
286                 vfs_unbusy(mp);
287                 return (error);
288         }
289         vp = NFSTOV(np);
290         mtx_lock(&nmp->nm_mtx);
291         if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) {
292                 mtx_unlock(&nmp->nm_mtx);
293                 error = nfsrpc_fsinfo(vp, &fs, td->td_ucred, td, &nfsva,
294                     &attrflag, NULL);
295                 if (!error)
296                         gotfsinfo = 1;
297         } else
298                 mtx_unlock(&nmp->nm_mtx);
299         if (!error)
300                 error = nfsrpc_statfs(vp, &sb, &fs, td->td_ucred, td, &nfsva,
301                     &attrflag, NULL);
302         if (attrflag == 0) {
303                 ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1,
304                     td->td_ucred, td, &nfsva, NULL);
305                 if (ret) {
306                         /*
307                          * Just set default values to get things going.
308                          */
309                         NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr));
310                         nfsva.na_vattr.va_type = VDIR;
311                         nfsva.na_vattr.va_mode = 0777;
312                         nfsva.na_vattr.va_nlink = 100;
313                         nfsva.na_vattr.va_uid = (uid_t)0;
314                         nfsva.na_vattr.va_gid = (gid_t)0;
315                         nfsva.na_vattr.va_fileid = 2;
316                         nfsva.na_vattr.va_gen = 1;
317                         nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE;
318                         nfsva.na_vattr.va_size = 512 * 1024;
319                 }
320         }
321         (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1);
322         if (!error) {
323             mtx_lock(&nmp->nm_mtx);
324             if (gotfsinfo || (nmp->nm_flag & NFSMNT_NFSV4))
325                 nfscl_loadfsinfo(nmp, &fs);
326             nfscl_loadsbinfo(nmp, &sb, sbp);
327             sbp->f_iosize = newnfs_iosize(nmp);
328             mtx_unlock(&nmp->nm_mtx);
329             if (sbp != &mp->mnt_stat) {
330                 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
331                 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
332             }
333             strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN);
334         } else if (NFS_ISV4(vp)) {
335                 error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0);
336         }
337         vput(vp);
338         vfs_unbusy(mp);
339         return (error);
340 }
341
342 /*
343  * nfs version 3 fsinfo rpc call
344  */
345 int
346 ncl_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred,
347     struct thread *td)
348 {
349         struct nfsfsinfo fs;
350         struct nfsvattr nfsva;
351         int error, attrflag;
352         
353         error = nfsrpc_fsinfo(vp, &fs, cred, td, &nfsva, &attrflag, NULL);
354         if (!error) {
355                 if (attrflag)
356                         (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0,
357                             1);
358                 mtx_lock(&nmp->nm_mtx);
359                 nfscl_loadfsinfo(nmp, &fs);
360                 mtx_unlock(&nmp->nm_mtx);
361         }
362         return (error);
363 }
364
365 /*
366  * Mount a remote root fs via. nfs. This depends on the info in the
367  * nfs_diskless structure that has been filled in properly by some primary
368  * bootstrap.
369  * It goes something like this:
370  * - do enough of "ifconfig" by calling ifioctl() so that the system
371  *   can talk to the server
372  * - If nfs_diskless.mygateway is filled in, use that address as
373  *   a default gateway.
374  * - build the rootfs mount point and call mountnfs() to do the rest.
375  *
376  * It is assumed to be safe to read, modify, and write the nfsv3_diskless
377  * structure, as well as other global NFS client variables here, as
378  * nfs_mountroot() will be called once in the boot before any other NFS
379  * client activity occurs.
380  */
381 static int
382 nfs_mountroot(struct mount *mp)
383 {
384         struct thread *td = curthread;
385         struct nfsv3_diskless *nd = &nfsv3_diskless;
386         struct socket *so;
387         struct vnode *vp;
388         struct ifreq ir;
389         int error;
390         u_long l;
391         char buf[128];
392         char *cp;
393
394 #if defined(BOOTP_NFSROOT) && defined(BOOTP)
395         bootpc_init();          /* use bootp to get nfs_diskless filled in */
396 #elif defined(NFS_ROOT)
397         nfs_setup_diskless();
398 #endif
399
400         if (nfs_diskless_valid == 0)
401                 return (-1);
402         if (nfs_diskless_valid == 1)
403                 nfs_convert_diskless();
404
405         /*
406          * XXX splnet, so networks will receive...
407          */
408         splnet();
409
410         /*
411          * Do enough of ifconfig(8) so that the critical net interface can
412          * talk to the server.
413          */
414         error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0,
415             td->td_ucred, td);
416         if (error)
417                 panic("nfs_mountroot: socreate(%04x): %d",
418                         nd->myif.ifra_addr.sa_family, error);
419
420 #if 0 /* XXX Bad idea */
421         /*
422          * We might not have been told the right interface, so we pass
423          * over the first ten interfaces of the same kind, until we get
424          * one of them configured.
425          */
426
427         for (i = strlen(nd->myif.ifra_name) - 1;
428                 nd->myif.ifra_name[i] >= '0' &&
429                 nd->myif.ifra_name[i] <= '9';
430                 nd->myif.ifra_name[i] ++) {
431                 error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
432                 if(!error)
433                         break;
434         }
435 #endif
436         error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
437         if (error)
438                 panic("nfs_mountroot: SIOCAIFADDR: %d", error);
439         if ((cp = getenv("boot.netif.mtu")) != NULL) {
440                 ir.ifr_mtu = strtol(cp, NULL, 10);
441                 bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ);
442                 freeenv(cp);
443                 error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td);
444                 if (error)
445                         printf("nfs_mountroot: SIOCSIFMTU: %d", error);
446         }
447         soclose(so);
448
449         /*
450          * If the gateway field is filled in, set it as the default route.
451          * Note that pxeboot will set a default route of 0 if the route
452          * is not set by the DHCP server.  Check also for a value of 0
453          * to avoid panicking inappropriately in that situation.
454          */
455         if (nd->mygateway.sin_len != 0 &&
456             nd->mygateway.sin_addr.s_addr != 0) {
457                 struct sockaddr_in mask, sin;
458
459                 bzero((caddr_t)&mask, sizeof(mask));
460                 sin = mask;
461                 sin.sin_family = AF_INET;
462                 sin.sin_len = sizeof(sin);
463                 /* XXX MRT use table 0 for this sort of thing */
464                 CURVNET_SET(TD_TO_VNET(td));
465                 error = rtrequest_fib(RTM_ADD, (struct sockaddr *)&sin,
466                     (struct sockaddr *)&nd->mygateway,
467                     (struct sockaddr *)&mask,
468                     RTF_UP | RTF_GATEWAY, NULL, RT_DEFAULT_FIB);
469                 CURVNET_RESTORE();
470                 if (error)
471                         panic("nfs_mountroot: RTM_ADD: %d", error);
472         }
473
474         /*
475          * Create the rootfs mount point.
476          */
477         nd->root_args.fh = nd->root_fh;
478         nd->root_args.fhsize = nd->root_fhsize;
479         l = ntohl(nd->root_saddr.sin_addr.s_addr);
480         snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s",
481                 (l >> 24) & 0xff, (l >> 16) & 0xff,
482                 (l >>  8) & 0xff, (l >>  0) & 0xff, nd->root_hostnam);
483         printf("NFS ROOT: %s\n", buf);
484         nd->root_args.hostname = buf;
485         if ((error = nfs_mountdiskless(buf,
486             &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) {
487                 return (error);
488         }
489
490         /*
491          * This is not really an nfs issue, but it is much easier to
492          * set hostname here and then let the "/etc/rc.xxx" files
493          * mount the right /var based upon its preset value.
494          */
495         mtx_lock(&prison0.pr_mtx);
496         strlcpy(prison0.pr_hostname, nd->my_hostnam,
497             sizeof(prison0.pr_hostname));
498         mtx_unlock(&prison0.pr_mtx);
499         inittodr(ntohl(nd->root_time));
500         return (0);
501 }
502
503 /*
504  * Internal version of mount system call for diskless setup.
505  */
506 static int
507 nfs_mountdiskless(char *path,
508     struct sockaddr_in *sin, struct nfs_args *args, struct thread *td,
509     struct vnode **vpp, struct mount *mp)
510 {
511         struct sockaddr *nam;
512         int dirlen, error;
513         char *dirpath;
514
515         /*
516          * Find the directory path in "path", which also has the server's
517          * name/ip address in it.
518          */
519         dirpath = strchr(path, ':');
520         if (dirpath != NULL)
521                 dirlen = strlen(++dirpath);
522         else
523                 dirlen = 0;
524         nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK);
525         if ((error = mountnfs(args, mp, nam, path, NULL, 0, dirpath, dirlen,
526             NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NAMETIMEO, 
527             NFS_DEFAULT_NEGNAMETIMEO)) != 0) {
528                 printf("nfs_mountroot: mount %s on /: %d\n", path, error);
529                 return (error);
530         }
531         return (0);
532 }
533
534 static void
535 nfs_sec_name(char *sec, int *flagsp)
536 {
537         if (!strcmp(sec, "krb5"))
538                 *flagsp |= NFSMNT_KERB;
539         else if (!strcmp(sec, "krb5i"))
540                 *flagsp |= (NFSMNT_KERB | NFSMNT_INTEGRITY);
541         else if (!strcmp(sec, "krb5p"))
542                 *flagsp |= (NFSMNT_KERB | NFSMNT_PRIVACY);
543 }
544
545 static void
546 nfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp,
547     const char *hostname, struct ucred *cred, struct thread *td)
548 {
549         int s;
550         int adjsock;
551         char *p;
552
553         s = splnet();
554
555         /*
556          * Set read-only flag if requested; otherwise, clear it if this is
557          * an update.  If this is not an update, then either the read-only
558          * flag is already clear, or this is a root mount and it was set
559          * intentionally at some previous point.
560          */
561         if (vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL) == 0) {
562                 MNT_ILOCK(mp);
563                 mp->mnt_flag |= MNT_RDONLY;
564                 MNT_IUNLOCK(mp);
565         } else if (mp->mnt_flag & MNT_UPDATE) {
566                 MNT_ILOCK(mp);
567                 mp->mnt_flag &= ~MNT_RDONLY;
568                 MNT_IUNLOCK(mp);
569         }
570
571         /*
572          * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes
573          * no sense in that context.  Also, set up appropriate retransmit
574          * and soft timeout behavior.
575          */
576         if (argp->sotype == SOCK_STREAM) {
577                 nmp->nm_flag &= ~NFSMNT_NOCONN;
578                 nmp->nm_timeo = NFS_MAXTIMEO;
579                 if ((argp->flags & NFSMNT_NFSV4) != 0)
580                         nmp->nm_retry = INT_MAX;
581                 else
582                         nmp->nm_retry = NFS_RETRANS_TCP;
583         }
584
585         /* Also clear RDIRPLUS if NFSv2, it crashes some servers */
586         if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) {
587                 argp->flags &= ~NFSMNT_RDIRPLUS;
588                 nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
589         }
590
591         /* Re-bind if rsrvd port requested and wasn't on one */
592         adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT)
593                   && (argp->flags & NFSMNT_RESVPORT);
594         /* Also re-bind if we're switching to/from a connected UDP socket */
595         adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) !=
596                     (argp->flags & NFSMNT_NOCONN));
597
598         /* Update flags atomically.  Don't change the lock bits. */
599         nmp->nm_flag = argp->flags | nmp->nm_flag;
600         splx(s);
601
602         if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
603                 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
604                 if (nmp->nm_timeo < NFS_MINTIMEO)
605                         nmp->nm_timeo = NFS_MINTIMEO;
606                 else if (nmp->nm_timeo > NFS_MAXTIMEO)
607                         nmp->nm_timeo = NFS_MAXTIMEO;
608         }
609
610         if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
611                 nmp->nm_retry = argp->retrans;
612                 if (nmp->nm_retry > NFS_MAXREXMIT)
613                         nmp->nm_retry = NFS_MAXREXMIT;
614         }
615
616         if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
617                 nmp->nm_wsize = argp->wsize;
618                 /* Round down to multiple of blocksize */
619                 nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
620                 if (nmp->nm_wsize <= 0)
621                         nmp->nm_wsize = NFS_FABLKSIZE;
622         }
623
624         if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
625                 nmp->nm_rsize = argp->rsize;
626                 /* Round down to multiple of blocksize */
627                 nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
628                 if (nmp->nm_rsize <= 0)
629                         nmp->nm_rsize = NFS_FABLKSIZE;
630         }
631
632         if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
633                 nmp->nm_readdirsize = argp->readdirsize;
634         }
635
636         if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0)
637                 nmp->nm_acregmin = argp->acregmin;
638         else
639                 nmp->nm_acregmin = NFS_MINATTRTIMO;
640         if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0)
641                 nmp->nm_acregmax = argp->acregmax;
642         else
643                 nmp->nm_acregmax = NFS_MAXATTRTIMO;
644         if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0)
645                 nmp->nm_acdirmin = argp->acdirmin;
646         else
647                 nmp->nm_acdirmin = NFS_MINDIRATTRTIMO;
648         if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0)
649                 nmp->nm_acdirmax = argp->acdirmax;
650         else
651                 nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO;
652         if (nmp->nm_acdirmin > nmp->nm_acdirmax)
653                 nmp->nm_acdirmin = nmp->nm_acdirmax;
654         if (nmp->nm_acregmin > nmp->nm_acregmax)
655                 nmp->nm_acregmin = nmp->nm_acregmax;
656
657         if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) {
658                 if (argp->readahead <= NFS_MAXRAHEAD)
659                         nmp->nm_readahead = argp->readahead;
660                 else
661                         nmp->nm_readahead = NFS_MAXRAHEAD;
662         }
663         if ((argp->flags & NFSMNT_WCOMMITSIZE) && argp->wcommitsize >= 0) {
664                 if (argp->wcommitsize < nmp->nm_wsize)
665                         nmp->nm_wcommitsize = nmp->nm_wsize;
666                 else
667                         nmp->nm_wcommitsize = argp->wcommitsize;
668         }
669
670         adjsock |= ((nmp->nm_sotype != argp->sotype) ||
671                     (nmp->nm_soproto != argp->proto));
672
673         if (nmp->nm_client != NULL && adjsock) {
674                 int haslock = 0, error = 0;
675
676                 if (nmp->nm_sotype == SOCK_STREAM) {
677                         error = newnfs_sndlock(&nmp->nm_sockreq.nr_lock);
678                         if (!error)
679                                 haslock = 1;
680                 }
681                 if (!error) {
682                     newnfs_disconnect(&nmp->nm_sockreq);
683                     if (haslock)
684                         newnfs_sndunlock(&nmp->nm_sockreq.nr_lock);
685                     nmp->nm_sotype = argp->sotype;
686                     nmp->nm_soproto = argp->proto;
687                     if (nmp->nm_sotype == SOCK_DGRAM)
688                         while (newnfs_connect(nmp, &nmp->nm_sockreq,
689                             cred, td, 0)) {
690                                 printf("newnfs_args: retrying connect\n");
691                                 (void) nfs_catnap(PSOCK, 0, "newnfscon");
692                         }
693                 }
694         } else {
695                 nmp->nm_sotype = argp->sotype;
696                 nmp->nm_soproto = argp->proto;
697         }
698
699         if (hostname != NULL) {
700                 strlcpy(nmp->nm_hostname, hostname,
701                     sizeof(nmp->nm_hostname));
702                 p = strchr(nmp->nm_hostname, ':');
703                 if (p != NULL)
704                         *p = '\0';
705         }
706 }
707
708 static const char *nfs_opts[] = { "from", "nfs_args",
709     "noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union",
710     "noclusterr", "noclusterw", "multilabel", "acls", "force", "update",
711     "async", "noconn", "nolockd", "conn", "lockd", "intr", "rdirplus",
712     "readdirsize", "soft", "hard", "mntudp", "tcp", "udp", "wsize", "rsize",
713     "retrans", "acregmin", "acregmax", "acdirmin", "acdirmax", "resvport",
714     "readahead", "hostname", "timeout", "addr", "fh", "nfsv3", "sec",
715     "principal", "nfsv4", "gssname", "allgssname", "dirpath",
716     "nametimeo", "negnametimeo", "nocto", "noncontigwr", "wcommitsize",
717     NULL };
718
719 /*
720  * VFS Operations.
721  *
722  * mount system call
723  * It seems a bit dumb to copyinstr() the host and path here and then
724  * bcopy() them in mountnfs(), but I wanted to detect errors before
725  * doing the sockargs() call because sockargs() allocates an mbuf and
726  * an error after that means that I have to release the mbuf.
727  */
728 /* ARGSUSED */
729 static int
730 nfs_mount(struct mount *mp)
731 {
732         struct nfs_args args = {
733             .version = NFS_ARGSVERSION,
734             .addr = NULL,
735             .addrlen = sizeof (struct sockaddr_in),
736             .sotype = SOCK_STREAM,
737             .proto = 0,
738             .fh = NULL,
739             .fhsize = 0,
740             .flags = NFSMNT_RESVPORT,
741             .wsize = NFS_WSIZE,
742             .rsize = NFS_RSIZE,
743             .readdirsize = NFS_READDIRSIZE,
744             .timeo = 10,
745             .retrans = NFS_RETRANS,
746             .readahead = NFS_DEFRAHEAD,
747             .wcommitsize = 0,                   /* was: NQ_DEFLEASE */
748             .hostname = NULL,
749             .acregmin = NFS_MINATTRTIMO,
750             .acregmax = NFS_MAXATTRTIMO,
751             .acdirmin = NFS_MINDIRATTRTIMO,
752             .acdirmax = NFS_MAXDIRATTRTIMO,
753         };
754         int error = 0, ret, len;
755         struct sockaddr *nam = NULL;
756         struct vnode *vp;
757         struct thread *td;
758         char hst[MNAMELEN];
759         u_char nfh[NFSX_FHMAX], krbname[100], dirpath[100], srvkrbname[100];
760         char *opt, *name, *secname;
761         int nametimeo = NFS_DEFAULT_NAMETIMEO;
762         int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO;
763         int dirlen, has_nfs_args_opt, krbnamelen, srvkrbnamelen;
764         size_t hstlen;
765
766         has_nfs_args_opt = 0;
767         if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) {
768                 error = EINVAL;
769                 goto out;
770         }
771
772         td = curthread;
773         if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS) {
774                 error = nfs_mountroot(mp);
775                 goto out;
776         }
777
778         nfscl_init();
779
780         /*
781          * The old mount_nfs program passed the struct nfs_args
782          * from userspace to kernel.  The new mount_nfs program
783          * passes string options via nmount() from userspace to kernel
784          * and we populate the struct nfs_args in the kernel.
785          */
786         if (vfs_getopt(mp->mnt_optnew, "nfs_args", NULL, NULL) == 0) {
787                 error = vfs_copyopt(mp->mnt_optnew, "nfs_args", &args,
788                     sizeof(args));
789                 if (error != 0)
790                         goto out;
791
792                 if (args.version != NFS_ARGSVERSION) {
793                         error = EPROGMISMATCH;
794                         goto out;
795                 }
796                 has_nfs_args_opt = 1;
797         }
798
799         /* Handle the new style options. */
800         if (vfs_getopt(mp->mnt_optnew, "noconn", NULL, NULL) == 0)
801                 args.flags |= NFSMNT_NOCONN;
802         if (vfs_getopt(mp->mnt_optnew, "conn", NULL, NULL) == 0)
803                 args.flags |= NFSMNT_NOCONN;
804         if (vfs_getopt(mp->mnt_optnew, "nolockd", NULL, NULL) == 0)
805                 args.flags |= NFSMNT_NOLOCKD;
806         if (vfs_getopt(mp->mnt_optnew, "lockd", NULL, NULL) == 0)
807                 args.flags &= ~NFSMNT_NOLOCKD;
808         if (vfs_getopt(mp->mnt_optnew, "intr", NULL, NULL) == 0)
809                 args.flags |= NFSMNT_INT;
810         if (vfs_getopt(mp->mnt_optnew, "rdirplus", NULL, NULL) == 0)
811                 args.flags |= NFSMNT_RDIRPLUS;
812         if (vfs_getopt(mp->mnt_optnew, "resvport", NULL, NULL) == 0)
813                 args.flags |= NFSMNT_RESVPORT;
814         if (vfs_getopt(mp->mnt_optnew, "noresvport", NULL, NULL) == 0)
815                 args.flags &= ~NFSMNT_RESVPORT;
816         if (vfs_getopt(mp->mnt_optnew, "soft", NULL, NULL) == 0)
817                 args.flags |= NFSMNT_SOFT;
818         if (vfs_getopt(mp->mnt_optnew, "hard", NULL, NULL) == 0)
819                 args.flags &= ~NFSMNT_SOFT;
820         if (vfs_getopt(mp->mnt_optnew, "mntudp", NULL, NULL) == 0)
821                 args.sotype = SOCK_DGRAM;
822         if (vfs_getopt(mp->mnt_optnew, "udp", NULL, NULL) == 0)
823                 args.sotype = SOCK_DGRAM;
824         if (vfs_getopt(mp->mnt_optnew, "tcp", NULL, NULL) == 0)
825                 args.sotype = SOCK_STREAM;
826         if (vfs_getopt(mp->mnt_optnew, "nfsv3", NULL, NULL) == 0)
827                 args.flags |= NFSMNT_NFSV3;
828         if (vfs_getopt(mp->mnt_optnew, "nfsv4", NULL, NULL) == 0) {
829                 args.flags |= NFSMNT_NFSV4;
830                 args.sotype = SOCK_STREAM;
831         }
832         if (vfs_getopt(mp->mnt_optnew, "allgssname", NULL, NULL) == 0)
833                 args.flags |= NFSMNT_ALLGSSNAME;
834         if (vfs_getopt(mp->mnt_optnew, "nocto", NULL, NULL) == 0)
835                 args.flags |= NFSMNT_NOCTO;
836         if (vfs_getopt(mp->mnt_optnew, "noncontigwr", NULL, NULL) == 0)
837                 args.flags |= NFSMNT_NONCONTIGWR;
838         if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) {
839                 if (opt == NULL) { 
840                         vfs_mount_error(mp, "illegal readdirsize");
841                         error = EINVAL;
842                         goto out;
843                 }
844                 ret = sscanf(opt, "%d", &args.readdirsize);
845                 if (ret != 1 || args.readdirsize <= 0) {
846                         vfs_mount_error(mp, "illegal readdirsize: %s",
847                             opt);
848                         error = EINVAL;
849                         goto out;
850                 }
851                 args.flags |= NFSMNT_READDIRSIZE;
852         }
853         if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) {
854                 if (opt == NULL) { 
855                         vfs_mount_error(mp, "illegal readahead");
856                         error = EINVAL;
857                         goto out;
858                 }
859                 ret = sscanf(opt, "%d", &args.readahead);
860                 if (ret != 1 || args.readahead <= 0) {
861                         vfs_mount_error(mp, "illegal readahead: %s",
862                             opt);
863                         error = EINVAL;
864                         goto out;
865                 }
866                 args.flags |= NFSMNT_READAHEAD;
867         }
868         if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) {
869                 if (opt == NULL) { 
870                         vfs_mount_error(mp, "illegal wsize");
871                         error = EINVAL;
872                         goto out;
873                 }
874                 ret = sscanf(opt, "%d", &args.wsize);
875                 if (ret != 1 || args.wsize <= 0) {
876                         vfs_mount_error(mp, "illegal wsize: %s",
877                             opt);
878                         error = EINVAL;
879                         goto out;
880                 }
881                 args.flags |= NFSMNT_WSIZE;
882         }
883         if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) {
884                 if (opt == NULL) { 
885                         vfs_mount_error(mp, "illegal rsize");
886                         error = EINVAL;
887                         goto out;
888                 }
889                 ret = sscanf(opt, "%d", &args.rsize);
890                 if (ret != 1 || args.rsize <= 0) {
891                         vfs_mount_error(mp, "illegal wsize: %s",
892                             opt);
893                         error = EINVAL;
894                         goto out;
895                 }
896                 args.flags |= NFSMNT_RSIZE;
897         }
898         if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) {
899                 if (opt == NULL) { 
900                         vfs_mount_error(mp, "illegal retrans");
901                         error = EINVAL;
902                         goto out;
903                 }
904                 ret = sscanf(opt, "%d", &args.retrans);
905                 if (ret != 1 || args.retrans <= 0) {
906                         vfs_mount_error(mp, "illegal retrans: %s",
907                             opt);
908                         error = EINVAL;
909                         goto out;
910                 }
911                 args.flags |= NFSMNT_RETRANS;
912         }
913         if (vfs_getopt(mp->mnt_optnew, "acregmin", (void **)&opt, NULL) == 0) {
914                 ret = sscanf(opt, "%d", &args.acregmin);
915                 if (ret != 1 || args.acregmin < 0) {
916                         vfs_mount_error(mp, "illegal acregmin: %s",
917                             opt);
918                         error = EINVAL;
919                         goto out;
920                 }
921                 args.flags |= NFSMNT_ACREGMIN;
922         }
923         if (vfs_getopt(mp->mnt_optnew, "acregmax", (void **)&opt, NULL) == 0) {
924                 ret = sscanf(opt, "%d", &args.acregmax);
925                 if (ret != 1 || args.acregmax < 0) {
926                         vfs_mount_error(mp, "illegal acregmax: %s",
927                             opt);
928                         error = EINVAL;
929                         goto out;
930                 }
931                 args.flags |= NFSMNT_ACREGMAX;
932         }
933         if (vfs_getopt(mp->mnt_optnew, "acdirmin", (void **)&opt, NULL) == 0) {
934                 ret = sscanf(opt, "%d", &args.acdirmin);
935                 if (ret != 1 || args.acdirmin < 0) {
936                         vfs_mount_error(mp, "illegal acdirmin: %s",
937                             opt);
938                         error = EINVAL;
939                         goto out;
940                 }
941                 args.flags |= NFSMNT_ACDIRMIN;
942         }
943         if (vfs_getopt(mp->mnt_optnew, "acdirmax", (void **)&opt, NULL) == 0) {
944                 ret = sscanf(opt, "%d", &args.acdirmax);
945                 if (ret != 1 || args.acdirmax < 0) {
946                         vfs_mount_error(mp, "illegal acdirmax: %s",
947                             opt);
948                         error = EINVAL;
949                         goto out;
950                 }
951                 args.flags |= NFSMNT_ACDIRMAX;
952         }
953         if (vfs_getopt(mp->mnt_optnew, "wcommitsize", (void **)&opt, NULL) == 0) {
954                 ret = sscanf(opt, "%d", &args.wcommitsize);
955                 if (ret != 1 || args.wcommitsize < 0) {
956                         vfs_mount_error(mp, "illegal wcommitsize: %s", opt);
957                         error = EINVAL;
958                         goto out;
959                 }
960                 args.flags |= NFSMNT_WCOMMITSIZE;
961         }
962         if (vfs_getopt(mp->mnt_optnew, "timeout", (void **)&opt, NULL) == 0) {
963                 ret = sscanf(opt, "%d", &args.timeo);
964                 if (ret != 1 || args.timeo <= 0) {
965                         vfs_mount_error(mp, "illegal timeout: %s",
966                             opt);
967                         error = EINVAL;
968                         goto out;
969                 }
970                 args.flags |= NFSMNT_TIMEO;
971         }
972         if (vfs_getopt(mp->mnt_optnew, "nametimeo", (void **)&opt, NULL) == 0) {
973                 ret = sscanf(opt, "%d", &nametimeo);
974                 if (ret != 1 || nametimeo < 0) {
975                         vfs_mount_error(mp, "illegal nametimeo: %s", opt);
976                         error = EINVAL;
977                         goto out;
978                 }
979         }
980         if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL)
981             == 0) {
982                 ret = sscanf(opt, "%d", &negnametimeo);
983                 if (ret != 1 || negnametimeo < 0) {
984                         vfs_mount_error(mp, "illegal negnametimeo: %s",
985                             opt);
986                         error = EINVAL;
987                         goto out;
988                 }
989         }
990         if (vfs_getopt(mp->mnt_optnew, "sec",
991                 (void **) &secname, NULL) == 0)
992                 nfs_sec_name(secname, &args.flags);
993
994         if (mp->mnt_flag & MNT_UPDATE) {
995                 struct nfsmount *nmp = VFSTONFS(mp);
996
997                 if (nmp == NULL) {
998                         error = EIO;
999                         goto out;
1000                 }
1001
1002                 /*
1003                  * If a change from TCP->UDP is done and there are thread(s)
1004                  * that have I/O RPC(s) in progress with a tranfer size
1005                  * greater than NFS_MAXDGRAMDATA, those thread(s) will be
1006                  * hung, retrying the RPC(s) forever. Usually these threads
1007                  * will be seen doing an uninterruptible sleep on wait channel
1008                  * "newnfsreq" (truncated to "newnfsre" by procstat).
1009                  */
1010                 if (args.sotype == SOCK_DGRAM && nmp->nm_sotype == SOCK_STREAM)
1011                         tprintf(td->td_proc, LOG_WARNING,
1012         "Warning: mount -u that changes TCP->UDP can result in hung threads\n");
1013
1014                 /*
1015                  * When doing an update, we can't change version,
1016                  * security, switch lockd strategies or change cookie
1017                  * translation
1018                  */
1019                 args.flags = (args.flags &
1020                     ~(NFSMNT_NFSV3 |
1021                       NFSMNT_NFSV4 |
1022                       NFSMNT_KERB |
1023                       NFSMNT_INTEGRITY |
1024                       NFSMNT_PRIVACY |
1025                       NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) |
1026                     (nmp->nm_flag &
1027                         (NFSMNT_NFSV3 |
1028                          NFSMNT_NFSV4 |
1029                          NFSMNT_KERB |
1030                          NFSMNT_INTEGRITY |
1031                          NFSMNT_PRIVACY |
1032                          NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/));
1033                 nfs_decode_args(mp, nmp, &args, NULL, td->td_ucred, td);
1034                 goto out;
1035         }
1036
1037         /*
1038          * Make the nfs_ip_paranoia sysctl serve as the default connection
1039          * or no-connection mode for those protocols that support 
1040          * no-connection mode (the flag will be cleared later for protocols
1041          * that do not support no-connection mode).  This will allow a client
1042          * to receive replies from a different IP then the request was
1043          * sent to.  Note: default value for nfs_ip_paranoia is 1 (paranoid),
1044          * not 0.
1045          */
1046         if (nfs_ip_paranoia == 0)
1047                 args.flags |= NFSMNT_NOCONN;
1048
1049         if (has_nfs_args_opt != 0) {
1050                 /*
1051                  * In the 'nfs_args' case, the pointers in the args
1052                  * structure are in userland - we copy them in here.
1053                  */
1054                 if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX) {
1055                         vfs_mount_error(mp, "Bad file handle");
1056                         error = EINVAL;
1057                         goto out;
1058                 }
1059                 error = copyin((caddr_t)args.fh, (caddr_t)nfh,
1060                     args.fhsize);
1061                 if (error != 0)
1062                         goto out;
1063                 error = copyinstr(args.hostname, hst, MNAMELEN - 1, &hstlen);
1064                 if (error != 0)
1065                         goto out;
1066                 bzero(&hst[hstlen], MNAMELEN - hstlen);
1067                 args.hostname = hst;
1068                 /* sockargs() call must be after above copyin() calls */
1069                 error = getsockaddr(&nam, (caddr_t)args.addr,
1070                     args.addrlen);
1071                 if (error != 0)
1072                         goto out;
1073         } else {
1074                 if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh,
1075                     &args.fhsize) == 0) {
1076                         if (args.fhsize < 0 || args.fhsize > NFSX_FHMAX) {
1077                                 vfs_mount_error(mp, "Bad file handle");
1078                                 error = EINVAL;
1079                                 goto out;
1080                         }
1081                         bcopy(args.fh, nfh, args.fhsize);
1082                 } else {
1083                         args.fhsize = 0;
1084                 }
1085                 (void) vfs_getopt(mp->mnt_optnew, "hostname",
1086                     (void **)&args.hostname, &len);
1087                 if (args.hostname == NULL) {
1088                         vfs_mount_error(mp, "Invalid hostname");
1089                         error = EINVAL;
1090                         goto out;
1091                 }
1092                 bcopy(args.hostname, hst, MNAMELEN);
1093                 hst[MNAMELEN - 1] = '\0';
1094         }
1095
1096         if (vfs_getopt(mp->mnt_optnew, "principal", (void **)&name, NULL) == 0)
1097                 strlcpy(srvkrbname, name, sizeof (srvkrbname));
1098         else
1099                 snprintf(srvkrbname, sizeof (srvkrbname), "nfs@%s", hst);
1100         srvkrbnamelen = strlen(srvkrbname);
1101
1102         if (vfs_getopt(mp->mnt_optnew, "gssname", (void **)&name, NULL) == 0)
1103                 strlcpy(krbname, name, sizeof (krbname));
1104         else
1105                 krbname[0] = '\0';
1106         krbnamelen = strlen(krbname);
1107
1108         if (vfs_getopt(mp->mnt_optnew, "dirpath", (void **)&name, NULL) == 0)
1109                 strlcpy(dirpath, name, sizeof (dirpath));
1110         else
1111                 dirpath[0] = '\0';
1112         dirlen = strlen(dirpath);
1113
1114         if (has_nfs_args_opt == 0) {
1115                 if (vfs_getopt(mp->mnt_optnew, "addr",
1116                     (void **)&args.addr, &args.addrlen) == 0) {
1117                         if (args.addrlen > SOCK_MAXADDRLEN) {
1118                                 error = ENAMETOOLONG;
1119                                 goto out;
1120                         }
1121                         nam = malloc(args.addrlen, M_SONAME, M_WAITOK);
1122                         bcopy(args.addr, nam, args.addrlen);
1123                         nam->sa_len = args.addrlen;
1124                 } else {
1125                         vfs_mount_error(mp, "No server address");
1126                         error = EINVAL;
1127                         goto out;
1128                 }
1129         }
1130
1131         args.fh = nfh;
1132         error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath,
1133             dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td,
1134             nametimeo, negnametimeo);
1135 out:
1136         if (!error) {
1137                 MNT_ILOCK(mp);
1138                 mp->mnt_kern_flag |= MNTK_MPSAFE | MNTK_LOOKUP_SHARED |
1139                     MNTK_NO_IOPF;
1140                 MNT_IUNLOCK(mp);
1141         }
1142         return (error);
1143 }
1144
1145
1146 /*
1147  * VFS Operations.
1148  *
1149  * mount system call
1150  * It seems a bit dumb to copyinstr() the host and path here and then
1151  * bcopy() them in mountnfs(), but I wanted to detect errors before
1152  * doing the sockargs() call because sockargs() allocates an mbuf and
1153  * an error after that means that I have to release the mbuf.
1154  */
1155 /* ARGSUSED */
1156 static int
1157 nfs_cmount(struct mntarg *ma, void *data, uint64_t flags)
1158 {
1159         int error;
1160         struct nfs_args args;
1161
1162         error = copyin(data, &args, sizeof (struct nfs_args));
1163         if (error)
1164                 return error;
1165
1166         ma = mount_arg(ma, "nfs_args", &args, sizeof args);
1167
1168         error = kernel_mount(ma, flags);
1169         return (error);
1170 }
1171
1172 /*
1173  * Common code for mount and mountroot
1174  */
1175 static int
1176 mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
1177     char *hst, u_char *krbname, int krbnamelen, u_char *dirpath, int dirlen,
1178     u_char *srvkrbname, int srvkrbnamelen, struct vnode **vpp,
1179     struct ucred *cred, struct thread *td, int nametimeo, int negnametimeo)
1180 {
1181         struct nfsmount *nmp;
1182         struct nfsnode *np;
1183         int error, trycnt, ret;
1184         struct nfsvattr nfsva;
1185         static u_int64_t clval = 0;
1186
1187         if (mp->mnt_flag & MNT_UPDATE) {
1188                 nmp = VFSTONFS(mp);
1189                 printf("%s: MNT_UPDATE is no longer handled here\n", __func__);
1190                 FREE(nam, M_SONAME);
1191                 return (0);
1192         } else {
1193                 MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount) +
1194                     krbnamelen + dirlen + srvkrbnamelen + 2,
1195                     M_NEWNFSMNT, M_WAITOK | M_ZERO);
1196                 TAILQ_INIT(&nmp->nm_bufq);
1197                 if (clval == 0)
1198                         clval = (u_int64_t)nfsboottime.tv_sec;
1199                 nmp->nm_clval = clval++;
1200                 nmp->nm_krbnamelen = krbnamelen;
1201                 nmp->nm_dirpathlen = dirlen;
1202                 nmp->nm_srvkrbnamelen = srvkrbnamelen;
1203                 if (td->td_ucred->cr_uid != (uid_t)0) {
1204                         /*
1205                          * nm_uid is used to get KerberosV credentials for
1206                          * the nfsv4 state handling operations if there is
1207                          * no host based principal set. Use the uid of
1208                          * this user if not root, since they are doing the
1209                          * mount. I don't think setting this for root will
1210                          * work, since root normally does not have user
1211                          * credentials in a credentials cache.
1212                          */
1213                         nmp->nm_uid = td->td_ucred->cr_uid;
1214                 } else {
1215                         /*
1216                          * Just set to -1, so it won't be used.
1217                          */
1218                         nmp->nm_uid = (uid_t)-1;
1219                 }
1220
1221                 /* Copy and null terminate all the names */
1222                 if (nmp->nm_krbnamelen > 0) {
1223                         bcopy(krbname, nmp->nm_krbname, nmp->nm_krbnamelen);
1224                         nmp->nm_name[nmp->nm_krbnamelen] = '\0';
1225                 }
1226                 if (nmp->nm_dirpathlen > 0) {
1227                         bcopy(dirpath, NFSMNT_DIRPATH(nmp),
1228                             nmp->nm_dirpathlen);
1229                         nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen
1230                             + 1] = '\0';
1231                 }
1232                 if (nmp->nm_srvkrbnamelen > 0) {
1233                         bcopy(srvkrbname, NFSMNT_SRVKRBNAME(nmp),
1234                             nmp->nm_srvkrbnamelen);
1235                         nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen
1236                             + nmp->nm_srvkrbnamelen + 2] = '\0';
1237                 }
1238                 nmp->nm_sockreq.nr_cred = crhold(cred);
1239                 mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF);
1240                 mp->mnt_data = nmp;
1241                 nmp->nm_getinfo = nfs_getnlminfo;
1242                 nmp->nm_vinvalbuf = ncl_vinvalbuf;
1243         }
1244         vfs_getnewfsid(mp);
1245         nmp->nm_mountp = mp;
1246         mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK);
1247
1248         /*
1249          * Since nfs_decode_args() might optionally set them, these
1250          * need to be set to defaults before the call, so that the
1251          * optional settings aren't overwritten.
1252          */
1253         nmp->nm_nametimeo = nametimeo;
1254         nmp->nm_negnametimeo = negnametimeo;
1255         nmp->nm_timeo = NFS_TIMEO;
1256         nmp->nm_retry = NFS_RETRANS;
1257         nmp->nm_readahead = NFS_DEFRAHEAD;
1258         if (desiredvnodes >= 11000)
1259                 nmp->nm_wcommitsize = hibufspace / (desiredvnodes / 1000);
1260         else
1261                 nmp->nm_wcommitsize = hibufspace / 10;
1262
1263         nfs_decode_args(mp, nmp, argp, hst, cred, td);
1264
1265         /*
1266          * V2 can only handle 32 bit filesizes.  A 4GB-1 limit may be too
1267          * high, depending on whether we end up with negative offsets in
1268          * the client or server somewhere.  2GB-1 may be safer.
1269          *
1270          * For V3, ncl_fsinfo will adjust this as necessary.  Assume maximum
1271          * that we can handle until we find out otherwise.
1272          * XXX Our "safe" limit on the client is what we can store in our
1273          * buffer cache using signed(!) block numbers.
1274          */
1275         if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0)
1276                 nmp->nm_maxfilesize = 0xffffffffLL;
1277         else
1278                 nmp->nm_maxfilesize = OFF_MAX;
1279
1280         if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) {
1281                 nmp->nm_wsize = NFS_WSIZE;
1282                 nmp->nm_rsize = NFS_RSIZE;
1283                 nmp->nm_readdirsize = NFS_READDIRSIZE;
1284         }
1285         nmp->nm_numgrps = NFS_MAXGRPS;
1286         nmp->nm_tprintf_delay = nfs_tprintf_delay;
1287         if (nmp->nm_tprintf_delay < 0)
1288                 nmp->nm_tprintf_delay = 0;
1289         nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay;
1290         if (nmp->nm_tprintf_initial_delay < 0)
1291                 nmp->nm_tprintf_initial_delay = 0;
1292         nmp->nm_fhsize = argp->fhsize;
1293         if (nmp->nm_fhsize > 0)
1294                 bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
1295         bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
1296         nmp->nm_nam = nam;
1297         /* Set up the sockets and per-host congestion */
1298         nmp->nm_sotype = argp->sotype;
1299         nmp->nm_soproto = argp->proto;
1300         nmp->nm_sockreq.nr_prog = NFS_PROG;
1301         if ((argp->flags & NFSMNT_NFSV4))
1302                 nmp->nm_sockreq.nr_vers = NFS_VER4;
1303         else if ((argp->flags & NFSMNT_NFSV3))
1304                 nmp->nm_sockreq.nr_vers = NFS_VER3;
1305         else
1306                 nmp->nm_sockreq.nr_vers = NFS_VER2;
1307
1308
1309         if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0)))
1310                 goto bad;
1311
1312         /*
1313          * A reference count is needed on the nfsnode representing the
1314          * remote root.  If this object is not persistent, then backward
1315          * traversals of the mount point (i.e. "..") will not work if
1316          * the nfsnode gets flushed out of the cache. Ufs does not have
1317          * this problem, because one can identify root inodes by their
1318          * number == ROOTINO (2).
1319          */
1320         if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) &&
1321             nmp->nm_dirpathlen > 0) {
1322                 /*
1323                  * If the fhsize on the mount point == 0 for V4, the mount
1324                  * path needs to be looked up.
1325                  */
1326                 trycnt = 3;
1327                 do {
1328                         error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
1329                             cred, td);
1330                         if (error)
1331                                 (void) nfs_catnap(PZERO, error, "nfsgetdirp");
1332                 } while (error && --trycnt > 0);
1333                 if (error) {
1334                         error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0);
1335                         goto bad;
1336                 }
1337         }
1338         if (nmp->nm_fhsize > 0) {
1339                 /*
1340                  * Set f_iosize to NFS_DIRBLKSIZ so that bo_bsize gets set
1341                  * non-zero for the root vnode. f_iosize will be set correctly
1342                  * by nfs_statfs() before any I/O occurs.
1343                  */
1344                 mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ;
1345                 error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np,
1346                     LK_EXCLUSIVE);
1347                 if (error)
1348                         goto bad;
1349                 *vpp = NFSTOV(np);
1350         
1351                 /*
1352                  * Get file attributes and transfer parameters for the
1353                  * mountpoint.  This has the side effect of filling in
1354                  * (*vpp)->v_type with the correct value.
1355                  */
1356                 ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1,
1357                     cred, td, &nfsva, NULL);
1358                 if (ret) {
1359                         /*
1360                          * Just set default values to get things going.
1361                          */
1362                         NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr));
1363                         nfsva.na_vattr.va_type = VDIR;
1364                         nfsva.na_vattr.va_mode = 0777;
1365                         nfsva.na_vattr.va_nlink = 100;
1366                         nfsva.na_vattr.va_uid = (uid_t)0;
1367                         nfsva.na_vattr.va_gid = (gid_t)0;
1368                         nfsva.na_vattr.va_fileid = 2;
1369                         nfsva.na_vattr.va_gen = 1;
1370                         nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE;
1371                         nfsva.na_vattr.va_size = 512 * 1024;
1372                 }
1373                 (void) nfscl_loadattrcache(vpp, &nfsva, NULL, NULL, 0, 1);
1374                 if (argp->flags & NFSMNT_NFSV3)
1375                         ncl_fsinfo(nmp, *vpp, cred, td);
1376         
1377                 /* Mark if the mount point supports NFSv4 ACLs. */
1378                 if ((argp->flags & NFSMNT_NFSV4) != 0 && nfsrv_useacl != 0 &&
1379                     ret == 0 &&
1380                     NFSISSET_ATTRBIT(&nfsva.na_suppattr, NFSATTRBIT_ACL)) {
1381                         MNT_ILOCK(mp);
1382                         mp->mnt_flag |= MNT_NFS4ACLS;
1383                         MNT_IUNLOCK(mp);
1384                 }
1385         
1386                 /*
1387                  * Lose the lock but keep the ref.
1388                  */
1389                 NFSVOPUNLOCK(*vpp, 0);
1390                 return (0);
1391         }
1392         error = EIO;
1393
1394 bad:
1395         newnfs_disconnect(&nmp->nm_sockreq);
1396         crfree(nmp->nm_sockreq.nr_cred);
1397         mtx_destroy(&nmp->nm_sockreq.nr_mtx);
1398         mtx_destroy(&nmp->nm_mtx);
1399         FREE(nmp, M_NEWNFSMNT);
1400         FREE(nam, M_SONAME);
1401         return (error);
1402 }
1403
1404 /*
1405  * unmount system call
1406  */
1407 static int
1408 nfs_unmount(struct mount *mp, int mntflags)
1409 {
1410         struct thread *td;
1411         struct nfsmount *nmp;
1412         int error, flags = 0, i, trycnt = 0;
1413
1414         td = curthread;
1415
1416         if (mntflags & MNT_FORCE)
1417                 flags |= FORCECLOSE;
1418         nmp = VFSTONFS(mp);
1419         /*
1420          * Goes something like this..
1421          * - Call vflush() to clear out vnodes for this filesystem
1422          * - Close the socket
1423          * - Free up the data structures
1424          */
1425         /* In the forced case, cancel any outstanding requests. */
1426         if (mntflags & MNT_FORCE) {
1427                 error = newnfs_nmcancelreqs(nmp);
1428                 if (error)
1429                         goto out;
1430                 /* For a forced close, get rid of the renew thread now */
1431                 nfscl_umount(nmp, td);
1432         }
1433         /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */
1434         do {
1435                 error = vflush(mp, 1, flags, td);
1436                 if ((mntflags & MNT_FORCE) && error != 0 && ++trycnt < 30)
1437                         (void) nfs_catnap(PSOCK, error, "newndm");
1438         } while ((mntflags & MNT_FORCE) && error != 0 && trycnt < 30);
1439         if (error)
1440                 goto out;
1441
1442         /*
1443          * We are now committed to the unmount.
1444          */
1445         if ((mntflags & MNT_FORCE) == 0)
1446                 nfscl_umount(nmp, td);
1447         /* Make sure no nfsiods are assigned to this mount. */
1448         mtx_lock(&ncl_iod_mutex);
1449         for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
1450                 if (ncl_iodmount[i] == nmp) {
1451                         ncl_iodwant[i] = NFSIOD_AVAILABLE;
1452                         ncl_iodmount[i] = NULL;
1453                 }
1454         mtx_unlock(&ncl_iod_mutex);
1455         newnfs_disconnect(&nmp->nm_sockreq);
1456         crfree(nmp->nm_sockreq.nr_cred);
1457         FREE(nmp->nm_nam, M_SONAME);
1458
1459         mtx_destroy(&nmp->nm_sockreq.nr_mtx);
1460         mtx_destroy(&nmp->nm_mtx);
1461         FREE(nmp, M_NEWNFSMNT);
1462 out:
1463         return (error);
1464 }
1465
1466 /*
1467  * Return root of a filesystem
1468  */
1469 static int
1470 nfs_root(struct mount *mp, int flags, struct vnode **vpp)
1471 {
1472         struct vnode *vp;
1473         struct nfsmount *nmp;
1474         struct nfsnode *np;
1475         int error;
1476
1477         nmp = VFSTONFS(mp);
1478         error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, flags);
1479         if (error)
1480                 return error;
1481         vp = NFSTOV(np);
1482         /*
1483          * Get transfer parameters and attributes for root vnode once.
1484          */
1485         mtx_lock(&nmp->nm_mtx);
1486         if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) {
1487                 mtx_unlock(&nmp->nm_mtx);
1488                 ncl_fsinfo(nmp, vp, curthread->td_ucred, curthread);
1489         } else 
1490                 mtx_unlock(&nmp->nm_mtx);
1491         if (vp->v_type == VNON)
1492             vp->v_type = VDIR;
1493         vp->v_vflag |= VV_ROOT;
1494         *vpp = vp;
1495         return (0);
1496 }
1497
1498 /*
1499  * Flush out the buffer cache
1500  */
1501 /* ARGSUSED */
1502 static int
1503 nfs_sync(struct mount *mp, int waitfor)
1504 {
1505         struct vnode *vp, *mvp;
1506         struct thread *td;
1507         int error, allerror = 0;
1508
1509         td = curthread;
1510
1511         MNT_ILOCK(mp);
1512         /*
1513          * If a forced dismount is in progress, return from here so that
1514          * the umount(2) syscall doesn't get stuck in VFS_SYNC() before
1515          * calling VFS_UNMOUNT().
1516          */
1517         if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1518                 MNT_IUNLOCK(mp);
1519                 return (EBADF);
1520         }
1521         MNT_IUNLOCK(mp);
1522
1523         /*
1524          * Force stale buffer cache information to be flushed.
1525          */
1526 loop:
1527         MNT_VNODE_FOREACH_ALL(vp, mp, mvp) {
1528                 /* XXX Racy bv_cnt check. */
1529                 if (NFSVOPISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0 ||
1530                     waitfor == MNT_LAZY) {
1531                         VI_UNLOCK(vp);
1532                         continue;
1533                 }
1534                 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) {
1535                         MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
1536                         goto loop;
1537                 }
1538                 error = VOP_FSYNC(vp, waitfor, td);
1539                 if (error)
1540                         allerror = error;
1541                 NFSVOPUNLOCK(vp, 0);
1542                 vrele(vp);
1543         }
1544         return (allerror);
1545 }
1546
1547 static int
1548 nfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req)
1549 {
1550         struct nfsmount *nmp = VFSTONFS(mp);
1551         struct vfsquery vq;
1552         int error;
1553
1554         bzero(&vq, sizeof(vq));
1555         switch (op) {
1556 #if 0
1557         case VFS_CTL_NOLOCKS:
1558                 val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0;
1559                 if (req->oldptr != NULL) {
1560                         error = SYSCTL_OUT(req, &val, sizeof(val));
1561                         if (error)
1562                                 return (error);
1563                 }
1564                 if (req->newptr != NULL) {
1565                         error = SYSCTL_IN(req, &val, sizeof(val));
1566                         if (error)
1567                                 return (error);
1568                         if (val)
1569                                 nmp->nm_flag |= NFSMNT_NOLOCKS;
1570                         else
1571                                 nmp->nm_flag &= ~NFSMNT_NOLOCKS;
1572                 }
1573                 break;
1574 #endif
1575         case VFS_CTL_QUERY:
1576                 mtx_lock(&nmp->nm_mtx);
1577                 if (nmp->nm_state & NFSSTA_TIMEO)
1578                         vq.vq_flags |= VQ_NOTRESP;
1579                 mtx_unlock(&nmp->nm_mtx);
1580 #if 0
1581                 if (!(nmp->nm_flag & NFSMNT_NOLOCKS) &&
1582                     (nmp->nm_state & NFSSTA_LOCKTIMEO))
1583                         vq.vq_flags |= VQ_NOTRESPLOCK;
1584 #endif
1585                 error = SYSCTL_OUT(req, &vq, sizeof(vq));
1586                 break;
1587         case VFS_CTL_TIMEO:
1588                 if (req->oldptr != NULL) {
1589                         error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay,
1590                             sizeof(nmp->nm_tprintf_initial_delay));
1591                         if (error)
1592                                 return (error);
1593                 }
1594                 if (req->newptr != NULL) {
1595                         error = vfs_suser(mp, req->td);
1596                         if (error)
1597                                 return (error);
1598                         error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay,
1599                             sizeof(nmp->nm_tprintf_initial_delay));
1600                         if (error)
1601                                 return (error);
1602                         if (nmp->nm_tprintf_initial_delay < 0)
1603                                 nmp->nm_tprintf_initial_delay = 0;
1604                 }
1605                 break;
1606         default:
1607                 return (ENOTSUP);
1608         }
1609         return (0);
1610 }
1611
1612 /*
1613  * Extract the information needed by the nlm from the nfs vnode.
1614  */
1615 static void
1616 nfs_getnlminfo(struct vnode *vp, uint8_t *fhp, size_t *fhlenp,
1617     struct sockaddr_storage *sp, int *is_v3p, off_t *sizep,
1618     struct timeval *timeop)
1619 {
1620         struct nfsmount *nmp;
1621         struct nfsnode *np = VTONFS(vp);
1622
1623         nmp = VFSTONFS(vp->v_mount);
1624         if (fhlenp != NULL)
1625                 *fhlenp = (size_t)np->n_fhp->nfh_len;
1626         if (fhp != NULL)
1627                 bcopy(np->n_fhp->nfh_fh, fhp, np->n_fhp->nfh_len);
1628         if (sp != NULL)
1629                 bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp)));
1630         if (is_v3p != NULL)
1631                 *is_v3p = NFS_ISV3(vp);
1632         if (sizep != NULL)
1633                 *sizep = np->n_size;
1634         if (timeop != NULL) {
1635                 timeop->tv_sec = nmp->nm_timeo / NFS_HZ;
1636                 timeop->tv_usec = (nmp->nm_timeo % NFS_HZ) * (1000000 / NFS_HZ);
1637         }
1638 }
1639
1640 /*
1641  * This function prints out an option name, based on the conditional
1642  * argument.
1643  */
1644 static __inline void nfscl_printopt(struct nfsmount *nmp, int testval,
1645     char *opt, char **buf, size_t *blen)
1646 {
1647         int len;
1648
1649         if (testval != 0 && *blen > strlen(opt)) {
1650                 len = snprintf(*buf, *blen, "%s", opt);
1651                 if (len != strlen(opt))
1652                         printf("EEK!!\n");
1653                 *buf += len;
1654                 *blen -= len;
1655         }
1656 }
1657
1658 /*
1659  * This function printf out an options integer value.
1660  */
1661 static __inline void nfscl_printoptval(struct nfsmount *nmp, int optval,
1662     char *opt, char **buf, size_t *blen)
1663 {
1664         int len;
1665
1666         if (*blen > strlen(opt) + 1) {
1667                 /* Could result in truncated output string. */
1668                 len = snprintf(*buf, *blen, "%s=%d", opt, optval);
1669                 if (len < *blen) {
1670                         *buf += len;
1671                         *blen -= len;
1672                 }
1673         }
1674 }
1675
1676 /*
1677  * Load the option flags and values into the buffer.
1678  */
1679 void nfscl_retopts(struct nfsmount *nmp, char *buffer, size_t buflen)
1680 {
1681         char *buf;
1682         size_t blen;
1683
1684         buf = buffer;
1685         blen = buflen;
1686         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV4) != 0, "nfsv4", &buf,
1687             &blen);
1688         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV3) != 0, "nfsv3", &buf,
1689             &blen);
1690         nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0,
1691             "nfsv2", &buf, &blen);
1692         nfscl_printopt(nmp, nmp->nm_sotype == SOCK_STREAM, ",tcp", &buf, &blen);
1693         nfscl_printopt(nmp, nmp->nm_sotype != SOCK_STREAM, ",udp", &buf, &blen);
1694         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RESVPORT) != 0, ",resvport",
1695             &buf, &blen);
1696         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCONN) != 0, ",noconn",
1697             &buf, &blen);
1698         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) == 0, ",hard", &buf,
1699             &blen);
1700         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) != 0, ",soft", &buf,
1701             &blen);
1702         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_INT) != 0, ",intr", &buf,
1703             &blen);
1704         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) == 0, ",cto", &buf,
1705             &blen);
1706         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) != 0, ",nocto", &buf,
1707             &blen);
1708         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NONCONTIGWR) != 0,
1709             ",noncontigwr", &buf, &blen);
1710         nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NOLOCKD | NFSMNT_NFSV4)) ==
1711             0, ",lockd", &buf, &blen);
1712         nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NOLOCKD | NFSMNT_NFSV4)) ==
1713             NFSMNT_NOLOCKD, ",nolockd", &buf, &blen);
1714         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RDIRPLUS) != 0, ",rdirplus",
1715             &buf, &blen);
1716         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_KERB) == 0, ",sec=sys",
1717             &buf, &blen);
1718         nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
1719             NFSMNT_PRIVACY)) == NFSMNT_KERB, ",sec=krb5", &buf, &blen);
1720         nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
1721             NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_INTEGRITY), ",sec=krb5i",
1722             &buf, &blen);
1723         nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
1724             NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_PRIVACY), ",sec=krb5p",
1725             &buf, &blen);
1726         nfscl_printoptval(nmp, nmp->nm_acdirmin, ",acdirmin", &buf, &blen);
1727         nfscl_printoptval(nmp, nmp->nm_acdirmax, ",acdirmax", &buf, &blen);
1728         nfscl_printoptval(nmp, nmp->nm_acregmin, ",acregmin", &buf, &blen);
1729         nfscl_printoptval(nmp, nmp->nm_acregmax, ",acregmax", &buf, &blen);
1730         nfscl_printoptval(nmp, nmp->nm_nametimeo, ",nametimeo", &buf, &blen);
1731         nfscl_printoptval(nmp, nmp->nm_negnametimeo, ",negnametimeo", &buf,
1732             &blen);
1733         nfscl_printoptval(nmp, nmp->nm_rsize, ",rsize", &buf, &blen);
1734         nfscl_printoptval(nmp, nmp->nm_wsize, ",wsize", &buf, &blen);
1735         nfscl_printoptval(nmp, nmp->nm_readdirsize, ",readdirsize", &buf,
1736             &blen);
1737         nfscl_printoptval(nmp, nmp->nm_readahead, ",readahead", &buf, &blen);
1738         nfscl_printoptval(nmp, nmp->nm_wcommitsize, ",wcommitsize", &buf,
1739             &blen);
1740         nfscl_printoptval(nmp, nmp->nm_timeo, ",timeout", &buf, &blen);
1741         nfscl_printoptval(nmp, nmp->nm_retry, ",retrans", &buf, &blen);
1742 }
1743