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