xref: /illumos-gate/usr/src/cmd/fs.d/nfs/nfsd/nfsd.c (revision 201f5eba)
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 /*
229ff75adeSSurya Prakki  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T		*/
267c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
307c478bd9Sstevel@tonic-gate  * The Regents of the University of California
317c478bd9Sstevel@tonic-gate  * All Rights Reserved
327c478bd9Sstevel@tonic-gate  *
337c478bd9Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
347c478bd9Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
357c478bd9Sstevel@tonic-gate  * contributors.
367c478bd9Sstevel@tonic-gate  */
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate /* LINTLIBRARY */
397c478bd9Sstevel@tonic-gate /* PROTOLIB1 */
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate /* NFS server */
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #include <sys/param.h>
447c478bd9Sstevel@tonic-gate #include <sys/types.h>
45cee86682Scalum #include <sys/stat.h>
467c478bd9Sstevel@tonic-gate #include <syslog.h>
477c478bd9Sstevel@tonic-gate #include <tiuser.h>
487c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
497c478bd9Sstevel@tonic-gate #include <errno.h>
507c478bd9Sstevel@tonic-gate #include <thread.h>
517c478bd9Sstevel@tonic-gate #include <sys/resource.h>
527c478bd9Sstevel@tonic-gate #include <sys/time.h>
537c478bd9Sstevel@tonic-gate #include <sys/file.h>
547c478bd9Sstevel@tonic-gate #include <nfs/nfs.h>
557c478bd9Sstevel@tonic-gate #include <nfs/nfs_acl.h>
567c478bd9Sstevel@tonic-gate #include <nfs/nfssys.h>
577c478bd9Sstevel@tonic-gate #include <stdio.h>
58004388ebScasper #include <stdio_ext.h>
597c478bd9Sstevel@tonic-gate #include <stdlib.h>
607c478bd9Sstevel@tonic-gate #include <signal.h>
617c478bd9Sstevel@tonic-gate #include <netconfig.h>
627c478bd9Sstevel@tonic-gate #include <netdir.h>
637c478bd9Sstevel@tonic-gate #include <string.h>
647c478bd9Sstevel@tonic-gate #include <unistd.h>
65dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include <limits.h>
667c478bd9Sstevel@tonic-gate #include <stropts.h>
677c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
68250a0733Sth199096 #include <sys/wait.h>
697c478bd9Sstevel@tonic-gate #include <poll.h>
707c478bd9Sstevel@tonic-gate #include <priv_utils.h>
717c478bd9Sstevel@tonic-gate #include <sys/tiuser.h>
727c478bd9Sstevel@tonic-gate #include <netinet/tcp.h>
737c478bd9Sstevel@tonic-gate #include <deflt.h>
747c478bd9Sstevel@tonic-gate #include <rpcsvc/daemon_utils.h>
757c478bd9Sstevel@tonic-gate #include <rpcsvc/nfs4_prot.h>
76cee86682Scalum #include <libnvpair.h>
77dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include <libscf.h>
78dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include <libshare.h>
797c478bd9Sstevel@tonic-gate #include "nfs_tbind.h"
807c478bd9Sstevel@tonic-gate #include "thrpool.h"
81dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include "smfcfg.h"
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /* quiesce requests will be ignored if nfs_server_vers_max < QUIESCE_VERSMIN */
847c478bd9Sstevel@tonic-gate #define	QUIESCE_VERSMIN	4
85cee86682Scalum /* DSS: distributed stable storage */
86cee86682Scalum #define	DSS_VERSMIN	4
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate static	int	nfssvc(int, struct netbuf, struct netconfig *);
897c478bd9Sstevel@tonic-gate static	int	nfssvcpool(int maxservers);
90cee86682Scalum static	int	dss_init(uint_t npaths, char **pathnames);
91cee86682Scalum static	void	dss_mkleafdirs(uint_t npaths, char **pathnames);
92cee86682Scalum static	void	dss_mkleafdir(char *dir, char *leaf, char *path);
937c478bd9Sstevel@tonic-gate static	void	usage(void);
94cee86682Scalum int		qstrcmp(const void *s1, const void *s2);
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate extern	int	_nfssys(int, void *);
977c478bd9Sstevel@tonic-gate 
98250a0733Sth199096 extern int	daemonize_init(void);
99250a0733Sth199096 extern void	daemonize_fini(int fd);
100250a0733Sth199096 
1017c478bd9Sstevel@tonic-gate /* signal handlers */
1027c478bd9Sstevel@tonic-gate static void sigflush(int);
1037c478bd9Sstevel@tonic-gate static void quiesce(int);
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate static	char	*MyName;
1067c478bd9Sstevel@tonic-gate static	NETSELDECL(defaultproviders)[] = { "/dev/tcp6", "/dev/tcp", "/dev/udp",
1077c478bd9Sstevel@tonic-gate 					    "/dev/udp6", NULL };
1087c478bd9Sstevel@tonic-gate /* static	NETSELDECL(defaultprotos)[] =	{ NC_UDP, NC_TCP, NULL }; */
1097c478bd9Sstevel@tonic-gate /*
1107c478bd9Sstevel@tonic-gate  * The following are all globals used by routines in nfs_tbind.c.
1117c478bd9Sstevel@tonic-gate  */
1127c478bd9Sstevel@tonic-gate size_t	end_listen_fds;		/* used by conn_close_oldest() */
1137c478bd9Sstevel@tonic-gate size_t	num_fds = 0;		/* used by multiple routines */
1147c478bd9Sstevel@tonic-gate int	listen_backlog = 32;	/* used by bind_to_{provider,proto}() */
1157c478bd9Sstevel@tonic-gate int	num_servers;		/* used by cots_listen_event() */
1167c478bd9Sstevel@tonic-gate int	(*Mysvc)(int, struct netbuf, struct netconfig *) = nfssvc;
1177c478bd9Sstevel@tonic-gate 				/* used by cots_listen_event() */
1187c478bd9Sstevel@tonic-gate int	max_conns_allowed = -1;	/* used by cots_listen_event() */
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate /*
1217c478bd9Sstevel@tonic-gate  * Keep track of min/max versions of NFS protocol to be started.
1227c478bd9Sstevel@tonic-gate  * Start with the defaults (min == 2, max == 3).  We have the
1237c478bd9Sstevel@tonic-gate  * capability of starting vers=4 but only if the user requests it.
1247c478bd9Sstevel@tonic-gate  */
1257c478bd9Sstevel@tonic-gate int	nfs_server_vers_min = NFS_VERSMIN_DEFAULT;
1267c478bd9Sstevel@tonic-gate int	nfs_server_vers_max = NFS_VERSMAX_DEFAULT;
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate /*
1297c478bd9Sstevel@tonic-gate  * Set the default for server delegation enablement and set per
1307c478bd9Sstevel@tonic-gate  * /etc/default/nfs configuration (if present).
1317c478bd9Sstevel@tonic-gate  */
1327c478bd9Sstevel@tonic-gate int	nfs_server_delegation = NFS_SERVER_DELEGATION_DEFAULT;
1337c478bd9Sstevel@tonic-gate 
13411606941Sjwahlig int
13511606941Sjwahlig main(int ac, char *av[])
1367c478bd9Sstevel@tonic-gate {
1377c478bd9Sstevel@tonic-gate 	char *dir = "/";
1387c478bd9Sstevel@tonic-gate 	int allflag = 0;
1397c478bd9Sstevel@tonic-gate 	int df_allflag = 0;
1407c478bd9Sstevel@tonic-gate 	int opt_cnt = 0;
141*201f5ebaSSebastien Roy 	int maxservers = 1024;	/* zero allows inifinte number of threads */
1427c478bd9Sstevel@tonic-gate 	int maxservers_set = 0;
1437c478bd9Sstevel@tonic-gate 	int logmaxservers = 0;
1447c478bd9Sstevel@tonic-gate 	int pid;
1457c478bd9Sstevel@tonic-gate 	int i;
1467c478bd9Sstevel@tonic-gate 	char *provider = (char *)NULL;
1477c478bd9Sstevel@tonic-gate 	char *df_provider = (char *)NULL;
1487c478bd9Sstevel@tonic-gate 	struct protob *protobp0, *protobp;
1497c478bd9Sstevel@tonic-gate 	NETSELDECL(proto) = NULL;
1507c478bd9Sstevel@tonic-gate 	NETSELDECL(df_proto) = NULL;
1517c478bd9Sstevel@tonic-gate 	NETSELPDECL(providerp);
1527c478bd9Sstevel@tonic-gate 	char *defval;
15345916cd2Sjpk 	boolean_t can_do_mlp;
154cee86682Scalum 	uint_t dss_npaths = 0;
155cee86682Scalum 	char **dss_pathnames = NULL;
156e8279403Smaheshvs 	sigset_t sgset;
157dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	char name[PATH_MAX], value[PATH_MAX];
158dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	int ret, bufsz;
1597c478bd9Sstevel@tonic-gate 
160250a0733Sth199096 	int pipe_fd = -1;
161250a0733Sth199096 
1627c478bd9Sstevel@tonic-gate 	MyName = *av;
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	/*
1657c478bd9Sstevel@tonic-gate 	 * Initializations that require more privileges than we need to run.
1667c478bd9Sstevel@tonic-gate 	 */
1677c478bd9Sstevel@tonic-gate 	(void) _create_daemon_lock(NFSD, DAEMON_UID, DAEMON_GID);
1687c478bd9Sstevel@tonic-gate 	svcsetprio();
1697c478bd9Sstevel@tonic-gate 
17045916cd2Sjpk 	can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
1717c478bd9Sstevel@tonic-gate 	if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET,
17245916cd2Sjpk 	    DAEMON_UID, DAEMON_GID, PRIV_SYS_NFS,
17345916cd2Sjpk 	    can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) {
1747c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s should be run with"
1757c478bd9Sstevel@tonic-gate 		    " sufficient privileges\n", av[0]);
1767c478bd9Sstevel@tonic-gate 		exit(1);
1777c478bd9Sstevel@tonic-gate 	}
1787c478bd9Sstevel@tonic-gate 
179004388ebScasper 	(void) enable_extended_FILE_stdio(-1, -1);
180004388ebScasper 
1817c478bd9Sstevel@tonic-gate 	/*
182dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	 * Read in the values from SMF first before we check
183dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	 * command line options so the options override SMF values.
1847c478bd9Sstevel@tonic-gate 	 */
185dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	bufsz = PATH_MAX;
186dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	ret = nfs_smf_get_prop("max_connections", value, DEFAULT_INSTANCE,
187dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	    SCF_TYPE_INTEGER, NFSD, &bufsz);
188dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	if (ret == SA_OK) {
1897c478bd9Sstevel@tonic-gate 		errno = 0;
190dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 		max_conns_allowed = strtol(value, (char **)NULL, 10);
191dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 		if (errno != 0)
1927c478bd9Sstevel@tonic-gate 			max_conns_allowed = -1;
1937c478bd9Sstevel@tonic-gate 	}
194dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 
195dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	bufsz = PATH_MAX;
196dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	ret = nfs_smf_get_prop("listen_backlog", value, DEFAULT_INSTANCE,
197dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	    SCF_TYPE_INTEGER, NFSD, &bufsz);
198dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	if (ret == SA_OK) {
1997c478bd9Sstevel@tonic-gate 		errno = 0;
200dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 		listen_backlog = strtol(value, (char **)NULL, 10);
2017c478bd9Sstevel@tonic-gate 		if (errno != 0) {
2027c478bd9Sstevel@tonic-gate 			listen_backlog = 32;
2037c478bd9Sstevel@tonic-gate 		}
2047c478bd9Sstevel@tonic-gate 	}
205dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 
206dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	bufsz = PATH_MAX;
207dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	ret = nfs_smf_get_prop("protocol", value, DEFAULT_INSTANCE,
208dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	    SCF_TYPE_ASTRING, NFSD, &bufsz);
209dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	if ((ret == SA_OK) && strlen(value) > 0) {
210dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 		df_proto = strdup(value);
2117c478bd9Sstevel@tonic-gate 		opt_cnt++;
212dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 		if (strncasecmp("ALL", value, 3) == 0) {
2137c478bd9Sstevel@tonic-gate 			free(df_proto);
2147c478bd9Sstevel@tonic-gate 			df_proto = NULL;
2157c478bd9Sstevel@tonic-gate 			df_allflag = 1;
2167c478bd9Sstevel@tonic-gate 		}
2177c478bd9Sstevel@tonic-gate 	}
218dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 
219dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	bufsz = PATH_MAX;
220dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	ret = nfs_smf_get_prop("device", value, DEFAULT_INSTANCE,
221dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	    SCF_TYPE_ASTRING, NFSD, &bufsz);
222dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	if ((ret == SA_OK) && strlen(value) > 0) {
223dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 		df_provider = strdup(value);
2247c478bd9Sstevel@tonic-gate 		opt_cnt++;
2257c478bd9Sstevel@tonic-gate 	}
226dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 
227dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	bufsz = PATH_MAX;
228dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	ret = nfs_smf_get_prop("servers", value, DEFAULT_INSTANCE,
229dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	    SCF_TYPE_INTEGER, NFSD, &bufsz);
230dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	if (ret == SA_OK) {
2317c478bd9Sstevel@tonic-gate 		errno = 0;
232dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 		maxservers = strtol(value, (char **)NULL, 10);
233dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 		if (errno != 0)
234*201f5ebaSSebastien Roy 			maxservers = 1024;
235dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 		else
2367c478bd9Sstevel@tonic-gate 			maxservers_set = 1;
2377c478bd9Sstevel@tonic-gate 	}
2387c478bd9Sstevel@tonic-gate 
239dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	bufsz = 4;
240dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	ret = nfs_smf_get_prop("server_versmin", value, DEFAULT_INSTANCE,
241dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	    SCF_TYPE_INTEGER, NFSD, &bufsz);
242dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	if (ret == SA_OK)
243dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 		nfs_server_vers_min = strtol(value, (char **)NULL, 10);
244dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 
245dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	bufsz = 4;
246dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	ret = nfs_smf_get_prop("server_versmax", value, DEFAULT_INSTANCE,
247dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	    SCF_TYPE_INTEGER, NFSD, &bufsz);
248dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	if (ret == SA_OK)
249dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 		nfs_server_vers_max = strtol(value, (char **)NULL, 10);
250dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 
251dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	bufsz = PATH_MAX;
252dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	ret = nfs_smf_get_prop("server_delegation", value, DEFAULT_INSTANCE,
253dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	    SCF_TYPE_ASTRING, NFSD, &bufsz);
254dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	if (ret == SA_OK)
255dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 		if (strncasecmp(value, "off", 3) == 0)
256dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 			nfs_server_delegation = FALSE;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	/*
2597c478bd9Sstevel@tonic-gate 	 * Conflict options error messages.
2607c478bd9Sstevel@tonic-gate 	 */
2617c478bd9Sstevel@tonic-gate 	if (opt_cnt > 1) {
2627c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "\nConflicting options, only one of "
2637c478bd9Sstevel@tonic-gate 		    "the following options can be specified\n"
264dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 		    "in SMF:\n"
265dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 		    "\tprotocol=ALL\n"
266dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 		    "\tprotocol=protocol\n"
267dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 		    "\tdevice=devicename\n\n");
2687c478bd9Sstevel@tonic-gate 		usage();
2697c478bd9Sstevel@tonic-gate 	}
2707c478bd9Sstevel@tonic-gate 	opt_cnt = 0;
2717c478bd9Sstevel@tonic-gate 
272cee86682Scalum 	while ((i = getopt(ac, av, "ac:p:s:t:l:")) != EOF) {
2737c478bd9Sstevel@tonic-gate 		switch (i) {
2747c478bd9Sstevel@tonic-gate 		case 'a':
2757c478bd9Sstevel@tonic-gate 			free(df_proto);
2767c478bd9Sstevel@tonic-gate 			df_proto = NULL;
2777c478bd9Sstevel@tonic-gate 			free(df_provider);
2787c478bd9Sstevel@tonic-gate 			df_provider = NULL;
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 			allflag = 1;
2817c478bd9Sstevel@tonic-gate 			opt_cnt++;
2827c478bd9Sstevel@tonic-gate 			break;
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 		case 'c':
2857c478bd9Sstevel@tonic-gate 			max_conns_allowed = atoi(optarg);
2867c478bd9Sstevel@tonic-gate 			break;
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 		case 'p':
2897c478bd9Sstevel@tonic-gate 			proto = optarg;
2907c478bd9Sstevel@tonic-gate 			df_allflag = 0;
2917c478bd9Sstevel@tonic-gate 			opt_cnt++;
2927c478bd9Sstevel@tonic-gate 			break;
2937c478bd9Sstevel@tonic-gate 
294cee86682Scalum 		/*
295cee86682Scalum 		 * DSS: NFSv4 distributed stable storage.
296cee86682Scalum 		 *
297cee86682Scalum 		 * This is a Contracted Project Private interface, for
298cee86682Scalum 		 * the sole use of Sun Cluster HA-NFS. See PSARC/2006/313.
299cee86682Scalum 		 */
300cee86682Scalum 		case 's':
301cee86682Scalum 			if (strlen(optarg) < MAXPATHLEN) {
302cee86682Scalum 				/* first "-s" option encountered? */
303cee86682Scalum 				if (dss_pathnames == NULL) {
304cee86682Scalum 					/*
305cee86682Scalum 					 * Allocate maximum possible space
306cee86682Scalum 					 * required given cmdline arg count;
307cee86682Scalum 					 * "-s <path>" consumes two args.
308cee86682Scalum 					 */
309cee86682Scalum 					size_t sz = (ac / 2) * sizeof (char *);
310cee86682Scalum 					dss_pathnames = (char **)malloc(sz);
311cee86682Scalum 					if (dss_pathnames == NULL) {
312cee86682Scalum 						(void) fprintf(stderr, "%s: "
313cee86682Scalum 						    "dss paths malloc failed\n",
314cee86682Scalum 						    av[0]);
315cee86682Scalum 						exit(1);
316cee86682Scalum 					}
317cee86682Scalum 					(void) memset(dss_pathnames, 0, sz);
318cee86682Scalum 				}
319cee86682Scalum 				dss_pathnames[dss_npaths] = optarg;
320cee86682Scalum 				dss_npaths++;
321cee86682Scalum 			} else {
322cee86682Scalum 				(void) fprintf(stderr,
323cee86682Scalum 				    "%s: -s pathname too long.\n", av[0]);
324cee86682Scalum 			}
325cee86682Scalum 			break;
326cee86682Scalum 
3277c478bd9Sstevel@tonic-gate 		case 't':
3287c478bd9Sstevel@tonic-gate 			provider = optarg;
3297c478bd9Sstevel@tonic-gate 			df_allflag = 0;
3307c478bd9Sstevel@tonic-gate 			opt_cnt++;
3317c478bd9Sstevel@tonic-gate 			break;
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 		case 'l':
3347c478bd9Sstevel@tonic-gate 			listen_backlog = atoi(optarg);
3357c478bd9Sstevel@tonic-gate 			break;
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 		case '?':
3387c478bd9Sstevel@tonic-gate 			usage();
3397c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
3407c478bd9Sstevel@tonic-gate 		}
3417c478bd9Sstevel@tonic-gate 	}
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	allflag = df_allflag;
3447c478bd9Sstevel@tonic-gate 	if (proto == NULL)
3457c478bd9Sstevel@tonic-gate 		proto = df_proto;
3467c478bd9Sstevel@tonic-gate 	if (provider == NULL)
3477c478bd9Sstevel@tonic-gate 		provider = df_provider;
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	/*
3507c478bd9Sstevel@tonic-gate 	 * Conflict options error messages.
3517c478bd9Sstevel@tonic-gate 	 */
3527c478bd9Sstevel@tonic-gate 	if (opt_cnt > 1) {
3537c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "\nConflicting options, only one of "
3547c478bd9Sstevel@tonic-gate 		    "the following options can be specified\n"
3557c478bd9Sstevel@tonic-gate 		    "on the command line:\n"
3567c478bd9Sstevel@tonic-gate 		    "\t-a\n"
3577c478bd9Sstevel@tonic-gate 		    "\t-p protocol\n"
3587c478bd9Sstevel@tonic-gate 		    "\t-t transport\n\n");
3597c478bd9Sstevel@tonic-gate 		usage();
3607c478bd9Sstevel@tonic-gate 	}
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	if (proto != NULL &&
3637c478bd9Sstevel@tonic-gate 	    strncasecmp(proto, NC_UDP, strlen(NC_UDP)) == 0) {
3647c478bd9Sstevel@tonic-gate 		if (nfs_server_vers_max == NFS_V4) {
3657c478bd9Sstevel@tonic-gate 			if (nfs_server_vers_min == NFS_V4) {
3667c478bd9Sstevel@tonic-gate 				fprintf(stderr,
3677c478bd9Sstevel@tonic-gate 				    "NFS version 4 is not supported "
3687c478bd9Sstevel@tonic-gate 				    "with the UDP protocol.  Exiting\n");
3697c478bd9Sstevel@tonic-gate 				exit(3);
3707c478bd9Sstevel@tonic-gate 			} else {
3717c478bd9Sstevel@tonic-gate 				fprintf(stderr,
3727c478bd9Sstevel@tonic-gate 				    "NFS version 4 is not supported "
3737c478bd9Sstevel@tonic-gate 				    "with the UDP protocol.\n");
3747c478bd9Sstevel@tonic-gate 			}
3757c478bd9Sstevel@tonic-gate 		}
3767c478bd9Sstevel@tonic-gate 	}
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 	/*
3797c478bd9Sstevel@tonic-gate 	 * If there is exactly one more argument, it is the number of
3807c478bd9Sstevel@tonic-gate 	 * servers.
3817c478bd9Sstevel@tonic-gate 	 */
3827c478bd9Sstevel@tonic-gate 	if (optind == ac - 1) {
3837c478bd9Sstevel@tonic-gate 		maxservers = atoi(av[optind]);
3847c478bd9Sstevel@tonic-gate 		maxservers_set = 1;
3857c478bd9Sstevel@tonic-gate 	}
3867c478bd9Sstevel@tonic-gate 	/*
3877c478bd9Sstevel@tonic-gate 	 * If there are two or more arguments, then this is a usage error.
3887c478bd9Sstevel@tonic-gate 	 */
3897c478bd9Sstevel@tonic-gate 	else if (optind < ac - 1)
3907c478bd9Sstevel@tonic-gate 		usage();
3917c478bd9Sstevel@tonic-gate 	/*
3927c478bd9Sstevel@tonic-gate 	 * Check the ranges for min/max version specified
3937c478bd9Sstevel@tonic-gate 	 */
3947c478bd9Sstevel@tonic-gate 	else if ((nfs_server_vers_min > nfs_server_vers_max) ||
3957c478bd9Sstevel@tonic-gate 	    (nfs_server_vers_min < NFS_VERSMIN) ||
3967c478bd9Sstevel@tonic-gate 	    (nfs_server_vers_max > NFS_VERSMAX))
3977c478bd9Sstevel@tonic-gate 		usage();
3987c478bd9Sstevel@tonic-gate 	/*
3997c478bd9Sstevel@tonic-gate 	 * There are no additional arguments, and we haven't set maxservers
4007c478bd9Sstevel@tonic-gate 	 * explicitly via the config file, we use a default number of
4017c478bd9Sstevel@tonic-gate 	 * servers.  We will log this.
4027c478bd9Sstevel@tonic-gate 	 */
4037c478bd9Sstevel@tonic-gate 	else if (maxservers_set == 0)
4047c478bd9Sstevel@tonic-gate 		logmaxservers = 1;
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	/*
4077c478bd9Sstevel@tonic-gate 	 * Basic Sanity checks on options
4087c478bd9Sstevel@tonic-gate 	 *
4097c478bd9Sstevel@tonic-gate 	 * max_conns_allowed must be positive, except for the special
4107c478bd9Sstevel@tonic-gate 	 * value of -1 which is used internally to mean unlimited, -1 isn't
4117c478bd9Sstevel@tonic-gate 	 * documented but we allow it anyway.
4127c478bd9Sstevel@tonic-gate 	 *
4137c478bd9Sstevel@tonic-gate 	 * maxservers must be positive
4147c478bd9Sstevel@tonic-gate 	 * listen_backlog must be positive or zero
4157c478bd9Sstevel@tonic-gate 	 */
4167c478bd9Sstevel@tonic-gate 	if (((max_conns_allowed != -1) && (max_conns_allowed <= 0)) ||
4177c478bd9Sstevel@tonic-gate 	    (listen_backlog < 0) || (maxservers <= 0)) {
4187c478bd9Sstevel@tonic-gate 		usage();
4197c478bd9Sstevel@tonic-gate 	}
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	/*
4227c478bd9Sstevel@tonic-gate 	 * Set current dir to server root
4237c478bd9Sstevel@tonic-gate 	 */
4247c478bd9Sstevel@tonic-gate 	if (chdir(dir) < 0) {
4257c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s:  ", MyName);
4267c478bd9Sstevel@tonic-gate 		perror(dir);
4277c478bd9Sstevel@tonic-gate 		exit(1);
4287c478bd9Sstevel@tonic-gate 	}
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate #ifndef DEBUG
431250a0733Sth199096 	pipe_fd = daemonize_init();
4327c478bd9Sstevel@tonic-gate #endif
433250a0733Sth199096 
4347c478bd9Sstevel@tonic-gate 	openlog(MyName, LOG_PID | LOG_NDELAY, LOG_DAEMON);
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	/*
4377c478bd9Sstevel@tonic-gate 	 * establish our lock on the lock file and write our pid to it.
4387c478bd9Sstevel@tonic-gate 	 * exit if some other process holds the lock, or if there's any
4397c478bd9Sstevel@tonic-gate 	 * error in writing/locking the file.
4407c478bd9Sstevel@tonic-gate 	 */
4417c478bd9Sstevel@tonic-gate 	pid = _enter_daemon_lock(NFSD);
4427c478bd9Sstevel@tonic-gate 	switch (pid) {
4437c478bd9Sstevel@tonic-gate 	case 0:
4447c478bd9Sstevel@tonic-gate 		break;
4457c478bd9Sstevel@tonic-gate 	case -1:
446b9709d3bSYuri Pankov 		fprintf(stderr, "error locking for %s: %s\n", NFSD,
4477c478bd9Sstevel@tonic-gate 		    strerror(errno));
4487c478bd9Sstevel@tonic-gate 		exit(2);
4497c478bd9Sstevel@tonic-gate 	default:
4507c478bd9Sstevel@tonic-gate 		/* daemon was already running */
4517c478bd9Sstevel@tonic-gate 		exit(0);
4527c478bd9Sstevel@tonic-gate 	}
4537c478bd9Sstevel@tonic-gate 
454cee86682Scalum 	/*
455cee86682Scalum 	 * If we've been given a list of paths to be used for distributed
456cee86682Scalum 	 * stable storage, and provided we're going to run a version
457cee86682Scalum 	 * that supports it, setup the DSS paths.
458cee86682Scalum 	 */
459cee86682Scalum 	if (dss_pathnames != NULL && nfs_server_vers_max >= DSS_VERSMIN) {
460cee86682Scalum 		if (dss_init(dss_npaths, dss_pathnames) != 0) {
461b9709d3bSYuri Pankov 			fprintf(stderr, "%s", "dss_init failed. Exiting.\n");
462cee86682Scalum 			exit(1);
463cee86682Scalum 		}
464cee86682Scalum 	}
465cee86682Scalum 
466e8279403Smaheshvs 	/*
467e8279403Smaheshvs 	 * Block all signals till we spawn other
468e8279403Smaheshvs 	 * threads.
469e8279403Smaheshvs 	 */
470e8279403Smaheshvs 	(void) sigfillset(&sgset);
471e8279403Smaheshvs 	(void) thr_sigsetmask(SIG_BLOCK, &sgset, NULL);
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	if (logmaxservers) {
474250a0733Sth199096 		fprintf(stderr,
475b9709d3bSYuri Pankov 		    "Number of servers not specified. Using default of %d.\n",
4767c478bd9Sstevel@tonic-gate 		    maxservers);
4777c478bd9Sstevel@tonic-gate 	}
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	/*
4807c478bd9Sstevel@tonic-gate 	 * Make sure to unregister any previous versions in case the
4817c478bd9Sstevel@tonic-gate 	 * user is reconfiguring the server in interesting ways.
4827c478bd9Sstevel@tonic-gate 	 */
4837c478bd9Sstevel@tonic-gate 	svc_unreg(NFS_PROGRAM, NFS_VERSION);
4847c478bd9Sstevel@tonic-gate 	svc_unreg(NFS_PROGRAM, NFS_V3);
4857c478bd9Sstevel@tonic-gate 	svc_unreg(NFS_PROGRAM, NFS_V4);
4867c478bd9Sstevel@tonic-gate 	svc_unreg(NFS_ACL_PROGRAM, NFS_ACL_V2);
4877c478bd9Sstevel@tonic-gate 	svc_unreg(NFS_ACL_PROGRAM, NFS_ACL_V3);
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	/*
4907c478bd9Sstevel@tonic-gate 	 * Set up kernel RPC thread pool for the NFS server.
4917c478bd9Sstevel@tonic-gate 	 */
4927c478bd9Sstevel@tonic-gate 	if (nfssvcpool(maxservers)) {
493b9709d3bSYuri Pankov 		fprintf(stderr, "Can't set up kernel NFS service: %s. "
494b9709d3bSYuri Pankov 		    "Exiting.\n", strerror(errno));
4957c478bd9Sstevel@tonic-gate 		exit(1);
4967c478bd9Sstevel@tonic-gate 	}
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 	/*
4997c478bd9Sstevel@tonic-gate 	 * Set up blocked thread to do LWP creation on behalf of the kernel.
5007c478bd9Sstevel@tonic-gate 	 */
5017c478bd9Sstevel@tonic-gate 	if (svcwait(NFS_SVCPOOL_ID)) {
502b9709d3bSYuri Pankov 		fprintf(stderr, "Can't set up NFS pool creator: %s. Exiting.\n",
503250a0733Sth199096 		    strerror(errno));
5047c478bd9Sstevel@tonic-gate 		exit(1);
5057c478bd9Sstevel@tonic-gate 	}
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	/*
5087c478bd9Sstevel@tonic-gate 	 * RDMA start and stop thread.
5097c478bd9Sstevel@tonic-gate 	 * Per pool RDMA listener creation and
5107c478bd9Sstevel@tonic-gate 	 * destructor thread.
5117c478bd9Sstevel@tonic-gate 	 *
5127c478bd9Sstevel@tonic-gate 	 * start rdma services and block in the kernel.
513ed629aefSSiddheshwar Mahesh 	 * (only if proto or provider is not set to TCP or UDP)
5147c478bd9Sstevel@tonic-gate 	 */
515ed629aefSSiddheshwar Mahesh 	if ((proto == NULL) && (provider == NULL)) {
516ed629aefSSiddheshwar Mahesh 		if (svcrdma(NFS_SVCPOOL_ID, nfs_server_vers_min,
517ed629aefSSiddheshwar Mahesh 		    nfs_server_vers_max, nfs_server_delegation)) {
518ed629aefSSiddheshwar Mahesh 			fprintf(stderr,
519b9709d3bSYuri Pankov 			    "Can't set up RDMA creator thread : %s\n",
520250a0733Sth199096 			    strerror(errno));
5217c478bd9Sstevel@tonic-gate 		}
522ed629aefSSiddheshwar Mahesh 	}
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	/*
525e8279403Smaheshvs 	 * Now open up for signal delivery
526e8279403Smaheshvs 	 */
527e8279403Smaheshvs 
528e8279403Smaheshvs 	(void) thr_sigsetmask(SIG_UNBLOCK, &sgset, NULL);
529e8279403Smaheshvs 	sigset(SIGTERM, sigflush);
530e8279403Smaheshvs 	sigset(SIGUSR1, quiesce);
531e8279403Smaheshvs 
532e8279403Smaheshvs 	/*
5337c478bd9Sstevel@tonic-gate 	 * Build a protocol block list for registration.
5347c478bd9Sstevel@tonic-gate 	 */
5357c478bd9Sstevel@tonic-gate 	protobp0 = protobp = (struct protob *)malloc(sizeof (struct protob));
5367c478bd9Sstevel@tonic-gate 	protobp->serv = "NFS";
5377c478bd9Sstevel@tonic-gate 	protobp->versmin = nfs_server_vers_min;
5387c478bd9Sstevel@tonic-gate 	protobp->versmax = nfs_server_vers_max;
5397c478bd9Sstevel@tonic-gate 	protobp->program = NFS_PROGRAM;
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	protobp->next = (struct protob *)malloc(sizeof (struct protob));
5427c478bd9Sstevel@tonic-gate 	protobp = protobp->next;
5437c478bd9Sstevel@tonic-gate 	protobp->serv = "NFS_ACL";		/* not used */
5447c478bd9Sstevel@tonic-gate 	protobp->versmin = nfs_server_vers_min;
5457c478bd9Sstevel@tonic-gate 	/* XXX - this needs work to get the version just right */
5467c478bd9Sstevel@tonic-gate 	protobp->versmax = (nfs_server_vers_max > NFS_ACL_V3) ?
5477c478bd9Sstevel@tonic-gate 	    NFS_ACL_V3 : nfs_server_vers_max;
5487c478bd9Sstevel@tonic-gate 	protobp->program = NFS_ACL_PROGRAM;
5497c478bd9Sstevel@tonic-gate 	protobp->next = (struct protob *)NULL;
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	if (allflag) {
5529ff75adeSSurya Prakki 		if (do_all(protobp0, nfssvc) == -1) {
553b9709d3bSYuri Pankov 			fprintf(stderr, "setnetconfig failed : %s\n",
554250a0733Sth199096 			    strerror(errno));
5557c478bd9Sstevel@tonic-gate 			exit(1);
556250a0733Sth199096 		}
5577c478bd9Sstevel@tonic-gate 	} else if (proto) {
5587c478bd9Sstevel@tonic-gate 		/* there's more than one match for the same protocol */
5597c478bd9Sstevel@tonic-gate 		struct netconfig *nconf;
5607c478bd9Sstevel@tonic-gate 		NCONF_HANDLE *nc;
5617c478bd9Sstevel@tonic-gate 		bool_t	protoFound = FALSE;
5627c478bd9Sstevel@tonic-gate 		if ((nc = setnetconfig()) == (NCONF_HANDLE *) NULL) {
563b9709d3bSYuri Pankov 			fprintf(stderr, "setnetconfig failed : %s\n",
564250a0733Sth199096 			    strerror(errno));
5657c478bd9Sstevel@tonic-gate 			goto done;
5667c478bd9Sstevel@tonic-gate 		}
5677c478bd9Sstevel@tonic-gate 		while (nconf = getnetconfig(nc)) {
5687c478bd9Sstevel@tonic-gate 			if (strcmp(nconf->nc_proto, proto) == 0) {
5697c478bd9Sstevel@tonic-gate 				protoFound = TRUE;
5707c478bd9Sstevel@tonic-gate 				do_one(nconf->nc_device, NULL,
5719ff75adeSSurya Prakki 				    protobp0, nfssvc);
5727c478bd9Sstevel@tonic-gate 			}
5737c478bd9Sstevel@tonic-gate 		}
5747c478bd9Sstevel@tonic-gate 		(void) endnetconfig(nc);
575250a0733Sth199096 		if (protoFound == FALSE) {
576250a0733Sth199096 			fprintf(stderr,
577b9709d3bSYuri Pankov 			    "couldn't find netconfig entry for protocol %s\n",
578250a0733Sth199096 			    proto);
579250a0733Sth199096 		}
5807c478bd9Sstevel@tonic-gate 	} else if (provider)
5819ff75adeSSurya Prakki 		do_one(provider, proto, protobp0, nfssvc);
5827c478bd9Sstevel@tonic-gate 	else {
5837c478bd9Sstevel@tonic-gate 		for (providerp = defaultproviders;
5847c478bd9Sstevel@tonic-gate 		    *providerp != NULL; providerp++) {
5857c478bd9Sstevel@tonic-gate 			provider = *providerp;
5869ff75adeSSurya Prakki 			do_one(provider, NULL, protobp0, nfssvc);
5877c478bd9Sstevel@tonic-gate 		}
5887c478bd9Sstevel@tonic-gate 	}
5897c478bd9Sstevel@tonic-gate done:
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	free(protobp);
5927c478bd9Sstevel@tonic-gate 	free(protobp0);
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	if (num_fds == 0) {
595250a0733Sth199096 		fprintf(stderr, "Could not start NFS service for any protocol."
596b9709d3bSYuri Pankov 		    " Exiting.\n");
5977c478bd9Sstevel@tonic-gate 		exit(1);
5987c478bd9Sstevel@tonic-gate 	}
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate 	end_listen_fds = num_fds;
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	/*
603250a0733Sth199096 	 * nfsd is up and running as far as we are concerned.
604250a0733Sth199096 	 */
605250a0733Sth199096 	daemonize_fini(pipe_fd);
606250a0733Sth199096 
607250a0733Sth199096 	/*
6087c478bd9Sstevel@tonic-gate 	 * Get rid of unneeded privileges.
6097c478bd9Sstevel@tonic-gate 	 */
6107c478bd9Sstevel@tonic-gate 	__fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION,
6117c478bd9Sstevel@tonic-gate 	    PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL);
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	/*
6147c478bd9Sstevel@tonic-gate 	 * Poll for non-data control events on the transport descriptors.
6157c478bd9Sstevel@tonic-gate 	 */
6167c478bd9Sstevel@tonic-gate 	poll_for_action();
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	/*
6197c478bd9Sstevel@tonic-gate 	 * If we get here, something failed in poll_for_action().
6207c478bd9Sstevel@tonic-gate 	 */
6217c478bd9Sstevel@tonic-gate 	return (1);
6227c478bd9Sstevel@tonic-gate }
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate static int
6257c478bd9Sstevel@tonic-gate nfssvcpool(int maxservers)
6267c478bd9Sstevel@tonic-gate {
6277c478bd9Sstevel@tonic-gate 	struct svcpool_args npa;
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	npa.id = NFS_SVCPOOL_ID;
6307c478bd9Sstevel@tonic-gate 	npa.maxthreads = maxservers;
6317c478bd9Sstevel@tonic-gate 	npa.redline = 0;
6327c478bd9Sstevel@tonic-gate 	npa.qsize = 0;
6337c478bd9Sstevel@tonic-gate 	npa.timeout = 0;
6347c478bd9Sstevel@tonic-gate 	npa.stksize = 0;
6357c478bd9Sstevel@tonic-gate 	npa.max_same_xprt = 0;
6367c478bd9Sstevel@tonic-gate 	return (_nfssys(SVCPOOL_CREATE, &npa));
6377c478bd9Sstevel@tonic-gate }
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate /*
6407c478bd9Sstevel@tonic-gate  * Establish NFS service thread.
6417c478bd9Sstevel@tonic-gate  */
6427c478bd9Sstevel@tonic-gate static int
6437c478bd9Sstevel@tonic-gate nfssvc(int fd, struct netbuf addrmask, struct netconfig *nconf)
6447c478bd9Sstevel@tonic-gate {
6457c478bd9Sstevel@tonic-gate 	struct nfs_svc_args nsa;
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	nsa.fd = fd;
6487c478bd9Sstevel@tonic-gate 	nsa.netid = nconf->nc_netid;
6497c478bd9Sstevel@tonic-gate 	nsa.addrmask = addrmask;
6507c478bd9Sstevel@tonic-gate 	if (strncasecmp(nconf->nc_proto, NC_UDP, strlen(NC_UDP)) == 0) {
6517c478bd9Sstevel@tonic-gate 		nsa.versmax = (nfs_server_vers_max > NFS_V3) ?
6527c478bd9Sstevel@tonic-gate 		    NFS_V3 : nfs_server_vers_max;
6537c478bd9Sstevel@tonic-gate 		nsa.versmin = nfs_server_vers_min;
6547c478bd9Sstevel@tonic-gate 		/*
6557c478bd9Sstevel@tonic-gate 		 * If no version left, silently do nothing, previous
6567c478bd9Sstevel@tonic-gate 		 * checks will have assured at least TCP is available.
6577c478bd9Sstevel@tonic-gate 		 */
6587c478bd9Sstevel@tonic-gate 		if (nsa.versmin > nsa.versmax)
6597c478bd9Sstevel@tonic-gate 			return (0);
6607c478bd9Sstevel@tonic-gate 	} else {
6617c478bd9Sstevel@tonic-gate 		nsa.versmax = nfs_server_vers_max;
6627c478bd9Sstevel@tonic-gate 		nsa.versmin = nfs_server_vers_min;
6637c478bd9Sstevel@tonic-gate 	}
6647c478bd9Sstevel@tonic-gate 	nsa.delegation = nfs_server_delegation;
6657c478bd9Sstevel@tonic-gate 	return (_nfssys(NFS_SVC, &nsa));
6667c478bd9Sstevel@tonic-gate }
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate static void
6697c478bd9Sstevel@tonic-gate usage(void)
6707c478bd9Sstevel@tonic-gate {
6717c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
6727c478bd9Sstevel@tonic-gate "usage: %s [ -a ] [ -c max_conns ] [ -p protocol ] [ -t transport ] ", MyName);
6737c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\n[ -l listen_backlog ] [ nservers ]\n");
6747c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
6757c478bd9Sstevel@tonic-gate "\twhere -a causes <nservers> to be started on each appropriate transport,\n");
6767c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
6777c478bd9Sstevel@tonic-gate "\tmax_conns is the maximum number of concurrent connections allowed,\n");
6787c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\t\tand max_conns must be a decimal number");
6797c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "> zero,\n");
6807c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\tprotocol is a protocol identifier,\n");
6817c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
6827c478bd9Sstevel@tonic-gate 	    "\ttransport is a transport provider name (i.e. device),\n");
6837c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
6847c478bd9Sstevel@tonic-gate 	    "\tlisten_backlog is the TCP listen backlog,\n");
6857c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
6867c478bd9Sstevel@tonic-gate 	    "\tand <nservers> must be a decimal number > zero.\n");
6877c478bd9Sstevel@tonic-gate 	exit(1);
6887c478bd9Sstevel@tonic-gate }
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate /*
6917c478bd9Sstevel@tonic-gate  * Issue nfssys system call to flush all logging buffers asynchronously.
6927c478bd9Sstevel@tonic-gate  *
6937c478bd9Sstevel@tonic-gate  * NOTICE: It is extremely important to flush NFS logging buffers when
6947c478bd9Sstevel@tonic-gate  *	   nfsd exits. When the system is halted or rebooted nfslogd
6957c478bd9Sstevel@tonic-gate  *	   may not have an opportunity to flush the buffers.
6967c478bd9Sstevel@tonic-gate  */
6977c478bd9Sstevel@tonic-gate static void
6987c478bd9Sstevel@tonic-gate nfsl_flush()
6997c478bd9Sstevel@tonic-gate {
7007c478bd9Sstevel@tonic-gate 	struct nfsl_flush_args nfa;
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	memset((void *)&nfa, 0, sizeof (nfa));
7037c478bd9Sstevel@tonic-gate 	nfa.version = NFSL_FLUSH_ARGS_VERS;
7047c478bd9Sstevel@tonic-gate 	nfa.directive = NFSL_ALL;	/* flush all asynchronously */
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	if (_nfssys(LOG_FLUSH, &nfa) < 0)
7077c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "_nfssys(LOG_FLUSH) failed: %s\n",
7087c478bd9Sstevel@tonic-gate 		    strerror(errno));
7097c478bd9Sstevel@tonic-gate }
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate /*
7127c478bd9Sstevel@tonic-gate  * SIGTERM handler.
7137c478bd9Sstevel@tonic-gate  * Flush logging buffers and exit.
7147c478bd9Sstevel@tonic-gate  */
7157c478bd9Sstevel@tonic-gate static void
7167c478bd9Sstevel@tonic-gate sigflush(int sig)
7177c478bd9Sstevel@tonic-gate {
7187c478bd9Sstevel@tonic-gate 	nfsl_flush();
719e8279403Smaheshvs 	_exit(0);
7207c478bd9Sstevel@tonic-gate }
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate /*
7237c478bd9Sstevel@tonic-gate  * SIGUSR1 handler.
724cee86682Scalum  *
725cee86682Scalum  * Request that server quiesce, then (nfsd) exit. For subsequent warm start.
726cee86682Scalum  *
727cee86682Scalum  * This is a Contracted Project Private interface, for the sole use
728cee86682Scalum  * of Sun Cluster HA-NFS. See PSARC/2004/497.
729cee86682Scalum  *
7307c478bd9Sstevel@tonic-gate  * Equivalent to SIGTERM handler if nfs_server_vers_max < QUIESCE_VERSMIN.
7317c478bd9Sstevel@tonic-gate  */
7327c478bd9Sstevel@tonic-gate static void
7337c478bd9Sstevel@tonic-gate quiesce(int sig)
7347c478bd9Sstevel@tonic-gate {
7357c478bd9Sstevel@tonic-gate 	int error;
7367c478bd9Sstevel@tonic-gate 	int id = NFS_SVCPOOL_ID;
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 	if (nfs_server_vers_max >= QUIESCE_VERSMIN) {
7397c478bd9Sstevel@tonic-gate 		/* Request server quiesce at next shutdown */
740cee86682Scalum 		error = _nfssys(NFS4_SVC_REQUEST_QUIESCE, &id);
741fdd1ecaeSmaheshvs 
742fdd1ecaeSmaheshvs 		/*
743fdd1ecaeSmaheshvs 		 * ENOENT is returned if there is no matching SVC pool
744fdd1ecaeSmaheshvs 		 * for the id. Possibly because the pool is not yet setup.
745fdd1ecaeSmaheshvs 		 * In this case, just exit as if no error. For all other errors,
746fdd1ecaeSmaheshvs 		 * just return and allow caller to retry.
747fdd1ecaeSmaheshvs 		 */
748e8279403Smaheshvs 		if (error && errno != ENOENT) {
7497c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR,
750cee86682Scalum 			    "_nfssys(NFS4_SVC_REQUEST_QUIESCE) failed: %s",
7517c478bd9Sstevel@tonic-gate 			    strerror(errno));
7527c478bd9Sstevel@tonic-gate 			return;
7537c478bd9Sstevel@tonic-gate 		}
7547c478bd9Sstevel@tonic-gate 	}
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 	/* Flush logging buffers */
7577c478bd9Sstevel@tonic-gate 	nfsl_flush();
7587c478bd9Sstevel@tonic-gate 
759e8279403Smaheshvs 	_exit(0);
7607c478bd9Sstevel@tonic-gate }
761cee86682Scalum 
762cee86682Scalum /*
763cee86682Scalum  * DSS: distributed stable storage.
764cee86682Scalum  * Create leaf directories as required, keeping an eye on path
765cee86682Scalum  * lengths. Calls exit(1) on failure.
766cee86682Scalum  * The pathnames passed in must already exist, and must be writeable by nfsd.
767cee86682Scalum  * Note: the leaf directories under NFS4_VAR_DIR are not created here;
768cee86682Scalum  * they're created at pkg install.
769cee86682Scalum  */
770cee86682Scalum static void
771cee86682Scalum dss_mkleafdirs(uint_t npaths, char **pathnames)
772cee86682Scalum {
773cee86682Scalum 	int i;
774cee86682Scalum 	char *tmppath = NULL;
775cee86682Scalum 
776cee86682Scalum 	/*
777cee86682Scalum 	 * Create the temporary storage used by dss_mkleafdir() here,
778cee86682Scalum 	 * rather than in that function, so that it only needs to be
779cee86682Scalum 	 * done once, rather than once for each call. Too big to put
780cee86682Scalum 	 * on the function's stack.
781cee86682Scalum 	 */
782cee86682Scalum 	tmppath = (char *)malloc(MAXPATHLEN);
783cee86682Scalum 	if (tmppath == NULL) {
784cee86682Scalum 		syslog(LOG_ERR, "tmppath malloc failed. Exiting");
785cee86682Scalum 		exit(1);
786cee86682Scalum 	}
787cee86682Scalum 
788cee86682Scalum 	for (i = 0; i < npaths; i++) {
789cee86682Scalum 		char *p = pathnames[i];
790cee86682Scalum 
791cee86682Scalum 		dss_mkleafdir(p, NFS4_DSS_STATE_LEAF, tmppath);
792cee86682Scalum 		dss_mkleafdir(p, NFS4_DSS_OLDSTATE_LEAF, tmppath);
793cee86682Scalum 	}
794cee86682Scalum 
795cee86682Scalum 	free(tmppath);
796cee86682Scalum }
797cee86682Scalum 
798cee86682Scalum /*
799cee86682Scalum  * Create "leaf" in "dir" (which must already exist).
800cee86682Scalum  * leaf: should start with a '/'
801cee86682Scalum  */
802cee86682Scalum static void
803cee86682Scalum dss_mkleafdir(char *dir, char *leaf, char *tmppath)
804cee86682Scalum {
805cee86682Scalum 	/* MAXPATHLEN includes the terminating NUL */
806cee86682Scalum 	if (strlen(dir) + strlen(leaf) > MAXPATHLEN - 1) {
807b9709d3bSYuri Pankov 		fprintf(stderr, "stable storage path too long: %s%s. "
808b9709d3bSYuri Pankov 		    "Exiting.\n", dir, leaf);
809cee86682Scalum 		exit(1);
810cee86682Scalum 	}
811cee86682Scalum 
812cee86682Scalum 	(void) snprintf(tmppath, MAXPATHLEN, "%s/%s", dir, leaf);
813cee86682Scalum 
814cee86682Scalum 	/* the directory may already exist: that's OK */
815cee86682Scalum 	if (mkdir(tmppath, NFS4_DSS_DIR_MODE) == -1 && errno != EEXIST) {
816250a0733Sth199096 		fprintf(stderr, "error creating stable storage directory: "
817b9709d3bSYuri Pankov 		    "%s: %s. Exiting.\n", strerror(errno), tmppath);
818cee86682Scalum 		exit(1);
819cee86682Scalum 	}
820cee86682Scalum }
821cee86682Scalum 
822cee86682Scalum /*
823cee86682Scalum  * Create the storage dirs, and pass the path list to the kernel.
824cee86682Scalum  * This requires the nfssrv module to be loaded; the _nfssys() syscall
825cee86682Scalum  * will fail ENOTSUP if it is not.
826cee86682Scalum  * Use libnvpair(3LIB) to pass the data to the kernel.
827cee86682Scalum  */
828cee86682Scalum static int
829cee86682Scalum dss_init(uint_t npaths, char **pathnames)
830cee86682Scalum {
831cee86682Scalum 	int i, j, nskipped, error;
832cee86682Scalum 	char *bufp;
833cee86682Scalum 	uint32_t bufsize;
834cee86682Scalum 	size_t buflen;
835cee86682Scalum 	nvlist_t *nvl;
836cee86682Scalum 
837cee86682Scalum 	if (npaths > 1) {
838cee86682Scalum 		/*
839cee86682Scalum 		 * We need to remove duplicate paths; this might be user error
840cee86682Scalum 		 * in the general case, but HA-NFSv4 can also cause this.
841cee86682Scalum 		 * Sort the pathnames array, and NULL out duplicates,
842cee86682Scalum 		 * then write the non-NULL entries to a new array.
843cee86682Scalum 		 * Sorting will also allow the kernel to optimise its searches.
844cee86682Scalum 		 */
845cee86682Scalum 
846cee86682Scalum 		qsort(pathnames, npaths, sizeof (char *), qstrcmp);
847cee86682Scalum 
848cee86682Scalum 		/* now NULL out any duplicates */
849cee86682Scalum 		i = 0; j = 1; nskipped = 0;
850cee86682Scalum 		while (j < npaths) {
851cee86682Scalum 			if (strcmp(pathnames[i], pathnames[j]) == NULL) {
852cee86682Scalum 				pathnames[j] = NULL;
853cee86682Scalum 				j++;
854cee86682Scalum 				nskipped++;
855cee86682Scalum 				continue;
856cee86682Scalum 			}
857cee86682Scalum 
858cee86682Scalum 			/* skip i over any of its NULLed duplicates */
859cee86682Scalum 			i = j++;
860cee86682Scalum 		}
861cee86682Scalum 
862cee86682Scalum 		/* finally, write the non-NULL entries to a new array */
863cee86682Scalum 		if (nskipped > 0) {
864cee86682Scalum 			int nreal;
865cee86682Scalum 			size_t sz;
866cee86682Scalum 			char **tmp_pathnames;
867cee86682Scalum 
868cee86682Scalum 			nreal = npaths - nskipped;
869cee86682Scalum 
870cee86682Scalum 			sz = nreal * sizeof (char *);
871cee86682Scalum 			tmp_pathnames = (char **)malloc(sz);
872cee86682Scalum 			if (tmp_pathnames == NULL) {
873b9709d3bSYuri Pankov 				fprintf(stderr, "tmp_pathnames malloc "
874b9709d3bSYuri Pankov 				    "failed\n");
875cee86682Scalum 				exit(1);
876cee86682Scalum 			}
877cee86682Scalum 
878cee86682Scalum 			for (i = 0, j = 0; i < npaths; i++)
879cee86682Scalum 				if (pathnames[i] != NULL)
880cee86682Scalum 					tmp_pathnames[j++] = pathnames[i];
881cee86682Scalum 			free(pathnames);
882cee86682Scalum 			pathnames = tmp_pathnames;
883cee86682Scalum 			npaths = nreal;
884cee86682Scalum 		}
885cee86682Scalum 
886cee86682Scalum 	}
887cee86682Scalum 
888cee86682Scalum 	/* Create directories to store the distributed state files */
889cee86682Scalum 	dss_mkleafdirs(npaths, pathnames);
890cee86682Scalum 
891cee86682Scalum 	/* Create the name-value pair list */
892cee86682Scalum 	error = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
893cee86682Scalum 	if (error) {
894b9709d3bSYuri Pankov 		fprintf(stderr, "nvlist_alloc failed: %s\n", strerror(errno));
895cee86682Scalum 		return (1);
896cee86682Scalum 	}
897cee86682Scalum 
898cee86682Scalum 	/* Add the pathnames array as a single name-value pair */
899cee86682Scalum 	error = nvlist_add_string_array(nvl, NFS4_DSS_NVPAIR_NAME,
900cee86682Scalum 	    pathnames, npaths);
901cee86682Scalum 	if (error) {
902b9709d3bSYuri Pankov 		fprintf(stderr, "nvlist_add_string_array failed: %s\n",
903cee86682Scalum 		    strerror(errno));
904cee86682Scalum 		nvlist_free(nvl);
905cee86682Scalum 		return (1);
906cee86682Scalum 	}
907cee86682Scalum 
908cee86682Scalum 	/*
909cee86682Scalum 	 * Pack list into contiguous memory, for passing to kernel.
910cee86682Scalum 	 * nvlist_pack() will allocate the memory for the buffer,
911cee86682Scalum 	 * which we should free() when no longer needed.
912cee86682Scalum 	 * NV_ENCODE_XDR for safety across ILP32/LP64 kernel boundary.
913cee86682Scalum 	 */
914cee86682Scalum 	bufp = NULL;
915cee86682Scalum 	error = nvlist_pack(nvl, &bufp, &buflen, NV_ENCODE_XDR, 0);
916cee86682Scalum 	if (error) {
917b9709d3bSYuri Pankov 		fprintf(stderr, "nvlist_pack failed: %s\n", strerror(errno));
918cee86682Scalum 		nvlist_free(nvl);
919cee86682Scalum 		return (1);
920cee86682Scalum 	}
921cee86682Scalum 
922cee86682Scalum 	/* Now we have the packed buffer, we no longer need the list */
923cee86682Scalum 	nvlist_free(nvl);
924cee86682Scalum 
925cee86682Scalum 	/*
926cee86682Scalum 	 * Let the kernel know in advance how big the buffer is.
927cee86682Scalum 	 * NOTE: we cannot just pass buflen, since size_t is a long, and
928cee86682Scalum 	 * thus a different size between ILP32 userland and LP64 kernel.
929cee86682Scalum 	 * Use an int for the transfer, since that should be big enough;
930cee86682Scalum 	 * this is a no-op at the moment, here, since nfsd is 32-bit, but
931cee86682Scalum 	 * that could change.
932cee86682Scalum 	 */
933cee86682Scalum 	bufsize = (uint32_t)buflen;
934cee86682Scalum 	error = _nfssys(NFS4_DSS_SETPATHS_SIZE, &bufsize);
935cee86682Scalum 	if (error) {
936250a0733Sth199096 		fprintf(stderr,
937b9709d3bSYuri Pankov 		    "_nfssys(NFS4_DSS_SETPATHS_SIZE) failed: %s\n",
938cee86682Scalum 		    strerror(errno));
939cee86682Scalum 		free(bufp);
940cee86682Scalum 		return (1);
941cee86682Scalum 	}
942cee86682Scalum 
943cee86682Scalum 	/* Pass the packed buffer to the kernel */
944cee86682Scalum 	error = _nfssys(NFS4_DSS_SETPATHS, bufp);
945cee86682Scalum 	if (error) {
946250a0733Sth199096 		fprintf(stderr,
947b9709d3bSYuri Pankov 		    "_nfssys(NFS4_DSS_SETPATHS) failed: %s\n", strerror(errno));
948cee86682Scalum 		free(bufp);
949cee86682Scalum 		return (1);
950cee86682Scalum 	}
951cee86682Scalum 
952cee86682Scalum 	/*
953cee86682Scalum 	 * The kernel has now unpacked the buffer and extracted the
954cee86682Scalum 	 * pathnames array, we no longer need the buffer.
955cee86682Scalum 	 */
956cee86682Scalum 	free(bufp);
957cee86682Scalum 
958cee86682Scalum 	return (0);
959cee86682Scalum }
960cee86682Scalum 
961cee86682Scalum /*
962cee86682Scalum  * Quick sort string compare routine, for qsort.
963cee86682Scalum  * Needed to make arg types correct.
964cee86682Scalum  */
965cee86682Scalum int
966cee86682Scalum qstrcmp(const void *p1, const void *p2)
967cee86682Scalum {
968cee86682Scalum 	char *s1 = *((char **)p1);
969cee86682Scalum 	char *s2 = *((char **)p2);
970cee86682Scalum 
971cee86682Scalum 	return (strcmp(s1, s2));
972cee86682Scalum }
973