nfsd.c revision 004388ebfdfe2ed7dfd2d153a876dfcc22d2c006
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T		*/
27/*	  All Rights Reserved  	*/
28
29/*
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
32 * All Rights Reserved
33 *
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
37 */
38
39/* LINTLIBRARY */
40/* PROTOLIB1 */
41
42#pragma ident	"%Z%%M%	%I%	%E% SMI"
43
44/* NFS server */
45
46#include <sys/param.h>
47#include <sys/types.h>
48#include <syslog.h>
49#include <tiuser.h>
50#include <rpc/rpc.h>
51#include <errno.h>
52#include <thread.h>
53#include <sys/resource.h>
54#include <sys/time.h>
55#include <sys/file.h>
56#include <nfs/nfs.h>
57#include <nfs/nfs_acl.h>
58#include <nfs/nfssys.h>
59#include <stdio.h>
60#include <stdio_ext.h>
61#include <stdlib.h>
62#include <signal.h>
63#include <netconfig.h>
64#include <netdir.h>
65#include <string.h>
66#include <unistd.h>
67#include <stropts.h>
68#include <sys/tihdr.h>
69#include <poll.h>
70#include <priv_utils.h>
71#include <sys/tiuser.h>
72#include <netinet/tcp.h>
73#include <deflt.h>
74#include <rpcsvc/daemon_utils.h>
75#include <rpcsvc/nfs4_prot.h>
76#include "nfs_tbind.h"
77#include "thrpool.h"
78
79/* quiesce requests will be ignored if nfs_server_vers_max < QUIESCE_VERSMIN */
80#define	QUIESCE_VERSMIN	4
81
82static	int	nfssvc(int, struct netbuf, struct netconfig *);
83static int nfssvcpool(int maxservers);
84static	void	usage(void);
85
86extern	int	_nfssys(int, void *);
87
88/* signal handlers */
89static void sigflush(int);
90static void quiesce(int);
91
92static	char	*MyName;
93static	NETSELDECL(defaultproviders)[] = { "/dev/tcp6", "/dev/tcp", "/dev/udp",
94					    "/dev/udp6", NULL };
95/* static	NETSELDECL(defaultprotos)[] =	{ NC_UDP, NC_TCP, NULL }; */
96/*
97 * The following are all globals used by routines in nfs_tbind.c.
98 */
99size_t	end_listen_fds;		/* used by conn_close_oldest() */
100size_t	num_fds = 0;		/* used by multiple routines */
101int	listen_backlog = 32;	/* used by bind_to_{provider,proto}() */
102int	num_servers;		/* used by cots_listen_event() */
103int	(*Mysvc)(int, struct netbuf, struct netconfig *) = nfssvc;
104				/* used by cots_listen_event() */
105int	max_conns_allowed = -1;	/* used by cots_listen_event() */
106
107/*
108 * Keep track of min/max versions of NFS protocol to be started.
109 * Start with the defaults (min == 2, max == 3).  We have the
110 * capability of starting vers=4 but only if the user requests it.
111 */
112int	nfs_server_vers_min = NFS_VERSMIN_DEFAULT;
113int	nfs_server_vers_max = NFS_VERSMAX_DEFAULT;
114
115/*
116 * Set the default for server delegation enablement and set per
117 * /etc/default/nfs configuration (if present).
118 */
119int	nfs_server_delegation = NFS_SERVER_DELEGATION_DEFAULT;
120
121int
122main(int ac, char *av[])
123{
124	char *dir = "/";
125	int allflag = 0;
126	int df_allflag = 0;
127	int opt_cnt = 0;
128	int maxservers = 1;	/* zero allows inifinte number of threads */
129	int maxservers_set = 0;
130	int logmaxservers = 0;
131	int pid;
132	int i;
133	char *provider = (char *)NULL;
134	char *df_provider = (char *)NULL;
135	struct protob *protobp0, *protobp;
136	NETSELDECL(proto) = NULL;
137	NETSELDECL(df_proto) = NULL;
138	NETSELPDECL(providerp);
139	char *defval;
140	boolean_t can_do_mlp;
141
142	MyName = *av;
143
144	/*
145	 * Initializations that require more privileges than we need to run.
146	 */
147	(void) _create_daemon_lock(NFSD, DAEMON_UID, DAEMON_GID);
148	svcsetprio();
149
150	can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
151	if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET,
152	    DAEMON_UID, DAEMON_GID, PRIV_SYS_NFS,
153	    can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) {
154		(void) fprintf(stderr, "%s should be run with"
155			" sufficient privileges\n", av[0]);
156		exit(1);
157	}
158
159	(void) enable_extended_FILE_stdio(-1, -1);
160
161	/*
162	 * Read in the values from config file first before we check
163	 * commandline options so the options override the file.
164	 */
165	if ((defopen(NFSADMIN)) == 0) {
166		if ((defval = defread("NFSD_MAX_CONNECTIONS=")) != NULL) {
167			errno = 0;
168			max_conns_allowed = strtol(defval, (char **)NULL, 10);
169			if (errno != 0) {
170				max_conns_allowed = -1;
171			}
172		}
173		if ((defval = defread("NFSD_LISTEN_BACKLOG=")) != NULL) {
174			errno = 0;
175			listen_backlog = strtol(defval, (char **)NULL, 10);
176			if (errno != 0) {
177				listen_backlog = 32;
178			}
179		}
180		if ((defval = defread("NFSD_PROTOCOL=")) != NULL) {
181			df_proto = strdup(defval);
182			opt_cnt++;
183			if (strncasecmp("ALL", defval, 3) == 0) {
184				free(df_proto);
185				df_proto = NULL;
186				df_allflag = 1;
187			}
188		}
189		if ((defval = defread("NFSD_DEVICE=")) != NULL) {
190			df_provider = strdup(defval);
191			opt_cnt++;
192		}
193		if ((defval = defread("NFSD_SERVERS=")) != NULL) {
194			errno = 0;
195			maxservers = strtol(defval, (char **)NULL, 10);
196			if (errno != 0) {
197				maxservers = 1;
198			} else {
199				maxservers_set = 1;
200			}
201		}
202		if ((defval = defread("NFS_SERVER_VERSMIN=")) != NULL) {
203			errno = 0;
204			nfs_server_vers_min =
205				strtol(defval, (char **)NULL, 10);
206			if (errno != 0) {
207				nfs_server_vers_min = NFS_VERSMIN_DEFAULT;
208			}
209		}
210		if ((defval = defread("NFS_SERVER_VERSMAX=")) != NULL) {
211			errno = 0;
212			nfs_server_vers_max =
213				strtol(defval, (char **)NULL, 10);
214			if (errno != 0) {
215				nfs_server_vers_max = NFS_VERSMAX_DEFAULT;
216			}
217		}
218		if ((defval = defread("NFS_SERVER_DELEGATION=")) != NULL) {
219			if (strcmp(defval, "off") == 0) {
220				nfs_server_delegation = FALSE;
221			}
222		}
223
224		/* close defaults file */
225		defopen(NULL);
226	}
227
228	/*
229	 * Conflict options error messages.
230	 */
231	if (opt_cnt > 1) {
232		(void) fprintf(stderr, "\nConflicting options, only one of "
233		    "the following options can be specified\n"
234		    "in " NFSADMIN ":\n"
235		    "\tNFSD_PROTOCOL=ALL\n"
236		    "\tNFSD_PROTOCOL=protocol\n"
237		    "\tNFSD_DEVICE=device\n\n");
238		usage();
239	}
240	opt_cnt = 0;
241
242	while ((i = getopt(ac, av, "ac:p:t:l:")) != EOF) {
243		switch (i) {
244		case 'a':
245			free(df_proto);
246			df_proto = NULL;
247			free(df_provider);
248			df_provider = NULL;
249
250			allflag = 1;
251			opt_cnt++;
252			break;
253
254		case 'c':
255			max_conns_allowed = atoi(optarg);
256			break;
257
258		case 'p':
259			proto = optarg;
260			df_allflag = 0;
261			opt_cnt++;
262			break;
263
264		case 't':
265			provider = optarg;
266			df_allflag = 0;
267			opt_cnt++;
268			break;
269
270		case 'l':
271			listen_backlog = atoi(optarg);
272			break;
273
274		case '?':
275			usage();
276			/* NOTREACHED */
277		}
278	}
279
280	allflag = df_allflag;
281	if (proto == NULL)
282		proto = df_proto;
283	if (provider == NULL)
284		provider = df_provider;
285
286	/*
287	 * Conflict options error messages.
288	 */
289	if (opt_cnt > 1) {
290		(void) fprintf(stderr, "\nConflicting options, only one of "
291		    "the following options can be specified\n"
292		    "on the command line:\n"
293		    "\t-a\n"
294		    "\t-p protocol\n"
295		    "\t-t transport\n\n");
296		usage();
297	}
298
299	if (proto != NULL &&
300	    strncasecmp(proto, NC_UDP, strlen(NC_UDP)) == 0) {
301		if (nfs_server_vers_max == NFS_V4) {
302			if (nfs_server_vers_min == NFS_V4) {
303				syslog(LOG_ERR,
304					"NFS version 4 is not supported "
305					"with the UDP protocol.  Exiting\n");
306				fprintf(stderr,
307					"NFS version 4 is not supported "
308					"with the UDP protocol.  Exiting\n");
309				exit(3);
310			} else {
311				fprintf(stderr,
312					"NFS version 4 is not supported "
313					"with the UDP protocol.\n");
314			}
315		}
316	}
317
318	/*
319	 * If there is exactly one more argument, it is the number of
320	 * servers.
321	 */
322	if (optind == ac - 1) {
323		maxservers = atoi(av[optind]);
324		maxservers_set = 1;
325	}
326	/*
327	 * If there are two or more arguments, then this is a usage error.
328	 */
329	else if (optind < ac - 1)
330		usage();
331	/*
332	 * Check the ranges for min/max version specified
333	 */
334	else if ((nfs_server_vers_min > nfs_server_vers_max) ||
335		(nfs_server_vers_min < NFS_VERSMIN) ||
336		(nfs_server_vers_max > NFS_VERSMAX))
337		usage();
338	/*
339	 * There are no additional arguments, and we haven't set maxservers
340	 * explicitly via the config file, we use a default number of
341	 * servers.  We will log this.
342	 */
343	else if (maxservers_set == 0)
344		logmaxservers = 1;
345
346	/*
347	 * Basic Sanity checks on options
348	 *
349	 * max_conns_allowed must be positive, except for the special
350	 * value of -1 which is used internally to mean unlimited, -1 isn't
351	 * documented but we allow it anyway.
352	 *
353	 * maxservers must be positive
354	 * listen_backlog must be positive or zero
355	 */
356	if (((max_conns_allowed != -1) && (max_conns_allowed <= 0)) ||
357	    (listen_backlog < 0) || (maxservers <= 0)) {
358		usage();
359	}
360
361	/*
362	 * Set current dir to server root
363	 */
364	if (chdir(dir) < 0) {
365		(void) fprintf(stderr, "%s:  ", MyName);
366		perror(dir);
367		exit(1);
368	}
369
370#ifndef DEBUG
371	/*
372	 * Background
373	 */
374	pid = fork();
375	if (pid < 0) {
376		perror("nfsd: fork");
377		exit(1);
378	}
379	if (pid != 0)
380		exit(0);
381
382	/*
383	 * Close existing file descriptors, open "/dev/null" as
384	 * standard input, output, and error, and detach from
385	 * controlling terminal.
386	 */
387	closefrom(0);
388	(void) open("/dev/null", O_RDONLY);
389	(void) open("/dev/null", O_WRONLY);
390	(void) dup(1);
391	(void) setsid();
392#endif
393	openlog(MyName, LOG_PID | LOG_NDELAY, LOG_DAEMON);
394
395	/*
396	 * establish our lock on the lock file and write our pid to it.
397	 * exit if some other process holds the lock, or if there's any
398	 * error in writing/locking the file.
399	 */
400	pid = _enter_daemon_lock(NFSD);
401	switch (pid) {
402	case 0:
403		break;
404	case -1:
405		syslog(LOG_ERR, "error locking for %s: %s", NFSD,
406		    strerror(errno));
407		exit(2);
408	default:
409		/* daemon was already running */
410		exit(0);
411	}
412
413	sigset(SIGTERM, sigflush);
414	sigset(SIGUSR1, quiesce);
415
416	if (logmaxservers) {
417		(void) syslog(LOG_INFO,
418			"Number of servers not specified. Using default of %d.",
419			maxservers);
420	}
421
422	/*
423	 * Make sure to unregister any previous versions in case the
424	 * user is reconfiguring the server in interesting ways.
425	 */
426	svc_unreg(NFS_PROGRAM, NFS_VERSION);
427	svc_unreg(NFS_PROGRAM, NFS_V3);
428	svc_unreg(NFS_PROGRAM, NFS_V4);
429	svc_unreg(NFS_ACL_PROGRAM, NFS_ACL_V2);
430	svc_unreg(NFS_ACL_PROGRAM, NFS_ACL_V3);
431
432	/*
433	 * Set up kernel RPC thread pool for the NFS server.
434	 */
435	if (nfssvcpool(maxservers)) {
436		(void) syslog(LOG_ERR,
437			"Can't set up kernel NFS service: %m. Exiting");
438		exit(1);
439	}
440
441
442	/*
443	 * Set up blocked thread to do LWP creation on behalf of the kernel.
444	 */
445	if (svcwait(NFS_SVCPOOL_ID)) {
446		(void) syslog(LOG_ERR,
447		    "Can't set up NFS pool creator: %m, Exiting");
448		exit(1);
449	}
450
451	/*
452	 * RDMA start and stop thread.
453	 * Per pool RDMA listener creation and
454	 * destructor thread.
455	 *
456	 * start rdma services and block in the kernel.
457	 */
458	if (svcrdma(NFS_SVCPOOL_ID, nfs_server_vers_min, nfs_server_vers_max,
459		nfs_server_delegation)) {
460		(void) syslog(LOG_ERR,
461		    "Can't set up RDMA creator thread : %m.");
462	}
463
464	/*
465	 * Build a protocol block list for registration.
466	 */
467	protobp0 = protobp = (struct protob *)malloc(sizeof (struct protob));
468	protobp->serv = "NFS";
469	protobp->versmin = nfs_server_vers_min;
470	protobp->versmax = nfs_server_vers_max;
471	protobp->program = NFS_PROGRAM;
472
473	protobp->next = (struct protob *)malloc(sizeof (struct protob));
474	protobp = protobp->next;
475	protobp->serv = "NFS_ACL";		/* not used */
476	protobp->versmin = nfs_server_vers_min;
477	/* XXX - this needs work to get the version just right */
478	protobp->versmax = (nfs_server_vers_max > NFS_ACL_V3) ?
479		NFS_ACL_V3 : nfs_server_vers_max;
480	protobp->program = NFS_ACL_PROGRAM;
481	protobp->next = (struct protob *)NULL;
482
483	if (allflag) {
484		if (do_all(protobp0, nfssvc) == -1)
485			exit(1);
486	} else if (proto) {
487		/* there's more than one match for the same protocol */
488		struct netconfig *nconf;
489		NCONF_HANDLE *nc;
490		bool_t	protoFound = FALSE;
491		if ((nc = setnetconfig()) == (NCONF_HANDLE *) NULL) {
492			syslog(LOG_ERR, "setnetconfig failed: %m");
493			goto done;
494		}
495		while (nconf = getnetconfig(nc)) {
496			if (strcmp(nconf->nc_proto, proto) == 0) {
497				protoFound = TRUE;
498				do_one(nconf->nc_device, NULL,
499					protobp0, nfssvc);
500			}
501		}
502		(void) endnetconfig(nc);
503		if (protoFound == FALSE)
504			syslog(LOG_ERR, "couldn't find netconfig entry \
505for protocol %s", proto);
506
507	} else if (provider)
508		do_one(provider, proto, protobp0, nfssvc);
509	else {
510		for (providerp = defaultproviders;
511			*providerp != NULL; providerp++) {
512			provider = *providerp;
513			do_one(provider, NULL, protobp0, nfssvc);
514		}
515	}
516done:
517
518	free(protobp);
519	free(protobp0);
520
521	if (num_fds == 0) {
522		(void) syslog(LOG_ERR,
523		"Could not start NFS service for any protocol. Exiting.");
524		exit(1);
525	}
526
527	end_listen_fds = num_fds;
528
529	/*
530	 * Get rid of unneeded privileges.
531	 */
532	__fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION,
533	    PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL);
534
535	/*
536	 * Poll for non-data control events on the transport descriptors.
537	 */
538	poll_for_action();
539
540	/*
541	 * If we get here, something failed in poll_for_action().
542	 */
543	return (1);
544}
545
546static int
547nfssvcpool(int maxservers)
548{
549	struct svcpool_args npa;
550
551	npa.id = NFS_SVCPOOL_ID;
552	npa.maxthreads = maxservers;
553	npa.redline = 0;
554	npa.qsize = 0;
555	npa.timeout = 0;
556	npa.stksize = 0;
557	npa.max_same_xprt = 0;
558	return (_nfssys(SVCPOOL_CREATE, &npa));
559}
560
561/*
562 * Establish NFS service thread.
563 */
564static int
565nfssvc(int fd, struct netbuf addrmask, struct netconfig *nconf)
566{
567	struct nfs_svc_args nsa;
568
569	nsa.fd = fd;
570	nsa.netid = nconf->nc_netid;
571	nsa.addrmask = addrmask;
572	if (strncasecmp(nconf->nc_proto, NC_UDP, strlen(NC_UDP)) == 0) {
573		nsa.versmax = (nfs_server_vers_max > NFS_V3) ?
574			NFS_V3 : nfs_server_vers_max;
575		nsa.versmin = nfs_server_vers_min;
576		/*
577		 * If no version left, silently do nothing, previous
578		 * checks will have assured at least TCP is available.
579		 */
580		if (nsa.versmin > nsa.versmax)
581			return (0);
582	} else {
583		nsa.versmax = nfs_server_vers_max;
584		nsa.versmin = nfs_server_vers_min;
585	}
586	nsa.delegation = nfs_server_delegation;
587	return (_nfssys(NFS_SVC, &nsa));
588}
589
590static void
591usage(void)
592{
593	(void) fprintf(stderr,
594"usage: %s [ -a ] [ -c max_conns ] [ -p protocol ] [ -t transport ] ", MyName);
595	(void) fprintf(stderr, "\n[ -l listen_backlog ] [ nservers ]\n");
596	(void) fprintf(stderr,
597"\twhere -a causes <nservers> to be started on each appropriate transport,\n");
598	(void) fprintf(stderr,
599"\tmax_conns is the maximum number of concurrent connections allowed,\n");
600	(void) fprintf(stderr, "\t\tand max_conns must be a decimal number");
601	(void) fprintf(stderr, "> zero,\n");
602	(void) fprintf(stderr, "\tprotocol is a protocol identifier,\n");
603	(void) fprintf(stderr,
604		"\ttransport is a transport provider name (i.e. device),\n");
605	(void) fprintf(stderr,
606		"\tlisten_backlog is the TCP listen backlog,\n");
607	(void) fprintf(stderr,
608		"\tand <nservers> must be a decimal number > zero.\n");
609	exit(1);
610}
611
612/*
613 * Issue nfssys system call to flush all logging buffers asynchronously.
614 *
615 * NOTICE: It is extremely important to flush NFS logging buffers when
616 *	   nfsd exits. When the system is halted or rebooted nfslogd
617 *	   may not have an opportunity to flush the buffers.
618 */
619static void
620nfsl_flush()
621{
622	struct nfsl_flush_args nfa;
623
624	memset((void *)&nfa, 0, sizeof (nfa));
625	nfa.version = NFSL_FLUSH_ARGS_VERS;
626	nfa.directive = NFSL_ALL;	/* flush all asynchronously */
627
628	if (_nfssys(LOG_FLUSH, &nfa) < 0)
629		syslog(LOG_ERR, "_nfssys(LOG_FLUSH) failed: %s\n",
630			strerror(errno));
631}
632
633/*
634 * SIGTERM handler.
635 * Flush logging buffers and exit.
636 */
637static void
638sigflush(int sig)
639{
640	nfsl_flush();
641	exit(0);
642}
643
644/*
645 * SIGUSR1 handler.
646 * Request server quiesce, then exit. For subsequent warm start.
647 * Equivalent to SIGTERM handler if nfs_server_vers_max < QUIESCE_VERSMIN.
648 */
649static void
650quiesce(int sig)
651{
652	int error;
653	int id = NFS_SVCPOOL_ID;
654
655	if (nfs_server_vers_max >= QUIESCE_VERSMIN) {
656		/* Request server quiesce at next shutdown */
657		error = _nfssys(NFS_SVC_REQUEST_QUIESCE, &id);
658		if (error) {
659			syslog(LOG_ERR,
660			    "_nfssys(NFS_SVC_REQUEST_QUIESCE) failed: %s\n",
661			    strerror(errno));
662			return;
663		}
664	}
665
666	/* Flush logging buffers */
667	nfsl_flush();
668
669	exit(0);
670}
671