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.
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.
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]
22 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
25 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
26 /* All Rights Reserved */
29 * University Copyright- Copyright (c) 1982, 1986, 1988
30 * The Regents of the University of California
33 * University Acknowledgment- Portions of this document are derived from
34 * software developed by the University of California, Berkeley, and its
43 #include <sys/param.h>
44 #include <sys/types.h>
51 #include <sys/resource.h>
55 #include <nfs/nfs_acl.h>
56 #include <nfs/nfssys.h>
58 #include <stdio_ext.h>
61 #include <netconfig.h>
67 #include <sys/tihdr.h>
70 #include <priv_utils.h>
71 #include <sys/tiuser.h>
72 #include <netinet/tcp.h>
74 #include <rpcsvc/daemon_utils.h>
75 #include <rpcsvc/nfs4_prot.h>
76 #include <libnvpair.h>
79 #include "nfs_tbind.h"
83 /* quiesce requests will be ignored if nfs_server_vers_max < QUIESCE_VERSMIN */
84 #define QUIESCE_VERSMIN 4
85 /* DSS: distributed stable storage */
88 static int nfssvc(int, struct netbuf
, struct netconfig
*);
89 static int nfssvcpool(int maxservers
);
90 static int dss_init(uint_t npaths
, char **pathnames
);
91 static void dss_mkleafdirs(uint_t npaths
, char **pathnames
);
92 static void dss_mkleafdir(char *dir
, char *leaf
, char *path
);
93 static void usage(void);
94 int qstrcmp(const void *s1
, const void *s2
);
96 extern int _nfssys(int, void *);
98 extern int daemonize_init(void);
99 extern void daemonize_fini(int fd
);
101 /* signal handlers */
102 static void sigflush(int);
103 static void quiesce(int);
106 static NETSELDECL(defaultproviders
)[] = { "/dev/tcp6", "/dev/tcp", "/dev/udp",
108 /* static NETSELDECL(defaultprotos)[] = { NC_UDP, NC_TCP, NULL }; */
110 * The following are all globals used by routines in nfs_tbind.c.
112 size_t end_listen_fds
; /* used by conn_close_oldest() */
113 size_t num_fds
= 0; /* used by multiple routines */
114 int listen_backlog
= 32; /* used by bind_to_{provider,proto}() */
115 int num_servers
; /* used by cots_listen_event() */
116 int (*Mysvc
)(int, struct netbuf
, struct netconfig
*) = nfssvc
;
117 /* used by cots_listen_event() */
118 int max_conns_allowed
= -1; /* used by cots_listen_event() */
121 * Keep track of min/max versions of NFS protocol to be started.
122 * Start with the defaults (min == 2, max == 3). We have the
123 * capability of starting vers=4 but only if the user requests it.
125 int nfs_server_vers_min
= NFS_VERSMIN_DEFAULT
;
126 int nfs_server_vers_max
= NFS_VERSMAX_DEFAULT
;
129 * Set the default for server delegation enablement and set per
130 * /etc/default/nfs configuration (if present).
132 int nfs_server_delegation
= NFS_SERVER_DELEGATION_DEFAULT
;
135 main(int ac
, char *av
[])
141 int maxservers
= 1024; /* zero allows inifinte number of threads */
142 int maxservers_set
= 0;
143 int logmaxservers
= 0;
146 char *provider
= (char *)NULL
;
147 char *df_provider
= (char *)NULL
;
148 struct protob
*protobp0
, *protobp
;
149 NETSELDECL(proto
) = NULL
;
150 NETSELDECL(df_proto
) = NULL
;
151 NETSELPDECL(providerp
);
153 boolean_t can_do_mlp
;
154 uint_t dss_npaths
= 0;
155 char **dss_pathnames
= NULL
;
157 char name
[PATH_MAX
], value
[PATH_MAX
];
165 * Initializations that require more privileges than we need to run.
167 (void) _create_daemon_lock(NFSD
, DAEMON_UID
, DAEMON_GID
);
170 can_do_mlp
= priv_ineffect(PRIV_NET_BINDMLP
);
171 if (__init_daemon_priv(PU_RESETGROUPS
|PU_CLEARLIMITSET
,
172 DAEMON_UID
, DAEMON_GID
, PRIV_SYS_NFS
,
173 can_do_mlp
? PRIV_NET_BINDMLP
: NULL
, NULL
) == -1) {
174 (void) fprintf(stderr
, "%s should be run with"
175 " sufficient privileges\n", av
[0]);
179 (void) enable_extended_FILE_stdio(-1, -1);
182 * Read in the values from SMF first before we check
183 * command line options so the options override SMF values.
186 ret
= nfs_smf_get_prop("max_connections", value
, DEFAULT_INSTANCE
,
187 SCF_TYPE_INTEGER
, NFSD
, &bufsz
);
190 max_conns_allowed
= strtol(value
, (char **)NULL
, 10);
192 max_conns_allowed
= -1;
196 ret
= nfs_smf_get_prop("listen_backlog", value
, DEFAULT_INSTANCE
,
197 SCF_TYPE_INTEGER
, NFSD
, &bufsz
);
200 listen_backlog
= strtol(value
, (char **)NULL
, 10);
207 ret
= nfs_smf_get_prop("protocol", value
, DEFAULT_INSTANCE
,
208 SCF_TYPE_ASTRING
, NFSD
, &bufsz
);
209 if ((ret
== SA_OK
) && strlen(value
) > 0) {
210 df_proto
= strdup(value
);
212 if (strncasecmp("ALL", value
, 3) == 0) {
220 ret
= nfs_smf_get_prop("device", value
, DEFAULT_INSTANCE
,
221 SCF_TYPE_ASTRING
, NFSD
, &bufsz
);
222 if ((ret
== SA_OK
) && strlen(value
) > 0) {
223 df_provider
= strdup(value
);
228 ret
= nfs_smf_get_prop("servers", value
, DEFAULT_INSTANCE
,
229 SCF_TYPE_INTEGER
, NFSD
, &bufsz
);
232 maxservers
= strtol(value
, (char **)NULL
, 10);
240 ret
= nfs_smf_get_prop("server_versmin", value
, DEFAULT_INSTANCE
,
241 SCF_TYPE_INTEGER
, NFSD
, &bufsz
);
243 nfs_server_vers_min
= strtol(value
, (char **)NULL
, 10);
246 ret
= nfs_smf_get_prop("server_versmax", value
, DEFAULT_INSTANCE
,
247 SCF_TYPE_INTEGER
, NFSD
, &bufsz
);
249 nfs_server_vers_max
= strtol(value
, (char **)NULL
, 10);
252 ret
= nfs_smf_get_prop("server_delegation", value
, DEFAULT_INSTANCE
,
253 SCF_TYPE_ASTRING
, NFSD
, &bufsz
);
255 if (strncasecmp(value
, "off", 3) == 0)
256 nfs_server_delegation
= FALSE
;
259 * Conflict options error messages.
262 (void) fprintf(stderr
, "\nConflicting options, only one of "
263 "the following options can be specified\n"
266 "\tprotocol=protocol\n"
267 "\tdevice=devicename\n\n");
272 while ((i
= getopt(ac
, av
, "ac:p:s:t:l:")) != EOF
) {
285 max_conns_allowed
= atoi(optarg
);
295 * DSS: NFSv4 distributed stable storage.
297 * This is a Contracted Project Private interface, for
298 * the sole use of Sun Cluster HA-NFS. See PSARC/2006/313.
301 if (strlen(optarg
) < MAXPATHLEN
) {
302 /* first "-s" option encountered? */
303 if (dss_pathnames
== NULL
) {
305 * Allocate maximum possible space
306 * required given cmdline arg count;
307 * "-s <path>" consumes two args.
309 size_t sz
= (ac
/ 2) * sizeof (char *);
310 dss_pathnames
= (char **)malloc(sz
);
311 if (dss_pathnames
== NULL
) {
312 (void) fprintf(stderr
, "%s: "
313 "dss paths malloc failed\n",
317 (void) memset(dss_pathnames
, 0, sz
);
319 dss_pathnames
[dss_npaths
] = optarg
;
322 (void) fprintf(stderr
,
323 "%s: -s pathname too long.\n", av
[0]);
334 listen_backlog
= atoi(optarg
);
343 allflag
= df_allflag
;
346 if (provider
== NULL
)
347 provider
= df_provider
;
350 * Conflict options error messages.
353 (void) fprintf(stderr
, "\nConflicting options, only one of "
354 "the following options can be specified\n"
355 "on the command line:\n"
358 "\t-t transport\n\n");
363 strncasecmp(proto
, NC_UDP
, strlen(NC_UDP
)) == 0) {
364 if (nfs_server_vers_max
== NFS_V4
) {
365 if (nfs_server_vers_min
== NFS_V4
) {
367 "NFS version 4 is not supported "
368 "with the UDP protocol. Exiting\n");
372 "NFS version 4 is not supported "
373 "with the UDP protocol.\n");
379 * If there is exactly one more argument, it is the number of
382 if (optind
== ac
- 1) {
383 maxservers
= atoi(av
[optind
]);
387 * If there are two or more arguments, then this is a usage error.
389 else if (optind
< ac
- 1)
392 * Check the ranges for min/max version specified
394 else if ((nfs_server_vers_min
> nfs_server_vers_max
) ||
395 (nfs_server_vers_min
< NFS_VERSMIN
) ||
396 (nfs_server_vers_max
> NFS_VERSMAX
))
399 * There are no additional arguments, and we haven't set maxservers
400 * explicitly via the config file, we use a default number of
401 * servers. We will log this.
403 else if (maxservers_set
== 0)
407 * Basic Sanity checks on options
409 * max_conns_allowed must be positive, except for the special
410 * value of -1 which is used internally to mean unlimited, -1 isn't
411 * documented but we allow it anyway.
413 * maxservers must be positive
414 * listen_backlog must be positive or zero
416 if (((max_conns_allowed
!= -1) && (max_conns_allowed
<= 0)) ||
417 (listen_backlog
< 0) || (maxservers
<= 0)) {
422 * Set current dir to server root
424 if (chdir(dir
) < 0) {
425 (void) fprintf(stderr
, "%s: ", MyName
);
431 pipe_fd
= daemonize_init();
434 openlog(MyName
, LOG_PID
| LOG_NDELAY
, LOG_DAEMON
);
437 * establish our lock on the lock file and write our pid to it.
438 * exit if some other process holds the lock, or if there's any
439 * error in writing/locking the file.
441 pid
= _enter_daemon_lock(NFSD
);
446 fprintf(stderr
, "error locking for %s: %s\n", NFSD
,
450 /* daemon was already running */
455 * If we've been given a list of paths to be used for distributed
456 * stable storage, and provided we're going to run a version
457 * that supports it, setup the DSS paths.
459 if (dss_pathnames
!= NULL
&& nfs_server_vers_max
>= DSS_VERSMIN
) {
460 if (dss_init(dss_npaths
, dss_pathnames
) != 0) {
461 fprintf(stderr
, "%s", "dss_init failed. Exiting.\n");
467 * Block all signals till we spawn other
470 (void) sigfillset(&sgset
);
471 (void) thr_sigsetmask(SIG_BLOCK
, &sgset
, NULL
);
475 "Number of servers not specified. Using default of %d.\n",
480 * Make sure to unregister any previous versions in case the
481 * user is reconfiguring the server in interesting ways.
483 svc_unreg(NFS_PROGRAM
, NFS_VERSION
);
484 svc_unreg(NFS_PROGRAM
, NFS_V3
);
485 svc_unreg(NFS_PROGRAM
, NFS_V4
);
486 svc_unreg(NFS_ACL_PROGRAM
, NFS_ACL_V2
);
487 svc_unreg(NFS_ACL_PROGRAM
, NFS_ACL_V3
);
490 * Set up kernel RPC thread pool for the NFS server.
492 if (nfssvcpool(maxservers
)) {
493 fprintf(stderr
, "Can't set up kernel NFS service: %s. "
494 "Exiting.\n", strerror(errno
));
499 * Set up blocked thread to do LWP creation on behalf of the kernel.
501 if (svcwait(NFS_SVCPOOL_ID
)) {
502 fprintf(stderr
, "Can't set up NFS pool creator: %s. Exiting.\n",
508 * RDMA start and stop thread.
509 * Per pool RDMA listener creation and
512 * start rdma services and block in the kernel.
513 * (only if proto or provider is not set to TCP or UDP)
515 if ((proto
== NULL
) && (provider
== NULL
)) {
516 if (svcrdma(NFS_SVCPOOL_ID
, nfs_server_vers_min
,
517 nfs_server_vers_max
, nfs_server_delegation
)) {
519 "Can't set up RDMA creator thread : %s\n",
525 * Now open up for signal delivery
528 (void) thr_sigsetmask(SIG_UNBLOCK
, &sgset
, NULL
);
529 sigset(SIGTERM
, sigflush
);
530 sigset(SIGUSR1
, quiesce
);
533 * Build a protocol block list for registration.
535 protobp0
= protobp
= (struct protob
*)malloc(sizeof (struct protob
));
536 protobp
->serv
= "NFS";
537 protobp
->versmin
= nfs_server_vers_min
;
538 protobp
->versmax
= nfs_server_vers_max
;
539 protobp
->program
= NFS_PROGRAM
;
541 protobp
->next
= (struct protob
*)malloc(sizeof (struct protob
));
542 protobp
= protobp
->next
;
543 protobp
->serv
= "NFS_ACL"; /* not used */
544 protobp
->versmin
= nfs_server_vers_min
;
545 /* XXX - this needs work to get the version just right */
546 protobp
->versmax
= (nfs_server_vers_max
> NFS_ACL_V3
) ?
547 NFS_ACL_V3
: nfs_server_vers_max
;
548 protobp
->program
= NFS_ACL_PROGRAM
;
549 protobp
->next
= (struct protob
*)NULL
;
552 if (do_all(protobp0
, nfssvc
) == -1) {
553 fprintf(stderr
, "setnetconfig failed : %s\n",
558 /* there's more than one match for the same protocol */
559 struct netconfig
*nconf
;
561 bool_t protoFound
= FALSE
;
562 if ((nc
= setnetconfig()) == (NCONF_HANDLE
*) NULL
) {
563 fprintf(stderr
, "setnetconfig failed : %s\n",
567 while (nconf
= getnetconfig(nc
)) {
568 if (strcmp(nconf
->nc_proto
, proto
) == 0) {
570 do_one(nconf
->nc_device
, NULL
,
574 (void) endnetconfig(nc
);
575 if (protoFound
== FALSE
) {
577 "couldn't find netconfig entry for protocol %s\n",
581 do_one(provider
, proto
, protobp0
, nfssvc
);
583 for (providerp
= defaultproviders
;
584 *providerp
!= NULL
; providerp
++) {
585 provider
= *providerp
;
586 do_one(provider
, NULL
, protobp0
, nfssvc
);
595 fprintf(stderr
, "Could not start NFS service for any protocol."
600 end_listen_fds
= num_fds
;
603 * nfsd is up and running as far as we are concerned.
605 daemonize_fini(pipe_fd
);
608 * Get rid of unneeded privileges.
610 __fini_daemon_priv(PRIV_PROC_FORK
, PRIV_PROC_EXEC
, PRIV_PROC_SESSION
,
611 PRIV_FILE_LINK_ANY
, PRIV_PROC_INFO
, (char *)NULL
);
614 * Poll for non-data control events on the transport descriptors.
619 * If we get here, something failed in poll_for_action().
625 nfssvcpool(int maxservers
)
627 struct svcpool_args npa
;
629 npa
.id
= NFS_SVCPOOL_ID
;
630 npa
.maxthreads
= maxservers
;
635 npa
.max_same_xprt
= 0;
636 return (_nfssys(SVCPOOL_CREATE
, &npa
));
640 * Establish NFS service thread.
643 nfssvc(int fd
, struct netbuf addrmask
, struct netconfig
*nconf
)
645 struct nfs_svc_args nsa
;
648 nsa
.netid
= nconf
->nc_netid
;
649 nsa
.addrmask
= addrmask
;
650 if (strncasecmp(nconf
->nc_proto
, NC_UDP
, strlen(NC_UDP
)) == 0) {
651 nsa
.versmax
= (nfs_server_vers_max
> NFS_V3
) ?
652 NFS_V3
: nfs_server_vers_max
;
653 nsa
.versmin
= nfs_server_vers_min
;
655 * If no version left, silently do nothing, previous
656 * checks will have assured at least TCP is available.
658 if (nsa
.versmin
> nsa
.versmax
)
661 nsa
.versmax
= nfs_server_vers_max
;
662 nsa
.versmin
= nfs_server_vers_min
;
664 nsa
.delegation
= nfs_server_delegation
;
665 return (_nfssys(NFS_SVC
, &nsa
));
671 (void) fprintf(stderr
,
672 "usage: %s [ -a ] [ -c max_conns ] [ -p protocol ] [ -t transport ] ", MyName
);
673 (void) fprintf(stderr
, "\n[ -l listen_backlog ] [ nservers ]\n");
674 (void) fprintf(stderr
,
675 "\twhere -a causes <nservers> to be started on each appropriate transport,\n");
676 (void) fprintf(stderr
,
677 "\tmax_conns is the maximum number of concurrent connections allowed,\n");
678 (void) fprintf(stderr
, "\t\tand max_conns must be a decimal number");
679 (void) fprintf(stderr
, "> zero,\n");
680 (void) fprintf(stderr
, "\tprotocol is a protocol identifier,\n");
681 (void) fprintf(stderr
,
682 "\ttransport is a transport provider name (i.e. device),\n");
683 (void) fprintf(stderr
,
684 "\tlisten_backlog is the TCP listen backlog,\n");
685 (void) fprintf(stderr
,
686 "\tand <nservers> must be a decimal number > zero.\n");
691 * Issue nfssys system call to flush all logging buffers asynchronously.
693 * NOTICE: It is extremely important to flush NFS logging buffers when
694 * nfsd exits. When the system is halted or rebooted nfslogd
695 * may not have an opportunity to flush the buffers.
700 struct nfsl_flush_args nfa
;
702 memset((void *)&nfa
, 0, sizeof (nfa
));
703 nfa
.version
= NFSL_FLUSH_ARGS_VERS
;
704 nfa
.directive
= NFSL_ALL
; /* flush all asynchronously */
706 if (_nfssys(LOG_FLUSH
, &nfa
) < 0)
707 syslog(LOG_ERR
, "_nfssys(LOG_FLUSH) failed: %s\n",
713 * Flush logging buffers and exit.
725 * Request that server quiesce, then (nfsd) exit. For subsequent warm start.
727 * This is a Contracted Project Private interface, for the sole use
728 * of Sun Cluster HA-NFS. See PSARC/2004/497.
730 * Equivalent to SIGTERM handler if nfs_server_vers_max < QUIESCE_VERSMIN.
736 int id
= NFS_SVCPOOL_ID
;
738 if (nfs_server_vers_max
>= QUIESCE_VERSMIN
) {
739 /* Request server quiesce at next shutdown */
740 error
= _nfssys(NFS4_SVC_REQUEST_QUIESCE
, &id
);
743 * ENOENT is returned if there is no matching SVC pool
744 * for the id. Possibly because the pool is not yet setup.
745 * In this case, just exit as if no error. For all other errors,
746 * just return and allow caller to retry.
748 if (error
&& errno
!= ENOENT
) {
750 "_nfssys(NFS4_SVC_REQUEST_QUIESCE) failed: %s",
756 /* Flush logging buffers */
763 * DSS: distributed stable storage.
764 * Create leaf directories as required, keeping an eye on path
765 * lengths. Calls exit(1) on failure.
766 * The pathnames passed in must already exist, and must be writeable by nfsd.
767 * Note: the leaf directories under NFS4_VAR_DIR are not created here;
768 * they're created at pkg install.
771 dss_mkleafdirs(uint_t npaths
, char **pathnames
)
774 char *tmppath
= NULL
;
777 * Create the temporary storage used by dss_mkleafdir() here,
778 * rather than in that function, so that it only needs to be
779 * done once, rather than once for each call. Too big to put
780 * on the function's stack.
782 tmppath
= (char *)malloc(MAXPATHLEN
);
783 if (tmppath
== NULL
) {
784 syslog(LOG_ERR
, "tmppath malloc failed. Exiting");
788 for (i
= 0; i
< npaths
; i
++) {
789 char *p
= pathnames
[i
];
791 dss_mkleafdir(p
, NFS4_DSS_STATE_LEAF
, tmppath
);
792 dss_mkleafdir(p
, NFS4_DSS_OLDSTATE_LEAF
, tmppath
);
799 * Create "leaf" in "dir" (which must already exist).
800 * leaf: should start with a '/'
803 dss_mkleafdir(char *dir
, char *leaf
, char *tmppath
)
805 /* MAXPATHLEN includes the terminating NUL */
806 if (strlen(dir
) + strlen(leaf
) > MAXPATHLEN
- 1) {
807 fprintf(stderr
, "stable storage path too long: %s%s. "
808 "Exiting.\n", dir
, leaf
);
812 (void) snprintf(tmppath
, MAXPATHLEN
, "%s/%s", dir
, leaf
);
814 /* the directory may already exist: that's OK */
815 if (mkdir(tmppath
, NFS4_DSS_DIR_MODE
) == -1 && errno
!= EEXIST
) {
816 fprintf(stderr
, "error creating stable storage directory: "
817 "%s: %s. Exiting.\n", strerror(errno
), tmppath
);
823 * Create the storage dirs, and pass the path list to the kernel.
824 * This requires the nfssrv module to be loaded; the _nfssys() syscall
825 * will fail ENOTSUP if it is not.
826 * Use libnvpair(3LIB) to pass the data to the kernel.
829 dss_init(uint_t npaths
, char **pathnames
)
831 int i
, j
, nskipped
, error
;
839 * We need to remove duplicate paths; this might be user error
840 * in the general case, but HA-NFSv4 can also cause this.
841 * Sort the pathnames array, and NULL out duplicates,
842 * then write the non-NULL entries to a new array.
843 * Sorting will also allow the kernel to optimise its searches.
846 qsort(pathnames
, npaths
, sizeof (char *), qstrcmp
);
848 /* now NULL out any duplicates */
849 i
= 0; j
= 1; nskipped
= 0;
851 if (strcmp(pathnames
[i
], pathnames
[j
]) == NULL
) {
858 /* skip i over any of its NULLed duplicates */
862 /* finally, write the non-NULL entries to a new array */
866 char **tmp_pathnames
;
868 nreal
= npaths
- nskipped
;
870 sz
= nreal
* sizeof (char *);
871 tmp_pathnames
= (char **)malloc(sz
);
872 if (tmp_pathnames
== NULL
) {
873 fprintf(stderr
, "tmp_pathnames malloc "
878 for (i
= 0, j
= 0; i
< npaths
; i
++)
879 if (pathnames
[i
] != NULL
)
880 tmp_pathnames
[j
++] = pathnames
[i
];
882 pathnames
= tmp_pathnames
;
888 /* Create directories to store the distributed state files */
889 dss_mkleafdirs(npaths
, pathnames
);
891 /* Create the name-value pair list */
892 error
= nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0);
894 fprintf(stderr
, "nvlist_alloc failed: %s\n", strerror(errno
));
898 /* Add the pathnames array as a single name-value pair */
899 error
= nvlist_add_string_array(nvl
, NFS4_DSS_NVPAIR_NAME
,
902 fprintf(stderr
, "nvlist_add_string_array failed: %s\n",
909 * Pack list into contiguous memory, for passing to kernel.
910 * nvlist_pack() will allocate the memory for the buffer,
911 * which we should free() when no longer needed.
912 * NV_ENCODE_XDR for safety across ILP32/LP64 kernel boundary.
915 error
= nvlist_pack(nvl
, &bufp
, &buflen
, NV_ENCODE_XDR
, 0);
917 fprintf(stderr
, "nvlist_pack failed: %s\n", strerror(errno
));
922 /* Now we have the packed buffer, we no longer need the list */
926 * Let the kernel know in advance how big the buffer is.
927 * NOTE: we cannot just pass buflen, since size_t is a long, and
928 * thus a different size between ILP32 userland and LP64 kernel.
929 * Use an int for the transfer, since that should be big enough;
930 * this is a no-op at the moment, here, since nfsd is 32-bit, but
933 bufsize
= (uint32_t)buflen
;
934 error
= _nfssys(NFS4_DSS_SETPATHS_SIZE
, &bufsize
);
937 "_nfssys(NFS4_DSS_SETPATHS_SIZE) failed: %s\n",
943 /* Pass the packed buffer to the kernel */
944 error
= _nfssys(NFS4_DSS_SETPATHS
, bufp
);
947 "_nfssys(NFS4_DSS_SETPATHS) failed: %s\n", strerror(errno
));
953 * The kernel has now unpacked the buffer and extracted the
954 * pathnames array, we no longer need the buffer.
962 * Quick sort string compare routine, for qsort.
963 * Needed to make arg types correct.
966 qstrcmp(const void *p1
, const void *p2
)
968 char *s1
= *((char **)p1
);
969 char *s2
= *((char **)p2
);
971 return (strcmp(s1
, s2
));