1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate * 26*7c478bd9Sstevel@tonic-gate * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T. 27*7c478bd9Sstevel@tonic-gate * All rights reserved. 28*7c478bd9Sstevel@tonic-gate */ 29*7c478bd9Sstevel@tonic-gate 30*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/cred.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/pathname.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/mount.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/mntent.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/statvfs.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/utsname.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/acl.h> 52*7c478bd9Sstevel@tonic-gate #include <sys/flock.h> 53*7c478bd9Sstevel@tonic-gate #include <sys/policy.h> 54*7c478bd9Sstevel@tonic-gate #include <sys/zone.h> 55*7c478bd9Sstevel@tonic-gate #include <sys/class.h> 56*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 57*7c478bd9Sstevel@tonic-gate #include <sys/netconfig.h> 58*7c478bd9Sstevel@tonic-gate 59*7c478bd9Sstevel@tonic-gate #include <rpc/types.h> 60*7c478bd9Sstevel@tonic-gate #include <rpc/auth.h> 61*7c478bd9Sstevel@tonic-gate #include <rpc/clnt.h> 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate #include <nfs/nfs.h> 64*7c478bd9Sstevel@tonic-gate #include <nfs/nfs_clnt.h> 65*7c478bd9Sstevel@tonic-gate #include <nfs/rnode.h> 66*7c478bd9Sstevel@tonic-gate #include <nfs/mount.h> 67*7c478bd9Sstevel@tonic-gate #include <nfs/nfs_acl.h> 68*7c478bd9Sstevel@tonic-gate 69*7c478bd9Sstevel@tonic-gate #include <fs/fs_subr.h> 70*7c478bd9Sstevel@tonic-gate 71*7c478bd9Sstevel@tonic-gate /* 72*7c478bd9Sstevel@tonic-gate * From rpcsec module (common/rpcsec). 73*7c478bd9Sstevel@tonic-gate */ 74*7c478bd9Sstevel@tonic-gate extern int sec_clnt_loadinfo(struct sec_data *, struct sec_data **, model_t); 75*7c478bd9Sstevel@tonic-gate extern void sec_clnt_freeinfo(struct sec_data *); 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate static int pathconf_get(struct mntinfo *, model_t, struct nfs_args *); 78*7c478bd9Sstevel@tonic-gate static void pathconf_rele(struct mntinfo *); 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate /* 81*7c478bd9Sstevel@tonic-gate * The order and contents of this structure must be kept in sync with that of 82*7c478bd9Sstevel@tonic-gate * rfsreqcnt_v2_tmpl in nfs_stats.c 83*7c478bd9Sstevel@tonic-gate */ 84*7c478bd9Sstevel@tonic-gate static char *rfsnames_v2[] = { 85*7c478bd9Sstevel@tonic-gate "null", "getattr", "setattr", "unused", "lookup", "readlink", "read", 86*7c478bd9Sstevel@tonic-gate "unused", "write", "create", "remove", "rename", "link", "symlink", 87*7c478bd9Sstevel@tonic-gate "mkdir", "rmdir", "readdir", "fsstat" 88*7c478bd9Sstevel@tonic-gate }; 89*7c478bd9Sstevel@tonic-gate 90*7c478bd9Sstevel@tonic-gate /* 91*7c478bd9Sstevel@tonic-gate * This table maps from NFS protocol number into call type. 92*7c478bd9Sstevel@tonic-gate * Zero means a "Lookup" type call 93*7c478bd9Sstevel@tonic-gate * One means a "Read" type call 94*7c478bd9Sstevel@tonic-gate * Two means a "Write" type call 95*7c478bd9Sstevel@tonic-gate * This is used to select a default time-out. 96*7c478bd9Sstevel@tonic-gate */ 97*7c478bd9Sstevel@tonic-gate static uchar_t call_type_v2[] = { 98*7c478bd9Sstevel@tonic-gate 0, 0, 1, 0, 0, 0, 1, 99*7c478bd9Sstevel@tonic-gate 0, 2, 2, 2, 2, 2, 2, 100*7c478bd9Sstevel@tonic-gate 2, 2, 1, 0 101*7c478bd9Sstevel@tonic-gate }; 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate /* 104*7c478bd9Sstevel@tonic-gate * Similar table, but to determine which timer to use 105*7c478bd9Sstevel@tonic-gate * (only real reads and writes!) 106*7c478bd9Sstevel@tonic-gate */ 107*7c478bd9Sstevel@tonic-gate static uchar_t timer_type_v2[] = { 108*7c478bd9Sstevel@tonic-gate 0, 0, 0, 0, 0, 0, 1, 109*7c478bd9Sstevel@tonic-gate 0, 2, 0, 0, 0, 0, 0, 110*7c478bd9Sstevel@tonic-gate 0, 0, 1, 0 111*7c478bd9Sstevel@tonic-gate }; 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate /* 114*7c478bd9Sstevel@tonic-gate * This table maps from NFS protocol number into a call type 115*7c478bd9Sstevel@tonic-gate * for the semisoft mount option. 116*7c478bd9Sstevel@tonic-gate * Zero means do not repeat operation. 117*7c478bd9Sstevel@tonic-gate * One means repeat. 118*7c478bd9Sstevel@tonic-gate */ 119*7c478bd9Sstevel@tonic-gate static uchar_t ss_call_type_v2[] = { 120*7c478bd9Sstevel@tonic-gate 0, 0, 1, 0, 0, 0, 0, 121*7c478bd9Sstevel@tonic-gate 0, 1, 1, 1, 1, 1, 1, 122*7c478bd9Sstevel@tonic-gate 1, 1, 0, 0 123*7c478bd9Sstevel@tonic-gate }; 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate /* 126*7c478bd9Sstevel@tonic-gate * nfs vfs operations. 127*7c478bd9Sstevel@tonic-gate */ 128*7c478bd9Sstevel@tonic-gate static int nfs_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *); 129*7c478bd9Sstevel@tonic-gate static int nfs_unmount(vfs_t *, int, cred_t *); 130*7c478bd9Sstevel@tonic-gate static int nfs_root(vfs_t *, vnode_t **); 131*7c478bd9Sstevel@tonic-gate static int nfs_statvfs(vfs_t *, struct statvfs64 *); 132*7c478bd9Sstevel@tonic-gate static int nfs_sync(vfs_t *, short, cred_t *); 133*7c478bd9Sstevel@tonic-gate static int nfs_vget(vfs_t *, vnode_t **, fid_t *); 134*7c478bd9Sstevel@tonic-gate static int nfs_mountroot(vfs_t *, whymountroot_t); 135*7c478bd9Sstevel@tonic-gate static void nfs_freevfs(vfs_t *); 136*7c478bd9Sstevel@tonic-gate 137*7c478bd9Sstevel@tonic-gate static int nfsrootvp(vnode_t **, vfs_t *, struct servinfo *, 138*7c478bd9Sstevel@tonic-gate int, cred_t *, zone_t *); 139*7c478bd9Sstevel@tonic-gate 140*7c478bd9Sstevel@tonic-gate /* 141*7c478bd9Sstevel@tonic-gate * Initialize the vfs structure 142*7c478bd9Sstevel@tonic-gate */ 143*7c478bd9Sstevel@tonic-gate 144*7c478bd9Sstevel@tonic-gate int nfsfstyp; 145*7c478bd9Sstevel@tonic-gate vfsops_t *nfs_vfsops; 146*7c478bd9Sstevel@tonic-gate 147*7c478bd9Sstevel@tonic-gate /* 148*7c478bd9Sstevel@tonic-gate * Debug variable to check for rdma based 149*7c478bd9Sstevel@tonic-gate * transport startup and cleanup. Controlled 150*7c478bd9Sstevel@tonic-gate * through /etc/system. Off by default. 151*7c478bd9Sstevel@tonic-gate */ 152*7c478bd9Sstevel@tonic-gate int rdma_debug = 0; 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate int 155*7c478bd9Sstevel@tonic-gate nfsinit(int fstyp, char *name) 156*7c478bd9Sstevel@tonic-gate { 157*7c478bd9Sstevel@tonic-gate static const fs_operation_def_t nfs_vfsops_template[] = { 158*7c478bd9Sstevel@tonic-gate VFSNAME_MOUNT, nfs_mount, 159*7c478bd9Sstevel@tonic-gate VFSNAME_UNMOUNT, nfs_unmount, 160*7c478bd9Sstevel@tonic-gate VFSNAME_ROOT, nfs_root, 161*7c478bd9Sstevel@tonic-gate VFSNAME_STATVFS, nfs_statvfs, 162*7c478bd9Sstevel@tonic-gate VFSNAME_SYNC, (fs_generic_func_p) nfs_sync, 163*7c478bd9Sstevel@tonic-gate VFSNAME_VGET, nfs_vget, 164*7c478bd9Sstevel@tonic-gate VFSNAME_MOUNTROOT, nfs_mountroot, 165*7c478bd9Sstevel@tonic-gate VFSNAME_FREEVFS, (fs_generic_func_p)nfs_freevfs, 166*7c478bd9Sstevel@tonic-gate NULL, NULL 167*7c478bd9Sstevel@tonic-gate }; 168*7c478bd9Sstevel@tonic-gate int error; 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate error = vfs_setfsops(fstyp, nfs_vfsops_template, &nfs_vfsops); 171*7c478bd9Sstevel@tonic-gate if (error != 0) { 172*7c478bd9Sstevel@tonic-gate zcmn_err(GLOBAL_ZONEID, CE_WARN, 173*7c478bd9Sstevel@tonic-gate "nfsinit: bad vfs ops template"); 174*7c478bd9Sstevel@tonic-gate return (error); 175*7c478bd9Sstevel@tonic-gate } 176*7c478bd9Sstevel@tonic-gate 177*7c478bd9Sstevel@tonic-gate error = vn_make_ops(name, nfs_vnodeops_template, &nfs_vnodeops); 178*7c478bd9Sstevel@tonic-gate if (error != 0) { 179*7c478bd9Sstevel@tonic-gate (void) vfs_freevfsops_by_type(fstyp); 180*7c478bd9Sstevel@tonic-gate zcmn_err(GLOBAL_ZONEID, CE_WARN, 181*7c478bd9Sstevel@tonic-gate "nfsinit: bad vnode ops template"); 182*7c478bd9Sstevel@tonic-gate return (error); 183*7c478bd9Sstevel@tonic-gate } 184*7c478bd9Sstevel@tonic-gate 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate nfsfstyp = fstyp; 187*7c478bd9Sstevel@tonic-gate 188*7c478bd9Sstevel@tonic-gate return (0); 189*7c478bd9Sstevel@tonic-gate } 190*7c478bd9Sstevel@tonic-gate 191*7c478bd9Sstevel@tonic-gate void 192*7c478bd9Sstevel@tonic-gate nfsfini(void) 193*7c478bd9Sstevel@tonic-gate { 194*7c478bd9Sstevel@tonic-gate } 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate /* 197*7c478bd9Sstevel@tonic-gate * nfs mount vfsop 198*7c478bd9Sstevel@tonic-gate * Set up mount info record and attach it to vfs struct. 199*7c478bd9Sstevel@tonic-gate */ 200*7c478bd9Sstevel@tonic-gate static int 201*7c478bd9Sstevel@tonic-gate nfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) 202*7c478bd9Sstevel@tonic-gate { 203*7c478bd9Sstevel@tonic-gate char *data = uap->dataptr; 204*7c478bd9Sstevel@tonic-gate int error; 205*7c478bd9Sstevel@tonic-gate vnode_t *rtvp; /* the server's root */ 206*7c478bd9Sstevel@tonic-gate mntinfo_t *mi; /* mount info, pointed at by vfs */ 207*7c478bd9Sstevel@tonic-gate size_t hlen; /* length of hostname */ 208*7c478bd9Sstevel@tonic-gate size_t nlen; /* length of netname */ 209*7c478bd9Sstevel@tonic-gate char netname[SYS_NMLN]; /* server's netname */ 210*7c478bd9Sstevel@tonic-gate struct netbuf addr; /* server's address */ 211*7c478bd9Sstevel@tonic-gate struct netbuf syncaddr; /* AUTH_DES time sync addr */ 212*7c478bd9Sstevel@tonic-gate struct knetconfig *knconf; /* transport knetconfig structure */ 213*7c478bd9Sstevel@tonic-gate struct knetconfig *rdma_knconf; /* rdma transport structure */ 214*7c478bd9Sstevel@tonic-gate rnode_t *rp; 215*7c478bd9Sstevel@tonic-gate struct servinfo *svp; /* nfs server info */ 216*7c478bd9Sstevel@tonic-gate struct servinfo *svp_tail = NULL; /* previous nfs server info */ 217*7c478bd9Sstevel@tonic-gate struct servinfo *svp_head; /* first nfs server info */ 218*7c478bd9Sstevel@tonic-gate struct servinfo *svp_2ndlast; /* 2nd last in the server info list */ 219*7c478bd9Sstevel@tonic-gate struct sec_data *secdata; /* security data */ 220*7c478bd9Sstevel@tonic-gate STRUCT_DECL(nfs_args, args); /* nfs mount arguments */ 221*7c478bd9Sstevel@tonic-gate STRUCT_DECL(knetconfig, knconf_tmp); 222*7c478bd9Sstevel@tonic-gate STRUCT_DECL(netbuf, addr_tmp); 223*7c478bd9Sstevel@tonic-gate int flags, addr_type; 224*7c478bd9Sstevel@tonic-gate char *p, *pf; 225*7c478bd9Sstevel@tonic-gate zone_t *zone = curproc->p_zone; 226*7c478bd9Sstevel@tonic-gate 227*7c478bd9Sstevel@tonic-gate if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0) 228*7c478bd9Sstevel@tonic-gate return (error); 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate if (mvp->v_type != VDIR) 231*7c478bd9Sstevel@tonic-gate return (ENOTDIR); 232*7c478bd9Sstevel@tonic-gate 233*7c478bd9Sstevel@tonic-gate /* 234*7c478bd9Sstevel@tonic-gate * get arguments 235*7c478bd9Sstevel@tonic-gate * 236*7c478bd9Sstevel@tonic-gate * nfs_args is now versioned and is extensible, so 237*7c478bd9Sstevel@tonic-gate * uap->datalen might be different from sizeof (args) 238*7c478bd9Sstevel@tonic-gate * in a compatible situation. 239*7c478bd9Sstevel@tonic-gate */ 240*7c478bd9Sstevel@tonic-gate more: 241*7c478bd9Sstevel@tonic-gate STRUCT_INIT(args, get_udatamodel()); 242*7c478bd9Sstevel@tonic-gate bzero(STRUCT_BUF(args), SIZEOF_STRUCT(nfs_args, DATAMODEL_NATIVE)); 243*7c478bd9Sstevel@tonic-gate if (copyin(data, STRUCT_BUF(args), MIN(uap->datalen, 244*7c478bd9Sstevel@tonic-gate STRUCT_SIZE(args)))) 245*7c478bd9Sstevel@tonic-gate return (EFAULT); 246*7c478bd9Sstevel@tonic-gate 247*7c478bd9Sstevel@tonic-gate flags = STRUCT_FGET(args, flags); 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate if (uap->flags & MS_REMOUNT) { 250*7c478bd9Sstevel@tonic-gate size_t n; 251*7c478bd9Sstevel@tonic-gate char name[FSTYPSZ]; 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate if (uap->flags & MS_SYSSPACE) 254*7c478bd9Sstevel@tonic-gate error = copystr(uap->fstype, name, FSTYPSZ, &n); 255*7c478bd9Sstevel@tonic-gate else 256*7c478bd9Sstevel@tonic-gate error = copyinstr(uap->fstype, name, FSTYPSZ, &n); 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate if (error) { 259*7c478bd9Sstevel@tonic-gate if (error == ENAMETOOLONG) 260*7c478bd9Sstevel@tonic-gate return (EINVAL); 261*7c478bd9Sstevel@tonic-gate return (error); 262*7c478bd9Sstevel@tonic-gate } 263*7c478bd9Sstevel@tonic-gate 264*7c478bd9Sstevel@tonic-gate /* 265*7c478bd9Sstevel@tonic-gate * This check is to ensure that the request is a 266*7c478bd9Sstevel@tonic-gate * genuine nfs remount request. 267*7c478bd9Sstevel@tonic-gate */ 268*7c478bd9Sstevel@tonic-gate 269*7c478bd9Sstevel@tonic-gate if (strncmp(name, "nfs", 3) != 0) 270*7c478bd9Sstevel@tonic-gate return (EINVAL); 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate /* 273*7c478bd9Sstevel@tonic-gate * If the request changes the locking type, disallow the 274*7c478bd9Sstevel@tonic-gate * remount, 275*7c478bd9Sstevel@tonic-gate * because it's questionable whether we can transfer the 276*7c478bd9Sstevel@tonic-gate * locking state correctly. 277*7c478bd9Sstevel@tonic-gate * 278*7c478bd9Sstevel@tonic-gate * Remounts need to save the pathconf information. 279*7c478bd9Sstevel@tonic-gate * Part of the infamous static kludge. 280*7c478bd9Sstevel@tonic-gate */ 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate if ((mi = VFTOMI(vfsp)) != NULL) { 283*7c478bd9Sstevel@tonic-gate uint_t new_mi_llock; 284*7c478bd9Sstevel@tonic-gate uint_t old_mi_llock; 285*7c478bd9Sstevel@tonic-gate 286*7c478bd9Sstevel@tonic-gate new_mi_llock = (flags & NFSMNT_LLOCK) ? 1 : 0; 287*7c478bd9Sstevel@tonic-gate old_mi_llock = (mi->mi_flags & MI_LLOCK) ? 1 : 0; 288*7c478bd9Sstevel@tonic-gate if (old_mi_llock != new_mi_llock) 289*7c478bd9Sstevel@tonic-gate return (EBUSY); 290*7c478bd9Sstevel@tonic-gate } 291*7c478bd9Sstevel@tonic-gate return (pathconf_get((struct mntinfo *)vfsp->vfs_data, 292*7c478bd9Sstevel@tonic-gate get_udatamodel(), STRUCT_BUF(args))); 293*7c478bd9Sstevel@tonic-gate } 294*7c478bd9Sstevel@tonic-gate 295*7c478bd9Sstevel@tonic-gate mutex_enter(&mvp->v_lock); 296*7c478bd9Sstevel@tonic-gate if (!(uap->flags & MS_OVERLAY) && 297*7c478bd9Sstevel@tonic-gate (mvp->v_count != 1 || (mvp->v_flag & VROOT))) { 298*7c478bd9Sstevel@tonic-gate mutex_exit(&mvp->v_lock); 299*7c478bd9Sstevel@tonic-gate return (EBUSY); 300*7c478bd9Sstevel@tonic-gate } 301*7c478bd9Sstevel@tonic-gate mutex_exit(&mvp->v_lock); 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate /* make sure things are zeroed for errout: */ 304*7c478bd9Sstevel@tonic-gate rtvp = NULL; 305*7c478bd9Sstevel@tonic-gate mi = NULL; 306*7c478bd9Sstevel@tonic-gate addr.buf = NULL; 307*7c478bd9Sstevel@tonic-gate syncaddr.buf = NULL; 308*7c478bd9Sstevel@tonic-gate secdata = NULL; 309*7c478bd9Sstevel@tonic-gate 310*7c478bd9Sstevel@tonic-gate /* 311*7c478bd9Sstevel@tonic-gate * A valid knetconfig structure is required. 312*7c478bd9Sstevel@tonic-gate */ 313*7c478bd9Sstevel@tonic-gate if (!(flags & NFSMNT_KNCONF)) 314*7c478bd9Sstevel@tonic-gate return (EINVAL); 315*7c478bd9Sstevel@tonic-gate 316*7c478bd9Sstevel@tonic-gate /* 317*7c478bd9Sstevel@tonic-gate * Allocate a servinfo struct. 318*7c478bd9Sstevel@tonic-gate */ 319*7c478bd9Sstevel@tonic-gate svp = kmem_zalloc(sizeof (*svp), KM_SLEEP); 320*7c478bd9Sstevel@tonic-gate mutex_init(&svp->sv_lock, NULL, MUTEX_DEFAULT, NULL); 321*7c478bd9Sstevel@tonic-gate if (svp_tail) { 322*7c478bd9Sstevel@tonic-gate svp_2ndlast = svp_tail; 323*7c478bd9Sstevel@tonic-gate svp_tail->sv_next = svp; 324*7c478bd9Sstevel@tonic-gate } else { 325*7c478bd9Sstevel@tonic-gate svp_head = svp; 326*7c478bd9Sstevel@tonic-gate svp_2ndlast = svp; 327*7c478bd9Sstevel@tonic-gate } 328*7c478bd9Sstevel@tonic-gate 329*7c478bd9Sstevel@tonic-gate svp_tail = svp; 330*7c478bd9Sstevel@tonic-gate 331*7c478bd9Sstevel@tonic-gate /* 332*7c478bd9Sstevel@tonic-gate * Allocate space for a knetconfig structure and 333*7c478bd9Sstevel@tonic-gate * its strings and copy in from user-land. 334*7c478bd9Sstevel@tonic-gate */ 335*7c478bd9Sstevel@tonic-gate knconf = kmem_zalloc(sizeof (*knconf), KM_SLEEP); 336*7c478bd9Sstevel@tonic-gate svp->sv_knconf = knconf; 337*7c478bd9Sstevel@tonic-gate STRUCT_INIT(knconf_tmp, get_udatamodel()); 338*7c478bd9Sstevel@tonic-gate if (copyin(STRUCT_FGETP(args, knconf), STRUCT_BUF(knconf_tmp), 339*7c478bd9Sstevel@tonic-gate STRUCT_SIZE(knconf_tmp))) { 340*7c478bd9Sstevel@tonic-gate sv_free(svp_head); 341*7c478bd9Sstevel@tonic-gate return (EFAULT); 342*7c478bd9Sstevel@tonic-gate } 343*7c478bd9Sstevel@tonic-gate 344*7c478bd9Sstevel@tonic-gate knconf->knc_semantics = STRUCT_FGET(knconf_tmp, knc_semantics); 345*7c478bd9Sstevel@tonic-gate knconf->knc_protofmly = STRUCT_FGETP(knconf_tmp, knc_protofmly); 346*7c478bd9Sstevel@tonic-gate knconf->knc_proto = STRUCT_FGETP(knconf_tmp, knc_proto); 347*7c478bd9Sstevel@tonic-gate if (get_udatamodel() != DATAMODEL_LP64) { 348*7c478bd9Sstevel@tonic-gate knconf->knc_rdev = expldev(STRUCT_FGET(knconf_tmp, knc_rdev)); 349*7c478bd9Sstevel@tonic-gate } else { 350*7c478bd9Sstevel@tonic-gate knconf->knc_rdev = STRUCT_FGET(knconf_tmp, knc_rdev); 351*7c478bd9Sstevel@tonic-gate } 352*7c478bd9Sstevel@tonic-gate 353*7c478bd9Sstevel@tonic-gate pf = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 354*7c478bd9Sstevel@tonic-gate p = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 355*7c478bd9Sstevel@tonic-gate error = copyinstr(knconf->knc_protofmly, pf, KNC_STRSIZE, NULL); 356*7c478bd9Sstevel@tonic-gate if (error) { 357*7c478bd9Sstevel@tonic-gate kmem_free(pf, KNC_STRSIZE); 358*7c478bd9Sstevel@tonic-gate kmem_free(p, KNC_STRSIZE); 359*7c478bd9Sstevel@tonic-gate sv_free(svp_head); 360*7c478bd9Sstevel@tonic-gate return (error); 361*7c478bd9Sstevel@tonic-gate } 362*7c478bd9Sstevel@tonic-gate error = copyinstr(knconf->knc_proto, p, KNC_STRSIZE, NULL); 363*7c478bd9Sstevel@tonic-gate if (error) { 364*7c478bd9Sstevel@tonic-gate kmem_free(pf, KNC_STRSIZE); 365*7c478bd9Sstevel@tonic-gate kmem_free(p, KNC_STRSIZE); 366*7c478bd9Sstevel@tonic-gate sv_free(svp_head); 367*7c478bd9Sstevel@tonic-gate return (error); 368*7c478bd9Sstevel@tonic-gate } 369*7c478bd9Sstevel@tonic-gate knconf->knc_protofmly = pf; 370*7c478bd9Sstevel@tonic-gate knconf->knc_proto = p; 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate /* 373*7c478bd9Sstevel@tonic-gate * Get server address 374*7c478bd9Sstevel@tonic-gate */ 375*7c478bd9Sstevel@tonic-gate STRUCT_INIT(addr_tmp, get_udatamodel()); 376*7c478bd9Sstevel@tonic-gate if (copyin(STRUCT_FGETP(args, addr), STRUCT_BUF(addr_tmp), 377*7c478bd9Sstevel@tonic-gate STRUCT_SIZE(addr_tmp))) { 378*7c478bd9Sstevel@tonic-gate addr.buf = NULL; 379*7c478bd9Sstevel@tonic-gate error = EFAULT; 380*7c478bd9Sstevel@tonic-gate } else { 381*7c478bd9Sstevel@tonic-gate char *userbufptr; 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate userbufptr = addr.buf = STRUCT_FGETP(addr_tmp, buf); 384*7c478bd9Sstevel@tonic-gate addr.len = STRUCT_FGET(addr_tmp, len); 385*7c478bd9Sstevel@tonic-gate addr.buf = kmem_alloc(addr.len, KM_SLEEP); 386*7c478bd9Sstevel@tonic-gate addr.maxlen = addr.len; 387*7c478bd9Sstevel@tonic-gate if (copyin(userbufptr, addr.buf, addr.len)) 388*7c478bd9Sstevel@tonic-gate error = EFAULT; 389*7c478bd9Sstevel@tonic-gate } 390*7c478bd9Sstevel@tonic-gate svp->sv_addr = addr; 391*7c478bd9Sstevel@tonic-gate if (error) 392*7c478bd9Sstevel@tonic-gate goto errout; 393*7c478bd9Sstevel@tonic-gate 394*7c478bd9Sstevel@tonic-gate /* 395*7c478bd9Sstevel@tonic-gate * Get the root fhandle 396*7c478bd9Sstevel@tonic-gate */ 397*7c478bd9Sstevel@tonic-gate if (copyin(STRUCT_FGETP(args, fh), &(svp->sv_fhandle.fh_buf), 398*7c478bd9Sstevel@tonic-gate NFS_FHSIZE)) { 399*7c478bd9Sstevel@tonic-gate error = EFAULT; 400*7c478bd9Sstevel@tonic-gate goto errout; 401*7c478bd9Sstevel@tonic-gate } 402*7c478bd9Sstevel@tonic-gate svp->sv_fhandle.fh_len = NFS_FHSIZE; 403*7c478bd9Sstevel@tonic-gate 404*7c478bd9Sstevel@tonic-gate /* 405*7c478bd9Sstevel@tonic-gate * Get server's hostname 406*7c478bd9Sstevel@tonic-gate */ 407*7c478bd9Sstevel@tonic-gate if (flags & NFSMNT_HOSTNAME) { 408*7c478bd9Sstevel@tonic-gate error = copyinstr(STRUCT_FGETP(args, hostname), 409*7c478bd9Sstevel@tonic-gate netname, sizeof (netname), &hlen); 410*7c478bd9Sstevel@tonic-gate if (error) 411*7c478bd9Sstevel@tonic-gate goto errout; 412*7c478bd9Sstevel@tonic-gate } else { 413*7c478bd9Sstevel@tonic-gate char *p = "unknown-host"; 414*7c478bd9Sstevel@tonic-gate hlen = strlen(p) + 1; 415*7c478bd9Sstevel@tonic-gate (void) strcpy(netname, p); 416*7c478bd9Sstevel@tonic-gate } 417*7c478bd9Sstevel@tonic-gate svp->sv_hostnamelen = hlen; 418*7c478bd9Sstevel@tonic-gate svp->sv_hostname = kmem_alloc(svp->sv_hostnamelen, KM_SLEEP); 419*7c478bd9Sstevel@tonic-gate (void) strcpy(svp->sv_hostname, netname); 420*7c478bd9Sstevel@tonic-gate 421*7c478bd9Sstevel@tonic-gate /* 422*7c478bd9Sstevel@tonic-gate * RDMA MOUNT SUPPORT FOR NFS v2: 423*7c478bd9Sstevel@tonic-gate * Establish, is it possible to use RDMA, if so overload the 424*7c478bd9Sstevel@tonic-gate * knconf with rdma specific knconf and free the orignal. 425*7c478bd9Sstevel@tonic-gate */ 426*7c478bd9Sstevel@tonic-gate if ((flags & NFSMNT_TRYRDMA) || (flags & NFSMNT_DORDMA)) { 427*7c478bd9Sstevel@tonic-gate /* 428*7c478bd9Sstevel@tonic-gate * Determine the addr type for RDMA, IPv4 or v6. 429*7c478bd9Sstevel@tonic-gate */ 430*7c478bd9Sstevel@tonic-gate if (strcmp(svp->sv_knconf->knc_protofmly, NC_INET) == 0) 431*7c478bd9Sstevel@tonic-gate addr_type = AF_INET; 432*7c478bd9Sstevel@tonic-gate else if (strcmp(svp->sv_knconf->knc_protofmly, NC_INET6) == 0) 433*7c478bd9Sstevel@tonic-gate addr_type = AF_INET6; 434*7c478bd9Sstevel@tonic-gate 435*7c478bd9Sstevel@tonic-gate if (rdma_reachable(addr_type, &svp->sv_addr, 436*7c478bd9Sstevel@tonic-gate &rdma_knconf) == 0) { 437*7c478bd9Sstevel@tonic-gate /* 438*7c478bd9Sstevel@tonic-gate * If successful, hijack, the orignal knconf and 439*7c478bd9Sstevel@tonic-gate * replace with a new one, depending on the flags. 440*7c478bd9Sstevel@tonic-gate */ 441*7c478bd9Sstevel@tonic-gate svp->sv_origknconf = svp->sv_knconf; 442*7c478bd9Sstevel@tonic-gate svp->sv_knconf = rdma_knconf; 443*7c478bd9Sstevel@tonic-gate knconf = rdma_knconf; 444*7c478bd9Sstevel@tonic-gate } else { 445*7c478bd9Sstevel@tonic-gate if (flags & NFSMNT_TRYRDMA) { 446*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 447*7c478bd9Sstevel@tonic-gate if (rdma_debug) 448*7c478bd9Sstevel@tonic-gate zcmn_err(getzoneid(), CE_WARN, 449*7c478bd9Sstevel@tonic-gate "no RDMA onboard, revert\n"); 450*7c478bd9Sstevel@tonic-gate #endif 451*7c478bd9Sstevel@tonic-gate } 452*7c478bd9Sstevel@tonic-gate 453*7c478bd9Sstevel@tonic-gate if (flags & NFSMNT_DORDMA) { 454*7c478bd9Sstevel@tonic-gate /* 455*7c478bd9Sstevel@tonic-gate * If proto=rdma is specified and no RDMA 456*7c478bd9Sstevel@tonic-gate * path to this server is avialable then 457*7c478bd9Sstevel@tonic-gate * ditch this server. 458*7c478bd9Sstevel@tonic-gate * This is not included in the mountable 459*7c478bd9Sstevel@tonic-gate * server list or the replica list. 460*7c478bd9Sstevel@tonic-gate * Check if more servers are specified; 461*7c478bd9Sstevel@tonic-gate * Failover case, otherwise bail out of mount. 462*7c478bd9Sstevel@tonic-gate */ 463*7c478bd9Sstevel@tonic-gate if (STRUCT_FGET(args, nfs_args_ext) == 464*7c478bd9Sstevel@tonic-gate NFS_ARGS_EXTB && STRUCT_FGETP(args, 465*7c478bd9Sstevel@tonic-gate nfs_ext_u.nfs_extB.next) != NULL) { 466*7c478bd9Sstevel@tonic-gate if (uap->flags & MS_RDONLY && 467*7c478bd9Sstevel@tonic-gate !(flags & NFSMNT_SOFT)) { 468*7c478bd9Sstevel@tonic-gate data = (char *) 469*7c478bd9Sstevel@tonic-gate STRUCT_FGETP(args, 470*7c478bd9Sstevel@tonic-gate nfs_ext_u.nfs_extB.next); 471*7c478bd9Sstevel@tonic-gate if (svp_head->sv_next == NULL) { 472*7c478bd9Sstevel@tonic-gate svp_tail = NULL; 473*7c478bd9Sstevel@tonic-gate svp_2ndlast = NULL; 474*7c478bd9Sstevel@tonic-gate sv_free(svp_head); 475*7c478bd9Sstevel@tonic-gate goto more; 476*7c478bd9Sstevel@tonic-gate } else { 477*7c478bd9Sstevel@tonic-gate svp_tail = svp_2ndlast; 478*7c478bd9Sstevel@tonic-gate svp_2ndlast->sv_next = 479*7c478bd9Sstevel@tonic-gate NULL; 480*7c478bd9Sstevel@tonic-gate sv_free(svp); 481*7c478bd9Sstevel@tonic-gate goto more; 482*7c478bd9Sstevel@tonic-gate } 483*7c478bd9Sstevel@tonic-gate } 484*7c478bd9Sstevel@tonic-gate } else { 485*7c478bd9Sstevel@tonic-gate /* 486*7c478bd9Sstevel@tonic-gate * This is the last server specified 487*7c478bd9Sstevel@tonic-gate * in the nfs_args list passed down 488*7c478bd9Sstevel@tonic-gate * and its not rdma capable. 489*7c478bd9Sstevel@tonic-gate */ 490*7c478bd9Sstevel@tonic-gate if (svp_head->sv_next == NULL) { 491*7c478bd9Sstevel@tonic-gate /* 492*7c478bd9Sstevel@tonic-gate * Is this the only one 493*7c478bd9Sstevel@tonic-gate */ 494*7c478bd9Sstevel@tonic-gate error = EINVAL; 495*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 496*7c478bd9Sstevel@tonic-gate if (rdma_debug) 497*7c478bd9Sstevel@tonic-gate zcmn_err(getzoneid(), 498*7c478bd9Sstevel@tonic-gate CE_WARN, 499*7c478bd9Sstevel@tonic-gate "No RDMA srv"); 500*7c478bd9Sstevel@tonic-gate #endif 501*7c478bd9Sstevel@tonic-gate goto errout; 502*7c478bd9Sstevel@tonic-gate } else { 503*7c478bd9Sstevel@tonic-gate /* 504*7c478bd9Sstevel@tonic-gate * There is list, since some 505*7c478bd9Sstevel@tonic-gate * servers specified before 506*7c478bd9Sstevel@tonic-gate * this passed all requirements 507*7c478bd9Sstevel@tonic-gate */ 508*7c478bd9Sstevel@tonic-gate svp_tail = svp_2ndlast; 509*7c478bd9Sstevel@tonic-gate svp_2ndlast->sv_next = NULL; 510*7c478bd9Sstevel@tonic-gate sv_free(svp); 511*7c478bd9Sstevel@tonic-gate goto proceed; 512*7c478bd9Sstevel@tonic-gate } 513*7c478bd9Sstevel@tonic-gate } 514*7c478bd9Sstevel@tonic-gate } 515*7c478bd9Sstevel@tonic-gate } 516*7c478bd9Sstevel@tonic-gate } 517*7c478bd9Sstevel@tonic-gate 518*7c478bd9Sstevel@tonic-gate /* 519*7c478bd9Sstevel@tonic-gate * Get the extention data which has the new security data structure. 520*7c478bd9Sstevel@tonic-gate */ 521*7c478bd9Sstevel@tonic-gate if (flags & NFSMNT_NEWARGS) { 522*7c478bd9Sstevel@tonic-gate switch (STRUCT_FGET(args, nfs_args_ext)) { 523*7c478bd9Sstevel@tonic-gate case NFS_ARGS_EXTA: 524*7c478bd9Sstevel@tonic-gate case NFS_ARGS_EXTB: 525*7c478bd9Sstevel@tonic-gate /* 526*7c478bd9Sstevel@tonic-gate * Indicating the application is using the new 527*7c478bd9Sstevel@tonic-gate * sec_data structure to pass in the security 528*7c478bd9Sstevel@tonic-gate * data. 529*7c478bd9Sstevel@tonic-gate */ 530*7c478bd9Sstevel@tonic-gate if (STRUCT_FGETP(args, 531*7c478bd9Sstevel@tonic-gate nfs_ext_u.nfs_extA.secdata) == NULL) { 532*7c478bd9Sstevel@tonic-gate error = EINVAL; 533*7c478bd9Sstevel@tonic-gate } else { 534*7c478bd9Sstevel@tonic-gate error = sec_clnt_loadinfo( 535*7c478bd9Sstevel@tonic-gate (struct sec_data *)STRUCT_FGETP(args, 536*7c478bd9Sstevel@tonic-gate nfs_ext_u.nfs_extA.secdata), 537*7c478bd9Sstevel@tonic-gate &secdata, get_udatamodel()); 538*7c478bd9Sstevel@tonic-gate } 539*7c478bd9Sstevel@tonic-gate break; 540*7c478bd9Sstevel@tonic-gate 541*7c478bd9Sstevel@tonic-gate default: 542*7c478bd9Sstevel@tonic-gate error = EINVAL; 543*7c478bd9Sstevel@tonic-gate break; 544*7c478bd9Sstevel@tonic-gate } 545*7c478bd9Sstevel@tonic-gate } else if (flags & NFSMNT_SECURE) { 546*7c478bd9Sstevel@tonic-gate /* 547*7c478bd9Sstevel@tonic-gate * Keep this for backward compatibility to support 548*7c478bd9Sstevel@tonic-gate * NFSMNT_SECURE/NFSMNT_RPCTIMESYNC flags. 549*7c478bd9Sstevel@tonic-gate */ 550*7c478bd9Sstevel@tonic-gate if (STRUCT_FGETP(args, syncaddr) == NULL) { 551*7c478bd9Sstevel@tonic-gate error = EINVAL; 552*7c478bd9Sstevel@tonic-gate } else { 553*7c478bd9Sstevel@tonic-gate /* 554*7c478bd9Sstevel@tonic-gate * get time sync address. 555*7c478bd9Sstevel@tonic-gate */ 556*7c478bd9Sstevel@tonic-gate if (copyin(STRUCT_FGETP(args, syncaddr), &addr_tmp, 557*7c478bd9Sstevel@tonic-gate STRUCT_SIZE(addr_tmp))) { 558*7c478bd9Sstevel@tonic-gate syncaddr.buf = NULL; 559*7c478bd9Sstevel@tonic-gate error = EFAULT; 560*7c478bd9Sstevel@tonic-gate } else { 561*7c478bd9Sstevel@tonic-gate char *userbufptr; 562*7c478bd9Sstevel@tonic-gate 563*7c478bd9Sstevel@tonic-gate userbufptr = syncaddr.buf = 564*7c478bd9Sstevel@tonic-gate STRUCT_FGETP(addr_tmp, buf); 565*7c478bd9Sstevel@tonic-gate syncaddr.len = 566*7c478bd9Sstevel@tonic-gate STRUCT_FGET(addr_tmp, len); 567*7c478bd9Sstevel@tonic-gate syncaddr.buf = kmem_alloc(syncaddr.len, 568*7c478bd9Sstevel@tonic-gate KM_SLEEP); 569*7c478bd9Sstevel@tonic-gate syncaddr.maxlen = syncaddr.len; 570*7c478bd9Sstevel@tonic-gate 571*7c478bd9Sstevel@tonic-gate if (copyin(userbufptr, syncaddr.buf, 572*7c478bd9Sstevel@tonic-gate syncaddr.len)) 573*7c478bd9Sstevel@tonic-gate error = EFAULT; 574*7c478bd9Sstevel@tonic-gate } 575*7c478bd9Sstevel@tonic-gate 576*7c478bd9Sstevel@tonic-gate /* 577*7c478bd9Sstevel@tonic-gate * get server's netname 578*7c478bd9Sstevel@tonic-gate */ 579*7c478bd9Sstevel@tonic-gate if (!error) { 580*7c478bd9Sstevel@tonic-gate error = copyinstr(STRUCT_FGETP(args, netname), 581*7c478bd9Sstevel@tonic-gate netname, sizeof (netname), &nlen); 582*7c478bd9Sstevel@tonic-gate netname[nlen] = '\0'; 583*7c478bd9Sstevel@tonic-gate } 584*7c478bd9Sstevel@tonic-gate 585*7c478bd9Sstevel@tonic-gate if (error && syncaddr.buf != NULL) { 586*7c478bd9Sstevel@tonic-gate kmem_free(syncaddr.buf, syncaddr.len); 587*7c478bd9Sstevel@tonic-gate syncaddr.buf = NULL; 588*7c478bd9Sstevel@tonic-gate } 589*7c478bd9Sstevel@tonic-gate } 590*7c478bd9Sstevel@tonic-gate 591*7c478bd9Sstevel@tonic-gate /* 592*7c478bd9Sstevel@tonic-gate * Move security related data to the sec_data structure. 593*7c478bd9Sstevel@tonic-gate */ 594*7c478bd9Sstevel@tonic-gate if (!error) { 595*7c478bd9Sstevel@tonic-gate dh_k4_clntdata_t *data; 596*7c478bd9Sstevel@tonic-gate char *pf, *p; 597*7c478bd9Sstevel@tonic-gate 598*7c478bd9Sstevel@tonic-gate secdata = kmem_alloc(sizeof (*secdata), KM_SLEEP); 599*7c478bd9Sstevel@tonic-gate if (flags & NFSMNT_RPCTIMESYNC) 600*7c478bd9Sstevel@tonic-gate secdata->flags |= AUTH_F_RPCTIMESYNC; 601*7c478bd9Sstevel@tonic-gate data = kmem_alloc(sizeof (*data), KM_SLEEP); 602*7c478bd9Sstevel@tonic-gate data->syncaddr = syncaddr; 603*7c478bd9Sstevel@tonic-gate 604*7c478bd9Sstevel@tonic-gate /* 605*7c478bd9Sstevel@tonic-gate * duplicate the knconf information for the 606*7c478bd9Sstevel@tonic-gate * new opaque data. 607*7c478bd9Sstevel@tonic-gate */ 608*7c478bd9Sstevel@tonic-gate data->knconf = kmem_alloc(sizeof (*knconf), KM_SLEEP); 609*7c478bd9Sstevel@tonic-gate *data->knconf = *knconf; 610*7c478bd9Sstevel@tonic-gate pf = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 611*7c478bd9Sstevel@tonic-gate p = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 612*7c478bd9Sstevel@tonic-gate bcopy(knconf->knc_protofmly, pf, KNC_STRSIZE); 613*7c478bd9Sstevel@tonic-gate bcopy(knconf->knc_proto, pf, KNC_STRSIZE); 614*7c478bd9Sstevel@tonic-gate data->knconf->knc_protofmly = pf; 615*7c478bd9Sstevel@tonic-gate data->knconf->knc_proto = p; 616*7c478bd9Sstevel@tonic-gate 617*7c478bd9Sstevel@tonic-gate /* move server netname to the sec_data structure */ 618*7c478bd9Sstevel@tonic-gate if (nlen != 0) { 619*7c478bd9Sstevel@tonic-gate data->netname = kmem_alloc(nlen, KM_SLEEP); 620*7c478bd9Sstevel@tonic-gate bcopy(netname, data->netname, nlen); 621*7c478bd9Sstevel@tonic-gate data->netnamelen = (int)nlen; 622*7c478bd9Sstevel@tonic-gate } 623*7c478bd9Sstevel@tonic-gate secdata->secmod = secdata->rpcflavor = AUTH_DES; 624*7c478bd9Sstevel@tonic-gate secdata->data = (caddr_t)data; 625*7c478bd9Sstevel@tonic-gate } 626*7c478bd9Sstevel@tonic-gate } else { 627*7c478bd9Sstevel@tonic-gate secdata = kmem_alloc(sizeof (*secdata), KM_SLEEP); 628*7c478bd9Sstevel@tonic-gate secdata->secmod = secdata->rpcflavor = AUTH_UNIX; 629*7c478bd9Sstevel@tonic-gate secdata->data = NULL; 630*7c478bd9Sstevel@tonic-gate } 631*7c478bd9Sstevel@tonic-gate svp->sv_secdata = secdata; 632*7c478bd9Sstevel@tonic-gate if (error) 633*7c478bd9Sstevel@tonic-gate goto errout; 634*7c478bd9Sstevel@tonic-gate 635*7c478bd9Sstevel@tonic-gate /* 636*7c478bd9Sstevel@tonic-gate * See bug 1180236. 637*7c478bd9Sstevel@tonic-gate * If mount secure failed, we will fall back to AUTH_NONE 638*7c478bd9Sstevel@tonic-gate * and try again. nfs3rootvp() will turn this back off. 639*7c478bd9Sstevel@tonic-gate * 640*7c478bd9Sstevel@tonic-gate * The NFS Version 2 mount uses GETATTR and STATFS procedures. 641*7c478bd9Sstevel@tonic-gate * The server does not care if these procedures have the proper 642*7c478bd9Sstevel@tonic-gate * authentication flavor, so if mount retries using AUTH_NONE 643*7c478bd9Sstevel@tonic-gate * that does not require a credential setup for root then the 644*7c478bd9Sstevel@tonic-gate * automounter would work without requiring root to be 645*7c478bd9Sstevel@tonic-gate * keylogged into AUTH_DES. 646*7c478bd9Sstevel@tonic-gate */ 647*7c478bd9Sstevel@tonic-gate if (secdata->rpcflavor != AUTH_UNIX && 648*7c478bd9Sstevel@tonic-gate secdata->rpcflavor != AUTH_LOOPBACK) 649*7c478bd9Sstevel@tonic-gate secdata->flags |= AUTH_F_TRYNONE; 650*7c478bd9Sstevel@tonic-gate 651*7c478bd9Sstevel@tonic-gate /* 652*7c478bd9Sstevel@tonic-gate * Failover support: 653*7c478bd9Sstevel@tonic-gate * 654*7c478bd9Sstevel@tonic-gate * We may have a linked list of nfs_args structures, 655*7c478bd9Sstevel@tonic-gate * which means the user is looking for failover. If 656*7c478bd9Sstevel@tonic-gate * the mount is either not "read-only" or "soft", 657*7c478bd9Sstevel@tonic-gate * we want to bail out with EINVAL. 658*7c478bd9Sstevel@tonic-gate */ 659*7c478bd9Sstevel@tonic-gate if (STRUCT_FGET(args, nfs_args_ext) == NFS_ARGS_EXTB && 660*7c478bd9Sstevel@tonic-gate STRUCT_FGETP(args, nfs_ext_u.nfs_extB.next) != NULL) { 661*7c478bd9Sstevel@tonic-gate if (uap->flags & MS_RDONLY && !(flags & NFSMNT_SOFT)) { 662*7c478bd9Sstevel@tonic-gate data = (char *)STRUCT_FGETP(args, 663*7c478bd9Sstevel@tonic-gate nfs_ext_u.nfs_extB.next); 664*7c478bd9Sstevel@tonic-gate goto more; 665*7c478bd9Sstevel@tonic-gate } 666*7c478bd9Sstevel@tonic-gate error = EINVAL; 667*7c478bd9Sstevel@tonic-gate goto errout; 668*7c478bd9Sstevel@tonic-gate } 669*7c478bd9Sstevel@tonic-gate 670*7c478bd9Sstevel@tonic-gate /* 671*7c478bd9Sstevel@tonic-gate * Determine the zone we're being mounted into. 672*7c478bd9Sstevel@tonic-gate */ 673*7c478bd9Sstevel@tonic-gate if (getzoneid() == GLOBAL_ZONEID) { 674*7c478bd9Sstevel@tonic-gate zone_t *mntzone; 675*7c478bd9Sstevel@tonic-gate 676*7c478bd9Sstevel@tonic-gate mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt)); 677*7c478bd9Sstevel@tonic-gate ASSERT(mntzone != NULL); 678*7c478bd9Sstevel@tonic-gate zone_rele(mntzone); 679*7c478bd9Sstevel@tonic-gate if (mntzone != zone) { 680*7c478bd9Sstevel@tonic-gate error = EBUSY; 681*7c478bd9Sstevel@tonic-gate goto errout; 682*7c478bd9Sstevel@tonic-gate } 683*7c478bd9Sstevel@tonic-gate } 684*7c478bd9Sstevel@tonic-gate 685*7c478bd9Sstevel@tonic-gate /* 686*7c478bd9Sstevel@tonic-gate * Stop the mount from going any further if the zone is going away. 687*7c478bd9Sstevel@tonic-gate */ 688*7c478bd9Sstevel@tonic-gate if (zone_status_get(zone) >= ZONE_IS_SHUTTING_DOWN) { 689*7c478bd9Sstevel@tonic-gate error = EBUSY; 690*7c478bd9Sstevel@tonic-gate goto errout; 691*7c478bd9Sstevel@tonic-gate } 692*7c478bd9Sstevel@tonic-gate 693*7c478bd9Sstevel@tonic-gate /* 694*7c478bd9Sstevel@tonic-gate * Get root vnode. 695*7c478bd9Sstevel@tonic-gate */ 696*7c478bd9Sstevel@tonic-gate proceed: 697*7c478bd9Sstevel@tonic-gate error = nfsrootvp(&rtvp, vfsp, svp_head, flags, cr, zone); 698*7c478bd9Sstevel@tonic-gate 699*7c478bd9Sstevel@tonic-gate if (error) 700*7c478bd9Sstevel@tonic-gate goto errout; 701*7c478bd9Sstevel@tonic-gate 702*7c478bd9Sstevel@tonic-gate /* 703*7c478bd9Sstevel@tonic-gate * Set option fields in the mount info record 704*7c478bd9Sstevel@tonic-gate */ 705*7c478bd9Sstevel@tonic-gate mi = VTOMI(rtvp); 706*7c478bd9Sstevel@tonic-gate 707*7c478bd9Sstevel@tonic-gate if (svp_head->sv_next) 708*7c478bd9Sstevel@tonic-gate mi->mi_flags |= MI_LLOCK; 709*7c478bd9Sstevel@tonic-gate 710*7c478bd9Sstevel@tonic-gate error = nfs_setopts(rtvp, get_udatamodel(), STRUCT_BUF(args)); 711*7c478bd9Sstevel@tonic-gate if (!error) { 712*7c478bd9Sstevel@tonic-gate /* static pathconf kludge */ 713*7c478bd9Sstevel@tonic-gate error = pathconf_get(mi, get_udatamodel(), STRUCT_BUF(args)); 714*7c478bd9Sstevel@tonic-gate } 715*7c478bd9Sstevel@tonic-gate 716*7c478bd9Sstevel@tonic-gate errout: 717*7c478bd9Sstevel@tonic-gate if (error) { 718*7c478bd9Sstevel@tonic-gate if (rtvp != NULL) { 719*7c478bd9Sstevel@tonic-gate rp = VTOR(rtvp); 720*7c478bd9Sstevel@tonic-gate if (rp->r_flags & RHASHED) 721*7c478bd9Sstevel@tonic-gate rp_rmhash(rp); 722*7c478bd9Sstevel@tonic-gate } 723*7c478bd9Sstevel@tonic-gate sv_free(svp_head); 724*7c478bd9Sstevel@tonic-gate if (mi != NULL) { 725*7c478bd9Sstevel@tonic-gate nfs_async_stop(vfsp); 726*7c478bd9Sstevel@tonic-gate nfs_async_manager_stop(vfsp); 727*7c478bd9Sstevel@tonic-gate if (mi->mi_io_kstats) { 728*7c478bd9Sstevel@tonic-gate kstat_delete(mi->mi_io_kstats); 729*7c478bd9Sstevel@tonic-gate mi->mi_io_kstats = NULL; 730*7c478bd9Sstevel@tonic-gate } 731*7c478bd9Sstevel@tonic-gate if (mi->mi_ro_kstats) { 732*7c478bd9Sstevel@tonic-gate kstat_delete(mi->mi_ro_kstats); 733*7c478bd9Sstevel@tonic-gate mi->mi_ro_kstats = NULL; 734*7c478bd9Sstevel@tonic-gate } 735*7c478bd9Sstevel@tonic-gate nfs_free_mi(mi); 736*7c478bd9Sstevel@tonic-gate } 737*7c478bd9Sstevel@tonic-gate } 738*7c478bd9Sstevel@tonic-gate 739*7c478bd9Sstevel@tonic-gate if (rtvp != NULL) 740*7c478bd9Sstevel@tonic-gate VN_RELE(rtvp); 741*7c478bd9Sstevel@tonic-gate 742*7c478bd9Sstevel@tonic-gate return (error); 743*7c478bd9Sstevel@tonic-gate } 744*7c478bd9Sstevel@tonic-gate 745*7c478bd9Sstevel@tonic-gate /* 746*7c478bd9Sstevel@tonic-gate * The pathconf information is kept on a linked list of kmem_alloc'ed 747*7c478bd9Sstevel@tonic-gate * structs. We search the list & add a new struct iff there is no other 748*7c478bd9Sstevel@tonic-gate * struct with the same information. 749*7c478bd9Sstevel@tonic-gate * See sys/pathconf.h for ``the rest of the story.'' 750*7c478bd9Sstevel@tonic-gate */ 751*7c478bd9Sstevel@tonic-gate static struct pathcnf *allpc = NULL; 752*7c478bd9Sstevel@tonic-gate 753*7c478bd9Sstevel@tonic-gate static int 754*7c478bd9Sstevel@tonic-gate pathconf_get(struct mntinfo *mi, model_t model, struct nfs_args *args) 755*7c478bd9Sstevel@tonic-gate { 756*7c478bd9Sstevel@tonic-gate struct pathcnf *p; 757*7c478bd9Sstevel@tonic-gate struct pathcnf pc; 758*7c478bd9Sstevel@tonic-gate STRUCT_DECL(pathcnf, pc_tmp); 759*7c478bd9Sstevel@tonic-gate STRUCT_HANDLE(nfs_args, ap); 760*7c478bd9Sstevel@tonic-gate int i; 761*7c478bd9Sstevel@tonic-gate 762*7c478bd9Sstevel@tonic-gate #ifdef lint 763*7c478bd9Sstevel@tonic-gate model = model; 764*7c478bd9Sstevel@tonic-gate #endif 765*7c478bd9Sstevel@tonic-gate 766*7c478bd9Sstevel@tonic-gate STRUCT_INIT(pc_tmp, model); 767*7c478bd9Sstevel@tonic-gate STRUCT_SET_HANDLE(ap, model, args); 768*7c478bd9Sstevel@tonic-gate 769*7c478bd9Sstevel@tonic-gate if (mi->mi_pathconf != NULL) { 770*7c478bd9Sstevel@tonic-gate pathconf_rele(mi); 771*7c478bd9Sstevel@tonic-gate mi->mi_pathconf = NULL; 772*7c478bd9Sstevel@tonic-gate } 773*7c478bd9Sstevel@tonic-gate if ((STRUCT_FGET(ap, flags) & NFSMNT_POSIX) && 774*7c478bd9Sstevel@tonic-gate STRUCT_FGETP(ap, pathconf) != NULL) { 775*7c478bd9Sstevel@tonic-gate if (copyin(STRUCT_FGETP(ap, pathconf), STRUCT_BUF(pc_tmp), 776*7c478bd9Sstevel@tonic-gate STRUCT_SIZE(pc_tmp))) 777*7c478bd9Sstevel@tonic-gate return (EFAULT); 778*7c478bd9Sstevel@tonic-gate if (_PC_ISSET(_PC_ERROR, STRUCT_FGET(pc_tmp, pc_mask))) 779*7c478bd9Sstevel@tonic-gate return (EINVAL); 780*7c478bd9Sstevel@tonic-gate 781*7c478bd9Sstevel@tonic-gate pc.pc_link_max = STRUCT_FGET(pc_tmp, pc_link_max); 782*7c478bd9Sstevel@tonic-gate pc.pc_max_canon = STRUCT_FGET(pc_tmp, pc_max_canon); 783*7c478bd9Sstevel@tonic-gate pc.pc_max_input = STRUCT_FGET(pc_tmp, pc_max_input); 784*7c478bd9Sstevel@tonic-gate pc.pc_name_max = STRUCT_FGET(pc_tmp, pc_name_max); 785*7c478bd9Sstevel@tonic-gate pc.pc_path_max = STRUCT_FGET(pc_tmp, pc_path_max); 786*7c478bd9Sstevel@tonic-gate pc.pc_pipe_buf = STRUCT_FGET(pc_tmp, pc_pipe_buf); 787*7c478bd9Sstevel@tonic-gate pc.pc_vdisable = STRUCT_FGET(pc_tmp, pc_vdisable); 788*7c478bd9Sstevel@tonic-gate pc.pc_xxx = STRUCT_FGET(pc_tmp, pc_xxx); 789*7c478bd9Sstevel@tonic-gate for (i = 0; i < _PC_N; i++) 790*7c478bd9Sstevel@tonic-gate pc.pc_mask[i] = STRUCT_FGET(pc_tmp, pc_mask[i]); 791*7c478bd9Sstevel@tonic-gate 792*7c478bd9Sstevel@tonic-gate for (p = allpc; p != NULL; p = p->pc_next) { 793*7c478bd9Sstevel@tonic-gate if (PCCMP(p, &pc) == 0) 794*7c478bd9Sstevel@tonic-gate break; 795*7c478bd9Sstevel@tonic-gate } 796*7c478bd9Sstevel@tonic-gate if (p != NULL) { 797*7c478bd9Sstevel@tonic-gate mi->mi_pathconf = p; 798*7c478bd9Sstevel@tonic-gate p->pc_refcnt++; 799*7c478bd9Sstevel@tonic-gate } else { 800*7c478bd9Sstevel@tonic-gate p = kmem_alloc(sizeof (*p), KM_SLEEP); 801*7c478bd9Sstevel@tonic-gate *p = pc; 802*7c478bd9Sstevel@tonic-gate p->pc_next = allpc; 803*7c478bd9Sstevel@tonic-gate p->pc_refcnt = 1; 804*7c478bd9Sstevel@tonic-gate allpc = mi->mi_pathconf = p; 805*7c478bd9Sstevel@tonic-gate } 806*7c478bd9Sstevel@tonic-gate } 807*7c478bd9Sstevel@tonic-gate return (0); 808*7c478bd9Sstevel@tonic-gate } 809*7c478bd9Sstevel@tonic-gate 810*7c478bd9Sstevel@tonic-gate /* 811*7c478bd9Sstevel@tonic-gate * release the static pathconf information 812*7c478bd9Sstevel@tonic-gate */ 813*7c478bd9Sstevel@tonic-gate static void 814*7c478bd9Sstevel@tonic-gate pathconf_rele(struct mntinfo *mi) 815*7c478bd9Sstevel@tonic-gate { 816*7c478bd9Sstevel@tonic-gate if (mi->mi_pathconf != NULL) { 817*7c478bd9Sstevel@tonic-gate if (--mi->mi_pathconf->pc_refcnt == 0) { 818*7c478bd9Sstevel@tonic-gate struct pathcnf *p; 819*7c478bd9Sstevel@tonic-gate struct pathcnf *p2; 820*7c478bd9Sstevel@tonic-gate 821*7c478bd9Sstevel@tonic-gate p2 = p = allpc; 822*7c478bd9Sstevel@tonic-gate while (p != NULL && p != mi->mi_pathconf) { 823*7c478bd9Sstevel@tonic-gate p2 = p; 824*7c478bd9Sstevel@tonic-gate p = p->pc_next; 825*7c478bd9Sstevel@tonic-gate } 826*7c478bd9Sstevel@tonic-gate if (p == NULL) { 827*7c478bd9Sstevel@tonic-gate panic("mi->pathconf"); 828*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 829*7c478bd9Sstevel@tonic-gate } 830*7c478bd9Sstevel@tonic-gate if (p == allpc) 831*7c478bd9Sstevel@tonic-gate allpc = p->pc_next; 832*7c478bd9Sstevel@tonic-gate else 833*7c478bd9Sstevel@tonic-gate p2->pc_next = p->pc_next; 834*7c478bd9Sstevel@tonic-gate kmem_free(p, sizeof (*p)); 835*7c478bd9Sstevel@tonic-gate mi->mi_pathconf = NULL; 836*7c478bd9Sstevel@tonic-gate } 837*7c478bd9Sstevel@tonic-gate } 838*7c478bd9Sstevel@tonic-gate } 839*7c478bd9Sstevel@tonic-gate 840*7c478bd9Sstevel@tonic-gate static int nfs_dynamic = 1; /* global variable to enable dynamic retrans. */ 841*7c478bd9Sstevel@tonic-gate static ushort_t nfs_max_threads = 8; /* max number of active async threads */ 842*7c478bd9Sstevel@tonic-gate static uint_t nfs_async_clusters = 1; /* # of reqs from each async queue */ 843*7c478bd9Sstevel@tonic-gate static uint_t nfs_cots_timeo = NFS_COTS_TIMEO; 844*7c478bd9Sstevel@tonic-gate 845*7c478bd9Sstevel@tonic-gate static int 846*7c478bd9Sstevel@tonic-gate nfsrootvp(vnode_t **rtvpp, vfs_t *vfsp, struct servinfo *svp, 847*7c478bd9Sstevel@tonic-gate int flags, cred_t *cr, zone_t *zone) 848*7c478bd9Sstevel@tonic-gate { 849*7c478bd9Sstevel@tonic-gate vnode_t *rtvp; 850*7c478bd9Sstevel@tonic-gate mntinfo_t *mi; 851*7c478bd9Sstevel@tonic-gate dev_t nfs_dev; 852*7c478bd9Sstevel@tonic-gate struct vattr va; 853*7c478bd9Sstevel@tonic-gate int error; 854*7c478bd9Sstevel@tonic-gate rnode_t *rp; 855*7c478bd9Sstevel@tonic-gate int i; 856*7c478bd9Sstevel@tonic-gate struct nfs_stats *nfsstatsp; 857*7c478bd9Sstevel@tonic-gate cred_t *lcr = NULL, *tcr = cr; 858*7c478bd9Sstevel@tonic-gate 859*7c478bd9Sstevel@tonic-gate nfsstatsp = zone_getspecific(nfsstat_zone_key, curproc->p_zone); 860*7c478bd9Sstevel@tonic-gate ASSERT(nfsstatsp != NULL); 861*7c478bd9Sstevel@tonic-gate 862*7c478bd9Sstevel@tonic-gate /* 863*7c478bd9Sstevel@tonic-gate * Create a mount record and link it to the vfs struct. 864*7c478bd9Sstevel@tonic-gate */ 865*7c478bd9Sstevel@tonic-gate mi = kmem_zalloc(sizeof (*mi), KM_SLEEP); 866*7c478bd9Sstevel@tonic-gate mutex_init(&mi->mi_lock, NULL, MUTEX_DEFAULT, NULL); 867*7c478bd9Sstevel@tonic-gate mi->mi_flags = MI_ACL | MI_EXTATTR; 868*7c478bd9Sstevel@tonic-gate if (!(flags & NFSMNT_SOFT)) 869*7c478bd9Sstevel@tonic-gate mi->mi_flags |= MI_HARD; 870*7c478bd9Sstevel@tonic-gate if ((flags & NFSMNT_SEMISOFT)) 871*7c478bd9Sstevel@tonic-gate mi->mi_flags |= MI_SEMISOFT; 872*7c478bd9Sstevel@tonic-gate if ((flags & NFSMNT_NOPRINT)) 873*7c478bd9Sstevel@tonic-gate mi->mi_flags |= MI_NOPRINT; 874*7c478bd9Sstevel@tonic-gate if (flags & NFSMNT_INT) 875*7c478bd9Sstevel@tonic-gate mi->mi_flags |= MI_INT; 876*7c478bd9Sstevel@tonic-gate mi->mi_retrans = NFS_RETRIES; 877*7c478bd9Sstevel@tonic-gate if (svp->sv_knconf->knc_semantics == NC_TPI_COTS_ORD || 878*7c478bd9Sstevel@tonic-gate svp->sv_knconf->knc_semantics == NC_TPI_COTS) 879*7c478bd9Sstevel@tonic-gate mi->mi_timeo = nfs_cots_timeo; 880*7c478bd9Sstevel@tonic-gate else 881*7c478bd9Sstevel@tonic-gate mi->mi_timeo = NFS_TIMEO; 882*7c478bd9Sstevel@tonic-gate mi->mi_prog = NFS_PROGRAM; 883*7c478bd9Sstevel@tonic-gate mi->mi_vers = NFS_VERSION; 884*7c478bd9Sstevel@tonic-gate mi->mi_rfsnames = rfsnames_v2; 885*7c478bd9Sstevel@tonic-gate mi->mi_reqs = nfsstatsp->nfs_stats_v2.rfsreqcnt_ptr; 886*7c478bd9Sstevel@tonic-gate mi->mi_call_type = call_type_v2; 887*7c478bd9Sstevel@tonic-gate mi->mi_ss_call_type = ss_call_type_v2; 888*7c478bd9Sstevel@tonic-gate mi->mi_timer_type = timer_type_v2; 889*7c478bd9Sstevel@tonic-gate mi->mi_aclnames = aclnames_v2; 890*7c478bd9Sstevel@tonic-gate mi->mi_aclreqs = nfsstatsp->nfs_stats_v2.aclreqcnt_ptr; 891*7c478bd9Sstevel@tonic-gate mi->mi_acl_call_type = acl_call_type_v2; 892*7c478bd9Sstevel@tonic-gate mi->mi_acl_ss_call_type = acl_ss_call_type_v2; 893*7c478bd9Sstevel@tonic-gate mi->mi_acl_timer_type = acl_timer_type_v2; 894*7c478bd9Sstevel@tonic-gate cv_init(&mi->mi_failover_cv, NULL, CV_DEFAULT, NULL); 895*7c478bd9Sstevel@tonic-gate mi->mi_servers = svp; 896*7c478bd9Sstevel@tonic-gate mi->mi_curr_serv = svp; 897*7c478bd9Sstevel@tonic-gate mi->mi_acregmin = SEC2HR(ACREGMIN); 898*7c478bd9Sstevel@tonic-gate mi->mi_acregmax = SEC2HR(ACREGMAX); 899*7c478bd9Sstevel@tonic-gate mi->mi_acdirmin = SEC2HR(ACDIRMIN); 900*7c478bd9Sstevel@tonic-gate mi->mi_acdirmax = SEC2HR(ACDIRMAX); 901*7c478bd9Sstevel@tonic-gate 902*7c478bd9Sstevel@tonic-gate if (nfs_dynamic) 903*7c478bd9Sstevel@tonic-gate mi->mi_flags |= MI_DYNAMIC; 904*7c478bd9Sstevel@tonic-gate 905*7c478bd9Sstevel@tonic-gate if (flags & NFSMNT_DIRECTIO) 906*7c478bd9Sstevel@tonic-gate mi->mi_flags |= MI_DIRECTIO; 907*7c478bd9Sstevel@tonic-gate 908*7c478bd9Sstevel@tonic-gate /* 909*7c478bd9Sstevel@tonic-gate * Make a vfs struct for nfs. We do this here instead of below 910*7c478bd9Sstevel@tonic-gate * because rtvp needs a vfs before we can do a getattr on it. 911*7c478bd9Sstevel@tonic-gate * 912*7c478bd9Sstevel@tonic-gate * Assign a unique device id to the mount 913*7c478bd9Sstevel@tonic-gate */ 914*7c478bd9Sstevel@tonic-gate mutex_enter(&nfs_minor_lock); 915*7c478bd9Sstevel@tonic-gate do { 916*7c478bd9Sstevel@tonic-gate nfs_minor = (nfs_minor + 1) & MAXMIN32; 917*7c478bd9Sstevel@tonic-gate nfs_dev = makedevice(nfs_major, nfs_minor); 918*7c478bd9Sstevel@tonic-gate } while (vfs_devismounted(nfs_dev)); 919*7c478bd9Sstevel@tonic-gate mutex_exit(&nfs_minor_lock); 920*7c478bd9Sstevel@tonic-gate 921*7c478bd9Sstevel@tonic-gate vfsp->vfs_dev = nfs_dev; 922*7c478bd9Sstevel@tonic-gate vfs_make_fsid(&vfsp->vfs_fsid, nfs_dev, nfsfstyp); 923*7c478bd9Sstevel@tonic-gate vfsp->vfs_data = (caddr_t)mi; 924*7c478bd9Sstevel@tonic-gate vfsp->vfs_fstype = nfsfstyp; 925*7c478bd9Sstevel@tonic-gate vfsp->vfs_bsize = NFS_MAXDATA; 926*7c478bd9Sstevel@tonic-gate 927*7c478bd9Sstevel@tonic-gate /* 928*7c478bd9Sstevel@tonic-gate * Initialize fields used to support async putpage operations. 929*7c478bd9Sstevel@tonic-gate */ 930*7c478bd9Sstevel@tonic-gate for (i = 0; i < NFS_ASYNC_TYPES; i++) 931*7c478bd9Sstevel@tonic-gate mi->mi_async_clusters[i] = nfs_async_clusters; 932*7c478bd9Sstevel@tonic-gate mi->mi_async_init_clusters = nfs_async_clusters; 933*7c478bd9Sstevel@tonic-gate mi->mi_async_curr = &mi->mi_async_reqs[0]; 934*7c478bd9Sstevel@tonic-gate mi->mi_max_threads = nfs_max_threads; 935*7c478bd9Sstevel@tonic-gate mutex_init(&mi->mi_async_lock, NULL, MUTEX_DEFAULT, NULL); 936*7c478bd9Sstevel@tonic-gate cv_init(&mi->mi_async_reqs_cv, NULL, CV_DEFAULT, NULL); 937*7c478bd9Sstevel@tonic-gate cv_init(&mi->mi_async_work_cv, NULL, CV_DEFAULT, NULL); 938*7c478bd9Sstevel@tonic-gate cv_init(&mi->mi_async_cv, NULL, CV_DEFAULT, NULL); 939*7c478bd9Sstevel@tonic-gate 940*7c478bd9Sstevel@tonic-gate mi->mi_vfsp = vfsp; 941*7c478bd9Sstevel@tonic-gate zone_hold(mi->mi_zone = zone); 942*7c478bd9Sstevel@tonic-gate nfs_mi_zonelist_add(mi); 943*7c478bd9Sstevel@tonic-gate 944*7c478bd9Sstevel@tonic-gate /* 945*7c478bd9Sstevel@tonic-gate * Make the root vnode, use it to get attributes, 946*7c478bd9Sstevel@tonic-gate * then remake it with the attributes. 947*7c478bd9Sstevel@tonic-gate */ 948*7c478bd9Sstevel@tonic-gate rtvp = makenfsnode((fhandle_t *)svp->sv_fhandle.fh_buf, 949*7c478bd9Sstevel@tonic-gate NULL, vfsp, gethrtime(), cr, NULL, NULL); 950*7c478bd9Sstevel@tonic-gate 951*7c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 952*7c478bd9Sstevel@tonic-gate 953*7c478bd9Sstevel@tonic-gate /* 954*7c478bd9Sstevel@tonic-gate * If the uid is set then set the creds for secure mounts 955*7c478bd9Sstevel@tonic-gate * by proxy processes such as automountd. 956*7c478bd9Sstevel@tonic-gate */ 957*7c478bd9Sstevel@tonic-gate if (svp->sv_secdata->uid != 0 && 958*7c478bd9Sstevel@tonic-gate svp->sv_secdata->rpcflavor == RPCSEC_GSS) { 959*7c478bd9Sstevel@tonic-gate lcr = crdup(cr); 960*7c478bd9Sstevel@tonic-gate (void) crsetugid(lcr, svp->sv_secdata->uid, crgetgid(cr)); 961*7c478bd9Sstevel@tonic-gate tcr = lcr; 962*7c478bd9Sstevel@tonic-gate } 963*7c478bd9Sstevel@tonic-gate 964*7c478bd9Sstevel@tonic-gate error = nfsgetattr(rtvp, &va, tcr); 965*7c478bd9Sstevel@tonic-gate if (error) 966*7c478bd9Sstevel@tonic-gate goto bad; 967*7c478bd9Sstevel@tonic-gate rtvp->v_type = va.va_type; 968*7c478bd9Sstevel@tonic-gate 969*7c478bd9Sstevel@tonic-gate /* 970*7c478bd9Sstevel@tonic-gate * Poll every server to get the filesystem stats; we're 971*7c478bd9Sstevel@tonic-gate * only interested in the server's transfer size, and we 972*7c478bd9Sstevel@tonic-gate * want the minimum. 973*7c478bd9Sstevel@tonic-gate * 974*7c478bd9Sstevel@tonic-gate * While we're looping, we'll turn off AUTH_F_TRYNONE, 975*7c478bd9Sstevel@tonic-gate * which is only for the mount operation. 976*7c478bd9Sstevel@tonic-gate */ 977*7c478bd9Sstevel@tonic-gate 978*7c478bd9Sstevel@tonic-gate mi->mi_tsize = MIN(NFS_MAXDATA, nfstsize()); 979*7c478bd9Sstevel@tonic-gate mi->mi_stsize = MIN(NFS_MAXDATA, nfstsize()); 980*7c478bd9Sstevel@tonic-gate 981*7c478bd9Sstevel@tonic-gate for (svp = mi->mi_servers; svp != NULL; svp = svp->sv_next) { 982*7c478bd9Sstevel@tonic-gate struct nfsstatfs fs; 983*7c478bd9Sstevel@tonic-gate int douprintf; 984*7c478bd9Sstevel@tonic-gate 985*7c478bd9Sstevel@tonic-gate douprintf = 1; 986*7c478bd9Sstevel@tonic-gate mi->mi_curr_serv = svp; 987*7c478bd9Sstevel@tonic-gate 988*7c478bd9Sstevel@tonic-gate error = rfs2call(mi, RFS_STATFS, 989*7c478bd9Sstevel@tonic-gate xdr_fhandle, (caddr_t)svp->sv_fhandle.fh_buf, 990*7c478bd9Sstevel@tonic-gate xdr_statfs, (caddr_t)&fs, tcr, &douprintf, 991*7c478bd9Sstevel@tonic-gate &fs.fs_status, 0, NULL); 992*7c478bd9Sstevel@tonic-gate if (error) 993*7c478bd9Sstevel@tonic-gate goto bad; 994*7c478bd9Sstevel@tonic-gate mi->mi_stsize = MIN(mi->mi_stsize, fs.fs_tsize); 995*7c478bd9Sstevel@tonic-gate svp->sv_secdata->flags &= ~AUTH_F_TRYNONE; 996*7c478bd9Sstevel@tonic-gate } 997*7c478bd9Sstevel@tonic-gate mi->mi_curr_serv = mi->mi_servers; 998*7c478bd9Sstevel@tonic-gate mi->mi_curread = mi->mi_tsize; 999*7c478bd9Sstevel@tonic-gate mi->mi_curwrite = mi->mi_stsize; 1000*7c478bd9Sstevel@tonic-gate 1001*7c478bd9Sstevel@tonic-gate /* 1002*7c478bd9Sstevel@tonic-gate * Start the manager thread responsible for handling async worker 1003*7c478bd9Sstevel@tonic-gate * threads. 1004*7c478bd9Sstevel@tonic-gate */ 1005*7c478bd9Sstevel@tonic-gate VFS_HOLD(vfsp); /* add reference for thread */ 1006*7c478bd9Sstevel@tonic-gate mi->mi_manager_thread = zthread_create(NULL, 0, nfs_async_manager, 1007*7c478bd9Sstevel@tonic-gate vfsp, 0, minclsyspri); 1008*7c478bd9Sstevel@tonic-gate ASSERT(mi->mi_manager_thread != NULL); 1009*7c478bd9Sstevel@tonic-gate 1010*7c478bd9Sstevel@tonic-gate /* 1011*7c478bd9Sstevel@tonic-gate * Initialize kstats 1012*7c478bd9Sstevel@tonic-gate */ 1013*7c478bd9Sstevel@tonic-gate nfs_mnt_kstat_init(vfsp); 1014*7c478bd9Sstevel@tonic-gate 1015*7c478bd9Sstevel@tonic-gate mi->mi_type = rtvp->v_type; 1016*7c478bd9Sstevel@tonic-gate 1017*7c478bd9Sstevel@tonic-gate *rtvpp = rtvp; 1018*7c478bd9Sstevel@tonic-gate if (lcr != NULL) 1019*7c478bd9Sstevel@tonic-gate crfree(lcr); 1020*7c478bd9Sstevel@tonic-gate 1021*7c478bd9Sstevel@tonic-gate return (0); 1022*7c478bd9Sstevel@tonic-gate bad: 1023*7c478bd9Sstevel@tonic-gate /* 1024*7c478bd9Sstevel@tonic-gate * An error occurred somewhere, need to clean up... 1025*7c478bd9Sstevel@tonic-gate * We need to release our reference to the root vnode and 1026*7c478bd9Sstevel@tonic-gate * destroy the mntinfo struct that we just created. 1027*7c478bd9Sstevel@tonic-gate */ 1028*7c478bd9Sstevel@tonic-gate if (lcr != NULL) 1029*7c478bd9Sstevel@tonic-gate crfree(lcr); 1030*7c478bd9Sstevel@tonic-gate rp = VTOR(rtvp); 1031*7c478bd9Sstevel@tonic-gate if (rp->r_flags & RHASHED) 1032*7c478bd9Sstevel@tonic-gate rp_rmhash(rp); 1033*7c478bd9Sstevel@tonic-gate VN_RELE(rtvp); 1034*7c478bd9Sstevel@tonic-gate nfs_async_stop(vfsp); 1035*7c478bd9Sstevel@tonic-gate nfs_async_manager_stop(vfsp); 1036*7c478bd9Sstevel@tonic-gate if (mi->mi_io_kstats) { 1037*7c478bd9Sstevel@tonic-gate kstat_delete(mi->mi_io_kstats); 1038*7c478bd9Sstevel@tonic-gate mi->mi_io_kstats = NULL; 1039*7c478bd9Sstevel@tonic-gate } 1040*7c478bd9Sstevel@tonic-gate if (mi->mi_ro_kstats) { 1041*7c478bd9Sstevel@tonic-gate kstat_delete(mi->mi_ro_kstats); 1042*7c478bd9Sstevel@tonic-gate mi->mi_ro_kstats = NULL; 1043*7c478bd9Sstevel@tonic-gate } 1044*7c478bd9Sstevel@tonic-gate nfs_free_mi(mi); 1045*7c478bd9Sstevel@tonic-gate *rtvpp = NULL; 1046*7c478bd9Sstevel@tonic-gate return (error); 1047*7c478bd9Sstevel@tonic-gate } 1048*7c478bd9Sstevel@tonic-gate 1049*7c478bd9Sstevel@tonic-gate /* 1050*7c478bd9Sstevel@tonic-gate * vfs operations 1051*7c478bd9Sstevel@tonic-gate */ 1052*7c478bd9Sstevel@tonic-gate static int 1053*7c478bd9Sstevel@tonic-gate nfs_unmount(vfs_t *vfsp, int flag, cred_t *cr) 1054*7c478bd9Sstevel@tonic-gate { 1055*7c478bd9Sstevel@tonic-gate mntinfo_t *mi; 1056*7c478bd9Sstevel@tonic-gate ushort_t omax; 1057*7c478bd9Sstevel@tonic-gate 1058*7c478bd9Sstevel@tonic-gate if (secpolicy_fs_unmount(cr, vfsp) != 0) 1059*7c478bd9Sstevel@tonic-gate return (EPERM); 1060*7c478bd9Sstevel@tonic-gate 1061*7c478bd9Sstevel@tonic-gate mi = VFTOMI(vfsp); 1062*7c478bd9Sstevel@tonic-gate if (flag & MS_FORCE) { 1063*7c478bd9Sstevel@tonic-gate vfsp->vfs_flag |= VFS_UNMOUNTED; 1064*7c478bd9Sstevel@tonic-gate /* 1065*7c478bd9Sstevel@tonic-gate * We need to stop the manager thread explicitly; the worker 1066*7c478bd9Sstevel@tonic-gate * threads can time out and exit on their own. 1067*7c478bd9Sstevel@tonic-gate */ 1068*7c478bd9Sstevel@tonic-gate nfs_async_manager_stop(vfsp); 1069*7c478bd9Sstevel@tonic-gate destroy_rtable(vfsp, cr); 1070*7c478bd9Sstevel@tonic-gate if (mi->mi_io_kstats) { 1071*7c478bd9Sstevel@tonic-gate kstat_delete(mi->mi_io_kstats); 1072*7c478bd9Sstevel@tonic-gate mi->mi_io_kstats = NULL; 1073*7c478bd9Sstevel@tonic-gate } 1074*7c478bd9Sstevel@tonic-gate if (mi->mi_ro_kstats) { 1075*7c478bd9Sstevel@tonic-gate kstat_delete(mi->mi_ro_kstats); 1076*7c478bd9Sstevel@tonic-gate mi->mi_ro_kstats = NULL; 1077*7c478bd9Sstevel@tonic-gate } 1078*7c478bd9Sstevel@tonic-gate return (0); 1079*7c478bd9Sstevel@tonic-gate } 1080*7c478bd9Sstevel@tonic-gate /* 1081*7c478bd9Sstevel@tonic-gate * Wait until all asynchronous putpage operations on 1082*7c478bd9Sstevel@tonic-gate * this file system are complete before flushing rnodes 1083*7c478bd9Sstevel@tonic-gate * from the cache. 1084*7c478bd9Sstevel@tonic-gate */ 1085*7c478bd9Sstevel@tonic-gate omax = mi->mi_max_threads; 1086*7c478bd9Sstevel@tonic-gate if (nfs_async_stop_sig(vfsp)) { 1087*7c478bd9Sstevel@tonic-gate return (EINTR); 1088*7c478bd9Sstevel@tonic-gate } 1089*7c478bd9Sstevel@tonic-gate rflush(vfsp, cr); 1090*7c478bd9Sstevel@tonic-gate /* 1091*7c478bd9Sstevel@tonic-gate * If there are any active vnodes on this file system, 1092*7c478bd9Sstevel@tonic-gate * then the file system is busy and can't be umounted. 1093*7c478bd9Sstevel@tonic-gate */ 1094*7c478bd9Sstevel@tonic-gate if (check_rtable(vfsp)) { 1095*7c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_async_lock); 1096*7c478bd9Sstevel@tonic-gate mi->mi_max_threads = omax; 1097*7c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_async_lock); 1098*7c478bd9Sstevel@tonic-gate return (EBUSY); 1099*7c478bd9Sstevel@tonic-gate } 1100*7c478bd9Sstevel@tonic-gate /* 1101*7c478bd9Sstevel@tonic-gate * The unmount can't fail from now on; stop the manager thread. 1102*7c478bd9Sstevel@tonic-gate */ 1103*7c478bd9Sstevel@tonic-gate nfs_async_manager_stop(vfsp); 1104*7c478bd9Sstevel@tonic-gate /* 1105*7c478bd9Sstevel@tonic-gate * Destroy all rnodes belonging to this file system from the 1106*7c478bd9Sstevel@tonic-gate * rnode hash queues and purge any resources allocated to 1107*7c478bd9Sstevel@tonic-gate * them. 1108*7c478bd9Sstevel@tonic-gate */ 1109*7c478bd9Sstevel@tonic-gate destroy_rtable(vfsp, cr); 1110*7c478bd9Sstevel@tonic-gate if (mi->mi_io_kstats) { 1111*7c478bd9Sstevel@tonic-gate kstat_delete(mi->mi_io_kstats); 1112*7c478bd9Sstevel@tonic-gate mi->mi_io_kstats = NULL; 1113*7c478bd9Sstevel@tonic-gate } 1114*7c478bd9Sstevel@tonic-gate if (mi->mi_ro_kstats) { 1115*7c478bd9Sstevel@tonic-gate kstat_delete(mi->mi_ro_kstats); 1116*7c478bd9Sstevel@tonic-gate mi->mi_ro_kstats = NULL; 1117*7c478bd9Sstevel@tonic-gate } 1118*7c478bd9Sstevel@tonic-gate return (0); 1119*7c478bd9Sstevel@tonic-gate } 1120*7c478bd9Sstevel@tonic-gate 1121*7c478bd9Sstevel@tonic-gate /* 1122*7c478bd9Sstevel@tonic-gate * find root of nfs 1123*7c478bd9Sstevel@tonic-gate */ 1124*7c478bd9Sstevel@tonic-gate static int 1125*7c478bd9Sstevel@tonic-gate nfs_root(vfs_t *vfsp, vnode_t **vpp) 1126*7c478bd9Sstevel@tonic-gate { 1127*7c478bd9Sstevel@tonic-gate mntinfo_t *mi; 1128*7c478bd9Sstevel@tonic-gate vnode_t *vp; 1129*7c478bd9Sstevel@tonic-gate servinfo_t *svp; 1130*7c478bd9Sstevel@tonic-gate 1131*7c478bd9Sstevel@tonic-gate mi = VFTOMI(vfsp); 1132*7c478bd9Sstevel@tonic-gate 1133*7c478bd9Sstevel@tonic-gate if (curproc->p_zone != mi->mi_zone) 1134*7c478bd9Sstevel@tonic-gate return (EPERM); 1135*7c478bd9Sstevel@tonic-gate 1136*7c478bd9Sstevel@tonic-gate svp = mi->mi_curr_serv; 1137*7c478bd9Sstevel@tonic-gate if (svp && (svp->sv_flags & SV_ROOT_STALE)) { 1138*7c478bd9Sstevel@tonic-gate mutex_enter(&svp->sv_lock); 1139*7c478bd9Sstevel@tonic-gate svp->sv_flags &= ~SV_ROOT_STALE; 1140*7c478bd9Sstevel@tonic-gate mutex_exit(&svp->sv_lock); 1141*7c478bd9Sstevel@tonic-gate return (ENOENT); 1142*7c478bd9Sstevel@tonic-gate } 1143*7c478bd9Sstevel@tonic-gate 1144*7c478bd9Sstevel@tonic-gate vp = makenfsnode((fhandle_t *)mi->mi_curr_serv->sv_fhandle.fh_buf, 1145*7c478bd9Sstevel@tonic-gate NULL, vfsp, gethrtime(), CRED(), NULL, NULL); 1146*7c478bd9Sstevel@tonic-gate 1147*7c478bd9Sstevel@tonic-gate if (VTOR(vp)->r_flags & RSTALE) { 1148*7c478bd9Sstevel@tonic-gate VN_RELE(vp); 1149*7c478bd9Sstevel@tonic-gate return (ENOENT); 1150*7c478bd9Sstevel@tonic-gate } 1151*7c478bd9Sstevel@tonic-gate 1152*7c478bd9Sstevel@tonic-gate ASSERT(vp->v_type == VNON || vp->v_type == mi->mi_type); 1153*7c478bd9Sstevel@tonic-gate 1154*7c478bd9Sstevel@tonic-gate vp->v_type = mi->mi_type; 1155*7c478bd9Sstevel@tonic-gate 1156*7c478bd9Sstevel@tonic-gate *vpp = vp; 1157*7c478bd9Sstevel@tonic-gate 1158*7c478bd9Sstevel@tonic-gate return (0); 1159*7c478bd9Sstevel@tonic-gate } 1160*7c478bd9Sstevel@tonic-gate 1161*7c478bd9Sstevel@tonic-gate /* 1162*7c478bd9Sstevel@tonic-gate * Get file system statistics. 1163*7c478bd9Sstevel@tonic-gate */ 1164*7c478bd9Sstevel@tonic-gate static int 1165*7c478bd9Sstevel@tonic-gate nfs_statvfs(vfs_t *vfsp, struct statvfs64 *sbp) 1166*7c478bd9Sstevel@tonic-gate { 1167*7c478bd9Sstevel@tonic-gate int error; 1168*7c478bd9Sstevel@tonic-gate mntinfo_t *mi; 1169*7c478bd9Sstevel@tonic-gate struct nfsstatfs fs; 1170*7c478bd9Sstevel@tonic-gate int douprintf; 1171*7c478bd9Sstevel@tonic-gate failinfo_t fi; 1172*7c478bd9Sstevel@tonic-gate vnode_t *vp; 1173*7c478bd9Sstevel@tonic-gate 1174*7c478bd9Sstevel@tonic-gate error = nfs_root(vfsp, &vp); 1175*7c478bd9Sstevel@tonic-gate if (error) 1176*7c478bd9Sstevel@tonic-gate return (error); 1177*7c478bd9Sstevel@tonic-gate 1178*7c478bd9Sstevel@tonic-gate mi = VFTOMI(vfsp); 1179*7c478bd9Sstevel@tonic-gate douprintf = 1; 1180*7c478bd9Sstevel@tonic-gate fi.vp = vp; 1181*7c478bd9Sstevel@tonic-gate fi.fhp = NULL; /* no need to update, filehandle not copied */ 1182*7c478bd9Sstevel@tonic-gate fi.copyproc = nfscopyfh; 1183*7c478bd9Sstevel@tonic-gate fi.lookupproc = nfslookup; 1184*7c478bd9Sstevel@tonic-gate fi.xattrdirproc = acl_getxattrdir2; 1185*7c478bd9Sstevel@tonic-gate 1186*7c478bd9Sstevel@tonic-gate error = rfs2call(mi, RFS_STATFS, 1187*7c478bd9Sstevel@tonic-gate xdr_fhandle, (caddr_t)VTOFH(vp), 1188*7c478bd9Sstevel@tonic-gate xdr_statfs, (caddr_t)&fs, CRED(), &douprintf, 1189*7c478bd9Sstevel@tonic-gate &fs.fs_status, 0, &fi); 1190*7c478bd9Sstevel@tonic-gate 1191*7c478bd9Sstevel@tonic-gate if (!error) { 1192*7c478bd9Sstevel@tonic-gate error = geterrno(fs.fs_status); 1193*7c478bd9Sstevel@tonic-gate if (!error) { 1194*7c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 1195*7c478bd9Sstevel@tonic-gate if (mi->mi_stsize) { 1196*7c478bd9Sstevel@tonic-gate mi->mi_stsize = MIN(mi->mi_stsize, fs.fs_tsize); 1197*7c478bd9Sstevel@tonic-gate } else { 1198*7c478bd9Sstevel@tonic-gate mi->mi_stsize = fs.fs_tsize; 1199*7c478bd9Sstevel@tonic-gate mi->mi_curwrite = mi->mi_stsize; 1200*7c478bd9Sstevel@tonic-gate } 1201*7c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 1202*7c478bd9Sstevel@tonic-gate sbp->f_bsize = fs.fs_bsize; 1203*7c478bd9Sstevel@tonic-gate sbp->f_frsize = fs.fs_bsize; 1204*7c478bd9Sstevel@tonic-gate sbp->f_blocks = (fsblkcnt64_t)fs.fs_blocks; 1205*7c478bd9Sstevel@tonic-gate sbp->f_bfree = (fsblkcnt64_t)fs.fs_bfree; 1206*7c478bd9Sstevel@tonic-gate /* 1207*7c478bd9Sstevel@tonic-gate * Some servers may return negative available 1208*7c478bd9Sstevel@tonic-gate * block counts. They may do this because they 1209*7c478bd9Sstevel@tonic-gate * calculate the number of available blocks by 1210*7c478bd9Sstevel@tonic-gate * subtracting the number of used blocks from 1211*7c478bd9Sstevel@tonic-gate * the total number of blocks modified by the 1212*7c478bd9Sstevel@tonic-gate * minimum free value. For example, if the 1213*7c478bd9Sstevel@tonic-gate * minumum free percentage is 10 and the file 1214*7c478bd9Sstevel@tonic-gate * system is greater than 90 percent full, then 1215*7c478bd9Sstevel@tonic-gate * 90 percent of the total blocks minus the 1216*7c478bd9Sstevel@tonic-gate * actual number of used blocks may be a 1217*7c478bd9Sstevel@tonic-gate * negative number. 1218*7c478bd9Sstevel@tonic-gate * 1219*7c478bd9Sstevel@tonic-gate * In this case, we need to sign extend the 1220*7c478bd9Sstevel@tonic-gate * negative number through the assignment from 1221*7c478bd9Sstevel@tonic-gate * the 32 bit bavail count to the 64 bit bavail 1222*7c478bd9Sstevel@tonic-gate * count. 1223*7c478bd9Sstevel@tonic-gate * 1224*7c478bd9Sstevel@tonic-gate * We need to be able to discern between there 1225*7c478bd9Sstevel@tonic-gate * just being a lot of available blocks on the 1226*7c478bd9Sstevel@tonic-gate * file system and the case described above. 1227*7c478bd9Sstevel@tonic-gate * We are making the assumption that it does 1228*7c478bd9Sstevel@tonic-gate * not make sense to have more available blocks 1229*7c478bd9Sstevel@tonic-gate * than there are free blocks. So, if there 1230*7c478bd9Sstevel@tonic-gate * are, then we treat the number as if it were 1231*7c478bd9Sstevel@tonic-gate * a negative number and arrange to have it 1232*7c478bd9Sstevel@tonic-gate * sign extended when it is converted from 32 1233*7c478bd9Sstevel@tonic-gate * bits to 64 bits. 1234*7c478bd9Sstevel@tonic-gate */ 1235*7c478bd9Sstevel@tonic-gate if (fs.fs_bavail <= fs.fs_bfree) 1236*7c478bd9Sstevel@tonic-gate sbp->f_bavail = (fsblkcnt64_t)fs.fs_bavail; 1237*7c478bd9Sstevel@tonic-gate else { 1238*7c478bd9Sstevel@tonic-gate sbp->f_bavail = 1239*7c478bd9Sstevel@tonic-gate (fsblkcnt64_t)((long)fs.fs_bavail); 1240*7c478bd9Sstevel@tonic-gate } 1241*7c478bd9Sstevel@tonic-gate sbp->f_files = (fsfilcnt64_t)-1; 1242*7c478bd9Sstevel@tonic-gate sbp->f_ffree = (fsfilcnt64_t)-1; 1243*7c478bd9Sstevel@tonic-gate sbp->f_favail = (fsfilcnt64_t)-1; 1244*7c478bd9Sstevel@tonic-gate sbp->f_fsid = (unsigned long)vfsp->vfs_fsid.val[0]; 1245*7c478bd9Sstevel@tonic-gate (void) strncpy(sbp->f_basetype, 1246*7c478bd9Sstevel@tonic-gate vfssw[vfsp->vfs_fstype].vsw_name, FSTYPSZ); 1247*7c478bd9Sstevel@tonic-gate sbp->f_flag = vf_to_stf(vfsp->vfs_flag); 1248*7c478bd9Sstevel@tonic-gate sbp->f_namemax = (uint32_t)-1; 1249*7c478bd9Sstevel@tonic-gate } else { 1250*7c478bd9Sstevel@tonic-gate PURGE_STALE_FH(error, vp, CRED()); 1251*7c478bd9Sstevel@tonic-gate } 1252*7c478bd9Sstevel@tonic-gate } 1253*7c478bd9Sstevel@tonic-gate 1254*7c478bd9Sstevel@tonic-gate VN_RELE(vp); 1255*7c478bd9Sstevel@tonic-gate 1256*7c478bd9Sstevel@tonic-gate return (error); 1257*7c478bd9Sstevel@tonic-gate } 1258*7c478bd9Sstevel@tonic-gate 1259*7c478bd9Sstevel@tonic-gate static kmutex_t nfs_syncbusy; 1260*7c478bd9Sstevel@tonic-gate 1261*7c478bd9Sstevel@tonic-gate /* 1262*7c478bd9Sstevel@tonic-gate * Flush dirty nfs files for file system vfsp. 1263*7c478bd9Sstevel@tonic-gate * If vfsp == NULL, all nfs files are flushed. 1264*7c478bd9Sstevel@tonic-gate */ 1265*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1266*7c478bd9Sstevel@tonic-gate static int 1267*7c478bd9Sstevel@tonic-gate nfs_sync(vfs_t *vfsp, short flag, cred_t *cr) 1268*7c478bd9Sstevel@tonic-gate { 1269*7c478bd9Sstevel@tonic-gate /* 1270*7c478bd9Sstevel@tonic-gate * Cross-zone calls are OK here, since this translates to a 1271*7c478bd9Sstevel@tonic-gate * VOP_PUTPAGE(B_ASYNC), which gets picked up by the right zone. 1272*7c478bd9Sstevel@tonic-gate */ 1273*7c478bd9Sstevel@tonic-gate if (!(flag & SYNC_ATTR) && mutex_tryenter(&nfs_syncbusy) != 0) { 1274*7c478bd9Sstevel@tonic-gate rflush(vfsp, cr); 1275*7c478bd9Sstevel@tonic-gate mutex_exit(&nfs_syncbusy); 1276*7c478bd9Sstevel@tonic-gate } 1277*7c478bd9Sstevel@tonic-gate return (0); 1278*7c478bd9Sstevel@tonic-gate } 1279*7c478bd9Sstevel@tonic-gate 1280*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1281*7c478bd9Sstevel@tonic-gate static int 1282*7c478bd9Sstevel@tonic-gate nfs_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp) 1283*7c478bd9Sstevel@tonic-gate { 1284*7c478bd9Sstevel@tonic-gate int error; 1285*7c478bd9Sstevel@tonic-gate vnode_t *vp; 1286*7c478bd9Sstevel@tonic-gate struct vattr va; 1287*7c478bd9Sstevel@tonic-gate struct nfs_fid *nfsfidp = (struct nfs_fid *)fidp; 1288*7c478bd9Sstevel@tonic-gate zoneid_t zoneid = VFTOMI(vfsp)->mi_zone->zone_id; 1289*7c478bd9Sstevel@tonic-gate 1290*7c478bd9Sstevel@tonic-gate if (curproc->p_zone != VFTOMI(vfsp)->mi_zone) 1291*7c478bd9Sstevel@tonic-gate return (EPERM); 1292*7c478bd9Sstevel@tonic-gate if (fidp->fid_len != (sizeof (*nfsfidp) - sizeof (short))) { 1293*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1294*7c478bd9Sstevel@tonic-gate zcmn_err(zoneid, CE_WARN, 1295*7c478bd9Sstevel@tonic-gate "nfs_vget: bad fid len, %d/%d", fidp->fid_len, 1296*7c478bd9Sstevel@tonic-gate (int)(sizeof (*nfsfidp) - sizeof (short))); 1297*7c478bd9Sstevel@tonic-gate #endif 1298*7c478bd9Sstevel@tonic-gate *vpp = NULL; 1299*7c478bd9Sstevel@tonic-gate return (ESTALE); 1300*7c478bd9Sstevel@tonic-gate } 1301*7c478bd9Sstevel@tonic-gate 1302*7c478bd9Sstevel@tonic-gate vp = makenfsnode((fhandle_t *)(nfsfidp->nf_data), NULL, vfsp, 1303*7c478bd9Sstevel@tonic-gate gethrtime(), CRED(), NULL, NULL); 1304*7c478bd9Sstevel@tonic-gate 1305*7c478bd9Sstevel@tonic-gate if (VTOR(vp)->r_flags & RSTALE) { 1306*7c478bd9Sstevel@tonic-gate VN_RELE(vp); 1307*7c478bd9Sstevel@tonic-gate *vpp = NULL; 1308*7c478bd9Sstevel@tonic-gate return (ENOENT); 1309*7c478bd9Sstevel@tonic-gate } 1310*7c478bd9Sstevel@tonic-gate 1311*7c478bd9Sstevel@tonic-gate if (vp->v_type == VNON) { 1312*7c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 1313*7c478bd9Sstevel@tonic-gate error = nfsgetattr(vp, &va, CRED()); 1314*7c478bd9Sstevel@tonic-gate if (error) { 1315*7c478bd9Sstevel@tonic-gate VN_RELE(vp); 1316*7c478bd9Sstevel@tonic-gate *vpp = NULL; 1317*7c478bd9Sstevel@tonic-gate return (error); 1318*7c478bd9Sstevel@tonic-gate } 1319*7c478bd9Sstevel@tonic-gate vp->v_type = va.va_type; 1320*7c478bd9Sstevel@tonic-gate } 1321*7c478bd9Sstevel@tonic-gate 1322*7c478bd9Sstevel@tonic-gate *vpp = vp; 1323*7c478bd9Sstevel@tonic-gate 1324*7c478bd9Sstevel@tonic-gate return (0); 1325*7c478bd9Sstevel@tonic-gate } 1326*7c478bd9Sstevel@tonic-gate 1327*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1328*7c478bd9Sstevel@tonic-gate static int 1329*7c478bd9Sstevel@tonic-gate nfs_mountroot(vfs_t *vfsp, whymountroot_t why) 1330*7c478bd9Sstevel@tonic-gate { 1331*7c478bd9Sstevel@tonic-gate vnode_t *rtvp; 1332*7c478bd9Sstevel@tonic-gate char root_hostname[SYS_NMLN+1]; 1333*7c478bd9Sstevel@tonic-gate struct servinfo *svp; 1334*7c478bd9Sstevel@tonic-gate int error; 1335*7c478bd9Sstevel@tonic-gate int vfsflags; 1336*7c478bd9Sstevel@tonic-gate size_t size; 1337*7c478bd9Sstevel@tonic-gate char *root_path; 1338*7c478bd9Sstevel@tonic-gate struct pathname pn; 1339*7c478bd9Sstevel@tonic-gate char *name; 1340*7c478bd9Sstevel@tonic-gate cred_t *cr; 1341*7c478bd9Sstevel@tonic-gate struct nfs_args args; /* nfs mount arguments */ 1342*7c478bd9Sstevel@tonic-gate static char token[10]; 1343*7c478bd9Sstevel@tonic-gate 1344*7c478bd9Sstevel@tonic-gate bzero(&args, sizeof (args)); 1345*7c478bd9Sstevel@tonic-gate 1346*7c478bd9Sstevel@tonic-gate /* do this BEFORE getfile which causes xid stamps to be initialized */ 1347*7c478bd9Sstevel@tonic-gate clkset(-1L); /* hack for now - until we get time svc? */ 1348*7c478bd9Sstevel@tonic-gate 1349*7c478bd9Sstevel@tonic-gate if (why == ROOT_REMOUNT) { 1350*7c478bd9Sstevel@tonic-gate /* 1351*7c478bd9Sstevel@tonic-gate * Shouldn't happen. 1352*7c478bd9Sstevel@tonic-gate */ 1353*7c478bd9Sstevel@tonic-gate panic("nfs_mountroot: why == ROOT_REMOUNT"); 1354*7c478bd9Sstevel@tonic-gate } 1355*7c478bd9Sstevel@tonic-gate 1356*7c478bd9Sstevel@tonic-gate if (why == ROOT_UNMOUNT) { 1357*7c478bd9Sstevel@tonic-gate /* 1358*7c478bd9Sstevel@tonic-gate * Nothing to do for NFS. 1359*7c478bd9Sstevel@tonic-gate */ 1360*7c478bd9Sstevel@tonic-gate return (0); 1361*7c478bd9Sstevel@tonic-gate } 1362*7c478bd9Sstevel@tonic-gate 1363*7c478bd9Sstevel@tonic-gate /* 1364*7c478bd9Sstevel@tonic-gate * why == ROOT_INIT 1365*7c478bd9Sstevel@tonic-gate */ 1366*7c478bd9Sstevel@tonic-gate 1367*7c478bd9Sstevel@tonic-gate name = token; 1368*7c478bd9Sstevel@tonic-gate *name = 0; 1369*7c478bd9Sstevel@tonic-gate getfsname("root", name, sizeof (token)); 1370*7c478bd9Sstevel@tonic-gate 1371*7c478bd9Sstevel@tonic-gate pn_alloc(&pn); 1372*7c478bd9Sstevel@tonic-gate root_path = pn.pn_path; 1373*7c478bd9Sstevel@tonic-gate 1374*7c478bd9Sstevel@tonic-gate svp = kmem_zalloc(sizeof (*svp), KM_SLEEP); 1375*7c478bd9Sstevel@tonic-gate svp->sv_knconf = kmem_zalloc(sizeof (*svp->sv_knconf), KM_SLEEP); 1376*7c478bd9Sstevel@tonic-gate svp->sv_knconf->knc_protofmly = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 1377*7c478bd9Sstevel@tonic-gate svp->sv_knconf->knc_proto = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 1378*7c478bd9Sstevel@tonic-gate 1379*7c478bd9Sstevel@tonic-gate /* 1380*7c478bd9Sstevel@tonic-gate * Get server address 1381*7c478bd9Sstevel@tonic-gate * Get the root fhandle 1382*7c478bd9Sstevel@tonic-gate * Get server's transport 1383*7c478bd9Sstevel@tonic-gate * Get server's hostname 1384*7c478bd9Sstevel@tonic-gate * Get options 1385*7c478bd9Sstevel@tonic-gate */ 1386*7c478bd9Sstevel@tonic-gate args.addr = &svp->sv_addr; 1387*7c478bd9Sstevel@tonic-gate args.fh = (char *)&svp->sv_fhandle.fh_buf; 1388*7c478bd9Sstevel@tonic-gate args.knconf = svp->sv_knconf; 1389*7c478bd9Sstevel@tonic-gate args.hostname = root_hostname; 1390*7c478bd9Sstevel@tonic-gate vfsflags = 0; 1391*7c478bd9Sstevel@tonic-gate if (error = mount_root(*name ? name : "root", root_path, NFS_VERSION, 1392*7c478bd9Sstevel@tonic-gate &args, &vfsflags)) { 1393*7c478bd9Sstevel@tonic-gate nfs_cmn_err(error, CE_WARN, 1394*7c478bd9Sstevel@tonic-gate "nfs_mountroot: mount_root failed: %m"); 1395*7c478bd9Sstevel@tonic-gate sv_free(svp); 1396*7c478bd9Sstevel@tonic-gate pn_free(&pn); 1397*7c478bd9Sstevel@tonic-gate return (error); 1398*7c478bd9Sstevel@tonic-gate } 1399*7c478bd9Sstevel@tonic-gate svp->sv_fhandle.fh_len = NFS_FHSIZE; 1400*7c478bd9Sstevel@tonic-gate svp->sv_hostnamelen = (int)(strlen(root_hostname) + 1); 1401*7c478bd9Sstevel@tonic-gate svp->sv_hostname = kmem_alloc(svp->sv_hostnamelen, KM_SLEEP); 1402*7c478bd9Sstevel@tonic-gate (void) strcpy(svp->sv_hostname, root_hostname); 1403*7c478bd9Sstevel@tonic-gate 1404*7c478bd9Sstevel@tonic-gate /* 1405*7c478bd9Sstevel@tonic-gate * Force root partition to always be mounted with AUTH_UNIX for now 1406*7c478bd9Sstevel@tonic-gate */ 1407*7c478bd9Sstevel@tonic-gate svp->sv_secdata = kmem_alloc(sizeof (*svp->sv_secdata), KM_SLEEP); 1408*7c478bd9Sstevel@tonic-gate svp->sv_secdata->secmod = AUTH_UNIX; 1409*7c478bd9Sstevel@tonic-gate svp->sv_secdata->rpcflavor = AUTH_UNIX; 1410*7c478bd9Sstevel@tonic-gate svp->sv_secdata->data = NULL; 1411*7c478bd9Sstevel@tonic-gate 1412*7c478bd9Sstevel@tonic-gate cr = crgetcred(); 1413*7c478bd9Sstevel@tonic-gate rtvp = NULL; 1414*7c478bd9Sstevel@tonic-gate 1415*7c478bd9Sstevel@tonic-gate error = nfsrootvp(&rtvp, vfsp, svp, args.flags, cr, global_zone); 1416*7c478bd9Sstevel@tonic-gate 1417*7c478bd9Sstevel@tonic-gate crfree(cr); 1418*7c478bd9Sstevel@tonic-gate 1419*7c478bd9Sstevel@tonic-gate if (error) { 1420*7c478bd9Sstevel@tonic-gate pn_free(&pn); 1421*7c478bd9Sstevel@tonic-gate goto errout; 1422*7c478bd9Sstevel@tonic-gate } 1423*7c478bd9Sstevel@tonic-gate 1424*7c478bd9Sstevel@tonic-gate error = nfs_setopts(rtvp, DATAMODEL_NATIVE, &args); 1425*7c478bd9Sstevel@tonic-gate if (error) { 1426*7c478bd9Sstevel@tonic-gate nfs_cmn_err(error, CE_WARN, 1427*7c478bd9Sstevel@tonic-gate "nfs_mountroot: invalid root mount options"); 1428*7c478bd9Sstevel@tonic-gate pn_free(&pn); 1429*7c478bd9Sstevel@tonic-gate goto errout; 1430*7c478bd9Sstevel@tonic-gate } 1431*7c478bd9Sstevel@tonic-gate 1432*7c478bd9Sstevel@tonic-gate (void) vfs_lock_wait(vfsp); 1433*7c478bd9Sstevel@tonic-gate vfs_add(NULL, vfsp, vfsflags); 1434*7c478bd9Sstevel@tonic-gate vfs_unlock(vfsp); 1435*7c478bd9Sstevel@tonic-gate 1436*7c478bd9Sstevel@tonic-gate size = strlen(svp->sv_hostname); 1437*7c478bd9Sstevel@tonic-gate (void) strcpy(rootfs.bo_name, svp->sv_hostname); 1438*7c478bd9Sstevel@tonic-gate rootfs.bo_name[size] = ':'; 1439*7c478bd9Sstevel@tonic-gate (void) strcpy(&rootfs.bo_name[size + 1], root_path); 1440*7c478bd9Sstevel@tonic-gate 1441*7c478bd9Sstevel@tonic-gate pn_free(&pn); 1442*7c478bd9Sstevel@tonic-gate 1443*7c478bd9Sstevel@tonic-gate errout: 1444*7c478bd9Sstevel@tonic-gate if (error) { 1445*7c478bd9Sstevel@tonic-gate sv_free(svp); 1446*7c478bd9Sstevel@tonic-gate nfs_async_stop(vfsp); 1447*7c478bd9Sstevel@tonic-gate nfs_async_manager_stop(vfsp); 1448*7c478bd9Sstevel@tonic-gate } 1449*7c478bd9Sstevel@tonic-gate 1450*7c478bd9Sstevel@tonic-gate if (rtvp != NULL) 1451*7c478bd9Sstevel@tonic-gate VN_RELE(rtvp); 1452*7c478bd9Sstevel@tonic-gate 1453*7c478bd9Sstevel@tonic-gate return (error); 1454*7c478bd9Sstevel@tonic-gate } 1455*7c478bd9Sstevel@tonic-gate 1456*7c478bd9Sstevel@tonic-gate /* 1457*7c478bd9Sstevel@tonic-gate * Initialization routine for VFS routines. Should only be called once 1458*7c478bd9Sstevel@tonic-gate */ 1459*7c478bd9Sstevel@tonic-gate int 1460*7c478bd9Sstevel@tonic-gate nfs_vfsinit(void) 1461*7c478bd9Sstevel@tonic-gate { 1462*7c478bd9Sstevel@tonic-gate mutex_init(&nfs_syncbusy, NULL, MUTEX_DEFAULT, NULL); 1463*7c478bd9Sstevel@tonic-gate return (0); 1464*7c478bd9Sstevel@tonic-gate } 1465*7c478bd9Sstevel@tonic-gate 1466*7c478bd9Sstevel@tonic-gate void 1467*7c478bd9Sstevel@tonic-gate nfs_vfsfini(void) 1468*7c478bd9Sstevel@tonic-gate { 1469*7c478bd9Sstevel@tonic-gate mutex_destroy(&nfs_syncbusy); 1470*7c478bd9Sstevel@tonic-gate } 1471*7c478bd9Sstevel@tonic-gate 1472*7c478bd9Sstevel@tonic-gate void 1473*7c478bd9Sstevel@tonic-gate nfs_freevfs(vfs_t *vfsp) 1474*7c478bd9Sstevel@tonic-gate { 1475*7c478bd9Sstevel@tonic-gate mntinfo_t *mi; 1476*7c478bd9Sstevel@tonic-gate servinfo_t *svp; 1477*7c478bd9Sstevel@tonic-gate 1478*7c478bd9Sstevel@tonic-gate /* free up the resources */ 1479*7c478bd9Sstevel@tonic-gate mi = VFTOMI(vfsp); 1480*7c478bd9Sstevel@tonic-gate pathconf_rele(mi); 1481*7c478bd9Sstevel@tonic-gate svp = mi->mi_servers; 1482*7c478bd9Sstevel@tonic-gate mi->mi_servers = mi->mi_curr_serv = NULL; 1483*7c478bd9Sstevel@tonic-gate sv_free(svp); 1484*7c478bd9Sstevel@tonic-gate 1485*7c478bd9Sstevel@tonic-gate /* 1486*7c478bd9Sstevel@tonic-gate * By this time we should have already deleted the 1487*7c478bd9Sstevel@tonic-gate * mi kstats in the unmount code. If they are still around 1488*7c478bd9Sstevel@tonic-gate * somethings wrong 1489*7c478bd9Sstevel@tonic-gate */ 1490*7c478bd9Sstevel@tonic-gate ASSERT(mi->mi_io_kstats == NULL); 1491*7c478bd9Sstevel@tonic-gate nfs_free_mi(mi); 1492*7c478bd9Sstevel@tonic-gate } 1493