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,
4397c478bd9Sstevel@tonic-gate 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
498*677f6ec2SJan Schlien if (ntime->seconds < 0 && ntime->nseconds != 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 ||
5507c478bd9Sstevel@tonic-gate 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,
6637c478bd9Sstevel@tonic-gate KM_SLEEP);
6647c478bd9Sstevel@tonic-gate bcopy(src->utf8string_val, dest->utf8string_val,
6657c478bd9Sstevel@tonic-gate 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;
7827c478bd9Sstevel@tonic-gate i++) {
7837c478bd9Sstevel@tonic-gate if (!(error = sec_clnt_geth(ch_client,
7847c478bd9Sstevel@tonic-gate &svp->sv_secinfo->sdata[i],
7857c478bd9Sstevel@tonic-gate 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,
8087c478bd9Sstevel@tonic-gate &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,
8127c478bd9Sstevel@tonic-gate &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,
8587c478bd9Sstevel@tonic-gate 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 &&
11307c478bd9Sstevel@tonic-gate 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)11797c478bd9Sstevel@tonic-gate clreclaim4(void *all)
11807c478bd9Sstevel@tonic-gate {
11817c478bd9Sstevel@tonic-gate struct nfs4_clnt *nfscl;
11827c478bd9Sstevel@tonic-gate
11837c478bd9Sstevel@tonic-gate /*
11847c478bd9Sstevel@tonic-gate * The system is low on memory; go through and try to reclaim some from
11857c478bd9Sstevel@tonic-gate * every zone on the system.
11867c478bd9Sstevel@tonic-gate */
11877c478bd9Sstevel@tonic-gate mutex_enter(&nfs4_clnt_list_lock);
11887c478bd9Sstevel@tonic-gate nfscl = list_head(&nfs4_clnt_list);
11897c478bd9Sstevel@tonic-gate for (; nfscl != NULL; nfscl = list_next(&nfs4_clnt_list, nfscl))
11907c478bd9Sstevel@tonic-gate clreclaim4_zone(nfscl, CL_HOLDTIME);
11917c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_clnt_list_lock);
11927c478bd9Sstevel@tonic-gate }
11937c478bd9Sstevel@tonic-gate
11947c478bd9Sstevel@tonic-gate /*
11957c478bd9Sstevel@tonic-gate * Minimum time-out values indexed by call type
11967c478bd9Sstevel@tonic-gate * These units are in "eights" of a second to avoid multiplies
11977c478bd9Sstevel@tonic-gate */
11987c478bd9Sstevel@tonic-gate static unsigned int minimum_timeo[] = {
11997c478bd9Sstevel@tonic-gate 6, 7, 10
12007c478bd9Sstevel@tonic-gate };
12017c478bd9Sstevel@tonic-gate
12027c478bd9Sstevel@tonic-gate #define SHORTWAIT (NFS_COTS_TIMEO / 10)
12037c478bd9Sstevel@tonic-gate
12047c478bd9Sstevel@tonic-gate /*
12057c478bd9Sstevel@tonic-gate * Back off for retransmission timeout, MAXTIMO is in hz of a sec
12067c478bd9Sstevel@tonic-gate */
12077c478bd9Sstevel@tonic-gate #define MAXTIMO (20*hz)
12087c478bd9Sstevel@tonic-gate #define backoff(tim) (((tim) < MAXTIMO) ? dobackoff(tim) : (tim))
12097c478bd9Sstevel@tonic-gate #define dobackoff(tim) ((((tim) << 1) > MAXTIMO) ? MAXTIMO : ((tim) << 1))
12107c478bd9Sstevel@tonic-gate
12117c478bd9Sstevel@tonic-gate static int
nfs4_rfscall(mntinfo4_t * mi,rpcproc_t which,xdrproc_t xdrargs,caddr_t argsp,xdrproc_t xdrres,caddr_t resp,cred_t * icr,int * doqueue,enum clnt_stat * rpc_statusp,int flags,struct nfs4_clnt * nfscl)12127c478bd9Sstevel@tonic-gate nfs4_rfscall(mntinfo4_t *mi, rpcproc_t which, xdrproc_t xdrargs, caddr_t argsp,
121345916cd2Sjpk xdrproc_t xdrres, caddr_t resp, cred_t *icr, int *doqueue,
12147c478bd9Sstevel@tonic-gate enum clnt_stat *rpc_statusp, int flags, struct nfs4_clnt *nfscl)
12157c478bd9Sstevel@tonic-gate {
12167c478bd9Sstevel@tonic-gate CLIENT *client;
12177c478bd9Sstevel@tonic-gate struct chtab *ch;
121845916cd2Sjpk cred_t *cr = icr;
1219e280ed37SDai Ngo struct rpc_err rpcerr, rpcerr_tmp;
12207c478bd9Sstevel@tonic-gate enum clnt_stat status;
12217c478bd9Sstevel@tonic-gate int error;
12227c478bd9Sstevel@tonic-gate struct timeval wait;
12237c478bd9Sstevel@tonic-gate int timeo; /* in units of hz */
12247c478bd9Sstevel@tonic-gate bool_t tryagain, is_recov;
122545916cd2Sjpk bool_t cred_cloned = FALSE;
12267c478bd9Sstevel@tonic-gate k_sigset_t smask;
12277c478bd9Sstevel@tonic-gate servinfo4_t *svp;
12287c478bd9Sstevel@tonic-gate #ifdef DEBUG
12297c478bd9Sstevel@tonic-gate char *bufp;
12307c478bd9Sstevel@tonic-gate #endif
12317c478bd9Sstevel@tonic-gate int firstcall;
12327c478bd9Sstevel@tonic-gate
12337c478bd9Sstevel@tonic-gate rpcerr.re_status = RPC_SUCCESS;
12347c478bd9Sstevel@tonic-gate
12357c478bd9Sstevel@tonic-gate /*
12367c478bd9Sstevel@tonic-gate * If we know that we are rebooting then let's
12377c478bd9Sstevel@tonic-gate * not bother with doing any over the wireness.
12387c478bd9Sstevel@tonic-gate */
12397c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock);
12407c478bd9Sstevel@tonic-gate if (mi->mi_flags & MI4_SHUTDOWN) {
12417c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock);
12427c478bd9Sstevel@tonic-gate return (EIO);
12437c478bd9Sstevel@tonic-gate }
12447c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock);
12457c478bd9Sstevel@tonic-gate
124645916cd2Sjpk /* For TSOL, use a new cred which has net_mac_aware flag */
124745916cd2Sjpk if (!cred_cloned && is_system_labeled()) {
124845916cd2Sjpk cred_cloned = TRUE;
124945916cd2Sjpk cr = crdup(icr);
125045916cd2Sjpk (void) setpflags(NET_MAC_AWARE, 1, cr);
125145916cd2Sjpk }
125245916cd2Sjpk
12537c478bd9Sstevel@tonic-gate /*
12547c478bd9Sstevel@tonic-gate * clget() calls clnt_tli_kinit() which clears the xid, so we
12557c478bd9Sstevel@tonic-gate * are guaranteed to reprocess the retry as a new request.
12567c478bd9Sstevel@tonic-gate */
12577c478bd9Sstevel@tonic-gate svp = mi->mi_curr_serv;
12587c478bd9Sstevel@tonic-gate rpcerr.re_errno = nfs_clget4(mi, svp, cr, &client, &ch, nfscl);
12597c478bd9Sstevel@tonic-gate if (rpcerr.re_errno != 0)
12607c478bd9Sstevel@tonic-gate return (rpcerr.re_errno);
12617c478bd9Sstevel@tonic-gate
12627c478bd9Sstevel@tonic-gate timeo = (mi->mi_timeo * hz) / 10;
12637c478bd9Sstevel@tonic-gate
12647c478bd9Sstevel@tonic-gate /*
12657c478bd9Sstevel@tonic-gate * If hard mounted fs, retry call forever unless hard error
12667c478bd9Sstevel@tonic-gate * occurs.
12677c478bd9Sstevel@tonic-gate *
12687c478bd9Sstevel@tonic-gate * For forced unmount, let the recovery thread through but return
12697c478bd9Sstevel@tonic-gate * an error for all others. This is so that user processes can
12707c478bd9Sstevel@tonic-gate * exit quickly. The recovery thread bails out after one
12717c478bd9Sstevel@tonic-gate * transmission so that it can tell if it needs to continue.
12727c478bd9Sstevel@tonic-gate *
12737c478bd9Sstevel@tonic-gate * For zone shutdown, behave as above to encourage quick
12747c478bd9Sstevel@tonic-gate * process exit, but also fail quickly when servers have
12757c478bd9Sstevel@tonic-gate * timed out before and reduce the timeouts.
12767c478bd9Sstevel@tonic-gate */
12777c478bd9Sstevel@tonic-gate is_recov = (curthread == mi->mi_recovthread);
12787c478bd9Sstevel@tonic-gate firstcall = 1;
12797c478bd9Sstevel@tonic-gate do {
12807c478bd9Sstevel@tonic-gate tryagain = FALSE;
12817c478bd9Sstevel@tonic-gate
12827c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_rfscall_debug, (CE_NOTE,
12837c478bd9Sstevel@tonic-gate "nfs4_rfscall: vfs_flag=0x%x, %s",
12847c478bd9Sstevel@tonic-gate mi->mi_vfsp->vfs_flag,
12857c478bd9Sstevel@tonic-gate is_recov ? "recov thread" : "not recov thread"));
12867c478bd9Sstevel@tonic-gate
12877c478bd9Sstevel@tonic-gate /*
12887c478bd9Sstevel@tonic-gate * It's possible while we're retrying the admin
12897c478bd9Sstevel@tonic-gate * decided to reboot.
12907c478bd9Sstevel@tonic-gate */
12917c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock);
12927c478bd9Sstevel@tonic-gate if (mi->mi_flags & MI4_SHUTDOWN) {
12937c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock);
12947c478bd9Sstevel@tonic-gate clfree4(client, ch, nfscl);
129545916cd2Sjpk if (cred_cloned)
129645916cd2Sjpk crfree(cr);
12977c478bd9Sstevel@tonic-gate return (EIO);
12987c478bd9Sstevel@tonic-gate }
12997c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock);
13007c478bd9Sstevel@tonic-gate
13017c478bd9Sstevel@tonic-gate if ((mi->mi_vfsp->vfs_flag & VFS_UNMOUNTED) &&
13027c478bd9Sstevel@tonic-gate (!is_recov || !firstcall)) {
13037c478bd9Sstevel@tonic-gate clfree4(client, ch, nfscl);
130445916cd2Sjpk if (cred_cloned)
130545916cd2Sjpk crfree(cr);
13067c478bd9Sstevel@tonic-gate return (EIO);
13077c478bd9Sstevel@tonic-gate }
13087c478bd9Sstevel@tonic-gate
13097c478bd9Sstevel@tonic-gate if (zone_status_get(curproc->p_zone) >= ZONE_IS_SHUTTING_DOWN) {
13107c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock);
13117c478bd9Sstevel@tonic-gate if ((mi->mi_flags & MI4_TIMEDOUT) ||
13127c478bd9Sstevel@tonic-gate !is_recov || !firstcall) {
13137c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock);
13147c478bd9Sstevel@tonic-gate clfree4(client, ch, nfscl);
131545916cd2Sjpk if (cred_cloned)
131645916cd2Sjpk crfree(cr);
13177c478bd9Sstevel@tonic-gate return (EIO);
13187c478bd9Sstevel@tonic-gate }
13197c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock);
13207c478bd9Sstevel@tonic-gate timeo = (MIN(mi->mi_timeo, SHORTWAIT) * hz) / 10;
13217c478bd9Sstevel@tonic-gate }
13227c478bd9Sstevel@tonic-gate
13237c478bd9Sstevel@tonic-gate firstcall = 0;
13247c478bd9Sstevel@tonic-gate TICK_TO_TIMEVAL(timeo, &wait);
13257c478bd9Sstevel@tonic-gate
13267c478bd9Sstevel@tonic-gate /*
13277c478bd9Sstevel@tonic-gate * Mask out all signals except SIGHUP, SIGINT, SIGQUIT
13287c478bd9Sstevel@tonic-gate * and SIGTERM. (Preserving the existing masks).
13297c478bd9Sstevel@tonic-gate * Mask out SIGINT if mount option nointr is specified.
13307c478bd9Sstevel@tonic-gate */
13317c478bd9Sstevel@tonic-gate sigintr(&smask, (int)mi->mi_flags & MI4_INT);
13327c478bd9Sstevel@tonic-gate if (!(mi->mi_flags & MI4_INT))
13337c478bd9Sstevel@tonic-gate client->cl_nosignal = TRUE;
13347c478bd9Sstevel@tonic-gate
13357c478bd9Sstevel@tonic-gate /*
13367c478bd9Sstevel@tonic-gate * If there is a current signal, then don't bother
13377c478bd9Sstevel@tonic-gate * even trying to send out the request because we
13387c478bd9Sstevel@tonic-gate * won't be able to block waiting for the response.
13397c478bd9Sstevel@tonic-gate * Simply assume RPC_INTR and get on with it.
13407c478bd9Sstevel@tonic-gate */
13417c478bd9Sstevel@tonic-gate if (ttolwp(curthread) != NULL && ISSIG(curthread, JUSTLOOKING))
13427c478bd9Sstevel@tonic-gate status = RPC_INTR;
13437c478bd9Sstevel@tonic-gate else {
13447c478bd9Sstevel@tonic-gate status = CLNT_CALL(client, which, xdrargs, argsp,
13457c478bd9Sstevel@tonic-gate xdrres, resp, wait);
13467c478bd9Sstevel@tonic-gate }
13477c478bd9Sstevel@tonic-gate
13487c478bd9Sstevel@tonic-gate if (!(mi->mi_flags & MI4_INT))
13497c478bd9Sstevel@tonic-gate client->cl_nosignal = FALSE;
13507c478bd9Sstevel@tonic-gate /*
13517c478bd9Sstevel@tonic-gate * restore original signal mask
13527c478bd9Sstevel@tonic-gate */
13537c478bd9Sstevel@tonic-gate sigunintr(&smask);
13547c478bd9Sstevel@tonic-gate
13557c478bd9Sstevel@tonic-gate switch (status) {
13567c478bd9Sstevel@tonic-gate case RPC_SUCCESS:
13577c478bd9Sstevel@tonic-gate break;
13587c478bd9Sstevel@tonic-gate
13597c478bd9Sstevel@tonic-gate case RPC_INTR:
13607c478bd9Sstevel@tonic-gate /*
13617c478bd9Sstevel@tonic-gate * There is no way to recover from this error,
13627c478bd9Sstevel@tonic-gate * even if mount option nointr is specified.
13637c478bd9Sstevel@tonic-gate * SIGKILL, for example, cannot be blocked.
13647c478bd9Sstevel@tonic-gate */
13657c478bd9Sstevel@tonic-gate rpcerr.re_status = RPC_INTR;
13667c478bd9Sstevel@tonic-gate rpcerr.re_errno = EINTR;
13677c478bd9Sstevel@tonic-gate break;
13687c478bd9Sstevel@tonic-gate
13697c478bd9Sstevel@tonic-gate case RPC_UDERROR:
13707c478bd9Sstevel@tonic-gate /*
13717c478bd9Sstevel@tonic-gate * If the NFS server is local (vold) and
13727c478bd9Sstevel@tonic-gate * it goes away then we get RPC_UDERROR.
13737c478bd9Sstevel@tonic-gate * This is a retryable error, so we would
13747c478bd9Sstevel@tonic-gate * loop, so check to see if the specific
13757c478bd9Sstevel@tonic-gate * error was ECONNRESET, indicating that
13767c478bd9Sstevel@tonic-gate * target did not exist at all. If so,
13777c478bd9Sstevel@tonic-gate * return with RPC_PROGUNAVAIL and
13787c478bd9Sstevel@tonic-gate * ECONNRESET to indicate why.
13797c478bd9Sstevel@tonic-gate */
13807c478bd9Sstevel@tonic-gate CLNT_GETERR(client, &rpcerr);
13817c478bd9Sstevel@tonic-gate if (rpcerr.re_errno == ECONNRESET) {
13827c478bd9Sstevel@tonic-gate rpcerr.re_status = RPC_PROGUNAVAIL;
13837c478bd9Sstevel@tonic-gate rpcerr.re_errno = ECONNRESET;
13847c478bd9Sstevel@tonic-gate break;
13857c478bd9Sstevel@tonic-gate }
13867c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/
13877c478bd9Sstevel@tonic-gate
13887c478bd9Sstevel@tonic-gate default: /* probably RPC_TIMEDOUT */
13897c478bd9Sstevel@tonic-gate
13907c478bd9Sstevel@tonic-gate if (IS_UNRECOVERABLE_RPC(status))
13917c478bd9Sstevel@tonic-gate break;
13927c478bd9Sstevel@tonic-gate
13937c478bd9Sstevel@tonic-gate /*
13947c478bd9Sstevel@tonic-gate * increment server not responding count
13957c478bd9Sstevel@tonic-gate */
13967c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock);
13977c478bd9Sstevel@tonic-gate mi->mi_noresponse++;
13987c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock);
13997c478bd9Sstevel@tonic-gate #ifdef DEBUG
14007c478bd9Sstevel@tonic-gate nfscl->nfscl_stat.noresponse.value.ui64++;
14017c478bd9Sstevel@tonic-gate #endif
14027c478bd9Sstevel@tonic-gate /*
14037c478bd9Sstevel@tonic-gate * On zone shutdown, mark server dead and move on.
14047c478bd9Sstevel@tonic-gate */
14057c478bd9Sstevel@tonic-gate if (zone_status_get(curproc->p_zone) >=
14067c478bd9Sstevel@tonic-gate ZONE_IS_SHUTTING_DOWN) {
14077c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock);
14087c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_TIMEDOUT;
14097c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock);
14107c478bd9Sstevel@tonic-gate clfree4(client, ch, nfscl);
141145916cd2Sjpk if (cred_cloned)
141245916cd2Sjpk crfree(cr);
14137c478bd9Sstevel@tonic-gate return (EIO);
14147c478bd9Sstevel@tonic-gate }
14157c478bd9Sstevel@tonic-gate
14167c478bd9Sstevel@tonic-gate /*
14177c478bd9Sstevel@tonic-gate * NFS client failover support:
14187c478bd9Sstevel@tonic-gate * return and let the caller take care of
14197c478bd9Sstevel@tonic-gate * failover. We only return for failover mounts
14207c478bd9Sstevel@tonic-gate * because otherwise we want the "not responding"
14217c478bd9Sstevel@tonic-gate * message, the timer updates, etc.
14227c478bd9Sstevel@tonic-gate */
14237c478bd9Sstevel@tonic-gate if (mi->mi_vers == 4 && FAILOVER_MOUNT4(mi) &&
14247c478bd9Sstevel@tonic-gate (error = try_failover(status)) != 0) {
14257c478bd9Sstevel@tonic-gate clfree4(client, ch, nfscl);
142645916cd2Sjpk if (cred_cloned)
142745916cd2Sjpk crfree(cr);
14287c478bd9Sstevel@tonic-gate *rpc_statusp = status;
14297c478bd9Sstevel@tonic-gate return (error);
14307c478bd9Sstevel@tonic-gate }
14317c478bd9Sstevel@tonic-gate
14327c478bd9Sstevel@tonic-gate if (flags & RFSCALL_SOFT)
14337c478bd9Sstevel@tonic-gate break;
14347c478bd9Sstevel@tonic-gate
14357c478bd9Sstevel@tonic-gate tryagain = TRUE;
14367c478bd9Sstevel@tonic-gate
14377c478bd9Sstevel@tonic-gate /*
14387c478bd9Sstevel@tonic-gate * The call is in progress (over COTS).
14397c478bd9Sstevel@tonic-gate * Try the CLNT_CALL again, but don't
14407c478bd9Sstevel@tonic-gate * print a noisy error message.
14417c478bd9Sstevel@tonic-gate */
14427c478bd9Sstevel@tonic-gate if (status == RPC_INPROGRESS)
14437c478bd9Sstevel@tonic-gate break;
14447c478bd9Sstevel@tonic-gate
14457c478bd9Sstevel@tonic-gate timeo = backoff(timeo);
1446e280ed37SDai Ngo CLNT_GETERR(client, &rpcerr_tmp);
1447e280ed37SDai Ngo
14487c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock);
14497c478bd9Sstevel@tonic-gate if (!(mi->mi_flags & MI4_PRINTED)) {
14507c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_PRINTED;
14517c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock);
1452e280ed37SDai Ngo if ((status == RPC_CANTSEND) &&
1453e280ed37SDai Ngo (rpcerr_tmp.re_errno == ENOBUFS))
1454e280ed37SDai Ngo nfs4_queue_fact(RF_SENDQ_FULL, mi, 0,
1455e280ed37SDai Ngo 0, 0, FALSE, NULL, 0, NULL);
1456e280ed37SDai Ngo else
1457e280ed37SDai Ngo nfs4_queue_fact(RF_SRV_NOT_RESPOND, mi,
1458e280ed37SDai Ngo 0, 0, 0, FALSE, NULL, 0, NULL);
14597c478bd9Sstevel@tonic-gate } else
14607c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock);
14617c478bd9Sstevel@tonic-gate
14629acbbeafSnn35248 if (*doqueue && nfs_has_ctty()) {
14637c478bd9Sstevel@tonic-gate *doqueue = 0;
1464e280ed37SDai Ngo if (!(mi->mi_flags & MI4_NOPRINT)) {
1465e280ed37SDai Ngo if ((status == RPC_CANTSEND) &&
1466e280ed37SDai Ngo (rpcerr_tmp.re_errno == ENOBUFS))
1467e280ed37SDai Ngo nfs4_queue_fact(RF_SENDQ_FULL,
1468e280ed37SDai Ngo mi, 0, 0, 0, FALSE, NULL,
1469e280ed37SDai Ngo 0, NULL);
1470e280ed37SDai Ngo else
1471e280ed37SDai Ngo nfs4_queue_fact(
1472e280ed37SDai Ngo RF_SRV_NOT_RESPOND, mi, 0,
1473e280ed37SDai Ngo 0, 0, FALSE, NULL, 0, NULL);
1474e280ed37SDai Ngo }
14757c478bd9Sstevel@tonic-gate }
14767c478bd9Sstevel@tonic-gate }
14777c478bd9Sstevel@tonic-gate } while (tryagain);
14787c478bd9Sstevel@tonic-gate
14797c478bd9Sstevel@tonic-gate DTRACE_PROBE2(nfs4__rfscall_debug, enum clnt_stat, status,
14807c478bd9Sstevel@tonic-gate int, rpcerr.re_errno);
14817c478bd9Sstevel@tonic-gate
14827c478bd9Sstevel@tonic-gate if (status != RPC_SUCCESS) {
14837c478bd9Sstevel@tonic-gate zoneid_t zoneid = mi->mi_zone->zone_id;
14847c478bd9Sstevel@tonic-gate
14857c478bd9Sstevel@tonic-gate /*
14867c478bd9Sstevel@tonic-gate * Let soft mounts use the timed out message.
14877c478bd9Sstevel@tonic-gate */
14887c478bd9Sstevel@tonic-gate if (status == RPC_INPROGRESS)
14897c478bd9Sstevel@tonic-gate status = RPC_TIMEDOUT;
14907c478bd9Sstevel@tonic-gate nfscl->nfscl_stat.badcalls.value.ui64++;
14917c478bd9Sstevel@tonic-gate if (status != RPC_INTR) {
14927c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock);
14937c478bd9Sstevel@tonic-gate mi->mi_flags |= MI4_DOWN;
14947c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock);
14957c478bd9Sstevel@tonic-gate CLNT_GETERR(client, &rpcerr);
14967c478bd9Sstevel@tonic-gate #ifdef DEBUG
14977c478bd9Sstevel@tonic-gate bufp = clnt_sperror(client, svp->sv_hostname);
14987c478bd9Sstevel@tonic-gate zprintf(zoneid, "NFS%d %s failed for %s\n",
14997c478bd9Sstevel@tonic-gate mi->mi_vers, mi->mi_rfsnames[which], bufp);
15009acbbeafSnn35248 if (nfs_has_ctty()) {
15017c478bd9Sstevel@tonic-gate if (!(mi->mi_flags & MI4_NOPRINT)) {
15027c478bd9Sstevel@tonic-gate uprintf("NFS%d %s failed for %s\n",
15037c478bd9Sstevel@tonic-gate mi->mi_vers, mi->mi_rfsnames[which],
15047c478bd9Sstevel@tonic-gate bufp);
15057c478bd9Sstevel@tonic-gate }
15067c478bd9Sstevel@tonic-gate }
15077c478bd9Sstevel@tonic-gate kmem_free(bufp, MAXPATHLEN);
15087c478bd9Sstevel@tonic-gate #else
15097c478bd9Sstevel@tonic-gate zprintf(zoneid,
15107c478bd9Sstevel@tonic-gate "NFS %s failed for server %s: error %d (%s)\n",
15117c478bd9Sstevel@tonic-gate mi->mi_rfsnames[which], svp->sv_hostname,
15127c478bd9Sstevel@tonic-gate status, clnt_sperrno(status));
15139acbbeafSnn35248 if (nfs_has_ctty()) {
15147c478bd9Sstevel@tonic-gate if (!(mi->mi_flags & MI4_NOPRINT)) {
15157c478bd9Sstevel@tonic-gate uprintf(
15167c478bd9Sstevel@tonic-gate "NFS %s failed for server %s: error %d (%s)\n",
15177c478bd9Sstevel@tonic-gate mi->mi_rfsnames[which],
15187c478bd9Sstevel@tonic-gate svp->sv_hostname, status,
15197c478bd9Sstevel@tonic-gate clnt_sperrno(status));
15207c478bd9Sstevel@tonic-gate }
15217c478bd9Sstevel@tonic-gate }
15227c478bd9Sstevel@tonic-gate #endif
15237c478bd9Sstevel@tonic-gate /*
15247c478bd9Sstevel@tonic-gate * when CLNT_CALL() fails with RPC_AUTHERROR,
15257c478bd9Sstevel@tonic-gate * re_errno is set appropriately depending on
15267c478bd9Sstevel@tonic-gate * the authentication error
15277c478bd9Sstevel@tonic-gate */
15287c478bd9Sstevel@tonic-gate if (status == RPC_VERSMISMATCH ||
15297c478bd9Sstevel@tonic-gate status == RPC_PROGVERSMISMATCH)
15307c478bd9Sstevel@tonic-gate rpcerr.re_errno = EIO;
15317c478bd9Sstevel@tonic-gate }
15327c478bd9Sstevel@tonic-gate } else {
15337c478bd9Sstevel@tonic-gate /*
15347c478bd9Sstevel@tonic-gate * Test the value of mi_down and mi_printed without
15357c478bd9Sstevel@tonic-gate * holding the mi_lock mutex. If they are both zero,
15367c478bd9Sstevel@tonic-gate * then it is okay to skip the down and printed
15377c478bd9Sstevel@tonic-gate * processing. This saves on a mutex_enter and
15387c478bd9Sstevel@tonic-gate * mutex_exit pair for a normal, successful RPC.
15397c478bd9Sstevel@tonic-gate * This was just complete overhead.
15407c478bd9Sstevel@tonic-gate */
15417c478bd9Sstevel@tonic-gate if (mi->mi_flags & (MI4_DOWN | MI4_PRINTED)) {
15427c478bd9Sstevel@tonic-gate mutex_enter(&mi->mi_lock);
15437c478bd9Sstevel@tonic-gate mi->mi_flags &= ~MI4_DOWN;
15447c478bd9Sstevel@tonic-gate if (mi->mi_flags & MI4_PRINTED) {
15457c478bd9Sstevel@tonic-gate mi->mi_flags &= ~MI4_PRINTED;
15467c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock);
15477c478bd9Sstevel@tonic-gate if (!(mi->mi_vfsp->vfs_flag & VFS_UNMOUNTED))
15487c478bd9Sstevel@tonic-gate nfs4_queue_fact(RF_SRV_OK, mi, 0, 0,
15497c478bd9Sstevel@tonic-gate 0, FALSE, NULL, 0, NULL);
15507c478bd9Sstevel@tonic-gate } else
15517c478bd9Sstevel@tonic-gate mutex_exit(&mi->mi_lock);
15527c478bd9Sstevel@tonic-gate }
15537c478bd9Sstevel@tonic-gate
15547c478bd9Sstevel@tonic-gate if (*doqueue == 0) {
15557c478bd9Sstevel@tonic-gate if (!(mi->mi_flags & MI4_NOPRINT) &&
15567c478bd9Sstevel@tonic-gate !(mi->mi_vfsp->vfs_flag & VFS_UNMOUNTED))
15577c478bd9Sstevel@tonic-gate nfs4_queue_fact(RF_SRV_OK, mi, 0, 0, 0,
15587c478bd9Sstevel@tonic-gate FALSE, NULL, 0, NULL);
15597c478bd9Sstevel@tonic-gate
15607c478bd9Sstevel@tonic-gate *doqueue = 1;
15617c478bd9Sstevel@tonic-gate }
15627c478bd9Sstevel@tonic-gate }
15637c478bd9Sstevel@tonic-gate
15647c478bd9Sstevel@tonic-gate clfree4(client, ch, nfscl);
156545916cd2Sjpk if (cred_cloned)
156645916cd2Sjpk crfree(cr);
15677c478bd9Sstevel@tonic-gate
15687c478bd9Sstevel@tonic-gate ASSERT(rpcerr.re_status == RPC_SUCCESS || rpcerr.re_errno != 0);
15697c478bd9Sstevel@tonic-gate
15707c478bd9Sstevel@tonic-gate TRACE_1(TR_FAC_NFS, TR_RFSCALL_END, "nfs4_rfscall_end:errno %d",
15717c478bd9Sstevel@tonic-gate rpcerr.re_errno);
15727c478bd9Sstevel@tonic-gate
15737c478bd9Sstevel@tonic-gate *rpc_statusp = status;
15747c478bd9Sstevel@tonic-gate return (rpcerr.re_errno);
15757c478bd9Sstevel@tonic-gate }
15767c478bd9Sstevel@tonic-gate
15777c478bd9Sstevel@tonic-gate /*
15787c478bd9Sstevel@tonic-gate * rfs4call - general wrapper for RPC calls initiated by the client
15797c478bd9Sstevel@tonic-gate */
15807c478bd9Sstevel@tonic-gate void
rfs4call(mntinfo4_t * mi,COMPOUND4args_clnt * argsp,COMPOUND4res_clnt * resp,cred_t * cr,int * doqueue,int flags,nfs4_error_t * ep)15817c478bd9Sstevel@tonic-gate rfs4call(mntinfo4_t *mi, COMPOUND4args_clnt *argsp, COMPOUND4res_clnt *resp,
15827c478bd9Sstevel@tonic-gate cred_t *cr, int *doqueue, int flags, nfs4_error_t *ep)
15837c478bd9Sstevel@tonic-gate {
15847c478bd9Sstevel@tonic-gate int i, error;
15857c478bd9Sstevel@tonic-gate enum clnt_stat rpc_status = NFS4_OK;
15867c478bd9Sstevel@tonic-gate int num_resops;
15877c478bd9Sstevel@tonic-gate struct nfs4_clnt *nfscl;
15887c478bd9Sstevel@tonic-gate
1589108322fbScarlsonj ASSERT(nfs_zone() == mi->mi_zone);
1590108322fbScarlsonj nfscl = zone_getspecific(nfs4clnt_zone_key, nfs_zone());
15917c478bd9Sstevel@tonic-gate ASSERT(nfscl != NULL);
15927c478bd9Sstevel@tonic-gate
15937c478bd9Sstevel@tonic-gate nfscl->nfscl_stat.calls.value.ui64++;
15947c478bd9Sstevel@tonic-gate mi->mi_reqs[NFSPROC4_COMPOUND].value.ui64++;
15957c478bd9Sstevel@tonic-gate
15967c478bd9Sstevel@tonic-gate /* Set up the results struct for XDR usage */
15977c478bd9Sstevel@tonic-gate resp->argsp = argsp;
15987c478bd9Sstevel@tonic-gate resp->array = NULL;
15997c478bd9Sstevel@tonic-gate resp->status = 0;
16007c478bd9Sstevel@tonic-gate resp->decode_len = 0;
16017c478bd9Sstevel@tonic-gate
16027c478bd9Sstevel@tonic-gate error = nfs4_rfscall(mi, NFSPROC4_COMPOUND,
16037c478bd9Sstevel@tonic-gate xdr_COMPOUND4args_clnt, (caddr_t)argsp,
16047c478bd9Sstevel@tonic-gate xdr_COMPOUND4res_clnt, (caddr_t)resp, cr,
16057c478bd9Sstevel@tonic-gate doqueue, &rpc_status, flags, nfscl);
16067c478bd9Sstevel@tonic-gate
16077c478bd9Sstevel@tonic-gate /* Return now if it was an RPC error */
16087c478bd9Sstevel@tonic-gate if (error) {
16097c478bd9Sstevel@tonic-gate ep->error = error;
16107c478bd9Sstevel@tonic-gate ep->stat = resp->status;
16117c478bd9Sstevel@tonic-gate ep->rpc_status = rpc_status;
16127c478bd9Sstevel@tonic-gate return;
16137c478bd9Sstevel@tonic-gate }
16147c478bd9Sstevel@tonic-gate
16157c478bd9Sstevel@tonic-gate /* else we'll count the processed operations */
16167c478bd9Sstevel@tonic-gate num_resops = resp->decode_len;
16177c478bd9Sstevel@tonic-gate for (i = 0; i < num_resops; i++) {
16187c478bd9Sstevel@tonic-gate /*
16197c478bd9Sstevel@tonic-gate * Count the individual operations
16207c478bd9Sstevel@tonic-gate * processed by the server.
16217c478bd9Sstevel@tonic-gate */
16227c478bd9Sstevel@tonic-gate if (resp->array[i].resop >= NFSPROC4_NULL &&
16237c478bd9Sstevel@tonic-gate resp->array[i].resop <= OP_WRITE)
16247c478bd9Sstevel@tonic-gate mi->mi_reqs[resp->array[i].resop].value.ui64++;
16257c478bd9Sstevel@tonic-gate }
16267c478bd9Sstevel@tonic-gate
16277c478bd9Sstevel@tonic-gate ep->error = 0;
16287c478bd9Sstevel@tonic-gate ep->stat = resp->status;
16297c478bd9Sstevel@tonic-gate ep->rpc_status = rpc_status;
16307c478bd9Sstevel@tonic-gate }
16317c478bd9Sstevel@tonic-gate
16327c478bd9Sstevel@tonic-gate /*
16337c478bd9Sstevel@tonic-gate * nfs4rename_update - updates stored state after a rename. Currently this
16347c478bd9Sstevel@tonic-gate * is the path of the object and anything under it, and the filehandle of
16357c478bd9Sstevel@tonic-gate * the renamed object.
16367c478bd9Sstevel@tonic-gate */
16377c478bd9Sstevel@tonic-gate void
nfs4rename_update(vnode_t * renvp,vnode_t * ndvp,nfs_fh4 * nfh4p,char * nnm)16387c478bd9Sstevel@tonic-gate nfs4rename_update(vnode_t *renvp, vnode_t *ndvp, nfs_fh4 *nfh4p, char *nnm)
16397c478bd9Sstevel@tonic-gate {
16407c478bd9Sstevel@tonic-gate sfh4_update(VTOR4(renvp)->r_fh, nfh4p);
16417c478bd9Sstevel@tonic-gate fn_move(VTOSV(renvp)->sv_name, VTOSV(ndvp)->sv_name, nnm);
16427c478bd9Sstevel@tonic-gate }
16437c478bd9Sstevel@tonic-gate
16447c478bd9Sstevel@tonic-gate /*
16457c478bd9Sstevel@tonic-gate * Routine to look up the filehandle for the given path and rootvp.
16467c478bd9Sstevel@tonic-gate *
16477c478bd9Sstevel@tonic-gate * Return values:
16487c478bd9Sstevel@tonic-gate * - success: returns zero and *statp is set to NFS4_OK, and *fhp is
16497c478bd9Sstevel@tonic-gate * updated.
16507c478bd9Sstevel@tonic-gate * - error: return value (errno value) and/or *statp is set appropriately.
16517c478bd9Sstevel@tonic-gate */
16527c478bd9Sstevel@tonic-gate #define RML_ORDINARY 1
16537c478bd9Sstevel@tonic-gate #define RML_NAMED_ATTR 2
16547c478bd9Sstevel@tonic-gate #define RML_ATTRDIR 3
16557c478bd9Sstevel@tonic-gate
16567c478bd9Sstevel@tonic-gate static void
remap_lookup(nfs4_fname_t * fname,vnode_t * rootvp,int filetype,cred_t * cr,nfs_fh4 * fhp,nfs4_ga_res_t * garp,nfs_fh4 * pfhp,nfs4_ga_res_t * pgarp,nfs4_error_t * ep)16577c478bd9Sstevel@tonic-gate remap_lookup(nfs4_fname_t *fname, vnode_t *rootvp,
16587c478bd9Sstevel@tonic-gate int filetype, cred_t *cr,
16597c478bd9Sstevel@tonic-gate nfs_fh4 *fhp, nfs4_ga_res_t *garp, /* fh, attrs for object */
16607c478bd9Sstevel@tonic-gate nfs_fh4 *pfhp, nfs4_ga_res_t *pgarp, /* fh, attrs for parent */
16617c478bd9Sstevel@tonic-gate nfs4_error_t *ep)
16627c478bd9Sstevel@tonic-gate {
16637c478bd9Sstevel@tonic-gate COMPOUND4args_clnt args;
16647c478bd9Sstevel@tonic-gate COMPOUND4res_clnt res;
16657c478bd9Sstevel@tonic-gate nfs_argop4 *argop;
16667c478bd9Sstevel@tonic-gate nfs_resop4 *resop;
16677c478bd9Sstevel@tonic-gate int num_argops;
16687c478bd9Sstevel@tonic-gate lookup4_param_t lookuparg;
16697c478bd9Sstevel@tonic-gate nfs_fh4 *tmpfhp;
16707c478bd9Sstevel@tonic-gate int doqueue = 1;
16717c478bd9Sstevel@tonic-gate char *path;
16727c478bd9Sstevel@tonic-gate mntinfo4_t *mi;
16737c478bd9Sstevel@tonic-gate
16747c478bd9Sstevel@tonic-gate ASSERT(fname != NULL);
16757c478bd9Sstevel@tonic-gate ASSERT(rootvp->v_type == VDIR);
16767c478bd9Sstevel@tonic-gate
16777c478bd9Sstevel@tonic-gate mi = VTOMI4(rootvp);
16787c478bd9Sstevel@tonic-gate path = fn_path(fname);
16797c478bd9Sstevel@tonic-gate switch (filetype) {
16807c478bd9Sstevel@tonic-gate case RML_NAMED_ATTR:
16817c478bd9Sstevel@tonic-gate lookuparg.l4_getattrs = LKP4_LAST_NAMED_ATTR;
16827c478bd9Sstevel@tonic-gate args.ctag = TAG_REMAP_LOOKUP_NA;
16837c478bd9Sstevel@tonic-gate break;
16847c478bd9Sstevel@tonic-gate case RML_ATTRDIR:
16857c478bd9Sstevel@tonic-gate lookuparg.l4_getattrs = LKP4_LAST_ATTRDIR;
16867c478bd9Sstevel@tonic-gate args.ctag = TAG_REMAP_LOOKUP_AD;
16877c478bd9Sstevel@tonic-gate break;
16887c478bd9Sstevel@tonic-gate case RML_ORDINARY:
16897c478bd9Sstevel@tonic-gate lookuparg.l4_getattrs = LKP4_ALL_ATTRIBUTES;
16907c478bd9Sstevel@tonic-gate args.ctag = TAG_REMAP_LOOKUP;
16917c478bd9Sstevel@tonic-gate break;
16927c478bd9Sstevel@tonic-gate default:
16937c478bd9Sstevel@tonic-gate ep->error = EINVAL;
16947c478bd9Sstevel@tonic-gate return;
16957c478bd9Sstevel@tonic-gate }
16967c478bd9Sstevel@tonic-gate lookuparg.argsp = &args;
16977c478bd9Sstevel@tonic-gate lookuparg.resp = &res;
16987c478bd9Sstevel@tonic-gate lookuparg.header_len = 1; /* Putfh */
16997c478bd9Sstevel@tonic-gate lookuparg.trailer_len = 0;
17007c478bd9Sstevel@tonic-gate lookuparg.ga_bits = NFS4_VATTR_MASK;
17017c478bd9Sstevel@tonic-gate lookuparg.mi = VTOMI4(rootvp);
17027c478bd9Sstevel@tonic-gate
17037c478bd9Sstevel@tonic-gate (void) nfs4lookup_setup(path, &lookuparg, 1);
17047c478bd9Sstevel@tonic-gate
17057c478bd9Sstevel@tonic-gate /* 0: putfh directory */
17067c478bd9Sstevel@tonic-gate argop = args.array;
17077c478bd9Sstevel@tonic-gate argop[0].argop = OP_CPUTFH;
17087c478bd9Sstevel@tonic-gate argop[0].nfs_argop4_u.opcputfh.sfh = VTOR4(rootvp)->r_fh;
17097c478bd9Sstevel@tonic-gate
17107c478bd9Sstevel@tonic-gate num_argops = args.array_len;
17117c478bd9Sstevel@tonic-gate
17127c478bd9Sstevel@tonic-gate rfs4call(mi, &args, &res, cr, &doqueue, RFSCALL_SOFT, ep);
17137c478bd9Sstevel@tonic-gate
17147c478bd9Sstevel@tonic-gate if (ep->error || res.status != NFS4_OK)
17157c478bd9Sstevel@tonic-gate goto exit;
17167c478bd9Sstevel@tonic-gate
17177c478bd9Sstevel@tonic-gate /* get the object filehandle */
17187c478bd9Sstevel@tonic-gate resop = &res.array[res.array_len - 2];
17197c478bd9Sstevel@tonic-gate if (resop->resop != OP_GETFH) {
17207c478bd9Sstevel@tonic-gate nfs4_queue_event(RE_FAIL_REMAP_OP, mi, NULL,
17217c478bd9Sstevel@tonic-gate 0, NULL, NULL, 0, NULL, 0, TAG_NONE, TAG_NONE, 0, 0);
17227c478bd9Sstevel@tonic-gate ep->stat = NFS4ERR_SERVERFAULT;
17237c478bd9Sstevel@tonic-gate goto exit;
17247c478bd9Sstevel@tonic-gate }
17257c478bd9Sstevel@tonic-gate tmpfhp = &resop->nfs_resop4_u.opgetfh.object;
17267c478bd9Sstevel@tonic-gate if (tmpfhp->nfs_fh4_len > NFS4_FHSIZE) {
17277c478bd9Sstevel@tonic-gate nfs4_queue_event(RE_FAIL_REMAP_LEN, mi, NULL,
17287c478bd9Sstevel@tonic-gate tmpfhp->nfs_fh4_len, NULL, NULL, 0, NULL, 0, TAG_NONE,
17297c478bd9Sstevel@tonic-gate TAG_NONE, 0, 0);
17307c478bd9Sstevel@tonic-gate ep->stat = NFS4ERR_SERVERFAULT;
17317c478bd9Sstevel@tonic-gate goto exit;
17327c478bd9Sstevel@tonic-gate }
17337c478bd9Sstevel@tonic-gate fhp->nfs_fh4_val = kmem_alloc(tmpfhp->nfs_fh4_len, KM_SLEEP);
17347c478bd9Sstevel@tonic-gate nfs_fh4_copy(tmpfhp, fhp);
17357c478bd9Sstevel@tonic-gate
17367c478bd9Sstevel@tonic-gate /* get the object attributes */
17377c478bd9Sstevel@tonic-gate resop = &res.array[res.array_len - 1];
17387c478bd9Sstevel@tonic-gate if (garp && resop->resop == OP_GETATTR)
17397c478bd9Sstevel@tonic-gate *garp = resop->nfs_resop4_u.opgetattr.ga_res;
17407c478bd9Sstevel@tonic-gate
17417c478bd9Sstevel@tonic-gate /* See if there are enough fields in the response for parent info */
17427c478bd9Sstevel@tonic-gate if ((int)res.array_len - 5 <= 0)
17437c478bd9Sstevel@tonic-gate goto exit;
17447c478bd9Sstevel@tonic-gate
17457c478bd9Sstevel@tonic-gate /* get the parent filehandle */
17467c478bd9Sstevel@tonic-gate resop = &res.array[res.array_len - 5];
17477c478bd9Sstevel@tonic-gate if (resop->resop != OP_GETFH) {
17487c478bd9Sstevel@tonic-gate nfs4_queue_event(RE_FAIL_REMAP_OP, mi, NULL,
17497c478bd9Sstevel@tonic-gate 0, NULL, NULL, 0, NULL, 0, TAG_NONE, TAG_NONE, 0, 0);
17507c478bd9Sstevel@tonic-gate ep->stat = NFS4ERR_SERVERFAULT;
17517c478bd9Sstevel@tonic-gate goto exit;
17527c478bd9Sstevel@tonic-gate }
17537c478bd9Sstevel@tonic-gate tmpfhp = &resop->nfs_resop4_u.opgetfh.object;
17547c478bd9Sstevel@tonic-gate if (tmpfhp->nfs_fh4_len > NFS4_FHSIZE) {
17557c478bd9Sstevel@tonic-gate nfs4_queue_event(RE_FAIL_REMAP_LEN, mi, NULL,
17567c478bd9Sstevel@tonic-gate tmpfhp->nfs_fh4_len, NULL, NULL, 0, NULL, 0, TAG_NONE,
17577c478bd9Sstevel@tonic-gate TAG_NONE, 0, 0);
17587c478bd9Sstevel@tonic-gate ep->stat = NFS4ERR_SERVERFAULT;
17597c478bd9Sstevel@tonic-gate goto exit;
17607c478bd9Sstevel@tonic-gate }
17617c478bd9Sstevel@tonic-gate pfhp->nfs_fh4_val = kmem_alloc(tmpfhp->nfs_fh4_len, KM_SLEEP);
17627c478bd9Sstevel@tonic-gate nfs_fh4_copy(tmpfhp, pfhp);
17637c478bd9Sstevel@tonic-gate
17647c478bd9Sstevel@tonic-gate /* get the parent attributes */
17657c478bd9Sstevel@tonic-gate resop = &res.array[res.array_len - 4];
17667c478bd9Sstevel@tonic-gate if (pgarp && resop->resop == OP_GETATTR)
17677c478bd9Sstevel@tonic-gate *pgarp = resop->nfs_resop4_u.opgetattr.ga_res;
17687c478bd9Sstevel@tonic-gate
17697c478bd9Sstevel@tonic-gate exit:
17707c478bd9Sstevel@tonic-gate /*
17717c478bd9Sstevel@tonic-gate * It is too hard to remember where all the OP_LOOKUPs are
17727c478bd9Sstevel@tonic-gate */
17737c478bd9Sstevel@tonic-gate nfs4args_lookup_free(argop, num_argops);
17747c478bd9Sstevel@tonic-gate kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4));
17757c478bd9Sstevel@tonic-gate
17767c478bd9Sstevel@tonic-gate if (!ep->error)
17777c478bd9Sstevel@tonic-gate (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
17787c478bd9Sstevel@tonic-gate kmem_free(path, strlen(path)+1);
17797c478bd9Sstevel@tonic-gate }
17807c478bd9Sstevel@tonic-gate
17817c478bd9Sstevel@tonic-gate /*
17827c478bd9Sstevel@tonic-gate * NFS client failover / volatile filehandle support
17837c478bd9Sstevel@tonic-gate *
17847c478bd9Sstevel@tonic-gate * Recover the filehandle for the given rnode.
17857c478bd9Sstevel@tonic-gate *
17867c478bd9Sstevel@tonic-gate * Errors are returned via the nfs4_error_t parameter.
17877c478bd9Sstevel@tonic-gate */
17887c478bd9Sstevel@tonic-gate
17897c478bd9Sstevel@tonic-gate void
nfs4_remap_file(mntinfo4_t * mi,vnode_t * vp,int flags,nfs4_error_t * ep)17907c478bd9Sstevel@tonic-gate nfs4_remap_file(mntinfo4_t *mi, vnode_t *vp, int flags, nfs4_error_t *ep)
17917c478bd9Sstevel@tonic-gate {
1792b9238976Sth199096 int is_stub;
17937c478bd9Sstevel@tonic-gate rnode4_t *rp = VTOR4(vp);
17947c478bd9Sstevel@tonic-gate vnode_t *rootvp = NULL;
17957c478bd9Sstevel@tonic-gate vnode_t *dvp = NULL;
17967c478bd9Sstevel@tonic-gate cred_t *cr, *cred_otw;
17977c478bd9Sstevel@tonic-gate nfs4_ga_res_t gar, pgar;
17987c478bd9Sstevel@tonic-gate nfs_fh4 newfh = {0, NULL}, newpfh = {0, NULL};
17997c478bd9Sstevel@tonic-gate int filetype = RML_ORDINARY;
18007c478bd9Sstevel@tonic-gate nfs4_recov_state_t recov = {NULL, 0, 0};
18017c478bd9Sstevel@tonic-gate int badfhcount = 0;
18027c478bd9Sstevel@tonic-gate nfs4_open_stream_t *osp = NULL;
18037c478bd9Sstevel@tonic-gate bool_t first_time = TRUE; /* first time getting OTW cred */
18047c478bd9Sstevel@tonic-gate bool_t last_time = FALSE; /* last time getting OTW cred */
18057c478bd9Sstevel@tonic-gate
18067c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_failover_debug, (CE_NOTE,
18077c478bd9Sstevel@tonic-gate "nfs4_remap_file: remapping %s", rnode4info(rp)));
18087c478bd9Sstevel@tonic-gate ASSERT(nfs4_consistent_type(vp));
18097c478bd9Sstevel@tonic-gate
18107c478bd9Sstevel@tonic-gate if (vp->v_flag & VROOT) {
18117c478bd9Sstevel@tonic-gate nfs4_remap_root(mi, ep, flags);
18127c478bd9Sstevel@tonic-gate return;
18137c478bd9Sstevel@tonic-gate }
18147c478bd9Sstevel@tonic-gate
18157c478bd9Sstevel@tonic-gate /*
18167c478bd9Sstevel@tonic-gate * Given the root fh, use the path stored in
18177c478bd9Sstevel@tonic-gate * the rnode to find the fh for the new server.
18187c478bd9Sstevel@tonic-gate */
18197c478bd9Sstevel@tonic-gate ep->error = VFS_ROOT(mi->mi_vfsp, &rootvp);
18207c478bd9Sstevel@tonic-gate if (ep->error != 0)
18217c478bd9Sstevel@tonic-gate return;
18227c478bd9Sstevel@tonic-gate
18237c478bd9Sstevel@tonic-gate cr = curthread->t_cred;
18247c478bd9Sstevel@tonic-gate ASSERT(cr != NULL);
18257c478bd9Sstevel@tonic-gate get_remap_cred:
18267c478bd9Sstevel@tonic-gate /*
18277c478bd9Sstevel@tonic-gate * Releases the osp, if it is provided.
18287c478bd9Sstevel@tonic-gate * Puts a hold on the cred_otw and the new osp (if found).
18297c478bd9Sstevel@tonic-gate */
18307c478bd9Sstevel@tonic-gate cred_otw = nfs4_get_otw_cred_by_osp(rp, cr, &osp,
18317c478bd9Sstevel@tonic-gate &first_time, &last_time);
18327c478bd9Sstevel@tonic-gate ASSERT(cred_otw != NULL);
18337c478bd9Sstevel@tonic-gate
18347c478bd9Sstevel@tonic-gate if (rp->r_flags & R4ISXATTR) {
18357c478bd9Sstevel@tonic-gate filetype = RML_NAMED_ATTR;
18367c478bd9Sstevel@tonic-gate (void) vtodv(vp, &dvp, cred_otw, FALSE);
18377c478bd9Sstevel@tonic-gate }
18387c478bd9Sstevel@tonic-gate
18397c478bd9Sstevel@tonic-gate if (vp->v_flag & V_XATTRDIR) {
18407c478bd9Sstevel@tonic-gate filetype = RML_ATTRDIR;
18417c478bd9Sstevel@tonic-gate }
18427c478bd9Sstevel@tonic-gate
18437c478bd9Sstevel@tonic-gate if (filetype == RML_ORDINARY && rootvp->v_type == VREG) {
18447c478bd9Sstevel@tonic-gate /* file mount, doesn't need a remap */
18457c478bd9Sstevel@tonic-gate goto done;
18467c478bd9Sstevel@tonic-gate }
18477c478bd9Sstevel@tonic-gate
18487c478bd9Sstevel@tonic-gate again:
18497c478bd9Sstevel@tonic-gate remap_lookup(rp->r_svnode.sv_name, rootvp, filetype, cred_otw,
18507c478bd9Sstevel@tonic-gate &newfh, &gar, &newpfh, &pgar, ep);
18517c478bd9Sstevel@tonic-gate
18527c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_failover_debug, (CE_NOTE,
18537c478bd9Sstevel@tonic-gate "nfs4_remap_file: remap_lookup returned %d/%d",
18547c478bd9Sstevel@tonic-gate ep->error, ep->stat));
18557c478bd9Sstevel@tonic-gate
18567c478bd9Sstevel@tonic-gate if (last_time == FALSE && ep->error == EACCES) {
18577c478bd9Sstevel@tonic-gate crfree(cred_otw);
18587c478bd9Sstevel@tonic-gate if (dvp != NULL)
18597c478bd9Sstevel@tonic-gate VN_RELE(dvp);
18607c478bd9Sstevel@tonic-gate goto get_remap_cred;
18617c478bd9Sstevel@tonic-gate }
18627c478bd9Sstevel@tonic-gate if (ep->error != 0)
18637c478bd9Sstevel@tonic-gate goto done;
18647c478bd9Sstevel@tonic-gate
18657c478bd9Sstevel@tonic-gate switch (ep->stat) {
18667c478bd9Sstevel@tonic-gate case NFS4_OK:
18677c478bd9Sstevel@tonic-gate badfhcount = 0;
18687c478bd9Sstevel@tonic-gate if (recov.rs_flags & NFS4_RS_DELAY_MSG) {
18697c478bd9Sstevel@tonic-gate mutex_enter(&rp->r_statelock);
18707c478bd9Sstevel@tonic-gate rp->r_delay_interval = 0;
18717c478bd9Sstevel@tonic-gate mutex_exit(&rp->r_statelock);
18727c478bd9Sstevel@tonic-gate uprintf("NFS File Available..\n");
18737c478bd9Sstevel@tonic-gate }
18747c478bd9Sstevel@tonic-gate break;
18757c478bd9Sstevel@tonic-gate case NFS4ERR_FHEXPIRED:
18767c478bd9Sstevel@tonic-gate case NFS4ERR_BADHANDLE:
1877ddbc368aSRick Mesta case NFS4ERR_STALE:
18787c478bd9Sstevel@tonic-gate /*
18797c478bd9Sstevel@tonic-gate * If we ran into filehandle problems, we should try to
18807c478bd9Sstevel@tonic-gate * remap the root vnode first and hope life gets better.
18817c478bd9Sstevel@tonic-gate * But we need to avoid loops.
18827c478bd9Sstevel@tonic-gate */
18837c478bd9Sstevel@tonic-gate if (badfhcount++ > 0)
18847c478bd9Sstevel@tonic-gate goto done;
18857c478bd9Sstevel@tonic-gate if (newfh.nfs_fh4_len != 0) {
18867c478bd9Sstevel@tonic-gate kmem_free(newfh.nfs_fh4_val, newfh.nfs_fh4_len);
18877c478bd9Sstevel@tonic-gate newfh.nfs_fh4_len = 0;
18887c478bd9Sstevel@tonic-gate }
18897c478bd9Sstevel@tonic-gate if (newpfh.nfs_fh4_len != 0) {
18907c478bd9Sstevel@tonic-gate kmem_free(newpfh.nfs_fh4_val, newpfh.nfs_fh4_len);
18917c478bd9Sstevel@tonic-gate newpfh.nfs_fh4_len = 0;
18927c478bd9Sstevel@tonic-gate }
18937c478bd9Sstevel@tonic-gate /* relative path - remap rootvp then retry */
18947c478bd9Sstevel@tonic-gate VN_RELE(rootvp);
18957c478bd9Sstevel@tonic-gate rootvp = NULL;
18967c478bd9Sstevel@tonic-gate nfs4_remap_root(mi, ep, flags);
18977c478bd9Sstevel@tonic-gate if (ep->error != 0 || ep->stat != NFS4_OK)
18987c478bd9Sstevel@tonic-gate goto done;
18997c478bd9Sstevel@tonic-gate ep->error = VFS_ROOT(mi->mi_vfsp, &rootvp);
19007c478bd9Sstevel@tonic-gate if (ep->error != 0)
19017c478bd9Sstevel@tonic-gate goto done;
19027c478bd9Sstevel@tonic-gate goto again;
19037c478bd9Sstevel@tonic-gate case NFS4ERR_DELAY:
19047c478bd9Sstevel@tonic-gate badfhcount = 0;
19057c478bd9Sstevel@tonic-gate nfs4_set_delay_wait(vp);
19067c478bd9Sstevel@tonic-gate ep->error = nfs4_wait_for_delay(vp, &recov);
19077c478bd9Sstevel@tonic-gate if (ep->error != 0)
19087c478bd9Sstevel@tonic-gate goto done;
19097c478bd9Sstevel@tonic-gate goto again;
19107c478bd9Sstevel@tonic-gate case NFS4ERR_ACCESS:
19117c478bd9Sstevel@tonic-gate /* get new cred, try again */
19127c478bd9Sstevel@tonic-gate if (last_time == TRUE)
19137c478bd9Sstevel@tonic-gate goto done;
19147c478bd9Sstevel@tonic-gate if (dvp != NULL)
19157c478bd9Sstevel@tonic-gate VN_RELE(dvp);
19167c478bd9Sstevel@tonic-gate crfree(cred_otw);
19177c478bd9Sstevel@tonic-gate goto get_remap_cred;
19187c478bd9Sstevel@tonic-gate default:
19197c478bd9Sstevel@tonic-gate goto done;
19207c478bd9Sstevel@tonic-gate }
19217c478bd9Sstevel@tonic-gate
19227c478bd9Sstevel@tonic-gate /*
19237c478bd9Sstevel@tonic-gate * Check on the new and old rnodes before updating;
19247c478bd9Sstevel@tonic-gate * if the vnode type or size changes, issue a warning
19257c478bd9Sstevel@tonic-gate * and mark the file dead.
19267c478bd9Sstevel@tonic-gate */
19277c478bd9Sstevel@tonic-gate mutex_enter(&rp->r_statelock);
19287c478bd9Sstevel@tonic-gate if (flags & NFS4_REMAP_CKATTRS) {
19297c478bd9Sstevel@tonic-gate if (vp->v_type != gar.n4g_va.va_type ||
19307c478bd9Sstevel@tonic-gate (vp->v_type != VDIR &&
19317c478bd9Sstevel@tonic-gate rp->r_size != gar.n4g_va.va_size)) {
19327c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_failover_debug, (CE_NOTE,
19337c478bd9Sstevel@tonic-gate "nfs4_remap_file: size %d vs. %d, type %d vs. %d",
19347c478bd9Sstevel@tonic-gate (int)rp->r_size, (int)gar.n4g_va.va_size,
19357c478bd9Sstevel@tonic-gate vp->v_type, gar.n4g_va.va_type));
19367c478bd9Sstevel@tonic-gate mutex_exit(&rp->r_statelock);
19377c478bd9Sstevel@tonic-gate nfs4_queue_event(RE_FILE_DIFF, mi,
19387c478bd9Sstevel@tonic-gate rp->r_server->sv_hostname, 0, vp, NULL, 0, NULL, 0,
19397c478bd9Sstevel@tonic-gate TAG_NONE, TAG_NONE, 0, 0);
19407c478bd9Sstevel@tonic-gate nfs4_fail_recov(vp, NULL, 0, NFS4_OK);
19417c478bd9Sstevel@tonic-gate goto done;
19427c478bd9Sstevel@tonic-gate }
19437c478bd9Sstevel@tonic-gate }
19447c478bd9Sstevel@tonic-gate ASSERT(gar.n4g_va.va_type != VNON);
19457c478bd9Sstevel@tonic-gate rp->r_server = mi->mi_curr_serv;
19467c478bd9Sstevel@tonic-gate
1947b9238976Sth199096 /*
1948b9238976Sth199096 * Turn this object into a "stub" object if we
1949b9238976Sth199096 * crossed an underlying server fs boundary.
1950b9238976Sth199096 *
1951b9238976Sth199096 * This stub will be for a mirror-mount.
19522f172c55SRobert Thurlow * A referral would look like a boundary crossing
19532f172c55SRobert Thurlow * as well, but would not be the same type of object,
19542f172c55SRobert Thurlow * so we would expect to mark the object dead.
1955b9238976Sth199096 *
1956b9238976Sth199096 * See comment in r4_do_attrcache() for more details.
1957b9238976Sth199096 */
1958b9238976Sth199096 is_stub = 0;
19597c478bd9Sstevel@tonic-gate if (gar.n4g_fsid_valid) {
19607c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&rp->r_server->sv_lock, RW_READER, 0);
19617c478bd9Sstevel@tonic-gate rp->r_srv_fsid = gar.n4g_fsid;
1962b9238976Sth199096 if (!FATTR4_FSID_EQ(&gar.n4g_fsid, &rp->r_server->sv_fsid))
1963b9238976Sth199096 is_stub = 1;
19647c478bd9Sstevel@tonic-gate nfs_rw_exit(&rp->r_server->sv_lock);
19657c478bd9Sstevel@tonic-gate #ifdef DEBUG
19667c478bd9Sstevel@tonic-gate } else {
19677c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_failover_debug, (CE_NOTE,
19687c478bd9Sstevel@tonic-gate "remap_file: fsid attr not provided by server. rp=%p",
19697c478bd9Sstevel@tonic-gate (void *)rp));
19707c478bd9Sstevel@tonic-gate #endif
19717c478bd9Sstevel@tonic-gate }
1972b9238976Sth199096 if (is_stub)
1973b9238976Sth199096 r4_stub_mirrormount(rp);
1974b9238976Sth199096 else
1975b9238976Sth199096 r4_stub_none(rp);
19767c478bd9Sstevel@tonic-gate mutex_exit(&rp->r_statelock);
19777c478bd9Sstevel@tonic-gate nfs4_attrcache_noinval(vp, &gar, gethrtime()); /* force update */
19787c478bd9Sstevel@tonic-gate sfh4_update(rp->r_fh, &newfh);
19797c478bd9Sstevel@tonic-gate ASSERT(nfs4_consistent_type(vp));
19807c478bd9Sstevel@tonic-gate
19817c478bd9Sstevel@tonic-gate /*
19827c478bd9Sstevel@tonic-gate * If we got parent info, use it to update the parent
19837c478bd9Sstevel@tonic-gate */
19847c478bd9Sstevel@tonic-gate if (newpfh.nfs_fh4_len != 0) {
19857c478bd9Sstevel@tonic-gate if (rp->r_svnode.sv_dfh != NULL)
19867c478bd9Sstevel@tonic-gate sfh4_update(rp->r_svnode.sv_dfh, &newpfh);
19877c478bd9Sstevel@tonic-gate if (dvp != NULL) {
19887c478bd9Sstevel@tonic-gate /* force update of attrs */
19897c478bd9Sstevel@tonic-gate nfs4_attrcache_noinval(dvp, &pgar, gethrtime());
19907c478bd9Sstevel@tonic-gate }
19917c478bd9Sstevel@tonic-gate }
19927c478bd9Sstevel@tonic-gate done:
19937c478bd9Sstevel@tonic-gate if (newfh.nfs_fh4_len != 0)
19947c478bd9Sstevel@tonic-gate kmem_free(newfh.nfs_fh4_val, newfh.nfs_fh4_len);
19957c478bd9Sstevel@tonic-gate if (newpfh.nfs_fh4_len != 0)
19967c478bd9Sstevel@tonic-gate kmem_free(newpfh.nfs_fh4_val, newpfh.nfs_fh4_len);
19977c478bd9Sstevel@tonic-gate if (cred_otw != NULL)
19987c478bd9Sstevel@tonic-gate crfree(cred_otw);
19997c478bd9Sstevel@tonic-gate if (rootvp != NULL)
20007c478bd9Sstevel@tonic-gate VN_RELE(rootvp);
20017c478bd9Sstevel@tonic-gate if (dvp != NULL)
20027c478bd9Sstevel@tonic-gate VN_RELE(dvp);
20037c478bd9Sstevel@tonic-gate if (osp != NULL)
20047c478bd9Sstevel@tonic-gate open_stream_rele(osp, rp);
20057c478bd9Sstevel@tonic-gate }
20067c478bd9Sstevel@tonic-gate
20077c478bd9Sstevel@tonic-gate /*
20087c478bd9Sstevel@tonic-gate * Client-side failover support: remap the filehandle for vp if it appears
20097c478bd9Sstevel@tonic-gate * necessary. errors are returned via the nfs4_error_t parameter; though,
20107c478bd9Sstevel@tonic-gate * if there is a problem, we will just try again later.
20117c478bd9Sstevel@tonic-gate */
20127c478bd9Sstevel@tonic-gate
20137c478bd9Sstevel@tonic-gate void
nfs4_check_remap(mntinfo4_t * mi,vnode_t * vp,int flags,nfs4_error_t * ep)20147c478bd9Sstevel@tonic-gate nfs4_check_remap(mntinfo4_t *mi, vnode_t *vp, int flags, nfs4_error_t *ep)
20157c478bd9Sstevel@tonic-gate {
20167c478bd9Sstevel@tonic-gate if (vp == NULL)
20177c478bd9Sstevel@tonic-gate return;
20187c478bd9Sstevel@tonic-gate
20197c478bd9Sstevel@tonic-gate if (!(vp->v_vfsp->vfs_flag & VFS_RDONLY))
20207c478bd9Sstevel@tonic-gate return;
20217c478bd9Sstevel@tonic-gate
20227c478bd9Sstevel@tonic-gate if (VTOR4(vp)->r_server == mi->mi_curr_serv)
20237c478bd9Sstevel@tonic-gate return;
20247c478bd9Sstevel@tonic-gate
20257c478bd9Sstevel@tonic-gate nfs4_remap_file(mi, vp, flags, ep);
20267c478bd9Sstevel@tonic-gate }
20277c478bd9Sstevel@tonic-gate
20287c478bd9Sstevel@tonic-gate /*
20297c478bd9Sstevel@tonic-gate * nfs4_make_dotdot() - find or create a parent vnode of a non-root node.
20307c478bd9Sstevel@tonic-gate *
20317c478bd9Sstevel@tonic-gate * Our caller has a filehandle for ".." relative to a particular
20327c478bd9Sstevel@tonic-gate * directory object. We want to find or create a parent vnode
20337c478bd9Sstevel@tonic-gate * with that filehandle and return it. We can of course create
20347c478bd9Sstevel@tonic-gate * a vnode from this filehandle, but we need to also make sure
20357c478bd9Sstevel@tonic-gate * that if ".." is a regular file (i.e. dvp is a V_XATTRDIR)
20367c478bd9Sstevel@tonic-gate * that we have a parent FH for future reopens as well. If
20377c478bd9Sstevel@tonic-gate * we have a remap failure, we won't be able to reopen this
20387c478bd9Sstevel@tonic-gate * file, but we won't treat that as fatal because a reopen
20397c478bd9Sstevel@tonic-gate * is at least unlikely. Someday nfs4_reopen() should look
20407c478bd9Sstevel@tonic-gate * for a missing parent FH and try a remap to recover from it.
20417c478bd9Sstevel@tonic-gate *
20427c478bd9Sstevel@tonic-gate * need_start_op argument indicates whether this function should
20437c478bd9Sstevel@tonic-gate * do a start_op before calling remap_lookup(). This should
20447c478bd9Sstevel@tonic-gate * be FALSE, if you are the recovery thread or in an op; otherwise,
20457c478bd9Sstevel@tonic-gate * set it to TRUE.
20467c478bd9Sstevel@tonic-gate */
20477c478bd9Sstevel@tonic-gate int
nfs4_make_dotdot(nfs4_sharedfh_t * fhp,hrtime_t t,vnode_t * dvp,cred_t * cr,vnode_t ** vpp,int need_start_op)20487c478bd9Sstevel@tonic-gate nfs4_make_dotdot(nfs4_sharedfh_t *fhp, hrtime_t t, vnode_t *dvp,
20497c478bd9Sstevel@tonic-gate cred_t *cr, vnode_t **vpp, int need_start_op)
20507c478bd9Sstevel@tonic-gate {
20517c478bd9Sstevel@tonic-gate mntinfo4_t *mi = VTOMI4(dvp);
20527c478bd9Sstevel@tonic-gate nfs4_fname_t *np = NULL, *pnp = NULL;
20537c478bd9Sstevel@tonic-gate vnode_t *vp = NULL, *rootvp = NULL;
20547c478bd9Sstevel@tonic-gate rnode4_t *rp;
20557c478bd9Sstevel@tonic-gate nfs_fh4 newfh = {0, NULL}, newpfh = {0, NULL};
20567c478bd9Sstevel@tonic-gate nfs4_ga_res_t gar, pgar;
20577c478bd9Sstevel@tonic-gate vattr_t va, pva;
20587c478bd9Sstevel@tonic-gate nfs4_error_t e = { 0, NFS4_OK, RPC_SUCCESS };
20597c478bd9Sstevel@tonic-gate nfs4_sharedfh_t *sfh = NULL, *psfh = NULL;
20607c478bd9Sstevel@tonic-gate nfs4_recov_state_t recov_state;
20617c478bd9Sstevel@tonic-gate
20627c478bd9Sstevel@tonic-gate #ifdef DEBUG
20637c478bd9Sstevel@tonic-gate /*
20647c478bd9Sstevel@tonic-gate * ensure need_start_op is correct
20657c478bd9Sstevel@tonic-gate */
20667c478bd9Sstevel@tonic-gate {
20677c478bd9Sstevel@tonic-gate int no_need_start_op = (tsd_get(nfs4_tsd_key) ||
20687c478bd9Sstevel@tonic-gate (curthread == mi->mi_recovthread));
20697c478bd9Sstevel@tonic-gate /* C needs a ^^ operator! */
20707c478bd9Sstevel@tonic-gate ASSERT(((need_start_op) && (!no_need_start_op)) ||
20717c478bd9Sstevel@tonic-gate ((! need_start_op) && (no_need_start_op)));
20727c478bd9Sstevel@tonic-gate }
20737c478bd9Sstevel@tonic-gate #endif
2074108322fbScarlsonj ASSERT(VTOMI4(dvp)->mi_zone == nfs_zone());
20757c478bd9Sstevel@tonic-gate
20767c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_shadow_debug, (CE_NOTE,
20777c478bd9Sstevel@tonic-gate "nfs4_make_dotdot: called with fhp %p, dvp %s", (void *)fhp,
20787c478bd9Sstevel@tonic-gate rnode4info(VTOR4(dvp))));
20797c478bd9Sstevel@tonic-gate
20807c478bd9Sstevel@tonic-gate /*
20817c478bd9Sstevel@tonic-gate * rootvp might be needed eventually. Holding it now will
20827c478bd9Sstevel@tonic-gate * ensure that r4find_unlocked() will find it, if ".." is the root.
20837c478bd9Sstevel@tonic-gate */
20847c478bd9Sstevel@tonic-gate e.error = VFS_ROOT(mi->mi_vfsp, &rootvp);
20857c478bd9Sstevel@tonic-gate if (e.error != 0)
20867c478bd9Sstevel@tonic-gate goto out;
20877c478bd9Sstevel@tonic-gate rp = r4find_unlocked(fhp, mi->mi_vfsp);
20887c478bd9Sstevel@tonic-gate if (rp != NULL) {
20897c478bd9Sstevel@tonic-gate *vpp = RTOV4(rp);
20907c478bd9Sstevel@tonic-gate VN_RELE(rootvp);
20917c478bd9Sstevel@tonic-gate return (0);
20927c478bd9Sstevel@tonic-gate }
20937c478bd9Sstevel@tonic-gate
20947c478bd9Sstevel@tonic-gate /*
20957c478bd9Sstevel@tonic-gate * Since we don't have the rnode, we have to go over the wire.
20967c478bd9Sstevel@tonic-gate * remap_lookup() can get all of the filehandles and attributes
20977c478bd9Sstevel@tonic-gate * we need in one operation.
20987c478bd9Sstevel@tonic-gate */
20997c478bd9Sstevel@tonic-gate np = fn_parent(VTOSV(dvp)->sv_name);
2100416a371aSGerald Thornbrugh /* if a parent was not found return an error */
2101416a371aSGerald Thornbrugh if (np == NULL) {
2102416a371aSGerald Thornbrugh e.error = ENOENT;
2103416a371aSGerald Thornbrugh goto out;
2104416a371aSGerald Thornbrugh }
21057c478bd9Sstevel@tonic-gate
21067c478bd9Sstevel@tonic-gate recov_state.rs_flags = 0;
21077c478bd9Sstevel@tonic-gate recov_state.rs_num_retry_despite_err = 0;
21087c478bd9Sstevel@tonic-gate recov_retry:
21097c478bd9Sstevel@tonic-gate if (need_start_op) {
21107c478bd9Sstevel@tonic-gate e.error = nfs4_start_fop(mi, rootvp, NULL, OH_LOOKUP,
21117c478bd9Sstevel@tonic-gate &recov_state, NULL);
21127c478bd9Sstevel@tonic-gate if (e.error != 0) {
21137c478bd9Sstevel@tonic-gate goto out;
21147c478bd9Sstevel@tonic-gate }
21157c478bd9Sstevel@tonic-gate }
211696e91bfeSSimon Klinkert
211796e91bfeSSimon Klinkert pgar.n4g_va.va_type = VNON;
211896e91bfeSSimon Klinkert gar.n4g_va.va_type = VNON;
211996e91bfeSSimon Klinkert
21207c478bd9Sstevel@tonic-gate remap_lookup(np, rootvp, RML_ORDINARY, cr,
21217c478bd9Sstevel@tonic-gate &newfh, &gar, &newpfh, &pgar, &e);
21227c478bd9Sstevel@tonic-gate if (nfs4_needs_recovery(&e, FALSE, mi->mi_vfsp)) {
21237c478bd9Sstevel@tonic-gate if (need_start_op) {
21247c478bd9Sstevel@tonic-gate bool_t abort;
21257c478bd9Sstevel@tonic-gate
21267c478bd9Sstevel@tonic-gate abort = nfs4_start_recovery(&e, mi,
21272f172c55SRobert Thurlow rootvp, NULL, NULL, NULL, OP_LOOKUP, NULL, NULL,
21282f172c55SRobert Thurlow NULL);
21297c478bd9Sstevel@tonic-gate if (abort) {
21307c478bd9Sstevel@tonic-gate nfs4_end_fop(mi, rootvp, NULL, OH_LOOKUP,
21317c478bd9Sstevel@tonic-gate &recov_state, FALSE);
21327c478bd9Sstevel@tonic-gate if (e.error == 0)
21337c478bd9Sstevel@tonic-gate e.error = EIO;
21347c478bd9Sstevel@tonic-gate goto out;
21357c478bd9Sstevel@tonic-gate }
21367c478bd9Sstevel@tonic-gate nfs4_end_fop(mi, rootvp, NULL, OH_LOOKUP,
21377c478bd9Sstevel@tonic-gate &recov_state, TRUE);
21387c478bd9Sstevel@tonic-gate goto recov_retry;
21397c478bd9Sstevel@tonic-gate }
21407c478bd9Sstevel@tonic-gate if (e.error == 0)
21417c478bd9Sstevel@tonic-gate e.error = EIO;
21427c478bd9Sstevel@tonic-gate goto out;
21437c478bd9Sstevel@tonic-gate }
21447c478bd9Sstevel@tonic-gate
21457c478bd9Sstevel@tonic-gate va = gar.n4g_va;
21467c478bd9Sstevel@tonic-gate pva = pgar.n4g_va;
21477c478bd9Sstevel@tonic-gate
21487c478bd9Sstevel@tonic-gate if ((e.error != 0) ||
21497c478bd9Sstevel@tonic-gate (va.va_type != VDIR)) {
2150c38d8a0cSth199096 if (need_start_op)
2151c38d8a0cSth199096 nfs4_end_fop(mi, rootvp, NULL, OH_LOOKUP,
2152c38d8a0cSth199096 &recov_state, FALSE);
21537c478bd9Sstevel@tonic-gate if (e.error == 0)
21547c478bd9Sstevel@tonic-gate e.error = EIO;
21557c478bd9Sstevel@tonic-gate goto out;
21567c478bd9Sstevel@tonic-gate }
21577c478bd9Sstevel@tonic-gate
21587c478bd9Sstevel@tonic-gate if (e.stat != NFS4_OK) {
2159c38d8a0cSth199096 if (need_start_op)
2160c38d8a0cSth199096 nfs4_end_fop(mi, rootvp, NULL, OH_LOOKUP,
2161c38d8a0cSth199096 &recov_state, FALSE);
21627c478bd9Sstevel@tonic-gate e.error = EIO;
21637c478bd9Sstevel@tonic-gate goto out;
21647c478bd9Sstevel@tonic-gate }
21657c478bd9Sstevel@tonic-gate
21667c478bd9Sstevel@tonic-gate /*
21677c478bd9Sstevel@tonic-gate * It is possible for remap_lookup() to return with no error,
21687c478bd9Sstevel@tonic-gate * but without providing the parent filehandle and attrs.
21697c478bd9Sstevel@tonic-gate */
21707c478bd9Sstevel@tonic-gate if (pva.va_type != VDIR) {
21717c478bd9Sstevel@tonic-gate /*
21727c478bd9Sstevel@tonic-gate * Call remap_lookup() again, this time with the
21737c478bd9Sstevel@tonic-gate * newpfh and pgar args in the first position.
21747c478bd9Sstevel@tonic-gate */
21757c478bd9Sstevel@tonic-gate pnp = fn_parent(np);
21767c478bd9Sstevel@tonic-gate if (pnp != NULL) {
21777c478bd9Sstevel@tonic-gate remap_lookup(pnp, rootvp, RML_ORDINARY, cr,
21787c478bd9Sstevel@tonic-gate &newpfh, &pgar, NULL, NULL, &e);
217996e91bfeSSimon Klinkert /*
218096e91bfeSSimon Klinkert * This remap_lookup call modifies pgar. The following
218196e91bfeSSimon Klinkert * line prevents trouble when checking the va_type of
218296e91bfeSSimon Klinkert * pva later in this code.
218396e91bfeSSimon Klinkert */
218496e91bfeSSimon Klinkert pva = pgar.n4g_va;
218596e91bfeSSimon Klinkert
21867c478bd9Sstevel@tonic-gate if (nfs4_needs_recovery(&e, FALSE,
21877c478bd9Sstevel@tonic-gate mi->mi_vfsp)) {
21887c478bd9Sstevel@tonic-gate if (need_start_op) {
21897c478bd9Sstevel@tonic-gate bool_t abort;
21907c478bd9Sstevel@tonic-gate
21917c478bd9Sstevel@tonic-gate abort = nfs4_start_recovery(&e, mi,
21927c478bd9Sstevel@tonic-gate rootvp, NULL, NULL, NULL,
21932f172c55SRobert Thurlow OP_LOOKUP, NULL, NULL, NULL);
21947c478bd9Sstevel@tonic-gate if (abort) {
21957c478bd9Sstevel@tonic-gate nfs4_end_fop(mi, rootvp, NULL,
21967c478bd9Sstevel@tonic-gate OH_LOOKUP, &recov_state,
21977c478bd9Sstevel@tonic-gate FALSE);
21987c478bd9Sstevel@tonic-gate if (e.error == 0)
21997c478bd9Sstevel@tonic-gate e.error = EIO;
22007c478bd9Sstevel@tonic-gate goto out;
22017c478bd9Sstevel@tonic-gate }
22027c478bd9Sstevel@tonic-gate nfs4_end_fop(mi, rootvp, NULL,
22037c478bd9Sstevel@tonic-gate OH_LOOKUP, &recov_state, TRUE);
22047c478bd9Sstevel@tonic-gate goto recov_retry;
22057c478bd9Sstevel@tonic-gate }
22067c478bd9Sstevel@tonic-gate if (e.error == 0)
22077c478bd9Sstevel@tonic-gate e.error = EIO;
22087c478bd9Sstevel@tonic-gate goto out;
22097c478bd9Sstevel@tonic-gate }
22107c478bd9Sstevel@tonic-gate
22117c478bd9Sstevel@tonic-gate if (e.stat != NFS4_OK) {
2212c38d8a0cSth199096 if (need_start_op)
2213c38d8a0cSth199096 nfs4_end_fop(mi, rootvp, NULL,
2214c38d8a0cSth199096 OH_LOOKUP, &recov_state, FALSE);
22157c478bd9Sstevel@tonic-gate e.error = EIO;
22167c478bd9Sstevel@tonic-gate goto out;
22177c478bd9Sstevel@tonic-gate }
22187c478bd9Sstevel@tonic-gate }
22197c478bd9Sstevel@tonic-gate if ((pnp == NULL) ||
22207c478bd9Sstevel@tonic-gate (e.error != 0) ||
22217c478bd9Sstevel@tonic-gate (pva.va_type == VNON)) {
22227c478bd9Sstevel@tonic-gate if (need_start_op)
22237c478bd9Sstevel@tonic-gate nfs4_end_fop(mi, rootvp, NULL, OH_LOOKUP,
22247c478bd9Sstevel@tonic-gate &recov_state, FALSE);
22257c478bd9Sstevel@tonic-gate if (e.error == 0)
22267c478bd9Sstevel@tonic-gate e.error = EIO;
22277c478bd9Sstevel@tonic-gate goto out;
22287c478bd9Sstevel@tonic-gate }
22297c478bd9Sstevel@tonic-gate }
22307c478bd9Sstevel@tonic-gate ASSERT(newpfh.nfs_fh4_len != 0);
22317c478bd9Sstevel@tonic-gate if (need_start_op)
22327c478bd9Sstevel@tonic-gate nfs4_end_fop(mi, rootvp, NULL, OH_LOOKUP, &recov_state, FALSE);
22337c478bd9Sstevel@tonic-gate psfh = sfh4_get(&newpfh, mi);
22347c478bd9Sstevel@tonic-gate
22357c478bd9Sstevel@tonic-gate sfh = sfh4_get(&newfh, mi);
22367c478bd9Sstevel@tonic-gate vp = makenfs4node_by_fh(sfh, psfh, &np, &gar, mi, cr, t);
22377c478bd9Sstevel@tonic-gate
22387c478bd9Sstevel@tonic-gate out:
22397c478bd9Sstevel@tonic-gate if (np != NULL)
22407c478bd9Sstevel@tonic-gate fn_rele(&np);
22417c478bd9Sstevel@tonic-gate if (pnp != NULL)
22427c478bd9Sstevel@tonic-gate fn_rele(&pnp);
22437c478bd9Sstevel@tonic-gate if (newfh.nfs_fh4_len != 0)
22447c478bd9Sstevel@tonic-gate kmem_free(newfh.nfs_fh4_val, newfh.nfs_fh4_len);
22457c478bd9Sstevel@tonic-gate if (newpfh.nfs_fh4_len != 0)
22467c478bd9Sstevel@tonic-gate kmem_free(newpfh.nfs_fh4_val, newpfh.nfs_fh4_len);
22477c478bd9Sstevel@tonic-gate if (sfh != NULL)
22487c478bd9Sstevel@tonic-gate sfh4_rele(&sfh);
22497c478bd9Sstevel@tonic-gate if (psfh != NULL)
22507c478bd9Sstevel@tonic-gate sfh4_rele(&psfh);
22517c478bd9Sstevel@tonic-gate if (rootvp != NULL)
22527c478bd9Sstevel@tonic-gate VN_RELE(rootvp);
22537c478bd9Sstevel@tonic-gate *vpp = vp;
22547c478bd9Sstevel@tonic-gate return (e.error);
22557c478bd9Sstevel@tonic-gate }
22567c478bd9Sstevel@tonic-gate
22577c478bd9Sstevel@tonic-gate #ifdef DEBUG
22587c478bd9Sstevel@tonic-gate size_t r_path_memuse = 0;
22597c478bd9Sstevel@tonic-gate #endif
22607c478bd9Sstevel@tonic-gate
22617c478bd9Sstevel@tonic-gate /*
22627c478bd9Sstevel@tonic-gate * NFS client failover support
22637c478bd9Sstevel@tonic-gate *
22647c478bd9Sstevel@tonic-gate * sv4_free() frees the malloc'd portion of a "servinfo_t".
22657c478bd9Sstevel@tonic-gate */
22667c478bd9Sstevel@tonic-gate void
sv4_free(servinfo4_t * svp)22677c478bd9Sstevel@tonic-gate sv4_free(servinfo4_t *svp)
22687c478bd9Sstevel@tonic-gate {
22697c478bd9Sstevel@tonic-gate servinfo4_t *next;
22707c478bd9Sstevel@tonic-gate struct knetconfig *knconf;
22717c478bd9Sstevel@tonic-gate
22727c478bd9Sstevel@tonic-gate while (svp != NULL) {
22737c478bd9Sstevel@tonic-gate next = svp->sv_next;
22747c478bd9Sstevel@tonic-gate if (svp->sv_dhsec)
22757c478bd9Sstevel@tonic-gate sec_clnt_freeinfo(svp->sv_dhsec);
22767c478bd9Sstevel@tonic-gate if (svp->sv_secdata)
22777c478bd9Sstevel@tonic-gate sec_clnt_freeinfo(svp->sv_secdata);
22787c478bd9Sstevel@tonic-gate if (svp->sv_save_secinfo &&
22797c478bd9Sstevel@tonic-gate svp->sv_save_secinfo != svp->sv_secinfo)
22807c478bd9Sstevel@tonic-gate secinfo_free(svp->sv_save_secinfo);
22817c478bd9Sstevel@tonic-gate if (svp->sv_secinfo)
22827c478bd9Sstevel@tonic-gate secinfo_free(svp->sv_secinfo);
22837c478bd9Sstevel@tonic-gate if (svp->sv_hostname && svp->sv_hostnamelen > 0)
22847c478bd9Sstevel@tonic-gate kmem_free(svp->sv_hostname, svp->sv_hostnamelen);
22857c478bd9Sstevel@tonic-gate knconf = svp->sv_knconf;
22867c478bd9Sstevel@tonic-gate if (knconf != NULL) {
22877c478bd9Sstevel@tonic-gate if (knconf->knc_protofmly != NULL)
22887c478bd9Sstevel@tonic-gate kmem_free(knconf->knc_protofmly, KNC_STRSIZE);
22897c478bd9Sstevel@tonic-gate if (knconf->knc_proto != NULL)
22907c478bd9Sstevel@tonic-gate kmem_free(knconf->knc_proto, KNC_STRSIZE);
22917c478bd9Sstevel@tonic-gate kmem_free(knconf, sizeof (*knconf));
22927c478bd9Sstevel@tonic-gate }
22937c478bd9Sstevel@tonic-gate knconf = svp->sv_origknconf;
22947c478bd9Sstevel@tonic-gate if (knconf != NULL) {
22957c478bd9Sstevel@tonic-gate if (knconf->knc_protofmly != NULL)
22967c478bd9Sstevel@tonic-gate kmem_free(knconf->knc_protofmly, KNC_STRSIZE);
22977c478bd9Sstevel@tonic-gate if (knconf->knc_proto != NULL)
22987c478bd9Sstevel@tonic-gate kmem_free(knconf->knc_proto, KNC_STRSIZE);
22997c478bd9Sstevel@tonic-gate kmem_free(knconf, sizeof (*knconf));
23007c478bd9Sstevel@tonic-gate }
23017c478bd9Sstevel@tonic-gate if (svp->sv_addr.buf != NULL && svp->sv_addr.maxlen != 0)
23027c478bd9Sstevel@tonic-gate kmem_free(svp->sv_addr.buf, svp->sv_addr.maxlen);
23037c478bd9Sstevel@tonic-gate if (svp->sv_path != NULL) {
23047c478bd9Sstevel@tonic-gate kmem_free(svp->sv_path, svp->sv_pathlen);
23057c478bd9Sstevel@tonic-gate }
23067c478bd9Sstevel@tonic-gate nfs_rw_destroy(&svp->sv_lock);
23077c478bd9Sstevel@tonic-gate kmem_free(svp, sizeof (*svp));
23087c478bd9Sstevel@tonic-gate svp = next;
23097c478bd9Sstevel@tonic-gate }
23107c478bd9Sstevel@tonic-gate }
23117c478bd9Sstevel@tonic-gate
23127c478bd9Sstevel@tonic-gate void
nfs4_printfhandle(nfs4_fhandle_t * fhp)23137c478bd9Sstevel@tonic-gate nfs4_printfhandle(nfs4_fhandle_t *fhp)
23147c478bd9Sstevel@tonic-gate {
23157c478bd9Sstevel@tonic-gate int *ip;
23167c478bd9Sstevel@tonic-gate char *buf;
23177c478bd9Sstevel@tonic-gate size_t bufsize;
23187c478bd9Sstevel@tonic-gate char *cp;
23197c478bd9Sstevel@tonic-gate
23207c478bd9Sstevel@tonic-gate /*
23217c478bd9Sstevel@tonic-gate * 13 == "(file handle:"
23227c478bd9Sstevel@tonic-gate * maximum of NFS_FHANDLE / sizeof (*ip) elements in fh_buf times
23237c478bd9Sstevel@tonic-gate * 1 == ' '
23247c478bd9Sstevel@tonic-gate * 8 == maximum strlen of "%x"
23257c478bd9Sstevel@tonic-gate * 3 == ")\n\0"
23267c478bd9Sstevel@tonic-gate */
23277c478bd9Sstevel@tonic-gate bufsize = 13 + ((NFS_FHANDLE_LEN / sizeof (*ip)) * (1 + 8)) + 3;
23287c478bd9Sstevel@tonic-gate buf = kmem_alloc(bufsize, KM_NOSLEEP);
23297c478bd9Sstevel@tonic-gate if (buf == NULL)
23307c478bd9Sstevel@tonic-gate return;
23317c478bd9Sstevel@tonic-gate
23327c478bd9Sstevel@tonic-gate cp = buf;
23337c478bd9Sstevel@tonic-gate (void) strcpy(cp, "(file handle:");
23347c478bd9Sstevel@tonic-gate while (*cp != '\0')
23357c478bd9Sstevel@tonic-gate cp++;
23367c478bd9Sstevel@tonic-gate for (ip = (int *)fhp->fh_buf;
23377c478bd9Sstevel@tonic-gate ip < (int *)&fhp->fh_buf[fhp->fh_len];
23387c478bd9Sstevel@tonic-gate ip++) {
23397c478bd9Sstevel@tonic-gate (void) sprintf(cp, " %x", *ip);
23407c478bd9Sstevel@tonic-gate while (*cp != '\0')
23417c478bd9Sstevel@tonic-gate cp++;
23427c478bd9Sstevel@tonic-gate }
23437c478bd9Sstevel@tonic-gate (void) strcpy(cp, ")\n");
23447c478bd9Sstevel@tonic-gate
23457c478bd9Sstevel@tonic-gate zcmn_err(getzoneid(), CE_CONT, "%s", buf);
23467c478bd9Sstevel@tonic-gate
23477c478bd9Sstevel@tonic-gate kmem_free(buf, bufsize);
23487c478bd9Sstevel@tonic-gate }
23497c478bd9Sstevel@tonic-gate
23507c478bd9Sstevel@tonic-gate /*
23517c478bd9Sstevel@tonic-gate * The NFSv4 readdir cache subsystem.
23527c478bd9Sstevel@tonic-gate *
23537c478bd9Sstevel@tonic-gate * We provide a set of interfaces to allow the rest of the system to utilize
23547c478bd9Sstevel@tonic-gate * a caching mechanism while encapsulating the details of the actual
23557c478bd9Sstevel@tonic-gate * implementation. This should allow for better maintainability and
2356da6c28aaSamw * extensibility by consolidating the implementation details in one location.
23577c478bd9Sstevel@tonic-gate */
23587c478bd9Sstevel@tonic-gate
23597c478bd9Sstevel@tonic-gate /*
23607c478bd9Sstevel@tonic-gate * Comparator used by AVL routines.
23617c478bd9Sstevel@tonic-gate */
23627c478bd9Sstevel@tonic-gate static int
rddir4_cache_compar(const void * x,const void * y)23637c478bd9Sstevel@tonic-gate rddir4_cache_compar(const void *x, const void *y)
23647c478bd9Sstevel@tonic-gate {
23657c478bd9Sstevel@tonic-gate rddir4_cache_impl *ai = (rddir4_cache_impl *)x;
23667c478bd9Sstevel@tonic-gate rddir4_cache_impl *bi = (rddir4_cache_impl *)y;
23677c478bd9Sstevel@tonic-gate rddir4_cache *a = &ai->rc;
23687c478bd9Sstevel@tonic-gate rddir4_cache *b = &bi->rc;
23697c478bd9Sstevel@tonic-gate
23707c478bd9Sstevel@tonic-gate if (a->nfs4_cookie == b->nfs4_cookie) {
23717c478bd9Sstevel@tonic-gate if (a->buflen == b->buflen)
23727c478bd9Sstevel@tonic-gate return (0);
23737c478bd9Sstevel@tonic-gate if (a->buflen < b->buflen)
23747c478bd9Sstevel@tonic-gate return (-1);
23757c478bd9Sstevel@tonic-gate return (1);
23767c478bd9Sstevel@tonic-gate }
23777c478bd9Sstevel@tonic-gate
23787c478bd9Sstevel@tonic-gate if (a->nfs4_cookie < b->nfs4_cookie)
23797c478bd9Sstevel@tonic-gate return (-1);
23807c478bd9Sstevel@tonic-gate
23817c478bd9Sstevel@tonic-gate return (1);
23827c478bd9Sstevel@tonic-gate }
23837c478bd9Sstevel@tonic-gate
23847c478bd9Sstevel@tonic-gate /*
23857c478bd9Sstevel@tonic-gate * Allocate an opaque handle for the readdir cache.
23867c478bd9Sstevel@tonic-gate */
23877c478bd9Sstevel@tonic-gate void
rddir4_cache_create(rnode4_t * rp)23887c478bd9Sstevel@tonic-gate rddir4_cache_create(rnode4_t *rp)
23897c478bd9Sstevel@tonic-gate {
23907c478bd9Sstevel@tonic-gate ASSERT(rp->r_dir == NULL);
23917c478bd9Sstevel@tonic-gate
23927c478bd9Sstevel@tonic-gate rp->r_dir = kmem_alloc(sizeof (avl_tree_t), KM_SLEEP);
23937c478bd9Sstevel@tonic-gate
23947c478bd9Sstevel@tonic-gate avl_create(rp->r_dir, rddir4_cache_compar, sizeof (rddir4_cache_impl),
23957c478bd9Sstevel@tonic-gate offsetof(rddir4_cache_impl, tree));
23967c478bd9Sstevel@tonic-gate }
23977c478bd9Sstevel@tonic-gate
23987c478bd9Sstevel@tonic-gate /*
23997c478bd9Sstevel@tonic-gate * Purge the cache of all cached readdir responses.
24007c478bd9Sstevel@tonic-gate */
24017c478bd9Sstevel@tonic-gate void
rddir4_cache_purge(rnode4_t * rp)24027c478bd9Sstevel@tonic-gate rddir4_cache_purge(rnode4_t *rp)
24037c478bd9Sstevel@tonic-gate {
24047c478bd9Sstevel@tonic-gate rddir4_cache_impl *rdip;
24057c478bd9Sstevel@tonic-gate rddir4_cache_impl *nrdip;
24067c478bd9Sstevel@tonic-gate
24077c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&rp->r_statelock));
24087c478bd9Sstevel@tonic-gate
24097c478bd9Sstevel@tonic-gate if (rp->r_dir == NULL)
24107c478bd9Sstevel@tonic-gate return;
24117c478bd9Sstevel@tonic-gate
24127c478bd9Sstevel@tonic-gate rdip = avl_first(rp->r_dir);
24137c478bd9Sstevel@tonic-gate
24147c478bd9Sstevel@tonic-gate while (rdip != NULL) {
24157c478bd9Sstevel@tonic-gate nrdip = AVL_NEXT(rp->r_dir, rdip);
24167c478bd9Sstevel@tonic-gate avl_remove(rp->r_dir, rdip);
24177c478bd9Sstevel@tonic-gate rdip->rc.flags &= ~RDDIRCACHED;
24187c478bd9Sstevel@tonic-gate rddir4_cache_rele(rp, &rdip->rc);
24197c478bd9Sstevel@tonic-gate rdip = nrdip;
24207c478bd9Sstevel@tonic-gate }
24217c478bd9Sstevel@tonic-gate ASSERT(avl_numnodes(rp->r_dir) == 0);
24227c478bd9Sstevel@tonic-gate }
24237c478bd9Sstevel@tonic-gate
24247c478bd9Sstevel@tonic-gate /*
24257c478bd9Sstevel@tonic-gate * Destroy the readdir cache.
24267c478bd9Sstevel@tonic-gate */
24277c478bd9Sstevel@tonic-gate void
rddir4_cache_destroy(rnode4_t * rp)24287c478bd9Sstevel@tonic-gate rddir4_cache_destroy(rnode4_t *rp)
24297c478bd9Sstevel@tonic-gate {
24307c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&rp->r_statelock));
24317c478bd9Sstevel@tonic-gate if (rp->r_dir == NULL)
24327c478bd9Sstevel@tonic-gate return;
24337c478bd9Sstevel@tonic-gate
24347c478bd9Sstevel@tonic-gate rddir4_cache_purge(rp);
24357c478bd9Sstevel@tonic-gate avl_destroy(rp->r_dir);
24367c478bd9Sstevel@tonic-gate kmem_free(rp->r_dir, sizeof (avl_tree_t));
24377c478bd9Sstevel@tonic-gate rp->r_dir = NULL;
24387c478bd9Sstevel@tonic-gate }
24397c478bd9Sstevel@tonic-gate
24407c478bd9Sstevel@tonic-gate /*
24417c478bd9Sstevel@tonic-gate * Locate a readdir response from the readdir cache.
24427c478bd9Sstevel@tonic-gate *
24437c478bd9Sstevel@tonic-gate * Return values:
24447c478bd9Sstevel@tonic-gate *
24457c478bd9Sstevel@tonic-gate * NULL - If there is an unrecoverable situation like the operation may have
24467c478bd9Sstevel@tonic-gate * been interrupted.
24477c478bd9Sstevel@tonic-gate *
24487c478bd9Sstevel@tonic-gate * rddir4_cache * - A pointer to a rddir4_cache is returned to the caller.
24497c478bd9Sstevel@tonic-gate * The flags are set approprately, such that the caller knows
24507c478bd9Sstevel@tonic-gate * what state the entry is in.
24517c478bd9Sstevel@tonic-gate */
24527c478bd9Sstevel@tonic-gate rddir4_cache *
rddir4_cache_lookup(rnode4_t * rp,offset_t cookie,int count)24537c478bd9Sstevel@tonic-gate rddir4_cache_lookup(rnode4_t *rp, offset_t cookie, int count)
24547c478bd9Sstevel@tonic-gate {
24557c478bd9Sstevel@tonic-gate rddir4_cache_impl *rdip = NULL;
24567c478bd9Sstevel@tonic-gate rddir4_cache_impl srdip;
24577c478bd9Sstevel@tonic-gate rddir4_cache *srdc;
24587c478bd9Sstevel@tonic-gate rddir4_cache *rdc = NULL;
24597c478bd9Sstevel@tonic-gate rddir4_cache *nrdc = NULL;
24607c478bd9Sstevel@tonic-gate avl_index_t where;
24617c478bd9Sstevel@tonic-gate
24627c478bd9Sstevel@tonic-gate top:
24637c478bd9Sstevel@tonic-gate ASSERT(nfs_rw_lock_held(&rp->r_rwlock, RW_READER));
24647c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&rp->r_statelock));
24657c478bd9Sstevel@tonic-gate /*
24667c478bd9Sstevel@tonic-gate * Check to see if the readdir cache has been disabled. If so, then
24677c478bd9Sstevel@tonic-gate * simply allocate an rddir4_cache entry and return it, since caching
24687c478bd9Sstevel@tonic-gate * operations do not apply.
24697c478bd9Sstevel@tonic-gate */
24707c478bd9Sstevel@tonic-gate if (rp->r_dir == NULL) {
24717c478bd9Sstevel@tonic-gate if (nrdc == NULL) {
24727c478bd9Sstevel@tonic-gate /*
24737c478bd9Sstevel@tonic-gate * Drop the lock because we are doing a sleeping
24747c478bd9Sstevel@tonic-gate * allocation.
24757c478bd9Sstevel@tonic-gate */
24767c478bd9Sstevel@tonic-gate mutex_exit(&rp->r_statelock);
24777c478bd9Sstevel@tonic-gate rdc = rddir4_cache_alloc(KM_SLEEP);
24787c478bd9Sstevel@tonic-gate rdc->nfs4_cookie = cookie;
24797c478bd9Sstevel@tonic-gate rdc->buflen = count;
24807c478bd9Sstevel@tonic-gate mutex_enter(&rp->r_statelock);
24817c478bd9Sstevel@tonic-gate return (rdc);
24827c478bd9Sstevel@tonic-gate }
24837c478bd9Sstevel@tonic-gate return (nrdc);
24847c478bd9Sstevel@tonic-gate }
24857c478bd9Sstevel@tonic-gate
24867c478bd9Sstevel@tonic-gate srdc = &srdip.rc;
24877c478bd9Sstevel@tonic-gate srdc->nfs4_cookie = cookie;
24887c478bd9Sstevel@tonic-gate srdc->buflen = count;
24897c478bd9Sstevel@tonic-gate
24907c478bd9Sstevel@tonic-gate rdip = avl_find(rp->r_dir, &srdip, &where);
24917c478bd9Sstevel@tonic-gate
24927c478bd9Sstevel@tonic-gate /*
24937c478bd9Sstevel@tonic-gate * If we didn't find an entry then create one and insert it
24947c478bd9Sstevel@tonic-gate * into the cache.
24957c478bd9Sstevel@tonic-gate */
24967c478bd9Sstevel@tonic-gate if (rdip == NULL) {
24977c478bd9Sstevel@tonic-gate /*
24987c478bd9Sstevel@tonic-gate * Check for the case where we have made a second pass through
24997c478bd9Sstevel@tonic-gate * the cache due to a lockless allocation. If we find that no
25007c478bd9Sstevel@tonic-gate * thread has already inserted this entry, do the insert now
25017c478bd9Sstevel@tonic-gate * and return.
25027c478bd9Sstevel@tonic-gate */
25037c478bd9Sstevel@tonic-gate if (nrdc != NULL) {
25047c478bd9Sstevel@tonic-gate avl_insert(rp->r_dir, nrdc->data, where);
25057c478bd9Sstevel@tonic-gate nrdc->flags |= RDDIRCACHED;
25067c478bd9Sstevel@tonic-gate rddir4_cache_hold(nrdc);
25077c478bd9Sstevel@tonic-gate return (nrdc);
25087c478bd9Sstevel@tonic-gate }
25097c478bd9Sstevel@tonic-gate
25107c478bd9Sstevel@tonic-gate #ifdef DEBUG
25117c478bd9Sstevel@tonic-gate nfs4_readdir_cache_misses++;
25127c478bd9Sstevel@tonic-gate #endif
25137c478bd9Sstevel@tonic-gate /*
25147c478bd9Sstevel@tonic-gate * First, try to allocate an entry without sleeping. If that
25157c478bd9Sstevel@tonic-gate * fails then drop the lock and do a sleeping allocation.
25167c478bd9Sstevel@tonic-gate */
25177c478bd9Sstevel@tonic-gate nrdc = rddir4_cache_alloc(KM_NOSLEEP);
25187c478bd9Sstevel@tonic-gate if (nrdc != NULL) {
25197c478bd9Sstevel@tonic-gate nrdc->nfs4_cookie = cookie;
25207c478bd9Sstevel@tonic-gate nrdc->buflen = count;
25217c478bd9Sstevel@tonic-gate avl_insert(rp->r_dir, nrdc->data, where);
25227c478bd9Sstevel@tonic-gate nrdc->flags |= RDDIRCACHED;
25237c478bd9Sstevel@tonic-gate rddir4_cache_hold(nrdc);
25247c478bd9Sstevel@tonic-gate return (nrdc);
25257c478bd9Sstevel@tonic-gate }
25267c478bd9Sstevel@tonic-gate
25277c478bd9Sstevel@tonic-gate /*
25287c478bd9Sstevel@tonic-gate * Drop the lock and do a sleeping allocation. We incur
25297c478bd9Sstevel@tonic-gate * additional overhead by having to search the cache again,
25307c478bd9Sstevel@tonic-gate * but this case should be rare.
25317c478bd9Sstevel@tonic-gate */
25327c478bd9Sstevel@tonic-gate mutex_exit(&rp->r_statelock);
25337c478bd9Sstevel@tonic-gate nrdc = rddir4_cache_alloc(KM_SLEEP);
25347c478bd9Sstevel@tonic-gate nrdc->nfs4_cookie = cookie;
25357c478bd9Sstevel@tonic-gate nrdc->buflen = count;
25367c478bd9Sstevel@tonic-gate mutex_enter(&rp->r_statelock);
25377c478bd9Sstevel@tonic-gate /*
25387c478bd9Sstevel@tonic-gate * We need to take another pass through the cache
25397c478bd9Sstevel@tonic-gate * since we dropped our lock to perform the alloc.
25407c478bd9Sstevel@tonic-gate * Another thread may have come by and inserted the
25417c478bd9Sstevel@tonic-gate * entry we are interested in.
25427c478bd9Sstevel@tonic-gate */
25437c478bd9Sstevel@tonic-gate goto top;
25447c478bd9Sstevel@tonic-gate }
25457c478bd9Sstevel@tonic-gate
25467c478bd9Sstevel@tonic-gate /*
25477c478bd9Sstevel@tonic-gate * Check to see if we need to free our entry. This can happen if
25487c478bd9Sstevel@tonic-gate * another thread came along beat us to the insert. We can
25497c478bd9Sstevel@tonic-gate * safely call rddir4_cache_free directly because no other thread
25507c478bd9Sstevel@tonic-gate * would have a reference to this entry.
25517c478bd9Sstevel@tonic-gate */
25527c478bd9Sstevel@tonic-gate if (nrdc != NULL)
25537c478bd9Sstevel@tonic-gate rddir4_cache_free((rddir4_cache_impl *)nrdc->data);
25547c478bd9Sstevel@tonic-gate
25557c478bd9Sstevel@tonic-gate #ifdef DEBUG
25567c478bd9Sstevel@tonic-gate nfs4_readdir_cache_hits++;
25577c478bd9Sstevel@tonic-gate #endif
25587c478bd9Sstevel@tonic-gate /*
25597c478bd9Sstevel@tonic-gate * Found something. Make sure it's ready to return.
25607c478bd9Sstevel@tonic-gate */
25617c478bd9Sstevel@tonic-gate rdc = &rdip->rc;
25627c478bd9Sstevel@tonic-gate rddir4_cache_hold(rdc);
25637c478bd9Sstevel@tonic-gate /*
25647c478bd9Sstevel@tonic-gate * If the cache entry is in the process of being filled in, wait
25657c478bd9Sstevel@tonic-gate * until this completes. The RDDIRWAIT bit is set to indicate that
25667c478bd9Sstevel@tonic-gate * someone is waiting and when the thread currently filling the entry
25677c478bd9Sstevel@tonic-gate * is done, it should do a cv_broadcast to wakeup all of the threads
25687c478bd9Sstevel@tonic-gate * waiting for it to finish. If the thread wakes up to find that
25697c478bd9Sstevel@tonic-gate * someone new is now trying to complete the the entry, go back
25707c478bd9Sstevel@tonic-gate * to sleep.
25717c478bd9Sstevel@tonic-gate */
25727c478bd9Sstevel@tonic-gate while (rdc->flags & RDDIR) {
25737c478bd9Sstevel@tonic-gate /*
25747c478bd9Sstevel@tonic-gate * The entry is not complete.
25757c478bd9Sstevel@tonic-gate */
25767c478bd9Sstevel@tonic-gate nfs_rw_exit(&rp->r_rwlock);
25777c478bd9Sstevel@tonic-gate rdc->flags |= RDDIRWAIT;
25787c478bd9Sstevel@tonic-gate #ifdef DEBUG
25797c478bd9Sstevel@tonic-gate nfs4_readdir_cache_waits++;
25807c478bd9Sstevel@tonic-gate #endif
25817c478bd9Sstevel@tonic-gate while (rdc->flags & RDDIRWAIT) {
25827c478bd9Sstevel@tonic-gate if (!cv_wait_sig(&rdc->cv, &rp->r_statelock)) {
25837c478bd9Sstevel@tonic-gate /*
25847c478bd9Sstevel@tonic-gate * We got interrupted, probably the user
25857c478bd9Sstevel@tonic-gate * typed ^C or an alarm fired. We free the
25867c478bd9Sstevel@tonic-gate * new entry if we allocated one.
25877c478bd9Sstevel@tonic-gate */
25887c478bd9Sstevel@tonic-gate rddir4_cache_rele(rp, rdc);
25897c478bd9Sstevel@tonic-gate mutex_exit(&rp->r_statelock);
25907c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&rp->r_rwlock,
25917c478bd9Sstevel@tonic-gate RW_READER, FALSE);
25927c478bd9Sstevel@tonic-gate mutex_enter(&rp->r_statelock);
25937c478bd9Sstevel@tonic-gate return (NULL);
25947c478bd9Sstevel@tonic-gate }
25957c478bd9Sstevel@tonic-gate }
25967c478bd9Sstevel@tonic-gate mutex_exit(&rp->r_statelock);
25977c478bd9Sstevel@tonic-gate (void) nfs_rw_enter_sig(&rp->r_rwlock,
25987c478bd9Sstevel@tonic-gate RW_READER, FALSE);
25997c478bd9Sstevel@tonic-gate mutex_enter(&rp->r_statelock);
26007c478bd9Sstevel@tonic-gate }
26017c478bd9Sstevel@tonic-gate
26027c478bd9Sstevel@tonic-gate /*
26037c478bd9Sstevel@tonic-gate * The entry we were waiting on may have been purged from
26047c478bd9Sstevel@tonic-gate * the cache and should no longer be used, release it and
26057c478bd9Sstevel@tonic-gate * start over.
26067c478bd9Sstevel@tonic-gate */
26077c478bd9Sstevel@tonic-gate if (!(rdc->flags & RDDIRCACHED)) {
26087c478bd9Sstevel@tonic-gate rddir4_cache_rele(rp, rdc);
26097c478bd9Sstevel@tonic-gate goto top;
26107c478bd9Sstevel@tonic-gate }
26117c478bd9Sstevel@tonic-gate
26127c478bd9Sstevel@tonic-gate /*
26137c478bd9Sstevel@tonic-gate * The entry is completed. Return it.
26147c478bd9Sstevel@tonic-gate */
26157c478bd9Sstevel@tonic-gate return (rdc);
26167c478bd9Sstevel@tonic-gate }
26177c478bd9Sstevel@tonic-gate
26187c478bd9Sstevel@tonic-gate /*
26197c478bd9Sstevel@tonic-gate * Allocate a cache element and return it. Can return NULL if memory is
26207c478bd9Sstevel@tonic-gate * low.
26217c478bd9Sstevel@tonic-gate */
26227c478bd9Sstevel@tonic-gate static rddir4_cache *
rddir4_cache_alloc(int flags)26237c478bd9Sstevel@tonic-gate rddir4_cache_alloc(int flags)
26247c478bd9Sstevel@tonic-gate {
26257c478bd9Sstevel@tonic-gate rddir4_cache_impl *rdip = NULL;
26267c478bd9Sstevel@tonic-gate rddir4_cache *rc = NULL;
26277c478bd9Sstevel@tonic-gate
26287c478bd9Sstevel@tonic-gate rdip = kmem_alloc(sizeof (rddir4_cache_impl), flags);
26297c478bd9Sstevel@tonic-gate
26307c478bd9Sstevel@tonic-gate if (rdip != NULL) {
26317c478bd9Sstevel@tonic-gate rc = &rdip->rc;
26327c478bd9Sstevel@tonic-gate rc->data = (void *)rdip;
26337c478bd9Sstevel@tonic-gate rc->nfs4_cookie = 0;
26347c478bd9Sstevel@tonic-gate rc->nfs4_ncookie = 0;
26357c478bd9Sstevel@tonic-gate rc->entries = NULL;
26367c478bd9Sstevel@tonic-gate rc->eof = 0;
26377c478bd9Sstevel@tonic-gate rc->entlen = 0;
26387c478bd9Sstevel@tonic-gate rc->buflen = 0;
26397c478bd9Sstevel@tonic-gate rc->actlen = 0;
26407c478bd9Sstevel@tonic-gate /*
26417c478bd9Sstevel@tonic-gate * A readdir is required so set the flag.
26427c478bd9Sstevel@tonic-gate */
26437c478bd9Sstevel@tonic-gate rc->flags = RDDIRREQ;
26447c478bd9Sstevel@tonic-gate cv_init(&rc->cv, NULL, CV_DEFAULT, NULL);
26457c478bd9Sstevel@tonic-gate rc->error = 0;
26467c478bd9Sstevel@tonic-gate mutex_init(&rdip->lock, NULL, MUTEX_DEFAULT, NULL);
26477c478bd9Sstevel@tonic-gate rdip->count = 1;
26487c478bd9Sstevel@tonic-gate #ifdef DEBUG
26491a5e258fSJosef 'Jeff' Sipek atomic_inc_64(&clstat4_debug.dirent.value.ui64);
26507c478bd9Sstevel@tonic-gate #endif
26517c478bd9Sstevel@tonic-gate }
26527c478bd9Sstevel@tonic-gate return (rc);
26537c478bd9Sstevel@tonic-gate }
26547c478bd9Sstevel@tonic-gate
26557c478bd9Sstevel@tonic-gate /*
26567c478bd9Sstevel@tonic-gate * Increment the reference count to this cache element.
26577c478bd9Sstevel@tonic-gate */
26587c478bd9Sstevel@tonic-gate static void
rddir4_cache_hold(rddir4_cache * rc)26597c478bd9Sstevel@tonic-gate rddir4_cache_hold(rddir4_cache *rc)
26607c478bd9Sstevel@tonic-gate {
26617c478bd9Sstevel@tonic-gate rddir4_cache_impl *rdip = (rddir4_cache_impl *)rc->data;
26627c478bd9Sstevel@tonic-gate
26637c478bd9Sstevel@tonic-gate mutex_enter(&rdip->lock);
26647c478bd9Sstevel@tonic-gate rdip->count++;
26657c478bd9Sstevel@tonic-gate mutex_exit(&rdip->lock);
26667c478bd9Sstevel@tonic-gate }
26677c478bd9Sstevel@tonic-gate
26687c478bd9Sstevel@tonic-gate /*
26697c478bd9Sstevel@tonic-gate * Release a reference to this cache element. If the count is zero then
26707c478bd9Sstevel@tonic-gate * free the element.
26717c478bd9Sstevel@tonic-gate */
26727c478bd9Sstevel@tonic-gate void
rddir4_cache_rele(rnode4_t * rp,rddir4_cache * rdc)26737c478bd9Sstevel@tonic-gate rddir4_cache_rele(rnode4_t *rp, rddir4_cache *rdc)
26747c478bd9Sstevel@tonic-gate {
26757c478bd9Sstevel@tonic-gate rddir4_cache_impl *rdip = (rddir4_cache_impl *)rdc->data;
26767c478bd9Sstevel@tonic-gate
26777c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&rp->r_statelock));
26787c478bd9Sstevel@tonic-gate
26797c478bd9Sstevel@tonic-gate /*
26807c478bd9Sstevel@tonic-gate * Check to see if we have any waiters. If so, we can wake them
26817c478bd9Sstevel@tonic-gate * so that they can proceed.
26827c478bd9Sstevel@tonic-gate */
26837c478bd9Sstevel@tonic-gate if (rdc->flags & RDDIRWAIT) {
26847c478bd9Sstevel@tonic-gate rdc->flags &= ~RDDIRWAIT;
26857c478bd9Sstevel@tonic-gate cv_broadcast(&rdc->cv);
26867c478bd9Sstevel@tonic-gate }
26877c478bd9Sstevel@tonic-gate
26887c478bd9Sstevel@tonic-gate mutex_enter(&rdip->lock);
26897c478bd9Sstevel@tonic-gate ASSERT(rdip->count > 0);
26907c478bd9Sstevel@tonic-gate if (--rdip->count == 0) {
26917c478bd9Sstevel@tonic-gate mutex_exit(&rdip->lock);
26927c478bd9Sstevel@tonic-gate rddir4_cache_free(rdip);
26937c478bd9Sstevel@tonic-gate } else
26947c478bd9Sstevel@tonic-gate mutex_exit(&rdip->lock);
26957c478bd9Sstevel@tonic-gate }
26967c478bd9Sstevel@tonic-gate
26977c478bd9Sstevel@tonic-gate /*
26987c478bd9Sstevel@tonic-gate * Free a cache element.
26997c478bd9Sstevel@tonic-gate */
27007c478bd9Sstevel@tonic-gate static void
rddir4_cache_free(rddir4_cache_impl * rdip)27017c478bd9Sstevel@tonic-gate rddir4_cache_free(rddir4_cache_impl *rdip)
27027c478bd9Sstevel@tonic-gate {
27037c478bd9Sstevel@tonic-gate rddir4_cache *rc = &rdip->rc;
27047c478bd9Sstevel@tonic-gate
27057c478bd9Sstevel@tonic-gate #ifdef DEBUG
27061a5e258fSJosef 'Jeff' Sipek atomic_dec_64(&clstat4_debug.dirent.value.ui64);
27077c478bd9Sstevel@tonic-gate #endif
27087c478bd9Sstevel@tonic-gate if (rc->entries != NULL)
27097c478bd9Sstevel@tonic-gate kmem_free(rc->entries, rc->buflen);
27107c478bd9Sstevel@tonic-gate cv_destroy(&rc->cv);
27117c478bd9Sstevel@tonic-gate mutex_destroy(&rdip->lock);
27127c478bd9Sstevel@tonic-gate kmem_free(rdip, sizeof (*rdip));
27137c478bd9Sstevel@tonic-gate }
27147c478bd9Sstevel@tonic-gate
27157c478bd9Sstevel@tonic-gate /*
27167c478bd9Sstevel@tonic-gate * Snapshot callback for nfs:0:nfs4_client as registered with the kstat
27177c478bd9Sstevel@tonic-gate * framework.
27187c478bd9Sstevel@tonic-gate */
27197c478bd9Sstevel@tonic-gate static int
cl4_snapshot(kstat_t * ksp,void * buf,int rw)27207c478bd9Sstevel@tonic-gate cl4_snapshot(kstat_t *ksp, void *buf, int rw)
27217c478bd9Sstevel@tonic-gate {
27227c478bd9Sstevel@tonic-gate ksp->ks_snaptime = gethrtime();
27237c478bd9Sstevel@tonic-gate if (rw == KSTAT_WRITE) {
27247c478bd9Sstevel@tonic-gate bcopy(buf, ksp->ks_private, sizeof (clstat4_tmpl));
27257c478bd9Sstevel@tonic-gate #ifdef DEBUG
27267c478bd9Sstevel@tonic-gate /*
27277c478bd9Sstevel@tonic-gate * Currently only the global zone can write to kstats, but we
27287c478bd9Sstevel@tonic-gate * add the check just for paranoia.
27297c478bd9Sstevel@tonic-gate */
27307c478bd9Sstevel@tonic-gate if (INGLOBALZONE(curproc))
2731b9238976Sth199096 bcopy((char *)buf + sizeof (clstat4_tmpl),
2732b9238976Sth199096 &clstat4_debug, sizeof (clstat4_debug));
27337c478bd9Sstevel@tonic-gate #endif
27347c478bd9Sstevel@tonic-gate } else {
27357c478bd9Sstevel@tonic-gate bcopy(ksp->ks_private, buf, sizeof (clstat4_tmpl));
27367c478bd9Sstevel@tonic-gate #ifdef DEBUG
27377c478bd9Sstevel@tonic-gate /*
27387c478bd9Sstevel@tonic-gate * If we're displaying the "global" debug kstat values, we
27397c478bd9Sstevel@tonic-gate * display them as-is to all zones since in fact they apply to
27407c478bd9Sstevel@tonic-gate * the system as a whole.
27417c478bd9Sstevel@tonic-gate */
27427c478bd9Sstevel@tonic-gate bcopy(&clstat4_debug, (char *)buf + sizeof (clstat4_tmpl),
27437c478bd9Sstevel@tonic-gate sizeof (clstat4_debug));
27447c478bd9Sstevel@tonic-gate #endif
27457c478bd9Sstevel@tonic-gate }
27467c478bd9Sstevel@tonic-gate return (0);
27477c478bd9Sstevel@tonic-gate }
27487c478bd9Sstevel@tonic-gate
27497c478bd9Sstevel@tonic-gate
27507c478bd9Sstevel@tonic-gate
27517c478bd9Sstevel@tonic-gate /*
27527c478bd9Sstevel@tonic-gate * Zone support
27537c478bd9Sstevel@tonic-gate */
27547c478bd9Sstevel@tonic-gate static void *
clinit4_zone(zoneid_t zoneid)27557c478bd9Sstevel@tonic-gate clinit4_zone(zoneid_t zoneid)
27567c478bd9Sstevel@tonic-gate {
27577c478bd9Sstevel@tonic-gate kstat_t *nfs4_client_kstat;
27587c478bd9Sstevel@tonic-gate struct nfs4_clnt *nfscl;
27597c478bd9Sstevel@tonic-gate uint_t ndata;
27607c478bd9Sstevel@tonic-gate
27617c478bd9Sstevel@tonic-gate nfscl = kmem_alloc(sizeof (*nfscl), KM_SLEEP);
27627c478bd9Sstevel@tonic-gate mutex_init(&nfscl->nfscl_chtable4_lock, NULL, MUTEX_DEFAULT, NULL);
27637c478bd9Sstevel@tonic-gate nfscl->nfscl_chtable4 = NULL;
27647c478bd9Sstevel@tonic-gate nfscl->nfscl_zoneid = zoneid;
27657c478bd9Sstevel@tonic-gate
27667c478bd9Sstevel@tonic-gate bcopy(&clstat4_tmpl, &nfscl->nfscl_stat, sizeof (clstat4_tmpl));
27677c478bd9Sstevel@tonic-gate ndata = sizeof (clstat4_tmpl) / sizeof (kstat_named_t);
27687c478bd9Sstevel@tonic-gate #ifdef DEBUG
27697c478bd9Sstevel@tonic-gate ndata += sizeof (clstat4_debug) / sizeof (kstat_named_t);
27707c478bd9Sstevel@tonic-gate #endif
27717c478bd9Sstevel@tonic-gate if ((nfs4_client_kstat = kstat_create_zone("nfs", 0, "nfs4_client",
27727c478bd9Sstevel@tonic-gate "misc", KSTAT_TYPE_NAMED, ndata,
27737c478bd9Sstevel@tonic-gate KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_WRITABLE, zoneid)) != NULL) {
27747c478bd9Sstevel@tonic-gate nfs4_client_kstat->ks_private = &nfscl->nfscl_stat;
27757c478bd9Sstevel@tonic-gate nfs4_client_kstat->ks_snapshot = cl4_snapshot;
27767c478bd9Sstevel@tonic-gate kstat_install(nfs4_client_kstat);
27777c478bd9Sstevel@tonic-gate }
27787c478bd9Sstevel@tonic-gate mutex_enter(&nfs4_clnt_list_lock);
27797c478bd9Sstevel@tonic-gate list_insert_head(&nfs4_clnt_list, nfscl);
27807c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_clnt_list_lock);
27812f172c55SRobert Thurlow
27827c478bd9Sstevel@tonic-gate return (nfscl);
27837c478bd9Sstevel@tonic-gate }
27847c478bd9Sstevel@tonic-gate
27857c478bd9Sstevel@tonic-gate /*ARGSUSED*/
27867c478bd9Sstevel@tonic-gate static void
clfini4_zone(zoneid_t zoneid,void * arg)27877c478bd9Sstevel@tonic-gate clfini4_zone(zoneid_t zoneid, void *arg)
27887c478bd9Sstevel@tonic-gate {
27897c478bd9Sstevel@tonic-gate struct nfs4_clnt *nfscl = arg;
27907c478bd9Sstevel@tonic-gate chhead_t *chp, *next;
27917c478bd9Sstevel@tonic-gate
27927c478bd9Sstevel@tonic-gate if (nfscl == NULL)
27937c478bd9Sstevel@tonic-gate return;
27947c478bd9Sstevel@tonic-gate mutex_enter(&nfs4_clnt_list_lock);
27957c478bd9Sstevel@tonic-gate list_remove(&nfs4_clnt_list, nfscl);
27967c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_clnt_list_lock);
27977c478bd9Sstevel@tonic-gate clreclaim4_zone(nfscl, 0);
27987c478bd9Sstevel@tonic-gate for (chp = nfscl->nfscl_chtable4; chp != NULL; chp = next) {
27997c478bd9Sstevel@tonic-gate ASSERT(chp->ch_list == NULL);
28007c478bd9Sstevel@tonic-gate kmem_free(chp->ch_protofmly, strlen(chp->ch_protofmly) + 1);
28017c478bd9Sstevel@tonic-gate next = chp->ch_next;
28027c478bd9Sstevel@tonic-gate kmem_free(chp, sizeof (*chp));
28037c478bd9Sstevel@tonic-gate }
28047c478bd9Sstevel@tonic-gate kstat_delete_byname_zone("nfs", 0, "nfs4_client", zoneid);
28057c478bd9Sstevel@tonic-gate mutex_destroy(&nfscl->nfscl_chtable4_lock);
28067c478bd9Sstevel@tonic-gate kmem_free(nfscl, sizeof (*nfscl));
28077c478bd9Sstevel@tonic-gate }
28087c478bd9Sstevel@tonic-gate
28097c478bd9Sstevel@tonic-gate /*
28107c478bd9Sstevel@tonic-gate * Called by endpnt_destructor to make sure the client handles are
28117c478bd9Sstevel@tonic-gate * cleaned up before the RPC endpoints. This becomes a no-op if
28127c478bd9Sstevel@tonic-gate * clfini_zone (above) is called first. This function is needed
28137c478bd9Sstevel@tonic-gate * (rather than relying on clfini_zone to clean up) because the ZSD
28147c478bd9Sstevel@tonic-gate * callbacks have no ordering mechanism, so we have no way to ensure
28157c478bd9Sstevel@tonic-gate * that clfini_zone is called before endpnt_destructor.
28167c478bd9Sstevel@tonic-gate */
28177c478bd9Sstevel@tonic-gate void
clcleanup4_zone(zoneid_t zoneid)28187c478bd9Sstevel@tonic-gate clcleanup4_zone(zoneid_t zoneid)
28197c478bd9Sstevel@tonic-gate {
28207c478bd9Sstevel@tonic-gate struct nfs4_clnt *nfscl;
28217c478bd9Sstevel@tonic-gate
28227c478bd9Sstevel@tonic-gate mutex_enter(&nfs4_clnt_list_lock);
28237c478bd9Sstevel@tonic-gate nfscl = list_head(&nfs4_clnt_list);
28247c478bd9Sstevel@tonic-gate for (; nfscl != NULL; nfscl = list_next(&nfs4_clnt_list, nfscl)) {
28257c478bd9Sstevel@tonic-gate if (nfscl->nfscl_zoneid == zoneid) {
28267c478bd9Sstevel@tonic-gate clreclaim4_zone(nfscl, 0);
28277c478bd9Sstevel@tonic-gate break;
28287c478bd9Sstevel@tonic-gate }
28297c478bd9Sstevel@tonic-gate }
28307c478bd9Sstevel@tonic-gate mutex_exit(&nfs4_clnt_list_lock);
28317c478bd9Sstevel@tonic-gate }
28327c478bd9Sstevel@tonic-gate
28337c478bd9Sstevel@tonic-gate int
nfs4_subr_init(void)28347c478bd9Sstevel@tonic-gate nfs4_subr_init(void)
28357c478bd9Sstevel@tonic-gate {
28367c478bd9Sstevel@tonic-gate /*
28377c478bd9Sstevel@tonic-gate * Allocate and initialize the client handle cache
28387c478bd9Sstevel@tonic-gate */
28397c478bd9Sstevel@tonic-gate chtab4_cache = kmem_cache_create("client_handle4_cache",
28407c478bd9Sstevel@tonic-gate sizeof (struct chtab), 0, NULL, NULL, clreclaim4, NULL,
28417c478bd9Sstevel@tonic-gate NULL, 0);
28427c478bd9Sstevel@tonic-gate
28437c478bd9Sstevel@tonic-gate /*
28447c478bd9Sstevel@tonic-gate * Initialize the list of per-zone client handles (and associated data).
28457c478bd9Sstevel@tonic-gate * This needs to be done before we call zone_key_create().
28467c478bd9Sstevel@tonic-gate */
28477c478bd9Sstevel@tonic-gate list_create(&nfs4_clnt_list, sizeof (struct nfs4_clnt),
28487c478bd9Sstevel@tonic-gate offsetof(struct nfs4_clnt, nfscl_node));
28497c478bd9Sstevel@tonic-gate
28507c478bd9Sstevel@tonic-gate /*
28517c478bd9Sstevel@tonic-gate * Initialize the zone_key for per-zone client handle lists.
28527c478bd9Sstevel@tonic-gate */
28537c478bd9Sstevel@tonic-gate zone_key_create(&nfs4clnt_zone_key, clinit4_zone, NULL, clfini4_zone);
28547c478bd9Sstevel@tonic-gate
28557c478bd9Sstevel@tonic-gate if (nfs4err_delay_time == 0)
28567c478bd9Sstevel@tonic-gate nfs4err_delay_time = NFS4ERR_DELAY_TIME;
28577c478bd9Sstevel@tonic-gate
28587c478bd9Sstevel@tonic-gate return (0);
28597c478bd9Sstevel@tonic-gate }
28607c478bd9Sstevel@tonic-gate
28617c478bd9Sstevel@tonic-gate int
nfs4_subr_fini(void)28627c478bd9Sstevel@tonic-gate nfs4_subr_fini(void)
28637c478bd9Sstevel@tonic-gate {
28647c478bd9Sstevel@tonic-gate /*
28657c478bd9Sstevel@tonic-gate * Deallocate the client handle cache
28667c478bd9Sstevel@tonic-gate */
28677c478bd9Sstevel@tonic-gate kmem_cache_destroy(chtab4_cache);
28687c478bd9Sstevel@tonic-gate
28697c478bd9Sstevel@tonic-gate /*
28707c478bd9Sstevel@tonic-gate * Destroy the zone_key
28717c478bd9Sstevel@tonic-gate */
28727c478bd9Sstevel@tonic-gate (void) zone_key_delete(nfs4clnt_zone_key);
28737c478bd9Sstevel@tonic-gate
28747c478bd9Sstevel@tonic-gate return (0);
28757c478bd9Sstevel@tonic-gate }
28767c478bd9Sstevel@tonic-gate /*
28777c478bd9Sstevel@tonic-gate * Set or Clear direct I/O flag
28787c478bd9Sstevel@tonic-gate * VOP_RWLOCK() is held for write access to prevent a race condition
28797c478bd9Sstevel@tonic-gate * which would occur if a process is in the middle of a write when
28807c478bd9Sstevel@tonic-gate * directio flag gets set. It is possible that all pages may not get flushed.
28817c478bd9Sstevel@tonic-gate *
28827c478bd9Sstevel@tonic-gate * This is a copy of nfs_directio, changes here may need to be made
28837c478bd9Sstevel@tonic-gate * there and vice versa.
28847c478bd9Sstevel@tonic-gate */
28857c478bd9Sstevel@tonic-gate
28867c478bd9Sstevel@tonic-gate int
nfs4_directio(vnode_t * vp,int cmd,cred_t * cr)28877c478bd9Sstevel@tonic-gate nfs4_directio(vnode_t *vp, int cmd, cred_t *cr)
28887c478bd9Sstevel@tonic-gate {
28897c478bd9Sstevel@tonic-gate int error = 0;
28907c478bd9Sstevel@tonic-gate rnode4_t *rp;
28917c478bd9Sstevel@tonic-gate
28927c478bd9Sstevel@tonic-gate rp = VTOR4(vp);
28937c478bd9Sstevel@tonic-gate
28947c478bd9Sstevel@tonic-gate if (cmd == DIRECTIO_ON) {
28957c478bd9Sstevel@tonic-gate
28967c478bd9Sstevel@tonic-gate if (rp->r_flags & R4DIRECTIO)
28977c478bd9Sstevel@tonic-gate return (0);
28987c478bd9Sstevel@tonic-gate
28997c478bd9Sstevel@tonic-gate /*
29007c478bd9Sstevel@tonic-gate * Flush the page cache.
29017c478bd9Sstevel@tonic-gate */
29027c478bd9Sstevel@tonic-gate
29037c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
29047c478bd9Sstevel@tonic-gate
29057c478bd9Sstevel@tonic-gate if (rp->r_flags & R4DIRECTIO) {
29067c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
29077c478bd9Sstevel@tonic-gate return (0);
29087c478bd9Sstevel@tonic-gate }
29097c478bd9Sstevel@tonic-gate
29107c478bd9Sstevel@tonic-gate if (nfs4_has_pages(vp) &&
29117c478bd9Sstevel@tonic-gate ((rp->r_flags & R4DIRTY) || rp->r_awcount > 0)) {
29127c478bd9Sstevel@tonic-gate error = VOP_PUTPAGE(vp, (offset_t)0, (uint_t)0,
2913da6c28aaSamw B_INVAL, cr, NULL);
29147c478bd9Sstevel@tonic-gate if (error) {
29157c478bd9Sstevel@tonic-gate if (error == ENOSPC || error == EDQUOT) {
29167c478bd9Sstevel@tonic-gate mutex_enter(&rp->r_statelock);
29177c478bd9Sstevel@tonic-gate if (!rp->r_error)
29187c478bd9Sstevel@tonic-gate rp->r_error = error;
29197c478bd9Sstevel@tonic-gate mutex_exit(&rp->r_statelock);
29207c478bd9Sstevel@tonic-gate }
29217c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
29227c478bd9Sstevel@tonic-gate return (error);
29237c478bd9Sstevel@tonic-gate }
29247c478bd9Sstevel@tonic-gate }
29257c478bd9Sstevel@tonic-gate
29267c478bd9Sstevel@tonic-gate mutex_enter(&rp->r_statelock);
29277c478bd9Sstevel@tonic-gate rp->r_flags |= R4DIRECTIO;
29287c478bd9Sstevel@tonic-gate mutex_exit(&rp->r_statelock);
29297c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
29307c478bd9Sstevel@tonic-gate return (0);
29317c478bd9Sstevel@tonic-gate }
29327c478bd9Sstevel@tonic-gate
29337c478bd9Sstevel@tonic-gate if (cmd == DIRECTIO_OFF) {
29347c478bd9Sstevel@tonic-gate mutex_enter(&rp->r_statelock);
29357c478bd9Sstevel@tonic-gate rp->r_flags &= ~R4DIRECTIO; /* disable direct mode */
29367c478bd9Sstevel@tonic-gate mutex_exit(&rp->r_statelock);
29377c478bd9Sstevel@tonic-gate return (0);
29387c478bd9Sstevel@tonic-gate }
29397c478bd9Sstevel@tonic-gate
29407c478bd9Sstevel@tonic-gate return (EINVAL);
29417c478bd9Sstevel@tonic-gate }
29427c478bd9Sstevel@tonic-gate
29437c478bd9Sstevel@tonic-gate /*
29447c478bd9Sstevel@tonic-gate * Return TRUE if the file has any pages. Always go back to
29457c478bd9Sstevel@tonic-gate * the master vnode to check v_pages since none of the shadows
29467c478bd9Sstevel@tonic-gate * can have pages.
29477c478bd9Sstevel@tonic-gate */
29487c478bd9Sstevel@tonic-gate
29497c478bd9Sstevel@tonic-gate bool_t
nfs4_has_pages(vnode_t * vp)29507c478bd9Sstevel@tonic-gate nfs4_has_pages(vnode_t *vp)
29517c478bd9Sstevel@tonic-gate {
29527c478bd9Sstevel@tonic-gate rnode4_t *rp;
29537c478bd9Sstevel@tonic-gate
29547c478bd9Sstevel@tonic-gate rp = VTOR4(vp);
29557c478bd9Sstevel@tonic-gate if (IS_SHADOW(vp, rp))
29567c478bd9Sstevel@tonic-gate vp = RTOV4(rp); /* RTOV4 always gives the master */
29577c478bd9Sstevel@tonic-gate
29587c478bd9Sstevel@tonic-gate return (vn_has_cached_data(vp));
29597c478bd9Sstevel@tonic-gate }
29607c478bd9Sstevel@tonic-gate
29617c478bd9Sstevel@tonic-gate /*
29627c478bd9Sstevel@tonic-gate * This table is used to determine whether the client should attempt
29637c478bd9Sstevel@tonic-gate * failover based on the clnt_stat value returned by CLNT_CALL. The
29647c478bd9Sstevel@tonic-gate * clnt_stat is used as an index into the table. If
29657c478bd9Sstevel@tonic-gate * the error value that corresponds to the clnt_stat value in the
29667c478bd9Sstevel@tonic-gate * table is non-zero, then that is the error to be returned AND
29677c478bd9Sstevel@tonic-gate * that signals that failover should be attempted.
29687c478bd9Sstevel@tonic-gate *
29697c478bd9Sstevel@tonic-gate * Special note: If the RPC_ values change, then direct indexing of the
29707c478bd9Sstevel@tonic-gate * table is no longer valid, but having the RPC_ values in the table
29717c478bd9Sstevel@tonic-gate * allow the functions to detect the change and issue a warning.
29727c478bd9Sstevel@tonic-gate * In this case, the code will always attempt failover as a defensive
29737c478bd9Sstevel@tonic-gate * measure.
29747c478bd9Sstevel@tonic-gate */
29757c478bd9Sstevel@tonic-gate
29767c478bd9Sstevel@tonic-gate static struct try_failover_tab {
29777c478bd9Sstevel@tonic-gate enum clnt_stat cstat;
29787c478bd9Sstevel@tonic-gate int error;
29797c478bd9Sstevel@tonic-gate } try_failover_table [] = {
29807c478bd9Sstevel@tonic-gate
29817c478bd9Sstevel@tonic-gate RPC_SUCCESS, 0,
29827c478bd9Sstevel@tonic-gate RPC_CANTENCODEARGS, 0,
29837c478bd9Sstevel@tonic-gate RPC_CANTDECODERES, 0,
29847c478bd9Sstevel@tonic-gate RPC_CANTSEND, ECOMM,
29857c478bd9Sstevel@tonic-gate RPC_CANTRECV, ECOMM,
29867c478bd9Sstevel@tonic-gate RPC_TIMEDOUT, ETIMEDOUT,
29877c478bd9Sstevel@tonic-gate RPC_VERSMISMATCH, 0,
29887c478bd9Sstevel@tonic-gate RPC_AUTHERROR, 0,
29897c478bd9Sstevel@tonic-gate RPC_PROGUNAVAIL, 0,
29907c478bd9Sstevel@tonic-gate RPC_PROGVERSMISMATCH, 0,
29917c478bd9Sstevel@tonic-gate RPC_PROCUNAVAIL, 0,
29927c478bd9Sstevel@tonic-gate RPC_CANTDECODEARGS, 0,
29937c478bd9Sstevel@tonic-gate RPC_SYSTEMERROR, ENOSR,
29947c478bd9Sstevel@tonic-gate RPC_UNKNOWNHOST, EHOSTUNREACH,
29957c478bd9Sstevel@tonic-gate RPC_RPCBFAILURE, ENETUNREACH,
29967c478bd9Sstevel@tonic-gate RPC_PROGNOTREGISTERED, ECONNREFUSED,
29977c478bd9Sstevel@tonic-gate RPC_FAILED, ETIMEDOUT,
29987c478bd9Sstevel@tonic-gate RPC_UNKNOWNPROTO, EHOSTUNREACH,
29997c478bd9Sstevel@tonic-gate RPC_INTR, 0,
30007c478bd9Sstevel@tonic-gate RPC_UNKNOWNADDR, EHOSTUNREACH,
30017c478bd9Sstevel@tonic-gate RPC_TLIERROR, 0,
30027c478bd9Sstevel@tonic-gate RPC_NOBROADCAST, EHOSTUNREACH,
30037c478bd9Sstevel@tonic-gate RPC_N2AXLATEFAILURE, ECONNREFUSED,
30047c478bd9Sstevel@tonic-gate RPC_UDERROR, 0,
30057c478bd9Sstevel@tonic-gate RPC_INPROGRESS, 0,
30067c478bd9Sstevel@tonic-gate RPC_STALERACHANDLE, EINVAL,
30077c478bd9Sstevel@tonic-gate RPC_CANTCONNECT, ECONNREFUSED,
30087c478bd9Sstevel@tonic-gate RPC_XPRTFAILED, ECONNABORTED,
30097c478bd9Sstevel@tonic-gate RPC_CANTCREATESTREAM, ECONNREFUSED,
30107c478bd9Sstevel@tonic-gate RPC_CANTSTORE, ENOBUFS
30117c478bd9Sstevel@tonic-gate };
30127c478bd9Sstevel@tonic-gate
30137c478bd9Sstevel@tonic-gate /*
30147c478bd9Sstevel@tonic-gate * nfs4_try_failover - determine whether the client should
30157c478bd9Sstevel@tonic-gate * attempt failover based on the values stored in the nfs4_error_t.
30167c478bd9Sstevel@tonic-gate */
30177c478bd9Sstevel@tonic-gate int
nfs4_try_failover(nfs4_error_t * ep)30187c478bd9Sstevel@tonic-gate nfs4_try_failover(nfs4_error_t *ep)
30197c478bd9Sstevel@tonic-gate {
30207c478bd9Sstevel@tonic-gate if (ep->error == ETIMEDOUT || ep->stat == NFS4ERR_RESOURCE)
30217c478bd9Sstevel@tonic-gate return (TRUE);
30227c478bd9Sstevel@tonic-gate
30237c478bd9Sstevel@tonic-gate if (ep->error && ep->rpc_status != RPC_SUCCESS)
30247c478bd9Sstevel@tonic-gate return (try_failover(ep->rpc_status) != 0 ? TRUE : FALSE);
30257c478bd9Sstevel@tonic-gate
30267c478bd9Sstevel@tonic-gate return (FALSE);
30277c478bd9Sstevel@tonic-gate }
30287c478bd9Sstevel@tonic-gate
30297c478bd9Sstevel@tonic-gate /*
30307c478bd9Sstevel@tonic-gate * try_failover - internal version of nfs4_try_failover, called
30317c478bd9Sstevel@tonic-gate * only by rfscall and aclcall. Determine if failover is warranted
30327c478bd9Sstevel@tonic-gate * based on the clnt_stat and return the error number if it is.
30337c478bd9Sstevel@tonic-gate */
30347c478bd9Sstevel@tonic-gate static int
try_failover(enum clnt_stat rpc_status)30357c478bd9Sstevel@tonic-gate try_failover(enum clnt_stat rpc_status)
30367c478bd9Sstevel@tonic-gate {
30377c478bd9Sstevel@tonic-gate int err = 0;
30387c478bd9Sstevel@tonic-gate
30397c478bd9Sstevel@tonic-gate if (rpc_status == RPC_SUCCESS)
30407c478bd9Sstevel@tonic-gate return (0);
30417c478bd9Sstevel@tonic-gate
30427c478bd9Sstevel@tonic-gate #ifdef DEBUG
30437c478bd9Sstevel@tonic-gate if (rpc_status != 0 && nfs4_try_failover_any) {
30447c478bd9Sstevel@tonic-gate err = ETIMEDOUT;
30457c478bd9Sstevel@tonic-gate goto done;
30467c478bd9Sstevel@tonic-gate }
30477c478bd9Sstevel@tonic-gate #endif
30487c478bd9Sstevel@tonic-gate /*
30497c478bd9Sstevel@tonic-gate * The rpc status is used as an index into the table.
30507c478bd9Sstevel@tonic-gate * If the rpc status is outside of the range of the
30517c478bd9Sstevel@tonic-gate * table or if the rpc error numbers have been changed
30527c478bd9Sstevel@tonic-gate * since the table was constructed, then print a warning
30537c478bd9Sstevel@tonic-gate * (DEBUG only) and try failover anyway. Otherwise, just
30547c478bd9Sstevel@tonic-gate * grab the resulting error number out of the table.
30557c478bd9Sstevel@tonic-gate */
30567c478bd9Sstevel@tonic-gate if (rpc_status < RPC_SUCCESS || rpc_status >=
30577c478bd9Sstevel@tonic-gate sizeof (try_failover_table)/sizeof (try_failover_table[0]) ||
30587c478bd9Sstevel@tonic-gate try_failover_table[rpc_status].cstat != rpc_status) {
30597c478bd9Sstevel@tonic-gate
30607c478bd9Sstevel@tonic-gate err = ETIMEDOUT;
30617c478bd9Sstevel@tonic-gate #ifdef DEBUG
30627c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "try_failover: unexpected rpc error %d",
30637c478bd9Sstevel@tonic-gate rpc_status);
30647c478bd9Sstevel@tonic-gate #endif
30657c478bd9Sstevel@tonic-gate } else
30667c478bd9Sstevel@tonic-gate err = try_failover_table[rpc_status].error;
30677c478bd9Sstevel@tonic-gate
30687c478bd9Sstevel@tonic-gate done:
30697c478bd9Sstevel@tonic-gate if (rpc_status)
30707c478bd9Sstevel@tonic-gate NFS4_DEBUG(nfs4_client_failover_debug, (CE_NOTE,
30717c478bd9Sstevel@tonic-gate "nfs4_try_failover: %strying failover on error %d",
30727c478bd9Sstevel@tonic-gate err ? "" : "NOT ", rpc_status));
30737c478bd9Sstevel@tonic-gate
30747c478bd9Sstevel@tonic-gate return (err);
30757c478bd9Sstevel@tonic-gate }
30767c478bd9Sstevel@tonic-gate
30777c478bd9Sstevel@tonic-gate void
nfs4_error_zinit(nfs4_error_t * ep)30787c478bd9Sstevel@tonic-gate nfs4_error_zinit(nfs4_error_t *ep)
30797c478bd9Sstevel@tonic-gate {
30807c478bd9Sstevel@tonic-gate ep->error = 0;
30817c478bd9Sstevel@tonic-gate ep->stat = NFS4_OK;
30827c478bd9Sstevel@tonic-gate ep->rpc_status = RPC_SUCCESS;
30837c478bd9Sstevel@tonic-gate }
30847c478bd9Sstevel@tonic-gate
30857c478bd9Sstevel@tonic-gate void
nfs4_error_init(nfs4_error_t * ep,int error)30867c478bd9Sstevel@tonic-gate nfs4_error_init(nfs4_error_t *ep, int error)
30877c478bd9Sstevel@tonic-gate {
30887c478bd9Sstevel@tonic-gate ep->error = error;
30897c478bd9Sstevel@tonic-gate ep->stat = NFS4_OK;
30907c478bd9Sstevel@tonic-gate ep->rpc_status = RPC_SUCCESS;
30917c478bd9Sstevel@tonic-gate }
30927c478bd9Sstevel@tonic-gate
30937c478bd9Sstevel@tonic-gate
30947c478bd9Sstevel@tonic-gate #ifdef DEBUG
30957c478bd9Sstevel@tonic-gate
30967c478bd9Sstevel@tonic-gate /*
30977c478bd9Sstevel@tonic-gate * Return a 16-bit hash for filehandle, stateid, clientid, owner.
30987c478bd9Sstevel@tonic-gate * use the same algorithm as for NFS v3.
30997c478bd9Sstevel@tonic-gate *
31007c478bd9Sstevel@tonic-gate */
31017c478bd9Sstevel@tonic-gate int
hash16(void * p,int len)31027c478bd9Sstevel@tonic-gate hash16(void *p, int len)
31037c478bd9Sstevel@tonic-gate {
31047c478bd9Sstevel@tonic-gate int i, rem;
31057c478bd9Sstevel@tonic-gate uint_t *wp;
31067c478bd9Sstevel@tonic-gate uint_t key = 0;
31077c478bd9Sstevel@tonic-gate
31087c478bd9Sstevel@tonic-gate /* protect against non word aligned */
31097c478bd9Sstevel@tonic-gate if ((rem = len & 3) != 0)
31107c478bd9Sstevel@tonic-gate len &= ~3;
31117c478bd9Sstevel@tonic-gate
31127c478bd9Sstevel@tonic-gate for (i = 0, wp = (uint_t *)p; i < len; i += 4, wp++) {
31137c478bd9Sstevel@tonic-gate key ^= (*wp >> 16) ^ *wp;
31147c478bd9Sstevel@tonic-gate }
31157c478bd9Sstevel@tonic-gate
31167c478bd9Sstevel@tonic-gate /* hash left-over bytes */
31177c478bd9Sstevel@tonic-gate for (i = 0; i < rem; i++)
31187c478bd9Sstevel@tonic-gate key ^= *((uchar_t *)p + i);
31197c478bd9Sstevel@tonic-gate
31207c478bd9Sstevel@tonic-gate return (key & 0xffff);
31217c478bd9Sstevel@tonic-gate }
31227c478bd9Sstevel@tonic-gate
31237c478bd9Sstevel@tonic-gate /*
31247c478bd9Sstevel@tonic-gate * rnode4info - return filehandle and path information for an rnode.
31257c478bd9Sstevel@tonic-gate * XXX MT issues: uses a single static buffer, no locking of path.
31267c478bd9Sstevel@tonic-gate */
31277c478bd9Sstevel@tonic-gate char *
rnode4info(rnode4_t * rp)31287c478bd9Sstevel@tonic-gate rnode4info(rnode4_t *rp)
31297c478bd9Sstevel@tonic-gate {
31307c478bd9Sstevel@tonic-gate static char buf[80];
31317c478bd9Sstevel@tonic-gate nfs4_fhandle_t fhandle;
31327c478bd9Sstevel@tonic-gate char *path;
31337c478bd9Sstevel@tonic-gate char *type;
31347c478bd9Sstevel@tonic-gate
31357c478bd9Sstevel@tonic-gate if (rp == NULL)
31367c478bd9Sstevel@tonic-gate return ("null");
31377c478bd9Sstevel@tonic-gate if (rp->r_flags & R4ISXATTR)
31387c478bd9Sstevel@tonic-gate type = "attr";
31397c478bd9Sstevel@tonic-gate else if (RTOV4(rp)->v_flag & V_XATTRDIR)
31407c478bd9Sstevel@tonic-gate type = "attrdir";
31417c478bd9Sstevel@tonic-gate else if (RTOV4(rp)->v_flag & VROOT)
31427c478bd9Sstevel@tonic-gate type = "root";
31437c478bd9Sstevel@tonic-gate else if (RTOV4(rp)->v_type == VDIR)
31447c478bd9Sstevel@tonic-gate type = "dir";
31457c478bd9Sstevel@tonic-gate else if (RTOV4(rp)->v_type == VREG)
31467c478bd9Sstevel@tonic-gate type = "file";
31477c478bd9Sstevel@tonic-gate else
31487c478bd9Sstevel@tonic-gate type = "other";
31497c478bd9Sstevel@tonic-gate sfh4_copyval(rp->r_fh, &fhandle);
31507c478bd9Sstevel@tonic-gate path = fn_path(rp->r_svnode.sv_name);
31517c478bd9Sstevel@tonic-gate (void) snprintf(buf, 80, "$%p[%s], type=%s, flags=%04X, FH=%04X\n",
31527c478bd9Sstevel@tonic-gate (void *)rp, path, type, rp->r_flags,
31537c478bd9Sstevel@tonic-gate hash16((void *)&fhandle.fh_buf, fhandle.fh_len));
31547c478bd9Sstevel@tonic-gate kmem_free(path, strlen(path)+1);
31557c478bd9Sstevel@tonic-gate return (buf);
31567c478bd9Sstevel@tonic-gate }
31577c478bd9Sstevel@tonic-gate #endif
3158