xref: /illumos-gate/usr/src/uts/common/fs/nfs/nfs4_srv.c (revision 214d537c)
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  */
216e062f4aSMarcel Telka 
227c478bd9Sstevel@tonic-gate /*
23bffeae97SMarcel Telka  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
2415721462SDaniil Lunev  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  *	Copyright (c) 1983,1984,1985,1986,1987,1988,1989  AT&T.
287c478bd9Sstevel@tonic-gate  *	All Rights Reserved
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
310dfe541eSEvan Layton /*
320dfe541eSEvan Layton  * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
330dfe541eSEvan Layton  * Copyright 2019 Nexenta Systems, Inc.
340dfe541eSEvan Layton  * Copyright 2019 Nexenta by DDN, Inc.
35*214d537cSVitaliy Gusev  * Copyright 2021 Racktop Systems, Inc.
360dfe541eSEvan Layton  */
370dfe541eSEvan Layton 
387c478bd9Sstevel@tonic-gate #include <sys/param.h>
397c478bd9Sstevel@tonic-gate #include <sys/types.h>
407c478bd9Sstevel@tonic-gate #include <sys/systm.h>
417c478bd9Sstevel@tonic-gate #include <sys/cred.h>
427c478bd9Sstevel@tonic-gate #include <sys/buf.h>
437c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
44aa59c4cbSrsb #include <sys/vfs_opreg.h>
457c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
467c478bd9Sstevel@tonic-gate #include <sys/uio.h>
477c478bd9Sstevel@tonic-gate #include <sys/errno.h>
487c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
497c478bd9Sstevel@tonic-gate #include <sys/statvfs.h>
507c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
517c478bd9Sstevel@tonic-gate #include <sys/dirent.h>
527c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
537c478bd9Sstevel@tonic-gate #include <sys/debug.h>
547c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
557c478bd9Sstevel@tonic-gate #include <sys/flock.h>
567c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
577c478bd9Sstevel@tonic-gate #include <sys/nbmlock.h>
587c478bd9Sstevel@tonic-gate #include <sys/share.h>
597c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
607c478bd9Sstevel@tonic-gate #include <sys/policy.h>
617c478bd9Sstevel@tonic-gate #include <sys/fem.h>
6245916cd2Sjpk #include <sys/sdt.h>
63cee86682Scalum #include <sys/ddi.h>
645679c89fSjv #include <sys/zone.h>
657c478bd9Sstevel@tonic-gate 
662f172c55SRobert Thurlow #include <fs/fs_reparse.h>
672f172c55SRobert Thurlow 
687c478bd9Sstevel@tonic-gate #include <rpc/types.h>
697c478bd9Sstevel@tonic-gate #include <rpc/auth.h>
707c478bd9Sstevel@tonic-gate #include <rpc/rpcsec_gss.h>
717c478bd9Sstevel@tonic-gate #include <rpc/svc.h>
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate #include <nfs/nfs.h>
740dfe541eSEvan Layton #include <nfs/nfssys.h>
757c478bd9Sstevel@tonic-gate #include <nfs/export.h>
76b89a8333Snatalie li - Sun Microsystems - Irvine United States #include <nfs/nfs_cmd.h>
777c478bd9Sstevel@tonic-gate #include <nfs/lm.h>
787c478bd9Sstevel@tonic-gate #include <nfs/nfs4.h>
790dfe541eSEvan Layton #include <nfs/nfs4_drc.h>
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
827c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate #include <inet/common.h>
857c478bd9Sstevel@tonic-gate #include <inet/ip.h>
867c478bd9Sstevel@tonic-gate #include <inet/ip6.h>
877c478bd9Sstevel@tonic-gate 
8845916cd2Sjpk #include <sys/tsol/label.h>
8945916cd2Sjpk #include <sys/tsol/tndb.h>
9045916cd2Sjpk 
917c478bd9Sstevel@tonic-gate #define	RFS4_MAXLOCK_TRIES 4	/* Try to get the lock this many times */
927c478bd9Sstevel@tonic-gate static int rfs4_maxlock_tries = RFS4_MAXLOCK_TRIES;
937c478bd9Sstevel@tonic-gate #define	RFS4_LOCK_DELAY 10	/* Milliseconds */
940a701b1eSRobert Gordon static clock_t  rfs4_lock_delay = RFS4_LOCK_DELAY;
950a701b1eSRobert Gordon extern struct svc_ops rdma_svc_ops;
96c242f9a0Schunli zhang - Sun Microsystems - Irvine United States extern int nfs_loaned_buffers;
97c242f9a0Schunli zhang - Sun Microsystems - Irvine United States /* End of Tunables */
987c478bd9Sstevel@tonic-gate 
990a701b1eSRobert Gordon static int rdma_setup_read_data4(READ4args *, READ4res *);
1000a701b1eSRobert Gordon 
1017c478bd9Sstevel@tonic-gate /*
1027c478bd9Sstevel@tonic-gate  * Used to bump the stateid4.seqid value and show changes in the stateid
1037c478bd9Sstevel@tonic-gate  */
1047c478bd9Sstevel@tonic-gate #define	next_stateid(sp) (++(sp)->bits.chgseq)
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate /*
1077c478bd9Sstevel@tonic-gate  * RFS4_MINLEN_ENTRY4: XDR-encoded size of smallest possible dirent.
1087c478bd9Sstevel@tonic-gate  *	This is used to return NFS4ERR_TOOSMALL when clients specify
1097c478bd9Sstevel@tonic-gate  *	maxcount that isn't large enough to hold the smallest possible
1107c478bd9Sstevel@tonic-gate  *	XDR encoded dirent.
1117c478bd9Sstevel@tonic-gate  *
1127c478bd9Sstevel@tonic-gate  *	    sizeof cookie (8 bytes) +
1137c478bd9Sstevel@tonic-gate  *	    sizeof name_len (4 bytes) +
1147c478bd9Sstevel@tonic-gate  *	    sizeof smallest (padded) name (4 bytes) +
1157c478bd9Sstevel@tonic-gate  *	    sizeof bitmap4_len (12 bytes) +   NOTE: we always encode len=2 bm4
1167c478bd9Sstevel@tonic-gate  *	    sizeof attrlist4_len (4 bytes) +
1177c478bd9Sstevel@tonic-gate  *	    sizeof next boolean (4 bytes)
1187c478bd9Sstevel@tonic-gate  *
1197c478bd9Sstevel@tonic-gate  * RFS4_MINLEN_RDDIR4: XDR-encoded size of READDIR op reply containing
1207c478bd9Sstevel@tonic-gate  * the smallest possible entry4 (assumes no attrs requested).
1217c478bd9Sstevel@tonic-gate  *	sizeof nfsstat4 (4 bytes) +
1227c478bd9Sstevel@tonic-gate  *	sizeof verifier4 (8 bytes) +
1237c478bd9Sstevel@tonic-gate  *	sizeof entry4list bool (4 bytes) +
1240dfe541eSEvan Layton  *	sizeof entry4 (36 bytes) +
1250dfe541eSEvan Layton  *	sizeof eof bool (4 bytes)
1267c478bd9Sstevel@tonic-gate  *
1277c478bd9Sstevel@tonic-gate  * RFS4_MINLEN_RDDIR_BUF: minimum length of buffer server will provide to
1287c478bd9Sstevel@tonic-gate  *	VOP_READDIR.  Its value is the size of the maximum possible dirent
1297c478bd9Sstevel@tonic-gate  *	for solaris.  The DIRENT64_RECLEN macro returns	the size of dirent
1307c478bd9Sstevel@tonic-gate  *	required for a given name length.  MAXNAMELEN is the maximum
1317c478bd9Sstevel@tonic-gate  *	filename length allowed in Solaris.  The first two DIRENT64_RECLEN()
1327c478bd9Sstevel@tonic-gate  *	macros are to allow for . and .. entries -- just a minor tweak to try
1337c478bd9Sstevel@tonic-gate  *	and guarantee that buffer we give to VOP_READDIR will be large enough
1347c478bd9Sstevel@tonic-gate  *	to hold ., .., and the largest possible solaris dirent64.
1357c478bd9Sstevel@tonic-gate  */
1367c478bd9Sstevel@tonic-gate #define	RFS4_MINLEN_ENTRY4 36
1377c478bd9Sstevel@tonic-gate #define	RFS4_MINLEN_RDDIR4 (4 + NFS4_VERIFIER_SIZE + 4 + RFS4_MINLEN_ENTRY4 + 4)
1387c478bd9Sstevel@tonic-gate #define	RFS4_MINLEN_RDDIR_BUF \
1397c478bd9Sstevel@tonic-gate 	(DIRENT64_RECLEN(1) + DIRENT64_RECLEN(2) + DIRENT64_RECLEN(MAXNAMELEN))
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate /*
1427c478bd9Sstevel@tonic-gate  * It would be better to pad to 4 bytes since that's what XDR would do,
1437c478bd9Sstevel@tonic-gate  * but the dirents UFS gives us are already padded to 8, so just take
1447c478bd9Sstevel@tonic-gate  * what we're given.  Dircount is only a hint anyway.  Currently the
1457c478bd9Sstevel@tonic-gate  * solaris kernel is ASCII only, so there's no point in calling the
1467c478bd9Sstevel@tonic-gate  * UTF8 functions.
1477c478bd9Sstevel@tonic-gate  *
1487c478bd9Sstevel@tonic-gate  * dirent64: named padded to provide 8 byte struct alignment
1497c478bd9Sstevel@tonic-gate  *	d_ino(8) + d_off(8) + d_reclen(2) + d_name(namelen + null(1) + pad)
1507c478bd9Sstevel@tonic-gate  *
1517c478bd9Sstevel@tonic-gate  * cookie: uint64_t   +  utf8namelen: uint_t  +   utf8name padded to 8 bytes
1527c478bd9Sstevel@tonic-gate  *
1537c478bd9Sstevel@tonic-gate  */
1547c478bd9Sstevel@tonic-gate #define	DIRENT64_TO_DIRCOUNT(dp) \
1557c478bd9Sstevel@tonic-gate 	(3 * BYTES_PER_XDR_UNIT + DIRENT64_NAMELEN((dp)->d_reclen))
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 
1580dfe541eSEvan Layton static sysid_t		lockt_sysid;	/* dummy sysid for all LOCKT calls */
1597c478bd9Sstevel@tonic-gate 
1600a701b1eSRobert Gordon u_longlong_t	nfs4_srv_caller_id;
1610a701b1eSRobert Gordon uint_t		nfs4_srv_vkey = 0;
1627c478bd9Sstevel@tonic-gate 
1630a701b1eSRobert Gordon void	rfs4_init_compound_state(struct compound_state *);
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate static void	nullfree(caddr_t);
1667c478bd9Sstevel@tonic-gate static void	rfs4_op_inval(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
1670dfe541eSEvan Layton 		    struct compound_state *);
1687c478bd9Sstevel@tonic-gate static void	rfs4_op_access(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
1690dfe541eSEvan Layton 		    struct compound_state *);
1707c478bd9Sstevel@tonic-gate static void	rfs4_op_close(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
1710dfe541eSEvan Layton 		    struct compound_state *);
1727c478bd9Sstevel@tonic-gate static void	rfs4_op_commit(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
1730dfe541eSEvan Layton 		    struct compound_state *);
1747c478bd9Sstevel@tonic-gate static void	rfs4_op_create(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
1750dfe541eSEvan Layton 		    struct compound_state *);
1767c478bd9Sstevel@tonic-gate static void	rfs4_op_create_free(nfs_resop4 *resop);
1777c478bd9Sstevel@tonic-gate static void	rfs4_op_delegreturn(nfs_argop4 *, nfs_resop4 *,
1780dfe541eSEvan Layton 		    struct svc_req *, struct compound_state *);
179f3b585ceSsamf static void	rfs4_op_delegpurge(nfs_argop4 *, nfs_resop4 *,
1800dfe541eSEvan Layton 		    struct svc_req *, struct compound_state *);
1817c478bd9Sstevel@tonic-gate static void	rfs4_op_getattr(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
1820dfe541eSEvan Layton 		    struct compound_state *);
1837c478bd9Sstevel@tonic-gate static void	rfs4_op_getattr_free(nfs_resop4 *);
1847c478bd9Sstevel@tonic-gate static void	rfs4_op_getfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
1850dfe541eSEvan Layton 		    struct compound_state *);
1867c478bd9Sstevel@tonic-gate static void	rfs4_op_getfh_free(nfs_resop4 *);
1877c478bd9Sstevel@tonic-gate static void	rfs4_op_illegal(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
1880dfe541eSEvan Layton 		    struct compound_state *);
1897c478bd9Sstevel@tonic-gate static void	rfs4_op_link(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
1900dfe541eSEvan Layton 		    struct compound_state *);
1917c478bd9Sstevel@tonic-gate static void	rfs4_op_lock(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
1920dfe541eSEvan Layton 		    struct compound_state *);
1937c478bd9Sstevel@tonic-gate static void	lock_denied_free(nfs_resop4 *);
1947c478bd9Sstevel@tonic-gate static void	rfs4_op_locku(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
1950dfe541eSEvan Layton 		    struct compound_state *);
1967c478bd9Sstevel@tonic-gate static void	rfs4_op_lockt(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
1970dfe541eSEvan Layton 		    struct compound_state *);
1987c478bd9Sstevel@tonic-gate static void	rfs4_op_lookup(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
1990dfe541eSEvan Layton 		    struct compound_state *);
2007c478bd9Sstevel@tonic-gate static void	rfs4_op_lookupp(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
2010dfe541eSEvan Layton 		    struct compound_state *);
2027c478bd9Sstevel@tonic-gate static void	rfs4_op_openattr(nfs_argop4 *argop, nfs_resop4 *resop,
2030dfe541eSEvan Layton 		    struct svc_req *req, struct compound_state *cs);
2047c478bd9Sstevel@tonic-gate static void	rfs4_op_nverify(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
2050dfe541eSEvan Layton 		    struct compound_state *);
2067c478bd9Sstevel@tonic-gate static void	rfs4_op_open(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
2070dfe541eSEvan Layton 		    struct compound_state *);
2087c478bd9Sstevel@tonic-gate static void	rfs4_op_open_confirm(nfs_argop4 *, nfs_resop4 *,
2090dfe541eSEvan Layton 		    struct svc_req *, struct compound_state *);
2107c478bd9Sstevel@tonic-gate static void	rfs4_op_open_downgrade(nfs_argop4 *, nfs_resop4 *,
2110dfe541eSEvan Layton 		    struct svc_req *, struct compound_state *);
2127c478bd9Sstevel@tonic-gate static void	rfs4_op_putfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
2130dfe541eSEvan Layton 		    struct compound_state *);
2147c478bd9Sstevel@tonic-gate static void	rfs4_op_putpubfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
2150dfe541eSEvan Layton 		    struct compound_state *);
2167c478bd9Sstevel@tonic-gate static void	rfs4_op_putrootfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
2170dfe541eSEvan Layton 		    struct compound_state *);
2187c478bd9Sstevel@tonic-gate static void	rfs4_op_read(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
2190dfe541eSEvan Layton 		    struct compound_state *);
2207c478bd9Sstevel@tonic-gate static void	rfs4_op_read_free(nfs_resop4 *);
2217c478bd9Sstevel@tonic-gate static void	rfs4_op_readdir_free(nfs_resop4 *resop);
2227c478bd9Sstevel@tonic-gate static void	rfs4_op_readlink(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
2230dfe541eSEvan Layton 		    struct compound_state *);
2247c478bd9Sstevel@tonic-gate static void	rfs4_op_readlink_free(nfs_resop4 *);
2257c478bd9Sstevel@tonic-gate static void	rfs4_op_release_lockowner(nfs_argop4 *, nfs_resop4 *,
2260dfe541eSEvan Layton 		    struct svc_req *, struct compound_state *);
2277c478bd9Sstevel@tonic-gate static void	rfs4_op_remove(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
2280dfe541eSEvan Layton 		    struct compound_state *);
2297c478bd9Sstevel@tonic-gate static void	rfs4_op_rename(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
2300dfe541eSEvan Layton 		    struct compound_state *);
2317c478bd9Sstevel@tonic-gate static void	rfs4_op_renew(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
2320dfe541eSEvan Layton 		    struct compound_state *);
2337c478bd9Sstevel@tonic-gate static void	rfs4_op_restorefh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
2340dfe541eSEvan Layton 		    struct compound_state *);
2357c478bd9Sstevel@tonic-gate static void	rfs4_op_savefh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
2360dfe541eSEvan Layton 		    struct compound_state *);
2377c478bd9Sstevel@tonic-gate static void	rfs4_op_setattr(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
2380dfe541eSEvan Layton 		    struct compound_state *);
2397c478bd9Sstevel@tonic-gate static void	rfs4_op_verify(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
2400dfe541eSEvan Layton 		    struct compound_state *);
2417c478bd9Sstevel@tonic-gate static void	rfs4_op_write(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
2420dfe541eSEvan Layton 		    struct compound_state *);
2437c478bd9Sstevel@tonic-gate static void	rfs4_op_setclientid(nfs_argop4 *, nfs_resop4 *,
2440dfe541eSEvan Layton 		    struct svc_req *, struct compound_state *);
2457c478bd9Sstevel@tonic-gate static void	rfs4_op_setclientid_confirm(nfs_argop4 *, nfs_resop4 *,
2460dfe541eSEvan Layton 		    struct svc_req *req, struct compound_state *);
2477c478bd9Sstevel@tonic-gate static void	rfs4_op_secinfo(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
2480dfe541eSEvan Layton 		    struct compound_state *);
2497c478bd9Sstevel@tonic-gate static void	rfs4_op_secinfo_free(nfs_resop4 *);
2507c478bd9Sstevel@tonic-gate 
2510dfe541eSEvan Layton static nfsstat4 check_open_access(uint32_t, struct compound_state *,
2520dfe541eSEvan Layton 		    struct svc_req *);
2530dfe541eSEvan Layton nfsstat4	rfs4_client_sysid(rfs4_client_t *, sysid_t *);
2540dfe541eSEvan Layton void		rfs4_ss_clid(nfs4_srv_t *, rfs4_client_t *);
2550dfe541eSEvan Layton 
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate /*
2587c478bd9Sstevel@tonic-gate  * translation table for attrs
2597c478bd9Sstevel@tonic-gate  */
2607c478bd9Sstevel@tonic-gate struct nfs4_ntov_table {
2617c478bd9Sstevel@tonic-gate 	union nfs4_attr_u *na;
2627c478bd9Sstevel@tonic-gate 	uint8_t amap[NFS4_MAXNUM_ATTRS];
2637c478bd9Sstevel@tonic-gate 	int attrcnt;
2647c478bd9Sstevel@tonic-gate 	bool_t vfsstat;
2657c478bd9Sstevel@tonic-gate };
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate static void	nfs4_ntov_table_init(struct nfs4_ntov_table *ntovp);
2687c478bd9Sstevel@tonic-gate static void	nfs4_ntov_table_free(struct nfs4_ntov_table *ntovp,
2690dfe541eSEvan Layton 		    struct nfs4_svgetit_arg *sargp);
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate static nfsstat4	do_rfs4_set_attrs(bitmap4 *resp, fattr4 *fattrp,
2727c478bd9Sstevel@tonic-gate 		    struct compound_state *cs, struct nfs4_svgetit_arg *sargp,
2737c478bd9Sstevel@tonic-gate 		    struct nfs4_ntov_table *ntovp, nfs4_attr_cmd_t cmd);
2747c478bd9Sstevel@tonic-gate 
2750dfe541eSEvan Layton static void	hanfsv4_failover(nfs4_srv_t *);
2760dfe541eSEvan Layton 
2770a701b1eSRobert Gordon fem_t		*deleg_rdops;
2780a701b1eSRobert Gordon fem_t		*deleg_wrops;
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate /*
2817c478bd9Sstevel@tonic-gate  * NFS4 op dispatch table
2827c478bd9Sstevel@tonic-gate  */
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate struct rfsv4disp {
2857c478bd9Sstevel@tonic-gate 	void	(*dis_proc)();		/* proc to call */
2867c478bd9Sstevel@tonic-gate 	void	(*dis_resfree)();	/* frees space allocated by proc */
2877c478bd9Sstevel@tonic-gate 	int	dis_flags;		/* RPC_IDEMPOTENT, etc... */
2887c478bd9Sstevel@tonic-gate };
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate static struct rfsv4disp rfsv4disptab[] = {
2917c478bd9Sstevel@tonic-gate 	/*
2927c478bd9Sstevel@tonic-gate 	 * NFS VERSION 4
2937c478bd9Sstevel@tonic-gate 	 */
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	/* RFS_NULL = 0 */
296f7877f5dSDan McDonald 	{rfs4_op_illegal, nullfree, 0},
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	/* UNUSED = 1 */
299f7877f5dSDan McDonald 	{rfs4_op_illegal, nullfree, 0},
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	/* UNUSED = 2 */
302f7877f5dSDan McDonald 	{rfs4_op_illegal, nullfree, 0},
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	/* OP_ACCESS = 3 */
305f7877f5dSDan McDonald 	{rfs4_op_access, nullfree, RPC_IDEMPOTENT},
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	/* OP_CLOSE = 4 */
308f7877f5dSDan McDonald 	{rfs4_op_close, nullfree, 0},
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	/* OP_COMMIT = 5 */
311f7877f5dSDan McDonald 	{rfs4_op_commit, nullfree, RPC_IDEMPOTENT},
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	/* OP_CREATE = 6 */
314f7877f5dSDan McDonald 	{rfs4_op_create, nullfree, 0},
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	/* OP_DELEGPURGE = 7 */
317f7877f5dSDan McDonald 	{rfs4_op_delegpurge, nullfree, 0},
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	/* OP_DELEGRETURN = 8 */
320f7877f5dSDan McDonald 	{rfs4_op_delegreturn, nullfree, 0},
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	/* OP_GETATTR = 9 */
323f7877f5dSDan McDonald 	{rfs4_op_getattr, rfs4_op_getattr_free, RPC_IDEMPOTENT},
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	/* OP_GETFH = 10 */
326f7877f5dSDan McDonald 	{rfs4_op_getfh, rfs4_op_getfh_free, RPC_ALL},
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	/* OP_LINK = 11 */
329f7877f5dSDan McDonald 	{rfs4_op_link, nullfree, 0},
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	/* OP_LOCK = 12 */
332f7877f5dSDan McDonald 	{rfs4_op_lock, lock_denied_free, 0},
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	/* OP_LOCKT = 13 */
335f7877f5dSDan McDonald 	{rfs4_op_lockt, lock_denied_free, 0},
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	/* OP_LOCKU = 14 */
338f7877f5dSDan McDonald 	{rfs4_op_locku, nullfree, 0},
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	/* OP_LOOKUP = 15 */
341f7877f5dSDan McDonald 	{rfs4_op_lookup, nullfree, (RPC_IDEMPOTENT | RPC_PUBLICFH_OK)},
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	/* OP_LOOKUPP = 16 */
344f7877f5dSDan McDonald 	{rfs4_op_lookupp, nullfree, (RPC_IDEMPOTENT | RPC_PUBLICFH_OK)},
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	/* OP_NVERIFY = 17 */
347f7877f5dSDan McDonald 	{rfs4_op_nverify, nullfree, RPC_IDEMPOTENT},
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	/* OP_OPEN = 18 */
350f7877f5dSDan McDonald 	{rfs4_op_open, rfs4_free_reply, 0},
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	/* OP_OPENATTR = 19 */
353f7877f5dSDan McDonald 	{rfs4_op_openattr, nullfree, 0},
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	/* OP_OPEN_CONFIRM = 20 */
356f7877f5dSDan McDonald 	{rfs4_op_open_confirm, nullfree, 0},
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	/* OP_OPEN_DOWNGRADE = 21 */
359f7877f5dSDan McDonald 	{rfs4_op_open_downgrade, nullfree, 0},
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	/* OP_OPEN_PUTFH = 22 */
362f7877f5dSDan McDonald 	{rfs4_op_putfh, nullfree, RPC_ALL},
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	/* OP_PUTPUBFH = 23 */
365f7877f5dSDan McDonald 	{rfs4_op_putpubfh, nullfree, RPC_ALL},
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 	/* OP_PUTROOTFH = 24 */
368f7877f5dSDan McDonald 	{rfs4_op_putrootfh, nullfree, RPC_ALL},
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	/* OP_READ = 25 */
371f7877f5dSDan McDonald 	{rfs4_op_read, rfs4_op_read_free, RPC_IDEMPOTENT},
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	/* OP_READDIR = 26 */
374f7877f5dSDan McDonald 	{rfs4_op_readdir, rfs4_op_readdir_free, RPC_IDEMPOTENT},
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	/* OP_READLINK = 27 */
377f7877f5dSDan McDonald 	{rfs4_op_readlink, rfs4_op_readlink_free, RPC_IDEMPOTENT},
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	/* OP_REMOVE = 28 */
380f7877f5dSDan McDonald 	{rfs4_op_remove, nullfree, 0},
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	/* OP_RENAME = 29 */
383f7877f5dSDan McDonald 	{rfs4_op_rename, nullfree, 0},
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	/* OP_RENEW = 30 */
386f7877f5dSDan McDonald 	{rfs4_op_renew, nullfree, 0},
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	/* OP_RESTOREFH = 31 */
389f7877f5dSDan McDonald 	{rfs4_op_restorefh, nullfree, RPC_ALL},
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	/* OP_SAVEFH = 32 */
392f7877f5dSDan McDonald 	{rfs4_op_savefh, nullfree, RPC_ALL},
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	/* OP_SECINFO = 33 */
395f7877f5dSDan McDonald 	{rfs4_op_secinfo, rfs4_op_secinfo_free, 0},
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	/* OP_SETATTR = 34 */
398f7877f5dSDan McDonald 	{rfs4_op_setattr, nullfree, 0},
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	/* OP_SETCLIENTID = 35 */
401f7877f5dSDan McDonald 	{rfs4_op_setclientid, nullfree, 0},
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	/* OP_SETCLIENTID_CONFIRM = 36 */
404f7877f5dSDan McDonald 	{rfs4_op_setclientid_confirm, nullfree, 0},
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	/* OP_VERIFY = 37 */
407f7877f5dSDan McDonald 	{rfs4_op_verify, nullfree, RPC_IDEMPOTENT},
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	/* OP_WRITE = 38 */
410f7877f5dSDan McDonald 	{rfs4_op_write, nullfree, 0},
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	/* OP_RELEASE_LOCKOWNER = 39 */
413f7877f5dSDan McDonald 	{rfs4_op_release_lockowner, nullfree, 0},
4147c478bd9Sstevel@tonic-gate };
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate static uint_t rfsv4disp_cnt = sizeof (rfsv4disptab) / sizeof (rfsv4disptab[0]);
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate #define	OP_ILLEGAL_IDX (rfsv4disp_cnt)
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate #ifdef DEBUG
4217c478bd9Sstevel@tonic-gate 
4220a701b1eSRobert Gordon int		rfs4_fillone_debug = 0;
4230a701b1eSRobert Gordon int		rfs4_no_stub_access = 1;
4240a701b1eSRobert Gordon int		rfs4_rddir_debug = 0;
4257c478bd9Sstevel@tonic-gate 
4260a701b1eSRobert Gordon static char    *rfs4_op_string[] = {
4277c478bd9Sstevel@tonic-gate 	"rfs4_op_null",
4287c478bd9Sstevel@tonic-gate 	"rfs4_op_1 unused",
4297c478bd9Sstevel@tonic-gate 	"rfs4_op_2 unused",
4307c478bd9Sstevel@tonic-gate 	"rfs4_op_access",
4317c478bd9Sstevel@tonic-gate 	"rfs4_op_close",
4327c478bd9Sstevel@tonic-gate 	"rfs4_op_commit",
4337c478bd9Sstevel@tonic-gate 	"rfs4_op_create",
4347c478bd9Sstevel@tonic-gate 	"rfs4_op_delegpurge",
4357c478bd9Sstevel@tonic-gate 	"rfs4_op_delegreturn",
4367c478bd9Sstevel@tonic-gate 	"rfs4_op_getattr",
4377c478bd9Sstevel@tonic-gate 	"rfs4_op_getfh",
4387c478bd9Sstevel@tonic-gate 	"rfs4_op_link",
4397c478bd9Sstevel@tonic-gate 	"rfs4_op_lock",
4407c478bd9Sstevel@tonic-gate 	"rfs4_op_lockt",
4417c478bd9Sstevel@tonic-gate 	"rfs4_op_locku",
4427c478bd9Sstevel@tonic-gate 	"rfs4_op_lookup",
4437c478bd9Sstevel@tonic-gate 	"rfs4_op_lookupp",
4447c478bd9Sstevel@tonic-gate 	"rfs4_op_nverify",
4457c478bd9Sstevel@tonic-gate 	"rfs4_op_open",
4467c478bd9Sstevel@tonic-gate 	"rfs4_op_openattr",
4477c478bd9Sstevel@tonic-gate 	"rfs4_op_open_confirm",
4487c478bd9Sstevel@tonic-gate 	"rfs4_op_open_downgrade",
4497c478bd9Sstevel@tonic-gate 	"rfs4_op_putfh",
4507c478bd9Sstevel@tonic-gate 	"rfs4_op_putpubfh",
4517c478bd9Sstevel@tonic-gate 	"rfs4_op_putrootfh",
4527c478bd9Sstevel@tonic-gate 	"rfs4_op_read",
4537c478bd9Sstevel@tonic-gate 	"rfs4_op_readdir",
4547c478bd9Sstevel@tonic-gate 	"rfs4_op_readlink",
4557c478bd9Sstevel@tonic-gate 	"rfs4_op_remove",
4567c478bd9Sstevel@tonic-gate 	"rfs4_op_rename",
4577c478bd9Sstevel@tonic-gate 	"rfs4_op_renew",
4587c478bd9Sstevel@tonic-gate 	"rfs4_op_restorefh",
4597c478bd9Sstevel@tonic-gate 	"rfs4_op_savefh",
4607c478bd9Sstevel@tonic-gate 	"rfs4_op_secinfo",
4617c478bd9Sstevel@tonic-gate 	"rfs4_op_setattr",
4627c478bd9Sstevel@tonic-gate 	"rfs4_op_setclientid",
4637c478bd9Sstevel@tonic-gate 	"rfs4_op_setclient_confirm",
4647c478bd9Sstevel@tonic-gate 	"rfs4_op_verify",
4657c478bd9Sstevel@tonic-gate 	"rfs4_op_write",
4667c478bd9Sstevel@tonic-gate 	"rfs4_op_release_lockowner",
4677c478bd9Sstevel@tonic-gate 	"rfs4_op_illegal"
4687c478bd9Sstevel@tonic-gate };
4697c478bd9Sstevel@tonic-gate #endif
4707c478bd9Sstevel@tonic-gate 
4710dfe541eSEvan Layton void	rfs4_ss_chkclid(nfs4_srv_t *, rfs4_client_t *);
4727c478bd9Sstevel@tonic-gate 
4730a701b1eSRobert Gordon extern size_t   strlcpy(char *dst, const char *src, size_t dstsize);
474cee86682Scalum 
4752f172c55SRobert Thurlow extern void	rfs4_free_fs_locations4(fs_locations4 *);
4762f172c55SRobert Thurlow 
4777c478bd9Sstevel@tonic-gate #ifdef	nextdp
4787c478bd9Sstevel@tonic-gate #undef nextdp
4797c478bd9Sstevel@tonic-gate #endif
4807c478bd9Sstevel@tonic-gate #define	nextdp(dp)	((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate static const fs_operation_def_t nfs4_rd_deleg_tmpl[] = {
483cfae96c2Sjwahlig 	VOPNAME_OPEN,		{ .femop_open = deleg_rd_open },
484cfae96c2Sjwahlig 	VOPNAME_WRITE,		{ .femop_write = deleg_rd_write },
485cfae96c2Sjwahlig 	VOPNAME_SETATTR,	{ .femop_setattr = deleg_rd_setattr },
486aa59c4cbSrsb 	VOPNAME_RWLOCK,		{ .femop_rwlock = deleg_rd_rwlock },
487cfae96c2Sjwahlig 	VOPNAME_SPACE,		{ .femop_space = deleg_rd_space },
488cfae96c2Sjwahlig 	VOPNAME_SETSECATTR,	{ .femop_setsecattr = deleg_rd_setsecattr },
489cfae96c2Sjwahlig 	VOPNAME_VNEVENT,	{ .femop_vnevent = deleg_rd_vnevent },
490aa59c4cbSrsb 	NULL,			NULL
4917c478bd9Sstevel@tonic-gate };
4927c478bd9Sstevel@tonic-gate static const fs_operation_def_t nfs4_wr_deleg_tmpl[] = {
493cfae96c2Sjwahlig 	VOPNAME_OPEN,		{ .femop_open = deleg_wr_open },
494cfae96c2Sjwahlig 	VOPNAME_READ,		{ .femop_read = deleg_wr_read },
495cfae96c2Sjwahlig 	VOPNAME_WRITE,		{ .femop_write = deleg_wr_write },
496cfae96c2Sjwahlig 	VOPNAME_SETATTR,	{ .femop_setattr = deleg_wr_setattr },
497aa59c4cbSrsb 	VOPNAME_RWLOCK,		{ .femop_rwlock = deleg_wr_rwlock },
498cfae96c2Sjwahlig 	VOPNAME_SPACE,		{ .femop_space = deleg_wr_space },
499cfae96c2Sjwahlig 	VOPNAME_SETSECATTR,	{ .femop_setsecattr = deleg_wr_setsecattr },
500cfae96c2Sjwahlig 	VOPNAME_VNEVENT,	{ .femop_vnevent = deleg_wr_vnevent },
501aa59c4cbSrsb 	NULL,			NULL
5027c478bd9Sstevel@tonic-gate };
5037c478bd9Sstevel@tonic-gate 
5040dfe541eSEvan Layton nfs4_srv_t *
nfs4_get_srv(void)5050dfe541eSEvan Layton nfs4_get_srv(void)
5060dfe541eSEvan Layton {
5070dfe541eSEvan Layton 	nfs_globals_t *ng = nfs_srv_getzg();
5080dfe541eSEvan Layton 	nfs4_srv_t *srv = ng->nfs4_srv;
5090dfe541eSEvan Layton 	ASSERT(srv != NULL);
5100dfe541eSEvan Layton 	return (srv);
5110dfe541eSEvan Layton }
5120dfe541eSEvan Layton 
5130dfe541eSEvan Layton void
rfs4_srv_zone_init(nfs_globals_t * ng)5140dfe541eSEvan Layton rfs4_srv_zone_init(nfs_globals_t *ng)
5157c478bd9Sstevel@tonic-gate {
5160dfe541eSEvan Layton 	nfs4_srv_t *nsrv4;
5177c478bd9Sstevel@tonic-gate 	timespec32_t verf;
5180dfe541eSEvan Layton 
5190dfe541eSEvan Layton 	nsrv4 = kmem_zalloc(sizeof (*nsrv4), KM_SLEEP);
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	/*
5227c478bd9Sstevel@tonic-gate 	 * The following algorithm attempts to find a unique verifier
5237c478bd9Sstevel@tonic-gate 	 * to be used as the write verifier returned from the server
5247c478bd9Sstevel@tonic-gate 	 * to the client.  It is important that this verifier change
5257c478bd9Sstevel@tonic-gate 	 * whenever the server reboots.  Of secondary importance, it
5267c478bd9Sstevel@tonic-gate 	 * is important for the verifier to be unique between two
5277c478bd9Sstevel@tonic-gate 	 * different servers.
5287c478bd9Sstevel@tonic-gate 	 *
5297c478bd9Sstevel@tonic-gate 	 * Thus, an attempt is made to use the system hostid and the
5307c478bd9Sstevel@tonic-gate 	 * current time in seconds when the nfssrv kernel module is
5317c478bd9Sstevel@tonic-gate 	 * loaded.  It is assumed that an NFS server will not be able
5327c478bd9Sstevel@tonic-gate 	 * to boot and then to reboot in less than a second.  If the
5337c478bd9Sstevel@tonic-gate 	 * hostid has not been set, then the current high resolution
5347c478bd9Sstevel@tonic-gate 	 * time is used.  This will ensure different verifiers each
5357c478bd9Sstevel@tonic-gate 	 * time the server reboots and minimize the chances that two
5367c478bd9Sstevel@tonic-gate 	 * different servers will have the same verifier.
5377c478bd9Sstevel@tonic-gate 	 * XXX - this is broken on LP64 kernels.
5387c478bd9Sstevel@tonic-gate 	 */
5395679c89fSjv 	verf.tv_sec = (time_t)zone_get_hostid(NULL);
5407c478bd9Sstevel@tonic-gate 	if (verf.tv_sec != 0) {
5417c478bd9Sstevel@tonic-gate 		verf.tv_nsec = gethrestime_sec();
5427c478bd9Sstevel@tonic-gate 	} else {
5437c478bd9Sstevel@tonic-gate 		timespec_t tverf;
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 		gethrestime(&tverf);
5467c478bd9Sstevel@tonic-gate 		verf.tv_sec = (time_t)tverf.tv_sec;
5477c478bd9Sstevel@tonic-gate 		verf.tv_nsec = tverf.tv_nsec;
5487c478bd9Sstevel@tonic-gate 	}
5490dfe541eSEvan Layton 	nsrv4->write4verf = *(uint64_t *)&verf;
5500dfe541eSEvan Layton 
5510dfe541eSEvan Layton 	/* Used to manage create/destroy of server state */
5520dfe541eSEvan Layton 	nsrv4->nfs4_server_state = NULL;
5530dfe541eSEvan Layton 	nsrv4->nfs4_cur_servinst = NULL;
5540dfe541eSEvan Layton 	nsrv4->nfs4_deleg_policy = SRV_NEVER_DELEGATE;
5550dfe541eSEvan Layton 	mutex_init(&nsrv4->deleg_lock, NULL, MUTEX_DEFAULT, NULL);
5560dfe541eSEvan Layton 	mutex_init(&nsrv4->state_lock, NULL, MUTEX_DEFAULT, NULL);
5570dfe541eSEvan Layton 	mutex_init(&nsrv4->servinst_lock, NULL, MUTEX_DEFAULT, NULL);
5580dfe541eSEvan Layton 	rw_init(&nsrv4->deleg_policy_lock, NULL, RW_DEFAULT, NULL);
5590dfe541eSEvan Layton 
5600dfe541eSEvan Layton 	ng->nfs4_srv = nsrv4;
5610dfe541eSEvan Layton }
5627c478bd9Sstevel@tonic-gate 
5630dfe541eSEvan Layton void
rfs4_srv_zone_fini(nfs_globals_t * ng)5640dfe541eSEvan Layton rfs4_srv_zone_fini(nfs_globals_t *ng)
5650dfe541eSEvan Layton {
5660dfe541eSEvan Layton 	nfs4_srv_t *nsrv4 = ng->nfs4_srv;
5677c478bd9Sstevel@tonic-gate 
5680dfe541eSEvan Layton 	ng->nfs4_srv = NULL;
5697c478bd9Sstevel@tonic-gate 
5700dfe541eSEvan Layton 	mutex_destroy(&nsrv4->deleg_lock);
5710dfe541eSEvan Layton 	mutex_destroy(&nsrv4->state_lock);
5720dfe541eSEvan Layton 	mutex_destroy(&nsrv4->servinst_lock);
5730dfe541eSEvan Layton 	rw_destroy(&nsrv4->deleg_policy_lock);
5747c478bd9Sstevel@tonic-gate 
5750dfe541eSEvan Layton 	kmem_free(nsrv4, sizeof (*nsrv4));
5760dfe541eSEvan Layton }
5777c478bd9Sstevel@tonic-gate 
5780dfe541eSEvan Layton void
rfs4_srvrinit(void)5790dfe541eSEvan Layton rfs4_srvrinit(void)
5800dfe541eSEvan Layton {
5810dfe541eSEvan Layton 	extern void rfs4_attr_init();
5827c478bd9Sstevel@tonic-gate 
5830dfe541eSEvan Layton 	rfs4_attr_init();
5840dfe541eSEvan Layton 
5850dfe541eSEvan Layton 	if (fem_create("deleg_rdops", nfs4_rd_deleg_tmpl, &deleg_rdops) != 0) {
5867c478bd9Sstevel@tonic-gate 		rfs4_disable_delegation();
5870dfe541eSEvan Layton 	} else if (fem_create("deleg_wrops", nfs4_wr_deleg_tmpl,
5880dfe541eSEvan Layton 	    &deleg_wrops) != 0) {
5890dfe541eSEvan Layton 		rfs4_disable_delegation();
5900dfe541eSEvan Layton 		fem_free(deleg_rdops);
5917c478bd9Sstevel@tonic-gate 	}
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 	nfs4_srv_caller_id = fs_new_caller_id();
5947c478bd9Sstevel@tonic-gate 	lockt_sysid = lm_alloc_sysidt();
5951b300de9Sjwahlig 	vsd_create(&nfs4_srv_vkey, NULL);
5960dfe541eSEvan Layton 	rfs4_state_g_init();
5977c478bd9Sstevel@tonic-gate }
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate void
rfs4_srvrfini(void)6007c478bd9Sstevel@tonic-gate rfs4_srvrfini(void)
6017c478bd9Sstevel@tonic-gate {
6027c478bd9Sstevel@tonic-gate 	if (lockt_sysid != LM_NOSYSID) {
6037c478bd9Sstevel@tonic-gate 		lm_free_sysidt(lockt_sysid);
6047c478bd9Sstevel@tonic-gate 		lockt_sysid = LM_NOSYSID;
6057c478bd9Sstevel@tonic-gate 	}
6067c478bd9Sstevel@tonic-gate 
6070dfe541eSEvan Layton 	rfs4_state_g_fini();
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	fem_free(deleg_rdops);
6107c478bd9Sstevel@tonic-gate 	fem_free(deleg_wrops);
6117c478bd9Sstevel@tonic-gate }
6127c478bd9Sstevel@tonic-gate 
6130dfe541eSEvan Layton void
rfs4_do_server_start(int server_upordown,int srv_delegation,int cluster_booted)6140dfe541eSEvan Layton rfs4_do_server_start(int server_upordown,
6150dfe541eSEvan Layton     int srv_delegation, int cluster_booted)
6160dfe541eSEvan Layton {
6170dfe541eSEvan Layton 	nfs4_srv_t *nsrv4 = nfs4_get_srv();
6180dfe541eSEvan Layton 
6190dfe541eSEvan Layton 	/* Is this a warm start? */
6200dfe541eSEvan Layton 	if (server_upordown == NFS_SERVER_QUIESCED) {
6210dfe541eSEvan Layton 		cmn_err(CE_NOTE, "nfs4_srv: "
6220dfe541eSEvan Layton 		    "server was previously quiesced; "
6230dfe541eSEvan Layton 		    "existing NFSv4 state will be re-used");
6240dfe541eSEvan Layton 
6250dfe541eSEvan Layton 		/*
6260dfe541eSEvan Layton 		 * HA-NFSv4: this is also the signal
6270dfe541eSEvan Layton 		 * that a Resource Group failover has
6280dfe541eSEvan Layton 		 * occurred.
6290dfe541eSEvan Layton 		 */
6300dfe541eSEvan Layton 		if (cluster_booted)
6310dfe541eSEvan Layton 			hanfsv4_failover(nsrv4);
6320dfe541eSEvan Layton 	} else {
6330dfe541eSEvan Layton 		/* Cold start */
6340dfe541eSEvan Layton 		nsrv4->rfs4_start_time = 0;
6350dfe541eSEvan Layton 		rfs4_state_zone_init(nsrv4);
6360dfe541eSEvan Layton 		nsrv4->nfs4_drc = rfs4_init_drc(nfs4_drc_max,
6370dfe541eSEvan Layton 		    nfs4_drc_hash);
6380dfe541eSEvan Layton 
6390dfe541eSEvan Layton 		/*
6400dfe541eSEvan Layton 		 * The nfsd service was started with the -s option
6410dfe541eSEvan Layton 		 * we need to pull in any state from the paths indicated.
6420dfe541eSEvan Layton 		 */
6430dfe541eSEvan Layton 		if (curzone == global_zone && rfs4_dss_numnewpaths > 0) {
6440dfe541eSEvan Layton 			/* read in the stable storage state from these paths */
6450dfe541eSEvan Layton 			rfs4_dss_readstate(nsrv4, rfs4_dss_numnewpaths,
6460dfe541eSEvan Layton 			    rfs4_dss_newpaths);
6470dfe541eSEvan Layton 		}
6480dfe541eSEvan Layton 	}
6490dfe541eSEvan Layton 
6500dfe541eSEvan Layton 	/* Check if delegation is to be enabled */
6510dfe541eSEvan Layton 	if (srv_delegation != FALSE)
6520dfe541eSEvan Layton 		rfs4_set_deleg_policy(nsrv4, SRV_NORMAL_DELEGATE);
6530dfe541eSEvan Layton }
6540dfe541eSEvan Layton 
6557c478bd9Sstevel@tonic-gate void
rfs4_init_compound_state(struct compound_state * cs)6567c478bd9Sstevel@tonic-gate rfs4_init_compound_state(struct compound_state *cs)
6577c478bd9Sstevel@tonic-gate {
6587c478bd9Sstevel@tonic-gate 	bzero(cs, sizeof (*cs));
6597c478bd9Sstevel@tonic-gate 	cs->cont = TRUE;
6607c478bd9Sstevel@tonic-gate 	cs->access = CS_ACCESS_DENIED;
6617c478bd9Sstevel@tonic-gate 	cs->deleg = FALSE;
6627c478bd9Sstevel@tonic-gate 	cs->mandlock = FALSE;
6637c478bd9Sstevel@tonic-gate 	cs->fh.nfs_fh4_val = cs->fhbuf;
6647c478bd9Sstevel@tonic-gate }
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate void
rfs4_grace_start(rfs4_servinst_t * sip)6677c478bd9Sstevel@tonic-gate rfs4_grace_start(rfs4_servinst_t *sip)
6687c478bd9Sstevel@tonic-gate {
6697c478bd9Sstevel@tonic-gate 	rw_enter(&sip->rwlock, RW_WRITER);
670d3d50737SRafael Vanoni 	sip->start_time = (time_t)TICK_TO_SEC(ddi_get_lbolt());
6717c478bd9Sstevel@tonic-gate 	sip->grace_period = rfs4_grace_period;
6727c478bd9Sstevel@tonic-gate 	rw_exit(&sip->rwlock);
6737c478bd9Sstevel@tonic-gate }
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate /*
6767c478bd9Sstevel@tonic-gate  * returns true if the instance's grace period has never been started
6777c478bd9Sstevel@tonic-gate  */
6787c478bd9Sstevel@tonic-gate int
rfs4_servinst_grace_new(rfs4_servinst_t * sip)6797c478bd9Sstevel@tonic-gate rfs4_servinst_grace_new(rfs4_servinst_t *sip)
6807c478bd9Sstevel@tonic-gate {
6817c478bd9Sstevel@tonic-gate 	time_t start_time;
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	rw_enter(&sip->rwlock, RW_READER);
6847c478bd9Sstevel@tonic-gate 	start_time = sip->start_time;
6857c478bd9Sstevel@tonic-gate 	rw_exit(&sip->rwlock);
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	return (start_time == 0);
6887c478bd9Sstevel@tonic-gate }
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate /*
6917c478bd9Sstevel@tonic-gate  * Indicates if server instance is within the
6927c478bd9Sstevel@tonic-gate  * grace period.
6937c478bd9Sstevel@tonic-gate  */
6947c478bd9Sstevel@tonic-gate int
rfs4_servinst_in_grace(rfs4_servinst_t * sip)6957c478bd9Sstevel@tonic-gate rfs4_servinst_in_grace(rfs4_servinst_t *sip)
6967c478bd9Sstevel@tonic-gate {
6977c478bd9Sstevel@tonic-gate 	time_t grace_expiry;
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 	rw_enter(&sip->rwlock, RW_READER);
7007c478bd9Sstevel@tonic-gate 	grace_expiry = sip->start_time + sip->grace_period;
7017c478bd9Sstevel@tonic-gate 	rw_exit(&sip->rwlock);
7027c478bd9Sstevel@tonic-gate 
703d3d50737SRafael Vanoni 	return (((time_t)TICK_TO_SEC(ddi_get_lbolt())) < grace_expiry);
7047c478bd9Sstevel@tonic-gate }
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate int
rfs4_clnt_in_grace(rfs4_client_t * cp)7077c478bd9Sstevel@tonic-gate rfs4_clnt_in_grace(rfs4_client_t *cp)
7087c478bd9Sstevel@tonic-gate {
709d216dff5SRobert Mastors 	ASSERT(rfs4_dbe_refcnt(cp->rc_dbe) > 0);
7107c478bd9Sstevel@tonic-gate 
711d216dff5SRobert Mastors 	return (rfs4_servinst_in_grace(cp->rc_server_instance));
7127c478bd9Sstevel@tonic-gate }
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate /*
7157c478bd9Sstevel@tonic-gate  * reset all currently active grace periods
7167c478bd9Sstevel@tonic-gate  */
7177c478bd9Sstevel@tonic-gate void
rfs4_grace_reset_all(nfs4_srv_t * nsrv4)7180dfe541eSEvan Layton rfs4_grace_reset_all(nfs4_srv_t *nsrv4)
7197c478bd9Sstevel@tonic-gate {
7207c478bd9Sstevel@tonic-gate 	rfs4_servinst_t *sip;
7217c478bd9Sstevel@tonic-gate 
7220dfe541eSEvan Layton 	mutex_enter(&nsrv4->servinst_lock);
7230dfe541eSEvan Layton 	for (sip = nsrv4->nfs4_cur_servinst; sip != NULL; sip = sip->prev)
724cee86682Scalum 		if (rfs4_servinst_in_grace(sip))
7257c478bd9Sstevel@tonic-gate 			rfs4_grace_start(sip);
7260dfe541eSEvan Layton 	mutex_exit(&nsrv4->servinst_lock);
7277c478bd9Sstevel@tonic-gate }
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate /*
7307c478bd9Sstevel@tonic-gate  * start any new instances' grace periods
7317c478bd9Sstevel@tonic-gate  */
7327c478bd9Sstevel@tonic-gate void
rfs4_grace_start_new(nfs4_srv_t * nsrv4)7330dfe541eSEvan Layton rfs4_grace_start_new(nfs4_srv_t *nsrv4)
7347c478bd9Sstevel@tonic-gate {
7357c478bd9Sstevel@tonic-gate 	rfs4_servinst_t *sip;
7367c478bd9Sstevel@tonic-gate 
7370dfe541eSEvan Layton 	mutex_enter(&nsrv4->servinst_lock);
7380dfe541eSEvan Layton 	for (sip = nsrv4->nfs4_cur_servinst; sip != NULL; sip = sip->prev)
7397c478bd9Sstevel@tonic-gate 		if (rfs4_servinst_grace_new(sip))
7407c478bd9Sstevel@tonic-gate 			rfs4_grace_start(sip);
7410dfe541eSEvan Layton 	mutex_exit(&nsrv4->servinst_lock);
742cee86682Scalum }
743cee86682Scalum 
744cee86682Scalum static rfs4_dss_path_t *
rfs4_dss_newpath(nfs4_srv_t * nsrv4,rfs4_servinst_t * sip,char * path,unsigned index)7450dfe541eSEvan Layton rfs4_dss_newpath(nfs4_srv_t *nsrv4, rfs4_servinst_t *sip,
7460dfe541eSEvan Layton     char *path, unsigned index)
747cee86682Scalum {
748cee86682Scalum 	size_t len;
749cee86682Scalum 	rfs4_dss_path_t *dss_path;
750cee86682Scalum 
751cee86682Scalum 	dss_path = kmem_alloc(sizeof (rfs4_dss_path_t), KM_SLEEP);
752cee86682Scalum 
753cee86682Scalum 	/*
754cee86682Scalum 	 * Take a copy of the string, since the original may be overwritten.
755cee86682Scalum 	 * Sadly, no strdup() in the kernel.
756cee86682Scalum 	 */
757cee86682Scalum 	/* allow for NUL */
758cee86682Scalum 	len = strlen(path) + 1;
759cee86682Scalum 	dss_path->path = kmem_alloc(len, KM_SLEEP);
760cee86682Scalum 	(void) strlcpy(dss_path->path, path, len);
761cee86682Scalum 
762cee86682Scalum 	/* associate with servinst */
763cee86682Scalum 	dss_path->sip = sip;
764cee86682Scalum 	dss_path->index = index;
765cee86682Scalum 
766cee86682Scalum 	/*
767cee86682Scalum 	 * Add to list of served paths.
768cee86682Scalum 	 * No locking required, as we're only ever called at startup.
769cee86682Scalum 	 */
7700dfe541eSEvan Layton 	if (nsrv4->dss_pathlist == NULL) {
771cee86682Scalum 		/* this is the first dss_path_t */
7727c478bd9Sstevel@tonic-gate 
773cee86682Scalum 		/* needed for insque/remque */
774cee86682Scalum 		dss_path->next = dss_path->prev = dss_path;
775cee86682Scalum 
7760dfe541eSEvan Layton 		nsrv4->dss_pathlist = dss_path;
777cee86682Scalum 	} else {
7780dfe541eSEvan Layton 		insque(dss_path, nsrv4->dss_pathlist);
779cee86682Scalum 	}
780cee86682Scalum 
781cee86682Scalum 	return (dss_path);
7827c478bd9Sstevel@tonic-gate }
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate /*
7857c478bd9Sstevel@tonic-gate  * Create a new server instance, and make it the currently active instance.
7867c478bd9Sstevel@tonic-gate  * Note that starting the grace period too early will reduce the clients'
7877c478bd9Sstevel@tonic-gate  * recovery window.
7887c478bd9Sstevel@tonic-gate  */
7897c478bd9Sstevel@tonic-gate void
rfs4_servinst_create(nfs4_srv_t * nsrv4,int start_grace,int dss_npaths,char ** dss_paths)7900dfe541eSEvan Layton rfs4_servinst_create(nfs4_srv_t *nsrv4, int start_grace,
7910dfe541eSEvan Layton     int dss_npaths, char **dss_paths)
7927c478bd9Sstevel@tonic-gate {
793cee86682Scalum 	unsigned i;
7947c478bd9Sstevel@tonic-gate 	rfs4_servinst_t *sip;
795cee86682Scalum 	rfs4_oldstate_t *oldstate;
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 	sip = kmem_alloc(sizeof (rfs4_servinst_t), KM_SLEEP);
7987c478bd9Sstevel@tonic-gate 	rw_init(&sip->rwlock, NULL, RW_DEFAULT, NULL);
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	sip->start_time = (time_t)0;
8017c478bd9Sstevel@tonic-gate 	sip->grace_period = (time_t)0;
8027c478bd9Sstevel@tonic-gate 	sip->next = NULL;
8037c478bd9Sstevel@tonic-gate 	sip->prev = NULL;
8047c478bd9Sstevel@tonic-gate 
805cee86682Scalum 	rw_init(&sip->oldstate_lock, NULL, RW_DEFAULT, NULL);
806cee86682Scalum 	/*
807cee86682Scalum 	 * This initial dummy entry is required to setup for insque/remque.
808cee86682Scalum 	 * It must be skipped over whenever the list is traversed.
809cee86682Scalum 	 */
810cee86682Scalum 	oldstate = kmem_alloc(sizeof (rfs4_oldstate_t), KM_SLEEP);
811cee86682Scalum 	/* insque/remque require initial list entry to be self-terminated */
812cee86682Scalum 	oldstate->next = oldstate;
813cee86682Scalum 	oldstate->prev = oldstate;
814cee86682Scalum 	sip->oldstate = oldstate;
815cee86682Scalum 
816cee86682Scalum 
817cee86682Scalum 	sip->dss_npaths = dss_npaths;
818cee86682Scalum