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 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate /* 28*7c478bd9Sstevel@tonic-gate * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T. 29*7c478bd9Sstevel@tonic-gate * All Rights Reserved 30*7c478bd9Sstevel@tonic-gate */ 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 33*7c478bd9Sstevel@tonic-gate 34*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/cred.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/pathname.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/mount.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/statvfs.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/utsname.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 52*7c478bd9Sstevel@tonic-gate #include <sys/acl.h> 53*7c478bd9Sstevel@tonic-gate #include <sys/flock.h> 54*7c478bd9Sstevel@tonic-gate #include <sys/time.h> 55*7c478bd9Sstevel@tonic-gate #include <sys/disp.h> 56*7c478bd9Sstevel@tonic-gate #include <sys/policy.h> 57*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 58*7c478bd9Sstevel@tonic-gate #include <sys/netconfig.h> 59*7c478bd9Sstevel@tonic-gate #include <sys/dnlc.h> 60*7c478bd9Sstevel@tonic-gate #include <sys/list.h> 61*7c478bd9Sstevel@tonic-gate 62*7c478bd9Sstevel@tonic-gate #include <rpc/types.h> 63*7c478bd9Sstevel@tonic-gate #include <rpc/auth.h> 64*7c478bd9Sstevel@tonic-gate #include <rpc/rpcsec_gss.h> 65*7c478bd9Sstevel@tonic-gate #include <rpc/clnt.h> 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate #include <nfs/nfs.h> 68*7c478bd9Sstevel@tonic-gate #include <nfs/nfs_clnt.h> 69*7c478bd9Sstevel@tonic-gate #include <nfs/mount.h> 70*7c478bd9Sstevel@tonic-gate #include <nfs/nfs_acl.h> 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate #include <fs/fs_subr.h> 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate #include <nfs/nfs4.h> 75*7c478bd9Sstevel@tonic-gate #include <nfs/rnode4.h> 76*7c478bd9Sstevel@tonic-gate #include <nfs/nfs4_clnt.h> 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate /* 79*7c478bd9Sstevel@tonic-gate * Arguments passed to thread to free data structures from forced unmount. 80*7c478bd9Sstevel@tonic-gate */ 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate typedef struct { 83*7c478bd9Sstevel@tonic-gate vfs_t *fm_vfsp; 84*7c478bd9Sstevel@tonic-gate cred_t *fm_cr; 85*7c478bd9Sstevel@tonic-gate } freemountargs_t; 86*7c478bd9Sstevel@tonic-gate 87*7c478bd9Sstevel@tonic-gate static void async_free_mount(vfs_t *, cred_t *); 88*7c478bd9Sstevel@tonic-gate static void nfs4_free_mount(vfs_t *, cred_t *); 89*7c478bd9Sstevel@tonic-gate static void nfs4_free_mount_thread(freemountargs_t *); 90*7c478bd9Sstevel@tonic-gate static int nfs4_chkdup_servinfo4(servinfo4_t *, servinfo4_t *); 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate /* 93*7c478bd9Sstevel@tonic-gate * From rpcsec module (common/rpcsec). 94*7c478bd9Sstevel@tonic-gate */ 95*7c478bd9Sstevel@tonic-gate extern int sec_clnt_loadinfo(struct sec_data *, struct sec_data **, model_t); 96*7c478bd9Sstevel@tonic-gate extern void sec_clnt_freeinfo(struct sec_data *); 97*7c478bd9Sstevel@tonic-gate 98*7c478bd9Sstevel@tonic-gate /* 99*7c478bd9Sstevel@tonic-gate * The order and contents of this structure must be kept in sync with that of 100*7c478bd9Sstevel@tonic-gate * rfsreqcnt_v4_tmpl in nfs_stats.c 101*7c478bd9Sstevel@tonic-gate */ 102*7c478bd9Sstevel@tonic-gate static char *rfsnames_v4[] = { 103*7c478bd9Sstevel@tonic-gate "null", "compound", "reserved", "access", "close", "commit", "create", 104*7c478bd9Sstevel@tonic-gate "delegpurge", "delegreturn", "getattr", "getfh", "link", "lock", 105*7c478bd9Sstevel@tonic-gate "lockt", "locku", "lookup", "lookupp", "nverify", "open", "openattr", 106*7c478bd9Sstevel@tonic-gate "open_confirm", "open_downgrade", "putfh", "putpubfh", "putrootfh", 107*7c478bd9Sstevel@tonic-gate "read", "readdir", "readlink", "remove", "rename", "renew", 108*7c478bd9Sstevel@tonic-gate "restorefh", "savefh", "secinfo", "setattr", "setclientid", 109*7c478bd9Sstevel@tonic-gate "setclientid_confirm", "verify", "write" 110*7c478bd9Sstevel@tonic-gate }; 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate /* 113*7c478bd9Sstevel@tonic-gate * nfs4_max_mount_retry is the number of times the client will redrive 114*7c478bd9Sstevel@tonic-gate * a mount compound before giving up and returning failure. The intent 115*7c478bd9Sstevel@tonic-gate * is to redrive mount compounds which fail NFS4ERR_STALE so that 116*7c478bd9Sstevel@tonic-gate * if a component of the server path being mounted goes stale, it can 117*7c478bd9Sstevel@tonic-gate * "recover" by redriving the mount compund (LOOKUP ops). This recovery 118*7c478bd9Sstevel@tonic-gate * code is needed outside of the recovery framework because mount is a 119*7c478bd9Sstevel@tonic-gate * special case. The client doesn't create vnodes/rnodes for components 120*7c478bd9Sstevel@tonic-gate * of the server path being mounted. The recovery code recovers real 121*7c478bd9Sstevel@tonic-gate * client objects, not STALE FHs which map to components of the server 122*7c478bd9Sstevel@tonic-gate * path being mounted. 123*7c478bd9Sstevel@tonic-gate * 124*7c478bd9Sstevel@tonic-gate * We could just fail the mount on the first time, but that would 125*7c478bd9Sstevel@tonic-gate * instantly trigger failover (from nfs4_mount), and the client should 126*7c478bd9Sstevel@tonic-gate * try to re-lookup the STALE FH before doing failover. The easiest 127*7c478bd9Sstevel@tonic-gate * way to "re-lookup" is to simply redrive the mount compound. 128*7c478bd9Sstevel@tonic-gate */ 129*7c478bd9Sstevel@tonic-gate static int nfs4_max_mount_retry = 2; 130*7c478bd9Sstevel@tonic-gate 131*7c478bd9Sstevel@tonic-gate /* 132*7c478bd9Sstevel@tonic-gate * nfs4 vfs operations. 133*7c478bd9Sstevel@tonic-gate */ 134*7c478bd9Sstevel@tonic-gate static int nfs4_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *); 135*7c478bd9Sstevel@tonic-gate static int nfs4_unmount(vfs_t *, int, cred_t *); 136*7c478bd9Sstevel@tonic-gate static int nfs4_root(vfs_t *, vnode_t **); 137*7c478bd9Sstevel@tonic-gate static int nfs4_statvfs(vfs_t *, struct statvfs64 *); 138*7c478bd9Sstevel@tonic-gate static int nfs4_sync(vfs_t *, short, cred_t *); 139*7c478bd9Sstevel@tonic-gate static int nfs4_vget(vfs_t *, vnode_t **, fid_t *); 140*7c478bd9Sstevel@tonic-gate static int nfs4_mountroot(vfs_t *, whymountroot_t); 141*7c478bd9Sstevel@tonic-gate static void nfs4_freevfs(vfs_t *); 142*7c478bd9Sstevel@tonic-gate 143*7c478bd9Sstevel@tonic-gate static int nfs4rootvp(vnode_t **, vfs_t *, struct servinfo4 *, 144*7c478bd9Sstevel@tonic-gate int, cred_t *, zone_t *); 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate vfsops_t *nfs4_vfsops; 147*7c478bd9Sstevel@tonic-gate 148*7c478bd9Sstevel@tonic-gate int nfs4_vfsinit(void); 149*7c478bd9Sstevel@tonic-gate void nfs4_vfsfini(void); 150*7c478bd9Sstevel@tonic-gate static void nfs4setclientid_init(void); 151*7c478bd9Sstevel@tonic-gate static void nfs4setclientid_fini(void); 152*7c478bd9Sstevel@tonic-gate static void nfs4setclientid_otw(mntinfo4_t *, servinfo4_t *, cred_t *, 153*7c478bd9Sstevel@tonic-gate struct nfs4_server *, nfs4_error_t *, int *); 154*7c478bd9Sstevel@tonic-gate static void destroy_nfs4_server(nfs4_server_t *); 155*7c478bd9Sstevel@tonic-gate static void remove_mi(nfs4_server_t *, mntinfo4_t *); 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gate /* 158*7c478bd9Sstevel@tonic-gate * Initialize the vfs structure 159*7c478bd9Sstevel@tonic-gate */ 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate static int nfs4fstyp; 162*7c478bd9Sstevel@tonic-gate 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate /* 165*7c478bd9Sstevel@tonic-gate * Debug variable to check for rdma based 166*7c478bd9Sstevel@tonic-gate * transport startup and cleanup. Controlled 167*7c478bd9Sstevel@tonic-gate * through /etc/system. Off by default. 168*7c478bd9Sstevel@tonic-gate */ 169*7c478bd9Sstevel@tonic-gate extern int rdma_debug; 170*7c478bd9Sstevel@tonic-gate 171*7c478bd9Sstevel@tonic-gate int 172*7c478bd9Sstevel@tonic-gate nfs4init(int fstyp, char *name) 173*7c478bd9Sstevel@tonic-gate { 174*7c478bd9Sstevel@tonic-gate static const fs_operation_def_t nfs4_vfsops_template[] = { 175*7c478bd9Sstevel@tonic-gate VFSNAME_MOUNT, nfs4_mount, 176*7c478bd9Sstevel@tonic-gate VFSNAME_UNMOUNT, nfs4_unmount, 177*7c478bd9Sstevel@tonic-gate VFSNAME_ROOT, nfs4_root, 178*7c478bd9Sstevel@tonic-gate VFSNAME_STATVFS, nfs4_statvfs, 179*7c478bd9Sstevel@tonic-gate VFSNAME_SYNC, (fs_generic_func_p) nfs4_sync, 180*7c478bd9Sstevel@tonic-gate VFSNAME_VGET, nfs4_vget, 181*7c478bd9Sstevel@tonic-gate VFSNAME_MOUNTROOT, nfs4_mountroot, 182*7c478bd9Sstevel@tonic-gate VFSNAME_FREEVFS, (fs_generic_func_p)nfs4_freevfs, 183*7c478bd9Sstevel@tonic-gate NULL, NULL 184*7c478bd9Sstevel@tonic-gate }; 185*7c478bd9Sstevel@tonic-gate int error; 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate error = vfs_setfsops(fstyp, nfs4_vfsops_template, &nfs4_vfsops); 188*7c478bd9Sstevel@tonic-gate if (error != 0) { 189*7c478bd9Sstevel@tonic-gate zcmn_err(GLOBAL_ZONEID, CE_WARN, 190*7c478bd9Sstevel@tonic-gate "nfs4init: bad vfs ops template"); 191*7c478bd9Sstevel@tonic-gate return (error); 192*7c478bd9Sstevel@tonic-gate } 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate error = vn_make_ops(name, nfs4_vnodeops_template, &nfs4_vnodeops); 195*7c478bd9Sstevel@tonic-gate if (error != 0) { 196*7c478bd9Sstevel@tonic-gate (void) vfs_freevfsops_by_type(fstyp); 197*7c478bd9Sstevel@tonic-gate zcmn_err(GLOBAL_ZONEID, CE_WARN, 198*7c478bd9Sstevel@tonic-gate "nfs4init: bad vnode ops template"); 199*7c478bd9Sstevel@tonic-gate return (error); 200*7c478bd9Sstevel@tonic-gate } 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate nfs4fstyp = fstyp; 203*7c478bd9Sstevel@tonic-gate 204*7c478bd9Sstevel@tonic-gate (void) nfs4_vfsinit(); 205*7c478bd9Sstevel@tonic-gate 206*7c478bd9Sstevel@tonic-gate (void) nfs4_init_dot_entries(); 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate return (0); 209*7c478bd9Sstevel@tonic-gate } 210*7c478bd9Sstevel@tonic-gate 211*7c478bd9Sstevel@tonic-gate void 212*7c478bd9Sstevel@tonic-gate nfs4fini(void) 213*7c478bd9Sstevel@tonic-gate { 214*7c478bd9Sstevel@tonic-gate (void) nfs4_destroy_dot_entries(); 215*7c478bd9Sstevel@tonic-gate nfs4_vfsfini(); 216*7c478bd9Sstevel@tonic-gate } 217*7c478bd9Sstevel@tonic-gate 218*7c478bd9Sstevel@tonic-gate /* 219*7c478bd9Sstevel@tonic-gate * Create a new sec_data structure to store AUTH_DH related data: 220*7c478bd9Sstevel@tonic-gate * netname, syncaddr, knetconfig. There is no AUTH_F_RPCTIMESYNC 221*7c478bd9Sstevel@tonic-gate * flag set for NFS V4 since we are avoiding to contact the rpcbind 222*7c478bd9Sstevel@tonic-gate * daemon and is using the IP time service (IPPORT_TIMESERVER). 223*7c478bd9Sstevel@tonic-gate * 224*7c478bd9Sstevel@tonic-gate * sec_data can be freed by sec_clnt_freeinfo(). 225*7c478bd9Sstevel@tonic-gate */ 226*7c478bd9Sstevel@tonic-gate struct sec_data * 227*7c478bd9Sstevel@tonic-gate create_authdh_data(char *netname, int nlen, struct netbuf *syncaddr, 228*7c478bd9Sstevel@tonic-gate struct knetconfig *knconf) { 229*7c478bd9Sstevel@tonic-gate struct sec_data *secdata; 230*7c478bd9Sstevel@tonic-gate dh_k4_clntdata_t *data; 231*7c478bd9Sstevel@tonic-gate char *pf, *p; 232*7c478bd9Sstevel@tonic-gate 233*7c478bd9Sstevel@tonic-gate if (syncaddr == NULL || syncaddr->buf == NULL || nlen == 0) 234*7c478bd9Sstevel@tonic-gate return (NULL); 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate secdata = kmem_alloc(sizeof (*secdata), KM_SLEEP); 237*7c478bd9Sstevel@tonic-gate secdata->flags = 0; 238*7c478bd9Sstevel@tonic-gate 239*7c478bd9Sstevel@tonic-gate data = kmem_alloc(sizeof (*data), KM_SLEEP); 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate data->syncaddr.maxlen = syncaddr->maxlen; 242*7c478bd9Sstevel@tonic-gate data->syncaddr.len = syncaddr->len; 243*7c478bd9Sstevel@tonic-gate data->syncaddr.buf = (char *)kmem_alloc(syncaddr->len, KM_SLEEP); 244*7c478bd9Sstevel@tonic-gate bcopy(syncaddr->buf, data->syncaddr.buf, syncaddr->len); 245*7c478bd9Sstevel@tonic-gate 246*7c478bd9Sstevel@tonic-gate /* 247*7c478bd9Sstevel@tonic-gate * duplicate the knconf information for the 248*7c478bd9Sstevel@tonic-gate * new opaque data. 249*7c478bd9Sstevel@tonic-gate */ 250*7c478bd9Sstevel@tonic-gate data->knconf = kmem_alloc(sizeof (*knconf), KM_SLEEP); 251*7c478bd9Sstevel@tonic-gate *data->knconf = *knconf; 252*7c478bd9Sstevel@tonic-gate pf = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 253*7c478bd9Sstevel@tonic-gate p = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 254*7c478bd9Sstevel@tonic-gate bcopy(knconf->knc_protofmly, pf, KNC_STRSIZE); 255*7c478bd9Sstevel@tonic-gate bcopy(knconf->knc_proto, p, KNC_STRSIZE); 256*7c478bd9Sstevel@tonic-gate data->knconf->knc_protofmly = pf; 257*7c478bd9Sstevel@tonic-gate data->knconf->knc_proto = p; 258*7c478bd9Sstevel@tonic-gate 259*7c478bd9Sstevel@tonic-gate /* move server netname to the sec_data structure */ 260*7c478bd9Sstevel@tonic-gate data->netname = kmem_alloc(nlen, KM_SLEEP); 261*7c478bd9Sstevel@tonic-gate bcopy(netname, data->netname, nlen); 262*7c478bd9Sstevel@tonic-gate data->netnamelen = (int)nlen; 263*7c478bd9Sstevel@tonic-gate 264*7c478bd9Sstevel@tonic-gate secdata->secmod = AUTH_DH; 265*7c478bd9Sstevel@tonic-gate secdata->rpcflavor = AUTH_DH; 266*7c478bd9Sstevel@tonic-gate secdata->data = (caddr_t)data; 267*7c478bd9Sstevel@tonic-gate 268*7c478bd9Sstevel@tonic-gate return (secdata); 269*7c478bd9Sstevel@tonic-gate } 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate static int 272*7c478bd9Sstevel@tonic-gate nfs4_chkdup_servinfo4(servinfo4_t *svp_head, servinfo4_t *svp) 273*7c478bd9Sstevel@tonic-gate { 274*7c478bd9Sstevel@tonic-gate servinfo4_t *si; 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate /* 277*7c478bd9Sstevel@tonic-gate * Iterate over the servinfo4 list to make sure 278*7c478bd9Sstevel@tonic-gate * we do not have a duplicate. Skip any servinfo4 279*7c478bd9Sstevel@tonic-gate * that has been marked "NOT IN USE" 280*7c478bd9Sstevel@tonic-gate */ 281*7c478bd9Sstevel@tonic-gate for (si = svp_head; si; si = si->sv_next) { 282*7c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&si->sv_lock, RW_READER, 0); 283*7c478bd9Sstevel@tonic-gate if (si->sv_flags & SV4_NOTINUSE) { 284*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&si->sv_lock); 285*7c478bd9Sstevel@tonic-gate continue; 286*7c478bd9Sstevel@tonic-gate } 287*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&si->sv_lock); 288*7c478bd9Sstevel@tonic-gate if (si == svp) 289*7c478bd9Sstevel@tonic-gate continue; 290*7c478bd9Sstevel@tonic-gate if (si->sv_addr.len == svp->sv_addr.len && 291*7c478bd9Sstevel@tonic-gate strcmp(si->sv_knconf->knc_protofmly, 292*7c478bd9Sstevel@tonic-gate svp->sv_knconf->knc_protofmly) == 0 && 293*7c478bd9Sstevel@tonic-gate bcmp(si->sv_addr.buf, svp->sv_addr.buf, 294*7c478bd9Sstevel@tonic-gate si->sv_addr.len) == 0) { 295*7c478bd9Sstevel@tonic-gate /* it's a duplicate */ 296*7c478bd9Sstevel@tonic-gate return (1); 297*7c478bd9Sstevel@tonic-gate } 298*7c478bd9Sstevel@tonic-gate } 299*7c478bd9Sstevel@tonic-gate /* it's not a duplicate */ 300*7c478bd9Sstevel@tonic-gate return (0); 301*7c478bd9Sstevel@tonic-gate } 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate /* 304*7c478bd9Sstevel@tonic-gate * nfs mount vfsop 305*7c478bd9Sstevel@tonic-gate * Set up mount info record and attach it to vfs struct. 306*7c478bd9Sstevel@tonic-gate */ 307*7c478bd9Sstevel@tonic-gate static int 308*7c478bd9Sstevel@tonic-gate nfs4_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) 309*7c478bd9Sstevel@tonic-gate { 310*7c478bd9Sstevel@tonic-gate char *data = uap->dataptr; 311*7c478bd9Sstevel@tonic-gate int error; 312*7c478bd9Sstevel@tonic-gate vnode_t *rtvp; /* the server's root */ 313*7c478bd9Sstevel@tonic-gate mntinfo4_t *mi; /* mount info, pointed at by vfs */ 314*7c478bd9Sstevel@tonic-gate size_t hlen; /* length of hostname */ 315*7c478bd9Sstevel@tonic-gate size_t nlen; /* length of netname */ 316*7c478bd9Sstevel@tonic-gate char netname[MAXNETNAMELEN+1]; /* server's netname */ 317*7c478bd9Sstevel@tonic-gate struct netbuf addr; /* server's address */ 318*7c478bd9Sstevel@tonic-gate struct netbuf syncaddr; /* AUTH_DES time sync addr */ 319*7c478bd9Sstevel@tonic-gate struct knetconfig *knconf; /* transport knetconfig structure */ 320*7c478bd9Sstevel@tonic-gate struct knetconfig *rdma_knconf; /* rdma transport structure */ 321*7c478bd9Sstevel@tonic-gate rnode4_t *rp; 322*7c478bd9Sstevel@tonic-gate struct servinfo4 *svp; /* nfs server info */ 323*7c478bd9Sstevel@tonic-gate struct servinfo4 *svp_tail = NULL; /* previous nfs server info */ 324*7c478bd9Sstevel@tonic-gate struct servinfo4 *svp_head; /* first nfs server info */ 325*7c478bd9Sstevel@tonic-gate struct servinfo4 *svp_2ndlast; /* 2nd last in server info list */ 326*7c478bd9Sstevel@tonic-gate struct sec_data *secdata; /* security data */ 327*7c478bd9Sstevel@tonic-gate STRUCT_DECL(nfs_args, args); /* nfs mount arguments */ 328*7c478bd9Sstevel@tonic-gate STRUCT_DECL(knetconfig, knconf_tmp); 329*7c478bd9Sstevel@tonic-gate STRUCT_DECL(netbuf, addr_tmp); 330*7c478bd9Sstevel@tonic-gate int flags, addr_type; 331*7c478bd9Sstevel@tonic-gate char *p, *pf; 332*7c478bd9Sstevel@tonic-gate struct pathname pn; 333*7c478bd9Sstevel@tonic-gate char *userbufptr; 334*7c478bd9Sstevel@tonic-gate zone_t *zone = curproc->p_zone; 335*7c478bd9Sstevel@tonic-gate nfs4_error_t n4e; 336*7c478bd9Sstevel@tonic-gate 337*7c478bd9Sstevel@tonic-gate if (secpolicy_fs_mount(cr, mvp, vfsp) != 0) 338*7c478bd9Sstevel@tonic-gate return (EPERM); 339*7c478bd9Sstevel@tonic-gate if (mvp->v_type != VDIR) 340*7c478bd9Sstevel@tonic-gate return (ENOTDIR); 341*7c478bd9Sstevel@tonic-gate /* 342*7c478bd9Sstevel@tonic-gate * get arguments 343*7c478bd9Sstevel@tonic-gate * 344*7c478bd9Sstevel@tonic-gate * nfs_args is now versioned and is extensible, so 345*7c478bd9Sstevel@tonic-gate * uap->datalen might be different from sizeof (args) 346*7c478bd9Sstevel@tonic-gate * in a compatible situation. 347*7c478bd9Sstevel@tonic-gate */ 348*7c478bd9Sstevel@tonic-gate more: 349*7c478bd9Sstevel@tonic-gate STRUCT_INIT(args, get_udatamodel()); 350*7c478bd9Sstevel@tonic-gate bzero(STRUCT_BUF(args), SIZEOF_STRUCT(nfs_args, DATAMODEL_NATIVE)); 351*7c478bd9Sstevel@tonic-gate if (copyin(data, STRUCT_BUF(args), MIN(uap->datalen, 352*7c478bd9Sstevel@tonic-gate STRUCT_SIZE(args)))) 353*7c478bd9Sstevel@tonic-gate return (EFAULT); 354*7c478bd9Sstevel@tonic-gate 355*7c478bd9Sstevel@tonic-gate flags = STRUCT_FGET(args, flags); 356*7c478bd9Sstevel@tonic-gate 357*7c478bd9Sstevel@tonic-gate /* 358*7c478bd9Sstevel@tonic-gate * If the request changes the locking type, disallow the remount, 359*7c478bd9Sstevel@tonic-gate * because it's questionable whether we can transfer the 360*7c478bd9Sstevel@tonic-gate * locking state correctly. 361*7c478bd9Sstevel@tonic-gate */ 362*7c478bd9Sstevel@tonic-gate if (uap->flags & MS_REMOUNT) { 363*7c478bd9Sstevel@tonic-gate if ((mi = VFTOMI4(vfsp)) != NULL) { 364*7c478bd9Sstevel@tonic-gate uint_t new_mi_llock; 365*7c478bd9Sstevel@tonic-gate uint_t old_mi_llock; 366*7c478bd9Sstevel@tonic-gate 367*7c478bd9Sstevel@tonic-gate new_mi_llock = (flags & NFSMNT_LLOCK) ? 1 : 0; 368*7c478bd9Sstevel@tonic-gate old_mi_llock = (mi->mi_flags & MI4_LLOCK) ? 1 : 0; 369*7c478bd9Sstevel@tonic-gate if (old_mi_llock != new_mi_llock) 370*7c478bd9Sstevel@tonic-gate return (EBUSY); 371*7c478bd9Sstevel@tonic-gate } 372*7c478bd9Sstevel@tonic-gate return (0); 373*7c478bd9Sstevel@tonic-gate } 374*7c478bd9Sstevel@tonic-gate 375*7c478bd9Sstevel@tonic-gate mutex_enter(&mvp->v_lock); 376*7c478bd9Sstevel@tonic-gate if (!(uap->flags & MS_OVERLAY) && 377*7c478bd9Sstevel@tonic-gate (mvp->v_count != 1 || (mvp->v_flag & VROOT))) { 378*7c478bd9Sstevel@tonic-gate mutex_exit(&mvp->v_lock); 379*7c478bd9Sstevel@tonic-gate return (EBUSY); 380*7c478bd9Sstevel@tonic-gate } 381*7c478bd9Sstevel@tonic-gate mutex_exit(&mvp->v_lock); 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate /* make sure things are zeroed for errout: */ 384*7c478bd9Sstevel@tonic-gate rtvp = NULL; 385*7c478bd9Sstevel@tonic-gate mi = NULL; 386*7c478bd9Sstevel@tonic-gate addr.buf = NULL; 387*7c478bd9Sstevel@tonic-gate syncaddr.buf = NULL; 388*7c478bd9Sstevel@tonic-gate secdata = NULL; 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate /* 391*7c478bd9Sstevel@tonic-gate * A valid knetconfig structure is required. 392*7c478bd9Sstevel@tonic-gate */ 393*7c478bd9Sstevel@tonic-gate if (!(flags & NFSMNT_KNCONF)) 394*7c478bd9Sstevel@tonic-gate return (EINVAL); 395*7c478bd9Sstevel@tonic-gate 396*7c478bd9Sstevel@tonic-gate /* 397*7c478bd9Sstevel@tonic-gate * Allocate a servinfo4 struct. 398*7c478bd9Sstevel@tonic-gate */ 399*7c478bd9Sstevel@tonic-gate svp = kmem_zalloc(sizeof (*svp), KM_SLEEP); 400*7c478bd9Sstevel@tonic-gate nfs_rw_init(&svp->sv_lock, NULL, RW_DEFAULT, NULL); 401*7c478bd9Sstevel@tonic-gate if (svp_tail) { 402*7c478bd9Sstevel@tonic-gate svp_2ndlast = svp_tail; 403*7c478bd9Sstevel@tonic-gate svp_tail->sv_next = svp; 404*7c478bd9Sstevel@tonic-gate } else { 405*7c478bd9Sstevel@tonic-gate svp_head = svp; 406*7c478bd9Sstevel@tonic-gate svp_2ndlast = svp; 407*7c478bd9Sstevel@tonic-gate } 408*7c478bd9Sstevel@tonic-gate 409*7c478bd9Sstevel@tonic-gate svp_tail = svp; 410*7c478bd9Sstevel@tonic-gate 411*7c478bd9Sstevel@tonic-gate /* 412*7c478bd9Sstevel@tonic-gate * Allocate space for a knetconfig structure and 413*7c478bd9Sstevel@tonic-gate * its strings and copy in from user-land. 414*7c478bd9Sstevel@tonic-gate */ 415*7c478bd9Sstevel@tonic-gate knconf = kmem_zalloc(sizeof (*knconf), KM_SLEEP); 416*7c478bd9Sstevel@tonic-gate svp->sv_knconf = knconf; 417*7c478bd9Sstevel@tonic-gate STRUCT_INIT(knconf_tmp, get_udatamodel()); 418*7c478bd9Sstevel@tonic-gate if (copyin(STRUCT_FGETP(args, knconf), STRUCT_BUF(knconf_tmp), 419*7c478bd9Sstevel@tonic-gate STRUCT_SIZE(knconf_tmp))) { 420*7c478bd9Sstevel@tonic-gate sv4_free(svp_head); 421*7c478bd9Sstevel@tonic-gate return (EFAULT); 422*7c478bd9Sstevel@tonic-gate } 423*7c478bd9Sstevel@tonic-gate 424*7c478bd9Sstevel@tonic-gate knconf->knc_semantics = STRUCT_FGET(knconf_tmp, knc_semantics); 425*7c478bd9Sstevel@tonic-gate knconf->knc_protofmly = STRUCT_FGETP(knconf_tmp, knc_protofmly); 426*7c478bd9Sstevel@tonic-gate knconf->knc_proto = STRUCT_FGETP(knconf_tmp, knc_proto); 427*7c478bd9Sstevel@tonic-gate if (get_udatamodel() != DATAMODEL_LP64) { 428*7c478bd9Sstevel@tonic-gate knconf->knc_rdev = expldev(STRUCT_FGET(knconf_tmp, knc_rdev)); 429*7c478bd9Sstevel@tonic-gate } else { 430*7c478bd9Sstevel@tonic-gate knconf->knc_rdev = STRUCT_FGET(knconf_tmp, knc_rdev); 431*7c478bd9Sstevel@tonic-gate } 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate pf = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 434*7c478bd9Sstevel@tonic-gate p = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 435*7c478bd9Sstevel@tonic-gate error = copyinstr(knconf->knc_protofmly, pf, KNC_STRSIZE, NULL); 436*7c478bd9Sstevel@tonic-gate if (error) { 437*7c478bd9Sstevel@tonic-gate kmem_free(pf, KNC_STRSIZE); 438*7c478bd9Sstevel@tonic-gate kmem_free(p, KNC_STRSIZE); 439*7c478bd9Sstevel@tonic-gate sv4_free(svp_head); 440*7c478bd9Sstevel@tonic-gate return (error); 441*7c478bd9Sstevel@tonic-gate } 442*7c478bd9Sstevel@tonic-gate error = copyinstr(knconf->knc_proto, p, KNC_STRSIZE, NULL); 443*7c478bd9Sstevel@tonic-gate if (error) { 444*7c478bd9Sstevel@tonic-gate kmem_free(pf, KNC_STRSIZE); 445*7c478bd9Sstevel@tonic-gate kmem_free(p, KNC_STRSIZE); 446*7c478bd9Sstevel@tonic-gate sv4_free(svp_head); 447*7c478bd9Sstevel@tonic-gate return (error); 448*7c478bd9Sstevel@tonic-gate } 449*7c478bd9Sstevel@tonic-gate if (strcmp(p, NC_UDP) == 0) { 450*7c478bd9Sstevel@tonic-gate kmem_free(pf, KNC_STRSIZE); 451*7c478bd9Sstevel@tonic-gate kmem_free(p, KNC_STRSIZE); 452*7c478bd9Sstevel@tonic-gate sv4_free(svp_head); 453*7c478bd9Sstevel@tonic-gate return (ENOTSUP); 454*7c478bd9Sstevel@tonic-gate } 455*7c478bd9Sstevel@tonic-gate knconf->knc_protofmly = pf; 456*7c478bd9Sstevel@tonic-gate knconf->knc_proto = p; 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate /* 459*7c478bd9Sstevel@tonic-gate * Get server address 460*7c478bd9Sstevel@tonic-gate */ 461*7c478bd9Sstevel@tonic-gate STRUCT_INIT(addr_tmp, get_udatamodel()); 462*7c478bd9Sstevel@tonic-gate if (copyin(STRUCT_FGETP(args, addr), STRUCT_BUF(addr_tmp), 463*7c478bd9Sstevel@tonic-gate STRUCT_SIZE(addr_tmp))) { 464*7c478bd9Sstevel@tonic-gate error = EFAULT; 465*7c478bd9Sstevel@tonic-gate goto errout; 466*7c478bd9Sstevel@tonic-gate } 467*7c478bd9Sstevel@tonic-gate 468*7c478bd9Sstevel@tonic-gate userbufptr = addr.buf = STRUCT_FGETP(addr_tmp, buf); 469*7c478bd9Sstevel@tonic-gate addr.len = STRUCT_FGET(addr_tmp, len); 470*7c478bd9Sstevel@tonic-gate addr.buf = kmem_alloc(addr.len, KM_SLEEP); 471*7c478bd9Sstevel@tonic-gate addr.maxlen = addr.len; 472*7c478bd9Sstevel@tonic-gate if (copyin(userbufptr, addr.buf, addr.len)) { 473*7c478bd9Sstevel@tonic-gate kmem_free(addr.buf, addr.len); 474*7c478bd9Sstevel@tonic-gate error = EFAULT; 475*7c478bd9Sstevel@tonic-gate goto errout; 476*7c478bd9Sstevel@tonic-gate } 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate svp->sv_addr = addr; 479*7c478bd9Sstevel@tonic-gate 480*7c478bd9Sstevel@tonic-gate /* 481*7c478bd9Sstevel@tonic-gate * Get the root fhandle 482*7c478bd9Sstevel@tonic-gate */ 483*7c478bd9Sstevel@tonic-gate error = pn_get(STRUCT_FGETP(args, fh), UIO_USERSPACE, &pn); 484*7c478bd9Sstevel@tonic-gate 485*7c478bd9Sstevel@tonic-gate if (error) 486*7c478bd9Sstevel@tonic-gate goto errout; 487*7c478bd9Sstevel@tonic-gate 488*7c478bd9Sstevel@tonic-gate /* Volatile fh: keep server paths, so use actual-size strings */ 489*7c478bd9Sstevel@tonic-gate svp->sv_path = kmem_alloc(pn.pn_pathlen + 1, KM_SLEEP); 490*7c478bd9Sstevel@tonic-gate bcopy(pn.pn_path, svp->sv_path, pn.pn_pathlen); 491*7c478bd9Sstevel@tonic-gate svp->sv_path[pn.pn_pathlen] = '\0'; 492*7c478bd9Sstevel@tonic-gate svp->sv_pathlen = pn.pn_pathlen + 1; 493*7c478bd9Sstevel@tonic-gate pn_free(&pn); 494*7c478bd9Sstevel@tonic-gate 495*7c478bd9Sstevel@tonic-gate /* 496*7c478bd9Sstevel@tonic-gate * Get server's hostname 497*7c478bd9Sstevel@tonic-gate */ 498*7c478bd9Sstevel@tonic-gate if (flags & NFSMNT_HOSTNAME) { 499*7c478bd9Sstevel@tonic-gate error = copyinstr(STRUCT_FGETP(args, hostname), 500*7c478bd9Sstevel@tonic-gate netname, sizeof (netname), &hlen); 501*7c478bd9Sstevel@tonic-gate if (error) 502*7c478bd9Sstevel@tonic-gate goto errout; 503*7c478bd9Sstevel@tonic-gate } else { 504*7c478bd9Sstevel@tonic-gate char *p = "unknown-host"; 505*7c478bd9Sstevel@tonic-gate hlen = strlen(p) + 1; 506*7c478bd9Sstevel@tonic-gate (void) strcpy(netname, p); 507*7c478bd9Sstevel@tonic-gate } 508*7c478bd9Sstevel@tonic-gate svp->sv_hostnamelen = hlen; 509*7c478bd9Sstevel@tonic-gate svp->sv_hostname = kmem_alloc(svp->sv_hostnamelen, KM_SLEEP); 510*7c478bd9Sstevel@tonic-gate (void) strcpy(svp->sv_hostname, netname); 511*7c478bd9Sstevel@tonic-gate 512*7c478bd9Sstevel@tonic-gate /* 513*7c478bd9Sstevel@tonic-gate * RDMA MOUNT SUPPORT FOR NFS v4. 514*7c478bd9Sstevel@tonic-gate * Establish, is it possible to use RDMA, if so overload the 515*7c478bd9Sstevel@tonic-gate * knconf with rdma specific knconf and free the orignal knconf. 516*7c478bd9Sstevel@tonic-gate */ 517*7c478bd9Sstevel@tonic-gate if ((flags & NFSMNT_TRYRDMA) || (flags & NFSMNT_DORDMA)) { 518*7c478bd9Sstevel@tonic-gate /* 519*7c478bd9Sstevel@tonic-gate * Determine the addr type for RDMA, IPv4 or v6. 520*7c478bd9Sstevel@tonic-gate */ 521*7c478bd9Sstevel@tonic-gate if (strcmp(svp->sv_knconf->knc_protofmly, NC_INET) == 0) 522*7c478bd9Sstevel@tonic-gate addr_type = AF_INET; 523*7c478bd9Sstevel@tonic-gate else if (strcmp(svp->sv_knconf->knc_protofmly, NC_INET6) == 0) 524*7c478bd9Sstevel@tonic-gate addr_type = AF_INET6; 525*7c478bd9Sstevel@tonic-gate 526*7c478bd9Sstevel@tonic-gate if (rdma_reachable(addr_type, &svp->sv_addr, 527*7c478bd9Sstevel@tonic-gate &rdma_knconf) == 0) { 528*7c478bd9Sstevel@tonic-gate /* 529*7c478bd9Sstevel@tonic-gate * If successful, hijack the orignal knconf and 530*7c478bd9Sstevel@tonic-gate * replace with the new one, depending on the flags. 531*7c478bd9Sstevel@tonic-gate */ 532*7c478bd9Sstevel@tonic-gate svp->sv_origknconf = svp->sv_knconf; 533*7c478bd9Sstevel@tonic-gate svp->sv_knconf = rdma_knconf; 534*7c478bd9Sstevel@tonic-gate knconf = rdma_knconf; 535*7c478bd9Sstevel@tonic-gate } else { 536*7c478bd9Sstevel@tonic-gate if (flags & NFSMNT_TRYRDMA) { 537*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 538*7c478bd9Sstevel@tonic-gate if (rdma_debug) 539*7c478bd9Sstevel@tonic-gate zcmn_err(getzoneid(), CE_WARN, 540*7c478bd9Sstevel@tonic-gate "no RDMA onboard, revert\n"); 541*7c478bd9Sstevel@tonic-gate #endif 542*7c478bd9Sstevel@tonic-gate } 543*7c478bd9Sstevel@tonic-gate 544*7c478bd9Sstevel@tonic-gate if (flags & NFSMNT_DORDMA) { 545*7c478bd9Sstevel@tonic-gate /* 546*7c478bd9Sstevel@tonic-gate * If proto=rdma is specified and no RDMA 547*7c478bd9Sstevel@tonic-gate * path to this server is avialable then 548*7c478bd9Sstevel@tonic-gate * ditch this server. 549*7c478bd9Sstevel@tonic-gate * This is not included in the mountable 550*7c478bd9Sstevel@tonic-gate * server list or the replica list. 551*7c478bd9Sstevel@tonic-gate * Check if more servers are specified; 552*7c478bd9Sstevel@tonic-gate * Failover case, otherwise bail out of mount. 553*7c478bd9Sstevel@tonic-gate */ 554*7c478bd9Sstevel@tonic-gate if (STRUCT_FGET(args, nfs_args_ext) == 555*7c478bd9Sstevel@tonic-gate NFS_ARGS_EXTB && STRUCT_FGETP(args, 556*7c478bd9Sstevel@tonic-gate nfs_ext_u.nfs_extB.next) != NULL) { 557*7c478bd9Sstevel@tonic-gate if (uap->flags & MS_RDONLY && 558*7c478bd9Sstevel@tonic-gate !(flags & NFSMNT_SOFT)) { 559*7c478bd9Sstevel@tonic-gate data = (char *) 560*7c478bd9Sstevel@tonic-gate STRUCT_FGETP(args, 561*7c478bd9Sstevel@tonic-gate nfs_ext_u.nfs_extB.next); 562*7c478bd9Sstevel@tonic-gate if (svp_head->sv_next == NULL) { 563*7c478bd9Sstevel@tonic-gate svp_tail = NULL; 564*7c478bd9Sstevel@tonic-gate svp_2ndlast = NULL; 565*7c478bd9Sstevel@tonic-gate sv4_free(svp_head); 566*7c478bd9Sstevel@tonic-gate goto more; 567*7c478bd9Sstevel@tonic-gate } else { 568*7c478bd9Sstevel@tonic-gate svp_tail = svp_2ndlast; 569*7c478bd9Sstevel@tonic-gate svp_2ndlast->sv_next = 570*7c478bd9Sstevel@tonic-gate NULL; 571*7c478bd9Sstevel@tonic-gate sv4_free(svp); 572*7c478bd9Sstevel@tonic-gate goto more; 573*7c478bd9Sstevel@tonic-gate } 574*7c478bd9Sstevel@tonic-gate } 575*7c478bd9Sstevel@tonic-gate } else { 576*7c478bd9Sstevel@tonic-gate /* 577*7c478bd9Sstevel@tonic-gate * This is the last server specified 578*7c478bd9Sstevel@tonic-gate * in the nfs_args list passed down 579*7c478bd9Sstevel@tonic-gate * and its not rdma capable. 580*7c478bd9Sstevel@tonic-gate */ 581*7c478bd9Sstevel@tonic-gate if (svp_head->sv_next == NULL) { 582*7c478bd9Sstevel@tonic-gate /* 583*7c478bd9Sstevel@tonic-gate * Is this the only one 584*7c478bd9Sstevel@tonic-gate */ 585*7c478bd9Sstevel@tonic-gate error = EINVAL; 586*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 587*7c478bd9Sstevel@tonic-gate if (rdma_debug) 588*7c478bd9Sstevel@tonic-gate zcmn_err(getzoneid(), 589*7c478bd9Sstevel@tonic-gate CE_WARN, 590*7c478bd9Sstevel@tonic-gate "No RDMA srv"); 591*7c478bd9Sstevel@tonic-gate #endif 592*7c478bd9Sstevel@tonic-gate goto errout; 593*7c478bd9Sstevel@tonic-gate } else { 594*7c478bd9Sstevel@tonic-gate /* 595*7c478bd9Sstevel@tonic-gate * There is list, since some 596*7c478bd9Sstevel@tonic-gate * servers specified before 597*7c478bd9Sstevel@tonic-gate * this passed all requirements 598*7c478bd9Sstevel@tonic-gate */ 599*7c478bd9Sstevel@tonic-gate svp_tail = svp_2ndlast; 600*7c478bd9Sstevel@tonic-gate svp_2ndlast->sv_next = NULL; 601*7c478bd9Sstevel@tonic-gate sv4_free(svp); 602*7c478bd9Sstevel@tonic-gate goto proceed; 603*7c478bd9Sstevel@tonic-gate } 604*7c478bd9Sstevel@tonic-gate } 605*7c478bd9Sstevel@tonic-gate } 606*7c478bd9Sstevel@tonic-gate } 607*7c478bd9Sstevel@tonic-gate } 608*7c478bd9Sstevel@tonic-gate 609*7c478bd9Sstevel@tonic-gate /* 610*7c478bd9Sstevel@tonic-gate * If there are syncaddr and netname data, load them in. This is 611*7c478bd9Sstevel@tonic-gate * to support data needed for NFSV4 when AUTH_DH is the negotiated 612*7c478bd9Sstevel@tonic-gate * flavor via SECINFO. (instead of using MOUNT protocol in V3). 613*7c478bd9Sstevel@tonic-gate */ 614*7c478bd9Sstevel@tonic-gate netname[0] = '\0'; 615*7c478bd9Sstevel@tonic-gate if (flags & NFSMNT_SECURE) { 616*7c478bd9Sstevel@tonic-gate 617*7c478bd9Sstevel@tonic-gate /* get syncaddr */ 618*7c478bd9Sstevel@tonic-gate STRUCT_INIT(addr_tmp, get_udatamodel()); 619*7c478bd9Sstevel@tonic-gate if (copyin(STRUCT_FGETP(args, syncaddr), STRUCT_BUF(addr_tmp), 620*7c478bd9Sstevel@tonic-gate STRUCT_SIZE(addr_tmp))) { 621*7c478bd9Sstevel@tonic-gate error = EINVAL; 622*7c478bd9Sstevel@tonic-gate goto errout; 623*7c478bd9Sstevel@tonic-gate } 624*7c478bd9Sstevel@tonic-gate userbufptr = STRUCT_FGETP(addr_tmp, buf); 625*7c478bd9Sstevel@tonic-gate syncaddr.len = STRUCT_FGET(addr_tmp, len); 626*7c478bd9Sstevel@tonic-gate syncaddr.buf = kmem_alloc(syncaddr.len, KM_SLEEP); 627*7c478bd9Sstevel@tonic-gate syncaddr.maxlen = syncaddr.len; 628*7c478bd9Sstevel@tonic-gate if (copyin(userbufptr, syncaddr.buf, syncaddr.len)) { 629*7c478bd9Sstevel@tonic-gate kmem_free(syncaddr.buf, syncaddr.len); 630*7c478bd9Sstevel@tonic-gate error = EFAULT; 631*7c478bd9Sstevel@tonic-gate goto errout; 632*7c478bd9Sstevel@tonic-gate } 633*7c478bd9Sstevel@tonic-gate 634*7c478bd9Sstevel@tonic-gate /* get server's netname */ 635*7c478bd9Sstevel@tonic-gate if (copyinstr(STRUCT_FGETP(args, netname), netname, 636*7c478bd9Sstevel@tonic-gate sizeof (netname), &nlen)) { 637*7c478bd9Sstevel@tonic-gate kmem_free(syncaddr.buf, syncaddr.len); 638*7c478bd9Sstevel@tonic-gate error = EFAULT; 639*7c478bd9Sstevel@tonic-gate goto errout; 640*7c478bd9Sstevel@tonic-gate } 641*7c478bd9Sstevel@tonic-gate netname[nlen] = '\0'; 642*7c478bd9Sstevel@tonic-gate 643*7c478bd9Sstevel@tonic-gate svp->sv_dhsec = create_authdh_data(netname, nlen, &syncaddr, 644*7c478bd9Sstevel@tonic-gate knconf); 645*7c478bd9Sstevel@tonic-gate } 646*7c478bd9Sstevel@tonic-gate 647*7c478bd9Sstevel@tonic-gate /* 648*7c478bd9Sstevel@tonic-gate * Get the extention data which has the security data structure. 649*7c478bd9Sstevel@tonic-gate * This includes data for AUTH_SYS as well. 650*7c478bd9Sstevel@tonic-gate */ 651*7c478bd9Sstevel@tonic-gate if (flags & NFSMNT_NEWARGS) { 652*7c478bd9Sstevel@tonic-gate switch (STRUCT_FGET(args, nfs_args_ext)) { 653*7c478bd9Sstevel@tonic-gate case NFS_ARGS_EXTA: 654*7c478bd9Sstevel@tonic-gate case NFS_ARGS_EXTB: 655*7c478bd9Sstevel@tonic-gate /* 656*7c478bd9Sstevel@tonic-gate * Indicating the application is using the new 657*7c478bd9Sstevel@tonic-gate * sec_data structure to pass in the security 658*7c478bd9Sstevel@tonic-gate * data. 659*7c478bd9Sstevel@tonic-gate */ 660*7c478bd9Sstevel@tonic-gate if (STRUCT_FGETP(args, 661*7c478bd9Sstevel@tonic-gate nfs_ext_u.nfs_extA.secdata) == NULL) { 662*7c478bd9Sstevel@tonic-gate error = EINVAL; 663*7c478bd9Sstevel@tonic-gate } else { 664*7c478bd9Sstevel@tonic-gate error = sec_clnt_loadinfo( 665*7c478bd9Sstevel@tonic-gate (struct sec_data *)STRUCT_FGETP(args, 666*7c478bd9Sstevel@tonic-gate nfs_ext_u.nfs_extA.secdata), 667*7c478bd9Sstevel@tonic-gate &secdata, get_udatamodel()); 668*7c478bd9Sstevel@tonic-gate } 669*7c478bd9Sstevel@tonic-gate break; 670*7c478bd9Sstevel@tonic-gate 671*7c478bd9Sstevel@tonic-gate default: 672*7c478bd9Sstevel@tonic-gate error = EINVAL; 673*7c478bd9Sstevel@tonic-gate break; 674*7c478bd9Sstevel@tonic-gate } 675*7c478bd9Sstevel@tonic-gate 676*7c478bd9Sstevel@tonic-gate } else if (flags & NFSMNT_SECURE) { 677*7c478bd9Sstevel@tonic-gate /* 678*7c478bd9Sstevel@tonic-gate * NFSMNT_SECURE is deprecated but we keep it 679*7c478bd9Sstevel@tonic-gate * to support the rouge user generated application 680*7c478bd9Sstevel@tonic-gate * that may use this undocumented interface to do 681*7c478bd9Sstevel@tonic-gate * AUTH_DH security. 682*7c478bd9Sstevel@tonic-gate */ 683*7c478bd9Sstevel@tonic-gate secdata = create_authdh_data(netname, nlen, &syncaddr, knconf); 684*7c478bd9Sstevel@tonic-gate 685*7c478bd9Sstevel@tonic-gate } else { 686*7c478bd9Sstevel@tonic-gate secdata = kmem_alloc(sizeof (*secdata), KM_SLEEP); 687*7c478bd9Sstevel@tonic-gate secdata->secmod = secdata->rpcflavor = AUTH_SYS; 688*7c478bd9Sstevel@tonic-gate secdata->data = NULL; 689*7c478bd9Sstevel@tonic-gate } 690*7c478bd9Sstevel@tonic-gate 691*7c478bd9Sstevel@tonic-gate svp->sv_secdata = secdata; 692*7c478bd9Sstevel@tonic-gate 693*7c478bd9Sstevel@tonic-gate /* syncaddr is no longer needed. */ 694*7c478bd9Sstevel@tonic-gate if (syncaddr.buf != NULL) 695*7c478bd9Sstevel@tonic-gate kmem_free(syncaddr.buf, syncaddr.len); 696*7c478bd9Sstevel@tonic-gate 697*7c478bd9Sstevel@tonic-gate /* 698*7c478bd9Sstevel@tonic-gate * User does not explictly specify a flavor, and a user 699*7c478bd9Sstevel@tonic-gate * defined default flavor is passed down. 700*7c478bd9Sstevel@tonic-gate */ 701*7c478bd9Sstevel@tonic-gate if (flags & NFSMNT_SECDEFAULT) { 702*7c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 703*7c478bd9Sstevel@tonic-gate svp->sv_flags |= SV4_TRYSECDEFAULT; 704*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 705*7c478bd9Sstevel@tonic-gate } 706*7c478bd9Sstevel@tonic-gate 707*7c478bd9Sstevel@tonic-gate /* 708*7c478bd9Sstevel@tonic-gate * Failover support: 709*7c478bd9Sstevel@tonic-gate * 710*7c478bd9Sstevel@tonic-gate * We may have a linked list of nfs_args structures, 711*7c478bd9Sstevel@tonic-gate * which means the user is looking for failover. If 712*7c478bd9Sstevel@tonic-gate * the mount is either not "read-only" or "soft", 713*7c478bd9Sstevel@tonic-gate * we want to bail out with EINVAL. 714*7c478bd9Sstevel@tonic-gate */ 715*7c478bd9Sstevel@tonic-gate if (STRUCT_FGET(args, nfs_args_ext) == NFS_ARGS_EXTB && 716*7c478bd9Sstevel@tonic-gate STRUCT_FGETP(args, nfs_ext_u.nfs_extB.next) != NULL) { 717*7c478bd9Sstevel@tonic-gate if (uap->flags & MS_RDONLY && !(flags & NFSMNT_SOFT)) { 718*7c478bd9Sstevel@tonic-gate data = (char *)STRUCT_FGETP(args, 719*7c478bd9Sstevel@tonic-gate nfs_ext_u.nfs_extB.next); 720*7c478bd9Sstevel@tonic-gate goto more; 721*7c478bd9Sstevel@tonic-gate } 722*7c478bd9Sstevel@tonic-gate error = EINVAL; 723*7c478bd9Sstevel@tonic-gate goto errout; 724*7c478bd9Sstevel@tonic-gate } 725*7c478bd9Sstevel@tonic-gate 726*7c478bd9Sstevel@tonic-gate /* 727*7c478bd9Sstevel@tonic-gate * Determine the zone we're being mounted into. 728*7c478bd9Sstevel@tonic-gate */ 729*7c478bd9Sstevel@tonic-gate if (getzoneid() == GLOBAL_ZONEID) { 730*7c478bd9Sstevel@tonic-gate zone_t *mntzone; 731*7c478bd9Sstevel@tonic-gate 732*7c478bd9Sstevel@tonic-gate mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt)); 733*7c478bd9Sstevel@tonic-gate ASSERT(mntzone != NULL); 734*7c478bd9Sstevel@tonic-gate zone_rele(mntzone); 735*7c478bd9Sstevel@tonic-gate if (mntzone != zone) { 736*7c478bd9Sstevel@tonic-gate error = EBUSY; 737*7c478bd9Sstevel@tonic-gate goto errout; 738*7c478bd9Sstevel@tonic-gate } 739*7c478bd9Sstevel@tonic-gate } 740*7c478bd9Sstevel@tonic-gate 741*7c478bd9Sstevel@tonic-gate /* 742*7c478bd9Sstevel@tonic-gate * Stop the mount from going any further if the zone is going away. 743*7c478bd9Sstevel@tonic-gate */ 744*7c478bd9Sstevel@tonic-gate if (zone_status_get(zone) >= ZONE_IS_SHUTTING_DOWN) { 745*7c478bd9Sstevel@tonic-gate error = EBUSY; 746*7c478bd9Sstevel@tonic-gate goto errout; 747*7c478bd9Sstevel@tonic-gate } 748*7c478bd9Sstevel@tonic-gate 749*7c478bd9Sstevel@tonic-gate /* 750*7c478bd9Sstevel@tonic-gate * Get root vnode. 751*7c478bd9Sstevel@tonic-gate */ 752*7c478bd9Sstevel@tonic-gate proceed: 753*7c478bd9Sstevel@tonic-gate error = nfs4rootvp(&rtvp, vfsp, svp_head, flags, cr, zone); 754*7c478bd9Sstevel@tonic-gate 755*7c478bd9Sstevel@tonic-gate if (error) 756*7c478bd9Sstevel@tonic-gate goto errout; 757*7c478bd9Sstevel@tonic-gate 758*7c478bd9Sstevel@tonic-gate mi = VTOMI4(rtvp); 759*7c478bd9Sstevel@tonic-gate 760*7c478bd9Sstevel@tonic-gate /* 761*7c478bd9Sstevel@tonic-gate * Send client id to the server, if necessary 762*7c478bd9Sstevel@tonic-gate */ 763*7c478bd9Sstevel@tonic-gate nfs4_error_zinit(&n4e); 764*7c478bd9Sstevel@tonic-gate nfs4setclientid(mi, cr, FALSE, &n4e); 765*7c478bd9Sstevel@tonic-gate error = n4e.error; 766*7c478bd9Sstevel@tonic-gate 767*7c478bd9Sstevel@tonic-gate if (error) 768*7c478bd9Sstevel@tonic-gate goto errout; 769*7c478bd9Sstevel@tonic-gate 770*7c478bd9Sstevel@tonic-gate /* 771*7c478bd9Sstevel@tonic-gate * Set option fields in the mount info record 772*7c478bd9Sstevel@tonic-gate */ 773*7c478bd9Sstevel@tonic-gate 774*7c478bd9Sstevel@tonic-gate if (svp_head->sv_next) { 775*7c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 776*7c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_LLOCK; 777*7c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 778*7c478bd9Sstevel@tonic-gate } 779*7c478bd9Sstevel@tonic-gate 780*7c478bd9Sstevel@tonic-gate error = nfs4_setopts(rtvp, get_udatamodel(), STRUCT_BUF(args)); 781*7c478bd9Sstevel@tonic-gate 782*7c478bd9Sstevel@tonic-gate errout: 783*7c478bd9Sstevel@tonic-gate if (error) { 784*7c478bd9Sstevel@tonic-gate if (rtvp != NULL) { 785*7c478bd9Sstevel@tonic-gate rp = VTOR4(rtvp); 786*7c478bd9Sstevel@tonic-gate if (rp->r_flags & R4HASHED) 787*7c478bd9Sstevel@tonic-gate rp4_rmhash(rp); 788*7c478bd9Sstevel@tonic-gate if (rp->r_flags & R4FILEIDMAP) 789*7c478bd9Sstevel@tonic-gate rp4_fileid_map_remove(rp); 790*7c478bd9Sstevel@tonic-gate } 791*7c478bd9Sstevel@tonic-gate if (mi != NULL) { 792*7c478bd9Sstevel@tonic-gate nfs4_async_stop(vfsp); 793*7c478bd9Sstevel@tonic-gate nfs4_async_manager_stop(vfsp); 794*7c478bd9Sstevel@tonic-gate nfs4_remove_mi_from_server(mi, NULL); 795*7c478bd9Sstevel@tonic-gate /* 796*7c478bd9Sstevel@tonic-gate * In this error path we need to sfh4_rele() before 797*7c478bd9Sstevel@tonic-gate * we free the mntinfo4_t as sfh4_rele() has a 798*7c478bd9Sstevel@tonic-gate * dependancy on mi_fh_lock. 799*7c478bd9Sstevel@tonic-gate */ 800*7c478bd9Sstevel@tonic-gate if (rtvp != NULL) 801*7c478bd9Sstevel@tonic-gate VN_RELE(rtvp); 802*7c478bd9Sstevel@tonic-gate if (mi->mi_io_kstats) { 803*7c478bd9Sstevel@tonic-gate kstat_delete(mi->mi_io_kstats); 804*7c478bd9Sstevel@tonic-gate mi->mi_io_kstats = NULL; 805*7c478bd9Sstevel@tonic-gate } 806*7c478bd9Sstevel@tonic-gate if (mi->mi_ro_kstats) { 807*7c478bd9Sstevel@tonic-gate kstat_delete(mi->mi_ro_kstats); 808*7c478bd9Sstevel@tonic-gate mi->mi_ro_kstats = NULL; 809*7c478bd9Sstevel@tonic-gate } 810*7c478bd9Sstevel@tonic-gate if (mi->mi_recov_ksp) { 811*7c478bd9Sstevel@tonic-gate kstat_delete(mi->mi_recov_ksp); 812*7c478bd9Sstevel@tonic-gate mi->mi_recov_ksp = NULL; 813*7c478bd9Sstevel@tonic-gate } 814*7c478bd9Sstevel@tonic-gate nfs_free_mi4(mi); 815*7c478bd9Sstevel@tonic-gate return (error); 816*7c478bd9Sstevel@tonic-gate } 817*7c478bd9Sstevel@tonic-gate sv4_free(svp_head); 818*7c478bd9Sstevel@tonic-gate } 819*7c478bd9Sstevel@tonic-gate 820*7c478bd9Sstevel@tonic-gate if (rtvp != NULL) 821*7c478bd9Sstevel@tonic-gate VN_RELE(rtvp); 822*7c478bd9Sstevel@tonic-gate 823*7c478bd9Sstevel@tonic-gate return (error); 824*7c478bd9Sstevel@tonic-gate } 825*7c478bd9Sstevel@tonic-gate 826*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 827*7c478bd9Sstevel@tonic-gate #define VERS_MSG "NFS4 server " 828*7c478bd9Sstevel@tonic-gate #else 829*7c478bd9Sstevel@tonic-gate #define VERS_MSG "NFS server " 830*7c478bd9Sstevel@tonic-gate #endif 831*7c478bd9Sstevel@tonic-gate 832*7c478bd9Sstevel@tonic-gate #define READ_MSG \ 833*7c478bd9Sstevel@tonic-gate VERS_MSG "%s returned 0 for read transfer size" 834*7c478bd9Sstevel@tonic-gate #define WRITE_MSG \ 835*7c478bd9Sstevel@tonic-gate VERS_MSG "%s returned 0 for write transfer size" 836*7c478bd9Sstevel@tonic-gate #define SIZE_MSG \ 837*7c478bd9Sstevel@tonic-gate VERS_MSG "%s returned 0 for maximum file size" 838*7c478bd9Sstevel@tonic-gate 839*7c478bd9Sstevel@tonic-gate /* 840*7c478bd9Sstevel@tonic-gate * Get the symbolic link text from the server for a given filehandle 841*7c478bd9Sstevel@tonic-gate * of that symlink. 842*7c478bd9Sstevel@tonic-gate * 843*7c478bd9Sstevel@tonic-gate * (get symlink text) PUTFH READLINK 844*7c478bd9Sstevel@tonic-gate */ 845*7c478bd9Sstevel@tonic-gate static int 846*7c478bd9Sstevel@tonic-gate getlinktext_otw(mntinfo4_t *mi, nfs_fh4 *fh, char **linktextp, cred_t *cr, 847*7c478bd9Sstevel@tonic-gate int flags) 848*7c478bd9Sstevel@tonic-gate { 849*7c478bd9Sstevel@tonic-gate COMPOUND4args_clnt args; 850*7c478bd9Sstevel@tonic-gate COMPOUND4res_clnt res; 851*7c478bd9Sstevel@tonic-gate int doqueue; 852*7c478bd9Sstevel@tonic-gate nfs_argop4 argop[2]; 853*7c478bd9Sstevel@tonic-gate nfs_resop4 *resop; 854*7c478bd9Sstevel@tonic-gate READLINK4res *lr_res; 855*7c478bd9Sstevel@tonic-gate uint_t len; 856*7c478bd9Sstevel@tonic-gate bool_t needrecov = FALSE; 857*7c478bd9Sstevel@tonic-gate nfs4_recov_state_t recov_state; 858*7c478bd9Sstevel@tonic-gate nfs4_sharedfh_t *sfh; 859*7c478bd9Sstevel@tonic-gate nfs4_error_t e; 860*7c478bd9Sstevel@tonic-gate int num_retry = nfs4_max_mount_retry; 861*7c478bd9Sstevel@tonic-gate int recovery = !(flags & NFS4_GETFH_NEEDSOP); 862*7c478bd9Sstevel@tonic-gate 863*7c478bd9Sstevel@tonic-gate sfh = sfh4_get(fh, mi); 864*7c478bd9Sstevel@tonic-gate recov_state.rs_flags = 0; 865*7c478bd9Sstevel@tonic-gate recov_state.rs_num_retry_despite_err = 0; 866*7c478bd9Sstevel@tonic-gate 867*7c478bd9Sstevel@tonic-gate recov_retry: 868*7c478bd9Sstevel@tonic-gate nfs4_error_zinit(&e); 869*7c478bd9Sstevel@tonic-gate 870*7c478bd9Sstevel@tonic-gate args.array_len = 2; 871*7c478bd9Sstevel@tonic-gate args.array = argop; 872*7c478bd9Sstevel@tonic-gate args.ctag = TAG_GET_SYMLINK; 873*7c478bd9Sstevel@tonic-gate 874*7c478bd9Sstevel@tonic-gate if (! recovery) { 875*7c478bd9Sstevel@tonic-gate e.error = nfs4_start_op(mi, NULL, NULL, &recov_state); 876*7c478bd9Sstevel@tonic-gate if (e.error) { 877*7c478bd9Sstevel@tonic-gate sfh4_rele(&sfh); 878*7c478bd9Sstevel@tonic-gate return (e.error); 879*7c478bd9Sstevel@tonic-gate } 880*7c478bd9Sstevel@tonic-gate } 881*7c478bd9Sstevel@tonic-gate 882*7c478bd9Sstevel@tonic-gate /* 0. putfh symlink fh */ 883*7c478bd9Sstevel@tonic-gate argop[0].argop = OP_CPUTFH; 884*7c478bd9Sstevel@tonic-gate argop[0].nfs_argop4_u.opcputfh.sfh = sfh; 885*7c478bd9Sstevel@tonic-gate 886*7c478bd9Sstevel@tonic-gate /* 1. readlink */ 887*7c478bd9Sstevel@tonic-gate argop[1].argop = OP_READLINK; 888*7c478bd9Sstevel@tonic-gate 889*7c478bd9Sstevel@tonic-gate doqueue = 1; 890*7c478bd9Sstevel@tonic-gate 891*7c478bd9Sstevel@tonic-gate rfs4call(mi, &args, &res, cr, &doqueue, 0, &e); 892*7c478bd9Sstevel@tonic-gate 893*7c478bd9Sstevel@tonic-gate needrecov = nfs4_needs_recovery(&e, FALSE, mi->mi_vfsp); 894*7c478bd9Sstevel@tonic-gate 895*7c478bd9Sstevel@tonic-gate if (needrecov && !recovery && num_retry-- > 0) { 896*7c478bd9Sstevel@tonic-gate 897*7c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE, 898*7c478bd9Sstevel@tonic-gate "getlinktext_otw: initiating recovery\n")); 899*7c478bd9Sstevel@tonic-gate 900*7c478bd9Sstevel@tonic-gate if (nfs4_start_recovery(&e, mi, NULL, NULL, NULL, NULL, 901*7c478bd9Sstevel@tonic-gate OP_READLINK, NULL) == FALSE) { 902*7c478bd9Sstevel@tonic-gate nfs4_end_op(mi, NULL, NULL, &recov_state, needrecov); 903*7c478bd9Sstevel@tonic-gate if (!e.error) 904*7c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, 905*7c478bd9Sstevel@tonic-gate (caddr_t)&res); 906*7c478bd9Sstevel@tonic-gate goto recov_retry; 907*7c478bd9Sstevel@tonic-gate } 908*7c478bd9Sstevel@tonic-gate } 909*7c478bd9Sstevel@tonic-gate 910*7c478bd9Sstevel@tonic-gate /* 911*7c478bd9Sstevel@tonic-gate * If non-NFS4 pcol error and/or we weren't able to recover. 912*7c478bd9Sstevel@tonic-gate */ 913*7c478bd9Sstevel@tonic-gate if (e.error != 0) { 914*7c478bd9Sstevel@tonic-gate if (! recovery) 915*7c478bd9Sstevel@tonic-gate nfs4_end_op(mi, NULL, NULL, &recov_state, needrecov); 916*7c478bd9Sstevel@tonic-gate sfh4_rele(&sfh); 917*7c478bd9Sstevel@tonic-gate return (e.error); 918*7c478bd9Sstevel@tonic-gate } 919*7c478bd9Sstevel@tonic-gate 920*7c478bd9Sstevel@tonic-gate if (res.status) { 921*7c478bd9Sstevel@tonic-gate e.error = geterrno4(res.status); 922*7c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 923*7c478bd9Sstevel@tonic-gate if (! recovery) 924*7c478bd9Sstevel@tonic-gate nfs4_end_op(mi, NULL, NULL, &recov_state, needrecov); 925*7c478bd9Sstevel@tonic-gate sfh4_rele(&sfh); 926*7c478bd9Sstevel@tonic-gate return (e.error); 927*7c478bd9Sstevel@tonic-gate } 928*7c478bd9Sstevel@tonic-gate 929*7c478bd9Sstevel@tonic-gate /* res.status == NFS4_OK */ 930*7c478bd9Sstevel@tonic-gate ASSERT(res.status == NFS4_OK); 931*7c478bd9Sstevel@tonic-gate 932*7c478bd9Sstevel@tonic-gate resop = &res.array[1]; /* readlink res */ 933*7c478bd9Sstevel@tonic-gate lr_res = &resop->nfs_resop4_u.opreadlink; 934*7c478bd9Sstevel@tonic-gate 935*7c478bd9Sstevel@tonic-gate /* treat symlink name as data */ 936*7c478bd9Sstevel@tonic-gate *linktextp = utf8_to_str(&lr_res->link, &len, NULL); 937*7c478bd9Sstevel@tonic-gate 938*7c478bd9Sstevel@tonic-gate if (! recovery) 939*7c478bd9Sstevel@tonic-gate nfs4_end_op(mi, NULL, NULL, &recov_state, needrecov); 940*7c478bd9Sstevel@tonic-gate sfh4_rele(&sfh); 941*7c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 942*7c478bd9Sstevel@tonic-gate 943*7c478bd9Sstevel@tonic-gate return (0); 944*7c478bd9Sstevel@tonic-gate } 945*7c478bd9Sstevel@tonic-gate 946*7c478bd9Sstevel@tonic-gate /* 947*7c478bd9Sstevel@tonic-gate * Skip over consecutive slashes and "/./" in a pathname. 948*7c478bd9Sstevel@tonic-gate */ 949*7c478bd9Sstevel@tonic-gate void 950*7c478bd9Sstevel@tonic-gate pathname_skipslashdot(struct pathname *pnp) 951*7c478bd9Sstevel@tonic-gate { 952*7c478bd9Sstevel@tonic-gate char *c1, *c2; 953*7c478bd9Sstevel@tonic-gate 954*7c478bd9Sstevel@tonic-gate while (pnp->pn_pathlen > 0 && *pnp->pn_path == '/') { 955*7c478bd9Sstevel@tonic-gate 956*7c478bd9Sstevel@tonic-gate c1 = pnp->pn_path + 1; 957*7c478bd9Sstevel@tonic-gate c2 = pnp->pn_path + 2; 958*7c478bd9Sstevel@tonic-gate 959*7c478bd9Sstevel@tonic-gate if (*c1 == '.' && (*c2 == '/' || *c2 == '\0')) { 960*7c478bd9Sstevel@tonic-gate pnp->pn_path = pnp->pn_path + 2; /* skip "/." */ 961*7c478bd9Sstevel@tonic-gate pnp->pn_pathlen = pnp->pn_pathlen - 2; 962*7c478bd9Sstevel@tonic-gate } else { 963*7c478bd9Sstevel@tonic-gate pnp->pn_path++; 964*7c478bd9Sstevel@tonic-gate pnp->pn_pathlen--; 965*7c478bd9Sstevel@tonic-gate } 966*7c478bd9Sstevel@tonic-gate } 967*7c478bd9Sstevel@tonic-gate } 968*7c478bd9Sstevel@tonic-gate 969*7c478bd9Sstevel@tonic-gate /* 970*7c478bd9Sstevel@tonic-gate * Resolve a symbolic link path. The symlink is in the nth component of 971*7c478bd9Sstevel@tonic-gate * svp->sv_path and has an nfs4 file handle "fh". 972*7c478bd9Sstevel@tonic-gate * Upon return, the sv_path will point to the new path that has the nth 973*7c478bd9Sstevel@tonic-gate * component resolved to its symlink text. 974*7c478bd9Sstevel@tonic-gate */ 975*7c478bd9Sstevel@tonic-gate int 976*7c478bd9Sstevel@tonic-gate resolve_sympath(mntinfo4_t *mi, servinfo4_t *svp, int nth, nfs_fh4 *fh, 977*7c478bd9Sstevel@tonic-gate cred_t *cr, int flags) 978*7c478bd9Sstevel@tonic-gate { 979*7c478bd9Sstevel@tonic-gate char *oldpath; 980*7c478bd9Sstevel@tonic-gate char *symlink, *newpath; 981*7c478bd9Sstevel@tonic-gate struct pathname oldpn, newpn; 982*7c478bd9Sstevel@tonic-gate char component[MAXNAMELEN]; 983*7c478bd9Sstevel@tonic-gate int i, addlen, error = 0; 984*7c478bd9Sstevel@tonic-gate int oldpathlen; 985*7c478bd9Sstevel@tonic-gate 986*7c478bd9Sstevel@tonic-gate /* Get the symbolic link text over the wire. */ 987*7c478bd9Sstevel@tonic-gate error = getlinktext_otw(mi, fh, &symlink, cr, flags); 988*7c478bd9Sstevel@tonic-gate 989*7c478bd9Sstevel@tonic-gate if (error || symlink == NULL || strlen(symlink) == 0) 990*7c478bd9Sstevel@tonic-gate return (error); 991*7c478bd9Sstevel@tonic-gate 992*7c478bd9Sstevel@tonic-gate /* 993*7c478bd9Sstevel@tonic-gate * Compose the new pathname. 994*7c478bd9Sstevel@tonic-gate * Note: 995*7c478bd9Sstevel@tonic-gate * - only the nth component is resolved for the pathname. 996*7c478bd9Sstevel@tonic-gate * - pathname.pn_pathlen does not count the ending null byte. 997*7c478bd9Sstevel@tonic-gate */ 998*7c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 999*7c478bd9Sstevel@tonic-gate oldpath = svp->sv_path; 1000*7c478bd9Sstevel@tonic-gate oldpathlen = svp->sv_pathlen; 1001*7c478bd9Sstevel@tonic-gate if (error = pn_get(oldpath, UIO_SYSSPACE, &oldpn)) { 1002*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 1003*7c478bd9Sstevel@tonic-gate kmem_free(symlink, strlen(symlink) + 1); 1004*7c478bd9Sstevel@tonic-gate return (error); 1005*7c478bd9Sstevel@tonic-gate } 1006*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 1007*7c478bd9Sstevel@tonic-gate pn_alloc(&newpn); 1008*7c478bd9Sstevel@tonic-gate 1009*7c478bd9Sstevel@tonic-gate /* 1010*7c478bd9Sstevel@tonic-gate * Skip over previous components from the oldpath so that the 1011*7c478bd9Sstevel@tonic-gate * oldpn.pn_path will point to the symlink component. Skip 1012*7c478bd9Sstevel@tonic-gate * leading slashes and "/./" (no OP_LOOKUP on ".") so that 1013*7c478bd9Sstevel@tonic-gate * pn_getcompnent can get the component. 1014*7c478bd9Sstevel@tonic-gate */ 1015*7c478bd9Sstevel@tonic-gate for (i = 1; i < nth; i++) { 1016*7c478bd9Sstevel@tonic-gate pathname_skipslashdot(&oldpn); 1017*7c478bd9Sstevel@tonic-gate error = pn_getcomponent(&oldpn, component); 1018*7c478bd9Sstevel@tonic-gate if (error) 1019*7c478bd9Sstevel@tonic-gate goto out; 1020*7c478bd9Sstevel@tonic-gate } 1021*7c478bd9Sstevel@tonic-gate 1022*7c478bd9Sstevel@tonic-gate /* 1023*7c478bd9Sstevel@tonic-gate * Copy the old path upto the component right before the symlink 1024*7c478bd9Sstevel@tonic-gate * if the symlink is not an absolute path. 1025*7c478bd9Sstevel@tonic-gate */ 1026*7c478bd9Sstevel@tonic-gate if (symlink[0] != '/') { 1027*7c478bd9Sstevel@tonic-gate addlen = oldpn.pn_path - oldpn.pn_buf; 1028*7c478bd9Sstevel@tonic-gate bcopy(oldpn.pn_buf, newpn.pn_path, addlen); 1029*7c478bd9Sstevel@tonic-gate newpn.pn_pathlen += addlen; 1030*7c478bd9Sstevel@tonic-gate newpn.pn_path += addlen; 1031*7c478bd9Sstevel@tonic-gate newpn.pn_buf[newpn.pn_pathlen] = '/'; 1032*7c478bd9Sstevel@tonic-gate newpn.pn_pathlen++; 1033*7c478bd9Sstevel@tonic-gate newpn.pn_path++; 1034*7c478bd9Sstevel@tonic-gate } 1035*7c478bd9Sstevel@tonic-gate 1036*7c478bd9Sstevel@tonic-gate /* copy the resolved symbolic link text */ 1037*7c478bd9Sstevel@tonic-gate addlen = strlen(symlink); 1038*7c478bd9Sstevel@tonic-gate if (newpn.pn_pathlen + addlen >= newpn.pn_bufsize) { 1039*7c478bd9Sstevel@tonic-gate error = ENAMETOOLONG; 1040*7c478bd9Sstevel@tonic-gate goto out; 1041*7c478bd9Sstevel@tonic-gate } 1042*7c478bd9Sstevel@tonic-gate bcopy(symlink, newpn.pn_path, addlen); 1043*7c478bd9Sstevel@tonic-gate newpn.pn_pathlen += addlen; 1044*7c478bd9Sstevel@tonic-gate newpn.pn_path += addlen; 1045*7c478bd9Sstevel@tonic-gate 1046*7c478bd9Sstevel@tonic-gate /* 1047*7c478bd9Sstevel@tonic-gate * Check if there is any remaining path after the symlink component. 1048*7c478bd9Sstevel@tonic-gate * First, skip the symlink component. 1049*7c478bd9Sstevel@tonic-gate */ 1050*7c478bd9Sstevel@tonic-gate pathname_skipslashdot(&oldpn); 1051*7c478bd9Sstevel@tonic-gate if (error = pn_getcomponent(&oldpn, component)) 1052*7c478bd9Sstevel@tonic-gate goto out; 1053*7c478bd9Sstevel@tonic-gate 1054*7c478bd9Sstevel@tonic-gate addlen = pn_pathleft(&oldpn); /* includes counting the slash */ 1055*7c478bd9Sstevel@tonic-gate 1056*7c478bd9Sstevel@tonic-gate /* 1057*7c478bd9Sstevel@tonic-gate * Copy the remaining path to the new pathname if there is any. 1058*7c478bd9Sstevel@tonic-gate */ 1059*7c478bd9Sstevel@tonic-gate if (addlen > 0) { 1060*7c478bd9Sstevel@tonic-gate if (newpn.pn_pathlen + addlen >= newpn.pn_bufsize) { 1061*7c478bd9Sstevel@tonic-gate error = ENAMETOOLONG; 1062*7c478bd9Sstevel@tonic-gate goto out; 1063*7c478bd9Sstevel@tonic-gate } 1064*7c478bd9Sstevel@tonic-gate bcopy(oldpn.pn_path, newpn.pn_path, addlen); 1065*7c478bd9Sstevel@tonic-gate newpn.pn_pathlen += addlen; 1066*7c478bd9Sstevel@tonic-gate } 1067*7c478bd9Sstevel@tonic-gate newpn.pn_buf[newpn.pn_pathlen] = '\0'; 1068*7c478bd9Sstevel@tonic-gate 1069*7c478bd9Sstevel@tonic-gate /* get the newpath and store it in the servinfo4_t */ 1070*7c478bd9Sstevel@tonic-gate newpath = kmem_alloc(newpn.pn_pathlen + 1, KM_SLEEP); 1071*7c478bd9Sstevel@tonic-gate bcopy(newpn.pn_buf, newpath, newpn.pn_pathlen); 1072*7c478bd9Sstevel@tonic-gate newpath[newpn.pn_pathlen] = '\0'; 1073*7c478bd9Sstevel@tonic-gate 1074*7c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 1075*7c478bd9Sstevel@tonic-gate svp->sv_path = newpath; 1076*7c478bd9Sstevel@tonic-gate svp->sv_pathlen = strlen(newpath) + 1; 1077*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 1078*7c478bd9Sstevel@tonic-gate 1079*7c478bd9Sstevel@tonic-gate kmem_free(oldpath, oldpathlen); 1080*7c478bd9Sstevel@tonic-gate out: 1081*7c478bd9Sstevel@tonic-gate kmem_free(symlink, strlen(symlink) + 1); 1082*7c478bd9Sstevel@tonic-gate pn_free(&newpn); 1083*7c478bd9Sstevel@tonic-gate pn_free(&oldpn); 1084*7c478bd9Sstevel@tonic-gate 1085*7c478bd9Sstevel@tonic-gate return (error); 1086*7c478bd9Sstevel@tonic-gate } 1087*7c478bd9Sstevel@tonic-gate 1088*7c478bd9Sstevel@tonic-gate /* 1089*7c478bd9Sstevel@tonic-gate * Get the root filehandle for the given filesystem and server, and update 1090*7c478bd9Sstevel@tonic-gate * svp. 1091*7c478bd9Sstevel@tonic-gate * 1092*7c478bd9Sstevel@tonic-gate * If NFS4_GETFH_NEEDSOP is set, then use nfs4_start_fop and nfs4_end_fop 1093*7c478bd9Sstevel@tonic-gate * to coordinate with recovery. Otherwise, the caller is assumed to be 1094*7c478bd9Sstevel@tonic-gate * the recovery thread or have already done a start_fop. 1095*7c478bd9Sstevel@tonic-gate * 1096*7c478bd9Sstevel@tonic-gate * Errors are returned by the nfs4_error_t parameter. 1097*7c478bd9Sstevel@tonic-gate */ 1098*7c478bd9Sstevel@tonic-gate 1099*7c478bd9Sstevel@tonic-gate static void 1100*7c478bd9Sstevel@tonic-gate nfs4getfh_otw(struct mntinfo4 *mi, servinfo4_t *svp, vtype_t *vtp, 1101*7c478bd9Sstevel@tonic-gate int flags, cred_t *cr, nfs4_error_t *ep) 1102*7c478bd9Sstevel@tonic-gate { 1103*7c478bd9Sstevel@tonic-gate COMPOUND4args_clnt args; 1104*7c478bd9Sstevel@tonic-gate COMPOUND4res_clnt res; 1105*7c478bd9Sstevel@tonic-gate int doqueue = 1; 1106*7c478bd9Sstevel@tonic-gate nfs_argop4 *argop; 1107*7c478bd9Sstevel@tonic-gate nfs_resop4 *resop; 1108*7c478bd9Sstevel@tonic-gate nfs4_ga_res_t *garp; 1109*7c478bd9Sstevel@tonic-gate int num_argops; 1110*7c478bd9Sstevel@tonic-gate lookup4_param_t lookuparg; 1111*7c478bd9Sstevel@tonic-gate nfs_fh4 *tmpfhp; 1112*7c478bd9Sstevel@tonic-gate nfs_fh4 *resfhp; 1113*7c478bd9Sstevel@tonic-gate bool_t needrecov = FALSE; 1114*7c478bd9Sstevel@tonic-gate nfs4_recov_state_t recov_state; 1115*7c478bd9Sstevel@tonic-gate int llndx; 1116*7c478bd9Sstevel@tonic-gate int nthcomp; 1117*7c478bd9Sstevel@tonic-gate int recovery = !(flags & NFS4_GETFH_NEEDSOP); 1118*7c478bd9Sstevel@tonic-gate 1119*7c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 1120*7c478bd9Sstevel@tonic-gate ASSERT(svp->sv_path != NULL); 1121*7c478bd9Sstevel@tonic-gate if (svp->sv_path[0] == '\0') { 1122*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 1123*7c478bd9Sstevel@tonic-gate nfs4_error_init(ep, EINVAL); 1124*7c478bd9Sstevel@tonic-gate return; 1125*7c478bd9Sstevel@tonic-gate } 1126*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 1127*7c478bd9Sstevel@tonic-gate 1128*7c478bd9Sstevel@tonic-gate recov_state.rs_flags = 0; 1129*7c478bd9Sstevel@tonic-gate recov_state.rs_num_retry_despite_err = 0; 1130*7c478bd9Sstevel@tonic-gate recov_retry: 1131*7c478bd9Sstevel@tonic-gate nfs4_error_zinit(ep); 1132*7c478bd9Sstevel@tonic-gate 1133*7c478bd9Sstevel@tonic-gate if (!recovery) { 1134*7c478bd9Sstevel@tonic-gate ep->error = nfs4_start_fop(mi, NULL, NULL, OH_MOUNT, 1135*7c478bd9Sstevel@tonic-gate &recov_state, NULL); 1136*7c478bd9Sstevel@tonic-gate 1137*7c478bd9Sstevel@tonic-gate /* 1138*7c478bd9Sstevel@tonic-gate * If recovery has been started and this request as 1139*7c478bd9Sstevel@tonic-gate * initiated by a mount, then we must wait for recovery 1140*7c478bd9Sstevel@tonic-gate * to finish before proceeding, otherwise, the error 1141*7c478bd9Sstevel@tonic-gate * cleanup would remove data structures needed by the 1142*7c478bd9Sstevel@tonic-gate * recovery thread. 1143*7c478bd9Sstevel@tonic-gate */ 1144*7c478bd9Sstevel@tonic-gate if (ep->error) { 1145*7c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 1146*7c478bd9Sstevel@tonic-gate if (mi->mi_flags & MI4_MOUNTING) { 1147*7c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_RECOV_FAIL; 1148*7c478bd9Sstevel@tonic-gate mi->mi_error = EIO; 1149*7c478bd9Sstevel@tonic-gate 1150*7c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE, 1151*7c478bd9Sstevel@tonic-gate "nfs4getfh_otw: waiting 4 recovery\n")); 1152*7c478bd9Sstevel@tonic-gate 1153*7c478bd9Sstevel@tonic-gate while (mi->mi_flags & MI4_RECOV_ACTIV) 1154*7c478bd9Sstevel@tonic-gate cv_wait(&mi->mi_failover_cv, 1155*7c478bd9Sstevel@tonic-gate &mi->mi_lock); 1156*7c478bd9Sstevel@tonic-gate } 1157*7c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 1158*7c478bd9Sstevel@tonic-gate return; 1159*7c478bd9Sstevel@tonic-gate } 1160*7c478bd9Sstevel@tonic-gate 1161*7c478bd9Sstevel@tonic-gate /* 1162*7c478bd9Sstevel@tonic-gate * If the client does not specify a specific flavor to use 1163*7c478bd9Sstevel@tonic-gate * and has not gotten a secinfo list from the server yet, 1164*7c478bd9Sstevel@tonic-gate * retrieve the secinfo list from the server and use a 1165*7c478bd9Sstevel@tonic-gate * flavor from the list to mount. 1166*7c478bd9Sstevel@tonic-gate * 1167*7c478bd9Sstevel@tonic-gate * If fail to get the secinfo list from the server, then 1168*7c478bd9Sstevel@tonic-gate * try the default flavor. 1169*7c478bd9Sstevel@tonic-gate */ 1170*7c478bd9Sstevel@tonic-gate if ((svp->sv_flags & SV4_TRYSECDEFAULT) && 1171*7c478bd9Sstevel@tonic-gate svp->sv_secinfo == NULL) { 1172*7c478bd9Sstevel@tonic-gate (void) nfs4_secinfo_path(mi, cr, FALSE); 1173*7c478bd9Sstevel@tonic-gate } 1174*7c478bd9Sstevel@tonic-gate } 1175*7c478bd9Sstevel@tonic-gate 1176*7c478bd9Sstevel@tonic-gate if (recovery) 1177*7c478bd9Sstevel@tonic-gate args.ctag = TAG_REMAP_MOUNT; 1178*7c478bd9Sstevel@tonic-gate else 1179*7c478bd9Sstevel@tonic-gate args.ctag = TAG_MOUNT; 1180*7c478bd9Sstevel@tonic-gate 1181*7c478bd9Sstevel@tonic-gate lookuparg.l4_getattrs = LKP4_ALL_ATTRIBUTES; 1182*7c478bd9Sstevel@tonic-gate lookuparg.argsp = &args; 1183*7c478bd9Sstevel@tonic-gate lookuparg.resp = &res; 1184*7c478bd9Sstevel@tonic-gate lookuparg.header_len = 2; /* Putrootfh, getfh */ 1185*7c478bd9Sstevel@tonic-gate lookuparg.trailer_len = 0; 1186*7c478bd9Sstevel@tonic-gate lookuparg.ga_bits = FATTR4_FSINFO_MASK; 1187*7c478bd9Sstevel@tonic-gate lookuparg.mi = mi; 1188*7c478bd9Sstevel@tonic-gate 1189*7c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 1190*7c478bd9Sstevel@tonic-gate ASSERT(svp->sv_path != NULL); 1191*7c478bd9Sstevel@tonic-gate llndx = nfs4lookup_setup(svp->sv_path, &lookuparg, 0); 1192*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 1193*7c478bd9Sstevel@tonic-gate 1194*7c478bd9Sstevel@tonic-gate argop = args.array; 1195*7c478bd9Sstevel@tonic-gate num_argops = args.array_len; 1196*7c478bd9Sstevel@tonic-gate 1197*7c478bd9Sstevel@tonic-gate /* choose public or root filehandle */ 1198*7c478bd9Sstevel@tonic-gate if (flags & NFS4_GETFH_PUBLIC) 1199*7c478bd9Sstevel@tonic-gate argop[0].argop = OP_PUTPUBFH; 1200*7c478bd9Sstevel@tonic-gate else 1201*7c478bd9Sstevel@tonic-gate argop[0].argop = OP_PUTROOTFH; 1202*7c478bd9Sstevel@tonic-gate 1203*7c478bd9Sstevel@tonic-gate /* get fh */ 1204*7c478bd9Sstevel@tonic-gate argop[1].argop = OP_GETFH; 1205*7c478bd9Sstevel@tonic-gate 1206*7c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_call_debug, (CE_NOTE, 1207*7c478bd9Sstevel@tonic-gate "nfs4getfh_otw: %s call, mi 0x%p", 1208*7c478bd9Sstevel@tonic-gate needrecov ? "recov" : "first", (void *)mi)); 1209*7c478bd9Sstevel@tonic-gate 1210*7c478bd9Sstevel@tonic-gate rfs4call(mi, &args, &res, cr, &doqueue, RFSCALL_SOFT, ep); 1211*7c478bd9Sstevel@tonic-gate 1212*7c478bd9Sstevel@tonic-gate needrecov = nfs4_needs_recovery(ep, FALSE, mi->mi_vfsp); 1213*7c478bd9Sstevel@tonic-gate 1214*7c478bd9Sstevel@tonic-gate if (needrecov) { 1215*7c478bd9Sstevel@tonic-gate bool_t abort; 1216*7c478bd9Sstevel@tonic-gate 1217*7c478bd9Sstevel@tonic-gate if (recovery) { 1218*7c478bd9Sstevel@tonic-gate nfs4args_lookup_free(argop, num_argops); 1219*7c478bd9Sstevel@tonic-gate kmem_free(argop, 1220*7c478bd9Sstevel@tonic-gate lookuparg.arglen * sizeof (nfs_argop4)); 1221*7c478bd9Sstevel@tonic-gate if (!ep->error) 1222*7c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, 1223*7c478bd9Sstevel@tonic-gate (caddr_t)&res); 1224*7c478bd9Sstevel@tonic-gate return; 1225*7c478bd9Sstevel@tonic-gate } 1226*7c478bd9Sstevel@tonic-gate 1227*7c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_recov_debug, 1228*7c478bd9Sstevel@tonic-gate (CE_NOTE, "nfs4getfh_otw: initiating recovery\n")); 1229*7c478bd9Sstevel@tonic-gate 1230*7c478bd9Sstevel@tonic-gate abort = nfs4_start_recovery(ep, mi, NULL, 1231*7c478bd9Sstevel@tonic-gate NULL, NULL, NULL, OP_GETFH, NULL); 1232*7c478bd9Sstevel@tonic-gate if (!ep->error) { 1233*7c478bd9Sstevel@tonic-gate ep->error = geterrno4(res.status); 1234*7c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 1235*7c478bd9Sstevel@tonic-gate } 1236*7c478bd9Sstevel@tonic-gate nfs4args_lookup_free(argop, num_argops); 1237*7c478bd9Sstevel@tonic-gate kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4)); 1238*7c478bd9Sstevel@tonic-gate nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state, needrecov); 1239*7c478bd9Sstevel@tonic-gate /* have another go? */ 1240*7c478bd9Sstevel@tonic-gate if (abort == FALSE) 1241*7c478bd9Sstevel@tonic-gate goto recov_retry; 1242*7c478bd9Sstevel@tonic-gate return; 1243*7c478bd9Sstevel@tonic-gate } 1244*7c478bd9Sstevel@tonic-gate 1245*7c478bd9Sstevel@tonic-gate /* 1246*7c478bd9Sstevel@tonic-gate * No recovery, but check if error is set. 1247*7c478bd9Sstevel@tonic-gate */ 1248*7c478bd9Sstevel@tonic-gate if (ep->error) { 1249*7c478bd9Sstevel@tonic-gate nfs4args_lookup_free(argop, num_argops); 1250*7c478bd9Sstevel@tonic-gate kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4)); 1251*7c478bd9Sstevel@tonic-gate if (!recovery) 1252*7c478bd9Sstevel@tonic-gate nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state, 1253*7c478bd9Sstevel@tonic-gate needrecov); 1254*7c478bd9Sstevel@tonic-gate return; 1255*7c478bd9Sstevel@tonic-gate } 1256*7c478bd9Sstevel@tonic-gate 1257*7c478bd9Sstevel@tonic-gate is_link_err: 1258*7c478bd9Sstevel@tonic-gate 1259*7c478bd9Sstevel@tonic-gate /* for non-recovery errors */ 1260*7c478bd9Sstevel@tonic-gate if (res.status && res.status != NFS4ERR_SYMLINK) { 1261*7c478bd9Sstevel@tonic-gate if (!recovery) { 1262*7c478bd9Sstevel@tonic-gate nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state, 1263*7c478bd9Sstevel@tonic-gate needrecov); 1264*7c478bd9Sstevel@tonic-gate } 1265*7c478bd9Sstevel@tonic-gate nfs4args_lookup_free(argop, num_argops); 1266*7c478bd9Sstevel@tonic-gate kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4)); 1267*7c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 1268*7c478bd9Sstevel@tonic-gate return; 1269*7c478bd9Sstevel@tonic-gate } 1270*7c478bd9Sstevel@tonic-gate 1271*7c478bd9Sstevel@tonic-gate /* 1272*7c478bd9Sstevel@tonic-gate * If any intermediate component in the path is a symbolic link, 1273*7c478bd9Sstevel@tonic-gate * resolve the symlink, then try mount again using the new path. 1274*7c478bd9Sstevel@tonic-gate */ 1275*7c478bd9Sstevel@tonic-gate if (res.status == NFS4ERR_SYMLINK) { 1276*7c478bd9Sstevel@tonic-gate int where; 1277*7c478bd9Sstevel@tonic-gate 1278*7c478bd9Sstevel@tonic-gate /* 1279*7c478bd9Sstevel@tonic-gate * This must be from OP_LOOKUP failure. The (cfh) for this 1280*7c478bd9Sstevel@tonic-gate * OP_LOOKUP is a symlink node. Found out where the 1281*7c478bd9Sstevel@tonic-gate * OP_GETFH is for the (cfh) that is a symlink node. 1282*7c478bd9Sstevel@tonic-gate * 1283*7c478bd9Sstevel@tonic-gate * Example: 1284*7c478bd9Sstevel@tonic-gate * (mount) PUTROOTFH, GETFH, LOOKUP comp1, GETFH, GETATTR, 1285*7c478bd9Sstevel@tonic-gate * LOOKUP comp2, GETFH, GETATTR, LOOKUP comp3, GETFH, GETATTR 1286*7c478bd9Sstevel@tonic-gate * 1287*7c478bd9Sstevel@tonic-gate * LOOKUP comp3 fails with SYMLINK because comp2 is a symlink. 1288*7c478bd9Sstevel@tonic-gate * In this case, where = 7, nthcomp = 2. 1289*7c478bd9Sstevel@tonic-gate */ 1290*7c478bd9Sstevel@tonic-gate where = res.array_len - 2; 1291*7c478bd9Sstevel@tonic-gate ASSERT(where > 0); 1292*7c478bd9Sstevel@tonic-gate 1293*7c478bd9Sstevel@tonic-gate resop = &res.array[where - 1]; 1294*7c478bd9Sstevel@tonic-gate ASSERT(resop->resop == OP_GETFH); 1295*7c478bd9Sstevel@tonic-gate tmpfhp = &resop->nfs_resop4_u.opgetfh.object; 1296*7c478bd9Sstevel@tonic-gate nthcomp = res.array_len/3 - 1; 1297*7c478bd9Sstevel@tonic-gate 1298*7c478bd9Sstevel@tonic-gate /* 1299*7c478bd9Sstevel@tonic-gate * Need to call nfs4_end_op before resolve_sympath to avoid 1300*7c478bd9Sstevel@tonic-gate * potential nfs4_start_op deadlock. 1301*7c478bd9Sstevel@tonic-gate */ 1302*7c478bd9Sstevel@tonic-gate if (!recovery) 1303*7c478bd9Sstevel@tonic-gate nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state, 1304*7c478bd9Sstevel@tonic-gate needrecov); 1305*7c478bd9Sstevel@tonic-gate 1306*7c478bd9Sstevel@tonic-gate ep->error = resolve_sympath(mi, svp, nthcomp, tmpfhp, cr, 1307*7c478bd9Sstevel@tonic-gate flags); 1308*7c478bd9Sstevel@tonic-gate 1309*7c478bd9Sstevel@tonic-gate nfs4args_lookup_free(argop, num_argops); 1310*7c478bd9Sstevel@tonic-gate kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4)); 1311*7c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 1312*7c478bd9Sstevel@tonic-gate 1313*7c478bd9Sstevel@tonic-gate if (ep->error) 1314*7c478bd9Sstevel@tonic-gate return; 1315*7c478bd9Sstevel@tonic-gate 1316*7c478bd9Sstevel@tonic-gate goto recov_retry; 1317*7c478bd9Sstevel@tonic-gate } 1318*7c478bd9Sstevel@tonic-gate 1319*7c478bd9Sstevel@tonic-gate /* getfh */ 1320*7c478bd9Sstevel@tonic-gate resop = &res.array[res.array_len - 2]; 1321*7c478bd9Sstevel@tonic-gate ASSERT(resop->resop == OP_GETFH); 1322*7c478bd9Sstevel@tonic-gate resfhp = &resop->nfs_resop4_u.opgetfh.object; 1323*7c478bd9Sstevel@tonic-gate 1324*7c478bd9Sstevel@tonic-gate /* getattr fsinfo res */ 1325*7c478bd9Sstevel@tonic-gate resop++; 1326*7c478bd9Sstevel@tonic-gate garp = &resop->nfs_resop4_u.opgetattr.ga_res; 1327*7c478bd9Sstevel@tonic-gate 1328*7c478bd9Sstevel@tonic-gate *vtp = garp->n4g_va.va_type; 1329*7c478bd9Sstevel@tonic-gate 1330*7c478bd9Sstevel@tonic-gate mi->mi_fh_expire_type = garp->n4g_ext_res->n4g_fet; 1331*7c478bd9Sstevel@tonic-gate 1332*7c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 1333*7c478bd9Sstevel@tonic-gate if (garp->n4g_ext_res->n4g_pc4.pc4_link_support) 1334*7c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_LINK; 1335*7c478bd9Sstevel@tonic-gate if (garp->n4g_ext_res->n4g_pc4.pc4_symlink_support) 1336*7c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_SYMLINK; 1337*7c478bd9Sstevel@tonic-gate if (garp->n4g_ext_res->n4g_suppattrs & FATTR4_ACL_MASK) 1338*7c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_ACL; 1339*7c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 1340*7c478bd9Sstevel@tonic-gate 1341*7c478bd9Sstevel@tonic-gate if (garp->n4g_ext_res->n4g_maxread == 0) 1342*7c478bd9Sstevel@tonic-gate mi->mi_tsize = 1343*7c478bd9Sstevel@tonic-gate MIN(MAXBSIZE, mi->mi_tsize); 1344*7c478bd9Sstevel@tonic-gate else 1345*7c478bd9Sstevel@tonic-gate mi->mi_tsize = 1346*7c478bd9Sstevel@tonic-gate MIN(garp->n4g_ext_res->n4g_maxread, 1347*7c478bd9Sstevel@tonic-gate mi->mi_tsize); 1348*7c478bd9Sstevel@tonic-gate 1349*7c478bd9Sstevel@tonic-gate if (garp->n4g_ext_res->n4g_maxwrite == 0) 1350*7c478bd9Sstevel@tonic-gate mi->mi_stsize = 1351*7c478bd9Sstevel@tonic-gate MIN(MAXBSIZE, mi->mi_stsize); 1352*7c478bd9Sstevel@tonic-gate else 1353*7c478bd9Sstevel@tonic-gate mi->mi_stsize = 1354*7c478bd9Sstevel@tonic-gate MIN(garp->n4g_ext_res->n4g_maxwrite, 1355*7c478bd9Sstevel@tonic-gate mi->mi_stsize); 1356*7c478bd9Sstevel@tonic-gate 1357*7c478bd9Sstevel@tonic-gate if (garp->n4g_ext_res->n4g_maxfilesize != 0) 1358*7c478bd9Sstevel@tonic-gate mi->mi_maxfilesize = 1359*7c478bd9Sstevel@tonic-gate MIN(garp->n4g_ext_res->n4g_maxfilesize, 1360*7c478bd9Sstevel@tonic-gate mi->mi_maxfilesize); 1361*7c478bd9Sstevel@tonic-gate 1362*7c478bd9Sstevel@tonic-gate /* 1363*7c478bd9Sstevel@tonic-gate * If the final component is a a symbolic link, resolve the symlink, 1364*7c478bd9Sstevel@tonic-gate * then try mount again using the new path. 1365*7c478bd9Sstevel@tonic-gate * 1366*7c478bd9Sstevel@tonic-gate * Assume no symbolic link for root filesysm "/". 1367*7c478bd9Sstevel@tonic-gate */ 1368*7c478bd9Sstevel@tonic-gate if (*vtp == VLNK) { 1369*7c478bd9Sstevel@tonic-gate /* 1370*7c478bd9Sstevel@tonic-gate * nthcomp is the total result length minus 1371*7c478bd9Sstevel@tonic-gate * the 1st 2 OPs (PUTROOTFH, GETFH), 1372*7c478bd9Sstevel@tonic-gate * then divided by 3 (LOOKUP,GETFH,GETATTR) 1373*7c478bd9Sstevel@tonic-gate * 1374*7c478bd9Sstevel@tonic-gate * e.g. PUTROOTFH GETFH LOOKUP 1st-comp GETFH GETATTR 1375*7c478bd9Sstevel@tonic-gate * LOOKUP 2nd-comp GETFH GETATTR 1376*7c478bd9Sstevel@tonic-gate * 1377*7c478bd9Sstevel@tonic-gate * (8 - 2)/3 = 2 1378*7c478bd9Sstevel@tonic-gate */ 1379*7c478bd9Sstevel@tonic-gate nthcomp = (res.array_len - 2)/3; 1380*7c478bd9Sstevel@tonic-gate 1381*7c478bd9Sstevel@tonic-gate /* 1382*7c478bd9Sstevel@tonic-gate * Need to call nfs4_end_op before resolve_sympath to avoid 1383*7c478bd9Sstevel@tonic-gate * potential nfs4_start_op deadlock. See RFE 4777612. 1384*7c478bd9Sstevel@tonic-gate */ 1385*7c478bd9Sstevel@tonic-gate if (!recovery) 1386*7c478bd9Sstevel@tonic-gate nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state, 1387*7c478bd9Sstevel@tonic-gate needrecov); 1388*7c478bd9Sstevel@tonic-gate 1389*7c478bd9Sstevel@tonic-gate ep->error = resolve_sympath(mi, svp, nthcomp, resfhp, cr, 1390*7c478bd9Sstevel@tonic-gate flags); 1391*7c478bd9Sstevel@tonic-gate 1392*7c478bd9Sstevel@tonic-gate nfs4args_lookup_free(argop, num_argops); 1393*7c478bd9Sstevel@tonic-gate kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4)); 1394*7c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 1395*7c478bd9Sstevel@tonic-gate 1396*7c478bd9Sstevel@tonic-gate if (ep->error) 1397*7c478bd9Sstevel@tonic-gate return; 1398*7c478bd9Sstevel@tonic-gate 1399*7c478bd9Sstevel@tonic-gate goto recov_retry; 1400*7c478bd9Sstevel@tonic-gate } 1401*7c478bd9Sstevel@tonic-gate 1402*7c478bd9Sstevel@tonic-gate /* 1403*7c478bd9Sstevel@tonic-gate * We need to figure out where in the compound the getfh 1404*7c478bd9Sstevel@tonic-gate * for the parent directory is. If the object to be mounted is 1405*7c478bd9Sstevel@tonic-gate * the root, then there is no lookup at all: 1406*7c478bd9Sstevel@tonic-gate * PUTROOTFH, GETFH. 1407*7c478bd9Sstevel@tonic-gate * If the object to be mounted is in the root, then the compound is: 1408*7c478bd9Sstevel@tonic-gate * PUTROOTFH, GETFH, LOOKUP, GETFH, GETATTR. 1409*7c478bd9Sstevel@tonic-gate * In either of these cases, the index of the GETFH is 1. 1410*7c478bd9Sstevel@tonic-gate * If it is not at the root, then it's something like: 1411*7c478bd9Sstevel@tonic-gate * PUTROOTFH, GETFH, LOOKUP, GETFH, GETATTR, 1412*7c478bd9Sstevel@tonic-gate * LOOKUP, GETFH, GETATTR 1413*7c478bd9Sstevel@tonic-gate * In this case, the index is llndx (last lookup index) - 2. 1414*7c478bd9Sstevel@tonic-gate */ 1415*7c478bd9Sstevel@tonic-gate if (llndx == -1 || llndx == 2) 1416*7c478bd9Sstevel@tonic-gate resop = &res.array[1]; 1417*7c478bd9Sstevel@tonic-gate else { 1418*7c478bd9Sstevel@tonic-gate ASSERT(llndx > 2); 1419*7c478bd9Sstevel@tonic-gate resop = &res.array[llndx-2]; 1420*7c478bd9Sstevel@tonic-gate } 1421*7c478bd9Sstevel@tonic-gate 1422*7c478bd9Sstevel@tonic-gate ASSERT(resop->resop == OP_GETFH); 1423*7c478bd9Sstevel@tonic-gate tmpfhp = &resop->nfs_resop4_u.opgetfh.object; 1424*7c478bd9Sstevel@tonic-gate 1425*7c478bd9Sstevel@tonic-gate /* save the filehandles for the replica */ 1426*7c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 1427*7c478bd9Sstevel@tonic-gate ASSERT(tmpfhp->nfs_fh4_len <= NFS4_FHSIZE); 1428*7c478bd9Sstevel@tonic-gate svp->sv_pfhandle.fh_len = tmpfhp->nfs_fh4_len; 1429*7c478bd9Sstevel@tonic-gate bcopy(tmpfhp->nfs_fh4_val, svp->sv_pfhandle.fh_buf, 1430*7c478bd9Sstevel@tonic-gate tmpfhp->nfs_fh4_len); 1431*7c478bd9Sstevel@tonic-gate ASSERT(resfhp->nfs_fh4_len <= NFS4_FHSIZE); 1432*7c478bd9Sstevel@tonic-gate svp->sv_fhandle.fh_len = resfhp->nfs_fh4_len; 1433*7c478bd9Sstevel@tonic-gate bcopy(resfhp->nfs_fh4_val, svp->sv_fhandle.fh_buf, resfhp->nfs_fh4_len); 1434*7c478bd9Sstevel@tonic-gate 1435*7c478bd9Sstevel@tonic-gate /* initialize fsid and supp_attrs for server fs */ 1436*7c478bd9Sstevel@tonic-gate svp->sv_fsid = garp->n4g_fsid; 1437*7c478bd9Sstevel@tonic-gate svp->sv_supp_attrs = 1438*7c478bd9Sstevel@tonic-gate garp->n4g_ext_res->n4g_suppattrs | FATTR4_MANDATTR_MASK; 1439*7c478bd9Sstevel@tonic-gate 1440*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 1441*7c478bd9Sstevel@tonic-gate 1442*7c478bd9Sstevel@tonic-gate nfs4args_lookup_free(argop, num_argops); 1443*7c478bd9Sstevel@tonic-gate kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4)); 1444*7c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 1445*7c478bd9Sstevel@tonic-gate if (!recovery) 1446*7c478bd9Sstevel@tonic-gate nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state, needrecov); 1447*7c478bd9Sstevel@tonic-gate } 1448*7c478bd9Sstevel@tonic-gate 1449*7c478bd9Sstevel@tonic-gate static ushort_t nfs4_max_threads = 8; /* max number of active async threads */ 1450*7c478bd9Sstevel@tonic-gate static uint_t nfs4_bsize = 32 * 1024; /* client `block' size */ 1451*7c478bd9Sstevel@tonic-gate static uint_t nfs4_async_clusters = 1; /* # of reqs from each async queue */ 1452*7c478bd9Sstevel@tonic-gate static uint_t nfs4_cots_timeo = NFS_COTS_TIMEO; 1453*7c478bd9Sstevel@tonic-gate 1454*7c478bd9Sstevel@tonic-gate /* 1455*7c478bd9Sstevel@tonic-gate * Remap the root filehandle for the given filesystem. 1456*7c478bd9Sstevel@tonic-gate * 1457*7c478bd9Sstevel@tonic-gate * results returned via the nfs4_error_t parameter. 1458*7c478bd9Sstevel@tonic-gate */ 1459*7c478bd9Sstevel@tonic-gate void 1460*7c478bd9Sstevel@tonic-gate nfs4_remap_root(mntinfo4_t *mi, nfs4_error_t *ep, int flags) 1461*7c478bd9Sstevel@tonic-gate { 1462*7c478bd9Sstevel@tonic-gate struct servinfo4 *svp; 1463*7c478bd9Sstevel@tonic-gate vtype_t vtype; 1464*7c478bd9Sstevel@tonic-gate nfs_fh4 rootfh; 1465*7c478bd9Sstevel@tonic-gate int getfh_flags; 1466*7c478bd9Sstevel@tonic-gate char *orig_sv_path; 1467*7c478bd9Sstevel@tonic-gate int orig_sv_pathlen, num_retry; 1468*7c478bd9Sstevel@tonic-gate 1469*7c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 1470*7c478bd9Sstevel@tonic-gate svp = mi->mi_curr_serv; 1471*7c478bd9Sstevel@tonic-gate getfh_flags = 1472*7c478bd9Sstevel@tonic-gate (flags & NFS4_REMAP_NEEDSOP) ? NFS4_GETFH_NEEDSOP : 0; 1473*7c478bd9Sstevel@tonic-gate getfh_flags |= 1474*7c478bd9Sstevel@tonic-gate (mi->mi_flags & MI4_PUBLIC) ? NFS4_GETFH_PUBLIC : 0; 1475*7c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 1476*7c478bd9Sstevel@tonic-gate 1477*7c478bd9Sstevel@tonic-gate /* 1478*7c478bd9Sstevel@tonic-gate * Just in case server path being mounted contains 1479*7c478bd9Sstevel@tonic-gate * symlinks and fails w/STALE, save the initial sv_path 1480*7c478bd9Sstevel@tonic-gate * so we can redrive the initial mount compound with the 1481*7c478bd9Sstevel@tonic-gate * initial sv_path -- not a symlink-expanded version. 1482*7c478bd9Sstevel@tonic-gate * 1483*7c478bd9Sstevel@tonic-gate * This could only happen if a symlink was expanded 1484*7c478bd9Sstevel@tonic-gate * and the expanded mount compound failed stale. Because 1485*7c478bd9Sstevel@tonic-gate * it could be the case that the symlink was removed at 1486*7c478bd9Sstevel@tonic-gate * the server (and replaced with another symlink/dir, 1487*7c478bd9Sstevel@tonic-gate * we need to use the initial sv_path when attempting 1488*7c478bd9Sstevel@tonic-gate * to re-lookup everything and recover. 1489*7c478bd9Sstevel@tonic-gate */ 1490*7c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 1491*7c478bd9Sstevel@tonic-gate orig_sv_pathlen = svp->sv_pathlen; 1492*7c478bd9Sstevel@tonic-gate orig_sv_path = kmem_alloc(orig_sv_pathlen, KM_SLEEP); 1493*7c478bd9Sstevel@tonic-gate bcopy(svp->sv_path, orig_sv_path, orig_sv_pathlen); 1494*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 1495*7c478bd9Sstevel@tonic-gate 1496*7c478bd9Sstevel@tonic-gate num_retry = nfs4_max_mount_retry; 1497*7c478bd9Sstevel@tonic-gate 1498*7c478bd9Sstevel@tonic-gate do { 1499*7c478bd9Sstevel@tonic-gate /* 1500*7c478bd9Sstevel@tonic-gate * Get the root fh from the server. Retry nfs4_max_mount_retry 1501*7c478bd9Sstevel@tonic-gate * (2) times if it fails with STALE since the recovery 1502*7c478bd9Sstevel@tonic-gate * infrastructure doesn't do STALE recovery for components 1503*7c478bd9Sstevel@tonic-gate * of the server path to the object being mounted. 1504*7c478bd9Sstevel@tonic-gate */ 1505*7c478bd9Sstevel@tonic-gate nfs4getfh_otw(mi, svp, &vtype, getfh_flags, CRED(), ep); 1506*7c478bd9Sstevel@tonic-gate 1507*7c478bd9Sstevel@tonic-gate if (ep->error == 0 && ep->stat == NFS4_OK) 1508*7c478bd9Sstevel@tonic-gate break; 1509*7c478bd9Sstevel@tonic-gate 1510*7c478bd9Sstevel@tonic-gate /* 1511*7c478bd9Sstevel@tonic-gate * For some reason, the mount compound failed. Before 1512*7c478bd9Sstevel@tonic-gate * retrying, we need to restore the original sv_path 1513*7c478bd9Sstevel@tonic-gate * because it might have contained symlinks that were 1514*7c478bd9Sstevel@tonic-gate * expanded by nfsgetfh_otw before the failure occurred. 1515*7c478bd9Sstevel@tonic-gate * replace current sv_path with orig sv_path -- just in case 1516*7c478bd9Sstevel@tonic-gate * it changed due to embedded symlinks. 1517*7c478bd9Sstevel@tonic-gate */ 1518*7c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 1519*7c478bd9Sstevel@tonic-gate if (orig_sv_pathlen != svp->sv_pathlen) { 1520*7c478bd9Sstevel@tonic-gate kmem_free(svp->sv_path, svp->sv_pathlen); 1521*7c478bd9Sstevel@tonic-gate svp->sv_path = kmem_alloc(orig_sv_pathlen, KM_SLEEP); 1522*7c478bd9Sstevel@tonic-gate svp->sv_pathlen = orig_sv_pathlen; 1523*7c478bd9Sstevel@tonic-gate 1524*7c478bd9Sstevel@tonic-gate } 1525*7c478bd9Sstevel@tonic-gate bcopy(orig_sv_path, svp->sv_path, orig_sv_pathlen); 1526*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 1527*7c478bd9Sstevel@tonic-gate 1528*7c478bd9Sstevel@tonic-gate } while (num_retry-- > 0); 1529*7c478bd9Sstevel@tonic-gate 1530*7c478bd9Sstevel@tonic-gate kmem_free(orig_sv_path, orig_sv_pathlen); 1531*7c478bd9Sstevel@tonic-gate 1532*7c478bd9Sstevel@tonic-gate if (ep->error != 0 || ep->stat != 0) { 1533*7c478bd9Sstevel@tonic-gate return; 1534*7c478bd9Sstevel@tonic-gate } 1535*7c478bd9Sstevel@tonic-gate 1536*7c478bd9Sstevel@tonic-gate if (vtype != VNON && vtype != mi->mi_type) { 1537*7c478bd9Sstevel@tonic-gate /* shouldn't happen */ 1538*7c478bd9Sstevel@tonic-gate zcmn_err(mi->mi_zone->zone_id, CE_WARN, 1539*7c478bd9Sstevel@tonic-gate "nfs4_remap_root: server root vnode type (%d) doesn't " 1540*7c478bd9Sstevel@tonic-gate "match mount info (%d)", vtype, mi->mi_type); 1541*7c478bd9Sstevel@tonic-gate } 1542*7c478bd9Sstevel@tonic-gate 1543*7c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 1544*7c478bd9Sstevel@tonic-gate rootfh.nfs_fh4_val = svp->sv_fhandle.fh_buf; 1545*7c478bd9Sstevel@tonic-gate rootfh.nfs_fh4_len = svp->sv_fhandle.fh_len; 1546*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 1547*7c478bd9Sstevel@tonic-gate sfh4_update(mi->mi_rootfh, &rootfh); 1548*7c478bd9Sstevel@tonic-gate 1549*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1550*7c478bd9Sstevel@tonic-gate /* 1551*7c478bd9Sstevel@tonic-gate * There shouldn't have been any other recovery activity on the 1552*7c478bd9Sstevel@tonic-gate * filesystem. 1553*7c478bd9Sstevel@tonic-gate */ 1554*7c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 1555*7c478bd9Sstevel@tonic-gate ASSERT(mi->mi_curr_serv == svp); 1556*7c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 1557*7c478bd9Sstevel@tonic-gate #endif 1558*7c478bd9Sstevel@tonic-gate } 1559*7c478bd9Sstevel@tonic-gate 1560*7c478bd9Sstevel@tonic-gate static int 1561*7c478bd9Sstevel@tonic-gate nfs4rootvp(vnode_t **rtvpp, vfs_t *vfsp, struct servinfo4 *svp_head, 1562*7c478bd9Sstevel@tonic-gate int flags, cred_t *cr, zone_t *zone) 1563*7c478bd9Sstevel@tonic-gate { 1564*7c478bd9Sstevel@tonic-gate vnode_t *rtvp = NULL; 1565*7c478bd9Sstevel@tonic-gate mntinfo4_t *mi; 1566*7c478bd9Sstevel@tonic-gate dev_t nfs_dev; 1567*7c478bd9Sstevel@tonic-gate int error = 0; 1568*7c478bd9Sstevel@tonic-gate rnode4_t *rp; 1569*7c478bd9Sstevel@tonic-gate int i; 1570*7c478bd9Sstevel@tonic-gate struct vattr va; 1571*7c478bd9Sstevel@tonic-gate vtype_t vtype = VNON; 1572*7c478bd9Sstevel@tonic-gate vtype_t tmp_vtype = VNON; 1573*7c478bd9Sstevel@tonic-gate struct servinfo4 *firstsvp = NULL, *svp = svp_head; 1574*7c478bd9Sstevel@tonic-gate nfs4_oo_hash_bucket_t *bucketp; 1575*7c478bd9Sstevel@tonic-gate nfs_fh4 fh; 1576*7c478bd9Sstevel@tonic-gate char *droptext = ""; 1577*7c478bd9Sstevel@tonic-gate struct nfs_stats *nfsstatsp; 1578*7c478bd9Sstevel@tonic-gate nfs4_fname_t *mfname; 1579*7c478bd9Sstevel@tonic-gate nfs4_error_t e; 1580*7c478bd9Sstevel@tonic-gate char *orig_sv_path; 1581*7c478bd9Sstevel@tonic-gate int orig_sv_pathlen, num_retry; 1582*7c478bd9Sstevel@tonic-gate cred_t *lcr = NULL, *tcr = cr; 1583*7c478bd9Sstevel@tonic-gate 1584*7c478bd9Sstevel@tonic-gate nfsstatsp = zone_getspecific(nfsstat_zone_key, curproc->p_zone); 1585*7c478bd9Sstevel@tonic-gate ASSERT(nfsstatsp != NULL); 1586*7c478bd9Sstevel@tonic-gate 1587*7c478bd9Sstevel@tonic-gate ASSERT(curproc->p_zone == zone); 1588*7c478bd9Sstevel@tonic-gate ASSERT(crgetref(cr)); 1589*7c478bd9Sstevel@tonic-gate 1590*7c478bd9Sstevel@tonic-gate /* 1591*7c478bd9Sstevel@tonic-gate * Create a mount record and link it to the vfs struct. 1592*7c478bd9Sstevel@tonic-gate */ 1593*7c478bd9Sstevel@tonic-gate mi = kmem_zalloc(sizeof (*mi), KM_SLEEP); 1594*7c478bd9Sstevel@tonic-gate mutex_init(&mi->mi_lock, NULL, MUTEX_DEFAULT, NULL); 1595*7c478bd9Sstevel@tonic-gate nfs_rw_init(&mi->mi_recovlock, NULL, RW_DEFAULT, NULL); 1596*7c478bd9Sstevel@tonic-gate nfs_rw_init(&mi->mi_rename_lock, NULL, RW_DEFAULT, NULL); 1597*7c478bd9Sstevel@tonic-gate nfs_rw_init(&mi->mi_fh_lock, NULL, RW_DEFAULT, NULL); 1598*7c478bd9Sstevel@tonic-gate 1599*7c478bd9Sstevel@tonic-gate if (!(flags & NFSMNT_SOFT)) 1600*7c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_HARD; 1601*7c478bd9Sstevel@tonic-gate if ((flags & NFSMNT_NOPRINT)) 1602*7c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_NOPRINT; 1603*7c478bd9Sstevel@tonic-gate if (flags & NFSMNT_INT) 1604*7c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_INT; 1605*7c478bd9Sstevel@tonic-gate if (flags & NFSMNT_PUBLIC) 1606*7c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_PUBLIC; 1607*7c478bd9Sstevel@tonic-gate mi->mi_retrans = NFS_RETRIES; 1608*7c478bd9Sstevel@tonic-gate if (svp->sv_knconf->knc_semantics == NC_TPI_COTS_ORD || 1609*7c478bd9Sstevel@tonic-gate svp->sv_knconf->knc_semantics == NC_TPI_COTS) 1610*7c478bd9Sstevel@tonic-gate mi->mi_timeo = nfs4_cots_timeo; 1611*7c478bd9Sstevel@tonic-gate else 1612*7c478bd9Sstevel@tonic-gate mi->mi_timeo = NFS_TIMEO; 1613*7c478bd9Sstevel@tonic-gate mi->mi_prog = NFS_PROGRAM; 1614*7c478bd9Sstevel@tonic-gate mi->mi_vers = NFS_V4; 1615*7c478bd9Sstevel@tonic-gate mi->mi_rfsnames = rfsnames_v4; 1616*7c478bd9Sstevel@tonic-gate mi->mi_reqs = nfsstatsp->nfs_stats_v4.rfsreqcnt_ptr; 1617*7c478bd9Sstevel@tonic-gate cv_init(&mi->mi_failover_cv, NULL, CV_DEFAULT, NULL); 1618*7c478bd9Sstevel@tonic-gate mi->mi_servers = svp; 1619*7c478bd9Sstevel@tonic-gate mi->mi_curr_serv = svp; 1620*7c478bd9Sstevel@tonic-gate mi->mi_acregmin = SEC2HR(ACREGMIN); 1621*7c478bd9Sstevel@tonic-gate mi->mi_acregmax = SEC2HR(ACREGMAX); 1622*7c478bd9Sstevel@tonic-gate mi->mi_acdirmin = SEC2HR(ACDIRMIN); 1623*7c478bd9Sstevel@tonic-gate mi->mi_acdirmax = SEC2HR(ACDIRMAX); 1624*7c478bd9Sstevel@tonic-gate mi->mi_fh_expire_type = FH4_PERSISTENT; 1625*7c478bd9Sstevel@tonic-gate mi->mi_clientid_next = NULL; 1626*7c478bd9Sstevel@tonic-gate mi->mi_clientid_prev = NULL; 1627*7c478bd9Sstevel@tonic-gate mi->mi_grace_wait = 0; 1628*7c478bd9Sstevel@tonic-gate mi->mi_error = 0; 1629*7c478bd9Sstevel@tonic-gate mi->mi_srvsettime = 0; 1630*7c478bd9Sstevel@tonic-gate 1631*7c478bd9Sstevel@tonic-gate mi->mi_tsize = nfs4_tsize(svp->sv_knconf); 1632*7c478bd9Sstevel@tonic-gate mi->mi_stsize = mi->mi_tsize; 1633*7c478bd9Sstevel@tonic-gate 1634*7c478bd9Sstevel@tonic-gate if (flags & NFSMNT_DIRECTIO) 1635*7c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_DIRECTIO; 1636*7c478bd9Sstevel@tonic-gate 1637*7c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_MOUNTING; 1638*7c478bd9Sstevel@tonic-gate 1639*7c478bd9Sstevel@tonic-gate /* 1640*7c478bd9Sstevel@tonic-gate * Make a vfs struct for nfs. We do this here instead of below 1641*7c478bd9Sstevel@tonic-gate * because rtvp needs a vfs before we can do a getattr on it. 1642*7c478bd9Sstevel@tonic-gate * 1643*7c478bd9Sstevel@tonic-gate * Assign a unique device id to the mount 1644*7c478bd9Sstevel@tonic-gate */ 1645*7c478bd9Sstevel@tonic-gate mutex_enter(&nfs_minor_lock); 1646*7c478bd9Sstevel@tonic-gate do { 1647*7c478bd9Sstevel@tonic-gate nfs_minor = (nfs_minor + 1) & MAXMIN32; 1648*7c478bd9Sstevel@tonic-gate nfs_dev = makedevice(nfs_major, nfs_minor); 1649*7c478bd9Sstevel@tonic-gate } while (vfs_devismounted(nfs_dev)); 1650*7c478bd9Sstevel@tonic-gate mutex_exit(&nfs_minor_lock); 1651*7c478bd9Sstevel@tonic-gate 1652*7c478bd9Sstevel@tonic-gate vfsp->vfs_dev = nfs_dev; 1653*7c478bd9Sstevel@tonic-gate vfs_make_fsid(&vfsp->vfs_fsid, nfs_dev, nfs4fstyp); 1654*7c478bd9Sstevel@tonic-gate vfsp->vfs_data = (caddr_t)mi; 1655*7c478bd9Sstevel@tonic-gate vfsp->vfs_fstype = nfsfstyp; 1656*7c478bd9Sstevel@tonic-gate vfsp->vfs_bsize = nfs4_bsize; 1657*7c478bd9Sstevel@tonic-gate 1658*7c478bd9Sstevel@tonic-gate /* 1659*7c478bd9Sstevel@tonic-gate * Initialize fields used to support async putpage operations. 1660*7c478bd9Sstevel@tonic-gate */ 1661*7c478bd9Sstevel@tonic-gate for (i = 0; i < NFS4_ASYNC_TYPES; i++) 1662*7c478bd9Sstevel@tonic-gate mi->mi_async_clusters[i] = nfs4_async_clusters; 1663*7c478bd9Sstevel@tonic-gate mi->mi_async_init_clusters = nfs4_async_clusters; 1664*7c478bd9Sstevel@tonic-gate mi->mi_async_curr = &mi->mi_async_reqs[0]; 1665*7c478bd9Sstevel@tonic-gate mi->mi_max_threads = nfs4_max_threads; 1666*7c478bd9Sstevel@tonic-gate mutex_init(&mi->mi_async_lock, NULL, MUTEX_DEFAULT, NULL); 1667*7c478bd9Sstevel@tonic-gate cv_init(&mi->mi_async_reqs_cv, NULL, CV_DEFAULT, NULL); 1668*7c478bd9Sstevel@tonic-gate cv_init(&mi->mi_async_work_cv, NULL, CV_DEFAULT, NULL); 1669*7c478bd9Sstevel@tonic-gate cv_init(&mi->mi_async_cv, NULL, CV_DEFAULT, NULL); 1670*7c478bd9Sstevel@tonic-gate cv_init(&mi->mi_inact_req_cv, NULL, CV_DEFAULT, NULL); 1671*7c478bd9Sstevel@tonic-gate 1672*7c478bd9Sstevel@tonic-gate mi->mi_vfsp = vfsp; 1673*7c478bd9Sstevel@tonic-gate zone_hold(mi->mi_zone = zone); 1674*7c478bd9Sstevel@tonic-gate nfs4_mi_zonelist_add(mi); 1675*7c478bd9Sstevel@tonic-gate 1676*7c478bd9Sstevel@tonic-gate /* 1677*7c478bd9Sstevel@tonic-gate * Initialize the <open owner/cred> hash table. 1678*7c478bd9Sstevel@tonic-gate */ 1679*7c478bd9Sstevel@tonic-gate for (i = 0; i < NFS4_NUM_OO_BUCKETS; i++) { 1680*7c478bd9Sstevel@tonic-gate bucketp = &(mi->mi_oo_list[i]); 1681*7c478bd9Sstevel@tonic-gate mutex_init(&bucketp->b_lock, NULL, MUTEX_DEFAULT, NULL); 1682*7c478bd9Sstevel@tonic-gate list_create(&bucketp->b_oo_hash_list, 1683*7c478bd9Sstevel@tonic-gate sizeof (nfs4_open_owner_t), 1684*7c478bd9Sstevel@tonic-gate offsetof(nfs4_open_owner_t, oo_hash_node)); 1685*7c478bd9Sstevel@tonic-gate } 1686*7c478bd9Sstevel@tonic-gate 1687*7c478bd9Sstevel@tonic-gate /* 1688*7c478bd9Sstevel@tonic-gate * Initialize the freed open owner list. 1689*7c478bd9Sstevel@tonic-gate */ 1690*7c478bd9Sstevel@tonic-gate mi->mi_foo_num = 0; 1691*7c478bd9Sstevel@tonic-gate mi->mi_foo_max = NFS4_NUM_FREED_OPEN_OWNERS; 1692*7c478bd9Sstevel@tonic-gate list_create(&mi->mi_foo_list, sizeof (nfs4_open_owner_t), 1693*7c478bd9Sstevel@tonic-gate offsetof(nfs4_open_owner_t, oo_foo_node)); 1694*7c478bd9Sstevel@tonic-gate 1695*7c478bd9Sstevel@tonic-gate list_create(&mi->mi_lost_state, sizeof (nfs4_lost_rqst_t), 1696*7c478bd9Sstevel@tonic-gate offsetof(nfs4_lost_rqst_t, lr_node)); 1697*7c478bd9Sstevel@tonic-gate 1698*7c478bd9Sstevel@tonic-gate list_create(&mi->mi_bseqid_list, sizeof (nfs4_bseqid_entry_t), 1699*7c478bd9Sstevel@tonic-gate offsetof(nfs4_bseqid_entry_t, bs_node)); 1700*7c478bd9Sstevel@tonic-gate 1701*7c478bd9Sstevel@tonic-gate /* 1702*7c478bd9Sstevel@tonic-gate * Initialize the msg buffer. 1703*7c478bd9Sstevel@tonic-gate */ 1704*7c478bd9Sstevel@tonic-gate list_create(&mi->mi_msg_list, sizeof (nfs4_debug_msg_t), 1705*7c478bd9Sstevel@tonic-gate offsetof(nfs4_debug_msg_t, msg_node)); 1706*7c478bd9Sstevel@tonic-gate mi->mi_msg_count = 0; 1707*7c478bd9Sstevel@tonic-gate mutex_init(&mi->mi_msg_list_lock, NULL, MUTEX_DEFAULT, NULL); 1708*7c478bd9Sstevel@tonic-gate 1709*7c478bd9Sstevel@tonic-gate /* 1710*7c478bd9Sstevel@tonic-gate * Initialize kstats 1711*7c478bd9Sstevel@tonic-gate */ 1712*7c478bd9Sstevel@tonic-gate nfs4_mnt_kstat_init(vfsp); 1713*7c478bd9Sstevel@tonic-gate 1714*7c478bd9Sstevel@tonic-gate /* 1715*7c478bd9Sstevel@tonic-gate * Initialize the shared filehandle pool, and get the fname for 1716*7c478bd9Sstevel@tonic-gate * the filesystem root. 1717*7c478bd9Sstevel@tonic-gate */ 1718*7c478bd9Sstevel@tonic-gate sfh4_createtab(&mi->mi_filehandles); 1719*7c478bd9Sstevel@tonic-gate mi->mi_fname = fn_get(NULL, "."); 1720*7c478bd9Sstevel@tonic-gate 1721*7c478bd9Sstevel@tonic-gate /* 1722*7c478bd9Sstevel@tonic-gate * Initialize the fileid map. 1723*7c478bd9Sstevel@tonic-gate */ 1724*7c478bd9Sstevel@tonic-gate mutex_init(&mi->mi_fileid_lock, NULL, MUTEX_DEFAULT, NULL); 1725*7c478bd9Sstevel@tonic-gate rp4_fileid_map_init(&mi->mi_fileid_map); 1726*7c478bd9Sstevel@tonic-gate 1727*7c478bd9Sstevel@tonic-gate /* 1728*7c478bd9Sstevel@tonic-gate * Save server path we're attempting to mount. 1729*7c478bd9Sstevel@tonic-gate */ 1730*7c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 1731*7c478bd9Sstevel@tonic-gate orig_sv_pathlen = svp_head->sv_pathlen; 1732*7c478bd9Sstevel@tonic-gate orig_sv_path = kmem_alloc(svp_head->sv_pathlen, KM_SLEEP); 1733*7c478bd9Sstevel@tonic-gate bcopy(svp_head->sv_path, orig_sv_path, svp_head->sv_pathlen); 1734*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 1735*7c478bd9Sstevel@tonic-gate 1736*7c478bd9Sstevel@tonic-gate /* 1737*7c478bd9Sstevel@tonic-gate * Make the GETFH call to get root fh for each replica. 1738*7c478bd9Sstevel@tonic-gate */ 1739*7c478bd9Sstevel@tonic-gate if (svp_head->sv_next) 1740*7c478bd9Sstevel@tonic-gate droptext = ", dropping replica"; 1741*7c478bd9Sstevel@tonic-gate 1742*7c478bd9Sstevel@tonic-gate /* 1743*7c478bd9Sstevel@tonic-gate * If the uid is set then set the creds for secure mounts 1744*7c478bd9Sstevel@tonic-gate * by proxy processes such as automountd. 1745*7c478bd9Sstevel@tonic-gate */ 1746*7c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 1747*7c478bd9Sstevel@tonic-gate if (svp->sv_secdata->uid != 0) { 1748*7c478bd9Sstevel@tonic-gate lcr = crdup(cr); 1749*7c478bd9Sstevel@tonic-gate (void) crsetugid(lcr, svp->sv_secdata->uid, crgetgid(cr)); 1750*7c478bd9Sstevel@tonic-gate tcr = lcr; 1751*7c478bd9Sstevel@tonic-gate } 1752*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 1753*7c478bd9Sstevel@tonic-gate for (svp = svp_head; svp; svp = svp->sv_next) { 1754*7c478bd9Sstevel@tonic-gate if (nfs4_chkdup_servinfo4(svp_head, svp)) { 1755*7c478bd9Sstevel@tonic-gate nfs_cmn_err(error, CE_WARN, 1756*7c478bd9Sstevel@tonic-gate VERS_MSG "Host %s is a duplicate%s", 1757*7c478bd9Sstevel@tonic-gate svp->sv_hostname, droptext); 1758*7c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 1759*7c478bd9Sstevel@tonic-gate svp->sv_flags |= SV4_NOTINUSE; 1760*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 1761*7c478bd9Sstevel@tonic-gate continue; 1762*7c478bd9Sstevel@tonic-gate } 1763*7c478bd9Sstevel@tonic-gate mi->mi_curr_serv = svp; 1764*7c478bd9Sstevel@tonic-gate 1765*7c478bd9Sstevel@tonic-gate /* 1766*7c478bd9Sstevel@tonic-gate * Just in case server path being mounted contains 1767*7c478bd9Sstevel@tonic-gate * symlinks and fails w/STALE, save the initial sv_path 1768*7c478bd9Sstevel@tonic-gate * so we can redrive the initial mount compound with the 1769*7c478bd9Sstevel@tonic-gate * initial sv_path -- not a symlink-expanded version. 1770*7c478bd9Sstevel@tonic-gate * 1771*7c478bd9Sstevel@tonic-gate * This could only happen if a symlink was expanded 1772*7c478bd9Sstevel@tonic-gate * and the expanded mount compound failed stale. Because 1773*7c478bd9Sstevel@tonic-gate * it could be the case that the symlink was removed at 1774*7c478bd9Sstevel@tonic-gate * the server (and replaced with another symlink/dir, 1775*7c478bd9Sstevel@tonic-gate * we need to use the initial sv_path when attempting 1776*7c478bd9Sstevel@tonic-gate * to re-lookup everything and recover. 1777*7c478bd9Sstevel@tonic-gate * 1778*7c478bd9Sstevel@tonic-gate * Other mount errors should evenutally be handled here also 1779*7c478bd9Sstevel@tonic-gate * (NFS4ERR_DELAY, NFS4ERR_RESOURCE). For now, all mount 1780*7c478bd9Sstevel@tonic-gate * failures will result in mount being redriven a few times. 1781*7c478bd9Sstevel@tonic-gate */ 1782*7c478bd9Sstevel@tonic-gate num_retry = nfs4_max_mount_retry; 1783*7c478bd9Sstevel@tonic-gate do { 1784*7c478bd9Sstevel@tonic-gate nfs4getfh_otw(mi, svp, &tmp_vtype, 1785*7c478bd9Sstevel@tonic-gate ((flags & NFSMNT_PUBLIC) ? NFS4_GETFH_PUBLIC : 0) | 1786*7c478bd9Sstevel@tonic-gate NFS4_GETFH_NEEDSOP, tcr, &e); 1787*7c478bd9Sstevel@tonic-gate 1788*7c478bd9Sstevel@tonic-gate if (e.error == 0 && e.stat == NFS4_OK) 1789*7c478bd9Sstevel@tonic-gate break; 1790*7c478bd9Sstevel@tonic-gate 1791*7c478bd9Sstevel@tonic-gate /* 1792*7c478bd9Sstevel@tonic-gate * replace current sv_path with orig sv_path -- just in 1793*7c478bd9Sstevel@tonic-gate * case it changed due to embedded symlinks. 1794*7c478bd9Sstevel@tonic-gate */ 1795*7c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 1796*7c478bd9Sstevel@tonic-gate if (orig_sv_pathlen != svp->sv_pathlen) { 1797*7c478bd9Sstevel@tonic-gate kmem_free(svp->sv_path, svp->sv_pathlen); 1798*7c478bd9Sstevel@tonic-gate svp->sv_path = kmem_alloc(orig_sv_pathlen, 1799*7c478bd9Sstevel@tonic-gate KM_SLEEP); 1800*7c478bd9Sstevel@tonic-gate svp->sv_pathlen = orig_sv_pathlen; 1801*7c478bd9Sstevel@tonic-gate } 1802*7c478bd9Sstevel@tonic-gate bcopy(orig_sv_path, svp->sv_path, orig_sv_pathlen); 1803*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 1804*7c478bd9Sstevel@tonic-gate 1805*7c478bd9Sstevel@tonic-gate } while (num_retry-- > 0); 1806*7c478bd9Sstevel@tonic-gate 1807*7c478bd9Sstevel@tonic-gate error = e.error ? e.error : geterrno4(e.stat); 1808*7c478bd9Sstevel@tonic-gate if (error) { 1809*7c478bd9Sstevel@tonic-gate nfs_cmn_err(error, CE_WARN, 1810*7c478bd9Sstevel@tonic-gate VERS_MSG "initial call to %s failed%s: %m", 1811*7c478bd9Sstevel@tonic-gate svp->sv_hostname, droptext); 1812*7c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 1813*7c478bd9Sstevel@tonic-gate svp->sv_flags |= SV4_NOTINUSE; 1814*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 1815*7c478bd9Sstevel@tonic-gate mi->mi_flags &= ~MI4_RECOV_FAIL; 1816*7c478bd9Sstevel@tonic-gate mi->mi_error = 0; 1817*7c478bd9Sstevel@tonic-gate continue; 1818*7c478bd9Sstevel@tonic-gate } 1819*7c478bd9Sstevel@tonic-gate 1820*7c478bd9Sstevel@tonic-gate if (tmp_vtype == VBAD) { 1821*7c478bd9Sstevel@tonic-gate zcmn_err(mi->mi_zone->zone_id, CE_WARN, 1822*7c478bd9Sstevel@tonic-gate VERS_MSG "%s returned a bad file type for " 1823*7c478bd9Sstevel@tonic-gate "root%s", svp->sv_hostname, droptext); 1824*7c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 1825*7c478bd9Sstevel@tonic-gate svp->sv_flags |= SV4_NOTINUSE; 1826*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 1827*7c478bd9Sstevel@tonic-gate continue; 1828*7c478bd9Sstevel@tonic-gate } 1829*7c478bd9Sstevel@tonic-gate 1830*7c478bd9Sstevel@tonic-gate if (vtype == VNON) { 1831*7c478bd9Sstevel@tonic-gate vtype = tmp_vtype; 1832*7c478bd9Sstevel@tonic-gate } else if (vtype != tmp_vtype) { 1833*7c478bd9Sstevel@tonic-gate zcmn_err(mi->mi_zone->zone_id, CE_WARN, 1834*7c478bd9Sstevel@tonic-gate VERS_MSG "%s returned a different file type " 1835*7c478bd9Sstevel@tonic-gate "for root%s", svp->sv_hostname, droptext); 1836*7c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 1837*7c478bd9Sstevel@tonic-gate svp->sv_flags |= SV4_NOTINUSE; 1838*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 1839*7c478bd9Sstevel@tonic-gate continue; 1840*7c478bd9Sstevel@tonic-gate } 1841*7c478bd9Sstevel@tonic-gate if (firstsvp == NULL) 1842*7c478bd9Sstevel@tonic-gate firstsvp = svp; 1843*7c478bd9Sstevel@tonic-gate } 1844*7c478bd9Sstevel@tonic-gate 1845*7c478bd9Sstevel@tonic-gate kmem_free(orig_sv_path, orig_sv_pathlen); 1846*7c478bd9Sstevel@tonic-gate 1847*7c478bd9Sstevel@tonic-gate if (firstsvp == NULL) { 1848*7c478bd9Sstevel@tonic-gate if (error == 0) 1849*7c478bd9Sstevel@tonic-gate error = ENOENT; 1850*7c478bd9Sstevel@tonic-gate goto bad; 1851*7c478bd9Sstevel@tonic-gate } 1852*7c478bd9Sstevel@tonic-gate 1853*7c478bd9Sstevel@tonic-gate mi->mi_curr_serv = svp = firstsvp; 1854*7c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 1855*7c478bd9Sstevel@tonic-gate ASSERT((mi->mi_curr_serv->sv_flags & SV4_NOTINUSE) == 0); 1856*7c478bd9Sstevel@tonic-gate fh.nfs_fh4_len = svp->sv_fhandle.fh_len; 1857*7c478bd9Sstevel@tonic-gate fh.nfs_fh4_val = svp->sv_fhandle.fh_buf; 1858*7c478bd9Sstevel@tonic-gate mi->mi_rootfh = sfh4_get(&fh, mi); 1859*7c478bd9Sstevel@tonic-gate fh.nfs_fh4_len = svp->sv_pfhandle.fh_len; 1860*7c478bd9Sstevel@tonic-gate fh.nfs_fh4_val = svp->sv_pfhandle.fh_buf; 1861*7c478bd9Sstevel@tonic-gate mi->mi_srvparentfh = sfh4_get(&fh, mi); 1862*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 1863*7c478bd9Sstevel@tonic-gate 1864*7c478bd9Sstevel@tonic-gate /* 1865*7c478bd9Sstevel@tonic-gate * Make the root vnode without attributes. 1866*7c478bd9Sstevel@tonic-gate */ 1867*7c478bd9Sstevel@tonic-gate mfname = mi->mi_fname; 1868*7c478bd9Sstevel@tonic-gate fn_hold(mfname); 1869*7c478bd9Sstevel@tonic-gate rtvp = makenfs4node_by_fh(mi->mi_rootfh, NULL, 1870*7c478bd9Sstevel@tonic-gate &mfname, NULL, mi, cr, gethrtime()); 1871*7c478bd9Sstevel@tonic-gate rtvp->v_type = vtype; 1872*7c478bd9Sstevel@tonic-gate 1873*7c478bd9Sstevel@tonic-gate mi->mi_curread = mi->mi_tsize; 1874*7c478bd9Sstevel@tonic-gate mi->mi_curwrite = mi->mi_stsize; 1875*7c478bd9Sstevel@tonic-gate 1876*7c478bd9Sstevel@tonic-gate /* 1877*7c478bd9Sstevel@tonic-gate * Start the manager thread responsible for handling async worker 1878*7c478bd9Sstevel@tonic-gate * threads. 1879*7c478bd9Sstevel@tonic-gate */ 1880*7c478bd9Sstevel@tonic-gate VFS_HOLD(vfsp); /* add reference for thread */ 1881*7c478bd9Sstevel@tonic-gate mi->mi_manager_thread = zthread_create(NULL, 0, nfs4_async_manager, 1882*7c478bd9Sstevel@tonic-gate vfsp, 0, minclsyspri); 1883*7c478bd9Sstevel@tonic-gate ASSERT(mi->mi_manager_thread != NULL); 1884*7c478bd9Sstevel@tonic-gate /* 1885*7c478bd9Sstevel@tonic-gate * Create the thread that handles over-the-wire calls for 1886*7c478bd9Sstevel@tonic-gate * VOP_INACTIVE. 1887*7c478bd9Sstevel@tonic-gate * This needs to happen after the manager thread is created. 1888*7c478bd9Sstevel@tonic-gate */ 1889*7c478bd9Sstevel@tonic-gate mi->mi_inactive_thread = zthread_create(NULL, 0, nfs4_inactive_thread, 1890*7c478bd9Sstevel@tonic-gate mi, 0, minclsyspri); 1891*7c478bd9Sstevel@tonic-gate ASSERT(mi->mi_inactive_thread != NULL); 1892*7c478bd9Sstevel@tonic-gate 1893*7c478bd9Sstevel@tonic-gate /* If we didn't get a type, get one now */ 1894*7c478bd9Sstevel@tonic-gate if (rtvp->v_type == VNON) { 1895*7c478bd9Sstevel@tonic-gate va.va_mask = AT_TYPE; 1896*7c478bd9Sstevel@tonic-gate error = nfs4getattr(rtvp, &va, tcr); 1897*7c478bd9Sstevel@tonic-gate if (error) 1898*7c478bd9Sstevel@tonic-gate goto bad; 1899*7c478bd9Sstevel@tonic-gate rtvp->v_type = va.va_type; 1900*7c478bd9Sstevel@tonic-gate } 1901*7c478bd9Sstevel@tonic-gate 1902*7c478bd9Sstevel@tonic-gate mi->mi_type = rtvp->v_type; 1903*7c478bd9Sstevel@tonic-gate 1904*7c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 1905*7c478bd9Sstevel@tonic-gate mi->mi_flags &= ~MI4_MOUNTING; 1906*7c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 1907*7c478bd9Sstevel@tonic-gate 1908*7c478bd9Sstevel@tonic-gate *rtvpp = rtvp; 1909*7c478bd9Sstevel@tonic-gate if (lcr != NULL) 1910*7c478bd9Sstevel@tonic-gate crfree(lcr); 1911*7c478bd9Sstevel@tonic-gate 1912*7c478bd9Sstevel@tonic-gate return (0); 1913*7c478bd9Sstevel@tonic-gate bad: 1914*7c478bd9Sstevel@tonic-gate /* 1915*7c478bd9Sstevel@tonic-gate * An error occurred somewhere, need to clean up... 1916*7c478bd9Sstevel@tonic-gate * 1917*7c478bd9Sstevel@tonic-gate * XXX Should not svp be cleaned too? 1918*7c478bd9Sstevel@tonic-gate */ 1919*7c478bd9Sstevel@tonic-gate if (lcr != NULL) 1920*7c478bd9Sstevel@tonic-gate crfree(lcr); 1921*7c478bd9Sstevel@tonic-gate if (rtvp != NULL) { 1922*7c478bd9Sstevel@tonic-gate /* 1923*7c478bd9Sstevel@tonic-gate * We need to release our reference to the root vnode and 1924*7c478bd9Sstevel@tonic-gate * destroy the mntinfo4 struct that we just created. 1925*7c478bd9Sstevel@tonic-gate */ 1926*7c478bd9Sstevel@tonic-gate rp = VTOR4(rtvp); 1927*7c478bd9Sstevel@tonic-gate if (rp->r_flags & R4HASHED) 1928*7c478bd9Sstevel@tonic-gate rp4_rmhash(rp); 1929*7c478bd9Sstevel@tonic-gate if (rp->r_flags & R4FILEIDMAP) 1930*7c478bd9Sstevel@tonic-gate rp4_fileid_map_remove(rp); 1931*7c478bd9Sstevel@tonic-gate VN_RELE(rtvp); 1932*7c478bd9Sstevel@tonic-gate } 1933*7c478bd9Sstevel@tonic-gate nfs4_async_stop(vfsp); 1934*7c478bd9Sstevel@tonic-gate nfs4_async_manager_stop(vfsp); 1935*7c478bd9Sstevel@tonic-gate if (mi->mi_io_kstats) { 1936*7c478bd9Sstevel@tonic-gate kstat_delete(mi->mi_io_kstats); 1937*7c478bd9Sstevel@tonic-gate mi->mi_io_kstats = NULL; 1938*7c478bd9Sstevel@tonic-gate } 1939*7c478bd9Sstevel@tonic-gate if (mi->mi_ro_kstats) { 1940*7c478bd9Sstevel@tonic-gate kstat_delete(mi->mi_ro_kstats); 1941*7c478bd9Sstevel@tonic-gate mi->mi_ro_kstats = NULL; 1942*7c478bd9Sstevel@tonic-gate } 1943*7c478bd9Sstevel@tonic-gate if (mi->mi_recov_ksp) { 1944*7c478bd9Sstevel@tonic-gate kstat_delete(mi->mi_recov_ksp); 1945*7c478bd9Sstevel@tonic-gate mi->mi_recov_ksp = NULL; 1946*7c478bd9Sstevel@tonic-gate } 1947*7c478bd9Sstevel@tonic-gate nfs_free_mi4(mi); 1948*7c478bd9Sstevel@tonic-gate *rtvpp = NULL; 1949*7c478bd9Sstevel@tonic-gate return (error); 1950*7c478bd9Sstevel@tonic-gate } 1951*7c478bd9Sstevel@tonic-gate 1952*7c478bd9Sstevel@tonic-gate /* 1953*7c478bd9Sstevel@tonic-gate * vfs operations 1954*7c478bd9Sstevel@tonic-gate */ 1955*7c478bd9Sstevel@tonic-gate static int 1956*7c478bd9Sstevel@tonic-gate nfs4_unmount(vfs_t *vfsp, int flag, cred_t *cr) 1957*7c478bd9Sstevel@tonic-gate { 1958*7c478bd9Sstevel@tonic-gate mntinfo4_t *mi; 1959*7c478bd9Sstevel@tonic-gate ushort_t omax; 1960*7c478bd9Sstevel@tonic-gate 1961*7c478bd9Sstevel@tonic-gate if (secpolicy_fs_unmount(cr, vfsp) != 0) 1962*7c478bd9Sstevel@tonic-gate return (EPERM); 1963*7c478bd9Sstevel@tonic-gate 1964*7c478bd9Sstevel@tonic-gate mi = VFTOMI4(vfsp); 1965*7c478bd9Sstevel@tonic-gate 1966*7c478bd9Sstevel@tonic-gate if (flag & MS_FORCE) { 1967*7c478bd9Sstevel@tonic-gate vfsp->vfs_flag |= VFS_UNMOUNTED; 1968*7c478bd9Sstevel@tonic-gate if (curproc->p_zone != mi->mi_zone) { 1969*7c478bd9Sstevel@tonic-gate /* 1970*7c478bd9Sstevel@tonic-gate * If the request is coming from the wrong zone, 1971*7c478bd9Sstevel@tonic-gate * we don't want to create any new threads, and 1972*7c478bd9Sstevel@tonic-gate * performance is not a concern. Do everything 1973*7c478bd9Sstevel@tonic-gate * inline. 1974*7c478bd9Sstevel@tonic-gate */ 1975*7c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_zone_debug, (CE_NOTE, 1976*7c478bd9Sstevel@tonic-gate "nfs4_unmount x-zone forced unmount of vfs %p\n", 1977*7c478bd9Sstevel@tonic-gate (void *)vfsp)); 1978*7c478bd9Sstevel@tonic-gate nfs4_free_mount(vfsp, cr); 1979*7c478bd9Sstevel@tonic-gate } else { 1980*7c478bd9Sstevel@tonic-gate /* 1981*7c478bd9Sstevel@tonic-gate * Free data structures asynchronously, to avoid 1982*7c478bd9Sstevel@tonic-gate * blocking the current thread (for performance 1983*7c478bd9Sstevel@tonic-gate * reasons only). 1984*7c478bd9Sstevel@tonic-gate */ 1985*7c478bd9Sstevel@tonic-gate async_free_mount(vfsp, cr); 1986*7c478bd9Sstevel@tonic-gate } 1987*7c478bd9Sstevel@tonic-gate return (0); 1988*7c478bd9Sstevel@tonic-gate } 1989*7c478bd9Sstevel@tonic-gate /* 1990*7c478bd9Sstevel@tonic-gate * Wait until all asynchronous putpage operations on 1991*7c478bd9Sstevel@tonic-gate * this file system are complete before flushing rnodes 1992*7c478bd9Sstevel@tonic-gate * from the cache. 1993*7c478bd9Sstevel@tonic-gate */ 1994*7c478bd9Sstevel@tonic-gate omax = mi->mi_max_threads; 1995*7c478bd9Sstevel@tonic-gate if (nfs4_async_stop_sig(vfsp)) { 1996*7c478bd9Sstevel@tonic-gate return (EINTR); 1997*7c478bd9Sstevel@tonic-gate } 1998*7c478bd9Sstevel@tonic-gate r4flush(vfsp, cr); 1999*7c478bd9Sstevel@tonic-gate /* 2000*7c478bd9Sstevel@tonic-gate * If there are any active vnodes on this file system, 2001*7c478bd9Sstevel@tonic-gate * then the file system is busy and can't be umounted. 2002*7c478bd9Sstevel@tonic-gate */ 2003*7c478bd9Sstevel@tonic-gate if (check_rtable4(vfsp)) { 2004*7c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_async_lock); 2005*7c478bd9Sstevel@tonic-gate mi->mi_max_threads = omax; 2006*7c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_async_lock); 2007*7c478bd9Sstevel@tonic-gate return (EBUSY); 2008*7c478bd9Sstevel@tonic-gate } 2009*7c478bd9Sstevel@tonic-gate /* 2010*7c478bd9Sstevel@tonic-gate * The unmount can't fail from now on, and there are no active 2011*7c478bd9Sstevel@tonic-gate * files that could require over-the-wire calls to the server, 2012*7c478bd9Sstevel@tonic-gate * so stop the async manager and the inactive thread. 2013*7c478bd9Sstevel@tonic-gate */ 2014*7c478bd9Sstevel@tonic-gate nfs4_async_manager_stop(vfsp); 2015*7c478bd9Sstevel@tonic-gate /* 2016*7c478bd9Sstevel@tonic-gate * Destroy all rnodes belonging to this file system from the 2017*7c478bd9Sstevel@tonic-gate * rnode hash queues and purge any resources allocated to 2018*7c478bd9Sstevel@tonic-gate * them. 2019*7c478bd9Sstevel@tonic-gate */ 2020*7c478bd9Sstevel@tonic-gate destroy_fileid_map(vfsp); 2021*7c478bd9Sstevel@tonic-gate destroy_rtable4(vfsp, cr); 2022*7c478bd9Sstevel@tonic-gate vfsp->vfs_flag |= VFS_UNMOUNTED; 2023*7c478bd9Sstevel@tonic-gate nfs4_remove_mi_from_server(mi, NULL); 2024*7c478bd9Sstevel@tonic-gate if (mi->mi_io_kstats) { 2025*7c478bd9Sstevel@tonic-gate kstat_delete(mi->mi_io_kstats); 2026*7c478bd9Sstevel@tonic-gate mi->mi_io_kstats = NULL; 2027*7c478bd9Sstevel@tonic-gate } 2028*7c478bd9Sstevel@tonic-gate if (mi->mi_ro_kstats) { 2029*7c478bd9Sstevel@tonic-gate kstat_delete(mi->mi_ro_kstats); 2030*7c478bd9Sstevel@tonic-gate mi->mi_ro_kstats = NULL; 2031*7c478bd9Sstevel@tonic-gate } 2032*7c478bd9Sstevel@tonic-gate if (mi->mi_recov_ksp) { 2033*7c478bd9Sstevel@tonic-gate kstat_delete(mi->mi_recov_ksp); 2034*7c478bd9Sstevel@tonic-gate mi->mi_recov_ksp = NULL; 2035*7c478bd9Sstevel@tonic-gate } 2036*7c478bd9Sstevel@tonic-gate return (0); 2037*7c478bd9Sstevel@tonic-gate } 2038*7c478bd9Sstevel@tonic-gate 2039*7c478bd9Sstevel@tonic-gate /* 2040*7c478bd9Sstevel@tonic-gate * find root of nfs 2041*7c478bd9Sstevel@tonic-gate */ 2042*7c478bd9Sstevel@tonic-gate static int 2043*7c478bd9Sstevel@tonic-gate nfs4_root(vfs_t *vfsp, vnode_t **vpp) 2044*7c478bd9Sstevel@tonic-gate { 2045*7c478bd9Sstevel@tonic-gate mntinfo4_t *mi; 2046*7c478bd9Sstevel@tonic-gate vnode_t *vp; 2047*7c478bd9Sstevel@tonic-gate nfs4_fname_t *mfname; 2048*7c478bd9Sstevel@tonic-gate servinfo4_t *svp; 2049*7c478bd9Sstevel@tonic-gate 2050*7c478bd9Sstevel@tonic-gate mi = VFTOMI4(vfsp); 2051*7c478bd9Sstevel@tonic-gate 2052*7c478bd9Sstevel@tonic-gate if (curproc->p_zone != mi->mi_zone) 2053*7c478bd9Sstevel@tonic-gate return (EPERM); 2054*7c478bd9Sstevel@tonic-gate 2055*7c478bd9Sstevel@tonic-gate svp = mi->mi_curr_serv; 2056*7c478bd9Sstevel@tonic-gate if (svp) { 2057*7c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 2058*7c478bd9Sstevel@tonic-gate if (svp->sv_flags & SV4_ROOT_STALE) { 2059*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 2060*7c478bd9Sstevel@tonic-gate 2061*7c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 2062*7c478bd9Sstevel@tonic-gate if (svp->sv_flags & SV4_ROOT_STALE) { 2063*7c478bd9Sstevel@tonic-gate svp->sv_flags &= ~SV4_ROOT_STALE; 2064*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 2065*7c478bd9Sstevel@tonic-gate return (ENOENT); 2066*7c478bd9Sstevel@tonic-gate } 2067*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 2068*7c478bd9Sstevel@tonic-gate } else 2069*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 2070*7c478bd9Sstevel@tonic-gate } 2071*7c478bd9Sstevel@tonic-gate 2072*7c478bd9Sstevel@tonic-gate mfname = mi->mi_fname; 2073*7c478bd9Sstevel@tonic-gate fn_hold(mfname); 2074*7c478bd9Sstevel@tonic-gate vp = makenfs4node_by_fh(mi->mi_rootfh, NULL, &mfname, NULL, 2075*7c478bd9Sstevel@tonic-gate VFTOMI4(vfsp), CRED(), gethrtime()); 2076*7c478bd9Sstevel@tonic-gate 2077*7c478bd9Sstevel@tonic-gate if (VTOR4(vp)->r_flags & R4STALE) { 2078*7c478bd9Sstevel@tonic-gate VN_RELE(vp); 2079*7c478bd9Sstevel@tonic-gate return (ENOENT); 2080*7c478bd9Sstevel@tonic-gate } 2081*7c478bd9Sstevel@tonic-gate 2082*7c478bd9Sstevel@tonic-gate ASSERT(vp->v_type == VNON || vp->v_type == mi->mi_type); 2083*7c478bd9Sstevel@tonic-gate 2084*7c478bd9Sstevel@tonic-gate vp->v_type = mi->mi_type; 2085*7c478bd9Sstevel@tonic-gate 2086*7c478bd9Sstevel@tonic-gate *vpp = vp; 2087*7c478bd9Sstevel@tonic-gate 2088*7c478bd9Sstevel@tonic-gate return (0); 2089*7c478bd9Sstevel@tonic-gate } 2090*7c478bd9Sstevel@tonic-gate 2091*7c478bd9Sstevel@tonic-gate static int 2092*7c478bd9Sstevel@tonic-gate nfs4_statfs_otw(vnode_t *vp, struct statvfs64 *sbp, cred_t *cr) 2093*7c478bd9Sstevel@tonic-gate { 2094*7c478bd9Sstevel@tonic-gate int error; 2095*7c478bd9Sstevel@tonic-gate nfs4_ga_res_t gar; 2096*7c478bd9Sstevel@tonic-gate nfs4_ga_ext_res_t ger; 2097*7c478bd9Sstevel@tonic-gate 2098*7c478bd9Sstevel@tonic-gate gar.n4g_ext_res = &ger; 2099*7c478bd9Sstevel@tonic-gate 2100*7c478bd9Sstevel@tonic-gate if (error = nfs4_attr_otw(vp, TAG_FSINFO, &gar, 2101*7c478bd9Sstevel@tonic-gate NFS4_STATFS_ATTR_MASK, cr)) 2102*7c478bd9Sstevel@tonic-gate return (error); 2103*7c478bd9Sstevel@tonic-gate 2104*7c478bd9Sstevel@tonic-gate *sbp = gar.n4g_ext_res->n4g_sb; 2105*7c478bd9Sstevel@tonic-gate 2106*7c478bd9Sstevel@tonic-gate return (0); 2107*7c478bd9Sstevel@tonic-gate } 2108*7c478bd9Sstevel@tonic-gate 2109*7c478bd9Sstevel@tonic-gate /* 2110*7c478bd9Sstevel@tonic-gate * Get file system statistics. 2111*7c478bd9Sstevel@tonic-gate */ 2112*7c478bd9Sstevel@tonic-gate static int 2113*7c478bd9Sstevel@tonic-gate nfs4_statvfs(vfs_t *vfsp, struct statvfs64 *sbp) 2114*7c478bd9Sstevel@tonic-gate { 2115*7c478bd9Sstevel@tonic-gate int error; 2116*7c478bd9Sstevel@tonic-gate vnode_t *vp; 2117*7c478bd9Sstevel@tonic-gate cred_t *cr; 2118*7c478bd9Sstevel@tonic-gate 2119*7c478bd9Sstevel@tonic-gate error = nfs4_root(vfsp, &vp); 2120*7c478bd9Sstevel@tonic-gate if (error) 2121*7c478bd9Sstevel@tonic-gate return (error); 2122*7c478bd9Sstevel@tonic-gate 2123*7c478bd9Sstevel@tonic-gate cr = CRED(); 2124*7c478bd9Sstevel@tonic-gate 2125*7c478bd9Sstevel@tonic-gate error = nfs4_statfs_otw(vp, sbp, cr); 2126*7c478bd9Sstevel@tonic-gate if (!error) { 2127*7c478bd9Sstevel@tonic-gate (void) strncpy(sbp->f_basetype, 2128*7c478bd9Sstevel@tonic-gate vfssw[vfsp->vfs_fstype].vsw_name, FSTYPSZ); 2129*7c478bd9Sstevel@tonic-gate sbp->f_flag = vf_to_stf(vfsp->vfs_flag); 2130*7c478bd9Sstevel@tonic-gate } else { 2131*7c478bd9Sstevel@tonic-gate nfs4_purge_stale_fh(error, vp, cr); 2132*7c478bd9Sstevel@tonic-gate } 2133*7c478bd9Sstevel@tonic-gate 2134*7c478bd9Sstevel@tonic-gate VN_RELE(vp); 2135*7c478bd9Sstevel@tonic-gate 2136*7c478bd9Sstevel@tonic-gate return (error); 2137*7c478bd9Sstevel@tonic-gate } 2138*7c478bd9Sstevel@tonic-gate 2139*7c478bd9Sstevel@tonic-gate static kmutex_t nfs4_syncbusy; 2140*7c478bd9Sstevel@tonic-gate 2141*7c478bd9Sstevel@tonic-gate /* 2142*7c478bd9Sstevel@tonic-gate * Flush dirty nfs files for file system vfsp. 2143*7c478bd9Sstevel@tonic-gate * If vfsp == NULL, all nfs files are flushed. 2144*7c478bd9Sstevel@tonic-gate * 2145*7c478bd9Sstevel@tonic-gate * SYNC_CLOSE in flag is passed to us to 2146*7c478bd9Sstevel@tonic-gate * indicate that we are shutting down and or 2147*7c478bd9Sstevel@tonic-gate * rebooting. 2148*7c478bd9Sstevel@tonic-gate */ 2149*7c478bd9Sstevel@tonic-gate static int 2150*7c478bd9Sstevel@tonic-gate nfs4_sync(vfs_t *vfsp, short flag, cred_t *cr) 2151*7c478bd9Sstevel@tonic-gate { 2152*7c478bd9Sstevel@tonic-gate /* 2153*7c478bd9Sstevel@tonic-gate * Cross-zone calls are OK here, since this translates to a 2154*7c478bd9Sstevel@tonic-gate * VOP_PUTPAGE(B_ASYNC), which gets picked up by the right zone. 2155*7c478bd9Sstevel@tonic-gate */ 2156*7c478bd9Sstevel@tonic-gate if (!(flag & SYNC_ATTR) && mutex_tryenter(&nfs4_syncbusy) != 0) { 2157*7c478bd9Sstevel@tonic-gate r4flush(vfsp, cr); 2158*7c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_syncbusy); 2159*7c478bd9Sstevel@tonic-gate } 2160*7c478bd9Sstevel@tonic-gate 2161*7c478bd9Sstevel@tonic-gate /* 2162*7c478bd9Sstevel@tonic-gate * if SYNC_CLOSE is set then we know that 2163*7c478bd9Sstevel@tonic-gate * the system is rebooting, mark the mntinfo 2164*7c478bd9Sstevel@tonic-gate * for later examination. 2165*7c478bd9Sstevel@tonic-gate */ 2166*7c478bd9Sstevel@tonic-gate if (vfsp && (flag & SYNC_CLOSE)) { 2167*7c478bd9Sstevel@tonic-gate mntinfo4_t *mi; 2168*7c478bd9Sstevel@tonic-gate 2169*7c478bd9Sstevel@tonic-gate mi = VFTOMI4(vfsp); 2170*7c478bd9Sstevel@tonic-gate if (!(mi->mi_flags & MI4_SHUTDOWN)) { 2171*7c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 2172*7c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_SHUTDOWN; 2173*7c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 2174*7c478bd9Sstevel@tonic-gate } 2175*7c478bd9Sstevel@tonic-gate } 2176*7c478bd9Sstevel@tonic-gate return (0); 2177*7c478bd9Sstevel@tonic-gate } 2178*7c478bd9Sstevel@tonic-gate 2179*7c478bd9Sstevel@tonic-gate /* 2180*7c478bd9Sstevel@tonic-gate * vget is difficult, if not impossible, to support in v4 because we don't 2181*7c478bd9Sstevel@tonic-gate * know the parent directory or name, which makes it impossible to create a 2182*7c478bd9Sstevel@tonic-gate * useful shadow vnode. And we need the shadow vnode for things like 2183*7c478bd9Sstevel@tonic-gate * OPEN. 2184*7c478bd9Sstevel@tonic-gate */ 2185*7c478bd9Sstevel@tonic-gate 2186*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2187*7c478bd9Sstevel@tonic-gate /* 2188*7c478bd9Sstevel@tonic-gate * XXX Check nfs4_vget_pseudo() for dependency. 2189*7c478bd9Sstevel@tonic-gate */ 2190*7c478bd9Sstevel@tonic-gate static int 2191*7c478bd9Sstevel@tonic-gate nfs4_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp) 2192*7c478bd9Sstevel@tonic-gate { 2193*7c478bd9Sstevel@tonic-gate return (EREMOTE); 2194*7c478bd9Sstevel@tonic-gate } 2195*7c478bd9Sstevel@tonic-gate 2196*7c478bd9Sstevel@tonic-gate /* 2197*7c478bd9Sstevel@tonic-gate * nfs4_mountroot get called in the case where we are diskless booting. All 2198*7c478bd9Sstevel@tonic-gate * we need from here is the ability to get the server info and from there we 2199*7c478bd9Sstevel@tonic-gate * can simply call nfs4_rootvp. 2200*7c478bd9Sstevel@tonic-gate */ 2201*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2202*7c478bd9Sstevel@tonic-gate static int 2203*7c478bd9Sstevel@tonic-gate nfs4_mountroot(vfs_t *vfsp, whymountroot_t why) 2204*7c478bd9Sstevel@tonic-gate { 2205*7c478bd9Sstevel@tonic-gate vnode_t *rtvp; 2206*7c478bd9Sstevel@tonic-gate char root_hostname[SYS_NMLN+1]; 2207*7c478bd9Sstevel@tonic-gate struct servinfo4 *svp; 2208*7c478bd9Sstevel@tonic-gate int error; 2209*7c478bd9Sstevel@tonic-gate int vfsflags; 2210*7c478bd9Sstevel@tonic-gate size_t size; 2211*7c478bd9Sstevel@tonic-gate char *root_path; 2212*7c478bd9Sstevel@tonic-gate struct pathname pn; 2213*7c478bd9Sstevel@tonic-gate char *name; 2214*7c478bd9Sstevel@tonic-gate cred_t *cr; 2215*7c478bd9Sstevel@tonic-gate mntinfo4_t *mi; 2216*7c478bd9Sstevel@tonic-gate struct nfs_args args; /* nfs mount arguments */ 2217*7c478bd9Sstevel@tonic-gate static char token[10]; 2218*7c478bd9Sstevel@tonic-gate nfs4_error_t n4e; 2219*7c478bd9Sstevel@tonic-gate 2220*7c478bd9Sstevel@tonic-gate bzero(&args, sizeof (args)); 2221*7c478bd9Sstevel@tonic-gate 2222*7c478bd9Sstevel@tonic-gate /* do this BEFORE getfile which causes xid stamps to be initialized */ 2223*7c478bd9Sstevel@tonic-gate clkset(-1L); /* hack for now - until we get time svc? */ 2224*7c478bd9Sstevel@tonic-gate 2225*7c478bd9Sstevel@tonic-gate if (why == ROOT_REMOUNT) { 2226*7c478bd9Sstevel@tonic-gate /* 2227*7c478bd9Sstevel@tonic-gate * Shouldn't happen. 2228*7c478bd9Sstevel@tonic-gate */ 2229*7c478bd9Sstevel@tonic-gate panic("nfs4_mountroot: why == ROOT_REMOUNT"); 2230*7c478bd9Sstevel@tonic-gate } 2231*7c478bd9Sstevel@tonic-gate 2232*7c478bd9Sstevel@tonic-gate if (why == ROOT_UNMOUNT) { 2233*7c478bd9Sstevel@tonic-gate /* 2234*7c478bd9Sstevel@tonic-gate * Nothing to do for NFS. 2235*7c478bd9Sstevel@tonic-gate */ 2236*7c478bd9Sstevel@tonic-gate return (0); 2237*7c478bd9Sstevel@tonic-gate } 2238*7c478bd9Sstevel@tonic-gate 2239*7c478bd9Sstevel@tonic-gate /* 2240*7c478bd9Sstevel@tonic-gate * why == ROOT_INIT 2241*7c478bd9Sstevel@tonic-gate */ 2242*7c478bd9Sstevel@tonic-gate 2243*7c478bd9Sstevel@tonic-gate name = token; 2244*7c478bd9Sstevel@tonic-gate *name = 0; 2245*7c478bd9Sstevel@tonic-gate (void) getfsname("root", name, sizeof (token)); 2246*7c478bd9Sstevel@tonic-gate 2247*7c478bd9Sstevel@tonic-gate pn_alloc(&pn); 2248*7c478bd9Sstevel@tonic-gate root_path = pn.pn_path; 2249*7c478bd9Sstevel@tonic-gate 2250*7c478bd9Sstevel@tonic-gate svp = kmem_zalloc(sizeof (*svp), KM_SLEEP); 2251*7c478bd9Sstevel@tonic-gate nfs_rw_init(&svp->sv_lock, NULL, RW_DEFAULT, NULL); 2252*7c478bd9Sstevel@tonic-gate svp->sv_knconf = kmem_zalloc(sizeof (*svp->sv_knconf), KM_SLEEP); 2253*7c478bd9Sstevel@tonic-gate svp->sv_knconf->knc_protofmly = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 2254*7c478bd9Sstevel@tonic-gate svp->sv_knconf->knc_proto = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 2255*7c478bd9Sstevel@tonic-gate 2256*7c478bd9Sstevel@tonic-gate /* 2257*7c478bd9Sstevel@tonic-gate * Get server address 2258*7c478bd9Sstevel@tonic-gate * Get the root path 2259*7c478bd9Sstevel@tonic-gate * Get server's transport 2260*7c478bd9Sstevel@tonic-gate * Get server's hostname 2261*7c478bd9Sstevel@tonic-gate * Get options 2262*7c478bd9Sstevel@tonic-gate */ 2263*7c478bd9Sstevel@tonic-gate args.addr = &svp->sv_addr; 2264*7c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 2265*7c478bd9Sstevel@tonic-gate args.fh = (char *)&svp->sv_fhandle; 2266*7c478bd9Sstevel@tonic-gate args.knconf = svp->sv_knconf; 2267*7c478bd9Sstevel@tonic-gate args.hostname = root_hostname; 2268*7c478bd9Sstevel@tonic-gate vfsflags = 0; 2269*7c478bd9Sstevel@tonic-gate if (error = mount_root(*name ? name : "root", root_path, NFS_V4, 2270*7c478bd9Sstevel@tonic-gate &args, &vfsflags)) { 2271*7c478bd9Sstevel@tonic-gate if (error == EPROTONOSUPPORT) 2272*7c478bd9Sstevel@tonic-gate nfs_cmn_err(error, CE_WARN, "nfs4_mountroot: " 2273*7c478bd9Sstevel@tonic-gate "mount_root failed: server doesn't support NFS V4"); 2274*7c478bd9Sstevel@tonic-gate else 2275*7c478bd9Sstevel@tonic-gate nfs_cmn_err(error, CE_WARN, 2276*7c478bd9Sstevel@tonic-gate "nfs4_mountroot: mount_root failed: %m"); 2277*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 2278*7c478bd9Sstevel@tonic-gate sv4_free(svp); 2279*7c478bd9Sstevel@tonic-gate pn_free(&pn); 2280*7c478bd9Sstevel@tonic-gate return (error); 2281*7c478bd9Sstevel@tonic-gate } 2282*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 2283*7c478bd9Sstevel@tonic-gate svp->sv_hostnamelen = (int)(strlen(root_hostname) + 1); 2284*7c478bd9Sstevel@tonic-gate svp->sv_hostname = kmem_alloc(svp->sv_hostnamelen, KM_SLEEP); 2285*7c478bd9Sstevel@tonic-gate (void) strcpy(svp->sv_hostname, root_hostname); 2286*7c478bd9Sstevel@tonic-gate 2287*7c478bd9Sstevel@tonic-gate svp->sv_pathlen = (int)(strlen(root_path) + 1); 2288*7c478bd9Sstevel@tonic-gate svp->sv_path = kmem_alloc(svp->sv_pathlen, KM_SLEEP); 2289*7c478bd9Sstevel@tonic-gate (void) strcpy(svp->sv_path, root_path); 2290*7c478bd9Sstevel@tonic-gate 2291*7c478bd9Sstevel@tonic-gate /* 2292*7c478bd9Sstevel@tonic-gate * Force root partition to always be mounted with AUTH_UNIX for now 2293*7c478bd9Sstevel@tonic-gate */ 2294*7c478bd9Sstevel@tonic-gate svp->sv_secdata = kmem_alloc(sizeof (*svp->sv_secdata), KM_SLEEP); 2295*7c478bd9Sstevel@tonic-gate svp->sv_secdata->secmod = AUTH_UNIX; 2296*7c478bd9Sstevel@tonic-gate svp->sv_secdata->rpcflavor = AUTH_UNIX; 2297*7c478bd9Sstevel@tonic-gate svp->sv_secdata->data = NULL; 2298*7c478bd9Sstevel@tonic-gate 2299*7c478bd9Sstevel@tonic-gate cr = crgetcred(); 2300*7c478bd9Sstevel@tonic-gate rtvp = NULL; 2301*7c478bd9Sstevel@tonic-gate 2302*7c478bd9Sstevel@tonic-gate error = nfs4rootvp(&rtvp, vfsp, svp, args.flags, cr, global_zone); 2303*7c478bd9Sstevel@tonic-gate 2304*7c478bd9Sstevel@tonic-gate if (error) { 2305*7c478bd9Sstevel@tonic-gate crfree(cr); 2306*7c478bd9Sstevel@tonic-gate pn_free(&pn); 2307*7c478bd9Sstevel@tonic-gate goto errout; 2308*7c478bd9Sstevel@tonic-gate } 2309*7c478bd9Sstevel@tonic-gate 2310*7c478bd9Sstevel@tonic-gate mi = VTOMI4(rtvp); 2311*7c478bd9Sstevel@tonic-gate 2312*7c478bd9Sstevel@tonic-gate /* 2313*7c478bd9Sstevel@tonic-gate * Send client id to the server, if necessary 2314*7c478bd9Sstevel@tonic-gate */ 2315*7c478bd9Sstevel@tonic-gate nfs4_error_zinit(&n4e); 2316*7c478bd9Sstevel@tonic-gate nfs4setclientid(mi, cr, FALSE, &n4e); 2317*7c478bd9Sstevel@tonic-gate error = n4e.error; 2318*7c478bd9Sstevel@tonic-gate 2319*7c478bd9Sstevel@tonic-gate crfree(cr); 2320*7c478bd9Sstevel@tonic-gate 2321*7c478bd9Sstevel@tonic-gate if (error) { 2322*7c478bd9Sstevel@tonic-gate pn_free(&pn); 2323*7c478bd9Sstevel@tonic-gate goto errout; 2324*7c478bd9Sstevel@tonic-gate } 2325*7c478bd9Sstevel@tonic-gate 2326*7c478bd9Sstevel@tonic-gate error = nfs4_setopts(rtvp, DATAMODEL_NATIVE, &args); 2327*7c478bd9Sstevel@tonic-gate if (error) { 2328*7c478bd9Sstevel@tonic-gate nfs_cmn_err(error, CE_WARN, 2329*7c478bd9Sstevel@tonic-gate "nfs4_mountroot: invalid root mount options"); 2330*7c478bd9Sstevel@tonic-gate pn_free(&pn); 2331*7c478bd9Sstevel@tonic-gate goto errout; 2332*7c478bd9Sstevel@tonic-gate } 2333*7c478bd9Sstevel@tonic-gate 2334*7c478bd9Sstevel@tonic-gate (void) vfs_lock_wait(vfsp); 2335*7c478bd9Sstevel@tonic-gate vfs_add(NULL, vfsp, vfsflags); 2336*7c478bd9Sstevel@tonic-gate vfs_unlock(vfsp); 2337*7c478bd9Sstevel@tonic-gate 2338*7c478bd9Sstevel@tonic-gate size = strlen(svp->sv_hostname); 2339*7c478bd9Sstevel@tonic-gate (void) strcpy(rootfs.bo_name, svp->sv_hostname); 2340*7c478bd9Sstevel@tonic-gate rootfs.bo_name[size] = ':'; 2341*7c478bd9Sstevel@tonic-gate (void) strcpy(&rootfs.bo_name[size + 1], root_path); 2342*7c478bd9Sstevel@tonic-gate 2343*7c478bd9Sstevel@tonic-gate pn_free(&pn); 2344*7c478bd9Sstevel@tonic-gate 2345*7c478bd9Sstevel@tonic-gate errout: 2346*7c478bd9Sstevel@tonic-gate if (error) { 2347*7c478bd9Sstevel@tonic-gate sv4_free(svp); 2348*7c478bd9Sstevel@tonic-gate nfs4_async_stop(vfsp); 2349*7c478bd9Sstevel@tonic-gate nfs4_async_manager_stop(vfsp); 2350*7c478bd9Sstevel@tonic-gate } 2351*7c478bd9Sstevel@tonic-gate 2352*7c478bd9Sstevel@tonic-gate if (rtvp != NULL) 2353*7c478bd9Sstevel@tonic-gate VN_RELE(rtvp); 2354*7c478bd9Sstevel@tonic-gate 2355*7c478bd9Sstevel@tonic-gate return (error); 2356*7c478bd9Sstevel@tonic-gate } 2357*7c478bd9Sstevel@tonic-gate 2358*7c478bd9Sstevel@tonic-gate /* 2359*7c478bd9Sstevel@tonic-gate * Initialization routine for VFS routines. Should only be called once 2360*7c478bd9Sstevel@tonic-gate */ 2361*7c478bd9Sstevel@tonic-gate int 2362*7c478bd9Sstevel@tonic-gate nfs4_vfsinit(void) 2363*7c478bd9Sstevel@tonic-gate { 2364*7c478bd9Sstevel@tonic-gate mutex_init(&nfs4_syncbusy, NULL, MUTEX_DEFAULT, NULL); 2365*7c478bd9Sstevel@tonic-gate nfs4setclientid_init(); 2366*7c478bd9Sstevel@tonic-gate return (0); 2367*7c478bd9Sstevel@tonic-gate } 2368*7c478bd9Sstevel@tonic-gate 2369*7c478bd9Sstevel@tonic-gate void 2370*7c478bd9Sstevel@tonic-gate nfs4_vfsfini(void) 2371*7c478bd9Sstevel@tonic-gate { 2372*7c478bd9Sstevel@tonic-gate nfs4setclientid_fini(); 2373*7c478bd9Sstevel@tonic-gate mutex_destroy(&nfs4_syncbusy); 2374*7c478bd9Sstevel@tonic-gate } 2375*7c478bd9Sstevel@tonic-gate 2376*7c478bd9Sstevel@tonic-gate void 2377*7c478bd9Sstevel@tonic-gate nfs4_freevfs(vfs_t *vfsp) 2378*7c478bd9Sstevel@tonic-gate { 2379*7c478bd9Sstevel@tonic-gate mntinfo4_t *mi; 2380*7c478bd9Sstevel@tonic-gate servinfo4_t *svp; 2381*7c478bd9Sstevel@tonic-gate 2382*7c478bd9Sstevel@tonic-gate /* free up the resources */ 2383*7c478bd9Sstevel@tonic-gate mi = VFTOMI4(vfsp); 2384*7c478bd9Sstevel@tonic-gate svp = mi->mi_servers; 2385*7c478bd9Sstevel@tonic-gate mi->mi_servers = mi->mi_curr_serv = NULL; 2386*7c478bd9Sstevel@tonic-gate sv4_free(svp); 2387*7c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, "nfs4_freevfs: " 2388*7c478bd9Sstevel@tonic-gate "free mi %p", (void *)mi)); 2389*7c478bd9Sstevel@tonic-gate 2390*7c478bd9Sstevel@tonic-gate /* 2391*7c478bd9Sstevel@tonic-gate * By this time we should have already deleted the 2392*7c478bd9Sstevel@tonic-gate * mi kstats in the unmount code. If they are still around 2393*7c478bd9Sstevel@tonic-gate * somethings wrong 2394*7c478bd9Sstevel@tonic-gate */ 2395*7c478bd9Sstevel@tonic-gate ASSERT(mi->mi_io_kstats == NULL); 2396*7c478bd9Sstevel@tonic-gate 2397*7c478bd9Sstevel@tonic-gate nfs_free_mi4(mi); 2398*7c478bd9Sstevel@tonic-gate } 2399*7c478bd9Sstevel@tonic-gate 2400*7c478bd9Sstevel@tonic-gate /* 2401*7c478bd9Sstevel@tonic-gate * Client side SETCLIENTID and SETCLIENTID_CONFIRM 2402*7c478bd9Sstevel@tonic-gate */ 2403*7c478bd9Sstevel@tonic-gate struct nfs4_server nfs4_server_lst = 2404*7c478bd9Sstevel@tonic-gate { &nfs4_server_lst, &nfs4_server_lst }; 2405*7c478bd9Sstevel@tonic-gate 2406*7c478bd9Sstevel@tonic-gate kmutex_t nfs4_server_lst_lock; 2407*7c478bd9Sstevel@tonic-gate 2408*7c478bd9Sstevel@tonic-gate static void 2409*7c478bd9Sstevel@tonic-gate nfs4setclientid_init(void) 2410*7c478bd9Sstevel@tonic-gate { 2411*7c478bd9Sstevel@tonic-gate mutex_init(&nfs4_server_lst_lock, NULL, MUTEX_DEFAULT, NULL); 2412*7c478bd9Sstevel@tonic-gate } 2413*7c478bd9Sstevel@tonic-gate 2414*7c478bd9Sstevel@tonic-gate static void 2415*7c478bd9Sstevel@tonic-gate nfs4setclientid_fini(void) 2416*7c478bd9Sstevel@tonic-gate { 2417*7c478bd9Sstevel@tonic-gate mutex_destroy(&nfs4_server_lst_lock); 2418*7c478bd9Sstevel@tonic-gate } 2419*7c478bd9Sstevel@tonic-gate 2420*7c478bd9Sstevel@tonic-gate int nfs4_retry_sclid_delay = NFS4_RETRY_SCLID_DELAY; 2421*7c478bd9Sstevel@tonic-gate int nfs4_num_sclid_retries = NFS4_NUM_SCLID_RETRIES; 2422*7c478bd9Sstevel@tonic-gate 2423*7c478bd9Sstevel@tonic-gate /* 2424*7c478bd9Sstevel@tonic-gate * Set the clientid for the server for "mi". No-op if the clientid is 2425*7c478bd9Sstevel@tonic-gate * already set. 2426*7c478bd9Sstevel@tonic-gate * 2427*7c478bd9Sstevel@tonic-gate * The recovery boolean should be set to TRUE if this function was called 2428*7c478bd9Sstevel@tonic-gate * by the recovery code, and FALSE otherwise. 2429*7c478bd9Sstevel@tonic-gate * 2430*7c478bd9Sstevel@tonic-gate * Error is returned via 'n4ep'. If there was a 'n4ep->stat' error, then 2431*7c478bd9Sstevel@tonic-gate * 'n4ep->error' is set to geterrno4(n4ep->stat). 2432*7c478bd9Sstevel@tonic-gate */ 2433*7c478bd9Sstevel@tonic-gate void 2434*7c478bd9Sstevel@tonic-gate nfs4setclientid(mntinfo4_t *mi, cred_t *cr, bool_t recovery, nfs4_error_t *n4ep) 2435*7c478bd9Sstevel@tonic-gate { 2436*7c478bd9Sstevel@tonic-gate struct nfs4_server *np; 2437*7c478bd9Sstevel@tonic-gate struct servinfo4 *svp = mi->mi_curr_serv; 2438*7c478bd9Sstevel@tonic-gate nfs4_recov_state_t recov_state; 2439*7c478bd9Sstevel@tonic-gate int num_retries = 0; 2440*7c478bd9Sstevel@tonic-gate bool_t retry = FALSE; 2441*7c478bd9Sstevel@tonic-gate cred_t *lcr = NULL; 2442*7c478bd9Sstevel@tonic-gate int retry_inuse = 1; /* only retry once on NFS4ERR_CLID_INUSE */ 2443*7c478bd9Sstevel@tonic-gate time_t lease_time = 0; 2444*7c478bd9Sstevel@tonic-gate 2445*7c478bd9Sstevel@tonic-gate recov_state.rs_flags = 0; 2446*7c478bd9Sstevel@tonic-gate recov_state.rs_num_retry_despite_err = 0; 2447*7c478bd9Sstevel@tonic-gate ASSERT(n4ep != NULL); 2448*7c478bd9Sstevel@tonic-gate 2449*7c478bd9Sstevel@tonic-gate recov_retry: 2450*7c478bd9Sstevel@tonic-gate nfs4_error_zinit(n4ep); 2451*7c478bd9Sstevel@tonic-gate /* This locks np if it is found */ 2452*7c478bd9Sstevel@tonic-gate np = servinfo4_to_nfs4_server(svp); 2453*7c478bd9Sstevel@tonic-gate ASSERT(np == NULL || MUTEX_HELD(&np->s_lock)); 2454*7c478bd9Sstevel@tonic-gate 2455*7c478bd9Sstevel@tonic-gate /* 2456*7c478bd9Sstevel@tonic-gate * If we find the server already in the list, then just 2457*7c478bd9Sstevel@tonic-gate * return, we've already done SETCLIENTID to that server 2458*7c478bd9Sstevel@tonic-gate */ 2459*7c478bd9Sstevel@tonic-gate 2460*7c478bd9Sstevel@tonic-gate if (np && (np->s_flags & N4S_CLIENTID_SET)) { 2461*7c478bd9Sstevel@tonic-gate /* 2462*7c478bd9Sstevel@tonic-gate * XXX - more is needed here. SETCLIENTID may not 2463*7c478bd9Sstevel@tonic-gate * be completed. A VFS lock may prevent multiple 2464*7c478bd9Sstevel@tonic-gate * mounts and provide needed serialization. 2465*7c478bd9Sstevel@tonic-gate */ 2466*7c478bd9Sstevel@tonic-gate /* add mi to np's mntinfo4_list */ 2467*7c478bd9Sstevel@tonic-gate nfs4_add_mi_to_server(np, mi); 2468*7c478bd9Sstevel@tonic-gate mutex_exit(&np->s_lock); 2469*7c478bd9Sstevel@tonic-gate nfs4_server_rele(np); 2470*7c478bd9Sstevel@tonic-gate return; 2471*7c478bd9Sstevel@tonic-gate } 2472*7c478bd9Sstevel@tonic-gate 2473*7c478bd9Sstevel@tonic-gate if (!np) 2474*7c478bd9Sstevel@tonic-gate np = new_nfs4_server(svp, cr); 2475*7c478bd9Sstevel@tonic-gate else 2476*7c478bd9Sstevel@tonic-gate mutex_exit(&np->s_lock); 2477*7c478bd9Sstevel@tonic-gate 2478*7c478bd9Sstevel@tonic-gate if (!recovery) { 2479*7c478bd9Sstevel@tonic-gate n4ep->error = nfs4_start_op(mi, NULL, NULL, &recov_state); 2480*7c478bd9Sstevel@tonic-gate if (n4ep->error) { 2481*7c478bd9Sstevel@tonic-gate nfs4_server_rele(np); 2482*7c478bd9Sstevel@tonic-gate return; 2483*7c478bd9Sstevel@tonic-gate } 2484*7c478bd9Sstevel@tonic-gate } 2485*7c478bd9Sstevel@tonic-gate 2486*7c478bd9Sstevel@tonic-gate /* 2487*7c478bd9Sstevel@tonic-gate * Will potentially add np to global list, which transfers 2488*7c478bd9Sstevel@tonic-gate * ownership of the reference to the list. 2489*7c478bd9Sstevel@tonic-gate */ 2490*7c478bd9Sstevel@tonic-gate mutex_enter(&nfs4_server_lst_lock); 2491*7c478bd9Sstevel@tonic-gate mutex_enter(&np->s_lock); 2492*7c478bd9Sstevel@tonic-gate 2493*7c478bd9Sstevel@tonic-gate /* 2494*7c478bd9Sstevel@tonic-gate * Reset the N4S_CB_PINGED flag. This is used to 2495*7c478bd9Sstevel@tonic-gate * indicate if we have received a CB_NULL from the 2496*7c478bd9Sstevel@tonic-gate * server. Also we reset the waiter flag. 2497*7c478bd9Sstevel@tonic-gate */ 2498*7c478bd9Sstevel@tonic-gate np->s_flags &= ~(N4S_CB_PINGED | N4S_CB_WAITER); 2499*7c478bd9Sstevel@tonic-gate 2500*7c478bd9Sstevel@tonic-gate if (np->s_flags & N4S_CLIENTID_SET) { 2501*7c478bd9Sstevel@tonic-gate /* XXX copied/pasted from above */ 2502*7c478bd9Sstevel@tonic-gate /* 2503*7c478bd9Sstevel@tonic-gate * XXX - more is needed here. SETCLIENTID may not 2504*7c478bd9Sstevel@tonic-gate * be completed. A VFS lock may prevent multiple 2505*7c478bd9Sstevel@tonic-gate * mounts and provide needed serialization. 2506*7c478bd9Sstevel@tonic-gate */ 2507*7c478bd9Sstevel@tonic-gate /* add mi to np's mntinfo4_list */ 2508*7c478bd9Sstevel@tonic-gate nfs4_add_mi_to_server(np, mi); 2509*7c478bd9Sstevel@tonic-gate mutex_exit(&np->s_lock); 2510*7c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_server_lst_lock); 2511*7c478bd9Sstevel@tonic-gate nfs4_server_rele(np); 2512*7c478bd9Sstevel@tonic-gate if (!recovery) 2513*7c478bd9Sstevel@tonic-gate nfs4_end_op(mi, NULL, NULL, &recov_state, recovery); 2514*7c478bd9Sstevel@tonic-gate return; 2515*7c478bd9Sstevel@tonic-gate } 2516*7c478bd9Sstevel@tonic-gate 2517*7c478bd9Sstevel@tonic-gate nfs4setclientid_otw(mi, svp, cr, np, n4ep, &retry_inuse); 2518*7c478bd9Sstevel@tonic-gate 2519*7c478bd9Sstevel@tonic-gate if (n4ep->error == EACCES) { 2520*7c478bd9Sstevel@tonic-gate /* 2521*7c478bd9Sstevel@tonic-gate * If the uid is set then set the creds for secure mounts 2522*7c478bd9Sstevel@tonic-gate * by proxy processes such as automountd. 2523*7c478bd9Sstevel@tonic-gate */ 2524*7c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 2525*7c478bd9Sstevel@tonic-gate if (svp->sv_secdata->uid != 0) { 2526*7c478bd9Sstevel@tonic-gate lcr = crdup(cr); 2527*7c478bd9Sstevel@tonic-gate (void) crsetugid(lcr, svp->sv_secdata->uid, 2528*7c478bd9Sstevel@tonic-gate crgetgid(cr)); 2529*7c478bd9Sstevel@tonic-gate crfree(np->s_cred); 2530*7c478bd9Sstevel@tonic-gate np->s_cred = lcr; 2531*7c478bd9Sstevel@tonic-gate } 2532*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 2533*7c478bd9Sstevel@tonic-gate 2534*7c478bd9Sstevel@tonic-gate if (lcr != NULL) 2535*7c478bd9Sstevel@tonic-gate nfs4setclientid_otw(mi, svp, lcr, np, n4ep, 2536*7c478bd9Sstevel@tonic-gate &retry_inuse); 2537*7c478bd9Sstevel@tonic-gate } 2538*7c478bd9Sstevel@tonic-gate lease_time = np->s_lease_time; 2539*7c478bd9Sstevel@tonic-gate mutex_exit(&np->s_lock); 2540*7c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_server_lst_lock); 2541*7c478bd9Sstevel@tonic-gate 2542*7c478bd9Sstevel@tonic-gate if (n4ep->error != 0 || n4ep->stat != NFS4_OK) { 2543*7c478bd9Sstevel@tonic-gate /* 2544*7c478bd9Sstevel@tonic-gate * Start recovery if failover is a possibility. If 2545*7c478bd9Sstevel@tonic-gate * invoked by the recovery thread itself, then just 2546*7c478bd9Sstevel@tonic-gate * return and let it handle the failover first. NB: 2547*7c478bd9Sstevel@tonic-gate * recovery is not allowed if the mount is in progress 2548*7c478bd9Sstevel@tonic-gate * since the infrastructure is not sufficiently setup 2549*7c478bd9Sstevel@tonic-gate * to allow it. Just return the error (after suitable 2550*7c478bd9Sstevel@tonic-gate * retries). 2551*7c478bd9Sstevel@tonic-gate */ 2552*7c478bd9Sstevel@tonic-gate if (FAILOVER_MOUNT4(mi) && nfs4_try_failover(n4ep)) { 2553*7c478bd9Sstevel@tonic-gate (void) nfs4_start_recovery(n4ep, mi, NULL, 2554*7c478bd9Sstevel@tonic-gate NULL, NULL, NULL, OP_SETCLIENTID, NULL); 2555*7c478bd9Sstevel@tonic-gate /* 2556*7c478bd9Sstevel@tonic-gate * Don't retry here, just return and let 2557*7c478bd9Sstevel@tonic-gate * recovery take over. 2558*7c478bd9Sstevel@tonic-gate */ 2559*7c478bd9Sstevel@tonic-gate if (recovery) 2560*7c478bd9Sstevel@tonic-gate retry = FALSE; 2561*7c478bd9Sstevel@tonic-gate } else if (nfs4_rpc_retry_error(n4ep->error) || 2562*7c478bd9Sstevel@tonic-gate n4ep->stat == NFS4ERR_RESOURCE || 2563*7c478bd9Sstevel@tonic-gate n4ep->stat == NFS4ERR_STALE_CLIENTID) { 2564*7c478bd9Sstevel@tonic-gate 2565*7c478bd9Sstevel@tonic-gate retry = TRUE; 2566*7c478bd9Sstevel@tonic-gate /* 2567*7c478bd9Sstevel@tonic-gate * Always retry if in recovery or once had 2568*7c478bd9Sstevel@tonic-gate * contact with the server (but now it's 2569*7c478bd9Sstevel@tonic-gate * overloaded). 2570*7c478bd9Sstevel@tonic-gate */ 2571*7c478bd9Sstevel@tonic-gate if (recovery == TRUE || 2572*7c478bd9Sstevel@tonic-gate n4ep->error == ETIMEDOUT || 2573*7c478bd9Sstevel@tonic-gate n4ep->error == ECONNRESET) 2574*7c478bd9Sstevel@tonic-gate num_retries = 0; 2575*7c478bd9Sstevel@tonic-gate } else if (retry_inuse && n4ep->error == 0 && 2576*7c478bd9Sstevel@tonic-gate n4ep->stat == NFS4ERR_CLID_INUSE) { 2577*7c478bd9Sstevel@tonic-gate retry = TRUE; 2578*7c478bd9Sstevel@tonic-gate num_retries = 0; 2579*7c478bd9Sstevel@tonic-gate } 2580*7c478bd9Sstevel@tonic-gate } 2581*7c478bd9Sstevel@tonic-gate 2582*7c478bd9Sstevel@tonic-gate if (!recovery) 2583*7c478bd9Sstevel@tonic-gate nfs4_end_op(mi, NULL, NULL, &recov_state, recovery); 2584*7c478bd9Sstevel@tonic-gate nfs4_server_rele(np); 2585*7c478bd9Sstevel@tonic-gate 2586*7c478bd9Sstevel@tonic-gate if (retry && num_retries++ < nfs4_num_sclid_retries) { 2587*7c478bd9Sstevel@tonic-gate if (retry_inuse) { 2588*7c478bd9Sstevel@tonic-gate delay(SEC_TO_TICK(lease_time + nfs4_retry_sclid_delay)); 2589*7c478bd9Sstevel@tonic-gate retry_inuse = 0; 2590*7c478bd9Sstevel@tonic-gate } else 2591*7c478bd9Sstevel@tonic-gate delay(SEC_TO_TICK(nfs4_retry_sclid_delay)); 2592*7c478bd9Sstevel@tonic-gate goto recov_retry; 2593*7c478bd9Sstevel@tonic-gate } 2594*7c478bd9Sstevel@tonic-gate 2595*7c478bd9Sstevel@tonic-gate if (n4ep->error == 0) 2596*7c478bd9Sstevel@tonic-gate n4ep->error = geterrno4(n4ep->stat); 2597*7c478bd9Sstevel@tonic-gate } 2598*7c478bd9Sstevel@tonic-gate 2599*7c478bd9Sstevel@tonic-gate int nfs4setclientid_otw_debug = 0; 2600*7c478bd9Sstevel@tonic-gate 2601*7c478bd9Sstevel@tonic-gate /* 2602*7c478bd9Sstevel@tonic-gate * This assumes np is locked down. 2603*7c478bd9Sstevel@tonic-gate * This function handles the recovery of STALE_CLIENTID for SETCLIENTID_CONFRIM, 2604*7c478bd9Sstevel@tonic-gate * but nothing else; the calling function must be designed to handle those 2605*7c478bd9Sstevel@tonic-gate * other errors. 2606*7c478bd9Sstevel@tonic-gate */ 2607*7c478bd9Sstevel@tonic-gate static void 2608*7c478bd9Sstevel@tonic-gate nfs4setclientid_otw(mntinfo4_t *mi, struct servinfo4 *svp, cred_t *cr, 2609*7c478bd9Sstevel@tonic-gate struct nfs4_server *np, nfs4_error_t *ep, int *retry_inusep) 2610*7c478bd9Sstevel@tonic-gate { 2611*7c478bd9Sstevel@tonic-gate COMPOUND4args_clnt args; 2612*7c478bd9Sstevel@tonic-gate COMPOUND4res_clnt res; 2613*7c478bd9Sstevel@tonic-gate nfs_argop4 argop[3]; 2614*7c478bd9Sstevel@tonic-gate SETCLIENTID4args *s_args; 2615*7c478bd9Sstevel@tonic-gate SETCLIENTID4resok *s_resok; 2616*7c478bd9Sstevel@tonic-gate int doqueue = 1; 2617*7c478bd9Sstevel@tonic-gate nfs4_ga_res_t *garp = NULL; 2618*7c478bd9Sstevel@tonic-gate timespec_t prop_time, after_time; 2619*7c478bd9Sstevel@tonic-gate verifier4 verf; 2620*7c478bd9Sstevel@tonic-gate clientid4 tmp_clientid; 2621*7c478bd9Sstevel@tonic-gate 2622*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&np->s_lock)); 2623*7c478bd9Sstevel@tonic-gate 2624*7c478bd9Sstevel@tonic-gate args.ctag = TAG_SETCLIENTID; 2625*7c478bd9Sstevel@tonic-gate 2626*7c478bd9Sstevel@tonic-gate args.array = argop; 2627*7c478bd9Sstevel@tonic-gate args.array_len = 3; 2628*7c478bd9Sstevel@tonic-gate 2629*7c478bd9Sstevel@tonic-gate /* PUTROOTFH */ 2630*7c478bd9Sstevel@tonic-gate argop[0].argop = OP_PUTROOTFH; 2631*7c478bd9Sstevel@tonic-gate 2632*7c478bd9Sstevel@tonic-gate /* GETATTR */ 2633*7c478bd9Sstevel@tonic-gate argop[1].argop = OP_GETATTR; 2634*7c478bd9Sstevel@tonic-gate argop[1].nfs_argop4_u.opgetattr.attr_request = FATTR4_LEASE_TIME_MASK; 2635*7c478bd9Sstevel@tonic-gate argop[1].nfs_argop4_u.opgetattr.mi = mi; 2636*7c478bd9Sstevel@tonic-gate 2637*7c478bd9Sstevel@tonic-gate /* SETCLIENTID */ 2638*7c478bd9Sstevel@tonic-gate argop[2].argop = OP_SETCLIENTID; 2639*7c478bd9Sstevel@tonic-gate 2640*7c478bd9Sstevel@tonic-gate s_args = &argop[2].nfs_argop4_u.opsetclientid; 2641*7c478bd9Sstevel@tonic-gate 2642*7c478bd9Sstevel@tonic-gate s_args->client.verifier = np->clidtosend.verifier; 2643*7c478bd9Sstevel@tonic-gate s_args->client.id_len = np->clidtosend.id_len; 2644*7c478bd9Sstevel@tonic-gate ASSERT(s_args->client.id_len <= NFS4_OPAQUE_LIMIT); 2645*7c478bd9Sstevel@tonic-gate s_args->client.id_val = np->clidtosend.id_val; 2646*7c478bd9Sstevel@tonic-gate 2647*7c478bd9Sstevel@tonic-gate /* 2648*7c478bd9Sstevel@tonic-gate * Callback needs to happen on non-RDMA transport 2649*7c478bd9Sstevel@tonic-gate * Check if we have saved the original knetconfig 2650*7c478bd9Sstevel@tonic-gate * if so, use that instead. 2651*7c478bd9Sstevel@tonic-gate */ 2652*7c478bd9Sstevel@tonic-gate if (svp->sv_origknconf != NULL) 2653*7c478bd9Sstevel@tonic-gate nfs4_cb_args(np, svp->sv_origknconf, s_args); 2654*7c478bd9Sstevel@tonic-gate else 2655*7c478bd9Sstevel@tonic-gate nfs4_cb_args(np, svp->sv_knconf, s_args); 2656*7c478bd9Sstevel@tonic-gate 2657*7c478bd9Sstevel@tonic-gate rfs4call(mi, &args, &res, cr, &doqueue, RFSCALL_SOFT, ep); 2658*7c478bd9Sstevel@tonic-gate 2659*7c478bd9Sstevel@tonic-gate if (ep->error) 2660*7c478bd9Sstevel@tonic-gate return; 2661*7c478bd9Sstevel@tonic-gate 2662*7c478bd9Sstevel@tonic-gate /* getattr lease_time res */ 2663*7c478bd9Sstevel@tonic-gate if (res.array_len >= 2) { 2664*7c478bd9Sstevel@tonic-gate garp = &res.array[1].nfs_resop4_u.opgetattr.ga_res; 2665*7c478bd9Sstevel@tonic-gate 2666*7c478bd9Sstevel@tonic-gate #ifndef _LP64 2667*7c478bd9Sstevel@tonic-gate /* 2668*7c478bd9Sstevel@tonic-gate * The 32 bit client cannot handle a lease time greater than 2669*7c478bd9Sstevel@tonic-gate * (INT32_MAX/1000000). This is due to the use of the 2670*7c478bd9Sstevel@tonic-gate * lease_time in calls to drv_usectohz() in 2671*7c478bd9Sstevel@tonic-gate * nfs4_renew_lease_thread(). The problem is that 2672*7c478bd9Sstevel@tonic-gate * drv_usectohz() takes a time_t (which is just a long = 4 2673*7c478bd9Sstevel@tonic-gate * bytes) as its parameter. The lease_time is multiplied by 2674*7c478bd9Sstevel@tonic-gate * 1000000 to convert seconds to usecs for the parameter. If 2675*7c478bd9Sstevel@tonic-gate * a number bigger than (INT32_MAX/1000000) is used then we 2676*7c478bd9Sstevel@tonic-gate * overflow on the 32bit client. 2677*7c478bd9Sstevel@tonic-gate */ 2678*7c478bd9Sstevel@tonic-gate if (garp->n4g_ext_res->n4g_leasetime > (INT32_MAX/1000000)) { 2679*7c478bd9Sstevel@tonic-gate garp->n4g_ext_res->n4g_leasetime = INT32_MAX/1000000; 2680*7c478bd9Sstevel@tonic-gate } 2681*7c478bd9Sstevel@tonic-gate #endif 2682*7c478bd9Sstevel@tonic-gate 2683*7c478bd9Sstevel@tonic-gate np->s_lease_time = garp->n4g_ext_res->n4g_leasetime; 2684*7c478bd9Sstevel@tonic-gate 2685*7c478bd9Sstevel@tonic-gate /* 2686*7c478bd9Sstevel@tonic-gate * Keep track of the lease period for the mi's 2687*7c478bd9Sstevel@tonic-gate * mi_msg_list. We need an appropiate time 2688*7c478bd9Sstevel@tonic-gate * bound to associate past facts with a current 2689*7c478bd9Sstevel@tonic-gate * event. The lease period is perfect for this. 2690*7c478bd9Sstevel@tonic-gate */ 2691*7c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_msg_list_lock); 2692*7c478bd9Sstevel@tonic-gate mi->mi_lease_period = np->s_lease_time; 2693*7c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_msg_list_lock); 2694*7c478bd9Sstevel@tonic-gate } 2695*7c478bd9Sstevel@tonic-gate 2696*7c478bd9Sstevel@tonic-gate 2697*7c478bd9Sstevel@tonic-gate if (res.status == NFS4ERR_CLID_INUSE) { 2698*7c478bd9Sstevel@tonic-gate clientaddr4 *clid_inuse; 2699*7c478bd9Sstevel@tonic-gate 2700*7c478bd9Sstevel@tonic-gate if (!(*retry_inusep)) { 2701*7c478bd9Sstevel@tonic-gate clid_inuse = &res.array->nfs_resop4_u. 2702*7c478bd9Sstevel@tonic-gate opsetclientid.SETCLIENTID4res_u.client_using; 2703*7c478bd9Sstevel@tonic-gate 2704*7c478bd9Sstevel@tonic-gate zcmn_err(mi->mi_zone->zone_id, CE_NOTE, 2705*7c478bd9Sstevel@tonic-gate "NFS4 mount (SETCLIENTID failed)." 2706*7c478bd9Sstevel@tonic-gate " nfs4_client_id.id is in" 2707*7c478bd9Sstevel@tonic-gate "use already by: r_netid<%s> r_addr<%s>", 2708*7c478bd9Sstevel@tonic-gate clid_inuse->r_netid, clid_inuse->r_addr); 2709*7c478bd9Sstevel@tonic-gate } 2710*7c478bd9Sstevel@tonic-gate 2711*7c478bd9Sstevel@tonic-gate /* 2712*7c478bd9Sstevel@tonic-gate * XXX - The client should be more robust in its 2713*7c478bd9Sstevel@tonic-gate * handling of clientid in use errors (regen another 2714*7c478bd9Sstevel@tonic-gate * clientid and try again?) 2715*7c478bd9Sstevel@tonic-gate */ 2716*7c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 2717*7c478bd9Sstevel@tonic-gate return; 2718*7c478bd9Sstevel@tonic-gate } 2719*7c478bd9Sstevel@tonic-gate 2720*7c478bd9Sstevel@tonic-gate if (res.status) { 2721*7c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 2722*7c478bd9Sstevel@tonic-gate return; 2723*7c478bd9Sstevel@tonic-gate } 2724*7c478bd9Sstevel@tonic-gate 2725*7c478bd9Sstevel@tonic-gate s_resok = &res.array[2].nfs_resop4_u. 2726*7c478bd9Sstevel@tonic-gate opsetclientid.SETCLIENTID4res_u.resok4; 2727*7c478bd9Sstevel@tonic-gate 2728*7c478bd9Sstevel@tonic-gate tmp_clientid = s_resok->clientid; 2729*7c478bd9Sstevel@tonic-gate 2730*7c478bd9Sstevel@tonic-gate verf = s_resok->setclientid_confirm; 2731*7c478bd9Sstevel@tonic-gate 2732*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2733*7c478bd9Sstevel@tonic-gate if (nfs4setclientid_otw_debug) { 2734*7c478bd9Sstevel@tonic-gate union { 2735*7c478bd9Sstevel@tonic-gate clientid4 clientid; 2736*7c478bd9Sstevel@tonic-gate int foo[2]; 2737*7c478bd9Sstevel@tonic-gate } cid; 2738*7c478bd9Sstevel@tonic-gate 2739*7c478bd9Sstevel@tonic-gate cid.clientid = s_resok->clientid; 2740*7c478bd9Sstevel@tonic-gate 2741*7c478bd9Sstevel@tonic-gate zcmn_err(mi->mi_zone->zone_id, CE_NOTE, 2742*7c478bd9Sstevel@tonic-gate "nfs4setclientid_otw: OK, clientid = %x,%x, " 2743*7c478bd9Sstevel@tonic-gate "verifier = %" PRIx64 "\n", cid.foo[0], cid.foo[1], verf); 2744*7c478bd9Sstevel@tonic-gate } 2745*7c478bd9Sstevel@tonic-gate #endif 2746*7c478bd9Sstevel@tonic-gate 2747*7c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 2748*7c478bd9Sstevel@tonic-gate 2749*7c478bd9Sstevel@tonic-gate /* Confirm the client id and get the lease_time attribute */ 2750*7c478bd9Sstevel@tonic-gate 2751*7c478bd9Sstevel@tonic-gate args.ctag = TAG_SETCLIENTID_CF; 2752*7c478bd9Sstevel@tonic-gate 2753*7c478bd9Sstevel@tonic-gate args.array = argop; 2754*7c478bd9Sstevel@tonic-gate args.array_len = 1; 2755*7c478bd9Sstevel@tonic-gate 2756*7c478bd9Sstevel@tonic-gate argop[0].argop = OP_SETCLIENTID_CONFIRM; 2757*7c478bd9Sstevel@tonic-gate 2758*7c478bd9Sstevel@tonic-gate argop[0].nfs_argop4_u.opsetclientid_confirm.clientid = tmp_clientid; 2759*7c478bd9Sstevel@tonic-gate argop[0].nfs_argop4_u.opsetclientid_confirm.setclientid_confirm = verf; 2760*7c478bd9Sstevel@tonic-gate 2761*7c478bd9Sstevel@tonic-gate /* used to figure out RTT for np */ 2762*7c478bd9Sstevel@tonic-gate gethrestime(&prop_time); 2763*7c478bd9Sstevel@tonic-gate 2764*7c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, "nfs4setlientid_otw: " 2765*7c478bd9Sstevel@tonic-gate "start time: %ld sec %ld nsec", prop_time.tv_sec, 2766*7c478bd9Sstevel@tonic-gate prop_time.tv_nsec)); 2767*7c478bd9Sstevel@tonic-gate 2768*7c478bd9Sstevel@tonic-gate rfs4call(mi, &args, &res, cr, &doqueue, 0, ep); 2769*7c478bd9Sstevel@tonic-gate 2770*7c478bd9Sstevel@tonic-gate gethrestime(&after_time); 2771*7c478bd9Sstevel@tonic-gate np->propagation_delay.tv_sec = 2772*7c478bd9Sstevel@tonic-gate MAX(1, after_time.tv_sec - prop_time.tv_sec); 2773*7c478bd9Sstevel@tonic-gate 2774*7c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, "nfs4setlcientid_otw: " 2775*7c478bd9Sstevel@tonic-gate "finish time: %ld sec ", after_time.tv_sec)); 2776*7c478bd9Sstevel@tonic-gate 2777*7c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, "nfs4setclientid_otw: " 2778*7c478bd9Sstevel@tonic-gate "propagation delay set to %ld sec", 2779*7c478bd9Sstevel@tonic-gate np->propagation_delay.tv_sec)); 2780*7c478bd9Sstevel@tonic-gate 2781*7c478bd9Sstevel@tonic-gate if (ep->error) 2782*7c478bd9Sstevel@tonic-gate return; 2783*7c478bd9Sstevel@tonic-gate 2784*7c478bd9Sstevel@tonic-gate if (res.status == NFS4ERR_CLID_INUSE) { 2785*7c478bd9Sstevel@tonic-gate clientaddr4 *clid_inuse; 2786*7c478bd9Sstevel@tonic-gate 2787*7c478bd9Sstevel@tonic-gate if (!(*retry_inusep)) { 2788*7c478bd9Sstevel@tonic-gate clid_inuse = &res.array->nfs_resop4_u. 2789*7c478bd9Sstevel@tonic-gate opsetclientid.SETCLIENTID4res_u.client_using; 2790*7c478bd9Sstevel@tonic-gate 2791*7c478bd9Sstevel@tonic-gate zcmn_err(mi->mi_zone->zone_id, CE_NOTE, 2792*7c478bd9Sstevel@tonic-gate "SETCLIENTID_CONFIRM failed. " 2793*7c478bd9Sstevel@tonic-gate "nfs4_client_id.id is in use already by: " 2794*7c478bd9Sstevel@tonic-gate "r_netid<%s> r_addr<%s>", 2795*7c478bd9Sstevel@tonic-gate clid_inuse->r_netid, clid_inuse->r_addr); 2796*7c478bd9Sstevel@tonic-gate } 2797*7c478bd9Sstevel@tonic-gate 2798*7c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 2799*7c478bd9Sstevel@tonic-gate return; 2800*7c478bd9Sstevel@tonic-gate } 2801*7c478bd9Sstevel@tonic-gate 2802*7c478bd9Sstevel@tonic-gate if (res.status) { 2803*7c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 2804*7c478bd9Sstevel@tonic-gate return; 2805*7c478bd9Sstevel@tonic-gate } 2806*7c478bd9Sstevel@tonic-gate 2807*7c478bd9Sstevel@tonic-gate if (!(np->s_flags & N4S_INSERTED)) { 2808*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&nfs4_server_lst_lock)); 2809*7c478bd9Sstevel@tonic-gate insque(np, &nfs4_server_lst); 2810*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&np->s_lock)); 2811*7c478bd9Sstevel@tonic-gate np->s_flags |= N4S_INSERTED; 2812*7c478bd9Sstevel@tonic-gate np->s_refcnt++; /* list gets a reference */ 2813*7c478bd9Sstevel@tonic-gate } 2814*7c478bd9Sstevel@tonic-gate 2815*7c478bd9Sstevel@tonic-gate np->clientid = tmp_clientid; 2816*7c478bd9Sstevel@tonic-gate np->s_flags |= N4S_CLIENTID_SET; 2817*7c478bd9Sstevel@tonic-gate 2818*7c478bd9Sstevel@tonic-gate /* Add mi to np's mntinfo4 list */ 2819*7c478bd9Sstevel@tonic-gate nfs4_add_mi_to_server(np, mi); 2820*7c478bd9Sstevel@tonic-gate 2821*7c478bd9Sstevel@tonic-gate if (np->lease_valid == NFS4_LEASE_NOT_STARTED) { 2822*7c478bd9Sstevel@tonic-gate /* 2823*7c478bd9Sstevel@tonic-gate * Start lease management thread. 2824*7c478bd9Sstevel@tonic-gate * Keep trying until we succeed. 2825*7c478bd9Sstevel@tonic-gate */ 2826*7c478bd9Sstevel@tonic-gate 2827*7c478bd9Sstevel@tonic-gate np->s_refcnt++; /* pass reference to thread */ 2828*7c478bd9Sstevel@tonic-gate (void) zthread_create(NULL, 0, nfs4_renew_lease_thread, np, 0, 2829*7c478bd9Sstevel@tonic-gate minclsyspri); 2830*7c478bd9Sstevel@tonic-gate } 2831*7c478bd9Sstevel@tonic-gate 2832*7c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 2833*7c478bd9Sstevel@tonic-gate } 2834*7c478bd9Sstevel@tonic-gate 2835*7c478bd9Sstevel@tonic-gate /* 2836*7c478bd9Sstevel@tonic-gate * Add mi to sp's mntinfo4_list if it isn't already in the list. Makes 2837*7c478bd9Sstevel@tonic-gate * mi's clientid the same as sp's. 2838*7c478bd9Sstevel@tonic-gate * Assumes sp is locked down. 2839*7c478bd9Sstevel@tonic-gate */ 2840*7c478bd9Sstevel@tonic-gate void 2841*7c478bd9Sstevel@tonic-gate nfs4_add_mi_to_server(nfs4_server_t *sp, mntinfo4_t *mi) 2842*7c478bd9Sstevel@tonic-gate { 2843*7c478bd9Sstevel@tonic-gate mntinfo4_t *tmi; 2844*7c478bd9Sstevel@tonic-gate int in_list = 0; 2845*7c478bd9Sstevel@tonic-gate 2846*7c478bd9Sstevel@tonic-gate ASSERT(sp != &nfs4_server_lst); 2847*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sp->s_lock)); 2848*7c478bd9Sstevel@tonic-gate 2849*7c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, 2850*7c478bd9Sstevel@tonic-gate "nfs4_add_mi_to_server: add mi %p to sp %p", 2851*7c478bd9Sstevel@tonic-gate (void*)mi, (void*)sp)); 2852*7c478bd9Sstevel@tonic-gate 2853*7c478bd9Sstevel@tonic-gate for (tmi = sp->mntinfo4_list; 2854*7c478bd9Sstevel@tonic-gate tmi != NULL; 2855*7c478bd9Sstevel@tonic-gate tmi = tmi->mi_clientid_next) { 2856*7c478bd9Sstevel@tonic-gate if (tmi == mi) { 2857*7c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, 2858*7c478bd9Sstevel@tonic-gate (CE_NOTE, 2859*7c478bd9Sstevel@tonic-gate "nfs4_add_mi_to_server: mi in list")); 2860*7c478bd9Sstevel@tonic-gate in_list = 1; 2861*7c478bd9Sstevel@tonic-gate } 2862*7c478bd9Sstevel@tonic-gate } 2863*7c478bd9Sstevel@tonic-gate 2864*7c478bd9Sstevel@tonic-gate /* 2865*7c478bd9Sstevel@tonic-gate * First put a hold on the mntinfo4's vfsp so that references via 2866*7c478bd9Sstevel@tonic-gate * mntinfo4_list will be valid. 2867*7c478bd9Sstevel@tonic-gate */ 2868*7c478bd9Sstevel@tonic-gate if (!in_list) 2869*7c478bd9Sstevel@tonic-gate VFS_HOLD(mi->mi_vfsp); 2870*7c478bd9Sstevel@tonic-gate 2871*7c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, "nfs4_add_mi_to_server: " 2872*7c478bd9Sstevel@tonic-gate "hold vfs %p for mi: %p", (void*)mi->mi_vfsp, (void*)mi)); 2873*7c478bd9Sstevel@tonic-gate 2874*7c478bd9Sstevel@tonic-gate if (!in_list) { 2875*7c478bd9Sstevel@tonic-gate if (sp->mntinfo4_list) 2876*7c478bd9Sstevel@tonic-gate sp->mntinfo4_list->mi_clientid_prev = mi; 2877*7c478bd9Sstevel@tonic-gate mi->mi_clientid_next = sp->mntinfo4_list; 2878*7c478bd9Sstevel@tonic-gate sp->mntinfo4_list = mi; 2879*7c478bd9Sstevel@tonic-gate mi->mi_srvsettime = gethrestime_sec(); 2880*7c478bd9Sstevel@tonic-gate } 2881*7c478bd9Sstevel@tonic-gate 2882*7c478bd9Sstevel@tonic-gate /* set mi's clientid to that of sp's for later matching */ 2883*7c478bd9Sstevel@tonic-gate mi->mi_clientid = sp->clientid; 2884*7c478bd9Sstevel@tonic-gate 2885*7c478bd9Sstevel@tonic-gate /* 2886*7c478bd9Sstevel@tonic-gate * Update the clientid for any other mi's belonging to sp. This 2887*7c478bd9Sstevel@tonic-gate * must be done here while we hold sp->s_lock, so that 2888*7c478bd9Sstevel@tonic-gate * find_nfs4_server() continues to work. 2889*7c478bd9Sstevel@tonic-gate */ 2890*7c478bd9Sstevel@tonic-gate 2891*7c478bd9Sstevel@tonic-gate for (tmi = sp->mntinfo4_list; 2892*7c478bd9Sstevel@tonic-gate tmi != NULL; 2893*7c478bd9Sstevel@tonic-gate tmi = tmi->mi_clientid_next) { 2894*7c478bd9Sstevel@tonic-gate if (tmi != mi) { 2895*7c478bd9Sstevel@tonic-gate tmi->mi_clientid = sp->clientid; 2896*7c478bd9Sstevel@tonic-gate } 2897*7c478bd9Sstevel@tonic-gate } 2898*7c478bd9Sstevel@tonic-gate } 2899*7c478bd9Sstevel@tonic-gate 2900*7c478bd9Sstevel@tonic-gate /* 2901*7c478bd9Sstevel@tonic-gate * Remove the mi from sp's mntinfo4_list and release its reference. 2902*7c478bd9Sstevel@tonic-gate * Exception: if mi still has open files, flag it for later removal (when 2903*7c478bd9Sstevel@tonic-gate * all the files are closed). 2904*7c478bd9Sstevel@tonic-gate * 2905*7c478bd9Sstevel@tonic-gate * If this is the last mntinfo4 in sp's list then tell the lease renewal 2906*7c478bd9Sstevel@tonic-gate * thread to exit. 2907*7c478bd9Sstevel@tonic-gate */ 2908*7c478bd9Sstevel@tonic-gate static void 2909*7c478bd9Sstevel@tonic-gate nfs4_remove_mi_from_server_nolock(mntinfo4_t *mi, nfs4_server_t *sp) 2910*7c478bd9Sstevel@tonic-gate { 2911*7c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, 2912*7c478bd9Sstevel@tonic-gate "nfs4_remove_mi_from_server_nolock: remove mi %p from sp %p", 2913*7c478bd9Sstevel@tonic-gate (void*)mi, (void*)sp)); 2914*7c478bd9Sstevel@tonic-gate 2915*7c478bd9Sstevel@tonic-gate ASSERT(sp != NULL); 2916*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sp->s_lock)); 2917*7c478bd9Sstevel@tonic-gate ASSERT(mi->mi_open_files >= 0); 2918*7c478bd9Sstevel@tonic-gate 2919*7c478bd9Sstevel@tonic-gate /* 2920*7c478bd9Sstevel@tonic-gate * First make sure this mntinfo4 can be taken off of the list, 2921*7c478bd9Sstevel@tonic-gate * ie: it doesn't have any open files remaining. 2922*7c478bd9Sstevel@tonic-gate */ 2923*7c478bd9Sstevel@tonic-gate if (mi->mi_open_files > 0) { 2924*7c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, 2925*7c478bd9Sstevel@tonic-gate "nfs4_remove_mi_from_server_nolock: don't " 2926*7c478bd9Sstevel@tonic-gate "remove mi since it still has files open")); 2927*7c478bd9Sstevel@tonic-gate 2928*7c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 2929*7c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_REMOVE_ON_LAST_CLOSE; 2930*7c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 2931*7c478bd9Sstevel@tonic-gate return; 2932*7c478bd9Sstevel@tonic-gate } 2933*7c478bd9Sstevel@tonic-gate 2934*7c478bd9Sstevel@tonic-gate remove_mi(sp, mi); 2935*7c478bd9Sstevel@tonic-gate 2936*7c478bd9Sstevel@tonic-gate if (sp->mntinfo4_list == NULL) { 2937*7c478bd9Sstevel@tonic-gate /* last fs unmounted, kill the thread */ 2938*7c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, 2939*7c478bd9Sstevel@tonic-gate "remove_mi_from_nfs4_server_nolock: kill the thread")); 2940*7c478bd9Sstevel@tonic-gate nfs4_mark_srv_dead(sp); 2941*7c478bd9Sstevel@tonic-gate } 2942*7c478bd9Sstevel@tonic-gate } 2943*7c478bd9Sstevel@tonic-gate 2944*7c478bd9Sstevel@tonic-gate /* 2945*7c478bd9Sstevel@tonic-gate * Remove mi from sp's mntinfo4_list and release the vfs reference. 2946*7c478bd9Sstevel@tonic-gate */ 2947*7c478bd9Sstevel@tonic-gate static void 2948*7c478bd9Sstevel@tonic-gate remove_mi(nfs4_server_t *sp, mntinfo4_t *mi) 2949*7c478bd9Sstevel@tonic-gate { 2950*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sp->s_lock)); 2951*7c478bd9Sstevel@tonic-gate 2952*7c478bd9Sstevel@tonic-gate /* 2953*7c478bd9Sstevel@tonic-gate * We release a reference, and the caller must still have a 2954*7c478bd9Sstevel@tonic-gate * reference. 2955*7c478bd9Sstevel@tonic-gate */ 2956*7c478bd9Sstevel@tonic-gate ASSERT(mi->mi_vfsp->vfs_count >= 2); 2957*7c478bd9Sstevel@tonic-gate 2958*7c478bd9Sstevel@tonic-gate if (mi->mi_clientid_prev) { 2959*7c478bd9Sstevel@tonic-gate mi->mi_clientid_prev->mi_clientid_next = mi->mi_clientid_next; 2960*7c478bd9Sstevel@tonic-gate } else { 2961*7c478bd9Sstevel@tonic-gate /* This is the first mi in sp's mntinfo4_list */ 2962*7c478bd9Sstevel@tonic-gate /* 2963*7c478bd9Sstevel@tonic-gate * Make sure the first mntinfo4 in the list is the actual 2964*7c478bd9Sstevel@tonic-gate * mntinfo4 passed in. 2965*7c478bd9Sstevel@tonic-gate */ 2966*7c478bd9Sstevel@tonic-gate ASSERT(sp->mntinfo4_list == mi); 2967*7c478bd9Sstevel@tonic-gate 2968*7c478bd9Sstevel@tonic-gate sp->mntinfo4_list = mi->mi_clientid_next; 2969*7c478bd9Sstevel@tonic-gate } 2970*7c478bd9Sstevel@tonic-gate if (mi->mi_clientid_next) 2971*7c478bd9Sstevel@tonic-gate mi->mi_clientid_next->mi_clientid_prev = mi->mi_clientid_prev; 2972*7c478bd9Sstevel@tonic-gate 2973*7c478bd9Sstevel@tonic-gate /* Now mark the mntinfo4's links as being removed */ 2974*7c478bd9Sstevel@tonic-gate mi->mi_clientid_prev = mi->mi_clientid_next = NULL; 2975*7c478bd9Sstevel@tonic-gate 2976*7c478bd9Sstevel@tonic-gate VFS_RELE(mi->mi_vfsp); 2977*7c478bd9Sstevel@tonic-gate } 2978*7c478bd9Sstevel@tonic-gate 2979*7c478bd9Sstevel@tonic-gate /* 2980*7c478bd9Sstevel@tonic-gate * Free all the entries in sp's mntinfo4_list. 2981*7c478bd9Sstevel@tonic-gate */ 2982*7c478bd9Sstevel@tonic-gate static void 2983*7c478bd9Sstevel@tonic-gate remove_all_mi(nfs4_server_t *sp) 2984*7c478bd9Sstevel@tonic-gate { 2985*7c478bd9Sstevel@tonic-gate mntinfo4_t *mi; 2986*7c478bd9Sstevel@tonic-gate 2987*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sp->s_lock)); 2988*7c478bd9Sstevel@tonic-gate 2989*7c478bd9Sstevel@tonic-gate while (sp->mntinfo4_list != NULL) { 2990*7c478bd9Sstevel@tonic-gate mi = sp->mntinfo4_list; 2991*7c478bd9Sstevel@tonic-gate /* 2992*7c478bd9Sstevel@tonic-gate * Grab a reference in case there is only one left (which 2993*7c478bd9Sstevel@tonic-gate * remove_mi() frees). 2994*7c478bd9Sstevel@tonic-gate */ 2995*7c478bd9Sstevel@tonic-gate VFS_HOLD(mi->mi_vfsp); 2996*7c478bd9Sstevel@tonic-gate remove_mi(sp, mi); 2997*7c478bd9Sstevel@tonic-gate VFS_RELE(mi->mi_vfsp); 2998*7c478bd9Sstevel@tonic-gate } 2999*7c478bd9Sstevel@tonic-gate } 3000*7c478bd9Sstevel@tonic-gate 3001*7c478bd9Sstevel@tonic-gate /* 3002*7c478bd9Sstevel@tonic-gate * Remove the mi from sp's mntinfo4_list as above, and rele the vfs. 3003*7c478bd9Sstevel@tonic-gate * 3004*7c478bd9Sstevel@tonic-gate * This version can be called with a null nfs4_server_t arg, 3005*7c478bd9Sstevel@tonic-gate * and will either find the right one and handle locking, or 3006*7c478bd9Sstevel@tonic-gate * do nothing because the mi wasn't added to an sp's mntinfo4_list. 3007*7c478bd9Sstevel@tonic-gate */ 3008*7c478bd9Sstevel@tonic-gate void 3009*7c478bd9Sstevel@tonic-gate nfs4_remove_mi_from_server(mntinfo4_t *mi, nfs4_server_t *esp) 3010*7c478bd9Sstevel@tonic-gate { 3011*7c478bd9Sstevel@tonic-gate nfs4_server_t *sp; 3012*7c478bd9Sstevel@tonic-gate 3013*7c478bd9Sstevel@tonic-gate if (esp == NULL) { 3014*7c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&mi->mi_recovlock, RW_READER, 0); 3015*7c478bd9Sstevel@tonic-gate sp = find_nfs4_server_all(mi, 1); 3016*7c478bd9Sstevel@tonic-gate } else 3017*7c478bd9Sstevel@tonic-gate sp = esp; 3018*7c478bd9Sstevel@tonic-gate 3019*7c478bd9Sstevel@tonic-gate if (sp != NULL) 3020*7c478bd9Sstevel@tonic-gate nfs4_remove_mi_from_server_nolock(mi, sp); 3021*7c478bd9Sstevel@tonic-gate 3022*7c478bd9Sstevel@tonic-gate /* 3023*7c478bd9Sstevel@tonic-gate * If we had a valid esp as input, the calling function will be 3024*7c478bd9Sstevel@tonic-gate * responsible for unlocking the esp nfs4_server. 3025*7c478bd9Sstevel@tonic-gate */ 3026*7c478bd9Sstevel@tonic-gate if (esp == NULL) { 3027*7c478bd9Sstevel@tonic-gate if (sp != NULL) 3028*7c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_lock); 3029*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&mi->mi_recovlock); 3030*7c478bd9Sstevel@tonic-gate if (sp != NULL) 3031*7c478bd9Sstevel@tonic-gate nfs4_server_rele(sp); 3032*7c478bd9Sstevel@tonic-gate } 3033*7c478bd9Sstevel@tonic-gate } 3034*7c478bd9Sstevel@tonic-gate 3035*7c478bd9Sstevel@tonic-gate /* 3036*7c478bd9Sstevel@tonic-gate * Return TRUE if the given server has any non-unmounted filesystems. 3037*7c478bd9Sstevel@tonic-gate */ 3038*7c478bd9Sstevel@tonic-gate 3039*7c478bd9Sstevel@tonic-gate bool_t 3040*7c478bd9Sstevel@tonic-gate nfs4_fs_active(nfs4_server_t *sp) 3041*7c478bd9Sstevel@tonic-gate { 3042*7c478bd9Sstevel@tonic-gate mntinfo4_t *mi; 3043*7c478bd9Sstevel@tonic-gate 3044*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sp->s_lock)); 3045*7c478bd9Sstevel@tonic-gate 3046*7c478bd9Sstevel@tonic-gate for (mi = sp->mntinfo4_list; mi != NULL; mi = mi->mi_clientid_next) { 3047*7c478bd9Sstevel@tonic-gate if (!(mi->mi_vfsp->vfs_flag & VFS_UNMOUNTED)) 3048*7c478bd9Sstevel@tonic-gate return (TRUE); 3049*7c478bd9Sstevel@tonic-gate } 3050*7c478bd9Sstevel@tonic-gate 3051*7c478bd9Sstevel@tonic-gate return (FALSE); 3052*7c478bd9Sstevel@tonic-gate } 3053*7c478bd9Sstevel@tonic-gate 3054*7c478bd9Sstevel@tonic-gate /* 3055*7c478bd9Sstevel@tonic-gate * Mark sp as finished and notify any waiters. 3056*7c478bd9Sstevel@tonic-gate */ 3057*7c478bd9Sstevel@tonic-gate 3058*7c478bd9Sstevel@tonic-gate void 3059*7c478bd9Sstevel@tonic-gate nfs4_mark_srv_dead(nfs4_server_t *sp) 3060*7c478bd9Sstevel@tonic-gate { 3061*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sp->s_lock)); 3062*7c478bd9Sstevel@tonic-gate 3063*7c478bd9Sstevel@tonic-gate sp->s_thread_exit = NFS4_THREAD_EXIT; 3064*7c478bd9Sstevel@tonic-gate cv_broadcast(&sp->cv_thread_exit); 3065*7c478bd9Sstevel@tonic-gate } 3066*7c478bd9Sstevel@tonic-gate 3067*7c478bd9Sstevel@tonic-gate /* 3068*7c478bd9Sstevel@tonic-gate * Create a new nfs4_server_t structure. 3069*7c478bd9Sstevel@tonic-gate * Returns new node unlocked and not in list, but with a reference count of 3070*7c478bd9Sstevel@tonic-gate * 1. 3071*7c478bd9Sstevel@tonic-gate */ 3072*7c478bd9Sstevel@tonic-gate struct nfs4_server * 3073*7c478bd9Sstevel@tonic-gate new_nfs4_server(struct servinfo4 *svp, cred_t *cr) 3074*7c478bd9Sstevel@tonic-gate { 3075*7c478bd9Sstevel@tonic-gate struct nfs4_server *np; 3076*7c478bd9Sstevel@tonic-gate timespec_t tt; 3077*7c478bd9Sstevel@tonic-gate union { 3078*7c478bd9Sstevel@tonic-gate struct { 3079*7c478bd9Sstevel@tonic-gate uint32_t sec; 3080*7c478bd9Sstevel@tonic-gate uint32_t subsec; 3081*7c478bd9Sstevel@tonic-gate } un_curtime; 3082*7c478bd9Sstevel@tonic-gate verifier4 un_verifier; 3083*7c478bd9Sstevel@tonic-gate } nfs4clientid_verifier; 3084*7c478bd9Sstevel@tonic-gate char id_val[] = "Solaris: %s, NFSv4 kernel client"; 3085*7c478bd9Sstevel@tonic-gate int len; 3086*7c478bd9Sstevel@tonic-gate 3087*7c478bd9Sstevel@tonic-gate np = kmem_zalloc(sizeof (struct nfs4_server), KM_SLEEP); 3088*7c478bd9Sstevel@tonic-gate np->saddr.len = svp->sv_addr.len; 3089*7c478bd9Sstevel@tonic-gate np->saddr.maxlen = svp->sv_addr.maxlen; 3090*7c478bd9Sstevel@tonic-gate np->saddr.buf = kmem_alloc(svp->sv_addr.maxlen, KM_SLEEP); 3091*7c478bd9Sstevel@tonic-gate bcopy(svp->sv_addr.buf, np->saddr.buf, svp->sv_addr.len); 3092*7c478bd9Sstevel@tonic-gate np->s_refcnt = 1; 3093*7c478bd9Sstevel@tonic-gate 3094*7c478bd9Sstevel@tonic-gate /* 3095*7c478bd9Sstevel@tonic-gate * Build the nfs_client_id4 for this server mount. Ensure 3096*7c478bd9Sstevel@tonic-gate * the verifier is useful and that the identification is 3097*7c478bd9Sstevel@tonic-gate * somehow based on the server's address for the case of 3098*7c478bd9Sstevel@tonic-gate * multi-homed servers. 3099*7c478bd9Sstevel@tonic-gate */ 3100*7c478bd9Sstevel@tonic-gate nfs4clientid_verifier.un_verifier = 0; 3101*7c478bd9Sstevel@tonic-gate gethrestime(&tt); 3102*7c478bd9Sstevel@tonic-gate nfs4clientid_verifier.un_curtime.sec = (uint32_t)tt.tv_sec; 3103*7c478bd9Sstevel@tonic-gate nfs4clientid_verifier.un_curtime.subsec = (uint32_t)tt.tv_nsec; 3104*7c478bd9Sstevel@tonic-gate np->clidtosend.verifier = nfs4clientid_verifier.un_verifier; 3105*7c478bd9Sstevel@tonic-gate 3106*7c478bd9Sstevel@tonic-gate /* 3107*7c478bd9Sstevel@tonic-gate * calculate the length of the opaque identifier. Subtract 2 3108*7c478bd9Sstevel@tonic-gate * for the "%s" and add the traditional +1 for null 3109*7c478bd9Sstevel@tonic-gate * termination. 3110*7c478bd9Sstevel@tonic-gate */ 3111*7c478bd9Sstevel@tonic-gate len = strlen(id_val) - 2 + strlen(uts_nodename()) + 1; 3112*7c478bd9Sstevel@tonic-gate np->clidtosend.id_len = len + np->saddr.maxlen; 3113*7c478bd9Sstevel@tonic-gate 3114*7c478bd9Sstevel@tonic-gate np->clidtosend.id_val = kmem_alloc(np->clidtosend.id_len, KM_SLEEP); 3115*7c478bd9Sstevel@tonic-gate (void) sprintf(np->clidtosend.id_val, id_val, uts_nodename()); 3116*7c478bd9Sstevel@tonic-gate bcopy(np->saddr.buf, &np->clidtosend.id_val[len], np->saddr.len); 3117*7c478bd9Sstevel@tonic-gate 3118*7c478bd9Sstevel@tonic-gate np->s_flags = 0; 3119*7c478bd9Sstevel@tonic-gate np->mntinfo4_list = NULL; 3120*7c478bd9Sstevel@tonic-gate /* save cred for issuing rfs4calls inside the renew thread */ 3121*7c478bd9Sstevel@tonic-gate crhold(cr); 3122*7c478bd9Sstevel@tonic-gate np->s_cred = cr; 3123*7c478bd9Sstevel@tonic-gate cv_init(&np->cv_thread_exit, NULL, CV_DEFAULT, NULL); 3124*7c478bd9Sstevel@tonic-gate mutex_init(&np->s_lock, NULL, MUTEX_DEFAULT, NULL); 3125*7c478bd9Sstevel@tonic-gate nfs_rw_init(&np->s_recovlock, NULL, RW_DEFAULT, NULL); 3126*7c478bd9Sstevel@tonic-gate list_create(&np->s_deleg_list, sizeof (rnode4_t), 3127*7c478bd9Sstevel@tonic-gate offsetof(rnode4_t, r_deleg_link)); 3128*7c478bd9Sstevel@tonic-gate np->s_thread_exit = 0; 3129*7c478bd9Sstevel@tonic-gate np->state_ref_count = 0; 3130*7c478bd9Sstevel@tonic-gate np->lease_valid = NFS4_LEASE_NOT_STARTED; 3131*7c478bd9Sstevel@tonic-gate cv_init(&np->s_cv_otw_count, NULL, CV_DEFAULT, NULL); 3132*7c478bd9Sstevel@tonic-gate np->s_otw_call_count = 0; 3133*7c478bd9Sstevel@tonic-gate cv_init(&np->wait_cb_null, NULL, CV_DEFAULT, NULL); 3134*7c478bd9Sstevel@tonic-gate np->zoneid = getzoneid(); 3135*7c478bd9Sstevel@tonic-gate np->zone_globals = nfs4_get_callback_globals(); 3136*7c478bd9Sstevel@tonic-gate ASSERT(np->zone_globals != NULL); 3137*7c478bd9Sstevel@tonic-gate return (np); 3138*7c478bd9Sstevel@tonic-gate } 3139*7c478bd9Sstevel@tonic-gate 3140*7c478bd9Sstevel@tonic-gate /* 3141*7c478bd9Sstevel@tonic-gate * Create a new nfs4_server_t structure and add it to the list. 3142*7c478bd9Sstevel@tonic-gate * Returns new node locked; reference must eventually be freed. 3143*7c478bd9Sstevel@tonic-gate */ 3144*7c478bd9Sstevel@tonic-gate static struct nfs4_server * 3145*7c478bd9Sstevel@tonic-gate add_new_nfs4_server(struct servinfo4 *svp, cred_t *cr) 3146*7c478bd9Sstevel@tonic-gate { 3147*7c478bd9Sstevel@tonic-gate nfs4_server_t *sp; 3148*7c478bd9Sstevel@tonic-gate 3149*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&nfs4_server_lst_lock)); 3150*7c478bd9Sstevel@tonic-gate sp = new_nfs4_server(svp, cr); 3151*7c478bd9Sstevel@tonic-gate mutex_enter(&sp->s_lock); 3152*7c478bd9Sstevel@tonic-gate insque(sp, &nfs4_server_lst); 3153*7c478bd9Sstevel@tonic-gate sp->s_refcnt++; /* list gets a reference */ 3154*7c478bd9Sstevel@tonic-gate sp->clientid = 0; 3155*7c478bd9Sstevel@tonic-gate sp->s_flags |= N4S_INSERTED; 3156*7c478bd9Sstevel@tonic-gate return (sp); 3157*7c478bd9Sstevel@tonic-gate } 3158*7c478bd9Sstevel@tonic-gate 3159*7c478bd9Sstevel@tonic-gate int nfs4_server_t_debug = 0; 3160*7c478bd9Sstevel@tonic-gate 3161*7c478bd9Sstevel@tonic-gate #ifdef lint 3162*7c478bd9Sstevel@tonic-gate extern void 3163*7c478bd9Sstevel@tonic-gate dumpnfs4slist(char *, mntinfo4_t *, clientid4, servinfo4_t *); 3164*7c478bd9Sstevel@tonic-gate #endif 3165*7c478bd9Sstevel@tonic-gate 3166*7c478bd9Sstevel@tonic-gate #ifndef lint 3167*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 3168*7c478bd9Sstevel@tonic-gate void 3169*7c478bd9Sstevel@tonic-gate dumpnfs4slist(char *txt, mntinfo4_t *mi, clientid4 clientid, servinfo4_t *srv_p) 3170*7c478bd9Sstevel@tonic-gate { 3171*7c478bd9Sstevel@tonic-gate int hash16(void *p, int len); 3172*7c478bd9Sstevel@tonic-gate nfs4_server_t *np; 3173*7c478bd9Sstevel@tonic-gate 3174*7c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_server_t_debug, (CE_NOTE, 3175*7c478bd9Sstevel@tonic-gate "dumping nfs4_server_t list in %s", txt)); 3176*7c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_server_t_debug, (CE_CONT, 3177*7c478bd9Sstevel@tonic-gate "mi 0x%p, want clientid %llx, addr %d/%04X", 3178*7c478bd9Sstevel@tonic-gate mi, (longlong_t)clientid, srv_p->sv_addr.len, 3179*7c478bd9Sstevel@tonic-gate hash16((void *)srv_p->sv_addr.buf, srv_p->sv_addr.len))); 3180*7c478bd9Sstevel@tonic-gate for (np = nfs4_server_lst.forw; np != &nfs4_server_lst; 3181*7c478bd9Sstevel@tonic-gate np = np->forw) { 3182*7c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_server_t_debug, (CE_CONT, 3183*7c478bd9Sstevel@tonic-gate "node 0x%p, clientid %llx, addr %d/%04X, cnt %d", 3184*7c478bd9Sstevel@tonic-gate np, (longlong_t)np->clientid, np->saddr.len, 3185*7c478bd9Sstevel@tonic-gate hash16((void *)np->saddr.buf, np->saddr.len), 3186*7c478bd9Sstevel@tonic-gate np->state_ref_count)); 3187*7c478bd9Sstevel@tonic-gate if (np->saddr.len == srv_p->sv_addr.len && 3188*7c478bd9Sstevel@tonic-gate bcmp(np->saddr.buf, srv_p->sv_addr.buf, 3189*7c478bd9Sstevel@tonic-gate np->saddr.len) == 0) 3190*7c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_server_t_debug, (CE_CONT, 3191*7c478bd9Sstevel@tonic-gate " - address matches")); 3192*7c478bd9Sstevel@tonic-gate if (np->clientid == clientid || np->clientid == 0) 3193*7c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_server_t_debug, (CE_CONT, 3194*7c478bd9Sstevel@tonic-gate " - clientid matches")); 3195*7c478bd9Sstevel@tonic-gate if (np->s_thread_exit != NFS4_THREAD_EXIT) 3196*7c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_server_t_debug, (CE_CONT, 3197*7c478bd9Sstevel@tonic-gate " - thread not exiting")); 3198*7c478bd9Sstevel@tonic-gate } 3199*7c478bd9Sstevel@tonic-gate delay(hz); 3200*7c478bd9Sstevel@tonic-gate } 3201*7c478bd9Sstevel@tonic-gate #endif 3202*7c478bd9Sstevel@tonic-gate #endif 3203*7c478bd9Sstevel@tonic-gate 3204*7c478bd9Sstevel@tonic-gate 3205*7c478bd9Sstevel@tonic-gate /* 3206*7c478bd9Sstevel@tonic-gate * Move a mntinfo4_t from one server list to another. 3207*7c478bd9Sstevel@tonic-gate * Locking of the two nfs4_server_t nodes will be done in list order. 3208*7c478bd9Sstevel@tonic-gate * 3209*7c478bd9Sstevel@tonic-gate * Returns NULL if the current nfs4_server_t for the filesystem could not 3210*7c478bd9Sstevel@tonic-gate * be found (e.g., due to forced unmount). Otherwise returns a reference 3211*7c478bd9Sstevel@tonic-gate * to the new nfs4_server_t, which must eventually be freed. 3212*7c478bd9Sstevel@tonic-gate */ 3213*7c478bd9Sstevel@tonic-gate nfs4_server_t * 3214*7c478bd9Sstevel@tonic-gate nfs4_move_mi(mntinfo4_t *mi, servinfo4_t *old, servinfo4_t *new) 3215*7c478bd9Sstevel@tonic-gate { 3216*7c478bd9Sstevel@tonic-gate nfs4_server_t *p, *op = NULL, *np = NULL; 3217*7c478bd9Sstevel@tonic-gate int num_open; 3218*7c478bd9Sstevel@tonic-gate zoneid_t zoneid = getzoneid(); 3219*7c478bd9Sstevel@tonic-gate 3220*7c478bd9Sstevel@tonic-gate ASSERT(curproc->p_zone == mi->mi_zone); 3221*7c478bd9Sstevel@tonic-gate 3222*7c478bd9Sstevel@tonic-gate mutex_enter(&nfs4_server_lst_lock); 3223*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 3224*7c478bd9Sstevel@tonic-gate if (nfs4_server_t_debug) 3225*7c478bd9Sstevel@tonic-gate dumpnfs4slist("nfs4_move_mi", mi, (clientid4)0, new); 3226*7c478bd9Sstevel@tonic-gate #endif 3227*7c478bd9Sstevel@tonic-gate for (p = nfs4_server_lst.forw; p != &nfs4_server_lst; p = p->forw) { 3228*7c478bd9Sstevel@tonic-gate if (p->zoneid != zoneid) 3229*7c478bd9Sstevel@tonic-gate continue; 3230*7c478bd9Sstevel@tonic-gate if (p->saddr.len == old->sv_addr.len && 3231*7c478bd9Sstevel@tonic-gate bcmp(p->saddr.buf, old->sv_addr.buf, p->saddr.len) == 0 && 3232*7c478bd9Sstevel@tonic-gate p->s_thread_exit != NFS4_THREAD_EXIT) { 3233*7c478bd9Sstevel@tonic-gate op = p; 3234*7c478bd9Sstevel@tonic-gate mutex_enter(&op->s_lock); 3235*7c478bd9Sstevel@tonic-gate op->s_refcnt++; 3236*7c478bd9Sstevel@tonic-gate } 3237*7c478bd9Sstevel@tonic-gate if (p->saddr.len == new->sv_addr.len && 3238*7c478bd9Sstevel@tonic-gate bcmp(p->saddr.buf, new->sv_addr.buf, p->saddr.len) == 0 && 3239*7c478bd9Sstevel@tonic-gate p->s_thread_exit != NFS4_THREAD_EXIT) { 3240*7c478bd9Sstevel@tonic-gate np = p; 3241*7c478bd9Sstevel@tonic-gate mutex_enter(&np->s_lock); 3242*7c478bd9Sstevel@tonic-gate } 3243*7c478bd9Sstevel@tonic-gate if (op != NULL && np != NULL) 3244*7c478bd9Sstevel@tonic-gate break; 3245*7c478bd9Sstevel@tonic-gate } 3246*7c478bd9Sstevel@tonic-gate if (op == NULL) { 3247*7c478bd9Sstevel@tonic-gate /* 3248*7c478bd9Sstevel@tonic-gate * Filesystem has been forcibly unmounted. Bail out. 3249*7c478bd9Sstevel@tonic-gate */ 3250*7c478bd9Sstevel@tonic-gate if (np != NULL) 3251*7c478bd9Sstevel@tonic-gate mutex_exit(&np->s_lock); 3252*7c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_server_lst_lock); 3253*7c478bd9Sstevel@tonic-gate return (NULL); 3254*7c478bd9Sstevel@tonic-gate } 3255*7c478bd9Sstevel@tonic-gate if (np != NULL) { 3256*7c478bd9Sstevel@tonic-gate np->s_refcnt++; 3257*7c478bd9Sstevel@tonic-gate } else { 3258*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 3259*7c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_failover_debug, (CE_NOTE, 3260*7c478bd9Sstevel@tonic-gate "nfs4_move_mi: no target nfs4_server, will create.")); 3261*7c478bd9Sstevel@tonic-gate #endif 3262*7c478bd9Sstevel@tonic-gate np = add_new_nfs4_server(new, kcred); 3263*7c478bd9Sstevel@tonic-gate } 3264*7c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_server_lst_lock); 3265*7c478bd9Sstevel@tonic-gate 3266*7c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_failover_debug, (CE_NOTE, 3267*7c478bd9Sstevel@tonic-gate "nfs4_move_mi: for mi 0x%p, " 3268*7c478bd9Sstevel@tonic-gate "old servinfo4 0x%p, new servinfo4 0x%p, " 3269*7c478bd9Sstevel@tonic-gate "old nfs4_server 0x%p, new nfs4_server 0x%p, ", 3270*7c478bd9Sstevel@tonic-gate (void*)mi, (void*)old, (void*)new, 3271*7c478bd9Sstevel@tonic-gate (void*)op, (void*)np)); 3272*7c478bd9Sstevel@tonic-gate ASSERT(op != NULL && np != NULL); 3273*7c478bd9Sstevel@tonic-gate 3274*7c478bd9Sstevel@tonic-gate /* discard any delegations */ 3275*7c478bd9Sstevel@tonic-gate nfs4_deleg_discard(mi, op); 3276*7c478bd9Sstevel@tonic-gate 3277*7c478bd9Sstevel@tonic-gate num_open = mi->mi_open_files; 3278*7c478bd9Sstevel@tonic-gate mi->mi_open_files = 0; 3279*7c478bd9Sstevel@tonic-gate op->state_ref_count -= num_open; 3280*7c478bd9Sstevel@tonic-gate ASSERT(op->state_ref_count >= 0); 3281*7c478bd9Sstevel@tonic-gate np->state_ref_count += num_open; 3282*7c478bd9Sstevel@tonic-gate nfs4_remove_mi_from_server_nolock(mi, op); 3283*7c478bd9Sstevel@tonic-gate mi->mi_open_files = num_open; 3284*7c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_failover_debug, (CE_NOTE, 3285*7c478bd9Sstevel@tonic-gate "nfs4_move_mi: mi_open_files %d, op->cnt %d, np->cnt %d", 3286*7c478bd9Sstevel@tonic-gate mi->mi_open_files, op->state_ref_count, np->state_ref_count)); 3287*7c478bd9Sstevel@tonic-gate 3288*7c478bd9Sstevel@tonic-gate nfs4_add_mi_to_server(np, mi); 3289*7c478bd9Sstevel@tonic-gate 3290*7c478bd9Sstevel@tonic-gate mutex_exit(&op->s_lock); 3291*7c478bd9Sstevel@tonic-gate nfs4_server_rele(op); 3292*7c478bd9Sstevel@tonic-gate mutex_exit(&np->s_lock); 3293*7c478bd9Sstevel@tonic-gate 3294*7c478bd9Sstevel@tonic-gate return (np); 3295*7c478bd9Sstevel@tonic-gate } 3296*7c478bd9Sstevel@tonic-gate 3297*7c478bd9Sstevel@tonic-gate /* 3298*7c478bd9Sstevel@tonic-gate * Search the nfs4_server list to find a match on this servinfo4 3299*7c478bd9Sstevel@tonic-gate * based on its address. 3300*7c478bd9Sstevel@tonic-gate * 3301*7c478bd9Sstevel@tonic-gate * Returns NULL if no match is found. Otherwise returns a reference (which 3302*7c478bd9Sstevel@tonic-gate * must eventually be freed) to a locked nfs4_server. 3303*7c478bd9Sstevel@tonic-gate */ 3304*7c478bd9Sstevel@tonic-gate nfs4_server_t * 3305*7c478bd9Sstevel@tonic-gate servinfo4_to_nfs4_server(servinfo4_t *srv_p) 3306*7c478bd9Sstevel@tonic-gate { 3307*7c478bd9Sstevel@tonic-gate nfs4_server_t *np; 3308*7c478bd9Sstevel@tonic-gate zoneid_t zoneid = getzoneid(); 3309*7c478bd9Sstevel@tonic-gate 3310*7c478bd9Sstevel@tonic-gate mutex_enter(&nfs4_server_lst_lock); 3311*7c478bd9Sstevel@tonic-gate for (np = nfs4_server_lst.forw; np != &nfs4_server_lst; np = np->forw) { 3312*7c478bd9Sstevel@tonic-gate if (np->zoneid == zoneid && 3313*7c478bd9Sstevel@tonic-gate np->saddr.len == srv_p->sv_addr.len && 3314*7c478bd9Sstevel@tonic-gate bcmp(np->saddr.buf, srv_p->sv_addr.buf, 3315*7c478bd9Sstevel@tonic-gate np->saddr.len) == 0 && 3316*7c478bd9Sstevel@tonic-gate np->s_thread_exit != NFS4_THREAD_EXIT) { 3317*7c478bd9Sstevel@tonic-gate mutex_enter(&np->s_lock); 3318*7c478bd9Sstevel@tonic-gate np->s_refcnt++; 3319*7c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_server_lst_lock); 3320*7c478bd9Sstevel@tonic-gate return (np); 3321*7c478bd9Sstevel@tonic-gate } 3322*7c478bd9Sstevel@tonic-gate } 3323*7c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_server_lst_lock); 3324*7c478bd9Sstevel@tonic-gate return (NULL); 3325*7c478bd9Sstevel@tonic-gate } 3326*7c478bd9Sstevel@tonic-gate 3327*7c478bd9Sstevel@tonic-gate /* 3328*7c478bd9Sstevel@tonic-gate * Search the nfs4_server_lst to find a match based on clientid and 3329*7c478bd9Sstevel@tonic-gate * addr. 3330*7c478bd9Sstevel@tonic-gate * Locks the nfs4_server down if it is found and returns a reference that 3331*7c478bd9Sstevel@tonic-gate * must eventually be freed. 3332*7c478bd9Sstevel@tonic-gate * 3333*7c478bd9Sstevel@tonic-gate * Returns NULL it no match is found. This means one of two things: either 3334*7c478bd9Sstevel@tonic-gate * mi is in the process of being mounted, or mi has been unmounted. 3335*7c478bd9Sstevel@tonic-gate * 3336*7c478bd9Sstevel@tonic-gate * The caller should be holding mi->mi_recovlock, and it should continue to 3337*7c478bd9Sstevel@tonic-gate * hold the lock until done with the returned nfs4_server_t. Once 3338*7c478bd9Sstevel@tonic-gate * mi->mi_recovlock is released, there is no guarantee that the returned 3339*7c478bd9Sstevel@tonic-gate * mi->nfs4_server_t will continue to correspond to mi. 3340*7c478bd9Sstevel@tonic-gate */ 3341*7c478bd9Sstevel@tonic-gate nfs4_server_t * 3342*7c478bd9Sstevel@tonic-gate find_nfs4_server(mntinfo4_t *mi) 3343*7c478bd9Sstevel@tonic-gate { 3344*7c478bd9Sstevel@tonic-gate return (find_nfs4_server_all(mi, 0)); 3345*7c478bd9Sstevel@tonic-gate } 3346*7c478bd9Sstevel@tonic-gate 3347*7c478bd9Sstevel@tonic-gate /* 3348*7c478bd9Sstevel@tonic-gate * Same as above, but takes an "all" parameter which can be 3349*7c478bd9Sstevel@tonic-gate * set to 1 if the caller wishes to find nfs4_server_t's which 3350*7c478bd9Sstevel@tonic-gate * have been marked for termination by the exit of the renew 3351*7c478bd9Sstevel@tonic-gate * thread. This should only be used by operations which are 3352*7c478bd9Sstevel@tonic-gate * cleaning up and will not cause an OTW op. 3353*7c478bd9Sstevel@tonic-gate */ 3354*7c478bd9Sstevel@tonic-gate nfs4_server_t * 3355*7c478bd9Sstevel@tonic-gate find_nfs4_server_all(mntinfo4_t *mi, int all) 3356*7c478bd9Sstevel@tonic-gate { 3357*7c478bd9Sstevel@tonic-gate nfs4_server_t *np; 3358*7c478bd9Sstevel@tonic-gate servinfo4_t *svp; 3359*7c478bd9Sstevel@tonic-gate zoneid_t zoneid = mi->mi_zone->zone_id; 3360*7c478bd9Sstevel@tonic-gate 3361*7c478bd9Sstevel@tonic-gate ASSERT(nfs_rw_lock_held(&mi->mi_recovlock, RW_READER) || 3362*7c478bd9Sstevel@tonic-gate nfs_rw_lock_held(&mi->mi_recovlock, RW_WRITER)); 3363*7c478bd9Sstevel@tonic-gate /* 3364*7c478bd9Sstevel@tonic-gate * This can be called from nfs4_unmount() which can be called from the 3365*7c478bd9Sstevel@tonic-gate * global zone, hence it's legal for the global zone to muck with 3366*7c478bd9Sstevel@tonic-gate * another zone's server list, as long as it doesn't try to contact 3367*7c478bd9Sstevel@tonic-gate * them. 3368*7c478bd9Sstevel@tonic-gate */ 3369*7c478bd9Sstevel@tonic-gate ASSERT(zoneid == getzoneid() || getzoneid() == GLOBAL_ZONEID); 3370*7c478bd9Sstevel@tonic-gate 3371*7c478bd9Sstevel@tonic-gate /* 3372*7c478bd9Sstevel@tonic-gate * The nfs4_server_lst_lock global lock is held when we get a new 3373*7c478bd9Sstevel@tonic-gate * clientid (via SETCLIENTID OTW). Holding this global lock and 3374*7c478bd9Sstevel@tonic-gate * mi_recovlock (READER is fine) ensures that the nfs4_server 3375*7c478bd9Sstevel@tonic-gate * and this mntinfo4 can't get out of sync, so the following search is 3376*7c478bd9Sstevel@tonic-gate * always valid. 3377*7c478bd9Sstevel@tonic-gate */ 3378*7c478bd9Sstevel@tonic-gate mutex_enter(&nfs4_server_lst_lock); 3379*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 3380*7c478bd9Sstevel@tonic-gate if (nfs4_server_t_debug) { 3381*7c478bd9Sstevel@tonic-gate /* mi->mi_clientid is unprotected, ok for debug output */ 3382*7c478bd9Sstevel@tonic-gate dumpnfs4slist("find_nfs4_server", mi, mi->mi_clientid, 3383*7c478bd9Sstevel@tonic-gate mi->mi_curr_serv); 3384*7c478bd9Sstevel@tonic-gate } 3385*7c478bd9Sstevel@tonic-gate #endif 3386*7c478bd9Sstevel@tonic-gate for (np = nfs4_server_lst.forw; np != &nfs4_server_lst; np = np->forw) { 3387*7c478bd9Sstevel@tonic-gate mutex_enter(&np->s_lock); 3388*7c478bd9Sstevel@tonic-gate svp = mi->mi_curr_serv; 3389*7c478bd9Sstevel@tonic-gate 3390*7c478bd9Sstevel@tonic-gate if (np->zoneid == zoneid && 3391*7c478bd9Sstevel@tonic-gate np->clientid == mi->mi_clientid && 3392*7c478bd9Sstevel@tonic-gate np->saddr.len == svp->sv_addr.len && 3393*7c478bd9Sstevel@tonic-gate bcmp(np->saddr.buf, svp->sv_addr.buf, np->saddr.len) == 0 && 3394*7c478bd9Sstevel@tonic-gate (np->s_thread_exit != NFS4_THREAD_EXIT || all != 0)) { 3395*7c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_server_lst_lock); 3396*7c478bd9Sstevel@tonic-gate np->s_refcnt++; 3397*7c478bd9Sstevel@tonic-gate return (np); 3398*7c478bd9Sstevel@tonic-gate } 3399*7c478bd9Sstevel@tonic-gate mutex_exit(&np->s_lock); 3400*7c478bd9Sstevel@tonic-gate } 3401*7c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_server_lst_lock); 3402*7c478bd9Sstevel@tonic-gate 3403*7c478bd9Sstevel@tonic-gate return (NULL); 3404*7c478bd9Sstevel@tonic-gate } 3405*7c478bd9Sstevel@tonic-gate 3406*7c478bd9Sstevel@tonic-gate /* 3407*7c478bd9Sstevel@tonic-gate * Release the reference to sp and destroy it if that's the last one. 3408*7c478bd9Sstevel@tonic-gate */ 3409*7c478bd9Sstevel@tonic-gate 3410*7c478bd9Sstevel@tonic-gate void 3411*7c478bd9Sstevel@tonic-gate nfs4_server_rele(nfs4_server_t *sp) 3412*7c478bd9Sstevel@tonic-gate { 3413*7c478bd9Sstevel@tonic-gate mutex_enter(&sp->s_lock); 3414*7c478bd9Sstevel@tonic-gate ASSERT(sp->s_refcnt > 0); 3415*7c478bd9Sstevel@tonic-gate sp->s_refcnt--; 3416*7c478bd9Sstevel@tonic-gate if (sp->s_refcnt > 0) { 3417*7c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_lock); 3418*7c478bd9Sstevel@tonic-gate return; 3419*7c478bd9Sstevel@tonic-gate } 3420*7c478bd9Sstevel@tonic-gate if (!(sp->s_flags & N4S_INSERTED)) { 3421*7c478bd9Sstevel@tonic-gate destroy_nfs4_server(sp); 3422*7c478bd9Sstevel@tonic-gate return; 3423*7c478bd9Sstevel@tonic-gate } 3424*7c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_lock); 3425*7c478bd9Sstevel@tonic-gate mutex_enter(&nfs4_server_lst_lock); 3426*7c478bd9Sstevel@tonic-gate mutex_enter(&sp->s_lock); 3427*7c478bd9Sstevel@tonic-gate if (sp->s_refcnt > 0) { 3428*7c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_lock); 3429*7c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_server_lst_lock); 3430*7c478bd9Sstevel@tonic-gate return; 3431*7c478bd9Sstevel@tonic-gate } 3432*7c478bd9Sstevel@tonic-gate if (sp->s_flags & N4S_INSERTED) { 3433*7c478bd9Sstevel@tonic-gate remque(sp); 3434*7c478bd9Sstevel@tonic-gate sp->forw = sp->back = NULL; 3435*7c478bd9Sstevel@tonic-gate sp->s_flags &= ~N4S_INSERTED; 3436*7c478bd9Sstevel@tonic-gate } 3437*7c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_server_lst_lock); 3438*7c478bd9Sstevel@tonic-gate destroy_nfs4_server(sp); 3439*7c478bd9Sstevel@tonic-gate } 3440*7c478bd9Sstevel@tonic-gate 3441*7c478bd9Sstevel@tonic-gate static void 3442*7c478bd9Sstevel@tonic-gate destroy_nfs4_server(nfs4_server_t *sp) 3443*7c478bd9Sstevel@tonic-gate { 3444*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sp->s_lock)); 3445*7c478bd9Sstevel@tonic-gate ASSERT(!(sp->s_flags & N4S_INSERTED)); 3446*7c478bd9Sstevel@tonic-gate ASSERT(sp->s_refcnt == 0); 3447*7c478bd9Sstevel@tonic-gate ASSERT(sp->s_otw_call_count == 0); 3448*7c478bd9Sstevel@tonic-gate 3449*7c478bd9Sstevel@tonic-gate remove_all_mi(sp); 3450*7c478bd9Sstevel@tonic-gate 3451*7c478bd9Sstevel@tonic-gate crfree(sp->s_cred); 3452*7c478bd9Sstevel@tonic-gate kmem_free(sp->saddr.buf, sp->saddr.maxlen); 3453*7c478bd9Sstevel@tonic-gate kmem_free(sp->clidtosend.id_val, sp->clidtosend.id_len); 3454*7c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_lock); 3455*7c478bd9Sstevel@tonic-gate 3456*7c478bd9Sstevel@tonic-gate /* destroy the nfs4_server */ 3457*7c478bd9Sstevel@tonic-gate nfs4callback_destroy(sp); 3458*7c478bd9Sstevel@tonic-gate list_destroy(&sp->s_deleg_list); 3459*7c478bd9Sstevel@tonic-gate mutex_destroy(&sp->s_lock); 3460*7c478bd9Sstevel@tonic-gate cv_destroy(&sp->cv_thread_exit); 3461*7c478bd9Sstevel@tonic-gate cv_destroy(&sp->s_cv_otw_count); 3462*7c478bd9Sstevel@tonic-gate cv_destroy(&sp->wait_cb_null); 3463*7c478bd9Sstevel@tonic-gate nfs_rw_destroy(&sp->s_recovlock); 3464*7c478bd9Sstevel@tonic-gate kmem_free(sp, sizeof (*sp)); 3465*7c478bd9Sstevel@tonic-gate } 3466*7c478bd9Sstevel@tonic-gate 3467*7c478bd9Sstevel@tonic-gate /* 3468*7c478bd9Sstevel@tonic-gate * Lock sp, but only if it's still active (in the list and hasn't been 3469*7c478bd9Sstevel@tonic-gate * flagged as exiting) or 'all' is non-zero. 3470*7c478bd9Sstevel@tonic-gate * Returns TRUE if sp got locked and adds a reference to sp. 3471*7c478bd9Sstevel@tonic-gate */ 3472*7c478bd9Sstevel@tonic-gate bool_t 3473*7c478bd9Sstevel@tonic-gate nfs4_server_vlock(nfs4_server_t *sp, int all) 3474*7c478bd9Sstevel@tonic-gate { 3475*7c478bd9Sstevel@tonic-gate nfs4_server_t *np; 3476*7c478bd9Sstevel@tonic-gate 3477*7c478bd9Sstevel@tonic-gate mutex_enter(&nfs4_server_lst_lock); 3478*7c478bd9Sstevel@tonic-gate for (np = nfs4_server_lst.forw; np != &nfs4_server_lst; np = np->forw) { 3479*7c478bd9Sstevel@tonic-gate if (sp == np && (np->s_thread_exit != NFS4_THREAD_EXIT || 3480*7c478bd9Sstevel@tonic-gate all != 0)) { 3481*7c478bd9Sstevel@tonic-gate mutex_enter(&np->s_lock); 3482*7c478bd9Sstevel@tonic-gate np->s_refcnt++; 3483*7c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_server_lst_lock); 3484*7c478bd9Sstevel@tonic-gate return (TRUE); 3485*7c478bd9Sstevel@tonic-gate } 3486*7c478bd9Sstevel@tonic-gate } 3487*7c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_server_lst_lock); 3488*7c478bd9Sstevel@tonic-gate return (FALSE); 3489*7c478bd9Sstevel@tonic-gate } 3490*7c478bd9Sstevel@tonic-gate 3491*7c478bd9Sstevel@tonic-gate /* 3492*7c478bd9Sstevel@tonic-gate * Fork off a thread to free the data structures for a mount. 3493*7c478bd9Sstevel@tonic-gate */ 3494*7c478bd9Sstevel@tonic-gate 3495*7c478bd9Sstevel@tonic-gate static void 3496*7c478bd9Sstevel@tonic-gate async_free_mount(vfs_t *vfsp, cred_t *cr) 3497*7c478bd9Sstevel@tonic-gate { 3498*7c478bd9Sstevel@tonic-gate freemountargs_t *args; 3499*7c478bd9Sstevel@tonic-gate 3500*7c478bd9Sstevel@tonic-gate args = kmem_alloc(sizeof (freemountargs_t), KM_SLEEP); 3501*7c478bd9Sstevel@tonic-gate args->fm_vfsp = vfsp; 3502*7c478bd9Sstevel@tonic-gate VFS_HOLD(vfsp); 3503*7c478bd9Sstevel@tonic-gate args->fm_cr = cr; 3504*7c478bd9Sstevel@tonic-gate crhold(cr); 3505*7c478bd9Sstevel@tonic-gate 3506*7c478bd9Sstevel@tonic-gate (void) zthread_create(NULL, 0, nfs4_free_mount_thread, args, 0, 3507*7c478bd9Sstevel@tonic-gate minclsyspri); 3508*7c478bd9Sstevel@tonic-gate } 3509*7c478bd9Sstevel@tonic-gate 3510*7c478bd9Sstevel@tonic-gate static void 3511*7c478bd9Sstevel@tonic-gate nfs4_free_mount_thread(freemountargs_t *args) 3512*7c478bd9Sstevel@tonic-gate { 3513*7c478bd9Sstevel@tonic-gate nfs4_free_mount(args->fm_vfsp, args->fm_cr); 3514*7c478bd9Sstevel@tonic-gate VFS_RELE(args->fm_vfsp); 3515*7c478bd9Sstevel@tonic-gate crfree(args->fm_cr); 3516*7c478bd9Sstevel@tonic-gate kmem_free(args, sizeof (freemountargs_t)); 3517*7c478bd9Sstevel@tonic-gate zthread_exit(); 3518*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3519*7c478bd9Sstevel@tonic-gate } 3520*7c478bd9Sstevel@tonic-gate 3521*7c478bd9Sstevel@tonic-gate /* 3522*7c478bd9Sstevel@tonic-gate * Thread to free the data structures for a given filesystem. 3523*7c478bd9Sstevel@tonic-gate */ 3524*7c478bd9Sstevel@tonic-gate static void 3525*7c478bd9Sstevel@tonic-gate nfs4_free_mount(vfs_t *vfsp, cred_t *cr) 3526*7c478bd9Sstevel@tonic-gate { 3527*7c478bd9Sstevel@tonic-gate mntinfo4_t *mi = VFTOMI4(vfsp); 3528*7c478bd9Sstevel@tonic-gate nfs4_server_t *sp; 3529*7c478bd9Sstevel@tonic-gate callb_cpr_t cpr_info; 3530*7c478bd9Sstevel@tonic-gate kmutex_t cpr_lock; 3531*7c478bd9Sstevel@tonic-gate boolean_t async_thread; 3532*7c478bd9Sstevel@tonic-gate 3533*7c478bd9Sstevel@tonic-gate /* 3534*7c478bd9Sstevel@tonic-gate * We need to participate in the CPR framework if this is a kernel 3535*7c478bd9Sstevel@tonic-gate * thread. 3536*7c478bd9Sstevel@tonic-gate */ 3537*7c478bd9Sstevel@tonic-gate async_thread = (curproc == curproc->p_zone->zone_zsched); 3538*7c478bd9Sstevel@tonic-gate if (async_thread) { 3539*7c478bd9Sstevel@tonic-gate mutex_init(&cpr_lock, NULL, MUTEX_DEFAULT, NULL); 3540*7c478bd9Sstevel@tonic-gate CALLB_CPR_INIT(&cpr_info, &cpr_lock, callb_generic_cpr, 3541*7c478bd9Sstevel@tonic-gate "nfsv4AsyncUnmount"); 3542*7c478bd9Sstevel@tonic-gate } 3543*7c478bd9Sstevel@tonic-gate 3544*7c478bd9Sstevel@tonic-gate /* 3545*7c478bd9Sstevel@tonic-gate * We need to wait for all outstanding OTW calls 3546*7c478bd9Sstevel@tonic-gate * and recovery to finish before we remove the mi 3547*7c478bd9Sstevel@tonic-gate * from the nfs4_server_t, as current pending 3548*7c478bd9Sstevel@tonic-gate * calls might still need this linkage (in order 3549*7c478bd9Sstevel@tonic-gate * to find a nfs4_server_t from a mntinfo4_t). 3550*7c478bd9Sstevel@tonic-gate */ 3551*7c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&mi->mi_recovlock, RW_READER, FALSE); 3552*7c478bd9Sstevel@tonic-gate sp = find_nfs4_server(mi); 3553*7c478bd9Sstevel@tonic-gate nfs_rw_exit(&mi->mi_recovlock); 3554*7c478bd9Sstevel@tonic-gate 3555*7c478bd9Sstevel@tonic-gate if (sp) { 3556*7c478bd9Sstevel@tonic-gate while (sp->s_otw_call_count != 0) { 3557*7c478bd9Sstevel@tonic-gate if (async_thread) { 3558*7c478bd9Sstevel@tonic-gate mutex_enter(&cpr_lock); 3559*7c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&cpr_info); 3560*7c478bd9Sstevel@tonic-gate mutex_exit(&cpr_lock); 3561*7c478bd9Sstevel@tonic-gate } 3562*7c478bd9Sstevel@tonic-gate cv_wait(&sp->s_cv_otw_count, &sp->s_lock); 3563*7c478bd9Sstevel@tonic-gate if (async_thread) { 3564*7c478bd9Sstevel@tonic-gate mutex_enter(&cpr_lock); 3565*7c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_END(&cpr_info, &cpr_lock); 3566*7c478bd9Sstevel@tonic-gate mutex_exit(&cpr_lock); 3567*7c478bd9Sstevel@tonic-gate } 3568*7c478bd9Sstevel@tonic-gate } 3569*7c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_lock); 3570*7c478bd9Sstevel@tonic-gate nfs4_server_rele(sp); 3571*7c478bd9Sstevel@tonic-gate sp = NULL; 3572*7c478bd9Sstevel@tonic-gate } 3573*7c478bd9Sstevel@tonic-gate 3574*7c478bd9Sstevel@tonic-gate 3575*7c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 3576*7c478bd9Sstevel@tonic-gate while (mi->mi_in_recovery != 0) { 3577*7c478bd9Sstevel@tonic-gate if (async_thread) { 3578*7c478bd9Sstevel@tonic-gate mutex_enter(&cpr_lock); 3579*7c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&cpr_info); 3580*7c478bd9Sstevel@tonic-gate mutex_exit(&cpr_lock); 3581*7c478bd9Sstevel@tonic-gate } 3582*7c478bd9Sstevel@tonic-gate cv_wait(&mi->mi_cv_in_recov, &mi->mi_lock); 3583*7c478bd9Sstevel@tonic-gate if (async_thread) { 3584*7c478bd9Sstevel@tonic-gate mutex_enter(&cpr_lock); 3585*7c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_END(&cpr_info, &cpr_lock); 3586*7c478bd9Sstevel@tonic-gate mutex_exit(&cpr_lock); 3587*7c478bd9Sstevel@tonic-gate } 3588*7c478bd9Sstevel@tonic-gate } 3589*7c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 3590*7c478bd9Sstevel@tonic-gate 3591*7c478bd9Sstevel@tonic-gate /* 3592*7c478bd9Sstevel@tonic-gate * The original purge of the dnlc via 'dounmount' 3593*7c478bd9Sstevel@tonic-gate * doesn't guarantee that another dnlc entry was not 3594*7c478bd9Sstevel@tonic-gate * added while we waitied for all outstanding OTW 3595*7c478bd9Sstevel@tonic-gate * and recovery calls to finish. So re-purge the 3596*7c478bd9Sstevel@tonic-gate * dnlc now. 3597*7c478bd9Sstevel@tonic-gate */ 3598*7c478bd9Sstevel@tonic-gate (void) dnlc_purge_vfsp(vfsp, 0); 3599*7c478bd9Sstevel@tonic-gate 3600*7c478bd9Sstevel@tonic-gate /* 3601*7c478bd9Sstevel@tonic-gate * We need to explicitly stop the manager thread; the asyc worker 3602*7c478bd9Sstevel@tonic-gate * threads can timeout and exit on their own. 3603*7c478bd9Sstevel@tonic-gate */ 3604*7c478bd9Sstevel@tonic-gate nfs4_async_manager_stop(vfsp); 3605*7c478bd9Sstevel@tonic-gate 3606*7c478bd9Sstevel@tonic-gate destroy_fileid_map(vfsp); 3607*7c478bd9Sstevel@tonic-gate destroy_rtable4(vfsp, cr); 3608*7c478bd9Sstevel@tonic-gate 3609*7c478bd9Sstevel@tonic-gate nfs4_remove_mi_from_server(mi, NULL); 3610*7c478bd9Sstevel@tonic-gate 3611*7c478bd9Sstevel@tonic-gate if (mi->mi_io_kstats) { 3612*7c478bd9Sstevel@tonic-gate kstat_delete(mi->mi_io_kstats); 3613*7c478bd9Sstevel@tonic-gate mi->mi_io_kstats = NULL; 3614*7c478bd9Sstevel@tonic-gate } 3615*7c478bd9Sstevel@tonic-gate if (mi->mi_ro_kstats) { 3616*7c478bd9Sstevel@tonic-gate kstat_delete(mi->mi_ro_kstats); 3617*7c478bd9Sstevel@tonic-gate mi->mi_ro_kstats = NULL; 3618*7c478bd9Sstevel@tonic-gate } 3619*7c478bd9Sstevel@tonic-gate if (mi->mi_recov_ksp) { 3620*7c478bd9Sstevel@tonic-gate kstat_delete(mi->mi_recov_ksp); 3621*7c478bd9Sstevel@tonic-gate mi->mi_recov_ksp = NULL; 3622*7c478bd9Sstevel@tonic-gate } 3623*7c478bd9Sstevel@tonic-gate 3624*7c478bd9Sstevel@tonic-gate if (async_thread) { 3625*7c478bd9Sstevel@tonic-gate mutex_enter(&cpr_lock); 3626*7c478bd9Sstevel@tonic-gate CALLB_CPR_EXIT(&cpr_info); /* drops cpr_lock */ 3627*7c478bd9Sstevel@tonic-gate mutex_destroy(&cpr_lock); 3628*7c478bd9Sstevel@tonic-gate } 3629*7c478bd9Sstevel@tonic-gate } 3630