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