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> 65*dd51520eSPavan 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> 77*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include <libscf.h> 78*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include <libshare.h> 797c478bd9Sstevel@tonic-gate #include "nfs_tbind.h" 807c478bd9Sstevel@tonic-gate #include "thrpool.h" 81*dd51520eSPavan 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; 1417c478bd9Sstevel@tonic-gate int maxservers = 1; /* 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; 157*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States char name[PATH_MAX], value[PATH_MAX]; 158*dd51520eSPavan 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 /* 182*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States * Read in the values from SMF first before we check 183*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States * command line options so the options override SMF values. 1847c478bd9Sstevel@tonic-gate */ 185*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States bufsz = PATH_MAX; 186*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States ret = nfs_smf_get_prop("max_connections", value, DEFAULT_INSTANCE, 187*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States SCF_TYPE_INTEGER, NFSD, &bufsz); 188*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States if (ret == SA_OK) { 1897c478bd9Sstevel@tonic-gate errno = 0; 190*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States max_conns_allowed = strtol(value, (char **)NULL, 10); 191*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States if (errno != 0) 1927c478bd9Sstevel@tonic-gate max_conns_allowed = -1; 1937c478bd9Sstevel@tonic-gate } 194*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 195*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States bufsz = PATH_MAX; 196*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States ret = nfs_smf_get_prop("listen_backlog", value, DEFAULT_INSTANCE, 197*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States SCF_TYPE_INTEGER, NFSD, &bufsz); 198*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States if (ret == SA_OK) { 1997c478bd9Sstevel@tonic-gate errno = 0; 200*dd51520eSPavan 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 } 205*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 206*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States bufsz = PATH_MAX; 207*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States ret = nfs_smf_get_prop("protocol", value, DEFAULT_INSTANCE, 208*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States SCF_TYPE_ASTRING, NFSD, &bufsz); 209*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States if ((ret == SA_OK) && strlen(value) > 0) { 210*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States df_proto = strdup(value); 2117c478bd9Sstevel@tonic-gate opt_cnt++; 212*dd51520eSPavan 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 } 218*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 219*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States bufsz = PATH_MAX; 220*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States ret = nfs_smf_get_prop("device", value, DEFAULT_INSTANCE, 221*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States SCF_TYPE_ASTRING, NFSD, &bufsz); 222*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States if ((ret == SA_OK) && strlen(value) > 0) { 223*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States df_provider = strdup(value); 2247c478bd9Sstevel@tonic-gate opt_cnt++; 2257c478bd9Sstevel@tonic-gate } 226*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 227*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States bufsz = PATH_MAX; 228*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States ret = nfs_smf_get_prop("servers", value, DEFAULT_INSTANCE, 229*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States SCF_TYPE_INTEGER, NFSD, &bufsz); 230*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States if (ret == SA_OK) { 2317c478bd9Sstevel@tonic-gate errno = 0; 232*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States maxservers = strtol(value, (char **)NULL, 10); 233*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States if (errno != 0) 2347c478bd9Sstevel@tonic-gate maxservers = 1; 235*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States else 2367c478bd9Sstevel@tonic-gate maxservers_set = 1; 2377c478bd9Sstevel@tonic-gate } 2387c478bd9Sstevel@tonic-gate 239*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States bufsz = 4; 240*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States ret = nfs_smf_get_prop("server_versmin", value, DEFAULT_INSTANCE, 241*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States SCF_TYPE_INTEGER, NFSD, &bufsz); 242*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States if (ret == SA_OK) 243*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States nfs_server_vers_min = strtol(value, (char **)NULL, 10); 244*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 245*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States bufsz = 4; 246*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States ret = nfs_smf_get_prop("server_versmax", value, DEFAULT_INSTANCE, 247*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States SCF_TYPE_INTEGER, NFSD, &bufsz); 248*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States if (ret == SA_OK) 249*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States nfs_server_vers_max = strtol(value, (char **)NULL, 10); 250*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 251*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States bufsz = PATH_MAX; 252*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States ret = nfs_smf_get_prop("server_delegation", value, DEFAULT_INSTANCE, 253*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States SCF_TYPE_ASTRING, NFSD, &bufsz); 254*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States if (ret == SA_OK) 255*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States if (strncasecmp(value, "off", 3) == 0) 256*dd51520eSPavan 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" 264*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States "in SMF:\n" 265*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States "\tprotocol=ALL\n" 266*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States "\tprotocol=protocol\n" 267*dd51520eSPavan 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: 446250a0733Sth199096 fprintf(stderr, "error locking for %s: %s", 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) { 461250a0733Sth199096 fprintf(stderr, "%s", "dss_init failed. Exiting."); 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, 4757c478bd9Sstevel@tonic-gate "Number of servers not specified. Using default of %d.", 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)) { 493250a0733Sth199096 fprintf(stderr, "Can't set up kernel NFS service: %s. Exiting", 494250a0733Sth199096 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)) { 502250a0733Sth199096 fprintf(stderr, "Can't set up NFS pool creator: %s. Exiting", 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, 519ed629aefSSiddheshwar Mahesh "Can't set up RDMA creator thread : %s", 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) { 553250a0733Sth199096 fprintf(stderr, "setnetconfig failed : %s", 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) { 563250a0733Sth199096 fprintf(stderr, "setnetconfig failed : %s", 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, 577250a0733Sth199096 "couldn't find netconfig entry for protocol %s", 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." 596250a0733Sth199096 " Exiting"); 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) { 807250a0733Sth199096 fprintf(stderr, "stable storage path too long: %s%s. Exiting", 808cee86682Scalum 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: " 817cee86682Scalum "%s: %s. Exiting", 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) { 873250a0733Sth199096 fprintf(stderr, "tmp_pathnames malloc failed"); 874cee86682Scalum exit(1); 875cee86682Scalum } 876cee86682Scalum 877cee86682Scalum for (i = 0, j = 0; i < npaths; i++) 878cee86682Scalum if (pathnames[i] != NULL) 879cee86682Scalum tmp_pathnames[j++] = pathnames[i]; 880cee86682Scalum free(pathnames); 881cee86682Scalum pathnames = tmp_pathnames; 882cee86682Scalum npaths = nreal; 883cee86682Scalum } 884cee86682Scalum 885cee86682Scalum } 886cee86682Scalum 887cee86682Scalum /* Create directories to store the distributed state files */ 888cee86682Scalum dss_mkleafdirs(npaths, pathnames); 889cee86682Scalum 890cee86682Scalum /* Create the name-value pair list */ 891cee86682Scalum error = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0); 892cee86682Scalum if (error) { 893250a0733Sth199096 fprintf(stderr, "nvlist_alloc failed: %s.", strerror(errno)); 894cee86682Scalum return (1); 895cee86682Scalum } 896cee86682Scalum 897cee86682Scalum /* Add the pathnames array as a single name-value pair */ 898cee86682Scalum error = nvlist_add_string_array(nvl, NFS4_DSS_NVPAIR_NAME, 899cee86682Scalum pathnames, npaths); 900cee86682Scalum if (error) { 901250a0733Sth199096 fprintf(stderr, "nvlist_add_string_array failed: %s.", 902cee86682Scalum strerror(errno)); 903cee86682Scalum nvlist_free(nvl); 904cee86682Scalum return (1); 905cee86682Scalum } 906cee86682Scalum 907cee86682Scalum /* 908cee86682Scalum * Pack list into contiguous memory, for passing to kernel. 909cee86682Scalum * nvlist_pack() will allocate the memory for the buffer, 910cee86682Scalum * which we should free() when no longer needed. 911cee86682Scalum * NV_ENCODE_XDR for safety across ILP32/LP64 kernel boundary. 912cee86682Scalum */ 913cee86682Scalum bufp = NULL; 914cee86682Scalum error = nvlist_pack(nvl, &bufp, &buflen, NV_ENCODE_XDR, 0); 915cee86682Scalum if (error) { 916250a0733Sth199096 fprintf(stderr, "nvlist_pack failed: %s.", strerror(errno)); 917cee86682Scalum nvlist_free(nvl); 918cee86682Scalum return (1); 919cee86682Scalum } 920cee86682Scalum 921cee86682Scalum /* Now we have the packed buffer, we no longer need the list */ 922cee86682Scalum nvlist_free(nvl); 923cee86682Scalum 924cee86682Scalum /* 925cee86682Scalum * Let the kernel know in advance how big the buffer is. 926cee86682Scalum * NOTE: we cannot just pass buflen, since size_t is a long, and 927cee86682Scalum * thus a different size between ILP32 userland and LP64 kernel. 928cee86682Scalum * Use an int for the transfer, since that should be big enough; 929cee86682Scalum * this is a no-op at the moment, here, since nfsd is 32-bit, but 930cee86682Scalum * that could change. 931cee86682Scalum */ 932cee86682Scalum bufsize = (uint32_t)buflen; 933cee86682Scalum error = _nfssys(NFS4_DSS_SETPATHS_SIZE, &bufsize); 934cee86682Scalum if (error) { 935250a0733Sth199096 fprintf(stderr, 936cee86682Scalum "_nfssys(NFS4_DSS_SETPATHS_SIZE) failed: %s. ", 937cee86682Scalum strerror(errno)); 938cee86682Scalum free(bufp); 939cee86682Scalum return (1); 940cee86682Scalum } 941cee86682Scalum 942cee86682Scalum /* Pass the packed buffer to the kernel */ 943cee86682Scalum error = _nfssys(NFS4_DSS_SETPATHS, bufp); 944cee86682Scalum if (error) { 945250a0733Sth199096 fprintf(stderr, 946cee86682Scalum "_nfssys(NFS4_DSS_SETPATHS) failed: %s. ", strerror(errno)); 947cee86682Scalum free(bufp); 948cee86682Scalum return (1); 949cee86682Scalum } 950cee86682Scalum 951cee86682Scalum /* 952cee86682Scalum * The kernel has now unpacked the buffer and extracted the 953cee86682Scalum * pathnames array, we no longer need the buffer. 954cee86682Scalum */ 955cee86682Scalum free(bufp); 956cee86682Scalum 957cee86682Scalum return (0); 958cee86682Scalum } 959cee86682Scalum 960cee86682Scalum /* 961cee86682Scalum * Quick sort string compare routine, for qsort. 962cee86682Scalum * Needed to make arg types correct. 963cee86682Scalum */ 964cee86682Scalum int 965cee86682Scalum qstrcmp(const void *p1, const void *p2) 966cee86682Scalum { 967cee86682Scalum char *s1 = *((char **)p1); 968cee86682Scalum char *s2 = *((char **)p2); 969cee86682Scalum 970cee86682Scalum return (strcmp(s1, s2)); 971cee86682Scalum } 972