xref: /titanic_51/usr/src/cmd/fs.d/nfs/nfsd/nfsd.c (revision 371c605ba674f768d61b9c4227e0a3382ba4db75)
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 
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 	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 \
505 for 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 	}
516 done:
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 
546 static int
547 nfssvcpool(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  */
564 static int
565 nfssvc(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 
590 static void
591 usage(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  */
619 static void
620 nfsl_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  */
637 static void
638 sigflush(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  */
649 static void
650 quiesce(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