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