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 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 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 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 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 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 /* 418*52d895feSEd 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 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 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 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 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 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 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 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 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"); 15271f60bfd8SRick Macklem clp = NULL; 15289ec7b004SRick Macklem if (mp->mnt_flag & MNT_UPDATE) { 15299ec7b004SRick Macklem nmp = VFSTONFS(mp); 15309ec7b004SRick Macklem printf("%s: MNT_UPDATE is no longer handled here\n", __func__); 1531222daa42SConrad Meyer free(nam, M_SONAME); 1532665b1365SRick Macklem free(tlscertname, M_NEWNFSMNT); 15339ec7b004SRick Macklem return (0); 15349ec7b004SRick Macklem } else { 15356e4b6ff8SRick Macklem /* NFS-over-TLS requires that rpctls be functioning. */ 15366e4b6ff8SRick Macklem if ((newflag & NFSMNT_TLS) != 0) { 15376e4b6ff8SRick Macklem error = EINVAL; 15386e4b6ff8SRick Macklem #ifdef KERN_TLS 15394cdbb07bSRick Macklem /* KERN_TLS is only supported for TCP. */ 15404cdbb07bSRick Macklem if (argp->sotype == SOCK_STREAM && 15414cdbb07bSRick Macklem rpctls_getinfo(&maxlen, true, false)) 15426e4b6ff8SRick Macklem error = 0; 15436e4b6ff8SRick Macklem #endif 15446e4b6ff8SRick Macklem if (error != 0) { 15456e4b6ff8SRick Macklem free(nam, M_SONAME); 1546665b1365SRick Macklem free(tlscertname, M_NEWNFSMNT); 15476e4b6ff8SRick Macklem return (error); 15486e4b6ff8SRick Macklem } 15496e4b6ff8SRick Macklem } 1550222daa42SConrad Meyer nmp = malloc(sizeof (struct nfsmount) + 1551385edc8eSRick Macklem krbnamelen + dirlen + srvkrbnamelen + 2, 1552385edc8eSRick Macklem M_NEWNFSMNT, M_WAITOK | M_ZERO); 1553665b1365SRick Macklem nmp->nm_tlscertname = tlscertname; 15546e4b6ff8SRick Macklem nmp->nm_newflag = newflag; 15559ec7b004SRick Macklem TAILQ_INIT(&nmp->nm_bufq); 1556b2fc0141SRick Macklem TAILQ_INIT(&nmp->nm_sess); 15579ec7b004SRick Macklem if (clval == 0) 15589ec7b004SRick Macklem clval = (u_int64_t)nfsboottime.tv_sec; 15599ec7b004SRick Macklem nmp->nm_clval = clval++; 1560385edc8eSRick Macklem nmp->nm_krbnamelen = krbnamelen; 1561385edc8eSRick Macklem nmp->nm_dirpathlen = dirlen; 1562385edc8eSRick Macklem nmp->nm_srvkrbnamelen = srvkrbnamelen; 156363bde62eSRick Macklem if (td->td_ucred->cr_uid != (uid_t)0) { 15649ec7b004SRick Macklem /* 156563bde62eSRick Macklem * nm_uid is used to get KerberosV credentials for 156663bde62eSRick Macklem * the nfsv4 state handling operations if there is 156763bde62eSRick Macklem * no host based principal set. Use the uid of 156863bde62eSRick Macklem * this user if not root, since they are doing the 156963bde62eSRick Macklem * mount. I don't think setting this for root will 157063bde62eSRick Macklem * work, since root normally does not have user 157163bde62eSRick Macklem * credentials in a credentials cache. 15729ec7b004SRick Macklem */ 157363bde62eSRick Macklem nmp->nm_uid = td->td_ucred->cr_uid; 15749ec7b004SRick Macklem } else { 15759ec7b004SRick Macklem /* 157663bde62eSRick Macklem * Just set to -1, so it won't be used. 15779ec7b004SRick Macklem */ 15789ec7b004SRick Macklem nmp->nm_uid = (uid_t)-1; 15799ec7b004SRick Macklem } 15809ec7b004SRick Macklem 15819ec7b004SRick Macklem /* Copy and null terminate all the names */ 15829ec7b004SRick Macklem if (nmp->nm_krbnamelen > 0) { 15839ec7b004SRick Macklem bcopy(krbname, nmp->nm_krbname, nmp->nm_krbnamelen); 15849ec7b004SRick Macklem nmp->nm_name[nmp->nm_krbnamelen] = '\0'; 15859ec7b004SRick Macklem } 15869ec7b004SRick Macklem if (nmp->nm_dirpathlen > 0) { 15879ec7b004SRick Macklem bcopy(dirpath, NFSMNT_DIRPATH(nmp), 15889ec7b004SRick Macklem nmp->nm_dirpathlen); 15899ec7b004SRick Macklem nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen 15909ec7b004SRick Macklem + 1] = '\0'; 15919ec7b004SRick Macklem } 15929ec7b004SRick Macklem if (nmp->nm_srvkrbnamelen > 0) { 15939ec7b004SRick Macklem bcopy(srvkrbname, NFSMNT_SRVKRBNAME(nmp), 15949ec7b004SRick Macklem nmp->nm_srvkrbnamelen); 15959ec7b004SRick Macklem nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen 15969ec7b004SRick Macklem + nmp->nm_srvkrbnamelen + 2] = '\0'; 15979ec7b004SRick Macklem } 15989ec7b004SRick Macklem nmp->nm_sockreq.nr_cred = crhold(cred); 15999ec7b004SRick Macklem mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF); 16009ec7b004SRick Macklem mp->mnt_data = nmp; 1601ca27c028SRick Macklem nmp->nm_getinfo = nfs_getnlminfo; 160290305aa3SRick Macklem nmp->nm_vinvalbuf = ncl_vinvalbuf; 16039ec7b004SRick Macklem } 16049ec7b004SRick Macklem vfs_getnewfsid(mp); 16059ec7b004SRick Macklem nmp->nm_mountp = mp; 16069ec7b004SRick Macklem mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK); 160790379d61SRick Macklem 160890379d61SRick Macklem /* 16090b17c7beSJohn Baldwin * Since nfs_decode_args() might optionally set them, these 16100b17c7beSJohn Baldwin * need to be set to defaults before the call, so that the 16110b17c7beSJohn Baldwin * optional settings aren't overwritten. 161290379d61SRick Macklem */ 16130b17c7beSJohn Baldwin nmp->nm_nametimeo = nametimeo; 1614dd5b5a94SRick Macklem nmp->nm_negnametimeo = negnametimeo; 161590379d61SRick Macklem nmp->nm_timeo = NFS_TIMEO; 161690379d61SRick Macklem nmp->nm_retry = NFS_RETRANS; 161790379d61SRick Macklem nmp->nm_readahead = NFS_DEFRAHEAD; 1618afdfc9a4SAlexander Motin 1619afdfc9a4SAlexander Motin /* This is empirical approximation of sqrt(hibufspace) * 256. */ 1620afdfc9a4SAlexander Motin nmp->nm_wcommitsize = NFS_MAXBSIZE / 256; 1621afdfc9a4SAlexander Motin while ((long)nmp->nm_wcommitsize * nmp->nm_wcommitsize < hibufspace) 1622afdfc9a4SAlexander Motin nmp->nm_wcommitsize *= 2; 1623afdfc9a4SAlexander Motin nmp->nm_wcommitsize *= 256; 1624afdfc9a4SAlexander Motin 1625a145cf3fSRick Macklem tryminvers = false; 1626a145cf3fSRick Macklem if ((argp->flags & NFSMNT_NFSV4) != 0) { 1627a145cf3fSRick Macklem if (minvers < 0) { 1628a145cf3fSRick Macklem tryminvers = true; 1629a145cf3fSRick Macklem minvers = NFSV42_MINORVERSION; 1630a145cf3fSRick Macklem } 16311f60bfd8SRick Macklem nmp->nm_minorvers = minvers; 1632a145cf3fSRick Macklem } else 16331f60bfd8SRick Macklem nmp->nm_minorvers = 0; 16349ec7b004SRick Macklem 1635ca27c028SRick Macklem nfs_decode_args(mp, nmp, argp, hst, cred, td); 1636682eec57SRick Macklem 16379ec7b004SRick Macklem /* 16389ec7b004SRick Macklem * V2 can only handle 32 bit filesizes. A 4GB-1 limit may be too 16399ec7b004SRick Macklem * high, depending on whether we end up with negative offsets in 16409ec7b004SRick Macklem * the client or server somewhere. 2GB-1 may be safer. 16419ec7b004SRick Macklem * 16429ec7b004SRick Macklem * For V3, ncl_fsinfo will adjust this as necessary. Assume maximum 16439ec7b004SRick Macklem * that we can handle until we find out otherwise. 16449ec7b004SRick Macklem */ 16459ec7b004SRick Macklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) 16469ec7b004SRick Macklem nmp->nm_maxfilesize = 0xffffffffLL; 16479ec7b004SRick Macklem else 16481dcad8ecSRick Macklem nmp->nm_maxfilesize = OFF_MAX; 16499ec7b004SRick Macklem 16509ec7b004SRick Macklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) { 16519ec7b004SRick Macklem nmp->nm_wsize = NFS_WSIZE; 16529ec7b004SRick Macklem nmp->nm_rsize = NFS_RSIZE; 16539ec7b004SRick Macklem nmp->nm_readdirsize = NFS_READDIRSIZE; 16549ec7b004SRick Macklem } 16559ec7b004SRick Macklem nmp->nm_numgrps = NFS_MAXGRPS; 16569ec7b004SRick Macklem nmp->nm_tprintf_delay = nfs_tprintf_delay; 16579ec7b004SRick Macklem if (nmp->nm_tprintf_delay < 0) 16589ec7b004SRick Macklem nmp->nm_tprintf_delay = 0; 16599ec7b004SRick Macklem nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay; 16609ec7b004SRick Macklem if (nmp->nm_tprintf_initial_delay < 0) 16619ec7b004SRick Macklem nmp->nm_tprintf_initial_delay = 0; 16629ec7b004SRick Macklem nmp->nm_fhsize = argp->fhsize; 16639ec7b004SRick Macklem if (nmp->nm_fhsize > 0) 16649ec7b004SRick Macklem bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize); 166544de1834SMark Johnston strlcpy(mp->mnt_stat.f_mntfromname, hst, MNAMELEN); 16669ec7b004SRick Macklem nmp->nm_nam = nam; 16679ec7b004SRick Macklem /* Set up the sockets and per-host congestion */ 16689ec7b004SRick Macklem nmp->nm_sotype = argp->sotype; 16699ec7b004SRick Macklem nmp->nm_soproto = argp->proto; 16709ec7b004SRick Macklem nmp->nm_sockreq.nr_prog = NFS_PROG; 16719ec7b004SRick Macklem if ((argp->flags & NFSMNT_NFSV4)) 16729ec7b004SRick Macklem nmp->nm_sockreq.nr_vers = NFS_VER4; 16739ec7b004SRick Macklem else if ((argp->flags & NFSMNT_NFSV3)) 16749ec7b004SRick Macklem nmp->nm_sockreq.nr_vers = NFS_VER3; 16759ec7b004SRick Macklem else 16769ec7b004SRick Macklem nmp->nm_sockreq.nr_vers = NFS_VER2; 16779ec7b004SRick Macklem 16781e0a518dSRick Macklem if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0, false, 16791e0a518dSRick Macklem &nmp->nm_sockreq.nr_client))) 16809ec7b004SRick Macklem goto bad; 1681aed98fa5SRick Macklem /* For NFSv4, get the clientid now. */ 1682aed98fa5SRick Macklem if ((argp->flags & NFSMNT_NFSV4) != 0) { 16831f60bfd8SRick Macklem NFSCL_DEBUG(3, "at getcl\n"); 1684120b20bdSRick Macklem error = nfscl_getcl(mp, cred, td, tryminvers, true, &clp); 16851f60bfd8SRick Macklem NFSCL_DEBUG(3, "aft getcl=%d\n", error); 16861f60bfd8SRick Macklem if (error != 0) 16871f60bfd8SRick Macklem goto bad; 16881e0a518dSRick Macklem if (aconn > 0 && nmp->nm_minorvers == 0) { 16891e0a518dSRick Macklem vfs_mount_error(mp, "nconnect should only be used " 16901e0a518dSRick Macklem "for NFSv4.1/4.2 mounts"); 16911e0a518dSRick Macklem error = EINVAL; 16921e0a518dSRick Macklem goto bad; 16931e0a518dSRick Macklem } 1694896516e5SRick Macklem if (NFSHASSYSKRB5(nmp) && nmp->nm_minorvers == 0) { 1695896516e5SRick Macklem vfs_mount_error(mp, "syskrb5 should only be used " 1696896516e5SRick Macklem "for NFSv4.1/4.2 mounts"); 1697896516e5SRick Macklem error = EINVAL; 1698896516e5SRick Macklem goto bad; 1699896516e5SRick Macklem } 17001f60bfd8SRick Macklem } 17011f60bfd8SRick Macklem 17021f60bfd8SRick Macklem if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) && 17031f60bfd8SRick Macklem nmp->nm_dirpathlen > 0) { 17041f60bfd8SRick Macklem NFSCL_DEBUG(3, "in dirp\n"); 17051f60bfd8SRick Macklem /* 17061f60bfd8SRick Macklem * If the fhsize on the mount point == 0 for V4, the mount 17071f60bfd8SRick Macklem * path needs to be looked up. 17081f60bfd8SRick Macklem */ 17091f60bfd8SRick Macklem trycnt = 3; 17101f60bfd8SRick Macklem do { 17111f60bfd8SRick Macklem error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), 17121f60bfd8SRick Macklem cred, td); 17131f60bfd8SRick Macklem NFSCL_DEBUG(3, "aft dirp=%d\n", error); 1714896516e5SRick Macklem if (error != 0 && (!NFSHASSYSKRB5(nmp) || 1715896516e5SRick Macklem error != NFSERR_WRONGSEC)) 17161f60bfd8SRick Macklem (void) nfs_catnap(PZERO, error, "nfsgetdirp"); 1717896516e5SRick Macklem } while (error != 0 && --trycnt > 0 && 1718896516e5SRick Macklem (!NFSHASSYSKRB5(nmp) || error != NFSERR_WRONGSEC)); 1719896516e5SRick Macklem if (error != 0 && (!NFSHASSYSKRB5(nmp) || 1720896516e5SRick Macklem error != NFSERR_WRONGSEC)) 17211f60bfd8SRick Macklem goto bad; 17221f60bfd8SRick Macklem } 17239ec7b004SRick Macklem 17249ec7b004SRick Macklem /* 17259ec7b004SRick Macklem * A reference count is needed on the nfsnode representing the 17269ec7b004SRick Macklem * remote root. If this object is not persistent, then backward 17279ec7b004SRick Macklem * traversals of the mount point (i.e. "..") will not work if 17289ec7b004SRick Macklem * the nfsnode gets flushed out of the cache. Ufs does not have 17299ec7b004SRick Macklem * this problem, because one can identify root inodes by their 17301dc349abSEd Maste * number == UFS_ROOTINO (2). 1731896516e5SRick Macklem * For the "syskrb5" mount, the file handle might not have 1732896516e5SRick Macklem * been acquired. As such, use a "fake" file handle which 1733896516e5SRick Macklem * can never be returned by a server for the root vnode. 17349ec7b004SRick Macklem */ 1735896516e5SRick Macklem if (nmp->nm_fhsize > 0 || NFSHASSYSKRB5(nmp)) { 173680e55695SRick Macklem /* 173780e55695SRick Macklem * Set f_iosize to NFS_DIRBLKSIZ so that bo_bsize gets set 173880e55695SRick Macklem * non-zero for the root vnode. f_iosize will be set correctly 173980e55695SRick Macklem * by nfs_statfs() before any I/O occurs. 174080e55695SRick Macklem */ 174180e55695SRick Macklem mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ; 1742896516e5SRick Macklem if (nmp->nm_fhsize == 0) { 1743896516e5SRick Macklem fakefh = malloc(NFSX_FHMAX + 1, M_TEMP, M_WAITOK | 1744896516e5SRick Macklem M_ZERO); 1745896516e5SRick Macklem error = ncl_nget(mp, fakefh, NFSX_FHMAX + 1, &np, 1746896516e5SRick Macklem LK_EXCLUSIVE); 1747896516e5SRick Macklem free(fakefh, M_TEMP); 1748896516e5SRick Macklem nmp->nm_privflag |= NFSMNTP_FAKEROOTFH; 1749896516e5SRick Macklem } else 17504b3a38ecSRick Macklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, 17514b3a38ecSRick Macklem LK_EXCLUSIVE); 17529ec7b004SRick Macklem if (error) 17539ec7b004SRick Macklem goto bad; 17549ec7b004SRick Macklem *vpp = NFSTOV(np); 17559ec7b004SRick Macklem 17569ec7b004SRick Macklem /* 17579ec7b004SRick Macklem * Get file attributes and transfer parameters for the 17589ec7b004SRick Macklem * mountpoint. This has the side effect of filling in 17599ec7b004SRick Macklem * (*vpp)->v_type with the correct value. 17609ec7b004SRick Macklem */ 1761896516e5SRick Macklem ret = ENXIO; 1762896516e5SRick Macklem if (nmp->nm_fhsize > 0) 1763896516e5SRick Macklem ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, 1764896516e5SRick Macklem nmp->nm_fhsize, 1, cred, td, &nfsva, NULL, &lease); 17659ec7b004SRick Macklem if (ret) { 17669ec7b004SRick Macklem /* 17679ec7b004SRick Macklem * Just set default values to get things going. 17689ec7b004SRick Macklem */ 17699ec7b004SRick Macklem NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr)); 17709ec7b004SRick Macklem nfsva.na_vattr.va_type = VDIR; 17719ec7b004SRick Macklem nfsva.na_vattr.va_mode = 0777; 17729ec7b004SRick Macklem nfsva.na_vattr.va_nlink = 100; 17739ec7b004SRick Macklem nfsva.na_vattr.va_uid = (uid_t)0; 17749ec7b004SRick Macklem nfsva.na_vattr.va_gid = (gid_t)0; 17759ec7b004SRick Macklem nfsva.na_vattr.va_fileid = 2; 17769ec7b004SRick Macklem nfsva.na_vattr.va_gen = 1; 17779ec7b004SRick Macklem nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; 17789ec7b004SRick Macklem nfsva.na_vattr.va_size = 512 * 1024; 1779896516e5SRick Macklem lease = 20; 17809ec7b004SRick Macklem } 17814ad3423bSRick Macklem (void) nfscl_loadattrcache(vpp, &nfsva, NULL, 0, 1); 1782aed98fa5SRick Macklem if ((argp->flags & NFSMNT_NFSV4) != 0) { 17831f60bfd8SRick Macklem NFSCL_DEBUG(3, "lease=%d\n", (int)lease); 17841f60bfd8SRick Macklem NFSLOCKCLSTATE(); 17851f60bfd8SRick Macklem clp->nfsc_renew = NFSCL_RENEW(lease); 17861f60bfd8SRick Macklem clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew; 17871f60bfd8SRick Macklem clp->nfsc_clientidrev++; 17881f60bfd8SRick Macklem if (clp->nfsc_clientidrev == 0) 17891f60bfd8SRick Macklem clp->nfsc_clientidrev++; 17901f60bfd8SRick Macklem NFSUNLOCKCLSTATE(); 17911f60bfd8SRick Macklem /* 17921f60bfd8SRick Macklem * Mount will succeed, so the renew thread can be 17931f60bfd8SRick Macklem * started now. 17941f60bfd8SRick Macklem */ 17951f60bfd8SRick Macklem nfscl_start_renewthread(clp); 17961f60bfd8SRick Macklem nfscl_clientrelease(clp); 17971f60bfd8SRick Macklem } 17989ec7b004SRick Macklem if (argp->flags & NFSMNT_NFSV3) 17999ec7b004SRick Macklem ncl_fsinfo(nmp, *vpp, cred, td); 18009ec7b004SRick Macklem 1801484c842dSRick Macklem /* Mark if the mount point supports NFSv4 ACLs. */ 1802484c842dSRick Macklem if ((argp->flags & NFSMNT_NFSV4) != 0 && nfsrv_useacl != 0 && 1803484c842dSRick Macklem ret == 0 && 1804484c842dSRick Macklem NFSISSET_ATTRBIT(&nfsva.na_suppattr, NFSATTRBIT_ACL)) { 1805484c842dSRick Macklem MNT_ILOCK(mp); 1806484c842dSRick Macklem mp->mnt_flag |= MNT_NFS4ACLS; 1807484c842dSRick Macklem MNT_IUNLOCK(mp); 1808484c842dSRick Macklem } 1809484c842dSRick Macklem 18101e0a518dSRick Macklem /* Can now allow additional connections. */ 18111e0a518dSRick Macklem if (aconn > 0) 18121e0a518dSRick Macklem nmp->nm_aconnect = aconn; 18131e0a518dSRick Macklem 18149ec7b004SRick Macklem /* 18159ec7b004SRick Macklem * Lose the lock but keep the ref. 18169ec7b004SRick Macklem */ 1817b249ce48SMateusz Guzik NFSVOPUNLOCK(*vpp); 1818d511f93eSMateusz Guzik vfs_cache_root_set(mp, *vpp); 18199ec7b004SRick Macklem return (0); 18209ec7b004SRick Macklem } 18219ec7b004SRick Macklem error = EIO; 18229ec7b004SRick Macklem 18239ec7b004SRick Macklem bad: 18241f60bfd8SRick Macklem if (clp != NULL) 18251f60bfd8SRick Macklem nfscl_clientrelease(clp); 18261e0a518dSRick Macklem newnfs_disconnect(NULL, &nmp->nm_sockreq); 18279ec7b004SRick Macklem crfree(nmp->nm_sockreq.nr_cred); 182888a2437aSRick Macklem if (nmp->nm_sockreq.nr_auth != NULL) 182988a2437aSRick Macklem AUTH_DESTROY(nmp->nm_sockreq.nr_auth); 18309ec7b004SRick Macklem mtx_destroy(&nmp->nm_sockreq.nr_mtx); 18319ec7b004SRick Macklem mtx_destroy(&nmp->nm_mtx); 18321f60bfd8SRick Macklem if (nmp->nm_clp != NULL) { 18331f60bfd8SRick Macklem NFSLOCKCLSTATE(); 18341f60bfd8SRick Macklem LIST_REMOVE(nmp->nm_clp, nfsc_list); 18351f60bfd8SRick Macklem NFSUNLOCKCLSTATE(); 18361f60bfd8SRick Macklem free(nmp->nm_clp, M_NFSCLCLIENT); 18371f60bfd8SRick Macklem } 1838c20a7210SRick Macklem TAILQ_FOREACH_SAFE(dsp, &nmp->nm_sess, nfsclds_list, tdsp) { 1839c20a7210SRick Macklem if (dsp != TAILQ_FIRST(&nmp->nm_sess) && 1840c20a7210SRick Macklem dsp->nfsclds_sockp != NULL) 18411e0a518dSRick Macklem newnfs_disconnect(NULL, dsp->nfsclds_sockp); 18421f60bfd8SRick Macklem nfscl_freenfsclds(dsp); 1843c20a7210SRick Macklem } 1844665b1365SRick Macklem free(nmp->nm_tlscertname, M_NEWNFSMNT); 1845222daa42SConrad Meyer free(nmp, M_NEWNFSMNT); 1846222daa42SConrad Meyer free(nam, M_SONAME); 18479ec7b004SRick Macklem return (error); 18489ec7b004SRick Macklem } 18499ec7b004SRick Macklem 18509ec7b004SRick Macklem /* 18519ec7b004SRick Macklem * unmount system call 18529ec7b004SRick Macklem */ 18539ec7b004SRick Macklem static int 1854dfd233edSAttilio Rao nfs_unmount(struct mount *mp, int mntflags) 18559ec7b004SRick Macklem { 1856dfd233edSAttilio Rao struct thread *td; 18579ec7b004SRick Macklem struct nfsmount *nmp; 185864a0e848SRick Macklem int error, flags = 0, i, trycnt = 0; 18591f60bfd8SRick Macklem struct nfsclds *dsp, *tdsp; 186044122258SRick Macklem struct nfscldeleg *dp, *ndp; 186144122258SRick Macklem struct nfscldeleghead dh; 18629ec7b004SRick Macklem 1863dfd233edSAttilio Rao td = curthread; 186444122258SRick Macklem TAILQ_INIT(&dh); 1865dfd233edSAttilio Rao 18669ec7b004SRick Macklem if (mntflags & MNT_FORCE) 18679ec7b004SRick Macklem flags |= FORCECLOSE; 18689ec7b004SRick Macklem nmp = VFSTONFS(mp); 186990d2dfabSRick Macklem error = 0; 18709ec7b004SRick Macklem /* 18719ec7b004SRick Macklem * Goes something like this.. 18729ec7b004SRick Macklem * - Call vflush() to clear out vnodes for this filesystem 18739ec7b004SRick Macklem * - Close the socket 18749ec7b004SRick Macklem * - Free up the data structures 18759ec7b004SRick Macklem */ 18769ec7b004SRick Macklem /* In the forced case, cancel any outstanding requests. */ 18779ec7b004SRick Macklem if (mntflags & MNT_FORCE) { 187890d2dfabSRick Macklem NFSDDSLOCK(); 187990d2dfabSRick Macklem if (nfsv4_findmirror(nmp) != NULL) 188090d2dfabSRick Macklem error = ENXIO; 188190d2dfabSRick Macklem NFSDDSUNLOCK(); 188290d2dfabSRick Macklem if (error) 188390d2dfabSRick Macklem goto out; 18849ec7b004SRick Macklem error = newnfs_nmcancelreqs(nmp); 18859ec7b004SRick Macklem if (error) 18869ec7b004SRick Macklem goto out; 18879ec7b004SRick Macklem /* For a forced close, get rid of the renew thread now */ 188844122258SRick Macklem nfscl_umount(nmp, td, &dh); 18899ec7b004SRick Macklem } 18909ec7b004SRick Macklem /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */ 18919ec7b004SRick Macklem do { 18929ec7b004SRick Macklem error = vflush(mp, 1, flags, td); 18939ec7b004SRick Macklem if ((mntflags & MNT_FORCE) && error != 0 && ++trycnt < 30) 189423f929dfSRick Macklem (void) nfs_catnap(PSOCK, error, "newndm"); 18959ec7b004SRick Macklem } while ((mntflags & MNT_FORCE) && error != 0 && trycnt < 30); 18969ec7b004SRick Macklem if (error) 18979ec7b004SRick Macklem goto out; 18989ec7b004SRick Macklem 18999ec7b004SRick Macklem /* 19009ec7b004SRick Macklem * We are now committed to the unmount. 19019ec7b004SRick Macklem */ 19029ec7b004SRick Macklem if ((mntflags & MNT_FORCE) == 0) 190344122258SRick Macklem nfscl_umount(nmp, td, NULL); 190447cbff34SRick Macklem else { 190547cbff34SRick Macklem mtx_lock(&nmp->nm_mtx); 190647cbff34SRick Macklem nmp->nm_privflag |= NFSMNTP_FORCEDISM; 190747cbff34SRick Macklem mtx_unlock(&nmp->nm_mtx); 190847cbff34SRick Macklem } 190964a0e848SRick Macklem /* Make sure no nfsiods are assigned to this mount. */ 1910b662b41eSRick Macklem NFSLOCKIOD(); 191164a0e848SRick Macklem for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 191264a0e848SRick Macklem if (ncl_iodmount[i] == nmp) { 191364a0e848SRick Macklem ncl_iodwant[i] = NFSIOD_AVAILABLE; 191464a0e848SRick Macklem ncl_iodmount[i] = NULL; 191564a0e848SRick Macklem } 1916b662b41eSRick Macklem NFSUNLOCKIOD(); 191747cbff34SRick Macklem 191847cbff34SRick Macklem /* 191947cbff34SRick Macklem * We can now set mnt_data to NULL and wait for 192047cbff34SRick Macklem * nfssvc(NFSSVC_FORCEDISM) to complete. 192147cbff34SRick Macklem */ 192247cbff34SRick Macklem mtx_lock(&mountlist_mtx); 192347cbff34SRick Macklem mtx_lock(&nmp->nm_mtx); 192447cbff34SRick Macklem mp->mnt_data = NULL; 192547cbff34SRick Macklem mtx_unlock(&mountlist_mtx); 192647cbff34SRick Macklem while ((nmp->nm_privflag & NFSMNTP_CANCELRPCS) != 0) 192747cbff34SRick Macklem msleep(nmp, &nmp->nm_mtx, PVFS, "nfsfdism", 0); 192847cbff34SRick Macklem mtx_unlock(&nmp->nm_mtx); 192947cbff34SRick Macklem 19301e0a518dSRick Macklem newnfs_disconnect(nmp, &nmp->nm_sockreq); 19319ec7b004SRick Macklem crfree(nmp->nm_sockreq.nr_cred); 1932222daa42SConrad Meyer free(nmp->nm_nam, M_SONAME); 193388a2437aSRick Macklem if (nmp->nm_sockreq.nr_auth != NULL) 193488a2437aSRick Macklem AUTH_DESTROY(nmp->nm_sockreq.nr_auth); 19359ec7b004SRick Macklem mtx_destroy(&nmp->nm_sockreq.nr_mtx); 19369ec7b004SRick Macklem mtx_destroy(&nmp->nm_mtx); 1937c20a7210SRick Macklem TAILQ_FOREACH_SAFE(dsp, &nmp->nm_sess, nfsclds_list, tdsp) { 1938c20a7210SRick Macklem if (dsp != TAILQ_FIRST(&nmp->nm_sess) && 1939c20a7210SRick Macklem dsp->nfsclds_sockp != NULL) 19401e0a518dSRick Macklem newnfs_disconnect(NULL, dsp->nfsclds_sockp); 19411f60bfd8SRick Macklem nfscl_freenfsclds(dsp); 1942c20a7210SRick Macklem } 1943665b1365SRick Macklem free(nmp->nm_tlscertname, M_NEWNFSMNT); 1944222daa42SConrad Meyer free(nmp, M_NEWNFSMNT); 194544122258SRick Macklem 194644122258SRick Macklem /* Free up the delegation structures for forced dismounts. */ 194744122258SRick Macklem TAILQ_FOREACH_SAFE(dp, &dh, nfsdl_list, ndp) { 194844122258SRick Macklem TAILQ_REMOVE(&dh, dp, nfsdl_list); 194944122258SRick Macklem free(dp, M_NFSCLDELEG); 195044122258SRick Macklem } 19519ec7b004SRick Macklem out: 19529ec7b004SRick Macklem return (error); 19539ec7b004SRick Macklem } 19549ec7b004SRick Macklem 19559ec7b004SRick Macklem /* 19569ec7b004SRick Macklem * Return root of a filesystem 19579ec7b004SRick Macklem */ 19589ec7b004SRick Macklem static int 1959dfd233edSAttilio Rao nfs_root(struct mount *mp, int flags, struct vnode **vpp) 19609ec7b004SRick Macklem { 19619ec7b004SRick Macklem struct vnode *vp; 19629ec7b004SRick Macklem struct nfsmount *nmp; 19639ec7b004SRick Macklem struct nfsnode *np; 19649ec7b004SRick Macklem int error; 1965896516e5SRick Macklem char *fakefh; 19669ec7b004SRick Macklem 19679ec7b004SRick Macklem nmp = VFSTONFS(mp); 1968896516e5SRick Macklem if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0) { 1969896516e5SRick Macklem /* Attempt to get the actual root file handle. */ 1970896516e5SRick Macklem if (nmp->nm_fhsize == 0) 1971896516e5SRick Macklem error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), 1972896516e5SRick Macklem curthread->td_ucred, curthread); 1973896516e5SRick Macklem fakefh = malloc(NFSX_FHMAX + 1, M_TEMP, M_WAITOK | M_ZERO); 1974896516e5SRick Macklem error = ncl_nget(mp, fakefh, NFSX_FHMAX + 1, &np, flags); 1975896516e5SRick Macklem free(fakefh, M_TEMP); 1976896516e5SRick Macklem } else { 19774b3a38ecSRick Macklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, flags); 1978896516e5SRick Macklem } 19799ec7b004SRick Macklem if (error) 19809ec7b004SRick Macklem return error; 19819ec7b004SRick Macklem vp = NFSTOV(np); 19829ec7b004SRick Macklem /* 19839ec7b004SRick Macklem * Get transfer parameters and attributes for root vnode once. 19849ec7b004SRick Macklem */ 19859ec7b004SRick Macklem mtx_lock(&nmp->nm_mtx); 19869ec7b004SRick Macklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 19879ec7b004SRick Macklem mtx_unlock(&nmp->nm_mtx); 19889ec7b004SRick Macklem ncl_fsinfo(nmp, vp, curthread->td_ucred, curthread); 19899ec7b004SRick Macklem } else 19909ec7b004SRick Macklem mtx_unlock(&nmp->nm_mtx); 19919ec7b004SRick Macklem if (vp->v_type == VNON) 19929ec7b004SRick Macklem vp->v_type = VDIR; 19939ec7b004SRick Macklem vp->v_vflag |= VV_ROOT; 19949ec7b004SRick Macklem *vpp = vp; 19959ec7b004SRick Macklem return (0); 19969ec7b004SRick Macklem } 19979ec7b004SRick Macklem 19989ec7b004SRick Macklem /* 19999ec7b004SRick Macklem * Flush out the buffer cache 20009ec7b004SRick Macklem */ 20019ec7b004SRick Macklem /* ARGSUSED */ 20029ec7b004SRick Macklem static int 2003dfd233edSAttilio Rao nfs_sync(struct mount *mp, int waitfor) 20049ec7b004SRick Macklem { 20059ec7b004SRick Macklem struct vnode *vp, *mvp; 2006dfd233edSAttilio Rao struct thread *td; 20079ec7b004SRick Macklem int error, allerror = 0; 20089ec7b004SRick Macklem 2009dfd233edSAttilio Rao td = curthread; 2010dfd233edSAttilio Rao 20118b5e8315SRick Macklem MNT_ILOCK(mp); 20128b5e8315SRick Macklem /* 20138b5e8315SRick Macklem * If a forced dismount is in progress, return from here so that 20148b5e8315SRick Macklem * the umount(2) syscall doesn't get stuck in VFS_SYNC() before 20158b5e8315SRick Macklem * calling VFS_UNMOUNT(). 20168b5e8315SRick Macklem */ 201716f300faSRick Macklem if (NFSCL_FORCEDISM(mp)) { 20188b5e8315SRick Macklem MNT_IUNLOCK(mp); 20198b5e8315SRick Macklem return (EBADF); 20208b5e8315SRick Macklem } 202171469bb3SKirk McKusick MNT_IUNLOCK(mp); 20228b5e8315SRick Macklem 20235ff7fb76SMateusz Guzik if (waitfor == MNT_LAZY) 20245ff7fb76SMateusz Guzik return (0); 20255ff7fb76SMateusz Guzik 20269ec7b004SRick Macklem /* 20279ec7b004SRick Macklem * Force stale buffer cache information to be flushed. 20289ec7b004SRick Macklem */ 20299ec7b004SRick Macklem loop: 203071469bb3SKirk McKusick MNT_VNODE_FOREACH_ALL(vp, mp, mvp) { 20319ec7b004SRick Macklem /* XXX Racy bv_cnt check. */ 20325ff7fb76SMateusz Guzik if (NFSVOPISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0) { 20339ec7b004SRick Macklem VI_UNLOCK(vp); 20349ec7b004SRick Macklem continue; 20359ec7b004SRick Macklem } 2036a92a971bSMateusz Guzik if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK)) { 203771469bb3SKirk McKusick MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); 20389ec7b004SRick Macklem goto loop; 20399ec7b004SRick Macklem } 20409ec7b004SRick Macklem error = VOP_FSYNC(vp, waitfor, td); 20419ec7b004SRick Macklem if (error) 20429ec7b004SRick Macklem allerror = error; 2043b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 20449ec7b004SRick Macklem vrele(vp); 20459ec7b004SRick Macklem } 20469ec7b004SRick Macklem return (allerror); 20479ec7b004SRick Macklem } 20489ec7b004SRick Macklem 20499ec7b004SRick Macklem static int 20509ec7b004SRick Macklem nfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req) 20519ec7b004SRick Macklem { 20529ec7b004SRick Macklem struct nfsmount *nmp = VFSTONFS(mp); 20539ec7b004SRick Macklem struct vfsquery vq; 20549ec7b004SRick Macklem int error; 20559ec7b004SRick Macklem 20569ec7b004SRick Macklem bzero(&vq, sizeof(vq)); 20579ec7b004SRick Macklem switch (op) { 20589ec7b004SRick Macklem #if 0 20599ec7b004SRick Macklem case VFS_CTL_NOLOCKS: 20609ec7b004SRick Macklem val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0; 20619ec7b004SRick Macklem if (req->oldptr != NULL) { 20629ec7b004SRick Macklem error = SYSCTL_OUT(req, &val, sizeof(val)); 20639ec7b004SRick Macklem if (error) 20649ec7b004SRick Macklem return (error); 20659ec7b004SRick Macklem } 20669ec7b004SRick Macklem if (req->newptr != NULL) { 20679ec7b004SRick Macklem error = SYSCTL_IN(req, &val, sizeof(val)); 20689ec7b004SRick Macklem if (error) 20699ec7b004SRick Macklem return (error); 20709ec7b004SRick Macklem if (val) 20719ec7b004SRick Macklem nmp->nm_flag |= NFSMNT_NOLOCKS; 20729ec7b004SRick Macklem else 20739ec7b004SRick Macklem nmp->nm_flag &= ~NFSMNT_NOLOCKS; 20749ec7b004SRick Macklem } 20759ec7b004SRick Macklem break; 20769ec7b004SRick Macklem #endif 20779ec7b004SRick Macklem case VFS_CTL_QUERY: 20789ec7b004SRick Macklem mtx_lock(&nmp->nm_mtx); 20799ec7b004SRick Macklem if (nmp->nm_state & NFSSTA_TIMEO) 20809ec7b004SRick Macklem vq.vq_flags |= VQ_NOTRESP; 20819ec7b004SRick Macklem mtx_unlock(&nmp->nm_mtx); 20829ec7b004SRick Macklem #if 0 20839ec7b004SRick Macklem if (!(nmp->nm_flag & NFSMNT_NOLOCKS) && 20849ec7b004SRick Macklem (nmp->nm_state & NFSSTA_LOCKTIMEO)) 20859ec7b004SRick Macklem vq.vq_flags |= VQ_NOTRESPLOCK; 20869ec7b004SRick Macklem #endif 20879ec7b004SRick Macklem error = SYSCTL_OUT(req, &vq, sizeof(vq)); 20889ec7b004SRick Macklem break; 20899ec7b004SRick Macklem case VFS_CTL_TIMEO: 20909ec7b004SRick Macklem if (req->oldptr != NULL) { 20919ec7b004SRick Macklem error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay, 20929ec7b004SRick Macklem sizeof(nmp->nm_tprintf_initial_delay)); 20939ec7b004SRick Macklem if (error) 20949ec7b004SRick Macklem return (error); 20959ec7b004SRick Macklem } 20969ec7b004SRick Macklem if (req->newptr != NULL) { 20979ec7b004SRick Macklem error = vfs_suser(mp, req->td); 20989ec7b004SRick Macklem if (error) 20999ec7b004SRick Macklem return (error); 21009ec7b004SRick Macklem error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay, 21019ec7b004SRick Macklem sizeof(nmp->nm_tprintf_initial_delay)); 21029ec7b004SRick Macklem if (error) 21039ec7b004SRick Macklem return (error); 21049ec7b004SRick Macklem if (nmp->nm_tprintf_initial_delay < 0) 21059ec7b004SRick Macklem nmp->nm_tprintf_initial_delay = 0; 21069ec7b004SRick Macklem } 21079ec7b004SRick Macklem break; 21089ec7b004SRick Macklem default: 21099ec7b004SRick Macklem return (ENOTSUP); 21109ec7b004SRick Macklem } 21119ec7b004SRick Macklem return (0); 21129ec7b004SRick Macklem } 21139ec7b004SRick Macklem 2114ca27c028SRick Macklem /* 21158fe6bddfSRick Macklem * Purge any RPCs in progress, so that they will all return errors. 21168fe6bddfSRick Macklem * This allows dounmount() to continue as far as VFS_UNMOUNT() for a 21178fe6bddfSRick Macklem * forced dismount. 21188fe6bddfSRick Macklem */ 21198fe6bddfSRick Macklem static void 21208fe6bddfSRick Macklem nfs_purge(struct mount *mp) 21218fe6bddfSRick Macklem { 21228fe6bddfSRick Macklem struct nfsmount *nmp = VFSTONFS(mp); 21238fe6bddfSRick Macklem 21248fe6bddfSRick Macklem newnfs_nmcancelreqs(nmp); 21258fe6bddfSRick Macklem } 21268fe6bddfSRick Macklem 21278fe6bddfSRick Macklem /* 2128ca27c028SRick Macklem * Extract the information needed by the nlm from the nfs vnode. 2129ca27c028SRick Macklem */ 2130ca27c028SRick Macklem static void 21314d4f9a37SRick Macklem nfs_getnlminfo(struct vnode *vp, uint8_t *fhp, size_t *fhlenp, 213290305aa3SRick Macklem struct sockaddr_storage *sp, int *is_v3p, off_t *sizep, 213390305aa3SRick Macklem struct timeval *timeop) 2134ca27c028SRick Macklem { 2135ca27c028SRick Macklem struct nfsmount *nmp; 2136ca27c028SRick Macklem struct nfsnode *np = VTONFS(vp); 2137ca27c028SRick Macklem 2138ca27c028SRick Macklem nmp = VFSTONFS(vp->v_mount); 2139ca27c028SRick Macklem if (fhlenp != NULL) 21404d4f9a37SRick Macklem *fhlenp = (size_t)np->n_fhp->nfh_len; 2141ca27c028SRick Macklem if (fhp != NULL) 2142ca27c028SRick Macklem bcopy(np->n_fhp->nfh_fh, fhp, np->n_fhp->nfh_len); 2143ca27c028SRick Macklem if (sp != NULL) 2144ca27c028SRick Macklem bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp))); 2145ca27c028SRick Macklem if (is_v3p != NULL) 2146ca27c028SRick Macklem *is_v3p = NFS_ISV3(vp); 2147ca27c028SRick Macklem if (sizep != NULL) 2148ca27c028SRick Macklem *sizep = np->n_size; 214990305aa3SRick Macklem if (timeop != NULL) { 215090305aa3SRick Macklem timeop->tv_sec = nmp->nm_timeo / NFS_HZ; 215190305aa3SRick Macklem timeop->tv_usec = (nmp->nm_timeo % NFS_HZ) * (1000000 / NFS_HZ); 215290305aa3SRick Macklem } 2153ca27c028SRick Macklem } 2154ca27c028SRick Macklem 215599d2727dSRick Macklem /* 215699d2727dSRick Macklem * This function prints out an option name, based on the conditional 215799d2727dSRick Macklem * argument. 215899d2727dSRick Macklem */ 215999d2727dSRick Macklem static __inline void nfscl_printopt(struct nfsmount *nmp, int testval, 216099d2727dSRick Macklem char *opt, char **buf, size_t *blen) 216199d2727dSRick Macklem { 216299d2727dSRick Macklem int len; 216399d2727dSRick Macklem 216499d2727dSRick Macklem if (testval != 0 && *blen > strlen(opt)) { 216599d2727dSRick Macklem len = snprintf(*buf, *blen, "%s", opt); 216699d2727dSRick Macklem if (len != strlen(opt)) 216799d2727dSRick Macklem printf("EEK!!\n"); 216899d2727dSRick Macklem *buf += len; 216999d2727dSRick Macklem *blen -= len; 217099d2727dSRick Macklem } 217199d2727dSRick Macklem } 217299d2727dSRick Macklem 217399d2727dSRick Macklem /* 217499d2727dSRick Macklem * This function printf out an options integer value. 217599d2727dSRick Macklem */ 217699d2727dSRick Macklem static __inline void nfscl_printoptval(struct nfsmount *nmp, int optval, 217799d2727dSRick Macklem char *opt, char **buf, size_t *blen) 217899d2727dSRick Macklem { 217999d2727dSRick Macklem int len; 218099d2727dSRick Macklem 218199d2727dSRick Macklem if (*blen > strlen(opt) + 1) { 218299d2727dSRick Macklem /* Could result in truncated output string. */ 218399d2727dSRick Macklem len = snprintf(*buf, *blen, "%s=%d", opt, optval); 218499d2727dSRick Macklem if (len < *blen) { 218599d2727dSRick Macklem *buf += len; 218699d2727dSRick Macklem *blen -= len; 218799d2727dSRick Macklem } 218899d2727dSRick Macklem } 218999d2727dSRick Macklem } 219099d2727dSRick Macklem 219199d2727dSRick Macklem /* 219299d2727dSRick Macklem * Load the option flags and values into the buffer. 219399d2727dSRick Macklem */ 219499d2727dSRick Macklem void nfscl_retopts(struct nfsmount *nmp, char *buffer, size_t buflen) 219599d2727dSRick Macklem { 219699d2727dSRick Macklem char *buf; 219799d2727dSRick Macklem size_t blen; 219899d2727dSRick Macklem 219999d2727dSRick Macklem buf = buffer; 220099d2727dSRick Macklem blen = buflen; 220199d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV4) != 0, "nfsv4", &buf, 220299d2727dSRick Macklem &blen); 2203ef8f1261SRick Macklem if ((nmp->nm_flag & NFSMNT_NFSV4) != 0) { 2204ef8f1261SRick Macklem nfscl_printoptval(nmp, nmp->nm_minorvers, ",minorversion", &buf, 2205ef8f1261SRick Macklem &blen); 2206ef8f1261SRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_PNFS) != 0, ",pnfs", 2207ef8f1261SRick Macklem &buf, &blen); 2208037a2012SRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_ONEOPENOWN) != 0 && 2209037a2012SRick Macklem nmp->nm_minorvers > 0, ",oneopenown", &buf, &blen); 2210ef8f1261SRick Macklem } 221199d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV3) != 0, "nfsv3", &buf, 221299d2727dSRick Macklem &blen); 221399d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0, 221499d2727dSRick Macklem "nfsv2", &buf, &blen); 221599d2727dSRick Macklem nfscl_printopt(nmp, nmp->nm_sotype == SOCK_STREAM, ",tcp", &buf, &blen); 221699d2727dSRick Macklem nfscl_printopt(nmp, nmp->nm_sotype != SOCK_STREAM, ",udp", &buf, &blen); 221799d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RESVPORT) != 0, ",resvport", 221899d2727dSRick Macklem &buf, &blen); 22196e4b6ff8SRick Macklem nfscl_printopt(nmp, (nmp->nm_newflag & NFSMNT_TLS) != 0, ",tls", &buf, 22206e4b6ff8SRick Macklem &blen); 2221896516e5SRick Macklem nfscl_printopt(nmp, (nmp->nm_newflag & NFSMNT_SYSKRB5) != 0, 2222896516e5SRick Macklem ",syskrb5", &buf, &blen); 222399d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCONN) != 0, ",noconn", 222499d2727dSRick Macklem &buf, &blen); 22251e0a518dSRick Macklem nfscl_printoptval(nmp, nmp->nm_aconnect + 1, ",nconnect", &buf, &blen); 222699d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) == 0, ",hard", &buf, 222799d2727dSRick Macklem &blen); 222899d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) != 0, ",soft", &buf, 222999d2727dSRick Macklem &blen); 223099d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_INT) != 0, ",intr", &buf, 223199d2727dSRick Macklem &blen); 223299d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) == 0, ",cto", &buf, 223399d2727dSRick Macklem &blen); 223499d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) != 0, ",nocto", &buf, 223599d2727dSRick Macklem &blen); 2236cf766161SRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NONCONTIGWR) != 0, 2237cf766161SRick Macklem ",noncontigwr", &buf, &blen); 223899d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NOLOCKD | NFSMNT_NFSV4)) == 223999d2727dSRick Macklem 0, ",lockd", &buf, &blen); 224033721eb9SRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOLOCKD) != 0, ",nolockd", 224133721eb9SRick Macklem &buf, &blen); 224299d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RDIRPLUS) != 0, ",rdirplus", 224399d2727dSRick Macklem &buf, &blen); 224499d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_KERB) == 0, ",sec=sys", 224599d2727dSRick Macklem &buf, &blen); 224699d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY | 224799d2727dSRick Macklem NFSMNT_PRIVACY)) == NFSMNT_KERB, ",sec=krb5", &buf, &blen); 224899d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY | 224999d2727dSRick Macklem NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_INTEGRITY), ",sec=krb5i", 225099d2727dSRick Macklem &buf, &blen); 225199d2727dSRick Macklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY | 225299d2727dSRick Macklem NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_PRIVACY), ",sec=krb5p", 225399d2727dSRick Macklem &buf, &blen); 225499d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_acdirmin, ",acdirmin", &buf, &blen); 225599d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_acdirmax, ",acdirmax", &buf, &blen); 225699d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_acregmin, ",acregmin", &buf, &blen); 225799d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_acregmax, ",acregmax", &buf, &blen); 225899d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_nametimeo, ",nametimeo", &buf, &blen); 225999d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_negnametimeo, ",negnametimeo", &buf, 226099d2727dSRick Macklem &blen); 226199d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_rsize, ",rsize", &buf, &blen); 226299d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_wsize, ",wsize", &buf, &blen); 226399d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_readdirsize, ",readdirsize", &buf, 226499d2727dSRick Macklem &blen); 226599d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_readahead, ",readahead", &buf, &blen); 226699d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_wcommitsize, ",wcommitsize", &buf, 226799d2727dSRick Macklem &blen); 226899d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_timeo, ",timeout", &buf, &blen); 226999d2727dSRick Macklem nfscl_printoptval(nmp, nmp->nm_retry, ",retrans", &buf, &blen); 227099d2727dSRick Macklem } 2271