17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5f86c6ccaSdm * Common Development and Distribution License (the "License"). 6f86c6ccaSdm * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22f86c6ccaSdm * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T. 287c478bd9Sstevel@tonic-gate * All Rights Reserved 297c478bd9Sstevel@tonic-gate */ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate #include <sys/param.h> 347c478bd9Sstevel@tonic-gate #include <sys/types.h> 357c478bd9Sstevel@tonic-gate #include <sys/systm.h> 367c478bd9Sstevel@tonic-gate #include <sys/cred.h> 377c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 387c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 397c478bd9Sstevel@tonic-gate #include <sys/pathname.h> 407c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 417c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 427c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 437c478bd9Sstevel@tonic-gate #include <sys/mount.h> 447c478bd9Sstevel@tonic-gate #include <sys/statvfs.h> 457c478bd9Sstevel@tonic-gate #include <sys/errno.h> 467c478bd9Sstevel@tonic-gate #include <sys/debug.h> 477c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 487c478bd9Sstevel@tonic-gate #include <sys/utsname.h> 497c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 507c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 517c478bd9Sstevel@tonic-gate #include <sys/acl.h> 527c478bd9Sstevel@tonic-gate #include <sys/flock.h> 537c478bd9Sstevel@tonic-gate #include <sys/time.h> 547c478bd9Sstevel@tonic-gate #include <sys/disp.h> 557c478bd9Sstevel@tonic-gate #include <sys/policy.h> 567c478bd9Sstevel@tonic-gate #include <sys/socket.h> 577c478bd9Sstevel@tonic-gate #include <sys/netconfig.h> 587c478bd9Sstevel@tonic-gate #include <sys/dnlc.h> 597c478bd9Sstevel@tonic-gate #include <sys/list.h> 6045916cd2Sjpk #include <sys/mntent.h> 6145916cd2Sjpk #include <sys/tsol/label.h> 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate #include <rpc/types.h> 647c478bd9Sstevel@tonic-gate #include <rpc/auth.h> 657c478bd9Sstevel@tonic-gate #include <rpc/rpcsec_gss.h> 667c478bd9Sstevel@tonic-gate #include <rpc/clnt.h> 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate #include <nfs/nfs.h> 697c478bd9Sstevel@tonic-gate #include <nfs/nfs_clnt.h> 707c478bd9Sstevel@tonic-gate #include <nfs/mount.h> 717c478bd9Sstevel@tonic-gate #include <nfs/nfs_acl.h> 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate #include <fs/fs_subr.h> 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate #include <nfs/nfs4.h> 767c478bd9Sstevel@tonic-gate #include <nfs/rnode4.h> 777c478bd9Sstevel@tonic-gate #include <nfs/nfs4_clnt.h> 78*39d3e169Sevanl #include <sys/fs/autofs.h> 79*39d3e169Sevanl 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate /* 827c478bd9Sstevel@tonic-gate * Arguments passed to thread to free data structures from forced unmount. 837c478bd9Sstevel@tonic-gate */ 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate typedef struct { 867c478bd9Sstevel@tonic-gate vfs_t *fm_vfsp; 877c478bd9Sstevel@tonic-gate cred_t *fm_cr; 887c478bd9Sstevel@tonic-gate } freemountargs_t; 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate static void async_free_mount(vfs_t *, cred_t *); 917c478bd9Sstevel@tonic-gate static void nfs4_free_mount(vfs_t *, cred_t *); 927c478bd9Sstevel@tonic-gate static void nfs4_free_mount_thread(freemountargs_t *); 937c478bd9Sstevel@tonic-gate static int nfs4_chkdup_servinfo4(servinfo4_t *, servinfo4_t *); 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate /* 967c478bd9Sstevel@tonic-gate * From rpcsec module (common/rpcsec). 977c478bd9Sstevel@tonic-gate */ 987c478bd9Sstevel@tonic-gate extern int sec_clnt_loadinfo(struct sec_data *, struct sec_data **, model_t); 997c478bd9Sstevel@tonic-gate extern void sec_clnt_freeinfo(struct sec_data *); 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate /* 1027c478bd9Sstevel@tonic-gate * The order and contents of this structure must be kept in sync with that of 1037c478bd9Sstevel@tonic-gate * rfsreqcnt_v4_tmpl in nfs_stats.c 1047c478bd9Sstevel@tonic-gate */ 1057c478bd9Sstevel@tonic-gate static char *rfsnames_v4[] = { 1067c478bd9Sstevel@tonic-gate "null", "compound", "reserved", "access", "close", "commit", "create", 1077c478bd9Sstevel@tonic-gate "delegpurge", "delegreturn", "getattr", "getfh", "link", "lock", 1087c478bd9Sstevel@tonic-gate "lockt", "locku", "lookup", "lookupp", "nverify", "open", "openattr", 1097c478bd9Sstevel@tonic-gate "open_confirm", "open_downgrade", "putfh", "putpubfh", "putrootfh", 1107c478bd9Sstevel@tonic-gate "read", "readdir", "readlink", "remove", "rename", "renew", 1117c478bd9Sstevel@tonic-gate "restorefh", "savefh", "secinfo", "setattr", "setclientid", 1127c478bd9Sstevel@tonic-gate "setclientid_confirm", "verify", "write" 1137c478bd9Sstevel@tonic-gate }; 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate /* 1167c478bd9Sstevel@tonic-gate * nfs4_max_mount_retry is the number of times the client will redrive 1177c478bd9Sstevel@tonic-gate * a mount compound before giving up and returning failure. The intent 1187c478bd9Sstevel@tonic-gate * is to redrive mount compounds which fail NFS4ERR_STALE so that 1197c478bd9Sstevel@tonic-gate * if a component of the server path being mounted goes stale, it can 1207c478bd9Sstevel@tonic-gate * "recover" by redriving the mount compund (LOOKUP ops). This recovery 1217c478bd9Sstevel@tonic-gate * code is needed outside of the recovery framework because mount is a 1227c478bd9Sstevel@tonic-gate * special case. The client doesn't create vnodes/rnodes for components 1237c478bd9Sstevel@tonic-gate * of the server path being mounted. The recovery code recovers real 1247c478bd9Sstevel@tonic-gate * client objects, not STALE FHs which map to components of the server 1257c478bd9Sstevel@tonic-gate * path being mounted. 1267c478bd9Sstevel@tonic-gate * 1277c478bd9Sstevel@tonic-gate * We could just fail the mount on the first time, but that would 1287c478bd9Sstevel@tonic-gate * instantly trigger failover (from nfs4_mount), and the client should 1297c478bd9Sstevel@tonic-gate * try to re-lookup the STALE FH before doing failover. The easiest 1307c478bd9Sstevel@tonic-gate * way to "re-lookup" is to simply redrive the mount compound. 1317c478bd9Sstevel@tonic-gate */ 1327c478bd9Sstevel@tonic-gate static int nfs4_max_mount_retry = 2; 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate /* 1357c478bd9Sstevel@tonic-gate * nfs4 vfs operations. 1367c478bd9Sstevel@tonic-gate */ 1377c478bd9Sstevel@tonic-gate static int nfs4_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *); 1387c478bd9Sstevel@tonic-gate static int nfs4_unmount(vfs_t *, int, cred_t *); 1397c478bd9Sstevel@tonic-gate static int nfs4_root(vfs_t *, vnode_t **); 1407c478bd9Sstevel@tonic-gate static int nfs4_statvfs(vfs_t *, struct statvfs64 *); 1417c478bd9Sstevel@tonic-gate static int nfs4_sync(vfs_t *, short, cred_t *); 1427c478bd9Sstevel@tonic-gate static int nfs4_vget(vfs_t *, vnode_t **, fid_t *); 1437c478bd9Sstevel@tonic-gate static int nfs4_mountroot(vfs_t *, whymountroot_t); 1447c478bd9Sstevel@tonic-gate static void nfs4_freevfs(vfs_t *); 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate static int nfs4rootvp(vnode_t **, vfs_t *, struct servinfo4 *, 1477c478bd9Sstevel@tonic-gate int, cred_t *, zone_t *); 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate vfsops_t *nfs4_vfsops; 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate int nfs4_vfsinit(void); 1527c478bd9Sstevel@tonic-gate void nfs4_vfsfini(void); 1537c478bd9Sstevel@tonic-gate static void nfs4setclientid_init(void); 1547c478bd9Sstevel@tonic-gate static void nfs4setclientid_fini(void); 1557c478bd9Sstevel@tonic-gate static void nfs4setclientid_otw(mntinfo4_t *, servinfo4_t *, cred_t *, 1567c478bd9Sstevel@tonic-gate struct nfs4_server *, nfs4_error_t *, int *); 1577c478bd9Sstevel@tonic-gate static void destroy_nfs4_server(nfs4_server_t *); 1587c478bd9Sstevel@tonic-gate static void remove_mi(nfs4_server_t *, mntinfo4_t *); 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate /* 1617c478bd9Sstevel@tonic-gate * Initialize the vfs structure 1627c478bd9Sstevel@tonic-gate */ 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate static int nfs4fstyp; 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate /* 1687c478bd9Sstevel@tonic-gate * Debug variable to check for rdma based 1697c478bd9Sstevel@tonic-gate * transport startup and cleanup. Controlled 1707c478bd9Sstevel@tonic-gate * through /etc/system. Off by default. 1717c478bd9Sstevel@tonic-gate */ 1727c478bd9Sstevel@tonic-gate extern int rdma_debug; 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate int 1757c478bd9Sstevel@tonic-gate nfs4init(int fstyp, char *name) 1767c478bd9Sstevel@tonic-gate { 1777c478bd9Sstevel@tonic-gate static const fs_operation_def_t nfs4_vfsops_template[] = { 1787c478bd9Sstevel@tonic-gate VFSNAME_MOUNT, nfs4_mount, 1797c478bd9Sstevel@tonic-gate VFSNAME_UNMOUNT, nfs4_unmount, 1807c478bd9Sstevel@tonic-gate VFSNAME_ROOT, nfs4_root, 1817c478bd9Sstevel@tonic-gate VFSNAME_STATVFS, nfs4_statvfs, 1827c478bd9Sstevel@tonic-gate VFSNAME_SYNC, (fs_generic_func_p) nfs4_sync, 1837c478bd9Sstevel@tonic-gate VFSNAME_VGET, nfs4_vget, 1847c478bd9Sstevel@tonic-gate VFSNAME_MOUNTROOT, nfs4_mountroot, 1857c478bd9Sstevel@tonic-gate VFSNAME_FREEVFS, (fs_generic_func_p)nfs4_freevfs, 1867c478bd9Sstevel@tonic-gate NULL, NULL 1877c478bd9Sstevel@tonic-gate }; 1887c478bd9Sstevel@tonic-gate int error; 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate error = vfs_setfsops(fstyp, nfs4_vfsops_template, &nfs4_vfsops); 1917c478bd9Sstevel@tonic-gate if (error != 0) { 1927c478bd9Sstevel@tonic-gate zcmn_err(GLOBAL_ZONEID, CE_WARN, 1937c478bd9Sstevel@tonic-gate "nfs4init: bad vfs ops template"); 1947c478bd9Sstevel@tonic-gate return (error); 1957c478bd9Sstevel@tonic-gate } 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate error = vn_make_ops(name, nfs4_vnodeops_template, &nfs4_vnodeops); 1987c478bd9Sstevel@tonic-gate if (error != 0) { 1997c478bd9Sstevel@tonic-gate (void) vfs_freevfsops_by_type(fstyp); 2007c478bd9Sstevel@tonic-gate zcmn_err(GLOBAL_ZONEID, CE_WARN, 2017c478bd9Sstevel@tonic-gate "nfs4init: bad vnode ops template"); 2027c478bd9Sstevel@tonic-gate return (error); 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate nfs4fstyp = fstyp; 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate (void) nfs4_vfsinit(); 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate (void) nfs4_init_dot_entries(); 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate return (0); 2127c478bd9Sstevel@tonic-gate } 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate void 2157c478bd9Sstevel@tonic-gate nfs4fini(void) 2167c478bd9Sstevel@tonic-gate { 2177c478bd9Sstevel@tonic-gate (void) nfs4_destroy_dot_entries(); 2187c478bd9Sstevel@tonic-gate nfs4_vfsfini(); 2197c478bd9Sstevel@tonic-gate } 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate /* 2227c478bd9Sstevel@tonic-gate * Create a new sec_data structure to store AUTH_DH related data: 2237c478bd9Sstevel@tonic-gate * netname, syncaddr, knetconfig. There is no AUTH_F_RPCTIMESYNC 2247c478bd9Sstevel@tonic-gate * flag set for NFS V4 since we are avoiding to contact the rpcbind 2257c478bd9Sstevel@tonic-gate * daemon and is using the IP time service (IPPORT_TIMESERVER). 2267c478bd9Sstevel@tonic-gate * 2277c478bd9Sstevel@tonic-gate * sec_data can be freed by sec_clnt_freeinfo(). 2287c478bd9Sstevel@tonic-gate */ 2297c478bd9Sstevel@tonic-gate struct sec_data * 2307c478bd9Sstevel@tonic-gate create_authdh_data(char *netname, int nlen, struct netbuf *syncaddr, 2317c478bd9Sstevel@tonic-gate struct knetconfig *knconf) { 2327c478bd9Sstevel@tonic-gate struct sec_data *secdata; 2337c478bd9Sstevel@tonic-gate dh_k4_clntdata_t *data; 2347c478bd9Sstevel@tonic-gate char *pf, *p; 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate if (syncaddr == NULL || syncaddr->buf == NULL || nlen == 0) 2377c478bd9Sstevel@tonic-gate return (NULL); 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate secdata = kmem_alloc(sizeof (*secdata), KM_SLEEP); 2407c478bd9Sstevel@tonic-gate secdata->flags = 0; 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate data = kmem_alloc(sizeof (*data), KM_SLEEP); 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate data->syncaddr.maxlen = syncaddr->maxlen; 2457c478bd9Sstevel@tonic-gate data->syncaddr.len = syncaddr->len; 2467c478bd9Sstevel@tonic-gate data->syncaddr.buf = (char *)kmem_alloc(syncaddr->len, KM_SLEEP); 2477c478bd9Sstevel@tonic-gate bcopy(syncaddr->buf, data->syncaddr.buf, syncaddr->len); 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate /* 2507c478bd9Sstevel@tonic-gate * duplicate the knconf information for the 2517c478bd9Sstevel@tonic-gate * new opaque data. 2527c478bd9Sstevel@tonic-gate */ 2537c478bd9Sstevel@tonic-gate data->knconf = kmem_alloc(sizeof (*knconf), KM_SLEEP); 2547c478bd9Sstevel@tonic-gate *data->knconf = *knconf; 2557c478bd9Sstevel@tonic-gate pf = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 2567c478bd9Sstevel@tonic-gate p = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 2577c478bd9Sstevel@tonic-gate bcopy(knconf->knc_protofmly, pf, KNC_STRSIZE); 2587c478bd9Sstevel@tonic-gate bcopy(knconf->knc_proto, p, KNC_STRSIZE); 2597c478bd9Sstevel@tonic-gate data->knconf->knc_protofmly = pf; 2607c478bd9Sstevel@tonic-gate data->knconf->knc_proto = p; 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate /* move server netname to the sec_data structure */ 2637c478bd9Sstevel@tonic-gate data->netname = kmem_alloc(nlen, KM_SLEEP); 2647c478bd9Sstevel@tonic-gate bcopy(netname, data->netname, nlen); 2657c478bd9Sstevel@tonic-gate data->netnamelen = (int)nlen; 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate secdata->secmod = AUTH_DH; 2687c478bd9Sstevel@tonic-gate secdata->rpcflavor = AUTH_DH; 2697c478bd9Sstevel@tonic-gate secdata->data = (caddr_t)data; 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate return (secdata); 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate static int 2757c478bd9Sstevel@tonic-gate nfs4_chkdup_servinfo4(servinfo4_t *svp_head, servinfo4_t *svp) 2767c478bd9Sstevel@tonic-gate { 2777c478bd9Sstevel@tonic-gate servinfo4_t *si; 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate /* 2807c478bd9Sstevel@tonic-gate * Iterate over the servinfo4 list to make sure 2817c478bd9Sstevel@tonic-gate * we do not have a duplicate. Skip any servinfo4 2827c478bd9Sstevel@tonic-gate * that has been marked "NOT IN USE" 2837c478bd9Sstevel@tonic-gate */ 2847c478bd9Sstevel@tonic-gate for (si = svp_head; si; si = si->sv_next) { 2857c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&si->sv_lock, RW_READER, 0); 2867c478bd9Sstevel@tonic-gate if (si->sv_flags & SV4_NOTINUSE) { 2877c478bd9Sstevel@tonic-gate nfs_rw_exit(&si->sv_lock); 2887c478bd9Sstevel@tonic-gate continue; 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate nfs_rw_exit(&si->sv_lock); 2917c478bd9Sstevel@tonic-gate if (si == svp) 2927c478bd9Sstevel@tonic-gate continue; 2937c478bd9Sstevel@tonic-gate if (si->sv_addr.len == svp->sv_addr.len && 2947c478bd9Sstevel@tonic-gate strcmp(si->sv_knconf->knc_protofmly, 2957c478bd9Sstevel@tonic-gate svp->sv_knconf->knc_protofmly) == 0 && 2967c478bd9Sstevel@tonic-gate bcmp(si->sv_addr.buf, svp->sv_addr.buf, 2977c478bd9Sstevel@tonic-gate si->sv_addr.len) == 0) { 2987c478bd9Sstevel@tonic-gate /* it's a duplicate */ 2997c478bd9Sstevel@tonic-gate return (1); 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate } 3027c478bd9Sstevel@tonic-gate /* it's not a duplicate */ 3037c478bd9Sstevel@tonic-gate return (0); 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate 306*39d3e169Sevanl void 307*39d3e169Sevanl nfs4_free_args(struct nfs_args *nargs) 308*39d3e169Sevanl { 309*39d3e169Sevanl if (nargs->knconf) { 310*39d3e169Sevanl if (nargs->knconf->knc_protofmly) 311*39d3e169Sevanl kmem_free(nargs->knconf->knc_protofmly, 312*39d3e169Sevanl KNC_STRSIZE); 313*39d3e169Sevanl if (nargs->knconf->knc_proto) 314*39d3e169Sevanl kmem_free(nargs->knconf->knc_proto, KNC_STRSIZE); 315*39d3e169Sevanl kmem_free(nargs->knconf, sizeof (*nargs->knconf)); 316*39d3e169Sevanl nargs->knconf = NULL; 317*39d3e169Sevanl } 318*39d3e169Sevanl 319*39d3e169Sevanl if (nargs->fh) { 320*39d3e169Sevanl kmem_free(nargs->fh, strlen(nargs->fh) + 1); 321*39d3e169Sevanl nargs->fh = NULL; 322*39d3e169Sevanl } 323*39d3e169Sevanl 324*39d3e169Sevanl if (nargs->hostname) { 325*39d3e169Sevanl kmem_free(nargs->hostname, strlen(nargs->hostname) + 1); 326*39d3e169Sevanl nargs->hostname = NULL; 327*39d3e169Sevanl } 328*39d3e169Sevanl 329*39d3e169Sevanl if (nargs->addr) { 330*39d3e169Sevanl if (nargs->addr->buf) { 331*39d3e169Sevanl ASSERT(nargs->addr->len); 332*39d3e169Sevanl kmem_free(nargs->addr->buf, nargs->addr->len); 333*39d3e169Sevanl } 334*39d3e169Sevanl kmem_free(nargs->addr, sizeof (struct netbuf)); 335*39d3e169Sevanl nargs->addr = NULL; 336*39d3e169Sevanl } 337*39d3e169Sevanl 338*39d3e169Sevanl if (nargs->syncaddr) { 339*39d3e169Sevanl ASSERT(nargs->syncaddr->len); 340*39d3e169Sevanl if (nargs->syncaddr->buf) { 341*39d3e169Sevanl ASSERT(nargs->syncaddr->len); 342*39d3e169Sevanl kmem_free(nargs->syncaddr->buf, nargs->syncaddr->len); 343*39d3e169Sevanl } 344*39d3e169Sevanl kmem_free(nargs->syncaddr, sizeof (struct netbuf)); 345*39d3e169Sevanl nargs->syncaddr = NULL; 346*39d3e169Sevanl } 347*39d3e169Sevanl 348*39d3e169Sevanl if (nargs->netname) { 349*39d3e169Sevanl kmem_free(nargs->netname, strlen(nargs->netname) + 1); 350*39d3e169Sevanl nargs->netname = NULL; 351*39d3e169Sevanl } 352*39d3e169Sevanl 353*39d3e169Sevanl if (nargs->nfs_ext_u.nfs_extA.secdata) { 354*39d3e169Sevanl sec_clnt_freeinfo( 355*39d3e169Sevanl nargs->nfs_ext_u.nfs_extA.secdata); 356*39d3e169Sevanl nargs->nfs_ext_u.nfs_extA.secdata = NULL; 357*39d3e169Sevanl } 358*39d3e169Sevanl } 359*39d3e169Sevanl 360*39d3e169Sevanl 361*39d3e169Sevanl int 362*39d3e169Sevanl nfs4_copyin(char *data, int datalen, struct nfs_args *nargs) 363*39d3e169Sevanl { 364*39d3e169Sevanl 365*39d3e169Sevanl int error; 366*39d3e169Sevanl size_t hlen; /* length of hostname */ 367*39d3e169Sevanl size_t nlen; /* length of netname */ 368*39d3e169Sevanl char netname[MAXNETNAMELEN+1]; /* server's netname */ 369*39d3e169Sevanl struct netbuf addr; /* server's address */ 370*39d3e169Sevanl struct netbuf syncaddr; /* AUTH_DES time sync addr */ 371*39d3e169Sevanl struct knetconfig *knconf; /* transport structure */ 372*39d3e169Sevanl struct sec_data *secdata = NULL; /* security data */ 373*39d3e169Sevanl STRUCT_DECL(nfs_args, args); /* nfs mount arguments */ 374*39d3e169Sevanl STRUCT_DECL(knetconfig, knconf_tmp); 375*39d3e169Sevanl STRUCT_DECL(netbuf, addr_tmp); 376*39d3e169Sevanl int flags; 377*39d3e169Sevanl char *p, *pf; 378*39d3e169Sevanl struct pathname pn; 379*39d3e169Sevanl char *userbufptr; 380*39d3e169Sevanl 381*39d3e169Sevanl 382*39d3e169Sevanl bzero(nargs, sizeof (*nargs)); 383*39d3e169Sevanl 384*39d3e169Sevanl STRUCT_INIT(args, get_udatamodel()); 385*39d3e169Sevanl bzero(STRUCT_BUF(args), SIZEOF_STRUCT(nfs_args, DATAMODEL_NATIVE)); 386*39d3e169Sevanl if (copyin(data, STRUCT_BUF(args), MIN(datalen, 387*39d3e169Sevanl STRUCT_SIZE(args)))) 388*39d3e169Sevanl return (EFAULT); 389*39d3e169Sevanl 390*39d3e169Sevanl nargs->wsize = STRUCT_FGET(args, wsize); 391*39d3e169Sevanl nargs->rsize = STRUCT_FGET(args, rsize); 392*39d3e169Sevanl nargs->timeo = STRUCT_FGET(args, timeo); 393*39d3e169Sevanl nargs->retrans = STRUCT_FGET(args, retrans); 394*39d3e169Sevanl nargs->acregmin = STRUCT_FGET(args, acregmin); 395*39d3e169Sevanl nargs->acregmax = STRUCT_FGET(args, acregmax); 396*39d3e169Sevanl nargs->acdirmin = STRUCT_FGET(args, acdirmin); 397*39d3e169Sevanl nargs->acdirmax = STRUCT_FGET(args, acdirmax); 398*39d3e169Sevanl 399*39d3e169Sevanl flags = STRUCT_FGET(args, flags); 400*39d3e169Sevanl nargs->flags = flags; 401*39d3e169Sevanl 402*39d3e169Sevanl addr.buf = NULL; 403*39d3e169Sevanl syncaddr.buf = NULL; 404*39d3e169Sevanl 405*39d3e169Sevanl 406*39d3e169Sevanl /* 407*39d3e169Sevanl * Allocate space for a knetconfig structure and 408*39d3e169Sevanl * its strings and copy in from user-land. 409*39d3e169Sevanl */ 410*39d3e169Sevanl knconf = kmem_zalloc(sizeof (*knconf), KM_SLEEP); 411*39d3e169Sevanl STRUCT_INIT(knconf_tmp, get_udatamodel()); 412*39d3e169Sevanl if (copyin(STRUCT_FGETP(args, knconf), STRUCT_BUF(knconf_tmp), 413*39d3e169Sevanl STRUCT_SIZE(knconf_tmp))) { 414*39d3e169Sevanl kmem_free(knconf, sizeof (*knconf)); 415*39d3e169Sevanl return (EFAULT); 416*39d3e169Sevanl } 417*39d3e169Sevanl 418*39d3e169Sevanl knconf->knc_semantics = STRUCT_FGET(knconf_tmp, knc_semantics); 419*39d3e169Sevanl knconf->knc_protofmly = STRUCT_FGETP(knconf_tmp, knc_protofmly); 420*39d3e169Sevanl knconf->knc_proto = STRUCT_FGETP(knconf_tmp, knc_proto); 421*39d3e169Sevanl if (get_udatamodel() != DATAMODEL_LP64) { 422*39d3e169Sevanl knconf->knc_rdev = expldev(STRUCT_FGET(knconf_tmp, knc_rdev)); 423*39d3e169Sevanl } else { 424*39d3e169Sevanl knconf->knc_rdev = STRUCT_FGET(knconf_tmp, knc_rdev); 425*39d3e169Sevanl } 426*39d3e169Sevanl 427*39d3e169Sevanl pf = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 428*39d3e169Sevanl p = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 429*39d3e169Sevanl error = copyinstr(knconf->knc_protofmly, pf, KNC_STRSIZE, NULL); 430*39d3e169Sevanl if (error) { 431*39d3e169Sevanl kmem_free(pf, KNC_STRSIZE); 432*39d3e169Sevanl kmem_free(p, KNC_STRSIZE); 433*39d3e169Sevanl kmem_free(knconf, sizeof (*knconf)); 434*39d3e169Sevanl return (error); 435*39d3e169Sevanl } 436*39d3e169Sevanl 437*39d3e169Sevanl error = copyinstr(knconf->knc_proto, p, KNC_STRSIZE, NULL); 438*39d3e169Sevanl if (error) { 439*39d3e169Sevanl kmem_free(pf, KNC_STRSIZE); 440*39d3e169Sevanl kmem_free(p, KNC_STRSIZE); 441*39d3e169Sevanl kmem_free(knconf, sizeof (*knconf)); 442*39d3e169Sevanl return (error); 443*39d3e169Sevanl } 444*39d3e169Sevanl 445*39d3e169Sevanl 446*39d3e169Sevanl knconf->knc_protofmly = pf; 447*39d3e169Sevanl knconf->knc_proto = p; 448*39d3e169Sevanl 449*39d3e169Sevanl nargs->knconf = knconf; 450*39d3e169Sevanl 451*39d3e169Sevanl /* 452*39d3e169Sevanl * Get server address 453*39d3e169Sevanl */ 454*39d3e169Sevanl STRUCT_INIT(addr_tmp, get_udatamodel()); 455*39d3e169Sevanl if (copyin(STRUCT_FGETP(args, addr), STRUCT_BUF(addr_tmp), 456*39d3e169Sevanl STRUCT_SIZE(addr_tmp))) { 457*39d3e169Sevanl error = EFAULT; 458*39d3e169Sevanl goto errout; 459*39d3e169Sevanl } 460*39d3e169Sevanl 461*39d3e169Sevanl nargs->addr = kmem_alloc(sizeof (struct netbuf), KM_SLEEP); 462*39d3e169Sevanl userbufptr = STRUCT_FGETP(addr_tmp, buf); 463*39d3e169Sevanl addr.len = STRUCT_FGET(addr_tmp, len); 464*39d3e169Sevanl addr.buf = kmem_alloc(addr.len, KM_SLEEP); 465*39d3e169Sevanl addr.maxlen = addr.len; 466*39d3e169Sevanl if (copyin(userbufptr, addr.buf, addr.len)) { 467*39d3e169Sevanl kmem_free(addr.buf, addr.len); 468*39d3e169Sevanl error = EFAULT; 469*39d3e169Sevanl goto errout; 470*39d3e169Sevanl } 471*39d3e169Sevanl bcopy(&addr, nargs->addr, sizeof (struct netbuf)); 472*39d3e169Sevanl 473*39d3e169Sevanl /* 474*39d3e169Sevanl * Get the root fhandle 475*39d3e169Sevanl */ 476*39d3e169Sevanl error = pn_get(STRUCT_FGETP(args, fh), UIO_USERSPACE, &pn); 477*39d3e169Sevanl if (error) 478*39d3e169Sevanl goto errout; 479*39d3e169Sevanl 480*39d3e169Sevanl /* Volatile fh: keep server paths, so use actual-size strings */ 481*39d3e169Sevanl nargs->fh = kmem_alloc(pn.pn_pathlen + 1, KM_SLEEP); 482*39d3e169Sevanl bcopy(pn.pn_path, nargs->fh, pn.pn_pathlen); 483*39d3e169Sevanl nargs->fh[pn.pn_pathlen] = '\0'; 484*39d3e169Sevanl pn_free(&pn); 485*39d3e169Sevanl 486*39d3e169Sevanl 487*39d3e169Sevanl /* 488*39d3e169Sevanl * Get server's hostname 489*39d3e169Sevanl */ 490*39d3e169Sevanl if (flags & NFSMNT_HOSTNAME) { 491*39d3e169Sevanl error = copyinstr(STRUCT_FGETP(args, hostname), 492*39d3e169Sevanl netname, sizeof (netname), &hlen); 493*39d3e169Sevanl if (error) 494*39d3e169Sevanl goto errout; 495*39d3e169Sevanl nargs->hostname = kmem_zalloc(hlen, KM_SLEEP); 496*39d3e169Sevanl (void) strcpy(nargs->hostname, netname); 497*39d3e169Sevanl 498*39d3e169Sevanl } else { 499*39d3e169Sevanl nargs->hostname = NULL; 500*39d3e169Sevanl } 501*39d3e169Sevanl 502*39d3e169Sevanl 503*39d3e169Sevanl /* 504*39d3e169Sevanl * If there are syncaddr and netname data, load them in. This is 505*39d3e169Sevanl * to support data needed for NFSV4 when AUTH_DH is the negotiated 506*39d3e169Sevanl * flavor via SECINFO. (instead of using MOUNT protocol in V3). 507*39d3e169Sevanl */ 508*39d3e169Sevanl netname[0] = '\0'; 509*39d3e169Sevanl if (flags & NFSMNT_SECURE) { 510*39d3e169Sevanl 511*39d3e169Sevanl /* get syncaddr */ 512*39d3e169Sevanl STRUCT_INIT(addr_tmp, get_udatamodel()); 513*39d3e169Sevanl if (copyin(STRUCT_FGETP(args, syncaddr), STRUCT_BUF(addr_tmp), 514*39d3e169Sevanl STRUCT_SIZE(addr_tmp))) { 515*39d3e169Sevanl error = EINVAL; 516*39d3e169Sevanl goto errout; 517*39d3e169Sevanl } 518*39d3e169Sevanl userbufptr = STRUCT_FGETP(addr_tmp, buf); 519*39d3e169Sevanl syncaddr.len = STRUCT_FGET(addr_tmp, len); 520*39d3e169Sevanl syncaddr.buf = kmem_alloc(syncaddr.len, KM_SLEEP); 521*39d3e169Sevanl syncaddr.maxlen = syncaddr.len; 522*39d3e169Sevanl if (copyin(userbufptr, syncaddr.buf, syncaddr.len)) { 523*39d3e169Sevanl kmem_free(syncaddr.buf, syncaddr.len); 524*39d3e169Sevanl error = EFAULT; 525*39d3e169Sevanl goto errout; 526*39d3e169Sevanl } 527*39d3e169Sevanl 528*39d3e169Sevanl nargs->syncaddr = kmem_alloc(sizeof (struct netbuf), KM_SLEEP); 529*39d3e169Sevanl bcopy(&syncaddr, nargs->syncaddr, sizeof (struct netbuf)); 530*39d3e169Sevanl } 531*39d3e169Sevanl /* get server's netname */ 532*39d3e169Sevanl if (copyinstr(STRUCT_FGETP(args, netname), netname, 533*39d3e169Sevanl sizeof (netname), &nlen)) { 534*39d3e169Sevanl error = EFAULT; 535*39d3e169Sevanl goto errout; 536*39d3e169Sevanl } 537*39d3e169Sevanl 538*39d3e169Sevanl netname[nlen] = '\0'; 539*39d3e169Sevanl nargs->netname = kmem_zalloc(nlen, KM_SLEEP); 540*39d3e169Sevanl (void) strcpy(nargs->netname, netname); 541*39d3e169Sevanl 542*39d3e169Sevanl /* 543*39d3e169Sevanl * Get the extention data which has the security data structure. 544*39d3e169Sevanl * This includes data for AUTH_SYS as well. 545*39d3e169Sevanl */ 546*39d3e169Sevanl if (flags & NFSMNT_NEWARGS) { 547*39d3e169Sevanl nargs->nfs_args_ext = STRUCT_FGET(args, nfs_args_ext); 548*39d3e169Sevanl if (nargs->nfs_args_ext == NFS_ARGS_EXTA || 549*39d3e169Sevanl nargs->nfs_args_ext == NFS_ARGS_EXTB) { 550*39d3e169Sevanl /* 551*39d3e169Sevanl * Indicating the application is using the new 552*39d3e169Sevanl * sec_data structure to pass in the security 553*39d3e169Sevanl * data. 554*39d3e169Sevanl */ 555*39d3e169Sevanl if (STRUCT_FGETP(args, 556*39d3e169Sevanl nfs_ext_u.nfs_extA.secdata) != NULL) { 557*39d3e169Sevanl error = sec_clnt_loadinfo( 558*39d3e169Sevanl (struct sec_data *)STRUCT_FGETP(args, 559*39d3e169Sevanl nfs_ext_u.nfs_extA.secdata), 560*39d3e169Sevanl &secdata, get_udatamodel()); 561*39d3e169Sevanl } 562*39d3e169Sevanl nargs->nfs_ext_u.nfs_extA.secdata = secdata; 563*39d3e169Sevanl } 564*39d3e169Sevanl } 565*39d3e169Sevanl 566*39d3e169Sevanl if (error) 567*39d3e169Sevanl goto errout; 568*39d3e169Sevanl 569*39d3e169Sevanl /* 570*39d3e169Sevanl * Failover support: 571*39d3e169Sevanl * 572*39d3e169Sevanl * We may have a linked list of nfs_args structures, 573*39d3e169Sevanl * which means the user is looking for failover. If 574*39d3e169Sevanl * the mount is either not "read-only" or "soft", 575*39d3e169Sevanl * we want to bail out with EINVAL. 576*39d3e169Sevanl */ 577*39d3e169Sevanl if (nargs->nfs_args_ext == NFS_ARGS_EXTB) 578*39d3e169Sevanl nargs->nfs_ext_u.nfs_extB.next = 579*39d3e169Sevanl STRUCT_FGETP(args, nfs_ext_u.nfs_extB.next); 580*39d3e169Sevanl 581*39d3e169Sevanl errout: 582*39d3e169Sevanl if (error) 583*39d3e169Sevanl nfs4_free_args(nargs); 584*39d3e169Sevanl 585*39d3e169Sevanl return (error); 586*39d3e169Sevanl } 587*39d3e169Sevanl 588*39d3e169Sevanl 5897c478bd9Sstevel@tonic-gate /* 5907c478bd9Sstevel@tonic-gate * nfs mount vfsop 5917c478bd9Sstevel@tonic-gate * Set up mount info record and attach it to vfs struct. 5927c478bd9Sstevel@tonic-gate */ 5937c478bd9Sstevel@tonic-gate static int 5947c478bd9Sstevel@tonic-gate nfs4_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) 5957c478bd9Sstevel@tonic-gate { 5967c478bd9Sstevel@tonic-gate char *data = uap->dataptr; 5977c478bd9Sstevel@tonic-gate int error; 5987c478bd9Sstevel@tonic-gate vnode_t *rtvp; /* the server's root */ 5997c478bd9Sstevel@tonic-gate mntinfo4_t *mi; /* mount info, pointed at by vfs */ 6007c478bd9Sstevel@tonic-gate struct knetconfig *rdma_knconf; /* rdma transport structure */ 6017c478bd9Sstevel@tonic-gate rnode4_t *rp; 6027c478bd9Sstevel@tonic-gate struct servinfo4 *svp; /* nfs server info */ 6037c478bd9Sstevel@tonic-gate struct servinfo4 *svp_tail = NULL; /* previous nfs server info */ 6047c478bd9Sstevel@tonic-gate struct servinfo4 *svp_head; /* first nfs server info */ 6057c478bd9Sstevel@tonic-gate struct servinfo4 *svp_2ndlast; /* 2nd last in server info list */ 6067c478bd9Sstevel@tonic-gate struct sec_data *secdata; /* security data */ 607*39d3e169Sevanl struct nfs_args *args = NULL; 60850a83466Sjwahlig int flags, addr_type, removed; 609108322fbScarlsonj zone_t *zone = nfs_zone(); 6107c478bd9Sstevel@tonic-gate nfs4_error_t n4e; 61145916cd2Sjpk zone_t *mntzone = NULL; 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate if (secpolicy_fs_mount(cr, mvp, vfsp) != 0) 6147c478bd9Sstevel@tonic-gate return (EPERM); 6157c478bd9Sstevel@tonic-gate if (mvp->v_type != VDIR) 6167c478bd9Sstevel@tonic-gate return (ENOTDIR); 6177c478bd9Sstevel@tonic-gate /* 6187c478bd9Sstevel@tonic-gate * get arguments 6197c478bd9Sstevel@tonic-gate * 6207c478bd9Sstevel@tonic-gate * nfs_args is now versioned and is extensible, so 6217c478bd9Sstevel@tonic-gate * uap->datalen might be different from sizeof (args) 6227c478bd9Sstevel@tonic-gate * in a compatible situation. 6237c478bd9Sstevel@tonic-gate */ 6247c478bd9Sstevel@tonic-gate more: 625*39d3e169Sevanl if (!(uap->flags & MS_SYSSPACE)) { 626*39d3e169Sevanl if (args == NULL) 627*39d3e169Sevanl args = kmem_zalloc(sizeof (struct nfs_args), KM_SLEEP); 628*39d3e169Sevanl else 629*39d3e169Sevanl nfs4_free_args(args); 630*39d3e169Sevanl error = nfs4_copyin(data, uap->datalen, args); 631*39d3e169Sevanl if (error) { 632*39d3e169Sevanl if (args) { 633*39d3e169Sevanl kmem_free(args, sizeof (*args)); 634*39d3e169Sevanl } 635*39d3e169Sevanl return (error); 636*39d3e169Sevanl } 637*39d3e169Sevanl } else { 638*39d3e169Sevanl args = (struct nfs_args *)data; 639*39d3e169Sevanl } 6407c478bd9Sstevel@tonic-gate 641*39d3e169Sevanl 642*39d3e169Sevanl flags = args->flags; 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate /* 6457c478bd9Sstevel@tonic-gate * If the request changes the locking type, disallow the remount, 6467c478bd9Sstevel@tonic-gate * because it's questionable whether we can transfer the 6477c478bd9Sstevel@tonic-gate * locking state correctly. 6487c478bd9Sstevel@tonic-gate */ 6497c478bd9Sstevel@tonic-gate if (uap->flags & MS_REMOUNT) { 650*39d3e169Sevanl if (!(uap->flags & MS_SYSSPACE)) { 651*39d3e169Sevanl nfs4_free_args(args); 652*39d3e169Sevanl kmem_free(args, sizeof (*args)); 653*39d3e169Sevanl } 6547c478bd9Sstevel@tonic-gate if ((mi = VFTOMI4(vfsp)) != NULL) { 6557c478bd9Sstevel@tonic-gate uint_t new_mi_llock; 6567c478bd9Sstevel@tonic-gate uint_t old_mi_llock; 6577c478bd9Sstevel@tonic-gate new_mi_llock = (flags & NFSMNT_LLOCK) ? 1 : 0; 6587c478bd9Sstevel@tonic-gate old_mi_llock = (mi->mi_flags & MI4_LLOCK) ? 1 : 0; 6597c478bd9Sstevel@tonic-gate if (old_mi_llock != new_mi_llock) 6607c478bd9Sstevel@tonic-gate return (EBUSY); 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate return (0); 6637c478bd9Sstevel@tonic-gate } 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate mutex_enter(&mvp->v_lock); 6667c478bd9Sstevel@tonic-gate if (!(uap->flags & MS_OVERLAY) && 6677c478bd9Sstevel@tonic-gate (mvp->v_count != 1 || (mvp->v_flag & VROOT))) { 6687c478bd9Sstevel@tonic-gate mutex_exit(&mvp->v_lock); 669*39d3e169Sevanl if (!(uap->flags & MS_SYSSPACE)) { 670*39d3e169Sevanl nfs4_free_args(args); 671*39d3e169Sevanl kmem_free(args, sizeof (*args)); 672*39d3e169Sevanl } 6737c478bd9Sstevel@tonic-gate return (EBUSY); 6747c478bd9Sstevel@tonic-gate } 6757c478bd9Sstevel@tonic-gate mutex_exit(&mvp->v_lock); 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate /* make sure things are zeroed for errout: */ 6787c478bd9Sstevel@tonic-gate rtvp = NULL; 6797c478bd9Sstevel@tonic-gate mi = NULL; 6807c478bd9Sstevel@tonic-gate secdata = NULL; 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate /* 6837c478bd9Sstevel@tonic-gate * A valid knetconfig structure is required. 6847c478bd9Sstevel@tonic-gate */ 685*39d3e169Sevanl 686*39d3e169Sevanl if (!(flags & NFSMNT_KNCONF) || 687*39d3e169Sevanl args->knconf == NULL || args->knconf->knc_protofmly == NULL || 688*39d3e169Sevanl args->knconf->knc_proto == NULL || 689*39d3e169Sevanl (strcmp(args->knconf->knc_proto, NC_UDP) == 0)) { 690*39d3e169Sevanl if (!(uap->flags & MS_SYSSPACE)) { 691*39d3e169Sevanl nfs4_free_args(args); 692*39d3e169Sevanl kmem_free(args, sizeof (*args)); 693*39d3e169Sevanl } 6947c478bd9Sstevel@tonic-gate return (EINVAL); 695*39d3e169Sevanl } 696*39d3e169Sevanl 697*39d3e169Sevanl if ((strlen(args->knconf->knc_protofmly) >= KNC_STRSIZE) || 698*39d3e169Sevanl (strlen(args->knconf->knc_proto) >= KNC_STRSIZE)) { 699*39d3e169Sevanl if (!(uap->flags & MS_SYSSPACE)) { 700*39d3e169Sevanl nfs4_free_args(args); 701*39d3e169Sevanl kmem_free(args, sizeof (*args)); 702*39d3e169Sevanl } 703*39d3e169Sevanl return (EINVAL); 704*39d3e169Sevanl } 705*39d3e169Sevanl 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate /* 7087c478bd9Sstevel@tonic-gate * Allocate a servinfo4 struct. 7097c478bd9Sstevel@tonic-gate */ 7107c478bd9Sstevel@tonic-gate svp = kmem_zalloc(sizeof (*svp), KM_SLEEP); 7117c478bd9Sstevel@tonic-gate nfs_rw_init(&svp->sv_lock, NULL, RW_DEFAULT, NULL); 7127c478bd9Sstevel@tonic-gate if (svp_tail) { 7137c478bd9Sstevel@tonic-gate svp_2ndlast = svp_tail; 7147c478bd9Sstevel@tonic-gate svp_tail->sv_next = svp; 7157c478bd9Sstevel@tonic-gate } else { 7167c478bd9Sstevel@tonic-gate svp_head = svp; 7177c478bd9Sstevel@tonic-gate svp_2ndlast = svp; 7187c478bd9Sstevel@tonic-gate } 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate svp_tail = svp; 721*39d3e169Sevanl svp->sv_knconf = args->knconf; 722*39d3e169Sevanl args->knconf = NULL; 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate /* 7267c478bd9Sstevel@tonic-gate * Get server address 7277c478bd9Sstevel@tonic-gate */ 7287c478bd9Sstevel@tonic-gate 729*39d3e169Sevanl if (args->addr == NULL || args->addr->buf == NULL) { 730*39d3e169Sevanl error = EINVAL; 7317c478bd9Sstevel@tonic-gate goto errout; 7327c478bd9Sstevel@tonic-gate } 7337c478bd9Sstevel@tonic-gate 734*39d3e169Sevanl svp->sv_addr.maxlen = args->addr->maxlen; 735*39d3e169Sevanl svp->sv_addr.len = args->addr->len; 736*39d3e169Sevanl svp->sv_addr.buf = args->addr->buf; 737*39d3e169Sevanl args->addr->buf = NULL; 738*39d3e169Sevanl 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate /* 7417c478bd9Sstevel@tonic-gate * Get the root fhandle 7427c478bd9Sstevel@tonic-gate */ 743*39d3e169Sevanl if (args->fh == NULL || (strlen(args->fh) >= MAXPATHLEN)) { 744*39d3e169Sevanl error = EINVAL; 7457c478bd9Sstevel@tonic-gate goto errout; 746*39d3e169Sevanl } 7477c478bd9Sstevel@tonic-gate 748*39d3e169Sevanl svp->sv_path = args->fh; 749*39d3e169Sevanl svp->sv_pathlen = strlen(args->fh) + 1; 750*39d3e169Sevanl args->fh = NULL; 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate /* 7537c478bd9Sstevel@tonic-gate * Get server's hostname 7547c478bd9Sstevel@tonic-gate */ 7557c478bd9Sstevel@tonic-gate if (flags & NFSMNT_HOSTNAME) { 756*39d3e169Sevanl if (args->hostname == NULL || (strlen(args->hostname) > 757*39d3e169Sevanl MAXNETNAMELEN)) { 758*39d3e169Sevanl error = EINVAL; 7597c478bd9Sstevel@tonic-gate goto errout; 760*39d3e169Sevanl } 761*39d3e169Sevanl svp->sv_hostnamelen = strlen(args->hostname) + 1; 762*39d3e169Sevanl svp->sv_hostname = args->hostname; 763*39d3e169Sevanl args->hostname = NULL; 7647c478bd9Sstevel@tonic-gate } else { 7657c478bd9Sstevel@tonic-gate char *p = "unknown-host"; 766*39d3e169Sevanl svp->sv_hostnamelen = strlen(p) + 1; 767*39d3e169Sevanl svp->sv_hostname = kmem_zalloc(svp->sv_hostnamelen, KM_SLEEP); 768*39d3e169Sevanl (void) strcpy(svp->sv_hostname, p); 7697c478bd9Sstevel@tonic-gate } 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate /* 7727c478bd9Sstevel@tonic-gate * RDMA MOUNT SUPPORT FOR NFS v4. 7737c478bd9Sstevel@tonic-gate * Establish, is it possible to use RDMA, if so overload the 7747c478bd9Sstevel@tonic-gate * knconf with rdma specific knconf and free the orignal knconf. 7757c478bd9Sstevel@tonic-gate */ 7767c478bd9Sstevel@tonic-gate if ((flags & NFSMNT_TRYRDMA) || (flags & NFSMNT_DORDMA)) { 7777c478bd9Sstevel@tonic-gate /* 7787c478bd9Sstevel@tonic-gate * Determine the addr type for RDMA, IPv4 or v6. 7797c478bd9Sstevel@tonic-gate */ 7807c478bd9Sstevel@tonic-gate if (strcmp(svp->sv_knconf->knc_protofmly, NC_INET) == 0) 7817c478bd9Sstevel@tonic-gate addr_type = AF_INET; 7827c478bd9Sstevel@tonic-gate else if (strcmp(svp->sv_knconf->knc_protofmly, NC_INET6) == 0) 7837c478bd9Sstevel@tonic-gate addr_type = AF_INET6; 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate if (rdma_reachable(addr_type, &svp->sv_addr, 7867c478bd9Sstevel@tonic-gate &rdma_knconf) == 0) { 7877c478bd9Sstevel@tonic-gate /* 7887c478bd9Sstevel@tonic-gate * If successful, hijack the orignal knconf and 7897c478bd9Sstevel@tonic-gate * replace with the new one, depending on the flags. 7907c478bd9Sstevel@tonic-gate */ 7917c478bd9Sstevel@tonic-gate svp->sv_origknconf = svp->sv_knconf; 7927c478bd9Sstevel@tonic-gate svp->sv_knconf = rdma_knconf; 7937c478bd9Sstevel@tonic-gate } else { 7947c478bd9Sstevel@tonic-gate if (flags & NFSMNT_TRYRDMA) { 7957c478bd9Sstevel@tonic-gate #ifdef DEBUG 7967c478bd9Sstevel@tonic-gate if (rdma_debug) 7977c478bd9Sstevel@tonic-gate zcmn_err(getzoneid(), CE_WARN, 7987c478bd9Sstevel@tonic-gate "no RDMA onboard, revert\n"); 7997c478bd9Sstevel@tonic-gate #endif 8007c478bd9Sstevel@tonic-gate } 8017c478bd9Sstevel@tonic-gate 8027c478bd9Sstevel@tonic-gate if (flags & NFSMNT_DORDMA) { 8037c478bd9Sstevel@tonic-gate /* 8047c478bd9Sstevel@tonic-gate * If proto=rdma is specified and no RDMA 8057c478bd9Sstevel@tonic-gate * path to this server is avialable then 8067c478bd9Sstevel@tonic-gate * ditch this server. 8077c478bd9Sstevel@tonic-gate * This is not included in the mountable 8087c478bd9Sstevel@tonic-gate * server list or the replica list. 8097c478bd9Sstevel@tonic-gate * Check if more servers are specified; 8107c478bd9Sstevel@tonic-gate * Failover case, otherwise bail out of mount. 8117c478bd9Sstevel@tonic-gate */ 812*39d3e169Sevanl if (args->nfs_args_ext == 813*39d3e169Sevanl NFS_ARGS_EXTB && 814*39d3e169Sevanl args->nfs_ext_u.nfs_extB.next 815*39d3e169Sevanl != NULL) { 816*39d3e169Sevanl data = (char *) 817*39d3e169Sevanl args->nfs_ext_u.nfs_extB.next; 8187c478bd9Sstevel@tonic-gate if (uap->flags & MS_RDONLY && 8197c478bd9Sstevel@tonic-gate !(flags & NFSMNT_SOFT)) { 8207c478bd9Sstevel@tonic-gate if (svp_head->sv_next == NULL) { 8217c478bd9Sstevel@tonic-gate svp_tail = NULL; 8227c478bd9Sstevel@tonic-gate svp_2ndlast = NULL; 8237c478bd9Sstevel@tonic-gate sv4_free(svp_head); 8247c478bd9Sstevel@tonic-gate goto more; 8257c478bd9Sstevel@tonic-gate } else { 8267c478bd9Sstevel@tonic-gate svp_tail = svp_2ndlast; 8277c478bd9Sstevel@tonic-gate svp_2ndlast->sv_next = 8287c478bd9Sstevel@tonic-gate NULL; 8297c478bd9Sstevel@tonic-gate sv4_free(svp); 8307c478bd9Sstevel@tonic-gate goto more; 8317c478bd9Sstevel@tonic-gate } 8327c478bd9Sstevel@tonic-gate } 8337c478bd9Sstevel@tonic-gate } else { 8347c478bd9Sstevel@tonic-gate /* 8357c478bd9Sstevel@tonic-gate * This is the last server specified 8367c478bd9Sstevel@tonic-gate * in the nfs_args list passed down 8377c478bd9Sstevel@tonic-gate * and its not rdma capable. 8387c478bd9Sstevel@tonic-gate */ 8397c478bd9Sstevel@tonic-gate if (svp_head->sv_next == NULL) { 8407c478bd9Sstevel@tonic-gate /* 8417c478bd9Sstevel@tonic-gate * Is this the only one 8427c478bd9Sstevel@tonic-gate */ 8437c478bd9Sstevel@tonic-gate error = EINVAL; 8447c478bd9Sstevel@tonic-gate #ifdef DEBUG 8457c478bd9Sstevel@tonic-gate if (rdma_debug) 8467c478bd9Sstevel@tonic-gate zcmn_err(getzoneid(), 8477c478bd9Sstevel@tonic-gate CE_WARN, 8487c478bd9Sstevel@tonic-gate "No RDMA srv"); 8497c478bd9Sstevel@tonic-gate #endif 8507c478bd9Sstevel@tonic-gate goto errout; 8517c478bd9Sstevel@tonic-gate } else { 8527c478bd9Sstevel@tonic-gate /* 8537c478bd9Sstevel@tonic-gate * There is list, since some 8547c478bd9Sstevel@tonic-gate * servers specified before 8557c478bd9Sstevel@tonic-gate * this passed all requirements 8567c478bd9Sstevel@tonic-gate */ 8577c478bd9Sstevel@tonic-gate svp_tail = svp_2ndlast; 8587c478bd9Sstevel@tonic-gate svp_2ndlast->sv_next = NULL; 8597c478bd9Sstevel@tonic-gate sv4_free(svp); 8607c478bd9Sstevel@tonic-gate goto proceed; 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate } 8647c478bd9Sstevel@tonic-gate } 8657c478bd9Sstevel@tonic-gate } 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate /* 8687c478bd9Sstevel@tonic-gate * If there are syncaddr and netname data, load them in. This is 8697c478bd9Sstevel@tonic-gate * to support data needed for NFSV4 when AUTH_DH is the negotiated 8707c478bd9Sstevel@tonic-gate * flavor via SECINFO. (instead of using MOUNT protocol in V3). 8717c478bd9Sstevel@tonic-gate */ 872*39d3e169Sevanl if (args->flags & NFSMNT_SECURE) { 873*39d3e169Sevanl svp->sv_dhsec = create_authdh_data(args->netname, 874*39d3e169Sevanl strlen(args->netname), 875*39d3e169Sevanl args->syncaddr, svp->sv_knconf); 8767c478bd9Sstevel@tonic-gate } 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate /* 8797c478bd9Sstevel@tonic-gate * Get the extention data which has the security data structure. 8807c478bd9Sstevel@tonic-gate * This includes data for AUTH_SYS as well. 8817c478bd9Sstevel@tonic-gate */ 8827c478bd9Sstevel@tonic-gate if (flags & NFSMNT_NEWARGS) { 883*39d3e169Sevanl switch (args->nfs_args_ext) { 8847c478bd9Sstevel@tonic-gate case NFS_ARGS_EXTA: 8857c478bd9Sstevel@tonic-gate case NFS_ARGS_EXTB: 8867c478bd9Sstevel@tonic-gate /* 8877c478bd9Sstevel@tonic-gate * Indicating the application is using the new 8887c478bd9Sstevel@tonic-gate * sec_data structure to pass in the security 8897c478bd9Sstevel@tonic-gate * data. 8907c478bd9Sstevel@tonic-gate */ 891*39d3e169Sevanl secdata = args->nfs_ext_u.nfs_extA.secdata; 892*39d3e169Sevanl if (secdata == NULL) { 8937c478bd9Sstevel@tonic-gate error = EINVAL; 894*39d3e169Sevanl } else if (uap->flags & MS_SYSSPACE) { 895*39d3e169Sevanl /* 896*39d3e169Sevanl * Need to validate the flavor here if 897*39d3e169Sevanl * sysspace, userspace was already 898*39d3e169Sevanl * validate from the nfs_copyin function. 899*39d3e169Sevanl */ 900*39d3e169Sevanl switch (secdata->rpcflavor) { 901*39d3e169Sevanl case AUTH_NONE: 902*39d3e169Sevanl case AUTH_UNIX: 903*39d3e169Sevanl case AUTH_LOOPBACK: 904*39d3e169Sevanl case AUTH_DES: 905*39d3e169Sevanl case RPCSEC_GSS: 906*39d3e169Sevanl break; 907*39d3e169Sevanl default: 908*39d3e169Sevanl error = EINVAL; 909*39d3e169Sevanl goto errout; 910*39d3e169Sevanl } 9117c478bd9Sstevel@tonic-gate } 912*39d3e169Sevanl args->nfs_ext_u.nfs_extA.secdata = NULL; 9137c478bd9Sstevel@tonic-gate break; 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate default: 9167c478bd9Sstevel@tonic-gate error = EINVAL; 9177c478bd9Sstevel@tonic-gate break; 9187c478bd9Sstevel@tonic-gate } 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate } else if (flags & NFSMNT_SECURE) { 9217c478bd9Sstevel@tonic-gate /* 9227c478bd9Sstevel@tonic-gate * NFSMNT_SECURE is deprecated but we keep it 9237c478bd9Sstevel@tonic-gate * to support the rouge user generated application 9247c478bd9Sstevel@tonic-gate * that may use this undocumented interface to do 9257c478bd9Sstevel@tonic-gate * AUTH_DH security. 9267c478bd9Sstevel@tonic-gate */ 927*39d3e169Sevanl secdata = create_authdh_data(args->netname, 928*39d3e169Sevanl strlen(args->netname), args->syncaddr, svp->sv_knconf); 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate } else { 9317c478bd9Sstevel@tonic-gate secdata = kmem_alloc(sizeof (*secdata), KM_SLEEP); 9327c478bd9Sstevel@tonic-gate secdata->secmod = secdata->rpcflavor = AUTH_SYS; 9337c478bd9Sstevel@tonic-gate secdata->data = NULL; 9347c478bd9Sstevel@tonic-gate } 9357c478bd9Sstevel@tonic-gate 9367c478bd9Sstevel@tonic-gate svp->sv_secdata = secdata; 9377c478bd9Sstevel@tonic-gate 9387c478bd9Sstevel@tonic-gate /* 9397c478bd9Sstevel@tonic-gate * User does not explictly specify a flavor, and a user 9407c478bd9Sstevel@tonic-gate * defined default flavor is passed down. 9417c478bd9Sstevel@tonic-gate */ 9427c478bd9Sstevel@tonic-gate if (flags & NFSMNT_SECDEFAULT) { 9437c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 9447c478bd9Sstevel@tonic-gate svp->sv_flags |= SV4_TRYSECDEFAULT; 9457c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 9467c478bd9Sstevel@tonic-gate } 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate /* 9497c478bd9Sstevel@tonic-gate * Failover support: 9507c478bd9Sstevel@tonic-gate * 9517c478bd9Sstevel@tonic-gate * We may have a linked list of nfs_args structures, 9527c478bd9Sstevel@tonic-gate * which means the user is looking for failover. If 9537c478bd9Sstevel@tonic-gate * the mount is either not "read-only" or "soft", 9547c478bd9Sstevel@tonic-gate * we want to bail out with EINVAL. 9557c478bd9Sstevel@tonic-gate */ 956*39d3e169Sevanl if (args->nfs_args_ext == NFS_ARGS_EXTB && 957*39d3e169Sevanl args->nfs_ext_u.nfs_extB.next != NULL) { 9587c478bd9Sstevel@tonic-gate if (uap->flags & MS_RDONLY && !(flags & NFSMNT_SOFT)) { 959*39d3e169Sevanl data = (char *)args->nfs_ext_u.nfs_extB.next; 9607c478bd9Sstevel@tonic-gate goto more; 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate error = EINVAL; 9637c478bd9Sstevel@tonic-gate goto errout; 9647c478bd9Sstevel@tonic-gate } 9657c478bd9Sstevel@tonic-gate 9667c478bd9Sstevel@tonic-gate /* 9677c478bd9Sstevel@tonic-gate * Determine the zone we're being mounted into. 9687c478bd9Sstevel@tonic-gate */ 96945916cd2Sjpk zone_hold(mntzone = zone); /* start with this assumption */ 9707c478bd9Sstevel@tonic-gate if (getzoneid() == GLOBAL_ZONEID) { 97145916cd2Sjpk zone_rele(mntzone); 9727c478bd9Sstevel@tonic-gate mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt)); 9737c478bd9Sstevel@tonic-gate ASSERT(mntzone != NULL); 9747c478bd9Sstevel@tonic-gate if (mntzone != zone) { 9757c478bd9Sstevel@tonic-gate error = EBUSY; 9767c478bd9Sstevel@tonic-gate goto errout; 9777c478bd9Sstevel@tonic-gate } 9787c478bd9Sstevel@tonic-gate } 9797c478bd9Sstevel@tonic-gate 98045916cd2Sjpk if (is_system_labeled()) { 98145916cd2Sjpk error = nfs_mount_label_policy(vfsp, &svp->sv_addr, 98245916cd2Sjpk svp->sv_knconf, cr); 98345916cd2Sjpk 98445916cd2Sjpk if (error > 0) 98545916cd2Sjpk goto errout; 98645916cd2Sjpk 98745916cd2Sjpk if (error == -1) { 98845916cd2Sjpk /* change mount to read-only to prevent write-down */ 98945916cd2Sjpk vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); 99045916cd2Sjpk } 99145916cd2Sjpk } 99245916cd2Sjpk 9937c478bd9Sstevel@tonic-gate /* 9947c478bd9Sstevel@tonic-gate * Stop the mount from going any further if the zone is going away. 9957c478bd9Sstevel@tonic-gate */ 99645916cd2Sjpk if (zone_status_get(mntzone) >= ZONE_IS_SHUTTING_DOWN) { 9977c478bd9Sstevel@tonic-gate error = EBUSY; 9987c478bd9Sstevel@tonic-gate goto errout; 9997c478bd9Sstevel@tonic-gate } 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate /* 10027c478bd9Sstevel@tonic-gate * Get root vnode. 10037c478bd9Sstevel@tonic-gate */ 10047c478bd9Sstevel@tonic-gate proceed: 100545916cd2Sjpk error = nfs4rootvp(&rtvp, vfsp, svp_head, flags, cr, mntzone); 10067c478bd9Sstevel@tonic-gate 100750a83466Sjwahlig if (error) { 100850a83466Sjwahlig /* if nfs4rootvp failed, it will free svp_head */ 100950a83466Sjwahlig svp_head = NULL; 10107c478bd9Sstevel@tonic-gate goto errout; 101150a83466Sjwahlig } 10127c478bd9Sstevel@tonic-gate 10137c478bd9Sstevel@tonic-gate mi = VTOMI4(rtvp); 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate /* 10167c478bd9Sstevel@tonic-gate * Send client id to the server, if necessary 10177c478bd9Sstevel@tonic-gate */ 10187c478bd9Sstevel@tonic-gate nfs4_error_zinit(&n4e); 10197c478bd9Sstevel@tonic-gate nfs4setclientid(mi, cr, FALSE, &n4e); 10207c478bd9Sstevel@tonic-gate error = n4e.error; 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate if (error) 10237c478bd9Sstevel@tonic-gate goto errout; 10247c478bd9Sstevel@tonic-gate 10257c478bd9Sstevel@tonic-gate /* 10267c478bd9Sstevel@tonic-gate * Set option fields in the mount info record 10277c478bd9Sstevel@tonic-gate */ 10287c478bd9Sstevel@tonic-gate 10297c478bd9Sstevel@tonic-gate if (svp_head->sv_next) { 10307c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 10317c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_LLOCK; 10327c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 10337c478bd9Sstevel@tonic-gate } 1034*39d3e169Sevanl error = nfs4_setopts(rtvp, DATAMODEL_NATIVE, args); 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate errout: 10377c478bd9Sstevel@tonic-gate if (error) { 10387c478bd9Sstevel@tonic-gate if (rtvp != NULL) { 10397c478bd9Sstevel@tonic-gate rp = VTOR4(rtvp); 10407c478bd9Sstevel@tonic-gate if (rp->r_flags & R4HASHED) 10417c478bd9Sstevel@tonic-gate rp4_rmhash(rp); 10427c478bd9Sstevel@tonic-gate } 10437c478bd9Sstevel@tonic-gate if (mi != NULL) { 10447c478bd9Sstevel@tonic-gate nfs4_async_stop(vfsp); 10457c478bd9Sstevel@tonic-gate nfs4_async_manager_stop(vfsp); 10467c478bd9Sstevel@tonic-gate nfs4_remove_mi_from_server(mi, NULL); 104750a83466Sjwahlig if (rtvp != NULL) 10487c478bd9Sstevel@tonic-gate VN_RELE(rtvp); 104945916cd2Sjpk if (mntzone != NULL) 105045916cd2Sjpk zone_rele(mntzone); 105150a83466Sjwahlig /* need to remove it from the zone */ 105250a83466Sjwahlig removed = nfs4_mi_zonelist_remove(mi); 105350a83466Sjwahlig if (removed) 105450a83466Sjwahlig zone_rele(mi->mi_zone); 105550a83466Sjwahlig MI4_RELE(mi); 1056*39d3e169Sevanl if (!(uap->flags & MS_SYSSPACE) && args) { 1057*39d3e169Sevanl nfs4_free_args(args); 1058*39d3e169Sevanl kmem_free(args, sizeof (*args)); 1059*39d3e169Sevanl } 10607c478bd9Sstevel@tonic-gate return (error); 10617c478bd9Sstevel@tonic-gate } 106250a83466Sjwahlig if (svp_head) 106350a83466Sjwahlig sv4_free(svp_head); 10647c478bd9Sstevel@tonic-gate } 10657c478bd9Sstevel@tonic-gate 1066*39d3e169Sevanl if (!(uap->flags & MS_SYSSPACE) && args) { 1067*39d3e169Sevanl nfs4_free_args(args); 1068*39d3e169Sevanl kmem_free(args, sizeof (*args)); 1069*39d3e169Sevanl } 10707c478bd9Sstevel@tonic-gate if (rtvp != NULL) 10717c478bd9Sstevel@tonic-gate VN_RELE(rtvp); 10727c478bd9Sstevel@tonic-gate 107345916cd2Sjpk if (mntzone != NULL) 107445916cd2Sjpk zone_rele(mntzone); 107545916cd2Sjpk 10767c478bd9Sstevel@tonic-gate return (error); 10777c478bd9Sstevel@tonic-gate } 10787c478bd9Sstevel@tonic-gate 1079*39d3e169Sevanl #ifdef DEBUG 10807c478bd9Sstevel@tonic-gate #define VERS_MSG "NFS4 server " 10817c478bd9Sstevel@tonic-gate #else 10827c478bd9Sstevel@tonic-gate #define VERS_MSG "NFS server " 10837c478bd9Sstevel@tonic-gate #endif 10847c478bd9Sstevel@tonic-gate 1085*39d3e169Sevanl #define READ_MSG \ 10867c478bd9Sstevel@tonic-gate VERS_MSG "%s returned 0 for read transfer size" 1087*39d3e169Sevanl #define WRITE_MSG \ 10887c478bd9Sstevel@tonic-gate VERS_MSG "%s returned 0 for write transfer size" 1089*39d3e169Sevanl #define SIZE_MSG \ 10907c478bd9Sstevel@tonic-gate VERS_MSG "%s returned 0 for maximum file size" 10917c478bd9Sstevel@tonic-gate 10927c478bd9Sstevel@tonic-gate /* 10937c478bd9Sstevel@tonic-gate * Get the symbolic link text from the server for a given filehandle 10947c478bd9Sstevel@tonic-gate * of that symlink. 10957c478bd9Sstevel@tonic-gate * 1096*39d3e169Sevanl * (get symlink text) PUTFH READLINK 10977c478bd9Sstevel@tonic-gate */ 10987c478bd9Sstevel@tonic-gate static int 10997c478bd9Sstevel@tonic-gate getlinktext_otw(mntinfo4_t *mi, nfs_fh4 *fh, char **linktextp, cred_t *cr, 1100*39d3e169Sevanl int flags) 1101*39d3e169Sevanl 11027c478bd9Sstevel@tonic-gate { 11037c478bd9Sstevel@tonic-gate COMPOUND4args_clnt args; 11047c478bd9Sstevel@tonic-gate COMPOUND4res_clnt res; 11057c478bd9Sstevel@tonic-gate int doqueue; 11067c478bd9Sstevel@tonic-gate nfs_argop4 argop[2]; 11077c478bd9Sstevel@tonic-gate nfs_resop4 *resop; 11087c478bd9Sstevel@tonic-gate READLINK4res *lr_res; 11097c478bd9Sstevel@tonic-gate uint_t len; 11107c478bd9Sstevel@tonic-gate bool_t needrecov = FALSE; 11117c478bd9Sstevel@tonic-gate nfs4_recov_state_t recov_state; 11127c478bd9Sstevel@tonic-gate nfs4_sharedfh_t *sfh; 11137c478bd9Sstevel@tonic-gate nfs4_error_t e; 11147c478bd9Sstevel@tonic-gate int num_retry = nfs4_max_mount_retry; 11157c478bd9Sstevel@tonic-gate int recovery = !(flags & NFS4_GETFH_NEEDSOP); 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate sfh = sfh4_get(fh, mi); 11187c478bd9Sstevel@tonic-gate recov_state.rs_flags = 0; 11197c478bd9Sstevel@tonic-gate recov_state.rs_num_retry_despite_err = 0; 11207c478bd9Sstevel@tonic-gate 11217c478bd9Sstevel@tonic-gate recov_retry: 11227c478bd9Sstevel@tonic-gate nfs4_error_zinit(&e); 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate args.array_len = 2; 11257c478bd9Sstevel@tonic-gate args.array = argop; 11267c478bd9Sstevel@tonic-gate args.ctag = TAG_GET_SYMLINK; 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate if (! recovery) { 11297c478bd9Sstevel@tonic-gate e.error = nfs4_start_op(mi, NULL, NULL, &recov_state); 11307c478bd9Sstevel@tonic-gate if (e.error) { 11317c478bd9Sstevel@tonic-gate sfh4_rele(&sfh); 11327c478bd9Sstevel@tonic-gate return (e.error); 11337c478bd9Sstevel@tonic-gate } 11347c478bd9Sstevel@tonic-gate } 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate /* 0. putfh symlink fh */ 11377c478bd9Sstevel@tonic-gate argop[0].argop = OP_CPUTFH; 11387c478bd9Sstevel@tonic-gate argop[0].nfs_argop4_u.opcputfh.sfh = sfh; 11397c478bd9Sstevel@tonic-gate 11407c478bd9Sstevel@tonic-gate /* 1. readlink */ 11417c478bd9Sstevel@tonic-gate argop[1].argop = OP_READLINK; 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate doqueue = 1; 11447c478bd9Sstevel@tonic-gate 11457c478bd9Sstevel@tonic-gate rfs4call(mi, &args, &res, cr, &doqueue, 0, &e); 11467c478bd9Sstevel@tonic-gate 11477c478bd9Sstevel@tonic-gate needrecov = nfs4_needs_recovery(&e, FALSE, mi->mi_vfsp); 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate if (needrecov && !recovery && num_retry-- > 0) { 11507c478bd9Sstevel@tonic-gate 11517c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE, 1152*39d3e169Sevanl "getlinktext_otw: initiating recovery\n")); 11537c478bd9Sstevel@tonic-gate 11547c478bd9Sstevel@tonic-gate if (nfs4_start_recovery(&e, mi, NULL, NULL, NULL, NULL, 1155*39d3e169Sevanl OP_READLINK, NULL) == FALSE) { 1156*39d3e169Sevanl nfs4_end_op(mi, NULL, NULL, &recov_state, needrecov); 1157*39d3e169Sevanl if (!e.error) 1158*39d3e169Sevanl (void) xdr_free(xdr_COMPOUND4res_clnt, 1159*39d3e169Sevanl (caddr_t)&res); 11607c478bd9Sstevel@tonic-gate goto recov_retry; 11617c478bd9Sstevel@tonic-gate } 11627c478bd9Sstevel@tonic-gate } 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate /* 11657c478bd9Sstevel@tonic-gate * If non-NFS4 pcol error and/or we weren't able to recover. 11667c478bd9Sstevel@tonic-gate */ 11677c478bd9Sstevel@tonic-gate if (e.error != 0) { 11687c478bd9Sstevel@tonic-gate if (! recovery) 11697c478bd9Sstevel@tonic-gate nfs4_end_op(mi, NULL, NULL, &recov_state, needrecov); 11707c478bd9Sstevel@tonic-gate sfh4_rele(&sfh); 11717c478bd9Sstevel@tonic-gate return (e.error); 11727c478bd9Sstevel@tonic-gate } 11737c478bd9Sstevel@tonic-gate 11747c478bd9Sstevel@tonic-gate if (res.status) { 11757c478bd9Sstevel@tonic-gate e.error = geterrno4(res.status); 11767c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 11777c478bd9Sstevel@tonic-gate if (! recovery) 11787c478bd9Sstevel@tonic-gate nfs4_end_op(mi, NULL, NULL, &recov_state, needrecov); 11797c478bd9Sstevel@tonic-gate sfh4_rele(&sfh); 11807c478bd9Sstevel@tonic-gate return (e.error); 11817c478bd9Sstevel@tonic-gate } 11827c478bd9Sstevel@tonic-gate 11837c478bd9Sstevel@tonic-gate /* res.status == NFS4_OK */ 11847c478bd9Sstevel@tonic-gate ASSERT(res.status == NFS4_OK); 11857c478bd9Sstevel@tonic-gate 1186*39d3e169Sevanl resop = &res.array[1]; /* readlink res */ 11877c478bd9Sstevel@tonic-gate lr_res = &resop->nfs_resop4_u.opreadlink; 11887c478bd9Sstevel@tonic-gate 11897c478bd9Sstevel@tonic-gate /* treat symlink name as data */ 11907c478bd9Sstevel@tonic-gate *linktextp = utf8_to_str(&lr_res->link, &len, NULL); 11917c478bd9Sstevel@tonic-gate 11927c478bd9Sstevel@tonic-gate if (! recovery) 11937c478bd9Sstevel@tonic-gate nfs4_end_op(mi, NULL, NULL, &recov_state, needrecov); 11947c478bd9Sstevel@tonic-gate sfh4_rele(&sfh); 11957c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 11967c478bd9Sstevel@tonic-gate return (0); 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate /* 12007c478bd9Sstevel@tonic-gate * Skip over consecutive slashes and "/./" in a pathname. 12017c478bd9Sstevel@tonic-gate */ 12027c478bd9Sstevel@tonic-gate void 12037c478bd9Sstevel@tonic-gate pathname_skipslashdot(struct pathname *pnp) 12047c478bd9Sstevel@tonic-gate { 12057c478bd9Sstevel@tonic-gate char *c1, *c2; 12067c478bd9Sstevel@tonic-gate 12077c478bd9Sstevel@tonic-gate while (pnp->pn_pathlen > 0 && *pnp->pn_path == '/') { 12087c478bd9Sstevel@tonic-gate 12097c478bd9Sstevel@tonic-gate c1 = pnp->pn_path + 1; 12107c478bd9Sstevel@tonic-gate c2 = pnp->pn_path + 2; 12117c478bd9Sstevel@tonic-gate 12127c478bd9Sstevel@tonic-gate if (*c1 == '.' && (*c2 == '/' || *c2 == '\0')) { 12137c478bd9Sstevel@tonic-gate pnp->pn_path = pnp->pn_path + 2; /* skip "/." */ 12147c478bd9Sstevel@tonic-gate pnp->pn_pathlen = pnp->pn_pathlen - 2; 12157c478bd9Sstevel@tonic-gate } else { 12167c478bd9Sstevel@tonic-gate pnp->pn_path++; 12177c478bd9Sstevel@tonic-gate pnp->pn_pathlen--; 12187c478bd9Sstevel@tonic-gate } 12197c478bd9Sstevel@tonic-gate } 12207c478bd9Sstevel@tonic-gate } 12217c478bd9Sstevel@tonic-gate 12227c478bd9Sstevel@tonic-gate /* 12237c478bd9Sstevel@tonic-gate * Resolve a symbolic link path. The symlink is in the nth component of 12247c478bd9Sstevel@tonic-gate * svp->sv_path and has an nfs4 file handle "fh". 12257c478bd9Sstevel@tonic-gate * Upon return, the sv_path will point to the new path that has the nth 12267c478bd9Sstevel@tonic-gate * component resolved to its symlink text. 12277c478bd9Sstevel@tonic-gate */ 12287c478bd9Sstevel@tonic-gate int 12297c478bd9Sstevel@tonic-gate resolve_sympath(mntinfo4_t *mi, servinfo4_t *svp, int nth, nfs_fh4 *fh, 12307c478bd9Sstevel@tonic-gate cred_t *cr, int flags) 12317c478bd9Sstevel@tonic-gate { 12327c478bd9Sstevel@tonic-gate char *oldpath; 12337c478bd9Sstevel@tonic-gate char *symlink, *newpath; 12347c478bd9Sstevel@tonic-gate struct pathname oldpn, newpn; 12357c478bd9Sstevel@tonic-gate char component[MAXNAMELEN]; 12367c478bd9Sstevel@tonic-gate int i, addlen, error = 0; 12377c478bd9Sstevel@tonic-gate int oldpathlen; 12387c478bd9Sstevel@tonic-gate 12397c478bd9Sstevel@tonic-gate /* Get the symbolic link text over the wire. */ 12407c478bd9Sstevel@tonic-gate error = getlinktext_otw(mi, fh, &symlink, cr, flags); 12417c478bd9Sstevel@tonic-gate 12427c478bd9Sstevel@tonic-gate if (error || symlink == NULL || strlen(symlink) == 0) 12437c478bd9Sstevel@tonic-gate return (error); 12447c478bd9Sstevel@tonic-gate 12457c478bd9Sstevel@tonic-gate /* 12467c478bd9Sstevel@tonic-gate * Compose the new pathname. 12477c478bd9Sstevel@tonic-gate * Note: 12487c478bd9Sstevel@tonic-gate * - only the nth component is resolved for the pathname. 12497c478bd9Sstevel@tonic-gate * - pathname.pn_pathlen does not count the ending null byte. 12507c478bd9Sstevel@tonic-gate */ 12517c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 12527c478bd9Sstevel@tonic-gate oldpath = svp->sv_path; 12537c478bd9Sstevel@tonic-gate oldpathlen = svp->sv_pathlen; 12547c478bd9Sstevel@tonic-gate if (error = pn_get(oldpath, UIO_SYSSPACE, &oldpn)) { 12557c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 12567c478bd9Sstevel@tonic-gate kmem_free(symlink, strlen(symlink) + 1); 12577c478bd9Sstevel@tonic-gate return (error); 12587c478bd9Sstevel@tonic-gate } 12597c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 12607c478bd9Sstevel@tonic-gate pn_alloc(&newpn); 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate /* 12637c478bd9Sstevel@tonic-gate * Skip over previous components from the oldpath so that the 12647c478bd9Sstevel@tonic-gate * oldpn.pn_path will point to the symlink component. Skip 12657c478bd9Sstevel@tonic-gate * leading slashes and "/./" (no OP_LOOKUP on ".") so that 12667c478bd9Sstevel@tonic-gate * pn_getcompnent can get the component. 12677c478bd9Sstevel@tonic-gate */ 12687c478bd9Sstevel@tonic-gate for (i = 1; i < nth; i++) { 12697c478bd9Sstevel@tonic-gate pathname_skipslashdot(&oldpn); 12707c478bd9Sstevel@tonic-gate error = pn_getcomponent(&oldpn, component); 12717c478bd9Sstevel@tonic-gate if (error) 12727c478bd9Sstevel@tonic-gate goto out; 12737c478bd9Sstevel@tonic-gate } 12747c478bd9Sstevel@tonic-gate 12757c478bd9Sstevel@tonic-gate /* 12767c478bd9Sstevel@tonic-gate * Copy the old path upto the component right before the symlink 12777c478bd9Sstevel@tonic-gate * if the symlink is not an absolute path. 12787c478bd9Sstevel@tonic-gate */ 12797c478bd9Sstevel@tonic-gate if (symlink[0] != '/') { 12807c478bd9Sstevel@tonic-gate addlen = oldpn.pn_path - oldpn.pn_buf; 12817c478bd9Sstevel@tonic-gate bcopy(oldpn.pn_buf, newpn.pn_path, addlen); 12827c478bd9Sstevel@tonic-gate newpn.pn_pathlen += addlen; 12837c478bd9Sstevel@tonic-gate newpn.pn_path += addlen; 12847c478bd9Sstevel@tonic-gate newpn.pn_buf[newpn.pn_pathlen] = '/'; 12857c478bd9Sstevel@tonic-gate newpn.pn_pathlen++; 12867c478bd9Sstevel@tonic-gate newpn.pn_path++; 12877c478bd9Sstevel@tonic-gate } 12887c478bd9Sstevel@tonic-gate 12897c478bd9Sstevel@tonic-gate /* copy the resolved symbolic link text */ 12907c478bd9Sstevel@tonic-gate addlen = strlen(symlink); 12917c478bd9Sstevel@tonic-gate if (newpn.pn_pathlen + addlen >= newpn.pn_bufsize) { 12927c478bd9Sstevel@tonic-gate error = ENAMETOOLONG; 12937c478bd9Sstevel@tonic-gate goto out; 12947c478bd9Sstevel@tonic-gate } 12957c478bd9Sstevel@tonic-gate bcopy(symlink, newpn.pn_path, addlen); 12967c478bd9Sstevel@tonic-gate newpn.pn_pathlen += addlen; 12977c478bd9Sstevel@tonic-gate newpn.pn_path += addlen; 12987c478bd9Sstevel@tonic-gate 12997c478bd9Sstevel@tonic-gate /* 13007c478bd9Sstevel@tonic-gate * Check if there is any remaining path after the symlink component. 13017c478bd9Sstevel@tonic-gate * First, skip the symlink component. 13027c478bd9Sstevel@tonic-gate */ 13037c478bd9Sstevel@tonic-gate pathname_skipslashdot(&oldpn); 13047c478bd9Sstevel@tonic-gate if (error = pn_getcomponent(&oldpn, component)) 13057c478bd9Sstevel@tonic-gate goto out; 13067c478bd9Sstevel@tonic-gate 13077c478bd9Sstevel@tonic-gate addlen = pn_pathleft(&oldpn); /* includes counting the slash */ 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate /* 13107c478bd9Sstevel@tonic-gate * Copy the remaining path to the new pathname if there is any. 13117c478bd9Sstevel@tonic-gate */ 13127c478bd9Sstevel@tonic-gate if (addlen > 0) { 13137c478bd9Sstevel@tonic-gate if (newpn.pn_pathlen + addlen >= newpn.pn_bufsize) { 13147c478bd9Sstevel@tonic-gate error = ENAMETOOLONG; 13157c478bd9Sstevel@tonic-gate goto out; 13167c478bd9Sstevel@tonic-gate } 13177c478bd9Sstevel@tonic-gate bcopy(oldpn.pn_path, newpn.pn_path, addlen); 13187c478bd9Sstevel@tonic-gate newpn.pn_pathlen += addlen; 13197c478bd9Sstevel@tonic-gate } 13207c478bd9Sstevel@tonic-gate newpn.pn_buf[newpn.pn_pathlen] = '\0'; 13217c478bd9Sstevel@tonic-gate 13227c478bd9Sstevel@tonic-gate /* get the newpath and store it in the servinfo4_t */ 13237c478bd9Sstevel@tonic-gate newpath = kmem_alloc(newpn.pn_pathlen + 1, KM_SLEEP); 13247c478bd9Sstevel@tonic-gate bcopy(newpn.pn_buf, newpath, newpn.pn_pathlen); 13257c478bd9Sstevel@tonic-gate newpath[newpn.pn_pathlen] = '\0'; 13267c478bd9Sstevel@tonic-gate 13277c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 13287c478bd9Sstevel@tonic-gate svp->sv_path = newpath; 13297c478bd9Sstevel@tonic-gate svp->sv_pathlen = strlen(newpath) + 1; 13307c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 13317c478bd9Sstevel@tonic-gate 13327c478bd9Sstevel@tonic-gate kmem_free(oldpath, oldpathlen); 13337c478bd9Sstevel@tonic-gate out: 13347c478bd9Sstevel@tonic-gate kmem_free(symlink, strlen(symlink) + 1); 13357c478bd9Sstevel@tonic-gate pn_free(&newpn); 13367c478bd9Sstevel@tonic-gate pn_free(&oldpn); 13377c478bd9Sstevel@tonic-gate 13387c478bd9Sstevel@tonic-gate return (error); 13397c478bd9Sstevel@tonic-gate } 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate /* 13427c478bd9Sstevel@tonic-gate * Get the root filehandle for the given filesystem and server, and update 13437c478bd9Sstevel@tonic-gate * svp. 13447c478bd9Sstevel@tonic-gate * 13457c478bd9Sstevel@tonic-gate * If NFS4_GETFH_NEEDSOP is set, then use nfs4_start_fop and nfs4_end_fop 13467c478bd9Sstevel@tonic-gate * to coordinate with recovery. Otherwise, the caller is assumed to be 13477c478bd9Sstevel@tonic-gate * the recovery thread or have already done a start_fop. 13487c478bd9Sstevel@tonic-gate * 13497c478bd9Sstevel@tonic-gate * Errors are returned by the nfs4_error_t parameter. 13507c478bd9Sstevel@tonic-gate */ 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate static void 13537c478bd9Sstevel@tonic-gate nfs4getfh_otw(struct mntinfo4 *mi, servinfo4_t *svp, vtype_t *vtp, 13547c478bd9Sstevel@tonic-gate int flags, cred_t *cr, nfs4_error_t *ep) 13557c478bd9Sstevel@tonic-gate { 13567c478bd9Sstevel@tonic-gate COMPOUND4args_clnt args; 13577c478bd9Sstevel@tonic-gate COMPOUND4res_clnt res; 13587c478bd9Sstevel@tonic-gate int doqueue = 1; 13597c478bd9Sstevel@tonic-gate nfs_argop4 *argop; 13607c478bd9Sstevel@tonic-gate nfs_resop4 *resop; 13617c478bd9Sstevel@tonic-gate nfs4_ga_res_t *garp; 13627c478bd9Sstevel@tonic-gate int num_argops; 13637c478bd9Sstevel@tonic-gate lookup4_param_t lookuparg; 13647c478bd9Sstevel@tonic-gate nfs_fh4 *tmpfhp; 13657c478bd9Sstevel@tonic-gate nfs_fh4 *resfhp; 13667c478bd9Sstevel@tonic-gate bool_t needrecov = FALSE; 13677c478bd9Sstevel@tonic-gate nfs4_recov_state_t recov_state; 13687c478bd9Sstevel@tonic-gate int llndx; 13697c478bd9Sstevel@tonic-gate int nthcomp; 13707c478bd9Sstevel@tonic-gate int recovery = !(flags & NFS4_GETFH_NEEDSOP); 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 13737c478bd9Sstevel@tonic-gate ASSERT(svp->sv_path != NULL); 13747c478bd9Sstevel@tonic-gate if (svp->sv_path[0] == '\0') { 13757c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 13767c478bd9Sstevel@tonic-gate nfs4_error_init(ep, EINVAL); 13777c478bd9Sstevel@tonic-gate return; 13787c478bd9Sstevel@tonic-gate } 13797c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate recov_state.rs_flags = 0; 13827c478bd9Sstevel@tonic-gate recov_state.rs_num_retry_despite_err = 0; 13837c478bd9Sstevel@tonic-gate recov_retry: 13847c478bd9Sstevel@tonic-gate nfs4_error_zinit(ep); 13857c478bd9Sstevel@tonic-gate 13867c478bd9Sstevel@tonic-gate if (!recovery) { 13877c478bd9Sstevel@tonic-gate ep->error = nfs4_start_fop(mi, NULL, NULL, OH_MOUNT, 13887c478bd9Sstevel@tonic-gate &recov_state, NULL); 13897c478bd9Sstevel@tonic-gate 13907c478bd9Sstevel@tonic-gate /* 13917c478bd9Sstevel@tonic-gate * If recovery has been started and this request as 13927c478bd9Sstevel@tonic-gate * initiated by a mount, then we must wait for recovery 13937c478bd9Sstevel@tonic-gate * to finish before proceeding, otherwise, the error 13947c478bd9Sstevel@tonic-gate * cleanup would remove data structures needed by the 13957c478bd9Sstevel@tonic-gate * recovery thread. 13967c478bd9Sstevel@tonic-gate */ 13977c478bd9Sstevel@tonic-gate if (ep->error) { 13987c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 13997c478bd9Sstevel@tonic-gate if (mi->mi_flags & MI4_MOUNTING) { 14007c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_RECOV_FAIL; 14017c478bd9Sstevel@tonic-gate mi->mi_error = EIO; 14027c478bd9Sstevel@tonic-gate 14037c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE, 14047c478bd9Sstevel@tonic-gate "nfs4getfh_otw: waiting 4 recovery\n")); 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate while (mi->mi_flags & MI4_RECOV_ACTIV) 14077c478bd9Sstevel@tonic-gate cv_wait(&mi->mi_failover_cv, 14087c478bd9Sstevel@tonic-gate &mi->mi_lock); 14097c478bd9Sstevel@tonic-gate } 14107c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 14117c478bd9Sstevel@tonic-gate return; 14127c478bd9Sstevel@tonic-gate } 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate /* 14157c478bd9Sstevel@tonic-gate * If the client does not specify a specific flavor to use 14167c478bd9Sstevel@tonic-gate * and has not gotten a secinfo list from the server yet, 14177c478bd9Sstevel@tonic-gate * retrieve the secinfo list from the server and use a 14187c478bd9Sstevel@tonic-gate * flavor from the list to mount. 14197c478bd9Sstevel@tonic-gate * 14207c478bd9Sstevel@tonic-gate * If fail to get the secinfo list from the server, then 14217c478bd9Sstevel@tonic-gate * try the default flavor. 14227c478bd9Sstevel@tonic-gate */ 14237c478bd9Sstevel@tonic-gate if ((svp->sv_flags & SV4_TRYSECDEFAULT) && 14247c478bd9Sstevel@tonic-gate svp->sv_secinfo == NULL) { 14257c478bd9Sstevel@tonic-gate (void) nfs4_secinfo_path(mi, cr, FALSE); 14267c478bd9Sstevel@tonic-gate } 14277c478bd9Sstevel@tonic-gate } 14287c478bd9Sstevel@tonic-gate 14297c478bd9Sstevel@tonic-gate if (recovery) 14307c478bd9Sstevel@tonic-gate args.ctag = TAG_REMAP_MOUNT; 14317c478bd9Sstevel@tonic-gate else 14327c478bd9Sstevel@tonic-gate args.ctag = TAG_MOUNT; 14337c478bd9Sstevel@tonic-gate 14347c478bd9Sstevel@tonic-gate lookuparg.l4_getattrs = LKP4_ALL_ATTRIBUTES; 14357c478bd9Sstevel@tonic-gate lookuparg.argsp = &args; 14367c478bd9Sstevel@tonic-gate lookuparg.resp = &res; 14377c478bd9Sstevel@tonic-gate lookuparg.header_len = 2; /* Putrootfh, getfh */ 14387c478bd9Sstevel@tonic-gate lookuparg.trailer_len = 0; 14397c478bd9Sstevel@tonic-gate lookuparg.ga_bits = FATTR4_FSINFO_MASK; 14407c478bd9Sstevel@tonic-gate lookuparg.mi = mi; 14417c478bd9Sstevel@tonic-gate 14427c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 14437c478bd9Sstevel@tonic-gate ASSERT(svp->sv_path != NULL); 14447c478bd9Sstevel@tonic-gate llndx = nfs4lookup_setup(svp->sv_path, &lookuparg, 0); 14457c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 14467c478bd9Sstevel@tonic-gate 14477c478bd9Sstevel@tonic-gate argop = args.array; 14487c478bd9Sstevel@tonic-gate num_argops = args.array_len; 14497c478bd9Sstevel@tonic-gate 14507c478bd9Sstevel@tonic-gate /* choose public or root filehandle */ 14517c478bd9Sstevel@tonic-gate if (flags & NFS4_GETFH_PUBLIC) 14527c478bd9Sstevel@tonic-gate argop[0].argop = OP_PUTPUBFH; 14537c478bd9Sstevel@tonic-gate else 14547c478bd9Sstevel@tonic-gate argop[0].argop = OP_PUTROOTFH; 14557c478bd9Sstevel@tonic-gate 14567c478bd9Sstevel@tonic-gate /* get fh */ 14577c478bd9Sstevel@tonic-gate argop[1].argop = OP_GETFH; 14587c478bd9Sstevel@tonic-gate 14597c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_call_debug, (CE_NOTE, 14607c478bd9Sstevel@tonic-gate "nfs4getfh_otw: %s call, mi 0x%p", 14617c478bd9Sstevel@tonic-gate needrecov ? "recov" : "first", (void *)mi)); 14627c478bd9Sstevel@tonic-gate 14637c478bd9Sstevel@tonic-gate rfs4call(mi, &args, &res, cr, &doqueue, RFSCALL_SOFT, ep); 14647c478bd9Sstevel@tonic-gate 14657c478bd9Sstevel@tonic-gate needrecov = nfs4_needs_recovery(ep, FALSE, mi->mi_vfsp); 14667c478bd9Sstevel@tonic-gate 14677c478bd9Sstevel@tonic-gate if (needrecov) { 14687c478bd9Sstevel@tonic-gate bool_t abort; 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate if (recovery) { 14717c478bd9Sstevel@tonic-gate nfs4args_lookup_free(argop, num_argops); 14727c478bd9Sstevel@tonic-gate kmem_free(argop, 14737c478bd9Sstevel@tonic-gate lookuparg.arglen * sizeof (nfs_argop4)); 14747c478bd9Sstevel@tonic-gate if (!ep->error) 14757c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, 14767c478bd9Sstevel@tonic-gate (caddr_t)&res); 14777c478bd9Sstevel@tonic-gate return; 14787c478bd9Sstevel@tonic-gate } 14797c478bd9Sstevel@tonic-gate 14807c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_recov_debug, 14817c478bd9Sstevel@tonic-gate (CE_NOTE, "nfs4getfh_otw: initiating recovery\n")); 14827c478bd9Sstevel@tonic-gate 14837c478bd9Sstevel@tonic-gate abort = nfs4_start_recovery(ep, mi, NULL, 14847c478bd9Sstevel@tonic-gate NULL, NULL, NULL, OP_GETFH, NULL); 14857c478bd9Sstevel@tonic-gate if (!ep->error) { 14867c478bd9Sstevel@tonic-gate ep->error = geterrno4(res.status); 14877c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 14887c478bd9Sstevel@tonic-gate } 14897c478bd9Sstevel@tonic-gate nfs4args_lookup_free(argop, num_argops); 14907c478bd9Sstevel@tonic-gate kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4)); 14917c478bd9Sstevel@tonic-gate nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state, needrecov); 14927c478bd9Sstevel@tonic-gate /* have another go? */ 14937c478bd9Sstevel@tonic-gate if (abort == FALSE) 14947c478bd9Sstevel@tonic-gate goto recov_retry; 14957c478bd9Sstevel@tonic-gate return; 14967c478bd9Sstevel@tonic-gate } 14977c478bd9Sstevel@tonic-gate 14987c478bd9Sstevel@tonic-gate /* 14997c478bd9Sstevel@tonic-gate * No recovery, but check if error is set. 15007c478bd9Sstevel@tonic-gate */ 15017c478bd9Sstevel@tonic-gate if (ep->error) { 15027c478bd9Sstevel@tonic-gate nfs4args_lookup_free(argop, num_argops); 15037c478bd9Sstevel@tonic-gate kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4)); 15047c478bd9Sstevel@tonic-gate if (!recovery) 15057c478bd9Sstevel@tonic-gate nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state, 15067c478bd9Sstevel@tonic-gate needrecov); 15077c478bd9Sstevel@tonic-gate return; 15087c478bd9Sstevel@tonic-gate } 15097c478bd9Sstevel@tonic-gate 15107c478bd9Sstevel@tonic-gate is_link_err: 15117c478bd9Sstevel@tonic-gate 15127c478bd9Sstevel@tonic-gate /* for non-recovery errors */ 15137c478bd9Sstevel@tonic-gate if (res.status && res.status != NFS4ERR_SYMLINK) { 15147c478bd9Sstevel@tonic-gate if (!recovery) { 15157c478bd9Sstevel@tonic-gate nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state, 15167c478bd9Sstevel@tonic-gate needrecov); 15177c478bd9Sstevel@tonic-gate } 15187c478bd9Sstevel@tonic-gate nfs4args_lookup_free(argop, num_argops); 15197c478bd9Sstevel@tonic-gate kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4)); 15207c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 15217c478bd9Sstevel@tonic-gate return; 15227c478bd9Sstevel@tonic-gate } 15237c478bd9Sstevel@tonic-gate 15247c478bd9Sstevel@tonic-gate /* 15257c478bd9Sstevel@tonic-gate * If any intermediate component in the path is a symbolic link, 15267c478bd9Sstevel@tonic-gate * resolve the symlink, then try mount again using the new path. 15277c478bd9Sstevel@tonic-gate */ 15287c478bd9Sstevel@tonic-gate if (res.status == NFS4ERR_SYMLINK) { 15297c478bd9Sstevel@tonic-gate int where; 15307c478bd9Sstevel@tonic-gate 15317c478bd9Sstevel@tonic-gate /* 15327c478bd9Sstevel@tonic-gate * This must be from OP_LOOKUP failure. The (cfh) for this 15337c478bd9Sstevel@tonic-gate * OP_LOOKUP is a symlink node. Found out where the 15347c478bd9Sstevel@tonic-gate * OP_GETFH is for the (cfh) that is a symlink node. 15357c478bd9Sstevel@tonic-gate * 15367c478bd9Sstevel@tonic-gate * Example: 15377c478bd9Sstevel@tonic-gate * (mount) PUTROOTFH, GETFH, LOOKUP comp1, GETFH, GETATTR, 15387c478bd9Sstevel@tonic-gate * LOOKUP comp2, GETFH, GETATTR, LOOKUP comp3, GETFH, GETATTR 15397c478bd9Sstevel@tonic-gate * 15407c478bd9Sstevel@tonic-gate * LOOKUP comp3 fails with SYMLINK because comp2 is a symlink. 15417c478bd9Sstevel@tonic-gate * In this case, where = 7, nthcomp = 2. 15427c478bd9Sstevel@tonic-gate */ 15437c478bd9Sstevel@tonic-gate where = res.array_len - 2; 15447c478bd9Sstevel@tonic-gate ASSERT(where > 0); 15457c478bd9Sstevel@tonic-gate 15467c478bd9Sstevel@tonic-gate resop = &res.array[where - 1]; 15477c478bd9Sstevel@tonic-gate ASSERT(resop->resop == OP_GETFH); 15487c478bd9Sstevel@tonic-gate tmpfhp = &resop->nfs_resop4_u.opgetfh.object; 15497c478bd9Sstevel@tonic-gate nthcomp = res.array_len/3 - 1; 15507c478bd9Sstevel@tonic-gate 15517c478bd9Sstevel@tonic-gate /* 15527c478bd9Sstevel@tonic-gate * Need to call nfs4_end_op before resolve_sympath to avoid 15537c478bd9Sstevel@tonic-gate * potential nfs4_start_op deadlock. 15547c478bd9Sstevel@tonic-gate */ 15557c478bd9Sstevel@tonic-gate if (!recovery) 15567c478bd9Sstevel@tonic-gate nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state, 15577c478bd9Sstevel@tonic-gate needrecov); 15587c478bd9Sstevel@tonic-gate 15597c478bd9Sstevel@tonic-gate ep->error = resolve_sympath(mi, svp, nthcomp, tmpfhp, cr, 15607c478bd9Sstevel@tonic-gate flags); 15617c478bd9Sstevel@tonic-gate 15627c478bd9Sstevel@tonic-gate nfs4args_lookup_free(argop, num_argops); 15637c478bd9Sstevel@tonic-gate kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4)); 15647c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 15657c478bd9Sstevel@tonic-gate 15667c478bd9Sstevel@tonic-gate if (ep->error) 15677c478bd9Sstevel@tonic-gate return; 15687c478bd9Sstevel@tonic-gate 15697c478bd9Sstevel@tonic-gate goto recov_retry; 15707c478bd9Sstevel@tonic-gate } 15717c478bd9Sstevel@tonic-gate 15727c478bd9Sstevel@tonic-gate /* getfh */ 15737c478bd9Sstevel@tonic-gate resop = &res.array[res.array_len - 2]; 15747c478bd9Sstevel@tonic-gate ASSERT(resop->resop == OP_GETFH); 15757c478bd9Sstevel@tonic-gate resfhp = &resop->nfs_resop4_u.opgetfh.object; 15767c478bd9Sstevel@tonic-gate 15777c478bd9Sstevel@tonic-gate /* getattr fsinfo res */ 15787c478bd9Sstevel@tonic-gate resop++; 15797c478bd9Sstevel@tonic-gate garp = &resop->nfs_resop4_u.opgetattr.ga_res; 15807c478bd9Sstevel@tonic-gate 15817c478bd9Sstevel@tonic-gate *vtp = garp->n4g_va.va_type; 15827c478bd9Sstevel@tonic-gate 15837c478bd9Sstevel@tonic-gate mi->mi_fh_expire_type = garp->n4g_ext_res->n4g_fet; 15847c478bd9Sstevel@tonic-gate 15857c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 15867c478bd9Sstevel@tonic-gate if (garp->n4g_ext_res->n4g_pc4.pc4_link_support) 15877c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_LINK; 15887c478bd9Sstevel@tonic-gate if (garp->n4g_ext_res->n4g_pc4.pc4_symlink_support) 15897c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_SYMLINK; 15907c478bd9Sstevel@tonic-gate if (garp->n4g_ext_res->n4g_suppattrs & FATTR4_ACL_MASK) 15917c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_ACL; 15927c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 15937c478bd9Sstevel@tonic-gate 15947c478bd9Sstevel@tonic-gate if (garp->n4g_ext_res->n4g_maxread == 0) 15957c478bd9Sstevel@tonic-gate mi->mi_tsize = 15967c478bd9Sstevel@tonic-gate MIN(MAXBSIZE, mi->mi_tsize); 15977c478bd9Sstevel@tonic-gate else 15987c478bd9Sstevel@tonic-gate mi->mi_tsize = 15997c478bd9Sstevel@tonic-gate MIN(garp->n4g_ext_res->n4g_maxread, 16007c478bd9Sstevel@tonic-gate mi->mi_tsize); 16017c478bd9Sstevel@tonic-gate 16027c478bd9Sstevel@tonic-gate if (garp->n4g_ext_res->n4g_maxwrite == 0) 16037c478bd9Sstevel@tonic-gate mi->mi_stsize = 16047c478bd9Sstevel@tonic-gate MIN(MAXBSIZE, mi->mi_stsize); 16057c478bd9Sstevel@tonic-gate else 16067c478bd9Sstevel@tonic-gate mi->mi_stsize = 16077c478bd9Sstevel@tonic-gate MIN(garp->n4g_ext_res->n4g_maxwrite, 16087c478bd9Sstevel@tonic-gate mi->mi_stsize); 16097c478bd9Sstevel@tonic-gate 16107c478bd9Sstevel@tonic-gate if (garp->n4g_ext_res->n4g_maxfilesize != 0) 16117c478bd9Sstevel@tonic-gate mi->mi_maxfilesize = 16127c478bd9Sstevel@tonic-gate MIN(garp->n4g_ext_res->n4g_maxfilesize, 16137c478bd9Sstevel@tonic-gate mi->mi_maxfilesize); 16147c478bd9Sstevel@tonic-gate 16157c478bd9Sstevel@tonic-gate /* 16167c478bd9Sstevel@tonic-gate * If the final component is a a symbolic link, resolve the symlink, 16177c478bd9Sstevel@tonic-gate * then try mount again using the new path. 16187c478bd9Sstevel@tonic-gate * 16197c478bd9Sstevel@tonic-gate * Assume no symbolic link for root filesysm "/". 16207c478bd9Sstevel@tonic-gate */ 16217c478bd9Sstevel@tonic-gate if (*vtp == VLNK) { 16227c478bd9Sstevel@tonic-gate /* 16237c478bd9Sstevel@tonic-gate * nthcomp is the total result length minus 16247c478bd9Sstevel@tonic-gate * the 1st 2 OPs (PUTROOTFH, GETFH), 16257c478bd9Sstevel@tonic-gate * then divided by 3 (LOOKUP,GETFH,GETATTR) 16267c478bd9Sstevel@tonic-gate * 16277c478bd9Sstevel@tonic-gate * e.g. PUTROOTFH GETFH LOOKUP 1st-comp GETFH GETATTR 16287c478bd9Sstevel@tonic-gate * LOOKUP 2nd-comp GETFH GETATTR 16297c478bd9Sstevel@tonic-gate * 16307c478bd9Sstevel@tonic-gate * (8 - 2)/3 = 2 16317c478bd9Sstevel@tonic-gate */ 16327c478bd9Sstevel@tonic-gate nthcomp = (res.array_len - 2)/3; 16337c478bd9Sstevel@tonic-gate 16347c478bd9Sstevel@tonic-gate /* 16357c478bd9Sstevel@tonic-gate * Need to call nfs4_end_op before resolve_sympath to avoid 16367c478bd9Sstevel@tonic-gate * potential nfs4_start_op deadlock. See RFE 4777612. 16377c478bd9Sstevel@tonic-gate */ 16387c478bd9Sstevel@tonic-gate if (!recovery) 16397c478bd9Sstevel@tonic-gate nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state, 16407c478bd9Sstevel@tonic-gate needrecov); 16417c478bd9Sstevel@tonic-gate 16427c478bd9Sstevel@tonic-gate ep->error = resolve_sympath(mi, svp, nthcomp, resfhp, cr, 16437c478bd9Sstevel@tonic-gate flags); 16447c478bd9Sstevel@tonic-gate 16457c478bd9Sstevel@tonic-gate nfs4args_lookup_free(argop, num_argops); 16467c478bd9Sstevel@tonic-gate kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4)); 16477c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 16487c478bd9Sstevel@tonic-gate 16497c478bd9Sstevel@tonic-gate if (ep->error) 16507c478bd9Sstevel@tonic-gate return; 16517c478bd9Sstevel@tonic-gate 16527c478bd9Sstevel@tonic-gate goto recov_retry; 16537c478bd9Sstevel@tonic-gate } 16547c478bd9Sstevel@tonic-gate 16557c478bd9Sstevel@tonic-gate /* 16567c478bd9Sstevel@tonic-gate * We need to figure out where in the compound the getfh 16577c478bd9Sstevel@tonic-gate * for the parent directory is. If the object to be mounted is 16587c478bd9Sstevel@tonic-gate * the root, then there is no lookup at all: 16597c478bd9Sstevel@tonic-gate * PUTROOTFH, GETFH. 16607c478bd9Sstevel@tonic-gate * If the object to be mounted is in the root, then the compound is: 16617c478bd9Sstevel@tonic-gate * PUTROOTFH, GETFH, LOOKUP, GETFH, GETATTR. 16627c478bd9Sstevel@tonic-gate * In either of these cases, the index of the GETFH is 1. 16637c478bd9Sstevel@tonic-gate * If it is not at the root, then it's something like: 16647c478bd9Sstevel@tonic-gate * PUTROOTFH, GETFH, LOOKUP, GETFH, GETATTR, 16657c478bd9Sstevel@tonic-gate * LOOKUP, GETFH, GETATTR 16667c478bd9Sstevel@tonic-gate * In this case, the index is llndx (last lookup index) - 2. 16677c478bd9Sstevel@tonic-gate */ 16687c478bd9Sstevel@tonic-gate if (llndx == -1 || llndx == 2) 16697c478bd9Sstevel@tonic-gate resop = &res.array[1]; 16707c478bd9Sstevel@tonic-gate else { 16717c478bd9Sstevel@tonic-gate ASSERT(llndx > 2); 16727c478bd9Sstevel@tonic-gate resop = &res.array[llndx-2]; 16737c478bd9Sstevel@tonic-gate } 16747c478bd9Sstevel@tonic-gate 16757c478bd9Sstevel@tonic-gate ASSERT(resop->resop == OP_GETFH); 16767c478bd9Sstevel@tonic-gate tmpfhp = &resop->nfs_resop4_u.opgetfh.object; 16777c478bd9Sstevel@tonic-gate 16787c478bd9Sstevel@tonic-gate /* save the filehandles for the replica */ 16797c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 16807c478bd9Sstevel@tonic-gate ASSERT(tmpfhp->nfs_fh4_len <= NFS4_FHSIZE); 16817c478bd9Sstevel@tonic-gate svp->sv_pfhandle.fh_len = tmpfhp->nfs_fh4_len; 16827c478bd9Sstevel@tonic-gate bcopy(tmpfhp->nfs_fh4_val, svp->sv_pfhandle.fh_buf, 16837c478bd9Sstevel@tonic-gate tmpfhp->nfs_fh4_len); 16847c478bd9Sstevel@tonic-gate ASSERT(resfhp->nfs_fh4_len <= NFS4_FHSIZE); 16857c478bd9Sstevel@tonic-gate svp->sv_fhandle.fh_len = resfhp->nfs_fh4_len; 16867c478bd9Sstevel@tonic-gate bcopy(resfhp->nfs_fh4_val, svp->sv_fhandle.fh_buf, resfhp->nfs_fh4_len); 16877c478bd9Sstevel@tonic-gate 16887c478bd9Sstevel@tonic-gate /* initialize fsid and supp_attrs for server fs */ 16897c478bd9Sstevel@tonic-gate svp->sv_fsid = garp->n4g_fsid; 16907c478bd9Sstevel@tonic-gate svp->sv_supp_attrs = 16917c478bd9Sstevel@tonic-gate garp->n4g_ext_res->n4g_suppattrs | FATTR4_MANDATTR_MASK; 16927c478bd9Sstevel@tonic-gate 16937c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 16947c478bd9Sstevel@tonic-gate 16957c478bd9Sstevel@tonic-gate nfs4args_lookup_free(argop, num_argops); 16967c478bd9Sstevel@tonic-gate kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4)); 16977c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 16987c478bd9Sstevel@tonic-gate if (!recovery) 16997c478bd9Sstevel@tonic-gate nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state, needrecov); 17007c478bd9Sstevel@tonic-gate } 17017c478bd9Sstevel@tonic-gate 17027c478bd9Sstevel@tonic-gate static ushort_t nfs4_max_threads = 8; /* max number of active async threads */ 17037c478bd9Sstevel@tonic-gate static uint_t nfs4_bsize = 32 * 1024; /* client `block' size */ 17047c478bd9Sstevel@tonic-gate static uint_t nfs4_async_clusters = 1; /* # of reqs from each async queue */ 17057c478bd9Sstevel@tonic-gate static uint_t nfs4_cots_timeo = NFS_COTS_TIMEO; 17067c478bd9Sstevel@tonic-gate 17077c478bd9Sstevel@tonic-gate /* 17087c478bd9Sstevel@tonic-gate * Remap the root filehandle for the given filesystem. 17097c478bd9Sstevel@tonic-gate * 17107c478bd9Sstevel@tonic-gate * results returned via the nfs4_error_t parameter. 17117c478bd9Sstevel@tonic-gate */ 17127c478bd9Sstevel@tonic-gate void 17137c478bd9Sstevel@tonic-gate nfs4_remap_root(mntinfo4_t *mi, nfs4_error_t *ep, int flags) 17147c478bd9Sstevel@tonic-gate { 17157c478bd9Sstevel@tonic-gate struct servinfo4 *svp; 17167c478bd9Sstevel@tonic-gate vtype_t vtype; 17177c478bd9Sstevel@tonic-gate nfs_fh4 rootfh; 17187c478bd9Sstevel@tonic-gate int getfh_flags; 17197c478bd9Sstevel@tonic-gate char *orig_sv_path; 17207c478bd9Sstevel@tonic-gate int orig_sv_pathlen, num_retry; 17217c478bd9Sstevel@tonic-gate 17227c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 17238c9e5ad2Saalok 17248c9e5ad2Saalok remap_retry: 17257c478bd9Sstevel@tonic-gate svp = mi->mi_curr_serv; 17267c478bd9Sstevel@tonic-gate getfh_flags = 17277c478bd9Sstevel@tonic-gate (flags & NFS4_REMAP_NEEDSOP) ? NFS4_GETFH_NEEDSOP : 0; 17287c478bd9Sstevel@tonic-gate getfh_flags |= 17297c478bd9Sstevel@tonic-gate (mi->mi_flags & MI4_PUBLIC) ? NFS4_GETFH_PUBLIC : 0; 17307c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 17317c478bd9Sstevel@tonic-gate 17327c478bd9Sstevel@tonic-gate /* 17337c478bd9Sstevel@tonic-gate * Just in case server path being mounted contains 17347c478bd9Sstevel@tonic-gate * symlinks and fails w/STALE, save the initial sv_path 17357c478bd9Sstevel@tonic-gate * so we can redrive the initial mount compound with the 17367c478bd9Sstevel@tonic-gate * initial sv_path -- not a symlink-expanded version. 17377c478bd9Sstevel@tonic-gate * 17387c478bd9Sstevel@tonic-gate * This could only happen if a symlink was expanded 17397c478bd9Sstevel@tonic-gate * and the expanded mount compound failed stale. Because 17407c478bd9Sstevel@tonic-gate * it could be the case that the symlink was removed at 17417c478bd9Sstevel@tonic-gate * the server (and replaced with another symlink/dir, 17427c478bd9Sstevel@tonic-gate * we need to use the initial sv_path when attempting 17437c478bd9Sstevel@tonic-gate * to re-lookup everything and recover. 17447c478bd9Sstevel@tonic-gate */ 17457c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 17467c478bd9Sstevel@tonic-gate orig_sv_pathlen = svp->sv_pathlen; 17477c478bd9Sstevel@tonic-gate orig_sv_path = kmem_alloc(orig_sv_pathlen, KM_SLEEP); 17487c478bd9Sstevel@tonic-gate bcopy(svp->sv_path, orig_sv_path, orig_sv_pathlen); 17497c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 17507c478bd9Sstevel@tonic-gate 17517c478bd9Sstevel@tonic-gate num_retry = nfs4_max_mount_retry; 17527c478bd9Sstevel@tonic-gate 17537c478bd9Sstevel@tonic-gate do { 17547c478bd9Sstevel@tonic-gate /* 17557c478bd9Sstevel@tonic-gate * Get the root fh from the server. Retry nfs4_max_mount_retry 17567c478bd9Sstevel@tonic-gate * (2) times if it fails with STALE since the recovery 17577c478bd9Sstevel@tonic-gate * infrastructure doesn't do STALE recovery for components 17587c478bd9Sstevel@tonic-gate * of the server path to the object being mounted. 17597c478bd9Sstevel@tonic-gate */ 17607c478bd9Sstevel@tonic-gate nfs4getfh_otw(mi, svp, &vtype, getfh_flags, CRED(), ep); 17617c478bd9Sstevel@tonic-gate 17627c478bd9Sstevel@tonic-gate if (ep->error == 0 && ep->stat == NFS4_OK) 17637c478bd9Sstevel@tonic-gate break; 17647c478bd9Sstevel@tonic-gate 17657c478bd9Sstevel@tonic-gate /* 17667c478bd9Sstevel@tonic-gate * For some reason, the mount compound failed. Before 17677c478bd9Sstevel@tonic-gate * retrying, we need to restore the original sv_path 17687c478bd9Sstevel@tonic-gate * because it might have contained symlinks that were 17697c478bd9Sstevel@tonic-gate * expanded by nfsgetfh_otw before the failure occurred. 17707c478bd9Sstevel@tonic-gate * replace current sv_path with orig sv_path -- just in case 17717c478bd9Sstevel@tonic-gate * it changed due to embedded symlinks. 17727c478bd9Sstevel@tonic-gate */ 17737c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 17747c478bd9Sstevel@tonic-gate if (orig_sv_pathlen != svp->sv_pathlen) { 17757c478bd9Sstevel@tonic-gate kmem_free(svp->sv_path, svp->sv_pathlen); 17767c478bd9Sstevel@tonic-gate svp->sv_path = kmem_alloc(orig_sv_pathlen, KM_SLEEP); 17777c478bd9Sstevel@tonic-gate svp->sv_pathlen = orig_sv_pathlen; 17787c478bd9Sstevel@tonic-gate } 17797c478bd9Sstevel@tonic-gate bcopy(orig_sv_path, svp->sv_path, orig_sv_pathlen); 17807c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 17817c478bd9Sstevel@tonic-gate 17827c478bd9Sstevel@tonic-gate } while (num_retry-- > 0); 17837c478bd9Sstevel@tonic-gate 17847c478bd9Sstevel@tonic-gate kmem_free(orig_sv_path, orig_sv_pathlen); 17857c478bd9Sstevel@tonic-gate 17867c478bd9Sstevel@tonic-gate if (ep->error != 0 || ep->stat != 0) { 17877c478bd9Sstevel@tonic-gate return; 17887c478bd9Sstevel@tonic-gate } 17897c478bd9Sstevel@tonic-gate 17907c478bd9Sstevel@tonic-gate if (vtype != VNON && vtype != mi->mi_type) { 17917c478bd9Sstevel@tonic-gate /* shouldn't happen */ 17927c478bd9Sstevel@tonic-gate zcmn_err(mi->mi_zone->zone_id, CE_WARN, 17937c478bd9Sstevel@tonic-gate "nfs4_remap_root: server root vnode type (%d) doesn't " 17947c478bd9Sstevel@tonic-gate "match mount info (%d)", vtype, mi->mi_type); 17957c478bd9Sstevel@tonic-gate } 17967c478bd9Sstevel@tonic-gate 17977c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 17987c478bd9Sstevel@tonic-gate rootfh.nfs_fh4_val = svp->sv_fhandle.fh_buf; 17997c478bd9Sstevel@tonic-gate rootfh.nfs_fh4_len = svp->sv_fhandle.fh_len; 18007c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 18017c478bd9Sstevel@tonic-gate sfh4_update(mi->mi_rootfh, &rootfh); 18027c478bd9Sstevel@tonic-gate 18037c478bd9Sstevel@tonic-gate /* 18048c9e5ad2Saalok * It's possible that recovery took place on the filesystem 18058c9e5ad2Saalok * and the server has been updated between the time we did 18068c9e5ad2Saalok * the nfs4getfh_otw and now. Re-drive the otw operation 18078c9e5ad2Saalok * to make sure we have a good fh. 18087c478bd9Sstevel@tonic-gate */ 18097c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 18108c9e5ad2Saalok if (mi->mi_curr_serv != svp) 18118c9e5ad2Saalok goto remap_retry; 18128c9e5ad2Saalok 18137c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 18147c478bd9Sstevel@tonic-gate } 18157c478bd9Sstevel@tonic-gate 18167c478bd9Sstevel@tonic-gate static int 18177c478bd9Sstevel@tonic-gate nfs4rootvp(vnode_t **rtvpp, vfs_t *vfsp, struct servinfo4 *svp_head, 18187c478bd9Sstevel@tonic-gate int flags, cred_t *cr, zone_t *zone) 18197c478bd9Sstevel@tonic-gate { 18207c478bd9Sstevel@tonic-gate vnode_t *rtvp = NULL; 18217c478bd9Sstevel@tonic-gate mntinfo4_t *mi; 18227c478bd9Sstevel@tonic-gate dev_t nfs_dev; 18237c478bd9Sstevel@tonic-gate int error = 0; 18247c478bd9Sstevel@tonic-gate rnode4_t *rp; 18257c478bd9Sstevel@tonic-gate int i; 18267c478bd9Sstevel@tonic-gate struct vattr va; 18277c478bd9Sstevel@tonic-gate vtype_t vtype = VNON; 18287c478bd9Sstevel@tonic-gate vtype_t tmp_vtype = VNON; 18297c478bd9Sstevel@tonic-gate struct servinfo4 *firstsvp = NULL, *svp = svp_head; 18307c478bd9Sstevel@tonic-gate nfs4_oo_hash_bucket_t *bucketp; 18317c478bd9Sstevel@tonic-gate nfs_fh4 fh; 18327c478bd9Sstevel@tonic-gate char *droptext = ""; 18337c478bd9Sstevel@tonic-gate struct nfs_stats *nfsstatsp; 18347c478bd9Sstevel@tonic-gate nfs4_fname_t *mfname; 18357c478bd9Sstevel@tonic-gate nfs4_error_t e; 18367c478bd9Sstevel@tonic-gate char *orig_sv_path; 183750a83466Sjwahlig int orig_sv_pathlen, num_retry, removed; 18387c478bd9Sstevel@tonic-gate cred_t *lcr = NULL, *tcr = cr; 18397c478bd9Sstevel@tonic-gate 1840108322fbScarlsonj nfsstatsp = zone_getspecific(nfsstat_zone_key, nfs_zone()); 18417c478bd9Sstevel@tonic-gate ASSERT(nfsstatsp != NULL); 18427c478bd9Sstevel@tonic-gate 1843108322fbScarlsonj ASSERT(nfs_zone() == zone); 18447c478bd9Sstevel@tonic-gate ASSERT(crgetref(cr)); 18457c478bd9Sstevel@tonic-gate 18467c478bd9Sstevel@tonic-gate /* 18477c478bd9Sstevel@tonic-gate * Create a mount record and link it to the vfs struct. 18487c478bd9Sstevel@tonic-gate */ 18497c478bd9Sstevel@tonic-gate mi = kmem_zalloc(sizeof (*mi), KM_SLEEP); 18507c478bd9Sstevel@tonic-gate mutex_init(&mi->mi_lock, NULL, MUTEX_DEFAULT, NULL); 18517c478bd9Sstevel@tonic-gate nfs_rw_init(&mi->mi_recovlock, NULL, RW_DEFAULT, NULL); 18527c478bd9Sstevel@tonic-gate nfs_rw_init(&mi->mi_rename_lock, NULL, RW_DEFAULT, NULL); 18537c478bd9Sstevel@tonic-gate nfs_rw_init(&mi->mi_fh_lock, NULL, RW_DEFAULT, NULL); 18547c478bd9Sstevel@tonic-gate 18557c478bd9Sstevel@tonic-gate if (!(flags & NFSMNT_SOFT)) 18567c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_HARD; 18577c478bd9Sstevel@tonic-gate if ((flags & NFSMNT_NOPRINT)) 18587c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_NOPRINT; 18597c478bd9Sstevel@tonic-gate if (flags & NFSMNT_INT) 18607c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_INT; 18617c478bd9Sstevel@tonic-gate if (flags & NFSMNT_PUBLIC) 18627c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_PUBLIC; 18637c478bd9Sstevel@tonic-gate mi->mi_retrans = NFS_RETRIES; 18647c478bd9Sstevel@tonic-gate if (svp->sv_knconf->knc_semantics == NC_TPI_COTS_ORD || 18657c478bd9Sstevel@tonic-gate svp->sv_knconf->knc_semantics == NC_TPI_COTS) 18667c478bd9Sstevel@tonic-gate mi->mi_timeo = nfs4_cots_timeo; 18677c478bd9Sstevel@tonic-gate else 18687c478bd9Sstevel@tonic-gate mi->mi_timeo = NFS_TIMEO; 18697c478bd9Sstevel@tonic-gate mi->mi_prog = NFS_PROGRAM; 18707c478bd9Sstevel@tonic-gate mi->mi_vers = NFS_V4; 18717c478bd9Sstevel@tonic-gate mi->mi_rfsnames = rfsnames_v4; 18727c478bd9Sstevel@tonic-gate mi->mi_reqs = nfsstatsp->nfs_stats_v4.rfsreqcnt_ptr; 18737c478bd9Sstevel@tonic-gate cv_init(&mi->mi_failover_cv, NULL, CV_DEFAULT, NULL); 18747c478bd9Sstevel@tonic-gate mi->mi_servers = svp; 18757c478bd9Sstevel@tonic-gate mi->mi_curr_serv = svp; 18767c478bd9Sstevel@tonic-gate mi->mi_acregmin = SEC2HR(ACREGMIN); 18777c478bd9Sstevel@tonic-gate mi->mi_acregmax = SEC2HR(ACREGMAX); 18787c478bd9Sstevel@tonic-gate mi->mi_acdirmin = SEC2HR(ACDIRMIN); 18797c478bd9Sstevel@tonic-gate mi->mi_acdirmax = SEC2HR(ACDIRMAX); 18807c478bd9Sstevel@tonic-gate mi->mi_fh_expire_type = FH4_PERSISTENT; 18817c478bd9Sstevel@tonic-gate mi->mi_clientid_next = NULL; 18827c478bd9Sstevel@tonic-gate mi->mi_clientid_prev = NULL; 18837c478bd9Sstevel@tonic-gate mi->mi_grace_wait = 0; 18847c478bd9Sstevel@tonic-gate mi->mi_error = 0; 18857c478bd9Sstevel@tonic-gate mi->mi_srvsettime = 0; 18867c478bd9Sstevel@tonic-gate 188750a83466Sjwahlig mi->mi_count = 1; 188850a83466Sjwahlig 18897c478bd9Sstevel@tonic-gate mi->mi_tsize = nfs4_tsize(svp->sv_knconf); 18907c478bd9Sstevel@tonic-gate mi->mi_stsize = mi->mi_tsize; 18917c478bd9Sstevel@tonic-gate 18927c478bd9Sstevel@tonic-gate if (flags & NFSMNT_DIRECTIO) 18937c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_DIRECTIO; 18947c478bd9Sstevel@tonic-gate 18957c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_MOUNTING; 18967c478bd9Sstevel@tonic-gate 18977c478bd9Sstevel@tonic-gate /* 18987c478bd9Sstevel@tonic-gate * Make a vfs struct for nfs. We do this here instead of below 18997c478bd9Sstevel@tonic-gate * because rtvp needs a vfs before we can do a getattr on it. 19007c478bd9Sstevel@tonic-gate * 19017c478bd9Sstevel@tonic-gate * Assign a unique device id to the mount 19027c478bd9Sstevel@tonic-gate */ 19037c478bd9Sstevel@tonic-gate mutex_enter(&nfs_minor_lock); 19047c478bd9Sstevel@tonic-gate do { 19057c478bd9Sstevel@tonic-gate nfs_minor = (nfs_minor + 1) & MAXMIN32; 19067c478bd9Sstevel@tonic-gate nfs_dev = makedevice(nfs_major, nfs_minor); 19077c478bd9Sstevel@tonic-gate } while (vfs_devismounted(nfs_dev)); 19087c478bd9Sstevel@tonic-gate mutex_exit(&nfs_minor_lock); 19097c478bd9Sstevel@tonic-gate 19107c478bd9Sstevel@tonic-gate vfsp->vfs_dev = nfs_dev; 19117c478bd9Sstevel@tonic-gate vfs_make_fsid(&vfsp->vfs_fsid, nfs_dev, nfs4fstyp); 19127c478bd9Sstevel@tonic-gate vfsp->vfs_data = (caddr_t)mi; 19137c478bd9Sstevel@tonic-gate vfsp->vfs_fstype = nfsfstyp; 19147c478bd9Sstevel@tonic-gate vfsp->vfs_bsize = nfs4_bsize; 19157c478bd9Sstevel@tonic-gate 19167c478bd9Sstevel@tonic-gate /* 19177c478bd9Sstevel@tonic-gate * Initialize fields used to support async putpage operations. 19187c478bd9Sstevel@tonic-gate */ 19197c478bd9Sstevel@tonic-gate for (i = 0; i < NFS4_ASYNC_TYPES; i++) 19207c478bd9Sstevel@tonic-gate mi->mi_async_clusters[i] = nfs4_async_clusters; 19217c478bd9Sstevel@tonic-gate mi->mi_async_init_clusters = nfs4_async_clusters; 19227c478bd9Sstevel@tonic-gate mi->mi_async_curr = &mi->mi_async_reqs[0]; 19237c478bd9Sstevel@tonic-gate mi->mi_max_threads = nfs4_max_threads; 19247c478bd9Sstevel@tonic-gate mutex_init(&mi->mi_async_lock, NULL, MUTEX_DEFAULT, NULL); 19257c478bd9Sstevel@tonic-gate cv_init(&mi->mi_async_reqs_cv, NULL, CV_DEFAULT, NULL); 19267c478bd9Sstevel@tonic-gate cv_init(&mi->mi_async_work_cv, NULL, CV_DEFAULT, NULL); 19277c478bd9Sstevel@tonic-gate cv_init(&mi->mi_async_cv, NULL, CV_DEFAULT, NULL); 19287c478bd9Sstevel@tonic-gate cv_init(&mi->mi_inact_req_cv, NULL, CV_DEFAULT, NULL); 19297c478bd9Sstevel@tonic-gate 19307c478bd9Sstevel@tonic-gate mi->mi_vfsp = vfsp; 19317c478bd9Sstevel@tonic-gate zone_hold(mi->mi_zone = zone); 19327c478bd9Sstevel@tonic-gate nfs4_mi_zonelist_add(mi); 19337c478bd9Sstevel@tonic-gate 19347c478bd9Sstevel@tonic-gate /* 19357c478bd9Sstevel@tonic-gate * Initialize the <open owner/cred> hash table. 19367c478bd9Sstevel@tonic-gate */ 19377c478bd9Sstevel@tonic-gate for (i = 0; i < NFS4_NUM_OO_BUCKETS; i++) { 19387c478bd9Sstevel@tonic-gate bucketp = &(mi->mi_oo_list[i]); 19397c478bd9Sstevel@tonic-gate mutex_init(&bucketp->b_lock, NULL, MUTEX_DEFAULT, NULL); 19407c478bd9Sstevel@tonic-gate list_create(&bucketp->b_oo_hash_list, 19417c478bd9Sstevel@tonic-gate sizeof (nfs4_open_owner_t), 19427c478bd9Sstevel@tonic-gate offsetof(nfs4_open_owner_t, oo_hash_node)); 19437c478bd9Sstevel@tonic-gate } 19447c478bd9Sstevel@tonic-gate 19457c478bd9Sstevel@tonic-gate /* 19467c478bd9Sstevel@tonic-gate * Initialize the freed open owner list. 19477c478bd9Sstevel@tonic-gate */ 19487c478bd9Sstevel@tonic-gate mi->mi_foo_num = 0; 19497c478bd9Sstevel@tonic-gate mi->mi_foo_max = NFS4_NUM_FREED_OPEN_OWNERS; 19507c478bd9Sstevel@tonic-gate list_create(&mi->mi_foo_list, sizeof (nfs4_open_owner_t), 19517c478bd9Sstevel@tonic-gate offsetof(nfs4_open_owner_t, oo_foo_node)); 19527c478bd9Sstevel@tonic-gate 19537c478bd9Sstevel@tonic-gate list_create(&mi->mi_lost_state, sizeof (nfs4_lost_rqst_t), 19547c478bd9Sstevel@tonic-gate offsetof(nfs4_lost_rqst_t, lr_node)); 19557c478bd9Sstevel@tonic-gate 19567c478bd9Sstevel@tonic-gate list_create(&mi->mi_bseqid_list, sizeof (nfs4_bseqid_entry_t), 19577c478bd9Sstevel@tonic-gate offsetof(nfs4_bseqid_entry_t, bs_node)); 19587c478bd9Sstevel@tonic-gate 19597c478bd9Sstevel@tonic-gate /* 19607c478bd9Sstevel@tonic-gate * Initialize the msg buffer. 19617c478bd9Sstevel@tonic-gate */ 19627c478bd9Sstevel@tonic-gate list_create(&mi->mi_msg_list, sizeof (nfs4_debug_msg_t), 19637c478bd9Sstevel@tonic-gate offsetof(nfs4_debug_msg_t, msg_node)); 19647c478bd9Sstevel@tonic-gate mi->mi_msg_count = 0; 19657c478bd9Sstevel@tonic-gate mutex_init(&mi->mi_msg_list_lock, NULL, MUTEX_DEFAULT, NULL); 19667c478bd9Sstevel@tonic-gate 19677c478bd9Sstevel@tonic-gate /* 19687c478bd9Sstevel@tonic-gate * Initialize kstats 19697c478bd9Sstevel@tonic-gate */ 19707c478bd9Sstevel@tonic-gate nfs4_mnt_kstat_init(vfsp); 19717c478bd9Sstevel@tonic-gate 19727c478bd9Sstevel@tonic-gate /* 19737c478bd9Sstevel@tonic-gate * Initialize the shared filehandle pool, and get the fname for 19747c478bd9Sstevel@tonic-gate * the filesystem root. 19757c478bd9Sstevel@tonic-gate */ 19767c478bd9Sstevel@tonic-gate sfh4_createtab(&mi->mi_filehandles); 19777c478bd9Sstevel@tonic-gate mi->mi_fname = fn_get(NULL, "."); 19787c478bd9Sstevel@tonic-gate 19797c478bd9Sstevel@tonic-gate /* 19807c478bd9Sstevel@tonic-gate * Save server path we're attempting to mount. 19817c478bd9Sstevel@tonic-gate */ 19827c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 19837c478bd9Sstevel@tonic-gate orig_sv_pathlen = svp_head->sv_pathlen; 19847c478bd9Sstevel@tonic-gate orig_sv_path = kmem_alloc(svp_head->sv_pathlen, KM_SLEEP); 19857c478bd9Sstevel@tonic-gate bcopy(svp_head->sv_path, orig_sv_path, svp_head->sv_pathlen); 19867c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 19877c478bd9Sstevel@tonic-gate 19887c478bd9Sstevel@tonic-gate /* 19897c478bd9Sstevel@tonic-gate * Make the GETFH call to get root fh for each replica. 19907c478bd9Sstevel@tonic-gate */ 19917c478bd9Sstevel@tonic-gate if (svp_head->sv_next) 19927c478bd9Sstevel@tonic-gate droptext = ", dropping replica"; 19937c478bd9Sstevel@tonic-gate 19947c478bd9Sstevel@tonic-gate /* 19957c478bd9Sstevel@tonic-gate * If the uid is set then set the creds for secure mounts 19967c478bd9Sstevel@tonic-gate * by proxy processes such as automountd. 19977c478bd9Sstevel@tonic-gate */ 19987c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 19997c478bd9Sstevel@tonic-gate if (svp->sv_secdata->uid != 0) { 20007c478bd9Sstevel@tonic-gate lcr = crdup(cr); 20017c478bd9Sstevel@tonic-gate (void) crsetugid(lcr, svp->sv_secdata->uid, crgetgid(cr)); 20027c478bd9Sstevel@tonic-gate tcr = lcr; 20037c478bd9Sstevel@tonic-gate } 20047c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 20057c478bd9Sstevel@tonic-gate for (svp = svp_head; svp; svp = svp->sv_next) { 20067c478bd9Sstevel@tonic-gate if (nfs4_chkdup_servinfo4(svp_head, svp)) { 20077c478bd9Sstevel@tonic-gate nfs_cmn_err(error, CE_WARN, 20087c478bd9Sstevel@tonic-gate VERS_MSG "Host %s is a duplicate%s", 20097c478bd9Sstevel@tonic-gate svp->sv_hostname, droptext); 20107c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 20117c478bd9Sstevel@tonic-gate svp->sv_flags |= SV4_NOTINUSE; 20127c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 20137c478bd9Sstevel@tonic-gate continue; 20147c478bd9Sstevel@tonic-gate } 20157c478bd9Sstevel@tonic-gate mi->mi_curr_serv = svp; 20167c478bd9Sstevel@tonic-gate 20177c478bd9Sstevel@tonic-gate /* 20187c478bd9Sstevel@tonic-gate * Just in case server path being mounted contains 20197c478bd9Sstevel@tonic-gate * symlinks and fails w/STALE, save the initial sv_path 20207c478bd9Sstevel@tonic-gate * so we can redrive the initial mount compound with the 20217c478bd9Sstevel@tonic-gate * initial sv_path -- not a symlink-expanded version. 20227c478bd9Sstevel@tonic-gate * 20237c478bd9Sstevel@tonic-gate * This could only happen if a symlink was expanded 20247c478bd9Sstevel@tonic-gate * and the expanded mount compound failed stale. Because 20257c478bd9Sstevel@tonic-gate * it could be the case that the symlink was removed at 20267c478bd9Sstevel@tonic-gate * the server (and replaced with another symlink/dir, 20277c478bd9Sstevel@tonic-gate * we need to use the initial sv_path when attempting 20287c478bd9Sstevel@tonic-gate * to re-lookup everything and recover. 20297c478bd9Sstevel@tonic-gate * 20307c478bd9Sstevel@tonic-gate * Other mount errors should evenutally be handled here also 20317c478bd9Sstevel@tonic-gate * (NFS4ERR_DELAY, NFS4ERR_RESOURCE). For now, all mount 20327c478bd9Sstevel@tonic-gate * failures will result in mount being redriven a few times. 20337c478bd9Sstevel@tonic-gate */ 20347c478bd9Sstevel@tonic-gate num_retry = nfs4_max_mount_retry; 20357c478bd9Sstevel@tonic-gate do { 20367c478bd9Sstevel@tonic-gate nfs4getfh_otw(mi, svp, &tmp_vtype, 20377c478bd9Sstevel@tonic-gate ((flags & NFSMNT_PUBLIC) ? NFS4_GETFH_PUBLIC : 0) | 20387c478bd9Sstevel@tonic-gate NFS4_GETFH_NEEDSOP, tcr, &e); 20397c478bd9Sstevel@tonic-gate 20407c478bd9Sstevel@tonic-gate if (e.error == 0 && e.stat == NFS4_OK) 20417c478bd9Sstevel@tonic-gate break; 20427c478bd9Sstevel@tonic-gate 20437c478bd9Sstevel@tonic-gate /* 20447c478bd9Sstevel@tonic-gate * replace current sv_path with orig sv_path -- just in 20457c478bd9Sstevel@tonic-gate * case it changed due to embedded symlinks. 20467c478bd9Sstevel@tonic-gate */ 20477c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 20487c478bd9Sstevel@tonic-gate if (orig_sv_pathlen != svp->sv_pathlen) { 20497c478bd9Sstevel@tonic-gate kmem_free(svp->sv_path, svp->sv_pathlen); 20507c478bd9Sstevel@tonic-gate svp->sv_path = kmem_alloc(orig_sv_pathlen, 20517c478bd9Sstevel@tonic-gate KM_SLEEP); 20527c478bd9Sstevel@tonic-gate svp->sv_pathlen = orig_sv_pathlen; 20537c478bd9Sstevel@tonic-gate } 20547c478bd9Sstevel@tonic-gate bcopy(orig_sv_path, svp->sv_path, orig_sv_pathlen); 20557c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 20567c478bd9Sstevel@tonic-gate 20577c478bd9Sstevel@tonic-gate } while (num_retry-- > 0); 20587c478bd9Sstevel@tonic-gate 20597c478bd9Sstevel@tonic-gate error = e.error ? e.error : geterrno4(e.stat); 20607c478bd9Sstevel@tonic-gate if (error) { 20617c478bd9Sstevel@tonic-gate nfs_cmn_err(error, CE_WARN, 20627c478bd9Sstevel@tonic-gate VERS_MSG "initial call to %s failed%s: %m", 20637c478bd9Sstevel@tonic-gate svp->sv_hostname, droptext); 20647c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 20657c478bd9Sstevel@tonic-gate svp->sv_flags |= SV4_NOTINUSE; 20667c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 20677c478bd9Sstevel@tonic-gate mi->mi_flags &= ~MI4_RECOV_FAIL; 20687c478bd9Sstevel@tonic-gate mi->mi_error = 0; 20697c478bd9Sstevel@tonic-gate continue; 20707c478bd9Sstevel@tonic-gate } 20717c478bd9Sstevel@tonic-gate 20727c478bd9Sstevel@tonic-gate if (tmp_vtype == VBAD) { 20737c478bd9Sstevel@tonic-gate zcmn_err(mi->mi_zone->zone_id, CE_WARN, 20747c478bd9Sstevel@tonic-gate VERS_MSG "%s returned a bad file type for " 20757c478bd9Sstevel@tonic-gate "root%s", svp->sv_hostname, droptext); 20767c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 20777c478bd9Sstevel@tonic-gate svp->sv_flags |= SV4_NOTINUSE; 20787c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 20797c478bd9Sstevel@tonic-gate continue; 20807c478bd9Sstevel@tonic-gate } 20817c478bd9Sstevel@tonic-gate 20827c478bd9Sstevel@tonic-gate if (vtype == VNON) { 20837c478bd9Sstevel@tonic-gate vtype = tmp_vtype; 20847c478bd9Sstevel@tonic-gate } else if (vtype != tmp_vtype) { 20857c478bd9Sstevel@tonic-gate zcmn_err(mi->mi_zone->zone_id, CE_WARN, 20867c478bd9Sstevel@tonic-gate VERS_MSG "%s returned a different file type " 20877c478bd9Sstevel@tonic-gate "for root%s", svp->sv_hostname, droptext); 20887c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 20897c478bd9Sstevel@tonic-gate svp->sv_flags |= SV4_NOTINUSE; 20907c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 20917c478bd9Sstevel@tonic-gate continue; 20927c478bd9Sstevel@tonic-gate } 20937c478bd9Sstevel@tonic-gate if (firstsvp == NULL) 20947c478bd9Sstevel@tonic-gate firstsvp = svp; 20957c478bd9Sstevel@tonic-gate } 20967c478bd9Sstevel@tonic-gate 20977c478bd9Sstevel@tonic-gate kmem_free(orig_sv_path, orig_sv_pathlen); 20987c478bd9Sstevel@tonic-gate 20997c478bd9Sstevel@tonic-gate if (firstsvp == NULL) { 21007c478bd9Sstevel@tonic-gate if (error == 0) 21017c478bd9Sstevel@tonic-gate error = ENOENT; 21027c478bd9Sstevel@tonic-gate goto bad; 21037c478bd9Sstevel@tonic-gate } 21047c478bd9Sstevel@tonic-gate 21057c478bd9Sstevel@tonic-gate mi->mi_curr_serv = svp = firstsvp; 21067c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 21077c478bd9Sstevel@tonic-gate ASSERT((mi->mi_curr_serv->sv_flags & SV4_NOTINUSE) == 0); 21087c478bd9Sstevel@tonic-gate fh.nfs_fh4_len = svp->sv_fhandle.fh_len; 21097c478bd9Sstevel@tonic-gate fh.nfs_fh4_val = svp->sv_fhandle.fh_buf; 21107c478bd9Sstevel@tonic-gate mi->mi_rootfh = sfh4_get(&fh, mi); 21117c478bd9Sstevel@tonic-gate fh.nfs_fh4_len = svp->sv_pfhandle.fh_len; 21127c478bd9Sstevel@tonic-gate fh.nfs_fh4_val = svp->sv_pfhandle.fh_buf; 21137c478bd9Sstevel@tonic-gate mi->mi_srvparentfh = sfh4_get(&fh, mi); 21147c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 21157c478bd9Sstevel@tonic-gate 21167c478bd9Sstevel@tonic-gate /* 21177c478bd9Sstevel@tonic-gate * Make the root vnode without attributes. 21187c478bd9Sstevel@tonic-gate */ 21197c478bd9Sstevel@tonic-gate mfname = mi->mi_fname; 21207c478bd9Sstevel@tonic-gate fn_hold(mfname); 21217c478bd9Sstevel@tonic-gate rtvp = makenfs4node_by_fh(mi->mi_rootfh, NULL, 21227c478bd9Sstevel@tonic-gate &mfname, NULL, mi, cr, gethrtime()); 21237c478bd9Sstevel@tonic-gate rtvp->v_type = vtype; 21247c478bd9Sstevel@tonic-gate 21257c478bd9Sstevel@tonic-gate mi->mi_curread = mi->mi_tsize; 21267c478bd9Sstevel@tonic-gate mi->mi_curwrite = mi->mi_stsize; 21277c478bd9Sstevel@tonic-gate 21287c478bd9Sstevel@tonic-gate /* 21297c478bd9Sstevel@tonic-gate * Start the manager thread responsible for handling async worker 21307c478bd9Sstevel@tonic-gate * threads. 21317c478bd9Sstevel@tonic-gate */ 213250a83466Sjwahlig MI4_HOLD(mi); 21337c478bd9Sstevel@tonic-gate VFS_HOLD(vfsp); /* add reference for thread */ 21347c478bd9Sstevel@tonic-gate mi->mi_manager_thread = zthread_create(NULL, 0, nfs4_async_manager, 21357c478bd9Sstevel@tonic-gate vfsp, 0, minclsyspri); 21367c478bd9Sstevel@tonic-gate ASSERT(mi->mi_manager_thread != NULL); 213750a83466Sjwahlig 21387c478bd9Sstevel@tonic-gate /* 21397c478bd9Sstevel@tonic-gate * Create the thread that handles over-the-wire calls for 21407c478bd9Sstevel@tonic-gate * VOP_INACTIVE. 21417c478bd9Sstevel@tonic-gate * This needs to happen after the manager thread is created. 21427c478bd9Sstevel@tonic-gate */ 214350a83466Sjwahlig MI4_HOLD(mi); 21447c478bd9Sstevel@tonic-gate mi->mi_inactive_thread = zthread_create(NULL, 0, nfs4_inactive_thread, 21457c478bd9Sstevel@tonic-gate mi, 0, minclsyspri); 21467c478bd9Sstevel@tonic-gate ASSERT(mi->mi_inactive_thread != NULL); 21477c478bd9Sstevel@tonic-gate 21487c478bd9Sstevel@tonic-gate /* If we didn't get a type, get one now */ 21497c478bd9Sstevel@tonic-gate if (rtvp->v_type == VNON) { 21507c478bd9Sstevel@tonic-gate va.va_mask = AT_TYPE; 21517c478bd9Sstevel@tonic-gate error = nfs4getattr(rtvp, &va, tcr); 21527c478bd9Sstevel@tonic-gate if (error) 21537c478bd9Sstevel@tonic-gate goto bad; 21547c478bd9Sstevel@tonic-gate rtvp->v_type = va.va_type; 21557c478bd9Sstevel@tonic-gate } 21567c478bd9Sstevel@tonic-gate 21577c478bd9Sstevel@tonic-gate mi->mi_type = rtvp->v_type; 21587c478bd9Sstevel@tonic-gate 21597c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 21607c478bd9Sstevel@tonic-gate mi->mi_flags &= ~MI4_MOUNTING; 21617c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 21627c478bd9Sstevel@tonic-gate 21637c478bd9Sstevel@tonic-gate *rtvpp = rtvp; 21647c478bd9Sstevel@tonic-gate if (lcr != NULL) 21657c478bd9Sstevel@tonic-gate crfree(lcr); 21667c478bd9Sstevel@tonic-gate 21677c478bd9Sstevel@tonic-gate return (0); 21687c478bd9Sstevel@tonic-gate bad: 21697c478bd9Sstevel@tonic-gate /* 21707c478bd9Sstevel@tonic-gate * An error occurred somewhere, need to clean up... 21717c478bd9Sstevel@tonic-gate */ 21727c478bd9Sstevel@tonic-gate if (lcr != NULL) 21737c478bd9Sstevel@tonic-gate crfree(lcr); 21747c478bd9Sstevel@tonic-gate if (rtvp != NULL) { 21757c478bd9Sstevel@tonic-gate /* 21767c478bd9Sstevel@tonic-gate * We need to release our reference to the root vnode and 21777c478bd9Sstevel@tonic-gate * destroy the mntinfo4 struct that we just created. 21787c478bd9Sstevel@tonic-gate */ 21797c478bd9Sstevel@tonic-gate rp = VTOR4(rtvp); 21807c478bd9Sstevel@tonic-gate if (rp->r_flags & R4HASHED) 21817c478bd9Sstevel@tonic-gate rp4_rmhash(rp); 21827c478bd9Sstevel@tonic-gate VN_RELE(rtvp); 21837c478bd9Sstevel@tonic-gate } 21847c478bd9Sstevel@tonic-gate nfs4_async_stop(vfsp); 21857c478bd9Sstevel@tonic-gate nfs4_async_manager_stop(vfsp); 218650a83466Sjwahlig removed = nfs4_mi_zonelist_remove(mi); 218750a83466Sjwahlig if (removed) 218850a83466Sjwahlig zone_rele(mi->mi_zone); 218950a83466Sjwahlig 219050a83466Sjwahlig /* 219150a83466Sjwahlig * This releases the initial "hold" of the mi since it will never 219250a83466Sjwahlig * be referenced by the vfsp. Also, when mount returns to vfs.c 219350a83466Sjwahlig * with an error, the vfsp will be destroyed, not rele'd. 219450a83466Sjwahlig */ 219550a83466Sjwahlig MI4_RELE(mi); 219650a83466Sjwahlig 21977c478bd9Sstevel@tonic-gate *rtvpp = NULL; 21987c478bd9Sstevel@tonic-gate return (error); 21997c478bd9Sstevel@tonic-gate } 22007c478bd9Sstevel@tonic-gate 22017c478bd9Sstevel@tonic-gate /* 22027c478bd9Sstevel@tonic-gate * vfs operations 22037c478bd9Sstevel@tonic-gate */ 22047c478bd9Sstevel@tonic-gate static int 22057c478bd9Sstevel@tonic-gate nfs4_unmount(vfs_t *vfsp, int flag, cred_t *cr) 22067c478bd9Sstevel@tonic-gate { 22077c478bd9Sstevel@tonic-gate mntinfo4_t *mi; 22087c478bd9Sstevel@tonic-gate ushort_t omax; 220950a83466Sjwahlig int removed; 22107c478bd9Sstevel@tonic-gate 22117c478bd9Sstevel@tonic-gate if (secpolicy_fs_unmount(cr, vfsp) != 0) 22127c478bd9Sstevel@tonic-gate return (EPERM); 22137c478bd9Sstevel@tonic-gate 22147c478bd9Sstevel@tonic-gate mi = VFTOMI4(vfsp); 22157c478bd9Sstevel@tonic-gate 22167c478bd9Sstevel@tonic-gate if (flag & MS_FORCE) { 22177c478bd9Sstevel@tonic-gate vfsp->vfs_flag |= VFS_UNMOUNTED; 2218108322fbScarlsonj if (nfs_zone() != mi->mi_zone) { 22197c478bd9Sstevel@tonic-gate /* 22207c478bd9Sstevel@tonic-gate * If the request is coming from the wrong zone, 22217c478bd9Sstevel@tonic-gate * we don't want to create any new threads, and 22227c478bd9Sstevel@tonic-gate * performance is not a concern. Do everything 22237c478bd9Sstevel@tonic-gate * inline. 22247c478bd9Sstevel@tonic-gate */ 22257c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_zone_debug, (CE_NOTE, 22267c478bd9Sstevel@tonic-gate "nfs4_unmount x-zone forced unmount of vfs %p\n", 22277c478bd9Sstevel@tonic-gate (void *)vfsp)); 22287c478bd9Sstevel@tonic-gate nfs4_free_mount(vfsp, cr); 22297c478bd9Sstevel@tonic-gate } else { 22307c478bd9Sstevel@tonic-gate /* 22317c478bd9Sstevel@tonic-gate * Free data structures asynchronously, to avoid 22327c478bd9Sstevel@tonic-gate * blocking the current thread (for performance 22337c478bd9Sstevel@tonic-gate * reasons only). 22347c478bd9Sstevel@tonic-gate */ 22357c478bd9Sstevel@tonic-gate async_free_mount(vfsp, cr); 22367c478bd9Sstevel@tonic-gate } 22377c478bd9Sstevel@tonic-gate return (0); 22387c478bd9Sstevel@tonic-gate } 22397c478bd9Sstevel@tonic-gate /* 22407c478bd9Sstevel@tonic-gate * Wait until all asynchronous putpage operations on 22417c478bd9Sstevel@tonic-gate * this file system are complete before flushing rnodes 22427c478bd9Sstevel@tonic-gate * from the cache. 22437c478bd9Sstevel@tonic-gate */ 22447c478bd9Sstevel@tonic-gate omax = mi->mi_max_threads; 22457c478bd9Sstevel@tonic-gate if (nfs4_async_stop_sig(vfsp)) { 2246*39d3e169Sevanl 22477c478bd9Sstevel@tonic-gate return (EINTR); 22487c478bd9Sstevel@tonic-gate } 22497c478bd9Sstevel@tonic-gate r4flush(vfsp, cr); 22507c478bd9Sstevel@tonic-gate /* 22517c478bd9Sstevel@tonic-gate * If there are any active vnodes on this file system, 22527c478bd9Sstevel@tonic-gate * then the file system is busy and can't be umounted. 22537c478bd9Sstevel@tonic-gate */ 22547c478bd9Sstevel@tonic-gate if (check_rtable4(vfsp)) { 22557c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_async_lock); 22567c478bd9Sstevel@tonic-gate mi->mi_max_threads = omax; 22577c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_async_lock); 22587c478bd9Sstevel@tonic-gate return (EBUSY); 22597c478bd9Sstevel@tonic-gate } 22607c478bd9Sstevel@tonic-gate /* 22617c478bd9Sstevel@tonic-gate * The unmount can't fail from now on, and there are no active 22627c478bd9Sstevel@tonic-gate * files that could require over-the-wire calls to the server, 22637c478bd9Sstevel@tonic-gate * so stop the async manager and the inactive thread. 22647c478bd9Sstevel@tonic-gate */ 22657c478bd9Sstevel@tonic-gate nfs4_async_manager_stop(vfsp); 22667c478bd9Sstevel@tonic-gate /* 22677c478bd9Sstevel@tonic-gate * Destroy all rnodes belonging to this file system from the 22687c478bd9Sstevel@tonic-gate * rnode hash queues and purge any resources allocated to 22697c478bd9Sstevel@tonic-gate * them. 22707c478bd9Sstevel@tonic-gate */ 22717c478bd9Sstevel@tonic-gate destroy_rtable4(vfsp, cr); 22727c478bd9Sstevel@tonic-gate vfsp->vfs_flag |= VFS_UNMOUNTED; 227350a83466Sjwahlig 22747c478bd9Sstevel@tonic-gate nfs4_remove_mi_from_server(mi, NULL); 227550a83466Sjwahlig removed = nfs4_mi_zonelist_remove(mi); 227650a83466Sjwahlig if (removed) 227750a83466Sjwahlig zone_rele(mi->mi_zone); 227850a83466Sjwahlig 22797c478bd9Sstevel@tonic-gate return (0); 22807c478bd9Sstevel@tonic-gate } 22817c478bd9Sstevel@tonic-gate 22827c478bd9Sstevel@tonic-gate /* 22837c478bd9Sstevel@tonic-gate * find root of nfs 22847c478bd9Sstevel@tonic-gate */ 22857c478bd9Sstevel@tonic-gate static int 22867c478bd9Sstevel@tonic-gate nfs4_root(vfs_t *vfsp, vnode_t **vpp) 22877c478bd9Sstevel@tonic-gate { 22887c478bd9Sstevel@tonic-gate mntinfo4_t *mi; 22897c478bd9Sstevel@tonic-gate vnode_t *vp; 22907c478bd9Sstevel@tonic-gate nfs4_fname_t *mfname; 22917c478bd9Sstevel@tonic-gate servinfo4_t *svp; 22927c478bd9Sstevel@tonic-gate 22937c478bd9Sstevel@tonic-gate mi = VFTOMI4(vfsp); 22947c478bd9Sstevel@tonic-gate 2295108322fbScarlsonj if (nfs_zone() != mi->mi_zone) 22967c478bd9Sstevel@tonic-gate return (EPERM); 22977c478bd9Sstevel@tonic-gate 22987c478bd9Sstevel@tonic-gate svp = mi->mi_curr_serv; 22997c478bd9Sstevel@tonic-gate if (svp) { 23007c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 23017c478bd9Sstevel@tonic-gate if (svp->sv_flags & SV4_ROOT_STALE) { 23027c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 23037c478bd9Sstevel@tonic-gate 23047c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 23057c478bd9Sstevel@tonic-gate if (svp->sv_flags & SV4_ROOT_STALE) { 23067c478bd9Sstevel@tonic-gate svp->sv_flags &= ~SV4_ROOT_STALE; 23077c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 23087c478bd9Sstevel@tonic-gate return (ENOENT); 23097c478bd9Sstevel@tonic-gate } 23107c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 23117c478bd9Sstevel@tonic-gate } else 23127c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 23137c478bd9Sstevel@tonic-gate } 23147c478bd9Sstevel@tonic-gate 23157c478bd9Sstevel@tonic-gate mfname = mi->mi_fname; 23167c478bd9Sstevel@tonic-gate fn_hold(mfname); 23177c478bd9Sstevel@tonic-gate vp = makenfs4node_by_fh(mi->mi_rootfh, NULL, &mfname, NULL, 23187c478bd9Sstevel@tonic-gate VFTOMI4(vfsp), CRED(), gethrtime()); 23197c478bd9Sstevel@tonic-gate 23207c478bd9Sstevel@tonic-gate if (VTOR4(vp)->r_flags & R4STALE) { 23217c478bd9Sstevel@tonic-gate VN_RELE(vp); 23227c478bd9Sstevel@tonic-gate return (ENOENT); 23237c478bd9Sstevel@tonic-gate } 23247c478bd9Sstevel@tonic-gate 23257c478bd9Sstevel@tonic-gate ASSERT(vp->v_type == VNON || vp->v_type == mi->mi_type); 23267c478bd9Sstevel@tonic-gate 23277c478bd9Sstevel@tonic-gate vp->v_type = mi->mi_type; 23287c478bd9Sstevel@tonic-gate 23297c478bd9Sstevel@tonic-gate *vpp = vp; 23307c478bd9Sstevel@tonic-gate 23317c478bd9Sstevel@tonic-gate return (0); 23327c478bd9Sstevel@tonic-gate } 23337c478bd9Sstevel@tonic-gate 23347c478bd9Sstevel@tonic-gate static int 23357c478bd9Sstevel@tonic-gate nfs4_statfs_otw(vnode_t *vp, struct statvfs64 *sbp, cred_t *cr) 23367c478bd9Sstevel@tonic-gate { 23377c478bd9Sstevel@tonic-gate int error; 23387c478bd9Sstevel@tonic-gate nfs4_ga_res_t gar; 23397c478bd9Sstevel@tonic-gate nfs4_ga_ext_res_t ger; 23407c478bd9Sstevel@tonic-gate 23417c478bd9Sstevel@tonic-gate gar.n4g_ext_res = &ger; 23427c478bd9Sstevel@tonic-gate 23437c478bd9Sstevel@tonic-gate if (error = nfs4_attr_otw(vp, TAG_FSINFO, &gar, 23447c478bd9Sstevel@tonic-gate NFS4_STATFS_ATTR_MASK, cr)) 23457c478bd9Sstevel@tonic-gate return (error); 23467c478bd9Sstevel@tonic-gate 23477c478bd9Sstevel@tonic-gate *sbp = gar.n4g_ext_res->n4g_sb; 23487c478bd9Sstevel@tonic-gate 23497c478bd9Sstevel@tonic-gate return (0); 23507c478bd9Sstevel@tonic-gate } 23517c478bd9Sstevel@tonic-gate 23527c478bd9Sstevel@tonic-gate /* 23537c478bd9Sstevel@tonic-gate * Get file system statistics. 23547c478bd9Sstevel@tonic-gate */ 23557c478bd9Sstevel@tonic-gate static int 23567c478bd9Sstevel@tonic-gate nfs4_statvfs(vfs_t *vfsp, struct statvfs64 *sbp) 23577c478bd9Sstevel@tonic-gate { 23587c478bd9Sstevel@tonic-gate int error; 23597c478bd9Sstevel@tonic-gate vnode_t *vp; 23607c478bd9Sstevel@tonic-gate cred_t *cr; 23617c478bd9Sstevel@tonic-gate 23627c478bd9Sstevel@tonic-gate error = nfs4_root(vfsp, &vp); 23637c478bd9Sstevel@tonic-gate if (error) 23647c478bd9Sstevel@tonic-gate return (error); 23657c478bd9Sstevel@tonic-gate 23667c478bd9Sstevel@tonic-gate cr = CRED(); 23677c478bd9Sstevel@tonic-gate 23687c478bd9Sstevel@tonic-gate error = nfs4_statfs_otw(vp, sbp, cr); 23697c478bd9Sstevel@tonic-gate if (!error) { 23707c478bd9Sstevel@tonic-gate (void) strncpy(sbp->f_basetype, 23717c478bd9Sstevel@tonic-gate vfssw[vfsp->vfs_fstype].vsw_name, FSTYPSZ); 23727c478bd9Sstevel@tonic-gate sbp->f_flag = vf_to_stf(vfsp->vfs_flag); 23737c478bd9Sstevel@tonic-gate } else { 23747c478bd9Sstevel@tonic-gate nfs4_purge_stale_fh(error, vp, cr); 23757c478bd9Sstevel@tonic-gate } 23767c478bd9Sstevel@tonic-gate 23777c478bd9Sstevel@tonic-gate VN_RELE(vp); 23787c478bd9Sstevel@tonic-gate 23797c478bd9Sstevel@tonic-gate return (error); 23807c478bd9Sstevel@tonic-gate } 23817c478bd9Sstevel@tonic-gate 23827c478bd9Sstevel@tonic-gate static kmutex_t nfs4_syncbusy; 23837c478bd9Sstevel@tonic-gate 23847c478bd9Sstevel@tonic-gate /* 23857c478bd9Sstevel@tonic-gate * Flush dirty nfs files for file system vfsp. 23867c478bd9Sstevel@tonic-gate * If vfsp == NULL, all nfs files are flushed. 23877c478bd9Sstevel@tonic-gate * 23887c478bd9Sstevel@tonic-gate * SYNC_CLOSE in flag is passed to us to 23897c478bd9Sstevel@tonic-gate * indicate that we are shutting down and or 23907c478bd9Sstevel@tonic-gate * rebooting. 23917c478bd9Sstevel@tonic-gate */ 23927c478bd9Sstevel@tonic-gate static int 23937c478bd9Sstevel@tonic-gate nfs4_sync(vfs_t *vfsp, short flag, cred_t *cr) 23947c478bd9Sstevel@tonic-gate { 23957c478bd9Sstevel@tonic-gate /* 23967c478bd9Sstevel@tonic-gate * Cross-zone calls are OK here, since this translates to a 23977c478bd9Sstevel@tonic-gate * VOP_PUTPAGE(B_ASYNC), which gets picked up by the right zone. 23987c478bd9Sstevel@tonic-gate */ 23997c478bd9Sstevel@tonic-gate if (!(flag & SYNC_ATTR) && mutex_tryenter(&nfs4_syncbusy) != 0) { 24007c478bd9Sstevel@tonic-gate r4flush(vfsp, cr); 24017c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_syncbusy); 24027c478bd9Sstevel@tonic-gate } 24037c478bd9Sstevel@tonic-gate 24047c478bd9Sstevel@tonic-gate /* 24057c478bd9Sstevel@tonic-gate * if SYNC_CLOSE is set then we know that 24067c478bd9Sstevel@tonic-gate * the system is rebooting, mark the mntinfo 24077c478bd9Sstevel@tonic-gate * for later examination. 24087c478bd9Sstevel@tonic-gate */ 24097c478bd9Sstevel@tonic-gate if (vfsp && (flag & SYNC_CLOSE)) { 24107c478bd9Sstevel@tonic-gate mntinfo4_t *mi; 24117c478bd9Sstevel@tonic-gate 24127c478bd9Sstevel@tonic-gate mi = VFTOMI4(vfsp); 24137c478bd9Sstevel@tonic-gate if (!(mi->mi_flags & MI4_SHUTDOWN)) { 24147c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 24157c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_SHUTDOWN; 24167c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 24177c478bd9Sstevel@tonic-gate } 24187c478bd9Sstevel@tonic-gate } 24197c478bd9Sstevel@tonic-gate return (0); 24207c478bd9Sstevel@tonic-gate } 24217c478bd9Sstevel@tonic-gate 24227c478bd9Sstevel@tonic-gate /* 24237c478bd9Sstevel@tonic-gate * vget is difficult, if not impossible, to support in v4 because we don't 24247c478bd9Sstevel@tonic-gate * know the parent directory or name, which makes it impossible to create a 24257c478bd9Sstevel@tonic-gate * useful shadow vnode. And we need the shadow vnode for things like 24267c478bd9Sstevel@tonic-gate * OPEN. 24277c478bd9Sstevel@tonic-gate */ 24287c478bd9Sstevel@tonic-gate 24297c478bd9Sstevel@tonic-gate /* ARGSUSED */ 24307c478bd9Sstevel@tonic-gate /* 24317c478bd9Sstevel@tonic-gate * XXX Check nfs4_vget_pseudo() for dependency. 24327c478bd9Sstevel@tonic-gate */ 24337c478bd9Sstevel@tonic-gate static int 24347c478bd9Sstevel@tonic-gate nfs4_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp) 24357c478bd9Sstevel@tonic-gate { 24367c478bd9Sstevel@tonic-gate return (EREMOTE); 24377c478bd9Sstevel@tonic-gate } 24387c478bd9Sstevel@tonic-gate 24397c478bd9Sstevel@tonic-gate /* 24407c478bd9Sstevel@tonic-gate * nfs4_mountroot get called in the case where we are diskless booting. All 24417c478bd9Sstevel@tonic-gate * we need from here is the ability to get the server info and from there we 24427c478bd9Sstevel@tonic-gate * can simply call nfs4_rootvp. 24437c478bd9Sstevel@tonic-gate */ 24447c478bd9Sstevel@tonic-gate /* ARGSUSED */ 24457c478bd9Sstevel@tonic-gate static int 24467c478bd9Sstevel@tonic-gate nfs4_mountroot(vfs_t *vfsp, whymountroot_t why) 24477c478bd9Sstevel@tonic-gate { 24487c478bd9Sstevel@tonic-gate vnode_t *rtvp; 24497c478bd9Sstevel@tonic-gate char root_hostname[SYS_NMLN+1]; 24507c478bd9Sstevel@tonic-gate struct servinfo4 *svp; 24517c478bd9Sstevel@tonic-gate int error; 24527c478bd9Sstevel@tonic-gate int vfsflags; 24537c478bd9Sstevel@tonic-gate size_t size; 24547c478bd9Sstevel@tonic-gate char *root_path; 24557c478bd9Sstevel@tonic-gate struct pathname pn; 24567c478bd9Sstevel@tonic-gate char *name; 24577c478bd9Sstevel@tonic-gate cred_t *cr; 24587c478bd9Sstevel@tonic-gate mntinfo4_t *mi; 24597c478bd9Sstevel@tonic-gate struct nfs_args args; /* nfs mount arguments */ 24607c478bd9Sstevel@tonic-gate static char token[10]; 24617c478bd9Sstevel@tonic-gate nfs4_error_t n4e; 24627c478bd9Sstevel@tonic-gate 24637c478bd9Sstevel@tonic-gate bzero(&args, sizeof (args)); 24647c478bd9Sstevel@tonic-gate 24657c478bd9Sstevel@tonic-gate /* do this BEFORE getfile which causes xid stamps to be initialized */ 24667c478bd9Sstevel@tonic-gate clkset(-1L); /* hack for now - until we get time svc? */ 24677c478bd9Sstevel@tonic-gate 24687c478bd9Sstevel@tonic-gate if (why == ROOT_REMOUNT) { 24697c478bd9Sstevel@tonic-gate /* 24707c478bd9Sstevel@tonic-gate * Shouldn't happen. 24717c478bd9Sstevel@tonic-gate */ 24727c478bd9Sstevel@tonic-gate panic("nfs4_mountroot: why == ROOT_REMOUNT"); 24737c478bd9Sstevel@tonic-gate } 24747c478bd9Sstevel@tonic-gate 24757c478bd9Sstevel@tonic-gate if (why == ROOT_UNMOUNT) { 24767c478bd9Sstevel@tonic-gate /* 24777c478bd9Sstevel@tonic-gate * Nothing to do for NFS. 24787c478bd9Sstevel@tonic-gate */ 24797c478bd9Sstevel@tonic-gate return (0); 24807c478bd9Sstevel@tonic-gate } 24817c478bd9Sstevel@tonic-gate 24827c478bd9Sstevel@tonic-gate /* 24837c478bd9Sstevel@tonic-gate * why == ROOT_INIT 24847c478bd9Sstevel@tonic-gate */ 24857c478bd9Sstevel@tonic-gate 24867c478bd9Sstevel@tonic-gate name = token; 24877c478bd9Sstevel@tonic-gate *name = 0; 24887c478bd9Sstevel@tonic-gate (void) getfsname("root", name, sizeof (token)); 24897c478bd9Sstevel@tonic-gate 24907c478bd9Sstevel@tonic-gate pn_alloc(&pn); 24917c478bd9Sstevel@tonic-gate root_path = pn.pn_path; 24927c478bd9Sstevel@tonic-gate 24937c478bd9Sstevel@tonic-gate svp = kmem_zalloc(sizeof (*svp), KM_SLEEP); 24947c478bd9Sstevel@tonic-gate nfs_rw_init(&svp->sv_lock, NULL, RW_DEFAULT, NULL); 24957c478bd9Sstevel@tonic-gate svp->sv_knconf = kmem_zalloc(sizeof (*svp->sv_knconf), KM_SLEEP); 24967c478bd9Sstevel@tonic-gate svp->sv_knconf->knc_protofmly = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 24977c478bd9Sstevel@tonic-gate svp->sv_knconf->knc_proto = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 24987c478bd9Sstevel@tonic-gate 24997c478bd9Sstevel@tonic-gate /* 25007c478bd9Sstevel@tonic-gate * Get server address 25017c478bd9Sstevel@tonic-gate * Get the root path 25027c478bd9Sstevel@tonic-gate * Get server's transport 25037c478bd9Sstevel@tonic-gate * Get server's hostname 25047c478bd9Sstevel@tonic-gate * Get options 25057c478bd9Sstevel@tonic-gate */ 25067c478bd9Sstevel@tonic-gate args.addr = &svp->sv_addr; 25077c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 25087c478bd9Sstevel@tonic-gate args.fh = (char *)&svp->sv_fhandle; 25097c478bd9Sstevel@tonic-gate args.knconf = svp->sv_knconf; 25107c478bd9Sstevel@tonic-gate args.hostname = root_hostname; 25117c478bd9Sstevel@tonic-gate vfsflags = 0; 25127c478bd9Sstevel@tonic-gate if (error = mount_root(*name ? name : "root", root_path, NFS_V4, 25137c478bd9Sstevel@tonic-gate &args, &vfsflags)) { 25147c478bd9Sstevel@tonic-gate if (error == EPROTONOSUPPORT) 25157c478bd9Sstevel@tonic-gate nfs_cmn_err(error, CE_WARN, "nfs4_mountroot: " 25167c478bd9Sstevel@tonic-gate "mount_root failed: server doesn't support NFS V4"); 25177c478bd9Sstevel@tonic-gate else 25187c478bd9Sstevel@tonic-gate nfs_cmn_err(error, CE_WARN, 25197c478bd9Sstevel@tonic-gate "nfs4_mountroot: mount_root failed: %m"); 25207c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 25217c478bd9Sstevel@tonic-gate sv4_free(svp); 25227c478bd9Sstevel@tonic-gate pn_free(&pn); 25237c478bd9Sstevel@tonic-gate return (error); 25247c478bd9Sstevel@tonic-gate } 25257c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 25267c478bd9Sstevel@tonic-gate svp->sv_hostnamelen = (int)(strlen(root_hostname) + 1); 25277c478bd9Sstevel@tonic-gate svp->sv_hostname = kmem_alloc(svp->sv_hostnamelen, KM_SLEEP); 25287c478bd9Sstevel@tonic-gate (void) strcpy(svp->sv_hostname, root_hostname); 25297c478bd9Sstevel@tonic-gate 25307c478bd9Sstevel@tonic-gate svp->sv_pathlen = (int)(strlen(root_path) + 1); 25317c478bd9Sstevel@tonic-gate svp->sv_path = kmem_alloc(svp->sv_pathlen, KM_SLEEP); 25327c478bd9Sstevel@tonic-gate (void) strcpy(svp->sv_path, root_path); 25337c478bd9Sstevel@tonic-gate 25347c478bd9Sstevel@tonic-gate /* 25357c478bd9Sstevel@tonic-gate * Force root partition to always be mounted with AUTH_UNIX for now 25367c478bd9Sstevel@tonic-gate */ 25377c478bd9Sstevel@tonic-gate svp->sv_secdata = kmem_alloc(sizeof (*svp->sv_secdata), KM_SLEEP); 25387c478bd9Sstevel@tonic-gate svp->sv_secdata->secmod = AUTH_UNIX; 25397c478bd9Sstevel@tonic-gate svp->sv_secdata->rpcflavor = AUTH_UNIX; 25407c478bd9Sstevel@tonic-gate svp->sv_secdata->data = NULL; 25417c478bd9Sstevel@tonic-gate 25427c478bd9Sstevel@tonic-gate cr = crgetcred(); 25437c478bd9Sstevel@tonic-gate rtvp = NULL; 25447c478bd9Sstevel@tonic-gate 25457c478bd9Sstevel@tonic-gate error = nfs4rootvp(&rtvp, vfsp, svp, args.flags, cr, global_zone); 25467c478bd9Sstevel@tonic-gate 25477c478bd9Sstevel@tonic-gate if (error) { 25487c478bd9Sstevel@tonic-gate crfree(cr); 25497c478bd9Sstevel@tonic-gate pn_free(&pn); 25507c478bd9Sstevel@tonic-gate goto errout; 25517c478bd9Sstevel@tonic-gate } 25527c478bd9Sstevel@tonic-gate 25537c478bd9Sstevel@tonic-gate mi = VTOMI4(rtvp); 25547c478bd9Sstevel@tonic-gate 25557c478bd9Sstevel@tonic-gate /* 25567c478bd9Sstevel@tonic-gate * Send client id to the server, if necessary 25577c478bd9Sstevel@tonic-gate */ 25587c478bd9Sstevel@tonic-gate nfs4_error_zinit(&n4e); 25597c478bd9Sstevel@tonic-gate nfs4setclientid(mi, cr, FALSE, &n4e); 25607c478bd9Sstevel@tonic-gate error = n4e.error; 25617c478bd9Sstevel@tonic-gate 25627c478bd9Sstevel@tonic-gate crfree(cr); 25637c478bd9Sstevel@tonic-gate 25647c478bd9Sstevel@tonic-gate if (error) { 25657c478bd9Sstevel@tonic-gate pn_free(&pn); 25667c478bd9Sstevel@tonic-gate goto errout; 25677c478bd9Sstevel@tonic-gate } 25687c478bd9Sstevel@tonic-gate 25697c478bd9Sstevel@tonic-gate error = nfs4_setopts(rtvp, DATAMODEL_NATIVE, &args); 25707c478bd9Sstevel@tonic-gate if (error) { 25717c478bd9Sstevel@tonic-gate nfs_cmn_err(error, CE_WARN, 25727c478bd9Sstevel@tonic-gate "nfs4_mountroot: invalid root mount options"); 25737c478bd9Sstevel@tonic-gate pn_free(&pn); 25747c478bd9Sstevel@tonic-gate goto errout; 25757c478bd9Sstevel@tonic-gate } 25767c478bd9Sstevel@tonic-gate 25777c478bd9Sstevel@tonic-gate (void) vfs_lock_wait(vfsp); 25787c478bd9Sstevel@tonic-gate vfs_add(NULL, vfsp, vfsflags); 25797c478bd9Sstevel@tonic-gate vfs_unlock(vfsp); 25807c478bd9Sstevel@tonic-gate 25817c478bd9Sstevel@tonic-gate size = strlen(svp->sv_hostname); 25827c478bd9Sstevel@tonic-gate (void) strcpy(rootfs.bo_name, svp->sv_hostname); 25837c478bd9Sstevel@tonic-gate rootfs.bo_name[size] = ':'; 25847c478bd9Sstevel@tonic-gate (void) strcpy(&rootfs.bo_name[size + 1], root_path); 25857c478bd9Sstevel@tonic-gate 25867c478bd9Sstevel@tonic-gate pn_free(&pn); 25877c478bd9Sstevel@tonic-gate 25887c478bd9Sstevel@tonic-gate errout: 25897c478bd9Sstevel@tonic-gate if (error) { 25907c478bd9Sstevel@tonic-gate sv4_free(svp); 25917c478bd9Sstevel@tonic-gate nfs4_async_stop(vfsp); 25927c478bd9Sstevel@tonic-gate nfs4_async_manager_stop(vfsp); 25937c478bd9Sstevel@tonic-gate } 25947c478bd9Sstevel@tonic-gate 25957c478bd9Sstevel@tonic-gate if (rtvp != NULL) 25967c478bd9Sstevel@tonic-gate VN_RELE(rtvp); 25977c478bd9Sstevel@tonic-gate 25987c478bd9Sstevel@tonic-gate return (error); 25997c478bd9Sstevel@tonic-gate } 26007c478bd9Sstevel@tonic-gate 26017c478bd9Sstevel@tonic-gate /* 26027c478bd9Sstevel@tonic-gate * Initialization routine for VFS routines. Should only be called once 26037c478bd9Sstevel@tonic-gate */ 26047c478bd9Sstevel@tonic-gate int 26057c478bd9Sstevel@tonic-gate nfs4_vfsinit(void) 26067c478bd9Sstevel@tonic-gate { 26077c478bd9Sstevel@tonic-gate mutex_init(&nfs4_syncbusy, NULL, MUTEX_DEFAULT, NULL); 26087c478bd9Sstevel@tonic-gate nfs4setclientid_init(); 26097c478bd9Sstevel@tonic-gate return (0); 26107c478bd9Sstevel@tonic-gate } 26117c478bd9Sstevel@tonic-gate 26127c478bd9Sstevel@tonic-gate void 26137c478bd9Sstevel@tonic-gate nfs4_vfsfini(void) 26147c478bd9Sstevel@tonic-gate { 26157c478bd9Sstevel@tonic-gate nfs4setclientid_fini(); 26167c478bd9Sstevel@tonic-gate mutex_destroy(&nfs4_syncbusy); 26177c478bd9Sstevel@tonic-gate } 26187c478bd9Sstevel@tonic-gate 26197c478bd9Sstevel@tonic-gate void 26207c478bd9Sstevel@tonic-gate nfs4_freevfs(vfs_t *vfsp) 26217c478bd9Sstevel@tonic-gate { 26227c478bd9Sstevel@tonic-gate mntinfo4_t *mi; 26237c478bd9Sstevel@tonic-gate 262450a83466Sjwahlig /* need to release the initial hold */ 26257c478bd9Sstevel@tonic-gate mi = VFTOMI4(vfsp); 262650a83466Sjwahlig MI4_RELE(mi); 26277c478bd9Sstevel@tonic-gate } 26287c478bd9Sstevel@tonic-gate 26297c478bd9Sstevel@tonic-gate /* 26307c478bd9Sstevel@tonic-gate * Client side SETCLIENTID and SETCLIENTID_CONFIRM 26317c478bd9Sstevel@tonic-gate */ 26327c478bd9Sstevel@tonic-gate struct nfs4_server nfs4_server_lst = 26337c478bd9Sstevel@tonic-gate { &nfs4_server_lst, &nfs4_server_lst }; 26347c478bd9Sstevel@tonic-gate 26357c478bd9Sstevel@tonic-gate kmutex_t nfs4_server_lst_lock; 26367c478bd9Sstevel@tonic-gate 26377c478bd9Sstevel@tonic-gate static void 26387c478bd9Sstevel@tonic-gate nfs4setclientid_init(void) 26397c478bd9Sstevel@tonic-gate { 26407c478bd9Sstevel@tonic-gate mutex_init(&nfs4_server_lst_lock, NULL, MUTEX_DEFAULT, NULL); 26417c478bd9Sstevel@tonic-gate } 26427c478bd9Sstevel@tonic-gate 26437c478bd9Sstevel@tonic-gate static void 26447c478bd9Sstevel@tonic-gate nfs4setclientid_fini(void) 26457c478bd9Sstevel@tonic-gate { 26467c478bd9Sstevel@tonic-gate mutex_destroy(&nfs4_server_lst_lock); 26477c478bd9Sstevel@tonic-gate } 26487c478bd9Sstevel@tonic-gate 26497c478bd9Sstevel@tonic-gate int nfs4_retry_sclid_delay = NFS4_RETRY_SCLID_DELAY; 26507c478bd9Sstevel@tonic-gate int nfs4_num_sclid_retries = NFS4_NUM_SCLID_RETRIES; 26517c478bd9Sstevel@tonic-gate 26527c478bd9Sstevel@tonic-gate /* 26537c478bd9Sstevel@tonic-gate * Set the clientid for the server for "mi". No-op if the clientid is 26547c478bd9Sstevel@tonic-gate * already set. 26557c478bd9Sstevel@tonic-gate * 26567c478bd9Sstevel@tonic-gate * The recovery boolean should be set to TRUE if this function was called 2657a092743bSek * by the recovery code, and FALSE otherwise. This is used to determine 2658a092743bSek * if we need to call nfs4_start/end_op as well as grab the mi_recovlock 2659a092743bSek * for adding a mntinfo4_t to a nfs4_server_t. 26607c478bd9Sstevel@tonic-gate * 26617c478bd9Sstevel@tonic-gate * Error is returned via 'n4ep'. If there was a 'n4ep->stat' error, then 26627c478bd9Sstevel@tonic-gate * 'n4ep->error' is set to geterrno4(n4ep->stat). 26637c478bd9Sstevel@tonic-gate */ 26647c478bd9Sstevel@tonic-gate void 26657c478bd9Sstevel@tonic-gate nfs4setclientid(mntinfo4_t *mi, cred_t *cr, bool_t recovery, nfs4_error_t *n4ep) 26667c478bd9Sstevel@tonic-gate { 26677c478bd9Sstevel@tonic-gate struct nfs4_server *np; 26687c478bd9Sstevel@tonic-gate struct servinfo4 *svp = mi->mi_curr_serv; 26697c478bd9Sstevel@tonic-gate nfs4_recov_state_t recov_state; 26707c478bd9Sstevel@tonic-gate int num_retries = 0; 2671f64c4ae1Sdm bool_t retry; 26727c478bd9Sstevel@tonic-gate cred_t *lcr = NULL; 26737c478bd9Sstevel@tonic-gate int retry_inuse = 1; /* only retry once on NFS4ERR_CLID_INUSE */ 26747c478bd9Sstevel@tonic-gate time_t lease_time = 0; 26757c478bd9Sstevel@tonic-gate 26767c478bd9Sstevel@tonic-gate recov_state.rs_flags = 0; 26777c478bd9Sstevel@tonic-gate recov_state.rs_num_retry_despite_err = 0; 26787c478bd9Sstevel@tonic-gate ASSERT(n4ep != NULL); 26797c478bd9Sstevel@tonic-gate 26807c478bd9Sstevel@tonic-gate recov_retry: 2681f64c4ae1Sdm retry = FALSE; 26827c478bd9Sstevel@tonic-gate nfs4_error_zinit(n4ep); 2683a092743bSek if (!recovery) 2684a092743bSek (void) nfs_rw_enter_sig(&mi->mi_recovlock, RW_READER, 0); 2685a092743bSek 2686f86c6ccaSdm mutex_enter(&nfs4_server_lst_lock); 2687f86c6ccaSdm np = servinfo4_to_nfs4_server(svp); /* This locks np if it is found */ 2688f86c6ccaSdm mutex_exit(&nfs4_server_lst_lock); 2689f86c6ccaSdm if (!np) { 2690f86c6ccaSdm struct nfs4_server *tnp; 2691f86c6ccaSdm np = new_nfs4_server(svp, cr); 269216237317Sdm mutex_enter(&np->s_lock); 26937c478bd9Sstevel@tonic-gate 2694f86c6ccaSdm mutex_enter(&nfs4_server_lst_lock); 2695f86c6ccaSdm tnp = servinfo4_to_nfs4_server(svp); 2696f86c6ccaSdm if (tnp) { 2697f86c6ccaSdm /* 2698f86c6ccaSdm * another thread snuck in and put server on list. 2699f86c6ccaSdm * since we aren't adding it to the nfs4_server_list 2700f86c6ccaSdm * we need to set the ref count to 0 and destroy it. 2701f86c6ccaSdm */ 2702f86c6ccaSdm np->s_refcnt = 0; 2703f86c6ccaSdm destroy_nfs4_server(np); 2704f86c6ccaSdm np = tnp; 2705f86c6ccaSdm } else { 2706f86c6ccaSdm /* 2707f86c6ccaSdm * do not give list a reference until everything 2708f86c6ccaSdm * succeeds 2709f86c6ccaSdm */ 2710f86c6ccaSdm insque(np, &nfs4_server_lst); 2711f86c6ccaSdm } 2712f86c6ccaSdm mutex_exit(&nfs4_server_lst_lock); 2713f86c6ccaSdm } 2714f86c6ccaSdm ASSERT(MUTEX_HELD(&np->s_lock)); 27157c478bd9Sstevel@tonic-gate /* 2716f86c6ccaSdm * If we find the server already has N4S_CLIENTID_SET, then 2717f86c6ccaSdm * just return, we've already done SETCLIENTID to that server 27187c478bd9Sstevel@tonic-gate */ 2719f86c6ccaSdm if (np->s_flags & N4S_CLIENTID_SET) { 27207c478bd9Sstevel@tonic-gate /* add mi to np's mntinfo4_list */ 27217c478bd9Sstevel@tonic-gate nfs4_add_mi_to_server(np, mi); 2722a092743bSek if (!recovery) 2723a092743bSek nfs_rw_exit(&mi->mi_recovlock); 27247c478bd9Sstevel@tonic-gate mutex_exit(&np->s_lock); 27257c478bd9Sstevel@tonic-gate nfs4_server_rele(np); 27267c478bd9Sstevel@tonic-gate return; 27277c478bd9Sstevel@tonic-gate } 2728f86c6ccaSdm mutex_exit(&np->s_lock); 2729f86c6ccaSdm 27307c478bd9Sstevel@tonic-gate 2731a092743bSek /* 2732a092743bSek * Drop the mi_recovlock since nfs4_start_op will 2733a092743bSek * acquire it again for us. 2734a092743bSek */ 2735f86c6ccaSdm if (!recovery) { 2736a092743bSek nfs_rw_exit(&mi->mi_recovlock); 2737a092743bSek 27387c478bd9Sstevel@tonic-gate n4ep->error = nfs4_start_op(mi, NULL, NULL, &recov_state); 27397c478bd9Sstevel@tonic-gate if (n4ep->error) { 27407c478bd9Sstevel@tonic-gate nfs4_server_rele(np); 27417c478bd9Sstevel@tonic-gate return; 27427c478bd9Sstevel@tonic-gate } 27437c478bd9Sstevel@tonic-gate } 27447c478bd9Sstevel@tonic-gate 27457c478bd9Sstevel@tonic-gate mutex_enter(&np->s_lock); 2746f86c6ccaSdm while (np->s_flags & N4S_CLIENTID_PEND) { 2747f86c6ccaSdm if (!cv_wait_sig(&np->s_clientid_pend, &np->s_lock)) { 2748f86c6ccaSdm mutex_exit(&np->s_lock); 2749f86c6ccaSdm nfs4_server_rele(np); 2750f86c6ccaSdm if (!recovery) 2751f86c6ccaSdm nfs4_end_op(mi, NULL, NULL, &recov_state, 2752f86c6ccaSdm recovery); 2753f86c6ccaSdm n4ep->error = EINTR; 2754f86c6ccaSdm return; 2755f86c6ccaSdm } 2756f86c6ccaSdm } 27577c478bd9Sstevel@tonic-gate 27587c478bd9Sstevel@tonic-gate if (np->s_flags & N4S_CLIENTID_SET) { 27597c478bd9Sstevel@tonic-gate /* XXX copied/pasted from above */ 27607c478bd9Sstevel@tonic-gate /* add mi to np's mntinfo4_list */ 27617c478bd9Sstevel@tonic-gate nfs4_add_mi_to_server(np, mi); 27627c478bd9Sstevel@tonic-gate mutex_exit(&np->s_lock); 27637c478bd9Sstevel@tonic-gate nfs4_server_rele(np); 27647c478bd9Sstevel@tonic-gate if (!recovery) 27657c478bd9Sstevel@tonic-gate nfs4_end_op(mi, NULL, NULL, &recov_state, recovery); 27667c478bd9Sstevel@tonic-gate return; 27677c478bd9Sstevel@tonic-gate } 27687c478bd9Sstevel@tonic-gate 2769f86c6ccaSdm /* 2770f86c6ccaSdm * Reset the N4S_CB_PINGED flag. This is used to 2771f86c6ccaSdm * indicate if we have received a CB_NULL from the 2772f86c6ccaSdm * server. Also we reset the waiter flag. 2773f86c6ccaSdm */ 2774f86c6ccaSdm np->s_flags &= ~(N4S_CB_PINGED | N4S_CB_WAITER); 2775f86c6ccaSdm /* any failure must now clear this flag */ 2776f86c6ccaSdm np->s_flags |= N4S_CLIENTID_PEND; 2777f86c6ccaSdm mutex_exit(&np->s_lock); 27787c478bd9Sstevel@tonic-gate nfs4setclientid_otw(mi, svp, cr, np, n4ep, &retry_inuse); 27797c478bd9Sstevel@tonic-gate 27807c478bd9Sstevel@tonic-gate if (n4ep->error == EACCES) { 27817c478bd9Sstevel@tonic-gate /* 27827c478bd9Sstevel@tonic-gate * If the uid is set then set the creds for secure mounts 27837c478bd9Sstevel@tonic-gate * by proxy processes such as automountd. 27847c478bd9Sstevel@tonic-gate */ 27857c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 27867c478bd9Sstevel@tonic-gate if (svp->sv_secdata->uid != 0) { 27877c478bd9Sstevel@tonic-gate lcr = crdup(cr); 27887c478bd9Sstevel@tonic-gate (void) crsetugid(lcr, svp->sv_secdata->uid, 27897c478bd9Sstevel@tonic-gate crgetgid(cr)); 27907c478bd9Sstevel@tonic-gate } 27917c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 27927c478bd9Sstevel@tonic-gate 2793f86c6ccaSdm if (lcr != NULL) { 2794f86c6ccaSdm mutex_enter(&np->s_lock); 2795f86c6ccaSdm crfree(np->s_cred); 2796f86c6ccaSdm np->s_cred = lcr; 2797f86c6ccaSdm mutex_exit(&np->s_lock); 27987c478bd9Sstevel@tonic-gate nfs4setclientid_otw(mi, svp, lcr, np, n4ep, 27997c478bd9Sstevel@tonic-gate &retry_inuse); 2800f86c6ccaSdm } 28017c478bd9Sstevel@tonic-gate } 2802f86c6ccaSdm mutex_enter(&np->s_lock); 28037c478bd9Sstevel@tonic-gate lease_time = np->s_lease_time; 2804f86c6ccaSdm np->s_flags &= ~N4S_CLIENTID_PEND; 28057c478bd9Sstevel@tonic-gate mutex_exit(&np->s_lock); 28067c478bd9Sstevel@tonic-gate 28077c478bd9Sstevel@tonic-gate if (n4ep->error != 0 || n4ep->stat != NFS4_OK) { 28087c478bd9Sstevel@tonic-gate /* 28097c478bd9Sstevel@tonic-gate * Start recovery if failover is a possibility. If 28107c478bd9Sstevel@tonic-gate * invoked by the recovery thread itself, then just 28117c478bd9Sstevel@tonic-gate * return and let it handle the failover first. NB: 28127c478bd9Sstevel@tonic-gate * recovery is not allowed if the mount is in progress 28137c478bd9Sstevel@tonic-gate * since the infrastructure is not sufficiently setup 28147c478bd9Sstevel@tonic-gate * to allow it. Just return the error (after suitable 28157c478bd9Sstevel@tonic-gate * retries). 28167c478bd9Sstevel@tonic-gate */ 28177c478bd9Sstevel@tonic-gate if (FAILOVER_MOUNT4(mi) && nfs4_try_failover(n4ep)) { 28187c478bd9Sstevel@tonic-gate (void) nfs4_start_recovery(n4ep, mi, NULL, 28197c478bd9Sstevel@tonic-gate NULL, NULL, NULL, OP_SETCLIENTID, NULL); 28207c478bd9Sstevel@tonic-gate /* 28217c478bd9Sstevel@tonic-gate * Don't retry here, just return and let 28227c478bd9Sstevel@tonic-gate * recovery take over. 28237c478bd9Sstevel@tonic-gate */ 28247c478bd9Sstevel@tonic-gate if (recovery) 28257c478bd9Sstevel@tonic-gate retry = FALSE; 28267c478bd9Sstevel@tonic-gate } else if (nfs4_rpc_retry_error(n4ep->error) || 28277c478bd9Sstevel@tonic-gate n4ep->stat == NFS4ERR_RESOURCE || 28287c478bd9Sstevel@tonic-gate n4ep->stat == NFS4ERR_STALE_CLIENTID) { 28297c478bd9Sstevel@tonic-gate 28307c478bd9Sstevel@tonic-gate retry = TRUE; 28317c478bd9Sstevel@tonic-gate /* 28327c478bd9Sstevel@tonic-gate * Always retry if in recovery or once had 28337c478bd9Sstevel@tonic-gate * contact with the server (but now it's 28347c478bd9Sstevel@tonic-gate * overloaded). 28357c478bd9Sstevel@tonic-gate */ 28367c478bd9Sstevel@tonic-gate if (recovery == TRUE || 28377c478bd9Sstevel@tonic-gate n4ep->error == ETIMEDOUT || 28387c478bd9Sstevel@tonic-gate n4ep->error == ECONNRESET) 28397c478bd9Sstevel@tonic-gate num_retries = 0; 28407c478bd9Sstevel@tonic-gate } else if (retry_inuse && n4ep->error == 0 && 28417c478bd9Sstevel@tonic-gate n4ep->stat == NFS4ERR_CLID_INUSE) { 28427c478bd9Sstevel@tonic-gate retry = TRUE; 28437c478bd9Sstevel@tonic-gate num_retries = 0; 28447c478bd9Sstevel@tonic-gate } 2845f86c6ccaSdm } else { 2846f64c4ae1Sdm /* 2847f64c4ae1Sdm * Since everything succeeded give the list a reference count if 2848f64c4ae1Sdm * it hasn't been given one by add_new_nfs4_server() or if this 2849f64c4ae1Sdm * is not a recovery situation in which case it is already on 2850f64c4ae1Sdm * the list. 2851f64c4ae1Sdm */ 2852f86c6ccaSdm mutex_enter(&np->s_lock); 2853f64c4ae1Sdm if ((np->s_flags & N4S_INSERTED) == 0) { 2854f64c4ae1Sdm np->s_refcnt++; 2855f64c4ae1Sdm np->s_flags |= N4S_INSERTED; 2856f64c4ae1Sdm } 2857f86c6ccaSdm mutex_exit(&np->s_lock); 28587c478bd9Sstevel@tonic-gate } 28597c478bd9Sstevel@tonic-gate 28607c478bd9Sstevel@tonic-gate if (!recovery) 28617c478bd9Sstevel@tonic-gate nfs4_end_op(mi, NULL, NULL, &recov_state, recovery); 2862f86c6ccaSdm 28637c478bd9Sstevel@tonic-gate 28647c478bd9Sstevel@tonic-gate if (retry && num_retries++ < nfs4_num_sclid_retries) { 28657c478bd9Sstevel@tonic-gate if (retry_inuse) { 28667c478bd9Sstevel@tonic-gate delay(SEC_TO_TICK(lease_time + nfs4_retry_sclid_delay)); 28677c478bd9Sstevel@tonic-gate retry_inuse = 0; 28687c478bd9Sstevel@tonic-gate } else 28697c478bd9Sstevel@tonic-gate delay(SEC_TO_TICK(nfs4_retry_sclid_delay)); 2870f86c6ccaSdm 2871f86c6ccaSdm nfs4_server_rele(np); 28727c478bd9Sstevel@tonic-gate goto recov_retry; 28737c478bd9Sstevel@tonic-gate } 28747c478bd9Sstevel@tonic-gate 2875f86c6ccaSdm 28767c478bd9Sstevel@tonic-gate if (n4ep->error == 0) 28777c478bd9Sstevel@tonic-gate n4ep->error = geterrno4(n4ep->stat); 2878f86c6ccaSdm 2879f86c6ccaSdm /* broadcast before release in case no other threads are waiting */ 2880f86c6ccaSdm cv_broadcast(&np->s_clientid_pend); 2881f86c6ccaSdm nfs4_server_rele(np); 28827c478bd9Sstevel@tonic-gate } 28837c478bd9Sstevel@tonic-gate 28847c478bd9Sstevel@tonic-gate int nfs4setclientid_otw_debug = 0; 28857c478bd9Sstevel@tonic-gate 28867c478bd9Sstevel@tonic-gate /* 28877c478bd9Sstevel@tonic-gate * This function handles the recovery of STALE_CLIENTID for SETCLIENTID_CONFRIM, 28887c478bd9Sstevel@tonic-gate * but nothing else; the calling function must be designed to handle those 28897c478bd9Sstevel@tonic-gate * other errors. 28907c478bd9Sstevel@tonic-gate */ 28917c478bd9Sstevel@tonic-gate static void 28927c478bd9Sstevel@tonic-gate nfs4setclientid_otw(mntinfo4_t *mi, struct servinfo4 *svp, cred_t *cr, 28937c478bd9Sstevel@tonic-gate struct nfs4_server *np, nfs4_error_t *ep, int *retry_inusep) 28947c478bd9Sstevel@tonic-gate { 28957c478bd9Sstevel@tonic-gate COMPOUND4args_clnt args; 28967c478bd9Sstevel@tonic-gate COMPOUND4res_clnt res; 28977c478bd9Sstevel@tonic-gate nfs_argop4 argop[3]; 28987c478bd9Sstevel@tonic-gate SETCLIENTID4args *s_args; 28997c478bd9Sstevel@tonic-gate SETCLIENTID4resok *s_resok; 29007c478bd9Sstevel@tonic-gate int doqueue = 1; 29017c478bd9Sstevel@tonic-gate nfs4_ga_res_t *garp = NULL; 29027c478bd9Sstevel@tonic-gate timespec_t prop_time, after_time; 29037c478bd9Sstevel@tonic-gate verifier4 verf; 29047c478bd9Sstevel@tonic-gate clientid4 tmp_clientid; 29057c478bd9Sstevel@tonic-gate 2906f86c6ccaSdm ASSERT(!MUTEX_HELD(&np->s_lock)); 29077c478bd9Sstevel@tonic-gate 29087c478bd9Sstevel@tonic-gate args.ctag = TAG_SETCLIENTID; 29097c478bd9Sstevel@tonic-gate 29107c478bd9Sstevel@tonic-gate args.array = argop; 29117c478bd9Sstevel@tonic-gate args.array_len = 3; 29127c478bd9Sstevel@tonic-gate 29137c478bd9Sstevel@tonic-gate /* PUTROOTFH */ 29147c478bd9Sstevel@tonic-gate argop[0].argop = OP_PUTROOTFH; 29157c478bd9Sstevel@tonic-gate 29167c478bd9Sstevel@tonic-gate /* GETATTR */ 29177c478bd9Sstevel@tonic-gate argop[1].argop = OP_GETATTR; 29187c478bd9Sstevel@tonic-gate argop[1].nfs_argop4_u.opgetattr.attr_request = FATTR4_LEASE_TIME_MASK; 29197c478bd9Sstevel@tonic-gate argop[1].nfs_argop4_u.opgetattr.mi = mi; 29207c478bd9Sstevel@tonic-gate 29217c478bd9Sstevel@tonic-gate /* SETCLIENTID */ 29227c478bd9Sstevel@tonic-gate argop[2].argop = OP_SETCLIENTID; 29237c478bd9Sstevel@tonic-gate 29247c478bd9Sstevel@tonic-gate s_args = &argop[2].nfs_argop4_u.opsetclientid; 29257c478bd9Sstevel@tonic-gate 2926f86c6ccaSdm mutex_enter(&np->s_lock); 2927f86c6ccaSdm 29287c478bd9Sstevel@tonic-gate s_args->client.verifier = np->clidtosend.verifier; 29297c478bd9Sstevel@tonic-gate s_args->client.id_len = np->clidtosend.id_len; 29307c478bd9Sstevel@tonic-gate ASSERT(s_args->client.id_len <= NFS4_OPAQUE_LIMIT); 29317c478bd9Sstevel@tonic-gate s_args->client.id_val = np->clidtosend.id_val; 29327c478bd9Sstevel@tonic-gate 29337c478bd9Sstevel@tonic-gate /* 29347c478bd9Sstevel@tonic-gate * Callback needs to happen on non-RDMA transport 29357c478bd9Sstevel@tonic-gate * Check if we have saved the original knetconfig 29367c478bd9Sstevel@tonic-gate * if so, use that instead. 29377c478bd9Sstevel@tonic-gate */ 29387c478bd9Sstevel@tonic-gate if (svp->sv_origknconf != NULL) 29397c478bd9Sstevel@tonic-gate nfs4_cb_args(np, svp->sv_origknconf, s_args); 29407c478bd9Sstevel@tonic-gate else 29417c478bd9Sstevel@tonic-gate nfs4_cb_args(np, svp->sv_knconf, s_args); 29427c478bd9Sstevel@tonic-gate 2943f86c6ccaSdm mutex_exit(&np->s_lock); 2944f86c6ccaSdm 2945f86c6ccaSdm rfs4call(mi, &args, &res, cr, &doqueue, 0, ep); 29467c478bd9Sstevel@tonic-gate 29477c478bd9Sstevel@tonic-gate if (ep->error) 29487c478bd9Sstevel@tonic-gate return; 29497c478bd9Sstevel@tonic-gate 29507c478bd9Sstevel@tonic-gate /* getattr lease_time res */ 29517c478bd9Sstevel@tonic-gate if (res.array_len >= 2) { 29527c478bd9Sstevel@tonic-gate garp = &res.array[1].nfs_resop4_u.opgetattr.ga_res; 29537c478bd9Sstevel@tonic-gate 29547c478bd9Sstevel@tonic-gate #ifndef _LP64 29557c478bd9Sstevel@tonic-gate /* 29567c478bd9Sstevel@tonic-gate * The 32 bit client cannot handle a lease time greater than 29577c478bd9Sstevel@tonic-gate * (INT32_MAX/1000000). This is due to the use of the 29587c478bd9Sstevel@tonic-gate * lease_time in calls to drv_usectohz() in 29597c478bd9Sstevel@tonic-gate * nfs4_renew_lease_thread(). The problem is that 29607c478bd9Sstevel@tonic-gate * drv_usectohz() takes a time_t (which is just a long = 4 29617c478bd9Sstevel@tonic-gate * bytes) as its parameter. The lease_time is multiplied by 29627c478bd9Sstevel@tonic-gate * 1000000 to convert seconds to usecs for the parameter. If 29637c478bd9Sstevel@tonic-gate * a number bigger than (INT32_MAX/1000000) is used then we 29647c478bd9Sstevel@tonic-gate * overflow on the 32bit client. 29657c478bd9Sstevel@tonic-gate */ 29667c478bd9Sstevel@tonic-gate if (garp->n4g_ext_res->n4g_leasetime > (INT32_MAX/1000000)) { 29677c478bd9Sstevel@tonic-gate garp->n4g_ext_res->n4g_leasetime = INT32_MAX/1000000; 29687c478bd9Sstevel@tonic-gate } 29697c478bd9Sstevel@tonic-gate #endif 29707c478bd9Sstevel@tonic-gate 2971f86c6ccaSdm mutex_enter(&np->s_lock); 29727c478bd9Sstevel@tonic-gate np->s_lease_time = garp->n4g_ext_res->n4g_leasetime; 29737c478bd9Sstevel@tonic-gate 29747c478bd9Sstevel@tonic-gate /* 29757c478bd9Sstevel@tonic-gate * Keep track of the lease period for the mi's 29767c478bd9Sstevel@tonic-gate * mi_msg_list. We need an appropiate time 29777c478bd9Sstevel@tonic-gate * bound to associate past facts with a current 29787c478bd9Sstevel@tonic-gate * event. The lease period is perfect for this. 29797c478bd9Sstevel@tonic-gate */ 29807c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_msg_list_lock); 29817c478bd9Sstevel@tonic-gate mi->mi_lease_period = np->s_lease_time; 29827c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_msg_list_lock); 2983f86c6ccaSdm mutex_exit(&np->s_lock); 29847c478bd9Sstevel@tonic-gate } 29857c478bd9Sstevel@tonic-gate 29867c478bd9Sstevel@tonic-gate 29877c478bd9Sstevel@tonic-gate if (res.status == NFS4ERR_CLID_INUSE) { 29887c478bd9Sstevel@tonic-gate clientaddr4 *clid_inuse; 29897c478bd9Sstevel@tonic-gate 29907c478bd9Sstevel@tonic-gate if (!(*retry_inusep)) { 29917c478bd9Sstevel@tonic-gate clid_inuse = &res.array->nfs_resop4_u. 29927c478bd9Sstevel@tonic-gate opsetclientid.SETCLIENTID4res_u.client_using; 29937c478bd9Sstevel@tonic-gate 29947c478bd9Sstevel@tonic-gate zcmn_err(mi->mi_zone->zone_id, CE_NOTE, 29957c478bd9Sstevel@tonic-gate "NFS4 mount (SETCLIENTID failed)." 29967c478bd9Sstevel@tonic-gate " nfs4_client_id.id is in" 29977c478bd9Sstevel@tonic-gate "use already by: r_netid<%s> r_addr<%s>", 29987c478bd9Sstevel@tonic-gate clid_inuse->r_netid, clid_inuse->r_addr); 29997c478bd9Sstevel@tonic-gate } 30007c478bd9Sstevel@tonic-gate 30017c478bd9Sstevel@tonic-gate /* 30027c478bd9Sstevel@tonic-gate * XXX - The client should be more robust in its 30037c478bd9Sstevel@tonic-gate * handling of clientid in use errors (regen another 30047c478bd9Sstevel@tonic-gate * clientid and try again?) 30057c478bd9Sstevel@tonic-gate */ 30067c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 30077c478bd9Sstevel@tonic-gate return; 30087c478bd9Sstevel@tonic-gate } 30097c478bd9Sstevel@tonic-gate 30107c478bd9Sstevel@tonic-gate if (res.status) { 30117c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 30127c478bd9Sstevel@tonic-gate return; 30137c478bd9Sstevel@tonic-gate } 30147c478bd9Sstevel@tonic-gate 30157c478bd9Sstevel@tonic-gate s_resok = &res.array[2].nfs_resop4_u. 30167c478bd9Sstevel@tonic-gate opsetclientid.SETCLIENTID4res_u.resok4; 30177c478bd9Sstevel@tonic-gate 30187c478bd9Sstevel@tonic-gate tmp_clientid = s_resok->clientid; 30197c478bd9Sstevel@tonic-gate 30207c478bd9Sstevel@tonic-gate verf = s_resok->setclientid_confirm; 30217c478bd9Sstevel@tonic-gate 30227c478bd9Sstevel@tonic-gate #ifdef DEBUG 30237c478bd9Sstevel@tonic-gate if (nfs4setclientid_otw_debug) { 30247c478bd9Sstevel@tonic-gate union { 30257c478bd9Sstevel@tonic-gate clientid4 clientid; 30267c478bd9Sstevel@tonic-gate int foo[2]; 30277c478bd9Sstevel@tonic-gate } cid; 30287c478bd9Sstevel@tonic-gate 30297c478bd9Sstevel@tonic-gate cid.clientid = s_resok->clientid; 30307c478bd9Sstevel@tonic-gate 30317c478bd9Sstevel@tonic-gate zcmn_err(mi->mi_zone->zone_id, CE_NOTE, 30327c478bd9Sstevel@tonic-gate "nfs4setclientid_otw: OK, clientid = %x,%x, " 30337c478bd9Sstevel@tonic-gate "verifier = %" PRIx64 "\n", cid.foo[0], cid.foo[1], verf); 30347c478bd9Sstevel@tonic-gate } 30357c478bd9Sstevel@tonic-gate #endif 30367c478bd9Sstevel@tonic-gate 30377c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 30387c478bd9Sstevel@tonic-gate 30397c478bd9Sstevel@tonic-gate /* Confirm the client id and get the lease_time attribute */ 30407c478bd9Sstevel@tonic-gate 30417c478bd9Sstevel@tonic-gate args.ctag = TAG_SETCLIENTID_CF; 30427c478bd9Sstevel@tonic-gate 30437c478bd9Sstevel@tonic-gate args.array = argop; 30447c478bd9Sstevel@tonic-gate args.array_len = 1; 30457c478bd9Sstevel@tonic-gate 30467c478bd9Sstevel@tonic-gate argop[0].argop = OP_SETCLIENTID_CONFIRM; 30477c478bd9Sstevel@tonic-gate 30487c478bd9Sstevel@tonic-gate argop[0].nfs_argop4_u.opsetclientid_confirm.clientid = tmp_clientid; 30497c478bd9Sstevel@tonic-gate argop[0].nfs_argop4_u.opsetclientid_confirm.setclientid_confirm = verf; 30507c478bd9Sstevel@tonic-gate 30517c478bd9Sstevel@tonic-gate /* used to figure out RTT for np */ 30527c478bd9Sstevel@tonic-gate gethrestime(&prop_time); 30537c478bd9Sstevel@tonic-gate 30547c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, "nfs4setlientid_otw: " 30557c478bd9Sstevel@tonic-gate "start time: %ld sec %ld nsec", prop_time.tv_sec, 30567c478bd9Sstevel@tonic-gate prop_time.tv_nsec)); 30577c478bd9Sstevel@tonic-gate 30587c478bd9Sstevel@tonic-gate rfs4call(mi, &args, &res, cr, &doqueue, 0, ep); 30597c478bd9Sstevel@tonic-gate 30607c478bd9Sstevel@tonic-gate gethrestime(&after_time); 3061f86c6ccaSdm mutex_enter(&np->s_lock); 30627c478bd9Sstevel@tonic-gate np->propagation_delay.tv_sec = 30637c478bd9Sstevel@tonic-gate MAX(1, after_time.tv_sec - prop_time.tv_sec); 3064f86c6ccaSdm mutex_exit(&np->s_lock); 30657c478bd9Sstevel@tonic-gate 30667c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, "nfs4setlcientid_otw: " 30677c478bd9Sstevel@tonic-gate "finish time: %ld sec ", after_time.tv_sec)); 30687c478bd9Sstevel@tonic-gate 30697c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, "nfs4setclientid_otw: " 30707c478bd9Sstevel@tonic-gate "propagation delay set to %ld sec", 30717c478bd9Sstevel@tonic-gate np->propagation_delay.tv_sec)); 30727c478bd9Sstevel@tonic-gate 30737c478bd9Sstevel@tonic-gate if (ep->error) 30747c478bd9Sstevel@tonic-gate return; 30757c478bd9Sstevel@tonic-gate 30767c478bd9Sstevel@tonic-gate if (res.status == NFS4ERR_CLID_INUSE) { 30777c478bd9Sstevel@tonic-gate clientaddr4 *clid_inuse; 30787c478bd9Sstevel@tonic-gate 30797c478bd9Sstevel@tonic-gate if (!(*retry_inusep)) { 30807c478bd9Sstevel@tonic-gate clid_inuse = &res.array->nfs_resop4_u. 30817c478bd9Sstevel@tonic-gate opsetclientid.SETCLIENTID4res_u.client_using; 30827c478bd9Sstevel@tonic-gate 30837c478bd9Sstevel@tonic-gate zcmn_err(mi->mi_zone->zone_id, CE_NOTE, 30847c478bd9Sstevel@tonic-gate "SETCLIENTID_CONFIRM failed. " 30857c478bd9Sstevel@tonic-gate "nfs4_client_id.id is in use already by: " 30867c478bd9Sstevel@tonic-gate "r_netid<%s> r_addr<%s>", 30877c478bd9Sstevel@tonic-gate clid_inuse->r_netid, clid_inuse->r_addr); 30887c478bd9Sstevel@tonic-gate } 30897c478bd9Sstevel@tonic-gate 30907c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 30917c478bd9Sstevel@tonic-gate return; 30927c478bd9Sstevel@tonic-gate } 30937c478bd9Sstevel@tonic-gate 30947c478bd9Sstevel@tonic-gate if (res.status) { 30957c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 30967c478bd9Sstevel@tonic-gate return; 30977c478bd9Sstevel@tonic-gate } 30987c478bd9Sstevel@tonic-gate 3099f86c6ccaSdm mutex_enter(&np->s_lock); 31007c478bd9Sstevel@tonic-gate np->clientid = tmp_clientid; 31017c478bd9Sstevel@tonic-gate np->s_flags |= N4S_CLIENTID_SET; 31027c478bd9Sstevel@tonic-gate 31037c478bd9Sstevel@tonic-gate /* Add mi to np's mntinfo4 list */ 31047c478bd9Sstevel@tonic-gate nfs4_add_mi_to_server(np, mi); 31057c478bd9Sstevel@tonic-gate 31067c478bd9Sstevel@tonic-gate if (np->lease_valid == NFS4_LEASE_NOT_STARTED) { 31077c478bd9Sstevel@tonic-gate /* 31087c478bd9Sstevel@tonic-gate * Start lease management thread. 31097c478bd9Sstevel@tonic-gate * Keep trying until we succeed. 31107c478bd9Sstevel@tonic-gate */ 31117c478bd9Sstevel@tonic-gate 31127c478bd9Sstevel@tonic-gate np->s_refcnt++; /* pass reference to thread */ 31137c478bd9Sstevel@tonic-gate (void) zthread_create(NULL, 0, nfs4_renew_lease_thread, np, 0, 31147c478bd9Sstevel@tonic-gate minclsyspri); 31157c478bd9Sstevel@tonic-gate } 3116f86c6ccaSdm mutex_exit(&np->s_lock); 31177c478bd9Sstevel@tonic-gate 31187c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 31197c478bd9Sstevel@tonic-gate } 31207c478bd9Sstevel@tonic-gate 31217c478bd9Sstevel@tonic-gate /* 31227c478bd9Sstevel@tonic-gate * Add mi to sp's mntinfo4_list if it isn't already in the list. Makes 31237c478bd9Sstevel@tonic-gate * mi's clientid the same as sp's. 31247c478bd9Sstevel@tonic-gate * Assumes sp is locked down. 31257c478bd9Sstevel@tonic-gate */ 31267c478bd9Sstevel@tonic-gate void 31277c478bd9Sstevel@tonic-gate nfs4_add_mi_to_server(nfs4_server_t *sp, mntinfo4_t *mi) 31287c478bd9Sstevel@tonic-gate { 31297c478bd9Sstevel@tonic-gate mntinfo4_t *tmi; 31307c478bd9Sstevel@tonic-gate int in_list = 0; 31317c478bd9Sstevel@tonic-gate 3132a092743bSek ASSERT(nfs_rw_lock_held(&mi->mi_recovlock, RW_READER) || 3133a092743bSek nfs_rw_lock_held(&mi->mi_recovlock, RW_WRITER)); 31347c478bd9Sstevel@tonic-gate ASSERT(sp != &nfs4_server_lst); 31357c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sp->s_lock)); 31367c478bd9Sstevel@tonic-gate 31377c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, 31387c478bd9Sstevel@tonic-gate "nfs4_add_mi_to_server: add mi %p to sp %p", 31397c478bd9Sstevel@tonic-gate (void*)mi, (void*)sp)); 31407c478bd9Sstevel@tonic-gate 31417c478bd9Sstevel@tonic-gate for (tmi = sp->mntinfo4_list; 31427c478bd9Sstevel@tonic-gate tmi != NULL; 31437c478bd9Sstevel@tonic-gate tmi = tmi->mi_clientid_next) { 31447c478bd9Sstevel@tonic-gate if (tmi == mi) { 31457c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, 31467c478bd9Sstevel@tonic-gate (CE_NOTE, 31477c478bd9Sstevel@tonic-gate "nfs4_add_mi_to_server: mi in list")); 31487c478bd9Sstevel@tonic-gate in_list = 1; 31497c478bd9Sstevel@tonic-gate } 31507c478bd9Sstevel@tonic-gate } 31517c478bd9Sstevel@tonic-gate 31527c478bd9Sstevel@tonic-gate /* 31537c478bd9Sstevel@tonic-gate * First put a hold on the mntinfo4's vfsp so that references via 31547c478bd9Sstevel@tonic-gate * mntinfo4_list will be valid. 31557c478bd9Sstevel@tonic-gate */ 31567c478bd9Sstevel@tonic-gate if (!in_list) 31577c478bd9Sstevel@tonic-gate VFS_HOLD(mi->mi_vfsp); 31587c478bd9Sstevel@tonic-gate 31597c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, "nfs4_add_mi_to_server: " 31607c478bd9Sstevel@tonic-gate "hold vfs %p for mi: %p", (void*)mi->mi_vfsp, (void*)mi)); 31617c478bd9Sstevel@tonic-gate 31627c478bd9Sstevel@tonic-gate if (!in_list) { 31637c478bd9Sstevel@tonic-gate if (sp->mntinfo4_list) 31647c478bd9Sstevel@tonic-gate sp->mntinfo4_list->mi_clientid_prev = mi; 31657c478bd9Sstevel@tonic-gate mi->mi_clientid_next = sp->mntinfo4_list; 31667c478bd9Sstevel@tonic-gate sp->mntinfo4_list = mi; 31677c478bd9Sstevel@tonic-gate mi->mi_srvsettime = gethrestime_sec(); 31687c478bd9Sstevel@tonic-gate } 31697c478bd9Sstevel@tonic-gate 31707c478bd9Sstevel@tonic-gate /* set mi's clientid to that of sp's for later matching */ 31717c478bd9Sstevel@tonic-gate mi->mi_clientid = sp->clientid; 31727c478bd9Sstevel@tonic-gate 31737c478bd9Sstevel@tonic-gate /* 31747c478bd9Sstevel@tonic-gate * Update the clientid for any other mi's belonging to sp. This 31757c478bd9Sstevel@tonic-gate * must be done here while we hold sp->s_lock, so that 31767c478bd9Sstevel@tonic-gate * find_nfs4_server() continues to work. 31777c478bd9Sstevel@tonic-gate */ 31787c478bd9Sstevel@tonic-gate 31797c478bd9Sstevel@tonic-gate for (tmi = sp->mntinfo4_list; 31807c478bd9Sstevel@tonic-gate tmi != NULL; 31817c478bd9Sstevel@tonic-gate tmi = tmi->mi_clientid_next) { 31827c478bd9Sstevel@tonic-gate if (tmi != mi) { 31837c478bd9Sstevel@tonic-gate tmi->mi_clientid = sp->clientid; 31847c478bd9Sstevel@tonic-gate } 31857c478bd9Sstevel@tonic-gate } 31867c478bd9Sstevel@tonic-gate } 31877c478bd9Sstevel@tonic-gate 31887c478bd9Sstevel@tonic-gate /* 31897c478bd9Sstevel@tonic-gate * Remove the mi from sp's mntinfo4_list and release its reference. 31907c478bd9Sstevel@tonic-gate * Exception: if mi still has open files, flag it for later removal (when 31917c478bd9Sstevel@tonic-gate * all the files are closed). 31927c478bd9Sstevel@tonic-gate * 31937c478bd9Sstevel@tonic-gate * If this is the last mntinfo4 in sp's list then tell the lease renewal 31947c478bd9Sstevel@tonic-gate * thread to exit. 31957c478bd9Sstevel@tonic-gate */ 31967c478bd9Sstevel@tonic-gate static void 31977c478bd9Sstevel@tonic-gate nfs4_remove_mi_from_server_nolock(mntinfo4_t *mi, nfs4_server_t *sp) 31987c478bd9Sstevel@tonic-gate { 31997c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, 32007c478bd9Sstevel@tonic-gate "nfs4_remove_mi_from_server_nolock: remove mi %p from sp %p", 32017c478bd9Sstevel@tonic-gate (void*)mi, (void*)sp)); 32027c478bd9Sstevel@tonic-gate 32037c478bd9Sstevel@tonic-gate ASSERT(sp != NULL); 32047c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sp->s_lock)); 32057c478bd9Sstevel@tonic-gate ASSERT(mi->mi_open_files >= 0); 32067c478bd9Sstevel@tonic-gate 32077c478bd9Sstevel@tonic-gate /* 32087c478bd9Sstevel@tonic-gate * First make sure this mntinfo4 can be taken off of the list, 32097c478bd9Sstevel@tonic-gate * ie: it doesn't have any open files remaining. 32107c478bd9Sstevel@tonic-gate */ 32117c478bd9Sstevel@tonic-gate if (mi->mi_open_files > 0) { 32127c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, 32137c478bd9Sstevel@tonic-gate "nfs4_remove_mi_from_server_nolock: don't " 32147c478bd9Sstevel@tonic-gate "remove mi since it still has files open")); 32157c478bd9Sstevel@tonic-gate 32167c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 32177c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_REMOVE_ON_LAST_CLOSE; 32187c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 32197c478bd9Sstevel@tonic-gate return; 32207c478bd9Sstevel@tonic-gate } 32217c478bd9Sstevel@tonic-gate 322250a83466Sjwahlig VFS_HOLD(mi->mi_vfsp); 32237c478bd9Sstevel@tonic-gate remove_mi(sp, mi); 322450a83466Sjwahlig VFS_RELE(mi->mi_vfsp); 32257c478bd9Sstevel@tonic-gate 32267c478bd9Sstevel@tonic-gate if (sp->mntinfo4_list == NULL) { 32277c478bd9Sstevel@tonic-gate /* last fs unmounted, kill the thread */ 32287c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, 32297c478bd9Sstevel@tonic-gate "remove_mi_from_nfs4_server_nolock: kill the thread")); 32307c478bd9Sstevel@tonic-gate nfs4_mark_srv_dead(sp); 32317c478bd9Sstevel@tonic-gate } 32327c478bd9Sstevel@tonic-gate } 32337c478bd9Sstevel@tonic-gate 32347c478bd9Sstevel@tonic-gate /* 32357c478bd9Sstevel@tonic-gate * Remove mi from sp's mntinfo4_list and release the vfs reference. 32367c478bd9Sstevel@tonic-gate */ 32377c478bd9Sstevel@tonic-gate static void 32387c478bd9Sstevel@tonic-gate remove_mi(nfs4_server_t *sp, mntinfo4_t *mi) 32397c478bd9Sstevel@tonic-gate { 32407c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sp->s_lock)); 32417c478bd9Sstevel@tonic-gate 32427c478bd9Sstevel@tonic-gate /* 32437c478bd9Sstevel@tonic-gate * We release a reference, and the caller must still have a 32447c478bd9Sstevel@tonic-gate * reference. 32457c478bd9Sstevel@tonic-gate */ 32467c478bd9Sstevel@tonic-gate ASSERT(mi->mi_vfsp->vfs_count >= 2); 32477c478bd9Sstevel@tonic-gate 32487c478bd9Sstevel@tonic-gate if (mi->mi_clientid_prev) { 32497c478bd9Sstevel@tonic-gate mi->mi_clientid_prev->mi_clientid_next = mi->mi_clientid_next; 32507c478bd9Sstevel@tonic-gate } else { 32517c478bd9Sstevel@tonic-gate /* This is the first mi in sp's mntinfo4_list */ 32527c478bd9Sstevel@tonic-gate /* 32537c478bd9Sstevel@tonic-gate * Make sure the first mntinfo4 in the list is the actual 32547c478bd9Sstevel@tonic-gate * mntinfo4 passed in. 32557c478bd9Sstevel@tonic-gate */ 32567c478bd9Sstevel@tonic-gate ASSERT(sp->mntinfo4_list == mi); 32577c478bd9Sstevel@tonic-gate 32587c478bd9Sstevel@tonic-gate sp->mntinfo4_list = mi->mi_clientid_next; 32597c478bd9Sstevel@tonic-gate } 32607c478bd9Sstevel@tonic-gate if (mi->mi_clientid_next) 32617c478bd9Sstevel@tonic-gate mi->mi_clientid_next->mi_clientid_prev = mi->mi_clientid_prev; 32627c478bd9Sstevel@tonic-gate 32637c478bd9Sstevel@tonic-gate /* Now mark the mntinfo4's links as being removed */ 32647c478bd9Sstevel@tonic-gate mi->mi_clientid_prev = mi->mi_clientid_next = NULL; 32657c478bd9Sstevel@tonic-gate 32667c478bd9Sstevel@tonic-gate VFS_RELE(mi->mi_vfsp); 32677c478bd9Sstevel@tonic-gate } 32687c478bd9Sstevel@tonic-gate 32697c478bd9Sstevel@tonic-gate /* 32707c478bd9Sstevel@tonic-gate * Free all the entries in sp's mntinfo4_list. 32717c478bd9Sstevel@tonic-gate */ 32727c478bd9Sstevel@tonic-gate static void 32737c478bd9Sstevel@tonic-gate remove_all_mi(nfs4_server_t *sp) 32747c478bd9Sstevel@tonic-gate { 32757c478bd9Sstevel@tonic-gate mntinfo4_t *mi; 32767c478bd9Sstevel@tonic-gate 32777c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sp->s_lock)); 32787c478bd9Sstevel@tonic-gate 32797c478bd9Sstevel@tonic-gate while (sp->mntinfo4_list != NULL) { 32807c478bd9Sstevel@tonic-gate mi = sp->mntinfo4_list; 32817c478bd9Sstevel@tonic-gate /* 32827c478bd9Sstevel@tonic-gate * Grab a reference in case there is only one left (which 32837c478bd9Sstevel@tonic-gate * remove_mi() frees). 32847c478bd9Sstevel@tonic-gate */ 32857c478bd9Sstevel@tonic-gate VFS_HOLD(mi->mi_vfsp); 32867c478bd9Sstevel@tonic-gate remove_mi(sp, mi); 32877c478bd9Sstevel@tonic-gate VFS_RELE(mi->mi_vfsp); 32887c478bd9Sstevel@tonic-gate } 32897c478bd9Sstevel@tonic-gate } 32907c478bd9Sstevel@tonic-gate 32917c478bd9Sstevel@tonic-gate /* 32927c478bd9Sstevel@tonic-gate * Remove the mi from sp's mntinfo4_list as above, and rele the vfs. 32937c478bd9Sstevel@tonic-gate * 32947c478bd9Sstevel@tonic-gate * This version can be called with a null nfs4_server_t arg, 32957c478bd9Sstevel@tonic-gate * and will either find the right one and handle locking, or 32967c478bd9Sstevel@tonic-gate * do nothing because the mi wasn't added to an sp's mntinfo4_list. 32977c478bd9Sstevel@tonic-gate */ 32987c478bd9Sstevel@tonic-gate void 32997c478bd9Sstevel@tonic-gate nfs4_remove_mi_from_server(mntinfo4_t *mi, nfs4_server_t *esp) 33007c478bd9Sstevel@tonic-gate { 33017c478bd9Sstevel@tonic-gate nfs4_server_t *sp; 33027c478bd9Sstevel@tonic-gate 33037c478bd9Sstevel@tonic-gate if (esp == NULL) { 33047c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&mi->mi_recovlock, RW_READER, 0); 33057c478bd9Sstevel@tonic-gate sp = find_nfs4_server_all(mi, 1); 33067c478bd9Sstevel@tonic-gate } else 33077c478bd9Sstevel@tonic-gate sp = esp; 33087c478bd9Sstevel@tonic-gate 33097c478bd9Sstevel@tonic-gate if (sp != NULL) 33107c478bd9Sstevel@tonic-gate nfs4_remove_mi_from_server_nolock(mi, sp); 33117c478bd9Sstevel@tonic-gate 33127c478bd9Sstevel@tonic-gate /* 33137c478bd9Sstevel@tonic-gate * If we had a valid esp as input, the calling function will be 33147c478bd9Sstevel@tonic-gate * responsible for unlocking the esp nfs4_server. 33157c478bd9Sstevel@tonic-gate */ 33167c478bd9Sstevel@tonic-gate if (esp == NULL) { 33177c478bd9Sstevel@tonic-gate if (sp != NULL) 33187c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_lock); 33197c478bd9Sstevel@tonic-gate nfs_rw_exit(&mi->mi_recovlock); 33207c478bd9Sstevel@tonic-gate if (sp != NULL) 33217c478bd9Sstevel@tonic-gate nfs4_server_rele(sp); 33227c478bd9Sstevel@tonic-gate } 33237c478bd9Sstevel@tonic-gate } 33247c478bd9Sstevel@tonic-gate 33257c478bd9Sstevel@tonic-gate /* 33267c478bd9Sstevel@tonic-gate * Return TRUE if the given server has any non-unmounted filesystems. 33277c478bd9Sstevel@tonic-gate */ 33287c478bd9Sstevel@tonic-gate 33297c478bd9Sstevel@tonic-gate bool_t 33307c478bd9Sstevel@tonic-gate nfs4_fs_active(nfs4_server_t *sp) 33317c478bd9Sstevel@tonic-gate { 33327c478bd9Sstevel@tonic-gate mntinfo4_t *mi; 33337c478bd9Sstevel@tonic-gate 33347c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sp->s_lock)); 33357c478bd9Sstevel@tonic-gate 33367c478bd9Sstevel@tonic-gate for (mi = sp->mntinfo4_list; mi != NULL; mi = mi->mi_clientid_next) { 33377c478bd9Sstevel@tonic-gate if (!(mi->mi_vfsp->vfs_flag & VFS_UNMOUNTED)) 33387c478bd9Sstevel@tonic-gate return (TRUE); 33397c478bd9Sstevel@tonic-gate } 33407c478bd9Sstevel@tonic-gate 33417c478bd9Sstevel@tonic-gate return (FALSE); 33427c478bd9Sstevel@tonic-gate } 33437c478bd9Sstevel@tonic-gate 33447c478bd9Sstevel@tonic-gate /* 33457c478bd9Sstevel@tonic-gate * Mark sp as finished and notify any waiters. 33467c478bd9Sstevel@tonic-gate */ 33477c478bd9Sstevel@tonic-gate 33487c478bd9Sstevel@tonic-gate void 33497c478bd9Sstevel@tonic-gate nfs4_mark_srv_dead(nfs4_server_t *sp) 33507c478bd9Sstevel@tonic-gate { 33517c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sp->s_lock)); 33527c478bd9Sstevel@tonic-gate 33537c478bd9Sstevel@tonic-gate sp->s_thread_exit = NFS4_THREAD_EXIT; 33547c478bd9Sstevel@tonic-gate cv_broadcast(&sp->cv_thread_exit); 33557c478bd9Sstevel@tonic-gate } 33567c478bd9Sstevel@tonic-gate 33577c478bd9Sstevel@tonic-gate /* 33587c478bd9Sstevel@tonic-gate * Create a new nfs4_server_t structure. 33597c478bd9Sstevel@tonic-gate * Returns new node unlocked and not in list, but with a reference count of 33607c478bd9Sstevel@tonic-gate * 1. 33617c478bd9Sstevel@tonic-gate */ 33627c478bd9Sstevel@tonic-gate struct nfs4_server * 33637c478bd9Sstevel@tonic-gate new_nfs4_server(struct servinfo4 *svp, cred_t *cr) 33647c478bd9Sstevel@tonic-gate { 33657c478bd9Sstevel@tonic-gate struct nfs4_server *np; 33667c478bd9Sstevel@tonic-gate timespec_t tt; 33677c478bd9Sstevel@tonic-gate union { 33687c478bd9Sstevel@tonic-gate struct { 33697c478bd9Sstevel@tonic-gate uint32_t sec; 33707c478bd9Sstevel@tonic-gate uint32_t subsec; 33717c478bd9Sstevel@tonic-gate } un_curtime; 33727c478bd9Sstevel@tonic-gate verifier4 un_verifier; 33737c478bd9Sstevel@tonic-gate } nfs4clientid_verifier; 33747c478bd9Sstevel@tonic-gate char id_val[] = "Solaris: %s, NFSv4 kernel client"; 33757c478bd9Sstevel@tonic-gate int len; 33767c478bd9Sstevel@tonic-gate 33777c478bd9Sstevel@tonic-gate np = kmem_zalloc(sizeof (struct nfs4_server), KM_SLEEP); 33787c478bd9Sstevel@tonic-gate np->saddr.len = svp->sv_addr.len; 33797c478bd9Sstevel@tonic-gate np->saddr.maxlen = svp->sv_addr.maxlen; 33807c478bd9Sstevel@tonic-gate np->saddr.buf = kmem_alloc(svp->sv_addr.maxlen, KM_SLEEP); 33817c478bd9Sstevel@tonic-gate bcopy(svp->sv_addr.buf, np->saddr.buf, svp->sv_addr.len); 33827c478bd9Sstevel@tonic-gate np->s_refcnt = 1; 33837c478bd9Sstevel@tonic-gate 33847c478bd9Sstevel@tonic-gate /* 33857c478bd9Sstevel@tonic-gate * Build the nfs_client_id4 for this server mount. Ensure 33867c478bd9Sstevel@tonic-gate * the verifier is useful and that the identification is 33877c478bd9Sstevel@tonic-gate * somehow based on the server's address for the case of 33887c478bd9Sstevel@tonic-gate * multi-homed servers. 33897c478bd9Sstevel@tonic-gate */ 33907c478bd9Sstevel@tonic-gate nfs4clientid_verifier.un_verifier = 0; 33917c478bd9Sstevel@tonic-gate gethrestime(&tt); 33927c478bd9Sstevel@tonic-gate nfs4clientid_verifier.un_curtime.sec = (uint32_t)tt.tv_sec; 33937c478bd9Sstevel@tonic-gate nfs4clientid_verifier.un_curtime.subsec = (uint32_t)tt.tv_nsec; 33947c478bd9Sstevel@tonic-gate np->clidtosend.verifier = nfs4clientid_verifier.un_verifier; 33957c478bd9Sstevel@tonic-gate 33967c478bd9Sstevel@tonic-gate /* 33977c478bd9Sstevel@tonic-gate * calculate the length of the opaque identifier. Subtract 2 33987c478bd9Sstevel@tonic-gate * for the "%s" and add the traditional +1 for null 33997c478bd9Sstevel@tonic-gate * termination. 34007c478bd9Sstevel@tonic-gate */ 34017c478bd9Sstevel@tonic-gate len = strlen(id_val) - 2 + strlen(uts_nodename()) + 1; 34027c478bd9Sstevel@tonic-gate np->clidtosend.id_len = len + np->saddr.maxlen; 34037c478bd9Sstevel@tonic-gate 34047c478bd9Sstevel@tonic-gate np->clidtosend.id_val = kmem_alloc(np->clidtosend.id_len, KM_SLEEP); 34057c478bd9Sstevel@tonic-gate (void) sprintf(np->clidtosend.id_val, id_val, uts_nodename()); 34067c478bd9Sstevel@tonic-gate bcopy(np->saddr.buf, &np->clidtosend.id_val[len], np->saddr.len); 34077c478bd9Sstevel@tonic-gate 34087c478bd9Sstevel@tonic-gate np->s_flags = 0; 34097c478bd9Sstevel@tonic-gate np->mntinfo4_list = NULL; 34107c478bd9Sstevel@tonic-gate /* save cred for issuing rfs4calls inside the renew thread */ 34117c478bd9Sstevel@tonic-gate crhold(cr); 34127c478bd9Sstevel@tonic-gate np->s_cred = cr; 34137c478bd9Sstevel@tonic-gate cv_init(&np->cv_thread_exit, NULL, CV_DEFAULT, NULL); 34147c478bd9Sstevel@tonic-gate mutex_init(&np->s_lock, NULL, MUTEX_DEFAULT, NULL); 34157c478bd9Sstevel@tonic-gate nfs_rw_init(&np->s_recovlock, NULL, RW_DEFAULT, NULL); 34167c478bd9Sstevel@tonic-gate list_create(&np->s_deleg_list, sizeof (rnode4_t), 34177c478bd9Sstevel@tonic-gate offsetof(rnode4_t, r_deleg_link)); 34187c478bd9Sstevel@tonic-gate np->s_thread_exit = 0; 34197c478bd9Sstevel@tonic-gate np->state_ref_count = 0; 34207c478bd9Sstevel@tonic-gate np->lease_valid = NFS4_LEASE_NOT_STARTED; 34217c478bd9Sstevel@tonic-gate cv_init(&np->s_cv_otw_count, NULL, CV_DEFAULT, NULL); 3422f86c6ccaSdm cv_init(&np->s_clientid_pend, NULL, CV_DEFAULT, NULL); 34237c478bd9Sstevel@tonic-gate np->s_otw_call_count = 0; 34247c478bd9Sstevel@tonic-gate cv_init(&np->wait_cb_null, NULL, CV_DEFAULT, NULL); 34257c478bd9Sstevel@tonic-gate np->zoneid = getzoneid(); 34267c478bd9Sstevel@tonic-gate np->zone_globals = nfs4_get_callback_globals(); 34277c478bd9Sstevel@tonic-gate ASSERT(np->zone_globals != NULL); 34287c478bd9Sstevel@tonic-gate return (np); 34297c478bd9Sstevel@tonic-gate } 34307c478bd9Sstevel@tonic-gate 34317c478bd9Sstevel@tonic-gate /* 34327c478bd9Sstevel@tonic-gate * Create a new nfs4_server_t structure and add it to the list. 34337c478bd9Sstevel@tonic-gate * Returns new node locked; reference must eventually be freed. 34347c478bd9Sstevel@tonic-gate */ 34357c478bd9Sstevel@tonic-gate static struct nfs4_server * 34367c478bd9Sstevel@tonic-gate add_new_nfs4_server(struct servinfo4 *svp, cred_t *cr) 34377c478bd9Sstevel@tonic-gate { 34387c478bd9Sstevel@tonic-gate nfs4_server_t *sp; 34397c478bd9Sstevel@tonic-gate 34407c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&nfs4_server_lst_lock)); 34417c478bd9Sstevel@tonic-gate sp = new_nfs4_server(svp, cr); 34427c478bd9Sstevel@tonic-gate mutex_enter(&sp->s_lock); 34437c478bd9Sstevel@tonic-gate insque(sp, &nfs4_server_lst); 34447c478bd9Sstevel@tonic-gate sp->s_refcnt++; /* list gets a reference */ 3445f64c4ae1Sdm sp->s_flags |= N4S_INSERTED; 34467c478bd9Sstevel@tonic-gate sp->clientid = 0; 34477c478bd9Sstevel@tonic-gate return (sp); 34487c478bd9Sstevel@tonic-gate } 34497c478bd9Sstevel@tonic-gate 34507c478bd9Sstevel@tonic-gate int nfs4_server_t_debug = 0; 34517c478bd9Sstevel@tonic-gate 34527c478bd9Sstevel@tonic-gate #ifdef lint 34537c478bd9Sstevel@tonic-gate extern void 34547c478bd9Sstevel@tonic-gate dumpnfs4slist(char *, mntinfo4_t *, clientid4, servinfo4_t *); 34557c478bd9Sstevel@tonic-gate #endif 34567c478bd9Sstevel@tonic-gate 34577c478bd9Sstevel@tonic-gate #ifndef lint 34587c478bd9Sstevel@tonic-gate #ifdef DEBUG 34597c478bd9Sstevel@tonic-gate void 34607c478bd9Sstevel@tonic-gate dumpnfs4slist(char *txt, mntinfo4_t *mi, clientid4 clientid, servinfo4_t *srv_p) 34617c478bd9Sstevel@tonic-gate { 34627c478bd9Sstevel@tonic-gate int hash16(void *p, int len); 34637c478bd9Sstevel@tonic-gate nfs4_server_t *np; 34647c478bd9Sstevel@tonic-gate 34657c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_server_t_debug, (CE_NOTE, 34667c478bd9Sstevel@tonic-gate "dumping nfs4_server_t list in %s", txt)); 34677c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_server_t_debug, (CE_CONT, 34687c478bd9Sstevel@tonic-gate "mi 0x%p, want clientid %llx, addr %d/%04X", 34697c478bd9Sstevel@tonic-gate mi, (longlong_t)clientid, srv_p->sv_addr.len, 34707c478bd9Sstevel@tonic-gate hash16((void *)srv_p->sv_addr.buf, srv_p->sv_addr.len))); 34717c478bd9Sstevel@tonic-gate for (np = nfs4_server_lst.forw; np != &nfs4_server_lst; 34727c478bd9Sstevel@tonic-gate np = np->forw) { 34737c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_server_t_debug, (CE_CONT, 34747c478bd9Sstevel@tonic-gate "node 0x%p, clientid %llx, addr %d/%04X, cnt %d", 34757c478bd9Sstevel@tonic-gate np, (longlong_t)np->clientid, np->saddr.len, 34767c478bd9Sstevel@tonic-gate hash16((void *)np->saddr.buf, np->saddr.len), 34777c478bd9Sstevel@tonic-gate np->state_ref_count)); 34787c478bd9Sstevel@tonic-gate if (np->saddr.len == srv_p->sv_addr.len && 34797c478bd9Sstevel@tonic-gate bcmp(np->saddr.buf, srv_p->sv_addr.buf, 34807c478bd9Sstevel@tonic-gate np->saddr.len) == 0) 34817c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_server_t_debug, (CE_CONT, 34827c478bd9Sstevel@tonic-gate " - address matches")); 34837c478bd9Sstevel@tonic-gate if (np->clientid == clientid || np->clientid == 0) 34847c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_server_t_debug, (CE_CONT, 34857c478bd9Sstevel@tonic-gate " - clientid matches")); 34867c478bd9Sstevel@tonic-gate if (np->s_thread_exit != NFS4_THREAD_EXIT) 34877c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_server_t_debug, (CE_CONT, 34887c478bd9Sstevel@tonic-gate " - thread not exiting")); 34897c478bd9Sstevel@tonic-gate } 34907c478bd9Sstevel@tonic-gate delay(hz); 34917c478bd9Sstevel@tonic-gate } 34927c478bd9Sstevel@tonic-gate #endif 34937c478bd9Sstevel@tonic-gate #endif 34947c478bd9Sstevel@tonic-gate 34957c478bd9Sstevel@tonic-gate 34967c478bd9Sstevel@tonic-gate /* 34977c478bd9Sstevel@tonic-gate * Move a mntinfo4_t from one server list to another. 34987c478bd9Sstevel@tonic-gate * Locking of the two nfs4_server_t nodes will be done in list order. 34997c478bd9Sstevel@tonic-gate * 35007c478bd9Sstevel@tonic-gate * Returns NULL if the current nfs4_server_t for the filesystem could not 35017c478bd9Sstevel@tonic-gate * be found (e.g., due to forced unmount). Otherwise returns a reference 35027c478bd9Sstevel@tonic-gate * to the new nfs4_server_t, which must eventually be freed. 35037c478bd9Sstevel@tonic-gate */ 35047c478bd9Sstevel@tonic-gate nfs4_server_t * 35057c478bd9Sstevel@tonic-gate nfs4_move_mi(mntinfo4_t *mi, servinfo4_t *old, servinfo4_t *new) 35067c478bd9Sstevel@tonic-gate { 35077c478bd9Sstevel@tonic-gate nfs4_server_t *p, *op = NULL, *np = NULL; 35087c478bd9Sstevel@tonic-gate int num_open; 3509108322fbScarlsonj zoneid_t zoneid = nfs_zoneid(); 35107c478bd9Sstevel@tonic-gate 3511108322fbScarlsonj ASSERT(nfs_zone() == mi->mi_zone); 35127c478bd9Sstevel@tonic-gate 35137c478bd9Sstevel@tonic-gate mutex_enter(&nfs4_server_lst_lock); 35147c478bd9Sstevel@tonic-gate #ifdef DEBUG 35157c478bd9Sstevel@tonic-gate if (nfs4_server_t_debug) 35167c478bd9Sstevel@tonic-gate dumpnfs4slist("nfs4_move_mi", mi, (clientid4)0, new); 35177c478bd9Sstevel@tonic-gate #endif 35187c478bd9Sstevel@tonic-gate for (p = nfs4_server_lst.forw; p != &nfs4_server_lst; p = p->forw) { 35197c478bd9Sstevel@tonic-gate if (p->zoneid != zoneid) 35207c478bd9Sstevel@tonic-gate continue; 35217c478bd9Sstevel@tonic-gate if (p->saddr.len == old->sv_addr.len && 35227c478bd9Sstevel@tonic-gate bcmp(p->saddr.buf, old->sv_addr.buf, p->saddr.len) == 0 && 35237c478bd9Sstevel@tonic-gate p->s_thread_exit != NFS4_THREAD_EXIT) { 35247c478bd9Sstevel@tonic-gate op = p; 35257c478bd9Sstevel@tonic-gate mutex_enter(&op->s_lock); 35267c478bd9Sstevel@tonic-gate op->s_refcnt++; 35277c478bd9Sstevel@tonic-gate } 35287c478bd9Sstevel@tonic-gate if (p->saddr.len == new->sv_addr.len && 35297c478bd9Sstevel@tonic-gate bcmp(p->saddr.buf, new->sv_addr.buf, p->saddr.len) == 0 && 35307c478bd9Sstevel@tonic-gate p->s_thread_exit != NFS4_THREAD_EXIT) { 35317c478bd9Sstevel@tonic-gate np = p; 35327c478bd9Sstevel@tonic-gate mutex_enter(&np->s_lock); 35337c478bd9Sstevel@tonic-gate } 35347c478bd9Sstevel@tonic-gate if (op != NULL && np != NULL) 35357c478bd9Sstevel@tonic-gate break; 35367c478bd9Sstevel@tonic-gate } 35377c478bd9Sstevel@tonic-gate if (op == NULL) { 35387c478bd9Sstevel@tonic-gate /* 35397c478bd9Sstevel@tonic-gate * Filesystem has been forcibly unmounted. Bail out. 35407c478bd9Sstevel@tonic-gate */ 35417c478bd9Sstevel@tonic-gate if (np != NULL) 35427c478bd9Sstevel@tonic-gate mutex_exit(&np->s_lock); 35437c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_server_lst_lock); 35447c478bd9Sstevel@tonic-gate return (NULL); 35457c478bd9Sstevel@tonic-gate } 35467c478bd9Sstevel@tonic-gate if (np != NULL) { 35477c478bd9Sstevel@tonic-gate np->s_refcnt++; 35487c478bd9Sstevel@tonic-gate } else { 35497c478bd9Sstevel@tonic-gate #ifdef DEBUG 35507c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_failover_debug, (CE_NOTE, 35517c478bd9Sstevel@tonic-gate "nfs4_move_mi: no target nfs4_server, will create.")); 35527c478bd9Sstevel@tonic-gate #endif 35537c478bd9Sstevel@tonic-gate np = add_new_nfs4_server(new, kcred); 35547c478bd9Sstevel@tonic-gate } 35557c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_server_lst_lock); 35567c478bd9Sstevel@tonic-gate 35577c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_failover_debug, (CE_NOTE, 35587c478bd9Sstevel@tonic-gate "nfs4_move_mi: for mi 0x%p, " 35597c478bd9Sstevel@tonic-gate "old servinfo4 0x%p, new servinfo4 0x%p, " 35607c478bd9Sstevel@tonic-gate "old nfs4_server 0x%p, new nfs4_server 0x%p, ", 35617c478bd9Sstevel@tonic-gate (void*)mi, (void*)old, (void*)new, 35627c478bd9Sstevel@tonic-gate (void*)op, (void*)np)); 35637c478bd9Sstevel@tonic-gate ASSERT(op != NULL && np != NULL); 35647c478bd9Sstevel@tonic-gate 35657c478bd9Sstevel@tonic-gate /* discard any delegations */ 35667c478bd9Sstevel@tonic-gate nfs4_deleg_discard(mi, op); 35677c478bd9Sstevel@tonic-gate 35687c478bd9Sstevel@tonic-gate num_open = mi->mi_open_files; 35697c478bd9Sstevel@tonic-gate mi->mi_open_files = 0; 35707c478bd9Sstevel@tonic-gate op->state_ref_count -= num_open; 35717c478bd9Sstevel@tonic-gate ASSERT(op->state_ref_count >= 0); 35727c478bd9Sstevel@tonic-gate np->state_ref_count += num_open; 35737c478bd9Sstevel@tonic-gate nfs4_remove_mi_from_server_nolock(mi, op); 35747c478bd9Sstevel@tonic-gate mi->mi_open_files = num_open; 35757c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_failover_debug, (CE_NOTE, 35767c478bd9Sstevel@tonic-gate "nfs4_move_mi: mi_open_files %d, op->cnt %d, np->cnt %d", 35777c478bd9Sstevel@tonic-gate mi->mi_open_files, op->state_ref_count, np->state_ref_count)); 35787c478bd9Sstevel@tonic-gate 35797c478bd9Sstevel@tonic-gate nfs4_add_mi_to_server(np, mi); 35807c478bd9Sstevel@tonic-gate 35817c478bd9Sstevel@tonic-gate mutex_exit(&op->s_lock); 35827c478bd9Sstevel@tonic-gate nfs4_server_rele(op); 35837c478bd9Sstevel@tonic-gate mutex_exit(&np->s_lock); 35847c478bd9Sstevel@tonic-gate 35857c478bd9Sstevel@tonic-gate return (np); 35867c478bd9Sstevel@tonic-gate } 35877c478bd9Sstevel@tonic-gate 35887c478bd9Sstevel@tonic-gate /* 3589f86c6ccaSdm * Need to have the nfs4_server_lst_lock. 35907c478bd9Sstevel@tonic-gate * Search the nfs4_server list to find a match on this servinfo4 35917c478bd9Sstevel@tonic-gate * based on its address. 35927c478bd9Sstevel@tonic-gate * 35937c478bd9Sstevel@tonic-gate * Returns NULL if no match is found. Otherwise returns a reference (which 35947c478bd9Sstevel@tonic-gate * must eventually be freed) to a locked nfs4_server. 35957c478bd9Sstevel@tonic-gate */ 35967c478bd9Sstevel@tonic-gate nfs4_server_t * 35977c478bd9Sstevel@tonic-gate servinfo4_to_nfs4_server(servinfo4_t *srv_p) 35987c478bd9Sstevel@tonic-gate { 35997c478bd9Sstevel@tonic-gate nfs4_server_t *np; 3600108322fbScarlsonj zoneid_t zoneid = nfs_zoneid(); 36017c478bd9Sstevel@tonic-gate 3602f86c6ccaSdm ASSERT(MUTEX_HELD(&nfs4_server_lst_lock)); 36037c478bd9Sstevel@tonic-gate for (np = nfs4_server_lst.forw; np != &nfs4_server_lst; np = np->forw) { 36047c478bd9Sstevel@tonic-gate if (np->zoneid == zoneid && 36057c478bd9Sstevel@tonic-gate np->saddr.len == srv_p->sv_addr.len && 36067c478bd9Sstevel@tonic-gate bcmp(np->saddr.buf, srv_p->sv_addr.buf, 36077c478bd9Sstevel@tonic-gate np->saddr.len) == 0 && 36087c478bd9Sstevel@tonic-gate np->s_thread_exit != NFS4_THREAD_EXIT) { 36097c478bd9Sstevel@tonic-gate mutex_enter(&np->s_lock); 36107c478bd9Sstevel@tonic-gate np->s_refcnt++; 36117c478bd9Sstevel@tonic-gate return (np); 36127c478bd9Sstevel@tonic-gate } 36137c478bd9Sstevel@tonic-gate } 36147c478bd9Sstevel@tonic-gate return (NULL); 36157c478bd9Sstevel@tonic-gate } 36167c478bd9Sstevel@tonic-gate 36177c478bd9Sstevel@tonic-gate /* 36187c478bd9Sstevel@tonic-gate * Search the nfs4_server_lst to find a match based on clientid and 36197c478bd9Sstevel@tonic-gate * addr. 36207c478bd9Sstevel@tonic-gate * Locks the nfs4_server down if it is found and returns a reference that 36217c478bd9Sstevel@tonic-gate * must eventually be freed. 36227c478bd9Sstevel@tonic-gate * 36237c478bd9Sstevel@tonic-gate * Returns NULL it no match is found. This means one of two things: either 36247c478bd9Sstevel@tonic-gate * mi is in the process of being mounted, or mi has been unmounted. 36257c478bd9Sstevel@tonic-gate * 36267c478bd9Sstevel@tonic-gate * The caller should be holding mi->mi_recovlock, and it should continue to 36277c478bd9Sstevel@tonic-gate * hold the lock until done with the returned nfs4_server_t. Once 36287c478bd9Sstevel@tonic-gate * mi->mi_recovlock is released, there is no guarantee that the returned 36297c478bd9Sstevel@tonic-gate * mi->nfs4_server_t will continue to correspond to mi. 36307c478bd9Sstevel@tonic-gate */ 36317c478bd9Sstevel@tonic-gate nfs4_server_t * 36327c478bd9Sstevel@tonic-gate find_nfs4_server(mntinfo4_t *mi) 36337c478bd9Sstevel@tonic-gate { 36347c478bd9Sstevel@tonic-gate return (find_nfs4_server_all(mi, 0)); 36357c478bd9Sstevel@tonic-gate } 36367c478bd9Sstevel@tonic-gate 36377c478bd9Sstevel@tonic-gate /* 36387c478bd9Sstevel@tonic-gate * Same as above, but takes an "all" parameter which can be 36397c478bd9Sstevel@tonic-gate * set to 1 if the caller wishes to find nfs4_server_t's which 36407c478bd9Sstevel@tonic-gate * have been marked for termination by the exit of the renew 36417c478bd9Sstevel@tonic-gate * thread. This should only be used by operations which are 36427c478bd9Sstevel@tonic-gate * cleaning up and will not cause an OTW op. 36437c478bd9Sstevel@tonic-gate */ 36447c478bd9Sstevel@tonic-gate nfs4_server_t * 36457c478bd9Sstevel@tonic-gate find_nfs4_server_all(mntinfo4_t *mi, int all) 36467c478bd9Sstevel@tonic-gate { 36477c478bd9Sstevel@tonic-gate nfs4_server_t *np; 36487c478bd9Sstevel@tonic-gate servinfo4_t *svp; 36497c478bd9Sstevel@tonic-gate zoneid_t zoneid = mi->mi_zone->zone_id; 36507c478bd9Sstevel@tonic-gate 36517c478bd9Sstevel@tonic-gate ASSERT(nfs_rw_lock_held(&mi->mi_recovlock, RW_READER) || 36527c478bd9Sstevel@tonic-gate nfs_rw_lock_held(&mi->mi_recovlock, RW_WRITER)); 36537c478bd9Sstevel@tonic-gate /* 36547c478bd9Sstevel@tonic-gate * This can be called from nfs4_unmount() which can be called from the 36557c478bd9Sstevel@tonic-gate * global zone, hence it's legal for the global zone to muck with 36567c478bd9Sstevel@tonic-gate * another zone's server list, as long as it doesn't try to contact 36577c478bd9Sstevel@tonic-gate * them. 36587c478bd9Sstevel@tonic-gate */ 3659108322fbScarlsonj ASSERT(zoneid == getzoneid() || getzoneid() == GLOBAL_ZONEID || 3660108322fbScarlsonj nfs_global_client_only != 0); 36617c478bd9Sstevel@tonic-gate 36627c478bd9Sstevel@tonic-gate /* 36637c478bd9Sstevel@tonic-gate * The nfs4_server_lst_lock global lock is held when we get a new 36647c478bd9Sstevel@tonic-gate * clientid (via SETCLIENTID OTW). Holding this global lock and 36657c478bd9Sstevel@tonic-gate * mi_recovlock (READER is fine) ensures that the nfs4_server 36667c478bd9Sstevel@tonic-gate * and this mntinfo4 can't get out of sync, so the following search is 36677c478bd9Sstevel@tonic-gate * always valid. 36687c478bd9Sstevel@tonic-gate */ 36697c478bd9Sstevel@tonic-gate mutex_enter(&nfs4_server_lst_lock); 36707c478bd9Sstevel@tonic-gate #ifdef DEBUG 36717c478bd9Sstevel@tonic-gate if (nfs4_server_t_debug) { 36727c478bd9Sstevel@tonic-gate /* mi->mi_clientid is unprotected, ok for debug output */ 36737c478bd9Sstevel@tonic-gate dumpnfs4slist("find_nfs4_server", mi, mi->mi_clientid, 36747c478bd9Sstevel@tonic-gate mi->mi_curr_serv); 36757c478bd9Sstevel@tonic-gate } 36767c478bd9Sstevel@tonic-gate #endif 36777c478bd9Sstevel@tonic-gate for (np = nfs4_server_lst.forw; np != &nfs4_server_lst; np = np->forw) { 36787c478bd9Sstevel@tonic-gate mutex_enter(&np->s_lock); 36797c478bd9Sstevel@tonic-gate svp = mi->mi_curr_serv; 36807c478bd9Sstevel@tonic-gate 36817c478bd9Sstevel@tonic-gate if (np->zoneid == zoneid && 36827c478bd9Sstevel@tonic-gate np->clientid == mi->mi_clientid && 36837c478bd9Sstevel@tonic-gate np->saddr.len == svp->sv_addr.len && 36847c478bd9Sstevel@tonic-gate bcmp(np->saddr.buf, svp->sv_addr.buf, np->saddr.len) == 0 && 36857c478bd9Sstevel@tonic-gate (np->s_thread_exit != NFS4_THREAD_EXIT || all != 0)) { 36867c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_server_lst_lock); 36877c478bd9Sstevel@tonic-gate np->s_refcnt++; 36887c478bd9Sstevel@tonic-gate return (np); 36897c478bd9Sstevel@tonic-gate } 36907c478bd9Sstevel@tonic-gate mutex_exit(&np->s_lock); 36917c478bd9Sstevel@tonic-gate } 36927c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_server_lst_lock); 36937c478bd9Sstevel@tonic-gate 36947c478bd9Sstevel@tonic-gate return (NULL); 36957c478bd9Sstevel@tonic-gate } 36967c478bd9Sstevel@tonic-gate 36977c478bd9Sstevel@tonic-gate /* 36987c478bd9Sstevel@tonic-gate * Release the reference to sp and destroy it if that's the last one. 36997c478bd9Sstevel@tonic-gate */ 37007c478bd9Sstevel@tonic-gate 37017c478bd9Sstevel@tonic-gate void 37027c478bd9Sstevel@tonic-gate nfs4_server_rele(nfs4_server_t *sp) 37037c478bd9Sstevel@tonic-gate { 37047c478bd9Sstevel@tonic-gate mutex_enter(&sp->s_lock); 37057c478bd9Sstevel@tonic-gate ASSERT(sp->s_refcnt > 0); 37067c478bd9Sstevel@tonic-gate sp->s_refcnt--; 37077c478bd9Sstevel@tonic-gate if (sp->s_refcnt > 0) { 37087c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_lock); 37097c478bd9Sstevel@tonic-gate return; 37107c478bd9Sstevel@tonic-gate } 37117c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_lock); 3712f86c6ccaSdm 37137c478bd9Sstevel@tonic-gate mutex_enter(&nfs4_server_lst_lock); 37147c478bd9Sstevel@tonic-gate mutex_enter(&sp->s_lock); 37157c478bd9Sstevel@tonic-gate if (sp->s_refcnt > 0) { 37167c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_lock); 37177c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_server_lst_lock); 37187c478bd9Sstevel@tonic-gate return; 37197c478bd9Sstevel@tonic-gate } 3720f86c6ccaSdm remque(sp); 3721f86c6ccaSdm sp->forw = sp->back = NULL; 37227c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_server_lst_lock); 37237c478bd9Sstevel@tonic-gate destroy_nfs4_server(sp); 37247c478bd9Sstevel@tonic-gate } 37257c478bd9Sstevel@tonic-gate 37267c478bd9Sstevel@tonic-gate static void 37277c478bd9Sstevel@tonic-gate destroy_nfs4_server(nfs4_server_t *sp) 37287c478bd9Sstevel@tonic-gate { 37297c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sp->s_lock)); 37307c478bd9Sstevel@tonic-gate ASSERT(sp->s_refcnt == 0); 37317c478bd9Sstevel@tonic-gate ASSERT(sp->s_otw_call_count == 0); 37327c478bd9Sstevel@tonic-gate 37337c478bd9Sstevel@tonic-gate remove_all_mi(sp); 37347c478bd9Sstevel@tonic-gate 37357c478bd9Sstevel@tonic-gate crfree(sp->s_cred); 37367c478bd9Sstevel@tonic-gate kmem_free(sp->saddr.buf, sp->saddr.maxlen); 37377c478bd9Sstevel@tonic-gate kmem_free(sp->clidtosend.id_val, sp->clidtosend.id_len); 37387c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_lock); 37397c478bd9Sstevel@tonic-gate 37407c478bd9Sstevel@tonic-gate /* destroy the nfs4_server */ 37417c478bd9Sstevel@tonic-gate nfs4callback_destroy(sp); 37427c478bd9Sstevel@tonic-gate list_destroy(&sp->s_deleg_list); 37437c478bd9Sstevel@tonic-gate mutex_destroy(&sp->s_lock); 37447c478bd9Sstevel@tonic-gate cv_destroy(&sp->cv_thread_exit); 37457c478bd9Sstevel@tonic-gate cv_destroy(&sp->s_cv_otw_count); 3746f86c6ccaSdm cv_destroy(&sp->s_clientid_pend); 37477c478bd9Sstevel@tonic-gate cv_destroy(&sp->wait_cb_null); 37487c478bd9Sstevel@tonic-gate nfs_rw_destroy(&sp->s_recovlock); 37497c478bd9Sstevel@tonic-gate kmem_free(sp, sizeof (*sp)); 37507c478bd9Sstevel@tonic-gate } 37517c478bd9Sstevel@tonic-gate 37527c478bd9Sstevel@tonic-gate /* 37537c478bd9Sstevel@tonic-gate * Lock sp, but only if it's still active (in the list and hasn't been 37547c478bd9Sstevel@tonic-gate * flagged as exiting) or 'all' is non-zero. 37557c478bd9Sstevel@tonic-gate * Returns TRUE if sp got locked and adds a reference to sp. 37567c478bd9Sstevel@tonic-gate */ 37577c478bd9Sstevel@tonic-gate bool_t 37587c478bd9Sstevel@tonic-gate nfs4_server_vlock(nfs4_server_t *sp, int all) 37597c478bd9Sstevel@tonic-gate { 37607c478bd9Sstevel@tonic-gate nfs4_server_t *np; 37617c478bd9Sstevel@tonic-gate 37627c478bd9Sstevel@tonic-gate mutex_enter(&nfs4_server_lst_lock); 37637c478bd9Sstevel@tonic-gate for (np = nfs4_server_lst.forw; np != &nfs4_server_lst; np = np->forw) { 37647c478bd9Sstevel@tonic-gate if (sp == np && (np->s_thread_exit != NFS4_THREAD_EXIT || 37657c478bd9Sstevel@tonic-gate all != 0)) { 37667c478bd9Sstevel@tonic-gate mutex_enter(&np->s_lock); 37677c478bd9Sstevel@tonic-gate np->s_refcnt++; 37687c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_server_lst_lock); 37697c478bd9Sstevel@tonic-gate return (TRUE); 37707c478bd9Sstevel@tonic-gate } 37717c478bd9Sstevel@tonic-gate } 37727c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_server_lst_lock); 37737c478bd9Sstevel@tonic-gate return (FALSE); 37747c478bd9Sstevel@tonic-gate } 37757c478bd9Sstevel@tonic-gate 37767c478bd9Sstevel@tonic-gate /* 37777c478bd9Sstevel@tonic-gate * Fork off a thread to free the data structures for a mount. 37787c478bd9Sstevel@tonic-gate */ 37797c478bd9Sstevel@tonic-gate 37807c478bd9Sstevel@tonic-gate static void 37817c478bd9Sstevel@tonic-gate async_free_mount(vfs_t *vfsp, cred_t *cr) 37827c478bd9Sstevel@tonic-gate { 37837c478bd9Sstevel@tonic-gate freemountargs_t *args; 37847c478bd9Sstevel@tonic-gate args = kmem_alloc(sizeof (freemountargs_t), KM_SLEEP); 37857c478bd9Sstevel@tonic-gate args->fm_vfsp = vfsp; 37867c478bd9Sstevel@tonic-gate VFS_HOLD(vfsp); 378750a83466Sjwahlig MI4_HOLD(VFTOMI4(vfsp)); 37887c478bd9Sstevel@tonic-gate args->fm_cr = cr; 37897c478bd9Sstevel@tonic-gate crhold(cr); 37907c478bd9Sstevel@tonic-gate (void) zthread_create(NULL, 0, nfs4_free_mount_thread, args, 0, 37917c478bd9Sstevel@tonic-gate minclsyspri); 37927c478bd9Sstevel@tonic-gate } 37937c478bd9Sstevel@tonic-gate 37947c478bd9Sstevel@tonic-gate static void 37957c478bd9Sstevel@tonic-gate nfs4_free_mount_thread(freemountargs_t *args) 37967c478bd9Sstevel@tonic-gate { 379750a83466Sjwahlig mntinfo4_t *mi; 37987c478bd9Sstevel@tonic-gate nfs4_free_mount(args->fm_vfsp, args->fm_cr); 379950a83466Sjwahlig mi = VFTOMI4(args->fm_vfsp); 38007c478bd9Sstevel@tonic-gate crfree(args->fm_cr); 380150a83466Sjwahlig VFS_RELE(args->fm_vfsp); 380250a83466Sjwahlig MI4_RELE(mi); 38037c478bd9Sstevel@tonic-gate kmem_free(args, sizeof (freemountargs_t)); 38047c478bd9Sstevel@tonic-gate zthread_exit(); 38057c478bd9Sstevel@tonic-gate /* NOTREACHED */ 38067c478bd9Sstevel@tonic-gate } 38077c478bd9Sstevel@tonic-gate 38087c478bd9Sstevel@tonic-gate /* 38097c478bd9Sstevel@tonic-gate * Thread to free the data structures for a given filesystem. 38107c478bd9Sstevel@tonic-gate */ 38117c478bd9Sstevel@tonic-gate static void 38127c478bd9Sstevel@tonic-gate nfs4_free_mount(vfs_t *vfsp, cred_t *cr) 38137c478bd9Sstevel@tonic-gate { 38147c478bd9Sstevel@tonic-gate mntinfo4_t *mi = VFTOMI4(vfsp); 38157c478bd9Sstevel@tonic-gate nfs4_server_t *sp; 38167c478bd9Sstevel@tonic-gate callb_cpr_t cpr_info; 38177c478bd9Sstevel@tonic-gate kmutex_t cpr_lock; 38187c478bd9Sstevel@tonic-gate boolean_t async_thread; 381950a83466Sjwahlig int removed; 38207c478bd9Sstevel@tonic-gate 38217c478bd9Sstevel@tonic-gate /* 38227c478bd9Sstevel@tonic-gate * We need to participate in the CPR framework if this is a kernel 38237c478bd9Sstevel@tonic-gate * thread. 38247c478bd9Sstevel@tonic-gate */ 3825108322fbScarlsonj async_thread = (curproc == nfs_zone()->zone_zsched); 38267c478bd9Sstevel@tonic-gate if (async_thread) { 38277c478bd9Sstevel@tonic-gate mutex_init(&cpr_lock, NULL, MUTEX_DEFAULT, NULL); 38287c478bd9Sstevel@tonic-gate CALLB_CPR_INIT(&cpr_info, &cpr_lock, callb_generic_cpr, 38297c478bd9Sstevel@tonic-gate "nfsv4AsyncUnmount"); 38307c478bd9Sstevel@tonic-gate } 38317c478bd9Sstevel@tonic-gate 38327c478bd9Sstevel@tonic-gate /* 38337c478bd9Sstevel@tonic-gate * We need to wait for all outstanding OTW calls 38347c478bd9Sstevel@tonic-gate * and recovery to finish before we remove the mi 38357c478bd9Sstevel@tonic-gate * from the nfs4_server_t, as current pending 38367c478bd9Sstevel@tonic-gate * calls might still need this linkage (in order 38377c478bd9Sstevel@tonic-gate * to find a nfs4_server_t from a mntinfo4_t). 38387c478bd9Sstevel@tonic-gate */ 38397c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&mi->mi_recovlock, RW_READER, FALSE); 38407c478bd9Sstevel@tonic-gate sp = find_nfs4_server(mi); 38417c478bd9Sstevel@tonic-gate nfs_rw_exit(&mi->mi_recovlock); 38427c478bd9Sstevel@tonic-gate 38437c478bd9Sstevel@tonic-gate if (sp) { 38447c478bd9Sstevel@tonic-gate while (sp->s_otw_call_count != 0) { 38457c478bd9Sstevel@tonic-gate if (async_thread) { 38467c478bd9Sstevel@tonic-gate mutex_enter(&cpr_lock); 38477c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&cpr_info); 38487c478bd9Sstevel@tonic-gate mutex_exit(&cpr_lock); 38497c478bd9Sstevel@tonic-gate } 38507c478bd9Sstevel@tonic-gate cv_wait(&sp->s_cv_otw_count, &sp->s_lock); 38517c478bd9Sstevel@tonic-gate if (async_thread) { 38527c478bd9Sstevel@tonic-gate mutex_enter(&cpr_lock); 38537c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_END(&cpr_info, &cpr_lock); 38547c478bd9Sstevel@tonic-gate mutex_exit(&cpr_lock); 38557c478bd9Sstevel@tonic-gate } 38567c478bd9Sstevel@tonic-gate } 38577c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_lock); 38587c478bd9Sstevel@tonic-gate nfs4_server_rele(sp); 38597c478bd9Sstevel@tonic-gate sp = NULL; 38607c478bd9Sstevel@tonic-gate } 38617c478bd9Sstevel@tonic-gate 38627c478bd9Sstevel@tonic-gate 38637c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 38647c478bd9Sstevel@tonic-gate while (mi->mi_in_recovery != 0) { 38657c478bd9Sstevel@tonic-gate if (async_thread) { 38667c478bd9Sstevel@tonic-gate mutex_enter(&cpr_lock); 38677c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&cpr_info); 38687c478bd9Sstevel@tonic-gate mutex_exit(&cpr_lock); 38697c478bd9Sstevel@tonic-gate } 38707c478bd9Sstevel@tonic-gate cv_wait(&mi->mi_cv_in_recov, &mi->mi_lock); 38717c478bd9Sstevel@tonic-gate if (async_thread) { 38727c478bd9Sstevel@tonic-gate mutex_enter(&cpr_lock); 38737c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_END(&cpr_info, &cpr_lock); 38747c478bd9Sstevel@tonic-gate mutex_exit(&cpr_lock); 38757c478bd9Sstevel@tonic-gate } 38767c478bd9Sstevel@tonic-gate } 38777c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 38787c478bd9Sstevel@tonic-gate 38797c478bd9Sstevel@tonic-gate /* 38807c478bd9Sstevel@tonic-gate * The original purge of the dnlc via 'dounmount' 38817c478bd9Sstevel@tonic-gate * doesn't guarantee that another dnlc entry was not 38827c478bd9Sstevel@tonic-gate * added while we waitied for all outstanding OTW 38837c478bd9Sstevel@tonic-gate * and recovery calls to finish. So re-purge the 38847c478bd9Sstevel@tonic-gate * dnlc now. 38857c478bd9Sstevel@tonic-gate */ 38867c478bd9Sstevel@tonic-gate (void) dnlc_purge_vfsp(vfsp, 0); 38877c478bd9Sstevel@tonic-gate 38887c478bd9Sstevel@tonic-gate /* 38897c478bd9Sstevel@tonic-gate * We need to explicitly stop the manager thread; the asyc worker 38907c478bd9Sstevel@tonic-gate * threads can timeout and exit on their own. 38917c478bd9Sstevel@tonic-gate */ 389250a83466Sjwahlig mutex_enter(&mi->mi_async_lock); 389350a83466Sjwahlig mi->mi_max_threads = 0; 389450a83466Sjwahlig cv_broadcast(&mi->mi_async_work_cv); 389550a83466Sjwahlig mutex_exit(&mi->mi_async_lock); 389650a83466Sjwahlig if (mi->mi_manager_thread) 389750a83466Sjwahlig nfs4_async_manager_stop(vfsp); 38987c478bd9Sstevel@tonic-gate 38997c478bd9Sstevel@tonic-gate destroy_rtable4(vfsp, cr); 39007c478bd9Sstevel@tonic-gate 39017c478bd9Sstevel@tonic-gate nfs4_remove_mi_from_server(mi, NULL); 39027c478bd9Sstevel@tonic-gate 39037c478bd9Sstevel@tonic-gate if (async_thread) { 39047c478bd9Sstevel@tonic-gate mutex_enter(&cpr_lock); 39057c478bd9Sstevel@tonic-gate CALLB_CPR_EXIT(&cpr_info); /* drops cpr_lock */ 39067c478bd9Sstevel@tonic-gate mutex_destroy(&cpr_lock); 39077c478bd9Sstevel@tonic-gate } 390850a83466Sjwahlig 390950a83466Sjwahlig removed = nfs4_mi_zonelist_remove(mi); 391050a83466Sjwahlig if (removed) 391150a83466Sjwahlig zone_rele(mi->mi_zone); 39127c478bd9Sstevel@tonic-gate } 3913