17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5f86c6ccaSdm  * Common Development and Distribution License (the "License").
6f86c6ccaSdm  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
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 {
88b9238976Sth 	vfs_t	*fm_vfsp;
89b9238976Sth 	int	fm_flag;
90b9238976Sth 	cred_t	*fm_cr;
917c478bd9Sstevel@tonic-gate } freemountargs_t;
927c478bd9Sstevel@tonic-gate 
93b9238976Sth static void	async_free_mount(vfs_t *, int, cred_t *);
94b9238976Sth 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  */
140b9238976Sth 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 
163b9238976Sth extern void nfs4_ephemeral_init(void);
164b9238976Sth extern void nfs4_ephemeral_fini(void);
165b9238976Sth 
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
nfs4init(int fstyp,char * name)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 },
200aa59c4cbSrsb 		NULL,			NULL
2017c478bd9Sstevel@tonic-gate 	};
2027c478bd9Sstevel@tonic-gate 	int error;
2037c478bd9Sstevel@tonic-gate 
204b9238976Sth 	nfs4_vfsops = NULL;
205b9238976Sth 	nfs4_vnodeops = NULL;
206b9238976Sth 	nfs4_trigger_vnodeops = NULL;
207b9238976Sth 
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");
212b9238976Sth 		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");
219b9238976Sth 		goto out;
2207c478bd9Sstevel@tonic-gate 	}
2217c478bd9Sstevel@tonic-gate 
222b9238976Sth 	error = vn_make_ops("nfs4_trigger", nfs4_trigger_vnodeops_template,
223b9238976Sth 	    &nfs4_trigger_vnodeops);
224b9238976Sth 	if (error != 0) {
225b9238976Sth 		zcmn_err(GLOBAL_ZONEID, CE_WARN,
226b9238976Sth 		    "nfs4init: bad trigger vnode ops template");
227b9238976Sth 		goto out;
228b9238976Sth 	}
2297c478bd9Sstevel@tonic-gate 
230b9238976Sth 	nfs4fstyp = fstyp;
2317c478bd9Sstevel@tonic-gate 	(void) nfs4_vfsinit();
2327c478bd9Sstevel@tonic-gate 	(void) nfs4_init_dot_entries();
2337c478bd9Sstevel@tonic-gate 
234b9238976Sth out:
235b9238976Sth 	if (error) {
236b9238976Sth 		if (nfs4_trigger_vnodeops != NULL)
237b9238976Sth 			vn_freevnodeops(nfs4_trigger_vnodeops);
238b9238976Sth 
239b9238976Sth 		if (nfs4_vnodeops != NULL)
240b9238976Sth 			vn_freevnodeops(nfs4_vnodeops);
241b9238976Sth 
242b9238976Sth 		(void) vfs_freevfsops_by_type(fstyp);
243b9238976Sth 	}
244b9238976Sth 
245b9238976Sth 	return (error);
2467c478bd9Sstevel@tonic-gate }
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate void
nfs4fini(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  */
263b9238976Sth static struct sec_data *
create_authdh_data(char * netname,int nlen,struct netbuf * syncaddr,struct knetconfig * knconf)2647c478bd9Sstevel@tonic-gate create_authdh_data(char *netname, int nlen, struct netbuf *syncaddr,
265a17ce845SMarcel Telka     struct knetconfig *knconf)
266a17ce845SMarcel Telka {
2677c478bd9Sstevel@tonic-gate 	struct sec_data *secdata;
2687c478bd9Sstevel@tonic-gate 	dh_k4_clntdata_t *data;
2697c478bd9Sstevel@tonic-gate 	char *pf, *p;
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	if (syncaddr == NULL || syncaddr->buf == NULL || nlen == 0)
2727c478bd9Sstevel@tonic-gate 		return (NULL);
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	secdata = kmem_alloc(sizeof (*secdata), KM_SLEEP);
2757c478bd9Sstevel@tonic-gate 	secdata->flags = 0;
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	data = kmem_alloc(sizeof (*data), KM_SLEEP);
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	data->syncaddr.maxlen = syncaddr->maxlen;
2807c478bd9Sstevel@tonic-gate 	data->syncaddr.len = syncaddr->len;
2817c478bd9Sstevel@tonic-gate 	data->syncaddr.buf = (char *)kmem_alloc(syncaddr->len, KM_SLEEP);
2827c478bd9Sstevel@tonic-gate 	bcopy(syncaddr->buf, data->syncaddr.buf, syncaddr->len);
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	/*
2857c478bd9Sstevel@tonic-gate 	 * duplicate the knconf information for the
2867c478bd9Sstevel@tonic-gate 	 * new opaque data.
2877c478bd9Sstevel@tonic-gate 	 */
2887c478bd9Sstevel@tonic-gate 	data->knconf = kmem_alloc(sizeof (*knconf), KM_SLEEP);
2897c478bd9Sstevel@tonic-gate 	*data->knconf = *knconf;
2907c478bd9Sstevel@tonic-gate 	pf = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
2917c478bd9Sstevel@tonic-gate 	p = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
2927c478bd9Sstevel@tonic-gate 	bcopy(knconf->knc_protofmly, pf, KNC_STRSIZE);
2937c478bd9Sstevel@tonic-gate 	bcopy(knconf->knc_proto, p, KNC_STRSIZE);
2947c478bd9Sstevel@tonic-gate 	data->knconf->knc_protofmly = pf;
2957c478bd9Sstevel@tonic-gate 	data->knconf->knc_proto = p;
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	/* move server netname to the sec_data structure */
2987c478bd9Sstevel@tonic-gate 	data->netname = kmem_alloc(nlen, KM_SLEEP);
2997c478bd9Sstevel@tonic-gate 	bcopy(netname, data->netname, nlen);
3007c478bd9Sstevel@tonic-gate 	data->netnamelen = (int)nlen;
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	secdata->secmod = AUTH_DH;
3037c478bd9Sstevel@tonic-gate 	secdata->rpcflavor = AUTH_DH;
3047c478bd9Sstevel@tonic-gate 	secdata->data = (caddr_t)data;
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	return (secdata);
3077c478bd9Sstevel@tonic-gate }
3087c478bd9Sstevel@tonic-gate 
309b9238976Sth /*
310b9238976Sth  * Returns (deep) copy of sec_data_t. Allocates all memory required; caller
311b9238976Sth  * is responsible for freeing.
312b9238976Sth  */
313b9238976Sth sec_data_t *
copy_sec_data(sec_data_t * fsecdata)314a17ce845SMarcel Telka copy_sec_data(sec_data_t *fsecdata)
315a17ce845SMarcel Telka {
316b9238976Sth 	sec_data_t *tsecdata;
317b9238976Sth 
318b9238976Sth 	if (fsecdata == NULL)
319b9238976Sth 		return (NULL);
320b9238976Sth 
321b9238976Sth 	if (fsecdata->rpcflavor == AUTH_DH) {
322b9238976Sth 		dh_k4_clntdata_t *fdata = (dh_k4_clntdata_t *)fsecdata->data;
323b9238976Sth 
324b9238976Sth 		if (fdata == NULL)
325b9238976Sth 			return (NULL);
326b9238976Sth 
327b9238976Sth 		tsecdata = (sec_data_t *)create_authdh_data(fdata->netname,
328b9238976Sth 		    fdata->netnamelen, &fdata->syncaddr, fdata->knconf);
329b9238976Sth 
330b9238976Sth 		return (tsecdata);
331b9238976Sth 	}
332b9238976Sth 
333b9238976Sth 	tsecdata = kmem_zalloc(sizeof (sec_data_t), KM_SLEEP);
334b9238976Sth 
335b9238976Sth 	tsecdata->secmod = fsecdata->secmod;
336b9238976Sth 	tsecdata->rpcflavor = fsecdata->rpcflavor;
337b9238976Sth 	tsecdata->flags = fsecdata->flags;
338b9238976Sth 	tsecdata->uid = fsecdata->uid;
339b9238976Sth 
340b9238976Sth 	if (fsecdata->rpcflavor == RPCSEC_GSS) {
341b9238976Sth 		gss_clntdata_t *gcd = (gss_clntdata_t *)fsecdata->data;
342b9238976Sth 
343b9238976Sth 		tsecdata->data = (caddr_t)copy_sec_data_gss(gcd);
344b9238976Sth 	} else {
345b9238976Sth 		tsecdata->data = NULL;
346b9238976Sth 	}
347b9238976Sth 
348b9238976Sth 	return (tsecdata);
349b9238976Sth }
350b9238976Sth 
351b9238976Sth gss_clntdata_t *
copy_sec_data_gss(gss_clntdata_t * fdata)352b9238976Sth copy_sec_data_gss(gss_clntdata_t *fdata)
353b9238976Sth {
354b9238976Sth 	gss_clntdata_t *tdata;
355b9238976Sth 
356b9238976Sth 	if (fdata == NULL)
357b9238976Sth 		return (NULL);
358b9238976Sth 
359b9238976Sth 	tdata = kmem_zalloc(sizeof (gss_clntdata_t), KM_SLEEP);
360b9238976Sth 
361b9238976Sth 	tdata->mechanism.length = fdata->mechanism.length;
362b9238976Sth 	tdata->mechanism.elements = kmem_zalloc(fdata->mechanism.length,
363b9238976Sth 	    KM_SLEEP);
364b9238976Sth 	bcopy(fdata->mechanism.elements, tdata->mechanism.elements,
365b9238976Sth 	    fdata->mechanism.length);
366b9238976Sth 
367b9238976Sth 	tdata->service = fdata->service;
368b9238976Sth 
369b9238976Sth 	(void) strcpy(tdata->uname, fdata->uname);
370b9238976Sth 	(void) strcpy(tdata->inst, fdata->inst);
371b9238976Sth 	(void) strcpy(tdata->realm, fdata->realm);
372b9238976Sth 
373b9238976Sth 	tdata->qop = fdata->qop;
374b9238976Sth 
375b9238976Sth 	return (tdata);
376b9238976Sth }
377b9238976Sth 
3787c478bd9Sstevel@tonic-gate static int
nfs4_chkdup_servinfo4(servinfo4_t * svp_head,servinfo4_t * svp)3797c478bd9Sstevel@tonic-gate nfs4_chkdup_servinfo4(servinfo4_t *svp_head, servinfo4_t *svp)
3807c478bd9Sstevel@tonic-gate {
3817c478bd9Sstevel@tonic-gate 	servinfo4_t *si;
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	/*
3847c478bd9Sstevel@tonic-gate 	 * Iterate over the servinfo4 list to make sure
3857c478bd9Sstevel@tonic-gate 	 * we do not have a duplicate. Skip any servinfo4
3867c478bd9Sstevel@tonic-gate 	 * that has been marked "NOT IN USE"
3877c478bd9Sstevel@tonic-gate 	 */
3887c478bd9Sstevel@tonic-gate 	for (si = svp_head; si; si = si->sv_next) {
3897c478bd9Sstevel@tonic-gate 		(void) nfs_rw_enter_sig(&si->sv_lock, RW_READER, 0);
3907c478bd9Sstevel@tonic-gate 		if (si->sv_flags & SV4_NOTINUSE) {
3917c478bd9Sstevel@tonic-gate 			nfs_rw_exit(&si->sv_lock);
3927c478bd9Sstevel@tonic-gate 			continue;
3937c478bd9Sstevel@tonic-gate 		}
3947c478bd9Sstevel@tonic-gate 		nfs_rw_exit(&si->sv_lock);
3957c478bd9Sstevel@tonic-gate 		if (si == svp)
3967c478bd9Sstevel@tonic-gate 			continue;
3977c478bd9Sstevel@tonic-gate 		if (si->sv_addr.len == svp->sv_addr.len &&
3987c478bd9Sstevel@tonic-gate 		    strcmp(si->sv_knconf->knc_protofmly,
399b9238976Sth 		    svp->sv_knconf->knc_protofmly) == 0 &&
4007c478bd9Sstevel@tonic-gate 		    bcmp(si->sv_addr.buf, svp->sv_addr.buf,
401b9238976Sth 		    si->sv_addr.len) == 0) {
4027c478bd9Sstevel@tonic-gate 			/* it's a duplicate */
4037c478bd9Sstevel@tonic-gate 			return (1);
4047c478bd9Sstevel@tonic-gate 		}
4057c478bd9Sstevel@tonic-gate 	}
4067c478bd9Sstevel@tonic-gate 	/* it's not a duplicate */
4077c478bd9Sstevel@tonic-gate 	return (0);
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate 
41039d3e169Sevanl void
nfs4_free_args(struct nfs_args * nargs)41139d3e169Sevanl nfs4_free_args(struct nfs_args *nargs)
41239d3e169Sevanl {
41339d3e169Sevanl 	if (nargs->knconf) {
41439d3e169Sevanl 		if (nargs->knconf->knc_protofmly)
41539d3e169Sevanl 			kmem_free(nargs->knconf->knc_protofmly,
416b9238976Sth 			    KNC_STRSIZE);
41739d3e169Sevanl 		if (nargs->knconf->knc_proto)
41839d3e169Sevanl 			kmem_free(nargs->knconf->knc_proto, KNC_STRSIZE);
41939d3e169Sevanl 		kmem_free(nargs->knconf, sizeof (*nargs->knconf));
42039d3e169Sevanl 		nargs->knconf = NULL;
42139d3e169Sevanl 	}
42239d3e169Sevanl 
42339d3e169Sevanl 	if (nargs->fh) {
42439d3e169Sevanl 		kmem_free(nargs->fh, strlen(nargs->fh) + 1);
42539d3e169Sevanl 		nargs->fh = NULL;
42639d3e169Sevanl 	}
42739d3e169Sevanl 
42839d3e169Sevanl 	if (nargs->hostname) {
42939d3e169Sevanl 		kmem_free(nargs->hostname, strlen(nargs->hostname) + 1);
43039d3e169Sevanl 		nargs->hostname = NULL;
43139d3e169Sevanl 	}
43239d3e169Sevanl 
43339d3e169Sevanl 	if (nargs->addr) {
43439d3e169Sevanl 		if (nargs->addr->buf) {
43539d3e169Sevanl 			ASSERT(nargs->addr->len);
43639d3e169Sevanl 			kmem_free(nargs->addr->buf, nargs->addr->len);
43739d3e169Sevanl 		}
43839d3e169Sevanl 		kmem_free(nargs->addr, sizeof (struct netbuf));
43939d3e169Sevanl 		nargs->addr = NULL;
44039d3e169Sevanl 	}
44139d3e169Sevanl 
44239d3e169Sevanl 	if (nargs->syncaddr) {
44339d3e169Sevanl 		ASSERT(nargs->syncaddr->len);
44439d3e169Sevanl 		if (nargs->syncaddr->buf) {
44539d3e169Sevanl 			ASSERT(nargs->syncaddr->len);
44639d3e169Sevanl 			kmem_free(nargs->syncaddr->buf, nargs->syncaddr->len);
44739d3e169Sevanl 		}
44839d3e169Sevanl 		kmem_free(nargs->syncaddr, sizeof (struct netbuf));
44939d3e169Sevanl 		nargs->syncaddr = NULL;
45039d3e169Sevanl 	}
45139d3e169Sevanl 
45239d3e169Sevanl 	if (nargs->netname) {
45339d3e169Sevanl 		kmem_free(nargs->netname, strlen(nargs->netname) + 1);
45439d3e169Sevanl 		nargs->netname = NULL;
45539d3e169Sevanl 	}
45639d3e169Sevanl 
45739d3e169Sevanl 	if (nargs->nfs_ext_u.nfs_extA.secdata) {
45839d3e169Sevanl 		sec_clnt_freeinfo(
459b9238976Sth 		    nargs->nfs_ext_u.nfs_extA.secdata);
46039d3e169Sevanl 		nargs->nfs_ext_u.nfs_extA.secdata = NULL;
46139d3e169Sevanl 	}
46239d3e169Sevanl }
46339d3e169Sevanl 
46439d3e169Sevanl 
46539d3e169Sevanl int
nfs4_copyin(char * data,int datalen,struct nfs_args * nargs)46639d3e169Sevanl nfs4_copyin(char *data, int datalen, struct nfs_args *nargs)
46739d3e169Sevanl {
46839d3e169Sevanl 
46939d3e169Sevanl 	int error;
47039d3e169Sevanl 	size_t hlen;			/* length of hostname */
47139d3e169Sevanl 	size_t nlen;			/* length of netname */
47239d3e169Sevanl 	char netname[MAXNETNAMELEN+1];	/* server's netname */
47339d3e169Sevanl 	struct netbuf addr;		/* server's address */
47439d3e169Sevanl 	struct netbuf syncaddr;		/* AUTH_DES time sync addr */
47539d3e169Sevanl 	struct knetconfig *knconf;		/* transport structure */
47639d3e169Sevanl 	struct sec_data *secdata = NULL;	/* security data */
47739d3e169Sevanl 	STRUCT_DECL(nfs_args, args);		/* nfs mount arguments */
47839d3e169Sevanl 	STRUCT_DECL(knetconfig, knconf_tmp);
47939d3e169Sevanl 	STRUCT_DECL(netbuf, addr_tmp);
48039d3e169Sevanl 	int flags;
48139d3e169Sevanl 	char *p, *pf;
48239d3e169Sevanl 	struct pathname pn;
48339d3e169Sevanl 	char *userbufptr;
48439d3e169Sevanl 
48539d3e169Sevanl 
48639d3e169Sevanl 	bzero(nargs, sizeof (*nargs));
48739d3e169Sevanl 
48839d3e169Sevanl 	STRUCT_INIT(args, get_udatamodel());
48939d3e169Sevanl 	bzero(STRUCT_BUF(args), SIZEOF_STRUCT(nfs_args, DATAMODEL_NATIVE));
49039d3e169Sevanl 	if (copyin(data, STRUCT_BUF(args), MIN(datalen,
49139d3e169Sevanl 	    STRUCT_SIZE(args))))
49239d3e169Sevanl 		return (EFAULT);
49339d3e169Sevanl 
49439d3e169Sevanl 	nargs->wsize = STRUCT_FGET(args, wsize);
49539d3e169Sevanl 	nargs->rsize = STRUCT_FGET(args, rsize);
49639d3e169Sevanl 	nargs->timeo = STRUCT_FGET(args, timeo);
49739d3e169Sevanl 	nargs->retrans = STRUCT_FGET(args, retrans);
49839d3e169Sevanl 	nargs->acregmin = STRUCT_FGET(args, acregmin);
49939d3e169Sevanl 	nargs->acregmax = STRUCT_FGET(args, acregmax);
50039d3e169Sevanl 	nargs->acdirmin = STRUCT_FGET(args, acdirmin);
50139d3e169Sevanl 	nargs->acdirmax = STRUCT_FGET(args, acdirmax);
50239d3e169Sevanl 
50339d3e169Sevanl 	flags = STRUCT_FGET(args, flags);
50439d3e169Sevanl 	nargs->flags = flags;
50539d3e169Sevanl 
50639d3e169Sevanl 	addr.buf = NULL;
50739d3e169Sevanl 	syncaddr.buf = NULL;
50839d3e169Sevanl 
50939d3e169Sevanl 
51039d3e169Sevanl 	/*
51139d3e169Sevanl 	 * Allocate space for a knetconfig structure and
51239d3e169Sevanl 	 * its strings and copy in from user-land.
51339d3e169Sevanl 	 */
51439d3e169Sevanl 	knconf = kmem_zalloc(sizeof (*knconf), KM_SLEEP);
51539d3e169Sevanl 	STRUCT_INIT(knconf_tmp, get_udatamodel());
51639d3e169Sevanl 	if (copyin(STRUCT_FGETP(args, knconf), STRUCT_BUF(knconf_tmp),
51739d3e169Sevanl 	    STRUCT_SIZE(knconf_tmp))) {
51839d3e169Sevanl 		kmem_free(knconf, sizeof (*knconf));
51939d3e169Sevanl 		return (EFAULT);
52039d3e169Sevanl 	}
52139d3e169Sevanl 
52239d3e169Sevanl 	knconf->knc_semantics = STRUCT_FGET(knconf_tmp, knc_semantics);
52339d3e169Sevanl 	knconf->knc_protofmly = STRUCT_FGETP(knconf_tmp, knc_protofmly);
52439d3e169Sevanl 	knconf->knc_proto = STRUCT_FGETP(knconf_tmp, knc_proto);
52539d3e169Sevanl 	if (get_udatamodel() != DATAMODEL_LP64) {
52639d3e169Sevanl 		knconf->knc_rdev = expldev(STRUCT_FGET(knconf_tmp, knc_rdev));
52739d3e169Sevanl 	} else {
52839d3e169Sevanl 		knconf->knc_rdev = STRUCT_FGET(knconf_tmp, knc_rdev);
52939d3e169Sevanl 	}
53039d3e169Sevanl 
53139d3e169Sevanl 	pf = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
53239d3e169Sevanl 	p = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
53339d3e169Sevanl 	error = copyinstr(knconf->knc_protofmly, pf, KNC_STRSIZE, NULL);
53439d3e169Sevanl 	if (error) {
53539d3e169Sevanl 		kmem_free(pf, KNC_STRSIZE);
53639d3e169Sevanl 		kmem_free(p, KNC_STRSIZE);
53739d3e169Sevanl 		kmem_free(knconf, sizeof (*knconf));
53839d3e169Sevanl 		return (error);
53939d3e169Sevanl 	}
54039d3e169Sevanl 
54139d3e169Sevanl 	error = copyinstr(knconf->knc_proto, p, KNC_STRSIZE, NULL);
54239d3e169Sevanl 	if (error) {
54339d3e169Sevanl 		kmem_free(pf, KNC_STRSIZE);
54439d3e169Sevanl 		kmem_free(p, KNC_STRSIZE);
54539d3e169Sevanl 		kmem_free(knconf, sizeof (*knconf));
54639d3e169Sevanl 		return (error);
54739d3e169Sevanl 	}
54839d3e169Sevanl 
54939d3e169Sevanl 
55039d3e169Sevanl 	knconf->knc_protofmly = pf;
55139d3e169Sevanl 	knconf->knc_proto = p;
55239d3e169Sevanl 
55339d3e169Sevanl 	nargs->knconf = knconf;
55439d3e169Sevanl 
55539d3e169Sevanl 	/*
55639d3e169Sevanl 	 * Get server address
55739d3e169Sevanl 	 */
55839d3e169Sevanl 	STRUCT_INIT(addr_tmp, get_udatamodel());
55939d3e169Sevanl 	if (copyin(STRUCT_FGETP(args, addr), STRUCT_BUF(addr_tmp),
56039d3e169Sevanl 	    STRUCT_SIZE(addr_tmp))) {
56139d3e169Sevanl 		error = EFAULT;
56239d3e169Sevanl 		goto errout;
56339d3e169Sevanl 	}
56439d3e169Sevanl 
5657e450cbcSJames Wahlig 	nargs->addr = kmem_zalloc(sizeof (struct netbuf), KM_SLEEP);
56639d3e169Sevanl 	userbufptr = STRUCT_FGETP(addr_tmp, buf);
56739d3e169Sevanl 	addr.len = STRUCT_FGET(addr_tmp, len);
56839d3e169Sevanl 	addr.buf = kmem_alloc(addr.len, KM_SLEEP);
56939d3e169Sevanl 	addr.maxlen = addr.len;
57039d3e169Sevanl 	if (copyin(userbufptr, addr.buf, addr.len)) {
57139d3e169Sevanl 		kmem_free(addr.buf, addr.len);
57239d3e169Sevanl 		error = EFAULT;
57339d3e169Sevanl 		goto errout;
57439d3e169Sevanl 	}
57539d3e169Sevanl 	bcopy(&addr, nargs->addr, sizeof (struct netbuf));
57639d3e169Sevanl 
57739d3e169Sevanl 	/*
57839d3e169Sevanl 	 * Get the root fhandle
57939d3e169Sevanl 	 */
58039d3e169Sevanl 	error = pn_get(STRUCT_FGETP(args, fh), UIO_USERSPACE, &pn);
58139d3e169Sevanl 	if (error)
58239d3e169Sevanl 		goto errout;
58339d3e169Sevanl 
58439d3e169Sevanl 	/* Volatile fh: keep server paths, so use actual-size strings */
58539d3e169Sevanl 	nargs->fh = kmem_alloc(pn.pn_pathlen + 1, KM_SLEEP);
58639d3e169Sevanl 	bcopy(pn.pn_path, nargs->fh, pn.pn_pathlen);
58739d3e169Sevanl 	nargs->fh[pn.pn_pathlen] = '\0';
58839d3e169Sevanl 	pn_free(&pn);
58939d3e169Sevanl 
59039d3e169Sevanl 
59139d3e169Sevanl 	/*
59239d3e169Sevanl 	 * Get server's hostname
59339d3e169Sevanl 	 */
59439d3e169Sevanl 	if (flags & NFSMNT_HOSTNAME) {
59539d3e169Sevanl 		error = copyinstr(STRUCT_FGETP(args, hostname),
596b9238976Sth 		    netname, sizeof (netname), &hlen);
59739d3e169Sevanl 		if (error)
59839d3e169Sevanl 			goto errout;
59939d3e169Sevanl 		nargs->hostname = kmem_zalloc(hlen, KM_SLEEP);
60039d3e169Sevanl 		(void) strcpy(nargs->hostname, netname);
60139d3e169Sevanl 
60239d3e169Sevanl 	} else {
60339d3e169Sevanl 		nargs->hostname = NULL;
60439d3e169Sevanl 	}
60539d3e169Sevanl 
60639d3e169Sevanl 
60739d3e169Sevanl 	/*
60839d3e169Sevanl 	 * If there are syncaddr and netname data, load them in. This is
60939d3e169Sevanl 	 * to support data needed for NFSV4 when AUTH_DH is the negotiated
61039d3e169Sevanl 	 * flavor via SECINFO. (instead of using MOUNT protocol in V3).
61139d3e169Sevanl 	 */
61239d3e169Sevanl 	netname[0] = '\0';
61339d3e169Sevanl 	if (flags & NFSMNT_SECURE) {
61439d3e169Sevanl 
61539d3e169Sevanl 		/* get syncaddr */
61639d3e169Sevanl 		STRUCT_INIT(addr_tmp, get_udatamodel());
61739d3e169Sevanl 		if (copyin(STRUCT_FGETP(args, syncaddr), STRUCT_BUF(addr_tmp),
618b9238976Sth 		    STRUCT_SIZE(addr_tmp))) {
61939d3e169Sevanl 			error = EINVAL;
62039d3e169Sevanl 			goto errout;
62139d3e169Sevanl 		}
62239d3e169Sevanl 		userbufptr = STRUCT_FGETP(addr_tmp, buf);
62339d3e169Sevanl 		syncaddr.len = STRUCT_FGET(addr_tmp, len);
62439d3e169Sevanl 		syncaddr.buf = kmem_alloc(syncaddr.len, KM_SLEEP);
62539d3e169Sevanl 		syncaddr.maxlen = syncaddr.len;
62639d3e169Sevanl 		if (copyin(userbufptr, syncaddr.buf, syncaddr.len)) {
62739d3e169Sevanl 			kmem_free(syncaddr.buf, syncaddr.len);
62839d3e169Sevanl 			error = EFAULT;
62939d3e169Sevanl 			goto errout;
63039d3e169Sevanl 		}
63139d3e169Sevanl 
63239d3e169Sevanl 		nargs->syncaddr = kmem_alloc(sizeof (struct netbuf), KM_SLEEP);
63339d3e169Sevanl 		bcopy(&syncaddr, nargs->syncaddr, sizeof (struct netbuf));
63439d3e169Sevanl 
63522d5e933Skr 		/* get server's netname */
63622d5e933Skr 		if (copyinstr(STRUCT_FGETP(args, netname), netname,
637b9238976Sth 		    sizeof (netname), &nlen)) {
63822d5e933Skr 			error = EFAULT;
63922d5e933Skr 			goto errout;
64022d5e933Skr 		}
64122d5e933Skr 
64222d5e933Skr 		netname[nlen] = '\0';
64322d5e933Skr 		nargs->netname = kmem_zalloc(nlen, KM_SLEEP);
64422d5e933Skr 		(void) strcpy(nargs->netname, netname);
64522d5e933Skr 	}
64639d3e169Sevanl 
64739d3e169Sevanl 	/*
64839d3e169Sevanl 	 * Get the extention data which has the security data structure.
64939d3e169Sevanl 	 * This includes data for AUTH_SYS as well.
65039d3e169Sevanl 	 */
65139d3e169Sevanl 	if (flags & NFSMNT_NEWARGS) {
65239d3e169Sevanl 		nargs->nfs_args_ext = STRUCT_FGET(args, nfs_args_ext);
65339d3e169Sevanl 		if (nargs->nfs_args_ext == NFS_ARGS_EXTA ||
654b9238976Sth 		    nargs->nfs_args_ext == NFS_ARGS_EXTB) {
65539d3e169Sevanl 			/*
65639d3e169Sevanl 			 * Indicating the application is using the new
65739d3e169Sevanl 			 * sec_data structure to pass in the security
65839d3e169Sevanl 			 * data.
65939d3e169Sevanl 			 */
66039d3e169Sevanl 			if (STRUCT_FGETP(args,
66139d3e169Sevanl 			    nfs_ext_u.nfs_extA.secdata) != NULL) {
66239d3e169Sevanl 				error = sec_clnt_loadinfo(
66339d3e169Sevanl 				    (struct sec_data *)STRUCT_FGETP(args,
664b9238976Sth 				    nfs_ext_u.nfs_extA.secdata),
66539d3e169Sevanl 				    &secdata, get_udatamodel());
66639d3e169Sevanl 			}
66739d3e169Sevanl 			nargs->nfs_ext_u.nfs_extA.secdata = secdata;
66839d3e169Sevanl 		}
66939d3e169Sevanl 	}
67039d3e169Sevanl 
67139d3e169Sevanl 	if (error)
67239d3e169Sevanl 		goto errout;
67339d3e169Sevanl 
67439d3e169Sevanl 	/*
67539d3e169Sevanl 	 * Failover support:
67639d3e169Sevanl 	 *
67739d3e169Sevanl 	 * We may have a linked list of nfs_args structures,
67839d3e169Sevanl 	 * which means the user is looking for failover.  If
67939d3e169Sevanl 	 * the mount is either not "read-only" or "soft",
68039d3e169Sevanl 	 * we want to bail out with EINVAL.
68139d3e169Sevanl 	 */
68239d3e169Sevanl 	if (nargs->nfs_args_ext == NFS_ARGS_EXTB)
68339d3e169Sevanl 		nargs->nfs_ext_u.nfs_extB.next =
684b9238976Sth 		    STRUCT_FGETP(args, nfs_ext_u.nfs_extB.next);
68539d3e169Sevanl 
68639d3e169Sevanl errout:
68739d3e169Sevanl 	if (error)
68839d3e169Sevanl 		nfs4_free_args(nargs);
68939d3e169Sevanl 
69039d3e169Sevanl 	return (error);
69139d3e169Sevanl }
69239d3e169Sevanl 
69339d3e169Sevanl 
6947c478bd9Sstevel@tonic-gate /*
6957c478bd9Sstevel@tonic-gate  * nfs mount vfsop
6967c478bd9Sstevel@tonic-gate  * Set up mount info record and attach it to vfs struct.
6977c478bd9Sstevel@tonic-gate  */
698b9238976Sth int
nfs4_mount(vfs_t * vfsp,vnode_t * mvp,struct mounta * uap,cred_t * cr)6997c478bd9Sstevel@tonic-gate nfs4_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
7007c478bd9Sstevel@tonic-gate {
7017c478bd9Sstevel@tonic-gate 	char *data = uap->dataptr;
7027c478bd9Sstevel@tonic-gate 	int error;
7037c478bd9Sstevel@tonic-gate 	vnode_t *rtvp;			/* the server's root */
7047c478bd9Sstevel@tonic-gate 	mntinfo4_t *mi;			/* mount info, pointed at by vfs */
7057c478bd9Sstevel@tonic-gate 	struct knetconfig *rdma_knconf;	/* rdma transport structure */
7067c478bd9Sstevel@tonic-gate 	rnode4_t *rp;
7077c478bd9Sstevel@tonic-gate 	struct servinfo4 *svp;		/* nfs server info */
7087c478bd9Sstevel@tonic-gate 	struct servinfo4 *svp_tail = NULL; /* previous nfs server info */
7097c478bd9Sstevel@tonic-gate 	struct servinfo4 *svp_head;	/* first nfs server info */
7107c478bd9Sstevel@tonic-gate 	struct servinfo4 *svp_2ndlast;	/* 2nd last in server info list */
7117c478bd9Sstevel@tonic-gate 	struct sec_data *secdata;	/* security data */
71239d3e169Sevanl 	struct nfs_args *args = NULL;
71350a83466Sjwahlig 	int flags, addr_type, removed;
714108322fbScarlsonj 	zone_t *zone = nfs_zone();
7157c478bd9Sstevel@tonic-gate 	nfs4_error_t n4e;
71645916cd2Sjpk 	zone_t *mntzone = NULL;
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 	if (secpolicy_fs_mount(cr, mvp, vfsp) != 0)
7197c478bd9Sstevel@tonic-gate 		return (EPERM);
7207c478bd9Sstevel@tonic-gate 	if (mvp->v_type != VDIR)
7217c478bd9Sstevel@tonic-gate 		return (ENOTDIR);
722b9238976Sth 
7237c478bd9Sstevel@tonic-gate 	/*
7247c478bd9Sstevel@tonic-gate 	 * get arguments
7257c478bd9Sstevel@tonic-gate 	 *
7267c478bd9Sstevel@tonic-gate 	 * nfs_args is now versioned and is extensible, so
7277c478bd9Sstevel@tonic-gate 	 * uap->datalen might be different from sizeof (args)
7287c478bd9Sstevel@tonic-gate 	 * in a compatible situation.
7297c478bd9Sstevel@tonic-gate 	 */
7307c478bd9Sstevel@tonic-gate more:
73139d3e169Sevanl 	if (!(uap->flags & MS_SYSSPACE)) {
73239d3e169Sevanl 		if (args == NULL)
73339d3e169Sevanl 			args = kmem_zalloc(sizeof (struct nfs_args), KM_SLEEP);
73439d3e169Sevanl 		else
73539d3e169Sevanl 			nfs4_free_args(args);
73639d3e169Sevanl 		error = nfs4_copyin(data, uap->datalen, args);
73739d3e169Sevanl 		if (error) {
73839d3e169Sevanl 			if (args) {
73939d3e169Sevanl 				kmem_free(args, sizeof (*args));
74039d3e169Sevanl 			}
74139d3e169Sevanl 			return (error);
74239d3e169Sevanl 		}
74339d3e169Sevanl 	} else {
74439d3e169Sevanl 		args = (struct nfs_args *)data;
74539d3e169Sevanl 	}
7467c478bd9Sstevel@tonic-gate 
74739d3e169Sevanl 	flags = args->flags;
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	/*
7507c478bd9Sstevel@tonic-gate 	 * If the request changes the locking type, disallow the remount,
7517c478bd9Sstevel@tonic-gate 	 * because it's questionable whether we can transfer the
7527c478bd9Sstevel@tonic-gate 	 * locking state correctly.
7537c478bd9Sstevel@tonic-gate 	 */
7547c478bd9Sstevel@tonic-gate 	if (uap->flags & MS_REMOUNT) {
75539d3e169Sevanl 		if (!(uap->flags & MS_SYSSPACE)) {
75639d3e169Sevanl 			nfs4_free_args(args);
75739d3e169Sevanl 			kmem_free(args, sizeof (*args));
75839d3e169Sevanl 		}
7597c478bd9Sstevel@tonic-gate 		if ((mi = VFTOMI4(vfsp)) != NULL) {
7607c478bd9Sstevel@tonic-gate 			uint_t new_mi_llock;
7617c478bd9Sstevel@tonic-gate 			uint_t old_mi_llock;
7627c478bd9Sstevel@tonic-gate 			new_mi_llock = (flags & NFSMNT_LLOCK) ? 1 : 0;
7637c478bd9Sstevel@tonic-gate 			old_mi_llock = (mi->mi_flags & MI4_LLOCK) ? 1 : 0;
7647c478bd9Sstevel@tonic-gate 			if (old_mi_llock != new_mi_llock)
7657c478bd9Sstevel@tonic-gate 				return (EBUSY);
7667c478bd9Sstevel@tonic-gate 		}
7677c478bd9Sstevel@tonic-gate 		return (0);
7687c478bd9Sstevel@tonic-gate 	}
7697c478bd9Sstevel@tonic-gate 
770b9238976Sth 	/*
771b9238976Sth 	 * For ephemeral mount trigger stub vnodes, we have two problems
772b9238976Sth 	 * to solve: racing threads will likely fail the v_count check, and
773b9238976Sth 	 * we want only one to proceed with the mount.
774b9238976Sth 	 *
775b9238976Sth 	 * For stubs, if the mount has already occurred (via a racing thread),
776b9238976Sth 	 * just return success. If not, skip the v_count check and proceed.
777b9238976Sth 	 * Note that we are already serialised at this point.
778b9238976Sth 	 */
7797c478bd9Sstevel@tonic-gate 	mutex_enter(&mvp->v_lock);
780b9238976Sth 	if (vn_matchops(mvp, nfs4_trigger_vnodeops)) {
781b9238976Sth 		/* mntpt is a v4 stub vnode */
782b9238976Sth 		ASSERT(RP_ISSTUB(VTOR4(mvp)));
783b9238976Sth 		ASSERT(!(uap->flags & MS_OVERLAY));
784b9238976Sth 		ASSERT(!(mvp->v_flag & VROOT));
785b9238976Sth 		if (vn_mountedvfs(mvp) != NULL) {
786b9238976Sth 			/* ephemeral mount has already occurred */
787b9238976Sth 			ASSERT(uap->flags & MS_SYSSPACE);
788b9238976Sth 			mutex_exit(&mvp->v_lock);
789b9238976Sth 			return (0);
790b9238976Sth 		}
791b9238976Sth 	} else {
792b9238976Sth 		/* mntpt is a non-v4 or v4 non-stub vnode */
793b9238976Sth 		if (!(uap->flags & MS_OVERLAY) &&
794b9238976Sth 		    (mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
795b9238976Sth 			mutex_exit(&mvp->v_lock);
796b9238976Sth 			if (!(uap->flags & MS_SYSSPACE)) {
797b9238976Sth 				nfs4_free_args(args);
798b9238976Sth 				kmem_free(args, sizeof (*args));
799b9238976Sth 			}
800b9238976Sth 			return (EBUSY);
80139d3e169Sevanl 		}
8027c478bd9Sstevel@tonic-gate 	}
8037c478bd9Sstevel@tonic-gate 	mutex_exit(&mvp->v_lock);
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 	/* make sure things are zeroed for errout: */
8067c478bd9Sstevel@tonic-gate 	rtvp = NULL;
8077c478bd9Sstevel@tonic-gate 	mi = NULL;
8087c478bd9Sstevel@tonic-gate 	secdata = NULL;
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	/*
8117c478bd9Sstevel@tonic-gate 	 * A valid knetconfig structure is required.
8127c478bd9Sstevel@tonic-gate 	 */
81339d3e169Sevanl 	if (!(flags & NFSMNT_KNCONF) ||
814b9238976Sth 	    args->knconf == NULL || args->knconf->knc_protofmly == NULL ||
815b9238976Sth 	    args->knconf->knc_proto == NULL ||
816b9238976Sth 	    (strcmp(args->knconf->knc_proto, NC_UDP) == 0)) {
81739d3e169Sevanl 		if (!(uap->flags & MS_SYSSPACE)) {
81839d3e169Sevanl 			nfs4_free_args(args);
81939d3e169Sevanl 			kmem_free(args, sizeof (*args));
82039d3e169Sevanl 		}
8217c478bd9Sstevel@tonic-gate 		return (EINVAL);
82239d3e169Sevanl 	}
82339d3e169Sevanl 
82439d3e169Sevanl 	if ((strlen(args->knconf->knc_protofmly) >= KNC_STRSIZE) ||
825b9238976Sth 	    (strlen(args->knconf->knc_proto) >= KNC_STRSIZE)) {
82639d3e169Sevanl 		if (!(uap->flags & MS_SYSSPACE)) {
82739d3e169Sevanl 			nfs4_free_args(args);
82839d3e169Sevanl 			kmem_free(args, sizeof (*args));
82939d3e169Sevanl 		}
83039d3e169Sevanl 		return (EINVAL);
83139d3e169Sevanl 	}
83239d3e169Sevanl 
8337c478bd9Sstevel@tonic-gate 	/*
8347c478bd9Sstevel@tonic-gate 	 * Allocate a servinfo4 struct.
8357c478bd9Sstevel@tonic-gate 	 */
8367c478bd9Sstevel@tonic-gate 	svp = kmem_zalloc(sizeof (*svp), KM_SLEEP);
8377c478bd9Sstevel@tonic-gate 	nfs_rw_init(&svp->sv_lock, NULL, RW_DEFAULT, NULL);
8387c478bd9Sstevel@tonic-gate 	if (svp_tail) {
8397c478bd9Sstevel@tonic-gate 		svp_2ndlast = svp_tail;
8407c478bd9Sstevel@tonic-gate 		svp_tail->sv_next = svp;
8417c478bd9Sstevel@tonic-gate 	} else {
8427c478bd9Sstevel@tonic-gate 		svp_head = svp;
8437c478bd9Sstevel@tonic-gate 		svp_2ndlast = svp;
8447c478bd9Sstevel@tonic-gate 	}
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 	svp_tail = svp;
84739d3e169Sevanl 	svp->sv_knconf = args->knconf;
84839d3e169Sevanl 	args->knconf = NULL;
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 	/*
8517c478bd9Sstevel@tonic-gate 	 * Get server address
8527c478bd9Sstevel@tonic-gate 	 */
85339d3e169Sevanl 	if (args->addr == NULL || args->addr->buf == NULL) {
85439d3e169Sevanl 		error = EINVAL;
8557c478bd9Sstevel@tonic-gate 		goto errout;
8567c478bd9Sstevel@tonic-gate 	}
8577c478bd9Sstevel@tonic-gate 
85839d3e169Sevanl 	svp->sv_addr.maxlen = args->addr->maxlen;
85939d3e169Sevanl 	svp->sv_addr.len = args->addr->len;
86039d3e169Sevanl 	svp->sv_addr.buf = args->addr->buf;
86139d3e169Sevanl 	args->addr->buf = NULL;
86239d3e169Sevanl 
8637c478bd9Sstevel@tonic-gate 	/*
8647c478bd9Sstevel@tonic-gate 	 * Get the root fhandle
8657c478bd9Sstevel@tonic-gate 	 */
86639d3e169Sevanl 	if (args->fh == NULL || (strlen(args->fh) >= MAXPATHLEN)) {
86739d3e169Sevanl 		error = EINVAL;
8687c478bd9Sstevel@tonic-gate 		goto errout;
86939d3e169Sevanl 	}
8707c478bd9Sstevel@tonic-gate 
87139d3e169Sevanl 	svp->sv_path = args->fh;
87239d3e169Sevanl 	svp->sv_pathlen = strlen(args->fh) + 1;
87339d3e169Sevanl 	args->fh = NULL;
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	/*
8767c478bd9Sstevel@tonic-gate 	 * Get server's hostname
8777c478bd9Sstevel@tonic-gate 	 */
8787c478bd9Sstevel@tonic-gate 	if (flags & NFSMNT_HOSTNAME) {
87939d3e169Sevanl 		if (args->hostname == NULL || (strlen(args->hostname) >
880b9238976Sth 		    MAXNETNAMELEN)) {
88139d3e169Sevanl 			error = EINVAL;
8827c478bd9Sstevel@tonic-gate 			goto errout;
88339d3e169Sevanl 		}
88439d3e169Sevanl 		svp->sv_hostnamelen = strlen(args->hostname) + 1;
88539d3e169Sevanl 		svp->sv_hostname = args->hostname;
88639d3e169Sevanl 		args->hostname = NULL;
8877c478bd9Sstevel@tonic-gate 	} else {
8887c478bd9Sstevel@tonic-gate 		char *p = "unknown-host";
88939d3e169Sevanl 		svp->sv_hostnamelen = strlen(p) + 1;
89039d3e169Sevanl 		svp->sv_hostname = kmem_zalloc(svp->sv_hostnamelen, KM_SLEEP);
89139d3e169Sevanl 		(void) strcpy(svp->sv_hostname, p);
8927c478bd9Sstevel@tonic-gate 	}
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 	/*
8957c478bd9Sstevel@tonic-gate 	 * RDMA MOUNT SUPPORT FOR NFS v4.
8967c478bd9Sstevel@tonic-gate 	 * Establish, is it possible to use RDMA, if so overload the
8977c478bd9Sstevel@tonic-gate 	 * knconf with rdma specific knconf and free the orignal knconf.
8987c478bd9Sstevel@tonic-gate 	 */
8997c478bd9Sstevel@tonic-gate 	if ((flags & NFSMNT_TRYRDMA) || (flags & NFSMNT_DORDMA)) {
9007c478bd9Sstevel@tonic-gate 		/*
9017c478bd9Sstevel@tonic-gate 		 * Determine the addr type for RDMA, IPv4 or v6.
9027c478bd9Sstevel@tonic-gate 		 */
9037c478bd9Sstevel@tonic-gate 		if (strcmp(svp->sv_knconf->knc_protofmly, NC_INET) == 0)
9047c478bd9Sstevel@tonic-gate 			addr_type = AF_INET;
9057c478bd9Sstevel@tonic-gate 		else if (strcmp(svp->sv_knconf->knc_protofmly, NC_INET6) == 0)
9067c478bd9Sstevel@tonic-gate 			addr_type = AF_INET6;
9077c478bd9Sstevel@tonic-gate 
908