]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/fs/nfsclient/nfs_clvfsops.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.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", "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, "readdirsize", (void **)&opt, NULL) == 0) {
837                 if (opt == NULL) { 
838                         vfs_mount_error(mp, "illegal readdirsize");
839                         error = EINVAL;
840                         goto out;
841                 }
842                 ret = sscanf(opt, "%d", &args.readdirsize);
843                 if (ret != 1 || args.readdirsize <= 0) {
844                         vfs_mount_error(mp, "illegal readdirsize: %s",
845                             opt);
846                         error = EINVAL;
847                         goto out;
848                 }
849                 args.flags |= NFSMNT_READDIRSIZE;
850         }
851         if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) {
852                 if (opt == NULL) { 
853                         vfs_mount_error(mp, "illegal readahead");
854                         error = EINVAL;
855                         goto out;
856                 }
857                 ret = sscanf(opt, "%d", &args.readahead);
858                 if (ret != 1 || args.readahead <= 0) {
859                         vfs_mount_error(mp, "illegal readahead: %s",
860                             opt);
861                         error = EINVAL;
862                         goto out;
863                 }
864                 args.flags |= NFSMNT_READAHEAD;
865         }
866         if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) {
867                 if (opt == NULL) { 
868                         vfs_mount_error(mp, "illegal wsize");
869                         error = EINVAL;
870                         goto out;
871                 }
872                 ret = sscanf(opt, "%d", &args.wsize);
873                 if (ret != 1 || args.wsize <= 0) {
874                         vfs_mount_error(mp, "illegal wsize: %s",
875                             opt);
876                         error = EINVAL;
877                         goto out;
878                 }
879                 args.flags |= NFSMNT_WSIZE;
880         }
881         if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) {
882                 if (opt == NULL) { 
883                         vfs_mount_error(mp, "illegal rsize");
884                         error = EINVAL;
885                         goto out;
886                 }
887                 ret = sscanf(opt, "%d", &args.rsize);
888                 if (ret != 1 || args.rsize <= 0) {
889                         vfs_mount_error(mp, "illegal wsize: %s",
890                             opt);
891                         error = EINVAL;
892                         goto out;
893                 }
894                 args.flags |= NFSMNT_RSIZE;
895         }
896         if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) {
897                 if (opt == NULL) { 
898                         vfs_mount_error(mp, "illegal retrans");
899                         error = EINVAL;
900                         goto out;
901                 }
902                 ret = sscanf(opt, "%d", &args.retrans);
903                 if (ret != 1 || args.retrans <= 0) {
904                         vfs_mount_error(mp, "illegal retrans: %s",
905                             opt);
906                         error = EINVAL;
907                         goto out;
908                 }
909                 args.flags |= NFSMNT_RETRANS;
910         }
911         if (vfs_getopt(mp->mnt_optnew, "acregmin", (void **)&opt, NULL) == 0) {
912                 ret = sscanf(opt, "%d", &args.acregmin);
913                 if (ret != 1 || args.acregmin < 0) {
914                         vfs_mount_error(mp, "illegal acregmin: %s",
915                             opt);
916                         error = EINVAL;
917                         goto out;
918                 }
919                 args.flags |= NFSMNT_ACREGMIN;
920         }
921         if (vfs_getopt(mp->mnt_optnew, "acregmax", (void **)&opt, NULL) == 0) {
922                 ret = sscanf(opt, "%d", &args.acregmax);
923                 if (ret != 1 || args.acregmax < 0) {
924                         vfs_mount_error(mp, "illegal acregmax: %s",
925                             opt);
926                         error = EINVAL;
927                         goto out;
928                 }
929                 args.flags |= NFSMNT_ACREGMAX;
930         }
931         if (vfs_getopt(mp->mnt_optnew, "acdirmin", (void **)&opt, NULL) == 0) {
932                 ret = sscanf(opt, "%d", &args.acdirmin);
933                 if (ret != 1 || args.acdirmin < 0) {
934                         vfs_mount_error(mp, "illegal acdirmin: %s",
935                             opt);
936                         error = EINVAL;
937                         goto out;
938                 }
939                 args.flags |= NFSMNT_ACDIRMIN;
940         }
941         if (vfs_getopt(mp->mnt_optnew, "acdirmax", (void **)&opt, NULL) == 0) {
942                 ret = sscanf(opt, "%d", &args.acdirmax);
943                 if (ret != 1 || args.acdirmax < 0) {
944                         vfs_mount_error(mp, "illegal acdirmax: %s",
945                             opt);
946                         error = EINVAL;
947                         goto out;
948                 }
949                 args.flags |= NFSMNT_ACDIRMAX;
950         }
951         if (vfs_getopt(mp->mnt_optnew, "wcommitsize", (void **)&opt, NULL) == 0) {
952                 ret = sscanf(opt, "%d", &args.wcommitsize);
953                 if (ret != 1 || args.wcommitsize < 0) {
954                         vfs_mount_error(mp, "illegal wcommitsize: %s", opt);
955                         error = EINVAL;
956                         goto out;
957                 }
958                 args.flags |= NFSMNT_WCOMMITSIZE;
959         }
960         if (vfs_getopt(mp->mnt_optnew, "timeout", (void **)&opt, NULL) == 0) {
961                 ret = sscanf(opt, "%d", &args.timeo);
962                 if (ret != 1 || args.timeo <= 0) {
963                         vfs_mount_error(mp, "illegal timeout: %s",
964                             opt);
965                         error = EINVAL;
966                         goto out;
967                 }
968                 args.flags |= NFSMNT_TIMEO;
969         }
970         if (vfs_getopt(mp->mnt_optnew, "nametimeo", (void **)&opt, NULL) == 0) {
971                 ret = sscanf(opt, "%d", &nametimeo);
972                 if (ret != 1 || nametimeo < 0) {
973                         vfs_mount_error(mp, "illegal nametimeo: %s", opt);
974                         error = EINVAL;
975                         goto out;
976                 }
977         }
978         if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL)
979             == 0) {
980                 ret = sscanf(opt, "%d", &negnametimeo);
981                 if (ret != 1 || negnametimeo < 0) {
982                         vfs_mount_error(mp, "illegal negnametimeo: %s",
983                             opt);
984                         error = EINVAL;
985                         goto out;
986                 }
987         }
988         if (vfs_getopt(mp->mnt_optnew, "sec",
989                 (void **) &secname, NULL) == 0)
990                 nfs_sec_name(secname, &args.flags);
991
992         if (mp->mnt_flag & MNT_UPDATE) {
993                 struct nfsmount *nmp = VFSTONFS(mp);
994
995                 if (nmp == NULL) {
996                         error = EIO;
997                         goto out;
998                 }
999
1000                 /*
1001                  * If a change from TCP->UDP is done and there are thread(s)
1002                  * that have I/O RPC(s) in progress with a tranfer size
1003                  * greater than NFS_MAXDGRAMDATA, those thread(s) will be
1004                  * hung, retrying the RPC(s) forever. Usually these threads
1005                  * will be seen doing an uninterruptible sleep on wait channel
1006                  * "newnfsreq" (truncated to "newnfsre" by procstat).
1007                  */
1008                 if (args.sotype == SOCK_DGRAM && nmp->nm_sotype == SOCK_STREAM)
1009                         tprintf(td->td_proc, LOG_WARNING,
1010         "Warning: mount -u that changes TCP->UDP can result in hung threads\n");
1011
1012                 /*
1013                  * When doing an update, we can't change version,
1014                  * security, switch lockd strategies or change cookie
1015                  * translation
1016                  */
1017                 args.flags = (args.flags &
1018                     ~(NFSMNT_NFSV3 |
1019                       NFSMNT_NFSV4 |
1020                       NFSMNT_KERB |
1021                       NFSMNT_INTEGRITY |
1022                       NFSMNT_PRIVACY |
1023                       NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) |
1024                     (nmp->nm_flag &
1025                         (NFSMNT_NFSV3 |
1026                          NFSMNT_NFSV4 |
1027                          NFSMNT_KERB |
1028                          NFSMNT_INTEGRITY |
1029                          NFSMNT_PRIVACY |
1030                          NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/));
1031                 nfs_decode_args(mp, nmp, &args, NULL, td->td_ucred, td);
1032                 goto out;
1033         }
1034
1035         /*
1036          * Make the nfs_ip_paranoia sysctl serve as the default connection
1037          * or no-connection mode for those protocols that support 
1038          * no-connection mode (the flag will be cleared later for protocols
1039          * that do not support no-connection mode).  This will allow a client
1040          * to receive replies from a different IP then the request was
1041          * sent to.  Note: default value for nfs_ip_paranoia is 1 (paranoid),
1042          * not 0.
1043          */
1044         if (nfs_ip_paranoia == 0)
1045                 args.flags |= NFSMNT_NOCONN;
1046
1047         if (has_nfs_args_opt != 0) {
1048                 /*
1049                  * In the 'nfs_args' case, the pointers in the args
1050                  * structure are in userland - we copy them in here.
1051                  */
1052                 if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX) {
1053                         vfs_mount_error(mp, "Bad file handle");
1054                         error = EINVAL;
1055                         goto out;
1056                 }
1057                 error = copyin((caddr_t)args.fh, (caddr_t)nfh,
1058                     args.fhsize);
1059                 if (error != 0)
1060                         goto out;
1061                 error = copyinstr(args.hostname, hst, MNAMELEN - 1, &hstlen);
1062                 if (error != 0)
1063                         goto out;
1064                 bzero(&hst[hstlen], MNAMELEN - hstlen);
1065                 args.hostname = hst;
1066                 /* sockargs() call must be after above copyin() calls */
1067                 error = getsockaddr(&nam, (caddr_t)args.addr,
1068                     args.addrlen);
1069                 if (error != 0)
1070                         goto out;
1071         } else {
1072                 if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh,
1073                     &args.fhsize) == 0) {
1074                         if (args.fhsize < 0 || args.fhsize > NFSX_FHMAX) {
1075                                 vfs_mount_error(mp, "Bad file handle");
1076                                 error = EINVAL;
1077                                 goto out;
1078                         }
1079                         bcopy(args.fh, nfh, args.fhsize);
1080                 } else {
1081                         args.fhsize = 0;
1082                 }
1083                 (void) vfs_getopt(mp->mnt_optnew, "hostname",
1084                     (void **)&args.hostname, &len);
1085                 if (args.hostname == NULL) {
1086                         vfs_mount_error(mp, "Invalid hostname");
1087                         error = EINVAL;
1088                         goto out;
1089                 }
1090                 bcopy(args.hostname, hst, MNAMELEN);
1091                 hst[MNAMELEN - 1] = '\0';
1092         }
1093
1094         if (vfs_getopt(mp->mnt_optnew, "principal", (void **)&name, NULL) == 0)
1095                 strlcpy(srvkrbname, name, sizeof (srvkrbname));
1096         else
1097                 snprintf(srvkrbname, sizeof (srvkrbname), "nfs@%s", hst);
1098         srvkrbnamelen = strlen(srvkrbname);
1099
1100         if (vfs_getopt(mp->mnt_optnew, "gssname", (void **)&name, NULL) == 0)
1101                 strlcpy(krbname, name, sizeof (krbname));
1102         else
1103                 krbname[0] = '\0';
1104         krbnamelen = strlen(krbname);
1105
1106         if (vfs_getopt(mp->mnt_optnew, "dirpath", (void **)&name, NULL) == 0)
1107                 strlcpy(dirpath, name, sizeof (dirpath));
1108         else
1109                 dirpath[0] = '\0';
1110         dirlen = strlen(dirpath);
1111
1112         if (has_nfs_args_opt == 0) {
1113                 if (vfs_getopt(mp->mnt_optnew, "addr",
1114                     (void **)&args.addr, &args.addrlen) == 0) {
1115                         if (args.addrlen > SOCK_MAXADDRLEN) {
1116                                 error = ENAMETOOLONG;
1117                                 goto out;
1118                         }
1119                         nam = malloc(args.addrlen, M_SONAME, M_WAITOK);
1120                         bcopy(args.addr, nam, args.addrlen);
1121                         nam->sa_len = args.addrlen;
1122                 } else {
1123                         vfs_mount_error(mp, "No server address");
1124                         error = EINVAL;
1125                         goto out;
1126                 }
1127         }
1128
1129         args.fh = nfh;
1130         error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath,
1131             dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td,
1132             nametimeo, negnametimeo);
1133 out:
1134         if (!error) {
1135                 MNT_ILOCK(mp);
1136                 mp->mnt_kern_flag |= MNTK_MPSAFE | MNTK_LOOKUP_SHARED |
1137                     MNTK_NO_IOPF;
1138                 MNT_IUNLOCK(mp);
1139         }
1140         return (error);
1141 }
1142
1143
1144 /*
1145  * VFS Operations.
1146  *
1147  * mount system call
1148  * It seems a bit dumb to copyinstr() the host and path here and then
1149  * bcopy() them in mountnfs(), but I wanted to detect errors before
1150  * doing the sockargs() call because sockargs() allocates an mbuf and
1151  * an error after that means that I have to release the mbuf.
1152  */
1153 /* ARGSUSED */
1154 static int
1155 nfs_cmount(struct mntarg *ma, void *data, uint64_t flags)
1156 {
1157         int error;
1158         struct nfs_args args;
1159
1160         error = copyin(data, &args, sizeof (struct nfs_args));
1161         if (error)
1162                 return error;
1163
1164         ma = mount_arg(ma, "nfs_args", &args, sizeof args);
1165
1166         error = kernel_mount(ma, flags);
1167         return (error);
1168 }
1169
1170 /*
1171  * Common code for mount and mountroot
1172  */
1173 static int
1174 mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
1175     char *hst, u_char *krbname, int krbnamelen, u_char *dirpath, int dirlen,
1176     u_char *srvkrbname, int srvkrbnamelen, struct vnode **vpp,
1177     struct ucred *cred, struct thread *td, int nametimeo, int negnametimeo)
1178 {
1179         struct nfsmount *nmp;
1180         struct nfsnode *np;
1181         int error, trycnt, ret;
1182         struct nfsvattr nfsva;
1183         static u_int64_t clval = 0;
1184
1185         if (mp->mnt_flag & MNT_UPDATE) {
1186                 nmp = VFSTONFS(mp);
1187                 printf("%s: MNT_UPDATE is no longer handled here\n", __func__);
1188                 FREE(nam, M_SONAME);
1189                 return (0);
1190         } else {
1191                 MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount) +
1192                     krbnamelen + dirlen + srvkrbnamelen + 2,
1193                     M_NEWNFSMNT, M_WAITOK | M_ZERO);
1194                 TAILQ_INIT(&nmp->nm_bufq);
1195                 if (clval == 0)
1196                         clval = (u_int64_t)nfsboottime.tv_sec;
1197                 nmp->nm_clval = clval++;
1198                 nmp->nm_krbnamelen = krbnamelen;
1199                 nmp->nm_dirpathlen = dirlen;
1200                 nmp->nm_srvkrbnamelen = srvkrbnamelen;
1201                 if (td->td_ucred->cr_uid != (uid_t)0) {
1202                         /*
1203                          * nm_uid is used to get KerberosV credentials for
1204                          * the nfsv4 state handling operations if there is
1205                          * no host based principal set. Use the uid of
1206                          * this user if not root, since they are doing the
1207                          * mount. I don't think setting this for root will
1208                          * work, since root normally does not have user
1209                          * credentials in a credentials cache.
1210                          */
1211                         nmp->nm_uid = td->td_ucred->cr_uid;
1212                 } else {
1213                         /*
1214                          * Just set to -1, so it won't be used.
1215                          */
1216                         nmp->nm_uid = (uid_t)-1;
1217                 }
1218
1219                 /* Copy and null terminate all the names */
1220                 if (nmp->nm_krbnamelen > 0) {
1221                         bcopy(krbname, nmp->nm_krbname, nmp->nm_krbnamelen);
1222                         nmp->nm_name[nmp->nm_krbnamelen] = '\0';
1223                 }
1224                 if (nmp->nm_dirpathlen > 0) {
1225                         bcopy(dirpath, NFSMNT_DIRPATH(nmp),
1226                             nmp->nm_dirpathlen);
1227                         nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen
1228                             + 1] = '\0';
1229                 }
1230                 if (nmp->nm_srvkrbnamelen > 0) {
1231                         bcopy(srvkrbname, NFSMNT_SRVKRBNAME(nmp),
1232                             nmp->nm_srvkrbnamelen);
1233                         nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen
1234                             + nmp->nm_srvkrbnamelen + 2] = '\0';
1235                 }
1236                 nmp->nm_sockreq.nr_cred = crhold(cred);
1237                 mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF);
1238                 mp->mnt_data = nmp;
1239                 nmp->nm_getinfo = nfs_getnlminfo;
1240                 nmp->nm_vinvalbuf = ncl_vinvalbuf;
1241         }
1242         vfs_getnewfsid(mp);
1243         nmp->nm_mountp = mp;
1244         mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK);
1245
1246         /*
1247          * Since nfs_decode_args() might optionally set them, these
1248          * need to be set to defaults before the call, so that the
1249          * optional settings aren't overwritten.
1250          */
1251         nmp->nm_nametimeo = nametimeo;
1252         nmp->nm_negnametimeo = negnametimeo;
1253         nmp->nm_timeo = NFS_TIMEO;
1254         nmp->nm_retry = NFS_RETRANS;
1255         nmp->nm_readahead = NFS_DEFRAHEAD;
1256         if (desiredvnodes >= 11000)
1257                 nmp->nm_wcommitsize = hibufspace / (desiredvnodes / 1000);
1258         else
1259                 nmp->nm_wcommitsize = hibufspace / 10;
1260
1261         nfs_decode_args(mp, nmp, argp, hst, cred, td);
1262
1263         /*
1264          * V2 can only handle 32 bit filesizes.  A 4GB-1 limit may be too
1265          * high, depending on whether we end up with negative offsets in
1266          * the client or server somewhere.  2GB-1 may be safer.
1267          *
1268          * For V3, ncl_fsinfo will adjust this as necessary.  Assume maximum
1269          * that we can handle until we find out otherwise.
1270          * XXX Our "safe" limit on the client is what we can store in our
1271          * buffer cache using signed(!) block numbers.
1272          */
1273         if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0)
1274                 nmp->nm_maxfilesize = 0xffffffffLL;
1275         else
1276                 nmp->nm_maxfilesize = OFF_MAX;
1277
1278         if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) {
1279                 nmp->nm_wsize = NFS_WSIZE;
1280                 nmp->nm_rsize = NFS_RSIZE;
1281                 nmp->nm_readdirsize = NFS_READDIRSIZE;
1282         }
1283         nmp->nm_numgrps = NFS_MAXGRPS;
1284         nmp->nm_tprintf_delay = nfs_tprintf_delay;
1285         if (nmp->nm_tprintf_delay < 0)
1286                 nmp->nm_tprintf_delay = 0;
1287         nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay;
1288         if (nmp->nm_tprintf_initial_delay < 0)
1289                 nmp->nm_tprintf_initial_delay = 0;
1290         nmp->nm_fhsize = argp->fhsize;
1291         if (nmp->nm_fhsize > 0)
1292                 bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
1293         bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
1294         nmp->nm_nam = nam;
1295         /* Set up the sockets and per-host congestion */
1296         nmp->nm_sotype = argp->sotype;
1297         nmp->nm_soproto = argp->proto;
1298         nmp->nm_sockreq.nr_prog = NFS_PROG;
1299         if ((argp->flags & NFSMNT_NFSV4))
1300                 nmp->nm_sockreq.nr_vers = NFS_VER4;
1301         else if ((argp->flags & NFSMNT_NFSV3))
1302                 nmp->nm_sockreq.nr_vers = NFS_VER3;
1303         else
1304                 nmp->nm_sockreq.nr_vers = NFS_VER2;
1305
1306
1307         if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0)))
1308                 goto bad;
1309
1310         /*
1311          * A reference count is needed on the nfsnode representing the
1312          * remote root.  If this object is not persistent, then backward
1313          * traversals of the mount point (i.e. "..") will not work if
1314          * the nfsnode gets flushed out of the cache. Ufs does not have
1315          * this problem, because one can identify root inodes by their
1316          * number == ROOTINO (2).
1317          */
1318         if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) &&
1319             nmp->nm_dirpathlen > 0) {
1320                 /*
1321                  * If the fhsize on the mount point == 0 for V4, the mount
1322                  * path needs to be looked up.
1323                  */
1324                 trycnt = 3;
1325                 do {
1326                         error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
1327                             cred, td);
1328                         if (error)
1329                                 (void) nfs_catnap(PZERO, error, "nfsgetdirp");
1330                 } while (error && --trycnt > 0);
1331                 if (error) {
1332                         error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0);
1333                         goto bad;
1334                 }
1335         }
1336         if (nmp->nm_fhsize > 0) {
1337                 /*
1338                  * Set f_iosize to NFS_DIRBLKSIZ so that bo_bsize gets set
1339                  * non-zero for the root vnode. f_iosize will be set correctly
1340                  * by nfs_statfs() before any I/O occurs.
1341                  */
1342                 mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ;
1343                 error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np,
1344                     LK_EXCLUSIVE);
1345                 if (error)
1346                         goto bad;
1347                 *vpp = NFSTOV(np);
1348         
1349                 /*
1350                  * Get file attributes and transfer parameters for the
1351                  * mountpoint.  This has the side effect of filling in
1352                  * (*vpp)->v_type with the correct value.
1353                  */
1354                 ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1,
1355                     cred, td, &nfsva, NULL);
1356                 if (ret) {
1357                         /*
1358                          * Just set default values to get things going.
1359                          */
1360                         NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr));
1361                         nfsva.na_vattr.va_type = VDIR;
1362                         nfsva.na_vattr.va_mode = 0777;
1363                         nfsva.na_vattr.va_nlink = 100;
1364                         nfsva.na_vattr.va_uid = (uid_t)0;
1365                         nfsva.na_vattr.va_gid = (gid_t)0;
1366                         nfsva.na_vattr.va_fileid = 2;
1367                         nfsva.na_vattr.va_gen = 1;
1368                         nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE;
1369                         nfsva.na_vattr.va_size = 512 * 1024;
1370                 }
1371                 (void) nfscl_loadattrcache(vpp, &nfsva, NULL, NULL, 0, 1);
1372                 if (argp->flags & NFSMNT_NFSV3)
1373                         ncl_fsinfo(nmp, *vpp, cred, td);
1374         
1375                 /* Mark if the mount point supports NFSv4 ACLs. */
1376                 if ((argp->flags & NFSMNT_NFSV4) != 0 && nfsrv_useacl != 0 &&
1377                     ret == 0 &&
1378                     NFSISSET_ATTRBIT(&nfsva.na_suppattr, NFSATTRBIT_ACL)) {
1379                         MNT_ILOCK(mp);
1380                         mp->mnt_flag |= MNT_NFS4ACLS;
1381                         MNT_IUNLOCK(mp);
1382                 }
1383         
1384                 /*
1385                  * Lose the lock but keep the ref.
1386                  */
1387                 NFSVOPUNLOCK(*vpp, 0);
1388                 return (0);
1389         }
1390         error = EIO;
1391
1392 bad:
1393         newnfs_disconnect(&nmp->nm_sockreq);
1394         crfree(nmp->nm_sockreq.nr_cred);
1395         mtx_destroy(&nmp->nm_sockreq.nr_mtx);
1396         mtx_destroy(&nmp->nm_mtx);
1397         FREE(nmp, M_NEWNFSMNT);
1398         FREE(nam, M_SONAME);
1399         return (error);
1400 }
1401
1402 /*
1403  * unmount system call
1404  */
1405 static int
1406 nfs_unmount(struct mount *mp, int mntflags)
1407 {
1408         struct thread *td;
1409         struct nfsmount *nmp;
1410         int error, flags = 0, i, trycnt = 0;
1411
1412         td = curthread;
1413
1414         if (mntflags & MNT_FORCE)
1415                 flags |= FORCECLOSE;
1416         nmp = VFSTONFS(mp);
1417         /*
1418          * Goes something like this..
1419          * - Call vflush() to clear out vnodes for this filesystem
1420          * - Close the socket
1421          * - Free up the data structures
1422          */
1423         /* In the forced case, cancel any outstanding requests. */
1424         if (mntflags & MNT_FORCE) {
1425                 error = newnfs_nmcancelreqs(nmp);
1426                 if (error)
1427                         goto out;
1428                 /* For a forced close, get rid of the renew thread now */
1429                 nfscl_umount(nmp, td);
1430         }
1431         /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */
1432         do {
1433                 error = vflush(mp, 1, flags, td);
1434                 if ((mntflags & MNT_FORCE) && error != 0 && ++trycnt < 30)
1435                         (void) nfs_catnap(PSOCK, error, "newndm");
1436         } while ((mntflags & MNT_FORCE) && error != 0 && trycnt < 30);
1437         if (error)
1438                 goto out;
1439
1440         /*
1441          * We are now committed to the unmount.
1442          */
1443         if ((mntflags & MNT_FORCE) == 0)
1444                 nfscl_umount(nmp, td);
1445         /* Make sure no nfsiods are assigned to this mount. */
1446         mtx_lock(&ncl_iod_mutex);
1447         for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
1448                 if (ncl_iodmount[i] == nmp) {
1449                         ncl_iodwant[i] = NFSIOD_AVAILABLE;
1450                         ncl_iodmount[i] = NULL;
1451                 }
1452         mtx_unlock(&ncl_iod_mutex);
1453         newnfs_disconnect(&nmp->nm_sockreq);
1454         crfree(nmp->nm_sockreq.nr_cred);
1455         FREE(nmp->nm_nam, M_SONAME);
1456
1457         mtx_destroy(&nmp->nm_sockreq.nr_mtx);
1458         mtx_destroy(&nmp->nm_mtx);
1459         FREE(nmp, M_NEWNFSMNT);
1460 out:
1461         return (error);
1462 }
1463
1464 /*
1465  * Return root of a filesystem
1466  */
1467 static int
1468 nfs_root(struct mount *mp, int flags, struct vnode **vpp)
1469 {
1470         struct vnode *vp;
1471         struct nfsmount *nmp;
1472         struct nfsnode *np;
1473         int error;
1474
1475         nmp = VFSTONFS(mp);
1476         error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, flags);
1477         if (error)
1478                 return error;
1479         vp = NFSTOV(np);
1480         /*
1481          * Get transfer parameters and attributes for root vnode once.
1482          */
1483         mtx_lock(&nmp->nm_mtx);
1484         if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) {
1485                 mtx_unlock(&nmp->nm_mtx);
1486                 ncl_fsinfo(nmp, vp, curthread->td_ucred, curthread);
1487         } else 
1488                 mtx_unlock(&nmp->nm_mtx);
1489         if (vp->v_type == VNON)
1490             vp->v_type = VDIR;
1491         vp->v_vflag |= VV_ROOT;
1492         *vpp = vp;
1493         return (0);
1494 }
1495
1496 /*
1497  * Flush out the buffer cache
1498  */
1499 /* ARGSUSED */
1500 static int
1501 nfs_sync(struct mount *mp, int waitfor)
1502 {
1503         struct vnode *vp, *mvp;
1504         struct thread *td;
1505         int error, allerror = 0;
1506
1507         td = curthread;
1508
1509         MNT_ILOCK(mp);
1510         /*
1511          * If a forced dismount is in progress, return from here so that
1512          * the umount(2) syscall doesn't get stuck in VFS_SYNC() before
1513          * calling VFS_UNMOUNT().
1514          */
1515         if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1516                 MNT_IUNLOCK(mp);
1517                 return (EBADF);
1518         }
1519         MNT_IUNLOCK(mp);
1520
1521         /*
1522          * Force stale buffer cache information to be flushed.
1523          */
1524 loop:
1525         MNT_VNODE_FOREACH_ALL(vp, mp, mvp) {
1526                 /* XXX Racy bv_cnt check. */
1527                 if (NFSVOPISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0 ||
1528                     waitfor == MNT_LAZY) {
1529                         VI_UNLOCK(vp);
1530                         continue;
1531                 }
1532                 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) {
1533                         MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
1534                         goto loop;
1535                 }
1536                 error = VOP_FSYNC(vp, waitfor, td);
1537                 if (error)
1538                         allerror = error;
1539                 NFSVOPUNLOCK(vp, 0);
1540                 vrele(vp);
1541         }
1542         return (allerror);
1543 }
1544
1545 static int
1546 nfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req)
1547 {
1548         struct nfsmount *nmp = VFSTONFS(mp);
1549         struct vfsquery vq;
1550         int error;
1551
1552         bzero(&vq, sizeof(vq));
1553         switch (op) {
1554 #if 0
1555         case VFS_CTL_NOLOCKS:
1556                 val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0;
1557                 if (req->oldptr != NULL) {
1558                         error = SYSCTL_OUT(req, &val, sizeof(val));
1559                         if (error)
1560                                 return (error);
1561                 }
1562                 if (req->newptr != NULL) {
1563                         error = SYSCTL_IN(req, &val, sizeof(val));
1564                         if (error)
1565                                 return (error);
1566                         if (val)
1567                                 nmp->nm_flag |= NFSMNT_NOLOCKS;
1568                         else
1569                                 nmp->nm_flag &= ~NFSMNT_NOLOCKS;
1570                 }
1571                 break;
1572 #endif
1573         case VFS_CTL_QUERY:
1574                 mtx_lock(&nmp->nm_mtx);
1575                 if (nmp->nm_state & NFSSTA_TIMEO)
1576                         vq.vq_flags |= VQ_NOTRESP;
1577                 mtx_unlock(&nmp->nm_mtx);
1578 #if 0
1579                 if (!(nmp->nm_flag & NFSMNT_NOLOCKS) &&
1580                     (nmp->nm_state & NFSSTA_LOCKTIMEO))
1581                         vq.vq_flags |= VQ_NOTRESPLOCK;
1582 #endif
1583                 error = SYSCTL_OUT(req, &vq, sizeof(vq));
1584                 break;
1585         case VFS_CTL_TIMEO:
1586                 if (req->oldptr != NULL) {
1587                         error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay,
1588                             sizeof(nmp->nm_tprintf_initial_delay));
1589                         if (error)
1590                                 return (error);
1591                 }
1592                 if (req->newptr != NULL) {
1593                         error = vfs_suser(mp, req->td);
1594                         if (error)
1595                                 return (error);
1596                         error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay,
1597                             sizeof(nmp->nm_tprintf_initial_delay));
1598                         if (error)
1599                                 return (error);
1600                         if (nmp->nm_tprintf_initial_delay < 0)
1601                                 nmp->nm_tprintf_initial_delay = 0;
1602                 }
1603                 break;
1604         default:
1605                 return (ENOTSUP);
1606         }
1607         return (0);
1608 }
1609
1610 /*
1611  * Extract the information needed by the nlm from the nfs vnode.
1612  */
1613 static void
1614 nfs_getnlminfo(struct vnode *vp, uint8_t *fhp, size_t *fhlenp,
1615     struct sockaddr_storage *sp, int *is_v3p, off_t *sizep,
1616     struct timeval *timeop)
1617 {
1618         struct nfsmount *nmp;
1619         struct nfsnode *np = VTONFS(vp);
1620
1621         nmp = VFSTONFS(vp->v_mount);
1622         if (fhlenp != NULL)
1623                 *fhlenp = (size_t)np->n_fhp->nfh_len;
1624         if (fhp != NULL)
1625                 bcopy(np->n_fhp->nfh_fh, fhp, np->n_fhp->nfh_len);
1626         if (sp != NULL)
1627                 bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp)));
1628         if (is_v3p != NULL)
1629                 *is_v3p = NFS_ISV3(vp);
1630         if (sizep != NULL)
1631                 *sizep = np->n_size;
1632         if (timeop != NULL) {
1633                 timeop->tv_sec = nmp->nm_timeo / NFS_HZ;
1634                 timeop->tv_usec = (nmp->nm_timeo % NFS_HZ) * (1000000 / NFS_HZ);
1635         }
1636 }
1637
1638 /*
1639  * This function prints out an option name, based on the conditional
1640  * argument.
1641  */
1642 static __inline void nfscl_printopt(struct nfsmount *nmp, int testval,
1643     char *opt, char **buf, size_t *blen)
1644 {
1645         int len;
1646
1647         if (testval != 0 && *blen > strlen(opt)) {
1648                 len = snprintf(*buf, *blen, "%s", opt);
1649                 if (len != strlen(opt))
1650                         printf("EEK!!\n");
1651                 *buf += len;
1652                 *blen -= len;
1653         }
1654 }
1655
1656 /*
1657  * This function printf out an options integer value.
1658  */
1659 static __inline void nfscl_printoptval(struct nfsmount *nmp, int optval,
1660     char *opt, char **buf, size_t *blen)
1661 {
1662         int len;
1663
1664         if (*blen > strlen(opt) + 1) {
1665                 /* Could result in truncated output string. */
1666                 len = snprintf(*buf, *blen, "%s=%d", opt, optval);
1667                 if (len < *blen) {
1668                         *buf += len;
1669                         *blen -= len;
1670                 }
1671         }
1672 }
1673
1674 /*
1675  * Load the option flags and values into the buffer.
1676  */
1677 void nfscl_retopts(struct nfsmount *nmp, char *buffer, size_t buflen)
1678 {
1679         char *buf;
1680         size_t blen;
1681
1682         buf = buffer;
1683         blen = buflen;
1684         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV4) != 0, "nfsv4", &buf,
1685             &blen);
1686         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV3) != 0, "nfsv3", &buf,
1687             &blen);
1688         nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0,
1689             "nfsv2", &buf, &blen);
1690         nfscl_printopt(nmp, nmp->nm_sotype == SOCK_STREAM, ",tcp", &buf, &blen);
1691         nfscl_printopt(nmp, nmp->nm_sotype != SOCK_STREAM, ",udp", &buf, &blen);
1692         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RESVPORT) != 0, ",resvport",
1693             &buf, &blen);
1694         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCONN) != 0, ",noconn",
1695             &buf, &blen);
1696         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) == 0, ",hard", &buf,
1697             &blen);
1698         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) != 0, ",soft", &buf,
1699             &blen);
1700         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_INT) != 0, ",intr", &buf,
1701             &blen);
1702         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) == 0, ",cto", &buf,
1703             &blen);
1704         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) != 0, ",nocto", &buf,
1705             &blen);
1706         nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NOLOCKD | NFSMNT_NFSV4)) ==
1707             0, ",lockd", &buf, &blen);
1708         nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NOLOCKD | NFSMNT_NFSV4)) ==
1709             NFSMNT_NOLOCKD, ",nolockd", &buf, &blen);
1710         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RDIRPLUS) != 0, ",rdirplus",
1711             &buf, &blen);
1712         nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_KERB) == 0, ",sec=sys",
1713             &buf, &blen);
1714         nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
1715             NFSMNT_PRIVACY)) == NFSMNT_KERB, ",sec=krb5", &buf, &blen);
1716         nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
1717             NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_INTEGRITY), ",sec=krb5i",
1718             &buf, &blen);
1719         nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
1720             NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_PRIVACY), ",sec=krb5p",
1721             &buf, &blen);
1722         nfscl_printoptval(nmp, nmp->nm_acdirmin, ",acdirmin", &buf, &blen);
1723         nfscl_printoptval(nmp, nmp->nm_acdirmax, ",acdirmax", &buf, &blen);
1724         nfscl_printoptval(nmp, nmp->nm_acregmin, ",acregmin", &buf, &blen);
1725         nfscl_printoptval(nmp, nmp->nm_acregmax, ",acregmax", &buf, &blen);
1726         nfscl_printoptval(nmp, nmp->nm_nametimeo, ",nametimeo", &buf, &blen);
1727         nfscl_printoptval(nmp, nmp->nm_negnametimeo, ",negnametimeo", &buf,
1728             &blen);
1729         nfscl_printoptval(nmp, nmp->nm_rsize, ",rsize", &buf, &blen);
1730         nfscl_printoptval(nmp, nmp->nm_wsize, ",wsize", &buf, &blen);
1731         nfscl_printoptval(nmp, nmp->nm_readdirsize, ",readdirsize", &buf,
1732             &blen);
1733         nfscl_printoptval(nmp, nmp->nm_readahead, ",readahead", &buf, &blen);
1734         nfscl_printoptval(nmp, nmp->nm_wcommitsize, ",wcommitsize", &buf,
1735             &blen);
1736         nfscl_printoptval(nmp, nmp->nm_timeo, ",timeout", &buf, &blen);
1737         nfscl_printoptval(nmp, nmp->nm_retry, ",retrans", &buf, &blen);
1738 }
1739