xref: /illumos-gate/usr/src/uts/common/fs/nfs/nfs4_subr.c (revision a17ce845)
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
545916cd2Sjpk  * Common Development and Distribution License (the "License").
645916cd2Sjpk  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22416a371aSGerald Thornbrugh  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
2515721462SDaniil Lunev /*
2615721462SDaniil Lunev  * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
2715721462SDaniil Lunev  */
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  *  	Copyright (c) 1983,1984,1985,1986,1987,1988,1989  AT&T.
317c478bd9Sstevel@tonic-gate  *	All Rights Reserved
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <sys/param.h>
357c478bd9Sstevel@tonic-gate #include <sys/types.h>
367c478bd9Sstevel@tonic-gate #include <sys/systm.h>
377c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
387c478bd9Sstevel@tonic-gate #include <sys/vtrace.h>
397c478bd9Sstevel@tonic-gate #include <sys/session.h>
407c478bd9Sstevel@tonic-gate #include <sys/thread.h>
417c478bd9Sstevel@tonic-gate #include <sys/dnlc.h>
42cbc96f51Sjwahlig #include <sys/cred.h>
43cbc96f51Sjwahlig #include <sys/priv.h>
447c478bd9Sstevel@tonic-gate #include <sys/list.h>
457c478bd9Sstevel@tonic-gate #include <sys/sdt.h>
4645916cd2Sjpk #include <sys/policy.h>
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate #include <rpc/types.h>
497c478bd9Sstevel@tonic-gate #include <rpc/xdr.h>
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate #include <nfs/nfs.h>
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate #include <nfs/nfs_clnt.h>
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate #include <nfs/nfs4.h>
567c478bd9Sstevel@tonic-gate #include <nfs/rnode4.h>
577c478bd9Sstevel@tonic-gate #include <nfs/nfs4_clnt.h>
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate /*
607c478bd9Sstevel@tonic-gate  * client side statistics
617c478bd9Sstevel@tonic-gate  */
627c478bd9Sstevel@tonic-gate static const struct clstat4 clstat4_tmpl = {
637c478bd9Sstevel@tonic-gate 	{ "calls",	KSTAT_DATA_UINT64 },
647c478bd9Sstevel@tonic-gate 	{ "badcalls",	KSTAT_DATA_UINT64 },
652f172c55SRobert Thurlow 	{ "referrals",	KSTAT_DATA_UINT64 },
662f172c55SRobert Thurlow 	{ "referlinks",	KSTAT_DATA_UINT64 },
677c478bd9Sstevel@tonic-gate 	{ "clgets",	KSTAT_DATA_UINT64 },
687c478bd9Sstevel@tonic-gate 	{ "cltoomany",	KSTAT_DATA_UINT64 },
697c478bd9Sstevel@tonic-gate #ifdef DEBUG
707c478bd9Sstevel@tonic-gate 	{ "clalloc",	KSTAT_DATA_UINT64 },
717c478bd9Sstevel@tonic-gate 	{ "noresponse",	KSTAT_DATA_UINT64 },
727c478bd9Sstevel@tonic-gate 	{ "failover",	KSTAT_DATA_UINT64 },
737c478bd9Sstevel@tonic-gate 	{ "remap",	KSTAT_DATA_UINT64 },
747c478bd9Sstevel@tonic-gate #endif
757c478bd9Sstevel@tonic-gate };
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate #ifdef DEBUG
787c478bd9Sstevel@tonic-gate struct clstat4_debug clstat4_debug = {
797c478bd9Sstevel@tonic-gate 	{ "nrnode",	KSTAT_DATA_UINT64 },
807c478bd9Sstevel@tonic-gate 	{ "access",	KSTAT_DATA_UINT64 },
817c478bd9Sstevel@tonic-gate 	{ "dirent",	KSTAT_DATA_UINT64 },
827c478bd9Sstevel@tonic-gate 	{ "dirents",	KSTAT_DATA_UINT64 },
837c478bd9Sstevel@tonic-gate 	{ "reclaim",	KSTAT_DATA_UINT64 },
847c478bd9Sstevel@tonic-gate 	{ "clreclaim",	KSTAT_DATA_UINT64 },
857c478bd9Sstevel@tonic-gate 	{ "f_reclaim",	KSTAT_DATA_UINT64 },
867c478bd9Sstevel@tonic-gate 	{ "a_reclaim",	KSTAT_DATA_UINT64 },
877c478bd9Sstevel@tonic-gate 	{ "r_reclaim",	KSTAT_DATA_UINT64 },
887c478bd9Sstevel@tonic-gate 	{ "r_path",	KSTAT_DATA_UINT64 },
897c478bd9Sstevel@tonic-gate };
907c478bd9Sstevel@tonic-gate #endif
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate /*
937c478bd9Sstevel@tonic-gate  * We keep a global list of per-zone client data, so we can clean up all zones
947c478bd9Sstevel@tonic-gate  * if we get low on memory.
957c478bd9Sstevel@tonic-gate  */
967c478bd9Sstevel@tonic-gate static list_t nfs4_clnt_list;
977c478bd9Sstevel@tonic-gate static kmutex_t nfs4_clnt_list_lock;
982f172c55SRobert Thurlow zone_key_t nfs4clnt_zone_key;
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate static struct kmem_cache *chtab4_cache;
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate #ifdef DEBUG
1037c478bd9Sstevel@tonic-gate static int nfs4_rfscall_debug;
1047c478bd9Sstevel@tonic-gate static int nfs4_try_failover_any;
1057c478bd9Sstevel@tonic-gate int nfs4_utf8_debug = 0;
1067c478bd9Sstevel@tonic-gate #endif
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate /*
1097c478bd9Sstevel@tonic-gate  * NFSv4 readdir cache implementation
1107c478bd9Sstevel@tonic-gate  */
1117c478bd9Sstevel@tonic-gate typedef struct rddir4_cache_impl {
1127c478bd9Sstevel@tonic-gate 	rddir4_cache	rc;		/* readdir cache element */
1137c478bd9Sstevel@tonic-gate 	kmutex_t	lock;		/* lock protects count */
1147c478bd9Sstevel@tonic-gate 	uint_t		count;		/* reference count */
1157c478bd9Sstevel@tonic-gate 	avl_node_t	tree;		/* AVL tree link */
1167c478bd9Sstevel@tonic-gate } rddir4_cache_impl;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate static int rddir4_cache_compar(const void *, const void *);
1197c478bd9Sstevel@tonic-gate static void rddir4_cache_free(rddir4_cache_impl *);
1207c478bd9Sstevel@tonic-gate static rddir4_cache *rddir4_cache_alloc(int);
1217c478bd9Sstevel@tonic-gate static void rddir4_cache_hold(rddir4_cache *);
1227c478bd9Sstevel@tonic-gate static int try_failover(enum clnt_stat);
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate static int nfs4_readdir_cache_hits = 0;
1257c478bd9Sstevel@tonic-gate static int nfs4_readdir_cache_waits = 0;
1267c478bd9Sstevel@tonic-gate static int nfs4_readdir_cache_misses = 0;
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate /*
1297c478bd9Sstevel@tonic-gate  * Shared nfs4 functions
1307c478bd9Sstevel@tonic-gate  */
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate /*
1337c478bd9Sstevel@tonic-gate  * Copy an nfs_fh4.  The destination storage (to->nfs_fh4_val) must already
1347c478bd9Sstevel@tonic-gate  * be allocated.
1357c478bd9Sstevel@tonic-gate  */
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate void
nfs_fh4_copy(nfs_fh4 * from,nfs_fh4 * to)1387c478bd9Sstevel@tonic-gate nfs_fh4_copy(nfs_fh4 *from, nfs_fh4 *to)
1397c478bd9Sstevel@tonic-gate {
1407c478bd9Sstevel@tonic-gate 	to->nfs_fh4_len = from->nfs_fh4_len;
1417c478bd9Sstevel@tonic-gate 	bcopy(from->nfs_fh4_val, to->nfs_fh4_val, to->nfs_fh4_len);
1427c478bd9Sstevel@tonic-gate }
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate /*
1457c478bd9Sstevel@tonic-gate  * nfs4cmpfh - compare 2 filehandles.
1467c478bd9Sstevel@tonic-gate  * Returns 0 if the two nfsv4 filehandles are the same, -1 if the first is
1477c478bd9Sstevel@tonic-gate  * "less" than the second, +1 if the first is "greater" than the second.
1487c478bd9Sstevel@tonic-gate  */
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate int
nfs4cmpfh(const nfs_fh4 * fh4p1,const nfs_fh4 * fh4p2)1517c478bd9Sstevel@tonic-gate nfs4cmpfh(const nfs_fh4 *fh4p1, const nfs_fh4 *fh4p2)
1527c478bd9Sstevel@tonic-gate {
1537c478bd9Sstevel@tonic-gate 	const char *c1, *c2;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	if (fh4p1->nfs_fh4_len < fh4p2->nfs_fh4_len)
1567c478bd9Sstevel@tonic-gate 		return (-1);
1577c478bd9Sstevel@tonic-gate 	if (fh4p1->nfs_fh4_len > fh4p2->nfs_fh4_len)
1587c478bd9Sstevel@tonic-gate 		return (1);
1597c478bd9Sstevel@tonic-gate 	for (c1 = fh4p1->nfs_fh4_val, c2 = fh4p2->nfs_fh4_val;
1607c478bd9Sstevel@tonic-gate 	    c1 < fh4p1->nfs_fh4_val + fh4p1->nfs_fh4_len;
1617c478bd9Sstevel@tonic-gate 	    c1++, c2++) {
1627c478bd9Sstevel@tonic-gate 		if (*c1 < *c2)
1637c478bd9Sstevel@tonic-gate 			return (-1);
1647c478bd9Sstevel@tonic-gate 		if (*c1 > *c2)
1657c478bd9Sstevel@tonic-gate 			return (1);
1667c478bd9Sstevel@tonic-gate 	}
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	return (0);
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate /*
1727c478bd9Sstevel@tonic-gate  * Compare two v4 filehandles.  Return zero if they're the same, non-zero
1737c478bd9Sstevel@tonic-gate  * if they're not.  Like nfs4cmpfh(), but different filehandle
1747c478bd9Sstevel@tonic-gate  * representation, and doesn't provide information about greater than or
1757c478bd9Sstevel@tonic-gate  * less than.
1767c478bd9Sstevel@tonic-gate  */
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate int
nfs4cmpfhandle(nfs4_fhandle_t * fh1,nfs4_fhandle_t * fh2)1797c478bd9Sstevel@tonic-gate nfs4cmpfhandle(nfs4_fhandle_t *fh1, nfs4_fhandle_t *fh2)
1807c478bd9Sstevel@tonic-gate {
1817c478bd9Sstevel@tonic-gate 	if (fh1->fh_len == fh2->fh_len)
1827c478bd9Sstevel@tonic-gate 		return (bcmp(fh1->fh_buf, fh2->fh_buf, fh1->fh_len));
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	return (1);
1857c478bd9Sstevel@tonic-gate }
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate int
stateid4_cmp(stateid4 * s1,stateid4 * s2)1887c478bd9Sstevel@tonic-gate stateid4_cmp(stateid4 *s1, stateid4 *s2)
1897c478bd9Sstevel@tonic-gate {
1907c478bd9Sstevel@tonic-gate 	if (bcmp(s1, s2, sizeof (stateid4)) == 0)
1917c478bd9Sstevel@tonic-gate 		return (1);
1927c478bd9Sstevel@tonic-gate 	else
1937c478bd9Sstevel@tonic-gate 		return (0);
1947c478bd9Sstevel@tonic-gate }
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate nfsstat4
puterrno4(int error)1977c478bd9Sstevel@tonic-gate puterrno4(int error)
1987c478bd9Sstevel@tonic-gate {
1997c478bd9Sstevel@tonic-gate 	switch (error) {
2007c478bd9Sstevel@tonic-gate 	case 0:
2017c478bd9Sstevel@tonic-gate 		return (NFS4_OK);
2027c478bd9Sstevel@tonic-gate 	case EPERM:
2037c478bd9Sstevel@tonic-gate 		return (NFS4ERR_PERM);
2047c478bd9Sstevel@tonic-gate 	case ENOENT:
2057c478bd9Sstevel@tonic-gate 		return (NFS4ERR_NOENT);
2067c478bd9Sstevel@tonic-gate 	case EINTR:
2077c478bd9Sstevel@tonic-gate 		return (NFS4ERR_IO);
2087c478bd9Sstevel@tonic-gate 	case EIO:
2097c478bd9Sstevel@tonic-gate 		return (NFS4ERR_IO);
2107c478bd9Sstevel@tonic-gate 	case ENXIO:
2117c478bd9Sstevel@tonic-gate 		return (NFS4ERR_NXIO);
2127c478bd9Sstevel@tonic-gate 	case ENOMEM:
2137c478bd9Sstevel@tonic-gate 		return (NFS4ERR_RESOURCE);
2147c478bd9Sstevel@tonic-gate 	case EACCES:
2157c478bd9Sstevel@tonic-gate 		return (NFS4ERR_ACCESS);
2167c478bd9Sstevel@tonic-gate 	case EBUSY:
2177c478bd9Sstevel@tonic-gate 		return (NFS4ERR_IO);
2187c478bd9Sstevel@tonic-gate 	case EEXIST:
2197c478bd9Sstevel@tonic-gate 		return (NFS4ERR_EXIST);
2207c478bd9Sstevel@tonic-gate 	case EXDEV:
2217c478bd9Sstevel@tonic-gate 		return (NFS4ERR_XDEV);
2227c478bd9Sstevel@tonic-gate 	case ENODEV:
2237c478bd9Sstevel@tonic-gate 		return (NFS4ERR_IO);
2247c478bd9Sstevel@tonic-gate 	case ENOTDIR:
2257c478bd9Sstevel@tonic-gate 		return (NFS4ERR_NOTDIR);
2267c478bd9Sstevel@tonic-gate 	case EISDIR:
2277c478bd9Sstevel@tonic-gate 		return (NFS4ERR_ISDIR);
2287c478bd9Sstevel@tonic-gate 	case EINVAL:
2297c478bd9Sstevel@tonic-gate 		return (NFS4ERR_INVAL);
2307c478bd9Sstevel@tonic-gate 	case EMFILE:
2317c478bd9Sstevel@tonic-gate 		return (NFS4ERR_RESOURCE);
2327c478bd9Sstevel@tonic-gate 	case EFBIG:
2337c478bd9Sstevel@tonic-gate 		return (NFS4ERR_FBIG);
2347c478bd9Sstevel@tonic-gate 	case ENOSPC:
2357c478bd9Sstevel@tonic-gate 		return (NFS4ERR_NOSPC);
2367c478bd9Sstevel@tonic-gate 	case EROFS:
2377c478bd9Sstevel@tonic-gate 		return (NFS4ERR_ROFS);
2387c478bd9Sstevel@tonic-gate 	case EMLINK:
2397c478bd9Sstevel@tonic-gate 		return (NFS4ERR_MLINK);
2407c478bd9Sstevel@tonic-gate 	case EDEADLK:
2417c478bd9Sstevel@tonic-gate 		return (NFS4ERR_DEADLOCK);
2427c478bd9Sstevel@tonic-gate 	case ENOLCK:
2437c478bd9Sstevel@tonic-gate 		return (NFS4ERR_DENIED);
2447c478bd9Sstevel@tonic-gate 	case EREMOTE:
2457c478bd9Sstevel@tonic-gate 		return (NFS4ERR_SERVERFAULT);
2467c478bd9Sstevel@tonic-gate 	case ENOTSUP:
2477c478bd9Sstevel@tonic-gate 		return (NFS4ERR_NOTSUPP);
2487c478bd9Sstevel@tonic-gate 	case EDQUOT:
2497c478bd9Sstevel@tonic-gate 		return (NFS4ERR_DQUOT);
2507c478bd9Sstevel@tonic-gate 	case ENAMETOOLONG:
2517c478bd9Sstevel@tonic-gate 		return (NFS4ERR_NAMETOOLONG);
2527c478bd9Sstevel@tonic-gate 	case EOVERFLOW:
2537c478bd9Sstevel@tonic-gate 		return (NFS4ERR_INVAL);
2547c478bd9Sstevel@tonic-gate 	case ENOSYS:
2557c478bd9Sstevel@tonic-gate 		return (NFS4ERR_NOTSUPP);
2567c478bd9Sstevel@tonic-gate 	case ENOTEMPTY:
2577c478bd9Sstevel@tonic-gate 		return (NFS4ERR_NOTEMPTY);
2587c478bd9Sstevel@tonic-gate 	case EOPNOTSUPP:
2597c478bd9Sstevel@tonic-gate 		return (NFS4ERR_NOTSUPP);
2607c478bd9Sstevel@tonic-gate 	case ESTALE:
2617c478bd9Sstevel@tonic-gate 		return (NFS4ERR_STALE);
2627c478bd9Sstevel@tonic-gate 	case EAGAIN:
2637c478bd9Sstevel@tonic-gate 		if (curthread->t_flag & T_WOULDBLOCK) {
2647c478bd9Sstevel@tonic-gate 			curthread->t_flag &= ~T_WOULDBLOCK;
2657c478bd9Sstevel@tonic-gate 			return (NFS4ERR_DELAY);
2667c478bd9Sstevel@tonic-gate 		}
2677c478bd9Sstevel@tonic-gate 		return (NFS4ERR_LOCKED);
2687c478bd9Sstevel@tonic-gate 	default:
2697c478bd9Sstevel@tonic-gate 		return ((enum nfsstat4)error);
2707c478bd9Sstevel@tonic-gate 	}
2717c478bd9Sstevel@tonic-gate }
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate int
geterrno4(enum nfsstat4 status)2747c478bd9Sstevel@tonic-gate geterrno4(enum nfsstat4 status)
2757c478bd9Sstevel@tonic-gate {
2767c478bd9Sstevel@tonic-gate 	switch (status) {
2777c478bd9Sstevel@tonic-gate 	case NFS4_OK:
2787c478bd9Sstevel@tonic-gate 		return (0);
2797c478bd9Sstevel@tonic-gate 	case NFS4ERR_PERM:
2807c478bd9Sstevel@tonic-gate 		return (EPERM);
2817c478bd9Sstevel@tonic-gate 	case NFS4ERR_NOENT:
2827c478bd9Sstevel@tonic-gate 		return (ENOENT);
2837c478bd9Sstevel@tonic-gate 	case NFS4ERR_IO:
2847c478bd9Sstevel@tonic-gate 		return (EIO);
2857c478bd9Sstevel@tonic-gate 	case NFS4ERR_NXIO:
2867c478bd9Sstevel@tonic-gate 		return (ENXIO);
2877c478bd9Sstevel@tonic-gate 	case NFS4ERR_ACCESS:
2887c478bd9Sstevel@tonic-gate 		return (EACCES);
2897c478bd9Sstevel@tonic-gate 	case NFS4ERR_EXIST:
2907c478bd9Sstevel@tonic-gate 		return (EEXIST);
2917c478bd9Sstevel@tonic-gate 	case NFS4ERR_XDEV:
2927c478bd9Sstevel@tonic-gate 		return (EXDEV);
2937c478bd9Sstevel@tonic-gate 	case NFS4ERR_NOTDIR:
2947c478bd9Sstevel@tonic-gate 		return (ENOTDIR);
2957c478bd9Sstevel@tonic-gate 	case NFS4ERR_ISDIR:
2967c478bd9Sstevel@tonic-gate 		return (EISDIR);
2977c478bd9Sstevel@tonic-gate 	case NFS4ERR_INVAL:
2987c478bd9Sstevel@tonic-gate 		return (EINVAL);
2997c478bd9Sstevel@tonic-gate 	case NFS4ERR_FBIG:
3007c478bd9Sstevel@tonic-gate 		return (EFBIG);
3017c478bd9Sstevel@tonic-gate 	case NFS4ERR_NOSPC:
3027c478bd9Sstevel@tonic-gate 		return (ENOSPC);
3037c478bd9Sstevel@tonic-gate 	case NFS4ERR_ROFS:
3047c478bd9Sstevel@tonic-gate 		return (EROFS);
3057c478bd9Sstevel@tonic-gate 	case NFS4ERR_MLINK:
3067c478bd9Sstevel@tonic-gate 		return (EMLINK);
3077c478bd9Sstevel@tonic-gate 	case NFS4ERR_NAMETOOLONG:
3087c478bd9Sstevel@tonic-gate 		return (ENAMETOOLONG);
3097c478bd9Sstevel@tonic-gate 	case NFS4ERR_NOTEMPTY:
3107c478bd9Sstevel@tonic-gate 		return (ENOTEMPTY);
3117c478bd9Sstevel@tonic-gate 	case NFS4ERR_DQUOT:
3127c478bd9Sstevel@tonic-gate 		return (EDQUOT);
3137c478bd9Sstevel@tonic-gate 	case NFS4ERR_STALE:
3147c478bd9Sstevel@tonic-gate 		return (ESTALE);
3157c478bd9Sstevel@tonic-gate 	case NFS4ERR_BADHANDLE:
3167c478bd9Sstevel@tonic-gate 		return (ESTALE);
3177c478bd9Sstevel@tonic-gate 	case NFS4ERR_BAD_COOKIE:
3187c478bd9Sstevel@tonic-gate 		return (EINVAL);
3197c478bd9Sstevel@tonic-gate 	case NFS4ERR_NOTSUPP:
3207c478bd9Sstevel@tonic-gate 		return (EOPNOTSUPP);
3217c478bd9Sstevel@tonic-gate 	case NFS4ERR_TOOSMALL:
3227c478bd9Sstevel@tonic-gate 		return (EINVAL);
3237c478bd9Sstevel@tonic-gate 	case NFS4ERR_SERVERFAULT:
3247c478bd9Sstevel@tonic-gate 		return (EIO);
3257c478bd9Sstevel@tonic-gate 	case NFS4ERR_BADTYPE:
3267c478bd9Sstevel@tonic-gate 		return (EINVAL);
3277c478bd9Sstevel@tonic-gate 	case NFS4ERR_DELAY:
3287c478bd9Sstevel@tonic-gate 		return (ENXIO);
3297c478bd9Sstevel@tonic-gate 	case NFS4ERR_SAME:
3307c478bd9Sstevel@tonic-gate 		return (EPROTO);
3317c478bd9Sstevel@tonic-gate 	case NFS4ERR_DENIED:
3327c478bd9Sstevel@tonic-gate 		return (ENOLCK);
3337c478bd9Sstevel@tonic-gate 	case NFS4ERR_EXPIRED:
3347c478bd9Sstevel@tonic-gate 		return (EPROTO);
3357c478bd9Sstevel@tonic-gate 	case NFS4ERR_LOCKED:
3367c478bd9Sstevel@tonic-gate 		return (EACCES);
3377c478bd9Sstevel@tonic-gate 	case NFS4ERR_GRACE:
3387c478bd9Sstevel@tonic-gate 		return (EAGAIN);
3397c478bd9Sstevel@tonic-gate 	case NFS4ERR_FHEXPIRED:	/* if got here, failed to get a new fh */
3407c478bd9Sstevel@tonic-gate 		return (ESTALE);
3417c478bd9Sstevel@tonic-gate 	case NFS4ERR_SHARE_DENIED:
3427c478bd9Sstevel@tonic-gate 		return (EACCES);
3437c478bd9Sstevel@tonic-gate 	case NFS4ERR_WRONGSEC:
3447c478bd9Sstevel@tonic-gate 		return (EPERM);
3457c478bd9Sstevel@tonic-gate 	case NFS4ERR_CLID_INUSE:
3467c478bd9Sstevel@tonic-gate 		return (EAGAIN);
3477c478bd9Sstevel@tonic-gate 	case NFS4ERR_RESOURCE:
3487c478bd9Sstevel@tonic-gate 		return (EAGAIN);
3497c478bd9Sstevel@tonic-gate 	case NFS4ERR_MOVED:
3507c478bd9Sstevel@tonic-gate 		return (EPROTO);
3517c478bd9Sstevel@tonic-gate 	case NFS4ERR_NOFILEHANDLE:
3527c478bd9Sstevel@tonic-gate 		return (EIO);
3537c478bd9Sstevel@tonic-gate 	case NFS4ERR_MINOR_VERS_MISMATCH:
3547c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
3557c478bd9Sstevel@tonic-gate 	case NFS4ERR_STALE_CLIENTID:
3567c478bd9Sstevel@tonic-gate 		return (EIO);
3577c478bd9Sstevel@tonic-gate 	case NFS4ERR_STALE_STATEID:
3587c478bd9Sstevel@tonic-gate 		return (EIO);
3597c478bd9Sstevel@tonic-gate 	case NFS4ERR_OLD_STATEID:
3607c478bd9Sstevel@tonic-gate 		return (EIO);
3617c478bd9Sstevel@tonic-gate 	case NFS4ERR_BAD_STATEID:
3627c478bd9Sstevel@tonic-gate 		return (EIO);
3637c478bd9Sstevel@tonic-gate 	case NFS4ERR_BAD_SEQID:
3647c478bd9Sstevel@tonic-gate 		return (EIO);
3657c478bd9Sstevel@tonic-gate 	case NFS4ERR_NOT_SAME:
3667c478bd9Sstevel@tonic-gate 		return (EPROTO);
3677c478bd9Sstevel@tonic-gate 	case NFS4ERR_LOCK_RANGE:
3687c478bd9Sstevel@tonic-gate 		return (EPROTO);
3697c478bd9Sstevel@tonic-gate 	case NFS4ERR_SYMLINK:
3707c478bd9Sstevel@tonic-gate 		return (EPROTO);
3717c478bd9Sstevel@tonic-gate 	case NFS4ERR_RESTOREFH:
3727c478bd9Sstevel@tonic-gate 		return (EPROTO);
3737c478bd9Sstevel@tonic-gate 	case NFS4ERR_LEASE_MOVED:
3747c478bd9Sstevel@tonic-gate 		return (EPROTO);
3757c478bd9Sstevel@tonic-gate 	case NFS4ERR_ATTRNOTSUPP:
3767c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
3777c478bd9Sstevel@tonic-gate 	case NFS4ERR_NO_GRACE:
3787c478bd9Sstevel@tonic-gate 		return (EPROTO);
3797c478bd9Sstevel@tonic-gate 	case NFS4ERR_RECLAIM_BAD:
3807c478bd9Sstevel@tonic-gate 		return (EPROTO);
3817c478bd9Sstevel@tonic-gate 	case NFS4ERR_RECLAIM_CONFLICT:
3827c478bd9Sstevel@tonic-gate 		return (EPROTO);
3837c478bd9Sstevel@tonic-gate 	case NFS4ERR_BADXDR:
3847c478bd9Sstevel@tonic-gate 		return (EINVAL);
3857c478bd9Sstevel@tonic-gate 	case NFS4ERR_LOCKS_HELD:
3867c478bd9Sstevel@tonic-gate 		return (EIO);
3877c478bd9Sstevel@tonic-gate 	case NFS4ERR_OPENMODE:
3887c478bd9Sstevel@tonic-gate 		return (EACCES);
3897c478bd9Sstevel@tonic-gate 	case NFS4ERR_BADOWNER:
3907c478bd9Sstevel@tonic-gate 		/*
3917c478bd9Sstevel@tonic-gate 		 * Client and server are in different DNS domains
3927c478bd9Sstevel@tonic-gate 		 * and the NFSMAPID_DOMAIN in /etc/default/nfs
3937c478bd9Sstevel@tonic-gate 		 * doesn't match.  No good answer here.  Return
3947c478bd9Sstevel@tonic-gate 		 * EACCESS, which translates to "permission denied".
3957c478bd9Sstevel@tonic-gate 		 */
3967c478bd9Sstevel@tonic-gate 		return (EACCES);
3977c478bd9Sstevel@tonic-gate 	case NFS4ERR_BADCHAR:
3987c478bd9Sstevel@tonic-gate 		return (EINVAL);
3997c478bd9Sstevel@tonic-gate 	case NFS4ERR_BADNAME:
4007c478bd9Sstevel@tonic-gate 		return (EINVAL);
4017c478bd9Sstevel@tonic-gate 	case NFS4ERR_BAD_RANGE:
4027c478bd9Sstevel@tonic-gate 		return (EIO);
4037c478bd9Sstevel@tonic-gate 	case NFS4ERR_LOCK_NOTSUPP:
4047c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
4057c478bd9Sstevel@tonic-gate 	case NFS4ERR_OP_ILLEGAL:
4067c478bd9Sstevel@tonic-gate 		return (EINVAL);
4077c478bd9Sstevel@tonic-gate 	case NFS4ERR_DEADLOCK:
4087c478bd9Sstevel@tonic-gate 		return (EDEADLK);
4097c478bd9Sstevel@tonic-gate 	case NFS4ERR_FILE_OPEN:
4107c478bd9Sstevel@tonic-gate 		return (EACCES);
4117c478bd9Sstevel@tonic-gate 	case NFS4ERR_ADMIN_REVOKED:
4127c478bd9Sstevel@tonic-gate 		return (EPROTO);
4137c478bd9Sstevel@tonic-gate 	case NFS4ERR_CB_PATH_DOWN:
4147c478bd9Sstevel@tonic-gate 		return (EPROTO);
4157c478bd9Sstevel@tonic-gate 	default:
4167c478bd9Sstevel@tonic-gate #ifdef DEBUG
4177c478bd9Sstevel@tonic-gate 		zcmn_err(getzoneid(), CE_WARN, "geterrno4: got status %d",
4187c478bd9Sstevel@tonic-gate 		    status);
4197c478bd9Sstevel@tonic-gate #endif
4207c478bd9Sstevel@tonic-gate 		return ((int)status);
4217c478bd9Sstevel@tonic-gate 	}
4227c478bd9Sstevel@tonic-gate }
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate void
nfs4_log_badowner(mntinfo4_t * mi,nfs_opnum4 op)4257c478bd9Sstevel@tonic-gate nfs4_log_badowner(mntinfo4_t *mi, nfs_opnum4 op)
4267c478bd9Sstevel@tonic-gate {
4277c478bd9Sstevel@tonic-gate 	nfs4_server_t *server;
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	/*
4307c478bd9Sstevel@tonic-gate 	 * Return if already printed/queued a msg
4317c478bd9Sstevel@tonic-gate 	 * for this mount point.
4327c478bd9Sstevel@tonic-gate 	 */
4337c478bd9Sstevel@tonic-gate 	if (mi->mi_flags & MI4_BADOWNER_DEBUG)
4347c478bd9Sstevel@tonic-gate 		return;
4357c478bd9Sstevel@tonic-gate 	/*
4367c478bd9Sstevel@tonic-gate 	 * Happens once per client <-> server pair.
4377c478bd9Sstevel@tonic-gate 	 */
4387c478bd9Sstevel@tonic-gate 	if (nfs_rw_enter_sig(&mi->mi_recovlock, RW_READER,
439b9238976Sth 	    mi->mi_flags & MI4_INT))
4407c478bd9Sstevel@tonic-gate 		return;
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	server = find_nfs4_server(mi);
4437c478bd9Sstevel@tonic-gate 	if (server == NULL) {
4447c478bd9Sstevel@tonic-gate 		nfs_rw_exit(&mi->mi_recovlock);
4457c478bd9Sstevel@tonic-gate 		return;
4467c478bd9Sstevel@tonic-gate 	}
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	if (!(server->s_flags & N4S_BADOWNER_DEBUG)) {
4497c478bd9Sstevel@tonic-gate 		zcmn_err(mi->mi_zone->zone_id, CE_WARN,
4507c478bd9Sstevel@tonic-gate 		    "!NFSMAPID_DOMAIN does not match"
4517c478bd9Sstevel@tonic-gate 		    " the server: %s domain.\n"
4527c478bd9Sstevel@tonic-gate 		    "Please check configuration",
4537c478bd9Sstevel@tonic-gate 		    mi->mi_curr_serv->sv_hostname);
4547c478bd9Sstevel@tonic-gate 		server->s_flags |= N4S_BADOWNER_DEBUG;
4557c478bd9Sstevel@tonic-gate 	}
4567c478bd9Sstevel@tonic-gate 	mutex_exit(&server->s_lock);
4577c478bd9Sstevel@tonic-gate 	nfs4_server_rele(server);
4587c478bd9Sstevel@tonic-gate 	nfs_rw_exit(&mi->mi_recovlock);
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	/*
4617c478bd9Sstevel@tonic-gate 	 * Happens once per mntinfo4_t.
4627c478bd9Sstevel@tonic-gate 	 * This error is deemed as one of the recovery facts "RF_BADOWNER",
4637c478bd9Sstevel@tonic-gate 	 * queue this in the mesg queue for this mount_info. This message
4647c478bd9Sstevel@tonic-gate 	 * is not printed, meaning its absent from id_to_dump_solo_fact()
4657c478bd9Sstevel@tonic-gate 	 * but its there for inspection if the queue is ever dumped/inspected.
4667c478bd9Sstevel@tonic-gate 	 */
4677c478bd9Sstevel@tonic-gate 	mutex_enter(&mi->mi_lock);
4687c478bd9Sstevel@tonic-gate 	if (!(mi->mi_flags & MI4_BADOWNER_DEBUG)) {
4697c478bd9Sstevel@tonic-gate 		nfs4_queue_fact(RF_BADOWNER, mi, NFS4ERR_BADOWNER, 0, op,
4707c478bd9Sstevel@tonic-gate 		    FALSE, NULL, 0, NULL);
4717c478bd9Sstevel@tonic-gate 		mi->mi_flags |= MI4_BADOWNER_DEBUG;
4727c478bd9Sstevel@tonic-gate 	}
4737c478bd9Sstevel@tonic-gate 	mutex_exit(&mi->mi_lock);
4747c478bd9Sstevel@tonic-gate }
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate int
nfs4_time_ntov(nfstime4 * ntime,timestruc_t * vatime)4777c478bd9Sstevel@tonic-gate nfs4_time_ntov(nfstime4 *ntime, timestruc_t *vatime)
4787c478bd9Sstevel@tonic-gate {
4797c478bd9Sstevel@tonic-gate 	int64_t sec;
4807c478bd9Sstevel@tonic-gate 	int32_t nsec;
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	/*
4837c478bd9Sstevel@tonic-gate 	 * Here check that the nfsv4 time is valid for the system.
4847c478bd9Sstevel@tonic-gate 	 * nfsv4 time value is a signed 64-bit, and the system time
4857c478bd9Sstevel@tonic-gate 	 * may be either int64_t or int32_t (depends on the kernel),
4867c478bd9Sstevel@tonic-gate 	 * so if the kernel is 32-bit, the nfsv4 time value may not fit.
4877c478bd9Sstevel@tonic-gate 	 */
4887c478bd9Sstevel@tonic-gate #ifndef _LP64
4897c478bd9Sstevel@tonic-gate 	if (! NFS4_TIME_OK(ntime->seconds)) {
4907c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
4917c478bd9Sstevel@tonic-gate 	}
4927c478bd9Sstevel@tonic-gate #endif
4937c478bd9Sstevel@tonic-gate 
4949720e166Sjasmith 	/* Invalid to specify 1 billion (or more) nsecs */
4959720e166Sjasmith 	if (ntime->nseconds >= 1000000000)
4969720e166Sjasmith 		return (EINVAL);
4979720e166Sjasmith 
4987c478bd9Sstevel@tonic-gate 	if (ntime->seconds < 0) {
4997c478bd9Sstevel@tonic-gate 		sec = ntime->seconds + 1;
5007c478bd9Sstevel@tonic-gate 		nsec = -1000000000 + ntime->nseconds;
5017c478bd9Sstevel@tonic-gate 	} else {
5027c478bd9Sstevel@tonic-gate 		sec = ntime->seconds;
5037c478bd9Sstevel@tonic-gate 		nsec = ntime->nseconds;
5047c478bd9Sstevel@tonic-gate 	}
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 	vatime->tv_sec = sec;
5077c478bd9Sstevel@tonic-gate 	vatime->tv_nsec = nsec;
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	return (0);
5107c478bd9Sstevel@tonic-gate }
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate int
nfs4_time_vton(timestruc_t * vatime,nfstime4 * ntime)5137c478bd9Sstevel@tonic-gate nfs4_time_vton(timestruc_t *vatime, nfstime4 *ntime)
5147c478bd9Sstevel@tonic-gate {
5157c478bd9Sstevel@tonic-gate 	int64_t sec;
5167c478bd9Sstevel@tonic-gate 	uint32_t nsec;
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	/*
5197c478bd9Sstevel@tonic-gate 	 * nfsv4 time value is a signed 64-bit, and the system time
5207c478bd9Sstevel@tonic-gate 	 * may be either int64_t or int32_t (depends on the kernel),
5217c478bd9Sstevel@tonic-gate 	 * so all system time values will fit.
5227c478bd9Sstevel@tonic-gate 	 */
5237c478bd9Sstevel@tonic-gate 	if (vatime->tv_nsec >= 0) {
5247c478bd9Sstevel@tonic-gate 		sec = vatime->tv_sec;
5257c478bd9Sstevel@tonic-gate 		nsec = vatime->tv_nsec;
5267c478bd9Sstevel@tonic-gate 	} else {
5277c478bd9Sstevel@tonic-gate 		sec = vatime->tv_sec - 1;
5287c478bd9Sstevel@tonic-gate 		nsec = 1000000000 + vatime->tv_nsec;
5297c478bd9Sstevel@tonic-gate 	}
5307c478bd9Sstevel@tonic-gate 	ntime->seconds = sec;
5317c478bd9Sstevel@tonic-gate 	ntime->nseconds = nsec;
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 	return (0);
5347c478bd9Sstevel@tonic-gate }
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate /*
5377c478bd9Sstevel@tonic-gate  * Converts a utf8 string to a valid null terminated filename string.
5387c478bd9Sstevel@tonic-gate  *
5397c478bd9Sstevel@tonic-gate  * XXX - Not actually translating the UTF-8 string as per RFC 2279.
5407c478bd9Sstevel@tonic-gate  *	 For now, just validate that the UTF-8 string off the wire
5417c478bd9Sstevel@tonic-gate  *	 does not have characters that will freak out UFS, and leave
5427c478bd9Sstevel@tonic-gate  *	 it at that.
5437c478bd9Sstevel@tonic-gate  */
5447c478bd9Sstevel@tonic-gate char *
utf8_to_fn(utf8string * u8s,uint_t * lenp,char * s)5457c478bd9Sstevel@tonic-gate utf8_to_fn(utf8string *u8s, uint_t *lenp, char *s)
5467c478bd9Sstevel@tonic-gate {
5477c478bd9Sstevel@tonic-gate 	ASSERT(lenp != NULL);
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	if (u8s == NULL || u8s->utf8string_len <= 0 ||
550b9238976Sth 	    u8s->utf8string_val == NULL)
5517c478bd9Sstevel@tonic-gate 		return (NULL);
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 	/*
5547c478bd9Sstevel@tonic-gate 	 * Check for obvious illegal filename chars
5557c478bd9Sstevel@tonic-gate 	 */
5567c478bd9Sstevel@tonic-gate 	if (utf8_strchr(u8s, '/') != NULL) {
5577c478bd9Sstevel@tonic-gate #ifdef DEBUG
5587c478bd9Sstevel@tonic-gate 		if (nfs4_utf8_debug) {
5597c478bd9Sstevel@tonic-gate 			char *path;
5607c478bd9Sstevel@tonic-gate 			int len = u8s->utf8string_len;
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 			path = kmem_alloc(len + 1, KM_SLEEP);
5637c478bd9Sstevel@tonic-gate 			bcopy(u8s->utf8string_val, path, len);
5647c478bd9Sstevel@tonic-gate 			path[len] = '\0';
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 			zcmn_err(getzoneid(), CE_WARN,
5677c478bd9Sstevel@tonic-gate 			    "Invalid UTF-8 filename: %s", path);
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 			kmem_free(path, len + 1);
5707c478bd9Sstevel@tonic-gate 		}
5717c478bd9Sstevel@tonic-gate #endif
5727c478bd9Sstevel@tonic-gate 		return (NULL);
5737c478bd9Sstevel@tonic-gate 	}
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 	return (utf8_to_str(u8s, lenp, s));
5767c478bd9Sstevel@tonic-gate }
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate /*
5797c478bd9Sstevel@tonic-gate  * Converts a utf8 string to a C string.
5807c478bd9Sstevel@tonic-gate  * kmem_allocs a new string if not supplied
5817c478bd9Sstevel@tonic-gate  */
5827c478bd9Sstevel@tonic-gate char *
utf8_to_str(utf8string * str,uint_t * lenp,char * s)5837c478bd9Sstevel@tonic-gate utf8_to_str(utf8string *str, uint_t *lenp, char *s)
5847c478bd9Sstevel@tonic-gate {
5857c478bd9Sstevel@tonic-gate 	char	*sp;
5867c478bd9Sstevel@tonic-gate 	char	*u8p;
5877c478bd9Sstevel@tonic-gate 	int	len;
5887c478bd9Sstevel@tonic-gate 	int	 i;
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 	ASSERT(lenp != NULL);
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	if (str == NULL)
5937c478bd9Sstevel@tonic-gate 		return (NULL);
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	u8p = str->utf8string_val;
5967c478bd9Sstevel@tonic-gate 	len = str->utf8string_len;
5977c478bd9Sstevel@tonic-gate 	if (len <= 0 || u8p == NULL) {
5987c478bd9Sstevel@tonic-gate 		if (s)
5997c478bd9Sstevel@tonic-gate 			*s = '\0';
6007c478bd9Sstevel@tonic-gate 		return (NULL);
6017c478bd9Sstevel@tonic-gate 	}
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	sp = s;
6047c478bd9Sstevel@tonic-gate 	if (sp == NULL)
6057c478bd9Sstevel@tonic-gate 		sp = kmem_alloc(len + 1, KM_SLEEP);
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	/*
6087c478bd9Sstevel@tonic-gate 	 * At least check for embedded nulls
6097c478bd9Sstevel@tonic-gate 	 */
6107c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
6117c478bd9Sstevel@tonic-gate 		sp[i] = u8p[i];
6127c478bd9Sstevel@tonic-gate 		if (u8p[i] == '\0') {
6137c478bd9Sstevel@tonic-gate #ifdef	DEBUG
6147c478bd9Sstevel@tonic-gate 			zcmn_err(getzoneid(), CE_WARN,
6157c478bd9Sstevel@tonic-gate 			    "Embedded NULL in UTF-8 string");
6167c478bd9Sstevel@tonic-gate #endif
6177c478bd9Sstevel@tonic-gate 			if (s == NULL)
6187c478bd9Sstevel@tonic-gate 				kmem_free(sp, len + 1);
6197c478bd9Sstevel@tonic-gate 			return (NULL);
6207c478bd9Sstevel@tonic-gate 		}
6217c478bd9Sstevel@tonic-gate 	}
6227c478bd9Sstevel@tonic-gate 	sp[len] = '\0';
6237c478bd9Sstevel@tonic-gate 	*lenp = len + 1;
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 	return (sp);
6267c478bd9Sstevel@tonic-gate }
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate /*
6297c478bd9Sstevel@tonic-gate  * str_to_utf8 - converts a null-terminated C string to a utf8 string
6307c478bd9Sstevel@tonic-gate  */
6317c478bd9Sstevel@tonic-gate utf8string *
str_to_utf8(char * nm,utf8string * str)6327c478bd9Sstevel@tonic-gate str_to_utf8(char *nm, utf8string *str)
6337c478bd9Sstevel@tonic-gate {
6347c478bd9Sstevel@tonic-gate 	int len;
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	if (str == NULL)
6377c478bd9Sstevel@tonic-gate 		return (NULL);
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 	if (nm == NULL || *nm == '\0') {
6407c478bd9Sstevel@tonic-gate 		str->utf8string_len = 0;
6417c478bd9Sstevel@tonic-gate 		str->utf8string_val = NULL;
6427c478bd9Sstevel@tonic-gate 	}
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	len = strlen(nm);
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	str->utf8string_val = kmem_alloc(len, KM_SLEEP);
6477c478bd9Sstevel@tonic-gate 	str->utf8string_len = len;
6487c478bd9Sstevel@tonic-gate 	bcopy(nm, str->utf8string_val, len);
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 	return (str);
6517c478bd9Sstevel@tonic-gate }
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate utf8string *
utf8_copy(utf8string * src,utf8string * dest)6547c478bd9Sstevel@tonic-gate utf8_copy(utf8string *src, utf8string *dest)
6557c478bd9Sstevel@tonic-gate {
6567c478bd9Sstevel@tonic-gate 	if (src == NULL)
6577c478bd9Sstevel@tonic-gate 		return (NULL);
6587c478bd9Sstevel@tonic-gate 	if (dest == NULL)
6597c478bd9Sstevel@tonic-gate 		return (NULL);
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 	if (src->utf8string_len > 0) {
6627c478bd9Sstevel@tonic-gate 		dest->utf8string_val = kmem_alloc(src->utf8string_len,
663b9238976Sth 		    KM_SLEEP);
6647c478bd9Sstevel@tonic-gate 		bcopy(src->utf8string_val, dest->utf8string_val,
665b9238976Sth 		    src->utf8string_len);
6667c478bd9Sstevel@tonic-gate 		dest->utf8string_len = src->utf8string_len;
6677c478bd9Sstevel@tonic-gate 	} else {
6687c478bd9Sstevel@tonic-gate 		dest->utf8string_val = NULL;
6697c478bd9Sstevel@tonic-gate 		dest->utf8string_len = 0;
6707c478bd9Sstevel@tonic-gate 	}
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	return (dest);
6737c478bd9Sstevel@tonic-gate }
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate int
utf8_compare(const utf8string * a,const utf8string * b)6767c478bd9Sstevel@tonic-gate utf8_compare(const utf8string *a, const utf8string *b)
6777c478bd9Sstevel@tonic-gate {
6787c478bd9Sstevel@tonic-gate 	int mlen, cmp;
6797c478bd9Sstevel@tonic-gate 	int alen, blen;
6807c478bd9Sstevel@tonic-gate 	char *aval, *bval;
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	if ((a == NULL) && (b == NULL))
6837c478bd9Sstevel@tonic-gate 		return (0);
6847c478bd9Sstevel@tonic-gate 	else if (a == NULL)
6857c478bd9Sstevel@tonic-gate 		return (-1);
6867c478bd9Sstevel@tonic-gate 	else if (b == NULL)
6877c478bd9Sstevel@tonic-gate 		return (1);
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	alen = a->utf8string_len;
6907c478bd9Sstevel@tonic-gate 	blen = b->utf8string_len;
6917c478bd9Sstevel@tonic-gate 	aval = a->utf8string_val;
6927c478bd9Sstevel@tonic-gate 	bval = b->utf8string_val;
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 	if (((alen == 0) || (aval == NULL)) &&
6957c478bd9Sstevel@tonic-gate 	    ((blen == 0) || (bval == NULL)))
6967c478bd9Sstevel@tonic-gate 		return (0);
6977c478bd9Sstevel@tonic-gate 	else if ((alen == 0) || (aval == NULL))
6987c478bd9Sstevel@tonic-gate 		return (-1);
6997c478bd9Sstevel@tonic-gate 	else if ((blen == 0) || (bval == NULL))
7007c478bd9Sstevel@tonic-gate 		return (1);
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	mlen = MIN(alen, blen);
7037c478bd9Sstevel@tonic-gate 	cmp = strncmp(aval, bval, mlen);
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	if ((cmp == 0) && (alen == blen))
7067c478bd9Sstevel@tonic-gate 		return (0);
7077c478bd9Sstevel@tonic-gate 	else if ((cmp == 0) && (alen < blen))
7087c478bd9Sstevel@tonic-gate 		return (-1);
7097c478bd9Sstevel@tonic-gate 	else if (cmp == 0)
7107c478bd9Sstevel@tonic-gate 		return (1);
7117c478bd9Sstevel@tonic-gate 	else if (cmp < 0)
7127c478bd9Sstevel@tonic-gate 		return (-1);
7137c478bd9Sstevel@tonic-gate 	return (1);
7147c478bd9Sstevel@tonic-gate }
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate /*
7177c478bd9Sstevel@tonic-gate  * utf8_dir_verify - checks that the utf8 string is valid
7187c478bd9Sstevel@tonic-gate  */
71915721462SDaniil Lunev nfsstat4
utf8_dir_verify(utf8string * str)7207c478bd9Sstevel@tonic-gate utf8_dir_verify(utf8string *str)
7217c478bd9Sstevel@tonic-gate {
7227c478bd9Sstevel@tonic-gate 	char *nm;
7237c478bd9Sstevel@tonic-gate 	int len;
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 	if (str == NULL)
72615721462SDaniil Lunev 		return (NFS4ERR_INVAL);
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate 	nm = str->utf8string_val;
7297c478bd9Sstevel@tonic-gate 	len = str->utf8string_len;
7307c478bd9Sstevel@tonic-gate 	if (nm == NULL || len == 0) {
73115721462SDaniil Lunev 		return (NFS4ERR_INVAL);
7327c478bd9Sstevel@tonic-gate 	}
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 	if (len == 1 && nm[0] == '.')
73515721462SDaniil Lunev 		return (NFS4ERR_BADNAME);
7367c478bd9Sstevel@tonic-gate 	if (len == 2 && nm[0] == '.' && nm[1] == '.')
73715721462SDaniil Lunev 		return (NFS4ERR_BADNAME);
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 	if (utf8_strchr(str, '/') != NULL)
74015721462SDaniil Lunev 		return (NFS4ERR_BADNAME);
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 	if (utf8_strchr(str, '\0') != NULL)
74315721462SDaniil Lunev 		return (NFS4ERR_BADNAME);
7447c478bd9Sstevel@tonic-gate 
7458cd69bcfSRichard Lowe 	return (NFS4_OK);
7467c478bd9Sstevel@tonic-gate }
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate /*
7497c478bd9Sstevel@tonic-gate  * from rpcsec module (common/rpcsec)
7507c478bd9Sstevel@tonic-gate  */
7517c478bd9Sstevel@tonic-gate extern int sec_clnt_geth(CLIENT *, struct sec_data *, cred_t *, AUTH **);
7527c478bd9Sstevel@tonic-gate extern void sec_clnt_freeh(AUTH *);
7537c478bd9Sstevel@tonic-gate extern void sec_clnt_freeinfo(struct sec_data *);
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate /*
7567c478bd9Sstevel@tonic-gate  * authget() gets an auth handle based on the security
7577c478bd9Sstevel@tonic-gate  * information from the servinfo in mountinfo.
7587c478bd9Sstevel@tonic-gate  * The auth handle is stored in ch_client->cl_auth.
7597c478bd9Sstevel@tonic-gate  *
7607c478bd9Sstevel@tonic-gate  * First security flavor of choice is to use sv_secdata
7617c478bd9Sstevel@tonic-gate  * which is initiated by the client. If that fails, get
7627c478bd9Sstevel@tonic-gate  * secinfo from the server and then select one from the
7637c478bd9Sstevel@tonic-gate  * server secinfo list .
7647c478bd9Sstevel@tonic-gate  *
7657c478bd9Sstevel@tonic-gate  * For RPCSEC_GSS flavor, upon success, a secure context is
7667c478bd9Sstevel@tonic-gate  * established between client and server.
7677c478bd9Sstevel@tonic-gate  */
7687c478bd9Sstevel@tonic-gate int
authget(servinfo4_t * svp,CLIENT * ch_client,cred_t * cr)7697c478bd9Sstevel@tonic-gate authget(servinfo4_t *svp, CLIENT *ch_client, cred_t *cr)
7707c478bd9Sstevel@tonic-gate {
7717c478bd9Sstevel@tonic-gate 	int error, i;
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 	/*
7747c478bd9Sstevel@tonic-gate 	 * SV4_TRYSECINFO indicates to try the secinfo list from
7757c478bd9Sstevel@tonic-gate 	 * sv_secinfo until a successful one is reached. Point
7767c478bd9Sstevel@tonic-gate 	 * sv_currsec to the selected security mechanism for
7777c478bd9Sstevel@tonic-gate 	 * later sessions.
7787c478bd9Sstevel@tonic-gate 	 */
7797c478bd9Sstevel@tonic-gate 	(void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0);
7807c478bd9Sstevel@tonic-gate 	if ((svp->sv_flags & SV4_TRYSECINFO) && svp->sv_secinfo) {
7817c478bd9Sstevel@tonic-gate 		for (i = svp->sv_secinfo->index; i < svp->sv_secinfo->count;
782b9238976Sth 		    i++) {
7837c478bd9Sstevel@tonic-gate 			if (!(error = sec_clnt_geth(ch_client,
784b9238976Sth 			    &svp->sv_secinfo->sdata[i],
785b9238976Sth 			    cr, &ch_client->cl_auth))) {
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 				svp->sv_currsec = &svp->sv_secinfo->sdata[i];
7887c478bd9Sstevel@tonic-gate 				svp->sv_secinfo->index = i;
7897c478bd9Sstevel@tonic-gate 				/* done */
7907c478bd9Sstevel@tonic-gate 				svp->sv_flags &= ~SV4_TRYSECINFO;
7917c478bd9Sstevel@tonic-gate 				break;
7927c478bd9Sstevel@tonic-gate 			}
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 			/*
7957c478bd9Sstevel@tonic-gate 			 * Allow the caller retry with the security flavor
7967c478bd9Sstevel@tonic-gate 			 * pointed by svp->sv_secinfo->index when
7977c478bd9Sstevel@tonic-gate 			 * ETIMEDOUT/ECONNRESET occurs.
7987c478bd9Sstevel@tonic-gate 			 */
7997c478bd9Sstevel@tonic-gate 			if (error == ETIMEDOUT || error == ECONNRESET) {
8007c478bd9Sstevel@tonic-gate 				svp->sv_secinfo->index = i;
8017c478bd9Sstevel@tonic-gate 				break;
8027c478bd9Sstevel@tonic-gate 			}
8037c478bd9Sstevel@tonic-gate 		}
8047c478bd9Sstevel@tonic-gate 	} else {
8057c478bd9Sstevel@tonic-gate 		/* sv_currsec points to one of the entries in sv_secinfo */
8067c478bd9Sstevel@tonic-gate 		if (svp->sv_currsec) {
8077c478bd9Sstevel@tonic-gate 			error = sec_clnt_geth(ch_client, svp->sv_currsec, cr,
808b9238976Sth 			    &ch_client->cl_auth);
8097c478bd9Sstevel@tonic-gate 		} else {
8107c478bd9Sstevel@tonic-gate 			/* If it's null, use sv_secdata. */
8117c478bd9Sstevel@tonic-gate 			error = sec_clnt_geth(ch_client, svp->sv_secdata, cr,
812b9238976Sth 			    &ch_client->cl_auth);
8137c478bd9Sstevel@tonic-gate 		}
8147c478bd9Sstevel@tonic-gate 	}
8157c478bd9Sstevel@tonic-gate 	nfs_rw_exit(&svp->sv_lock);
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 	return (error);
8187c478bd9Sstevel@tonic-gate }
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate /*
8217c478bd9Sstevel@tonic-gate  * Common handle get program for NFS, NFS ACL, and NFS AUTH client.
8227c478bd9Sstevel@tonic-gate  */
8237c478bd9Sstevel@tonic-gate int
clget4(clinfo_t * ci,servinfo4_t * svp,cred_t * cr,CLIENT ** newcl,struct chtab ** chp,struct nfs4_clnt * nfscl)8247c478bd9Sstevel@tonic-gate clget4(clinfo_t *ci, servinfo4_t *svp, cred_t *cr, CLIENT **newcl,
8257c478bd9Sstevel@tonic-gate     struct chtab **chp, struct nfs4_clnt *nfscl)
8267c478bd9Sstevel@tonic-gate {
8277c478bd9Sstevel@tonic-gate 	struct chhead *ch, *newch;
8287c478bd9Sstevel@tonic-gate 	struct chhead **plistp;
8297c478bd9Sstevel@tonic-gate 	struct chtab *cp;
8307c478bd9Sstevel@tonic-gate 	int error;
8317c478bd9Sstevel@tonic-gate 	k_sigset_t smask;
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 	if (newcl == NULL || chp == NULL || ci == NULL)
8347c478bd9Sstevel@tonic-gate 		return (EINVAL);
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 	*newcl = NULL;
8377c478bd9Sstevel@tonic-gate 	*chp = NULL;
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 	/*
8407c478bd9Sstevel@tonic-gate 	 * Find an unused handle or create one
8417c478bd9Sstevel@tonic-gate 	 */
8427c478bd9Sstevel@tonic-gate 	newch = NULL;
8437c478bd9Sstevel@tonic-gate 	nfscl->nfscl_stat.clgets.value.ui64++;
8447c478bd9Sstevel@tonic-gate top:
8457c478bd9Sstevel@tonic-gate 	/*
8467c478bd9Sstevel@tonic-gate 	 * Find the correct entry in the cache to check for free
8477c478bd9Sstevel@tonic-gate 	 * client handles.  The search is based on the RPC program
8487c478bd9Sstevel@tonic-gate 	 * number, program version number, dev_t for the transport
8497c478bd9Sstevel@tonic-gate 	 * device, and the protocol family.
8507c478bd9Sstevel@tonic-gate 	 */
8517c478bd9Sstevel@tonic-gate 	mutex_enter(&nfscl->nfscl_chtable4_lock);
8527c478bd9Sstevel@tonic-gate 	plistp = &nfscl->nfscl_chtable4;
8537c478bd9Sstevel@tonic-gate 	for (ch = nfscl->nfscl_chtable4; ch != NULL; ch = ch->ch_next) {
8547c478bd9Sstevel@tonic-gate 		if (ch->ch_prog == ci->cl_prog &&
8557c478bd9Sstevel@tonic-gate 		    ch->ch_vers == ci->cl_vers &&
8567c478bd9Sstevel@tonic-gate 		    ch->ch_dev == svp->sv_knconf->knc_rdev &&
8577c478bd9Sstevel@tonic-gate 		    (strcmp(ch->ch_protofmly,
858b9238976Sth 		    svp->sv_knconf->knc_protofmly) == 0))
8597c478bd9Sstevel@tonic-gate 			break;
8607c478bd9Sstevel@tonic-gate 		plistp = &ch->ch_next;
8617c478bd9Sstevel@tonic-gate 	}
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate 	/*
8647c478bd9Sstevel@tonic-gate 	 * If we didn't find a cache entry for this quadruple, then
8657c478bd9Sstevel@tonic-gate 	 * create one.  If we don't have one already preallocated,
8667c478bd9Sstevel@tonic-gate 	 * then drop the cache lock, create one, and then start over.
8677c478bd9Sstevel@tonic-gate 	 * If we did have a preallocated entry, then just add it to
8687c478bd9Sstevel@tonic-gate 	 * the front of the list.
8697c478bd9Sstevel@tonic-gate 	 */
8707c478bd9Sstevel@tonic-gate 	if (ch == NULL) {
8717c478bd9Sstevel@tonic-gate 		if (newch == NULL) {
8727c478bd9Sstevel@tonic-gate 			mutex_exit(&nfscl->nfscl_chtable4_lock);
8737c478bd9Sstevel@tonic-gate 			newch = kmem_alloc(sizeof (*newch), KM_SLEEP);
8747c478bd9Sstevel@tonic-gate 			newch->ch_timesused = 0;
8757c478bd9Sstevel@tonic-gate 			newch->ch_prog = ci->cl_prog;
8767c478bd9Sstevel@tonic-gate 			newch->ch_vers = ci->cl_vers;
8777c478bd9Sstevel@tonic-gate 			newch->ch_dev = svp->sv_knconf->knc_rdev;
8787c478bd9Sstevel@tonic-gate 			newch->ch_protofmly = kmem_alloc(
8797c478bd9Sstevel@tonic-gate 			    strlen(svp->sv_knconf->knc_protofmly) + 1,
8807c478bd9Sstevel@tonic-gate 			    KM_SLEEP);
8817c478bd9Sstevel@tonic-gate 			(void) strcpy(newch->ch_protofmly,
8827c478bd9Sstevel@tonic-gate 			    svp->sv_knconf->knc_protofmly);
8837c478bd9Sstevel@tonic-gate 			newch->ch_list = NULL;
8847c478bd9Sstevel@tonic-gate 			goto top;
8857c478bd9Sstevel@tonic-gate 		}
8867c478bd9Sstevel@tonic-gate 		ch = newch;
8877c478bd9Sstevel@tonic-gate 		newch = NULL;
8887c478bd9Sstevel@tonic-gate 		ch->ch_next = nfscl->nfscl_chtable4;
8897c478bd9Sstevel@tonic-gate 		nfscl->nfscl_chtable4 = ch;
8907c478bd9Sstevel@tonic-gate 	/*
8917c478bd9Sstevel@tonic-gate 	 * We found a cache entry, but if it isn't on the front of the
8927c478bd9Sstevel@tonic-gate 	 * list, then move it to the front of the list to try to take
8937c478bd9Sstevel@tonic-gate 	 * advantage of locality of operations.
8947c478bd9Sstevel@tonic-gate 	 */
8957c478bd9Sstevel@tonic-gate 	} else if (ch != nfscl->nfscl_chtable4) {
8967c478bd9Sstevel@tonic-gate 		*plistp = ch->ch_next;
8977c478bd9Sstevel@tonic-gate 		ch->ch_next = nfscl->nfscl_chtable4;
8987c478bd9Sstevel@tonic-gate 		nfscl->nfscl_chtable4 = ch;
8997c478bd9Sstevel@tonic-gate 	}
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 	/*
9027c478bd9Sstevel@tonic-gate 	 * If there was a free client handle cached, then remove it
9037c478bd9Sstevel@tonic-gate 	 * from the list, init it, and use it.
9047c478bd9Sstevel@tonic-gate 	 */
9057c478bd9Sstevel@tonic-gate 	if (ch->ch_list != NULL) {
9067c478bd9Sstevel@tonic-gate 		cp = ch->ch_list;
9077c478bd9Sstevel@tonic-gate 		ch->ch_list = cp->ch_list;
9087c478bd9Sstevel@tonic-gate 		mutex_exit(&nfscl->nfscl_chtable4_lock);
9097c478bd9Sstevel@tonic-gate 		if (newch != NULL) {
9107c478bd9Sstevel@tonic-gate 			kmem_free(newch->ch_protofmly,
9117c478bd9Sstevel@tonic-gate 			    strlen(newch->ch_protofmly) + 1);
9127c478bd9Sstevel@tonic-gate 			kmem_free(newch, sizeof (*newch));
9137c478bd9Sstevel@tonic-gate 		}
9147c478bd9Sstevel@tonic-gate 		(void) clnt_tli_kinit(cp->ch_client, svp->sv_knconf,
9157c478bd9Sstevel@tonic-gate 		    &svp->sv_addr, ci->cl_readsize, ci->cl_retrans, cr);
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 		/*
9187c478bd9Sstevel@tonic-gate 		 * Get an auth handle.
9197c478bd9Sstevel@tonic-gate 		 */
9207c478bd9Sstevel@tonic-gate 		error = authget(svp, cp->ch_client, cr);
9217c478bd9Sstevel@tonic-gate 		if (error || cp->ch_client->cl_auth == NULL) {
9227c478bd9Sstevel@tonic-gate 			CLNT_DESTROY(cp->ch_client);
9237c478bd9Sstevel@tonic-gate 			kmem_cache_free(chtab4_cache, cp);
9247c478bd9Sstevel@tonic-gate 			return ((error != 0) ? error : EINTR);
9257c478bd9Sstevel@tonic-gate 		}
9267c478bd9Sstevel@tonic-gate 		ch->ch_timesused++;
9277c478bd9Sstevel@tonic-gate 		*newcl = cp->ch_client;
9287c478bd9Sstevel@tonic-gate 		*chp = cp;
9297c478bd9Sstevel@tonic-gate 		return (0);
9307c478bd9Sstevel@tonic-gate 	}
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 	/*
9337c478bd9Sstevel@tonic-gate 	 * There weren't any free client handles which fit, so allocate
9347c478bd9Sstevel@tonic-gate 	 * a new one and use that.
9357c478bd9Sstevel@tonic-gate 	 */
9367c478bd9Sstevel@tonic-gate #ifdef DEBUG
9371a5e258fSJosef 'Jeff' Sipek 	atomic_inc_64(&nfscl->nfscl_stat.clalloc.value.ui64);
9387c478bd9Sstevel@tonic-gate #endif
9397c478bd9Sstevel@tonic-gate 	mutex_exit(&nfscl->nfscl_chtable4_lock);
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 	nfscl->nfscl_stat.cltoomany.value.ui64++;
9427c478bd9Sstevel@tonic-gate 	if (newch != NULL) {
9437c478bd9Sstevel@tonic-gate 		kmem_free(newch->ch_protofmly, strlen(newch->ch_protofmly) + 1);
9447c478bd9Sstevel@tonic-gate 		kmem_free(newch, sizeof (*newch));
9457c478bd9Sstevel@tonic-gate 	}
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate 	cp = kmem_cache_alloc(chtab4_cache, KM_SLEEP);
9487c478bd9Sstevel@tonic-gate 	cp->ch_head = ch;
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 	sigintr(&smask, (int)ci->cl_flags & MI4_INT);
9517c478bd9Sstevel@tonic-gate 	error = clnt_tli_kcreate(svp->sv_knconf, &svp->sv_addr, ci->cl_prog,
9527c478bd9Sstevel@tonic-gate 	    ci->cl_vers, ci->cl_readsize, ci->cl_retrans, cr, &cp->ch_client);
9537c478bd9Sstevel@tonic-gate 	sigunintr(&smask);
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	if (error != 0) {
9567c478bd9Sstevel@tonic-gate 		kmem_cache_free(chtab4_cache, cp);
9577c478bd9Sstevel@tonic-gate #ifdef DEBUG
9581a5e258fSJosef 'Jeff' Sipek 		atomic_dec_64(&nfscl->nfscl_stat.clalloc.value.ui64);
9597c478bd9Sstevel@tonic-gate #endif
9607c478bd9Sstevel@tonic-gate 		/*
9617c478bd9Sstevel@tonic-gate 		 * Warning is unnecessary if error is EINTR.
9627c478bd9Sstevel@tonic-gate 		 */
9637c478bd9Sstevel@tonic-gate 		if (error != EINTR) {
9647c478bd9Sstevel@tonic-gate 			nfs_cmn_err(error, CE_WARN,
9657c478bd9Sstevel@tonic-gate 			    "clget: couldn't create handle: %m\n");
9667c478bd9Sstevel@tonic-gate 		}
9677c478bd9Sstevel@tonic-gate 		return (error);
9687c478bd9Sstevel@tonic-gate 	}
9697c478bd9Sstevel@tonic-gate 	(void) CLNT_CONTROL(cp->ch_client, CLSET_PROGRESS, NULL);
9707c478bd9Sstevel@tonic-gate 	auth_destroy(cp->ch_client->cl_auth);
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 	/*
9737c478bd9Sstevel@tonic-gate 	 * Get an auth handle.
9747c478bd9Sstevel@tonic-gate 	 */
9757c478bd9Sstevel@tonic-gate 	error = authget(svp, cp->ch_client, cr);
9767c478bd9Sstevel@tonic-gate 	if (error || cp->ch_client->cl_auth == NULL) {
9777c478bd9Sstevel@tonic-gate 		CLNT_DESTROY(cp->ch_client);
9787c478bd9Sstevel@tonic-gate 		kmem_cache_free(chtab4_cache, cp);
9797c478bd9Sstevel@tonic-gate #ifdef DEBUG
9801a5e258fSJosef 'Jeff' Sipek 		atomic_dec_64(&nfscl->nfscl_stat.clalloc.value.ui64);
9817c478bd9Sstevel@tonic-gate #endif
9827c478bd9Sstevel@tonic-gate 		return ((error != 0) ? error : EINTR);
9837c478bd9Sstevel@tonic-gate 	}
9847c478bd9Sstevel@tonic-gate 	ch->ch_timesused++;
9857c478bd9Sstevel@tonic-gate 	*newcl = cp->ch_client;
9867c478bd9Sstevel@tonic-gate 	ASSERT(cp->ch_client->cl_nosignal == FALSE);
9877c478bd9Sstevel@tonic-gate 	*chp = cp;
9887c478bd9Sstevel@tonic-gate 	return (0);
9897c478bd9Sstevel@tonic-gate }
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate static int
nfs_clget4(mntinfo4_t * mi,servinfo4_t * svp,cred_t * cr,CLIENT ** newcl,struct chtab ** chp,struct nfs4_clnt * nfscl)9927c478bd9Sstevel@tonic-gate nfs_clget4(mntinfo4_t *mi, servinfo4_t *svp, cred_t *cr, CLIENT **newcl,
9937c478bd9Sstevel@tonic-gate     struct chtab **chp, struct nfs4_clnt *nfscl)
9947c478bd9Sstevel@tonic-gate {
9957c478bd9Sstevel@tonic-gate 	clinfo_t ci;
9967c478bd9Sstevel@tonic-gate 	bool_t is_recov;
9977c478bd9Sstevel@tonic-gate 	int firstcall, error = 0;
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 	/*
10007c478bd9Sstevel@tonic-gate 	 * Set read buffer size to rsize
10017c478bd9Sstevel@tonic-gate 	 * and add room for RPC headers.
10027c478bd9Sstevel@tonic-gate 	 */
10037c478bd9Sstevel@tonic-gate 	ci.cl_readsize = mi->mi_tsize;
10047c478bd9Sstevel@tonic-gate 	if (ci.cl_readsize != 0)
10057c478bd9Sstevel@tonic-gate 		ci.cl_readsize += (RPC_MAXDATASIZE - NFS_MAXDATA);
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 	/*
10087c478bd9Sstevel@tonic-gate 	 * If soft mount and server is down just try once.
10097c478bd9Sstevel@tonic-gate 	 * meaning: do not retransmit.
10107c478bd9Sstevel@tonic-gate 	 */
10117c478bd9Sstevel@tonic-gate 	if (!(mi->mi_flags & MI4_HARD) && (mi->mi_flags & MI4_DOWN))
10127c478bd9Sstevel@tonic-gate 		ci.cl_retrans = 0;
10137c478bd9Sstevel@tonic-gate 	else
10147c478bd9Sstevel@tonic-gate 		ci.cl_retrans = mi->mi_retrans;
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate 	ci.cl_prog = mi->mi_prog;
10177c478bd9Sstevel@tonic-gate 	ci.cl_vers = mi->mi_vers;
10187c478bd9Sstevel@tonic-gate 	ci.cl_flags = mi->mi_flags;
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 	/*
10217c478bd9Sstevel@tonic-gate 	 * clget4 calls authget() to get an auth handle. For RPCSEC_GSS
10227c478bd9Sstevel@tonic-gate 	 * security flavor, the client tries to establish a security context
10237c478bd9Sstevel@tonic-gate 	 * by contacting the server. If the connection is timed out or reset,
10247c478bd9Sstevel@tonic-gate 	 * e.g. server reboot, we will try again.
10257c478bd9Sstevel@tonic-gate 	 */
10267c478bd9Sstevel@tonic-gate 	is_recov = (curthread == mi->mi_recovthread);
10277c478bd9Sstevel@tonic-gate 	firstcall = 1;
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 	do {
10307c478bd9Sstevel@tonic-gate 		error = clget4(&ci, svp, cr, newcl, chp, nfscl);
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate 		if (error == 0)
10337c478bd9Sstevel@tonic-gate 			break;
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate 		/*
10367c478bd9Sstevel@tonic-gate 		 * For forced unmount and zone shutdown, bail out but
10377c478bd9Sstevel@tonic-gate 		 * let the recovery thread do one more transmission.
10387c478bd9Sstevel@tonic-gate 		 */
10397c478bd9Sstevel@tonic-gate 		if ((FS_OR_ZONE_GONE4(mi->mi_vfsp)) &&
10407c478bd9Sstevel@tonic-gate 		    (!is_recov || !firstcall)) {
10417c478bd9Sstevel@tonic-gate 			error = EIO;
10427c478bd9Sstevel@tonic-gate 			break;
10437c478bd9Sstevel@tonic-gate 		}
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate 		/* do not retry for soft mount */
10467c478bd9Sstevel@tonic-gate 		if (!(mi->mi_flags & MI4_HARD))
10477c478bd9Sstevel@tonic-gate 			break;
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 		/* let the caller deal with the failover case */
10507c478bd9Sstevel@tonic-gate 		if (FAILOVER_MOUNT4(mi))
10517c478bd9Sstevel@tonic-gate 			break;
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate 		firstcall = 0;
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate 	} while (error == ETIMEDOUT || error == ECONNRESET);
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 	return (error);
10587c478bd9Sstevel@tonic-gate }
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate void
clfree4(CLIENT * cl,struct chtab * cp,struct nfs4_clnt * nfscl)10617c478bd9Sstevel@tonic-gate clfree4(CLIENT *cl, struct chtab *cp, struct nfs4_clnt *nfscl)
10627c478bd9Sstevel@tonic-gate {
10637c478bd9Sstevel@tonic-gate 	if (cl->cl_auth != NULL) {
10647c478bd9Sstevel@tonic-gate 		sec_clnt_freeh(cl->cl_auth);
10657c478bd9Sstevel@tonic-gate 		cl->cl_auth = NULL;
10667c478bd9Sstevel@tonic-gate 	}
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 	/*
10697c478bd9Sstevel@tonic-gate 	 * Timestamp this cache entry so that we know when it was last
10707c478bd9Sstevel@tonic-gate 	 * used.
10717c478bd9Sstevel@tonic-gate 	 */
10727c478bd9Sstevel@tonic-gate 	cp->ch_freed = gethrestime_sec();
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate 	/*
10757c478bd9Sstevel@tonic-gate 	 * Add the free client handle to the front of the list.
10767c478bd9Sstevel@tonic-gate 	 * This way, the list will be sorted in youngest to oldest
10777c478bd9Sstevel@tonic-gate 	 * order.
10787c478bd9Sstevel@tonic-gate 	 */
10797c478bd9Sstevel@tonic-gate 	mutex_enter(&nfscl->nfscl_chtable4_lock);
10807c478bd9Sstevel@tonic-gate 	cp->ch_list = cp->ch_head->ch_list;
10817c478bd9Sstevel@tonic-gate 	cp->ch_head->ch_list = cp;
10827c478bd9Sstevel@tonic-gate 	mutex_exit(&nfscl->nfscl_chtable4_lock);
10837c478bd9Sstevel@tonic-gate }
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate #define	CL_HOLDTIME	60	/* time to hold client handles */
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate static void
clreclaim4_zone(struct nfs4_clnt * nfscl,uint_t cl_holdtime)10887c478bd9Sstevel@tonic-gate clreclaim4_zone(struct nfs4_clnt *nfscl, uint_t cl_holdtime)
10897c478bd9Sstevel@tonic-gate {
10907c478bd9Sstevel@tonic-gate 	struct chhead *ch;
10917c478bd9Sstevel@tonic-gate 	struct chtab *cp;	/* list of objects that can be reclaimed */
10927c478bd9Sstevel@tonic-gate 	struct chtab *cpe;
10937c478bd9Sstevel@tonic-gate 	struct chtab *cpl;
10947c478bd9Sstevel@tonic-gate 	struct chtab **cpp;
10957c478bd9Sstevel@tonic-gate #ifdef DEBUG
10967c478bd9Sstevel@tonic-gate 	int n = 0;
10977c478bd9Sstevel@tonic-gate 	clstat4_debug.clreclaim.value.ui64++;
10987c478bd9Sstevel@tonic-gate #endif
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 	/*
11017c478bd9Sstevel@tonic-gate 	 * Need to reclaim some memory, so step through the cache
11027c478bd9Sstevel@tonic-gate 	 * looking through the lists for entries which can be freed.
11037c478bd9Sstevel@tonic-gate 	 */
11047c478bd9Sstevel@tonic-gate 	cp = NULL;
11057c478bd9Sstevel@tonic-gate 
11067c478bd9Sstevel@tonic-gate 	mutex_enter(&nfscl->nfscl_chtable4_lock);
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate 	/*
11097c478bd9Sstevel@tonic-gate 	 * Here we step through each non-NULL quadruple and start to
11107c478bd9Sstevel@tonic-gate 	 * construct the reclaim list pointed to by cp.  Note that
11117c478bd9Sstevel@tonic-gate 	 * cp will contain all eligible chtab entries.  When this traversal
11127c478bd9Sstevel@tonic-gate 	 * completes, chtab entries from the last quadruple will be at the
11137c478bd9Sstevel@tonic-gate 	 * front of cp and entries from previously inspected quadruples have
11147c478bd9Sstevel@tonic-gate 	 * been appended to the rear of cp.
11157c478bd9Sstevel@tonic-gate 	 */
11167c478bd9Sstevel@tonic-gate 	for (ch = nfscl->nfscl_chtable4; ch != NULL; ch = ch->ch_next) {
11177c478bd9Sstevel@tonic-gate 		if (ch->ch_list == NULL)
11187c478bd9Sstevel@tonic-gate 			continue;
11197c478bd9Sstevel@tonic-gate 		/*
11207c478bd9Sstevel@tonic-gate 		 * Search each list for entries older then
11217c478bd9Sstevel@tonic-gate 		 * cl_holdtime seconds.  The lists are maintained
11227c478bd9Sstevel@tonic-gate 		 * in youngest to oldest order so that when the
11237c478bd9Sstevel@tonic-gate 		 * first entry is found which is old enough, then
11247c478bd9Sstevel@tonic-gate 		 * all of the rest of the entries on the list will
11257c478bd9Sstevel@tonic-gate 		 * be old enough as well.
11267c478bd9Sstevel@tonic-gate 		 */
11277c478bd9Sstevel@tonic-gate 		cpl = ch->ch_list;
11287c478bd9Sstevel@tonic-gate 		cpp = &ch->ch_list;
11297c478bd9Sstevel@tonic-gate 		while (cpl != NULL &&
1130b9238976Sth 		    cpl->ch_freed + cl_holdtime > gethrestime_sec()) {
11317c478bd9Sstevel@tonic-gate 			cpp = &cpl->ch_list;
11327c478bd9Sstevel@tonic-gate 			cpl = cpl->ch_list;
11337c478bd9Sstevel@tonic-gate 		}
11347c478bd9Sstevel@tonic-gate 		if (cpl != NULL) {
11357c478bd9Sstevel@tonic-gate 			*cpp = NULL;
11367c478bd9Sstevel@tonic-gate 			if (cp != NULL) {
11377c478bd9Sstevel@tonic-gate 				cpe = cpl;
11387c478bd9Sstevel@tonic-gate 				while (cpe->ch_list != NULL)
11397c478bd9Sstevel@tonic-gate 					cpe = cpe->ch_list;
11407c478bd9Sstevel@tonic-gate 				cpe->ch_list = cp;
11417c478bd9Sstevel@tonic-gate 			}
11427c478bd9Sstevel@tonic-gate 			cp = cpl;
11437c478bd9Sstevel@tonic-gate 		}
11447c478bd9Sstevel@tonic-gate 	}
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 	mutex_exit(&nfscl->nfscl_chtable4_lock);
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate 	/*
11497c478bd9Sstevel@tonic-gate 	 * If cp is empty, then there is nothing to reclaim here.
11507c478bd9Sstevel@tonic-gate 	 */
11517c478bd9Sstevel@tonic-gate 	if (cp == NULL)
11527c478bd9Sstevel@tonic-gate 		return;
11537c478bd9Sstevel@tonic-gate 
11547c478bd9Sstevel@tonic-gate 	/*
11557c478bd9Sstevel@tonic-gate 	 * Step through the list of entries to free, destroying each client
11567c478bd9Sstevel@tonic-gate 	 * handle and kmem_free'ing the memory for each entry.
11577c478bd9Sstevel@tonic-gate 	 */
11587c478bd9Sstevel@tonic-gate 	while (cp != NULL) {
11597c478bd9Sstevel@tonic-gate #ifdef DEBUG
11607c478bd9Sstevel@tonic-gate 		n++;
11617c478bd9Sstevel@tonic-gate #endif
11627c478bd9Sstevel@tonic-gate 		CLNT_DESTROY(cp->ch_client);
11637c478bd9Sstevel@tonic-gate 		cpl = cp->ch_list;
11647c478bd9Sstevel@tonic-gate 		kmem_cache_free(chtab4_cache, cp);
11657c478bd9Sstevel@tonic-gate 		cp = cpl;
11667c478bd9Sstevel@tonic-gate 	}
11677c478bd9Sstevel@tonic-gate 
11687c478bd9Sstevel@tonic-gate #ifdef DEBUG
11697c478bd9Sstevel@tonic-gate 	/*
11707c478bd9Sstevel@tonic-gate 	 * Update clalloc so that nfsstat shows the current number
11717c478bd9Sstevel@tonic-gate 	 * of allocated client handles.
11727c478bd9Sstevel@tonic-gate 	 */
11737c478bd9Sstevel@tonic-gate 	atomic_add_64(&nfscl->nfscl_stat.clalloc.value.ui64, -n);
11747c478bd9Sstevel@tonic-gate #endif
11757c478bd9Sstevel@tonic-gate }
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate /* ARGSUSED */
11787c478bd9Sstevel@tonic-gate static void
clreclaim4(void * all)1179