2 * Copyright (c) 1989, 1993, 1995
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
32 * @(#)nfs_vfsops.c 8.12 (Berkeley) 5/20/95
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
39 #include "opt_bootp.h"
40 #include "opt_nfsroot.h"
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
48 #include <sys/limits.h>
50 #include <sys/malloc.h>
52 #include <sys/module.h>
53 #include <sys/mount.h>
55 #include <sys/socket.h>
56 #include <sys/socketvar.h>
57 #include <sys/sockio.h>
58 #include <sys/sysctl.h>
59 #include <sys/vnode.h>
60 #include <sys/signalvar.h>
63 #include <vm/vm_extern.h>
67 #include <net/route.h>
70 #include <netinet/in.h>
74 #include <nfs/nfsproto.h>
75 #include <nfsclient/nfs.h>
76 #include <nfsclient/nfsnode.h>
77 #include <nfsclient/nfsmount.h>
78 #include <nfs/xdr_subs.h>
79 #include <nfsclient/nfsm_subs.h>
80 #include <nfs/nfsdiskless.h>
82 FEATURE(nfsclient, "NFS client");
84 MALLOC_DEFINE(M_NFSREQ, "nfsclient_req", "NFS request header");
85 MALLOC_DEFINE(M_NFSBIGFH, "nfsclient_bigfh", "NFS version 3 file handle");
86 MALLOC_DEFINE(M_NFSDIROFF, "nfsclient_diroff", "NFS directory offset data");
87 MALLOC_DEFINE(M_NFSHASH, "nfsclient_hash", "NFS hash tables");
88 MALLOC_DEFINE(M_NFSDIRECTIO, "nfsclient_directio", "NFS Direct IO async write state");
90 uma_zone_t nfsmount_zone;
92 struct nfsstats nfsstats;
94 SYSCTL_NODE(_vfs, OID_AUTO, oldnfs, CTLFLAG_RW, 0, "Old NFS filesystem");
95 SYSCTL_STRUCT(_vfs_oldnfs, NFS_NFSSTATS, nfsstats, CTLFLAG_RW,
96 &nfsstats, nfsstats, "S,nfsstats");
97 static int nfs_ip_paranoia = 1;
98 SYSCTL_INT(_vfs_oldnfs, OID_AUTO, nfs_ip_paranoia, CTLFLAG_RW,
100 "Disallow accepting replies from IPs which differ from those sent");
103 SYSCTL_INT(_vfs_oldnfs, OID_AUTO, debug, CTLFLAG_RW, &nfs_debug, 0,
104 "Toggle debug flag");
106 static int nfs_tprintf_initial_delay = NFS_TPRINTF_INITIAL_DELAY;
107 SYSCTL_INT(_vfs_oldnfs, NFS_TPRINTF_INITIAL_DELAY,
108 downdelayinitial, CTLFLAG_RW, &nfs_tprintf_initial_delay, 0,
109 "Delay before printing \"nfs server not responding\" messages");
110 /* how long between console messages "nfs server foo not responding" */
111 static int nfs_tprintf_delay = NFS_TPRINTF_DELAY;
112 SYSCTL_INT(_vfs_oldnfs, NFS_TPRINTF_DELAY,
113 downdelayinterval, CTLFLAG_RW, &nfs_tprintf_delay, 0,
114 "Delay between printing \"nfs server not responding\" messages");
116 static void nfs_decode_args(struct mount *mp, struct nfsmount *nmp,
117 struct nfs_args *argp, const char *hostname);
118 static int mountnfs(struct nfs_args *, struct mount *,
119 struct sockaddr *, char *, struct vnode **,
120 struct ucred *cred, int);
121 static void nfs_getnlminfo(struct vnode *, uint8_t *, size_t *,
122 struct sockaddr_storage *, int *, off_t *,
124 static vfs_mount_t nfs_mount;
125 static vfs_cmount_t nfs_cmount;
126 static vfs_unmount_t nfs_unmount;
127 static vfs_root_t nfs_root;
128 static vfs_statfs_t nfs_statfs;
129 static vfs_sync_t nfs_sync;
130 static vfs_sysctl_t nfs_sysctl;
132 static int fake_wchan;
135 * nfs vfs operations.
137 static struct vfsops nfs_vfsops = {
138 .vfs_init = nfs_init,
139 .vfs_mount = nfs_mount,
140 .vfs_cmount = nfs_cmount,
141 .vfs_root = nfs_root,
142 .vfs_statfs = nfs_statfs,
143 .vfs_sync = nfs_sync,
144 .vfs_uninit = nfs_uninit,
145 .vfs_unmount = nfs_unmount,
146 .vfs_sysctl = nfs_sysctl,
148 VFS_SET(nfs_vfsops, oldnfs, VFCF_NETWORK);
150 /* So that loader and kldload(2) can find us, wherever we are.. */
151 MODULE_VERSION(oldnfs, 1);
152 MODULE_DEPEND(oldnfs, krpc, 1, 1, 1);
154 MODULE_DEPEND(oldnfs, kgssapi, 1, 1, 1);
156 MODULE_DEPEND(oldnfs, nfs_common, 1, 1, 1);
157 MODULE_DEPEND(oldnfs, nfslock, 1, 1, 1);
159 static struct nfs_rpcops nfs_rpcops = {
169 * This structure is now defined in sys/nfs/nfs_diskless.c so that it
170 * can be shared by both NFS clients. It is declared here so that it
171 * will be defined for kernels built without NFS_ROOT, although it
172 * isn't used in that case.
175 struct nfs_diskless nfs_diskless = { { { 0 } } };
176 struct nfsv3_diskless nfsv3_diskless = { { { 0 } } };
177 int nfs_diskless_valid = 0;
180 SYSCTL_INT(_vfs_oldnfs, OID_AUTO, diskless_valid, CTLFLAG_RD,
181 &nfs_diskless_valid, 0,
182 "Has the diskless struct been filled correctly");
184 SYSCTL_STRING(_vfs_oldnfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD,
185 nfsv3_diskless.root_hostnam, 0, "Path to nfs root");
187 SYSCTL_OPAQUE(_vfs_oldnfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD,
188 &nfsv3_diskless.root_saddr, sizeof nfsv3_diskless.root_saddr,
189 "%Ssockaddr_in", "Diskless root nfs address");
192 void nfsargs_ntoh(struct nfs_args *);
193 static int nfs_mountdiskless(char *,
194 struct sockaddr_in *, struct nfs_args *,
195 struct thread *, struct vnode **, struct mount *);
196 static void nfs_convert_diskless(void);
197 static void nfs_convert_oargs(struct nfs_args *args,
198 struct onfs_args *oargs);
201 nfs_iosize(struct nfsmount *nmp)
206 * Calculate the size used for io buffers. Use the larger
207 * of the two sizes to minimise nfs requests but make sure
208 * that it is at least one VM page to avoid wasting buffer
211 iosize = imax(nmp->nm_rsize, nmp->nm_wsize);
212 iosize = imax(iosize, PAGE_SIZE);
217 nfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs)
220 args->version = NFS_ARGSVERSION;
221 args->addr = oargs->addr;
222 args->addrlen = oargs->addrlen;
223 args->sotype = oargs->sotype;
224 args->proto = oargs->proto;
225 args->fh = oargs->fh;
226 args->fhsize = oargs->fhsize;
227 args->flags = oargs->flags;
228 args->wsize = oargs->wsize;
229 args->rsize = oargs->rsize;
230 args->readdirsize = oargs->readdirsize;
231 args->timeo = oargs->timeo;
232 args->retrans = oargs->retrans;
233 args->maxgrouplist = oargs->maxgrouplist;
234 args->readahead = oargs->readahead;
235 args->deadthresh = oargs->deadthresh;
236 args->hostname = oargs->hostname;
240 nfs_convert_diskless(void)
243 bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif,
244 sizeof(struct ifaliasreq));
245 bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway,
246 sizeof(struct sockaddr_in));
247 nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args);
248 if (nfsv3_diskless.root_args.flags & NFSMNT_NFSV3) {
249 nfsv3_diskless.root_fhsize = NFSX_V3FH;
250 bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_V3FH);
252 nfsv3_diskless.root_fhsize = NFSX_V2FH;
253 bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_V2FH);
255 bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr,
256 sizeof(struct sockaddr_in));
257 bcopy(nfs_diskless.root_hostnam, nfsv3_diskless.root_hostnam, MNAMELEN);
258 nfsv3_diskless.root_time = nfs_diskless.root_time;
259 bcopy(nfs_diskless.my_hostnam, nfsv3_diskless.my_hostnam,
261 nfs_diskless_valid = 3;
268 nfs_statfs(struct mount *mp, struct statfs *sbp)
272 struct nfs_statfs *sfp;
274 struct nfsmount *nmp = VFSTONFS(mp);
275 int error = 0, v3 = (nmp->nm_flag & NFSMNT_NFSV3), retattr;
276 struct mbuf *mreq, *mrep, *md, *mb;
284 error = vfs_busy(mp, MBF_NOWAIT);
287 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np, LK_EXCLUSIVE);
293 mtx_lock(&nmp->nm_mtx);
294 if (v3 && (nmp->nm_state & NFSSTA_GOTFSINFO) == 0) {
295 mtx_unlock(&nmp->nm_mtx);
296 (void)nfs_fsinfo(nmp, vp, td->td_ucred, td);
298 mtx_unlock(&nmp->nm_mtx);
299 nfsstats.rpccnt[NFSPROC_FSSTAT]++;
300 mreq = nfsm_reqhead(vp, NFSPROC_FSSTAT, NFSX_FH(v3));
302 bpos = mtod(mb, caddr_t);
304 nfsm_request(vp, NFSPROC_FSSTAT, td, td->td_ucred);
306 nfsm_postop_attr(vp, retattr);
312 sfp = nfsm_dissect(struct nfs_statfs *, NFSX_STATFS(v3));
313 mtx_lock(&nmp->nm_mtx);
314 sbp->f_iosize = nfs_iosize(nmp);
315 mtx_unlock(&nmp->nm_mtx);
317 sbp->f_bsize = NFS_FABLKSIZE;
318 tquad = fxdr_hyper(&sfp->sf_tbytes);
319 sbp->f_blocks = tquad / NFS_FABLKSIZE;
320 tquad = fxdr_hyper(&sfp->sf_fbytes);
321 sbp->f_bfree = tquad / NFS_FABLKSIZE;
322 tquad = fxdr_hyper(&sfp->sf_abytes);
323 sbp->f_bavail = tquad / NFS_FABLKSIZE;
324 sbp->f_files = (fxdr_unsigned(int32_t,
325 sfp->sf_tfiles.nfsuquad[1]) & 0x7fffffff);
326 sbp->f_ffree = (fxdr_unsigned(int32_t,
327 sfp->sf_ffiles.nfsuquad[1]) & 0x7fffffff);
329 sbp->f_bsize = fxdr_unsigned(int32_t, sfp->sf_bsize);
330 sbp->f_blocks = fxdr_unsigned(int32_t, sfp->sf_blocks);
331 sbp->f_bfree = fxdr_unsigned(int32_t, sfp->sf_bfree);
332 sbp->f_bavail = fxdr_unsigned(int32_t, sfp->sf_bavail);
344 * nfs version 3 fsinfo rpc call
347 nfs_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred,
350 struct nfsv3_fsinfo *fsp;
353 int error = 0, retattr;
354 struct mbuf *mreq, *mrep, *md, *mb;
357 nfsstats.rpccnt[NFSPROC_FSINFO]++;
358 mreq = nfsm_reqhead(vp, NFSPROC_FSINFO, NFSX_FH(1));
360 bpos = mtod(mb, caddr_t);
362 nfsm_request(vp, NFSPROC_FSINFO, td, cred);
363 nfsm_postop_attr(vp, retattr);
365 fsp = nfsm_dissect(struct nfsv3_fsinfo *, NFSX_V3FSINFO);
366 pref = fxdr_unsigned(u_int32_t, fsp->fs_wtpref);
367 mtx_lock(&nmp->nm_mtx);
368 if (pref < nmp->nm_wsize && pref >= NFS_FABLKSIZE)
369 nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) &
370 ~(NFS_FABLKSIZE - 1);
371 max = fxdr_unsigned(u_int32_t, fsp->fs_wtmax);
372 if (max < nmp->nm_wsize && max > 0) {
373 nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1);
374 if (nmp->nm_wsize == 0)
377 pref = fxdr_unsigned(u_int32_t, fsp->fs_rtpref);
378 if (pref < nmp->nm_rsize && pref >= NFS_FABLKSIZE)
379 nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) &
380 ~(NFS_FABLKSIZE - 1);
381 max = fxdr_unsigned(u_int32_t, fsp->fs_rtmax);
382 if (max < nmp->nm_rsize && max > 0) {
383 nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1);
384 if (nmp->nm_rsize == 0)
387 pref = fxdr_unsigned(u_int32_t, fsp->fs_dtpref);
388 if (pref < nmp->nm_readdirsize && pref >= NFS_DIRBLKSIZ)
389 nmp->nm_readdirsize = (pref + NFS_DIRBLKSIZ - 1) &
390 ~(NFS_DIRBLKSIZ - 1);
391 if (max < nmp->nm_readdirsize && max > 0) {
392 nmp->nm_readdirsize = max & ~(NFS_DIRBLKSIZ - 1);
393 if (nmp->nm_readdirsize == 0)
394 nmp->nm_readdirsize = max;
396 maxfsize = fxdr_hyper(&fsp->fs_maxfilesize);
397 if (maxfsize > 0 && maxfsize < nmp->nm_maxfilesize)
398 nmp->nm_maxfilesize = maxfsize;
399 nmp->nm_mountp->mnt_stat.f_iosize = nfs_iosize(nmp);
400 nmp->nm_state |= NFSSTA_GOTFSINFO;
401 mtx_unlock(&nmp->nm_mtx);
409 * Mount a remote root fs via. nfs. This depends on the info in the
410 * nfs_diskless structure that has been filled in properly by some primary
412 * It goes something like this:
413 * - do enough of "ifconfig" by calling ifioctl() so that the system
414 * can talk to the server
415 * - If nfs_diskless.mygateway is filled in, use that address as
417 * - build the rootfs mount point and call mountnfs() to do the rest.
419 * It is assumed to be safe to read, modify, and write the nfsv3_diskless
420 * structure, as well as other global NFS client variables here, as
421 * nfs_mountroot() will be called once in the boot before any other NFS
422 * client activity occurs.
425 nfs_mountroot(struct mount *mp)
427 struct thread *td = curthread;
428 struct nfsv3_diskless *nd = &nfsv3_diskless;
438 #if defined(BOOTP_NFSROOT) && defined(BOOTP)
439 bootpc_init(); /* use bootp to get nfs_diskless filled in */
440 #elif defined(NFS_ROOT)
441 nfs_setup_diskless();
444 if (nfs_diskless_valid == 0) {
447 if (nfs_diskless_valid == 1)
448 nfs_convert_diskless();
451 * XXX splnet, so networks will receive...
456 * Do enough of ifconfig(8) so that the critical net interface can
457 * talk to the server.
459 error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0,
462 panic("nfs_mountroot: socreate(%04x): %d",
463 nd->myif.ifra_addr.sa_family, error);
465 #if 0 /* XXX Bad idea */
467 * We might not have been told the right interface, so we pass
468 * over the first ten interfaces of the same kind, until we get
469 * one of them configured.
472 for (i = strlen(nd->myif.ifra_name) - 1;
473 nd->myif.ifra_name[i] >= '0' &&
474 nd->myif.ifra_name[i] <= '9';
475 nd->myif.ifra_name[i] ++) {
476 error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
482 error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
484 panic("nfs_mountroot: SIOCAIFADDR: %d", error);
486 if ((cp = getenv("boot.netif.mtu")) != NULL) {
487 ir.ifr_mtu = strtol(cp, NULL, 10);
488 bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ);
490 error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td);
492 printf("nfs_mountroot: SIOCSIFMTU: %d", error);
497 * If the gateway field is filled in, set it as the default route.
498 * Note that pxeboot will set a default route of 0 if the route
499 * is not set by the DHCP server. Check also for a value of 0
500 * to avoid panicking inappropriately in that situation.
502 if (nd->mygateway.sin_len != 0 &&
503 nd->mygateway.sin_addr.s_addr != 0) {
504 struct sockaddr_in mask, sin;
506 bzero((caddr_t)&mask, sizeof(mask));
508 sin.sin_family = AF_INET;
509 sin.sin_len = sizeof(sin);
510 /* XXX MRT use table 0 for this sort of thing */
511 CURVNET_SET(TD_TO_VNET(td));
512 error = rtrequest(RTM_ADD, (struct sockaddr *)&sin,
513 (struct sockaddr *)&nd->mygateway,
514 (struct sockaddr *)&mask,
515 RTF_UP | RTF_GATEWAY, NULL);
518 panic("nfs_mountroot: RTM_ADD: %d", error);
522 * Create the rootfs mount point.
524 nd->root_args.fh = nd->root_fh;
525 nd->root_args.fhsize = nd->root_fhsize;
526 l = ntohl(nd->root_saddr.sin_addr.s_addr);
527 snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s",
528 (l >> 24) & 0xff, (l >> 16) & 0xff,
529 (l >> 8) & 0xff, (l >> 0) & 0xff, nd->root_hostnam);
530 printf("NFS ROOT: %s\n", buf);
531 nd->root_args.hostname = buf;
532 if ((error = nfs_mountdiskless(buf,
533 &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) {
538 * This is not really an nfs issue, but it is much easier to
539 * set hostname here and then let the "/etc/rc.xxx" files
540 * mount the right /var based upon its preset value.
542 mtx_lock(&prison0.pr_mtx);
543 strlcpy(prison0.pr_hostname, nd->my_hostnam,
544 sizeof (prison0.pr_hostname));
545 mtx_unlock(&prison0.pr_mtx);
546 inittodr(ntohl(nd->root_time));
551 * Internal version of mount system call for diskless setup.
554 nfs_mountdiskless(char *path,
555 struct sockaddr_in *sin, struct nfs_args *args, struct thread *td,
556 struct vnode **vpp, struct mount *mp)
558 struct sockaddr *nam;
561 nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK);
562 if ((error = mountnfs(args, mp, nam, path, vpp,
563 td->td_ucred, NFS_DEFAULT_NEGNAMETIMEO)) != 0) {
564 printf("nfs_mountroot: mount %s on /: %d\n", path, error);
571 nfs_sec_name_to_num(char *sec)
573 if (!strcmp(sec, "krb5"))
574 return (RPCSEC_GSS_KRB5);
575 if (!strcmp(sec, "krb5i"))
576 return (RPCSEC_GSS_KRB5I);
577 if (!strcmp(sec, "krb5p"))
578 return (RPCSEC_GSS_KRB5P);
579 if (!strcmp(sec, "sys"))
582 * Userland should validate the string but we will try and
583 * cope with unexpected values.
589 nfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp,
590 const char *hostname)
602 * Set read-only flag if requested; otherwise, clear it if this is
603 * an update. If this is not an update, then either the read-only
604 * flag is already clear, or this is a root mount and it was set
605 * intentionally at some previous point.
607 if (vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL) == 0) {
609 mp->mnt_flag |= MNT_RDONLY;
611 } else if (mp->mnt_flag & MNT_UPDATE) {
613 mp->mnt_flag &= ~MNT_RDONLY;
618 * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes
619 * no sense in that context. Also, set up appropriate retransmit
620 * and soft timeout behavior.
622 if (argp->sotype == SOCK_STREAM) {
623 nmp->nm_flag &= ~NFSMNT_NOCONN;
624 nmp->nm_flag |= NFSMNT_DUMBTIMR;
625 nmp->nm_timeo = NFS_MAXTIMEO;
626 nmp->nm_retry = NFS_RETRANS_TCP;
629 /* Also clear RDIRPLUS if not NFSv3, it crashes some servers */
630 if ((argp->flags & NFSMNT_NFSV3) == 0)
631 nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
633 /* Re-bind if rsrvd port requested and wasn't on one */
634 adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT)
635 && (argp->flags & NFSMNT_RESVPORT);
636 /* Also re-bind if we're switching to/from a connected UDP socket */
637 adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) !=
638 (argp->flags & NFSMNT_NOCONN));
640 /* Update flags atomically. Don't change the lock bits. */
641 nmp->nm_flag = argp->flags | nmp->nm_flag;
644 if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
645 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
646 if (nmp->nm_timeo < NFS_MINTIMEO)
647 nmp->nm_timeo = NFS_MINTIMEO;
648 else if (nmp->nm_timeo > NFS_MAXTIMEO)
649 nmp->nm_timeo = NFS_MAXTIMEO;
652 if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
653 nmp->nm_retry = argp->retrans;
654 if (nmp->nm_retry > NFS_MAXREXMIT)
655 nmp->nm_retry = NFS_MAXREXMIT;
658 if (argp->flags & NFSMNT_NFSV3) {
659 if (argp->sotype == SOCK_DGRAM)
660 maxio = NFS_MAXDGRAMDATA;
664 maxio = NFS_V2MAXDATA;
666 if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
667 nmp->nm_wsize = argp->wsize;
668 /* Round down to multiple of blocksize */
669 nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
670 if (nmp->nm_wsize <= 0)
671 nmp->nm_wsize = NFS_FABLKSIZE;
673 if (nmp->nm_wsize > maxio)
674 nmp->nm_wsize = maxio;
675 if (nmp->nm_wsize > MAXBSIZE)
676 nmp->nm_wsize = MAXBSIZE;
678 if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
679 nmp->nm_rsize = argp->rsize;
680 /* Round down to multiple of blocksize */
681 nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
682 if (nmp->nm_rsize <= 0)
683 nmp->nm_rsize = NFS_FABLKSIZE;
685 if (nmp->nm_rsize > maxio)
686 nmp->nm_rsize = maxio;
687 if (nmp->nm_rsize > MAXBSIZE)
688 nmp->nm_rsize = MAXBSIZE;
690 if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
691 nmp->nm_readdirsize = argp->readdirsize;
693 if (nmp->nm_readdirsize > maxio)
694 nmp->nm_readdirsize = maxio;
695 if (nmp->nm_readdirsize > nmp->nm_rsize)
696 nmp->nm_readdirsize = nmp->nm_rsize;
698 if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0)
699 nmp->nm_acregmin = argp->acregmin;
701 nmp->nm_acregmin = NFS_MINATTRTIMO;
702 if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0)
703 nmp->nm_acregmax = argp->acregmax;
705 nmp->nm_acregmax = NFS_MAXATTRTIMO;
706 if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0)
707 nmp->nm_acdirmin = argp->acdirmin;
709 nmp->nm_acdirmin = NFS_MINDIRATTRTIMO;
710 if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0)
711 nmp->nm_acdirmax = argp->acdirmax;
713 nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO;
714 if (nmp->nm_acdirmin > nmp->nm_acdirmax)
715 nmp->nm_acdirmin = nmp->nm_acdirmax;
716 if (nmp->nm_acregmin > nmp->nm_acregmax)
717 nmp->nm_acregmin = nmp->nm_acregmax;
719 if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0) {
720 if (argp->maxgrouplist <= NFS_MAXGRPS)
721 nmp->nm_numgrps = argp->maxgrouplist;
723 nmp->nm_numgrps = NFS_MAXGRPS;
725 if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) {
726 if (argp->readahead <= NFS_MAXRAHEAD)
727 nmp->nm_readahead = argp->readahead;
729 nmp->nm_readahead = NFS_MAXRAHEAD;
731 if ((argp->flags & NFSMNT_WCOMMITSIZE) && argp->wcommitsize >= 0) {
732 if (argp->wcommitsize < nmp->nm_wsize)
733 nmp->nm_wcommitsize = nmp->nm_wsize;
735 nmp->nm_wcommitsize = argp->wcommitsize;
737 if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 0) {
738 if (argp->deadthresh <= NFS_MAXDEADTHRESH)
739 nmp->nm_deadthresh = argp->deadthresh;
741 nmp->nm_deadthresh = NFS_MAXDEADTHRESH;
744 adjsock |= ((nmp->nm_sotype != argp->sotype) ||
745 (nmp->nm_soproto != argp->proto));
746 nmp->nm_sotype = argp->sotype;
747 nmp->nm_soproto = argp->proto;
749 if (nmp->nm_client && adjsock) {
750 nfs_safedisconnect(nmp);
751 if (nmp->nm_sotype == SOCK_DGRAM)
752 while (nfs_connect(nmp)) {
753 printf("nfs_args: retrying connect\n");
754 (void) tsleep(&fake_wchan, PSOCK, "nfscon", hz);
759 strlcpy(nmp->nm_hostname, hostname,
760 sizeof(nmp->nm_hostname));
761 p = strchr(nmp->nm_hostname, ':');
766 if (vfs_getopt(mp->mnt_optnew, "sec",
767 (void **) &secname, NULL) == 0) {
768 nmp->nm_secflavor = nfs_sec_name_to_num(secname);
770 nmp->nm_secflavor = AUTH_SYS;
773 if (vfs_getopt(mp->mnt_optnew, "principal",
774 (void **) &principal, NULL) == 0) {
775 strlcpy(nmp->nm_principal, principal,
776 sizeof(nmp->nm_principal));
778 snprintf(nmp->nm_principal, sizeof(nmp->nm_principal),
779 "nfs@%s", nmp->nm_hostname);
783 static const char *nfs_opts[] = { "from", "nfs_args",
784 "noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union",
785 "noclusterr", "noclusterw", "multilabel", "acls", "force", "update",
786 "async", "dumbtimer", "noconn", "nolockd", "intr", "rdirplus", "resvport",
787 "readahead", "readdirsize", "soft", "hard", "mntudp", "tcp", "udp",
788 "wsize", "rsize", "retrans", "acregmin", "acregmax", "acdirmin",
789 "acdirmax", "deadthresh", "hostname", "timeout", "addr", "fh", "nfsv3",
790 "sec", "maxgroups", "principal", "negnametimeo", "nocto", "wcommitsize",
797 * It seems a bit dumb to copyinstr() the host and path here and then
798 * bcopy() them in mountnfs(), but I wanted to detect errors before
799 * doing the sockargs() call because sockargs() allocates an mbuf and
800 * an error after that means that I have to release the mbuf.
804 nfs_mount(struct mount *mp)
806 struct nfs_args args = {
807 .version = NFS_ARGSVERSION,
809 .addrlen = sizeof (struct sockaddr_in),
810 .sotype = SOCK_STREAM,
814 .flags = NFSMNT_RESVPORT,
817 .readdirsize = NFS_READDIRSIZE,
819 .retrans = NFS_RETRANS,
820 .maxgrouplist = NFS_MAXGRPS,
821 .readahead = NFS_DEFRAHEAD,
822 .wcommitsize = 0, /* was: NQ_DEFLEASE */
823 .deadthresh = NFS_MAXDEADTHRESH, /* was: NQ_DEADTHRESH */
826 .acregmin = NFS_MINATTRTIMO,
827 .acregmax = NFS_MAXATTRTIMO,
828 .acdirmin = NFS_MINDIRATTRTIMO,
829 .acdirmax = NFS_MAXDIRATTRTIMO,
831 int error, ret, has_nfs_args_opt;
832 int has_addr_opt, has_fh_opt, has_hostname_opt;
833 struct sockaddr *nam;
837 u_char nfh[NFSX_V3FHMAX];
839 int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO;
841 has_nfs_args_opt = 0;
844 has_hostname_opt = 0;
846 if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) {
851 if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS) {
852 error = nfs_mountroot(mp);
857 * The old mount_nfs program passed the struct nfs_args
858 * from userspace to kernel. The new mount_nfs program
859 * passes string options via nmount() from userspace to kernel
860 * and we populate the struct nfs_args in the kernel.
862 if (vfs_getopt(mp->mnt_optnew, "nfs_args", NULL, NULL) == 0) {
863 error = vfs_copyopt(mp->mnt_optnew, "nfs_args", &args,
868 if (args.version != NFS_ARGSVERSION) {
869 error = EPROGMISMATCH;
872 has_nfs_args_opt = 1;
875 if (vfs_getopt(mp->mnt_optnew, "dumbtimer", NULL, NULL) == 0)
876 args.flags |= NFSMNT_DUMBTIMR;
877 if (vfs_getopt(mp->mnt_optnew, "noconn", NULL, NULL) == 0)
878 args.flags |= NFSMNT_NOCONN;
879 if (vfs_getopt(mp->mnt_optnew, "conn", NULL, NULL) == 0)
880 args.flags |= NFSMNT_NOCONN;
881 if (vfs_getopt(mp->mnt_optnew, "nolockd", NULL, NULL) == 0)
882 args.flags |= NFSMNT_NOLOCKD;
883 if (vfs_getopt(mp->mnt_optnew, "lockd", NULL, NULL) == 0)
884 args.flags &= ~NFSMNT_NOLOCKD;
885 if (vfs_getopt(mp->mnt_optnew, "intr", NULL, NULL) == 0)
886 args.flags |= NFSMNT_INT;
887 if (vfs_getopt(mp->mnt_optnew, "rdirplus", NULL, NULL) == 0)
888 args.flags |= NFSMNT_RDIRPLUS;
889 if (vfs_getopt(mp->mnt_optnew, "resvport", NULL, NULL) == 0)
890 args.flags |= NFSMNT_RESVPORT;
891 if (vfs_getopt(mp->mnt_optnew, "noresvport", NULL, NULL) == 0)
892 args.flags &= ~NFSMNT_RESVPORT;
893 if (vfs_getopt(mp->mnt_optnew, "soft", NULL, NULL) == 0)
894 args.flags |= NFSMNT_SOFT;
895 if (vfs_getopt(mp->mnt_optnew, "hard", NULL, NULL) == 0)
896 args.flags &= ~NFSMNT_SOFT;
897 if (vfs_getopt(mp->mnt_optnew, "mntudp", NULL, NULL) == 0)
898 args.sotype = SOCK_DGRAM;
899 if (vfs_getopt(mp->mnt_optnew, "udp", NULL, NULL) == 0)
900 args.sotype = SOCK_DGRAM;
901 if (vfs_getopt(mp->mnt_optnew, "tcp", NULL, NULL) == 0)
902 args.sotype = SOCK_STREAM;
903 if (vfs_getopt(mp->mnt_optnew, "nfsv3", NULL, NULL) == 0)
904 args.flags |= NFSMNT_NFSV3;
905 if (vfs_getopt(mp->mnt_optnew, "nocto", NULL, NULL) == 0)
906 args.flags |= NFSMNT_NOCTO;
907 if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) {
909 vfs_mount_error(mp, "illegal readdirsize");
913 ret = sscanf(opt, "%d", &args.readdirsize);
914 if (ret != 1 || args.readdirsize <= 0) {
915 vfs_mount_error(mp, "illegal readdirsize: %s",
920 args.flags |= NFSMNT_READDIRSIZE;
922 if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) {
924 vfs_mount_error(mp, "illegal readahead");
928 ret = sscanf(opt, "%d", &args.readahead);
929 if (ret != 1 || args.readahead <= 0) {
930 vfs_mount_error(mp, "illegal readahead: %s",
935 args.flags |= NFSMNT_READAHEAD;
937 if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) {
939 vfs_mount_error(mp, "illegal wsize");
943 ret = sscanf(opt, "%d", &args.wsize);
944 if (ret != 1 || args.wsize <= 0) {
945 vfs_mount_error(mp, "illegal wsize: %s",
950 args.flags |= NFSMNT_WSIZE;
952 if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) {
954 vfs_mount_error(mp, "illegal rsize");
958 ret = sscanf(opt, "%d", &args.rsize);
959 if (ret != 1 || args.rsize <= 0) {
960 vfs_mount_error(mp, "illegal wsize: %s",
965 args.flags |= NFSMNT_RSIZE;
967 if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) {
969 vfs_mount_error(mp, "illegal retrans");
973 ret = sscanf(opt, "%d", &args.retrans);
974 if (ret != 1 || args.retrans <= 0) {
975 vfs_mount_error(mp, "illegal retrans: %s",
980 args.flags |= NFSMNT_RETRANS;
982 if (vfs_getopt(mp->mnt_optnew, "acregmin", (void **)&opt, NULL) == 0) {
983 ret = sscanf(opt, "%d", &args.acregmin);
984 if (ret != 1 || args.acregmin < 0) {
985 vfs_mount_error(mp, "illegal acregmin: %s",
990 args.flags |= NFSMNT_ACREGMIN;
992 if (vfs_getopt(mp->mnt_optnew, "acregmax", (void **)&opt, NULL) == 0) {
993 ret = sscanf(opt, "%d", &args.acregmax);
994 if (ret != 1 || args.acregmax < 0) {
995 vfs_mount_error(mp, "illegal acregmax: %s",
1000 args.flags |= NFSMNT_ACREGMAX;
1002 if (vfs_getopt(mp->mnt_optnew, "acdirmin", (void **)&opt, NULL) == 0) {
1003 ret = sscanf(opt, "%d", &args.acdirmin);
1004 if (ret != 1 || args.acdirmin < 0) {
1005 vfs_mount_error(mp, "illegal acdirmin: %s",
1010 args.flags |= NFSMNT_ACDIRMIN;
1012 if (vfs_getopt(mp->mnt_optnew, "acdirmax", (void **)&opt, NULL) == 0) {
1013 ret = sscanf(opt, "%d", &args.acdirmax);
1014 if (ret != 1 || args.acdirmax < 0) {
1015 vfs_mount_error(mp, "illegal acdirmax: %s",
1020 args.flags |= NFSMNT_ACDIRMAX;
1022 if (vfs_getopt(mp->mnt_optnew, "wcommitsize", (void **)&opt, NULL) == 0) {
1023 ret = sscanf(opt, "%d", &args.wcommitsize);
1024 if (ret != 1 || args.wcommitsize < 0) {
1025 vfs_mount_error(mp, "illegal wcommitsize: %s", opt);
1029 args.flags |= NFSMNT_WCOMMITSIZE;
1031 if (vfs_getopt(mp->mnt_optnew, "deadthresh", (void **)&opt, NULL) == 0) {
1032 ret = sscanf(opt, "%d", &args.deadthresh);
1033 if (ret != 1 || args.deadthresh <= 0) {
1034 vfs_mount_error(mp, "illegal deadthresh: %s",
1039 args.flags |= NFSMNT_DEADTHRESH;
1041 if (vfs_getopt(mp->mnt_optnew, "timeout", (void **)&opt, NULL) == 0) {
1042 ret = sscanf(opt, "%d", &args.timeo);
1043 if (ret != 1 || args.timeo <= 0) {
1044 vfs_mount_error(mp, "illegal timeout: %s",
1049 args.flags |= NFSMNT_TIMEO;
1051 if (vfs_getopt(mp->mnt_optnew, "maxgroups", (void **)&opt, NULL) == 0) {
1052 ret = sscanf(opt, "%d", &args.maxgrouplist);
1053 if (ret != 1 || args.maxgrouplist <= 0) {
1054 vfs_mount_error(mp, "illegal maxgroups: %s",
1059 args.flags |= NFSMNT_MAXGRPS;
1061 if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL)
1063 ret = sscanf(opt, "%d", &negnametimeo);
1064 if (ret != 1 || negnametimeo < 0) {
1065 vfs_mount_error(mp, "illegal negnametimeo: %s",
1071 if (vfs_getopt(mp->mnt_optnew, "addr", (void **)&args.addr,
1072 &args.addrlen) == 0) {
1074 if (args.addrlen > SOCK_MAXADDRLEN) {
1075 error = ENAMETOOLONG;
1078 nam = malloc(args.addrlen, M_SONAME,
1080 bcopy(args.addr, nam, args.addrlen);
1081 nam->sa_len = args.addrlen;
1083 if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh,
1084 &args.fhsize) == 0) {
1087 if (vfs_getopt(mp->mnt_optnew, "hostname", (void **)&args.hostname,
1089 has_hostname_opt = 1;
1091 if (args.hostname == NULL) {
1092 vfs_mount_error(mp, "Invalid hostname");
1096 if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX) {
1097 vfs_mount_error(mp, "Bad file handle");
1102 if (mp->mnt_flag & MNT_UPDATE) {
1103 struct nfsmount *nmp = VFSTONFS(mp);
1110 * When doing an update, we can't change from or to
1111 * v3, switch lockd strategies or change cookie translation
1113 args.flags = (args.flags &
1114 ~(NFSMNT_NFSV3 | NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) |
1116 (NFSMNT_NFSV3 | NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/));
1117 nfs_decode_args(mp, nmp, &args, NULL);
1122 * Make the nfs_ip_paranoia sysctl serve as the default connection
1123 * or no-connection mode for those protocols that support
1124 * no-connection mode (the flag will be cleared later for protocols
1125 * that do not support no-connection mode). This will allow a client
1126 * to receive replies from a different IP then the request was
1127 * sent to. Note: default value for nfs_ip_paranoia is 1 (paranoid),
1130 if (nfs_ip_paranoia == 0)
1131 args.flags |= NFSMNT_NOCONN;
1133 if (has_nfs_args_opt) {
1135 * In the 'nfs_args' case, the pointers in the args
1136 * structure are in userland - we copy them in here.
1139 error = copyin((caddr_t)args.fh, (caddr_t)nfh,
1146 if (!has_hostname_opt) {
1147 error = copyinstr(args.hostname, hst, MNAMELEN-1, &len);
1151 bzero(&hst[len], MNAMELEN - len);
1152 args.hostname = hst;
1154 if (!has_addr_opt) {
1155 /* sockargs() call must be after above copyin() calls */
1156 error = getsockaddr(&nam, (caddr_t)args.addr,
1162 } else if (has_addr_opt == 0) {
1163 vfs_mount_error(mp, "No server address");
1167 error = mountnfs(&args, mp, nam, args.hostname, &vp,
1168 curthread->td_ucred, negnametimeo);
1172 mp->mnt_kern_flag |= (MNTK_MPSAFE|MNTK_LOOKUP_SHARED);
1183 * It seems a bit dumb to copyinstr() the host and path here and then
1184 * bcopy() them in mountnfs(), but I wanted to detect errors before
1185 * doing the sockargs() call because sockargs() allocates an mbuf and
1186 * an error after that means that I have to release the mbuf.
1190 nfs_cmount(struct mntarg *ma, void *data, int flags)
1193 struct nfs_args args;
1195 error = copyin(data, &args, sizeof (struct nfs_args));
1199 ma = mount_arg(ma, "nfs_args", &args, sizeof args);
1201 error = kernel_mount(ma, flags);
1206 * Common code for mount and mountroot
1209 mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
1210 char *hst, struct vnode **vpp, struct ucred *cred, int negnametimeo)
1212 struct nfsmount *nmp;
1217 if (mp->mnt_flag & MNT_UPDATE) {
1219 printf("%s: MNT_UPDATE is no longer handled here\n", __func__);
1220 free(nam, M_SONAME);
1223 nmp = uma_zalloc(nfsmount_zone, M_WAITOK);
1224 bzero((caddr_t)nmp, sizeof (struct nfsmount));
1225 TAILQ_INIT(&nmp->nm_bufq);
1227 nmp->nm_getinfo = nfs_getnlminfo;
1228 nmp->nm_vinvalbuf = nfs_vinvalbuf;
1231 nmp->nm_mountp = mp;
1232 mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF);
1235 * V2 can only handle 32 bit filesizes. A 4GB-1 limit may be too
1236 * high, depending on whether we end up with negative offsets in
1237 * the client or server somewhere. 2GB-1 may be safer.
1239 * For V3, nfs_fsinfo will adjust this as necessary. Assume maximum
1240 * that we can handle until we find out otherwise.
1242 if ((argp->flags & NFSMNT_NFSV3) == 0)
1243 nmp->nm_maxfilesize = 0xffffffffLL;
1245 nmp->nm_maxfilesize = OFF_MAX;
1247 nmp->nm_timeo = NFS_TIMEO;
1248 nmp->nm_retry = NFS_RETRANS;
1249 if ((argp->flags & NFSMNT_NFSV3) && argp->sotype == SOCK_STREAM) {
1250 nmp->nm_wsize = nmp->nm_rsize = NFS_MAXDATA;
1252 nmp->nm_wsize = NFS_WSIZE;
1253 nmp->nm_rsize = NFS_RSIZE;
1255 nmp->nm_wcommitsize = hibufspace / (desiredvnodes / 1000);
1256 nmp->nm_readdirsize = NFS_READDIRSIZE;
1257 nmp->nm_numgrps = NFS_MAXGRPS;
1258 nmp->nm_readahead = NFS_DEFRAHEAD;
1259 nmp->nm_deadthresh = NFS_MAXDEADTHRESH;
1260 nmp->nm_negnametimeo = negnametimeo;
1261 nmp->nm_tprintf_delay = nfs_tprintf_delay;
1262 if (nmp->nm_tprintf_delay < 0)
1263 nmp->nm_tprintf_delay = 0;
1264 nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay;
1265 if (nmp->nm_tprintf_initial_delay < 0)
1266 nmp->nm_tprintf_initial_delay = 0;
1267 nmp->nm_fhsize = argp->fhsize;
1268 bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
1269 bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
1271 /* Set up the sockets and per-host congestion */
1272 nmp->nm_sotype = argp->sotype;
1273 nmp->nm_soproto = argp->proto;
1274 nmp->nm_rpcops = &nfs_rpcops;
1276 nfs_decode_args(mp, nmp, argp, hst);
1279 * For Connection based sockets (TCP,...) defer the connect until
1280 * the first request, in case the server is not responding.
1282 if (nmp->nm_sotype == SOCK_DGRAM &&
1283 (error = nfs_connect(nmp)))
1287 * This is silly, but it has to be set so that vinifod() works.
1288 * We do not want to do an nfs_statfs() here since we can get
1289 * stuck on a dead server and we are holding a lock on the mount
1292 mtx_lock(&nmp->nm_mtx);
1293 mp->mnt_stat.f_iosize = nfs_iosize(nmp);
1294 mtx_unlock(&nmp->nm_mtx);
1296 * A reference count is needed on the nfsnode representing the
1297 * remote root. If this object is not persistent, then backward
1298 * traversals of the mount point (i.e. "..") will not work if
1299 * the nfsnode gets flushed out of the cache. Ufs does not have
1300 * this problem, because one can identify root inodes by their
1301 * number == ROOTINO (2).
1303 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np, LK_EXCLUSIVE);
1309 * Get file attributes and transfer parameters for the
1310 * mountpoint. This has the side effect of filling in
1311 * (*vpp)->v_type with the correct value.
1313 if (argp->flags & NFSMNT_NFSV3)
1314 nfs_fsinfo(nmp, *vpp, curthread->td_ucred, curthread);
1316 VOP_GETATTR(*vpp, &attrs, curthread->td_ucred);
1319 * Lose the lock but keep the ref.
1321 VOP_UNLOCK(*vpp, 0);
1325 nfs_disconnect(nmp);
1326 mtx_destroy(&nmp->nm_mtx);
1327 uma_zfree(nfsmount_zone, nmp);
1328 free(nam, M_SONAME);
1333 * unmount system call
1336 nfs_unmount(struct mount *mp, int mntflags)
1338 struct nfsmount *nmp;
1339 int error, flags = 0;
1341 if (mntflags & MNT_FORCE)
1342 flags |= FORCECLOSE;
1345 * Goes something like this..
1346 * - Call vflush() to clear out vnodes for this filesystem
1347 * - Close the socket
1348 * - Free up the data structures
1350 /* In the forced case, cancel any outstanding requests. */
1351 if (flags & FORCECLOSE) {
1352 error = nfs_nmcancelreqs(nmp);
1356 /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */
1357 error = vflush(mp, 1, flags, curthread);
1362 * We are now committed to the unmount.
1364 nfs_disconnect(nmp);
1365 free(nmp->nm_nam, M_SONAME);
1367 mtx_destroy(&nmp->nm_mtx);
1368 uma_zfree(nfsmount_zone, nmp);
1374 * Return root of a filesystem
1377 nfs_root(struct mount *mp, int flags, struct vnode **vpp)
1380 struct nfsmount *nmp;
1385 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np, flags);
1390 * Get transfer parameters and attributes for root vnode once.
1392 mtx_lock(&nmp->nm_mtx);
1393 if ((nmp->nm_state & NFSSTA_GOTFSINFO) == 0 &&
1394 (nmp->nm_flag & NFSMNT_NFSV3)) {
1395 mtx_unlock(&nmp->nm_mtx);
1396 nfs_fsinfo(nmp, vp, curthread->td_ucred, curthread);
1398 mtx_unlock(&nmp->nm_mtx);
1399 if (vp->v_type == VNON)
1401 vp->v_vflag |= VV_ROOT;
1407 * Flush out the buffer cache
1411 nfs_sync(struct mount *mp, int waitfor)
1413 struct vnode *vp, *mvp;
1415 int error, allerror = 0;
1421 * If a forced dismount is in progress, return from here so that
1422 * the umount(2) syscall doesn't get stuck in VFS_SYNC() before
1423 * calling VFS_UNMOUNT().
1425 if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1431 * Force stale buffer cache information to be flushed.
1434 MNT_VNODE_FOREACH(vp, mp, mvp) {
1437 /* XXX Racy bv_cnt check. */
1438 if (VOP_ISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0 ||
1439 waitfor == MNT_LAZY) {
1444 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) {
1446 MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp);
1449 error = VOP_FSYNC(vp, waitfor, td);
1462 nfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req)
1464 struct nfsmount *nmp = VFSTONFS(mp);
1468 bzero(&vq, sizeof(vq));
1471 case VFS_CTL_NOLOCKS:
1472 val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0;
1473 if (req->oldptr != NULL) {
1474 error = SYSCTL_OUT(req, &val, sizeof(val));
1478 if (req->newptr != NULL) {
1479 error = SYSCTL_IN(req, &val, sizeof(val));
1483 nmp->nm_flag |= NFSMNT_NOLOCKS;
1485 nmp->nm_flag &= ~NFSMNT_NOLOCKS;
1490 mtx_lock(&nmp->nm_mtx);
1491 if (nmp->nm_state & NFSSTA_TIMEO)
1492 vq.vq_flags |= VQ_NOTRESP;
1493 mtx_unlock(&nmp->nm_mtx);
1495 if (!(nmp->nm_flag & NFSMNT_NOLOCKS) &&
1496 (nmp->nm_state & NFSSTA_LOCKTIMEO))
1497 vq.vq_flags |= VQ_NOTRESPLOCK;
1499 error = SYSCTL_OUT(req, &vq, sizeof(vq));
1502 if (req->oldptr != NULL) {
1503 error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay,
1504 sizeof(nmp->nm_tprintf_initial_delay));
1508 if (req->newptr != NULL) {
1509 error = vfs_suser(mp, req->td);
1512 error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay,
1513 sizeof(nmp->nm_tprintf_initial_delay));
1516 if (nmp->nm_tprintf_initial_delay < 0)
1517 nmp->nm_tprintf_initial_delay = 0;
1527 * Extract the information needed by the nlm from the nfs vnode.
1530 nfs_getnlminfo(struct vnode *vp, uint8_t *fhp, size_t *fhlenp,
1531 struct sockaddr_storage *sp, int *is_v3p, off_t *sizep,
1532 struct timeval *timeop)
1534 struct nfsmount *nmp;
1535 struct nfsnode *np = VTONFS(vp);
1537 nmp = VFSTONFS(vp->v_mount);
1539 *fhlenp = (size_t)np->n_fhsize;
1541 bcopy(np->n_fhp, fhp, np->n_fhsize);
1543 bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp)));
1545 *is_v3p = NFS_ISV3(vp);
1547 *sizep = np->n_size;
1548 if (timeop != NULL) {
1549 timeop->tv_sec = nmp->nm_timeo / NFS_HZ;
1550 timeop->tv_usec = (nmp->nm_timeo % NFS_HZ) * (1000000 / NFS_HZ);