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 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 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 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 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 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 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 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 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*0ea5f25dSJan 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 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 * 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 * 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 * 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 * 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