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 5f86c6ccaSdm120769 * Common Development and Distribution License (the "License"). 6f86c6ccaSdm120769 * 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 */ 21bbe876c0SMarcel Telka 227c478bd9Sstevel@tonic-gate /* 23bbe876c0SMarcel Telka * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 24d7de0ceaSRobert Harris * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T. 297c478bd9Sstevel@tonic-gate * All Rights Reserved 307c478bd9Sstevel@tonic-gate */ 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include <sys/param.h> 337c478bd9Sstevel@tonic-gate #include <sys/types.h> 347c478bd9Sstevel@tonic-gate #include <sys/systm.h> 357c478bd9Sstevel@tonic-gate #include <sys/cred.h> 367c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 37aa59c4cbSrsb #include <sys/vfs_opreg.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> 7839d3e169Sevanl #include <sys/fs/autofs.h> 7939d3e169Sevanl 802f172c55SRobert Thurlow #include <sys/sdt.h> 812f172c55SRobert Thurlow 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate /* 847c478bd9Sstevel@tonic-gate * Arguments passed to thread to free data structures from forced unmount. 857c478bd9Sstevel@tonic-gate */ 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate typedef struct { 887c478bd9Sstevel@tonic-gate vfs_t *fm_vfsp; 89b9238976Sth199096 int fm_flag; 907c478bd9Sstevel@tonic-gate cred_t *fm_cr; 917c478bd9Sstevel@tonic-gate } freemountargs_t; 927c478bd9Sstevel@tonic-gate 93b9238976Sth199096 static void async_free_mount(vfs_t *, int, cred_t *); 94b9238976Sth199096 static void nfs4_free_mount(vfs_t *, int, cred_t *); 957c478bd9Sstevel@tonic-gate static void nfs4_free_mount_thread(freemountargs_t *); 967c478bd9Sstevel@tonic-gate static int nfs4_chkdup_servinfo4(servinfo4_t *, servinfo4_t *); 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate /* 997c478bd9Sstevel@tonic-gate * From rpcsec module (common/rpcsec). 1007c478bd9Sstevel@tonic-gate */ 1017c478bd9Sstevel@tonic-gate extern int sec_clnt_loadinfo(struct sec_data *, struct sec_data **, model_t); 1027c478bd9Sstevel@tonic-gate extern void sec_clnt_freeinfo(struct sec_data *); 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate /* 1057c478bd9Sstevel@tonic-gate * The order and contents of this structure must be kept in sync with that of 1067c478bd9Sstevel@tonic-gate * rfsreqcnt_v4_tmpl in nfs_stats.c 1077c478bd9Sstevel@tonic-gate */ 1087c478bd9Sstevel@tonic-gate static char *rfsnames_v4[] = { 1097c478bd9Sstevel@tonic-gate "null", "compound", "reserved", "access", "close", "commit", "create", 1107c478bd9Sstevel@tonic-gate "delegpurge", "delegreturn", "getattr", "getfh", "link", "lock", 1117c478bd9Sstevel@tonic-gate "lockt", "locku", "lookup", "lookupp", "nverify", "open", "openattr", 1127c478bd9Sstevel@tonic-gate "open_confirm", "open_downgrade", "putfh", "putpubfh", "putrootfh", 1137c478bd9Sstevel@tonic-gate "read", "readdir", "readlink", "remove", "rename", "renew", 1147c478bd9Sstevel@tonic-gate "restorefh", "savefh", "secinfo", "setattr", "setclientid", 1157c478bd9Sstevel@tonic-gate "setclientid_confirm", "verify", "write" 1167c478bd9Sstevel@tonic-gate }; 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate /* 1197c478bd9Sstevel@tonic-gate * nfs4_max_mount_retry is the number of times the client will redrive 1207c478bd9Sstevel@tonic-gate * a mount compound before giving up and returning failure. The intent 1217c478bd9Sstevel@tonic-gate * is to redrive mount compounds which fail NFS4ERR_STALE so that 1227c478bd9Sstevel@tonic-gate * if a component of the server path being mounted goes stale, it can 1237c478bd9Sstevel@tonic-gate * "recover" by redriving the mount compund (LOOKUP ops). This recovery 1247c478bd9Sstevel@tonic-gate * code is needed outside of the recovery framework because mount is a 1257c478bd9Sstevel@tonic-gate * special case. The client doesn't create vnodes/rnodes for components 1267c478bd9Sstevel@tonic-gate * of the server path being mounted. The recovery code recovers real 1277c478bd9Sstevel@tonic-gate * client objects, not STALE FHs which map to components of the server 1287c478bd9Sstevel@tonic-gate * path being mounted. 1297c478bd9Sstevel@tonic-gate * 1307c478bd9Sstevel@tonic-gate * We could just fail the mount on the first time, but that would 1317c478bd9Sstevel@tonic-gate * instantly trigger failover (from nfs4_mount), and the client should 1327c478bd9Sstevel@tonic-gate * try to re-lookup the STALE FH before doing failover. The easiest 1337c478bd9Sstevel@tonic-gate * way to "re-lookup" is to simply redrive the mount compound. 1347c478bd9Sstevel@tonic-gate */ 1357c478bd9Sstevel@tonic-gate static int nfs4_max_mount_retry = 2; 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate /* 1387c478bd9Sstevel@tonic-gate * nfs4 vfs operations. 1397c478bd9Sstevel@tonic-gate */ 140b9238976Sth199096 int nfs4_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *); 1417c478bd9Sstevel@tonic-gate static int nfs4_unmount(vfs_t *, int, cred_t *); 1427c478bd9Sstevel@tonic-gate static int nfs4_root(vfs_t *, vnode_t **); 1437c478bd9Sstevel@tonic-gate static int nfs4_statvfs(vfs_t *, struct statvfs64 *); 1447c478bd9Sstevel@tonic-gate static int nfs4_sync(vfs_t *, short, cred_t *); 1457c478bd9Sstevel@tonic-gate static int nfs4_vget(vfs_t *, vnode_t **, fid_t *); 1467c478bd9Sstevel@tonic-gate static int nfs4_mountroot(vfs_t *, whymountroot_t); 1477c478bd9Sstevel@tonic-gate static void nfs4_freevfs(vfs_t *); 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate static int nfs4rootvp(vnode_t **, vfs_t *, struct servinfo4 *, 1507c478bd9Sstevel@tonic-gate int, cred_t *, zone_t *); 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate vfsops_t *nfs4_vfsops; 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate int nfs4_vfsinit(void); 1557c478bd9Sstevel@tonic-gate void nfs4_vfsfini(void); 1567c478bd9Sstevel@tonic-gate static void nfs4setclientid_init(void); 1577c478bd9Sstevel@tonic-gate static void nfs4setclientid_fini(void); 1587c478bd9Sstevel@tonic-gate static void nfs4setclientid_otw(mntinfo4_t *, servinfo4_t *, cred_t *, 1597c478bd9Sstevel@tonic-gate struct nfs4_server *, nfs4_error_t *, int *); 1607c478bd9Sstevel@tonic-gate static void destroy_nfs4_server(nfs4_server_t *); 1617c478bd9Sstevel@tonic-gate static void remove_mi(nfs4_server_t *, mntinfo4_t *); 1627c478bd9Sstevel@tonic-gate 163b9238976Sth199096 extern void nfs4_ephemeral_init(void); 164b9238976Sth199096 extern void nfs4_ephemeral_fini(void); 165b9238976Sth199096 1662f172c55SRobert Thurlow /* referral related routines */ 1672f172c55SRobert Thurlow static servinfo4_t *copy_svp(servinfo4_t *); 1682f172c55SRobert Thurlow static void free_knconf_contents(struct knetconfig *k); 1692f172c55SRobert Thurlow static char *extract_referral_point(const char *, int); 1702f172c55SRobert Thurlow static void setup_newsvpath(servinfo4_t *, int); 1712f172c55SRobert Thurlow static void update_servinfo4(servinfo4_t *, fs_location4 *, 1722f172c55SRobert Thurlow struct nfs_fsl_info *, char *, int); 1732f172c55SRobert Thurlow 1747c478bd9Sstevel@tonic-gate /* 1757c478bd9Sstevel@tonic-gate * Initialize the vfs structure 1767c478bd9Sstevel@tonic-gate */ 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate static int nfs4fstyp; 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate /* 1827c478bd9Sstevel@tonic-gate * Debug variable to check for rdma based 1837c478bd9Sstevel@tonic-gate * transport startup and cleanup. Controlled 1847c478bd9Sstevel@tonic-gate * through /etc/system. Off by default. 1857c478bd9Sstevel@tonic-gate */ 1867c478bd9Sstevel@tonic-gate extern int rdma_debug; 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate int 1897c478bd9Sstevel@tonic-gate nfs4init(int fstyp, char *name) 1907c478bd9Sstevel@tonic-gate { 1917c478bd9Sstevel@tonic-gate static const fs_operation_def_t nfs4_vfsops_template[] = { 192aa59c4cbSrsb VFSNAME_MOUNT, { .vfs_mount = nfs4_mount }, 193aa59c4cbSrsb VFSNAME_UNMOUNT, { .vfs_unmount = nfs4_unmount }, 194aa59c4cbSrsb VFSNAME_ROOT, { .vfs_root = nfs4_root }, 195aa59c4cbSrsb VFSNAME_STATVFS, { .vfs_statvfs = nfs4_statvfs }, 196aa59c4cbSrsb VFSNAME_SYNC, { .vfs_sync = nfs4_sync }, 197aa59c4cbSrsb VFSNAME_VGET, { .vfs_vget = nfs4_vget }, 198aa59c4cbSrsb VFSNAME_MOUNTROOT, { .vfs_mountroot = nfs4_mountroot }, 199aa59c4cbSrsb VFSNAME_FREEVFS, { .vfs_freevfs = nfs4_freevfs }, 2007c478bd9Sstevel@tonic-gate NULL, NULL 2017c478bd9Sstevel@tonic-gate }; 2027c478bd9Sstevel@tonic-gate int error; 2037c478bd9Sstevel@tonic-gate 204b9238976Sth199096 nfs4_vfsops = NULL; 205b9238976Sth199096 nfs4_vnodeops = NULL; 206b9238976Sth199096 nfs4_trigger_vnodeops = NULL; 207b9238976Sth199096 2087c478bd9Sstevel@tonic-gate error = vfs_setfsops(fstyp, nfs4_vfsops_template, &nfs4_vfsops); 2097c478bd9Sstevel@tonic-gate if (error != 0) { 2107c478bd9Sstevel@tonic-gate zcmn_err(GLOBAL_ZONEID, CE_WARN, 2117c478bd9Sstevel@tonic-gate "nfs4init: bad vfs ops template"); 212b9238976Sth199096 goto out; 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate error = vn_make_ops(name, nfs4_vnodeops_template, &nfs4_vnodeops); 2167c478bd9Sstevel@tonic-gate if (error != 0) { 2177c478bd9Sstevel@tonic-gate zcmn_err(GLOBAL_ZONEID, CE_WARN, 2187c478bd9Sstevel@tonic-gate "nfs4init: bad vnode ops template"); 219b9238976Sth199096 goto out; 220b9238976Sth199096 } 221b9238976Sth199096 222b9238976Sth199096 error = vn_make_ops("nfs4_trigger", nfs4_trigger_vnodeops_template, 223b9238976Sth199096 &nfs4_trigger_vnodeops); 224b9238976Sth199096 if (error != 0) { 225b9238976Sth199096 zcmn_err(GLOBAL_ZONEID, CE_WARN, 226b9238976Sth199096 "nfs4init: bad trigger vnode ops template"); 227b9238976Sth199096 goto out; 2287c478bd9Sstevel@tonic-gate } 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate nfs4fstyp = fstyp; 2317c478bd9Sstevel@tonic-gate (void) nfs4_vfsinit(); 2327c478bd9Sstevel@tonic-gate (void) nfs4_init_dot_entries(); 2337c478bd9Sstevel@tonic-gate 234b9238976Sth199096 out: 235b9238976Sth199096 if (error) { 236b9238976Sth199096 if (nfs4_trigger_vnodeops != NULL) 237b9238976Sth199096 vn_freevnodeops(nfs4_trigger_vnodeops); 238b9238976Sth199096 239b9238976Sth199096 if (nfs4_vnodeops != NULL) 240b9238976Sth199096 vn_freevnodeops(nfs4_vnodeops); 241b9238976Sth199096 242b9238976Sth199096 (void) vfs_freevfsops_by_type(fstyp); 243b9238976Sth199096 } 244b9238976Sth199096 245b9238976Sth199096 return (error); 2467c478bd9Sstevel@tonic-gate } 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate void 2497c478bd9Sstevel@tonic-gate nfs4fini(void) 2507c478bd9Sstevel@tonic-gate { 2517c478bd9Sstevel@tonic-gate (void) nfs4_destroy_dot_entries(); 2527c478bd9Sstevel@tonic-gate nfs4_vfsfini(); 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate /* 2567c478bd9Sstevel@tonic-gate * Create a new sec_data structure to store AUTH_DH related data: 2577c478bd9Sstevel@tonic-gate * netname, syncaddr, knetconfig. There is no AUTH_F_RPCTIMESYNC 2587c478bd9Sstevel@tonic-gate * flag set for NFS V4 since we are avoiding to contact the rpcbind 2597c478bd9Sstevel@tonic-gate * daemon and is using the IP time service (IPPORT_TIMESERVER). 2607c478bd9Sstevel@tonic-gate * 2617c478bd9Sstevel@tonic-gate * sec_data can be freed by sec_clnt_freeinfo(). 2627c478bd9Sstevel@tonic-gate */ 263b9238976Sth199096 static struct sec_data * 2647c478bd9Sstevel@tonic-gate create_authdh_data(char *netname, int nlen, struct netbuf *syncaddr, 2657c478bd9Sstevel@tonic-gate struct knetconfig *knconf) { 2667c478bd9Sstevel@tonic-gate struct sec_data *secdata; 2677c478bd9Sstevel@tonic-gate dh_k4_clntdata_t *data; 2687c478bd9Sstevel@tonic-gate char *pf, *p; 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate if (syncaddr == NULL || syncaddr->buf == NULL || nlen == 0) 2717c478bd9Sstevel@tonic-gate return (NULL); 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate secdata = kmem_alloc(sizeof (*secdata), KM_SLEEP); 2747c478bd9Sstevel@tonic-gate secdata->flags = 0; 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate data = kmem_alloc(sizeof (*data), KM_SLEEP); 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate data->syncaddr.maxlen = syncaddr->maxlen; 2797c478bd9Sstevel@tonic-gate data->syncaddr.len = syncaddr->len; 2807c478bd9Sstevel@tonic-gate data->syncaddr.buf = (char *)kmem_alloc(syncaddr->len, KM_SLEEP); 2817c478bd9Sstevel@tonic-gate bcopy(syncaddr->buf, data->syncaddr.buf, syncaddr->len); 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate /* 2847c478bd9Sstevel@tonic-gate * duplicate the knconf information for the 2857c478bd9Sstevel@tonic-gate * new opaque data. 2867c478bd9Sstevel@tonic-gate */ 2877c478bd9Sstevel@tonic-gate data->knconf = kmem_alloc(sizeof (*knconf), KM_SLEEP); 2887c478bd9Sstevel@tonic-gate *data->knconf = *knconf; 2897c478bd9Sstevel@tonic-gate pf = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 2907c478bd9Sstevel@tonic-gate p = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 2917c478bd9Sstevel@tonic-gate bcopy(knconf->knc_protofmly, pf, KNC_STRSIZE); 2927c478bd9Sstevel@tonic-gate bcopy(knconf->knc_proto, p, KNC_STRSIZE); 2937c478bd9Sstevel@tonic-gate data->knconf->knc_protofmly = pf; 2947c478bd9Sstevel@tonic-gate data->knconf->knc_proto = p; 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate /* move server netname to the sec_data structure */ 2977c478bd9Sstevel@tonic-gate data->netname = kmem_alloc(nlen, KM_SLEEP); 2987c478bd9Sstevel@tonic-gate bcopy(netname, data->netname, nlen); 2997c478bd9Sstevel@tonic-gate data->netnamelen = (int)nlen; 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate secdata->secmod = AUTH_DH; 3027c478bd9Sstevel@tonic-gate secdata->rpcflavor = AUTH_DH; 3037c478bd9Sstevel@tonic-gate secdata->data = (caddr_t)data; 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate return (secdata); 3067c478bd9Sstevel@tonic-gate } 3077c478bd9Sstevel@tonic-gate 308b9238976Sth199096 /* 309b9238976Sth199096 * Returns (deep) copy of sec_data_t. Allocates all memory required; caller 310b9238976Sth199096 * is responsible for freeing. 311b9238976Sth199096 */ 312b9238976Sth199096 sec_data_t * 313b9238976Sth199096 copy_sec_data(sec_data_t *fsecdata) { 314b9238976Sth199096 sec_data_t *tsecdata; 315b9238976Sth199096 316b9238976Sth199096 if (fsecdata == NULL) 317b9238976Sth199096 return (NULL); 318b9238976Sth199096 319b9238976Sth199096 if (fsecdata->rpcflavor == AUTH_DH) { 320b9238976Sth199096 dh_k4_clntdata_t *fdata = (dh_k4_clntdata_t *)fsecdata->data; 321b9238976Sth199096 322b9238976Sth199096 if (fdata == NULL) 323b9238976Sth199096 return (NULL); 324b9238976Sth199096 325b9238976Sth199096 tsecdata = (sec_data_t *)create_authdh_data(fdata->netname, 326b9238976Sth199096 fdata->netnamelen, &fdata->syncaddr, fdata->knconf); 327b9238976Sth199096 328b9238976Sth199096 return (tsecdata); 329b9238976Sth199096 } 330b9238976Sth199096 331b9238976Sth199096 tsecdata = kmem_zalloc(sizeof (sec_data_t), KM_SLEEP); 332b9238976Sth199096 333b9238976Sth199096 tsecdata->secmod = fsecdata->secmod; 334b9238976Sth199096 tsecdata->rpcflavor = fsecdata->rpcflavor; 335b9238976Sth199096 tsecdata->flags = fsecdata->flags; 336b9238976Sth199096 tsecdata->uid = fsecdata->uid; 337b9238976Sth199096 338b9238976Sth199096 if (fsecdata->rpcflavor == RPCSEC_GSS) { 339b9238976Sth199096 gss_clntdata_t *gcd = (gss_clntdata_t *)fsecdata->data; 340b9238976Sth199096 341b9238976Sth199096 tsecdata->data = (caddr_t)copy_sec_data_gss(gcd); 342b9238976Sth199096 } else { 343b9238976Sth199096 tsecdata->data = NULL; 344b9238976Sth199096 } 345b9238976Sth199096 346b9238976Sth199096 return (tsecdata); 347b9238976Sth199096 } 348b9238976Sth199096 349b9238976Sth199096 gss_clntdata_t * 350b9238976Sth199096 copy_sec_data_gss(gss_clntdata_t *fdata) 351b9238976Sth199096 { 352b9238976Sth199096 gss_clntdata_t *tdata; 353b9238976Sth199096 354b9238976Sth199096 if (fdata == NULL) 355b9238976Sth199096 return (NULL); 356b9238976Sth199096 357b9238976Sth199096 tdata = kmem_zalloc(sizeof (gss_clntdata_t), KM_SLEEP); 358b9238976Sth199096 359b9238976Sth199096 tdata->mechanism.length = fdata->mechanism.length; 360b9238976Sth199096 tdata->mechanism.elements = kmem_zalloc(fdata->mechanism.length, 361b9238976Sth199096 KM_SLEEP); 362b9238976Sth199096 bcopy(fdata->mechanism.elements, tdata->mechanism.elements, 363b9238976Sth199096 fdata->mechanism.length); 364b9238976Sth199096 365b9238976Sth199096 tdata->service = fdata->service; 366b9238976Sth199096 367b9238976Sth199096 (void) strcpy(tdata->uname, fdata->uname); 368b9238976Sth199096 (void) strcpy(tdata->inst, fdata->inst); 369b9238976Sth199096 (void) strcpy(tdata->realm, fdata->realm); 370b9238976Sth199096 371b9238976Sth199096 tdata->qop = fdata->qop; 372b9238976Sth199096 373b9238976Sth199096 return (tdata); 374b9238976Sth199096 } 375b9238976Sth199096 3767c478bd9Sstevel@tonic-gate static int 3777c478bd9Sstevel@tonic-gate nfs4_chkdup_servinfo4(servinfo4_t *svp_head, servinfo4_t *svp) 3787c478bd9Sstevel@tonic-gate { 3797c478bd9Sstevel@tonic-gate servinfo4_t *si; 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate /* 3827c478bd9Sstevel@tonic-gate * Iterate over the servinfo4 list to make sure 3837c478bd9Sstevel@tonic-gate * we do not have a duplicate. Skip any servinfo4 3847c478bd9Sstevel@tonic-gate * that has been marked "NOT IN USE" 3857c478bd9Sstevel@tonic-gate */ 3867c478bd9Sstevel@tonic-gate for (si = svp_head; si; si = si->sv_next) { 3877c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&si->sv_lock, RW_READER, 0); 3887c478bd9Sstevel@tonic-gate if (si->sv_flags & SV4_NOTINUSE) { 3897c478bd9Sstevel@tonic-gate nfs_rw_exit(&si->sv_lock); 3907c478bd9Sstevel@tonic-gate continue; 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate nfs_rw_exit(&si->sv_lock); 3937c478bd9Sstevel@tonic-gate if (si == svp) 3947c478bd9Sstevel@tonic-gate continue; 3957c478bd9Sstevel@tonic-gate if (si->sv_addr.len == svp->sv_addr.len && 3967c478bd9Sstevel@tonic-gate strcmp(si->sv_knconf->knc_protofmly, 3977c478bd9Sstevel@tonic-gate svp->sv_knconf->knc_protofmly) == 0 && 3987c478bd9Sstevel@tonic-gate bcmp(si->sv_addr.buf, svp->sv_addr.buf, 3997c478bd9Sstevel@tonic-gate si->sv_addr.len) == 0) { 4007c478bd9Sstevel@tonic-gate /* it's a duplicate */ 4017c478bd9Sstevel@tonic-gate return (1); 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate } 4047c478bd9Sstevel@tonic-gate /* it's not a duplicate */ 4057c478bd9Sstevel@tonic-gate return (0); 4067c478bd9Sstevel@tonic-gate } 4077c478bd9Sstevel@tonic-gate 40839d3e169Sevanl void 40939d3e169Sevanl nfs4_free_args(struct nfs_args *nargs) 4107c478bd9Sstevel@tonic-gate { 41139d3e169Sevanl if (nargs->knconf) { 41239d3e169Sevanl if (nargs->knconf->knc_protofmly) 41339d3e169Sevanl kmem_free(nargs->knconf->knc_protofmly, 41439d3e169Sevanl KNC_STRSIZE); 41539d3e169Sevanl if (nargs->knconf->knc_proto) 41639d3e169Sevanl kmem_free(nargs->knconf->knc_proto, KNC_STRSIZE); 41739d3e169Sevanl kmem_free(nargs->knconf, sizeof (*nargs->knconf)); 41839d3e169Sevanl nargs->knconf = NULL; 41939d3e169Sevanl } 42039d3e169Sevanl 42139d3e169Sevanl if (nargs->fh) { 42239d3e169Sevanl kmem_free(nargs->fh, strlen(nargs->fh) + 1); 42339d3e169Sevanl nargs->fh = NULL; 42439d3e169Sevanl } 42539d3e169Sevanl 42639d3e169Sevanl if (nargs->hostname) { 42739d3e169Sevanl kmem_free(nargs->hostname, strlen(nargs->hostname) + 1); 42839d3e169Sevanl nargs->hostname = NULL; 42939d3e169Sevanl } 43039d3e169Sevanl 43139d3e169Sevanl if (nargs->addr) { 43239d3e169Sevanl if (nargs->addr->buf) { 43339d3e169Sevanl ASSERT(nargs->addr->len); 43439d3e169Sevanl kmem_free(nargs->addr->buf, nargs->addr->len); 43539d3e169Sevanl } 43639d3e169Sevanl kmem_free(nargs->addr, sizeof (struct netbuf)); 43739d3e169Sevanl nargs->addr = NULL; 43839d3e169Sevanl } 43939d3e169Sevanl 44039d3e169Sevanl if (nargs->syncaddr) { 44139d3e169Sevanl ASSERT(nargs->syncaddr->len); 44239d3e169Sevanl if (nargs->syncaddr->buf) { 44339d3e169Sevanl ASSERT(nargs->syncaddr->len); 44439d3e169Sevanl kmem_free(nargs->syncaddr->buf, nargs->syncaddr->len); 44539d3e169Sevanl } 44639d3e169Sevanl kmem_free(nargs->syncaddr, sizeof (struct netbuf)); 44739d3e169Sevanl nargs->syncaddr = NULL; 44839d3e169Sevanl } 44939d3e169Sevanl 45039d3e169Sevanl if (nargs->netname) { 45139d3e169Sevanl kmem_free(nargs->netname, strlen(nargs->netname) + 1); 45239d3e169Sevanl nargs->netname = NULL; 45339d3e169Sevanl } 45439d3e169Sevanl 45539d3e169Sevanl if (nargs->nfs_ext_u.nfs_extA.secdata) { 45639d3e169Sevanl sec_clnt_freeinfo( 45739d3e169Sevanl nargs->nfs_ext_u.nfs_extA.secdata); 45839d3e169Sevanl nargs->nfs_ext_u.nfs_extA.secdata = NULL; 45939d3e169Sevanl } 46039d3e169Sevanl } 46139d3e169Sevanl 46239d3e169Sevanl 46339d3e169Sevanl int 46439d3e169Sevanl nfs4_copyin(char *data, int datalen, struct nfs_args *nargs) 46539d3e169Sevanl { 46639d3e169Sevanl 4677c478bd9Sstevel@tonic-gate int error; 4687c478bd9Sstevel@tonic-gate size_t hlen; /* length of hostname */ 4697c478bd9Sstevel@tonic-gate size_t nlen; /* length of netname */ 4707c478bd9Sstevel@tonic-gate char netname[MAXNETNAMELEN+1]; /* server's netname */ 4717c478bd9Sstevel@tonic-gate struct netbuf addr; /* server's address */ 4727c478bd9Sstevel@tonic-gate struct netbuf syncaddr; /* AUTH_DES time sync addr */ 47339d3e169Sevanl struct knetconfig *knconf; /* transport structure */ 47439d3e169Sevanl struct sec_data *secdata = NULL; /* security data */ 4757c478bd9Sstevel@tonic-gate STRUCT_DECL(nfs_args, args); /* nfs mount arguments */ 4767c478bd9Sstevel@tonic-gate STRUCT_DECL(knetconfig, knconf_tmp); 4777c478bd9Sstevel@tonic-gate STRUCT_DECL(netbuf, addr_tmp); 47839d3e169Sevanl int flags; 4797c478bd9Sstevel@tonic-gate char *p, *pf; 4807c478bd9Sstevel@tonic-gate struct pathname pn; 4817c478bd9Sstevel@tonic-gate char *userbufptr; 4827c478bd9Sstevel@tonic-gate 48339d3e169Sevanl 48439d3e169Sevanl bzero(nargs, sizeof (*nargs)); 48539d3e169Sevanl 4867c478bd9Sstevel@tonic-gate STRUCT_INIT(args, get_udatamodel()); 4877c478bd9Sstevel@tonic-gate bzero(STRUCT_BUF(args), SIZEOF_STRUCT(nfs_args, DATAMODEL_NATIVE)); 48839d3e169Sevanl if (copyin(data, STRUCT_BUF(args), MIN(datalen, 4897c478bd9Sstevel@tonic-gate STRUCT_SIZE(args)))) 4907c478bd9Sstevel@tonic-gate return (EFAULT); 4917c478bd9Sstevel@tonic-gate 49239d3e169Sevanl nargs->wsize = STRUCT_FGET(args, wsize); 49339d3e169Sevanl nargs->rsize = STRUCT_FGET(args, rsize); 49439d3e169Sevanl nargs->timeo = STRUCT_FGET(args, timeo); 49539d3e169Sevanl nargs->retrans = STRUCT_FGET(args, retrans); 49639d3e169Sevanl nargs->acregmin = STRUCT_FGET(args, acregmin); 49739d3e169Sevanl nargs->acregmax = STRUCT_FGET(args, acregmax); 49839d3e169Sevanl nargs->acdirmin = STRUCT_FGET(args, acdirmin); 49939d3e169Sevanl nargs->acdirmax = STRUCT_FGET(args, acdirmax); 50039d3e169Sevanl 5017c478bd9Sstevel@tonic-gate flags = STRUCT_FGET(args, flags); 50239d3e169Sevanl nargs->flags = flags; 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate addr.buf = NULL; 5057c478bd9Sstevel@tonic-gate syncaddr.buf = NULL; 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate /* 5097c478bd9Sstevel@tonic-gate * Allocate space for a knetconfig structure and 5107c478bd9Sstevel@tonic-gate * its strings and copy in from user-land. 5117c478bd9Sstevel@tonic-gate */ 5127c478bd9Sstevel@tonic-gate knconf = kmem_zalloc(sizeof (*knconf), KM_SLEEP); 5137c478bd9Sstevel@tonic-gate STRUCT_INIT(knconf_tmp, get_udatamodel()); 5147c478bd9Sstevel@tonic-gate if (copyin(STRUCT_FGETP(args, knconf), STRUCT_BUF(knconf_tmp), 5157c478bd9Sstevel@tonic-gate STRUCT_SIZE(knconf_tmp))) { 51639d3e169Sevanl kmem_free(knconf, sizeof (*knconf)); 5177c478bd9Sstevel@tonic-gate return (EFAULT); 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate knconf->knc_semantics = STRUCT_FGET(knconf_tmp, knc_semantics); 5217c478bd9Sstevel@tonic-gate knconf->knc_protofmly = STRUCT_FGETP(knconf_tmp, knc_protofmly); 5227c478bd9Sstevel@tonic-gate knconf->knc_proto = STRUCT_FGETP(knconf_tmp, knc_proto); 5237c478bd9Sstevel@tonic-gate if (get_udatamodel() != DATAMODEL_LP64) { 5247c478bd9Sstevel@tonic-gate knconf->knc_rdev = expldev(STRUCT_FGET(knconf_tmp, knc_rdev)); 5257c478bd9Sstevel@tonic-gate } else { 5267c478bd9Sstevel@tonic-gate knconf->knc_rdev = STRUCT_FGET(knconf_tmp, knc_rdev); 5277c478bd9Sstevel@tonic-gate } 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate pf = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 5307c478bd9Sstevel@tonic-gate p = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 5317c478bd9Sstevel@tonic-gate error = copyinstr(knconf->knc_protofmly, pf, KNC_STRSIZE, NULL); 5327c478bd9Sstevel@tonic-gate if (error) { 5337c478bd9Sstevel@tonic-gate kmem_free(pf, KNC_STRSIZE); 5347c478bd9Sstevel@tonic-gate kmem_free(p, KNC_STRSIZE); 53539d3e169Sevanl kmem_free(knconf, sizeof (*knconf)); 5367c478bd9Sstevel@tonic-gate return (error); 5377c478bd9Sstevel@tonic-gate } 53839d3e169Sevanl 5397c478bd9Sstevel@tonic-gate error = copyinstr(knconf->knc_proto, p, KNC_STRSIZE, NULL); 5407c478bd9Sstevel@tonic-gate if (error) { 5417c478bd9Sstevel@tonic-gate kmem_free(pf, KNC_STRSIZE); 5427c478bd9Sstevel@tonic-gate kmem_free(p, KNC_STRSIZE); 54339d3e169Sevanl kmem_free(knconf, sizeof (*knconf)); 5447c478bd9Sstevel@tonic-gate return (error); 5457c478bd9Sstevel@tonic-gate } 54639d3e169Sevanl 54739d3e169Sevanl 5487c478bd9Sstevel@tonic-gate knconf->knc_protofmly = pf; 5497c478bd9Sstevel@tonic-gate knconf->knc_proto = p; 5507c478bd9Sstevel@tonic-gate 55139d3e169Sevanl nargs->knconf = knconf; 55239d3e169Sevanl 5537c478bd9Sstevel@tonic-gate /* 5547c478bd9Sstevel@tonic-gate * Get server address 5557c478bd9Sstevel@tonic-gate */ 5567c478bd9Sstevel@tonic-gate STRUCT_INIT(addr_tmp, get_udatamodel()); 5577c478bd9Sstevel@tonic-gate if (copyin(STRUCT_FGETP(args, addr), STRUCT_BUF(addr_tmp), 5587c478bd9Sstevel@tonic-gate STRUCT_SIZE(addr_tmp))) { 5597c478bd9Sstevel@tonic-gate error = EFAULT; 5607c478bd9Sstevel@tonic-gate goto errout; 5617c478bd9Sstevel@tonic-gate } 5627c478bd9Sstevel@tonic-gate 5637e450cbcSJames Wahlig nargs->addr = kmem_zalloc(sizeof (struct netbuf), KM_SLEEP); 56439d3e169Sevanl userbufptr = STRUCT_FGETP(addr_tmp, buf); 5657c478bd9Sstevel@tonic-gate addr.len = STRUCT_FGET(addr_tmp, len); 5667c478bd9Sstevel@tonic-gate addr.buf = kmem_alloc(addr.len, KM_SLEEP); 5677c478bd9Sstevel@tonic-gate addr.maxlen = addr.len; 5687c478bd9Sstevel@tonic-gate if (copyin(userbufptr, addr.buf, addr.len)) { 5697c478bd9Sstevel@tonic-gate kmem_free(addr.buf, addr.len); 5707c478bd9Sstevel@tonic-gate error = EFAULT; 5717c478bd9Sstevel@tonic-gate goto errout; 5727c478bd9Sstevel@tonic-gate } 57339d3e169Sevanl bcopy(&addr, nargs->addr, sizeof (struct netbuf)); 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate /* 5767c478bd9Sstevel@tonic-gate * Get the root fhandle 5777c478bd9Sstevel@tonic-gate */ 5787c478bd9Sstevel@tonic-gate error = pn_get(STRUCT_FGETP(args, fh), UIO_USERSPACE, &pn); 5797c478bd9Sstevel@tonic-gate if (error) 5807c478bd9Sstevel@tonic-gate goto errout; 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate /* Volatile fh: keep server paths, so use actual-size strings */ 58339d3e169Sevanl nargs->fh = kmem_alloc(pn.pn_pathlen + 1, KM_SLEEP); 58439d3e169Sevanl bcopy(pn.pn_path, nargs->fh, pn.pn_pathlen); 58539d3e169Sevanl nargs->fh[pn.pn_pathlen] = '\0'; 5867c478bd9Sstevel@tonic-gate pn_free(&pn); 5877c478bd9Sstevel@tonic-gate 58839d3e169Sevanl 5897c478bd9Sstevel@tonic-gate /* 5907c478bd9Sstevel@tonic-gate * Get server's hostname 5917c478bd9Sstevel@tonic-gate */ 5927c478bd9Sstevel@tonic-gate if (flags & NFSMNT_HOSTNAME) { 5937c478bd9Sstevel@tonic-gate error = copyinstr(STRUCT_FGETP(args, hostname), 5947c478bd9Sstevel@tonic-gate netname, sizeof (netname), &hlen); 5957c478bd9Sstevel@tonic-gate if (error) 5967c478bd9Sstevel@tonic-gate goto errout; 59739d3e169Sevanl nargs->hostname = kmem_zalloc(hlen, KM_SLEEP); 59839d3e169Sevanl (void) strcpy(nargs->hostname, netname); 59939d3e169Sevanl 60039d3e169Sevanl } else { 60139d3e169Sevanl nargs->hostname = NULL; 60239d3e169Sevanl } 60339d3e169Sevanl 60439d3e169Sevanl 60539d3e169Sevanl /* 60639d3e169Sevanl * If there are syncaddr and netname data, load them in. This is 60739d3e169Sevanl * to support data needed for NFSV4 when AUTH_DH is the negotiated 60839d3e169Sevanl * flavor via SECINFO. (instead of using MOUNT protocol in V3). 60939d3e169Sevanl */ 61039d3e169Sevanl netname[0] = '\0'; 61139d3e169Sevanl if (flags & NFSMNT_SECURE) { 61239d3e169Sevanl 61339d3e169Sevanl /* get syncaddr */ 61439d3e169Sevanl STRUCT_INIT(addr_tmp, get_udatamodel()); 61539d3e169Sevanl if (copyin(STRUCT_FGETP(args, syncaddr), STRUCT_BUF(addr_tmp), 61639d3e169Sevanl STRUCT_SIZE(addr_tmp))) { 61739d3e169Sevanl error = EINVAL; 61839d3e169Sevanl goto errout; 61939d3e169Sevanl } 62039d3e169Sevanl userbufptr = STRUCT_FGETP(addr_tmp, buf); 62139d3e169Sevanl syncaddr.len = STRUCT_FGET(addr_tmp, len); 62239d3e169Sevanl syncaddr.buf = kmem_alloc(syncaddr.len, KM_SLEEP); 62339d3e169Sevanl syncaddr.maxlen = syncaddr.len; 62439d3e169Sevanl if (copyin(userbufptr, syncaddr.buf, syncaddr.len)) { 62539d3e169Sevanl kmem_free(syncaddr.buf, syncaddr.len); 62639d3e169Sevanl error = EFAULT; 62739d3e169Sevanl goto errout; 62839d3e169Sevanl } 62939d3e169Sevanl 63039d3e169Sevanl nargs->syncaddr = kmem_alloc(sizeof (struct netbuf), KM_SLEEP); 63139d3e169Sevanl bcopy(&syncaddr, nargs->syncaddr, sizeof (struct netbuf)); 63222d5e933Skr143551 63339d3e169Sevanl /* get server's netname */ 63439d3e169Sevanl if (copyinstr(STRUCT_FGETP(args, netname), netname, 63539d3e169Sevanl sizeof (netname), &nlen)) { 63639d3e169Sevanl error = EFAULT; 63739d3e169Sevanl goto errout; 63839d3e169Sevanl } 63939d3e169Sevanl 64039d3e169Sevanl netname[nlen] = '\0'; 64139d3e169Sevanl nargs->netname = kmem_zalloc(nlen, KM_SLEEP); 64239d3e169Sevanl (void) strcpy(nargs->netname, netname); 64322d5e933Skr143551 } 64439d3e169Sevanl 64539d3e169Sevanl /* 64639d3e169Sevanl * Get the extention data which has the security data structure. 64739d3e169Sevanl * This includes data for AUTH_SYS as well. 64839d3e169Sevanl */ 64939d3e169Sevanl if (flags & NFSMNT_NEWARGS) { 65039d3e169Sevanl nargs->nfs_args_ext = STRUCT_FGET(args, nfs_args_ext); 65139d3e169Sevanl if (nargs->nfs_args_ext == NFS_ARGS_EXTA || 65239d3e169Sevanl nargs->nfs_args_ext == NFS_ARGS_EXTB) { 65339d3e169Sevanl /* 65439d3e169Sevanl * Indicating the application is using the new 65539d3e169Sevanl * sec_data structure to pass in the security 65639d3e169Sevanl * data. 65739d3e169Sevanl */ 65839d3e169Sevanl if (STRUCT_FGETP(args, 65939d3e169Sevanl nfs_ext_u.nfs_extA.secdata) != NULL) { 66039d3e169Sevanl error = sec_clnt_loadinfo( 66139d3e169Sevanl (struct sec_data *)STRUCT_FGETP(args, 66239d3e169Sevanl nfs_ext_u.nfs_extA.secdata), 66339d3e169Sevanl &secdata, get_udatamodel()); 66439d3e169Sevanl } 66539d3e169Sevanl nargs->nfs_ext_u.nfs_extA.secdata = secdata; 66639d3e169Sevanl } 66739d3e169Sevanl } 66839d3e169Sevanl 66939d3e169Sevanl if (error) 67039d3e169Sevanl goto errout; 67139d3e169Sevanl 67239d3e169Sevanl /* 67339d3e169Sevanl * Failover support: 67439d3e169Sevanl * 67539d3e169Sevanl * We may have a linked list of nfs_args structures, 67639d3e169Sevanl * which means the user is looking for failover. If 67739d3e169Sevanl * the mount is either not "read-only" or "soft", 67839d3e169Sevanl * we want to bail out with EINVAL. 67939d3e169Sevanl */ 68039d3e169Sevanl if (nargs->nfs_args_ext == NFS_ARGS_EXTB) 68139d3e169Sevanl nargs->nfs_ext_u.nfs_extB.next = 68239d3e169Sevanl STRUCT_FGETP(args, nfs_ext_u.nfs_extB.next); 68339d3e169Sevanl 68439d3e169Sevanl errout: 68539d3e169Sevanl if (error) 68639d3e169Sevanl nfs4_free_args(nargs); 68739d3e169Sevanl 68839d3e169Sevanl return (error); 68939d3e169Sevanl } 69039d3e169Sevanl 69139d3e169Sevanl 69239d3e169Sevanl /* 69339d3e169Sevanl * nfs mount vfsop 69439d3e169Sevanl * Set up mount info record and attach it to vfs struct. 69539d3e169Sevanl */ 696b9238976Sth199096 int 69739d3e169Sevanl nfs4_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) 69839d3e169Sevanl { 69939d3e169Sevanl char *data = uap->dataptr; 70039d3e169Sevanl int error; 70139d3e169Sevanl vnode_t *rtvp; /* the server's root */ 70239d3e169Sevanl mntinfo4_t *mi; /* mount info, pointed at by vfs */ 70339d3e169Sevanl struct knetconfig *rdma_knconf; /* rdma transport structure */ 70439d3e169Sevanl rnode4_t *rp; 70539d3e169Sevanl struct servinfo4 *svp; /* nfs server info */ 70639d3e169Sevanl struct servinfo4 *svp_tail = NULL; /* previous nfs server info */ 70739d3e169Sevanl struct servinfo4 *svp_head; /* first nfs server info */ 70839d3e169Sevanl struct servinfo4 *svp_2ndlast; /* 2nd last in server info list */ 70939d3e169Sevanl struct sec_data *secdata; /* security data */ 71039d3e169Sevanl struct nfs_args *args = NULL; 71139d3e169Sevanl int flags, addr_type, removed; 71239d3e169Sevanl zone_t *zone = nfs_zone(); 71339d3e169Sevanl nfs4_error_t n4e; 71439d3e169Sevanl zone_t *mntzone = NULL; 71539d3e169Sevanl 71639d3e169Sevanl if (secpolicy_fs_mount(cr, mvp, vfsp) != 0) 71739d3e169Sevanl return (EPERM); 71839d3e169Sevanl if (mvp->v_type != VDIR) 71939d3e169Sevanl return (ENOTDIR); 720b9238976Sth199096 72139d3e169Sevanl /* 72239d3e169Sevanl * get arguments 72339d3e169Sevanl * 72439d3e169Sevanl * nfs_args is now versioned and is extensible, so 72539d3e169Sevanl * uap->datalen might be different from sizeof (args) 72639d3e169Sevanl * in a compatible situation. 72739d3e169Sevanl */ 72839d3e169Sevanl more: 72939d3e169Sevanl if (!(uap->flags & MS_SYSSPACE)) { 73039d3e169Sevanl if (args == NULL) 73139d3e169Sevanl args = kmem_zalloc(sizeof (struct nfs_args), KM_SLEEP); 73239d3e169Sevanl else 73339d3e169Sevanl nfs4_free_args(args); 73439d3e169Sevanl error = nfs4_copyin(data, uap->datalen, args); 73539d3e169Sevanl if (error) { 73639d3e169Sevanl if (args) { 73739d3e169Sevanl kmem_free(args, sizeof (*args)); 73839d3e169Sevanl } 73939d3e169Sevanl return (error); 74039d3e169Sevanl } 74139d3e169Sevanl } else { 74239d3e169Sevanl args = (struct nfs_args *)data; 74339d3e169Sevanl } 74439d3e169Sevanl 74539d3e169Sevanl flags = args->flags; 74639d3e169Sevanl 74739d3e169Sevanl /* 74839d3e169Sevanl * If the request changes the locking type, disallow the remount, 74939d3e169Sevanl * because it's questionable whether we can transfer the 75039d3e169Sevanl * locking state correctly. 75139d3e169Sevanl */ 75239d3e169Sevanl if (uap->flags & MS_REMOUNT) { 75339d3e169Sevanl if (!(uap->flags & MS_SYSSPACE)) { 75439d3e169Sevanl nfs4_free_args(args); 75539d3e169Sevanl kmem_free(args, sizeof (*args)); 75639d3e169Sevanl } 75739d3e169Sevanl if ((mi = VFTOMI4(vfsp)) != NULL) { 75839d3e169Sevanl uint_t new_mi_llock; 75939d3e169Sevanl uint_t old_mi_llock; 76039d3e169Sevanl new_mi_llock = (flags & NFSMNT_LLOCK) ? 1 : 0; 76139d3e169Sevanl old_mi_llock = (mi->mi_flags & MI4_LLOCK) ? 1 : 0; 76239d3e169Sevanl if (old_mi_llock != new_mi_llock) 76339d3e169Sevanl return (EBUSY); 76439d3e169Sevanl } 76539d3e169Sevanl return (0); 76639d3e169Sevanl } 76739d3e169Sevanl 768b9238976Sth199096 /* 769b9238976Sth199096 * For ephemeral mount trigger stub vnodes, we have two problems 770b9238976Sth199096 * to solve: racing threads will likely fail the v_count check, and 771b9238976Sth199096 * we want only one to proceed with the mount. 772b9238976Sth199096 * 773b9238976Sth199096 * For stubs, if the mount has already occurred (via a racing thread), 774b9238976Sth199096 * just return success. If not, skip the v_count check and proceed. 775b9238976Sth199096 * Note that we are already serialised at this point. 776b9238976Sth199096 */ 77739d3e169Sevanl mutex_enter(&mvp->v_lock); 778b9238976Sth199096 if (vn_matchops(mvp, nfs4_trigger_vnodeops)) { 779b9238976Sth199096 /* mntpt is a v4 stub vnode */ 780b9238976Sth199096 ASSERT(RP_ISSTUB(VTOR4(mvp))); 781b9238976Sth199096 ASSERT(!(uap->flags & MS_OVERLAY)); 782b9238976Sth199096 ASSERT(!(mvp->v_flag & VROOT)); 783b9238976Sth199096 if (vn_mountedvfs(mvp) != NULL) { 784b9238976Sth199096 /* ephemeral mount has already occurred */ 785b9238976Sth199096 ASSERT(uap->flags & MS_SYSSPACE); 786b9238976Sth199096 mutex_exit(&mvp->v_lock); 787b9238976Sth199096 return (0); 788b9238976Sth199096 } 789b9238976Sth199096 } else { 790b9238976Sth199096 /* mntpt is a non-v4 or v4 non-stub vnode */ 79139d3e169Sevanl if (!(uap->flags & MS_OVERLAY) && 79239d3e169Sevanl (mvp->v_count != 1 || (mvp->v_flag & VROOT))) { 79339d3e169Sevanl mutex_exit(&mvp->v_lock); 79439d3e169Sevanl if (!(uap->flags & MS_SYSSPACE)) { 79539d3e169Sevanl nfs4_free_args(args); 79639d3e169Sevanl kmem_free(args, sizeof (*args)); 79739d3e169Sevanl } 79839d3e169Sevanl return (EBUSY); 79939d3e169Sevanl } 800b9238976Sth199096 } 80139d3e169Sevanl mutex_exit(&mvp->v_lock); 80239d3e169Sevanl 80339d3e169Sevanl /* make sure things are zeroed for errout: */ 80439d3e169Sevanl rtvp = NULL; 80539d3e169Sevanl mi = NULL; 80639d3e169Sevanl secdata = NULL; 80739d3e169Sevanl 80839d3e169Sevanl /* 80939d3e169Sevanl * A valid knetconfig structure is required. 81039d3e169Sevanl */ 81139d3e169Sevanl if (!(flags & NFSMNT_KNCONF) || 81239d3e169Sevanl args->knconf == NULL || args->knconf->knc_protofmly == NULL || 81339d3e169Sevanl args->knconf->knc_proto == NULL || 81439d3e169Sevanl (strcmp(args->knconf->knc_proto, NC_UDP) == 0)) { 81539d3e169Sevanl if (!(uap->flags & MS_SYSSPACE)) { 81639d3e169Sevanl nfs4_free_args(args); 81739d3e169Sevanl kmem_free(args, sizeof (*args)); 81839d3e169Sevanl } 81939d3e169Sevanl return (EINVAL); 82039d3e169Sevanl } 82139d3e169Sevanl 82239d3e169Sevanl if ((strlen(args->knconf->knc_protofmly) >= KNC_STRSIZE) || 82339d3e169Sevanl (strlen(args->knconf->knc_proto) >= KNC_STRSIZE)) { 82439d3e169Sevanl if (!(uap->flags & MS_SYSSPACE)) { 82539d3e169Sevanl nfs4_free_args(args); 82639d3e169Sevanl kmem_free(args, sizeof (*args)); 82739d3e169Sevanl } 82839d3e169Sevanl return (EINVAL); 82939d3e169Sevanl } 83039d3e169Sevanl 83139d3e169Sevanl /* 83239d3e169Sevanl * Allocate a servinfo4 struct. 83339d3e169Sevanl */ 83439d3e169Sevanl svp = kmem_zalloc(sizeof (*svp), KM_SLEEP); 83539d3e169Sevanl nfs_rw_init(&svp->sv_lock, NULL, RW_DEFAULT, NULL); 83639d3e169Sevanl if (svp_tail) { 83739d3e169Sevanl svp_2ndlast = svp_tail; 83839d3e169Sevanl svp_tail->sv_next = svp; 83939d3e169Sevanl } else { 84039d3e169Sevanl svp_head = svp; 84139d3e169Sevanl svp_2ndlast = svp; 84239d3e169Sevanl } 84339d3e169Sevanl 84439d3e169Sevanl svp_tail = svp; 84539d3e169Sevanl svp->sv_knconf = args->knconf; 84639d3e169Sevanl args->knconf = NULL; 84739d3e169Sevanl 84839d3e169Sevanl /* 84939d3e169Sevanl * Get server address 85039d3e169Sevanl */ 85139d3e169Sevanl if (args->addr == NULL || args->addr->buf == NULL) { 85239d3e169Sevanl error = EINVAL; 85339d3e169Sevanl goto errout; 85439d3e169Sevanl } 85539d3e169Sevanl 85639d3e169Sevanl svp->sv_addr.maxlen = args->addr->maxlen; 85739d3e169Sevanl svp->sv_addr.len = args->addr->len; 85839d3e169Sevanl svp->sv_addr.buf = args->addr->buf; 85939d3e169Sevanl args->addr->buf = NULL; 86039d3e169Sevanl 86139d3e169Sevanl /* 86239d3e169Sevanl * Get the root fhandle 86339d3e169Sevanl */ 86439d3e169Sevanl if (args->fh == NULL || (strlen(args->fh) >= MAXPATHLEN)) { 86539d3e169Sevanl error = EINVAL; 86639d3e169Sevanl goto errout; 86739d3e169Sevanl } 86839d3e169Sevanl 86939d3e169Sevanl svp->sv_path = args->fh; 87039d3e169Sevanl svp->sv_pathlen = strlen(args->fh) + 1; 87139d3e169Sevanl args->fh = NULL; 87239d3e169Sevanl 87339d3e169Sevanl /* 87439d3e169Sevanl * Get server's hostname 87539d3e169Sevanl */ 87639d3e169Sevanl if (flags & NFSMNT_HOSTNAME) { 87739d3e169Sevanl if (args->hostname == NULL || (strlen(args->hostname) > 87839d3e169Sevanl MAXNETNAMELEN)) { 87939d3e169Sevanl error = EINVAL; 88039d3e169Sevanl goto errout; 88139d3e169Sevanl } 88239d3e169Sevanl svp->sv_hostnamelen = strlen(args->hostname) + 1; 88339d3e169Sevanl svp->sv_hostname = args->hostname; 88439d3e169Sevanl args->hostname = NULL; 8857c478bd9Sstevel@tonic-gate } else { 8867c478bd9Sstevel@tonic-gate char *p = "unknown-host"; 88739d3e169Sevanl svp->sv_hostnamelen = strlen(p) + 1; 88839d3e169Sevanl svp->sv_hostname = kmem_zalloc(svp->sv_hostnamelen, KM_SLEEP); 88939d3e169Sevanl (void) strcpy(svp->sv_hostname, p); 8907c478bd9Sstevel@tonic-gate } 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate /* 8937c478bd9Sstevel@tonic-gate * RDMA MOUNT SUPPORT FOR NFS v4. 8947c478bd9Sstevel@tonic-gate * Establish, is it possible to use RDMA, if so overload the 8957c478bd9Sstevel@tonic-gate * knconf with rdma specific knconf and free the orignal knconf. 8967c478bd9Sstevel@tonic-gate */ 8977c478bd9Sstevel@tonic-gate if ((flags & NFSMNT_TRYRDMA) || (flags & NFSMNT_DORDMA)) { 8987c478bd9Sstevel@tonic-gate /* 8997c478bd9Sstevel@tonic-gate * Determine the addr type for RDMA, IPv4 or v6. 9007c478bd9Sstevel@tonic-gate */ 9017c478bd9Sstevel@tonic-gate if (strcmp(svp->sv_knconf->knc_protofmly, NC_INET) == 0) 9027c478bd9Sstevel@tonic-gate addr_type = AF_INET; 9037c478bd9Sstevel@tonic-gate else if (strcmp(svp->sv_knconf->knc_protofmly, NC_INET6) == 0) 9047c478bd9Sstevel@tonic-gate addr_type = AF_INET6; 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate if (rdma_reachable(addr_type, &svp->sv_addr, 9077c478bd9Sstevel@tonic-gate &rdma_knconf) == 0) { 9087c478bd9Sstevel@tonic-gate /* 9097c478bd9Sstevel@tonic-gate * If successful, hijack the orignal knconf and 9107c478bd9Sstevel@tonic-gate * replace with the new one, depending on the flags. 9117c478bd9Sstevel@tonic-gate */ 9127c478bd9Sstevel@tonic-gate svp->sv_origknconf = svp->sv_knconf; 9137c478bd9Sstevel@tonic-gate svp->sv_knconf = rdma_knconf; 9147c478bd9Sstevel@tonic-gate } else { 9157c478bd9Sstevel@tonic-gate if (flags & NFSMNT_TRYRDMA) { 9167c478bd9Sstevel@tonic-gate #ifdef DEBUG 9177c478bd9Sstevel@tonic-gate if (rdma_debug) 9187c478bd9Sstevel@tonic-gate zcmn_err(getzoneid(), CE_WARN, 9197c478bd9Sstevel@tonic-gate "no RDMA onboard, revert\n"); 9207c478bd9Sstevel@tonic-gate #endif 9217c478bd9Sstevel@tonic-gate } 9227c478bd9Sstevel@tonic-gate 9237c478bd9Sstevel@tonic-gate if (flags & NFSMNT_DORDMA) { 9247c478bd9Sstevel@tonic-gate /* 9257c478bd9Sstevel@tonic-gate * If proto=rdma is specified and no RDMA 9267c478bd9Sstevel@tonic-gate * path to this server is avialable then 9277c478bd9Sstevel@tonic-gate * ditch this server. 9287c478bd9Sstevel@tonic-gate * This is not included in the mountable 9297c478bd9Sstevel@tonic-gate * server list or the replica list. 9307c478bd9Sstevel@tonic-gate * Check if more servers are specified; 9317c478bd9Sstevel@tonic-gate * Failover case, otherwise bail out of mount. 9327c478bd9Sstevel@tonic-gate */ 933b9238976Sth199096 if (args->nfs_args_ext == NFS_ARGS_EXTB && 934b9238976Sth199096 args->nfs_ext_u.nfs_extB.next != NULL) { 93539d3e169Sevanl data = (char *) 93639d3e169Sevanl args->nfs_ext_u.nfs_extB.next; 9377c478bd9Sstevel@tonic-gate if (uap->flags & MS_RDONLY && 9387c478bd9Sstevel@tonic-gate !(flags & NFSMNT_SOFT)) { 9397c478bd9Sstevel@tonic-gate if (svp_head->sv_next == NULL) { 9407c478bd9Sstevel@tonic-gate svp_tail = NULL; 9417c478bd9Sstevel@tonic-gate svp_2ndlast = NULL; 9427c478bd9Sstevel@tonic-gate sv4_free(svp_head); 9437c478bd9Sstevel@tonic-gate goto more; 9447c478bd9Sstevel@tonic-gate } else { 9457c478bd9Sstevel@tonic-gate svp_tail = svp_2ndlast; 9467c478bd9Sstevel@tonic-gate svp_2ndlast->sv_next = 9477c478bd9Sstevel@tonic-gate NULL; 9487c478bd9Sstevel@tonic-gate sv4_free(svp); 9497c478bd9Sstevel@tonic-gate goto more; 9507c478bd9Sstevel@tonic-gate } 9517c478bd9Sstevel@tonic-gate } 9527c478bd9Sstevel@tonic-gate } else { 9537c478bd9Sstevel@tonic-gate /* 9547c478bd9Sstevel@tonic-gate * This is the last server specified 9557c478bd9Sstevel@tonic-gate * in the nfs_args list passed down 9567c478bd9Sstevel@tonic-gate * and its not rdma capable. 9577c478bd9Sstevel@tonic-gate */ 9587c478bd9Sstevel@tonic-gate if (svp_head->sv_next == NULL) { 9597c478bd9Sstevel@tonic-gate /* 9607c478bd9Sstevel@tonic-gate * Is this the only one 9617c478bd9Sstevel@tonic-gate */ 9627c478bd9Sstevel@tonic-gate error = EINVAL; 9637c478bd9Sstevel@tonic-gate #ifdef DEBUG 9647c478bd9Sstevel@tonic-gate if (rdma_debug) 9657c478bd9Sstevel@tonic-gate zcmn_err(getzoneid(), 9667c478bd9Sstevel@tonic-gate CE_WARN, 9677c478bd9Sstevel@tonic-gate "No RDMA srv"); 9687c478bd9Sstevel@tonic-gate #endif 9697c478bd9Sstevel@tonic-gate goto errout; 9707c478bd9Sstevel@tonic-gate } else { 9717c478bd9Sstevel@tonic-gate /* 9727c478bd9Sstevel@tonic-gate * There is list, since some 9737c478bd9Sstevel@tonic-gate * servers specified before 9747c478bd9Sstevel@tonic-gate * this passed all requirements 9757c478bd9Sstevel@tonic-gate */ 9767c478bd9Sstevel@tonic-gate svp_tail = svp_2ndlast; 9777c478bd9Sstevel@tonic-gate svp_2ndlast->sv_next = NULL; 9787c478bd9Sstevel@tonic-gate sv4_free(svp); 9797c478bd9Sstevel@tonic-gate goto proceed; 9807c478bd9Sstevel@tonic-gate } 9817c478bd9Sstevel@tonic-gate } 9827c478bd9Sstevel@tonic-gate } 9837c478bd9Sstevel@tonic-gate } 9847c478bd9Sstevel@tonic-gate } 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate /* 9877c478bd9Sstevel@tonic-gate * If there are syncaddr and netname data, load them in. This is 9887c478bd9Sstevel@tonic-gate * to support data needed for NFSV4 when AUTH_DH is the negotiated 9897c478bd9Sstevel@tonic-gate * flavor via SECINFO. (instead of using MOUNT protocol in V3). 9907c478bd9Sstevel@tonic-gate */ 99139d3e169Sevanl if (args->flags & NFSMNT_SECURE) { 99239d3e169Sevanl svp->sv_dhsec = create_authdh_data(args->netname, 99339d3e169Sevanl strlen(args->netname), 99439d3e169Sevanl args->syncaddr, svp->sv_knconf); 9957c478bd9Sstevel@tonic-gate } 9967c478bd9Sstevel@tonic-gate 9977c478bd9Sstevel@tonic-gate /* 9987c478bd9Sstevel@tonic-gate * Get the extention data which has the security data structure. 9997c478bd9Sstevel@tonic-gate * This includes data for AUTH_SYS as well. 10007c478bd9Sstevel@tonic-gate */ 10017c478bd9Sstevel@tonic-gate if (flags & NFSMNT_NEWARGS) { 100239d3e169Sevanl switch (args->nfs_args_ext) { 10037c478bd9Sstevel@tonic-gate case NFS_ARGS_EXTA: 10047c478bd9Sstevel@tonic-gate case NFS_ARGS_EXTB: 10057c478bd9Sstevel@tonic-gate /* 10067c478bd9Sstevel@tonic-gate * Indicating the application is using the new 10077c478bd9Sstevel@tonic-gate * sec_data structure to pass in the security 10087c478bd9Sstevel@tonic-gate * data. 10097c478bd9Sstevel@tonic-gate */ 101039d3e169Sevanl secdata = args->nfs_ext_u.nfs_extA.secdata; 101139d3e169Sevanl if (secdata == NULL) { 10127c478bd9Sstevel@tonic-gate error = EINVAL; 101339d3e169Sevanl } else if (uap->flags & MS_SYSSPACE) { 101439d3e169Sevanl /* 101539d3e169Sevanl * Need to validate the flavor here if 101639d3e169Sevanl * sysspace, userspace was already 101739d3e169Sevanl * validate from the nfs_copyin function. 101839d3e169Sevanl */ 101939d3e169Sevanl switch (secdata->rpcflavor) { 102039d3e169Sevanl case AUTH_NONE: 102139d3e169Sevanl case AUTH_UNIX: 102239d3e169Sevanl case AUTH_LOOPBACK: 102339d3e169Sevanl case AUTH_DES: 102439d3e169Sevanl case RPCSEC_GSS: 102539d3e169Sevanl break; 102639d3e169Sevanl default: 102739d3e169Sevanl error = EINVAL; 102839d3e169Sevanl goto errout; 10297c478bd9Sstevel@tonic-gate } 103039d3e169Sevanl } 103139d3e169Sevanl args->nfs_ext_u.nfs_extA.secdata = NULL; 10327c478bd9Sstevel@tonic-gate break; 10337c478bd9Sstevel@tonic-gate 10347c478bd9Sstevel@tonic-gate default: 10357c478bd9Sstevel@tonic-gate error = EINVAL; 10367c478bd9Sstevel@tonic-gate break; 10377c478bd9Sstevel@tonic-gate } 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate } else if (flags & NFSMNT_SECURE) { 10407c478bd9Sstevel@tonic-gate /* 10417c478bd9Sstevel@tonic-gate * NFSMNT_SECURE is deprecated but we keep it 1042b9238976Sth199096 * to support the rogue user-generated application 10437c478bd9Sstevel@tonic-gate * that may use this undocumented interface to do 1044b9238976Sth199096 * AUTH_DH security, e.g. our own rexd. 1045b9238976Sth199096 * 1046b9238976Sth199096 * Also note that NFSMNT_SECURE is used for passing 1047b9238976Sth199096 * AUTH_DH info to be used in negotiation. 10487c478bd9Sstevel@tonic-gate */ 104939d3e169Sevanl secdata = create_authdh_data(args->netname, 105039d3e169Sevanl strlen(args->netname), args->syncaddr, svp->sv_knconf); 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate } else { 10537c478bd9Sstevel@tonic-gate secdata = kmem_alloc(sizeof (*secdata), KM_SLEEP); 10547c478bd9Sstevel@tonic-gate secdata->secmod = secdata->rpcflavor = AUTH_SYS; 10557c478bd9Sstevel@tonic-gate secdata->data = NULL; 10567c478bd9Sstevel@tonic-gate } 10577c478bd9Sstevel@tonic-gate 10587c478bd9Sstevel@tonic-gate svp->sv_secdata = secdata; 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate /* 10617c478bd9Sstevel@tonic-gate * User does not explictly specify a flavor, and a user 10627c478bd9Sstevel@tonic-gate * defined default flavor is passed down. 10637c478bd9Sstevel@tonic-gate */ 10647c478bd9Sstevel@tonic-gate if (flags & NFSMNT_SECDEFAULT) { 10657c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 10667c478bd9Sstevel@tonic-gate svp->sv_flags |= SV4_TRYSECDEFAULT; 10677c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 10687c478bd9Sstevel@tonic-gate } 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate /* 10717c478bd9Sstevel@tonic-gate * Failover support: 10727c478bd9Sstevel@tonic-gate * 10737c478bd9Sstevel@tonic-gate * We may have a linked list of nfs_args structures, 10747c478bd9Sstevel@tonic-gate * which means the user is looking for failover. If 10757c478bd9Sstevel@tonic-gate * the mount is either not "read-only" or "soft", 10767c478bd9Sstevel@tonic-gate * we want to bail out with EINVAL. 10777c478bd9Sstevel@tonic-gate */ 107839d3e169Sevanl if (args->nfs_args_ext == NFS_ARGS_EXTB && 107939d3e169Sevanl args->nfs_ext_u.nfs_extB.next != NULL) { 10807c478bd9Sstevel@tonic-gate if (uap->flags & MS_RDONLY && !(flags & NFSMNT_SOFT)) { 108139d3e169Sevanl data = (char *)args->nfs_ext_u.nfs_extB.next; 10827c478bd9Sstevel@tonic-gate goto more; 10837c478bd9Sstevel@tonic-gate } 10847c478bd9Sstevel@tonic-gate error = EINVAL; 10857c478bd9Sstevel@tonic-gate goto errout; 10867c478bd9Sstevel@tonic-gate } 10877c478bd9Sstevel@tonic-gate 10887c478bd9Sstevel@tonic-gate /* 10897c478bd9Sstevel@tonic-gate * Determine the zone we're being mounted into. 10907c478bd9Sstevel@tonic-gate */ 109145916cd2Sjpk zone_hold(mntzone = zone); /* start with this assumption */ 10927c478bd9Sstevel@tonic-gate if (getzoneid() == GLOBAL_ZONEID) { 109345916cd2Sjpk zone_rele(mntzone); 10947c478bd9Sstevel@tonic-gate mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt)); 10957c478bd9Sstevel@tonic-gate ASSERT(mntzone != NULL); 10967c478bd9Sstevel@tonic-gate if (mntzone != zone) { 10977c478bd9Sstevel@tonic-gate error = EBUSY; 10987c478bd9Sstevel@tonic-gate goto errout; 10997c478bd9Sstevel@tonic-gate } 11007c478bd9Sstevel@tonic-gate } 11017c478bd9Sstevel@tonic-gate 110245916cd2Sjpk if (is_system_labeled()) { 110345916cd2Sjpk error = nfs_mount_label_policy(vfsp, &svp->sv_addr, 110445916cd2Sjpk svp->sv_knconf, cr); 110545916cd2Sjpk 110645916cd2Sjpk if (error > 0) 110745916cd2Sjpk goto errout; 110845916cd2Sjpk 110945916cd2Sjpk if (error == -1) { 111045916cd2Sjpk /* change mount to read-only to prevent write-down */ 111145916cd2Sjpk vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); 111245916cd2Sjpk } 111345916cd2Sjpk } 111445916cd2Sjpk 11157c478bd9Sstevel@tonic-gate /* 11167c478bd9Sstevel@tonic-gate * Stop the mount from going any further if the zone is going away. 11177c478bd9Sstevel@tonic-gate */ 111845916cd2Sjpk if (zone_status_get(mntzone) >= ZONE_IS_SHUTTING_DOWN) { 11197c478bd9Sstevel@tonic-gate error = EBUSY; 11207c478bd9Sstevel@tonic-gate goto errout; 11217c478bd9Sstevel@tonic-gate } 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate /* 11247c478bd9Sstevel@tonic-gate * Get root vnode. 11257c478bd9Sstevel@tonic-gate */ 11267c478bd9Sstevel@tonic-gate proceed: 112745916cd2Sjpk error = nfs4rootvp(&rtvp, vfsp, svp_head, flags, cr, mntzone); 112850a83466Sjwahlig if (error) { 112950a83466Sjwahlig /* if nfs4rootvp failed, it will free svp_head */ 113050a83466Sjwahlig svp_head = NULL; 11317c478bd9Sstevel@tonic-gate goto errout; 113250a83466Sjwahlig } 11337c478bd9Sstevel@tonic-gate 11347c478bd9Sstevel@tonic-gate mi = VTOMI4(rtvp); 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate /* 11377c478bd9Sstevel@tonic-gate * Send client id to the server, if necessary 11387c478bd9Sstevel@tonic-gate */ 11397c478bd9Sstevel@tonic-gate nfs4_error_zinit(&n4e); 11407c478bd9Sstevel@tonic-gate nfs4setclientid(mi, cr, FALSE, &n4e); 1141b9238976Sth199096 11427c478bd9Sstevel@tonic-gate error = n4e.error; 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate if (error) 11457c478bd9Sstevel@tonic-gate goto errout; 11467c478bd9Sstevel@tonic-gate 11477c478bd9Sstevel@tonic-gate /* 11487c478bd9Sstevel@tonic-gate * Set option fields in the mount info record 11497c478bd9Sstevel@tonic-gate */ 11507c478bd9Sstevel@tonic-gate 11517c478bd9Sstevel@tonic-gate if (svp_head->sv_next) { 11527c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 11537c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_LLOCK; 11547c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 11557c478bd9Sstevel@tonic-gate } 115639d3e169Sevanl error = nfs4_setopts(rtvp, DATAMODEL_NATIVE, args); 1157b9238976Sth199096 if (error) 1158b9238976Sth199096 goto errout; 1159b9238976Sth199096 1160b9238976Sth199096 /* 1161b9238976Sth199096 * Time to tie in the mirror mount info at last! 1162b9238976Sth199096 */ 1163b9238976Sth199096 if (flags & NFSMNT_EPHEMERAL) 1164d3a14591SThomas Haynes error = nfs4_record_ephemeral_mount(mi, mvp); 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate errout: 11677c478bd9Sstevel@tonic-gate if (error) { 11687c478bd9Sstevel@tonic-gate if (rtvp != NULL) { 11697c478bd9Sstevel@tonic-gate rp = VTOR4(rtvp); 11707c478bd9Sstevel@tonic-gate if (rp->r_flags & R4HASHED) 11717c478bd9Sstevel@tonic-gate rp4_rmhash(rp); 11727c478bd9Sstevel@tonic-gate } 11737c478bd9Sstevel@tonic-gate if (mi != NULL) { 11747c478bd9Sstevel@tonic-gate nfs4_async_stop(vfsp); 11757c478bd9Sstevel@tonic-gate nfs4_async_manager_stop(vfsp); 11767c478bd9Sstevel@tonic-gate nfs4_remove_mi_from_server(mi, NULL); 117750a83466Sjwahlig if (rtvp != NULL) 11787c478bd9Sstevel@tonic-gate VN_RELE(rtvp); 117945916cd2Sjpk if (mntzone != NULL) 118045916cd2Sjpk zone_rele(mntzone); 118150a83466Sjwahlig /* need to remove it from the zone */ 118250a83466Sjwahlig removed = nfs4_mi_zonelist_remove(mi); 118350a83466Sjwahlig if (removed) 1184a19609f8Sjv227347 zone_rele_ref(&mi->mi_zone_ref, 1185a19609f8Sjv227347 ZONE_REF_NFSV4); 118650a83466Sjwahlig MI4_RELE(mi); 118739d3e169Sevanl if (!(uap->flags & MS_SYSSPACE) && args) { 118839d3e169Sevanl nfs4_free_args(args); 118939d3e169Sevanl kmem_free(args, sizeof (*args)); 119039d3e169Sevanl } 11917c478bd9Sstevel@tonic-gate return (error); 11927c478bd9Sstevel@tonic-gate } 119350a83466Sjwahlig if (svp_head) 11947c478bd9Sstevel@tonic-gate sv4_free(svp_head); 11957c478bd9Sstevel@tonic-gate } 11967c478bd9Sstevel@tonic-gate 119739d3e169Sevanl if (!(uap->flags & MS_SYSSPACE) && args) { 119839d3e169Sevanl nfs4_free_args(args); 119939d3e169Sevanl kmem_free(args, sizeof (*args)); 120039d3e169Sevanl } 12017c478bd9Sstevel@tonic-gate if (rtvp != NULL) 12027c478bd9Sstevel@tonic-gate VN_RELE(rtvp); 12037c478bd9Sstevel@tonic-gate 120445916cd2Sjpk if (mntzone != NULL) 120545916cd2Sjpk zone_rele(mntzone); 120645916cd2Sjpk 12077c478bd9Sstevel@tonic-gate return (error); 12087c478bd9Sstevel@tonic-gate } 12097c478bd9Sstevel@tonic-gate 12107c478bd9Sstevel@tonic-gate #ifdef DEBUG 12117c478bd9Sstevel@tonic-gate #define VERS_MSG "NFS4 server " 12127c478bd9Sstevel@tonic-gate #else 12137c478bd9Sstevel@tonic-gate #define VERS_MSG "NFS server " 12147c478bd9Sstevel@tonic-gate #endif 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate #define READ_MSG \ 12177c478bd9Sstevel@tonic-gate VERS_MSG "%s returned 0 for read transfer size" 12187c478bd9Sstevel@tonic-gate #define WRITE_MSG \ 12197c478bd9Sstevel@tonic-gate VERS_MSG "%s returned 0 for write transfer size" 12207c478bd9Sstevel@tonic-gate #define SIZE_MSG \ 12217c478bd9Sstevel@tonic-gate VERS_MSG "%s returned 0 for maximum file size" 12227c478bd9Sstevel@tonic-gate 12237c478bd9Sstevel@tonic-gate /* 12247c478bd9Sstevel@tonic-gate * Get the symbolic link text from the server for a given filehandle 12257c478bd9Sstevel@tonic-gate * of that symlink. 12267c478bd9Sstevel@tonic-gate * 12277c478bd9Sstevel@tonic-gate * (get symlink text) PUTFH READLINK 12287c478bd9Sstevel@tonic-gate */ 12297c478bd9Sstevel@tonic-gate static int 12307c478bd9Sstevel@tonic-gate getlinktext_otw(mntinfo4_t *mi, nfs_fh4 *fh, char **linktextp, cred_t *cr, 12317c478bd9Sstevel@tonic-gate int flags) 12327c478bd9Sstevel@tonic-gate { 12337c478bd9Sstevel@tonic-gate COMPOUND4args_clnt args; 12347c478bd9Sstevel@tonic-gate COMPOUND4res_clnt res; 12357c478bd9Sstevel@tonic-gate int doqueue; 12367c478bd9Sstevel@tonic-gate nfs_argop4 argop[2]; 12377c478bd9Sstevel@tonic-gate nfs_resop4 *resop; 12387c478bd9Sstevel@tonic-gate READLINK4res *lr_res; 12397c478bd9Sstevel@tonic-gate uint_t len; 12407c478bd9Sstevel@tonic-gate bool_t needrecov = FALSE; 12417c478bd9Sstevel@tonic-gate nfs4_recov_state_t recov_state; 12427c478bd9Sstevel@tonic-gate nfs4_sharedfh_t *sfh; 12437c478bd9Sstevel@tonic-gate nfs4_error_t e; 12447c478bd9Sstevel@tonic-gate int num_retry = nfs4_max_mount_retry; 12457c478bd9Sstevel@tonic-gate int recovery = !(flags & NFS4_GETFH_NEEDSOP); 12467c478bd9Sstevel@tonic-gate 12477c478bd9Sstevel@tonic-gate sfh = sfh4_get(fh, mi); 12487c478bd9Sstevel@tonic-gate recov_state.rs_flags = 0; 12497c478bd9Sstevel@tonic-gate recov_state.rs_num_retry_despite_err = 0; 12507c478bd9Sstevel@tonic-gate 12517c478bd9Sstevel@tonic-gate recov_retry: 12527c478bd9Sstevel@tonic-gate nfs4_error_zinit(&e); 12537c478bd9Sstevel@tonic-gate 12547c478bd9Sstevel@tonic-gate args.array_len = 2; 12557c478bd9Sstevel@tonic-gate args.array = argop; 12567c478bd9Sstevel@tonic-gate args.ctag = TAG_GET_SYMLINK; 12577c478bd9Sstevel@tonic-gate 12587c478bd9Sstevel@tonic-gate if (! recovery) { 12597c478bd9Sstevel@tonic-gate e.error = nfs4_start_op(mi, NULL, NULL, &recov_state); 12607c478bd9Sstevel@tonic-gate if (e.error) { 12617c478bd9Sstevel@tonic-gate sfh4_rele(&sfh); 12627c478bd9Sstevel@tonic-gate return (e.error); 12637c478bd9Sstevel@tonic-gate } 12647c478bd9Sstevel@tonic-gate } 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate /* 0. putfh symlink fh */ 12677c478bd9Sstevel@tonic-gate argop[0].argop = OP_CPUTFH; 12687c478bd9Sstevel@tonic-gate argop[0].nfs_argop4_u.opcputfh.sfh = sfh; 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate /* 1. readlink */ 12717c478bd9Sstevel@tonic-gate argop[1].argop = OP_READLINK; 12727c478bd9Sstevel@tonic-gate 12737c478bd9Sstevel@tonic-gate doqueue = 1; 12747c478bd9Sstevel@tonic-gate 12757c478bd9Sstevel@tonic-gate rfs4call(mi, &args, &res, cr, &doqueue, 0, &e); 12767c478bd9Sstevel@tonic-gate 12777c478bd9Sstevel@tonic-gate needrecov = nfs4_needs_recovery(&e, FALSE, mi->mi_vfsp); 12787c478bd9Sstevel@tonic-gate 12797c478bd9Sstevel@tonic-gate if (needrecov && !recovery && num_retry-- > 0) { 12807c478bd9Sstevel@tonic-gate 12817c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE, 12827c478bd9Sstevel@tonic-gate "getlinktext_otw: initiating recovery\n")); 12837c478bd9Sstevel@tonic-gate 12847c478bd9Sstevel@tonic-gate if (nfs4_start_recovery(&e, mi, NULL, NULL, NULL, NULL, 12852f172c55SRobert Thurlow OP_READLINK, NULL, NULL, NULL) == FALSE) { 12867c478bd9Sstevel@tonic-gate nfs4_end_op(mi, NULL, NULL, &recov_state, needrecov); 12877c478bd9Sstevel@tonic-gate if (!e.error) 12887c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, 12897c478bd9Sstevel@tonic-gate (caddr_t)&res); 12907c478bd9Sstevel@tonic-gate goto recov_retry; 12917c478bd9Sstevel@tonic-gate } 12927c478bd9Sstevel@tonic-gate } 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate /* 12957c478bd9Sstevel@tonic-gate * If non-NFS4 pcol error and/or we weren't able to recover. 12967c478bd9Sstevel@tonic-gate */ 12977c478bd9Sstevel@tonic-gate if (e.error != 0) { 12987c478bd9Sstevel@tonic-gate if (! recovery) 12997c478bd9Sstevel@tonic-gate nfs4_end_op(mi, NULL, NULL, &recov_state, needrecov); 13007c478bd9Sstevel@tonic-gate sfh4_rele(&sfh); 13017c478bd9Sstevel@tonic-gate return (e.error); 13027c478bd9Sstevel@tonic-gate } 13037c478bd9Sstevel@tonic-gate 13047c478bd9Sstevel@tonic-gate if (res.status) { 13057c478bd9Sstevel@tonic-gate e.error = geterrno4(res.status); 13067c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 13077c478bd9Sstevel@tonic-gate if (! recovery) 13087c478bd9Sstevel@tonic-gate nfs4_end_op(mi, NULL, NULL, &recov_state, needrecov); 13097c478bd9Sstevel@tonic-gate sfh4_rele(&sfh); 13107c478bd9Sstevel@tonic-gate return (e.error); 13117c478bd9Sstevel@tonic-gate } 13127c478bd9Sstevel@tonic-gate 13137c478bd9Sstevel@tonic-gate /* res.status == NFS4_OK */ 13147c478bd9Sstevel@tonic-gate ASSERT(res.status == NFS4_OK); 13157c478bd9Sstevel@tonic-gate 13167c478bd9Sstevel@tonic-gate resop = &res.array[1]; /* readlink res */ 13177c478bd9Sstevel@tonic-gate lr_res = &resop->nfs_resop4_u.opreadlink; 13187c478bd9Sstevel@tonic-gate 13197c478bd9Sstevel@tonic-gate /* treat symlink name as data */ 1320bbe876c0SMarcel Telka *linktextp = utf8_to_str((utf8string *)&lr_res->link, &len, NULL); 13217c478bd9Sstevel@tonic-gate 13227c478bd9Sstevel@tonic-gate if (! recovery) 13237c478bd9Sstevel@tonic-gate nfs4_end_op(mi, NULL, NULL, &recov_state, needrecov); 13247c478bd9Sstevel@tonic-gate sfh4_rele(&sfh); 13257c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 13267c478bd9Sstevel@tonic-gate return (0); 13277c478bd9Sstevel@tonic-gate } 13287c478bd9Sstevel@tonic-gate 13297c478bd9Sstevel@tonic-gate /* 13307c478bd9Sstevel@tonic-gate * Skip over consecutive slashes and "/./" in a pathname. 13317c478bd9Sstevel@tonic-gate */ 13327c478bd9Sstevel@tonic-gate void 13337c478bd9Sstevel@tonic-gate pathname_skipslashdot(struct pathname *pnp) 13347c478bd9Sstevel@tonic-gate { 13357c478bd9Sstevel@tonic-gate char *c1, *c2; 13367c478bd9Sstevel@tonic-gate 13377c478bd9Sstevel@tonic-gate while (pnp->pn_pathlen > 0 && *pnp->pn_path == '/') { 13387c478bd9Sstevel@tonic-gate 13397c478bd9Sstevel@tonic-gate c1 = pnp->pn_path + 1; 13407c478bd9Sstevel@tonic-gate c2 = pnp->pn_path + 2; 13417c478bd9Sstevel@tonic-gate 13427c478bd9Sstevel@tonic-gate if (*c1 == '.' && (*c2 == '/' || *c2 == '\0')) { 13437c478bd9Sstevel@tonic-gate pnp->pn_path = pnp->pn_path + 2; /* skip "/." */ 13447c478bd9Sstevel@tonic-gate pnp->pn_pathlen = pnp->pn_pathlen - 2; 13457c478bd9Sstevel@tonic-gate } else { 13467c478bd9Sstevel@tonic-gate pnp->pn_path++; 13477c478bd9Sstevel@tonic-gate pnp->pn_pathlen--; 13487c478bd9Sstevel@tonic-gate } 13497c478bd9Sstevel@tonic-gate } 13507c478bd9Sstevel@tonic-gate } 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate /* 13537c478bd9Sstevel@tonic-gate * Resolve a symbolic link path. The symlink is in the nth component of 13547c478bd9Sstevel@tonic-gate * svp->sv_path and has an nfs4 file handle "fh". 13557c478bd9Sstevel@tonic-gate * Upon return, the sv_path will point to the new path that has the nth 13567c478bd9Sstevel@tonic-gate * component resolved to its symlink text. 13577c478bd9Sstevel@tonic-gate */ 13587c478bd9Sstevel@tonic-gate int 13597c478bd9Sstevel@tonic-gate resolve_sympath(mntinfo4_t *mi, servinfo4_t *svp, int nth, nfs_fh4 *fh, 13607c478bd9Sstevel@tonic-gate cred_t *cr, int flags) 13617c478bd9Sstevel@tonic-gate { 13627c478bd9Sstevel@tonic-gate char *oldpath; 13637c478bd9Sstevel@tonic-gate char *symlink, *newpath; 13647c478bd9Sstevel@tonic-gate struct pathname oldpn, newpn; 13657c478bd9Sstevel@tonic-gate char component[MAXNAMELEN]; 13667c478bd9Sstevel@tonic-gate int i, addlen, error = 0; 13677c478bd9Sstevel@tonic-gate int oldpathlen; 13687c478bd9Sstevel@tonic-gate 13697c478bd9Sstevel@tonic-gate /* Get the symbolic link text over the wire. */ 13707c478bd9Sstevel@tonic-gate error = getlinktext_otw(mi, fh, &symlink, cr, flags); 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate if (error || symlink == NULL || strlen(symlink) == 0) 13737c478bd9Sstevel@tonic-gate return (error); 13747c478bd9Sstevel@tonic-gate 13757c478bd9Sstevel@tonic-gate /* 13767c478bd9Sstevel@tonic-gate * Compose the new pathname. 13777c478bd9Sstevel@tonic-gate * Note: 13787c478bd9Sstevel@tonic-gate * - only the nth component is resolved for the pathname. 13797c478bd9Sstevel@tonic-gate * - pathname.pn_pathlen does not count the ending null byte. 13807c478bd9Sstevel@tonic-gate */ 13817c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 13827c478bd9Sstevel@tonic-gate oldpath = svp->sv_path; 13837c478bd9Sstevel@tonic-gate oldpathlen = svp->sv_pathlen; 13847c478bd9Sstevel@tonic-gate if (error = pn_get(oldpath, UIO_SYSSPACE, &oldpn)) { 13857c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 13867c478bd9Sstevel@tonic-gate kmem_free(symlink, strlen(symlink) + 1); 13877c478bd9Sstevel@tonic-gate return (error); 13887c478bd9Sstevel@tonic-gate } 13897c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 13907c478bd9Sstevel@tonic-gate pn_alloc(&newpn); 13917c478bd9Sstevel@tonic-gate 13927c478bd9Sstevel@tonic-gate /* 13937c478bd9Sstevel@tonic-gate * Skip over previous components from the oldpath so that the 13947c478bd9Sstevel@tonic-gate * oldpn.pn_path will point to the symlink component. Skip 13957c478bd9Sstevel@tonic-gate * leading slashes and "/./" (no OP_LOOKUP on ".") so that 13967c478bd9Sstevel@tonic-gate * pn_getcompnent can get the component. 13977c478bd9Sstevel@tonic-gate */ 13987c478bd9Sstevel@tonic-gate for (i = 1; i < nth; i++) { 13997c478bd9Sstevel@tonic-gate pathname_skipslashdot(&oldpn); 14007c478bd9Sstevel@tonic-gate error = pn_getcomponent(&oldpn, component); 14017c478bd9Sstevel@tonic-gate if (error) 14027c478bd9Sstevel@tonic-gate goto out; 14037c478bd9Sstevel@tonic-gate } 14047c478bd9Sstevel@tonic-gate 14057c478bd9Sstevel@tonic-gate /* 14067c478bd9Sstevel@tonic-gate * Copy the old path upto the component right before the symlink 14077c478bd9Sstevel@tonic-gate * if the symlink is not an absolute path. 14087c478bd9Sstevel@tonic-gate */ 14097c478bd9Sstevel@tonic-gate if (symlink[0] != '/') { 14107c478bd9Sstevel@tonic-gate addlen = oldpn.pn_path - oldpn.pn_buf; 14117c478bd9Sstevel@tonic-gate bcopy(oldpn.pn_buf, newpn.pn_path, addlen); 14127c478bd9Sstevel@tonic-gate newpn.pn_pathlen += addlen; 14137c478bd9Sstevel@tonic-gate newpn.pn_path += addlen; 14147c478bd9Sstevel@tonic-gate newpn.pn_buf[newpn.pn_pathlen] = '/'; 14157c478bd9Sstevel@tonic-gate newpn.pn_pathlen++; 14167c478bd9Sstevel@tonic-gate newpn.pn_path++; 14177c478bd9Sstevel@tonic-gate } 14187c478bd9Sstevel@tonic-gate 14197c478bd9Sstevel@tonic-gate /* copy the resolved symbolic link text */ 14207c478bd9Sstevel@tonic-gate addlen = strlen(symlink); 14217c478bd9Sstevel@tonic-gate if (newpn.pn_pathlen + addlen >= newpn.pn_bufsize) { 14227c478bd9Sstevel@tonic-gate error = ENAMETOOLONG; 14237c478bd9Sstevel@tonic-gate goto out; 14247c478bd9Sstevel@tonic-gate } 14257c478bd9Sstevel@tonic-gate bcopy(symlink, newpn.pn_path, addlen); 14267c478bd9Sstevel@tonic-gate newpn.pn_pathlen += addlen; 14277c478bd9Sstevel@tonic-gate newpn.pn_path += addlen; 14287c478bd9Sstevel@tonic-gate 14297c478bd9Sstevel@tonic-gate /* 14307c478bd9Sstevel@tonic-gate * Check if there is any remaining path after the symlink component. 14317c478bd9Sstevel@tonic-gate * First, skip the symlink component. 14327c478bd9Sstevel@tonic-gate */ 14337c478bd9Sstevel@tonic-gate pathname_skipslashdot(&oldpn); 14347c478bd9Sstevel@tonic-gate if (error = pn_getcomponent(&oldpn, component)) 14357c478bd9Sstevel@tonic-gate goto out; 14367c478bd9Sstevel@tonic-gate 14377c478bd9Sstevel@tonic-gate addlen = pn_pathleft(&oldpn); /* includes counting the slash */ 14387c478bd9Sstevel@tonic-gate 14397c478bd9Sstevel@tonic-gate /* 14407c478bd9Sstevel@tonic-gate * Copy the remaining path to the new pathname if there is any. 14417c478bd9Sstevel@tonic-gate */ 14427c478bd9Sstevel@tonic-gate if (addlen > 0) { 14437c478bd9Sstevel@tonic-gate if (newpn.pn_pathlen + addlen >= newpn.pn_bufsize) { 14447c478bd9Sstevel@tonic-gate error = ENAMETOOLONG; 14457c478bd9Sstevel@tonic-gate goto out; 14467c478bd9Sstevel@tonic-gate } 14477c478bd9Sstevel@tonic-gate bcopy(oldpn.pn_path, newpn.pn_path, addlen); 14487c478bd9Sstevel@tonic-gate newpn.pn_pathlen += addlen; 14497c478bd9Sstevel@tonic-gate } 14507c478bd9Sstevel@tonic-gate newpn.pn_buf[newpn.pn_pathlen] = '\0'; 14517c478bd9Sstevel@tonic-gate 14527c478bd9Sstevel@tonic-gate /* get the newpath and store it in the servinfo4_t */ 14537c478bd9Sstevel@tonic-gate newpath = kmem_alloc(newpn.pn_pathlen + 1, KM_SLEEP); 14547c478bd9Sstevel@tonic-gate bcopy(newpn.pn_buf, newpath, newpn.pn_pathlen); 14557c478bd9Sstevel@tonic-gate newpath[newpn.pn_pathlen] = '\0'; 14567c478bd9Sstevel@tonic-gate 14577c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 14587c478bd9Sstevel@tonic-gate svp->sv_path = newpath; 14597c478bd9Sstevel@tonic-gate svp->sv_pathlen = strlen(newpath) + 1; 14607c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 14617c478bd9Sstevel@tonic-gate 14627c478bd9Sstevel@tonic-gate kmem_free(oldpath, oldpathlen); 14637c478bd9Sstevel@tonic-gate out: 14647c478bd9Sstevel@tonic-gate kmem_free(symlink, strlen(symlink) + 1); 14657c478bd9Sstevel@tonic-gate pn_free(&newpn); 14667c478bd9Sstevel@tonic-gate pn_free(&oldpn); 14677c478bd9Sstevel@tonic-gate 14687c478bd9Sstevel@tonic-gate return (error); 14697c478bd9Sstevel@tonic-gate } 14707c478bd9Sstevel@tonic-gate 14717c478bd9Sstevel@tonic-gate /* 14722f172c55SRobert Thurlow * This routine updates servinfo4 structure with the new referred server 14732f172c55SRobert Thurlow * info. 14742f172c55SRobert Thurlow * nfsfsloc has the location related information 14752f172c55SRobert Thurlow * fsp has the hostname and pathname info. 14762f172c55SRobert Thurlow * new path = pathname from referral + part of orig pathname(based on nth). 14772f172c55SRobert Thurlow */ 14782f172c55SRobert Thurlow static void 14792f172c55SRobert Thurlow update_servinfo4(servinfo4_t *svp, fs_location4 *fsp, 14802f172c55SRobert Thurlow struct nfs_fsl_info *nfsfsloc, char *orig_path, int nth) 14812f172c55SRobert Thurlow { 14822f172c55SRobert Thurlow struct knetconfig *knconf, *svknconf; 14832f172c55SRobert Thurlow struct netbuf *saddr; 14842f172c55SRobert Thurlow sec_data_t *secdata; 14852f172c55SRobert Thurlow utf8string *host; 14862f172c55SRobert Thurlow int i = 0, num_slashes = 0; 14872f172c55SRobert Thurlow char *p, *spath, *op, *new_path; 14882f172c55SRobert Thurlow 14892f172c55SRobert Thurlow /* Update knconf */ 14902f172c55SRobert Thurlow knconf = svp->sv_knconf; 14912f172c55SRobert Thurlow free_knconf_contents(knconf); 14922f172c55SRobert Thurlow bzero(knconf, sizeof (struct knetconfig)); 14932f172c55SRobert Thurlow svknconf = nfsfsloc->knconf; 14942f172c55SRobert Thurlow knconf->knc_semantics = svknconf->knc_semantics; 14952f172c55SRobert Thurlow knconf->knc_protofmly = kmem_zalloc(KNC_STRSIZE, KM_SLEEP); 14962f172c55SRobert Thurlow knconf->knc_proto = kmem_zalloc(KNC_STRSIZE, KM_SLEEP); 14972f172c55SRobert Thurlow knconf->knc_rdev = svknconf->knc_rdev; 14982f172c55SRobert Thurlow bcopy(svknconf->knc_protofmly, knconf->knc_protofmly, KNC_STRSIZE); 14992f172c55SRobert Thurlow bcopy(svknconf->knc_proto, knconf->knc_proto, KNC_STRSIZE); 15002f172c55SRobert Thurlow 15012f172c55SRobert Thurlow /* Update server address */ 15022f172c55SRobert Thurlow saddr = &svp->sv_addr; 15032f172c55SRobert Thurlow if (saddr->buf != NULL) 15042f172c55SRobert Thurlow kmem_free(saddr->buf, saddr->maxlen); 15052f172c55SRobert Thurlow saddr->buf = kmem_alloc(nfsfsloc->addr->maxlen, KM_SLEEP); 15062f172c55SRobert Thurlow saddr->len = nfsfsloc->addr->len; 15072f172c55SRobert Thurlow saddr->maxlen = nfsfsloc->addr->maxlen; 15082f172c55SRobert Thurlow bcopy(nfsfsloc->addr->buf, saddr->buf, nfsfsloc->addr->len); 15092f172c55SRobert Thurlow 15102f172c55SRobert Thurlow /* Update server name */ 15112f172c55SRobert Thurlow host = fsp->server_val; 15122f172c55SRobert Thurlow kmem_free(svp->sv_hostname, svp->sv_hostnamelen); 15132f172c55SRobert Thurlow svp->sv_hostname = kmem_zalloc(host->utf8string_len + 1, KM_SLEEP); 15142f172c55SRobert Thurlow bcopy(host->utf8string_val, svp->sv_hostname, host->utf8string_len); 15152f172c55SRobert Thurlow svp->sv_hostname[host->utf8string_len] = '\0'; 15162f172c55SRobert Thurlow svp->sv_hostnamelen = host->utf8string_len + 1; 15172f172c55SRobert Thurlow 15182f172c55SRobert Thurlow /* 15192f172c55SRobert Thurlow * Update server path. 15202f172c55SRobert Thurlow * We need to setup proper path here. 15212f172c55SRobert Thurlow * For ex., If we got a path name serv1:/rp/aaa/bbb 15222f172c55SRobert Thurlow * where aaa is a referral and points to serv2:/rpool/aa 15232f172c55SRobert Thurlow * we need to set the path to serv2:/rpool/aa/bbb 15242f172c55SRobert Thurlow * The first part of this below code generates /rpool/aa 15252f172c55SRobert Thurlow * and the second part appends /bbb to the server path. 15262f172c55SRobert Thurlow */ 15272f172c55SRobert Thurlow spath = p = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 15282f172c55SRobert Thurlow *p++ = '/'; 15292f172c55SRobert Thurlow for (i = 0; i < fsp->rootpath.pathname4_len; i++) { 15302f172c55SRobert Thurlow component4 *comp; 15312f172c55SRobert Thurlow 15322f172c55SRobert Thurlow comp = &fsp->rootpath.pathname4_val[i]; 15332f172c55SRobert Thurlow /* If no space, null the string and bail */ 15342f172c55SRobert Thurlow if ((p - spath) + comp->utf8string_len + 1 > MAXPATHLEN) { 15352f172c55SRobert Thurlow p = spath + MAXPATHLEN - 1; 15362f172c55SRobert Thurlow spath[0] = '\0'; 15372f172c55SRobert Thurlow break; 15382f172c55SRobert Thurlow } 15392f172c55SRobert Thurlow bcopy(comp->utf8string_val, p, comp->utf8string_len); 15402f172c55SRobert Thurlow p += comp->utf8string_len; 15412f172c55SRobert Thurlow *p++ = '/'; 15422f172c55SRobert Thurlow } 15432f172c55SRobert Thurlow if (fsp->rootpath.pathname4_len != 0) 15442f172c55SRobert Thurlow *(p - 1) = '\0'; 15452f172c55SRobert Thurlow else 15462f172c55SRobert Thurlow *p = '\0'; 15472f172c55SRobert Thurlow p = spath; 15482f172c55SRobert Thurlow 15492f172c55SRobert Thurlow new_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 15502f172c55SRobert Thurlow (void) strlcpy(new_path, p, MAXPATHLEN); 15512f172c55SRobert Thurlow kmem_free(p, MAXPATHLEN); 15522f172c55SRobert Thurlow i = strlen(new_path); 15532f172c55SRobert Thurlow 15542f172c55SRobert Thurlow for (op = orig_path; *op; op++) { 15552f172c55SRobert Thurlow if (*op == '/') 15562f172c55SRobert Thurlow num_slashes++; 15572f172c55SRobert Thurlow if (num_slashes == nth + 2) { 15582f172c55SRobert Thurlow while (*op != '\0') { 15592f172c55SRobert Thurlow new_path[i] = *op; 15602f172c55SRobert Thurlow i++; 15612f172c55SRobert Thurlow op++; 15622f172c55SRobert Thurlow } 15632f172c55SRobert Thurlow break; 15642f172c55SRobert Thurlow } 15652f172c55SRobert Thurlow } 15662f172c55SRobert Thurlow new_path[i] = '\0'; 15672f172c55SRobert Thurlow 15682f172c55SRobert Thurlow kmem_free(svp->sv_path, svp->sv_pathlen); 15692f172c55SRobert Thurlow svp->sv_pathlen = strlen(new_path) + 1; 15702f172c55SRobert Thurlow svp->sv_path = kmem_alloc(svp->sv_pathlen, KM_SLEEP); 15712f172c55SRobert Thurlow bcopy(new_path, svp->sv_path, svp->sv_pathlen); 15722f172c55SRobert Thurlow kmem_free(new_path, MAXPATHLEN); 15732f172c55SRobert Thurlow 15742f172c55SRobert Thurlow /* 15752f172c55SRobert Thurlow * All the security data is specific to old server. 15762f172c55SRobert Thurlow * Clean it up except secdata which deals with mount options. 15772f172c55SRobert Thurlow * We need to inherit that data. Copy secdata into our new servinfo4. 15782f172c55SRobert Thurlow */ 15792f172c55SRobert Thurlow if (svp->sv_dhsec) { 15802f172c55SRobert Thurlow sec_clnt_freeinfo(svp->sv_dhsec); 15812f172c55SRobert Thurlow svp->sv_dhsec = NULL; 15822f172c55SRobert Thurlow } 15832f172c55SRobert Thurlow if (svp->sv_save_secinfo && 15842f172c55SRobert Thurlow svp->sv_save_secinfo != svp->sv_secinfo) { 15852f172c55SRobert Thurlow secinfo_free(svp->sv_save_secinfo); 15862f172c55SRobert Thurlow svp->sv_save_secinfo = NULL; 15872f172c55SRobert Thurlow } 15882f172c55SRobert Thurlow if (svp->sv_secinfo) { 15892f172c55SRobert Thurlow secinfo_free(svp->sv_secinfo); 15902f172c55SRobert Thurlow svp->sv_secinfo = NULL; 15912f172c55SRobert Thurlow } 15922f172c55SRobert Thurlow svp->sv_currsec = NULL; 15932f172c55SRobert Thurlow 15942f172c55SRobert Thurlow secdata = kmem_alloc(sizeof (*secdata), KM_SLEEP); 15952f172c55SRobert Thurlow *secdata = *svp->sv_secdata; 15962f172c55SRobert Thurlow secdata->data = NULL; 15972f172c55SRobert Thurlow if (svp->sv_secdata) { 15982f172c55SRobert Thurlow sec_clnt_freeinfo(svp->sv_secdata); 15992f172c55SRobert Thurlow svp->sv_secdata = NULL; 16002f172c55SRobert Thurlow } 16012f172c55SRobert Thurlow svp->sv_secdata = secdata; 16022f172c55SRobert Thurlow } 16032f172c55SRobert Thurlow 16042f172c55SRobert Thurlow /* 16052f172c55SRobert Thurlow * Resolve a referral. The referral is in the n+1th component of 16062f172c55SRobert Thurlow * svp->sv_path and has a parent nfs4 file handle "fh". 16072f172c55SRobert Thurlow * Upon return, the sv_path will point to the new path that has referral 16082f172c55SRobert Thurlow * component resolved to its referred path and part of original path. 16092f172c55SRobert Thurlow * Hostname and other address information is also updated. 16102f172c55SRobert Thurlow */ 16112f172c55SRobert Thurlow int 16122f172c55SRobert Thurlow resolve_referral(mntinfo4_t *mi, servinfo4_t *svp, cred_t *cr, int nth, 16132f172c55SRobert Thurlow nfs_fh4 *fh) 16142f172c55SRobert Thurlow { 16152f172c55SRobert Thurlow nfs4_sharedfh_t *sfh; 16162f172c55SRobert Thurlow struct nfs_fsl_info nfsfsloc; 16172f172c55SRobert Thurlow nfs4_ga_res_t garp; 16182f172c55SRobert Thurlow COMPOUND4res_clnt callres; 16192f172c55SRobert Thurlow fs_location4 *fsp; 16202f172c55SRobert Thurlow char *nm, *orig_path; 16212f172c55SRobert Thurlow int orig_pathlen = 0, ret = -1, index; 16222f172c55SRobert Thurlow 16232f172c55SRobert Thurlow if (svp->sv_pathlen <= 0) 16242f172c55SRobert Thurlow return (ret); 16252f172c55SRobert Thurlow 16262f172c55SRobert Thurlow (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 16272f172c55SRobert Thurlow orig_pathlen = svp->sv_pathlen; 16282f172c55SRobert Thurlow orig_path = kmem_alloc(orig_pathlen, KM_SLEEP); 16292f172c55SRobert Thurlow bcopy(svp->sv_path, orig_path, orig_pathlen); 16302f172c55SRobert Thurlow nm = extract_referral_point(svp->sv_path, nth); 16312f172c55SRobert Thurlow setup_newsvpath(svp, nth); 16322f172c55SRobert Thurlow nfs_rw_exit(&svp->sv_lock); 16332f172c55SRobert Thurlow 16342f172c55SRobert Thurlow sfh = sfh4_get(fh, mi); 16352f172c55SRobert Thurlow index = nfs4_process_referral(mi, sfh, nm, cr, 16362f172c55SRobert Thurlow &garp, &callres, &nfsfsloc); 16372f172c55SRobert Thurlow sfh4_rele(&sfh); 16382f172c55SRobert Thurlow kmem_free(nm, MAXPATHLEN); 16392f172c55SRobert Thurlow if (index < 0) { 16402f172c55SRobert Thurlow kmem_free(orig_path, orig_pathlen); 16412f172c55SRobert Thurlow return (index); 16422f172c55SRobert Thurlow } 16432f172c55SRobert Thurlow 16442f172c55SRobert Thurlow fsp = &garp.n4g_ext_res->n4g_fslocations.locations_val[index]; 16452f172c55SRobert Thurlow (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 16462f172c55SRobert Thurlow update_servinfo4(svp, fsp, &nfsfsloc, orig_path, nth); 16472f172c55SRobert Thurlow nfs_rw_exit(&svp->sv_lock); 16482f172c55SRobert Thurlow 16492f172c55SRobert Thurlow mutex_enter(&mi->mi_lock); 16502f172c55SRobert Thurlow mi->mi_vfs_referral_loop_cnt++; 16512f172c55SRobert Thurlow mutex_exit(&mi->mi_lock); 16522f172c55SRobert Thurlow 16532f172c55SRobert Thurlow ret = 0; 16542f172c55SRobert Thurlow bad: 16552f172c55SRobert Thurlow /* Free up XDR memory allocated in nfs4_process_referral() */ 16562f172c55SRobert Thurlow xdr_free(xdr_nfs_fsl_info, (char *)&nfsfsloc); 16572f172c55SRobert Thurlow xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&callres); 16582f172c55SRobert Thurlow kmem_free(orig_path, orig_pathlen); 16592f172c55SRobert Thurlow 16602f172c55SRobert Thurlow return (ret); 16612f172c55SRobert Thurlow } 16622f172c55SRobert Thurlow 16632f172c55SRobert Thurlow /* 16647c478bd9Sstevel@tonic-gate * Get the root filehandle for the given filesystem and server, and update 16657c478bd9Sstevel@tonic-gate * svp. 16667c478bd9Sstevel@tonic-gate * 16677c478bd9Sstevel@tonic-gate * If NFS4_GETFH_NEEDSOP is set, then use nfs4_start_fop and nfs4_end_fop 16687c478bd9Sstevel@tonic-gate * to coordinate with recovery. Otherwise, the caller is assumed to be 16697c478bd9Sstevel@tonic-gate * the recovery thread or have already done a start_fop. 16707c478bd9Sstevel@tonic-gate * 16717c478bd9Sstevel@tonic-gate * Errors are returned by the nfs4_error_t parameter. 16727c478bd9Sstevel@tonic-gate */ 16737c478bd9Sstevel@tonic-gate static void 16747c478bd9Sstevel@tonic-gate nfs4getfh_otw(struct mntinfo4 *mi, servinfo4_t *svp, vtype_t *vtp, 16757c478bd9Sstevel@tonic-gate int flags, cred_t *cr, nfs4_error_t *ep) 16767c478bd9Sstevel@tonic-gate { 16777c478bd9Sstevel@tonic-gate COMPOUND4args_clnt args; 16787c478bd9Sstevel@tonic-gate COMPOUND4res_clnt res; 16797c478bd9Sstevel@tonic-gate int doqueue = 1; 16807c478bd9Sstevel@tonic-gate nfs_argop4 *argop; 16817c478bd9Sstevel@tonic-gate nfs_resop4 *resop; 16827c478bd9Sstevel@tonic-gate nfs4_ga_res_t *garp; 16837c478bd9Sstevel@tonic-gate int num_argops; 16847c478bd9Sstevel@tonic-gate lookup4_param_t lookuparg; 16857c478bd9Sstevel@tonic-gate nfs_fh4 *tmpfhp; 16867c478bd9Sstevel@tonic-gate nfs_fh4 *resfhp; 16877c478bd9Sstevel@tonic-gate bool_t needrecov = FALSE; 16887c478bd9Sstevel@tonic-gate nfs4_recov_state_t recov_state; 16897c478bd9Sstevel@tonic-gate int llndx; 16907c478bd9Sstevel@tonic-gate int nthcomp; 16917c478bd9Sstevel@tonic-gate int recovery = !(flags & NFS4_GETFH_NEEDSOP); 16927c478bd9Sstevel@tonic-gate 16937c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 16947c478bd9Sstevel@tonic-gate ASSERT(svp->sv_path != NULL); 16957c478bd9Sstevel@tonic-gate if (svp->sv_path[0] == '\0') { 16967c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 16977c478bd9Sstevel@tonic-gate nfs4_error_init(ep, EINVAL); 16987c478bd9Sstevel@tonic-gate return; 16997c478bd9Sstevel@tonic-gate } 17007c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 17017c478bd9Sstevel@tonic-gate 17027c478bd9Sstevel@tonic-gate recov_state.rs_flags = 0; 17037c478bd9Sstevel@tonic-gate recov_state.rs_num_retry_despite_err = 0; 17042f172c55SRobert Thurlow 17057c478bd9Sstevel@tonic-gate recov_retry: 17062f172c55SRobert Thurlow if (mi->mi_vfs_referral_loop_cnt >= NFS4_REFERRAL_LOOP_MAX) { 17072f172c55SRobert Thurlow DTRACE_PROBE3(nfs4clnt__debug__referral__loop, mntinfo4 *, 17082f172c55SRobert Thurlow mi, servinfo4_t *, svp, char *, "nfs4getfh_otw"); 17092f172c55SRobert Thurlow nfs4_error_init(ep, EINVAL); 17102f172c55SRobert Thurlow return; 17112f172c55SRobert Thurlow } 17127c478bd9Sstevel@tonic-gate nfs4_error_zinit(ep); 17137c478bd9Sstevel@tonic-gate 17147c478bd9Sstevel@tonic-gate if (!recovery) { 17157c478bd9Sstevel@tonic-gate ep->error = nfs4_start_fop(mi, NULL, NULL, OH_MOUNT, 17167c478bd9Sstevel@tonic-gate &recov_state, NULL); 17177c478bd9Sstevel@tonic-gate 17187c478bd9Sstevel@tonic-gate /* 17197c478bd9Sstevel@tonic-gate * If recovery has been started and this request as 17207c478bd9Sstevel@tonic-gate * initiated by a mount, then we must wait for recovery 17217c478bd9Sstevel@tonic-gate * to finish before proceeding, otherwise, the error 17227c478bd9Sstevel@tonic-gate * cleanup would remove data structures needed by the 17237c478bd9Sstevel@tonic-gate * recovery thread. 17247c478bd9Sstevel@tonic-gate */ 17257c478bd9Sstevel@tonic-gate if (ep->error) { 17267c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 17277c478bd9Sstevel@tonic-gate if (mi->mi_flags & MI4_MOUNTING) { 17287c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_RECOV_FAIL; 17297c478bd9Sstevel@tonic-gate mi->mi_error = EIO; 17307c478bd9Sstevel@tonic-gate 17317c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE, 17327c478bd9Sstevel@tonic-gate "nfs4getfh_otw: waiting 4 recovery\n")); 17337c478bd9Sstevel@tonic-gate 17347c478bd9Sstevel@tonic-gate while (mi->mi_flags & MI4_RECOV_ACTIV) 17357c478bd9Sstevel@tonic-gate cv_wait(&mi->mi_failover_cv, 17367c478bd9Sstevel@tonic-gate &mi->mi_lock); 17377c478bd9Sstevel@tonic-gate } 17387c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 17397c478bd9Sstevel@tonic-gate return; 17407c478bd9Sstevel@tonic-gate } 17417c478bd9Sstevel@tonic-gate 17427c478bd9Sstevel@tonic-gate /* 17437c478bd9Sstevel@tonic-gate * If the client does not specify a specific flavor to use 17447c478bd9Sstevel@tonic-gate * and has not gotten a secinfo list from the server yet, 17457c478bd9Sstevel@tonic-gate * retrieve the secinfo list from the server and use a 17467c478bd9Sstevel@tonic-gate * flavor from the list to mount. 17477c478bd9Sstevel@tonic-gate * 17487c478bd9Sstevel@tonic-gate * If fail to get the secinfo list from the server, then 17497c478bd9Sstevel@tonic-gate * try the default flavor. 17507c478bd9Sstevel@tonic-gate */ 17517c478bd9Sstevel@tonic-gate if ((svp->sv_flags & SV4_TRYSECDEFAULT) && 17527c478bd9Sstevel@tonic-gate svp->sv_secinfo == NULL) { 17537c478bd9Sstevel@tonic-gate (void) nfs4_secinfo_path(mi, cr, FALSE); 17547c478bd9Sstevel@tonic-gate } 17557c478bd9Sstevel@tonic-gate } 17567c478bd9Sstevel@tonic-gate 17577c478bd9Sstevel@tonic-gate if (recovery) 17587c478bd9Sstevel@tonic-gate args.ctag = TAG_REMAP_MOUNT; 17597c478bd9Sstevel@tonic-gate else 17607c478bd9Sstevel@tonic-gate args.ctag = TAG_MOUNT; 17617c478bd9Sstevel@tonic-gate 17627c478bd9Sstevel@tonic-gate lookuparg.l4_getattrs = LKP4_ALL_ATTRIBUTES; 17637c478bd9Sstevel@tonic-gate lookuparg.argsp = &args; 17647c478bd9Sstevel@tonic-gate lookuparg.resp = &res; 17657c478bd9Sstevel@tonic-gate lookuparg.header_len = 2; /* Putrootfh, getfh */ 17667c478bd9Sstevel@tonic-gate lookuparg.trailer_len = 0; 17677c478bd9Sstevel@tonic-gate lookuparg.ga_bits = FATTR4_FSINFO_MASK; 17687c478bd9Sstevel@tonic-gate lookuparg.mi = mi; 17697c478bd9Sstevel@tonic-gate 17707c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 17717c478bd9Sstevel@tonic-gate ASSERT(svp->sv_path != NULL); 17727c478bd9Sstevel@tonic-gate llndx = nfs4lookup_setup(svp->sv_path, &lookuparg, 0); 17737c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 17747c478bd9Sstevel@tonic-gate 17757c478bd9Sstevel@tonic-gate argop = args.array; 17767c478bd9Sstevel@tonic-gate num_argops = args.array_len; 17777c478bd9Sstevel@tonic-gate 17787c478bd9Sstevel@tonic-gate /* choose public or root filehandle */ 17797c478bd9Sstevel@tonic-gate if (flags & NFS4_GETFH_PUBLIC) 17807c478bd9Sstevel@tonic-gate argop[0].argop = OP_PUTPUBFH; 17817c478bd9Sstevel@tonic-gate else 17827c478bd9Sstevel@tonic-gate argop[0].argop = OP_PUTROOTFH; 17837c478bd9Sstevel@tonic-gate 17847c478bd9Sstevel@tonic-gate /* get fh */ 17857c478bd9Sstevel@tonic-gate argop[1].argop = OP_GETFH; 17867c478bd9Sstevel@tonic-gate 17877c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_call_debug, (CE_NOTE, 17887c478bd9Sstevel@tonic-gate "nfs4getfh_otw: %s call, mi 0x%p", 17897c478bd9Sstevel@tonic-gate needrecov ? "recov" : "first", (void *)mi)); 17907c478bd9Sstevel@tonic-gate 17917c478bd9Sstevel@tonic-gate rfs4call(mi, &args, &res, cr, &doqueue, RFSCALL_SOFT, ep); 17927c478bd9Sstevel@tonic-gate 17937c478bd9Sstevel@tonic-gate needrecov = nfs4_needs_recovery(ep, FALSE, mi->mi_vfsp); 17947c478bd9Sstevel@tonic-gate 17957c478bd9Sstevel@tonic-gate if (needrecov) { 17967c478bd9Sstevel@tonic-gate bool_t abort; 17977c478bd9Sstevel@tonic-gate 17987c478bd9Sstevel@tonic-gate if (recovery) { 17997c478bd9Sstevel@tonic-gate nfs4args_lookup_free(argop, num_argops); 18007c478bd9Sstevel@tonic-gate kmem_free(argop, 18017c478bd9Sstevel@tonic-gate lookuparg.arglen * sizeof (nfs_argop4)); 18027c478bd9Sstevel@tonic-gate if (!ep->error) 18037c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, 18047c478bd9Sstevel@tonic-gate (caddr_t)&res); 18057c478bd9Sstevel@tonic-gate return; 18067c478bd9Sstevel@tonic-gate } 18077c478bd9Sstevel@tonic-gate 18087c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_recov_debug, 18097c478bd9Sstevel@tonic-gate (CE_NOTE, "nfs4getfh_otw: initiating recovery\n")); 18107c478bd9Sstevel@tonic-gate 18117c478bd9Sstevel@tonic-gate abort = nfs4_start_recovery(ep, mi, NULL, 18122f172c55SRobert Thurlow NULL, NULL, NULL, OP_GETFH, NULL, NULL, NULL); 18137c478bd9Sstevel@tonic-gate if (!ep->error) { 18147c478bd9Sstevel@tonic-gate ep->error = geterrno4(res.status); 18157c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 18167c478bd9Sstevel@tonic-gate } 18177c478bd9Sstevel@tonic-gate nfs4args_lookup_free(argop, num_argops); 18187c478bd9Sstevel@tonic-gate kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4)); 18197c478bd9Sstevel@tonic-gate nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state, needrecov); 18207c478bd9Sstevel@tonic-gate /* have another go? */ 18217c478bd9Sstevel@tonic-gate if (abort == FALSE) 18227c478bd9Sstevel@tonic-gate goto recov_retry; 18237c478bd9Sstevel@tonic-gate return; 18247c478bd9Sstevel@tonic-gate } 18257c478bd9Sstevel@tonic-gate 18267c478bd9Sstevel@tonic-gate /* 18277c478bd9Sstevel@tonic-gate * No recovery, but check if error is set. 18287c478bd9Sstevel@tonic-gate */ 18297c478bd9Sstevel@tonic-gate if (ep->error) { 18307c478bd9Sstevel@tonic-gate nfs4args_lookup_free(argop, num_argops); 18317c478bd9Sstevel@tonic-gate kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4)); 18327c478bd9Sstevel@tonic-gate if (!recovery) 18337c478bd9Sstevel@tonic-gate nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state, 18347c478bd9Sstevel@tonic-gate needrecov); 18357c478bd9Sstevel@tonic-gate return; 18367c478bd9Sstevel@tonic-gate } 18377c478bd9Sstevel@tonic-gate 18387c478bd9Sstevel@tonic-gate is_link_err: 18397c478bd9Sstevel@tonic-gate 18407c478bd9Sstevel@tonic-gate /* for non-recovery errors */ 18412f172c55SRobert Thurlow if (res.status && res.status != NFS4ERR_SYMLINK && 18422f172c55SRobert Thurlow res.status != NFS4ERR_MOVED) { 18437c478bd9Sstevel@tonic-gate if (!recovery) { 18447c478bd9Sstevel@tonic-gate nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state, 18457c478bd9Sstevel@tonic-gate needrecov); 18467c478bd9Sstevel@tonic-gate } 18477c478bd9Sstevel@tonic-gate nfs4args_lookup_free(argop, num_argops); 18487c478bd9Sstevel@tonic-gate kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4)); 18497c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 18507c478bd9Sstevel@tonic-gate return; 18517c478bd9Sstevel@tonic-gate } 18527c478bd9Sstevel@tonic-gate 18537c478bd9Sstevel@tonic-gate /* 18547c478bd9Sstevel@tonic-gate * If any intermediate component in the path is a symbolic link, 18557c478bd9Sstevel@tonic-gate * resolve the symlink, then try mount again using the new path. 18567c478bd9Sstevel@tonic-gate */ 18572f172c55SRobert Thurlow if (res.status == NFS4ERR_SYMLINK || res.status == NFS4ERR_MOVED) { 18587c478bd9Sstevel@tonic-gate int where; 18597c478bd9Sstevel@tonic-gate 18607c478bd9Sstevel@tonic-gate /* 18612f172c55SRobert Thurlow * Need to call nfs4_end_op before resolve_sympath to avoid 18622f172c55SRobert Thurlow * potential nfs4_start_op deadlock. 18632f172c55SRobert Thurlow */ 18642f172c55SRobert Thurlow if (!recovery) 18652f172c55SRobert Thurlow nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state, 18662f172c55SRobert Thurlow needrecov); 18672f172c55SRobert Thurlow 18682f172c55SRobert Thurlow /* 18697c478bd9Sstevel@tonic-gate * This must be from OP_LOOKUP failure. The (cfh) for this 18707c478bd9Sstevel@tonic-gate * OP_LOOKUP is a symlink node. Found out where the 18717c478bd9Sstevel@tonic-gate * OP_GETFH is for the (cfh) that is a symlink node. 18727c478bd9Sstevel@tonic-gate * 18737c478bd9Sstevel@tonic-gate * Example: 18747c478bd9Sstevel@tonic-gate * (mount) PUTROOTFH, GETFH, LOOKUP comp1, GETFH, GETATTR, 18757c478bd9Sstevel@tonic-gate * LOOKUP comp2, GETFH, GETATTR, LOOKUP comp3, GETFH, GETATTR 18767c478bd9Sstevel@tonic-gate * 18777c478bd9Sstevel@tonic-gate * LOOKUP comp3 fails with SYMLINK because comp2 is a symlink. 18787c478bd9Sstevel@tonic-gate * In this case, where = 7, nthcomp = 2. 18797c478bd9Sstevel@tonic-gate */ 18807c478bd9Sstevel@tonic-gate where = res.array_len - 2; 18817c478bd9Sstevel@tonic-gate ASSERT(where > 0); 18827c478bd9Sstevel@tonic-gate 18832f172c55SRobert Thurlow if (res.status == NFS4ERR_SYMLINK) { 18842f172c55SRobert Thurlow 18857c478bd9Sstevel@tonic-gate resop = &res.array[where - 1]; 18867c478bd9Sstevel@tonic-gate ASSERT(resop->resop == OP_GETFH); 18877c478bd9Sstevel@tonic-gate tmpfhp = &resop->nfs_resop4_u.opgetfh.object; 18887c478bd9Sstevel@tonic-gate nthcomp = res.array_len/3 - 1; 18892f172c55SRobert Thurlow ep->error = resolve_sympath(mi, svp, nthcomp, 18902f172c55SRobert Thurlow tmpfhp, cr, flags); 18917c478bd9Sstevel@tonic-gate 18922f172c55SRobert Thurlow } else if (res.status == NFS4ERR_MOVED) { 18937c478bd9Sstevel@tonic-gate 18942f172c55SRobert Thurlow resop = &res.array[where - 2]; 18952f172c55SRobert Thurlow ASSERT(resop->resop == OP_GETFH); 18962f172c55SRobert Thurlow tmpfhp = &resop->nfs_resop4_u.opgetfh.object; 18972f172c55SRobert Thurlow nthcomp = res.array_len/3 - 1; 18982f172c55SRobert Thurlow ep->error = resolve_referral(mi, svp, cr, nthcomp, 18992f172c55SRobert Thurlow tmpfhp); 19002f172c55SRobert Thurlow } 19017c478bd9Sstevel@tonic-gate 19027c478bd9Sstevel@tonic-gate nfs4args_lookup_free(argop, num_argops); 19037c478bd9Sstevel@tonic-gate kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4)); 19047c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 19057c478bd9Sstevel@tonic-gate 19067c478bd9Sstevel@tonic-gate if (ep->error) 19077c478bd9Sstevel@tonic-gate return; 19087c478bd9Sstevel@tonic-gate 19097c478bd9Sstevel@tonic-gate goto recov_retry; 19107c478bd9Sstevel@tonic-gate } 19117c478bd9Sstevel@tonic-gate 19127c478bd9Sstevel@tonic-gate /* getfh */ 19137c478bd9Sstevel@tonic-gate resop = &res.array[res.array_len - 2]; 19147c478bd9Sstevel@tonic-gate ASSERT(resop->resop == OP_GETFH); 19157c478bd9Sstevel@tonic-gate resfhp = &resop->nfs_resop4_u.opgetfh.object; 19167c478bd9Sstevel@tonic-gate 19177c478bd9Sstevel@tonic-gate /* getattr fsinfo res */ 19187c478bd9Sstevel@tonic-gate resop++; 19197c478bd9Sstevel@tonic-gate garp = &resop->nfs_resop4_u.opgetattr.ga_res; 19207c478bd9Sstevel@tonic-gate 19217c478bd9Sstevel@tonic-gate *vtp = garp->n4g_va.va_type; 19227c478bd9Sstevel@tonic-gate 19237c478bd9Sstevel@tonic-gate mi->mi_fh_expire_type = garp->n4g_ext_res->n4g_fet; 19247c478bd9Sstevel@tonic-gate 19257c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 19267c478bd9Sstevel@tonic-gate if (garp->n4g_ext_res->n4g_pc4.pc4_link_support) 19277c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_LINK; 19287c478bd9Sstevel@tonic-gate if (garp->n4g_ext_res->n4g_pc4.pc4_symlink_support) 19297c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_SYMLINK; 19307c478bd9Sstevel@tonic-gate if (garp->n4g_ext_res->n4g_suppattrs & FATTR4_ACL_MASK) 19317c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_ACL; 19327c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 19337c478bd9Sstevel@tonic-gate 19347c478bd9Sstevel@tonic-gate if (garp->n4g_ext_res->n4g_maxread == 0) 19357c478bd9Sstevel@tonic-gate mi->mi_tsize = 19367c478bd9Sstevel@tonic-gate MIN(MAXBSIZE, mi->mi_tsize); 19377c478bd9Sstevel@tonic-gate else 19387c478bd9Sstevel@tonic-gate mi->mi_tsize = 19397c478bd9Sstevel@tonic-gate MIN(garp->n4g_ext_res->n4g_maxread, 19407c478bd9Sstevel@tonic-gate mi->mi_tsize); 19417c478bd9Sstevel@tonic-gate 19427c478bd9Sstevel@tonic-gate if (garp->n4g_ext_res->n4g_maxwrite == 0) 19437c478bd9Sstevel@tonic-gate mi->mi_stsize = 19447c478bd9Sstevel@tonic-gate MIN(MAXBSIZE, mi->mi_stsize); 19457c478bd9Sstevel@tonic-gate else 19467c478bd9Sstevel@tonic-gate mi->mi_stsize = 19477c478bd9Sstevel@tonic-gate MIN(garp->n4g_ext_res->n4g_maxwrite, 19487c478bd9Sstevel@tonic-gate mi->mi_stsize); 19497c478bd9Sstevel@tonic-gate 19507c478bd9Sstevel@tonic-gate if (garp->n4g_ext_res->n4g_maxfilesize != 0) 19517c478bd9Sstevel@tonic-gate mi->mi_maxfilesize = 19527c478bd9Sstevel@tonic-gate MIN(garp->n4g_ext_res->n4g_maxfilesize, 19537c478bd9Sstevel@tonic-gate mi->mi_maxfilesize); 19547c478bd9Sstevel@tonic-gate 19557c478bd9Sstevel@tonic-gate /* 19567c478bd9Sstevel@tonic-gate * If the final component is a a symbolic link, resolve the symlink, 19577c478bd9Sstevel@tonic-gate * then try mount again using the new path. 19587c478bd9Sstevel@tonic-gate * 19597c478bd9Sstevel@tonic-gate * Assume no symbolic link for root filesysm "/". 19607c478bd9Sstevel@tonic-gate */ 19617c478bd9Sstevel@tonic-gate if (*vtp == VLNK) { 19627c478bd9Sstevel@tonic-gate /* 19637c478bd9Sstevel@tonic-gate * nthcomp is the total result length minus 19647c478bd9Sstevel@tonic-gate * the 1st 2 OPs (PUTROOTFH, GETFH), 19657c478bd9Sstevel@tonic-gate * then divided by 3 (LOOKUP,GETFH,GETATTR) 19667c478bd9Sstevel@tonic-gate * 19677c478bd9Sstevel@tonic-gate * e.g. PUTROOTFH GETFH LOOKUP 1st-comp GETFH GETATTR 19687c478bd9Sstevel@tonic-gate * LOOKUP 2nd-comp GETFH GETATTR 19697c478bd9Sstevel@tonic-gate * 19707c478bd9Sstevel@tonic-gate * (8 - 2)/3 = 2 19717c478bd9Sstevel@tonic-gate */ 19727c478bd9Sstevel@tonic-gate nthcomp = (res.array_len - 2)/3; 19737c478bd9Sstevel@tonic-gate 19747c478bd9Sstevel@tonic-gate /* 19757c478bd9Sstevel@tonic-gate * Need to call nfs4_end_op before resolve_sympath to avoid 19767c478bd9Sstevel@tonic-gate * potential nfs4_start_op deadlock. See RFE 4777612. 19777c478bd9Sstevel@tonic-gate */ 19787c478bd9Sstevel@tonic-gate if (!recovery) 19797c478bd9Sstevel@tonic-gate nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state, 19807c478bd9Sstevel@tonic-gate needrecov); 19817c478bd9Sstevel@tonic-gate 19827c478bd9Sstevel@tonic-gate ep->error = resolve_sympath(mi, svp, nthcomp, resfhp, cr, 19837c478bd9Sstevel@tonic-gate flags); 19847c478bd9Sstevel@tonic-gate 19857c478bd9Sstevel@tonic-gate nfs4args_lookup_free(argop, num_argops); 19867c478bd9Sstevel@tonic-gate kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4)); 19877c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 19887c478bd9Sstevel@tonic-gate 19897c478bd9Sstevel@tonic-gate if (ep->error) 19907c478bd9Sstevel@tonic-gate return; 19917c478bd9Sstevel@tonic-gate 19927c478bd9Sstevel@tonic-gate goto recov_retry; 19937c478bd9Sstevel@tonic-gate } 19947c478bd9Sstevel@tonic-gate 19957c478bd9Sstevel@tonic-gate /* 19967c478bd9Sstevel@tonic-gate * We need to figure out where in the compound the getfh 19977c478bd9Sstevel@tonic-gate * for the parent directory is. If the object to be mounted is 19987c478bd9Sstevel@tonic-gate * the root, then there is no lookup at all: 19997c478bd9Sstevel@tonic-gate * PUTROOTFH, GETFH. 20007c478bd9Sstevel@tonic-gate * If the object to be mounted is in the root, then the compound is: 20017c478bd9Sstevel@tonic-gate * PUTROOTFH, GETFH, LOOKUP, GETFH, GETATTR. 20027c478bd9Sstevel@tonic-gate * In either of these cases, the index of the GETFH is 1. 20037c478bd9Sstevel@tonic-gate * If it is not at the root, then it's something like: 20047c478bd9Sstevel@tonic-gate * PUTROOTFH, GETFH, LOOKUP, GETFH, GETATTR, 20057c478bd9Sstevel@tonic-gate * LOOKUP, GETFH, GETATTR 20067c478bd9Sstevel@tonic-gate * In this case, the index is llndx (last lookup index) - 2. 20077c478bd9Sstevel@tonic-gate */ 20087c478bd9Sstevel@tonic-gate if (llndx == -1 || llndx == 2) 20097c478bd9Sstevel@tonic-gate resop = &res.array[1]; 20107c478bd9Sstevel@tonic-gate else { 20117c478bd9Sstevel@tonic-gate ASSERT(llndx > 2); 20127c478bd9Sstevel@tonic-gate resop = &res.array[llndx-2]; 20137c478bd9Sstevel@tonic-gate } 20147c478bd9Sstevel@tonic-gate 20157c478bd9Sstevel@tonic-gate ASSERT(resop->resop == OP_GETFH); 20167c478bd9Sstevel@tonic-gate tmpfhp = &resop->nfs_resop4_u.opgetfh.object; 20177c478bd9Sstevel@tonic-gate 20187c478bd9Sstevel@tonic-gate /* save the filehandles for the replica */ 20197c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 20207c478bd9Sstevel@tonic-gate ASSERT(tmpfhp->nfs_fh4_len <= NFS4_FHSIZE); 20217c478bd9Sstevel@tonic-gate svp->sv_pfhandle.fh_len = tmpfhp->nfs_fh4_len; 20227c478bd9Sstevel@tonic-gate bcopy(tmpfhp->nfs_fh4_val, svp->sv_pfhandle.fh_buf, 20237c478bd9Sstevel@tonic-gate tmpfhp->nfs_fh4_len); 20247c478bd9Sstevel@tonic-gate ASSERT(resfhp->nfs_fh4_len <= NFS4_FHSIZE); 20257c478bd9Sstevel@tonic-gate svp->sv_fhandle.fh_len = resfhp->nfs_fh4_len; 20267c478bd9Sstevel@tonic-gate bcopy(resfhp->nfs_fh4_val, svp->sv_fhandle.fh_buf, resfhp->nfs_fh4_len); 20277c478bd9Sstevel@tonic-gate 20287c478bd9Sstevel@tonic-gate /* initialize fsid and supp_attrs for server fs */ 20297c478bd9Sstevel@tonic-gate svp->sv_fsid = garp->n4g_fsid; 20307c478bd9Sstevel@tonic-gate svp->sv_supp_attrs = 20317c478bd9Sstevel@tonic-gate garp->n4g_ext_res->n4g_suppattrs | FATTR4_MANDATTR_MASK; 20327c478bd9Sstevel@tonic-gate 20337c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 20347c478bd9Sstevel@tonic-gate nfs4args_lookup_free(argop, num_argops); 20357c478bd9Sstevel@tonic-gate kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4)); 20367c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 20377c478bd9Sstevel@tonic-gate if (!recovery) 20387c478bd9Sstevel@tonic-gate nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state, needrecov); 20397c478bd9Sstevel@tonic-gate } 20407c478bd9Sstevel@tonic-gate 20412f172c55SRobert Thurlow /* 20422f172c55SRobert Thurlow * Save a copy of Servinfo4_t structure. 20432f172c55SRobert Thurlow * We might need when there is a failure in getting file handle 20442f172c55SRobert Thurlow * in case of a referral to replace servinfo4 struct and try again. 20452f172c55SRobert Thurlow */ 20462f172c55SRobert Thurlow static struct servinfo4 * 20472f172c55SRobert Thurlow copy_svp(servinfo4_t *nsvp) 20482f172c55SRobert Thurlow { 20492f172c55SRobert Thurlow servinfo4_t *svp = NULL; 20502f172c55SRobert Thurlow struct knetconfig *sknconf, *tknconf; 20512f172c55SRobert Thurlow struct netbuf *saddr, *taddr; 20522f172c55SRobert Thurlow 20532f172c55SRobert Thurlow svp = kmem_zalloc(sizeof (*svp), KM_SLEEP); 20542f172c55SRobert Thurlow nfs_rw_init(&svp->sv_lock, NULL, RW_DEFAULT, NULL); 20552f172c55SRobert Thurlow svp->sv_flags = nsvp->sv_flags; 20562f172c55SRobert Thurlow svp->sv_fsid = nsvp->sv_fsid; 20572f172c55SRobert Thurlow svp->sv_hostnamelen = nsvp->sv_hostnamelen; 20582f172c55SRobert Thurlow svp->sv_pathlen = nsvp->sv_pathlen; 20592f172c55SRobert Thurlow svp->sv_supp_attrs = nsvp->sv_supp_attrs; 20602f172c55SRobert Thurlow 20612f172c55SRobert Thurlow svp->sv_path = kmem_alloc(svp->sv_pathlen, KM_SLEEP); 20622f172c55SRobert Thurlow svp->sv_hostname = kmem_alloc(svp->sv_hostnamelen, KM_SLEEP); 20632f172c55SRobert Thurlow bcopy(nsvp->sv_hostname, svp->sv_hostname, svp->sv_hostnamelen); 20642f172c55SRobert Thurlow bcopy(nsvp->sv_path, svp->sv_path, svp->sv_pathlen); 20652f172c55SRobert Thurlow 20662f172c55SRobert Thurlow saddr = &nsvp->sv_addr; 20672f172c55SRobert Thurlow taddr = &svp->sv_addr; 20682f172c55SRobert Thurlow taddr->maxlen = saddr->maxlen; 20692f172c55SRobert Thurlow taddr->len = saddr->len; 20702f172c55SRobert Thurlow if (saddr->len > 0) { 20712f172c55SRobert Thurlow taddr->buf = kmem_zalloc(saddr->maxlen, KM_SLEEP); 20722f172c55SRobert Thurlow bcopy(saddr->buf, taddr->buf, saddr->len); 20732f172c55SRobert Thurlow } 20742f172c55SRobert Thurlow 20752f172c55SRobert Thurlow svp->sv_knconf = kmem_zalloc(sizeof (struct knetconfig), KM_SLEEP); 20762f172c55SRobert Thurlow sknconf = nsvp->sv_knconf; 20772f172c55SRobert Thurlow tknconf = svp->sv_knconf; 20782f172c55SRobert Thurlow tknconf->knc_semantics = sknconf->knc_semantics; 20792f172c55SRobert Thurlow tknconf->knc_rdev = sknconf->knc_rdev; 20802f172c55SRobert Thurlow if (sknconf->knc_proto != NULL) { 20812f172c55SRobert Thurlow tknconf->knc_proto = kmem_zalloc(KNC_STRSIZE, KM_SLEEP); 20822f172c55SRobert Thurlow bcopy(sknconf->knc_proto, (char *)tknconf->knc_proto, 20832f172c55SRobert Thurlow KNC_STRSIZE); 20842f172c55SRobert Thurlow } 20852f172c55SRobert Thurlow if (sknconf->knc_protofmly != NULL) { 20862f172c55SRobert Thurlow tknconf->knc_protofmly = kmem_zalloc(KNC_STRSIZE, KM_SLEEP); 20872f172c55SRobert Thurlow bcopy(sknconf->knc_protofmly, (char *)tknconf->knc_protofmly, 20882f172c55SRobert Thurlow KNC_STRSIZE); 20892f172c55SRobert Thurlow } 20902f172c55SRobert Thurlow 20912f172c55SRobert Thurlow if (nsvp->sv_origknconf != NULL) { 20922f172c55SRobert Thurlow svp->sv_origknconf = kmem_zalloc(sizeof (struct knetconfig), 20932f172c55SRobert Thurlow KM_SLEEP); 20942f172c55SRobert Thurlow sknconf = nsvp->sv_origknconf; 20952f172c55SRobert Thurlow tknconf = svp->sv_origknconf; 20962f172c55SRobert Thurlow tknconf->knc_semantics = sknconf->knc_semantics; 20972f172c55SRobert Thurlow tknconf->knc_rdev = sknconf->knc_rdev; 20982f172c55SRobert Thurlow if (sknconf->knc_proto != NULL) { 20992f172c55SRobert Thurlow tknconf->knc_proto = kmem_zalloc(KNC_STRSIZE, KM_SLEEP); 21002f172c55SRobert Thurlow bcopy(sknconf->knc_proto, (char *)tknconf->knc_proto, 21012f172c55SRobert Thurlow KNC_STRSIZE); 21022f172c55SRobert Thurlow } 21032f172c55SRobert Thurlow if (sknconf->knc_protofmly != NULL) { 21042f172c55SRobert Thurlow tknconf->knc_protofmly = kmem_zalloc(KNC_STRSIZE, 21052f172c55SRobert Thurlow KM_SLEEP); 21062f172c55SRobert Thurlow bcopy(sknconf->knc_protofmly, 21072f172c55SRobert Thurlow (char *)tknconf->knc_protofmly, KNC_STRSIZE); 21082f172c55SRobert Thurlow } 21092f172c55SRobert Thurlow } 21102f172c55SRobert Thurlow 21112f172c55SRobert Thurlow svp->sv_secdata = copy_sec_data(nsvp->sv_secdata); 21122f172c55SRobert Thurlow svp->sv_dhsec = copy_sec_data(svp->sv_dhsec); 21132f172c55SRobert Thurlow /* 21142f172c55SRobert Thurlow * Rest of the security information is not copied as they are built 21152f172c55SRobert Thurlow * with the information available from secdata and dhsec. 21162f172c55SRobert Thurlow */ 21172f172c55SRobert Thurlow svp->sv_next = NULL; 21182f172c55SRobert Thurlow 21192f172c55SRobert Thurlow return (svp); 21202f172c55SRobert Thurlow } 21212f172c55SRobert Thurlow 21222f172c55SRobert Thurlow servinfo4_t * 21232f172c55SRobert Thurlow restore_svp(mntinfo4_t *mi, servinfo4_t *svp, servinfo4_t *origsvp) 21242f172c55SRobert Thurlow { 21252f172c55SRobert Thurlow servinfo4_t *srvnext, *tmpsrv; 21262f172c55SRobert Thurlow 21272f172c55SRobert Thurlow if (strcmp(svp->sv_hostname, origsvp->sv_hostname) != 0) { 21282f172c55SRobert Thurlow /* 21292f172c55SRobert Thurlow * Since the hostname changed, we must be dealing 21302f172c55SRobert Thurlow * with a referral, and the lookup failed. We will 21312f172c55SRobert Thurlow * restore the whole servinfo4_t to what it was before. 21322f172c55SRobert Thurlow */ 21332f172c55SRobert Thurlow srvnext = svp->sv_next; 21342f172c55SRobert Thurlow svp->sv_next = NULL; 21352f172c55SRobert Thurlow tmpsrv = copy_svp(origsvp); 21362f172c55SRobert Thurlow sv4_free(svp); 21372f172c55SRobert Thurlow svp = tmpsrv; 21382f172c55SRobert Thurlow svp->sv_next = srvnext; 21392f172c55SRobert Thurlow mutex_enter(&mi->mi_lock); 21402f172c55SRobert Thurlow mi->mi_servers = svp; 21412f172c55SRobert Thurlow mi->mi_curr_serv = svp; 21422f172c55SRobert Thurlow mutex_exit(&mi->mi_lock); 21432f172c55SRobert Thurlow 21442f172c55SRobert Thurlow } else if (origsvp->sv_pathlen != svp->sv_pathlen) { 21452f172c55SRobert Thurlow 21462f172c55SRobert Thurlow /* 21472f172c55SRobert Thurlow * For symlink case: restore original path because 21482f172c55SRobert Thurlow * it might have contained symlinks that were 21492f172c55SRobert Thurlow * expanded by nfsgetfh_otw before the failure occurred. 21502f172c55SRobert Thurlow */ 21515301ec54SRobert Thurlow (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 21522f172c55SRobert Thurlow kmem_free(svp->sv_path, svp->sv_pathlen); 21532f172c55SRobert Thurlow svp->sv_path = 21542f172c55SRobert Thurlow kmem_alloc(origsvp->sv_pathlen, KM_SLEEP); 21552f172c55SRobert Thurlow svp->sv_pathlen = origsvp->sv_pathlen; 21562f172c55SRobert Thurlow bcopy(origsvp->sv_path, svp->sv_path, 21572f172c55SRobert Thurlow origsvp->sv_pathlen); 21582f172c55SRobert Thurlow nfs_rw_exit(&svp->sv_lock); 21592f172c55SRobert Thurlow } 21602f172c55SRobert Thurlow return (svp); 21612f172c55SRobert Thurlow } 21622f172c55SRobert Thurlow 21637c478bd9Sstevel@tonic-gate static ushort_t nfs4_max_threads = 8; /* max number of active async threads */ 2164c242f9a0Schunli zhang - Sun Microsystems - Irvine United States uint_t nfs4_bsize = 32 * 1024; /* client `block' size */ 21657c478bd9Sstevel@tonic-gate static uint_t nfs4_async_clusters = 1; /* # of reqs from each async queue */ 21667c478bd9Sstevel@tonic-gate static uint_t nfs4_cots_timeo = NFS_COTS_TIMEO; 21677c478bd9Sstevel@tonic-gate 21687c478bd9Sstevel@tonic-gate /* 21697c478bd9Sstevel@tonic-gate * Remap the root filehandle for the given filesystem. 21707c478bd9Sstevel@tonic-gate * 21717c478bd9Sstevel@tonic-gate * results returned via the nfs4_error_t parameter. 21727c478bd9Sstevel@tonic-gate */ 21737c478bd9Sstevel@tonic-gate void 21747c478bd9Sstevel@tonic-gate nfs4_remap_root(mntinfo4_t *mi, nfs4_error_t *ep, int flags) 21757c478bd9Sstevel@tonic-gate { 21762f172c55SRobert Thurlow struct servinfo4 *svp, *origsvp; 21777c478bd9Sstevel@tonic-gate vtype_t vtype; 21787c478bd9Sstevel@tonic-gate nfs_fh4 rootfh; 21797c478bd9Sstevel@tonic-gate int getfh_flags; 21802f172c55SRobert Thurlow int num_retry; 21817c478bd9Sstevel@tonic-gate 21827c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 21838c9e5ad2Saalok 21848c9e5ad2Saalok remap_retry: 21857c478bd9Sstevel@tonic-gate svp = mi->mi_curr_serv; 21867c478bd9Sstevel@tonic-gate getfh_flags = 21877c478bd9Sstevel@tonic-gate (flags & NFS4_REMAP_NEEDSOP) ? NFS4_GETFH_NEEDSOP : 0; 21887c478bd9Sstevel@tonic-gate getfh_flags |= 21897c478bd9Sstevel@tonic-gate (mi->mi_flags & MI4_PUBLIC) ? NFS4_GETFH_PUBLIC : 0; 21907c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 21917c478bd9Sstevel@tonic-gate 21927c478bd9Sstevel@tonic-gate /* 21937c478bd9Sstevel@tonic-gate * Just in case server path being mounted contains 21947c478bd9Sstevel@tonic-gate * symlinks and fails w/STALE, save the initial sv_path 21957c478bd9Sstevel@tonic-gate * so we can redrive the initial mount compound with the 21967c478bd9Sstevel@tonic-gate * initial sv_path -- not a symlink-expanded version. 21977c478bd9Sstevel@tonic-gate * 21987c478bd9Sstevel@tonic-gate * This could only happen if a symlink was expanded 21997c478bd9Sstevel@tonic-gate * and the expanded mount compound failed stale. Because 22007c478bd9Sstevel@tonic-gate * it could be the case that the symlink was removed at 22017c478bd9Sstevel@tonic-gate * the server (and replaced with another symlink/dir, 22027c478bd9Sstevel@tonic-gate * we need to use the initial sv_path when attempting 22037c478bd9Sstevel@tonic-gate * to re-lookup everything and recover. 22047c478bd9Sstevel@tonic-gate */ 22057c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 22062f172c55SRobert Thurlow origsvp = copy_svp(svp); 22077c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 22087c478bd9Sstevel@tonic-gate 22097c478bd9Sstevel@tonic-gate num_retry = nfs4_max_mount_retry; 22107c478bd9Sstevel@tonic-gate 22117c478bd9Sstevel@tonic-gate do { 22127c478bd9Sstevel@tonic-gate /* 22137c478bd9Sstevel@tonic-gate * Get the root fh from the server. Retry nfs4_max_mount_retry 22147c478bd9Sstevel@tonic-gate * (2) times if it fails with STALE since the recovery 22157c478bd9Sstevel@tonic-gate * infrastructure doesn't do STALE recovery for components 22167c478bd9Sstevel@tonic-gate * of the server path to the object being mounted. 22177c478bd9Sstevel@tonic-gate */ 22187c478bd9Sstevel@tonic-gate nfs4getfh_otw(mi, svp, &vtype, getfh_flags, CRED(), ep); 22197c478bd9Sstevel@tonic-gate 22207c478bd9Sstevel@tonic-gate if (ep->error == 0 && ep->stat == NFS4_OK) 22217c478bd9Sstevel@tonic-gate break; 22227c478bd9Sstevel@tonic-gate 22237c478bd9Sstevel@tonic-gate /* 22247c478bd9Sstevel@tonic-gate * For some reason, the mount compound failed. Before 22252f172c55SRobert Thurlow * retrying, we need to restore original conditions. 22267c478bd9Sstevel@tonic-gate */ 22272f172c55SRobert Thurlow svp = restore_svp(mi, svp, origsvp); 22287c478bd9Sstevel@tonic-gate 22297c478bd9Sstevel@tonic-gate } while (num_retry-- > 0); 22307c478bd9Sstevel@tonic-gate 22312f172c55SRobert Thurlow sv4_free(origsvp); 22327c478bd9Sstevel@tonic-gate 22337c478bd9Sstevel@tonic-gate if (ep->error != 0 || ep->stat != 0) { 22347c478bd9Sstevel@tonic-gate return; 22357c478bd9Sstevel@tonic-gate } 22367c478bd9Sstevel@tonic-gate 22377c478bd9Sstevel@tonic-gate if (vtype != VNON && vtype != mi->mi_type) { 22387c478bd9Sstevel@tonic-gate /* shouldn't happen */ 22397c478bd9Sstevel@tonic-gate zcmn_err(mi->mi_zone->zone_id, CE_WARN, 22407c478bd9Sstevel@tonic-gate "nfs4_remap_root: server root vnode type (%d) doesn't " 22417c478bd9Sstevel@tonic-gate "match mount info (%d)", vtype, mi->mi_type); 22427c478bd9Sstevel@tonic-gate } 22437c478bd9Sstevel@tonic-gate 22447c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 22457c478bd9Sstevel@tonic-gate rootfh.nfs_fh4_val = svp->sv_fhandle.fh_buf; 22467c478bd9Sstevel@tonic-gate rootfh.nfs_fh4_len = svp->sv_fhandle.fh_len; 22477c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 22487c478bd9Sstevel@tonic-gate sfh4_update(mi->mi_rootfh, &rootfh); 22497c478bd9Sstevel@tonic-gate 22507c478bd9Sstevel@tonic-gate /* 22518c9e5ad2Saalok * It's possible that recovery took place on the filesystem 22528c9e5ad2Saalok * and the server has been updated between the time we did 22538c9e5ad2Saalok * the nfs4getfh_otw and now. Re-drive the otw operation 22548c9e5ad2Saalok * to make sure we have a good fh. 22557c478bd9Sstevel@tonic-gate */ 22567c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 22578c9e5ad2Saalok if (mi->mi_curr_serv != svp) 22588c9e5ad2Saalok goto remap_retry; 22598c9e5ad2Saalok 22607c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 22617c478bd9Sstevel@tonic-gate } 22627c478bd9Sstevel@tonic-gate 22637c478bd9Sstevel@tonic-gate static int 22647c478bd9Sstevel@tonic-gate nfs4rootvp(vnode_t **rtvpp, vfs_t *vfsp, struct servinfo4 *svp_head, 22657c478bd9Sstevel@tonic-gate int flags, cred_t *cr, zone_t *zone) 22667c478bd9Sstevel@tonic-gate { 22677c478bd9Sstevel@tonic-gate vnode_t *rtvp = NULL; 22687c478bd9Sstevel@tonic-gate mntinfo4_t *mi; 22697c478bd9Sstevel@tonic-gate dev_t nfs_dev; 22707c478bd9Sstevel@tonic-gate int error = 0; 22717c478bd9Sstevel@tonic-gate rnode4_t *rp; 22722f172c55SRobert Thurlow int i, len; 22737c478bd9Sstevel@tonic-gate struct vattr va; 22747c478bd9Sstevel@tonic-gate vtype_t vtype = VNON; 22757c478bd9Sstevel@tonic-gate vtype_t tmp_vtype = VNON; 22767c478bd9Sstevel@tonic-gate struct servinfo4 *firstsvp = NULL, *svp = svp_head; 22777c478bd9Sstevel@tonic-gate nfs4_oo_hash_bucket_t *bucketp; 22787c478bd9Sstevel@tonic-gate nfs_fh4 fh; 22797c478bd9Sstevel@tonic-gate char *droptext = ""; 22807c478bd9Sstevel@tonic-gate struct nfs_stats *nfsstatsp; 22817c478bd9Sstevel@tonic-gate nfs4_fname_t *mfname; 22827c478bd9Sstevel@tonic-gate nfs4_error_t e; 22832f172c55SRobert Thurlow int num_retry, removed; 22847c478bd9Sstevel@tonic-gate cred_t *lcr = NULL, *tcr = cr; 22852f172c55SRobert Thurlow struct servinfo4 *origsvp; 22862f172c55SRobert Thurlow char *resource; 22877c478bd9Sstevel@tonic-gate 2288108322fbScarlsonj nfsstatsp = zone_getspecific(nfsstat_zone_key, nfs_zone()); 22897c478bd9Sstevel@tonic-gate ASSERT(nfsstatsp != NULL); 22907c478bd9Sstevel@tonic-gate 2291108322fbScarlsonj ASSERT(nfs_zone() == zone); 22927c478bd9Sstevel@tonic-gate ASSERT(crgetref(cr)); 22937c478bd9Sstevel@tonic-gate 22947c478bd9Sstevel@tonic-gate /* 22957c478bd9Sstevel@tonic-gate * Create a mount record and link it to the vfs struct. 22967c478bd9Sstevel@tonic-gate */ 22977c478bd9Sstevel@tonic-gate mi = kmem_zalloc(sizeof (*mi), KM_SLEEP); 22987c478bd9Sstevel@tonic-gate mutex_init(&mi->mi_lock, NULL, MUTEX_DEFAULT, NULL); 22997c478bd9Sstevel@tonic-gate nfs_rw_init(&mi->mi_recovlock, NULL, RW_DEFAULT, NULL); 23007c478bd9Sstevel@tonic-gate nfs_rw_init(&mi->mi_rename_lock, NULL, RW_DEFAULT, NULL); 23017c478bd9Sstevel@tonic-gate nfs_rw_init(&mi->mi_fh_lock, NULL, RW_DEFAULT, NULL); 23027c478bd9Sstevel@tonic-gate 23037c478bd9Sstevel@tonic-gate if (!(flags & NFSMNT_SOFT)) 23047c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_HARD; 23057c478bd9Sstevel@tonic-gate if ((flags & NFSMNT_NOPRINT)) 23067c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_NOPRINT; 23077c478bd9Sstevel@tonic-gate if (flags & NFSMNT_INT) 23087c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_INT; 23097c478bd9Sstevel@tonic-gate if (flags & NFSMNT_PUBLIC) 23107c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_PUBLIC; 2311b9238976Sth199096 if (flags & NFSMNT_MIRRORMOUNT) 2312b9238976Sth199096 mi->mi_flags |= MI4_MIRRORMOUNT; 23132f172c55SRobert Thurlow if (flags & NFSMNT_REFERRAL) 23142f172c55SRobert Thurlow mi->mi_flags |= MI4_REFERRAL; 23157c478bd9Sstevel@tonic-gate mi->mi_retrans = NFS_RETRIES; 23167c478bd9Sstevel@tonic-gate if (svp->sv_knconf->knc_semantics == NC_TPI_COTS_ORD || 23177c478bd9Sstevel@tonic-gate svp->sv_knconf->knc_semantics == NC_TPI_COTS) 23187c478bd9Sstevel@tonic-gate mi->mi_timeo = nfs4_cots_timeo; 23197c478bd9Sstevel@tonic-gate else 23207c478bd9Sstevel@tonic-gate mi->mi_timeo = NFS_TIMEO; 23217c478bd9Sstevel@tonic-gate mi->mi_prog = NFS_PROGRAM; 23227c478bd9Sstevel@tonic-gate mi->mi_vers = NFS_V4; 23237c478bd9Sstevel@tonic-gate mi->mi_rfsnames = rfsnames_v4; 23247c478bd9Sstevel@tonic-gate mi->mi_reqs = nfsstatsp->nfs_stats_v4.rfsreqcnt_ptr; 23257c478bd9Sstevel@tonic-gate cv_init(&mi->mi_failover_cv, NULL, CV_DEFAULT, NULL); 23267c478bd9Sstevel@tonic-gate mi->mi_servers = svp; 23277c478bd9Sstevel@tonic-gate mi->mi_curr_serv = svp; 23287c478bd9Sstevel@tonic-gate mi->mi_acregmin = SEC2HR(ACREGMIN); 23297c478bd9Sstevel@tonic-gate mi->mi_acregmax = SEC2HR(ACREGMAX); 23307c478bd9Sstevel@tonic-gate mi->mi_acdirmin = SEC2HR(ACDIRMIN); 23317c478bd9Sstevel@tonic-gate mi->mi_acdirmax = SEC2HR(ACDIRMAX); 23327c478bd9Sstevel@tonic-gate mi->mi_fh_expire_type = FH4_PERSISTENT; 23337c478bd9Sstevel@tonic-gate mi->mi_clientid_next = NULL; 23347c478bd9Sstevel@tonic-gate mi->mi_clientid_prev = NULL; 23353b895386SPavel Filipensky mi->mi_srv = NULL; 23367c478bd9Sstevel@tonic-gate mi->mi_grace_wait = 0; 23377c478bd9Sstevel@tonic-gate mi->mi_error = 0; 23387c478bd9Sstevel@tonic-gate mi->mi_srvsettime = 0; 23393b895386SPavel Filipensky mi->mi_srvset_cnt = 0; 23407c478bd9Sstevel@tonic-gate 234150a83466Sjwahlig mi->mi_count = 1; 234250a83466Sjwahlig 23437c478bd9Sstevel@tonic-gate mi->mi_tsize = nfs4_tsize(svp->sv_knconf); 23447c478bd9Sstevel@tonic-gate mi->mi_stsize = mi->mi_tsize; 23457c478bd9Sstevel@tonic-gate 23467c478bd9Sstevel@tonic-gate if (flags & NFSMNT_DIRECTIO) 23477c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_DIRECTIO; 23487c478bd9Sstevel@tonic-gate 23497c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_MOUNTING; 23507c478bd9Sstevel@tonic-gate 23518a790dc6SMarcel Telka mutex_init(&mi->mi_rnodes_lock, NULL, MUTEX_DEFAULT, NULL); 23528a790dc6SMarcel Telka list_create(&mi->mi_rnodes, sizeof (rnode4_t), 23538a790dc6SMarcel Telka offsetof(rnode4_t, r_mi_link)); 23548a790dc6SMarcel Telka 23557c478bd9Sstevel@tonic-gate /* 23567c478bd9Sstevel@tonic-gate * Make a vfs struct for nfs. We do this here instead of below 23577c478bd9Sstevel@tonic-gate * because rtvp needs a vfs before we can do a getattr on it. 23587c478bd9Sstevel@tonic-gate * 23597c478bd9Sstevel@tonic-gate * Assign a unique device id to the mount 23607c478bd9Sstevel@tonic-gate */ 23617c478bd9Sstevel@tonic-gate mutex_enter(&nfs_minor_lock); 23627c478bd9Sstevel@tonic-gate do { 23637c478bd9Sstevel@tonic-gate nfs_minor = (nfs_minor + 1) & MAXMIN32; 23647c478bd9Sstevel@tonic-gate nfs_dev = makedevice(nfs_major, nfs_minor); 23657c478bd9Sstevel@tonic-gate } while (vfs_devismounted(nfs_dev)); 23667c478bd9Sstevel@tonic-gate mutex_exit(&nfs_minor_lock); 23677c478bd9Sstevel@tonic-gate 23687c478bd9Sstevel@tonic-gate vfsp->vfs_dev = nfs_dev; 23697c478bd9Sstevel@tonic-gate vfs_make_fsid(&vfsp->vfs_fsid, nfs_dev, nfs4fstyp); 23707c478bd9Sstevel@tonic-gate vfsp->vfs_data = (caddr_t)mi; 23717c478bd9Sstevel@tonic-gate vfsp->vfs_fstype = nfsfstyp; 23727c478bd9Sstevel@tonic-gate vfsp->vfs_bsize = nfs4_bsize; 23737c478bd9Sstevel@tonic-gate 23747c478bd9Sstevel@tonic-gate /* 23757c478bd9Sstevel@tonic-gate * Initialize fields used to support async putpage operations. 23767c478bd9Sstevel@tonic-gate */ 23777c478bd9Sstevel@tonic-gate for (i = 0; i < NFS4_ASYNC_TYPES; i++) 23787c478bd9Sstevel@tonic-gate mi->mi_async_clusters[i] = nfs4_async_clusters; 23797c478bd9Sstevel@tonic-gate mi->mi_async_init_clusters = nfs4_async_clusters; 23800776f5e6SVallish Vaidyeshwara mi->mi_async_curr[NFS4_ASYNC_QUEUE] = 23810776f5e6SVallish Vaidyeshwara mi->mi_async_curr[NFS4_ASYNC_PGOPS_QUEUE] = &mi->mi_async_reqs[0]; 23827c478bd9Sstevel@tonic-gate mi->mi_max_threads = nfs4_max_threads; 23837c478bd9Sstevel@tonic-gate mutex_init(&mi->mi_async_lock, NULL, MUTEX_DEFAULT, NULL); 23847c478bd9Sstevel@tonic-gate cv_init(&mi->mi_async_reqs_cv, NULL, CV_DEFAULT, NULL); 23850776f5e6SVallish Vaidyeshwara cv_init(&mi->mi_async_work_cv[NFS4_ASYNC_QUEUE], NULL, CV_DEFAULT, 23860776f5e6SVallish Vaidyeshwara NULL); 23870776f5e6SVallish Vaidyeshwara cv_init(&mi->mi_async_work_cv[NFS4_ASYNC_PGOPS_QUEUE], NULL, 23880776f5e6SVallish Vaidyeshwara CV_DEFAULT, NULL); 23897c478bd9Sstevel@tonic-gate cv_init(&mi->mi_async_cv, NULL, CV_DEFAULT, NULL); 23907c478bd9Sstevel@tonic-gate cv_init(&mi->mi_inact_req_cv, NULL, CV_DEFAULT, NULL); 23917c478bd9Sstevel@tonic-gate 23927c478bd9Sstevel@tonic-gate mi->mi_vfsp = vfsp; 2393a19609f8Sjv227347 mi->mi_zone = zone; 2394a19609f8Sjv227347 zone_init_ref(&mi->mi_zone_ref); 2395a19609f8Sjv227347 zone_hold_ref(zone, &mi->mi_zone_ref, ZONE_REF_NFSV4); 23967c478bd9Sstevel@tonic-gate nfs4_mi_zonelist_add(mi); 23977c478bd9Sstevel@tonic-gate 23987c478bd9Sstevel@tonic-gate /* 23997c478bd9Sstevel@tonic-gate * Initialize the <open owner/cred> hash table. 24007c478bd9Sstevel@tonic-gate */ 24017c478bd9Sstevel@tonic-gate for (i = 0; i < NFS4_NUM_OO_BUCKETS; i++) { 24027c478bd9Sstevel@tonic-gate bucketp = &(mi->mi_oo_list[i]); 24037c478bd9Sstevel@tonic-gate mutex_init(&bucketp->b_lock, NULL, MUTEX_DEFAULT, NULL); 24047c478bd9Sstevel@tonic-gate list_create(&bucketp->b_oo_hash_list, 24057c478bd9Sstevel@tonic-gate sizeof (nfs4_open_owner_t), 24067c478bd9Sstevel@tonic-gate offsetof(nfs4_open_owner_t, oo_hash_node)); 24077c478bd9Sstevel@tonic-gate } 24087c478bd9Sstevel@tonic-gate 24097c478bd9Sstevel@tonic-gate /* 24107c478bd9Sstevel@tonic-gate * Initialize the freed open owner list. 24117c478bd9Sstevel@tonic-gate */ 24127c478bd9Sstevel@tonic-gate mi->mi_foo_num = 0; 24137c478bd9Sstevel@tonic-gate mi->mi_foo_max = NFS4_NUM_FREED_OPEN_OWNERS; 24147c478bd9Sstevel@tonic-gate list_create(&mi->mi_foo_list, sizeof (nfs4_open_owner_t), 24157c478bd9Sstevel@tonic-gate offsetof(nfs4_open_owner_t, oo_foo_node)); 24167c478bd9Sstevel@tonic-gate 24177c478bd9Sstevel@tonic-gate list_create(&mi->mi_lost_state, sizeof (nfs4_lost_rqst_t), 24187c478bd9Sstevel@tonic-gate offsetof(nfs4_lost_rqst_t, lr_node)); 24197c478bd9Sstevel@tonic-gate 24207c478bd9Sstevel@tonic-gate list_create(&mi->mi_bseqid_list, sizeof (nfs4_bseqid_entry_t), 24217c478bd9Sstevel@tonic-gate offsetof(nfs4_bseqid_entry_t, bs_node)); 24227c478bd9Sstevel@tonic-gate 24237c478bd9Sstevel@tonic-gate /* 24247c478bd9Sstevel@tonic-gate * Initialize the msg buffer. 24257c478bd9Sstevel@tonic-gate */ 24267c478bd9Sstevel@tonic-gate list_create(&mi->mi_msg_list, sizeof (nfs4_debug_msg_t), 24277c478bd9Sstevel@tonic-gate offsetof(nfs4_debug_msg_t, msg_node)); 24287c478bd9Sstevel@tonic-gate mi->mi_msg_count = 0; 24297c478bd9Sstevel@tonic-gate mutex_init(&mi->mi_msg_list_lock, NULL, MUTEX_DEFAULT, NULL); 24307c478bd9Sstevel@tonic-gate 24317c478bd9Sstevel@tonic-gate /* 24327c478bd9Sstevel@tonic-gate * Initialize kstats 24337c478bd9Sstevel@tonic-gate */ 24347c478bd9Sstevel@tonic-gate nfs4_mnt_kstat_init(vfsp); 24357c478bd9Sstevel@tonic-gate 24367c478bd9Sstevel@tonic-gate /* 2437bbf2a467SNagakiran Rajashekar * Initialize the shared filehandle pool. 24387c478bd9Sstevel@tonic-gate */ 24397c478bd9Sstevel@tonic-gate sfh4_createtab(&mi->mi_filehandles); 24407c478bd9Sstevel@tonic-gate 24417c478bd9Sstevel@tonic-gate /* 24427c478bd9Sstevel@tonic-gate * Save server path we're attempting to mount. 24437c478bd9Sstevel@tonic-gate */ 24447c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 24452f172c55SRobert Thurlow origsvp = copy_svp(svp); 24467c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 24477c478bd9Sstevel@tonic-gate 24487c478bd9Sstevel@tonic-gate /* 24497c478bd9Sstevel@tonic-gate * Make the GETFH call to get root fh for each replica. 24507c478bd9Sstevel@tonic-gate */ 24517c478bd9Sstevel@tonic-gate if (svp_head->sv_next) 24527c478bd9Sstevel@tonic-gate droptext = ", dropping replica"; 24537c478bd9Sstevel@tonic-gate 24547c478bd9Sstevel@tonic-gate /* 24557c478bd9Sstevel@tonic-gate * If the uid is set then set the creds for secure mounts 24567c478bd9Sstevel@tonic-gate * by proxy processes such as automountd. 24577c478bd9Sstevel@tonic-gate */ 24587c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 2459f722863dSSiyamaladevi Santhana Krishnan if (svp->sv_secdata->uid != 0 && 2460f722863dSSiyamaladevi Santhana Krishnan svp->sv_secdata->rpcflavor == RPCSEC_GSS) { 24617c478bd9Sstevel@tonic-gate lcr = crdup(cr); 24627c478bd9Sstevel@tonic-gate (void) crsetugid(lcr, svp->sv_secdata->uid, crgetgid(cr)); 24637c478bd9Sstevel@tonic-gate tcr = lcr; 24647c478bd9Sstevel@tonic-gate } 24657c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 24667c478bd9Sstevel@tonic-gate for (svp = svp_head; svp; svp = svp->sv_next) { 24677c478bd9Sstevel@tonic-gate if (nfs4_chkdup_servinfo4(svp_head, svp)) { 24687c478bd9Sstevel@tonic-gate nfs_cmn_err(error, CE_WARN, 24697c478bd9Sstevel@tonic-gate VERS_MSG "Host %s is a duplicate%s", 24707c478bd9Sstevel@tonic-gate svp->sv_hostname, droptext); 24717c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 24727c478bd9Sstevel@tonic-gate svp->sv_flags |= SV4_NOTINUSE; 24737c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 24747c478bd9Sstevel@tonic-gate continue; 24757c478bd9Sstevel@tonic-gate } 24767c478bd9Sstevel@tonic-gate mi->mi_curr_serv = svp; 24777c478bd9Sstevel@tonic-gate 24787c478bd9Sstevel@tonic-gate /* 24797c478bd9Sstevel@tonic-gate * Just in case server path being mounted contains 24807c478bd9Sstevel@tonic-gate * symlinks and fails w/STALE, save the initial sv_path 24817c478bd9Sstevel@tonic-gate * so we can redrive the initial mount compound with the 24827c478bd9Sstevel@tonic-gate * initial sv_path -- not a symlink-expanded version. 24837c478bd9Sstevel@tonic-gate * 24847c478bd9Sstevel@tonic-gate * This could only happen if a symlink was expanded 24857c478bd9Sstevel@tonic-gate * and the expanded mount compound failed stale. Because 24867c478bd9Sstevel@tonic-gate * it could be the case that the symlink was removed at 24877c478bd9Sstevel@tonic-gate * the server (and replaced with another symlink/dir, 24887c478bd9Sstevel@tonic-gate * we need to use the initial sv_path when attempting 24897c478bd9Sstevel@tonic-gate * to re-lookup everything and recover. 24907c478bd9Sstevel@tonic-gate * 24917c478bd9Sstevel@tonic-gate * Other mount errors should evenutally be handled here also 24927c478bd9Sstevel@tonic-gate * (NFS4ERR_DELAY, NFS4ERR_RESOURCE). For now, all mount 24937c478bd9Sstevel@tonic-gate * failures will result in mount being redriven a few times. 24947c478bd9Sstevel@tonic-gate */ 24957c478bd9Sstevel@tonic-gate num_retry = nfs4_max_mount_retry; 24967c478bd9Sstevel@tonic-gate do { 24977c478bd9Sstevel@tonic-gate nfs4getfh_otw(mi, svp, &tmp_vtype, 24987c478bd9Sstevel@tonic-gate ((flags & NFSMNT_PUBLIC) ? NFS4_GETFH_PUBLIC : 0) | 24997c478bd9Sstevel@tonic-gate NFS4_GETFH_NEEDSOP, tcr, &e); 25007c478bd9Sstevel@tonic-gate 25017c478bd9Sstevel@tonic-gate if (e.error == 0 && e.stat == NFS4_OK) 25027c478bd9Sstevel@tonic-gate break; 25037c478bd9Sstevel@tonic-gate 25047c478bd9Sstevel@tonic-gate /* 25052f172c55SRobert Thurlow * For some reason, the mount compound failed. Before 25062f172c55SRobert Thurlow * retrying, we need to restore original conditions. 25077c478bd9Sstevel@tonic-gate */ 25082f172c55SRobert Thurlow svp = restore_svp(mi, svp, origsvp); 25092f172c55SRobert Thurlow svp_head = svp; 25107c478bd9Sstevel@tonic-gate 25117c478bd9Sstevel@tonic-gate } while (num_retry-- > 0); 25127c478bd9Sstevel@tonic-gate error = e.error ? e.error : geterrno4(e.stat); 25137c478bd9Sstevel@tonic-gate if (error) { 25147c478bd9Sstevel@tonic-gate nfs_cmn_err(error, CE_WARN, 25157c478bd9Sstevel@tonic-gate VERS_MSG "initial call to %s failed%s: %m", 25167c478bd9Sstevel@tonic-gate svp->sv_hostname, droptext); 25177c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 25187c478bd9Sstevel@tonic-gate svp->sv_flags |= SV4_NOTINUSE; 25197c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 25207c478bd9Sstevel@tonic-gate mi->mi_flags &= ~MI4_RECOV_FAIL; 25217c478bd9Sstevel@tonic-gate mi->mi_error = 0; 25227c478bd9Sstevel@tonic-gate continue; 25237c478bd9Sstevel@tonic-gate } 25247c478bd9Sstevel@tonic-gate 25257c478bd9Sstevel@tonic-gate if (tmp_vtype == VBAD) { 25267c478bd9Sstevel@tonic-gate zcmn_err(mi->mi_zone->zone_id, CE_WARN, 25277c478bd9Sstevel@tonic-gate VERS_MSG "%s returned a bad file type for " 25287c478bd9Sstevel@tonic-gate "root%s", svp->sv_hostname, droptext); 25297c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 25307c478bd9Sstevel@tonic-gate svp->sv_flags |= SV4_NOTINUSE; 25317c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 25327c478bd9Sstevel@tonic-gate continue; 25337c478bd9Sstevel@tonic-gate } 25347c478bd9Sstevel@tonic-gate 25357c478bd9Sstevel@tonic-gate if (vtype == VNON) { 25367c478bd9Sstevel@tonic-gate vtype = tmp_vtype; 25377c478bd9Sstevel@tonic-gate } else if (vtype != tmp_vtype) { 25387c478bd9Sstevel@tonic-gate zcmn_err(mi->mi_zone->zone_id, CE_WARN, 25397c478bd9Sstevel@tonic-gate VERS_MSG "%s returned a different file type " 25407c478bd9Sstevel@tonic-gate "for root%s", svp->sv_hostname, droptext); 25417c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 25427c478bd9Sstevel@tonic-gate svp->sv_flags |= SV4_NOTINUSE; 25437c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 25447c478bd9Sstevel@tonic-gate continue; 25457c478bd9Sstevel@tonic-gate } 25467c478bd9Sstevel@tonic-gate if (firstsvp == NULL) 25477c478bd9Sstevel@tonic-gate firstsvp = svp; 25487c478bd9Sstevel@tonic-gate } 25497c478bd9Sstevel@tonic-gate 25507c478bd9Sstevel@tonic-gate if (firstsvp == NULL) { 25517c478bd9Sstevel@tonic-gate if (error == 0) 25527c478bd9Sstevel@tonic-gate error = ENOENT; 25537c478bd9Sstevel@tonic-gate goto bad; 25547c478bd9Sstevel@tonic-gate } 25557c478bd9Sstevel@tonic-gate 25567c478bd9Sstevel@tonic-gate mi->mi_curr_serv = svp = firstsvp; 25577c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 25587c478bd9Sstevel@tonic-gate ASSERT((mi->mi_curr_serv->sv_flags & SV4_NOTINUSE) == 0); 25597c478bd9Sstevel@tonic-gate fh.nfs_fh4_len = svp->sv_fhandle.fh_len; 25607c478bd9Sstevel@tonic-gate fh.nfs_fh4_val = svp->sv_fhandle.fh_buf; 25617c478bd9Sstevel@tonic-gate mi->mi_rootfh = sfh4_get(&fh, mi); 25627c478bd9Sstevel@tonic-gate fh.nfs_fh4_len = svp->sv_pfhandle.fh_len; 25637c478bd9Sstevel@tonic-gate fh.nfs_fh4_val = svp->sv_pfhandle.fh_buf; 25647c478bd9Sstevel@tonic-gate mi->mi_srvparentfh = sfh4_get(&fh, mi); 25657c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 25667c478bd9Sstevel@tonic-gate 25677c478bd9Sstevel@tonic-gate /* 2568bbf2a467SNagakiran Rajashekar * Get the fname for filesystem root. 25697c478bd9Sstevel@tonic-gate */ 2570bbf2a467SNagakiran Rajashekar mi->mi_fname = fn_get(NULL, ".", mi->mi_rootfh); 25717c478bd9Sstevel@tonic-gate mfname = mi->mi_fname; 25727c478bd9Sstevel@tonic-gate fn_hold(mfname); 2573bbf2a467SNagakiran Rajashekar 2574bbf2a467SNagakiran Rajashekar /* 2575bbf2a467SNagakiran Rajashekar * Make the root vnode without attributes. 2576bbf2a467SNagakiran Rajashekar */ 25777c478bd9Sstevel@tonic-gate rtvp = makenfs4node_by_fh(mi->mi_rootfh, NULL, 25787c478bd9Sstevel@tonic-gate &mfname, NULL, mi, cr, gethrtime()); 25797c478bd9Sstevel@tonic-gate rtvp->v_type = vtype; 25807c478bd9Sstevel@tonic-gate 25817c478bd9Sstevel@tonic-gate mi->mi_curread = mi->mi_tsize; 25827c478bd9Sstevel@tonic-gate mi->mi_curwrite = mi->mi_stsize; 25837c478bd9Sstevel@tonic-gate 25847c478bd9Sstevel@tonic-gate /* 25857c478bd9Sstevel@tonic-gate * Start the manager thread responsible for handling async worker 25867c478bd9Sstevel@tonic-gate * threads. 25877c478bd9Sstevel@tonic-gate */ 258850a83466Sjwahlig MI4_HOLD(mi); 25897c478bd9Sstevel@tonic-gate VFS_HOLD(vfsp); /* add reference for thread */ 25907c478bd9Sstevel@tonic-gate mi->mi_manager_thread = zthread_create(NULL, 0, nfs4_async_manager, 25917c478bd9Sstevel@tonic-gate vfsp, 0, minclsyspri); 25927c478bd9Sstevel@tonic-gate ASSERT(mi->mi_manager_thread != NULL); 259350a83466Sjwahlig 25947c478bd9Sstevel@tonic-gate /* 25957c478bd9Sstevel@tonic-gate * Create the thread that handles over-the-wire calls for 25967c478bd9Sstevel@tonic-gate * VOP_INACTIVE. 25977c478bd9Sstevel@tonic-gate * This needs to happen after the manager thread is created. 25987c478bd9Sstevel@tonic-gate */ 259950a83466Sjwahlig MI4_HOLD(mi); 26007c478bd9Sstevel@tonic-gate mi->mi_inactive_thread = zthread_create(NULL, 0, nfs4_inactive_thread, 26017c478bd9Sstevel@tonic-gate mi, 0, minclsyspri); 26027c478bd9Sstevel@tonic-gate ASSERT(mi->mi_inactive_thread != NULL); 26037c478bd9Sstevel@tonic-gate 26047c478bd9Sstevel@tonic-gate /* If we didn't get a type, get one now */ 26057c478bd9Sstevel@tonic-gate if (rtvp->v_type == VNON) { 26067c478bd9Sstevel@tonic-gate va.va_mask = AT_TYPE; 26077c478bd9Sstevel@tonic-gate error = nfs4getattr(rtvp, &va, tcr); 26087c478bd9Sstevel@tonic-gate if (error) 26097c478bd9Sstevel@tonic-gate goto bad; 26107c478bd9Sstevel@tonic-gate rtvp->v_type = va.va_type; 26117c478bd9Sstevel@tonic-gate } 26127c478bd9Sstevel@tonic-gate 26137c478bd9Sstevel@tonic-gate mi->mi_type = rtvp->v_type; 26147c478bd9Sstevel@tonic-gate 26157c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 26167c478bd9Sstevel@tonic-gate mi->mi_flags &= ~MI4_MOUNTING; 26177c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 26187c478bd9Sstevel@tonic-gate 26192f172c55SRobert Thurlow /* Update VFS with new server and path info */ 26202f172c55SRobert Thurlow if ((strcmp(svp->sv_hostname, origsvp->sv_hostname) != 0) || 26212f172c55SRobert Thurlow (strcmp(svp->sv_path, origsvp->sv_path) != 0)) { 26222f172c55SRobert Thurlow len = svp->sv_hostnamelen + svp->sv_pathlen; 26232f172c55SRobert Thurlow resource = kmem_zalloc(len, KM_SLEEP); 26242f172c55SRobert Thurlow (void) strcat(resource, svp->sv_hostname); 26252f172c55SRobert Thurlow (void) strcat(resource, ":"); 26262f172c55SRobert Thurlow (void) strcat(resource, svp->sv_path); 2627d7de0ceaSRobert Harris vfs_setresource(vfsp, resource, 0); 26282f172c55SRobert Thurlow kmem_free(resource, len); 26292f172c55SRobert Thurlow } 26302f172c55SRobert Thurlow 26312f172c55SRobert Thurlow sv4_free(origsvp); 26327c478bd9Sstevel@tonic-gate *rtvpp = rtvp; 26337c478bd9Sstevel@tonic-gate if (lcr != NULL) 26347c478bd9Sstevel@tonic-gate crfree(lcr); 26357c478bd9Sstevel@tonic-gate 26367c478bd9Sstevel@tonic-gate return (0); 26377c478bd9Sstevel@tonic-gate bad: 26387c478bd9Sstevel@tonic-gate /* 26397c478bd9Sstevel@tonic-gate * An error occurred somewhere, need to clean up... 26407c478bd9Sstevel@tonic-gate */ 26417c478bd9Sstevel@tonic-gate if (lcr != NULL) 26427c478bd9Sstevel@tonic-gate crfree(lcr); 2643b9238976Sth199096 26447c478bd9Sstevel@tonic-gate if (rtvp != NULL) { 26457c478bd9Sstevel@tonic-gate /* 26467c478bd9Sstevel@tonic-gate * We need to release our reference to the root vnode and 26477c478bd9Sstevel@tonic-gate * destroy the mntinfo4 struct that we just created. 26487c478bd9Sstevel@tonic-gate */ 26497c478bd9Sstevel@tonic-gate rp = VTOR4(rtvp); 26507c478bd9Sstevel@tonic-gate if (rp->r_flags & R4HASHED) 26517c478bd9Sstevel@tonic-gate rp4_rmhash(rp); 26527c478bd9Sstevel@tonic-gate VN_RELE(rtvp); 26537c478bd9Sstevel@tonic-gate } 26547c478bd9Sstevel@tonic-gate nfs4_async_stop(vfsp); 26557c478bd9Sstevel@tonic-gate nfs4_async_manager_stop(vfsp); 265650a83466Sjwahlig removed = nfs4_mi_zonelist_remove(mi); 265750a83466Sjwahlig if (removed) 2658a19609f8Sjv227347 zone_rele_ref(&mi->mi_zone_ref, ZONE_REF_NFSV4); 265950a83466Sjwahlig 266050a83466Sjwahlig /* 266150a83466Sjwahlig * This releases the initial "hold" of the mi since it will never 266250a83466Sjwahlig * be referenced by the vfsp. Also, when mount returns to vfs.c 266350a83466Sjwahlig * with an error, the vfsp will be destroyed, not rele'd. 266450a83466Sjwahlig */ 266550a83466Sjwahlig MI4_RELE(mi); 266650a83466Sjwahlig 26672f172c55SRobert Thurlow if (origsvp != NULL) 26682f172c55SRobert Thurlow sv4_free(origsvp); 26692f172c55SRobert Thurlow 26707c478bd9Sstevel@tonic-gate *rtvpp = NULL; 26717c478bd9Sstevel@tonic-gate return (error); 26727c478bd9Sstevel@tonic-gate } 26737c478bd9Sstevel@tonic-gate 26747c478bd9Sstevel@tonic-gate /* 26757c478bd9Sstevel@tonic-gate * vfs operations 26767c478bd9Sstevel@tonic-gate */ 26777c478bd9Sstevel@tonic-gate static int 26787c478bd9Sstevel@tonic-gate nfs4_unmount(vfs_t *vfsp, int flag, cred_t *cr) 26797c478bd9Sstevel@tonic-gate { 26807c478bd9Sstevel@tonic-gate mntinfo4_t *mi; 26817c478bd9Sstevel@tonic-gate ushort_t omax; 268250a83466Sjwahlig int removed; 26837c478bd9Sstevel@tonic-gate 2684d3a14591SThomas Haynes bool_t must_unlock; 2685b9238976Sth199096 2686b9238976Sth199096 nfs4_ephemeral_tree_t *eph_tree; 2687b9238976Sth199096 26887c478bd9Sstevel@tonic-gate if (secpolicy_fs_unmount(cr, vfsp) != 0) 26897c478bd9Sstevel@tonic-gate return (EPERM); 26907c478bd9Sstevel@tonic-gate 26917c478bd9Sstevel@tonic-gate mi = VFTOMI4(vfsp); 26927c478bd9Sstevel@tonic-gate 26937c478bd9Sstevel@tonic-gate if (flag & MS_FORCE) { 26947c478bd9Sstevel@tonic-gate vfsp->vfs_flag |= VFS_UNMOUNTED; 2695108322fbScarlsonj if (nfs_zone() != mi->mi_zone) { 26967c478bd9Sstevel@tonic-gate /* 26977c478bd9Sstevel@tonic-gate * If the request is coming from the wrong zone, 26987c478bd9Sstevel@tonic-gate * we don't want to create any new threads, and 26997c478bd9Sstevel@tonic-gate * performance is not a concern. Do everything 27007c478bd9Sstevel@tonic-gate * inline. 27017c478bd9Sstevel@tonic-gate */ 27027c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_zone_debug, (CE_NOTE, 27037c478bd9Sstevel@tonic-gate "nfs4_unmount x-zone forced unmount of vfs %p\n", 27047c478bd9Sstevel@tonic-gate (void *)vfsp)); 2705b9238976Sth199096 nfs4_free_mount(vfsp, flag, cr); 27067c478bd9Sstevel@tonic-gate } else { 27077c478bd9Sstevel@tonic-gate /* 27087c478bd9Sstevel@tonic-gate * Free data structures asynchronously, to avoid 27097c478bd9Sstevel@tonic-gate * blocking the current thread (for performance 27107c478bd9Sstevel@tonic-gate * reasons only). 27117c478bd9Sstevel@tonic-gate */ 2712b9238976Sth199096 async_free_mount(vfsp, flag, cr); 27137c478bd9Sstevel@tonic-gate } 2714b9238976Sth199096 27157c478bd9Sstevel@tonic-gate return (0); 27167c478bd9Sstevel@tonic-gate } 2717b9238976Sth199096 27187c478bd9Sstevel@tonic-gate /* 27197c478bd9Sstevel@tonic-gate * Wait until all asynchronous putpage operations on 27207c478bd9Sstevel@tonic-gate * this file system are complete before flushing rnodes 27217c478bd9Sstevel@tonic-gate * from the cache. 27227c478bd9Sstevel@tonic-gate */ 27237c478bd9Sstevel@tonic-gate omax = mi->mi_max_threads; 2724b9238976Sth199096 if (nfs4_async_stop_sig(vfsp)) 27257c478bd9Sstevel@tonic-gate return (EINTR); 2726b9238976Sth199096 27277c478bd9Sstevel@tonic-gate r4flush(vfsp, cr); 2728b9238976Sth199096 2729eabd0450Sth199096 /* 2730eabd0450Sth199096 * About the only reason that this would fail would be 2731eabd0450Sth199096 * that the harvester is already busy tearing down this 2732eabd0450Sth199096 * node. So we fail back to the caller and let them try 2733eabd0450Sth199096 * again when needed. 2734eabd0450Sth199096 */ 2735eabd0450Sth199096 if (nfs4_ephemeral_umount(mi, flag, cr, 27362f172c55SRobert Thurlow &must_unlock, &eph_tree)) { 2737d3a14591SThomas Haynes ASSERT(must_unlock == FALSE); 2738eabd0450Sth199096 mutex_enter(&mi->mi_async_lock); 2739eabd0450Sth199096 mi->mi_max_threads = omax; 2740eabd0450Sth199096 mutex_exit(&mi->mi_async_lock); 2741eabd0450Sth199096 2742eabd0450Sth199096 return (EBUSY); 2743eabd0450Sth199096 } 2744b9238976Sth199096 27457c478bd9Sstevel@tonic-gate /* 27467c478bd9Sstevel@tonic-gate * If there are any active vnodes on this file system, 2747b9238976Sth199096 * then the file system is busy and can't be unmounted. 27487c478bd9Sstevel@tonic-gate */ 27497c478bd9Sstevel@tonic-gate if (check_rtable4(vfsp)) { 27502f172c55SRobert Thurlow nfs4_ephemeral_umount_unlock(&must_unlock, &eph_tree); 2751b9238976Sth199096 27527c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_async_lock); 27537c478bd9Sstevel@tonic-gate mi->mi_max_threads = omax; 27547c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_async_lock); 2755b9238976Sth199096 27567c478bd9Sstevel@tonic-gate return (EBUSY); 27577c478bd9Sstevel@tonic-gate } 2758b9238976Sth199096 27597c478bd9Sstevel@tonic-gate /* 2760b9238976Sth199096 * The unmount can't fail from now on, so record any 2761b9238976Sth199096 * ephemeral changes. 2762b9238976Sth199096 */ 27632f172c55SRobert Thurlow nfs4_ephemeral_umount_activate(mi, &must_unlock, &eph_tree); 2764b9238976Sth199096 2765b9238976Sth199096 /* 2766b9238976Sth199096 * There are no active files that could require over-the-wire 2767b9238976Sth199096 * calls to the server, so stop the async manager and the 2768b9238976Sth199096 * inactive thread. 27697c478bd9Sstevel@tonic-gate */ 27707c478bd9Sstevel@tonic-gate nfs4_async_manager_stop(vfsp); 2771b9238976Sth199096 27727c478bd9Sstevel@tonic-gate /* 27737c478bd9Sstevel@tonic-gate * Destroy all rnodes belonging to this file system from the 27747c478bd9Sstevel@tonic-gate * rnode hash queues and purge any resources allocated to 27757c478bd9Sstevel@tonic-gate * them. 27767c478bd9Sstevel@tonic-gate */ 27777c478bd9Sstevel@tonic-gate destroy_rtable4(vfsp, cr); 27787c478bd9Sstevel@tonic-gate vfsp->vfs_flag |= VFS_UNMOUNTED; 277950a83466Sjwahlig 27807c478bd9Sstevel@tonic-gate nfs4_remove_mi_from_server(mi, NULL); 278150a83466Sjwahlig removed = nfs4_mi_zonelist_remove(mi); 278250a83466Sjwahlig if (removed) 2783a19609f8Sjv227347 zone_rele_ref(&mi->mi_zone_ref, ZONE_REF_NFSV4); 278450a83466Sjwahlig 27857c478bd9Sstevel@tonic-gate return (0); 27867c478bd9Sstevel@tonic-gate } 27877c478bd9Sstevel@tonic-gate 27887c478bd9Sstevel@tonic-gate /* 27897c478bd9Sstevel@tonic-gate * find root of nfs 27907c478bd9Sstevel@tonic-gate */ 27917c478bd9Sstevel@tonic-gate static int 27927c478bd9Sstevel@tonic-gate nfs4_root(vfs_t *vfsp, vnode_t **vpp) 27937c478bd9Sstevel@tonic-gate { 27947c478bd9Sstevel@tonic-gate mntinfo4_t *mi; 27957c478bd9Sstevel@tonic-gate vnode_t *vp; 27967c478bd9Sstevel@tonic-gate nfs4_fname_t *mfname; 27977c478bd9Sstevel@tonic-gate servinfo4_t *svp; 27987c478bd9Sstevel@tonic-gate 27997c478bd9Sstevel@tonic-gate mi = VFTOMI4(vfsp); 28007c478bd9Sstevel@tonic-gate 2801108322fbScarlsonj if (nfs_zone() != mi->mi_zone) 28027c478bd9Sstevel@tonic-gate return (EPERM); 28037c478bd9Sstevel@tonic-gate 28047c478bd9Sstevel@tonic-gate svp = mi->mi_curr_serv; 28057c478bd9Sstevel@tonic-gate if (svp) { 28067c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 28077c478bd9Sstevel@tonic-gate if (svp->sv_flags & SV4_ROOT_STALE) { 28087c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 28097c478bd9Sstevel@tonic-gate 28107c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); 28117c478bd9Sstevel@tonic-gate if (svp->sv_flags & SV4_ROOT_STALE) { 28127c478bd9Sstevel@tonic-gate svp->sv_flags &= ~SV4_ROOT_STALE; 28137c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 28147c478bd9Sstevel@tonic-gate return (ENOENT); 28157c478bd9Sstevel@tonic-gate } 28167c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 28177c478bd9Sstevel@tonic-gate } else 28187c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 28197c478bd9Sstevel@tonic-gate } 28207c478bd9Sstevel@tonic-gate 28217c478bd9Sstevel@tonic-gate mfname = mi->mi_fname; 28227c478bd9Sstevel@tonic-gate fn_hold(mfname); 28237c478bd9Sstevel@tonic-gate vp = makenfs4node_by_fh(mi->mi_rootfh, NULL, &mfname, NULL, 28247c478bd9Sstevel@tonic-gate VFTOMI4(vfsp), CRED(), gethrtime()); 28257c478bd9Sstevel@tonic-gate 28267c478bd9Sstevel@tonic-gate if (VTOR4(vp)->r_flags & R4STALE) { 28277c478bd9Sstevel@tonic-gate VN_RELE(vp); 28287c478bd9Sstevel@tonic-gate return (ENOENT); 28297c478bd9Sstevel@tonic-gate } 28307c478bd9Sstevel@tonic-gate 28317c478bd9Sstevel@tonic-gate ASSERT(vp->v_type == VNON || vp->v_type == mi->mi_type); 28327c478bd9Sstevel@tonic-gate 28337c478bd9Sstevel@tonic-gate vp->v_type = mi->mi_type; 28347c478bd9Sstevel@tonic-gate 28357c478bd9Sstevel@tonic-gate *vpp = vp; 28367c478bd9Sstevel@tonic-gate 28377c478bd9Sstevel@tonic-gate return (0); 28387c478bd9Sstevel@tonic-gate } 28397c478bd9Sstevel@tonic-gate 28407c478bd9Sstevel@tonic-gate static int 28417c478bd9Sstevel@tonic-gate nfs4_statfs_otw(vnode_t *vp, struct statvfs64 *sbp, cred_t *cr) 28427c478bd9Sstevel@tonic-gate { 28437c478bd9Sstevel@tonic-gate int error; 28447c478bd9Sstevel@tonic-gate nfs4_ga_res_t gar; 28457c478bd9Sstevel@tonic-gate nfs4_ga_ext_res_t ger; 28467c478bd9Sstevel@tonic-gate 28477c478bd9Sstevel@tonic-gate gar.n4g_ext_res = &ger; 28487c478bd9Sstevel@tonic-gate 28497c478bd9Sstevel@tonic-gate if (error = nfs4_attr_otw(vp, TAG_FSINFO, &gar, 28507c478bd9Sstevel@tonic-gate NFS4_STATFS_ATTR_MASK, cr)) 28517c478bd9Sstevel@tonic-gate return (error); 28527c478bd9Sstevel@tonic-gate 28537c478bd9Sstevel@tonic-gate *sbp = gar.n4g_ext_res->n4g_sb; 28547c478bd9Sstevel@tonic-gate 28557c478bd9Sstevel@tonic-gate return (0); 28567c478bd9Sstevel@tonic-gate } 28577c478bd9Sstevel@tonic-gate 28587c478bd9Sstevel@tonic-gate /* 28597c478bd9Sstevel@tonic-gate * Get file system statistics. 28607c478bd9Sstevel@tonic-gate */ 28617c478bd9Sstevel@tonic-gate static int 28627c478bd9Sstevel@tonic-gate nfs4_statvfs(vfs_t *vfsp, struct statvfs64 *sbp) 28637c478bd9Sstevel@tonic-gate { 28647c478bd9Sstevel@tonic-gate int error; 28657c478bd9Sstevel@tonic-gate vnode_t *vp; 28667c478bd9Sstevel@tonic-gate cred_t *cr; 28677c478bd9Sstevel@tonic-gate 28687c478bd9Sstevel@tonic-gate error = nfs4_root(vfsp, &vp); 28697c478bd9Sstevel@tonic-gate if (error) 28707c478bd9Sstevel@tonic-gate return (error); 28717c478bd9Sstevel@tonic-gate 28727c478bd9Sstevel@tonic-gate cr = CRED(); 28737c478bd9Sstevel@tonic-gate 28747c478bd9Sstevel@tonic-gate error = nfs4_statfs_otw(vp, sbp, cr); 28757c478bd9Sstevel@tonic-gate if (!error) { 28767c478bd9Sstevel@tonic-gate (void) strncpy(sbp->f_basetype, 28777c478bd9Sstevel@tonic-gate vfssw[vfsp->vfs_fstype].vsw_name, FSTYPSZ); 28787c478bd9Sstevel@tonic-gate sbp->f_flag = vf_to_stf(vfsp->vfs_flag); 28797c478bd9Sstevel@tonic-gate } else { 28807c478bd9Sstevel@tonic-gate nfs4_purge_stale_fh(error, vp, cr); 28817c478bd9Sstevel@tonic-gate } 28827c478bd9Sstevel@tonic-gate 28837c478bd9Sstevel@tonic-gate VN_RELE(vp); 28847c478bd9Sstevel@tonic-gate 28857c478bd9Sstevel@tonic-gate return (error); 28867c478bd9Sstevel@tonic-gate } 28877c478bd9Sstevel@tonic-gate 28887c478bd9Sstevel@tonic-gate static kmutex_t nfs4_syncbusy; 28897c478bd9Sstevel@tonic-gate 28907c478bd9Sstevel@tonic-gate /* 28917c478bd9Sstevel@tonic-gate * Flush dirty nfs files for file system vfsp. 28927c478bd9Sstevel@tonic-gate * If vfsp == NULL, all nfs files are flushed. 28937c478bd9Sstevel@tonic-gate * 28947c478bd9Sstevel@tonic-gate * SYNC_CLOSE in flag is passed to us to 28957c478bd9Sstevel@tonic-gate * indicate that we are shutting down and or 28967c478bd9Sstevel@tonic-gate * rebooting. 28977c478bd9Sstevel@tonic-gate */ 28987c478bd9Sstevel@tonic-gate static int 28997c478bd9Sstevel@tonic-gate nfs4_sync(vfs_t *vfsp, short flag, cred_t *cr) 29007c478bd9Sstevel@tonic-gate { 29017c478bd9Sstevel@tonic-gate /* 29027c478bd9Sstevel@tonic-gate * Cross-zone calls are OK here, since this translates to a 29037c478bd9Sstevel@tonic-gate * VOP_PUTPAGE(B_ASYNC), which gets picked up by the right zone. 29047c478bd9Sstevel@tonic-gate */ 29057c478bd9Sstevel@tonic-gate if (!(flag & SYNC_ATTR) && mutex_tryenter(&nfs4_syncbusy) != 0) { 29067c478bd9Sstevel@tonic-gate r4flush(vfsp, cr); 29077c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_syncbusy); 29087c478bd9Sstevel@tonic-gate } 29097c478bd9Sstevel@tonic-gate 29107c478bd9Sstevel@tonic-gate /* 29117c478bd9Sstevel@tonic-gate * if SYNC_CLOSE is set then we know that 29127c478bd9Sstevel@tonic-gate * the system is rebooting, mark the mntinfo 29137c478bd9Sstevel@tonic-gate * for later examination. 29147c478bd9Sstevel@tonic-gate */ 29157c478bd9Sstevel@tonic-gate if (vfsp && (flag & SYNC_CLOSE)) { 29167c478bd9Sstevel@tonic-gate mntinfo4_t *mi; 29177c478bd9Sstevel@tonic-gate 29187c478bd9Sstevel@tonic-gate mi = VFTOMI4(vfsp); 29197c478bd9Sstevel@tonic-gate if (!(mi->mi_flags & MI4_SHUTDOWN)) { 29207c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 29217c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_SHUTDOWN; 29227c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 29237c478bd9Sstevel@tonic-gate } 29247c478bd9Sstevel@tonic-gate } 29257c478bd9Sstevel@tonic-gate return (0); 29267c478bd9Sstevel@tonic-gate } 29277c478bd9Sstevel@tonic-gate 29287c478bd9Sstevel@tonic-gate /* 29297c478bd9Sstevel@tonic-gate * vget is difficult, if not impossible, to support in v4 because we don't 29307c478bd9Sstevel@tonic-gate * know the parent directory or name, which makes it impossible to create a 29317c478bd9Sstevel@tonic-gate * useful shadow vnode. And we need the shadow vnode for things like 29327c478bd9Sstevel@tonic-gate * OPEN. 29337c478bd9Sstevel@tonic-gate */ 29347c478bd9Sstevel@tonic-gate 29357c478bd9Sstevel@tonic-gate /* ARGSUSED */ 29367c478bd9Sstevel@tonic-gate /* 29377c478bd9Sstevel@tonic-gate * XXX Check nfs4_vget_pseudo() for dependency. 29387c478bd9Sstevel@tonic-gate */ 29397c478bd9Sstevel@tonic-gate static int 29407c478bd9Sstevel@tonic-gate nfs4_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp) 29417c478bd9Sstevel@tonic-gate { 29427c478bd9Sstevel@tonic-gate return (EREMOTE); 29437c478bd9Sstevel@tonic-gate } 29447c478bd9Sstevel@tonic-gate 29457c478bd9Sstevel@tonic-gate /* 29467c478bd9Sstevel@tonic-gate * nfs4_mountroot get called in the case where we are diskless booting. All 29477c478bd9Sstevel@tonic-gate * we need from here is the ability to get the server info and from there we 29487c478bd9Sstevel@tonic-gate * can simply call nfs4_rootvp. 29497c478bd9Sstevel@tonic-gate */ 29507c478bd9Sstevel@tonic-gate /* ARGSUSED */ 29517c478bd9Sstevel@tonic-gate static int 29527c478bd9Sstevel@tonic-gate nfs4_mountroot(vfs_t *vfsp, whymountroot_t why) 29537c478bd9Sstevel@tonic-gate { 29547c478bd9Sstevel@tonic-gate vnode_t *rtvp; 29557c478bd9Sstevel@tonic-gate char root_hostname[SYS_NMLN+1]; 29567c478bd9Sstevel@tonic-gate struct servinfo4 *svp; 29577c478bd9Sstevel@tonic-gate int error; 29587c478bd9Sstevel@tonic-gate int vfsflags; 29597c478bd9Sstevel@tonic-gate size_t size; 29607c478bd9Sstevel@tonic-gate char *root_path; 29617c478bd9Sstevel@tonic-gate struct pathname pn; 29627c478bd9Sstevel@tonic-gate char *name; 29637c478bd9Sstevel@tonic-gate cred_t *cr; 29647c478bd9Sstevel@tonic-gate mntinfo4_t *mi; 29657c478bd9Sstevel@tonic-gate struct nfs_args args; /* nfs mount arguments */ 29667c478bd9Sstevel@tonic-gate static char token[10]; 29677c478bd9Sstevel@tonic-gate nfs4_error_t n4e; 29687c478bd9Sstevel@tonic-gate 29697c478bd9Sstevel@tonic-gate bzero(&args, sizeof (args)); 29707c478bd9Sstevel@tonic-gate 29717c478bd9Sstevel@tonic-gate /* do this BEFORE getfile which causes xid stamps to be initialized */ 29727c478bd9Sstevel@tonic-gate clkset(-1L); /* hack for now - until we get time svc? */ 29737c478bd9Sstevel@tonic-gate 29747c478bd9Sstevel@tonic-gate if (why == ROOT_REMOUNT) { 29757c478bd9Sstevel@tonic-gate /* 29767c478bd9Sstevel@tonic-gate * Shouldn't happen. 29777c478bd9Sstevel@tonic-gate */ 29787c478bd9Sstevel@tonic-gate panic("nfs4_mountroot: why == ROOT_REMOUNT"); 29797c478bd9Sstevel@tonic-gate } 29807c478bd9Sstevel@tonic-gate 29817c478bd9Sstevel@tonic-gate if (why == ROOT_UNMOUNT) { 29827c478bd9Sstevel@tonic-gate /* 29837c478bd9Sstevel@tonic-gate * Nothing to do for NFS. 29847c478bd9Sstevel@tonic-gate */ 29857c478bd9Sstevel@tonic-gate return (0); 29867c478bd9Sstevel@tonic-gate } 29877c478bd9Sstevel@tonic-gate 29887c478bd9Sstevel@tonic-gate /* 29897c478bd9Sstevel@tonic-gate * why == ROOT_INIT 29907c478bd9Sstevel@tonic-gate */ 29917c478bd9Sstevel@tonic-gate 29927c478bd9Sstevel@tonic-gate name = token; 29937c478bd9Sstevel@tonic-gate *name = 0; 29947c478bd9Sstevel@tonic-gate (void) getfsname("root", name, sizeof (token)); 29957c478bd9Sstevel@tonic-gate 29967c478bd9Sstevel@tonic-gate pn_alloc(&pn); 29977c478bd9Sstevel@tonic-gate root_path = pn.pn_path; 29987c478bd9Sstevel@tonic-gate 29997c478bd9Sstevel@tonic-gate svp = kmem_zalloc(sizeof (*svp), KM_SLEEP); 30007c478bd9Sstevel@tonic-gate nfs_rw_init(&svp->sv_lock, NULL, RW_DEFAULT, NULL); 30017c478bd9Sstevel@tonic-gate svp->sv_knconf = kmem_zalloc(sizeof (*svp->sv_knconf), KM_SLEEP); 30027c478bd9Sstevel@tonic-gate svp->sv_knconf->knc_protofmly = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 30037c478bd9Sstevel@tonic-gate svp->sv_knconf->knc_proto = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 30047c478bd9Sstevel@tonic-gate 30057c478bd9Sstevel@tonic-gate /* 30067c478bd9Sstevel@tonic-gate * Get server address 30077c478bd9Sstevel@tonic-gate * Get the root path 30087c478bd9Sstevel@tonic-gate * Get server's transport 30097c478bd9Sstevel@tonic-gate * Get server's hostname 30107c478bd9Sstevel@tonic-gate * Get options 30117c478bd9Sstevel@tonic-gate */ 30127c478bd9Sstevel@tonic-gate args.addr = &svp->sv_addr; 30137c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 30147c478bd9Sstevel@tonic-gate args.fh = (char *)&svp->sv_fhandle; 30157c478bd9Sstevel@tonic-gate args.knconf = svp->sv_knconf; 30167c478bd9Sstevel@tonic-gate args.hostname = root_hostname; 30177c478bd9Sstevel@tonic-gate vfsflags = 0; 30187c478bd9Sstevel@tonic-gate if (error = mount_root(*name ? name : "root", root_path, NFS_V4, 30197c478bd9Sstevel@tonic-gate &args, &vfsflags)) { 30207c478bd9Sstevel@tonic-gate if (error == EPROTONOSUPPORT) 30217c478bd9Sstevel@tonic-gate nfs_cmn_err(error, CE_WARN, "nfs4_mountroot: " 30227c478bd9Sstevel@tonic-gate "mount_root failed: server doesn't support NFS V4"); 30237c478bd9Sstevel@tonic-gate else 30247c478bd9Sstevel@tonic-gate nfs_cmn_err(error, CE_WARN, 30257c478bd9Sstevel@tonic-gate "nfs4_mountroot: mount_root failed: %m"); 30267c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 30277c478bd9Sstevel@tonic-gate sv4_free(svp); 30287c478bd9Sstevel@tonic-gate pn_free(&pn); 30297c478bd9Sstevel@tonic-gate return (error); 30307c478bd9Sstevel@tonic-gate } 30317c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 30327c478bd9Sstevel@tonic-gate svp->sv_hostnamelen = (int)(strlen(root_hostname) + 1); 30337c478bd9Sstevel@tonic-gate svp->sv_hostname = kmem_alloc(svp->sv_hostnamelen, KM_SLEEP); 30347c478bd9Sstevel@tonic-gate (void) strcpy(svp->sv_hostname, root_hostname); 30357c478bd9Sstevel@tonic-gate 30367c478bd9Sstevel@tonic-gate svp->sv_pathlen = (int)(strlen(root_path) + 1); 30377c478bd9Sstevel@tonic-gate svp->sv_path = kmem_alloc(svp->sv_pathlen, KM_SLEEP); 30387c478bd9Sstevel@tonic-gate (void) strcpy(svp->sv_path, root_path); 30397c478bd9Sstevel@tonic-gate 30407c478bd9Sstevel@tonic-gate /* 30417c478bd9Sstevel@tonic-gate * Force root partition to always be mounted with AUTH_UNIX for now 30427c478bd9Sstevel@tonic-gate */ 30437c478bd9Sstevel@tonic-gate svp->sv_secdata = kmem_alloc(sizeof (*svp->sv_secdata), KM_SLEEP); 30447c478bd9Sstevel@tonic-gate svp->sv_secdata->secmod = AUTH_UNIX; 30457c478bd9Sstevel@tonic-gate svp->sv_secdata->rpcflavor = AUTH_UNIX; 30467c478bd9Sstevel@tonic-gate svp->sv_secdata->data = NULL; 30477c478bd9Sstevel@tonic-gate 30487c478bd9Sstevel@tonic-gate cr = crgetcred(); 30497c478bd9Sstevel@tonic-gate rtvp = NULL; 30507c478bd9Sstevel@tonic-gate 30517c478bd9Sstevel@tonic-gate error = nfs4rootvp(&rtvp, vfsp, svp, args.flags, cr, global_zone); 30527c478bd9Sstevel@tonic-gate 30537c478bd9Sstevel@tonic-gate if (error) { 30547c478bd9Sstevel@tonic-gate crfree(cr); 30557c478bd9Sstevel@tonic-gate pn_free(&pn); 3056ab7762b6Smaheshvs sv4_free(svp); 3057ab7762b6Smaheshvs return (error); 30587c478bd9Sstevel@tonic-gate } 30597c478bd9Sstevel@tonic-gate 30607c478bd9Sstevel@tonic-gate mi = VTOMI4(rtvp); 30617c478bd9Sstevel@tonic-gate 30627c478bd9Sstevel@tonic-gate /* 30637c478bd9Sstevel@tonic-gate * Send client id to the server, if necessary 30647c478bd9Sstevel@tonic-gate */ 30657c478bd9Sstevel@tonic-gate nfs4_error_zinit(&n4e); 30667c478bd9Sstevel@tonic-gate nfs4setclientid(mi, cr, FALSE, &n4e); 30677c478bd9Sstevel@tonic-gate error = n4e.error; 30687c478bd9Sstevel@tonic-gate 30697c478bd9Sstevel@tonic-gate crfree(cr); 30707c478bd9Sstevel@tonic-gate 30717c478bd9Sstevel@tonic-gate if (error) { 30727c478bd9Sstevel@tonic-gate pn_free(&pn); 30737c478bd9Sstevel@tonic-gate goto errout; 30747c478bd9Sstevel@tonic-gate } 30757c478bd9Sstevel@tonic-gate 30767c478bd9Sstevel@tonic-gate error = nfs4_setopts(rtvp, DATAMODEL_NATIVE, &args); 30777c478bd9Sstevel@tonic-gate if (error) { 30787c478bd9Sstevel@tonic-gate nfs_cmn_err(error, CE_WARN, 30797c478bd9Sstevel@tonic-gate "nfs4_mountroot: invalid root mount options"); 30807c478bd9Sstevel@tonic-gate pn_free(&pn); 30817c478bd9Sstevel@tonic-gate goto errout; 30827c478bd9Sstevel@tonic-gate } 30837c478bd9Sstevel@tonic-gate 30847c478bd9Sstevel@tonic-gate (void) vfs_lock_wait(vfsp); 30857c478bd9Sstevel@tonic-gate vfs_add(NULL, vfsp, vfsflags); 30867c478bd9Sstevel@tonic-gate vfs_unlock(vfsp); 30877c478bd9Sstevel@tonic-gate 30887c478bd9Sstevel@tonic-gate size = strlen(svp->sv_hostname); 30897c478bd9Sstevel@tonic-gate (void) strcpy(rootfs.bo_name, svp->sv_hostname); 30907c478bd9Sstevel@tonic-gate rootfs.bo_name[size] = ':'; 30917c478bd9Sstevel@tonic-gate (void) strcpy(&rootfs.bo_name[size + 1], root_path); 30927c478bd9Sstevel@tonic-gate 30937c478bd9Sstevel@tonic-gate pn_free(&pn); 30947c478bd9Sstevel@tonic-gate 30957c478bd9Sstevel@tonic-gate errout: 30967c478bd9Sstevel@tonic-gate if (error) { 30977c478bd9Sstevel@tonic-gate sv4_free(svp); 30987c478bd9Sstevel@tonic-gate nfs4_async_stop(vfsp); 30997c478bd9Sstevel@tonic-gate nfs4_async_manager_stop(vfsp); 31007c478bd9Sstevel@tonic-gate } 31017c478bd9Sstevel@tonic-gate 31027c478bd9Sstevel@tonic-gate if (rtvp != NULL) 31037c478bd9Sstevel@tonic-gate VN_RELE(rtvp); 31047c478bd9Sstevel@tonic-gate 31057c478bd9Sstevel@tonic-gate return (error); 31067c478bd9Sstevel@tonic-gate } 31077c478bd9Sstevel@tonic-gate 31087c478bd9Sstevel@tonic-gate /* 31097c478bd9Sstevel@tonic-gate * Initialization routine for VFS routines. Should only be called once 31107c478bd9Sstevel@tonic-gate */ 31117c478bd9Sstevel@tonic-gate int 31127c478bd9Sstevel@tonic-gate nfs4_vfsinit(void) 31137c478bd9Sstevel@tonic-gate { 31147c478bd9Sstevel@tonic-gate mutex_init(&nfs4_syncbusy, NULL, MUTEX_DEFAULT, NULL); 31157c478bd9Sstevel@tonic-gate nfs4setclientid_init(); 3116b9238976Sth199096 nfs4_ephemeral_init(); 31177c478bd9Sstevel@tonic-gate return (0); 31187c478bd9Sstevel@tonic-gate } 31197c478bd9Sstevel@tonic-gate 31207c478bd9Sstevel@tonic-gate void 31217c478bd9Sstevel@tonic-gate nfs4_vfsfini(void) 31227c478bd9Sstevel@tonic-gate { 3123b9238976Sth199096 nfs4_ephemeral_fini(); 31247c478bd9Sstevel@tonic-gate nfs4setclientid_fini(); 31257c478bd9Sstevel@tonic-gate mutex_destroy(&nfs4_syncbusy); 31267c478bd9Sstevel@tonic-gate } 31277c478bd9Sstevel@tonic-gate 31287c478bd9Sstevel@tonic-gate void 31297c478bd9Sstevel@tonic-gate nfs4_freevfs(vfs_t *vfsp) 31307c478bd9Sstevel@tonic-gate { 31317c478bd9Sstevel@tonic-gate mntinfo4_t *mi; 31327c478bd9Sstevel@tonic-gate 313350a83466Sjwahlig /* need to release the initial hold */ 31347c478bd9Sstevel@tonic-gate mi = VFTOMI4(vfsp); 3135b87f76edSThomas Haynes 3136b87f76edSThomas Haynes /* 3137b87f76edSThomas Haynes * At this point, we can no longer reference the vfs 3138b87f76edSThomas Haynes * and need to inform other holders of the reference 3139b87f76edSThomas Haynes * to the mntinfo4_t. 3140b87f76edSThomas Haynes */ 3141b87f76edSThomas Haynes mi->mi_vfsp = NULL; 3142b87f76edSThomas Haynes 314350a83466Sjwahlig MI4_RELE(mi); 31447c478bd9Sstevel@tonic-gate } 31457c478bd9Sstevel@tonic-gate 31467c478bd9Sstevel@tonic-gate /* 31477c478bd9Sstevel@tonic-gate * Client side SETCLIENTID and SETCLIENTID_CONFIRM 31487c478bd9Sstevel@tonic-gate */ 31497c478bd9Sstevel@tonic-gate struct nfs4_server nfs4_server_lst = 31507c478bd9Sstevel@tonic-gate { &nfs4_server_lst, &nfs4_server_lst }; 31517c478bd9Sstevel@tonic-gate 31527c478bd9Sstevel@tonic-gate kmutex_t nfs4_server_lst_lock; 31537c478bd9Sstevel@tonic-gate 31547c478bd9Sstevel@tonic-gate static void 31557c478bd9Sstevel@tonic-gate nfs4setclientid_init(void) 31567c478bd9Sstevel@tonic-gate { 31577c478bd9Sstevel@tonic-gate mutex_init(&nfs4_server_lst_lock, NULL, MUTEX_DEFAULT, NULL); 31587c478bd9Sstevel@tonic-gate } 31597c478bd9Sstevel@tonic-gate 31607c478bd9Sstevel@tonic-gate static void 31617c478bd9Sstevel@tonic-gate nfs4setclientid_fini(void) 31627c478bd9Sstevel@tonic-gate { 31637c478bd9Sstevel@tonic-gate mutex_destroy(&nfs4_server_lst_lock); 31647c478bd9Sstevel@tonic-gate } 31657c478bd9Sstevel@tonic-gate 31667c478bd9Sstevel@tonic-gate int nfs4_retry_sclid_delay = NFS4_RETRY_SCLID_DELAY; 31677c478bd9Sstevel@tonic-gate int nfs4_num_sclid_retries = NFS4_NUM_SCLID_RETRIES; 31687c478bd9Sstevel@tonic-gate 31697c478bd9Sstevel@tonic-gate /* 31707c478bd9Sstevel@tonic-gate * Set the clientid for the server for "mi". No-op if the clientid is 31717c478bd9Sstevel@tonic-gate * already set. 31727c478bd9Sstevel@tonic-gate * 31737c478bd9Sstevel@tonic-gate * The recovery boolean should be set to TRUE if this function was called 3174a092743bSek110237 * by the recovery code, and FALSE otherwise. This is used to determine 3175a092743bSek110237 * if we need to call nfs4_start/end_op as well as grab the mi_recovlock 3176a092743bSek110237 * for adding a mntinfo4_t to a nfs4_server_t. 31777c478bd9Sstevel@tonic-gate * 31787c478bd9Sstevel@tonic-gate * Error is returned via 'n4ep'. If there was a 'n4ep->stat' error, then 31797c478bd9Sstevel@tonic-gate * 'n4ep->error' is set to geterrno4(n4ep->stat). 31807c478bd9Sstevel@tonic-gate */ 31817c478bd9Sstevel@tonic-gate void 31827c478bd9Sstevel@tonic-gate nfs4setclientid(mntinfo4_t *mi, cred_t *cr, bool_t recovery, nfs4_error_t *n4ep) 31837c478bd9Sstevel@tonic-gate { 31847c478bd9Sstevel@tonic-gate struct nfs4_server *np; 31857c478bd9Sstevel@tonic-gate struct servinfo4 *svp = mi->mi_curr_serv; 31867c478bd9Sstevel@tonic-gate nfs4_recov_state_t recov_state; 31877c478bd9Sstevel@tonic-gate int num_retries = 0; 3188f64c4ae1Sdm120769 bool_t retry; 31897c478bd9Sstevel@tonic-gate cred_t *lcr = NULL; 31907c478bd9Sstevel@tonic-gate int retry_inuse = 1; /* only retry once on NFS4ERR_CLID_INUSE */ 31917c478bd9Sstevel@tonic-gate time_t lease_time = 0; 31927c478bd9Sstevel@tonic-gate 31937c478bd9Sstevel@tonic-gate recov_state.rs_flags = 0; 31947c478bd9Sstevel@tonic-gate recov_state.rs_num_retry_despite_err = 0; 31957c478bd9Sstevel@tonic-gate ASSERT(n4ep != NULL); 31967c478bd9Sstevel@tonic-gate 31977c478bd9Sstevel@tonic-gate recov_retry: 3198f64c4ae1Sdm120769 retry = FALSE; 31997c478bd9Sstevel@tonic-gate nfs4_error_zinit(n4ep); 3200a092743bSek110237 if (!recovery) 3201a092743bSek110237 (void) nfs_rw_enter_sig(&mi->mi_recovlock, RW_READER, 0); 3202a092743bSek110237 3203f86c6ccaSdm120769 mutex_enter(&nfs4_server_lst_lock); 3204f86c6ccaSdm120769 np = servinfo4_to_nfs4_server(svp); /* This locks np if it is found */ 3205f86c6ccaSdm120769 mutex_exit(&nfs4_server_lst_lock); 3206f86c6ccaSdm120769 if (!np) { 3207f86c6ccaSdm120769 struct nfs4_server *tnp; 3208f86c6ccaSdm120769 np = new_nfs4_server(svp, cr); 320916237317Sdm120769 mutex_enter(&np->s_lock); 32107c478bd9Sstevel@tonic-gate 3211f86c6ccaSdm120769 mutex_enter(&nfs4_server_lst_lock); 3212f86c6ccaSdm120769 tnp = servinfo4_to_nfs4_server(svp); 3213f86c6ccaSdm120769 if (tnp) { 32147c478bd9Sstevel@tonic-gate /* 3215f86c6ccaSdm120769 * another thread snuck in and put server on list. 3216f86c6ccaSdm120769 * since we aren't adding it to the nfs4_server_list 3217f86c6ccaSdm120769 * we need to set the ref count to 0 and destroy it. 32187c478bd9Sstevel@tonic-gate */ 3219f86c6ccaSdm120769 np->s_refcnt = 0; 3220f86c6ccaSdm120769 destroy_nfs4_server(np); 3221f86c6ccaSdm120769 np = tnp; 3222f86c6ccaSdm120769 } else { 32237c478bd9Sstevel@tonic-gate /* 3224f86c6ccaSdm120769 * do not give list a reference until everything 3225f86c6ccaSdm120769 * succeeds 32267c478bd9Sstevel@tonic-gate */ 3227f86c6ccaSdm120769 insque(np, &nfs4_server_lst); 3228f86c6ccaSdm120769 } 3229f86c6ccaSdm120769 mutex_exit(&nfs4_server_lst_lock); 3230f86c6ccaSdm120769 } 3231f86c6ccaSdm120769 ASSERT(MUTEX_HELD(&np->s_lock)); 3232f86c6ccaSdm120769 /* 3233f86c6ccaSdm120769 * If we find the server already has N4S_CLIENTID_SET, then 3234f86c6ccaSdm120769 * just return, we've already done SETCLIENTID to that server 3235f86c6ccaSdm120769 */ 3236f86c6ccaSdm120769 if (np->s_flags & N4S_CLIENTID_SET) { 32377c478bd9Sstevel@tonic-gate /* add mi to np's mntinfo4_list */ 32387c478bd9Sstevel@tonic-gate nfs4_add_mi_to_server(np, mi); 3239a092743bSek110237 if (!recovery) 3240a092743bSek110237 nfs_rw_exit(&mi->mi_recovlock); 32417c478bd9Sstevel@tonic-gate mutex_exit(&np->s_lock); 32427c478bd9Sstevel@tonic-gate nfs4_server_rele(np); 32437c478bd9Sstevel@tonic-gate return; 32447c478bd9Sstevel@tonic-gate } 3245f86c6ccaSdm120769 mutex_exit(&np->s_lock); 3246f86c6ccaSdm120769 32477c478bd9Sstevel@tonic-gate 3248a092743bSek110237 /* 3249a092743bSek110237 * Drop the mi_recovlock since nfs4_start_op will 3250a092743bSek110237 * acquire it again for us. 3251a092743bSek110237 */ 3252f86c6ccaSdm120769 if (!recovery) { 3253a092743bSek110237 nfs_rw_exit(&mi->mi_recovlock); 3254a092743bSek110237 32557c478bd9Sstevel@tonic-gate n4ep->error = nfs4_start_op(mi, NULL, NULL, &recov_state); 32567c478bd9Sstevel@tonic-gate if (n4ep->error) { 32577c478bd9Sstevel@tonic-gate nfs4_server_rele(np); 32587c478bd9Sstevel@tonic-gate return; 32597c478bd9Sstevel@tonic-gate } 32607c478bd9Sstevel@tonic-gate } 32617c478bd9Sstevel@tonic-gate 32627c478bd9Sstevel@tonic-gate mutex_enter(&np->s_lock); 3263f86c6ccaSdm120769 while (np->s_flags & N4S_CLIENTID_PEND) { 3264f86c6ccaSdm120769 if (!cv_wait_sig(&np->s_clientid_pend, &np->s_lock)) { 3265f86c6ccaSdm120769 mutex_exit(&np->s_lock); 3266f86c6ccaSdm120769 nfs4_server_rele(np); 3267f86c6ccaSdm120769 if (!recovery) 3268f86c6ccaSdm120769 nfs4_end_op(mi, NULL, NULL, &recov_state, 3269f86c6ccaSdm120769 recovery); 3270f86c6ccaSdm120769 n4ep->error = EINTR; 3271f86c6ccaSdm120769 return; 3272f86c6ccaSdm120769 } 3273f86c6ccaSdm120769 } 3274f86c6ccaSdm120769 3275f86c6ccaSdm120769 if (np->s_flags & N4S_CLIENTID_SET) { 3276f86c6ccaSdm120769 /* XXX copied/pasted from above */ 3277f86c6ccaSdm120769 /* add mi to np's mntinfo4_list */ 3278f86c6ccaSdm120769 nfs4_add_mi_to_server(np, mi); 3279f86c6ccaSdm120769 mutex_exit(&np->s_lock); 3280f86c6ccaSdm120769 nfs4_server_rele(np); 3281f86c6ccaSdm120769 if (!recovery) 3282f86c6ccaSdm120769 nfs4_end_op(mi, NULL, NULL, &recov_state, recovery); 3283f86c6ccaSdm120769 return; 3284f86c6ccaSdm120769 } 32857c478bd9Sstevel@tonic-gate 32867c478bd9Sstevel@tonic-gate /* 32877c478bd9Sstevel@tonic-gate * Reset the N4S_CB_PINGED flag. This is used to 32887c478bd9Sstevel@tonic-gate * indicate if we have received a CB_NULL from the 32897c478bd9Sstevel@tonic-gate * server. Also we reset the waiter flag. 32907c478bd9Sstevel@tonic-gate */ 32917c478bd9Sstevel@tonic-gate np->s_flags &= ~(N4S_CB_PINGED | N4S_CB_WAITER); 3292f86c6ccaSdm120769 /* any failure must now clear this flag */ 3293f86c6ccaSdm120769 np->s_flags |= N4S_CLIENTID_PEND; 32947c478bd9Sstevel@tonic-gate mutex_exit(&np->s_lock); 32957c478bd9Sstevel@tonic-gate nfs4setclientid_otw(mi, svp, cr, np, n4ep, &retry_inuse); 32967c478bd9Sstevel@tonic-gate 32977c478bd9Sstevel@tonic-gate if (n4ep->error == EACCES) { 32987c478bd9Sstevel@tonic-gate /* 32997c478bd9Sstevel@tonic-gate * If the uid is set then set the creds for secure mounts 33007c478bd9Sstevel@tonic-gate * by proxy processes such as automountd. 33017c478bd9Sstevel@tonic-gate */ 33027c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); 33037c478bd9Sstevel@tonic-gate if (svp->sv_secdata->uid != 0) { 33047c478bd9Sstevel@tonic-gate lcr = crdup(cr); 33057c478bd9Sstevel@tonic-gate (void) crsetugid(lcr, svp->sv_secdata->uid, 33067c478bd9Sstevel@tonic-gate crgetgid(cr)); 33077c478bd9Sstevel@tonic-gate } 33087c478bd9Sstevel@tonic-gate nfs_rw_exit(&svp->sv_lock); 33097c478bd9Sstevel@tonic-gate 3310f86c6ccaSdm120769 if (lcr != NULL) { 3311f86c6ccaSdm120769 mutex_enter(&np->s_lock); 3312f86c6ccaSdm120769 crfree(np->s_cred); 3313f86c6ccaSdm120769 np->s_cred = lcr; 3314f86c6ccaSdm120769 mutex_exit(&np->s_lock); 33157c478bd9Sstevel@tonic-gate nfs4setclientid_otw(mi, svp, lcr, np, n4ep, 33167c478bd9Sstevel@tonic-gate &retry_inuse); 33177c478bd9Sstevel@tonic-gate } 3318f86c6ccaSdm120769 } 3319f86c6ccaSdm120769 mutex_enter(&np->s_lock); 33207c478bd9Sstevel@tonic-gate lease_time = np->s_lease_time; 3321f86c6ccaSdm120769 np->s_flags &= ~N4S_CLIENTID_PEND; 33227c478bd9Sstevel@tonic-gate mutex_exit(&np->s_lock); 33237c478bd9Sstevel@tonic-gate 33247c478bd9Sstevel@tonic-gate if (n4ep->error != 0 || n4ep->stat != NFS4_OK) { 33257c478bd9Sstevel@tonic-gate /* 33267c478bd9Sstevel@tonic-gate * Start recovery if failover is a possibility. If 33277c478bd9Sstevel@tonic-gate * invoked by the recovery thread itself, then just 33287c478bd9Sstevel@tonic-gate * return and let it handle the failover first. NB: 33297c478bd9Sstevel@tonic-gate * recovery is not allowed if the mount is in progress 33307c478bd9Sstevel@tonic-gate * since the infrastructure is not sufficiently setup 33317c478bd9Sstevel@tonic-gate * to allow it. Just return the error (after suitable 33327c478bd9Sstevel@tonic-gate * retries). 33337c478bd9Sstevel@tonic-gate */ 33347c478bd9Sstevel@tonic-gate if (FAILOVER_MOUNT4(mi) && nfs4_try_failover(n4ep)) { 33357c478bd9Sstevel@tonic-gate (void) nfs4_start_recovery(n4ep, mi, NULL, 33362f172c55SRobert Thurlow NULL, NULL, NULL, OP_SETCLIENTID, NULL, NULL, NULL); 33377c478bd9Sstevel@tonic-gate /* 33387c478bd9Sstevel@tonic-gate * Don't retry here, just return and let 33397c478bd9Sstevel@tonic-gate * recovery take over. 33407c478bd9Sstevel@tonic-gate */ 33417c478bd9Sstevel@tonic-gate if (recovery) 33427c478bd9Sstevel@tonic-gate retry = FALSE; 33437c478bd9Sstevel@tonic-gate } else if (nfs4_rpc_retry_error(n4ep->error) || 33447c478bd9Sstevel@tonic-gate n4ep->stat == NFS4ERR_RESOURCE || 33457c478bd9Sstevel@tonic-gate n4ep->stat == NFS4ERR_STALE_CLIENTID) { 33467c478bd9Sstevel@tonic-gate 33477c478bd9Sstevel@tonic-gate retry = TRUE; 33487c478bd9Sstevel@tonic-gate /* 33497c478bd9Sstevel@tonic-gate * Always retry if in recovery or once had 33507c478bd9Sstevel@tonic-gate * contact with the server (but now it's 33517c478bd9Sstevel@tonic-gate * overloaded). 33527c478bd9Sstevel@tonic-gate */ 33537c478bd9Sstevel@tonic-gate if (recovery == TRUE || 33547c478bd9Sstevel@tonic-gate n4ep->error == ETIMEDOUT || 33557c478bd9Sstevel@tonic-gate n4ep->error == ECONNRESET) 33567c478bd9Sstevel@tonic-gate num_retries = 0; 33577c478bd9Sstevel@tonic-gate } else if (retry_inuse && n4ep->error == 0 && 33587c478bd9Sstevel@tonic-gate n4ep->stat == NFS4ERR_CLID_INUSE) { 33597c478bd9Sstevel@tonic-gate retry = TRUE; 33607c478bd9Sstevel@tonic-gate num_retries = 0; 33617c478bd9Sstevel@tonic-gate } 3362f86c6ccaSdm120769 } else { 3363f64c4ae1Sdm120769 /* 3364f64c4ae1Sdm120769 * Since everything succeeded give the list a reference count if 3365f64c4ae1Sdm120769 * it hasn't been given one by add_new_nfs4_server() or if this 3366f64c4ae1Sdm120769 * is not a recovery situation in which case it is already on 3367f64c4ae1Sdm120769 * the list. 3368f64c4ae1Sdm120769 */ 3369f86c6ccaSdm120769 mutex_enter(&np->s_lock); 3370f64c4ae1Sdm120769 if ((np->s_flags & N4S_INSERTED) == 0) { 3371f86c6ccaSdm120769 np->s_refcnt++; 3372f64c4ae1Sdm120769 np->s_flags |= N4S_INSERTED; 3373f64c4ae1Sdm120769 } 3374f86c6ccaSdm120769 mutex_exit(&np->s_lock); 33757c478bd9Sstevel@tonic-gate } 33767c478bd9Sstevel@tonic-gate 33777c478bd9Sstevel@tonic-gate if (!recovery) 33787c478bd9Sstevel@tonic-gate nfs4_end_op(mi, NULL, NULL, &recov_state, recovery); 3379f86c6ccaSdm120769 33807c478bd9Sstevel@tonic-gate 33817c478bd9Sstevel@tonic-gate if (retry && num_retries++ < nfs4_num_sclid_retries) { 33827c478bd9Sstevel@tonic-gate if (retry_inuse) { 33837c478bd9Sstevel@tonic-gate delay(SEC_TO_TICK(lease_time + nfs4_retry_sclid_delay)); 33847c478bd9Sstevel@tonic-gate retry_inuse = 0; 33857c478bd9Sstevel@tonic-gate } else 33867c478bd9Sstevel@tonic-gate delay(SEC_TO_TICK(nfs4_retry_sclid_delay)); 3387f86c6ccaSdm120769 3388f86c6ccaSdm120769 nfs4_server_rele(np); 33897c478bd9Sstevel@tonic-gate goto recov_retry; 33907c478bd9Sstevel@tonic-gate } 33917c478bd9Sstevel@tonic-gate 3392f86c6ccaSdm120769 33937c478bd9Sstevel@tonic-gate if (n4ep->error == 0) 33947c478bd9Sstevel@tonic-gate n4ep->error = geterrno4(n4ep->stat); 3395f86c6ccaSdm120769 3396f86c6ccaSdm120769 /* broadcast before release in case no other threads are waiting */ 3397f86c6ccaSdm120769 cv_broadcast(&np->s_clientid_pend); 3398f86c6ccaSdm120769 nfs4_server_rele(np); 33997c478bd9Sstevel@tonic-gate } 34007c478bd9Sstevel@tonic-gate 34017c478bd9Sstevel@tonic-gate int nfs4setclientid_otw_debug = 0; 34027c478bd9Sstevel@tonic-gate 34037c478bd9Sstevel@tonic-gate /* 34047c478bd9Sstevel@tonic-gate * This function handles the recovery of STALE_CLIENTID for SETCLIENTID_CONFRIM, 34057c478bd9Sstevel@tonic-gate * but nothing else; the calling function must be designed to handle those 34067c478bd9Sstevel@tonic-gate * other errors. 34077c478bd9Sstevel@tonic-gate */ 34087c478bd9Sstevel@tonic-gate static void 34097c478bd9Sstevel@tonic-gate nfs4setclientid_otw(mntinfo4_t *mi, struct servinfo4 *svp, cred_t *cr, 34107c478bd9Sstevel@tonic-gate struct nfs4_server *np, nfs4_error_t *ep, int *retry_inusep) 34117c478bd9Sstevel@tonic-gate { 34127c478bd9Sstevel@tonic-gate COMPOUND4args_clnt args; 34137c478bd9Sstevel@tonic-gate COMPOUND4res_clnt res; 34147c478bd9Sstevel@tonic-gate nfs_argop4 argop[3]; 34157c478bd9Sstevel@tonic-gate SETCLIENTID4args *s_args; 34167c478bd9Sstevel@tonic-gate SETCLIENTID4resok *s_resok; 34177c478bd9Sstevel@tonic-gate int doqueue = 1; 34187c478bd9Sstevel@tonic-gate nfs4_ga_res_t *garp = NULL; 34197c478bd9Sstevel@tonic-gate timespec_t prop_time, after_time; 34207c478bd9Sstevel@tonic-gate verifier4 verf; 34217c478bd9Sstevel@tonic-gate clientid4 tmp_clientid; 34227c478bd9Sstevel@tonic-gate 3423f86c6ccaSdm120769 ASSERT(!MUTEX_HELD(&np->s_lock)); 34247c478bd9Sstevel@tonic-gate 34257c478bd9Sstevel@tonic-gate args.ctag = TAG_SETCLIENTID; 34267c478bd9Sstevel@tonic-gate 34277c478bd9Sstevel@tonic-gate args.array = argop; 34287c478bd9Sstevel@tonic-gate args.array_len = 3; 34297c478bd9Sstevel@tonic-gate 34307c478bd9Sstevel@tonic-gate /* PUTROOTFH */ 34317c478bd9Sstevel@tonic-gate argop[0].argop = OP_PUTROOTFH; 34327c478bd9Sstevel@tonic-gate 34337c478bd9Sstevel@tonic-gate /* GETATTR */ 34347c478bd9Sstevel@tonic-gate argop[1].argop = OP_GETATTR; 34357c478bd9Sstevel@tonic-gate argop[1].nfs_argop4_u.opgetattr.attr_request = FATTR4_LEASE_TIME_MASK; 34367c478bd9Sstevel@tonic-gate argop[1].nfs_argop4_u.opgetattr.mi = mi; 34377c478bd9Sstevel@tonic-gate 34387c478bd9Sstevel@tonic-gate /* SETCLIENTID */ 34397c478bd9Sstevel@tonic-gate argop[2].argop = OP_SETCLIENTID; 34407c478bd9Sstevel@tonic-gate 34417c478bd9Sstevel@tonic-gate s_args = &argop[2].nfs_argop4_u.opsetclientid; 34427c478bd9Sstevel@tonic-gate 3443f86c6ccaSdm120769 mutex_enter(&np->s_lock); 3444f86c6ccaSdm120769 34457c478bd9Sstevel@tonic-gate s_args->client.verifier = np->clidtosend.verifier; 34467c478bd9Sstevel@tonic-gate s_args->client.id_len = np->clidtosend.id_len; 34477c478bd9Sstevel@tonic-gate ASSERT(s_args->client.id_len <= NFS4_OPAQUE_LIMIT); 34487c478bd9Sstevel@tonic-gate s_args->client.id_val = np->clidtosend.id_val; 34497c478bd9Sstevel@tonic-gate 34507c478bd9Sstevel@tonic-gate /* 34517c478bd9Sstevel@tonic-gate * Callback needs to happen on non-RDMA transport 34527c478bd9Sstevel@tonic-gate * Check if we have saved the original knetconfig 34537c478bd9Sstevel@tonic-gate * if so, use that instead. 34547c478bd9Sstevel@tonic-gate */ 34557c478bd9Sstevel@tonic-gate if (svp->sv_origknconf != NULL) 34567c478bd9Sstevel@tonic-gate nfs4_cb_args(np, svp->sv_origknconf, s_args); 34577c478bd9Sstevel@tonic-gate else 34587c478bd9Sstevel@tonic-gate nfs4_cb_args(np, svp->sv_knconf, s_args); 34597c478bd9Sstevel@tonic-gate 3460f86c6ccaSdm120769 mutex_exit(&np->s_lock); 3461f86c6ccaSdm120769 3462f86c6ccaSdm120769 rfs4call(mi, &args, &res, cr, &doqueue, 0, ep); 34637c478bd9Sstevel@tonic-gate 34647c478bd9Sstevel@tonic-gate if (ep->error) 34657c478bd9Sstevel@tonic-gate return; 34667c478bd9Sstevel@tonic-gate 34677c478bd9Sstevel@tonic-gate /* getattr lease_time res */ 3468e557fb2cSDai Ngo if ((res.array_len >= 2) && 3469e557fb2cSDai Ngo (res.array[1].nfs_resop4_u.opgetattr.status == NFS4_OK)) { 34707c478bd9Sstevel@tonic-gate garp = &res.array[1].nfs_resop4_u.opgetattr.ga_res; 34717c478bd9Sstevel@tonic-gate 34727c478bd9Sstevel@tonic-gate #ifndef _LP64 34737c478bd9Sstevel@tonic-gate /* 34747c478bd9Sstevel@tonic-gate * The 32 bit client cannot handle a lease time greater than 34757c478bd9Sstevel@tonic-gate * (INT32_MAX/1000000). This is due to the use of the 34767c478bd9Sstevel@tonic-gate * lease_time in calls to drv_usectohz() in 34777c478bd9Sstevel@tonic-gate * nfs4_renew_lease_thread(). The problem is that 34787c478bd9Sstevel@tonic-gate * drv_usectohz() takes a time_t (which is just a long = 4 34797c478bd9Sstevel@tonic-gate * bytes) as its parameter. The lease_time is multiplied by 34807c478bd9Sstevel@tonic-gate * 1000000 to convert seconds to usecs for the parameter. If 34817c478bd9Sstevel@tonic-gate * a number bigger than (INT32_MAX/1000000) is used then we 34827c478bd9Sstevel@tonic-gate * overflow on the 32bit client. 34837c478bd9Sstevel@tonic-gate */ 34847c478bd9Sstevel@tonic-gate if (garp->n4g_ext_res->n4g_leasetime > (INT32_MAX/1000000)) { 34857c478bd9Sstevel@tonic-gate garp->n4g_ext_res->n4g_leasetime = INT32_MAX/1000000; 34867c478bd9Sstevel@tonic-gate } 34877c478bd9Sstevel@tonic-gate #endif 34887c478bd9Sstevel@tonic-gate 3489f86c6ccaSdm120769 mutex_enter(&np->s_lock); 34907c478bd9Sstevel@tonic-gate np->s_lease_time = garp->n4g_ext_res->n4g_leasetime; 34917c478bd9Sstevel@tonic-gate 34927c478bd9Sstevel@tonic-gate /* 34937c478bd9Sstevel@tonic-gate * Keep track of the lease period for the mi's 34947c478bd9Sstevel@tonic-gate * mi_msg_list. We need an appropiate time 34957c478bd9Sstevel@tonic-gate * bound to associate past facts with a current 34967c478bd9Sstevel@tonic-gate * event. The lease period is perfect for this. 34977c478bd9Sstevel@tonic-gate */ 34987c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_msg_list_lock); 34997c478bd9Sstevel@tonic-gate mi->mi_lease_period = np->s_lease_time; 35007c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_msg_list_lock); 3501f86c6ccaSdm120769 mutex_exit(&np->s_lock); 35027c478bd9Sstevel@tonic-gate } 35037c478bd9Sstevel@tonic-gate 35047c478bd9Sstevel@tonic-gate 35057c478bd9Sstevel@tonic-gate if (res.status == NFS4ERR_CLID_INUSE) { 35067c478bd9Sstevel@tonic-gate clientaddr4 *clid_inuse; 35077c478bd9Sstevel@tonic-gate 35087c478bd9Sstevel@tonic-gate if (!(*retry_inusep)) { 35097c478bd9Sstevel@tonic-gate clid_inuse = &res.array->nfs_resop4_u. 35107c478bd9Sstevel@tonic-gate opsetclientid.SETCLIENTID4res_u.client_using; 35117c478bd9Sstevel@tonic-gate 35127c478bd9Sstevel@tonic-gate zcmn_err(mi->mi_zone->zone_id, CE_NOTE, 35137c478bd9Sstevel@tonic-gate "NFS4 mount (SETCLIENTID failed)." 35147c478bd9Sstevel@tonic-gate " nfs4_client_id.id is in" 35157c478bd9Sstevel@tonic-gate "use already by: r_netid<%s> r_addr<%s>", 35167c478bd9Sstevel@tonic-gate clid_inuse->r_netid, clid_inuse->r_addr); 35177c478bd9Sstevel@tonic-gate } 35187c478bd9Sstevel@tonic-gate 35197c478bd9Sstevel@tonic-gate /* 35207c478bd9Sstevel@tonic-gate * XXX - The client should be more robust in its 35217c478bd9Sstevel@tonic-gate * handling of clientid in use errors (regen another 35227c478bd9Sstevel@tonic-gate * clientid and try again?) 35237c478bd9Sstevel@tonic-gate */ 35247c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 35257c478bd9Sstevel@tonic-gate return; 35267c478bd9Sstevel@tonic-gate } 35277c478bd9Sstevel@tonic-gate 35287c478bd9Sstevel@tonic-gate if (res.status) { 35297c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 35307c478bd9Sstevel@tonic-gate return; 35317c478bd9Sstevel@tonic-gate } 35327c478bd9Sstevel@tonic-gate 35337c478bd9Sstevel@tonic-gate s_resok = &res.array[2].nfs_resop4_u. 35347c478bd9Sstevel@tonic-gate opsetclientid.SETCLIENTID4res_u.resok4; 35357c478bd9Sstevel@tonic-gate 35367c478bd9Sstevel@tonic-gate tmp_clientid = s_resok->clientid; 35377c478bd9Sstevel@tonic-gate 35387c478bd9Sstevel@tonic-gate verf = s_resok->setclientid_confirm; 35397c478bd9Sstevel@tonic-gate 35407c478bd9Sstevel@tonic-gate #ifdef DEBUG 35417c478bd9Sstevel@tonic-gate if (nfs4setclientid_otw_debug) { 35427c478bd9Sstevel@tonic-gate union { 35437c478bd9Sstevel@tonic-gate clientid4 clientid; 35447c478bd9Sstevel@tonic-gate int foo[2]; 35457c478bd9Sstevel@tonic-gate } cid; 35467c478bd9Sstevel@tonic-gate 35477c478bd9Sstevel@tonic-gate cid.clientid = s_resok->clientid; 35487c478bd9Sstevel@tonic-gate 35497c478bd9Sstevel@tonic-gate zcmn_err(mi->mi_zone->zone_id, CE_NOTE, 35507c478bd9Sstevel@tonic-gate "nfs4setclientid_otw: OK, clientid = %x,%x, " 35517c478bd9Sstevel@tonic-gate "verifier = %" PRIx64 "\n", cid.foo[0], cid.foo[1], verf); 35527c478bd9Sstevel@tonic-gate } 35537c478bd9Sstevel@tonic-gate #endif 35547c478bd9Sstevel@tonic-gate 35557c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 35567c478bd9Sstevel@tonic-gate 35577c478bd9Sstevel@tonic-gate /* Confirm the client id and get the lease_time attribute */ 35587c478bd9Sstevel@tonic-gate 35597c478bd9Sstevel@tonic-gate args.ctag = TAG_SETCLIENTID_CF; 35607c478bd9Sstevel@tonic-gate 35617c478bd9Sstevel@tonic-gate args.array = argop; 35627c478bd9Sstevel@tonic-gate args.array_len = 1; 35637c478bd9Sstevel@tonic-gate 35647c478bd9Sstevel@tonic-gate argop[0].argop = OP_SETCLIENTID_CONFIRM; 35657c478bd9Sstevel@tonic-gate 35667c478bd9Sstevel@tonic-gate argop[0].nfs_argop4_u.opsetclientid_confirm.clientid = tmp_clientid; 35677c478bd9Sstevel@tonic-gate argop[0].nfs_argop4_u.opsetclientid_confirm.setclientid_confirm = verf; 35687c478bd9Sstevel@tonic-gate 35697c478bd9Sstevel@tonic-gate /* used to figure out RTT for np */ 35707c478bd9Sstevel@tonic-gate gethrestime(&prop_time); 35717c478bd9Sstevel@tonic-gate 35727c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, "nfs4setlientid_otw: " 35737c478bd9Sstevel@tonic-gate "start time: %ld sec %ld nsec", prop_time.tv_sec, 35747c478bd9Sstevel@tonic-gate prop_time.tv_nsec)); 35757c478bd9Sstevel@tonic-gate 35767c478bd9Sstevel@tonic-gate rfs4call(mi, &args, &res, cr, &doqueue, 0, ep); 35777c478bd9Sstevel@tonic-gate 35787c478bd9Sstevel@tonic-gate gethrestime(&after_time); 3579f86c6ccaSdm120769 mutex_enter(&np->s_lock); 35807c478bd9Sstevel@tonic-gate np->propagation_delay.tv_sec = 35817c478bd9Sstevel@tonic-gate MAX(1, after_time.tv_sec - prop_time.tv_sec); 3582f86c6ccaSdm120769 mutex_exit(&np->s_lock); 35837c478bd9Sstevel@tonic-gate 35847c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, "nfs4setlcientid_otw: " 35857c478bd9Sstevel@tonic-gate "finish time: %ld sec ", after_time.tv_sec)); 35867c478bd9Sstevel@tonic-gate 35877c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, "nfs4setclientid_otw: " 35887c478bd9Sstevel@tonic-gate "propagation delay set to %ld sec", 35897c478bd9Sstevel@tonic-gate np->propagation_delay.tv_sec)); 35907c478bd9Sstevel@tonic-gate 35917c478bd9Sstevel@tonic-gate if (ep->error) 35927c478bd9Sstevel@tonic-gate return; 35937c478bd9Sstevel@tonic-gate 35947c478bd9Sstevel@tonic-gate if (res.status == NFS4ERR_CLID_INUSE) { 35957c478bd9Sstevel@tonic-gate clientaddr4 *clid_inuse; 35967c478bd9Sstevel@tonic-gate 35977c478bd9Sstevel@tonic-gate if (!(*retry_inusep)) { 35987c478bd9Sstevel@tonic-gate clid_inuse = &res.array->nfs_resop4_u. 35997c478bd9Sstevel@tonic-gate opsetclientid.SETCLIENTID4res_u.client_using; 36007c478bd9Sstevel@tonic-gate 36017c478bd9Sstevel@tonic-gate zcmn_err(mi->mi_zone->zone_id, CE_NOTE, 36027c478bd9Sstevel@tonic-gate "SETCLIENTID_CONFIRM failed. " 36037c478bd9Sstevel@tonic-gate "nfs4_client_id.id is in use already by: " 36047c478bd9Sstevel@tonic-gate "r_netid<%s> r_addr<%s>", 36057c478bd9Sstevel@tonic-gate clid_inuse->r_netid, clid_inuse->r_addr); 36067c478bd9Sstevel@tonic-gate } 36077c478bd9Sstevel@tonic-gate 36087c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 36097c478bd9Sstevel@tonic-gate return; 36107c478bd9Sstevel@tonic-gate } 36117c478bd9Sstevel@tonic-gate 36127c478bd9Sstevel@tonic-gate if (res.status) { 36137c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 36147c478bd9Sstevel@tonic-gate return; 36157c478bd9Sstevel@tonic-gate } 36167c478bd9Sstevel@tonic-gate 3617f86c6ccaSdm120769 mutex_enter(&np->s_lock); 36187c478bd9Sstevel@tonic-gate np->clientid = tmp_clientid; 36197c478bd9Sstevel@tonic-gate np->s_flags |= N4S_CLIENTID_SET; 36207c478bd9Sstevel@tonic-gate 36217c478bd9Sstevel@tonic-gate /* Add mi to np's mntinfo4 list */ 36227c478bd9Sstevel@tonic-gate nfs4_add_mi_to_server(np, mi); 36237c478bd9Sstevel@tonic-gate 36247c478bd9Sstevel@tonic-gate if (np->lease_valid == NFS4_LEASE_NOT_STARTED) { 36257c478bd9Sstevel@tonic-gate /* 36267c478bd9Sstevel@tonic-gate * Start lease management thread. 36277c478bd9Sstevel@tonic-gate * Keep trying until we succeed. 36287c478bd9Sstevel@tonic-gate */ 36297c478bd9Sstevel@tonic-gate 36307c478bd9Sstevel@tonic-gate np->s_refcnt++; /* pass reference to thread */ 36317c478bd9Sstevel@tonic-gate (void) zthread_create(NULL, 0, nfs4_renew_lease_thread, np, 0, 36327c478bd9Sstevel@tonic-gate minclsyspri); 36337c478bd9Sstevel@tonic-gate } 3634f86c6ccaSdm120769 mutex_exit(&np->s_lock); 36357c478bd9Sstevel@tonic-gate 36367c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); 36377c478bd9Sstevel@tonic-gate } 36387c478bd9Sstevel@tonic-gate 36397c478bd9Sstevel@tonic-gate /* 36407c478bd9Sstevel@tonic-gate * Add mi to sp's mntinfo4_list if it isn't already in the list. Makes 36417c478bd9Sstevel@tonic-gate * mi's clientid the same as sp's. 36427c478bd9Sstevel@tonic-gate * Assumes sp is locked down. 36437c478bd9Sstevel@tonic-gate */ 36447c478bd9Sstevel@tonic-gate void 36457c478bd9Sstevel@tonic-gate nfs4_add_mi_to_server(nfs4_server_t *sp, mntinfo4_t *mi) 36467c478bd9Sstevel@tonic-gate { 36477c478bd9Sstevel@tonic-gate mntinfo4_t *tmi; 36487c478bd9Sstevel@tonic-gate int in_list = 0; 36497c478bd9Sstevel@tonic-gate 3650a092743bSek110237 ASSERT(nfs_rw_lock_held(&mi->mi_recovlock, RW_READER) || 3651a092743bSek110237 nfs_rw_lock_held(&mi->mi_recovlock, RW_WRITER)); 36527c478bd9Sstevel@tonic-gate ASSERT(sp != &nfs4_server_lst); 36537c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sp->s_lock)); 36547c478bd9Sstevel@tonic-gate 36557c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, 36567c478bd9Sstevel@tonic-gate "nfs4_add_mi_to_server: add mi %p to sp %p", 36577c478bd9Sstevel@tonic-gate (void*)mi, (void*)sp)); 36587c478bd9Sstevel@tonic-gate 36597c478bd9Sstevel@tonic-gate for (tmi = sp->mntinfo4_list; 36607c478bd9Sstevel@tonic-gate tmi != NULL; 36617c478bd9Sstevel@tonic-gate tmi = tmi->mi_clientid_next) { 36627c478bd9Sstevel@tonic-gate if (tmi == mi) { 36637c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, 36647c478bd9Sstevel@tonic-gate (CE_NOTE, 36657c478bd9Sstevel@tonic-gate "nfs4_add_mi_to_server: mi in list")); 36667c478bd9Sstevel@tonic-gate in_list = 1; 36677c478bd9Sstevel@tonic-gate } 36687c478bd9Sstevel@tonic-gate } 36697c478bd9Sstevel@tonic-gate 36707c478bd9Sstevel@tonic-gate /* 36717c478bd9Sstevel@tonic-gate * First put a hold on the mntinfo4's vfsp so that references via 36727c478bd9Sstevel@tonic-gate * mntinfo4_list will be valid. 36737c478bd9Sstevel@tonic-gate */ 36747c478bd9Sstevel@tonic-gate if (!in_list) 36757c478bd9Sstevel@tonic-gate VFS_HOLD(mi->mi_vfsp); 36767c478bd9Sstevel@tonic-gate 36777c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, "nfs4_add_mi_to_server: " 36787c478bd9Sstevel@tonic-gate "hold vfs %p for mi: %p", (void*)mi->mi_vfsp, (void*)mi)); 36797c478bd9Sstevel@tonic-gate 36807c478bd9Sstevel@tonic-gate if (!in_list) { 36817c478bd9Sstevel@tonic-gate if (sp->mntinfo4_list) 36827c478bd9Sstevel@tonic-gate sp->mntinfo4_list->mi_clientid_prev = mi; 36837c478bd9Sstevel@tonic-gate mi->mi_clientid_next = sp->mntinfo4_list; 36843b895386SPavel Filipensky mi->mi_srv = sp; 36857c478bd9Sstevel@tonic-gate sp->mntinfo4_list = mi; 36867c478bd9Sstevel@tonic-gate mi->mi_srvsettime = gethrestime_sec(); 36873b895386SPavel Filipensky mi->mi_srvset_cnt++; 36887c478bd9Sstevel@tonic-gate } 36897c478bd9Sstevel@tonic-gate 36907c478bd9Sstevel@tonic-gate /* set mi's clientid to that of sp's for later matching */ 36917c478bd9Sstevel@tonic-gate mi->mi_clientid = sp->clientid; 36927c478bd9Sstevel@tonic-gate 36937c478bd9Sstevel@tonic-gate /* 36947c478bd9Sstevel@tonic-gate * Update the clientid for any other mi's belonging to sp. This 36957c478bd9Sstevel@tonic-gate * must be done here while we hold sp->s_lock, so that 36967c478bd9Sstevel@tonic-gate * find_nfs4_server() continues to work. 36977c478bd9Sstevel@tonic-gate */ 36987c478bd9Sstevel@tonic-gate 36997c478bd9Sstevel@tonic-gate for (tmi = sp->mntinfo4_list; 37007c478bd9Sstevel@tonic-gate tmi != NULL; 37017c478bd9Sstevel@tonic-gate tmi = tmi->mi_clientid_next) { 37027c478bd9Sstevel@tonic-gate if (tmi != mi) { 37037c478bd9Sstevel@tonic-gate tmi->mi_clientid = sp->clientid; 37047c478bd9Sstevel@tonic-gate } 37057c478bd9Sstevel@tonic-gate } 37067c478bd9Sstevel@tonic-gate } 37077c478bd9Sstevel@tonic-gate 37087c478bd9Sstevel@tonic-gate /* 37097c478bd9Sstevel@tonic-gate * Remove the mi from sp's mntinfo4_list and release its reference. 37107c478bd9Sstevel@tonic-gate * Exception: if mi still has open files, flag it for later removal (when 37117c478bd9Sstevel@tonic-gate * all the files are closed). 37127c478bd9Sstevel@tonic-gate * 37137c478bd9Sstevel@tonic-gate * If this is the last mntinfo4 in sp's list then tell the lease renewal 37147c478bd9Sstevel@tonic-gate * thread to exit. 37157c478bd9Sstevel@tonic-gate */ 37167c478bd9Sstevel@tonic-gate static void 37177c478bd9Sstevel@tonic-gate nfs4_remove_mi_from_server_nolock(mntinfo4_t *mi, nfs4_server_t *sp) 37187c478bd9Sstevel@tonic-gate { 37197c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, 37207c478bd9Sstevel@tonic-gate "nfs4_remove_mi_from_server_nolock: remove mi %p from sp %p", 37217c478bd9Sstevel@tonic-gate (void*)mi, (void*)sp)); 37227c478bd9Sstevel@tonic-gate 37237c478bd9Sstevel@tonic-gate ASSERT(sp != NULL); 37247c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sp->s_lock)); 37257c478bd9Sstevel@tonic-gate ASSERT(mi->mi_open_files >= 0); 37267c478bd9Sstevel@tonic-gate 37277c478bd9Sstevel@tonic-gate /* 37287c478bd9Sstevel@tonic-gate * First make sure this mntinfo4 can be taken off of the list, 37297c478bd9Sstevel@tonic-gate * ie: it doesn't have any open files remaining. 37307c478bd9Sstevel@tonic-gate */ 37317c478bd9Sstevel@tonic-gate if (mi->mi_open_files > 0) { 37327c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, 37337c478bd9Sstevel@tonic-gate "nfs4_remove_mi_from_server_nolock: don't " 37347c478bd9Sstevel@tonic-gate "remove mi since it still has files open")); 37357c478bd9Sstevel@tonic-gate 37367c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 37377c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_REMOVE_ON_LAST_CLOSE; 37387c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 37397c478bd9Sstevel@tonic-gate return; 37407c478bd9Sstevel@tonic-gate } 37417c478bd9Sstevel@tonic-gate 374250a83466Sjwahlig VFS_HOLD(mi->mi_vfsp); 37437c478bd9Sstevel@tonic-gate remove_mi(sp, mi); 374450a83466Sjwahlig VFS_RELE(mi->mi_vfsp); 37457c478bd9Sstevel@tonic-gate 37467c478bd9Sstevel@tonic-gate if (sp->mntinfo4_list == NULL) { 37477c478bd9Sstevel@tonic-gate /* last fs unmounted, kill the thread */ 37487c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, 37497c478bd9Sstevel@tonic-gate "remove_mi_from_nfs4_server_nolock: kill the thread")); 37507c478bd9Sstevel@tonic-gate nfs4_mark_srv_dead(sp); 37517c478bd9Sstevel@tonic-gate } 37527c478bd9Sstevel@tonic-gate } 37537c478bd9Sstevel@tonic-gate 37547c478bd9Sstevel@tonic-gate /* 37557c478bd9Sstevel@tonic-gate * Remove mi from sp's mntinfo4_list and release the vfs reference. 37567c478bd9Sstevel@tonic-gate */ 37577c478bd9Sstevel@tonic-gate static void 37587c478bd9Sstevel@tonic-gate remove_mi(nfs4_server_t *sp, mntinfo4_t *mi) 37597c478bd9Sstevel@tonic-gate { 3760*8e46f7b4SArne Jansen bool_t need_broadcast = FALSE; 3761*8e46f7b4SArne Jansen nfs4_rcsync_t *rcp; 3762*8e46f7b4SArne Jansen nfs4_rcsync_t *rcp_next; 3763*8e46f7b4SArne Jansen 37647c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sp->s_lock)); 37657c478bd9Sstevel@tonic-gate 37667c478bd9Sstevel@tonic-gate /* 37677c478bd9Sstevel@tonic-gate * We release a reference, and the caller must still have a 37687c478bd9Sstevel@tonic-gate * reference. 37697c478bd9Sstevel@tonic-gate */ 37707c478bd9Sstevel@tonic-gate ASSERT(mi->mi_vfsp->vfs_count >= 2); 37717c478bd9Sstevel@tonic-gate 37727c478bd9Sstevel@tonic-gate if (mi->mi_clientid_prev) { 37737c478bd9Sstevel@tonic-gate mi->mi_clientid_prev->mi_clientid_next = mi->mi_clientid_next; 37747c478bd9Sstevel@tonic-gate } else { 37757c478bd9Sstevel@tonic-gate /* This is the first mi in sp's mntinfo4_list */ 37767c478bd9Sstevel@tonic-gate /* 37777c478bd9Sstevel@tonic-gate * Make sure the first mntinfo4 in the list is the actual 37787c478bd9Sstevel@tonic-gate * mntinfo4 passed in. 37797c478bd9Sstevel@tonic-gate */ 37807c478bd9Sstevel@tonic-gate ASSERT(sp->mntinfo4_list == mi); 37817c478bd9Sstevel@tonic-gate 37827c478bd9Sstevel@tonic-gate sp->mntinfo4_list = mi->mi_clientid_next; 37837c478bd9Sstevel@tonic-gate } 37847c478bd9Sstevel@tonic-gate if (mi->mi_clientid_next) 37857c478bd9Sstevel@tonic-gate mi->mi_clientid_next->mi_clientid_prev = mi->mi_clientid_prev; 37867c478bd9Sstevel@tonic-gate 3787*8e46f7b4SArne Jansen /* remove pending opens */ 3788*8e46f7b4SArne Jansen mutex_enter(&sp->s_rcsync_lock); 3789*8e46f7b4SArne Jansen rcp = list_head(&sp->s_rcsync_list); 3790*8e46f7b4SArne Jansen while (rcp != NULL) { 3791*8e46f7b4SArne Jansen rcp_next = list_next(&sp->s_rcsync_list, rcp); 3792*8e46f7b4SArne Jansen if (rcp->rs_mi == mi) { 3793*8e46f7b4SArne Jansen rcp->rs_flags |= RS_SERVER_GONE; 3794*8e46f7b4SArne Jansen list_remove(&sp->s_rcsync_list, rcp); 3795*8e46f7b4SArne Jansen need_broadcast = TRUE; 3796*8e46f7b4SArne Jansen } 3797*8e46f7b4SArne Jansen rcp = rcp_next; 3798*8e46f7b4SArne Jansen } 3799*8e46f7b4SArne Jansen if (need_broadcast == TRUE) 3800*8e46f7b4SArne Jansen cv_broadcast(&sp->s_rcsync_cv); 3801*8e46f7b4SArne Jansen mutex_exit(&sp->s_rcsync_lock); 3802*8e46f7b4SArne Jansen 38037c478bd9Sstevel@tonic-gate /* Now mark the mntinfo4's links as being removed */ 38047c478bd9Sstevel@tonic-gate mi->mi_clientid_prev = mi->mi_clientid_next = NULL; 38053b895386SPavel Filipensky mi->mi_srv = NULL; 380622dc8f51SPavel Filipensky mi->mi_srvset_cnt++; 38077c478bd9Sstevel@tonic-gate 38087c478bd9Sstevel@tonic-gate VFS_RELE(mi->mi_vfsp); 38097c478bd9Sstevel@tonic-gate } 38107c478bd9Sstevel@tonic-gate 38117c478bd9Sstevel@tonic-gate /* 38127c478bd9Sstevel@tonic-gate * Free all the entries in sp's mntinfo4_list. 38137c478bd9Sstevel@tonic-gate */ 38147c478bd9Sstevel@tonic-gate static void 38157c478bd9Sstevel@tonic-gate remove_all_mi(nfs4_server_t *sp) 38167c478bd9Sstevel@tonic-gate { 38177c478bd9Sstevel@tonic-gate mntinfo4_t *mi; 38187c478bd9Sstevel@tonic-gate 38197c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sp->s_lock)); 38207c478bd9Sstevel@tonic-gate 38217c478bd9Sstevel@tonic-gate while (sp->mntinfo4_list != NULL) { 38227c478bd9Sstevel@tonic-gate mi = sp->mntinfo4_list; 38237c478bd9Sstevel@tonic-gate /* 38247c478bd9Sstevel@tonic-gate * Grab a reference in case there is only one left (which 38257c478bd9Sstevel@tonic-gate * remove_mi() frees). 38267c478bd9Sstevel@tonic-gate */ 38277c478bd9Sstevel@tonic-gate VFS_HOLD(mi->mi_vfsp); 38287c478bd9Sstevel@tonic-gate remove_mi(sp, mi); 38297c478bd9Sstevel@tonic-gate VFS_RELE(mi->mi_vfsp); 38307c478bd9Sstevel@tonic-gate } 38317c478bd9Sstevel@tonic-gate } 38327c478bd9Sstevel@tonic-gate 38337c478bd9Sstevel@tonic-gate /* 38347c478bd9Sstevel@tonic-gate * Remove the mi from sp's mntinfo4_list as above, and rele the vfs. 38357c478bd9Sstevel@tonic-gate * 38367c478bd9Sstevel@tonic-gate * This version can be called with a null nfs4_server_t arg, 38377c478bd9Sstevel@tonic-gate * and will either find the right one and handle locking, or 38387c478bd9Sstevel@tonic-gate * do nothing because the mi wasn't added to an sp's mntinfo4_list. 38397c478bd9Sstevel@tonic-gate */ 38407c478bd9Sstevel@tonic-gate void 38417c478bd9Sstevel@tonic-gate nfs4_remove_mi_from_server(mntinfo4_t *mi, nfs4_server_t *esp) 38427c478bd9Sstevel@tonic-gate { 38437c478bd9Sstevel@tonic-gate nfs4_server_t *sp; 38447c478bd9Sstevel@tonic-gate 38453b895386SPavel Filipensky if (esp) { 38463b895386SPavel Filipensky nfs4_remove_mi_from_server_nolock(mi, esp); 38473b895386SPavel Filipensky return; 38487c478bd9Sstevel@tonic-gate } 38493b895386SPavel Filipensky 38503b895386SPavel Filipensky (void) nfs_rw_enter_sig(&mi->mi_recovlock, RW_READER, 0); 385122dc8f51SPavel Filipensky if (sp = find_nfs4_server_all(mi, 1)) { 38523b895386SPavel Filipensky nfs4_remove_mi_from_server_nolock(mi, sp); 38533b895386SPavel Filipensky mutex_exit(&sp->s_lock); 385422dc8f51SPavel Filipensky nfs4_server_rele(sp); 38553b895386SPavel Filipensky } 38563b895386SPavel Filipensky nfs_rw_exit(&mi->mi_recovlock); 38577c478bd9Sstevel@tonic-gate } 38587c478bd9Sstevel@tonic-gate 38597c478bd9Sstevel@tonic-gate /* 38607c478bd9Sstevel@tonic-gate * Return TRUE if the given server has any non-unmounted filesystems. 38617c478bd9Sstevel@tonic-gate */ 38627c478bd9Sstevel@tonic-gate 38637c478bd9Sstevel@tonic-gate bool_t 38647c478bd9Sstevel@tonic-gate nfs4_fs_active(nfs4_server_t *sp) 38657c478bd9Sstevel@tonic-gate { 38667c478bd9Sstevel@tonic-gate mntinfo4_t *mi; 38677c478bd9Sstevel@tonic-gate 38687c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sp->s_lock)); 38697c478bd9Sstevel@tonic-gate 38707c478bd9Sstevel@tonic-gate for (mi = sp->mntinfo4_list; mi != NULL; mi = mi->mi_clientid_next) { 38717c478bd9Sstevel@tonic-gate if (!(mi->mi_vfsp->vfs_flag & VFS_UNMOUNTED)) 38727c478bd9Sstevel@tonic-gate return (TRUE); 38737c478bd9Sstevel@tonic-gate } 38747c478bd9Sstevel@tonic-gate 38757c478bd9Sstevel@tonic-gate return (FALSE); 38767c478bd9Sstevel@tonic-gate } 38777c478bd9Sstevel@tonic-gate 38787c478bd9Sstevel@tonic-gate /* 38797c478bd9Sstevel@tonic-gate * Mark sp as finished and notify any waiters. 38807c478bd9Sstevel@tonic-gate */ 38817c478bd9Sstevel@tonic-gate 38827c478bd9Sstevel@tonic-gate void 38837c478bd9Sstevel@tonic-gate nfs4_mark_srv_dead(nfs4_server_t *sp) 38847c478bd9Sstevel@tonic-gate { 38857c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sp->s_lock)); 38867c478bd9Sstevel@tonic-gate 38877c478bd9Sstevel@tonic-gate sp->s_thread_exit = NFS4_THREAD_EXIT; 38887c478bd9Sstevel@tonic-gate cv_broadcast(&sp->cv_thread_exit); 38897c478bd9Sstevel@tonic-gate } 38907c478bd9Sstevel@tonic-gate 38917c478bd9Sstevel@tonic-gate /* 38927c478bd9Sstevel@tonic-gate * Create a new nfs4_server_t structure. 38937c478bd9Sstevel@tonic-gate * Returns new node unlocked and not in list, but with a reference count of 38947c478bd9Sstevel@tonic-gate * 1. 38957c478bd9Sstevel@tonic-gate */ 38967c478bd9Sstevel@tonic-gate struct nfs4_server * 38977c478bd9Sstevel@tonic-gate new_nfs4_server(struct servinfo4 *svp, cred_t *cr) 38987c478bd9Sstevel@tonic-gate { 38997c478bd9Sstevel@tonic-gate struct nfs4_server *np; 39007c478bd9Sstevel@tonic-gate timespec_t tt; 39017c478bd9Sstevel@tonic-gate union { 39027c478bd9Sstevel@tonic-gate struct { 39037c478bd9Sstevel@tonic-gate uint32_t sec; 39047c478bd9Sstevel@tonic-gate uint32_t subsec; 39057c478bd9Sstevel@tonic-gate } un_curtime; 39067c478bd9Sstevel@tonic-gate verifier4 un_verifier; 39077c478bd9Sstevel@tonic-gate } nfs4clientid_verifier; 39082f172c55SRobert Thurlow /* 39092f172c55SRobert Thurlow * We change this ID string carefully and with the Solaris 39102f172c55SRobert Thurlow * NFS server behaviour in mind. "+referrals" indicates 39112f172c55SRobert Thurlow * a client that can handle an NFSv4 referral. 39122f172c55SRobert Thurlow */ 39132f172c55SRobert Thurlow char id_val[] = "Solaris: %s, NFSv4 kernel client +referrals"; 39147c478bd9Sstevel@tonic-gate int len; 39157c478bd9Sstevel@tonic-gate 39167c478bd9Sstevel@tonic-gate np = kmem_zalloc(sizeof (struct nfs4_server), KM_SLEEP); 39177c478bd9Sstevel@tonic-gate np->saddr.len = svp->sv_addr.len; 39187c478bd9Sstevel@tonic-gate np->saddr.maxlen = svp->sv_addr.maxlen; 39197c478bd9Sstevel@tonic-gate np->saddr.buf = kmem_alloc(svp->sv_addr.maxlen, KM_SLEEP); 39207c478bd9Sstevel@tonic-gate bcopy(svp->sv_addr.buf, np->saddr.buf, svp->sv_addr.len); 39217c478bd9Sstevel@tonic-gate np->s_refcnt = 1; 39227c478bd9Sstevel@tonic-gate 39237c478bd9Sstevel@tonic-gate /* 39247c478bd9Sstevel@tonic-gate * Build the nfs_client_id4 for this server mount. Ensure 39257c478bd9Sstevel@tonic-gate * the verifier is useful and that the identification is 39267c478bd9Sstevel@tonic-gate * somehow based on the server's address for the case of 39277c478bd9Sstevel@tonic-gate * multi-homed servers. 39287c478bd9Sstevel@tonic-gate */ 39297c478bd9Sstevel@tonic-gate nfs4clientid_verifier.un_verifier = 0; 39307c478bd9Sstevel@tonic-gate gethrestime(&tt); 39317c478bd9Sstevel@tonic-gate nfs4clientid_verifier.un_curtime.sec = (uint32_t)tt.tv_sec; 39327c478bd9Sstevel@tonic-gate nfs4clientid_verifier.un_curtime.subsec = (uint32_t)tt.tv_nsec; 39337c478bd9Sstevel@tonic-gate np->clidtosend.verifier = nfs4clientid_verifier.un_verifier; 39347c478bd9Sstevel@tonic-gate 39357c478bd9Sstevel@tonic-gate /* 39367c478bd9Sstevel@tonic-gate * calculate the length of the opaque identifier. Subtract 2 39377c478bd9Sstevel@tonic-gate * for the "%s" and add the traditional +1 for null 39387c478bd9Sstevel@tonic-gate * termination. 39397c478bd9Sstevel@tonic-gate */ 39407c478bd9Sstevel@tonic-gate len = strlen(id_val) - 2 + strlen(uts_nodename()) + 1; 39417c478bd9Sstevel@tonic-gate np->clidtosend.id_len = len + np->saddr.maxlen; 39427c478bd9Sstevel@tonic-gate 39437c478bd9Sstevel@tonic-gate np->clidtosend.id_val = kmem_alloc(np->clidtosend.id_len, KM_SLEEP); 39447c478bd9Sstevel@tonic-gate (void) sprintf(np->clidtosend.id_val, id_val, uts_nodename()); 39457c478bd9Sstevel@tonic-gate bcopy(np->saddr.buf, &np->clidtosend.id_val[len], np->saddr.len); 39467c478bd9Sstevel@tonic-gate 39477c478bd9Sstevel@tonic-gate np->s_flags = 0; 39487c478bd9Sstevel@tonic-gate np->mntinfo4_list = NULL; 39497c478bd9Sstevel@tonic-gate /* save cred for issuing rfs4calls inside the renew thread */ 39507c478bd9Sstevel@tonic-gate crhold(cr); 39517c478bd9Sstevel@tonic-gate np->s_cred = cr; 39527c478bd9Sstevel@tonic-gate cv_init(&np->cv_thread_exit, NULL, CV_DEFAULT, NULL); 39537c478bd9Sstevel@tonic-gate mutex_init(&np->s_lock, NULL, MUTEX_DEFAULT, NULL); 39547c478bd9Sstevel@tonic-gate nfs_rw_init(&np->s_recovlock, NULL, RW_DEFAULT, NULL); 39557c478bd9Sstevel@tonic-gate list_create(&np->s_deleg_list, sizeof (rnode4_t), 39567c478bd9Sstevel@tonic-gate offsetof(rnode4_t, r_deleg_link)); 39577c478bd9Sstevel@tonic-gate np->s_thread_exit = 0; 39587c478bd9Sstevel@tonic-gate np->state_ref_count = 0; 39597c478bd9Sstevel@tonic-gate np->lease_valid = NFS4_LEASE_NOT_STARTED; 39607c478bd9Sstevel@tonic-gate cv_init(&np->s_cv_otw_count, NULL, CV_DEFAULT, NULL); 3961f86c6ccaSdm120769 cv_init(&np->s_clientid_pend, NULL, CV_DEFAULT, NULL); 39627c478bd9Sstevel@tonic-gate np->s_otw_call_count = 0; 39637c478bd9Sstevel@tonic-gate cv_init(&np->wait_cb_null, NULL, CV_DEFAULT, NULL); 39647c478bd9Sstevel@tonic-gate np->zoneid = getzoneid(); 39657c478bd9Sstevel@tonic-gate np->zone_globals = nfs4_get_callback_globals(); 39667c478bd9Sstevel@tonic-gate ASSERT(np->zone_globals != NULL); 3967*8e46f7b4SArne Jansen mutex_init(&np->s_rcsync_lock, NULL, MUTEX_DEFAULT, NULL); 3968*8e46f7b4SArne Jansen cv_init(&np->s_rcsync_cv, NULL, CV_DEFAULT, NULL); 3969*8e46f7b4SArne Jansen list_create(&np->s_rcsync_list, sizeof (nfs4_rcsync_t), 3970*8e46f7b4SArne Jansen offsetof(nfs4_rcsync_t, rs_link)); 3971*8e46f7b4SArne Jansen np->s_rcsync_seq = 1; 3972*8e46f7b4SArne Jansen 39737c478bd9Sstevel@tonic-gate return (np); 39747c478bd9Sstevel@tonic-gate } 39757c478bd9Sstevel@tonic-gate 39767c478bd9Sstevel@tonic-gate /* 39777c478bd9Sstevel@tonic-gate * Create a new nfs4_server_t structure and add it to the list. 39787c478bd9Sstevel@tonic-gate * Returns new node locked; reference must eventually be freed. 39797c478bd9Sstevel@tonic-gate */ 39807c478bd9Sstevel@tonic-gate static struct nfs4_server * 39817c478bd9Sstevel@tonic-gate add_new_nfs4_server(struct servinfo4 *svp, cred_t *cr) 39827c478bd9Sstevel@tonic-gate { 39837c478bd9Sstevel@tonic-gate nfs4_server_t *sp; 39847c478bd9Sstevel@tonic-gate 39857c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&nfs4_server_lst_lock)); 39867c478bd9Sstevel@tonic-gate sp = new_nfs4_server(svp, cr); 39877c478bd9Sstevel@tonic-gate mutex_enter(&sp->s_lock); 39887c478bd9Sstevel@tonic-gate insque(sp, &nfs4_server_lst); 39897c478bd9Sstevel@tonic-gate sp->s_refcnt++; /* list gets a reference */ 3990f64c4ae1Sdm120769 sp->s_flags |= N4S_INSERTED; 39917c478bd9Sstevel@tonic-gate sp->clientid = 0; 39927c478bd9Sstevel@tonic-gate return (sp); 39937c478bd9Sstevel@tonic-gate } 39947c478bd9Sstevel@tonic-gate 39957c478bd9Sstevel@tonic-gate int nfs4_server_t_debug = 0; 39967c478bd9Sstevel@tonic-gate 39977c478bd9Sstevel@tonic-gate #ifdef lint 39987c478bd9Sstevel@tonic-gate extern void 39997c478bd9Sstevel@tonic-gate dumpnfs4slist(char *, mntinfo4_t *, clientid4, servinfo4_t *); 40007c478bd9Sstevel@tonic-gate #endif 40017c478bd9Sstevel@tonic-gate 40027c478bd9Sstevel@tonic-gate #ifndef lint 40037c478bd9Sstevel@tonic-gate #ifdef DEBUG 40047c478bd9Sstevel@tonic-gate void 40057c478bd9Sstevel@tonic-gate dumpnfs4slist(char *txt, mntinfo4_t *mi, clientid4 clientid, servinfo4_t *srv_p) 40067c478bd9Sstevel@tonic-gate { 40077c478bd9Sstevel@tonic-gate int hash16(void *p, int len); 40087c478bd9Sstevel@tonic-gate nfs4_server_t *np; 40097c478bd9Sstevel@tonic-gate 40107c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_server_t_debug, (CE_NOTE, 40117c478bd9Sstevel@tonic-gate "dumping nfs4_server_t list in %s", txt)); 40127c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_server_t_debug, (CE_CONT, 40137c478bd9Sstevel@tonic-gate "mi 0x%p, want clientid %llx, addr %d/%04X", 40147c478bd9Sstevel@tonic-gate mi, (longlong_t)clientid, srv_p->sv_addr.len, 40157c478bd9Sstevel@tonic-gate hash16((void *)srv_p->sv_addr.buf, srv_p->sv_addr.len))); 40167c478bd9Sstevel@tonic-gate for (np = nfs4_server_lst.forw; np != &nfs4_server_lst; 40177c478bd9Sstevel@tonic-gate np = np->forw) { 40187c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_server_t_debug, (CE_CONT, 40197c478bd9Sstevel@tonic-gate "node 0x%p, clientid %llx, addr %d/%04X, cnt %d", 40207c478bd9Sstevel@tonic-gate np, (longlong_t)np->clientid, np->saddr.len, 40217c478bd9Sstevel@tonic-gate hash16((void *)np->saddr.buf, np->saddr.len), 40227c478bd9Sstevel@tonic-gate np->state_ref_count)); 40237c478bd9Sstevel@tonic-gate if (np->saddr.len == srv_p->sv_addr.len && 40247c478bd9Sstevel@tonic-gate bcmp(np->saddr.buf, srv_p->sv_addr.buf, 40257c478bd9Sstevel@tonic-gate np->saddr.len) == 0) 40267c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_server_t_debug, (CE_CONT, 40277c478bd9Sstevel@tonic-gate " - address matches")); 40287c478bd9Sstevel@tonic-gate if (np->clientid == clientid || np->clientid == 0) 40297c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_server_t_debug, (CE_CONT, 40307c478bd9Sstevel@tonic-gate " - clientid matches")); 40317c478bd9Sstevel@tonic-gate if (np->s_thread_exit != NFS4_THREAD_EXIT) 40327c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_server_t_debug, (CE_CONT, 40337c478bd9Sstevel@tonic-gate " - thread not exiting")); 40347c478bd9Sstevel@tonic-gate } 40357c478bd9Sstevel@tonic-gate delay(hz); 40367c478bd9Sstevel@tonic-gate } 40377c478bd9Sstevel@tonic-gate #endif 40387c478bd9Sstevel@tonic-gate #endif 40397c478bd9Sstevel@tonic-gate 40407c478bd9Sstevel@tonic-gate 40417c478bd9Sstevel@tonic-gate /* 40427c478bd9Sstevel@tonic-gate * Move a mntinfo4_t from one server list to another. 40437c478bd9Sstevel@tonic-gate * Locking of the two nfs4_server_t nodes will be done in list order. 40447c478bd9Sstevel@tonic-gate * 40457c478bd9Sstevel@tonic-gate * Returns NULL if the current nfs4_server_t for the filesystem could not 40467c478bd9Sstevel@tonic-gate * be found (e.g., due to forced unmount). Otherwise returns a reference 40477c478bd9Sstevel@tonic-gate * to the new nfs4_server_t, which must eventually be freed. 40487c478bd9Sstevel@tonic-gate */ 40497c478bd9Sstevel@tonic-gate nfs4_server_t * 40507c478bd9Sstevel@tonic-gate nfs4_move_mi(mntinfo4_t *mi, servinfo4_t *old, servinfo4_t *new) 40517c478bd9Sstevel@tonic-gate { 40527c478bd9Sstevel@tonic-gate nfs4_server_t *p, *op = NULL, *np = NULL; 40537c478bd9Sstevel@tonic-gate int num_open; 4054108322fbScarlsonj zoneid_t zoneid = nfs_zoneid(); 40557c478bd9Sstevel@tonic-gate 4056108322fbScarlsonj ASSERT(nfs_zone() == mi->mi_zone); 40577c478bd9Sstevel@tonic-gate 40587c478bd9Sstevel@tonic-gate mutex_enter(&nfs4_server_lst_lock); 40597c478bd9Sstevel@tonic-gate #ifdef DEBUG 40607c478bd9Sstevel@tonic-gate if (nfs4_server_t_debug) 40617c478bd9Sstevel@tonic-gate dumpnfs4slist("nfs4_move_mi", mi, (clientid4)0, new); 40627c478bd9Sstevel@tonic-gate #endif 40637c478bd9Sstevel@tonic-gate for (p = nfs4_server_lst.forw; p != &nfs4_server_lst; p = p->forw) { 40647c478bd9Sstevel@tonic-gate if (p->zoneid != zoneid) 40657c478bd9Sstevel@tonic-gate continue; 40667c478bd9Sstevel@tonic-gate if (p->saddr.len == old->sv_addr.len && 40677c478bd9Sstevel@tonic-gate bcmp(p->saddr.buf, old->sv_addr.buf, p->saddr.len) == 0 && 40687c478bd9Sstevel@tonic-gate p->s_thread_exit != NFS4_THREAD_EXIT) { 40697c478bd9Sstevel@tonic-gate op = p; 40707c478bd9Sstevel@tonic-gate mutex_enter(&op->s_lock); 40717c478bd9Sstevel@tonic-gate op->s_refcnt++; 40727c478bd9Sstevel@tonic-gate } 40737c478bd9Sstevel@tonic-gate if (p->saddr.len == new->sv_addr.len && 40747c478bd9Sstevel@tonic-gate bcmp(p->saddr.buf, new->sv_addr.buf, p->saddr.len) == 0 && 40757c478bd9Sstevel@tonic-gate p->s_thread_exit != NFS4_THREAD_EXIT) { 40767c478bd9Sstevel@tonic-gate np = p; 40777c478bd9Sstevel@tonic-gate mutex_enter(&np->s_lock); 40787c478bd9Sstevel@tonic-gate } 40797c478bd9Sstevel@tonic-gate if (op != NULL && np != NULL) 40807c478bd9Sstevel@tonic-gate break; 40817c478bd9Sstevel@tonic-gate } 40827c478bd9Sstevel@tonic-gate if (op == NULL) { 40837c478bd9Sstevel@tonic-gate /* 40847c478bd9Sstevel@tonic-gate * Filesystem has been forcibly unmounted. Bail out. 40857c478bd9Sstevel@tonic-gate */ 40867c478bd9Sstevel@tonic-gate if (np != NULL) 40877c478bd9Sstevel@tonic-gate mutex_exit(&np->s_lock); 40887c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_server_lst_lock); 40897c478bd9Sstevel@tonic-gate return (NULL); 40907c478bd9Sstevel@tonic-gate } 40917c478bd9Sstevel@tonic-gate if (np != NULL) { 40927c478bd9Sstevel@tonic-gate np->s_refcnt++; 40937c478bd9Sstevel@tonic-gate } else { 40947c478bd9Sstevel@tonic-gate #ifdef DEBUG 40957c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_failover_debug, (CE_NOTE, 40967c478bd9Sstevel@tonic-gate "nfs4_move_mi: no target nfs4_server, will create.")); 40977c478bd9Sstevel@tonic-gate #endif 40987c478bd9Sstevel@tonic-gate np = add_new_nfs4_server(new, kcred); 40997c478bd9Sstevel@tonic-gate } 41007c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_server_lst_lock); 41017c478bd9Sstevel@tonic-gate 41027c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_failover_debug, (CE_NOTE, 41037c478bd9Sstevel@tonic-gate "nfs4_move_mi: for mi 0x%p, " 41047c478bd9Sstevel@tonic-gate "old servinfo4 0x%p, new servinfo4 0x%p, " 41057c478bd9Sstevel@tonic-gate "old nfs4_server 0x%p, new nfs4_server 0x%p, ", 41067c478bd9Sstevel@tonic-gate (void*)mi, (void*)old, (void*)new, 41077c478bd9Sstevel@tonic-gate (void*)op, (void*)np)); 41087c478bd9Sstevel@tonic-gate ASSERT(op != NULL && np != NULL); 41097c478bd9Sstevel@tonic-gate 41107c478bd9Sstevel@tonic-gate /* discard any delegations */ 41117c478bd9Sstevel@tonic-gate nfs4_deleg_discard(mi, op); 41127c478bd9Sstevel@tonic-gate 41137c478bd9Sstevel@tonic-gate num_open = mi->mi_open_files; 41147c478bd9Sstevel@tonic-gate mi->mi_open_files = 0; 41157c478bd9Sstevel@tonic-gate op->state_ref_count -= num_open; 41167c478bd9Sstevel@tonic-gate ASSERT(op->state_ref_count >= 0); 41177c478bd9Sstevel@tonic-gate np->state_ref_count += num_open; 41187c478bd9Sstevel@tonic-gate nfs4_remove_mi_from_server_nolock(mi, op); 41197c478bd9Sstevel@tonic-gate mi->mi_open_files = num_open; 41207c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_failover_debug, (CE_NOTE, 41217c478bd9Sstevel@tonic-gate "nfs4_move_mi: mi_open_files %d, op->cnt %d, np->cnt %d", 41227c478bd9Sstevel@tonic-gate mi->mi_open_files, op->state_ref_count, np->state_ref_count)); 41237c478bd9Sstevel@tonic-gate 41247c478bd9Sstevel@tonic-gate nfs4_add_mi_to_server(np, mi); 41257c478bd9Sstevel@tonic-gate 41267c478bd9Sstevel@tonic-gate mutex_exit(&op->s_lock); 41277c478bd9Sstevel@tonic-gate mutex_exit(&np->s_lock); 412895c7fa91SPavel Filipensky nfs4_server_rele(op); 41297c478bd9Sstevel@tonic-gate 41307c478bd9Sstevel@tonic-gate return (np); 41317c478bd9Sstevel@tonic-gate } 41327c478bd9Sstevel@tonic-gate 41337c478bd9Sstevel@tonic-gate /* 4134f86c6ccaSdm120769 * Need to have the nfs4_server_lst_lock. 41357c478bd9Sstevel@tonic-gate * Search the nfs4_server list to find a match on this servinfo4 41367c478bd9Sstevel@tonic-gate * based on its address. 41377c478bd9Sstevel@tonic-gate * 41387c478bd9Sstevel@tonic-gate * Returns NULL if no match is found. Otherwise returns a reference (which 41397c478bd9Sstevel@tonic-gate * must eventually be freed) to a locked nfs4_server. 41407c478bd9Sstevel@tonic-gate */ 41417c478bd9Sstevel@tonic-gate nfs4_server_t * 41427c478bd9Sstevel@tonic-gate servinfo4_to_nfs4_server(servinfo4_t *srv_p) 41437c478bd9Sstevel@tonic-gate { 41447c478bd9Sstevel@tonic-gate nfs4_server_t *np; 4145108322fbScarlsonj zoneid_t zoneid = nfs_zoneid(); 41467c478bd9Sstevel@tonic-gate 4147f86c6ccaSdm120769 ASSERT(MUTEX_HELD(&nfs4_server_lst_lock)); 41487c478bd9Sstevel@tonic-gate for (np = nfs4_server_lst.forw; np != &nfs4_server_lst; np = np->forw) { 41497c478bd9Sstevel@tonic-gate if (np->zoneid == zoneid && 41507c478bd9Sstevel@tonic-gate np->saddr.len == srv_p->sv_addr.len && 41517c478bd9Sstevel@tonic-gate bcmp(np->saddr.buf, srv_p->sv_addr.buf, 41527c478bd9Sstevel@tonic-gate np->saddr.len) == 0 && 41537c478bd9Sstevel@tonic-gate np->s_thread_exit != NFS4_THREAD_EXIT) { 41547c478bd9Sstevel@tonic-gate mutex_enter(&np->s_lock); 41557c478bd9Sstevel@tonic-gate np->s_refcnt++; 41567c478bd9Sstevel@tonic-gate return (np); 41577c478bd9Sstevel@tonic-gate } 41587c478bd9Sstevel@tonic-gate } 41597c478bd9Sstevel@tonic-gate return (NULL); 41607c478bd9Sstevel@tonic-gate } 41617c478bd9Sstevel@tonic-gate 41627c478bd9Sstevel@tonic-gate /* 41637c478bd9Sstevel@tonic-gate * Locks the nfs4_server down if it is found and returns a reference that 41647c478bd9Sstevel@tonic-gate * must eventually be freed. 416522dc8f51SPavel Filipensky */ 416622dc8f51SPavel Filipensky static nfs4_server_t * 416722dc8f51SPavel Filipensky lookup_nfs4_server(nfs4_server_t *sp, int any_state) 416822dc8f51SPavel Filipensky { 416922dc8f51SPavel Filipensky nfs4_server_t *np; 417022dc8f51SPavel Filipensky 417122dc8f51SPavel Filipensky mutex_enter(&nfs4_server_lst_lock); 417222dc8f51SPavel Filipensky for (np = nfs4_server_lst.forw; np != &nfs4_server_lst; np = np->forw) { 417322dc8f51SPavel Filipensky mutex_enter(&np->s_lock); 417422dc8f51SPavel Filipensky if (np == sp && np->s_refcnt > 0 && 417522dc8f51SPavel Filipensky (np->s_thread_exit != NFS4_THREAD_EXIT || any_state)) { 417622dc8f51SPavel Filipensky mutex_exit(&nfs4_server_lst_lock); 417722dc8f51SPavel Filipensky np->s_refcnt++; 417822dc8f51SPavel Filipensky return (np); 417922dc8f51SPavel Filipensky } 418022dc8f51SPavel Filipensky mutex_exit(&np->s_lock); 418122dc8f51SPavel Filipensky } 418222dc8f51SPavel Filipensky mutex_exit(&nfs4_server_lst_lock); 418322dc8f51SPavel Filipensky 418422dc8f51SPavel Filipensky return (NULL); 418522dc8f51SPavel Filipensky } 418622dc8f51SPavel Filipensky 418722dc8f51SPavel Filipensky /* 41887c478bd9Sstevel@tonic-gate * The caller should be holding mi->mi_recovlock, and it should continue to 41897c478bd9Sstevel@tonic-gate * hold the lock until done with the returned nfs4_server_t. Once 41907c478bd9Sstevel@tonic-gate * mi->mi_recovlock is released, there is no guarantee that the returned 41917c478bd9Sstevel@tonic-gate * mi->nfs4_server_t will continue to correspond to mi. 41927c478bd9Sstevel@tonic-gate */ 41937c478bd9Sstevel@tonic-gate nfs4_server_t * 41947c478bd9Sstevel@tonic-gate find_nfs4_server(mntinfo4_t *mi) 41957c478bd9Sstevel@tonic-gate { 419622dc8f51SPavel Filipensky ASSERT(nfs_rw_lock_held(&mi->mi_recovlock, RW_READER) || 419722dc8f51SPavel Filipensky nfs_rw_lock_held(&mi->mi_recovlock, RW_WRITER)); 419822dc8f51SPavel Filipensky 419922dc8f51SPavel Filipensky return (lookup_nfs4_server(mi->mi_srv, 0)); 42007c478bd9Sstevel@tonic-gate } 42017c478bd9Sstevel@tonic-gate 42027c478bd9Sstevel@tonic-gate /* 420322dc8f51SPavel Filipensky * Same as above, but takes an "any_state" parameter which can be 42047c478bd9Sstevel@tonic-gate * set to 1 if the caller wishes to find nfs4_server_t's which 42057c478bd9Sstevel@tonic-gate * have been marked for termination by the exit of the renew 42067c478bd9Sstevel@tonic-gate * thread. This should only be used by operations which are 42077c478bd9Sstevel@tonic-gate * cleaning up and will not cause an OTW op. 42087c478bd9Sstevel@tonic-gate */ 42097c478bd9Sstevel@tonic-gate nfs4_server_t * 421022dc8f51SPavel Filipensky find_nfs4_server_all(mntinfo4_t *mi, int any_state) 42117c478bd9Sstevel@tonic-gate { 42127c478bd9Sstevel@tonic-gate ASSERT(nfs_rw_lock_held(&mi->mi_recovlock, RW_READER) || 42137c478bd9Sstevel@tonic-gate nfs_rw_lock_held(&mi->mi_recovlock, RW_WRITER)); 42147c478bd9Sstevel@tonic-gate 421522dc8f51SPavel Filipensky return (lookup_nfs4_server(mi->mi_srv, any_state)); 42167c478bd9Sstevel@tonic-gate } 421722dc8f51SPavel Filipensky 421822dc8f51SPavel Filipensky /* 421922dc8f51SPavel Filipensky * Lock sp, but only if it's still active (in the list and hasn't been 422022dc8f51SPavel Filipensky * flagged as exiting) or 'any_state' is non-zero. 422122dc8f51SPavel Filipensky * Returns TRUE if sp got locked and adds a reference to sp. 422222dc8f51SPavel Filipensky */ 422322dc8f51SPavel Filipensky bool_t 422422dc8f51SPavel Filipensky nfs4_server_vlock(nfs4_server_t *sp, int any_state) 422522dc8f51SPavel Filipensky { 422622dc8f51SPavel Filipensky return (lookup_nfs4_server(sp, any_state) != NULL); 42277c478bd9Sstevel@tonic-gate } 42287c478bd9Sstevel@tonic-gate 42297c478bd9Sstevel@tonic-gate /* 42307c478bd9Sstevel@tonic-gate * Release the reference to sp and destroy it if that's the last one. 42317c478bd9Sstevel@tonic-gate */ 42327c478bd9Sstevel@tonic-gate 42337c478bd9Sstevel@tonic-gate void 42347c478bd9Sstevel@tonic-gate nfs4_server_rele(nfs4_server_t *sp) 42357c478bd9Sstevel@tonic-gate { 42367c478bd9Sstevel@tonic-gate mutex_enter(&sp->s_lock); 42377c478bd9Sstevel@tonic-gate ASSERT(sp->s_refcnt > 0); 42387c478bd9Sstevel@tonic-gate sp->s_refcnt--; 42397c478bd9Sstevel@tonic-gate if (sp->s_refcnt > 0) { 42407c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_lock); 42417c478bd9Sstevel@tonic-gate return; 42427c478bd9Sstevel@tonic-gate } 42437c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_lock); 4244f86c6ccaSdm120769 42457c478bd9Sstevel@tonic-gate mutex_enter(&nfs4_server_lst_lock); 42467c478bd9Sstevel@tonic-gate mutex_enter(&sp->s_lock); 42477c478bd9Sstevel@tonic-gate if (sp->s_refcnt > 0) { 42487c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_lock); 42497c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_server_lst_lock); 42507c478bd9Sstevel@tonic-gate return; 42517c478bd9Sstevel@tonic-gate } 42527c478bd9Sstevel@tonic-gate remque(sp); 42537c478bd9Sstevel@tonic-gate sp->forw = sp->back = NULL; 42547c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_server_lst_lock); 42557c478bd9Sstevel@tonic-gate destroy_nfs4_server(sp); 42567c478bd9Sstevel@tonic-gate } 42577c478bd9Sstevel@tonic-gate 42587c478bd9Sstevel@tonic-gate static void 42597c478bd9Sstevel@tonic-gate destroy_nfs4_server(nfs4_server_t *sp) 42607c478bd9Sstevel@tonic-gate { 42617c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sp->s_lock)); 42627c478bd9Sstevel@tonic-gate ASSERT(sp->s_refcnt == 0); 42637c478bd9Sstevel@tonic-gate ASSERT(sp->s_otw_call_count == 0); 42647c478bd9Sstevel@tonic-gate 42657c478bd9Sstevel@tonic-gate remove_all_mi(sp); 42667c478bd9Sstevel@tonic-gate 42677c478bd9Sstevel@tonic-gate crfree(sp->s_cred); 42687c478bd9Sstevel@tonic-gate kmem_free(sp->saddr.buf, sp->saddr.maxlen); 42697c478bd9Sstevel@tonic-gate kmem_free(sp->clidtosend.id_val, sp->clidtosend.id_len); 42707c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_lock); 42717c478bd9Sstevel@tonic-gate 42727c478bd9Sstevel@tonic-gate /* destroy the nfs4_server */ 42737c478bd9Sstevel@tonic-gate nfs4callback_destroy(sp); 42747c478bd9Sstevel@tonic-gate list_destroy(&sp->s_deleg_list); 42757c478bd9Sstevel@tonic-gate mutex_destroy(&sp->s_lock); 42767c478bd9Sstevel@tonic-gate cv_destroy(&sp->cv_thread_exit); 42777c478bd9Sstevel@tonic-gate cv_destroy(&sp->s_cv_otw_count); 4278f86c6ccaSdm120769 cv_destroy(&sp->s_clientid_pend); 42797c478bd9Sstevel@tonic-gate cv_destroy(&sp->wait_cb_null); 42807c478bd9Sstevel@tonic-gate nfs_rw_destroy(&sp->s_recovlock); 4281*8e46f7b4SArne Jansen mutex_destroy(&sp->s_rcsync_lock); 4282*8e46f7b4SArne Jansen cv_destroy(&sp->s_rcsync_cv); 4283*8e46f7b4SArne Jansen list_destroy(&sp->s_rcsync_list); 42847c478bd9Sstevel@tonic-gate kmem_free(sp, sizeof (*sp)); 42857c478bd9Sstevel@tonic-gate } 42867c478bd9Sstevel@tonic-gate 42877c478bd9Sstevel@tonic-gate /* 42887c478bd9Sstevel@tonic-gate * Fork off a thread to free the data structures for a mount. 42897c478bd9Sstevel@tonic-gate */ 42907c478bd9Sstevel@tonic-gate 42917c478bd9Sstevel@tonic-gate static void 4292b9238976Sth199096 async_free_mount(vfs_t *vfsp, int flag, cred_t *cr) 42937c478bd9Sstevel@tonic-gate { 42947c478bd9Sstevel@tonic-gate freemountargs_t *args; 42957c478bd9Sstevel@tonic-gate args = kmem_alloc(sizeof (freemountargs_t), KM_SLEEP); 42967c478bd9Sstevel@tonic-gate args->fm_vfsp = vfsp; 42977c478bd9Sstevel@tonic-gate VFS_HOLD(vfsp); 429850a83466Sjwahlig MI4_HOLD(VFTOMI4(vfsp)); 4299b9238976Sth199096 args->fm_flag = flag; 43007c478bd9Sstevel@tonic-gate args->fm_cr = cr; 43017c478bd9Sstevel@tonic-gate crhold(cr); 43027c478bd9Sstevel@tonic-gate (void) zthread_create(NULL, 0, nfs4_free_mount_thread, args, 0, 43037c478bd9Sstevel@tonic-gate minclsyspri); 43047c478bd9Sstevel@tonic-gate } 43057c478bd9Sstevel@tonic-gate 43067c478bd9Sstevel@tonic-gate static void 43077c478bd9Sstevel@tonic-gate nfs4_free_mount_thread(freemountargs_t *args) 43087c478bd9Sstevel@tonic-gate { 430950a83466Sjwahlig mntinfo4_t *mi; 4310b9238976Sth199096 nfs4_free_mount(args->fm_vfsp, args->fm_flag, args->fm_cr); 431150a83466Sjwahlig mi = VFTOMI4(args->fm_vfsp); 43127c478bd9Sstevel@tonic-gate crfree(args->fm_cr); 431350a83466Sjwahlig VFS_RELE(args->fm_vfsp); 431450a83466Sjwahlig MI4_RELE(mi); 43157c478bd9Sstevel@tonic-gate kmem_free(args, sizeof (freemountargs_t)); 43167c478bd9Sstevel@tonic-gate zthread_exit(); 43177c478bd9Sstevel@tonic-gate /* NOTREACHED */ 43187c478bd9Sstevel@tonic-gate } 43197c478bd9Sstevel@tonic-gate 43207c478bd9Sstevel@tonic-gate /* 43217c478bd9Sstevel@tonic-gate * Thread to free the data structures for a given filesystem. 43227c478bd9Sstevel@tonic-gate */ 43237c478bd9Sstevel@tonic-gate static void 4324b9238976Sth199096 nfs4_free_mount(vfs_t *vfsp, int flag, cred_t *cr) 43257c478bd9Sstevel@tonic-gate { 43267c478bd9Sstevel@tonic-gate mntinfo4_t *mi = VFTOMI4(vfsp); 43277c478bd9Sstevel@tonic-gate nfs4_server_t *sp; 43287c478bd9Sstevel@tonic-gate callb_cpr_t cpr_info; 43297c478bd9Sstevel@tonic-gate kmutex_t cpr_lock; 43307c478bd9Sstevel@tonic-gate boolean_t async_thread; 433150a83466Sjwahlig int removed; 43327c478bd9Sstevel@tonic-gate 4333d3a14591SThomas Haynes bool_t must_unlock; 4334b9238976Sth199096 nfs4_ephemeral_tree_t *eph_tree; 4335b9238976Sth199096 43367c478bd9Sstevel@tonic-gate /* 43377c478bd9Sstevel@tonic-gate * We need to participate in the CPR framework if this is a kernel 43387c478bd9Sstevel@tonic-gate * thread. 43397c478bd9Sstevel@tonic-gate */ 4340108322fbScarlsonj async_thread = (curproc == nfs_zone()->zone_zsched); 43417c478bd9Sstevel@tonic-gate if (async_thread) { 43427c478bd9Sstevel@tonic-gate mutex_init(&cpr_lock, NULL, MUTEX_DEFAULT, NULL); 43437c478bd9Sstevel@tonic-gate CALLB_CPR_INIT(&cpr_info, &cpr_lock, callb_generic_cpr, 43447c478bd9Sstevel@tonic-gate "nfsv4AsyncUnmount"); 43457c478bd9Sstevel@tonic-gate } 43467c478bd9Sstevel@tonic-gate 43477c478bd9Sstevel@tonic-gate /* 43487c478bd9Sstevel@tonic-gate * We need to wait for all outstanding OTW calls 43497c478bd9Sstevel@tonic-gate * and recovery to finish before we remove the mi 43507c478bd9Sstevel@tonic-gate * from the nfs4_server_t, as current pending 43517c478bd9Sstevel@tonic-gate * calls might still need this linkage (in order 43527c478bd9Sstevel@tonic-gate * to find a nfs4_server_t from a mntinfo4_t). 43537c478bd9Sstevel@tonic-gate */ 43547c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&mi->mi_recovlock, RW_READER, FALSE); 43557c478bd9Sstevel@tonic-gate sp = find_nfs4_server(mi); 43567c478bd9Sstevel@tonic-gate nfs_rw_exit(&mi->mi_recovlock); 43577c478bd9Sstevel@tonic-gate 43587c478bd9Sstevel@tonic-gate if (sp) { 43597c478bd9Sstevel@tonic-gate while (sp->s_otw_call_count != 0) { 43607c478bd9Sstevel@tonic-gate if (async_thread) { 43617c478bd9Sstevel@tonic-gate mutex_enter(&cpr_lock); 43627c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&cpr_info); 43637c478bd9Sstevel@tonic-gate mutex_exit(&cpr_lock); 43647c478bd9Sstevel@tonic-gate } 43657c478bd9Sstevel@tonic-gate cv_wait(&sp->s_cv_otw_count, &sp->s_lock); 43667c478bd9Sstevel@tonic-gate if (async_thread) { 43677c478bd9Sstevel@tonic-gate mutex_enter(&cpr_lock); 43687c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_END(&cpr_info, &cpr_lock); 43697c478bd9Sstevel@tonic-gate mutex_exit(&cpr_lock); 43707c478bd9Sstevel@tonic-gate } 43717c478bd9Sstevel@tonic-gate } 43727c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_lock); 43737c478bd9Sstevel@tonic-gate nfs4_server_rele(sp); 43747c478bd9Sstevel@tonic-gate sp = NULL; 43757c478bd9Sstevel@tonic-gate } 43767c478bd9Sstevel@tonic-gate 43777c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock); 43787c478bd9Sstevel@tonic-gate while (mi->mi_in_recovery != 0) { 43797c478bd9Sstevel@tonic-gate if (async_thread) { 43807c478bd9Sstevel@tonic-gate mutex_enter(&cpr_lock); 43817c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&cpr_info); 43827c478bd9Sstevel@tonic-gate mutex_exit(&cpr_lock); 43837c478bd9Sstevel@tonic-gate } 43847c478bd9Sstevel@tonic-gate cv_wait(&mi->mi_cv_in_recov, &mi->mi_lock); 43857c478bd9Sstevel@tonic-gate if (async_thread) { 43867c478bd9Sstevel@tonic-gate mutex_enter(&cpr_lock); 43877c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_END(&cpr_info, &cpr_lock); 43887c478bd9Sstevel@tonic-gate mutex_exit(&cpr_lock); 43897c478bd9Sstevel@tonic-gate } 43907c478bd9Sstevel@tonic-gate } 43917c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock); 43927c478bd9Sstevel@tonic-gate 4393eabd0450Sth199096 /* 4394eabd0450Sth199096 * If we got an error, then do not nuke the 4395eabd0450Sth199096 * tree. Either the harvester is busy reclaiming 4396eabd0450Sth199096 * this node or we ran into some busy condition. 4397eabd0450Sth199096 * 4398eabd0450Sth199096 * The harvester will eventually come along and cleanup. 4399eabd0450Sth199096 * The only problem would be the root mount point. 4400eabd0450Sth199096 * 4401eabd0450Sth199096 * Since the busy node can occur for a variety 4402eabd0450Sth199096 * of reasons and can result in an entry staying 4403eabd0450Sth199096 * in df output but no longer accessible from the 4404eabd0450Sth199096 * directory tree, we are okay. 4405eabd0450Sth199096 */ 4406eabd0450Sth199096 if (!nfs4_ephemeral_umount(mi, flag, cr, 44072f172c55SRobert Thurlow &must_unlock, &eph_tree)) 4408eabd0450Sth199096 nfs4_ephemeral_umount_activate(mi, &must_unlock, 44092f172c55SRobert Thurlow &eph_tree); 4410b9238976Sth199096 44117c478bd9Sstevel@tonic-gate /* 44127c478bd9Sstevel@tonic-gate * The original purge of the dnlc via 'dounmount' 44137c478bd9Sstevel@tonic-gate * doesn't guarantee that another dnlc entry was not 44147c478bd9Sstevel@tonic-gate * added while we waitied for all outstanding OTW 44157c478bd9Sstevel@tonic-gate * and recovery calls to finish. So re-purge the 44167c478bd9Sstevel@tonic-gate * dnlc now. 44177c478bd9Sstevel@tonic-gate */ 44187c478bd9Sstevel@tonic-gate (void) dnlc_purge_vfsp(vfsp, 0); 44197c478bd9Sstevel@tonic-gate 44207c478bd9Sstevel@tonic-gate /* 44217c478bd9Sstevel@tonic-gate * We need to explicitly stop the manager thread; the asyc worker 44227c478bd9Sstevel@tonic-gate * threads can timeout and exit on their own. 44237c478bd9Sstevel@tonic-gate */ 442450a83466Sjwahlig mutex_enter(&mi->mi_async_lock); 442550a83466Sjwahlig mi->mi_max_threads = 0; 44260776f5e6SVallish Vaidyeshwara NFS4_WAKEALL_ASYNC_WORKERS(mi->mi_async_work_cv); 442750a83466Sjwahlig mutex_exit(&mi->mi_async_lock); 442850a83466Sjwahlig if (mi->mi_manager_thread) 44297c478bd9Sstevel@tonic-gate nfs4_async_manager_stop(vfsp); 44307c478bd9Sstevel@tonic-gate 44317c478bd9Sstevel@tonic-gate destroy_rtable4(vfsp, cr); 44327c478bd9Sstevel@tonic-gate 44337c478bd9Sstevel@tonic-gate nfs4_remove_mi_from_server(mi, NULL); 44347c478bd9Sstevel@tonic-gate 44357c478bd9Sstevel@tonic-gate if (async_thread) { 44367c478bd9Sstevel@tonic-gate mutex_enter(&cpr_lock); 44377c478bd9Sstevel@tonic-gate CALLB_CPR_EXIT(&cpr_info); /* drops cpr_lock */ 44387c478bd9Sstevel@tonic-gate mutex_destroy(&cpr_lock); 44397c478bd9Sstevel@tonic-gate } 444050a83466Sjwahlig 444150a83466Sjwahlig removed = nfs4_mi_zonelist_remove(mi); 444250a83466Sjwahlig if (removed) 4443a19609f8Sjv227347 zone_rele_ref(&mi->mi_zone_ref, ZONE_REF_NFSV4); 44447c478bd9Sstevel@tonic-gate } 44452f172c55SRobert Thurlow 44462f172c55SRobert Thurlow /* Referral related sub-routines */ 44472f172c55SRobert Thurlow 44482f172c55SRobert Thurlow /* Freeup knetconfig */ 44492f172c55SRobert Thurlow static void 44502f172c55SRobert Thurlow free_knconf_contents(struct knetconfig *k) 44512f172c55SRobert Thurlow { 44522f172c55SRobert Thurlow if (k == NULL) 44532f172c55SRobert Thurlow return; 44542f172c55SRobert Thurlow if (k->knc_protofmly) 44552f172c55SRobert Thurlow kmem_free(k->knc_protofmly, KNC_STRSIZE); 44562f172c55SRobert Thurlow if (k->knc_proto) 44572f172c55SRobert Thurlow kmem_free(k->knc_proto, KNC_STRSIZE); 44582f172c55SRobert Thurlow } 44592f172c55SRobert Thurlow 44602f172c55SRobert Thurlow /* 44612f172c55SRobert Thurlow * This updates newpath variable with exact name component from the 44622f172c55SRobert Thurlow * path which gave us a NFS4ERR_MOVED error. 44632f172c55SRobert Thurlow * If the path is /rp/aaa/bbb and nth value is 1, aaa is returned. 44642f172c55SRobert Thurlow */ 44652f172c55SRobert Thurlow static char * 44662f172c55SRobert Thurlow extract_referral_point(const char *svp, int nth) 44672f172c55SRobert Thurlow { 44682f172c55SRobert Thurlow int num_slashes = 0; 44692f172c55SRobert Thurlow const char *p; 44702f172c55SRobert Thurlow char *newpath = NULL; 44712f172c55SRobert Thurlow int i = 0; 44722f172c55SRobert Thurlow 44732f172c55SRobert Thurlow newpath = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 44742f172c55SRobert Thurlow for (p = svp; *p; p++) { 44752f172c55SRobert Thurlow if (*p == '/') 44762f172c55SRobert Thurlow num_slashes++; 44772f172c55SRobert Thurlow if (num_slashes == nth + 1) { 44782f172c55SRobert Thurlow p++; 44792f172c55SRobert Thurlow while (*p != '/') { 44802f172c55SRobert Thurlow if (*p == '\0') 44812f172c55SRobert Thurlow break; 44822f172c55SRobert Thurlow newpath[i] = *p; 44832f172c55SRobert Thurlow i++; 44842f172c55SRobert Thurlow p++; 44852f172c55SRobert Thurlow } 44862f172c55SRobert Thurlow newpath[i++] = '\0'; 44872f172c55SRobert Thurlow break; 44882f172c55SRobert Thurlow } 44892f172c55SRobert Thurlow } 44902f172c55SRobert Thurlow return (newpath); 44912f172c55SRobert Thurlow } 44922f172c55SRobert Thurlow 44932f172c55SRobert Thurlow /* 44942f172c55SRobert Thurlow * This sets up a new path in sv_path to do a lookup of the referral point. 44952f172c55SRobert Thurlow * If the path is /rp/aaa/bbb and the referral point is aaa, 44962f172c55SRobert Thurlow * this updates /rp/aaa. This path will be used to get referral 44972f172c55SRobert Thurlow * location. 44982f172c55SRobert Thurlow */ 44992f172c55SRobert Thurlow static void 45002f172c55SRobert Thurlow setup_newsvpath(servinfo4_t *svp, int nth) 45012f172c55SRobert Thurlow { 45022f172c55SRobert Thurlow int num_slashes = 0, pathlen, i = 0; 45032f172c55SRobert Thurlow char *newpath, *p; 45042f172c55SRobert Thurlow 45052f172c55SRobert Thurlow newpath = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 45062f172c55SRobert Thurlow for (p = svp->sv_path; *p; p++) { 45072f172c55SRobert Thurlow newpath[i] = *p; 45082f172c55SRobert Thurlow if (*p == '/') 45092f172c55SRobert Thurlow num_slashes++; 45102f172c55SRobert Thurlow if (num_slashes == nth + 1) { 45112f172c55SRobert Thurlow newpath[i] = '\0'; 45122f172c55SRobert Thurlow pathlen = strlen(newpath) + 1; 45132f172c55SRobert Thurlow kmem_free(svp->sv_path, svp->sv_pathlen); 45142f172c55SRobert Thurlow svp->sv_path = kmem_alloc(pathlen, KM_SLEEP); 45152f172c55SRobert Thurlow svp->sv_pathlen = pathlen; 45162f172c55SRobert Thurlow bcopy(newpath, svp->sv_path, pathlen); 45172f172c55SRobert Thurlow break; 45182f172c55SRobert Thurlow } 45192f172c55SRobert Thurlow i++; 45202f172c55SRobert Thurlow } 45212f172c55SRobert Thurlow kmem_free(newpath, MAXPATHLEN); 45222f172c55SRobert Thurlow } 4523