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