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