Print this page
Marcel's update to 7651
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/fs.d/nfs/nfsd/nfsd.c
+++ new/usr/src/cmd/fs.d/nfs/nfsd/nfsd.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 */
24 24
25 25 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
26 26 /* All Rights Reserved */
27 27
28 28 /*
29 29 * University Copyright- Copyright (c) 1982, 1986, 1988
30 30 * The Regents of the University of California
31 31 * All Rights Reserved
32 32 *
33 33 * University Acknowledgment- Portions of this document are derived from
34 34 * software developed by the University of California, Berkeley, and its
35 35 * contributors.
36 36 */
37 37
38 38 /* LINTLIBRARY */
39 39 /* PROTOLIB1 */
40 40
41 41 /* NFS server */
42 42
43 43 #include <sys/param.h>
44 44 #include <sys/types.h>
45 45 #include <sys/stat.h>
46 46 #include <syslog.h>
47 47 #include <tiuser.h>
48 48 #include <rpc/rpc.h>
49 49 #include <errno.h>
50 50 #include <thread.h>
51 51 #include <sys/resource.h>
52 52 #include <sys/time.h>
53 53 #include <sys/file.h>
54 54 #include <nfs/nfs.h>
55 55 #include <nfs/nfs_acl.h>
56 56 #include <nfs/nfssys.h>
57 57 #include <stdio.h>
58 58 #include <stdio_ext.h>
59 59 #include <stdlib.h>
60 60 #include <signal.h>
61 61 #include <netconfig.h>
62 62 #include <netdir.h>
63 63 #include <string.h>
64 64 #include <unistd.h>
65 65 #include <limits.h>
66 66 #include <stropts.h>
67 67 #include <sys/tihdr.h>
68 68 #include <sys/wait.h>
69 69 #include <poll.h>
70 70 #include <priv_utils.h>
71 71 #include <sys/tiuser.h>
72 72 #include <netinet/tcp.h>
73 73 #include <deflt.h>
74 74 #include <rpcsvc/daemon_utils.h>
75 75 #include <rpcsvc/nfs4_prot.h>
76 76 #include <libnvpair.h>
77 77 #include <libscf.h>
78 78 #include <libshare.h>
79 79 #include "nfs_tbind.h"
80 80 #include "thrpool.h"
81 81 #include "smfcfg.h"
82 82
83 83 /* quiesce requests will be ignored if nfs_server_vers_max < QUIESCE_VERSMIN */
84 84 #define QUIESCE_VERSMIN 4
85 85 /* DSS: distributed stable storage */
86 86 #define DSS_VERSMIN 4
87 87
88 88 static int nfssvc(int, struct netbuf, struct netconfig *);
89 89 static int nfssvcpool(int maxservers);
90 90 static int dss_init(uint_t npaths, char **pathnames);
91 91 static void dss_mkleafdirs(uint_t npaths, char **pathnames);
92 92 static void dss_mkleafdir(char *dir, char *leaf, char *path);
93 93 static void usage(void);
94 94 int qstrcmp(const void *s1, const void *s2);
95 95
96 96 extern int _nfssys(int, void *);
97 97
98 98 extern int daemonize_init(void);
99 99 extern void daemonize_fini(int fd);
100 100
101 101 /* signal handlers */
102 102 static void sigflush(int);
103 103 static void quiesce(int);
104 104
105 105 static char *MyName;
106 106 static NETSELDECL(defaultproviders)[] = { "/dev/tcp6", "/dev/tcp", "/dev/udp",
107 107 "/dev/udp6", NULL };
108 108 /* static NETSELDECL(defaultprotos)[] = { NC_UDP, NC_TCP, NULL }; */
109 109 /*
110 110 * The following are all globals used by routines in nfs_tbind.c.
111 111 */
112 112 size_t end_listen_fds; /* used by conn_close_oldest() */
113 113 size_t num_fds = 0; /* used by multiple routines */
114 114 int listen_backlog = 32; /* used by bind_to_{provider,proto}() */
115 115 int num_servers; /* used by cots_listen_event() */
116 116 int (*Mysvc)(int, struct netbuf, struct netconfig *) = nfssvc;
117 117 /* used by cots_listen_event() */
118 118 int max_conns_allowed = -1; /* used by cots_listen_event() */
119 119
120 120 /*
121 121 * Keep track of min/max versions of NFS protocol to be started.
122 122 * Start with the defaults (min == 2, max == 3). We have the
123 123 * capability of starting vers=4 but only if the user requests it.
124 124 */
125 125 int nfs_server_vers_min = NFS_VERSMIN_DEFAULT;
126 126 int nfs_server_vers_max = NFS_VERSMAX_DEFAULT;
127 127
128 128 /*
129 129 * Set the default for server delegation enablement and set per
130 130 * /etc/default/nfs configuration (if present).
|
↓ open down ↓ |
130 lines elided |
↑ open up ↑ |
131 131 */
132 132 int nfs_server_delegation = NFS_SERVER_DELEGATION_DEFAULT;
133 133
134 134 int
135 135 main(int ac, char *av[])
136 136 {
137 137 char *dir = "/";
138 138 int allflag = 0;
139 139 int df_allflag = 0;
140 140 int opt_cnt = 0;
141 - int maxservers = 1; /* zero allows inifinte number of threads */
141 + int maxservers = 1024; /* zero allows inifinte number of threads */
142 142 int maxservers_set = 0;
143 143 int logmaxservers = 0;
144 144 int pid;
145 145 int i;
146 146 char *provider = (char *)NULL;
147 147 char *df_provider = (char *)NULL;
148 148 struct protob *protobp0, *protobp;
149 149 NETSELDECL(proto) = NULL;
150 150 NETSELDECL(df_proto) = NULL;
151 151 NETSELPDECL(providerp);
152 152 char *defval;
153 153 boolean_t can_do_mlp;
154 154 uint_t dss_npaths = 0;
155 155 char **dss_pathnames = NULL;
156 156 sigset_t sgset;
157 157 char name[PATH_MAX], value[PATH_MAX];
158 158 int ret, bufsz;
159 159
160 160 int pipe_fd = -1;
161 161
162 162 MyName = *av;
163 163
164 164 /*
165 165 * Initializations that require more privileges than we need to run.
166 166 */
167 167 (void) _create_daemon_lock(NFSD, DAEMON_UID, DAEMON_GID);
168 168 svcsetprio();
169 169
170 170 can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
171 171 if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET,
172 172 DAEMON_UID, DAEMON_GID, PRIV_SYS_NFS,
173 173 can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) {
174 174 (void) fprintf(stderr, "%s should be run with"
175 175 " sufficient privileges\n", av[0]);
176 176 exit(1);
177 177 }
178 178
179 179 (void) enable_extended_FILE_stdio(-1, -1);
180 180
181 181 /*
182 182 * Read in the values from SMF first before we check
183 183 * command line options so the options override SMF values.
184 184 */
185 185 bufsz = PATH_MAX;
186 186 ret = nfs_smf_get_prop("max_connections", value, DEFAULT_INSTANCE,
187 187 SCF_TYPE_INTEGER, NFSD, &bufsz);
188 188 if (ret == SA_OK) {
189 189 errno = 0;
190 190 max_conns_allowed = strtol(value, (char **)NULL, 10);
191 191 if (errno != 0)
192 192 max_conns_allowed = -1;
193 193 }
194 194
195 195 bufsz = PATH_MAX;
196 196 ret = nfs_smf_get_prop("listen_backlog", value, DEFAULT_INSTANCE,
197 197 SCF_TYPE_INTEGER, NFSD, &bufsz);
198 198 if (ret == SA_OK) {
199 199 errno = 0;
200 200 listen_backlog = strtol(value, (char **)NULL, 10);
201 201 if (errno != 0) {
202 202 listen_backlog = 32;
203 203 }
204 204 }
205 205
206 206 bufsz = PATH_MAX;
207 207 ret = nfs_smf_get_prop("protocol", value, DEFAULT_INSTANCE,
208 208 SCF_TYPE_ASTRING, NFSD, &bufsz);
209 209 if ((ret == SA_OK) && strlen(value) > 0) {
210 210 df_proto = strdup(value);
211 211 opt_cnt++;
212 212 if (strncasecmp("ALL", value, 3) == 0) {
213 213 free(df_proto);
214 214 df_proto = NULL;
215 215 df_allflag = 1;
216 216 }
217 217 }
218 218
219 219 bufsz = PATH_MAX;
220 220 ret = nfs_smf_get_prop("device", value, DEFAULT_INSTANCE,
221 221 SCF_TYPE_ASTRING, NFSD, &bufsz);
222 222 if ((ret == SA_OK) && strlen(value) > 0) {
223 223 df_provider = strdup(value);
|
↓ open down ↓ |
72 lines elided |
↑ open up ↑ |
224 224 opt_cnt++;
225 225 }
226 226
227 227 bufsz = PATH_MAX;
228 228 ret = nfs_smf_get_prop("servers", value, DEFAULT_INSTANCE,
229 229 SCF_TYPE_INTEGER, NFSD, &bufsz);
230 230 if (ret == SA_OK) {
231 231 errno = 0;
232 232 maxservers = strtol(value, (char **)NULL, 10);
233 233 if (errno != 0)
234 - maxservers = 1;
234 + maxservers = 1024;
235 235 else
236 236 maxservers_set = 1;
237 237 }
238 238
239 239 bufsz = 4;
240 240 ret = nfs_smf_get_prop("server_versmin", value, DEFAULT_INSTANCE,
241 241 SCF_TYPE_INTEGER, NFSD, &bufsz);
242 242 if (ret == SA_OK)
243 243 nfs_server_vers_min = strtol(value, (char **)NULL, 10);
244 244
245 245 bufsz = 4;
246 246 ret = nfs_smf_get_prop("server_versmax", value, DEFAULT_INSTANCE,
247 247 SCF_TYPE_INTEGER, NFSD, &bufsz);
248 248 if (ret == SA_OK)
249 249 nfs_server_vers_max = strtol(value, (char **)NULL, 10);
250 250
251 251 bufsz = PATH_MAX;
252 252 ret = nfs_smf_get_prop("server_delegation", value, DEFAULT_INSTANCE,
253 253 SCF_TYPE_ASTRING, NFSD, &bufsz);
254 254 if (ret == SA_OK)
255 255 if (strncasecmp(value, "off", 3) == 0)
256 256 nfs_server_delegation = FALSE;
257 257
258 258 /*
259 259 * Conflict options error messages.
260 260 */
261 261 if (opt_cnt > 1) {
262 262 (void) fprintf(stderr, "\nConflicting options, only one of "
263 263 "the following options can be specified\n"
264 264 "in SMF:\n"
265 265 "\tprotocol=ALL\n"
266 266 "\tprotocol=protocol\n"
267 267 "\tdevice=devicename\n\n");
268 268 usage();
269 269 }
270 270 opt_cnt = 0;
271 271
272 272 while ((i = getopt(ac, av, "ac:p:s:t:l:")) != EOF) {
273 273 switch (i) {
274 274 case 'a':
275 275 free(df_proto);
276 276 df_proto = NULL;
277 277 free(df_provider);
278 278 df_provider = NULL;
279 279
280 280 allflag = 1;
281 281 opt_cnt++;
282 282 break;
283 283
284 284 case 'c':
285 285 max_conns_allowed = atoi(optarg);
286 286 break;
287 287
288 288 case 'p':
289 289 proto = optarg;
290 290 df_allflag = 0;
291 291 opt_cnt++;
292 292 break;
293 293
294 294 /*
295 295 * DSS: NFSv4 distributed stable storage.
296 296 *
297 297 * This is a Contracted Project Private interface, for
298 298 * the sole use of Sun Cluster HA-NFS. See PSARC/2006/313.
299 299 */
300 300 case 's':
301 301 if (strlen(optarg) < MAXPATHLEN) {
302 302 /* first "-s" option encountered? */
303 303 if (dss_pathnames == NULL) {
304 304 /*
305 305 * Allocate maximum possible space
306 306 * required given cmdline arg count;
307 307 * "-s <path>" consumes two args.
308 308 */
309 309 size_t sz = (ac / 2) * sizeof (char *);
310 310 dss_pathnames = (char **)malloc(sz);
311 311 if (dss_pathnames == NULL) {
312 312 (void) fprintf(stderr, "%s: "
313 313 "dss paths malloc failed\n",
314 314 av[0]);
315 315 exit(1);
316 316 }
317 317 (void) memset(dss_pathnames, 0, sz);
318 318 }
319 319 dss_pathnames[dss_npaths] = optarg;
320 320 dss_npaths++;
321 321 } else {
322 322 (void) fprintf(stderr,
323 323 "%s: -s pathname too long.\n", av[0]);
324 324 }
325 325 break;
326 326
327 327 case 't':
328 328 provider = optarg;
329 329 df_allflag = 0;
330 330 opt_cnt++;
331 331 break;
332 332
333 333 case 'l':
334 334 listen_backlog = atoi(optarg);
335 335 break;
336 336
337 337 case '?':
338 338 usage();
339 339 /* NOTREACHED */
340 340 }
341 341 }
342 342
343 343 allflag = df_allflag;
344 344 if (proto == NULL)
345 345 proto = df_proto;
346 346 if (provider == NULL)
347 347 provider = df_provider;
348 348
349 349 /*
350 350 * Conflict options error messages.
351 351 */
352 352 if (opt_cnt > 1) {
353 353 (void) fprintf(stderr, "\nConflicting options, only one of "
354 354 "the following options can be specified\n"
355 355 "on the command line:\n"
356 356 "\t-a\n"
357 357 "\t-p protocol\n"
358 358 "\t-t transport\n\n");
359 359 usage();
360 360 }
361 361
362 362 if (proto != NULL &&
363 363 strncasecmp(proto, NC_UDP, strlen(NC_UDP)) == 0) {
364 364 if (nfs_server_vers_max == NFS_V4) {
365 365 if (nfs_server_vers_min == NFS_V4) {
366 366 fprintf(stderr,
367 367 "NFS version 4 is not supported "
368 368 "with the UDP protocol. Exiting\n");
369 369 exit(3);
370 370 } else {
371 371 fprintf(stderr,
372 372 "NFS version 4 is not supported "
373 373 "with the UDP protocol.\n");
374 374 }
375 375 }
376 376 }
377 377
378 378 /*
379 379 * If there is exactly one more argument, it is the number of
380 380 * servers.
381 381 */
382 382 if (optind == ac - 1) {
383 383 maxservers = atoi(av[optind]);
384 384 maxservers_set = 1;
385 385 }
386 386 /*
387 387 * If there are two or more arguments, then this is a usage error.
388 388 */
389 389 else if (optind < ac - 1)
390 390 usage();
391 391 /*
392 392 * Check the ranges for min/max version specified
393 393 */
394 394 else if ((nfs_server_vers_min > nfs_server_vers_max) ||
395 395 (nfs_server_vers_min < NFS_VERSMIN) ||
396 396 (nfs_server_vers_max > NFS_VERSMAX))
397 397 usage();
398 398 /*
399 399 * There are no additional arguments, and we haven't set maxservers
400 400 * explicitly via the config file, we use a default number of
401 401 * servers. We will log this.
402 402 */
403 403 else if (maxservers_set == 0)
404 404 logmaxservers = 1;
405 405
406 406 /*
407 407 * Basic Sanity checks on options
408 408 *
409 409 * max_conns_allowed must be positive, except for the special
410 410 * value of -1 which is used internally to mean unlimited, -1 isn't
411 411 * documented but we allow it anyway.
412 412 *
413 413 * maxservers must be positive
414 414 * listen_backlog must be positive or zero
415 415 */
416 416 if (((max_conns_allowed != -1) && (max_conns_allowed <= 0)) ||
417 417 (listen_backlog < 0) || (maxservers <= 0)) {
418 418 usage();
419 419 }
420 420
421 421 /*
422 422 * Set current dir to server root
423 423 */
424 424 if (chdir(dir) < 0) {
425 425 (void) fprintf(stderr, "%s: ", MyName);
426 426 perror(dir);
427 427 exit(1);
428 428 }
429 429
430 430 #ifndef DEBUG
431 431 pipe_fd = daemonize_init();
432 432 #endif
433 433
434 434 openlog(MyName, LOG_PID | LOG_NDELAY, LOG_DAEMON);
435 435
436 436 /*
437 437 * establish our lock on the lock file and write our pid to it.
438 438 * exit if some other process holds the lock, or if there's any
439 439 * error in writing/locking the file.
440 440 */
441 441 pid = _enter_daemon_lock(NFSD);
442 442 switch (pid) {
443 443 case 0:
444 444 break;
445 445 case -1:
446 446 fprintf(stderr, "error locking for %s: %s\n", NFSD,
447 447 strerror(errno));
448 448 exit(2);
449 449 default:
450 450 /* daemon was already running */
451 451 exit(0);
452 452 }
453 453
454 454 /*
455 455 * If we've been given a list of paths to be used for distributed
456 456 * stable storage, and provided we're going to run a version
457 457 * that supports it, setup the DSS paths.
458 458 */
459 459 if (dss_pathnames != NULL && nfs_server_vers_max >= DSS_VERSMIN) {
460 460 if (dss_init(dss_npaths, dss_pathnames) != 0) {
461 461 fprintf(stderr, "%s", "dss_init failed. Exiting.\n");
462 462 exit(1);
463 463 }
464 464 }
465 465
466 466 /*
467 467 * Block all signals till we spawn other
468 468 * threads.
469 469 */
470 470 (void) sigfillset(&sgset);
471 471 (void) thr_sigsetmask(SIG_BLOCK, &sgset, NULL);
472 472
473 473 if (logmaxservers) {
474 474 fprintf(stderr,
475 475 "Number of servers not specified. Using default of %d.\n",
476 476 maxservers);
477 477 }
478 478
479 479 /*
480 480 * Make sure to unregister any previous versions in case the
481 481 * user is reconfiguring the server in interesting ways.
482 482 */
483 483 svc_unreg(NFS_PROGRAM, NFS_VERSION);
484 484 svc_unreg(NFS_PROGRAM, NFS_V3);
485 485 svc_unreg(NFS_PROGRAM, NFS_V4);
486 486 svc_unreg(NFS_ACL_PROGRAM, NFS_ACL_V2);
487 487 svc_unreg(NFS_ACL_PROGRAM, NFS_ACL_V3);
488 488
489 489 /*
490 490 * Set up kernel RPC thread pool for the NFS server.
491 491 */
492 492 if (nfssvcpool(maxservers)) {
493 493 fprintf(stderr, "Can't set up kernel NFS service: %s. "
494 494 "Exiting.\n", strerror(errno));
495 495 exit(1);
496 496 }
497 497
498 498 /*
499 499 * Set up blocked thread to do LWP creation on behalf of the kernel.
500 500 */
501 501 if (svcwait(NFS_SVCPOOL_ID)) {
502 502 fprintf(stderr, "Can't set up NFS pool creator: %s. Exiting.\n",
503 503 strerror(errno));
504 504 exit(1);
505 505 }
506 506
507 507 /*
508 508 * RDMA start and stop thread.
509 509 * Per pool RDMA listener creation and
510 510 * destructor thread.
511 511 *
512 512 * start rdma services and block in the kernel.
513 513 * (only if proto or provider is not set to TCP or UDP)
514 514 */
515 515 if ((proto == NULL) && (provider == NULL)) {
516 516 if (svcrdma(NFS_SVCPOOL_ID, nfs_server_vers_min,
517 517 nfs_server_vers_max, nfs_server_delegation)) {
518 518 fprintf(stderr,
519 519 "Can't set up RDMA creator thread : %s\n",
520 520 strerror(errno));
521 521 }
522 522 }
523 523
524 524 /*
525 525 * Now open up for signal delivery
526 526 */
527 527
528 528 (void) thr_sigsetmask(SIG_UNBLOCK, &sgset, NULL);
529 529 sigset(SIGTERM, sigflush);
530 530 sigset(SIGUSR1, quiesce);
531 531
532 532 /*
533 533 * Build a protocol block list for registration.
534 534 */
535 535 protobp0 = protobp = (struct protob *)malloc(sizeof (struct protob));
536 536 protobp->serv = "NFS";
537 537 protobp->versmin = nfs_server_vers_min;
538 538 protobp->versmax = nfs_server_vers_max;
539 539 protobp->program = NFS_PROGRAM;
540 540
541 541 protobp->next = (struct protob *)malloc(sizeof (struct protob));
542 542 protobp = protobp->next;
543 543 protobp->serv = "NFS_ACL"; /* not used */
544 544 protobp->versmin = nfs_server_vers_min;
545 545 /* XXX - this needs work to get the version just right */
546 546 protobp->versmax = (nfs_server_vers_max > NFS_ACL_V3) ?
547 547 NFS_ACL_V3 : nfs_server_vers_max;
548 548 protobp->program = NFS_ACL_PROGRAM;
549 549 protobp->next = (struct protob *)NULL;
550 550
551 551 if (allflag) {
552 552 if (do_all(protobp0, nfssvc) == -1) {
553 553 fprintf(stderr, "setnetconfig failed : %s\n",
554 554 strerror(errno));
555 555 exit(1);
556 556 }
557 557 } else if (proto) {
558 558 /* there's more than one match for the same protocol */
559 559 struct netconfig *nconf;
560 560 NCONF_HANDLE *nc;
561 561 bool_t protoFound = FALSE;
562 562 if ((nc = setnetconfig()) == (NCONF_HANDLE *) NULL) {
563 563 fprintf(stderr, "setnetconfig failed : %s\n",
564 564 strerror(errno));
565 565 goto done;
566 566 }
567 567 while (nconf = getnetconfig(nc)) {
568 568 if (strcmp(nconf->nc_proto, proto) == 0) {
569 569 protoFound = TRUE;
570 570 do_one(nconf->nc_device, NULL,
571 571 protobp0, nfssvc);
572 572 }
573 573 }
574 574 (void) endnetconfig(nc);
575 575 if (protoFound == FALSE) {
576 576 fprintf(stderr,
577 577 "couldn't find netconfig entry for protocol %s\n",
578 578 proto);
579 579 }
580 580 } else if (provider)
581 581 do_one(provider, proto, protobp0, nfssvc);
582 582 else {
583 583 for (providerp = defaultproviders;
584 584 *providerp != NULL; providerp++) {
585 585 provider = *providerp;
586 586 do_one(provider, NULL, protobp0, nfssvc);
587 587 }
588 588 }
589 589 done:
590 590
591 591 free(protobp);
592 592 free(protobp0);
593 593
594 594 if (num_fds == 0) {
595 595 fprintf(stderr, "Could not start NFS service for any protocol."
596 596 " Exiting.\n");
597 597 exit(1);
598 598 }
599 599
600 600 end_listen_fds = num_fds;
601 601
602 602 /*
603 603 * nfsd is up and running as far as we are concerned.
604 604 */
605 605 daemonize_fini(pipe_fd);
606 606
607 607 /*
608 608 * Get rid of unneeded privileges.
609 609 */
610 610 __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION,
611 611 PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL);
612 612
613 613 /*
614 614 * Poll for non-data control events on the transport descriptors.
615 615 */
616 616 poll_for_action();
617 617
618 618 /*
619 619 * If we get here, something failed in poll_for_action().
620 620 */
621 621 return (1);
622 622 }
623 623
624 624 static int
625 625 nfssvcpool(int maxservers)
626 626 {
627 627 struct svcpool_args npa;
628 628
629 629 npa.id = NFS_SVCPOOL_ID;
630 630 npa.maxthreads = maxservers;
631 631 npa.redline = 0;
632 632 npa.qsize = 0;
633 633 npa.timeout = 0;
634 634 npa.stksize = 0;
635 635 npa.max_same_xprt = 0;
636 636 return (_nfssys(SVCPOOL_CREATE, &npa));
637 637 }
638 638
639 639 /*
640 640 * Establish NFS service thread.
641 641 */
642 642 static int
643 643 nfssvc(int fd, struct netbuf addrmask, struct netconfig *nconf)
644 644 {
645 645 struct nfs_svc_args nsa;
646 646
647 647 nsa.fd = fd;
648 648 nsa.netid = nconf->nc_netid;
649 649 nsa.addrmask = addrmask;
650 650 if (strncasecmp(nconf->nc_proto, NC_UDP, strlen(NC_UDP)) == 0) {
651 651 nsa.versmax = (nfs_server_vers_max > NFS_V3) ?
652 652 NFS_V3 : nfs_server_vers_max;
653 653 nsa.versmin = nfs_server_vers_min;
654 654 /*
655 655 * If no version left, silently do nothing, previous
656 656 * checks will have assured at least TCP is available.
657 657 */
658 658 if (nsa.versmin > nsa.versmax)
659 659 return (0);
660 660 } else {
661 661 nsa.versmax = nfs_server_vers_max;
662 662 nsa.versmin = nfs_server_vers_min;
663 663 }
664 664 nsa.delegation = nfs_server_delegation;
665 665 return (_nfssys(NFS_SVC, &nsa));
666 666 }
667 667
668 668 static void
669 669 usage(void)
670 670 {
671 671 (void) fprintf(stderr,
672 672 "usage: %s [ -a ] [ -c max_conns ] [ -p protocol ] [ -t transport ] ", MyName);
673 673 (void) fprintf(stderr, "\n[ -l listen_backlog ] [ nservers ]\n");
674 674 (void) fprintf(stderr,
675 675 "\twhere -a causes <nservers> to be started on each appropriate transport,\n");
676 676 (void) fprintf(stderr,
677 677 "\tmax_conns is the maximum number of concurrent connections allowed,\n");
678 678 (void) fprintf(stderr, "\t\tand max_conns must be a decimal number");
679 679 (void) fprintf(stderr, "> zero,\n");
680 680 (void) fprintf(stderr, "\tprotocol is a protocol identifier,\n");
681 681 (void) fprintf(stderr,
682 682 "\ttransport is a transport provider name (i.e. device),\n");
683 683 (void) fprintf(stderr,
684 684 "\tlisten_backlog is the TCP listen backlog,\n");
685 685 (void) fprintf(stderr,
686 686 "\tand <nservers> must be a decimal number > zero.\n");
687 687 exit(1);
688 688 }
689 689
690 690 /*
691 691 * Issue nfssys system call to flush all logging buffers asynchronously.
692 692 *
693 693 * NOTICE: It is extremely important to flush NFS logging buffers when
694 694 * nfsd exits. When the system is halted or rebooted nfslogd
695 695 * may not have an opportunity to flush the buffers.
696 696 */
697 697 static void
698 698 nfsl_flush()
699 699 {
700 700 struct nfsl_flush_args nfa;
701 701
702 702 memset((void *)&nfa, 0, sizeof (nfa));
703 703 nfa.version = NFSL_FLUSH_ARGS_VERS;
704 704 nfa.directive = NFSL_ALL; /* flush all asynchronously */
705 705
706 706 if (_nfssys(LOG_FLUSH, &nfa) < 0)
707 707 syslog(LOG_ERR, "_nfssys(LOG_FLUSH) failed: %s\n",
708 708 strerror(errno));
709 709 }
710 710
711 711 /*
712 712 * SIGTERM handler.
713 713 * Flush logging buffers and exit.
714 714 */
715 715 static void
716 716 sigflush(int sig)
717 717 {
718 718 nfsl_flush();
719 719 _exit(0);
720 720 }
721 721
722 722 /*
723 723 * SIGUSR1 handler.
724 724 *
725 725 * Request that server quiesce, then (nfsd) exit. For subsequent warm start.
726 726 *
727 727 * This is a Contracted Project Private interface, for the sole use
728 728 * of Sun Cluster HA-NFS. See PSARC/2004/497.
729 729 *
730 730 * Equivalent to SIGTERM handler if nfs_server_vers_max < QUIESCE_VERSMIN.
731 731 */
732 732 static void
733 733 quiesce(int sig)
734 734 {
735 735 int error;
736 736 int id = NFS_SVCPOOL_ID;
737 737
738 738 if (nfs_server_vers_max >= QUIESCE_VERSMIN) {
739 739 /* Request server quiesce at next shutdown */
740 740 error = _nfssys(NFS4_SVC_REQUEST_QUIESCE, &id);
741 741
742 742 /*
743 743 * ENOENT is returned if there is no matching SVC pool
744 744 * for the id. Possibly because the pool is not yet setup.
745 745 * In this case, just exit as if no error. For all other errors,
746 746 * just return and allow caller to retry.
747 747 */
748 748 if (error && errno != ENOENT) {
749 749 syslog(LOG_ERR,
750 750 "_nfssys(NFS4_SVC_REQUEST_QUIESCE) failed: %s",
751 751 strerror(errno));
752 752 return;
753 753 }
754 754 }
755 755
756 756 /* Flush logging buffers */
757 757 nfsl_flush();
758 758
759 759 _exit(0);
760 760 }
761 761
762 762 /*
763 763 * DSS: distributed stable storage.
764 764 * Create leaf directories as required, keeping an eye on path
765 765 * lengths. Calls exit(1) on failure.
766 766 * The pathnames passed in must already exist, and must be writeable by nfsd.
767 767 * Note: the leaf directories under NFS4_VAR_DIR are not created here;
768 768 * they're created at pkg install.
769 769 */
770 770 static void
771 771 dss_mkleafdirs(uint_t npaths, char **pathnames)
772 772 {
773 773 int i;
774 774 char *tmppath = NULL;
775 775
776 776 /*
777 777 * Create the temporary storage used by dss_mkleafdir() here,
778 778 * rather than in that function, so that it only needs to be
779 779 * done once, rather than once for each call. Too big to put
780 780 * on the function's stack.
781 781 */
782 782 tmppath = (char *)malloc(MAXPATHLEN);
783 783 if (tmppath == NULL) {
784 784 syslog(LOG_ERR, "tmppath malloc failed. Exiting");
785 785 exit(1);
786 786 }
787 787
788 788 for (i = 0; i < npaths; i++) {
789 789 char *p = pathnames[i];
790 790
791 791 dss_mkleafdir(p, NFS4_DSS_STATE_LEAF, tmppath);
792 792 dss_mkleafdir(p, NFS4_DSS_OLDSTATE_LEAF, tmppath);
793 793 }
794 794
795 795 free(tmppath);
796 796 }
797 797
798 798 /*
799 799 * Create "leaf" in "dir" (which must already exist).
800 800 * leaf: should start with a '/'
801 801 */
802 802 static void
803 803 dss_mkleafdir(char *dir, char *leaf, char *tmppath)
804 804 {
805 805 /* MAXPATHLEN includes the terminating NUL */
806 806 if (strlen(dir) + strlen(leaf) > MAXPATHLEN - 1) {
807 807 fprintf(stderr, "stable storage path too long: %s%s. "
808 808 "Exiting.\n", dir, leaf);
809 809 exit(1);
810 810 }
811 811
812 812 (void) snprintf(tmppath, MAXPATHLEN, "%s/%s", dir, leaf);
813 813
814 814 /* the directory may already exist: that's OK */
815 815 if (mkdir(tmppath, NFS4_DSS_DIR_MODE) == -1 && errno != EEXIST) {
816 816 fprintf(stderr, "error creating stable storage directory: "
817 817 "%s: %s. Exiting.\n", strerror(errno), tmppath);
818 818 exit(1);
819 819 }
820 820 }
821 821
822 822 /*
823 823 * Create the storage dirs, and pass the path list to the kernel.
824 824 * This requires the nfssrv module to be loaded; the _nfssys() syscall
825 825 * will fail ENOTSUP if it is not.
826 826 * Use libnvpair(3LIB) to pass the data to the kernel.
827 827 */
828 828 static int
829 829 dss_init(uint_t npaths, char **pathnames)
830 830 {
831 831 int i, j, nskipped, error;
832 832 char *bufp;
833 833 uint32_t bufsize;
834 834 size_t buflen;
835 835 nvlist_t *nvl;
836 836
837 837 if (npaths > 1) {
838 838 /*
839 839 * We need to remove duplicate paths; this might be user error
840 840 * in the general case, but HA-NFSv4 can also cause this.
841 841 * Sort the pathnames array, and NULL out duplicates,
842 842 * then write the non-NULL entries to a new array.
843 843 * Sorting will also allow the kernel to optimise its searches.
844 844 */
845 845
846 846 qsort(pathnames, npaths, sizeof (char *), qstrcmp);
847 847
848 848 /* now NULL out any duplicates */
849 849 i = 0; j = 1; nskipped = 0;
850 850 while (j < npaths) {
851 851 if (strcmp(pathnames[i], pathnames[j]) == NULL) {
852 852 pathnames[j] = NULL;
853 853 j++;
854 854 nskipped++;
855 855 continue;
856 856 }
857 857
858 858 /* skip i over any of its NULLed duplicates */
859 859 i = j++;
860 860 }
861 861
862 862 /* finally, write the non-NULL entries to a new array */
863 863 if (nskipped > 0) {
864 864 int nreal;
865 865 size_t sz;
866 866 char **tmp_pathnames;
867 867
868 868 nreal = npaths - nskipped;
869 869
870 870 sz = nreal * sizeof (char *);
871 871 tmp_pathnames = (char **)malloc(sz);
872 872 if (tmp_pathnames == NULL) {
873 873 fprintf(stderr, "tmp_pathnames malloc "
874 874 "failed\n");
875 875 exit(1);
876 876 }
877 877
878 878 for (i = 0, j = 0; i < npaths; i++)
879 879 if (pathnames[i] != NULL)
880 880 tmp_pathnames[j++] = pathnames[i];
881 881 free(pathnames);
882 882 pathnames = tmp_pathnames;
883 883 npaths = nreal;
884 884 }
885 885
886 886 }
887 887
888 888 /* Create directories to store the distributed state files */
889 889 dss_mkleafdirs(npaths, pathnames);
890 890
891 891 /* Create the name-value pair list */
892 892 error = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
893 893 if (error) {
894 894 fprintf(stderr, "nvlist_alloc failed: %s\n", strerror(errno));
895 895 return (1);
896 896 }
897 897
898 898 /* Add the pathnames array as a single name-value pair */
899 899 error = nvlist_add_string_array(nvl, NFS4_DSS_NVPAIR_NAME,
900 900 pathnames, npaths);
901 901 if (error) {
902 902 fprintf(stderr, "nvlist_add_string_array failed: %s\n",
903 903 strerror(errno));
904 904 nvlist_free(nvl);
905 905 return (1);
906 906 }
907 907
908 908 /*
909 909 * Pack list into contiguous memory, for passing to kernel.
910 910 * nvlist_pack() will allocate the memory for the buffer,
911 911 * which we should free() when no longer needed.
912 912 * NV_ENCODE_XDR for safety across ILP32/LP64 kernel boundary.
913 913 */
914 914 bufp = NULL;
915 915 error = nvlist_pack(nvl, &bufp, &buflen, NV_ENCODE_XDR, 0);
916 916 if (error) {
917 917 fprintf(stderr, "nvlist_pack failed: %s\n", strerror(errno));
918 918 nvlist_free(nvl);
919 919 return (1);
920 920 }
921 921
922 922 /* Now we have the packed buffer, we no longer need the list */
923 923 nvlist_free(nvl);
924 924
925 925 /*
926 926 * Let the kernel know in advance how big the buffer is.
927 927 * NOTE: we cannot just pass buflen, since size_t is a long, and
928 928 * thus a different size between ILP32 userland and LP64 kernel.
929 929 * Use an int for the transfer, since that should be big enough;
930 930 * this is a no-op at the moment, here, since nfsd is 32-bit, but
931 931 * that could change.
932 932 */
933 933 bufsize = (uint32_t)buflen;
934 934 error = _nfssys(NFS4_DSS_SETPATHS_SIZE, &bufsize);
935 935 if (error) {
936 936 fprintf(stderr,
937 937 "_nfssys(NFS4_DSS_SETPATHS_SIZE) failed: %s\n",
938 938 strerror(errno));
939 939 free(bufp);
940 940 return (1);
941 941 }
942 942
943 943 /* Pass the packed buffer to the kernel */
944 944 error = _nfssys(NFS4_DSS_SETPATHS, bufp);
945 945 if (error) {
946 946 fprintf(stderr,
947 947 "_nfssys(NFS4_DSS_SETPATHS) failed: %s\n", strerror(errno));
948 948 free(bufp);
949 949 return (1);
950 950 }
951 951
952 952 /*
953 953 * The kernel has now unpacked the buffer and extracted the
954 954 * pathnames array, we no longer need the buffer.
955 955 */
956 956 free(bufp);
957 957
958 958 return (0);
959 959 }
960 960
961 961 /*
962 962 * Quick sort string compare routine, for qsort.
963 963 * Needed to make arg types correct.
964 964 */
965 965 int
966 966 qstrcmp(const void *p1, const void *p2)
967 967 {
968 968 char *s1 = *((char **)p1);
969 969 char *s2 = *((char **)p2);
970 970
971 971 return (strcmp(s1, s2));
972 972 }
|
↓ open down ↓ |
728 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX