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