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