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 /* NFS server */
397c478bd9Sstevel@tonic-gate
407c478bd9Sstevel@tonic-gate #include <sys/param.h>
417c478bd9Sstevel@tonic-gate #include <sys/types.h>
42cee86682Scalum #include <sys/stat.h>
437c478bd9Sstevel@tonic-gate #include <syslog.h>
447c478bd9Sstevel@tonic-gate #include <tiuser.h>
457c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
467c478bd9Sstevel@tonic-gate #include <errno.h>
477c478bd9Sstevel@tonic-gate #include <thread.h>
487c478bd9Sstevel@tonic-gate #include <sys/resource.h>
497c478bd9Sstevel@tonic-gate #include <sys/time.h>
507c478bd9Sstevel@tonic-gate #include <sys/file.h>
517c478bd9Sstevel@tonic-gate #include <nfs/nfs.h>
52*f44e1126SVitaliy Gusev #include <nfs/nfs4.h>
537c478bd9Sstevel@tonic-gate #include <nfs/nfs_acl.h>
547c478bd9Sstevel@tonic-gate #include <nfs/nfssys.h>
557c478bd9Sstevel@tonic-gate #include <stdio.h>
56004388ebScasper #include <stdio_ext.h>
577c478bd9Sstevel@tonic-gate #include <stdlib.h>
587c478bd9Sstevel@tonic-gate #include <signal.h>
597c478bd9Sstevel@tonic-gate #include <netconfig.h>
607c478bd9Sstevel@tonic-gate #include <netdir.h>
617c478bd9Sstevel@tonic-gate #include <string.h>
627c478bd9Sstevel@tonic-gate #include <unistd.h>
63dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include <limits.h>
647c478bd9Sstevel@tonic-gate #include <stropts.h>
657c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
66250a0733Sth199096 #include <sys/wait.h>
677c478bd9Sstevel@tonic-gate #include <poll.h>
687c478bd9Sstevel@tonic-gate #include <priv_utils.h>
697c478bd9Sstevel@tonic-gate #include <sys/tiuser.h>
707c478bd9Sstevel@tonic-gate #include <netinet/tcp.h>
717c478bd9Sstevel@tonic-gate #include <deflt.h>
727c478bd9Sstevel@tonic-gate #include <rpcsvc/daemon_utils.h>
737c478bd9Sstevel@tonic-gate #include <rpcsvc/nfs4_prot.h>
74cee86682Scalum #include <libnvpair.h>
75dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include <libscf.h>
76dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include <libshare.h>
777c478bd9Sstevel@tonic-gate #include "nfs_tbind.h"
787c478bd9Sstevel@tonic-gate #include "thrpool.h"
79dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include "smfcfg.h"
807c478bd9Sstevel@tonic-gate
817c478bd9Sstevel@tonic-gate /* quiesce requests will be ignored if nfs_server_vers_max < QUIESCE_VERSMIN */
827c478bd9Sstevel@tonic-gate #define QUIESCE_VERSMIN 4
83cee86682Scalum /* DSS: distributed stable storage */
84cee86682Scalum #define DSS_VERSMIN 4
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate static int nfssvc(int, struct netbuf, struct netconfig *);
877c478bd9Sstevel@tonic-gate static int nfssvcpool(int maxservers);
88cee86682Scalum static int dss_init(uint_t npaths, char **pathnames);
89cee86682Scalum static void dss_mkleafdirs(uint_t npaths, char **pathnames);
90cee86682Scalum static void dss_mkleafdir(char *dir, char *leaf, char *path);
917c478bd9Sstevel@tonic-gate static void usage(void);
92cee86682Scalum int qstrcmp(const void *s1, const void *s2);
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate extern int _nfssys(int, void *);
957c478bd9Sstevel@tonic-gate
96250a0733Sth199096 extern int daemonize_init(void);
97250a0733Sth199096 extern void daemonize_fini(int fd);
98250a0733Sth199096
997c478bd9Sstevel@tonic-gate /* signal handlers */
1007c478bd9Sstevel@tonic-gate static void sigflush(int);
1017c478bd9Sstevel@tonic-gate static void quiesce(int);
1027c478bd9Sstevel@tonic-gate
1037c478bd9Sstevel@tonic-gate static char *MyName;
1047c478bd9Sstevel@tonic-gate static NETSELDECL(defaultproviders)[] = { "/dev/tcp6", "/dev/tcp", "/dev/udp",
1057c478bd9Sstevel@tonic-gate "/dev/udp6", NULL };
106*f44e1126SVitaliy Gusev
1077c478bd9Sstevel@tonic-gate /*
1087c478bd9Sstevel@tonic-gate * The following are all globals used by routines in nfs_tbind.c.
1097c478bd9Sstevel@tonic-gate */
1107c478bd9Sstevel@tonic-gate size_t end_listen_fds; /* used by conn_close_oldest() */
1117c478bd9Sstevel@tonic-gate size_t num_fds = 0; /* used by multiple routines */
1127c478bd9Sstevel@tonic-gate int listen_backlog = 32; /* used by bind_to_{provider,proto}() */
1137c478bd9Sstevel@tonic-gate int num_servers; /* used by cots_listen_event() */
1147c478bd9Sstevel@tonic-gate int (*Mysvc)(int, struct netbuf, struct netconfig *) = nfssvc;
1157c478bd9Sstevel@tonic-gate /* used by cots_listen_event() */
1167c478bd9Sstevel@tonic-gate int max_conns_allowed = -1; /* used by cots_listen_event() */
1177c478bd9Sstevel@tonic-gate
1187c478bd9Sstevel@tonic-gate /*
1197c478bd9Sstevel@tonic-gate * Keep track of min/max versions of NFS protocol to be started.
120*f44e1126SVitaliy Gusev * Start with the defaults (min == 2, max == 4).
121*f44e1126SVitaliy Gusev * Used NFS_VERS_... and should be analyzed with NFS_PROT_VERSION
122*f44e1126SVitaliy Gusev * macros.
1237c478bd9Sstevel@tonic-gate */
124*f44e1126SVitaliy Gusev uint32_t nfs_server_vers_min = NFS_SRV_VERS_MIN;
125*f44e1126SVitaliy Gusev uint32_t nfs_server_vers_max = NFS_SRV_VERS_MAX;
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate /*
1287c478bd9Sstevel@tonic-gate * Set the default for server delegation enablement and set per
1297c478bd9Sstevel@tonic-gate * /etc/default/nfs configuration (if present).
1307c478bd9Sstevel@tonic-gate */
1317c478bd9Sstevel@tonic-gate int nfs_server_delegation = NFS_SERVER_DELEGATION_DEFAULT;
1327c478bd9Sstevel@tonic-gate
13311606941Sjwahlig int
main(int ac,char * av[])13411606941Sjwahlig main(int ac, char *av[])
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate char *dir = "/";
1377c478bd9Sstevel@tonic-gate int allflag = 0;
1387c478bd9Sstevel@tonic-gate int df_allflag = 0;
1397c478bd9Sstevel@tonic-gate int opt_cnt = 0;
140201f5ebaSSebastien Roy int maxservers = 1024; /* zero allows inifinte number of threads */
1417c478bd9Sstevel@tonic-gate int maxservers_set = 0;
1427c478bd9Sstevel@tonic-gate int logmaxservers = 0;
1437c478bd9Sstevel@tonic-gate int pid;
1447c478bd9Sstevel@tonic-gate int i;
14586147f89SToomas Soome char *provider = NULL;
14686147f89SToomas Soome char *df_provider = NULL;
1477c478bd9Sstevel@tonic-gate struct protob *protobp0, *protobp;
1487c478bd9Sstevel@tonic-gate NETSELDECL(proto) = NULL;
1497c478bd9Sstevel@tonic-gate NETSELDECL(df_proto) = NULL;
1507c478bd9Sstevel@tonic-gate NETSELPDECL(providerp);
1517c478bd9Sstevel@tonic-gate char *defval;
15245916cd2Sjpk boolean_t can_do_mlp;
153cee86682Scalum uint_t dss_npaths = 0;
154cee86682Scalum char **dss_pathnames = NULL;
155e8279403Smaheshvs sigset_t sgset;
156dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States char name[PATH_MAX], value[PATH_MAX];
157dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States int ret, bufsz;
158250a0733Sth199096 int pipe_fd = -1;
15986147f89SToomas Soome const char *errstr;
160250a0733Sth199096
1617c478bd9Sstevel@tonic-gate MyName = *av;
1627c478bd9Sstevel@tonic-gate
1637c478bd9Sstevel@tonic-gate /*
1647c478bd9Sstevel@tonic-gate * Initializations that require more privileges than we need to run.
1657c478bd9Sstevel@tonic-gate */
1667c478bd9Sstevel@tonic-gate (void) _create_daemon_lock(NFSD, DAEMON_UID, DAEMON_GID);
1677c478bd9Sstevel@tonic-gate svcsetprio();
1687c478bd9Sstevel@tonic-gate
16945916cd2Sjpk can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
1707c478bd9Sstevel@tonic-gate if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET,
17145916cd2Sjpk DAEMON_UID, DAEMON_GID, PRIV_SYS_NFS,
17245916cd2Sjpk can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) {
1737c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s should be run with"
1747c478bd9Sstevel@tonic-gate " sufficient privileges\n", av[0]);
1757c478bd9Sstevel@tonic-gate exit(1);
1767c478bd9Sstevel@tonic-gate }
1777c478bd9Sstevel@tonic-gate
178004388ebScasper (void) enable_extended_FILE_stdio(-1, -1);
179004388ebScasper
18086147f89SToomas Soome /* Upgrade SMF settings, if necessary. */
18186147f89SToomas Soome nfs_config_upgrade(NFSD);
18286147f89SToomas Soome
1837c478bd9Sstevel@tonic-gate /*
184dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States * Read in the values from SMF first before we check
185dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States * command line options so the options override SMF values.
1867c478bd9Sstevel@tonic-gate */
187dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States bufsz = PATH_MAX;
188dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States ret = nfs_smf_get_prop("max_connections", value, DEFAULT_INSTANCE,
189dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States SCF_TYPE_INTEGER, NFSD, &bufsz);
190dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States if (ret == SA_OK) {
191*f44e1126SVitaliy Gusev max_conns_allowed = strtonum(value, -1, INT32_MAX, &errstr);
192*f44e1126SVitaliy Gusev if (errstr != NULL)
1937c478bd9Sstevel@tonic-gate max_conns_allowed = -1;
1947c478bd9Sstevel@tonic-gate }
195dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States
196dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States bufsz = PATH_MAX;
197dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States ret = nfs_smf_get_prop("listen_backlog", value, DEFAULT_INSTANCE,
198dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States SCF_TYPE_INTEGER, NFSD, &bufsz);
199dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States if (ret == SA_OK) {
200*f44e1126SVitaliy Gusev listen_backlog = strtonum(value, 0, INT32_MAX, &errstr);
201*f44e1126SVitaliy Gusev if (errstr != NULL) {
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) {
231*f44e1126SVitaliy Gusev maxservers = strtonum(value, 1, INT32_MAX, &errstr);
232*f44e1126SVitaliy Gusev if (errstr != NULL)
233201f5ebaSSebastien Roy maxservers = 1024;
234dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States else
2357c478bd9Sstevel@tonic-gate maxservers_set = 1;
2367c478bd9Sstevel@tonic-gate }
2377c478bd9Sstevel@tonic-gate
238*f44e1126SVitaliy Gusev bufsz = PATH_MAX;
239dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States ret = nfs_smf_get_prop("server_versmin", value, DEFAULT_INSTANCE,
24086147f89SToomas Soome SCF_TYPE_ASTRING, NFSD, &bufsz);
24186147f89SToomas Soome if (ret == SA_OK) {
242*f44e1126SVitaliy Gusev ret = nfs_convert_version_str(value);
243*f44e1126SVitaliy Gusev if (ret == 0) {
24486147f89SToomas Soome (void) fprintf(stderr, "invalid server_versmin: %s\n",
245*f44e1126SVitaliy Gusev value);
24686147f89SToomas Soome } else {
24786147f89SToomas Soome nfs_server_vers_min = ret;
24886147f89SToomas Soome }
24986147f89SToomas Soome }
250dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States
251*f44e1126SVitaliy Gusev bufsz = PATH_MAX;
252dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States ret = nfs_smf_get_prop("server_versmax", value, DEFAULT_INSTANCE,
25386147f89SToomas Soome SCF_TYPE_ASTRING, NFSD, &bufsz);
25486147f89SToomas Soome if (ret == SA_OK) {
255*f44e1126SVitaliy Gusev ret = nfs_convert_version_str(value);
256*f44e1126SVitaliy Gusev if (ret == 0) {
25786147f89SToomas Soome (void) fprintf(stderr, "invalid server_versmax: %s\n",
258*f44e1126SVitaliy Gusev value);
25986147f89SToomas Soome } else {
26086147f89SToomas Soome nfs_server_vers_max = ret;
26186147f89SToomas Soome }
26286147f89SToomas Soome }
263dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States
264dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States bufsz = PATH_MAX;
265dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States ret = nfs_smf_get_prop("server_delegation", value, DEFAULT_INSTANCE,
266dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States SCF_TYPE_ASTRING, NFSD, &bufsz);
267dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States if (ret == SA_OK)
268dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States if (strncasecmp(value, "off", 3) == 0)
269dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States nfs_server_delegation = FALSE;
2707c478bd9Sstevel@tonic-gate
2717c478bd9Sstevel@tonic-gate /*
2727c478bd9Sstevel@tonic-gate * Conflict options error messages.
2737c478bd9Sstevel@tonic-gate */
2747c478bd9Sstevel@tonic-gate if (opt_cnt > 1) {
2757c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\nConflicting options, only one of "
2767c478bd9Sstevel@tonic-gate "the following options can be specified\n"
277dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States "in SMF:\n"
278dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States "\tprotocol=ALL\n"
279dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States "\tprotocol=protocol\n"
280dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States "\tdevice=devicename\n\n");
2817c478bd9Sstevel@tonic-gate usage();
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate opt_cnt = 0;
2847c478bd9Sstevel@tonic-gate
285cee86682Scalum while ((i = getopt(ac, av, "ac:p:s:t:l:")) != EOF) {
2867c478bd9Sstevel@tonic-gate switch (i) {
2877c478bd9Sstevel@tonic-gate case 'a':
2887c478bd9Sstevel@tonic-gate free(df_proto);
2897c478bd9Sstevel@tonic-gate df_proto = NULL;
2907c478bd9Sstevel@tonic-gate free(df_provider);
2917c478bd9Sstevel@tonic-gate df_provider = NULL;
2927c478bd9Sstevel@tonic-gate
2937c478bd9Sstevel@tonic-gate allflag = 1;
2947c478bd9Sstevel@tonic-gate opt_cnt++;
2957c478bd9Sstevel@tonic-gate break;
2967c478bd9Sstevel@tonic-gate
2977c478bd9Sstevel@tonic-gate case 'c':
2987c478bd9Sstevel@tonic-gate max_conns_allowed = atoi(optarg);
2997c478bd9Sstevel@tonic-gate break;
3007c478bd9Sstevel@tonic-gate
3017c478bd9Sstevel@tonic-gate case 'p':
3027c478bd9Sstevel@tonic-gate proto = optarg;
3037c478bd9Sstevel@tonic-gate df_allflag = 0;
3047c478bd9Sstevel@tonic-gate opt_cnt++;
3057c478bd9Sstevel@tonic-gate break;
3067c478bd9Sstevel@tonic-gate
307cee86682Scalum /*
308cee86682Scalum * DSS: NFSv4 distributed stable storage.
309cee86682Scalum *
310cee86682Scalum * This is a Contracted Project Private interface, for
311cee86682Scalum * the sole use of Sun Cluster HA-NFS. See PSARC/2006/313.
312cee86682Scalum */
313cee86682Scalum case 's':
314cee86682Scalum if (strlen(optarg) < MAXPATHLEN) {
315cee86682Scalum /* first "-s" option encountered? */
316cee86682Scalum if (dss_pathnames == NULL) {
317cee86682Scalum /*
318cee86682Scalum * Allocate maximum possible space
319cee86682Scalum * required given cmdline arg count;
320cee86682Scalum * "-s <path>" consumes two args.
321cee86682Scalum */
322cee86682Scalum size_t sz = (ac / 2) * sizeof (char *);
323cee86682Scalum dss_pathnames = (char **)malloc(sz);
324cee86682Scalum if (dss_pathnames == NULL) {
325cee86682Scalum (void) fprintf(stderr, "%s: "
326cee86682Scalum "dss paths malloc failed\n",
327cee86682Scalum av[0]);
328cee86682Scalum exit(1);
329cee86682Scalum }
330cee86682Scalum (void) memset(dss_pathnames, 0, sz);
331cee86682Scalum }
332cee86682Scalum dss_pathnames[dss_npaths] = optarg;
333cee86682Scalum dss_npaths++;
334cee86682Scalum } else {
335cee86682Scalum (void) fprintf(stderr,
336cee86682Scalum "%s: -s pathname too long.\n", av[0]);
337cee86682Scalum }
338cee86682Scalum break;
339cee86682Scalum
3407c478bd9Sstevel@tonic-gate case 't':
3417c478bd9Sstevel@tonic-gate provider = optarg;
3427c478bd9Sstevel@tonic-gate df_allflag = 0;
3437c478bd9Sstevel@tonic-gate opt_cnt++;
3447c478bd9Sstevel@tonic-gate break;
3457c478bd9Sstevel@tonic-gate
3467c478bd9Sstevel@tonic-gate case 'l':
3477c478bd9Sstevel@tonic-gate listen_backlog = atoi(optarg);
3487c478bd9Sstevel@tonic-gate break;
3497c478bd9Sstevel@tonic-gate
3507c478bd9Sstevel@tonic-gate case '?':
3517c478bd9Sstevel@tonic-gate usage();
3527c478bd9Sstevel@tonic-gate /* NOTREACHED */
3537c478bd9Sstevel@tonic-gate }
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate
3567c478bd9Sstevel@tonic-gate allflag = df_allflag;
3577c478bd9Sstevel@tonic-gate if (proto == NULL)
3587c478bd9Sstevel@tonic-gate proto = df_proto;
3597c478bd9Sstevel@tonic-gate if (provider == NULL)
3607c478bd9Sstevel@tonic-gate provider = df_provider;
3617c478bd9Sstevel@tonic-gate
3627c478bd9Sstevel@tonic-gate /*
3637c478bd9Sstevel@tonic-gate * Conflict options error messages.
3647c478bd9Sstevel@tonic-gate */
3657c478bd9Sstevel@tonic-gate if (opt_cnt > 1) {
3667c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\nConflicting options, only one of "
3677c478bd9Sstevel@tonic-gate "the following options can be specified\n"
3687c478bd9Sstevel@tonic-gate "on the command line:\n"
3697c478bd9Sstevel@tonic-gate "\t-a\n"
3707c478bd9Sstevel@tonic-gate "\t-p protocol\n"
3717c478bd9Sstevel@tonic-gate "\t-t transport\n\n");
3727c478bd9Sstevel@tonic-gate usage();
3737c478bd9Sstevel@tonic-gate }
3747c478bd9Sstevel@tonic-gate
3757c478bd9Sstevel@tonic-gate if (proto != NULL &&
3767c478bd9Sstevel@tonic-gate strncasecmp(proto, NC_UDP, strlen(NC_UDP)) == 0) {
377*f44e1126SVitaliy Gusev if (NFS_PROT_VERSION(nfs_server_vers_max) == NFS_V4) {
378*f44e1126SVitaliy Gusev if (NFS_PROT_VERSION(nfs_server_vers_min) == NFS_V4) {
3797c478bd9Sstevel@tonic-gate fprintf(stderr,
3807c478bd9Sstevel@tonic-gate "NFS version 4 is not supported "
3817c478bd9Sstevel@tonic-gate "with the UDP protocol. Exiting\n");
3827c478bd9Sstevel@tonic-gate exit(3);
3837c478bd9Sstevel@tonic-gate } else {
3847c478bd9Sstevel@tonic-gate fprintf(stderr,
3857c478bd9Sstevel@tonic-gate "NFS version 4 is not supported "
3867c478bd9Sstevel@tonic-gate "with the UDP protocol.\n");
3877c478bd9Sstevel@tonic-gate }
3887c478bd9Sstevel@tonic-gate }
3897c478bd9Sstevel@tonic-gate }
3907c478bd9Sstevel@tonic-gate
3917c478bd9Sstevel@tonic-gate /*
3927c478bd9Sstevel@tonic-gate * If there is exactly one more argument, it is the number of
3937c478bd9Sstevel@tonic-gate * servers.
3947c478bd9Sstevel@tonic-gate */
3957c478bd9Sstevel@tonic-gate if (optind == ac - 1) {
3967c478bd9Sstevel@tonic-gate maxservers = atoi(av[optind]);
3977c478bd9Sstevel@tonic-gate maxservers_set = 1;
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate /*
4007c478bd9Sstevel@tonic-gate * If there are two or more arguments, then this is a usage error.
4017c478bd9Sstevel@tonic-gate */
4027c478bd9Sstevel@tonic-gate else if (optind < ac - 1)
4037c478bd9Sstevel@tonic-gate usage();
4047c478bd9Sstevel@tonic-gate /*
4057c478bd9Sstevel@tonic-gate * Check the ranges for min/max version specified
4067c478bd9Sstevel@tonic-gate */
4077c478bd9Sstevel@tonic-gate else if ((nfs_server_vers_min > nfs_server_vers_max) ||
408*f44e1126SVitaliy Gusev (nfs_server_vers_min < NFS_SRV_VERS_MIN) ||
409*f44e1126SVitaliy Gusev (nfs_server_vers_max > NFS_SRV_VERS_MAX))
4107c478bd9Sstevel@tonic-gate usage();
4117c478bd9Sstevel@tonic-gate /*
4127c478bd9Sstevel@tonic-gate * There are no additional arguments, and we haven't set maxservers
4137c478bd9Sstevel@tonic-gate * explicitly via the config file, we use a default number of
4147c478bd9Sstevel@tonic-gate * servers. We will log this.
4157c478bd9Sstevel@tonic-gate */
4167c478bd9Sstevel@tonic-gate else if (maxservers_set == 0)
4177c478bd9Sstevel@tonic-gate logmaxservers = 1;
4187c478bd9Sstevel@tonic-gate
4197c478bd9Sstevel@tonic-gate /*
4207c478bd9Sstevel@tonic-gate * Basic Sanity checks on options
4217c478bd9Sstevel@tonic-gate *
4227c478bd9Sstevel@tonic-gate * max_conns_allowed must be positive, except for the special
4237c478bd9Sstevel@tonic-gate * value of -1 which is used internally to mean unlimited, -1 isn't
4247c478bd9Sstevel@tonic-gate * documented but we allow it anyway.
4257c478bd9Sstevel@tonic-gate *
4267c478bd9Sstevel@tonic-gate * maxservers must be positive
4277c478bd9Sstevel@tonic-gate * listen_backlog must be positive or zero
4287c478bd9Sstevel@tonic-gate */
4297c478bd9Sstevel@tonic-gate if (((max_conns_allowed != -1) && (max_conns_allowed <= 0)) ||
4307c478bd9Sstevel@tonic-gate (listen_backlog < 0) || (maxservers <= 0)) {
4317c478bd9Sstevel@tonic-gate usage();
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate
4347c478bd9Sstevel@tonic-gate /*
4357c478bd9Sstevel@tonic-gate * Set current dir to server root
4367c478bd9Sstevel@tonic-gate */
4377c478bd9Sstevel@tonic-gate if (chdir(dir) < 0) {
4387c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", MyName);
4397c478bd9Sstevel@tonic-gate perror(dir);
4407c478bd9Sstevel@tonic-gate exit(1);
4417c478bd9Sstevel@tonic-gate }
4427c478bd9Sstevel@tonic-gate
4437c478bd9Sstevel@tonic-gate #ifndef DEBUG
444250a0733Sth199096 pipe_fd = daemonize_init();
4457c478bd9Sstevel@tonic-gate #endif
446250a0733Sth199096
4477c478bd9Sstevel@tonic-gate openlog(MyName, LOG_PID | LOG_NDELAY, LOG_DAEMON);
4487c478bd9Sstevel@tonic-gate
4497c478bd9Sstevel@tonic-gate /*
4507c478bd9Sstevel@tonic-gate * establish our lock on the lock file and write our pid to it.
4517c478bd9Sstevel@tonic-gate * exit if some other process holds the lock, or if there's any
4527c478bd9Sstevel@tonic-gate * error in writing/locking the file.
4537c478bd9Sstevel@tonic-gate */
4547c478bd9Sstevel@tonic-gate pid = _enter_daemon_lock(NFSD);
4557c478bd9Sstevel@tonic-gate switch (pid) {
4567c478bd9Sstevel@tonic-gate case 0:
4577c478bd9Sstevel@tonic-gate break;
4587c478bd9Sstevel@tonic-gate case -1:
459b9709d3bSYuri Pankov fprintf(stderr, "error locking for %s: %s\n", NFSD,
4607c478bd9Sstevel@tonic-gate strerror(errno));
4617c478bd9Sstevel@tonic-gate exit(2);
4627c478bd9Sstevel@tonic-gate default:
4637c478bd9Sstevel@tonic-gate /* daemon was already running */
4647c478bd9Sstevel@tonic-gate exit(0);
4657c478bd9Sstevel@tonic-gate }
4667c478bd9Sstevel@tonic-gate
467cee86682Scalum /*
468cee86682Scalum * If we've been given a list of paths to be used for distributed
469cee86682Scalum * stable storage, and provided we're going to run a version
470cee86682Scalum * that supports it, setup the DSS paths.
471cee86682Scalum */
472*f44e1126SVitaliy Gusev if (dss_pathnames != NULL &&
473*f44e1126SVitaliy Gusev NFS_PROT_VERSION(nfs_server_vers_max) >= DSS_VERSMIN) {
474cee86682Scalum if (dss_init(dss_npaths, dss_pathnames) != 0) {
475b9709d3bSYuri Pankov fprintf(stderr, "%s", "dss_init failed. Exiting.\n");
476cee86682Scalum exit(1);
477cee86682Scalum }
478cee86682Scalum }
479cee86682Scalum
480e8279403Smaheshvs /*
481e8279403Smaheshvs * Block all signals till we spawn other
482e8279403Smaheshvs * threads.
483e8279403Smaheshvs */
484e8279403Smaheshvs (void) sigfillset(&sgset);
485e8279403Smaheshvs (void) thr_sigsetmask(SIG_BLOCK, &sgset, NULL);
4867c478bd9Sstevel@tonic-gate
4877c478bd9Sstevel@tonic-gate if (logmaxservers) {
488250a0733Sth199096 fprintf(stderr,
489b9709d3bSYuri Pankov "Number of servers not specified. Using default of %d.\n",
4907c478bd9Sstevel@tonic-gate maxservers);
4917c478bd9Sstevel@tonic-gate }
4927c478bd9Sstevel@tonic-gate
4937c478bd9Sstevel@tonic-gate /*
4947c478bd9Sstevel@tonic-gate * Make sure to unregister any previous versions in case the
4957c478bd9Sstevel@tonic-gate * user is reconfiguring the server in interesting ways.
4967c478bd9Sstevel@tonic-gate */
4977c478bd9Sstevel@tonic-gate svc_unreg(NFS_PROGRAM, NFS_VERSION);
4987c478bd9Sstevel@tonic-gate svc_unreg(NFS_PROGRAM, NFS_V3);
4997c478bd9Sstevel@tonic-gate svc_unreg(NFS_PROGRAM, NFS_V4);
5007c478bd9Sstevel@tonic-gate svc_unreg(NFS_ACL_PROGRAM, NFS_ACL_V2);
5017c478bd9Sstevel@tonic-gate svc_unreg(NFS_ACL_PROGRAM, NFS_ACL_V3);
5027c478bd9Sstevel@tonic-gate
5037c478bd9Sstevel@tonic-gate /*
5047c478bd9Sstevel@tonic-gate * Set up kernel RPC thread pool for the NFS server.
5057c478bd9Sstevel@tonic-gate */
5067c478bd9Sstevel@tonic-gate if (nfssvcpool(maxservers)) {
507b9709d3bSYuri Pankov fprintf(stderr, "Can't set up kernel NFS service: %s. "
508b9709d3bSYuri Pankov "Exiting.\n", strerror(errno));
5097c478bd9Sstevel@tonic-gate exit(1);
5107c478bd9Sstevel@tonic-gate }
5117c478bd9Sstevel@tonic-gate
5127c478bd9Sstevel@tonic-gate /*
5137c478bd9Sstevel@tonic-gate * Set up blocked thread to do LWP creation on behalf of the kernel.
5147c478bd9Sstevel@tonic-gate */
5157c478bd9Sstevel@tonic-gate if (svcwait(NFS_SVCPOOL_ID)) {
516b9709d3bSYuri Pankov fprintf(stderr, "Can't set up NFS pool creator: %s. Exiting.\n",
517250a0733Sth199096 strerror(errno));
5187c478bd9Sstevel@tonic-gate exit(1);
5197c478bd9Sstevel@tonic-gate }
5207c478bd9Sstevel@tonic-gate
5217c478bd9Sstevel@tonic-gate /*
5227c478bd9Sstevel@tonic-gate * RDMA start and stop thread.
5237c478bd9Sstevel@tonic-gate * Per pool RDMA listener creation and
5247c478bd9Sstevel@tonic-gate * destructor thread.
5257c478bd9Sstevel@tonic-gate *
5267c478bd9Sstevel@tonic-gate * start rdma services and block in the kernel.
527ed629aefSSiddheshwar Mahesh * (only if proto or provider is not set to TCP or UDP)
5287c478bd9Sstevel@tonic-gate */
529ed629aefSSiddheshwar Mahesh if ((proto == NULL) && (provider == NULL)) {
530ed629aefSSiddheshwar Mahesh if (svcrdma(NFS_SVCPOOL_ID, nfs_server_vers_min,
531ed629aefSSiddheshwar Mahesh nfs_server_vers_max, nfs_server_delegation)) {
532ed629aefSSiddheshwar Mahesh fprintf(stderr,
533b9709d3bSYuri Pankov "Can't set up RDMA creator thread : %s\n",
534250a0733Sth199096 strerror(errno));
5357c478bd9Sstevel@tonic-gate }
536ed629aefSSiddheshwar Mahesh }
5377c478bd9Sstevel@tonic-gate
5387c478bd9Sstevel@tonic-gate /*
539e8279403Smaheshvs * Now open up for signal delivery
540e8279403Smaheshvs */
541e8279403Smaheshvs
542e8279403Smaheshvs (void) thr_sigsetmask(SIG_UNBLOCK, &sgset, NULL);
543e8279403Smaheshvs sigset(SIGTERM, sigflush);
544e8279403Smaheshvs sigset(SIGUSR1, quiesce);
545e8279403Smaheshvs
546e8279403Smaheshvs /*
5477c478bd9Sstevel@tonic-gate * Build a protocol block list for registration.
548*f44e1126SVitaliy Gusev * In protocol list we have first block for NFS and second
549*f44e1126SVitaliy Gusev * block for NFS_ACL - which is needed up to v3, as support
550*f44e1126SVitaliy Gusev * for ACL is included in NFS protocol since v4.
5517c478bd9Sstevel@tonic-gate */
5527c478bd9Sstevel@tonic-gate protobp0 = protobp = (struct protob *)malloc(sizeof (struct protob));
5537c478bd9Sstevel@tonic-gate protobp->serv = "NFS";
554*f44e1126SVitaliy Gusev protobp->versmin = NFS_PROT_VERSION(nfs_server_vers_min);
555*f44e1126SVitaliy Gusev protobp->versmax = NFS_PROT_VERSION(nfs_server_vers_max);
5567c478bd9Sstevel@tonic-gate protobp->program = NFS_PROGRAM;
5577c478bd9Sstevel@tonic-gate
5587c478bd9Sstevel@tonic-gate protobp->next = (struct protob *)malloc(sizeof (struct protob));
5597c478bd9Sstevel@tonic-gate protobp = protobp->next;
5607c478bd9Sstevel@tonic-gate protobp->serv = "NFS_ACL"; /* not used */
561*f44e1126SVitaliy Gusev protobp->versmin = NFS_PROT_VERSION(nfs_server_vers_min);
5627c478bd9Sstevel@tonic-gate /* XXX - this needs work to get the version just right */
563*f44e1126SVitaliy Gusev protobp->versmax =
564*f44e1126SVitaliy Gusev MIN(NFS_PROT_VERSION(nfs_server_vers_max), NFS_ACL_V3);
5657c478bd9Sstevel@tonic-gate protobp->program = NFS_ACL_PROGRAM;
566*f44e1126SVitaliy Gusev protobp->next = NULL;
5677c478bd9Sstevel@tonic-gate
5687c478bd9Sstevel@tonic-gate if (allflag) {
5699ff75adeSSurya Prakki if (do_all(protobp0, nfssvc) == -1) {
570b9709d3bSYuri Pankov fprintf(stderr, "setnetconfig failed : %s\n",
571250a0733Sth199096 strerror(errno));
5727c478bd9Sstevel@tonic-gate exit(1);
573250a0733Sth199096 }
5747c478bd9Sstevel@tonic-gate } else if (proto) {
5757c478bd9Sstevel@tonic-gate /* there's more than one match for the same protocol */
5767c478bd9Sstevel@tonic-gate struct netconfig *nconf;
5777c478bd9Sstevel@tonic-gate NCONF_HANDLE *nc;
5787c478bd9Sstevel@tonic-gate bool_t protoFound = FALSE;
5797c478bd9Sstevel@tonic-gate if ((nc = setnetconfig()) == (NCONF_HANDLE *) NULL) {
580b9709d3bSYuri Pankov fprintf(stderr, "setnetconfig failed : %s\n",
581250a0733Sth199096 strerror(errno));
5827c478bd9Sstevel@tonic-gate goto done;
5837c478bd9Sstevel@tonic-gate }
5847c478bd9Sstevel@tonic-gate while (nconf = getnetconfig(nc)) {
5857c478bd9Sstevel@tonic-gate if (strcmp(nconf->nc_proto, proto) == 0) {
5867c478bd9Sstevel@tonic-gate protoFound = TRUE;
5877c478bd9Sstevel@tonic-gate do_one(nconf->nc_device, NULL,
5889ff75adeSSurya Prakki protobp0, nfssvc);
5897c478bd9Sstevel@tonic-gate }
5907c478bd9Sstevel@tonic-gate }
5917c478bd9Sstevel@tonic-gate (void) endnetconfig(nc);
592250a0733Sth199096 if (protoFound == FALSE) {
593250a0733Sth199096 fprintf(stderr,
594b9709d3bSYuri Pankov "couldn't find netconfig entry for protocol %s\n",
595250a0733Sth199096 proto);
596250a0733Sth199096 }
5977c478bd9Sstevel@tonic-gate } else if (provider)
5989ff75adeSSurya Prakki do_one(provider, proto, protobp0, nfssvc);
5997c478bd9Sstevel@tonic-gate else {
6007c478bd9Sstevel@tonic-gate for (providerp = defaultproviders;
6017c478bd9Sstevel@tonic-gate *providerp != NULL; providerp++) {
6027c478bd9Sstevel@tonic-gate provider = *providerp;
6039ff75adeSSurya Prakki do_one(provider, NULL, protobp0, nfssvc);
6047c478bd9Sstevel@tonic-gate }
6057c478bd9Sstevel@tonic-gate }
6067c478bd9Sstevel@tonic-gate done:
6077c478bd9Sstevel@tonic-gate
6087c478bd9Sstevel@tonic-gate free(protobp);
6097c478bd9Sstevel@tonic-gate free(protobp0);
6107c478bd9Sstevel@tonic-gate
6117c478bd9Sstevel@tonic-gate if (num_fds == 0) {
612250a0733Sth199096 fprintf(stderr, "Could not start NFS service for any protocol."
613b9709d3bSYuri Pankov " Exiting.\n");
6147c478bd9Sstevel@tonic-gate exit(1);
6157c478bd9Sstevel@tonic-gate }
6167c478bd9Sstevel@tonic-gate
6177c478bd9Sstevel@tonic-gate end_listen_fds = num_fds;
6187c478bd9Sstevel@tonic-gate
6197c478bd9Sstevel@tonic-gate /*
620250a0733Sth199096 * nfsd is up and running as far as we are concerned.
621250a0733Sth199096 */
622250a0733Sth199096 daemonize_fini(pipe_fd);
623250a0733Sth199096
624250a0733Sth199096 /*
6257c478bd9Sstevel@tonic-gate * Get rid of unneeded privileges.
6267c478bd9Sstevel@tonic-gate */
6277c478bd9Sstevel@tonic-gate __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION,
6287c478bd9Sstevel@tonic-gate PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL);
6297c478bd9Sstevel@tonic-gate
6307c478bd9Sstevel@tonic-gate /*
6317c478bd9Sstevel@tonic-gate * Poll for non-data control events on the transport descriptors.
6327c478bd9Sstevel@tonic-gate */
6337c478bd9Sstevel@tonic-gate poll_for_action();
6347c478bd9Sstevel@tonic-gate
6357c478bd9Sstevel@tonic-gate /*
6367c478bd9Sstevel@tonic-gate * If we get here, something failed in poll_for_action().
6377c478bd9Sstevel@tonic-gate */
6387c478bd9Sstevel@tonic-gate return (1);
6397c478bd9Sstevel@tonic-gate }
6407c478bd9Sstevel@tonic-gate
6417c478bd9Sstevel@tonic-gate static int
nfssvcpool(int maxservers)6427c478bd9Sstevel@tonic-gate nfssvcpool(int maxservers)
6437c478bd9Sstevel@tonic-gate {
6447c478bd9Sstevel@tonic-gate struct svcpool_args npa;
6457c478bd9Sstevel@tonic-gate
6467c478bd9Sstevel@tonic-gate npa.id = NFS_SVCPOOL_ID;
6477c478bd9Sstevel@tonic-gate npa.maxthreads = maxservers;
6487c478bd9Sstevel@tonic-gate npa.redline = 0;
6497c478bd9Sstevel@tonic-gate npa.qsize = 0;
6507c478bd9Sstevel@tonic-gate npa.timeout = 0;
6517c478bd9Sstevel@tonic-gate npa.stksize = 0;
6527c478bd9Sstevel@tonic-gate npa.max_same_xprt = 0;
6537c478bd9Sstevel@tonic-gate return (_nfssys(SVCPOOL_CREATE, &npa));
6547c478bd9Sstevel@tonic-gate }
6557c478bd9Sstevel@tonic-gate
6567c478bd9Sstevel@tonic-gate /*
6577c478bd9Sstevel@tonic-gate * Establish NFS service thread.
6587c478bd9Sstevel@tonic-gate */
6597c478bd9Sstevel@tonic-gate static int
nfssvc(int fd,struct netbuf addrmask,struct netconfig * nconf)6607c478bd9Sstevel@tonic-gate nfssvc(int fd, struct netbuf addrmask, struct netconfig *nconf)
6617c478bd9Sstevel@tonic-gate {
6627c478bd9Sstevel@tonic-gate struct nfs_svc_args nsa;
6637c478bd9Sstevel@tonic-gate
6647c478bd9Sstevel@tonic-gate nsa.fd = fd;
6657c478bd9Sstevel@tonic-gate nsa.netid = nconf->nc_netid;
6667c478bd9Sstevel@tonic-gate nsa.addrmask = addrmask;
6677c478bd9Sstevel@tonic-gate if (strncasecmp(nconf->nc_proto, NC_UDP, strlen(NC_UDP)) == 0) {
668*f44e1126SVitaliy Gusev nsa.nfs_versmax = MIN(nfs_server_vers_max, NFS_VERS_3);
669*f44e1126SVitaliy Gusev nsa.nfs_versmin = nfs_server_vers_min;
6707c478bd9Sstevel@tonic-gate /*
6717c478bd9Sstevel@tonic-gate * If no version left, silently do nothing, previous
6727c478bd9Sstevel@tonic-gate * checks will have assured at least TCP is available.
6737c478bd9Sstevel@tonic-gate */
674*f44e1126SVitaliy Gusev if (nsa.nfs_versmin > nsa.nfs_versmax)
6757c478bd9Sstevel@tonic-gate return (0);
6767c478bd9Sstevel@tonic-gate } else {
677*f44e1126SVitaliy Gusev nsa.nfs_versmax = nfs_server_vers_max;
678*f44e1126SVitaliy Gusev nsa.nfs_versmin = nfs_server_vers_min;
6797c478bd9Sstevel@tonic-gate }
6807c478bd9Sstevel@tonic-gate nsa.delegation = nfs_server_delegation;
6817c478bd9Sstevel@tonic-gate return (_nfssys(NFS_SVC, &nsa));
6827c478bd9Sstevel@tonic-gate }
6837c478bd9Sstevel@tonic-gate
6847c478bd9Sstevel@tonic-gate static void
usage(void)6857c478bd9Sstevel@tonic-gate usage(void)
6867c478bd9Sstevel@tonic-gate {
6877c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
6887c478bd9Sstevel@tonic-gate "usage: %s [ -a ] [ -c max_conns ] [ -p protocol ] [ -t transport ] ", MyName);
6897c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\n[ -l listen_backlog ] [ nservers ]\n");
6907c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
6917c478bd9Sstevel@tonic-gate "\twhere -a causes <nservers> to be started on each appropriate transport,\n");
6927c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
6937c478bd9Sstevel@tonic-gate "\tmax_conns is the maximum number of concurrent connections allowed,\n");
6947c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\t\tand max_conns must be a decimal number");
6957c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "> zero,\n");
6967c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\tprotocol is a protocol identifier,\n");
6977c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
6987c478bd9Sstevel@tonic-gate "\ttransport is a transport provider name (i.e. device),\n");
6997c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
7007c478bd9Sstevel@tonic-gate "\tlisten_backlog is the TCP listen backlog,\n");
7017c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
7027c478bd9Sstevel@tonic-gate "\tand <nservers> must be a decimal number > zero.\n");
7037c478bd9Sstevel@tonic-gate exit(1);
7047c478bd9Sstevel@tonic-gate }
7057c478bd9Sstevel@tonic-gate
7067c478bd9Sstevel@tonic-gate /*
7077c478bd9Sstevel@tonic-gate * Issue nfssys system call to flush all logging buffers asynchronously.
7087c478bd9Sstevel@tonic-gate *
7097c478bd9Sstevel@tonic-gate * NOTICE: It is extremely important to flush NFS logging buffers when
7107c478bd9Sstevel@tonic-gate * nfsd exits. When the system is halted or rebooted nfslogd
7117c478bd9Sstevel@tonic-gate * may not have an opportunity to flush the buffers.
7127c478bd9Sstevel@tonic-gate */
7137c478bd9Sstevel@tonic-gate static void
nfsl_flush()7147c478bd9Sstevel@tonic-gate nfsl_flush()
7157c478bd9Sstevel@tonic-gate {
7167c478bd9Sstevel@tonic-gate struct nfsl_flush_args nfa;
7177c478bd9Sstevel@tonic-gate
7187c478bd9Sstevel@tonic-gate memset((void *)&nfa, 0, sizeof (nfa));
7197c478bd9Sstevel@tonic-gate nfa.version = NFSL_FLUSH_ARGS_VERS;
7207c478bd9Sstevel@tonic-gate nfa.directive = NFSL_ALL; /* flush all asynchronously */
7217c478bd9Sstevel@tonic-gate
7227c478bd9Sstevel@tonic-gate if (_nfssys(LOG_FLUSH, &nfa) < 0)
7237c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "_nfssys(LOG_FLUSH) failed: %s\n",
7247c478bd9Sstevel@tonic-gate strerror(errno));
7257c478bd9Sstevel@tonic-gate }
7267c478bd9Sstevel@tonic-gate
7277c478bd9Sstevel@tonic-gate /*
7287c478bd9Sstevel@tonic-gate * SIGTERM handler.
7297c478bd9Sstevel@tonic-gate * Flush logging buffers and exit.
7307c478bd9Sstevel@tonic-gate */
7317c478bd9Sstevel@tonic-gate static void
sigflush(int sig)7327c478bd9Sstevel@tonic-gate sigflush(int sig)
7337c478bd9Sstevel@tonic-gate {
7347c478bd9Sstevel@tonic-gate nfsl_flush();
735e8279403Smaheshvs _exit(0);
7367c478bd9Sstevel@tonic-gate }
7377c478bd9Sstevel@tonic-gate
7387c478bd9Sstevel@tonic-gate /*
7397c478bd9Sstevel@tonic-gate * SIGUSR1 handler.
740cee86682Scalum *
741cee86682Scalum * Request that server quiesce, then (nfsd) exit. For subsequent warm start.
742cee86682Scalum *
743cee86682Scalum * This is a Contracted Project Private interface, for the sole use
744cee86682Scalum * of Sun Cluster HA-NFS. See PSARC/2004/497.
745cee86682Scalum *
7467c478bd9Sstevel@tonic-gate * Equivalent to SIGTERM handler if nfs_server_vers_max < QUIESCE_VERSMIN.
7477c478bd9Sstevel@tonic-gate */
7487c478bd9Sstevel@tonic-gate static void
quiesce(int sig)7497c478bd9Sstevel@tonic-gate quiesce(int sig)
7507c478bd9Sstevel@tonic-gate {
7517c478bd9Sstevel@tonic-gate int error;
7527c478bd9Sstevel@tonic-gate int id = NFS_SVCPOOL_ID;
7537c478bd9Sstevel@tonic-gate
754*f44e1126SVitaliy Gusev if (NFS_PROT_VERSION(nfs_server_vers_max) >= QUIESCE_VERSMIN) {
7557c478bd9Sstevel@tonic-gate /* Request server quiesce at next shutdown */
756cee86682Scalum error = _nfssys(NFS4_SVC_REQUEST_QUIESCE, &id);
757fdd1ecaeSmaheshvs
758fdd1ecaeSmaheshvs /*
759fdd1ecaeSmaheshvs * ENOENT is returned if there is no matching SVC pool
760fdd1ecaeSmaheshvs * for the id. Possibly because the pool is not yet setup.
761fdd1ecaeSmaheshvs * In this case, just exit as if no error. For all other errors,
762fdd1ecaeSmaheshvs * just return and allow caller to retry.
763fdd1ecaeSmaheshvs */
764e8279403Smaheshvs if (error && errno != ENOENT) {
7657c478bd9Sstevel@tonic-gate syslog(LOG_ERR,
766cee86682Scalum "_nfssys(NFS4_SVC_REQUEST_QUIESCE) failed: %s",
7677c478bd9Sstevel@tonic-gate strerror(errno));
7687c478bd9Sstevel@tonic-gate return;
7697c478bd9Sstevel@tonic-gate }
7707c478bd9Sstevel@tonic-gate }
7717c478bd9Sstevel@tonic-gate
7727c478bd9Sstevel@tonic-gate /* Flush logging buffers */
7737c478bd9Sstevel@tonic-gate nfsl_flush();
7747c478bd9Sstevel@tonic-gate
775e8279403Smaheshvs _exit(0);
7767c478bd9Sstevel@tonic-gate }
777cee86682Scalum
778cee86682Scalum /*
779cee86682Scalum * DSS: distributed stable storage.
780cee86682Scalum * Create leaf directories as required, keeping an eye on path
781cee86682Scalum * lengths. Calls exit(1) on failure.
782cee86682Scalum * The pathnames passed in must already exist, and must be writeable by nfsd.
783cee86682Scalum * Note: the leaf directories under NFS4_VAR_DIR are not created here;
784cee86682Scalum * they're created at pkg install.
785cee86682Scalum */
786cee86682Scalum static void
dss_mkleafdirs(uint_t npaths,char ** pathnames)787cee86682Scalum dss_mkleafdirs(uint_t npaths, char **pathnames)
788cee86682Scalum {
789cee86682Scalum int i;
790cee86682Scalum char *tmppath = NULL;
791cee86682Scalum
792cee86682Scalum /*
793cee86682Scalum * Create the temporary storage used by dss_mkleafdir() here,
794cee86682Scalum * rather than in that function, so that it only needs to be
795cee86682Scalum * done once, rather than once for each call. Too big to put
796cee86682Scalum * on the function's stack.
797cee86682Scalum */
798cee86682Scalum tmppath = (char *)malloc(MAXPATHLEN);
799cee86682Scalum if (tmppath == NULL) {
800cee86682Scalum syslog(LOG_ERR, "tmppath malloc failed. Exiting");
801cee86682Scalum exit(1);
802cee86682Scalum }
803cee86682Scalum
804cee86682Scalum for (i = 0; i < npaths; i++) {
805cee86682Scalum char *p = pathnames[i];
806cee86682Scalum
807cee86682Scalum dss_mkleafdir(p, NFS4_DSS_STATE_LEAF, tmppath);
808cee86682Scalum dss_mkleafdir(p, NFS4_DSS_OLDSTATE_LEAF, tmppath);
809cee86682Scalum }
810cee86682Scalum
811cee86682Scalum free(tmppath);
812cee86682Scalum }
813cee86682Scalum
814cee86682Scalum /*
815cee86682Scalum * Create "leaf" in "dir" (which must already exist).
816cee86682Scalum * leaf: should start with a '/'
817cee86682Scalum */
818cee86682Scalum static void
dss_mkleafdir(char * dir,char * leaf,char * tmppath)819cee86682Scalum dss_mkleafdir(char *dir, char *leaf, char *tmppath)
820cee86682Scalum {
821cee86682Scalum /* MAXPATHLEN includes the terminating NUL */
822cee86682Scalum if (strlen(dir) + strlen(leaf) > MAXPATHLEN - 1) {
823b9709d3bSYuri Pankov fprintf(stderr, "stable storage path too long: %s%s. "
824b9709d3bSYuri Pankov "Exiting.\n", dir, leaf);
825cee86682Scalum exit(1);
826cee86682Scalum }
827cee86682Scalum
828cee86682Scalum (void) snprintf(tmppath, MAXPATHLEN, "%s/%s", dir, leaf);
829cee86682Scalum
830cee86682Scalum /* the directory may already exist: that's OK */
831cee86682Scalum if (mkdir(tmppath, NFS4_DSS_DIR_MODE) == -1 && errno != EEXIST) {
832250a0733Sth199096 fprintf(stderr, "error creating stable storage directory: "
833b9709d3bSYuri Pankov "%s: %s. Exiting.\n", strerror(errno), tmppath);
834cee86682Scalum exit(1);
835cee86682Scalum }
836cee86682Scalum }
837cee86682Scalum
838cee86682Scalum /*
839cee86682Scalum * Create the storage dirs, and pass the path list to the kernel.
840cee86682Scalum * This requires the nfssrv module to be loaded; the _nfssys() syscall
841cee86682Scalum * will fail ENOTSUP if it is not.
842cee86682Scalum * Use libnvpair(3LIB) to pass the data to the kernel.
843cee86682Scalum */
844cee86682Scalum static int
dss_init(uint_t npaths,char ** pathnames)845cee86682Scalum dss_init(uint_t npaths, char **pathnames)
846cee86682Scalum {
847cee86682Scalum int i, j, nskipped, error;
848cee86682Scalum char *bufp;
849cee86682Scalum uint32_t bufsize;
850cee86682Scalum size_t buflen;
851cee86682Scalum nvlist_t *nvl;
852cee86682Scalum
853cee86682Scalum if (npaths > 1) {
854cee86682Scalum /*
855cee86682Scalum * We need to remove duplicate paths; this might be user error
856cee86682Scalum * in the general case, but HA-NFSv4 can also cause this.
857cee86682Scalum * Sort the pathnames array, and NULL out duplicates,
858cee86682Scalum * then write the non-NULL entries to a new array.
859cee86682Scalum * Sorting will also allow the kernel to optimise its searches.
860cee86682Scalum */
861cee86682Scalum
862cee86682Scalum qsort(pathnames, npaths, sizeof (char *), qstrcmp);
863cee86682Scalum
864cee86682Scalum /* now NULL out any duplicates */
865cee86682Scalum i = 0; j = 1; nskipped = 0;
866cee86682Scalum while (j < npaths) {
8678509e9caSToomas Soome if (strcmp(pathnames[i], pathnames[j]) == 0) {
868cee86682Scalum pathnames[j] = NULL;
869cee86682Scalum j++;
870cee86682Scalum nskipped++;
871cee86682Scalum continue;
872cee86682Scalum }
873cee86682Scalum
874cee86682Scalum /* skip i over any of its NULLed duplicates */
875cee86682Scalum i = j++;
876cee86682Scalum }
877cee86682Scalum
878cee86682Scalum /* finally, write the non-NULL entries to a new array */
879cee86682Scalum if (nskipped > 0) {
880cee86682Scalum int nreal;
881cee86682Scalum size_t sz;
882cee86682Scalum char **tmp_pathnames;
883cee86682Scalum
884cee86682Scalum nreal = npaths - nskipped;
885cee86682Scalum
886cee86682Scalum sz = nreal * sizeof (char *);
887cee86682Scalum tmp_pathnames = (char **)malloc(sz);
888cee86682Scalum if (tmp_pathnames == NULL) {
889b9709d3bSYuri Pankov fprintf(stderr, "tmp_pathnames malloc "
890b9709d3bSYuri Pankov "failed\n");
891cee86682Scalum exit(1);
892cee86682Scalum }
893cee86682Scalum
894cee86682Scalum for (i = 0, j = 0; i < npaths; i++)
895cee86682Scalum if (pathnames[i] != NULL)
896cee86682Scalum tmp_pathnames[j++] = pathnames[i];
897cee86682Scalum free(pathnames);
898cee86682Scalum pathnames = tmp_pathnames;
899cee86682Scalum npaths = nreal;
900cee86682Scalum }
901cee86682Scalum
902cee86682Scalum }
903cee86682Scalum
904cee86682Scalum /* Create directories to store the distributed state files */
905cee86682Scalum dss_mkleafdirs(npaths, pathnames);
906cee86682Scalum
907cee86682Scalum /* Create the name-value pair list */
908cee86682Scalum error = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
909cee86682Scalum if (error) {
910b9709d3bSYuri Pankov fprintf(stderr, "nvlist_alloc failed: %s\n", strerror(errno));
911cee86682Scalum return (1);
912cee86682Scalum }
913cee86682Scalum
914cee86682Scalum /* Add the pathnames array as a single name-value pair */
915cee86682Scalum error = nvlist_add_string_array(nvl, NFS4_DSS_NVPAIR_NAME,
916cee86682Scalum pathnames, npaths);
917cee86682Scalum if (error) {
918b9709d3bSYuri Pankov fprintf(stderr, "nvlist_add_string_array failed: %s\n",
919cee86682Scalum strerror(errno));
920cee86682Scalum nvlist_free(nvl);
921cee86682Scalum return (1);
922cee86682Scalum }
923cee86682Scalum
924cee86682Scalum /*
925cee86682Scalum * Pack list into contiguous memory, for passing to kernel.
926cee86682Scalum * nvlist_pack() will allocate the memory for the buffer,
927cee86682Scalum * which we should free() when no longer needed.
928cee86682Scalum * NV_ENCODE_XDR for safety across ILP32/LP64 kernel boundary.
929cee86682Scalum */
930cee86682Scalum bufp = NULL;
931cee86682Scalum error = nvlist_pack(nvl, &bufp, &buflen, NV_ENCODE_XDR, 0);
932cee86682Scalum if (error) {
933b9709d3bSYuri Pankov fprintf(stderr, "nvlist_pack failed: %s\n", strerror(errno));
934cee86682Scalum nvlist_free(nvl);
935cee86682Scalum return (1);
936cee86682Scalum }
937cee86682Scalum
938cee86682Scalum /* Now we have the packed buffer, we no longer need the list */
939cee86682Scalum nvlist_free(nvl);
940cee86682Scalum
941cee86682Scalum /*
942cee86682Scalum * Let the kernel know in advance how big the buffer is.
943cee86682Scalum * NOTE: we cannot just pass buflen, since size_t is a long, and
944cee86682Scalum * thus a different size between ILP32 userland and LP64 kernel.
945cee86682Scalum * Use an int for the transfer, since that should be big enough;
946cee86682Scalum * this is a no-op at the moment, here, since nfsd is 32-bit, but
947cee86682Scalum * that could change.
948cee86682Scalum */
949cee86682Scalum bufsize = (uint32_t)buflen;
950cee86682Scalum error = _nfssys(NFS4_DSS_SETPATHS_SIZE, &bufsize);
951cee86682Scalum if (error) {
952250a0733Sth199096 fprintf(stderr,
953b9709d3bSYuri Pankov "_nfssys(NFS4_DSS_SETPATHS_SIZE) failed: %s\n",
954cee86682Scalum strerror(errno));
955cee86682Scalum free(bufp);
956cee86682Scalum return (1);
957cee86682Scalum }
958cee86682Scalum
959cee86682Scalum /* Pass the packed buffer to the kernel */
960cee86682Scalum error = _nfssys(NFS4_DSS_SETPATHS, bufp);
961cee86682Scalum if (error) {
962250a0733Sth199096 fprintf(stderr,
963b9709d3bSYuri Pankov "_nfssys(NFS4_DSS_SETPATHS) failed: %s\n", strerror(errno));
964cee86682Scalum free(bufp);
965cee86682Scalum return (1);
966cee86682Scalum }
967cee86682Scalum
968cee86682Scalum /*
969cee86682Scalum * The kernel has now unpacked the buffer and extracted the
970cee86682Scalum * pathnames array, we no longer need the buffer.
971cee86682Scalum */
972cee86682Scalum free(bufp);
973cee86682Scalum
974cee86682Scalum return (0);
975cee86682Scalum }
976cee86682Scalum
977cee86682Scalum /*
978cee86682Scalum * Quick sort string compare routine, for qsort.
979cee86682Scalum * Needed to make arg types correct.
980cee86682Scalum */
981cee86682Scalum int
qstrcmp(const void * p1,const void * p2)982cee86682Scalum qstrcmp(const void *p1, const void *p2)
983cee86682Scalum {
984cee86682Scalum char *s1 = *((char **)p1);
985cee86682Scalum char *s2 = *((char **)p2);
986cee86682Scalum
987cee86682Scalum return (strcmp(s1, s2));
988cee86682Scalum }
989