19ec7b004SRick Macklem /*-
251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni *
49ec7b004SRick Macklem * Copyright (c) 1989, 1993, 1995
59ec7b004SRick Macklem * The Regents of the University of California. All rights reserved.
69ec7b004SRick Macklem *
79ec7b004SRick Macklem * This code is derived from software contributed to Berkeley by
89ec7b004SRick Macklem * Rick Macklem at The University of Guelph.
99ec7b004SRick Macklem *
109ec7b004SRick Macklem * Redistribution and use in source and binary forms, with or without
119ec7b004SRick Macklem * modification, are permitted provided that the following conditions
129ec7b004SRick Macklem * are met:
139ec7b004SRick Macklem * 1. Redistributions of source code must retain the above copyright
149ec7b004SRick Macklem * notice, this list of conditions and the following disclaimer.
159ec7b004SRick Macklem * 2. Redistributions in binary form must reproduce the above copyright
169ec7b004SRick Macklem * notice, this list of conditions and the following disclaimer in the
179ec7b004SRick Macklem * documentation and/or other materials provided with the distribution.
18fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
199ec7b004SRick Macklem * may be used to endorse or promote products derived from this software
209ec7b004SRick Macklem * without specific prior written permission.
219ec7b004SRick Macklem *
229ec7b004SRick Macklem * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
239ec7b004SRick Macklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
249ec7b004SRick Macklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
259ec7b004SRick Macklem * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
269ec7b004SRick Macklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
279ec7b004SRick Macklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
289ec7b004SRick Macklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
299ec7b004SRick Macklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
309ec7b004SRick Macklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
319ec7b004SRick Macklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
329ec7b004SRick Macklem * SUCH DAMAGE.
339ec7b004SRick Macklem *
349ec7b004SRick Macklem * from nfs_vfsops.c 8.12 (Berkeley) 5/20/95
359ec7b004SRick Macklem */
369ec7b004SRick Macklem
379ec7b004SRick Macklem #include <sys/cdefs.h>
389ec7b004SRick Macklem #include "opt_bootp.h"
399ec7b004SRick Macklem #include "opt_nfsroot.h"
406e4b6ff8SRick Macklem #include "opt_kern_tls.h"
419ec7b004SRick Macklem
429ec7b004SRick Macklem #include <sys/param.h>
439ec7b004SRick Macklem #include <sys/systm.h>
449ec7b004SRick Macklem #include <sys/kernel.h>
459ec7b004SRick Macklem #include <sys/bio.h>
469ec7b004SRick Macklem #include <sys/buf.h>
479ec7b004SRick Macklem #include <sys/clock.h>
4876ca6f88SJamie Gritton #include <sys/jail.h>
498e82d541SRick Macklem #include <sys/limits.h>
509ec7b004SRick Macklem #include <sys/lock.h>
519ec7b004SRick Macklem #include <sys/malloc.h>
529ec7b004SRick Macklem #include <sys/mbuf.h>
539ec7b004SRick Macklem #include <sys/mount.h>
549ec7b004SRick Macklem #include <sys/proc.h>
559ec7b004SRick Macklem #include <sys/socket.h>
569ec7b004SRick Macklem #include <sys/socketvar.h>
579ec7b004SRick Macklem #include <sys/sockio.h>
589ec7b004SRick Macklem #include <sys/sysctl.h>
599ec7b004SRick Macklem #include <sys/vnode.h>
609ec7b004SRick Macklem #include <sys/signalvar.h>
619ec7b004SRick Macklem
629ec7b004SRick Macklem #include <vm/vm.h>
639ec7b004SRick Macklem #include <vm/vm_extern.h>
649ec7b004SRick Macklem #include <vm/uma.h>
659ec7b004SRick Macklem
669ec7b004SRick Macklem #include <net/if.h>
679ec7b004SRick Macklem #include <net/route.h>
68e1c05fd2SAlexander V. Chernikov #include <net/route/route_ctl.h>
699ec7b004SRick Macklem #include <netinet/in.h>
709ec7b004SRick Macklem
719ec7b004SRick Macklem #include <fs/nfs/nfsport.h>
729ec7b004SRick Macklem #include <fs/nfsclient/nfsnode.h>
739ec7b004SRick Macklem #include <fs/nfsclient/nfsmount.h>
749ec7b004SRick Macklem #include <fs/nfsclient/nfs.h>
758954032fSRick Macklem #include <nfs/nfsdiskless.h>
769ec7b004SRick Macklem
776e4b6ff8SRick Macklem #include <rpc/rpcsec_tls.h>
786e4b6ff8SRick Macklem
79de5b1952SAlexander Leidinger FEATURE(nfscl, "NFSv4 client");
80de5b1952SAlexander Leidinger
819ec7b004SRick Macklem extern int nfscl_ticks;
829ec7b004SRick Macklem extern struct timeval nfsboottime;
83484c842dSRick Macklem extern int nfsrv_useacl;
841f60bfd8SRick Macklem extern int nfscl_debuglevel;
8564a0e848SRick Macklem extern enum nfsiod_state ncl_iodwant[NFS_MAXASYNCDAEMON];
8664a0e848SRick Macklem extern struct nfsmount *ncl_iodmount[NFS_MAXASYNCDAEMON];
8764a0e848SRick Macklem extern struct mtx ncl_iod_mutex;
881f60bfd8SRick Macklem NFSCLSTATEMUTEX;
8990d2dfabSRick Macklem extern struct mtx nfsrv_dslock_mtx;
909ec7b004SRick Macklem
9150a220c6SEdward Tomasz Napierala MALLOC_DEFINE(M_NEWNFSREQ, "newnfsclient_req", "NFS request header");
9250a220c6SEdward Tomasz Napierala MALLOC_DEFINE(M_NEWNFSMNT, "newnfsmnt", "NFS mount struct");
939ec7b004SRick Macklem
941f376590SRick Macklem SYSCTL_DECL(_vfs_nfs);
959ec7b004SRick Macklem static int nfs_ip_paranoia = 1;
961f376590SRick Macklem SYSCTL_INT(_vfs_nfs, OID_AUTO, nfs_ip_paranoia, CTLFLAG_RW,
979ec7b004SRick Macklem &nfs_ip_paranoia, 0, "");
989ec7b004SRick Macklem static int nfs_tprintf_initial_delay = NFS_TPRINTF_INITIAL_DELAY;
991f376590SRick Macklem SYSCTL_INT(_vfs_nfs, NFS_TPRINTF_INITIAL_DELAY,
1009ec7b004SRick Macklem downdelayinitial, CTLFLAG_RW, &nfs_tprintf_initial_delay, 0, "");
1019ec7b004SRick Macklem /* how long between console messages "nfs server foo not responding" */
1029ec7b004SRick Macklem static int nfs_tprintf_delay = NFS_TPRINTF_DELAY;
1031f376590SRick Macklem SYSCTL_INT(_vfs_nfs, NFS_TPRINTF_DELAY,
1049ec7b004SRick Macklem downdelayinterval, CTLFLAG_RW, &nfs_tprintf_delay, 0, "");
10562c23db9SRick Macklem #ifdef NFS_DEBUG
10662c23db9SRick Macklem int nfs_debug;
10762c23db9SRick Macklem SYSCTL_INT(_vfs_nfs, OID_AUTO, debug, CTLFLAG_RW, &nfs_debug, 0,
10862c23db9SRick Macklem "Toggle debug flag");
10962c23db9SRick Macklem #endif
1109ec7b004SRick Macklem
1118954032fSRick Macklem static int nfs_mountroot(struct mount *);
112682eec57SRick Macklem static void nfs_sec_name(char *, int *);
1139ec7b004SRick Macklem static void nfs_decode_args(struct mount *mp, struct nfsmount *nmp,
114ca27c028SRick Macklem struct nfs_args *argp, const char *, struct ucred *,
115ca27c028SRick Macklem struct thread *);
1169ec7b004SRick Macklem static int mountnfs(struct nfs_args *, struct mount *,
117385edc8eSRick Macklem struct sockaddr *, char *, u_char *, int, u_char *, int,
118385edc8eSRick Macklem u_char *, int, struct vnode **, struct ucred *,
1191e0a518dSRick Macklem struct thread *, int, int, int, uint32_t, char *, int);
1204d4f9a37SRick Macklem static void nfs_getnlminfo(struct vnode *, uint8_t *, size_t *,
12190305aa3SRick Macklem struct sockaddr_storage *, int *, off_t *,
12290305aa3SRick Macklem struct timeval *);
1239ec7b004SRick Macklem static vfs_mount_t nfs_mount;
1249ec7b004SRick Macklem static vfs_cmount_t nfs_cmount;
1259ec7b004SRick Macklem static vfs_unmount_t nfs_unmount;
1269ec7b004SRick Macklem static vfs_root_t nfs_root;
1279ec7b004SRick Macklem static vfs_statfs_t nfs_statfs;
1289ec7b004SRick Macklem static vfs_sync_t nfs_sync;
1299ec7b004SRick Macklem static vfs_sysctl_t nfs_sysctl;
1308fe6bddfSRick Macklem static vfs_purge_t nfs_purge;
1319ec7b004SRick Macklem
1329ec7b004SRick Macklem /*
1339ec7b004SRick Macklem * nfs vfs operations.
1349ec7b004SRick Macklem */
1359ec7b004SRick Macklem static struct vfsops nfs_vfsops = {
1369ec7b004SRick Macklem .vfs_init = ncl_init,
1379ec7b004SRick Macklem .vfs_mount = nfs_mount,
1389ec7b004SRick Macklem .vfs_cmount = nfs_cmount,
139d511f93eSMateusz Guzik .vfs_root = vfs_cache_root,
140d511f93eSMateusz Guzik .vfs_cachedroot = nfs_root,
1419ec7b004SRick Macklem .vfs_statfs = nfs_statfs,
1429ec7b004SRick Macklem .vfs_sync = nfs_sync,
1439ec7b004SRick Macklem .vfs_uninit = ncl_uninit,
1449ec7b004SRick Macklem .vfs_unmount = nfs_unmount,
1459ec7b004SRick Macklem .vfs_sysctl = nfs_sysctl,
1468fe6bddfSRick Macklem .vfs_purge = nfs_purge,
1479ec7b004SRick Macklem };
148cb07628dSRick Macklem /*
149cb07628dSRick Macklem * This macro declares that the file system type is named "nfs".
150cb07628dSRick Macklem * It also declares a module name of "nfs" and uses vfs_modevent()
151cb07628dSRick Macklem * as the event handling function.
152cb07628dSRick Macklem * The main module declaration is found in sys/fs/nfsclient/nfs_clport.c
153cb07628dSRick Macklem * for "nfscl" and is needed so that a custom event handling
154cb07628dSRick Macklem * function gets called. MODULE_DEPEND() macros are found there.
155cb07628dSRick Macklem */
156593efaf9SJohn Baldwin VFS_SET(nfs_vfsops, nfs, VFCF_NETWORK | VFCF_SBDRY);
1579ec7b004SRick Macklem
158afea7465SRick Macklem MODULE_VERSION(nfs, 1);
1599ec7b004SRick Macklem
1609ec7b004SRick Macklem /*
161541cb7a3SRick Macklem * This structure is now defined in sys/nfs/nfs_diskless.c so that it
162541cb7a3SRick Macklem * can be shared by both NFS clients. It is declared here so that it
163541cb7a3SRick Macklem * will be defined for kernels built without NFS_ROOT, although it
164541cb7a3SRick Macklem * isn't used in that case.
1659ec7b004SRick Macklem */
166c15882f0SRick Macklem #if !defined(NFS_ROOT)
167541cb7a3SRick Macklem struct nfs_diskless nfs_diskless = { { { 0 } } };
168541cb7a3SRick Macklem struct nfsv3_diskless nfsv3_diskless = { { { 0 } } };
169541cb7a3SRick Macklem int nfs_diskless_valid = 0;
170541cb7a3SRick Macklem #endif
171541cb7a3SRick Macklem
1721f376590SRick Macklem SYSCTL_INT(_vfs_nfs, OID_AUTO, diskless_valid, CTLFLAG_RD,
1738954032fSRick Macklem &nfs_diskless_valid, 0,
174d34b41c9SRick Macklem "Has the diskless struct been filled correctly");
1759ec7b004SRick Macklem
1761f376590SRick Macklem SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD,
1778954032fSRick Macklem nfsv3_diskless.root_hostnam, 0, "Path to nfs root");
1789ec7b004SRick Macklem
1791f376590SRick Macklem SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD,
1808954032fSRick Macklem &nfsv3_diskless.root_saddr, sizeof(nfsv3_diskless.root_saddr),
181d34b41c9SRick Macklem "%Ssockaddr_in", "Diskless root nfs address");
1829ec7b004SRick Macklem
1839ec7b004SRick Macklem void newnfsargs_ntoh(struct nfs_args *);
1849ec7b004SRick Macklem static int nfs_mountdiskless(char *,
1859ec7b004SRick Macklem struct sockaddr_in *, struct nfs_args *,
1869ec7b004SRick Macklem struct thread *, struct vnode **, struct mount *);
1879ec7b004SRick Macklem static void nfs_convert_diskless(void);
1889ec7b004SRick Macklem static void nfs_convert_oargs(struct nfs_args *args,
1899ec7b004SRick Macklem struct onfs_args *oargs);
1909ec7b004SRick Macklem
1919ec7b004SRick Macklem int
newnfs_iosize(struct nfsmount * nmp)1929ec7b004SRick Macklem newnfs_iosize(struct nfsmount *nmp)
1939ec7b004SRick Macklem {
1949ec7b004SRick Macklem int iosize, maxio;
1959ec7b004SRick Macklem
1969ec7b004SRick Macklem /* First, set the upper limit for iosize */
1979ec7b004SRick Macklem if (nmp->nm_flag & NFSMNT_NFSV4) {
1989ec7b004SRick Macklem maxio = NFS_MAXBSIZE;
1999ec7b004SRick Macklem } else if (nmp->nm_flag & NFSMNT_NFSV3) {
2009ec7b004SRick Macklem if (nmp->nm_sotype == SOCK_DGRAM)
2019ec7b004SRick Macklem maxio = NFS_MAXDGRAMDATA;
2029ec7b004SRick Macklem else
2039ec7b004SRick Macklem maxio = NFS_MAXBSIZE;
2049ec7b004SRick Macklem } else {
2059ec7b004SRick Macklem maxio = NFS_V2MAXDATA;
2069ec7b004SRick Macklem }
2079ec7b004SRick Macklem if (nmp->nm_rsize > maxio || nmp->nm_rsize == 0)
2089ec7b004SRick Macklem nmp->nm_rsize = maxio;
2097cfdc2a7SRick Macklem if (nmp->nm_rsize > NFS_MAXBSIZE)
2107cfdc2a7SRick Macklem nmp->nm_rsize = NFS_MAXBSIZE;
2119ec7b004SRick Macklem if (nmp->nm_readdirsize > maxio || nmp->nm_readdirsize == 0)
2129ec7b004SRick Macklem nmp->nm_readdirsize = maxio;
2139ec7b004SRick Macklem if (nmp->nm_readdirsize > nmp->nm_rsize)
2149ec7b004SRick Macklem nmp->nm_readdirsize = nmp->nm_rsize;
2159ec7b004SRick Macklem if (nmp->nm_wsize > maxio || nmp->nm_wsize == 0)
2169ec7b004SRick Macklem nmp->nm_wsize = maxio;
2177cfdc2a7SRick Macklem if (nmp->nm_wsize > NFS_MAXBSIZE)
2187cfdc2a7SRick Macklem nmp->nm_wsize = NFS_MAXBSIZE;
2199ec7b004SRick Macklem
2209ec7b004SRick Macklem /*
2219ec7b004SRick Macklem * Calculate the size used for io buffers. Use the larger
2229ec7b004SRick Macklem * of the two sizes to minimise nfs requests but make sure
2239ec7b004SRick Macklem * that it is at least one VM page to avoid wasting buffer
224f3153834SRick Macklem * space. It must also be at least NFS_DIRBLKSIZ, since
225f3153834SRick Macklem * that is the buffer size used for directories.
2269ec7b004SRick Macklem */
2279ec7b004SRick Macklem iosize = imax(nmp->nm_rsize, nmp->nm_wsize);
2289ec7b004SRick Macklem iosize = imax(iosize, PAGE_SIZE);
229f3153834SRick Macklem iosize = imax(iosize, NFS_DIRBLKSIZ);
2309ec7b004SRick Macklem nmp->nm_mountp->mnt_stat.f_iosize = iosize;
2319ec7b004SRick Macklem return (iosize);
2329ec7b004SRick Macklem }
2339ec7b004SRick Macklem
2349ec7b004SRick Macklem static void
nfs_convert_oargs(struct nfs_args * args,struct onfs_args * oargs)2359ec7b004SRick Macklem nfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs)
2369ec7b004SRick Macklem {
2379ec7b004SRick Macklem
2389ec7b004SRick Macklem args->version = NFS_ARGSVERSION;
2399ec7b004SRick Macklem args->addr = oargs->addr;
2409ec7b004SRick Macklem args->addrlen = oargs->addrlen;
2419ec7b004SRick Macklem args->sotype = oargs->sotype;
2429ec7b004SRick Macklem args->proto = oargs->proto;
2439ec7b004SRick Macklem args->fh = oargs->fh;
2449ec7b004SRick Macklem args->fhsize = oargs->fhsize;
2459ec7b004SRick Macklem args->flags = oargs->flags;
2469ec7b004SRick Macklem args->wsize = oargs->wsize;
2479ec7b004SRick Macklem args->rsize = oargs->rsize;
2489ec7b004SRick Macklem args->readdirsize = oargs->readdirsize;
2499ec7b004SRick Macklem args->timeo = oargs->timeo;
2509ec7b004SRick Macklem args->retrans = oargs->retrans;
2519ec7b004SRick Macklem args->readahead = oargs->readahead;
2529ec7b004SRick Macklem args->hostname = oargs->hostname;
2539ec7b004SRick Macklem }
2549ec7b004SRick Macklem
2559ec7b004SRick Macklem static void
nfs_convert_diskless(void)2569ec7b004SRick Macklem nfs_convert_diskless(void)
2579ec7b004SRick Macklem {
2589ec7b004SRick Macklem
2598954032fSRick Macklem bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif,
2609ec7b004SRick Macklem sizeof(struct ifaliasreq));
2618954032fSRick Macklem bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway,
2629ec7b004SRick Macklem sizeof(struct sockaddr_in));
2638954032fSRick Macklem nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args);
2648954032fSRick Macklem if (nfsv3_diskless.root_args.flags & NFSMNT_NFSV3) {
2658954032fSRick Macklem nfsv3_diskless.root_fhsize = NFSX_MYFH;
2668954032fSRick Macklem bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_MYFH);
2679ec7b004SRick Macklem } else {
2688954032fSRick Macklem nfsv3_diskless.root_fhsize = NFSX_V2FH;
2698954032fSRick Macklem bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_V2FH);
2709ec7b004SRick Macklem }
2718954032fSRick Macklem bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr,
2729ec7b004SRick Macklem sizeof(struct sockaddr_in));
2738954032fSRick Macklem bcopy(nfs_diskless.root_hostnam, nfsv3_diskless.root_hostnam, MNAMELEN);
2748954032fSRick Macklem nfsv3_diskless.root_time = nfs_diskless.root_time;
2758954032fSRick Macklem bcopy(nfs_diskless.my_hostnam, nfsv3_diskless.my_hostnam,
2769ec7b004SRick Macklem MAXHOSTNAMELEN);
2778954032fSRick Macklem nfs_diskless_valid = 3;
2789ec7b004SRick Macklem }
2799ec7b004SRick Macklem
2809ec7b004SRick Macklem /*
2819ec7b004SRick Macklem * nfs statfs call
2829ec7b004SRick Macklem */
2839ec7b004SRick Macklem static int
nfs_statfs(struct mount * mp,struct statfs * sbp)284dfd233edSAttilio Rao nfs_statfs(struct mount *mp, struct statfs *sbp)
2859ec7b004SRick Macklem {
2869ec7b004SRick Macklem struct vnode *vp;
287dfd233edSAttilio Rao struct thread *td;
2889ec7b004SRick Macklem struct nfsmount *nmp = VFSTONFS(mp);
2899ec7b004SRick Macklem struct nfsvattr nfsva;
2909ec7b004SRick Macklem struct nfsfsinfo fs;
2919ec7b004SRick Macklem struct nfsstatfs sb;
2929ec7b004SRick Macklem int error = 0, attrflag, gotfsinfo = 0, ret;
2939ec7b004SRick Macklem struct nfsnode *np;
294896516e5SRick Macklem char *fakefh;
2959ec7b004SRick Macklem
296dfd233edSAttilio Rao td = curthread;
297dfd233edSAttilio Rao
2989ec7b004SRick Macklem error = vfs_busy(mp, MBF_NOWAIT);
2999ec7b004SRick Macklem if (error)
3009ec7b004SRick Macklem return (error);
301896516e5SRick Macklem if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0) {
302896516e5SRick Macklem if (nmp->nm_fhsize == 0) {
303896516e5SRick Macklem error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
304896516e5SRick Macklem td->td_ucred, td);
305896516e5SRick Macklem if (error != 0) {
306896516e5SRick Macklem /*
307896516e5SRick Macklem * We cannot do anything yet. Hopefully what
308896516e5SRick Macklem * is in mnt_stat is sufficient.
309896516e5SRick Macklem */
310896516e5SRick Macklem if (sbp != &mp->mnt_stat)
311896516e5SRick Macklem *sbp = mp->mnt_stat;
312896516e5SRick Macklem strncpy(&sbp->f_fstypename[0],
313896516e5SRick Macklem mp->mnt_vfc->vfc_name, MFSNAMELEN);
314896516e5SRick Macklem vfs_unbusy(mp);
315896516e5SRick Macklem return (0);
316896516e5SRick Macklem }
317896516e5SRick Macklem }
318896516e5SRick Macklem fakefh = malloc(NFSX_FHMAX + 1, M_TEMP, M_WAITOK | M_ZERO);
319896516e5SRick Macklem error = ncl_nget(mp, fakefh, NFSX_FHMAX + 1, &np, LK_EXCLUSIVE);
320896516e5SRick Macklem free(fakefh, M_TEMP);
321896516e5SRick Macklem } else {
322896516e5SRick Macklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np,
323896516e5SRick Macklem LK_EXCLUSIVE);
324896516e5SRick Macklem }
3259ec7b004SRick Macklem if (error) {
3269ec7b004SRick Macklem vfs_unbusy(mp);
3279ec7b004SRick Macklem return (error);
3289ec7b004SRick Macklem }
3299ec7b004SRick Macklem vp = NFSTOV(np);
3309ec7b004SRick Macklem mtx_lock(&nmp->nm_mtx);
3319ec7b004SRick Macklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) {
3329ec7b004SRick Macklem mtx_unlock(&nmp->nm_mtx);
3339ec7b004SRick Macklem error = nfsrpc_fsinfo(vp, &fs, td->td_ucred, td, &nfsva,
3341e70163cSRick Macklem &attrflag);
3359ec7b004SRick Macklem if (!error)
3369ec7b004SRick Macklem gotfsinfo = 1;
3379ec7b004SRick Macklem } else
3389ec7b004SRick Macklem mtx_unlock(&nmp->nm_mtx);
3399ec7b004SRick Macklem if (!error)
340896516e5SRick Macklem error = nfsrpc_statfs(vp, &sb, &fs, NULL, td->td_ucred, td,
341896516e5SRick Macklem &nfsva, &attrflag);
342896516e5SRick Macklem if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0 &&
343896516e5SRick Macklem error == NFSERR_WRONGSEC) {
344896516e5SRick Macklem /* Cannot get new stats, so return what is in mnt_stat. */
345896516e5SRick Macklem if (sbp != &mp->mnt_stat)
346896516e5SRick Macklem *sbp = mp->mnt_stat;
347896516e5SRick Macklem strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name,
348896516e5SRick Macklem MFSNAMELEN);
349896516e5SRick Macklem vput(vp);
350896516e5SRick Macklem vfs_unbusy(mp);
351896516e5SRick Macklem return (0);
352896516e5SRick Macklem }
3531f60bfd8SRick Macklem if (error != 0)
3541f60bfd8SRick Macklem NFSCL_DEBUG(2, "statfs=%d\n", error);
3559ec7b004SRick Macklem if (attrflag == 0) {
3569ec7b004SRick Macklem ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1,
3571f60bfd8SRick Macklem td->td_ucred, td, &nfsva, NULL, NULL);
3589ec7b004SRick Macklem if (ret) {
3599ec7b004SRick Macklem /*
3609ec7b004SRick Macklem * Just set default values to get things going.
3619ec7b004SRick Macklem */
3629ec7b004SRick Macklem NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr));
3639ec7b004SRick Macklem nfsva.na_vattr.va_type = VDIR;
3649ec7b004SRick Macklem nfsva.na_vattr.va_mode = 0777;
3659ec7b004SRick Macklem nfsva.na_vattr.va_nlink = 100;
3669ec7b004SRick Macklem nfsva.na_vattr.va_uid = (uid_t)0;
3679ec7b004SRick Macklem nfsva.na_vattr.va_gid = (gid_t)0;
3689ec7b004SRick Macklem nfsva.na_vattr.va_fileid = 2;
3699ec7b004SRick Macklem nfsva.na_vattr.va_gen = 1;
3709ec7b004SRick Macklem nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE;
3719ec7b004SRick Macklem nfsva.na_vattr.va_size = 512 * 1024;
3729ec7b004SRick Macklem }
3739ec7b004SRick Macklem }
3744ad3423bSRick Macklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1);
3759ec7b004SRick Macklem if (!error) {
3769ec7b004SRick Macklem mtx_lock(&nmp->nm_mtx);
3779ec7b004SRick Macklem if (gotfsinfo || (nmp->nm_flag & NFSMNT_NFSV4))
3789ec7b004SRick Macklem nfscl_loadfsinfo(nmp, &fs);
3799ec7b004SRick Macklem nfscl_loadsbinfo(nmp, &sb, sbp);
3809ec7b004SRick Macklem sbp->f_iosize = newnfs_iosize(nmp);
3819ec7b004SRick Macklem mtx_unlock(&nmp->nm_mtx);
3829ec7b004SRick Macklem if (sbp != &mp->mnt_stat) {
3839ec7b004SRick Macklem bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
3849ec7b004SRick Macklem bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
3859ec7b004SRick Macklem }
3869ec7b004SRick Macklem strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN);
3879ec7b004SRick Macklem } else if (NFS_ISV4(vp)) {
3889ec7b004SRick Macklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0);
3899ec7b004SRick Macklem }
3909ec7b004SRick Macklem vput(vp);
3919ec7b004SRick Macklem vfs_unbusy(mp);
3929ec7b004SRick Macklem return (error);
3939ec7b004SRick Macklem }
3949ec7b004SRick Macklem
3959ec7b004SRick Macklem /*
3969ec7b004SRick Macklem * nfs version 3 fsinfo rpc call
3979ec7b004SRick Macklem */
3989ec7b004SRick Macklem int
ncl_fsinfo(struct nfsmount * nmp,struct vnode * vp,struct ucred * cred,struct thread * td)3999ec7b004SRick Macklem ncl_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred,
4009ec7b004SRick Macklem struct thread *td)
4019ec7b004SRick Macklem {
4029ec7b004SRick Macklem struct nfsfsinfo fs;
4039ec7b004SRick Macklem struct nfsvattr nfsva;
4049ec7b004SRick Macklem int error, attrflag;
4059ec7b004SRick Macklem
4061e70163cSRick Macklem error = nfsrpc_fsinfo(vp, &fs, cred, td, &nfsva, &attrflag);
4079ec7b004SRick Macklem if (!error) {
4089ec7b004SRick Macklem if (attrflag)
4094ad3423bSRick Macklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1);
4109ec7b004SRick Macklem mtx_lock(&nmp->nm_mtx);
4119ec7b004SRick Macklem nfscl_loadfsinfo(nmp, &fs);
4129ec7b004SRick Macklem mtx_unlock(&nmp->nm_mtx);
4139ec7b004SRick Macklem }
4149ec7b004SRick Macklem return (error);
4159ec7b004SRick Macklem }
4169ec7b004SRick Macklem
4179ec7b004SRick Macklem /*
41852d895feSEd Maste * Mount a remote root fs via nfs. This depends on the info in the
4198954032fSRick Macklem * nfs_diskless structure that has been filled in properly by some primary
4209ec7b004SRick Macklem * bootstrap.
4219ec7b004SRick Macklem * It goes something like this:
4229ec7b004SRick Macklem * - do enough of "ifconfig" by calling ifioctl() so that the system
4239ec7b004SRick Macklem * can talk to the server
4248954032fSRick Macklem * - If nfs_diskless.mygateway is filled in, use that address as
4259ec7b004SRick Macklem * a default gateway.
4269ec7b004SRick Macklem * - build the rootfs mount point and call mountnfs() to do the rest.
4279ec7b004SRick Macklem *
4289ec7b004SRick Macklem * It is assumed to be safe to read, modify, and write the nfsv3_diskless
4299ec7b004SRick Macklem * structure, as well as other global NFS client variables here, as
430d34b41c9SRick Macklem * nfs_mountroot() will be called once in the boot before any other NFS
4319ec7b004SRick Macklem * client activity occurs.
4329ec7b004SRick Macklem */
4338954032fSRick Macklem static int
nfs_mountroot(struct mount * mp)4348954032fSRick Macklem nfs_mountroot(struct mount *mp)
4359ec7b004SRick Macklem {
436d34b41c9SRick Macklem struct thread *td = curthread;
4378954032fSRick Macklem struct nfsv3_diskless *nd = &nfsv3_diskless;
4389ec7b004SRick Macklem struct socket *so;
4399ec7b004SRick Macklem struct vnode *vp;
4409ec7b004SRick Macklem struct ifreq ir;
44176ca6f88SJamie Gritton int error;
4429ec7b004SRick Macklem u_long l;
4439ec7b004SRick Macklem char buf[128];
4449ec7b004SRick Macklem char *cp;
4459ec7b004SRick Macklem
4469ec7b004SRick Macklem #if defined(BOOTP_NFSROOT) && defined(BOOTP)
447d34b41c9SRick Macklem bootpc_init(); /* use bootp to get nfs_diskless filled in */
4489ec7b004SRick Macklem #elif defined(NFS_ROOT)
4499ec7b004SRick Macklem nfs_setup_diskless();
4509ec7b004SRick Macklem #endif
4519ec7b004SRick Macklem
4528954032fSRick Macklem if (nfs_diskless_valid == 0)
4539ec7b004SRick Macklem return (-1);
4548954032fSRick Macklem if (nfs_diskless_valid == 1)
4559ec7b004SRick Macklem nfs_convert_diskless();
4569ec7b004SRick Macklem
4579ec7b004SRick Macklem /*
4589ec7b004SRick Macklem * Do enough of ifconfig(8) so that the critical net interface can
4599ec7b004SRick Macklem * talk to the server.
4609ec7b004SRick Macklem */
4619ec7b004SRick Macklem error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0,
4629ec7b004SRick Macklem td->td_ucred, td);
4639ec7b004SRick Macklem if (error)
464d34b41c9SRick Macklem panic("nfs_mountroot: socreate(%04x): %d",
4659ec7b004SRick Macklem nd->myif.ifra_addr.sa_family, error);
4669ec7b004SRick Macklem
4679ec7b004SRick Macklem #if 0 /* XXX Bad idea */
4689ec7b004SRick Macklem /*
4699ec7b004SRick Macklem * We might not have been told the right interface, so we pass
4709ec7b004SRick Macklem * over the first ten interfaces of the same kind, until we get
4719ec7b004SRick Macklem * one of them configured.
4729ec7b004SRick Macklem */
4739ec7b004SRick Macklem
4749ec7b004SRick Macklem for (i = strlen(nd->myif.ifra_name) - 1;
4759ec7b004SRick Macklem nd->myif.ifra_name[i] >= '0' &&
4769ec7b004SRick Macklem nd->myif.ifra_name[i] <= '9';
4779ec7b004SRick Macklem nd->myif.ifra_name[i] ++) {
4789ec7b004SRick Macklem error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
4799ec7b004SRick Macklem if(!error)
4809ec7b004SRick Macklem break;
4819ec7b004SRick Macklem }
4829ec7b004SRick Macklem #endif
4839ec7b004SRick Macklem error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
4849ec7b004SRick Macklem if (error)
485d34b41c9SRick Macklem panic("nfs_mountroot: SIOCAIFADDR: %d", error);
4862be111bfSDavide Italiano if ((cp = kern_getenv("boot.netif.mtu")) != NULL) {
4879ec7b004SRick Macklem ir.ifr_mtu = strtol(cp, NULL, 10);
4889ec7b004SRick Macklem bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ);
4899ec7b004SRick Macklem freeenv(cp);
4909ec7b004SRick Macklem error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td);
4919ec7b004SRick Macklem if (error)
492d34b41c9SRick Macklem printf("nfs_mountroot: SIOCSIFMTU: %d", error);
4939ec7b004SRick Macklem }
4949ec7b004SRick Macklem soclose(so);
4959ec7b004SRick Macklem
4969ec7b004SRick Macklem /*
4979ec7b004SRick Macklem * If the gateway field is filled in, set it as the default route.
4989ec7b004SRick Macklem * Note that pxeboot will set a default route of 0 if the route
4999ec7b004SRick Macklem * is not set by the DHCP server. Check also for a value of 0
5009ec7b004SRick Macklem * to avoid panicking inappropriately in that situation.
5019ec7b004SRick Macklem */
5029ec7b004SRick Macklem if (nd->mygateway.sin_len != 0 &&
5039ec7b004SRick Macklem nd->mygateway.sin_addr.s_addr != 0) {
5049ec7b004SRick Macklem struct sockaddr_in mask, sin;
5052bbab0afSAlexander V. Chernikov struct epoch_tracker et;
506e1c05fd2SAlexander V. Chernikov struct rt_addrinfo info;
507e1c05fd2SAlexander V. Chernikov struct rib_cmd_info rc;
5089ec7b004SRick Macklem
5099ec7b004SRick Macklem bzero((caddr_t)&mask, sizeof(mask));
5109ec7b004SRick Macklem sin = mask;
5119ec7b004SRick Macklem sin.sin_family = AF_INET;
5129ec7b004SRick Macklem sin.sin_len = sizeof(sin);
513d34b41c9SRick Macklem /* XXX MRT use table 0 for this sort of thing */
5142bbab0afSAlexander V. Chernikov NET_EPOCH_ENTER(et);
5151fb51a12SBjoern A. Zeeb CURVNET_SET(TD_TO_VNET(td));
516e1c05fd2SAlexander V. Chernikov
517e1c05fd2SAlexander V. Chernikov bzero((caddr_t)&info, sizeof(info));
518e1c05fd2SAlexander V. Chernikov info.rti_flags = RTF_UP | RTF_GATEWAY;
519e1c05fd2SAlexander V. Chernikov info.rti_info[RTAX_DST] = (struct sockaddr *)&sin;
520e1c05fd2SAlexander V. Chernikov info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&nd->mygateway;
521e1c05fd2SAlexander V. Chernikov info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask;
522e1c05fd2SAlexander V. Chernikov
523e1c05fd2SAlexander V. Chernikov error = rib_action(RT_DEFAULT_FIB, RTM_ADD, &info, &rc);
5241fb51a12SBjoern A. Zeeb CURVNET_RESTORE();
5252bbab0afSAlexander V. Chernikov NET_EPOCH_EXIT(et);
5269ec7b004SRick Macklem if (error)
527d34b41c9SRick Macklem panic("nfs_mountroot: RTM_ADD: %d", error);
5289ec7b004SRick Macklem }
5299ec7b004SRick Macklem
5309ec7b004SRick Macklem /*
5319ec7b004SRick Macklem * Create the rootfs mount point.
5329ec7b004SRick Macklem */
5339ec7b004SRick Macklem nd->root_args.fh = nd->root_fh;
5349ec7b004SRick Macklem nd->root_args.fhsize = nd->root_fhsize;
5359ec7b004SRick Macklem l = ntohl(nd->root_saddr.sin_addr.s_addr);
5369ec7b004SRick Macklem snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s",
5379ec7b004SRick Macklem (l >> 24) & 0xff, (l >> 16) & 0xff,
5389ec7b004SRick Macklem (l >> 8) & 0xff, (l >> 0) & 0xff, nd->root_hostnam);
5399ec7b004SRick Macklem printf("NFS ROOT: %s\n", buf);
540d34b41c9SRick Macklem nd->root_args.hostname = buf;
5419ec7b004SRick Macklem if ((error = nfs_mountdiskless(buf,
5429ec7b004SRick Macklem &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) {
5439ec7b004SRick Macklem return (error);
5449ec7b004SRick Macklem }
5459ec7b004SRick Macklem
5469ec7b004SRick Macklem /*
5479ec7b004SRick Macklem * This is not really an nfs issue, but it is much easier to
5489ec7b004SRick Macklem * set hostname here and then let the "/etc/rc.xxx" files
5499ec7b004SRick Macklem * mount the right /var based upon its preset value.
5509ec7b004SRick Macklem */
55176ca6f88SJamie Gritton mtx_lock(&prison0.pr_mtx);
552c1f19219SJamie Gritton strlcpy(prison0.pr_hostname, nd->my_hostnam,
553c1f19219SJamie Gritton sizeof(prison0.pr_hostname));
55476ca6f88SJamie Gritton mtx_unlock(&prison0.pr_mtx);
5559ec7b004SRick Macklem inittodr(ntohl(nd->root_time));
5569ec7b004SRick Macklem return (0);
5579ec7b004SRick Macklem }
5589ec7b004SRick Macklem
5599ec7b004SRick Macklem /*
5609ec7b004SRick Macklem * Internal version of mount system call for diskless setup.
5619ec7b004SRick Macklem */
5629ec7b004SRick Macklem static int
nfs_mountdiskless(char * path,struct sockaddr_in * sin,struct nfs_args * args,struct thread * td,struct vnode ** vpp,struct mount * mp)5639ec7b004SRick Macklem nfs_mountdiskless(char *path,
5649ec7b004SRick Macklem struct sockaddr_in *sin, struct nfs_args *args, struct thread *td,
5659ec7b004SRick Macklem struct vnode **vpp, struct mount *mp)
5669ec7b004SRick Macklem {
5679ec7b004SRick Macklem struct sockaddr *nam;
568385edc8eSRick Macklem int dirlen, error;
569385edc8eSRick Macklem char *dirpath;
5709ec7b004SRick Macklem
571385edc8eSRick Macklem /*
572385edc8eSRick Macklem * Find the directory path in "path", which also has the server's
573385edc8eSRick Macklem * name/ip address in it.
574385edc8eSRick Macklem */
575385edc8eSRick Macklem dirpath = strchr(path, ':');
576385edc8eSRick Macklem if (dirpath != NULL)
577385edc8eSRick Macklem dirlen = strlen(++dirpath);
578385edc8eSRick Macklem else
579385edc8eSRick Macklem dirlen = 0;
5809ec7b004SRick Macklem nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK);
581385edc8eSRick Macklem if ((error = mountnfs(args, mp, nam, path, NULL, 0, dirpath, dirlen,
5820b17c7beSJohn Baldwin NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NAMETIMEO,
5831e0a518dSRick Macklem NFS_DEFAULT_NEGNAMETIMEO, 0, 0, NULL, 0)) != 0) {
584d34b41c9SRick Macklem printf("nfs_mountroot: mount %s on /: %d\n", path, error);
5859ec7b004SRick Macklem return (error);
5869ec7b004SRick Macklem }
5879ec7b004SRick Macklem return (0);
5889ec7b004SRick Macklem }
5899ec7b004SRick Macklem
5909ec7b004SRick Macklem static void
nfs_sec_name(char * sec,int * flagsp)591682eec57SRick Macklem nfs_sec_name(char *sec, int *flagsp)
592682eec57SRick Macklem {
593682eec57SRick Macklem if (!strcmp(sec, "krb5"))
594682eec57SRick Macklem *flagsp |= NFSMNT_KERB;
595682eec57SRick Macklem else if (!strcmp(sec, "krb5i"))
596682eec57SRick Macklem *flagsp |= (NFSMNT_KERB | NFSMNT_INTEGRITY);
597682eec57SRick Macklem else if (!strcmp(sec, "krb5p"))
598682eec57SRick Macklem *flagsp |= (NFSMNT_KERB | NFSMNT_PRIVACY);
599682eec57SRick Macklem }
600682eec57SRick Macklem
601682eec57SRick Macklem static void
nfs_decode_args(struct mount * mp,struct nfsmount * nmp,struct nfs_args * argp,const char * hostname,struct ucred * cred,struct thread * td)6029ec7b004SRick Macklem nfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp,
603ca27c028SRick Macklem const char *hostname, struct ucred *cred, struct thread *td)
6049ec7b004SRick Macklem {
6059ec7b004SRick Macklem int adjsock;
606ca27c028SRick Macklem char *p;
6079ec7b004SRick Macklem
6089ec7b004SRick Macklem /*
6099ec7b004SRick Macklem * Set read-only flag if requested; otherwise, clear it if this is
6109ec7b004SRick Macklem * an update. If this is not an update, then either the read-only
6119ec7b004SRick Macklem * flag is already clear, or this is a root mount and it was set
6129ec7b004SRick Macklem * intentionally at some previous point.
6139ec7b004SRick Macklem */
6149ec7b004SRick Macklem if (vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL) == 0) {
6159ec7b004SRick Macklem MNT_ILOCK(mp);
6169ec7b004SRick Macklem mp->mnt_flag |= MNT_RDONLY;
6179ec7b004SRick Macklem MNT_IUNLOCK(mp);
6189ec7b004SRick Macklem } else if (mp->mnt_flag & MNT_UPDATE) {
6199ec7b004SRick Macklem MNT_ILOCK(mp);
6209ec7b004SRick Macklem mp->mnt_flag &= ~MNT_RDONLY;
6219ec7b004SRick Macklem MNT_IUNLOCK(mp);
6229ec7b004SRick Macklem }
6239ec7b004SRick Macklem
6249ec7b004SRick Macklem /*
6259ec7b004SRick Macklem * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes
6269ec7b004SRick Macklem * no sense in that context. Also, set up appropriate retransmit
6279ec7b004SRick Macklem * and soft timeout behavior.
6289ec7b004SRick Macklem */
6299ec7b004SRick Macklem if (argp->sotype == SOCK_STREAM) {
6309ec7b004SRick Macklem nmp->nm_flag &= ~NFSMNT_NOCONN;
6319ec7b004SRick Macklem nmp->nm_timeo = NFS_MAXTIMEO;
6328e82d541SRick Macklem if ((argp->flags & NFSMNT_NFSV4) != 0)
6338e82d541SRick Macklem nmp->nm_retry = INT_MAX;
6348e82d541SRick Macklem else
6358e82d541SRick Macklem nmp->nm_retry = NFS_RETRANS_TCP;
6369ec7b004SRick Macklem }
6379ec7b004SRick Macklem
6388e82d541SRick Macklem /* Also clear RDIRPLUS if NFSv2, it crashes some servers */
6398e82d541SRick Macklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) {
6408e82d541SRick Macklem argp->flags &= ~NFSMNT_RDIRPLUS;
6419ec7b004SRick Macklem nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
6428e82d541SRick Macklem }
6439ec7b004SRick Macklem
644037a2012SRick Macklem /* Clear ONEOPENOWN for NFSv2, 3 and 4.0. */
645037a2012SRick Macklem if (nmp->nm_minorvers == 0) {
646037a2012SRick Macklem argp->flags &= ~NFSMNT_ONEOPENOWN;
647037a2012SRick Macklem nmp->nm_flag &= ~NFSMNT_ONEOPENOWN;
648037a2012SRick Macklem }
649037a2012SRick Macklem
6508e82d541SRick Macklem /* Re-bind if rsrvd port requested and wasn't on one */
6518e82d541SRick Macklem adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT)
6528e82d541SRick Macklem && (argp->flags & NFSMNT_RESVPORT);
6539ec7b004SRick Macklem /* Also re-bind if we're switching to/from a connected UDP socket */
6548e82d541SRick Macklem adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) !=
6559ec7b004SRick Macklem (argp->flags & NFSMNT_NOCONN));
6569ec7b004SRick Macklem
6579ec7b004SRick Macklem /* Update flags atomically. Don't change the lock bits. */
6589ec7b004SRick Macklem nmp->nm_flag = argp->flags | nmp->nm_flag;
6599ec7b004SRick Macklem
6609ec7b004SRick Macklem if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
6619ec7b004SRick Macklem nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
6629ec7b004SRick Macklem if (nmp->nm_timeo < NFS_MINTIMEO)
6639ec7b004SRick Macklem nmp->nm_timeo = NFS_MINTIMEO;
6649ec7b004SRick Macklem else if (nmp->nm_timeo > NFS_MAXTIMEO)
6659ec7b004SRick Macklem nmp->nm_timeo = NFS_MAXTIMEO;
6669ec7b004SRick Macklem }
6679ec7b004SRick Macklem
6689ec7b004SRick Macklem if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
6699ec7b004SRick Macklem nmp->nm_retry = argp->retrans;
6709ec7b004SRick Macklem if (nmp->nm_retry > NFS_MAXREXMIT)
6719ec7b004SRick Macklem nmp->nm_retry = NFS_MAXREXMIT;
6729ec7b004SRick Macklem }
6739ec7b004SRick Macklem
6749ec7b004SRick Macklem if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
6759ec7b004SRick Macklem nmp->nm_wsize = argp->wsize;
6766a30c96cSRick Macklem /*
6776a30c96cSRick Macklem * Clip at the power of 2 below the size. There is an
6786a30c96cSRick Macklem * issue (not isolated) that causes intermittent page
6796a30c96cSRick Macklem * faults if this is not done.
6806a30c96cSRick Macklem */
6816a30c96cSRick Macklem if (nmp->nm_wsize > NFS_FABLKSIZE)
6826a30c96cSRick Macklem nmp->nm_wsize = 1 << (fls(nmp->nm_wsize) - 1);
6836a30c96cSRick Macklem else
684fcf121d4SRick Macklem nmp->nm_wsize = NFS_FABLKSIZE;
6859ec7b004SRick Macklem }
6869ec7b004SRick Macklem
6879ec7b004SRick Macklem if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
6889ec7b004SRick Macklem nmp->nm_rsize = argp->rsize;
6896a30c96cSRick Macklem /*
6906a30c96cSRick Macklem * Clip at the power of 2 below the size. There is an
6916a30c96cSRick Macklem * issue (not isolated) that causes intermittent page
6926a30c96cSRick Macklem * faults if this is not done.
6936a30c96cSRick Macklem */
6946a30c96cSRick Macklem if (nmp->nm_rsize > NFS_FABLKSIZE)
6956a30c96cSRick Macklem nmp->nm_rsize = 1 << (fls(nmp->nm_rsize) - 1);
6966a30c96cSRick Macklem else
697fcf121d4SRick Macklem nmp->nm_rsize = NFS_FABLKSIZE;
6989ec7b004SRick Macklem }
6999ec7b004SRick Macklem
7009ec7b004SRick Macklem if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
7019ec7b004SRick Macklem nmp->nm_readdirsize = argp->readdirsize;
7029ec7b004SRick Macklem }
7039ec7b004SRick Macklem
7049ec7b004SRick Macklem if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0)
7059ec7b004SRick Macklem nmp->nm_acregmin = argp->acregmin;
7069ec7b004SRick Macklem else
7079ec7b004SRick Macklem nmp->nm_acregmin = NFS_MINATTRTIMO;
7089ec7b004SRick Macklem if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0)
7099ec7b004SRick Macklem nmp->nm_acregmax = argp->acregmax;
7109ec7b004SRick Macklem else
7119ec7b004SRick Macklem nmp->nm_acregmax = NFS_MAXATTRTIMO;
7129ec7b004SRick Macklem if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0)
7139ec7b004SRick Macklem nmp->nm_acdirmin = argp->acdirmin;
7149ec7b004SRick Macklem else
7159ec7b004SRick Macklem nmp->nm_acdirmin = NFS_MINDIRATTRTIMO;
7169ec7b004SRick Macklem if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0)
7179ec7b004SRick Macklem nmp->nm_acdirmax = argp->acdirmax;
7189ec7b004SRick Macklem else
7199ec7b004SRick Macklem nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO;
7209ec7b004SRick Macklem if (nmp->nm_acdirmin > nmp->nm_acdirmax)
7219ec7b004SRick Macklem nmp->nm_acdirmin = nmp->nm_acdirmax;
7229ec7b004SRick Macklem if (nmp->nm_acregmin > nmp->nm_acregmax)
7239ec7b004SRick Macklem nmp->nm_acregmin = nmp->nm_acregmax;
7249ec7b004SRick Macklem
7259ec7b004SRick Macklem if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) {
7269ec7b004SRick Macklem if (argp->readahead <= NFS_MAXRAHEAD)
7279ec7b004SRick Macklem nmp->nm_readahead = argp->readahead;
7289ec7b004SRick Macklem else
7299ec7b004SRick Macklem nmp->nm_readahead = NFS_MAXRAHEAD;
7309ec7b004SRick Macklem }
7319ec7b004SRick Macklem if ((argp->flags & NFSMNT_WCOMMITSIZE) && argp->wcommitsize >= 0) {
7329ec7b004SRick Macklem if (argp->wcommitsize < nmp->nm_wsize)
7339ec7b004SRick Macklem nmp->nm_wcommitsize = nmp->nm_wsize;
7349ec7b004SRick Macklem else
7359ec7b004SRick Macklem nmp->nm_wcommitsize = argp->wcommitsize;
7369ec7b004SRick Macklem }
7379ec7b004SRick Macklem
7389ec7b004SRick Macklem adjsock |= ((nmp->nm_sotype != argp->sotype) ||
7399ec7b004SRick Macklem (nmp->nm_soproto != argp->proto));
7409ec7b004SRick Macklem
7419ec7b004SRick Macklem if (nmp->nm_client != NULL && adjsock) {
7429ec7b004SRick Macklem int haslock = 0, error = 0;
7439ec7b004SRick Macklem
7449ec7b004SRick Macklem if (nmp->nm_sotype == SOCK_STREAM) {
7459ec7b004SRick Macklem error = newnfs_sndlock(&nmp->nm_sockreq.nr_lock);
7469ec7b004SRick Macklem if (!error)
7479ec7b004SRick Macklem haslock = 1;
7489ec7b004SRick Macklem }
7499ec7b004SRick Macklem if (!error) {
7501e0a518dSRick Macklem newnfs_disconnect(nmp, &nmp->nm_sockreq);
7519ec7b004SRick Macklem if (haslock)
7529ec7b004SRick Macklem newnfs_sndunlock(&nmp->nm_sockreq.nr_lock);
7539ec7b004SRick Macklem nmp->nm_sotype = argp->sotype;
7549ec7b004SRick Macklem nmp->nm_soproto = argp->proto;
7559ec7b004SRick Macklem if (nmp->nm_sotype == SOCK_DGRAM)
7569ec7b004SRick Macklem while (newnfs_connect(nmp, &nmp->nm_sockreq,
7571e0a518dSRick Macklem cred, td, 0, false, &nmp->nm_sockreq.nr_client)) {
7589ec7b004SRick Macklem printf("newnfs_args: retrying connect\n");
759c15882f0SRick Macklem (void) nfs_catnap(PSOCK, 0, "nfscon");
7609ec7b004SRick Macklem }
7619ec7b004SRick Macklem }
7629ec7b004SRick Macklem } else {
7639ec7b004SRick Macklem nmp->nm_sotype = argp->sotype;
7649ec7b004SRick Macklem nmp->nm_soproto = argp->proto;
7659ec7b004SRick Macklem }
766ca27c028SRick Macklem
767ca27c028SRick Macklem if (hostname != NULL) {
768ca27c028SRick Macklem strlcpy(nmp->nm_hostname, hostname,
769ca27c028SRick Macklem sizeof(nmp->nm_hostname));
770ca27c028SRick Macklem p = strchr(nmp->nm_hostname, ':');
771ca27c028SRick Macklem if (p != NULL)
772ca27c028SRick Macklem *p = '\0';
773ca27c028SRick Macklem }
7749ec7b004SRick Macklem }
7759ec7b004SRick Macklem
77661c82720SRick Macklem static const char *nfs_opts[] = { "from", "nfs_args",
7775a06ac35SEdward Tomasz Napierala "noac", "noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union",
7789ec7b004SRick Macklem "noclusterr", "noclusterw", "multilabel", "acls", "force", "update",
779682eec57SRick Macklem "async", "noconn", "nolockd", "conn", "lockd", "intr", "rdirplus",
780682eec57SRick Macklem "readdirsize", "soft", "hard", "mntudp", "tcp", "udp", "wsize", "rsize",
7815a06ac35SEdward Tomasz Napierala "retrans", "actimeo", "acregmin", "acregmax", "acdirmin", "acdirmax",
7825a06ac35SEdward Tomasz Napierala "resvport", "readahead", "hostname", "timeo", "timeout", "addr", "fh",
7835a06ac35SEdward Tomasz Napierala "nfsv3", "sec", "principal", "nfsv4", "gssname", "allgssname", "dirpath",
7845a06ac35SEdward Tomasz Napierala "minorversion", "nametimeo", "negnametimeo", "nocto", "noncontigwr",
7851e0a518dSRick Macklem "pnfs", "wcommitsize", "oneopenown", "tls", "tlscertname", "nconnect",
786896516e5SRick Macklem "syskrb5", NULL };
7879ec7b004SRick Macklem
7889ec7b004SRick Macklem /*
7890d1654c3SEdward Tomasz Napierala * Parse the "from" mountarg, passed by the generic mount(8) program
7900d1654c3SEdward Tomasz Napierala * or the mountroot code. This is used when rerooting into NFS.
7910d1654c3SEdward Tomasz Napierala *
7920d1654c3SEdward Tomasz Napierala * Note that the "hostname" is actually a "hostname:/share/path" string.
7930d1654c3SEdward Tomasz Napierala */
7940d1654c3SEdward Tomasz Napierala static int
nfs_mount_parse_from(struct vfsoptlist * opts,char ** hostnamep,struct sockaddr_in ** sinp,char * dirpath,size_t dirpathsize,int * dirlenp)7950d1654c3SEdward Tomasz Napierala nfs_mount_parse_from(struct vfsoptlist *opts, char **hostnamep,
7960d1654c3SEdward Tomasz Napierala struct sockaddr_in **sinp, char *dirpath, size_t dirpathsize, int *dirlenp)
7970d1654c3SEdward Tomasz Napierala {
798599009e2SKonstantin Belousov char *nam, *delimp, *hostp, *spec;
7990d1654c3SEdward Tomasz Napierala int error, have_bracket = 0, offset, rv, speclen;
8000d1654c3SEdward Tomasz Napierala struct sockaddr_in *sin;
8010d1654c3SEdward Tomasz Napierala size_t len;
8020d1654c3SEdward Tomasz Napierala
8030d1654c3SEdward Tomasz Napierala error = vfs_getopt(opts, "from", (void **)&spec, &speclen);
8040d1654c3SEdward Tomasz Napierala if (error != 0)
8050d1654c3SEdward Tomasz Napierala return (error);
806599009e2SKonstantin Belousov nam = malloc(MNAMELEN + 1, M_TEMP, M_WAITOK);
8070d1654c3SEdward Tomasz Napierala
8080d1654c3SEdward Tomasz Napierala /*
8090d1654c3SEdward Tomasz Napierala * This part comes from sbin/mount_nfs/mount_nfs.c:getnfsargs().
8100d1654c3SEdward Tomasz Napierala */
8110d1654c3SEdward Tomasz Napierala if (*spec == '[' && (delimp = strchr(spec + 1, ']')) != NULL &&
8120d1654c3SEdward Tomasz Napierala *(delimp + 1) == ':') {
8130d1654c3SEdward Tomasz Napierala hostp = spec + 1;
8140d1654c3SEdward Tomasz Napierala spec = delimp + 2;
8150d1654c3SEdward Tomasz Napierala have_bracket = 1;
8160d1654c3SEdward Tomasz Napierala } else if ((delimp = strrchr(spec, ':')) != NULL) {
8170d1654c3SEdward Tomasz Napierala hostp = spec;
8180d1654c3SEdward Tomasz Napierala spec = delimp + 1;
8190d1654c3SEdward Tomasz Napierala } else if ((delimp = strrchr(spec, '@')) != NULL) {
8200d1654c3SEdward Tomasz Napierala printf("%s: path@server syntax is deprecated, "
8210d1654c3SEdward Tomasz Napierala "use server:path\n", __func__);
8220d1654c3SEdward Tomasz Napierala hostp = delimp + 1;
8230d1654c3SEdward Tomasz Napierala } else {
8240d1654c3SEdward Tomasz Napierala printf("%s: no <host>:<dirpath> nfs-name\n", __func__);
825599009e2SKonstantin Belousov free(nam, M_TEMP);
8260d1654c3SEdward Tomasz Napierala return (EINVAL);
8270d1654c3SEdward Tomasz Napierala }
8280d1654c3SEdward Tomasz Napierala *delimp = '\0';
8290d1654c3SEdward Tomasz Napierala
8300d1654c3SEdward Tomasz Napierala /*
8310d1654c3SEdward Tomasz Napierala * If there has been a trailing slash at mounttime it seems
8320d1654c3SEdward Tomasz Napierala * that some mountd implementations fail to remove the mount
8330d1654c3SEdward Tomasz Napierala * entries from their mountlist while unmounting.
8340d1654c3SEdward Tomasz Napierala */
8350d1654c3SEdward Tomasz Napierala for (speclen = strlen(spec);
8360d1654c3SEdward Tomasz Napierala speclen > 1 && spec[speclen - 1] == '/';
8370d1654c3SEdward Tomasz Napierala speclen--)
8380d1654c3SEdward Tomasz Napierala spec[speclen - 1] = '\0';
8390d1654c3SEdward Tomasz Napierala if (strlen(hostp) + strlen(spec) + 1 > MNAMELEN) {
8400d1654c3SEdward Tomasz Napierala printf("%s: %s:%s: name too long", __func__, hostp, spec);
841599009e2SKonstantin Belousov free(nam, M_TEMP);
8420d1654c3SEdward Tomasz Napierala return (EINVAL);
8430d1654c3SEdward Tomasz Napierala }
8440d1654c3SEdward Tomasz Napierala /* Make both '@' and ':' notations equal */
8450d1654c3SEdward Tomasz Napierala if (*hostp != '\0') {
8460d1654c3SEdward Tomasz Napierala len = strlen(hostp);
8470d1654c3SEdward Tomasz Napierala offset = 0;
8480d1654c3SEdward Tomasz Napierala if (have_bracket)
8490d1654c3SEdward Tomasz Napierala nam[offset++] = '[';
8500d1654c3SEdward Tomasz Napierala memmove(nam + offset, hostp, len);
8510d1654c3SEdward Tomasz Napierala if (have_bracket)
8520d1654c3SEdward Tomasz Napierala nam[len + offset++] = ']';
8530d1654c3SEdward Tomasz Napierala nam[len + offset++] = ':';
8540d1654c3SEdward Tomasz Napierala memmove(nam + len + offset, spec, speclen);
8550d1654c3SEdward Tomasz Napierala nam[len + speclen + offset] = '\0';
85615634fd6SConrad Meyer } else
85715634fd6SConrad Meyer nam[0] = '\0';
8580d1654c3SEdward Tomasz Napierala
8590d1654c3SEdward Tomasz Napierala /*
8600d1654c3SEdward Tomasz Napierala * XXX: IPv6
8610d1654c3SEdward Tomasz Napierala */
8620d1654c3SEdward Tomasz Napierala sin = malloc(sizeof(*sin), M_SONAME, M_WAITOK);
8630d1654c3SEdward Tomasz Napierala rv = inet_pton(AF_INET, hostp, &sin->sin_addr);
8640d1654c3SEdward Tomasz Napierala if (rv != 1) {
8650d1654c3SEdward Tomasz Napierala printf("%s: cannot parse '%s', inet_pton() returned %d\n",
8660d1654c3SEdward Tomasz Napierala __func__, hostp, rv);
867599009e2SKonstantin Belousov free(nam, M_TEMP);
8680d1654c3SEdward Tomasz Napierala free(sin, M_SONAME);
8690d1654c3SEdward Tomasz Napierala return (EINVAL);
8700d1654c3SEdward Tomasz Napierala }
8710d1654c3SEdward Tomasz Napierala
8720d1654c3SEdward Tomasz Napierala sin->sin_len = sizeof(*sin);
8730d1654c3SEdward Tomasz Napierala sin->sin_family = AF_INET;
8740d1654c3SEdward Tomasz Napierala /*
8750d1654c3SEdward Tomasz Napierala * XXX: hardcoded port number.
8760d1654c3SEdward Tomasz Napierala */
8770d1654c3SEdward Tomasz Napierala sin->sin_port = htons(2049);
8780d1654c3SEdward Tomasz Napierala
8790d1654c3SEdward Tomasz Napierala *hostnamep = strdup(nam, M_NEWNFSMNT);
8800d1654c3SEdward Tomasz Napierala *sinp = sin;
8810d1654c3SEdward Tomasz Napierala strlcpy(dirpath, spec, dirpathsize);
8820d1654c3SEdward Tomasz Napierala *dirlenp = strlen(dirpath);
8830d1654c3SEdward Tomasz Napierala
884599009e2SKonstantin Belousov free(nam, M_TEMP);
8850d1654c3SEdward Tomasz Napierala return (0);
8860d1654c3SEdward Tomasz Napierala }
8870d1654c3SEdward Tomasz Napierala
8880d1654c3SEdward Tomasz Napierala /*
8899ec7b004SRick Macklem * VFS Operations.
8909ec7b004SRick Macklem *
8919ec7b004SRick Macklem * mount system call
8929ec7b004SRick Macklem * It seems a bit dumb to copyinstr() the host and path here and then
8939ec7b004SRick Macklem * bcopy() them in mountnfs(), but I wanted to detect errors before
894fefbf770SGleb Smirnoff * doing the getsockaddr() call because getsockaddr() allocates an mbuf and
8959ec7b004SRick Macklem * an error after that means that I have to release the mbuf.
8969ec7b004SRick Macklem */
8979ec7b004SRick Macklem /* ARGSUSED */
8989ec7b004SRick Macklem static int
nfs_mount(struct mount * mp)899dfd233edSAttilio Rao nfs_mount(struct mount *mp)
9009ec7b004SRick Macklem {
9019ec7b004SRick Macklem struct nfs_args args = {
9029ec7b004SRick Macklem .version = NFS_ARGSVERSION,
9039ec7b004SRick Macklem .addr = NULL,
9049ec7b004SRick Macklem .addrlen = sizeof (struct sockaddr_in),
9059ec7b004SRick Macklem .sotype = SOCK_STREAM,
9069ec7b004SRick Macklem .proto = 0,
9079ec7b004SRick Macklem .fh = NULL,
9089ec7b004SRick Macklem .fhsize = 0,
9098e82d541SRick Macklem .flags = NFSMNT_RESVPORT,
9109ec7b004SRick Macklem .wsize = NFS_WSIZE,
9119ec7b004SRick Macklem .rsize = NFS_RSIZE,
9129ec7b004SRick Macklem .readdirsize = NFS_READDIRSIZE,
9139ec7b004SRick Macklem .timeo = 10,
9149ec7b004SRick Macklem .retrans = NFS_RETRANS,
9159ec7b004SRick Macklem .readahead = NFS_DEFRAHEAD,
9169ec7b004SRick Macklem .wcommitsize = 0, /* was: NQ_DEFLEASE */
9179ec7b004SRick Macklem .hostname = NULL,
9189ec7b004SRick Macklem .acregmin = NFS_MINATTRTIMO,
9199ec7b004SRick Macklem .acregmax = NFS_MAXATTRTIMO,
9209ec7b004SRick Macklem .acdirmin = NFS_MINDIRATTRTIMO,
9219ec7b004SRick Macklem .acdirmax = NFS_MAXDIRATTRTIMO,
9229ec7b004SRick Macklem };
923682eec57SRick Macklem int error = 0, ret, len;
924682eec57SRick Macklem struct sockaddr *nam = NULL;
9259ec7b004SRick Macklem struct vnode *vp;
926dfd233edSAttilio Rao struct thread *td;
927599009e2SKonstantin Belousov char *hst;
9289ec7b004SRick Macklem u_char nfh[NFSX_FHMAX], krbname[100], dirpath[100], srvkrbname[100];
929665b1365SRick Macklem char *cp, *opt, *name, *secname, *tlscertname;
9300b17c7beSJohn Baldwin int nametimeo = NFS_DEFAULT_NAMETIMEO;
931dd5b5a94SRick Macklem int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO;
932a145cf3fSRick Macklem int minvers = -1;
9330d1654c3SEdward Tomasz Napierala int dirlen, has_nfs_args_opt, has_nfs_from_opt,
9340d1654c3SEdward Tomasz Napierala krbnamelen, srvkrbnamelen;
9358b713a2fSRick Macklem size_t hstlen;
9366e4b6ff8SRick Macklem uint32_t newflag;
9371e0a518dSRick Macklem int aconn = 0;
9389ec7b004SRick Macklem
93961c82720SRick Macklem has_nfs_args_opt = 0;
9400d1654c3SEdward Tomasz Napierala has_nfs_from_opt = 0;
9416e4b6ff8SRick Macklem newflag = 0;
942665b1365SRick Macklem tlscertname = NULL;
943599009e2SKonstantin Belousov hst = malloc(MNAMELEN, M_TEMP, M_WAITOK);
9449ec7b004SRick Macklem if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) {
9459ec7b004SRick Macklem error = EINVAL;
9469ec7b004SRick Macklem goto out;
9479ec7b004SRick Macklem }
9489ec7b004SRick Macklem
949dfd233edSAttilio Rao td = curthread;
9500d1654c3SEdward Tomasz Napierala if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS &&
9510d1654c3SEdward Tomasz Napierala nfs_diskless_valid != 0) {
9528954032fSRick Macklem error = nfs_mountroot(mp);
9539ec7b004SRick Macklem goto out;
9549ec7b004SRick Macklem }
9559ec7b004SRick Macklem
956682eec57SRick Macklem nfscl_init();
9579ec7b004SRick Macklem
95861c82720SRick Macklem /*
95961c82720SRick Macklem * The old mount_nfs program passed the struct nfs_args
96061c82720SRick Macklem * from userspace to kernel. The new mount_nfs program
96161c82720SRick Macklem * passes string options via nmount() from userspace to kernel
96261c82720SRick Macklem * and we populate the struct nfs_args in the kernel.
96361c82720SRick Macklem */
96461c82720SRick Macklem if (vfs_getopt(mp->mnt_optnew, "nfs_args", NULL, NULL) == 0) {
96561c82720SRick Macklem error = vfs_copyopt(mp->mnt_optnew, "nfs_args", &args,
96661c82720SRick Macklem sizeof(args));
96761c82720SRick Macklem if (error != 0)
96861c82720SRick Macklem goto out;
96961c82720SRick Macklem
97061c82720SRick Macklem if (args.version != NFS_ARGSVERSION) {
97161c82720SRick Macklem error = EPROGMISMATCH;
97261c82720SRick Macklem goto out;
97361c82720SRick Macklem }
97461c82720SRick Macklem has_nfs_args_opt = 1;
97561c82720SRick Macklem }
97661c82720SRick Macklem
977682eec57SRick Macklem /* Handle the new style options. */
9785a06ac35SEdward Tomasz Napierala if (vfs_getopt(mp->mnt_optnew, "noac", NULL, NULL) == 0) {
9795a06ac35SEdward Tomasz Napierala args.acdirmin = args.acdirmax =
9805a06ac35SEdward Tomasz Napierala args.acregmin = args.acregmax = 0;
9815a06ac35SEdward Tomasz Napierala args.flags |= NFSMNT_ACDIRMIN | NFSMNT_ACDIRMAX |
9825a06ac35SEdward Tomasz Napierala NFSMNT_ACREGMIN | NFSMNT_ACREGMAX;
9835a06ac35SEdward Tomasz Napierala }
984682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "noconn", NULL, NULL) == 0)
985682eec57SRick Macklem args.flags |= NFSMNT_NOCONN;
986682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "conn", NULL, NULL) == 0)
9872fbe0cffSEdward Tomasz Napierala args.flags &= ~NFSMNT_NOCONN;
988682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "nolockd", NULL, NULL) == 0)
989682eec57SRick Macklem args.flags |= NFSMNT_NOLOCKD;
990682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "lockd", NULL, NULL) == 0)
991682eec57SRick Macklem args.flags &= ~NFSMNT_NOLOCKD;
992682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "intr", NULL, NULL) == 0)
993682eec57SRick Macklem args.flags |= NFSMNT_INT;
994682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "rdirplus", NULL, NULL) == 0)
995682eec57SRick Macklem args.flags |= NFSMNT_RDIRPLUS;
996682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "resvport", NULL, NULL) == 0)
997682eec57SRick Macklem args.flags |= NFSMNT_RESVPORT;
998682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "noresvport", NULL, NULL) == 0)
999682eec57SRick Macklem args.flags &= ~NFSMNT_RESVPORT;
1000682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "soft", NULL, NULL) == 0)
1001682eec57SRick Macklem args.flags |= NFSMNT_SOFT;
1002682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "hard", NULL, NULL) == 0)
1003682eec57SRick Macklem args.flags &= ~NFSMNT_SOFT;
1004682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "mntudp", NULL, NULL) == 0)
1005682eec57SRick Macklem args.sotype = SOCK_DGRAM;
1006682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "udp", NULL, NULL) == 0)
1007682eec57SRick Macklem args.sotype = SOCK_DGRAM;
1008682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "tcp", NULL, NULL) == 0)
1009682eec57SRick Macklem args.sotype = SOCK_STREAM;
1010682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "nfsv3", NULL, NULL) == 0)
1011682eec57SRick Macklem args.flags |= NFSMNT_NFSV3;
1012682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "nfsv4", NULL, NULL) == 0) {
1013682eec57SRick Macklem args.flags |= NFSMNT_NFSV4;
1014682eec57SRick Macklem args.sotype = SOCK_STREAM;
1015682eec57SRick Macklem }
1016682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "allgssname", NULL, NULL) == 0)
1017682eec57SRick Macklem args.flags |= NFSMNT_ALLGSSNAME;
1018e2f2b370SRuslan Ermilov if (vfs_getopt(mp->mnt_optnew, "nocto", NULL, NULL) == 0)
1019e2f2b370SRuslan Ermilov args.flags |= NFSMNT_NOCTO;
1020cf766161SRick Macklem if (vfs_getopt(mp->mnt_optnew, "noncontigwr", NULL, NULL) == 0)
1021cf766161SRick Macklem args.flags |= NFSMNT_NONCONTIGWR;
10221f60bfd8SRick Macklem if (vfs_getopt(mp->mnt_optnew, "pnfs", NULL, NULL) == 0)
10231f60bfd8SRick Macklem args.flags |= NFSMNT_PNFS;
1024037a2012SRick Macklem if (vfs_getopt(mp->mnt_optnew, "oneopenown", NULL, NULL) == 0)
1025037a2012SRick Macklem args.flags |= NFSMNT_ONEOPENOWN;
10266e4b6ff8SRick Macklem if (vfs_getopt(mp->mnt_optnew, "tls", NULL, NULL) == 0)
10276e4b6ff8SRick Macklem newflag |= NFSMNT_TLS;
1028665b1365SRick Macklem if (vfs_getopt(mp->mnt_optnew, "tlscertname", (void **)&opt, &len) ==
1029665b1365SRick Macklem 0) {
1030665b1365SRick Macklem /*
1031665b1365SRick Macklem * tlscertname with "key.pem" appended to it forms a file
1032665b1365SRick Macklem * name. As such, the maximum allowable strlen(tlscertname) is
1033665b1365SRick Macklem * NAME_MAX - 7. However, "len" includes the nul termination
1034665b1365SRick Macklem * byte so it can be up to NAME_MAX - 6.
1035665b1365SRick Macklem */
1036665b1365SRick Macklem if (opt == NULL || len <= 1 || len > NAME_MAX - 6) {
1037665b1365SRick Macklem vfs_mount_error(mp, "invalid tlscertname");
1038665b1365SRick Macklem error = EINVAL;
1039665b1365SRick Macklem goto out;
1040665b1365SRick Macklem }
1041665b1365SRick Macklem tlscertname = malloc(len, M_NEWNFSMNT, M_WAITOK);
1042665b1365SRick Macklem strlcpy(tlscertname, opt, len);
1043665b1365SRick Macklem }
1044682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) {
1045682eec57SRick Macklem if (opt == NULL) {
1046682eec57SRick Macklem vfs_mount_error(mp, "illegal readdirsize");
1047682eec57SRick Macklem error = EINVAL;
10489ec7b004SRick Macklem goto out;
10499ec7b004SRick Macklem }
1050682eec57SRick Macklem ret = sscanf(opt, "%d", &args.readdirsize);
1051682eec57SRick Macklem if (ret != 1 || args.readdirsize <= 0) {
1052682eec57SRick Macklem vfs_mount_error(mp, "illegal readdirsize: %s",
1053682eec57SRick Macklem opt);
1054682eec57SRick Macklem error = EINVAL;
1055682eec57SRick Macklem goto out;
1056682eec57SRick Macklem }
1057682eec57SRick Macklem args.flags |= NFSMNT_READDIRSIZE;
1058682eec57SRick Macklem }
1059682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) {
1060682eec57SRick Macklem if (opt == NULL) {
1061682eec57SRick Macklem vfs_mount_error(mp, "illegal readahead");
1062682eec57SRick Macklem error = EINVAL;
1063682eec57SRick Macklem goto out;
1064682eec57SRick Macklem }
1065682eec57SRick Macklem ret = sscanf(opt, "%d", &args.readahead);
1066682eec57SRick Macklem if (ret != 1 || args.readahead <= 0) {
1067682eec57SRick Macklem vfs_mount_error(mp, "illegal readahead: %s",
1068682eec57SRick Macklem opt);
1069682eec57SRick Macklem error = EINVAL;
1070682eec57SRick Macklem goto out;
1071682eec57SRick Macklem }
1072682eec57SRick Macklem args.flags |= NFSMNT_READAHEAD;
1073682eec57SRick Macklem }
1074682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) {
1075682eec57SRick Macklem if (opt == NULL) {
1076682eec57SRick Macklem vfs_mount_error(mp, "illegal wsize");
1077682eec57SRick Macklem error = EINVAL;
1078682eec57SRick Macklem goto out;
1079682eec57SRick Macklem }
1080682eec57SRick Macklem ret = sscanf(opt, "%d", &args.wsize);
1081682eec57SRick Macklem if (ret != 1 || args.wsize <= 0) {
1082682eec57SRick Macklem vfs_mount_error(mp, "illegal wsize: %s",
1083682eec57SRick Macklem opt);
1084682eec57SRick Macklem error = EINVAL;
1085682eec57SRick Macklem goto out;
1086682eec57SRick Macklem }
1087682eec57SRick Macklem args.flags |= NFSMNT_WSIZE;
1088682eec57SRick Macklem }
1089682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) {
1090682eec57SRick Macklem if (opt == NULL) {
1091682eec57SRick Macklem vfs_mount_error(mp, "illegal rsize");
1092682eec57SRick Macklem error = EINVAL;
1093682eec57SRick Macklem goto out;
1094682eec57SRick Macklem }
1095682eec57SRick Macklem ret = sscanf(opt, "%d", &args.rsize);
1096682eec57SRick Macklem if (ret != 1 || args.rsize <= 0) {
1097682eec57SRick Macklem vfs_mount_error(mp, "illegal wsize: %s",
1098682eec57SRick Macklem opt);
1099682eec57SRick Macklem error = EINVAL;
1100682eec57SRick Macklem goto out;
1101682eec57SRick Macklem }
1102682eec57SRick Macklem args.flags |= NFSMNT_RSIZE;
1103682eec57SRick Macklem }
1104682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) {
1105682eec57SRick Macklem if (opt == NULL) {
1106682eec57SRick Macklem vfs_mount_error(mp, "illegal retrans");
1107682eec57SRick Macklem error = EINVAL;
1108682eec57SRick Macklem goto out;
1109682eec57SRick Macklem }
1110682eec57SRick Macklem ret = sscanf(opt, "%d", &args.retrans);
1111682eec57SRick Macklem if (ret != 1 || args.retrans <= 0) {
1112682eec57SRick Macklem vfs_mount_error(mp, "illegal retrans: %s",
1113682eec57SRick Macklem opt);
1114682eec57SRick Macklem error = EINVAL;
1115682eec57SRick Macklem goto out;
1116682eec57SRick Macklem }
1117682eec57SRick Macklem args.flags |= NFSMNT_RETRANS;
1118682eec57SRick Macklem }
11195a06ac35SEdward Tomasz Napierala if (vfs_getopt(mp->mnt_optnew, "actimeo", (void **)&opt, NULL) == 0) {
11205a06ac35SEdward Tomasz Napierala ret = sscanf(opt, "%d", &args.acregmin);
11215a06ac35SEdward Tomasz Napierala if (ret != 1 || args.acregmin < 0) {
11225a06ac35SEdward Tomasz Napierala vfs_mount_error(mp, "illegal actimeo: %s",
11235a06ac35SEdward Tomasz Napierala opt);
11245a06ac35SEdward Tomasz Napierala error = EINVAL;
11255a06ac35SEdward Tomasz Napierala goto out;
11265a06ac35SEdward Tomasz Napierala }
11275a06ac35SEdward Tomasz Napierala args.acdirmin = args.acdirmax = args.acregmax = args.acregmin;
11285a06ac35SEdward Tomasz Napierala args.flags |= NFSMNT_ACDIRMIN | NFSMNT_ACDIRMAX |
11295a06ac35SEdward Tomasz Napierala NFSMNT_ACREGMIN | NFSMNT_ACREGMAX;
11305a06ac35SEdward Tomasz Napierala }
1131682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "acregmin", (void **)&opt, NULL) == 0) {
1132682eec57SRick Macklem ret = sscanf(opt, "%d", &args.acregmin);
1133682eec57SRick Macklem if (ret != 1 || args.acregmin < 0) {
1134682eec57SRick Macklem vfs_mount_error(mp, "illegal acregmin: %s",
1135682eec57SRick Macklem opt);
1136682eec57SRick Macklem error = EINVAL;
1137682eec57SRick Macklem goto out;
1138682eec57SRick Macklem }
1139682eec57SRick Macklem args.flags |= NFSMNT_ACREGMIN;
1140682eec57SRick Macklem }
1141682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "acregmax", (void **)&opt, NULL) == 0) {
1142682eec57SRick Macklem ret = sscanf(opt, "%d", &args.acregmax);
1143682eec57SRick Macklem if (ret != 1 || args.acregmax < 0) {
1144682eec57SRick Macklem vfs_mount_error(mp, "illegal acregmax: %s",
1145682eec57SRick Macklem opt);
1146682eec57SRick Macklem error = EINVAL;
1147682eec57SRick Macklem goto out;
1148682eec57SRick Macklem }
1149682eec57SRick Macklem args.flags |= NFSMNT_ACREGMAX;
1150682eec57SRick Macklem }
1151682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "acdirmin", (void **)&opt, NULL) == 0) {
1152682eec57SRick Macklem ret = sscanf(opt, "%d", &args.acdirmin);
1153682eec57SRick Macklem if (ret != 1 || args.acdirmin < 0) {
1154682eec57SRick Macklem vfs_mount_error(mp, "illegal acdirmin: %s",
1155682eec57SRick Macklem opt);
1156682eec57SRick Macklem error = EINVAL;
1157682eec57SRick Macklem goto out;
1158682eec57SRick Macklem }
1159682eec57SRick Macklem args.flags |= NFSMNT_ACDIRMIN;
1160682eec57SRick Macklem }
1161682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "acdirmax", (void **)&opt, NULL) == 0) {
1162682eec57SRick Macklem ret = sscanf(opt, "%d", &args.acdirmax);
1163682eec57SRick Macklem if (ret != 1 || args.acdirmax < 0) {
1164682eec57SRick Macklem vfs_mount_error(mp, "illegal acdirmax: %s",
1165682eec57SRick Macklem opt);
1166682eec57SRick Macklem error = EINVAL;
1167682eec57SRick Macklem goto out;
1168682eec57SRick Macklem }
1169682eec57SRick Macklem args.flags |= NFSMNT_ACDIRMAX;
1170682eec57SRick Macklem }
1171840fb1c0SJohn Baldwin if (vfs_getopt(mp->mnt_optnew, "wcommitsize", (void **)&opt, NULL) == 0) {
1172840fb1c0SJohn Baldwin ret = sscanf(opt, "%d", &args.wcommitsize);
1173840fb1c0SJohn Baldwin if (ret != 1 || args.wcommitsize < 0) {
1174840fb1c0SJohn Baldwin vfs_mount_error(mp, "illegal wcommitsize: %s", opt);
1175840fb1c0SJohn Baldwin error = EINVAL;
1176840fb1c0SJohn Baldwin goto out;
1177840fb1c0SJohn Baldwin }
1178840fb1c0SJohn Baldwin args.flags |= NFSMNT_WCOMMITSIZE;
1179840fb1c0SJohn Baldwin }
11805a06ac35SEdward Tomasz Napierala if (vfs_getopt(mp->mnt_optnew, "timeo", (void **)&opt, NULL) == 0) {
11815a06ac35SEdward Tomasz Napierala ret = sscanf(opt, "%d", &args.timeo);
11825a06ac35SEdward Tomasz Napierala if (ret != 1 || args.timeo <= 0) {
11835a06ac35SEdward Tomasz Napierala vfs_mount_error(mp, "illegal timeo: %s",
11845a06ac35SEdward Tomasz Napierala opt);
11855a06ac35SEdward Tomasz Napierala error = EINVAL;
11865a06ac35SEdward Tomasz Napierala goto out;
11875a06ac35SEdward Tomasz Napierala }
11885a06ac35SEdward Tomasz Napierala args.flags |= NFSMNT_TIMEO;
11895a06ac35SEdward Tomasz Napierala }
1190682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "timeout", (void **)&opt, NULL) == 0) {
1191682eec57SRick Macklem ret = sscanf(opt, "%d", &args.timeo);
1192682eec57SRick Macklem if (ret != 1 || args.timeo <= 0) {
1193682eec57SRick Macklem vfs_mount_error(mp, "illegal timeout: %s",
1194682eec57SRick Macklem opt);
1195682eec57SRick Macklem error = EINVAL;
1196682eec57SRick Macklem goto out;
1197682eec57SRick Macklem }
1198682eec57SRick Macklem args.flags |= NFSMNT_TIMEO;
1199682eec57SRick Macklem }
12000b17c7beSJohn Baldwin if (vfs_getopt(mp->mnt_optnew, "nametimeo", (void **)&opt, NULL) == 0) {
12010b17c7beSJohn Baldwin ret = sscanf(opt, "%d", &nametimeo);
12020b17c7beSJohn Baldwin if (ret != 1 || nametimeo < 0) {
12030b17c7beSJohn Baldwin vfs_mount_error(mp, "illegal nametimeo: %s", opt);
12040b17c7beSJohn Baldwin error = EINVAL;
12050b17c7beSJohn Baldwin goto out;
12060b17c7beSJohn Baldwin }
12070b17c7beSJohn Baldwin }
1208dd5b5a94SRick Macklem if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL)
1209dd5b5a94SRick Macklem == 0) {
1210dd5b5a94SRick Macklem ret = sscanf(opt, "%d", &negnametimeo);
1211dd5b5a94SRick Macklem if (ret != 1 || negnametimeo < 0) {
1212dd5b5a94SRick Macklem vfs_mount_error(mp, "illegal negnametimeo: %s",
1213dd5b5a94SRick Macklem opt);
1214dd5b5a94SRick Macklem error = EINVAL;
1215dd5b5a94SRick Macklem goto out;
1216dd5b5a94SRick Macklem }
1217dd5b5a94SRick Macklem }
12181f60bfd8SRick Macklem if (vfs_getopt(mp->mnt_optnew, "minorversion", (void **)&opt, NULL) ==
12191f60bfd8SRick Macklem 0) {
12201f60bfd8SRick Macklem ret = sscanf(opt, "%d", &minvers);
1221c057a378SRick Macklem if (ret != 1 || minvers < 0 || minvers > 2 ||
12221f60bfd8SRick Macklem (args.flags & NFSMNT_NFSV4) == 0) {
12231f60bfd8SRick Macklem vfs_mount_error(mp, "illegal minorversion: %s", opt);
12241f60bfd8SRick Macklem error = EINVAL;
12251f60bfd8SRick Macklem goto out;
12261f60bfd8SRick Macklem }
12271f60bfd8SRick Macklem }
12281e0a518dSRick Macklem if (vfs_getopt(mp->mnt_optnew, "nconnect", (void **)&opt, NULL) ==
12291e0a518dSRick Macklem 0) {
12301e0a518dSRick Macklem ret = sscanf(opt, "%d", &aconn);
12311e0a518dSRick Macklem if (ret != 1 || aconn < 1 || aconn > NFS_MAXNCONN) {
12321e0a518dSRick Macklem vfs_mount_error(mp, "illegal nconnect: %s", opt);
12331e0a518dSRick Macklem error = EINVAL;
12341e0a518dSRick Macklem goto out;
12351e0a518dSRick Macklem }
12361e0a518dSRick Macklem /*
12371e0a518dSRick Macklem * Setting nconnect=1 is a no-op, allowed so that
12381e0a518dSRick Macklem * the option can be used in a Linux compatible way.
12391e0a518dSRick Macklem */
12401e0a518dSRick Macklem aconn--;
12411e0a518dSRick Macklem }
1242896516e5SRick Macklem if (vfs_getopt(mp->mnt_optnew, "syskrb5", NULL, NULL) == 0)
1243896516e5SRick Macklem newflag |= NFSMNT_SYSKRB5;
1244682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "sec",
1245682eec57SRick Macklem (void **) &secname, NULL) == 0)
1246682eec57SRick Macklem nfs_sec_name(secname, &args.flags);
12479ec7b004SRick Macklem
12489ec7b004SRick Macklem if (mp->mnt_flag & MNT_UPDATE) {
12499ec7b004SRick Macklem struct nfsmount *nmp = VFSTONFS(mp);
12509ec7b004SRick Macklem
12519ec7b004SRick Macklem if (nmp == NULL) {
12529ec7b004SRick Macklem error = EIO;
12539ec7b004SRick Macklem goto out;
12549ec7b004SRick Macklem }
125587b63367SRick Macklem
125687b63367SRick Macklem /*
125787b63367SRick Macklem * If a change from TCP->UDP is done and there are thread(s)
1258a96c9b30SPedro F. Giffuni * that have I/O RPC(s) in progress with a transfer size
125987b63367SRick Macklem * greater than NFS_MAXDGRAMDATA, those thread(s) will be
126087b63367SRick Macklem * hung, retrying the RPC(s) forever. Usually these threads
126187b63367SRick Macklem * will be seen doing an uninterruptible sleep on wait channel
1262c15882f0SRick Macklem * "nfsreq".
126387b63367SRick Macklem */
126487b63367SRick Macklem if (args.sotype == SOCK_DGRAM && nmp->nm_sotype == SOCK_STREAM)
126587b63367SRick Macklem tprintf(td->td_proc, LOG_WARNING,
126687b63367SRick Macklem "Warning: mount -u that changes TCP->UDP can result in hung threads\n");
126787b63367SRick Macklem
12689ec7b004SRick Macklem /*
12699ec7b004SRick Macklem * When doing an update, we can't change version,
1270037a2012SRick Macklem * security, switch lockd strategies, change cookie
1271037a2012SRick Macklem * translation or switch oneopenown.
12729ec7b004SRick Macklem */
12739ec7b004SRick Macklem args.flags = (args.flags &
12749ec7b004SRick Macklem ~(NFSMNT_NFSV3 |
12759ec7b004SRick Macklem NFSMNT_NFSV4 |
12769ec7b004SRick Macklem NFSMNT_KERB |
12779ec7b004SRick Macklem NFSMNT_INTEGRITY |
12789ec7b004SRick Macklem NFSMNT_PRIVACY |
1279037a2012SRick Macklem NFSMNT_ONEOPENOWN |
12809ec7b004SRick Macklem NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) |
12819ec7b004SRick Macklem (nmp->nm_flag &
12829ec7b004SRick Macklem (NFSMNT_NFSV3 |
12839ec7b004SRick Macklem NFSMNT_NFSV4 |
12849ec7b004SRick Macklem NFSMNT_KERB |
12859ec7b004SRick Macklem NFSMNT_INTEGRITY |
12869ec7b004SRick Macklem NFSMNT_PRIVACY |
1287037a2012SRick Macklem NFSMNT_ONEOPENOWN |
12889ec7b004SRick Macklem NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/));
1289ca27c028SRick Macklem nfs_decode_args(mp, nmp, &args, NULL, td->td_ucred, td);
12909ec7b004SRick Macklem goto out;
12919ec7b004SRick Macklem }
12929ec7b004SRick Macklem
12939ec7b004SRick Macklem /*
12949ec7b004SRick Macklem * Make the nfs_ip_paranoia sysctl serve as the default connection
12959ec7b004SRick Macklem * or no-connection mode for those protocols that support
12969ec7b004SRick Macklem * no-connection mode (the flag will be cleared later for protocols
12979ec7b004SRick Macklem * that do not support no-connection mode). This will allow a client
12989ec7b004SRick Macklem * to receive replies from a different IP then the request was
12999ec7b004SRick Macklem * sent to. Note: default value for nfs_ip_paranoia is 1 (paranoid),
13009ec7b004SRick Macklem * not 0.
13019ec7b004SRick Macklem */
13029ec7b004SRick Macklem if (nfs_ip_paranoia == 0)
13039ec7b004SRick Macklem args.flags |= NFSMNT_NOCONN;
1304682eec57SRick Macklem
130561c82720SRick Macklem if (has_nfs_args_opt != 0) {
130661c82720SRick Macklem /*
130761c82720SRick Macklem * In the 'nfs_args' case, the pointers in the args
130861c82720SRick Macklem * structure are in userland - we copy them in here.
130961c82720SRick Macklem */
131061c82720SRick Macklem if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX) {
131161c82720SRick Macklem vfs_mount_error(mp, "Bad file handle");
131261c82720SRick Macklem error = EINVAL;
131361c82720SRick Macklem goto out;
131461c82720SRick Macklem }
131561c82720SRick Macklem error = copyin((caddr_t)args.fh, (caddr_t)nfh,
131661c82720SRick Macklem args.fhsize);
131761c82720SRick Macklem if (error != 0)
131861c82720SRick Macklem goto out;
13198b713a2fSRick Macklem error = copyinstr(args.hostname, hst, MNAMELEN - 1, &hstlen);
132061c82720SRick Macklem if (error != 0)
132161c82720SRick Macklem goto out;
13228b713a2fSRick Macklem bzero(&hst[hstlen], MNAMELEN - hstlen);
132361c82720SRick Macklem args.hostname = hst;
1324fefbf770SGleb Smirnoff /* getsockaddr() call must be after above copyin() calls */
1325318f0d77SBrooks Davis error = getsockaddr(&nam, args.addr, args.addrlen);
132661c82720SRick Macklem if (error != 0)
132761c82720SRick Macklem goto out;
13280d1654c3SEdward Tomasz Napierala } else if (nfs_mount_parse_from(mp->mnt_optnew,
13290d1654c3SEdward Tomasz Napierala &args.hostname, (struct sockaddr_in **)&nam, dirpath,
13300d1654c3SEdward Tomasz Napierala sizeof(dirpath), &dirlen) == 0) {
13310d1654c3SEdward Tomasz Napierala has_nfs_from_opt = 1;
13320d1654c3SEdward Tomasz Napierala bcopy(args.hostname, hst, MNAMELEN);
13330d1654c3SEdward Tomasz Napierala hst[MNAMELEN - 1] = '\0';
13340d1654c3SEdward Tomasz Napierala
13350d1654c3SEdward Tomasz Napierala /*
13360d1654c3SEdward Tomasz Napierala * This only works with NFSv4 for now.
13370d1654c3SEdward Tomasz Napierala */
13380d1654c3SEdward Tomasz Napierala args.fhsize = 0;
13390d1654c3SEdward Tomasz Napierala args.flags |= NFSMNT_NFSV4;
13400d1654c3SEdward Tomasz Napierala args.sotype = SOCK_STREAM;
134161c82720SRick Macklem } else {
1342682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh,
1343682eec57SRick Macklem &args.fhsize) == 0) {
13445ed9b964SRick Macklem if (args.fhsize < 0 || args.fhsize > NFSX_FHMAX) {
1345682eec57SRick Macklem vfs_mount_error(mp, "Bad file handle");
13469ec7b004SRick Macklem error = EINVAL;
13479ec7b004SRick Macklem goto out;
13489ec7b004SRick Macklem }
1349682eec57SRick Macklem bcopy(args.fh, nfh, args.fhsize);
13509ec7b004SRick Macklem } else {
1351682eec57SRick Macklem args.fhsize = 0;
1352682eec57SRick Macklem }
135361c82720SRick Macklem (void) vfs_getopt(mp->mnt_optnew, "hostname",
135461c82720SRick Macklem (void **)&args.hostname, &len);
1355682eec57SRick Macklem if (args.hostname == NULL) {
1356682eec57SRick Macklem vfs_mount_error(mp, "Invalid hostname");
1357682eec57SRick Macklem error = EINVAL;
1358682eec57SRick Macklem goto out;
1359682eec57SRick Macklem }
1360bd1623deSKonstantin Belousov if (len >= MNAMELEN) {
1361bd1623deSKonstantin Belousov vfs_mount_error(mp, "Hostname too long");
1362bd1623deSKonstantin Belousov error = EINVAL;
1363bd1623deSKonstantin Belousov goto out;
1364bd1623deSKonstantin Belousov }
1365bd1623deSKonstantin Belousov bcopy(args.hostname, hst, len);
1366bd1623deSKonstantin Belousov hst[len] = '\0';
136761c82720SRick Macklem }
1368682eec57SRick Macklem
1369682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "principal", (void **)&name, NULL) == 0)
1370682eec57SRick Macklem strlcpy(srvkrbname, name, sizeof (srvkrbname));
13712a3508ebSRick Macklem else {
1372682eec57SRick Macklem snprintf(srvkrbname, sizeof (srvkrbname), "nfs@%s", hst);
13732a3508ebSRick Macklem cp = strchr(srvkrbname, ':');
13742a3508ebSRick Macklem if (cp != NULL)
13752a3508ebSRick Macklem *cp = '\0';
13762a3508ebSRick Macklem }
1377385edc8eSRick Macklem srvkrbnamelen = strlen(srvkrbname);
1378682eec57SRick Macklem
1379682eec57SRick Macklem if (vfs_getopt(mp->mnt_optnew, "gssname", (void **)&name, NULL) == 0)
1380682eec57SRick Macklem strlcpy(krbname, name, sizeof (krbname));
1381682eec57SRick Macklem else
13829ec7b004SRick Macklem krbname[0] = '\0';
1383385edc8eSRick Macklem krbnamelen = strlen(krbname);
1384682eec57SRick Macklem
13850d1654c3SEdward Tomasz Napierala if (has_nfs_from_opt == 0) {
13860d1654c3SEdward Tomasz Napierala if (vfs_getopt(mp->mnt_optnew,
13870d1654c3SEdward Tomasz Napierala "dirpath", (void **)&name, NULL) == 0)
1388682eec57SRick Macklem strlcpy(dirpath, name, sizeof (dirpath));
1389682eec57SRick Macklem else
13909ec7b004SRick Macklem dirpath[0] = '\0';
1391385edc8eSRick Macklem dirlen = strlen(dirpath);
13920d1654c3SEdward Tomasz Napierala }
1393682eec57SRick Macklem
13940d1654c3SEdward Tomasz Napierala if (has_nfs_args_opt == 0 && has_nfs_from_opt == 0) {
1395b70cddbaSRick Macklem if (vfs_getopt(mp->mnt_optnew, "addr",
139661c82720SRick Macklem (void **)&args.addr, &args.addrlen) == 0) {
1397682eec57SRick Macklem if (args.addrlen > SOCK_MAXADDRLEN) {
1398682eec57SRick Macklem error = ENAMETOOLONG;
13999ec7b004SRick Macklem goto out;
14009ec7b004SRick Macklem }
1401682eec57SRick Macklem nam = malloc(args.addrlen, M_SONAME, M_WAITOK);
1402682eec57SRick Macklem bcopy(args.addr, nam, args.addrlen);
1403682eec57SRick Macklem nam->sa_len = args.addrlen;
1404b70cddbaSRick Macklem } else {
1405b70cddbaSRick Macklem vfs_mount_error(mp, "No server address");
1406b70cddbaSRick Macklem error = EINVAL;
1407b70cddbaSRick Macklem goto out;
1408b70cddbaSRick Macklem }
14099ec7b004SRick Macklem }
1410682eec57SRick Macklem
14111e0a518dSRick Macklem if (aconn > 0 && (args.sotype != SOCK_STREAM ||
14121e0a518dSRick Macklem (args.flags & NFSMNT_NFSV4) == 0 || minvers == 0)) {
14131e0a518dSRick Macklem /*
14141e0a518dSRick Macklem * RFC 5661 requires that an NFSv4.1/4.2 server
14151e0a518dSRick Macklem * send an RPC reply on the same TCP connection
14161e0a518dSRick Macklem * as the one it received the request on.
14171e0a518dSRick Macklem * This property in required for "nconnect" and
14181e0a518dSRick Macklem * might not be the case for NFSv3 or NFSv4.0 servers.
14191e0a518dSRick Macklem */
14201e0a518dSRick Macklem vfs_mount_error(mp, "nconnect should only be used "
14211e0a518dSRick Macklem "for NFSv4.1/4.2 mounts");
14221e0a518dSRick Macklem error = EINVAL;
14231e0a518dSRick Macklem goto out;
14241e0a518dSRick Macklem }
14251e0a518dSRick Macklem
1426896516e5SRick Macklem if ((newflag & NFSMNT_SYSKRB5) != 0 &&
1427896516e5SRick Macklem ((args.flags & NFSMNT_NFSV4) == 0 || minvers == 0)) {
1428896516e5SRick Macklem /*
1429896516e5SRick Macklem * This option requires the use of SP4_NONE, which
1430896516e5SRick Macklem * is only in NFSv4.1/4.2.
1431896516e5SRick Macklem */
1432896516e5SRick Macklem vfs_mount_error(mp, "syskrb5 should only be used "
1433896516e5SRick Macklem "for NFSv4.1/4.2 mounts");
1434896516e5SRick Macklem error = EINVAL;
1435896516e5SRick Macklem goto out;
1436896516e5SRick Macklem }
1437896516e5SRick Macklem
1438896516e5SRick Macklem if ((newflag & NFSMNT_SYSKRB5) != 0 &&
1439896516e5SRick Macklem (args.flags & NFSMNT_KERB) == 0) {
1440896516e5SRick Macklem /*
1441896516e5SRick Macklem * This option modifies the behaviour of sec=krb5[ip].
1442896516e5SRick Macklem */
1443896516e5SRick Macklem vfs_mount_error(mp, "syskrb5 should only be used "
1444896516e5SRick Macklem "for sec=krb5[ip] mounts");
1445896516e5SRick Macklem error = EINVAL;
1446896516e5SRick Macklem goto out;
1447896516e5SRick Macklem }
1448896516e5SRick Macklem
1449896516e5SRick Macklem if ((newflag & NFSMNT_SYSKRB5) != 0 && krbname[0] != '\0') {
1450896516e5SRick Macklem /*
1451896516e5SRick Macklem * This option is used as an alternative to "gssname".
1452896516e5SRick Macklem */
1453896516e5SRick Macklem vfs_mount_error(mp, "syskrb5 should not be used "
1454896516e5SRick Macklem "with the gssname option");
1455896516e5SRick Macklem error = EINVAL;
1456896516e5SRick Macklem goto out;
1457896516e5SRick Macklem }
1458896516e5SRick Macklem
14599ec7b004SRick Macklem args.fh = nfh;
1460385edc8eSRick Macklem error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath,
1461385edc8eSRick Macklem dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td,
14621e0a518dSRick Macklem nametimeo, negnametimeo, minvers, newflag, tlscertname, aconn);
14639ec7b004SRick Macklem out:
14649ec7b004SRick Macklem if (!error) {
14659ec7b004SRick Macklem MNT_ILOCK(mp);
1466dda11d4aSRick Macklem mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_NO_IOPF |
1467dda11d4aSRick Macklem MNTK_USES_BCACHE;
1468abc15156SKonstantin Belousov if ((VFSTONFS(mp)->nm_flag & NFSMNT_NFSV4) != 0)
1469abc15156SKonstantin Belousov mp->mnt_kern_flag |= MNTK_NULL_NOCACHE;
14709ec7b004SRick Macklem MNT_IUNLOCK(mp);
14719ec7b004SRick Macklem }
1472599009e2SKonstantin Belousov free(hst, M_TEMP);
14739ec7b004SRick Macklem return (error);
14749ec7b004SRick Macklem }
14759ec7b004SRick Macklem
14769ec7b004SRick Macklem /*
14779ec7b004SRick Macklem * VFS Operations.
14789ec7b004SRick Macklem *
14799ec7b004SRick Macklem * mount system call
14809ec7b004SRick Macklem * It seems a bit dumb to copyinstr() the host and path here and then
14819ec7b004SRick Macklem * bcopy() them in mountnfs(), but I wanted to detect errors before
1482fefbf770SGleb Smirnoff * doing the getsockaddr() call because getsockaddr() allocates an mbuf and
14839ec7b004SRick Macklem * an error after that means that I have to release the mbuf.
14849ec7b004SRick Macklem */
14859ec7b004SRick Macklem /* ARGSUSED */
14869ec7b004SRick Macklem static int
nfs_cmount(struct mntarg * ma,void * data,uint64_t flags)1487cc672d35SKirk McKusick nfs_cmount(struct mntarg *ma, void *data, uint64_t flags)
14889ec7b004SRick Macklem {
14899ec7b004SRick Macklem int error;
14909ec7b004SRick Macklem struct nfs_args args;
14919ec7b004SRick Macklem
14929ec7b004SRick Macklem error = copyin(data, &args, sizeof (struct nfs_args));
14939ec7b004SRick Macklem if (error)
14949ec7b004SRick Macklem return error;
14959ec7b004SRick Macklem
14969ec7b004SRick Macklem ma = mount_arg(ma, "nfs_args", &args, sizeof args);
14979ec7b004SRick Macklem
14989ec7b004SRick Macklem error = kernel_mount(ma, flags);
14999ec7b004SRick Macklem return (error);
15009ec7b004SRick Macklem }
15019ec7b004SRick Macklem
15029ec7b004SRick Macklem /*
15039ec7b004SRick Macklem * Common code for mount and mountroot
15049ec7b004SRick Macklem */
15059ec7b004SRick Macklem static int
mountnfs(struct nfs_args * argp,struct mount * mp,struct sockaddr * nam,char * hst,u_char * krbname,int krbnamelen,u_char * dirpath,int dirlen,u_char * srvkrbname,int srvkrbnamelen,struct vnode ** vpp,struct ucred * cred,struct thread * td,int nametimeo,int negnametimeo,int minvers,uint32_t newflag,char * tlscertname,int aconn)15069ec7b004SRick Macklem mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
1507385edc8eSRick Macklem char *hst, u_char *krbname, int krbnamelen, u_char *dirpath, int dirlen,
1508385edc8eSRick Macklem u_char *srvkrbname, int srvkrbnamelen, struct vnode **vpp,
15091f60bfd8SRick Macklem struct ucred *cred, struct thread *td, int nametimeo, int negnametimeo,
15101e0a518dSRick Macklem int minvers, uint32_t newflag, char *tlscertname, int aconn)
15119ec7b004SRick Macklem {
15129ec7b004SRick Macklem struct nfsmount *nmp;
15139ec7b004SRick Macklem struct nfsnode *np;
151480e55695SRick Macklem int error, trycnt, ret;
15159ec7b004SRick Macklem struct nfsvattr nfsva;
15161f60bfd8SRick Macklem struct nfsclclient *clp;
15171f60bfd8SRick Macklem struct nfsclds *dsp, *tdsp;
15181f60bfd8SRick Macklem uint32_t lease;
1519a145cf3fSRick Macklem bool tryminvers;
1520896516e5SRick Macklem char *fakefh;
15219ec7b004SRick Macklem static u_int64_t clval = 0;
15226e4b6ff8SRick Macklem #ifdef KERN_TLS
15236e4b6ff8SRick Macklem u_int maxlen;
15246e4b6ff8SRick Macklem #endif
15259ec7b004SRick Macklem
15261f60bfd8SRick Macklem NFSCL_DEBUG(3, "in mnt\n");
1527b837f100SGleb Smirnoff CURVNET_SET(CRED_TO_VNET(cred));
15281f60bfd8SRick Macklem clp = NULL;
15299ec7b004SRick Macklem if (mp->mnt_flag & MNT_UPDATE) {
15309ec7b004SRick Macklem nmp = VFSTONFS(mp);
15319ec7b004SRick Macklem printf("%s: MNT_UPDATE is no longer handled here\n", __func__);
1532222daa42SConrad Meyer free(nam, M_SONAME);
1533665b1365SRick Macklem free(tlscertname, M_NEWNFSMNT);
1534b837f100SGleb Smirnoff CURVNET_RESTORE();
15359ec7b004SRick Macklem return (0);
15369ec7b004SRick Macklem } else {
15376e4b6ff8SRick Macklem /* NFS-over-TLS requires that rpctls be functioning. */
15386e4b6ff8SRick Macklem if ((newflag & NFSMNT_TLS) != 0) {
15396e4b6ff8SRick Macklem error = EINVAL;
15406e4b6ff8SRick Macklem #ifdef KERN_TLS
15414cdbb07bSRick Macklem /* KERN_TLS is only supported for TCP. */
15424cdbb07bSRick Macklem if (argp->sotype == SOCK_STREAM &&
15434cdbb07bSRick Macklem rpctls_getinfo(&maxlen, true, false))
15446e4b6ff8SRick Macklem error = 0;
15456e4b6ff8SRick Macklem #endif
15466e4b6ff8SRick Macklem if (error != 0) {
15476e4b6ff8SRick Macklem free(nam, M_SONAME);
1548665b1365SRick Macklem free(tlscertname, M_NEWNFSMNT);
1549b837f100SGleb Smirnoff CURVNET_RESTORE();
15506e4b6ff8SRick Macklem return (error);
15516e4b6ff8SRick Macklem }
15526e4b6ff8SRick Macklem }
1553222daa42SConrad Meyer nmp = malloc(sizeof (struct nfsmount) +
1554385edc8eSRick Macklem krbnamelen + dirlen + srvkrbnamelen + 2,
1555385edc8eSRick Macklem M_NEWNFSMNT, M_WAITOK | M_ZERO);
1556665b1365SRick Macklem nmp->nm_tlscertname = tlscertname;
15576e4b6ff8SRick Macklem nmp->nm_newflag = newflag;
15589ec7b004SRick Macklem TAILQ_INIT(&nmp->nm_bufq);
1559b2fc0141SRick Macklem TAILQ_INIT(&nmp->nm_sess);
15609ec7b004SRick Macklem if (clval == 0)
15619ec7b004SRick Macklem clval = (u_int64_t)nfsboottime.tv_sec;
15629ec7b004SRick Macklem nmp->nm_clval = clval++;
1563385edc8eSRick Macklem nmp->nm_krbnamelen = krbnamelen;
1564385edc8eSRick Macklem nmp->nm_dirpathlen = dirlen;
1565385edc8eSRick Macklem nmp->nm_srvkrbnamelen = srvkrbnamelen;
156663bde62eSRick Macklem if (td->td_ucred->cr_uid != (uid_t)0) {
15679ec7b004SRick Macklem /*
156863bde62eSRick Macklem * nm_uid is used to get KerberosV credentials for
156963bde62eSRick Macklem * the nfsv4 state handling operations if there is
157063bde62eSRick Macklem * no host based principal set. Use the uid of
157163bde62eSRick Macklem * this user if not root, since they are doing the
157263bde62eSRick Macklem * mount. I don't think setting this for root will
157363bde62eSRick Macklem * work, since root normally does not have user
157463bde62eSRick Macklem * credentials in a credentials cache.
15759ec7b004SRick Macklem */
157663bde62eSRick Macklem nmp->nm_uid = td->td_ucred->cr_uid;
15779ec7b004SRick Macklem } else {
15789ec7b004SRick Macklem /*
157963bde62eSRick Macklem * Just set to -1, so it won't be used.
15809ec7b004SRick Macklem */
15819ec7b004SRick Macklem nmp->nm_uid = (uid_t)-1;
15829ec7b004SRick Macklem }
15839ec7b004SRick Macklem
15849ec7b004SRick Macklem /* Copy and null terminate all the names */
15859ec7b004SRick Macklem if (nmp->nm_krbnamelen > 0) {
15869ec7b004SRick Macklem bcopy(krbname, nmp->nm_krbname, nmp->nm_krbnamelen);
15879ec7b004SRick Macklem nmp->nm_name[nmp->nm_krbnamelen] = '\0';
15889ec7b004SRick Macklem }
15899ec7b004SRick Macklem if (nmp->nm_dirpathlen > 0) {
15909ec7b004SRick Macklem bcopy(dirpath, NFSMNT_DIRPATH(nmp),
15919ec7b004SRick Macklem nmp->nm_dirpathlen);
15929ec7b004SRick Macklem nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen
15939ec7b004SRick Macklem + 1] = '\0';
15949ec7b004SRick Macklem }
15959ec7b004SRick Macklem if (nmp->nm_srvkrbnamelen > 0) {
15969ec7b004SRick Macklem bcopy(srvkrbname, NFSMNT_SRVKRBNAME(nmp),
15979ec7b004SRick Macklem nmp->nm_srvkrbnamelen);
15989ec7b004SRick Macklem nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen
15999ec7b004SRick Macklem + nmp->nm_srvkrbnamelen + 2] = '\0';
16009ec7b004SRick Macklem }
16019ec7b004SRick Macklem nmp->nm_sockreq.nr_cred = crhold(cred);
16029ec7b004SRick Macklem mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF);
16039ec7b004SRick Macklem mp->mnt_data = nmp;
1604ca27c028SRick Macklem nmp->nm_getinfo = nfs_getnlminfo;
160590305aa3SRick Macklem nmp->nm_vinvalbuf = ncl_vinvalbuf;
16069ec7b004SRick Macklem }
16079ec7b004SRick Macklem vfs_getnewfsid(mp);
16089ec7b004SRick Macklem nmp->nm_mountp = mp;
16099ec7b004SRick Macklem mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK);
161090379d61SRick Macklem
161190379d61SRick Macklem /*
16120b17c7beSJohn Baldwin * Since nfs_decode_args() might optionally set them, these
16130b17c7beSJohn Baldwin * need to be set to defaults before the call, so that the
16140b17c7beSJohn Baldwin * optional settings aren't overwritten.
161590379d61SRick Macklem */
16160b17c7beSJohn Baldwin nmp->nm_nametimeo = nametimeo;
1617dd5b5a94SRick Macklem nmp->nm_negnametimeo = negnametimeo;
161890379d61SRick Macklem nmp->nm_timeo = NFS_TIMEO;
161990379d61SRick Macklem nmp->nm_retry = NFS_RETRANS;
162090379d61SRick Macklem nmp->nm_readahead = NFS_DEFRAHEAD;
1621afdfc9a4SAlexander Motin
1622afdfc9a4SAlexander Motin /* This is empirical approximation of sqrt(hibufspace) * 256. */
1623afdfc9a4SAlexander Motin nmp->nm_wcommitsize = NFS_MAXBSIZE / 256;
1624afdfc9a4SAlexander Motin while ((long)nmp->nm_wcommitsize * nmp->nm_wcommitsize < hibufspace)
1625afdfc9a4SAlexander Motin nmp->nm_wcommitsize *= 2;
1626afdfc9a4SAlexander Motin nmp->nm_wcommitsize *= 256;
1627afdfc9a4SAlexander Motin
1628a145cf3fSRick Macklem tryminvers = false;
1629a145cf3fSRick Macklem if ((argp->flags & NFSMNT_NFSV4) != 0) {
1630a145cf3fSRick Macklem if (minvers < 0) {
1631a145cf3fSRick Macklem tryminvers = true;
1632a145cf3fSRick Macklem minvers = NFSV42_MINORVERSION;
1633a145cf3fSRick Macklem }
16341f60bfd8SRick Macklem nmp->nm_minorvers = minvers;
1635a145cf3fSRick Macklem } else
16361f60bfd8SRick Macklem nmp->nm_minorvers = 0;
16379ec7b004SRick Macklem
1638ca27c028SRick Macklem nfs_decode_args(mp, nmp, argp, hst, cred, td);
1639682eec57SRick Macklem
16409ec7b004SRick Macklem /*
16419ec7b004SRick Macklem * V2 can only handle 32 bit filesizes. A 4GB-1 limit may be too
16429ec7b004SRick Macklem * high, depending on whether we end up with negative offsets in
16439ec7b004SRick Macklem * the client or server somewhere. 2GB-1 may be safer.
16449ec7b004SRick Macklem *
16459ec7b004SRick Macklem * For V3, ncl_fsinfo will adjust this as necessary. Assume maximum
16469ec7b004SRick Macklem * that we can handle until we find out otherwise.
16479ec7b004SRick Macklem */
16489ec7b004SRick Macklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0)
16499ec7b004SRick Macklem nmp->nm_maxfilesize = 0xffffffffLL;
16509ec7b004SRick Macklem else
16511dcad8ecSRick Macklem nmp->nm_maxfilesize = OFF_MAX;
16529ec7b004SRick Macklem
16539ec7b004SRick Macklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) {
16549ec7b004SRick Macklem nmp->nm_wsize = NFS_WSIZE;
16559ec7b004SRick Macklem nmp->nm_rsize = NFS_RSIZE;
16569ec7b004SRick Macklem nmp->nm_readdirsize = NFS_READDIRSIZE;
16579ec7b004SRick Macklem }
16589ec7b004SRick Macklem nmp->nm_numgrps = NFS_MAXGRPS;
16599ec7b004SRick Macklem nmp->nm_tprintf_delay = nfs_tprintf_delay;
16609ec7b004SRick Macklem if (nmp->nm_tprintf_delay < 0)
16619ec7b004SRick Macklem nmp->nm_tprintf_delay = 0;
16629ec7b004SRick Macklem nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay;
16639ec7b004SRick Macklem if (nmp->nm_tprintf_initial_delay < 0)
16649ec7b004SRick Macklem nmp->nm_tprintf_initial_delay = 0;
16659ec7b004SRick Macklem nmp->nm_fhsize = argp->fhsize;
16669ec7b004SRick Macklem if (nmp->nm_fhsize > 0)
16679ec7b004SRick Macklem bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
166844de1834SMark Johnston strlcpy(mp->mnt_stat.f_mntfromname, hst, MNAMELEN);
16699ec7b004SRick Macklem nmp->nm_nam = nam;
16709ec7b004SRick Macklem /* Set up the sockets and per-host congestion */
16719ec7b004SRick Macklem nmp->nm_sotype = argp->sotype;
16729ec7b004SRick Macklem nmp->nm_soproto = argp->proto;
16739ec7b004SRick Macklem nmp->nm_sockreq.nr_prog = NFS_PROG;
16749ec7b004SRick Macklem if ((argp->flags & NFSMNT_NFSV4))
16759ec7b004SRick Macklem nmp->nm_sockreq.nr_vers = NFS_VER4;
16769ec7b004SRick Macklem else if ((argp->flags & NFSMNT_NFSV3))
16779ec7b004SRick Macklem nmp->nm_sockreq.nr_vers = NFS_VER3;
16789ec7b004SRick Macklem else
16799ec7b004SRick Macklem nmp->nm_sockreq.nr_vers = NFS_VER2;
16809ec7b004SRick Macklem
16811e0a518dSRick Macklem if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0, false,
16821e0a518dSRick Macklem &nmp->nm_sockreq.nr_client)))
16839ec7b004SRick Macklem goto bad;
1684aed98fa5SRick Macklem /* For NFSv4, get the clientid now. */
1685aed98fa5SRick Macklem if ((argp->flags & NFSMNT_NFSV4) != 0) {
16861f60bfd8SRick Macklem NFSCL_DEBUG(3, "at getcl\n");
1687120b20bdSRick Macklem error = nfscl_getcl(mp, cred, td, tryminvers, true, &clp);
16881f60bfd8SRick Macklem NFSCL_DEBUG(3, "aft getcl=%d\n", error);
16891f60bfd8SRick Macklem if (error != 0)
16901f60bfd8SRick Macklem goto bad;
16911e0a518dSRick Macklem if (aconn > 0 && nmp->nm_minorvers == 0) {
16921e0a518dSRick Macklem vfs_mount_error(mp, "nconnect should only be used "
16931e0a518dSRick Macklem "for NFSv4.1/4.2 mounts");
16941e0a518dSRick Macklem error = EINVAL;
16951e0a518dSRick Macklem goto bad;
16961e0a518dSRick Macklem }
1697896516e5SRick Macklem if (NFSHASSYSKRB5(nmp) && nmp->nm_minorvers == 0) {
1698896516e5SRick Macklem vfs_mount_error(mp, "syskrb5 should only be used "
1699896516e5SRick Macklem "for NFSv4.1/4.2 mounts");
1700896516e5SRick Macklem error = EINVAL;
1701896516e5SRick Macklem goto bad;
1702896516e5SRick Macklem }
17031f60bfd8SRick Macklem }
17041f60bfd8SRick Macklem
17051f60bfd8SRick Macklem if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) &&
17061f60bfd8SRick Macklem nmp->nm_dirpathlen > 0) {
17071f60bfd8SRick Macklem NFSCL_DEBUG(3, "in dirp\n");
17081f60bfd8SRick Macklem /*
17091f60bfd8SRick Macklem * If the fhsize on the mount point == 0 for V4, the mount
17101f60bfd8SRick Macklem * path needs to be looked up.
17111f60bfd8SRick Macklem */
17121f60bfd8SRick Macklem trycnt = 3;
17131f60bfd8SRick Macklem do {
17141f60bfd8SRick Macklem error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
17151f60bfd8SRick Macklem cred, td);
17161f60bfd8SRick Macklem NFSCL_DEBUG(3, "aft dirp=%d\n", error);
1717896516e5SRick Macklem if (error != 0 && (!NFSHASSYSKRB5(nmp) ||
1718896516e5SRick Macklem error != NFSERR_WRONGSEC))
17191f60bfd8SRick Macklem (void) nfs_catnap(PZERO, error, "nfsgetdirp");
1720896516e5SRick Macklem } while (error != 0 && --trycnt > 0 &&
1721896516e5SRick Macklem (!NFSHASSYSKRB5(nmp) || error != NFSERR_WRONGSEC));
1722896516e5SRick Macklem if (error != 0 && (!NFSHASSYSKRB5(nmp) ||
1723896516e5SRick Macklem error != NFSERR_WRONGSEC))
17241f60bfd8SRick Macklem goto bad;
17251f60bfd8SRick Macklem }
17269ec7b004SRick Macklem
17279ec7b004SRick Macklem /*
17289ec7b004SRick Macklem * A reference count is needed on the nfsnode representing the
17299ec7b004SRick Macklem * remote root. If this object is not persistent, then backward
17309ec7b004SRick Macklem * traversals of the mount point (i.e. "..") will not work if
17319ec7b004SRick Macklem * the nfsnode gets flushed out of the cache. Ufs does not have
17329ec7b004SRick Macklem * this problem, because one can identify root inodes by their
17331dc349abSEd Maste * number == UFS_ROOTINO (2).
1734896516e5SRick Macklem * For the "syskrb5" mount, the file handle might not have
1735896516e5SRick Macklem * been acquired. As such, use a "fake" file handle which
1736896516e5SRick Macklem * can never be returned by a server for the root vnode.
17379ec7b004SRick Macklem */
1738896516e5SRick Macklem if (nmp->nm_fhsize > 0 || NFSHASSYSKRB5(nmp)) {
173980e55695SRick Macklem /*
174080e55695SRick Macklem * Set f_iosize to NFS_DIRBLKSIZ so that bo_bsize gets set
174180e55695SRick Macklem * non-zero for the root vnode. f_iosize will be set correctly
174280e55695SRick Macklem * by nfs_statfs() before any I/O occurs.
174380e55695SRick Macklem */
174480e55695SRick Macklem mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ;
1745896516e5SRick Macklem if (nmp->nm_fhsize == 0) {
1746896516e5SRick Macklem fakefh = malloc(NFSX_FHMAX + 1, M_TEMP, M_WAITOK |
1747896516e5SRick Macklem M_ZERO);
1748896516e5SRick Macklem error = ncl_nget(mp, fakefh, NFSX_FHMAX + 1, &np,
1749896516e5SRick Macklem LK_EXCLUSIVE);
1750896516e5SRick Macklem free(fakefh, M_TEMP);
1751896516e5SRick Macklem nmp->nm_privflag |= NFSMNTP_FAKEROOTFH;
1752896516e5SRick Macklem } else
17534b3a38ecSRick Macklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np,
17544b3a38ecSRick Macklem LK_EXCLUSIVE);
17559ec7b004SRick Macklem if (error)
17569ec7b004SRick Macklem goto bad;
17579ec7b004SRick Macklem *vpp = NFSTOV(np);
17589ec7b004SRick Macklem
17599ec7b004SRick Macklem /*
17609ec7b004SRick Macklem * Get file attributes and transfer parameters for the
17619ec7b004SRick Macklem * mountpoint. This has the side effect of filling in
17629ec7b004SRick Macklem * (*vpp)->v_type with the correct value.
17639ec7b004SRick Macklem */
1764896516e5SRick Macklem ret = ENXIO;
1765896516e5SRick Macklem if (nmp->nm_fhsize > 0)
1766896516e5SRick Macklem ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh,
1767896516e5SRick Macklem nmp->nm_fhsize, 1, cred, td, &nfsva, NULL, &lease);
17689ec7b004SRick Macklem if (ret) {
17699ec7b004SRick Macklem /*
17709ec7b004SRick Macklem * Just set default values to get things going.
17719ec7b004SRick Macklem */
17729ec7b004SRick Macklem NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr));
17739ec7b004SRick Macklem nfsva.na_vattr.va_type = VDIR;
17749ec7b004SRick Macklem nfsva.na_vattr.va_mode = 0777;
17759ec7b004SRick Macklem nfsva.na_vattr.va_nlink = 100;
17769ec7b004SRick Macklem nfsva.na_vattr.va_uid = (uid_t)0;
17779ec7b004SRick Macklem nfsva.na_vattr.va_gid = (gid_t)0;
17789ec7b004SRick Macklem nfsva.na_vattr.va_fileid = 2;
17799ec7b004SRick Macklem nfsva.na_vattr.va_gen = 1;
17809ec7b004SRick Macklem nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE;
17819ec7b004SRick Macklem nfsva.na_vattr.va_size = 512 * 1024;
1782896516e5SRick Macklem lease = 20;
17839ec7b004SRick Macklem }
17844ad3423bSRick Macklem (void) nfscl_loadattrcache(vpp, &nfsva, NULL, 0, 1);
1785aed98fa5SRick Macklem if ((argp->flags & NFSMNT_NFSV4) != 0) {
17861f60bfd8SRick Macklem NFSCL_DEBUG(3, "lease=%d\n", (int)lease);
17871f60bfd8SRick Macklem NFSLOCKCLSTATE();
17881f60bfd8SRick Macklem clp->nfsc_renew = NFSCL_RENEW(lease);
17891f60bfd8SRick Macklem clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew;
17901f60bfd8SRick Macklem clp->nfsc_clientidrev++;
17911f60bfd8SRick Macklem if (clp->nfsc_clientidrev == 0)
17921f60bfd8SRick Macklem clp->nfsc_clientidrev++;
17931f60bfd8SRick Macklem NFSUNLOCKCLSTATE();
17941f60bfd8SRick Macklem /*
17951f60bfd8SRick Macklem * Mount will succeed, so the renew thread can be
17961f60bfd8SRick Macklem * started now.
17971f60bfd8SRick Macklem */
17981f60bfd8SRick Macklem nfscl_start_renewthread(clp);
17991f60bfd8SRick Macklem nfscl_clientrelease(clp);
18001f60bfd8SRick Macklem }
18019ec7b004SRick Macklem if (argp->flags & NFSMNT_NFSV3)
18029ec7b004SRick Macklem ncl_fsinfo(nmp, *vpp, cred, td);
18039ec7b004SRick Macklem
1804*e4c7b2b6SRick Macklem /*
1805*e4c7b2b6SRick Macklem * Mark if the mount point supports NFSv4 ACLs and
1806*e4c7b2b6SRick Macklem * named attributes.
1807*e4c7b2b6SRick Macklem */
1808*e4c7b2b6SRick Macklem if ((argp->flags & NFSMNT_NFSV4) != 0) {
1809484c842dSRick Macklem MNT_ILOCK(mp);
1810*e4c7b2b6SRick Macklem if (ret == 0 && nfsrv_useacl != 0 &&
1811*e4c7b2b6SRick Macklem NFSISSET_ATTRBIT(&nfsva.na_suppattr,
1812*e4c7b2b6SRick Macklem NFSATTRBIT_ACL))
1813484c842dSRick Macklem mp->mnt_flag |= MNT_NFS4ACLS;
1814*e4c7b2b6SRick Macklem if (nmp->nm_minorvers > 0)
1815*e4c7b2b6SRick Macklem mp->mnt_flag |= MNT_NAMEDATTR;
1816484c842dSRick Macklem MNT_IUNLOCK(mp);
1817484c842dSRick Macklem }
1818484c842dSRick Macklem
18191e0a518dSRick Macklem /* Can now allow additional connections. */
18201e0a518dSRick Macklem if (aconn > 0)
18211e0a518dSRick Macklem nmp->nm_aconnect = aconn;
18221e0a518dSRick Macklem
18239ec7b004SRick Macklem /*
18249ec7b004SRick Macklem * Lose the lock but keep the ref.
18259ec7b004SRick Macklem */
1826b249ce48SMateusz Guzik NFSVOPUNLOCK(*vpp);
1827d511f93eSMateusz Guzik vfs_cache_root_set(mp, *vpp);
1828b837f100SGleb Smirnoff CURVNET_RESTORE();
18299ec7b004SRick Macklem return (0);
18309ec7b004SRick Macklem }
18319ec7b004SRick Macklem error = EIO;
18329ec7b004SRick Macklem
18339ec7b004SRick Macklem bad:
18341f60bfd8SRick Macklem if (clp != NULL)
18351f60bfd8SRick Macklem nfscl_clientrelease(clp);
18361e0a518dSRick Macklem newnfs_disconnect(NULL, &nmp->nm_sockreq);
18379ec7b004SRick Macklem crfree(nmp->nm_sockreq.nr_cred);
183888a2437aSRick Macklem if (nmp->nm_sockreq.nr_auth != NULL)
183988a2437aSRick Macklem AUTH_DESTROY(nmp->nm_sockreq.nr_auth);
18409ec7b004SRick Macklem mtx_destroy(&nmp->nm_sockreq.nr_mtx);
18419ec7b004SRick Macklem mtx_destroy(&nmp->nm_mtx);
18421f60bfd8SRick Macklem if (nmp->nm_clp != NULL) {
18431f60bfd8SRick Macklem NFSLOCKCLSTATE();
18441f60bfd8SRick Macklem LIST_REMOVE(nmp->nm_clp, nfsc_list);
18451f60bfd8SRick Macklem NFSUNLOCKCLSTATE();
18461f60bfd8SRick Macklem free(nmp->nm_clp, M_NFSCLCLIENT);
18471f60bfd8SRick Macklem }
1848c20a7210SRick Macklem TAILQ_FOREACH_SAFE(dsp, &nmp->nm_sess, nfsclds_list, tdsp) {
1849c20a7210SRick Macklem if (dsp != TAILQ_FIRST(&nmp->nm_sess) &&
1850c20a7210SRick Macklem dsp->nfsclds_sockp != NULL)
18511e0a518dSRick Macklem newnfs_disconnect(NULL, dsp->nfsclds_sockp);
18521f60bfd8SRick Macklem nfscl_freenfsclds(dsp);
1853c20a7210SRick Macklem }
1854665b1365SRick Macklem free(nmp->nm_tlscertname, M_NEWNFSMNT);
1855222daa42SConrad Meyer free(nmp, M_NEWNFSMNT);
1856222daa42SConrad Meyer free(nam, M_SONAME);
1857b837f100SGleb Smirnoff CURVNET_RESTORE();
18589ec7b004SRick Macklem return (error);
18599ec7b004SRick Macklem }
18609ec7b004SRick Macklem
18619ec7b004SRick Macklem /*
18629ec7b004SRick Macklem * unmount system call
18639ec7b004SRick Macklem */
18649ec7b004SRick Macklem static int
nfs_unmount(struct mount * mp,int mntflags)1865dfd233edSAttilio Rao nfs_unmount(struct mount *mp, int mntflags)
18669ec7b004SRick Macklem {
1867dfd233edSAttilio Rao struct thread *td;
18689ec7b004SRick Macklem struct nfsmount *nmp;
186964a0e848SRick Macklem int error, flags = 0, i, trycnt = 0;
18701f60bfd8SRick Macklem struct nfsclds *dsp, *tdsp;
187144122258SRick Macklem struct nfscldeleg *dp, *ndp;
187244122258SRick Macklem struct nfscldeleghead dh;
18739ec7b004SRick Macklem
1874dfd233edSAttilio Rao td = curthread;
187544122258SRick Macklem TAILQ_INIT(&dh);
1876dfd233edSAttilio Rao
18779ec7b004SRick Macklem if (mntflags & MNT_FORCE)
18789ec7b004SRick Macklem flags |= FORCECLOSE;
18799ec7b004SRick Macklem nmp = VFSTONFS(mp);
188090d2dfabSRick Macklem error = 0;
18819ec7b004SRick Macklem /*
18829ec7b004SRick Macklem * Goes something like this..
18839ec7b004SRick Macklem * - Call vflush() to clear out vnodes for this filesystem
18849ec7b004SRick Macklem * - Close the socket
18859ec7b004SRick Macklem * - Free up the data structures
18869ec7b004SRick Macklem */
18879ec7b004SRick Macklem /* In the forced case, cancel any outstanding requests. */
18889ec7b004SRick Macklem if (mntflags & MNT_FORCE) {
188990d2dfabSRick Macklem NFSDDSLOCK();
189090d2dfabSRick Macklem if (nfsv4_findmirror(nmp) != NULL)
189190d2dfabSRick Macklem error = ENXIO;
189290d2dfabSRick Macklem NFSDDSUNLOCK();
189390d2dfabSRick Macklem if (error)
189490d2dfabSRick Macklem goto out;
18959ec7b004SRick Macklem error = newnfs_nmcancelreqs(nmp);
18969ec7b004SRick Macklem if (error)
18979ec7b004SRick Macklem goto out;
18989ec7b004SRick Macklem /* For a forced close, get rid of the renew thread now */
189944122258SRick Macklem nfscl_umount(nmp, td, &dh);
19009ec7b004SRick Macklem }
19019ec7b004SRick Macklem /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */
19029ec7b004SRick Macklem do {
19039ec7b004SRick Macklem error = vflush(mp, 1, flags, td);
19049ec7b004SRick Macklem if ((mntflags & MNT_FORCE) && error != 0 && ++trycnt < 30)
190523f929dfSRick Macklem (void) nfs_catnap(PSOCK, error, "newndm");
19069ec7b004SRick Macklem } while ((mntflags & MNT_FORCE) && error != 0 && trycnt < 30);
19079ec7b004SRick Macklem if (error)
19089ec7b004SRick Macklem goto out;
19099ec7b004SRick Macklem
19109ec7b004SRick Macklem /*
19119ec7b004SRick Macklem * We are now committed to the unmount.
19129ec7b004SRick Macklem */
19139ec7b004SRick Macklem if ((mntflags & MNT_FORCE) == 0)
191444122258SRick Macklem nfscl_umount(nmp, td, NULL);
191547cbff34SRick Macklem else {
191647cbff34SRick Macklem mtx_lock(&nmp->nm_mtx);
191747cbff34SRick Macklem nmp->nm_privflag |= NFSMNTP_FORCEDISM;
191847cbff34SRick Macklem mtx_unlock(&nmp->nm_mtx);
191947cbff34SRick Macklem }
192064a0e848SRick Macklem /* Make sure no nfsiods are assigned to this mount. */
1921b662b41eSRick Macklem NFSLOCKIOD();
192264a0e848SRick Macklem for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
192364a0e848SRick Macklem if (ncl_iodmount[i] == nmp) {
192464a0e848SRick Macklem ncl_iodwant[i] = NFSIOD_AVAILABLE;
192564a0e848SRick Macklem ncl_iodmount[i] = NULL;
192664a0e848SRick Macklem }
1927b662b41eSRick Macklem NFSUNLOCKIOD();
192847cbff34SRick Macklem
192947cbff34SRick Macklem /*
193047cbff34SRick Macklem * We can now set mnt_data to NULL and wait for
193147cbff34SRick Macklem * nfssvc(NFSSVC_FORCEDISM) to complete.
193247cbff34SRick Macklem */
193347cbff34SRick Macklem mtx_lock(&mountlist_mtx);
193447cbff34SRick Macklem mtx_lock(&nmp->nm_mtx);
193547cbff34SRick Macklem mp->mnt_data = NULL;
193647cbff34SRick Macklem mtx_unlock(&mountlist_mtx);
193747cbff34SRick Macklem while ((nmp->nm_privflag & NFSMNTP_CANCELRPCS) != 0)
193847cbff34SRick Macklem msleep(nmp, &nmp->nm_mtx, PVFS, "nfsfdism", 0);
193947cbff34SRick Macklem mtx_unlock(&nmp->nm_mtx);
194047cbff34SRick Macklem
19411e0a518dSRick Macklem newnfs_disconnect(nmp, &nmp->nm_sockreq);
19429ec7b004SRick Macklem crfree(nmp->nm_sockreq.nr_cred);
1943222daa42SConrad Meyer free(nmp->nm_nam, M_SONAME);
194488a2437aSRick Macklem if (nmp->nm_sockreq.nr_auth != NULL)
194588a2437aSRick Macklem AUTH_DESTROY(nmp->nm_sockreq.nr_auth);
19469ec7b004SRick Macklem mtx_destroy(&nmp->nm_sockreq.nr_mtx);
19479ec7b004SRick Macklem mtx_destroy(&nmp->nm_mtx);
1948c20a7210SRick Macklem TAILQ_FOREACH_SAFE(dsp, &nmp->nm_sess, nfsclds_list, tdsp) {
1949c20a7210SRick Macklem if (dsp != TAILQ_FIRST(&nmp->nm_sess) &&
1950c20a7210SRick Macklem dsp->nfsclds_sockp != NULL)
19511e0a518dSRick Macklem newnfs_disconnect(NULL, dsp->nfsclds_sockp);
19521f60bfd8SRick Macklem nfscl_freenfsclds(dsp);
1953c20a7210SRick Macklem }
1954665b1365SRick Macklem free(nmp->nm_tlscertname, M_NEWNFSMNT);
1955222daa42SConrad Meyer free(nmp, M_NEWNFSMNT);
195644122258SRick Macklem
195744122258SRick Macklem /* Free up the delegation structures for forced dismounts. */
195844122258SRick Macklem TAILQ_FOREACH_SAFE(dp, &dh, nfsdl_list, ndp) {
195944122258SRick Macklem TAILQ_REMOVE(&dh, dp, nfsdl_list);
196044122258SRick Macklem free(dp, M_NFSCLDELEG);
196144122258SRick Macklem }
19629ec7b004SRick Macklem out:
19639ec7b004SRick Macklem return (error);
19649ec7b004SRick Macklem }
19659ec7b004SRick Macklem
19669ec7b004SRick Macklem /*
19679ec7b004SRick Macklem * Return root of a filesystem
19689ec7b004SRick Macklem */
19699ec7b004SRick Macklem static int
nfs_root(struct mount * mp,int flags,struct vnode ** vpp)1970dfd233edSAttilio Rao nfs_root(struct mount *mp, int flags, struct vnode **vpp)
19719ec7b004SRick Macklem {
19729ec7b004SRick Macklem struct vnode *vp;
19739ec7b004SRick Macklem struct nfsmount *nmp;
19749ec7b004SRick Macklem struct nfsnode *np;
19759ec7b004SRick Macklem int error;
1976896516e5SRick Macklem char *fakefh;
19779ec7b004SRick Macklem
19789ec7b004SRick Macklem nmp = VFSTONFS(mp);
1979896516e5SRick Macklem if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0) {
1980896516e5SRick Macklem /* Attempt to get the actual root file handle. */
1981896516e5SRick Macklem if (nmp->nm_fhsize == 0)
1982896516e5SRick Macklem error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
1983896516e5SRick Macklem curthread->td_ucred, curthread);
1984896516e5SRick Macklem fakefh = malloc(NFSX_FHMAX + 1, M_TEMP, M_WAITOK | M_ZERO);
1985896516e5SRick Macklem error = ncl_nget(mp, fakefh, NFSX_FHMAX + 1, &np, flags);
1986896516e5SRick Macklem free(fakefh, M_TEMP);
1987896516e5SRick Macklem } else {
19884b3a38ecSRick Macklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, flags);
1989896516e5SRick Macklem }
19909ec7b004SRick Macklem if (error)
19919ec7b004SRick Macklem return error;
19929ec7b004SRick Macklem vp = NFSTOV(np);
19939ec7b004SRick Macklem /*
19949ec7b004SRick Macklem * Get transfer parameters and attributes for root vnode once.
19959ec7b004SRick Macklem */
19969ec7b004SRick Macklem mtx_lock(&nmp->nm_mtx);
19979ec7b004SRick Macklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) {
19989ec7b004SRick Macklem mtx_unlock(&nmp->nm_mtx);
19999ec7b004SRick Macklem ncl_fsinfo(nmp, vp, curthread->td_ucred, curthread);
20009ec7b004SRick Macklem } else
20019ec7b004SRick Macklem mtx_unlock(&nmp->nm_mtx);
20029ec7b004SRick Macklem if (vp->v_type == VNON)
20039ec7b004SRick Macklem vp->v_type = VDIR;
20049ec7b004SRick Macklem vp->v_vflag |= VV_ROOT;
20059ec7b004SRick Macklem *vpp = vp;
20069ec7b004SRick Macklem return (0);
20079ec7b004SRick Macklem }
20089ec7b004SRick Macklem
20099ec7b004SRick Macklem /*
20109ec7b004SRick Macklem * Flush out the buffer cache
20119ec7b004SRick Macklem */
20129ec7b004SRick Macklem /* ARGSUSED */
20139ec7b004SRick Macklem static int
nfs_sync(struct mount * mp,int waitfor)2014dfd233edSAttilio Rao nfs_sync(struct mount *mp, int waitfor)
20159ec7b004SRick Macklem {
20169ec7b004SRick Macklem struct vnode *vp, *mvp;
2017dfd233edSAttilio Rao struct thread *td;
20189ec7b004SRick Macklem int error, allerror = 0;
20199ec7b004SRick Macklem
2020dfd233edSAttilio Rao td = curthread;
2021dfd233edSAttilio Rao
20228b5e8315SRick Macklem MNT_ILOCK(mp);
20238b5e8315SRick Macklem /*
20248b5e8315SRick Macklem * If a forced dismount is in progress, return from here so that
20258b5e8315SRick Macklem * the umount(2) syscall doesn't get stuck in VFS_SYNC() before
20268b5e8315SRick Macklem * calling VFS_UNMOUNT().
20278b5e8315SRick Macklem */
202816f300faSRick Macklem if (NFSCL_FORCEDISM(mp)) {
20298b5e8315SRick Macklem MNT_IUNLOCK(mp);
20308b5e8315SRick Macklem return (EBADF);
20318b5e8315SRick Macklem }
203271469bb3SKirk McKusick MNT_IUNLOCK(mp);
20338b5e8315SRick Macklem
20345ff7fb76SMateusz Guzik if (waitfor == MNT_LAZY)
20355ff7fb76SMateusz Guzik return (0);
20365ff7fb76SMateusz Guzik
20379ec7b004SRick Macklem /*
20389ec7b004SRick Macklem * Force stale buffer cache information to be flushed.
20399ec7b004SRick Macklem */
20409ec7b004SRick Macklem loop:
204171469bb3SKirk McKusick MNT_VNODE_FOREACH_ALL(vp, mp, mvp) {
20429ec7b004SRick Macklem /* XXX Racy bv_cnt check. */
20435ff7fb76SMateusz Guzik if (NFSVOPISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0) {
20449ec7b004SRick Macklem VI_UNLOCK(vp);
20459ec7b004SRick Macklem continue;
20469ec7b004SRick Macklem }
2047a92a971bSMateusz Guzik if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK)) {
204871469bb3SKirk McKusick MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
20499ec7b004SRick Macklem goto loop;
20509ec7b004SRick Macklem }
20519ec7b004SRick Macklem error = VOP_FSYNC(vp, waitfor, td);
20529ec7b004SRick Macklem if (error)
20539ec7b004SRick Macklem allerror = error;
2054b249ce48SMateusz Guzik NFSVOPUNLOCK(vp);
20559ec7b004SRick Macklem vrele(vp);
20569ec7b004SRick Macklem }
20579ec7b004SRick Macklem return (allerror);
20589ec7b004SRick Macklem }
20599ec7b004SRick Macklem
20609ec7b004SRick Macklem static int
nfs_sysctl(struct mount * mp,fsctlop_t op,struct sysctl_req * req)20619ec7b004SRick Macklem nfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req)
20629ec7b004SRick Macklem {
20639ec7b004SRick Macklem struct nfsmount *nmp = VFSTONFS(mp);
20649ec7b004SRick Macklem struct vfsquery vq;
20659ec7b004SRick Macklem int error;
20669ec7b004SRick Macklem
20679ec7b004SRick Macklem bzero(&vq, sizeof(vq));
20689ec7b004SRick Macklem switch (op) {
20699ec7b004SRick Macklem #if 0
20709ec7b004SRick Macklem case VFS_CTL_NOLOCKS:
20719ec7b004SRick Macklem val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0;
20729ec7b004SRick Macklem if (req->oldptr != NULL) {
20739ec7b004SRick Macklem error = SYSCTL_OUT(req, &val, sizeof(val));
20749ec7b004SRick Macklem if (error)
20759ec7b004SRick Macklem return (error);
20769ec7b004SRick Macklem }
20779ec7b004SRick Macklem if (req->newptr != NULL) {
20789ec7b004SRick Macklem error = SYSCTL_IN(req, &val, sizeof(val));
20799ec7b004SRick Macklem if (error)
20809ec7b004SRick Macklem return (error);
20819ec7b004SRick Macklem if (val)
20829ec7b004SRick Macklem nmp->nm_flag |= NFSMNT_NOLOCKS;
20839ec7b004SRick Macklem else
20849ec7b004SRick Macklem nmp->nm_flag &= ~NFSMNT_NOLOCKS;
20859ec7b004SRick Macklem }
20869ec7b004SRick Macklem break;
20879ec7b004SRick Macklem #endif
20889ec7b004SRick Macklem case VFS_CTL_QUERY:
20899ec7b004SRick Macklem mtx_lock(&nmp->nm_mtx);
20909ec7b004SRick Macklem if (nmp->nm_state & NFSSTA_TIMEO)
20919ec7b004SRick Macklem vq.vq_flags |= VQ_NOTRESP;
20929ec7b004SRick Macklem mtx_unlock(&nmp->nm_mtx);
20939ec7b004SRick Macklem #if 0
20949ec7b004SRick Macklem if (!(nmp->nm_flag & NFSMNT_NOLOCKS) &&
20959ec7b004SRick Macklem (nmp->nm_state & NFSSTA_LOCKTIMEO))
20969ec7b004SRick Macklem vq.vq_flags |= VQ_NOTRESPLOCK;
20979ec7b004SRick Macklem #endif
20989ec7b004SRick Macklem error = SYSCTL_OUT(req, &vq, sizeof(vq));
20999ec7b004SRick Macklem break;
21009ec7b004SRick Macklem case VFS_CTL_TIMEO:
21019ec7b004SRick Macklem if (req->oldptr != NULL) {
21029ec7b004SRick Macklem error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay,
21039ec7b004SRick Macklem sizeof(nmp->nm_tprintf_initial_delay));
21049ec7b004SRick Macklem if (error)
21059ec7b004SRick Macklem return (error);
21069ec7b004SRick Macklem }
21079ec7b004SRick Macklem if (req->newptr != NULL) {
21089ec7b004SRick Macklem error = vfs_suser(mp, req->td);
21099ec7b004SRick Macklem if (error)
21109ec7b004SRick Macklem return (error);
21119ec7b004SRick Macklem error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay,
21129ec7b004SRick Macklem sizeof(nmp->nm_tprintf_initial_delay));
21139ec7b004SRick Macklem if (error)
21149ec7b004SRick Macklem return (error);
21159ec7b004SRick Macklem if (nmp->nm_tprintf_initial_delay < 0)
21169ec7b004SRick Macklem nmp->nm_tprintf_initial_delay = 0;
21179ec7b004SRick Macklem }
21189ec7b004SRick Macklem break;
21199ec7b004SRick Macklem default:
21209ec7b004SRick Macklem return (ENOTSUP);
21219ec7b004SRick Macklem }
21229ec7b004SRick Macklem return (0);
21239ec7b004SRick Macklem }
21249ec7b004SRick Macklem
2125ca27c028SRick Macklem /*
21268fe6bddfSRick Macklem * Purge any RPCs in progress, so that they will all return errors.
21278fe6bddfSRick Macklem * This allows dounmount() to continue as far as VFS_UNMOUNT() for a
21288fe6bddfSRick Macklem * forced dismount.
21298fe6bddfSRick Macklem */
21308fe6bddfSRick Macklem static void
nfs_purge(struct mount * mp)21318fe6bddfSRick Macklem nfs_purge(struct mount *mp)
21328fe6bddfSRick Macklem {
21338fe6bddfSRick Macklem struct nfsmount *nmp = VFSTONFS(mp);
21348fe6bddfSRick Macklem
21358fe6bddfSRick Macklem newnfs_nmcancelreqs(nmp);
21368fe6bddfSRick Macklem }
21378fe6bddfSRick Macklem
21388fe6bddfSRick Macklem /*
2139ca27c028SRick Macklem * Extract the information needed by the nlm from the nfs vnode.
2140ca27c028SRick Macklem */
2141ca27c028SRick Macklem static void
nfs_getnlminfo(struct vnode * vp,uint8_t * fhp,size_t * fhlenp,struct sockaddr_storage * sp,int * is_v3p,off_t * sizep,struct timeval * timeop)21424d4f9a37SRick Macklem nfs_getnlminfo(struct vnode *vp, uint8_t *fhp, size_t *fhlenp,
214390305aa3SRick Macklem struct sockaddr_storage *sp, int *is_v3p, off_t *sizep,
214490305aa3SRick Macklem struct timeval *timeop)
2145ca27c028SRick Macklem {
2146ca27c028SRick Macklem struct nfsmount *nmp;
2147ca27c028SRick Macklem struct nfsnode *np = VTONFS(vp);
2148ca27c028SRick Macklem
2149ca27c028SRick Macklem nmp = VFSTONFS(vp->v_mount);
2150ca27c028SRick Macklem if (fhlenp != NULL)
21514d4f9a37SRick Macklem *fhlenp = (size_t)np->n_fhp->nfh_len;
2152ca27c028SRick Macklem if (fhp != NULL)
2153ca27c028SRick Macklem bcopy(np->n_fhp->nfh_fh, fhp, np->n_fhp->nfh_len);
2154ca27c028SRick Macklem if (sp != NULL)
2155ca27c028SRick Macklem bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp)));
2156ca27c028SRick Macklem if (is_v3p != NULL)
2157ca27c028SRick Macklem *is_v3p = NFS_ISV3(vp);
2158ca27c028SRick Macklem if (sizep != NULL)
2159ca27c028SRick Macklem *sizep = np->n_size;
216090305aa3SRick Macklem if (timeop != NULL) {
216190305aa3SRick Macklem timeop->tv_sec = nmp->nm_timeo / NFS_HZ;
216290305aa3SRick Macklem timeop->tv_usec = (nmp->nm_timeo % NFS_HZ) * (1000000 / NFS_HZ);
216390305aa3SRick Macklem }
2164ca27c028SRick Macklem }
2165ca27c028SRick Macklem
216699d2727dSRick Macklem /*
216799d2727dSRick Macklem * This function prints out an option name, based on the conditional
216899d2727dSRick Macklem * argument.
216999d2727dSRick Macklem */
nfscl_printopt(struct nfsmount * nmp,int testval,char * opt,char ** buf,size_t * blen)217099d2727dSRick Macklem static __inline void nfscl_printopt(struct nfsmount *nmp, int testval,
217199d2727dSRick Macklem char *opt, char **buf, size_t *blen)
217299d2727dSRick Macklem {
217399d2727dSRick Macklem int len;
217499d2727dSRick Macklem
217599d2727dSRick Macklem if (testval != 0 && *blen > strlen(opt)) {
217699d2727dSRick Macklem len = snprintf(*buf, *blen, "%s", opt);
217799d2727dSRick Macklem if (len != strlen(opt))
217899d2727dSRick Macklem printf("EEK!!\n");
217999d2727dSRick Macklem *buf += len;
218099d2727dSRick Macklem *blen -= len;
218199d2727dSRick Macklem }
218299d2727dSRick Macklem }
218399d2727dSRick Macklem
218499d2727dSRick Macklem /*
218599d2727dSRick Macklem * This function printf out an options integer value.
218699d2727dSRick Macklem */
nfscl_printoptval(struct nfsmount * nmp,int optval,char * opt,char ** buf,size_t * blen)218799d2727dSRick Macklem static __inline void nfscl_printoptval(struct nfsmount *nmp, int optval,
218899d2727dSRick Macklem char *opt, char **buf, size_t *blen)
218999d2727dSRick Macklem {
219099d2727dSRick Macklem int len;
219199d2727dSRick Macklem
219299d2727dSRick Macklem if (*blen > strlen(opt) + 1) {
219399d2727dSRick Macklem /* Could result in truncated output string. */
219499d2727dSRick Macklem len = snprintf(*buf, *blen, "%s=%d", opt, optval);
219599d2727dSRick Macklem if (len < *blen) {
219699d2727dSRick Macklem *buf += len;
219799d2727dSRick Macklem *blen -= len;
219899d2727dSRick Macklem }
219999d2727dSRick Macklem }
220099d2727dSRick Macklem }
220199d2727dSRick Macklem
220299d2727dSRick Macklem /*
220399d2727dSRick Macklem * Load the option flags and values into the buffer.
220499d2727dSRick Macklem */
nfscl_retopts(struct nfsmount * nmp,char * buffer,size_t buflen)220599d2727dSRick Macklem void nfscl_retopts(struct nfsmount *nmp, char *buffer, size_t buflen)
220699d2727dSRick Macklem {
220799d2727dSRick Macklem char *buf;
220899d2727dSRick Macklem size_t blen;
220999d2727dSRick Macklem
221099d2727dSRick Macklem buf = buffer;
221199d2727dSRick Macklem blen = buflen;
221299d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV4) != 0, "nfsv4", &buf,
221399d2727dSRick Macklem &blen);
2214ef8f1261SRick Macklem if ((nmp->nm_flag & NFSMNT_NFSV4) != 0) {
2215ef8f1261SRick Macklem nfscl_printoptval(nmp, nmp->nm_minorvers, ",minorversion", &buf,
2216ef8f1261SRick Macklem &blen);
2217ef8f1261SRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_PNFS) != 0, ",pnfs",
2218ef8f1261SRick Macklem &buf, &blen);
2219037a2012SRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_ONEOPENOWN) != 0 &&
2220037a2012SRick Macklem nmp->nm_minorvers > 0, ",oneopenown", &buf, &blen);
2221ef8f1261SRick Macklem }
222299d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV3) != 0, "nfsv3", &buf,
222399d2727dSRick Macklem &blen);
222499d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0,
222599d2727dSRick Macklem "nfsv2", &buf, &blen);
222699d2727dSRick Macklem nfscl_printopt(nmp, nmp->nm_sotype == SOCK_STREAM, ",tcp", &buf, &blen);
222799d2727dSRick Macklem nfscl_printopt(nmp, nmp->nm_sotype != SOCK_STREAM, ",udp", &buf, &blen);
222899d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RESVPORT) != 0, ",resvport",
222999d2727dSRick Macklem &buf, &blen);
22306e4b6ff8SRick Macklem nfscl_printopt(nmp, (nmp->nm_newflag & NFSMNT_TLS) != 0, ",tls", &buf,
22316e4b6ff8SRick Macklem &blen);
2232896516e5SRick Macklem nfscl_printopt(nmp, (nmp->nm_newflag & NFSMNT_SYSKRB5) != 0,
2233896516e5SRick Macklem ",syskrb5", &buf, &blen);
223499d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCONN) != 0, ",noconn",
223599d2727dSRick Macklem &buf, &blen);
22361e0a518dSRick Macklem nfscl_printoptval(nmp, nmp->nm_aconnect + 1, ",nconnect", &buf, &blen);
223799d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) == 0, ",hard", &buf,
223899d2727dSRick Macklem &blen);
223999d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) != 0, ",soft", &buf,
224099d2727dSRick Macklem &blen);
224199d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_INT) != 0, ",intr", &buf,
224299d2727dSRick Macklem &blen);
224399d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) == 0, ",cto", &buf,
224499d2727dSRick Macklem &blen);
224599d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) != 0, ",nocto", &buf,
224699d2727dSRick Macklem &blen);
2247cf766161SRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NONCONTIGWR) != 0,
2248cf766161SRick Macklem ",noncontigwr", &buf, &blen);
224999d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NOLOCKD | NFSMNT_NFSV4)) ==
225099d2727dSRick Macklem 0, ",lockd", &buf, &blen);
225133721eb9SRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOLOCKD) != 0, ",nolockd",
225233721eb9SRick Macklem &buf, &blen);
225399d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RDIRPLUS) != 0, ",rdirplus",
225499d2727dSRick Macklem &buf, &blen);
225599d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_KERB) == 0, ",sec=sys",
225699d2727dSRick Macklem &buf, &blen);
225799d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
225899d2727dSRick Macklem NFSMNT_PRIVACY)) == NFSMNT_KERB, ",sec=krb5", &buf, &blen);
225999d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
226099d2727dSRick Macklem NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_INTEGRITY), ",sec=krb5i",
226199d2727dSRick Macklem &buf, &blen);
226299d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
226399d2727dSRick Macklem NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_PRIVACY), ",sec=krb5p",
226499d2727dSRick Macklem &buf, &blen);
226599d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_acdirmin, ",acdirmin", &buf, &blen);
226699d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_acdirmax, ",acdirmax", &buf, &blen);
226799d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_acregmin, ",acregmin", &buf, &blen);
226899d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_acregmax, ",acregmax", &buf, &blen);
226999d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_nametimeo, ",nametimeo", &buf, &blen);
227099d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_negnametimeo, ",negnametimeo", &buf,
227199d2727dSRick Macklem &blen);
227299d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_rsize, ",rsize", &buf, &blen);
227399d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_wsize, ",wsize", &buf, &blen);
227499d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_readdirsize, ",readdirsize", &buf,
227599d2727dSRick Macklem &blen);
227699d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_readahead, ",readahead", &buf, &blen);
227799d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_wcommitsize, ",wcommitsize", &buf,
227899d2727dSRick Macklem &blen);
227999d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_timeo, ",timeout", &buf, &blen);
228099d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_retry, ",retrans", &buf, &blen);
228199d2727dSRick Macklem }
2282