diff --git a/.gitignore b/.gitignore index afcfcf8..2f191db 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ Makefile /nfs-utils-1.2.8.tar.bz2 /nfs-utils-1.2.9.tar.bz2 /nfs-utils-1.3.0.tar.xz +/nfs-utils-1.3.1.tar.xz diff --git a/nfs-utils-1.3.1-rc3.patch b/nfs-utils-1.3.1-rc3.patch deleted file mode 100644 index 9e4048b..0000000 --- a/nfs-utils-1.3.1-rc3.patch +++ /dev/null @@ -1,1086 +0,0 @@ -diff --git a/Makefile.am b/Makefile.am -index ae7cd16..5824adc 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -54,13 +54,13 @@ install-data-hook: - touch $(DESTDIR)$(statedir)/xtab; chmod 644 $(DESTDIR)$(statedir)/xtab - touch $(DESTDIR)$(statedir)/etab; chmod 644 $(DESTDIR)$(statedir)/etab - touch $(DESTDIR)$(statedir)/rmtab; chmod 644 $(DESTDIR)$(statedir)/rmtab -- mkdir -p $(DESTDIR)$(statedir)/sm $(DESTDIR)$(statedir)/sm.bak -- touch $(DESTDIR)$(statedir)/state -- chmod go-rwx $(DESTDIR)$(statedir)/sm $(DESTDIR)$(statedir)/sm.bak $(DESTDIR)$(statedir)/state -- -chown $(statduser) $(DESTDIR)$(statedir)/sm $(DESTDIR)$(statedir)/sm.bak $(DESTDIR)$(statedir)/state -+ mkdir -p $(DESTDIR)$(statdpath)/sm $(DESTDIR)$(statdpath)/sm.bak -+ touch $(DESTDIR)$(statdpath)/state -+ chmod go-rwx $(DESTDIR)$(statdpath)/sm $(DESTDIR)$(statdpath)/sm.bak $(DESTDIR)$(statdpath)/state -+ -chown $(statduser) $(DESTDIR)$(statdpath)/sm $(DESTDIR)$(statdpath)/sm.bak $(DESTDIR)$(statdpath)/state - - uninstall-hook: - rm $(DESTDIR)$(statedir)/xtab - rm $(DESTDIR)$(statedir)/etab - rm $(DESTDIR)$(statedir)/rmtab -- rm $(DESTDIR)$(statedir)/state -+ rm $(DESTDIR)$(statdpath)/state -diff --git a/configure.ac b/configure.ac -index 7b93de6..408f4c8 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -411,7 +411,7 @@ AC_CHECK_FUNCS([alarm atexit dup2 fdatasync ftruncate getcwd \ - getnameinfo getrpcbyname getifaddrs \ - gettimeofday hasmntopt inet_ntoa innetgr memset mkdir pathconf \ - ppoll realpath rmdir select socket strcasecmp strchr strdup \ -- strerror strrchr strtol strtoul sigprocmask]) -+ strerror strrchr strtol strtoul sigprocmask name_to_handle_at]) - - - dnl ************************************************************* -diff --git a/support/export/client.c b/support/export/client.c -index dbf47b9..f85e11c 100644 ---- a/support/export/client.c -+++ b/support/export/client.c -@@ -482,8 +482,12 @@ add_name(char *old, const char *add) - else - cp = cp + strlen(cp); - } -- strncpy(new, old, cp-old); -- new[cp-old] = 0; -+ if (old) { -+ strncpy(new, old, cp-old); -+ new[cp-old] = 0; -+ } else { -+ new[0] = 0; -+ } - if (cp != old && !*cp) - strcat(new, ","); - strcat(new, add); -diff --git a/tools/mountstats/mountstats.py b/tools/mountstats/mountstats.py -index e46105d..1fb3e2f 100644 ---- a/tools/mountstats/mountstats.py -+++ b/tools/mountstats/mountstats.py -@@ -371,7 +371,7 @@ def parse_stats_file(filename): - ms_dict = dict() - key = '' - -- f = file(filename) -+ f = open(filename) - for line in f.readlines(): - words = line.split() - if len(words) == 0: -diff --git a/tools/nfs-iostat/nfs-iostat.py b/tools/nfs-iostat/nfs-iostat.py -index 341cdbf..61d15a5 100644 ---- a/tools/nfs-iostat/nfs-iostat.py -+++ b/tools/nfs-iostat/nfs-iostat.py -@@ -213,7 +213,8 @@ class DeviceData: - # the reference to them. so we build new lists here - # for the result object. - for op in result.__rpc_data['ops']: -- result.__rpc_data[op] = map(difference, self.__rpc_data[op], old_stats.__rpc_data[op]) -+ result.__rpc_data[op] = list(map( -+ difference, self.__rpc_data[op], old_stats.__rpc_data[op])) - - # update the remaining keys we care about - result.__rpc_data['rpcsends'] -= old_stats.__rpc_data['rpcsends'] -@@ -243,27 +244,15 @@ class DeviceData: - """Print attribute cache efficiency stats - """ - nfs_stats = self.__nfs_data -- getattr_stats = self.__rpc_data['GETATTR'] -- -- if nfs_stats['inoderevalidates'] != 0: -- getattr_ops = float(getattr_stats[1]) -- opens = float(nfs_stats['vfsopen']) -- revalidates = float(nfs_stats['inoderevalidates']) - opens -- if revalidates != 0: -- ratio = ((revalidates - getattr_ops) * 100) / revalidates -- else: -- ratio = 0.0 -- -- data_invalidates = float(nfs_stats['datainvalidates']) -- attr_invalidates = float(nfs_stats['attrinvalidates']) - -- print() -- print('%d inode revalidations, hitting in cache %4.2f%% of the time' % \ -- (revalidates, ratio)) -- print('%d open operations (mandatory GETATTR requests)' % opens) -- if getattr_ops != 0: -- print('%4.2f%% of GETATTRs resulted in data cache invalidations' % \ -- ((data_invalidates * 100) / getattr_ops)) -+ print() -+ print('%d VFS opens' % (nfs_stats['vfsopen'])) -+ print('%d inoderevalidates (forced GETATTRs)' % \ -+ (nfs_stats['inoderevalidates'])) -+ print('%d page cache invalidations' % \ -+ (nfs_stats['datainvalidates'])) -+ print('%d attribute cache invalidations' % \ -+ (nfs_stats['attrinvalidates'])) - - def __print_dir_cache_stats(self, sample_time): - """Print directory stats -@@ -353,15 +342,21 @@ class DeviceData: - exe_per_op = 0.0 - - op += ':' -- print('%s' % op.lower().ljust(15), end='') -- print(' ops/s\t\t kB/s\t\t kB/op\t\tretrans\t\tavg RTT (ms)\tavg exe (ms)') -- -- print('\t\t%7.3f' % (ops / sample_time), end='') -- print('\t%7.3f' % (kilobytes / sample_time), end='') -- print('\t%7.3f' % kb_per_op, end='') -- print(' %7d (%3.1f%%)' % (retrans, retrans_percent), end='') -- print('\t%7.3f' % rtt_per_op, end='') -- print('\t%7.3f' % exe_per_op) -+ print(format(op.lower(), '<16s'), end='') -+ print(format('ops/s', '>8s'), end='') -+ print(format('kB/s', '>16s'), end='') -+ print(format('kB/op', '>16s'), end='') -+ print(format('retrans', '>16s'), end='') -+ print(format('avg RTT (ms)', '>16s'), end='') -+ print(format('avg exe (ms)', '>16s')) -+ -+ print(format((ops / sample_time), '>24.3f'), end='') -+ print(format((kilobytes / sample_time), '>16.3f'), end='') -+ print(format(kb_per_op, '>16.3f'), end='') -+ retransmits = '{0:>10.0f} ({1:>3.1f}%)'.format(retrans, retrans_percent).strip() -+ print(format(retransmits, '>16'), end='') -+ print(format(rtt_per_op, '>16.3f'), end='') -+ print(format(exe_per_op, '>16.3f')) - - def ops(self, sample_time): - sends = float(self.__rpc_data['rpcsends']) -@@ -391,9 +386,10 @@ class DeviceData: - (self.__nfs_data['export'], self.__nfs_data['mountpoint'])) - print() - -- print(' op/s\t\trpc bklog') -- print('%7.2f' % (sends / sample_time), end='') -- print('\t%7.2f' % backlog) -+ print(format('ops/s', '>16') + format('rpc bklog', '>16')) -+ print(format((sends / sample_time), '>16.3f'), end='') -+ print(format(backlog, '>16.3f')) -+ print() - - if which == 0: - self.__print_rpc_op_stats('READ', sample_time) -diff --git a/tools/nfs-iostat/nfsiostat.man b/tools/nfs-iostat/nfsiostat.man -index 3ec245d..b477a9a 100644 ---- a/tools/nfs-iostat/nfsiostat.man -+++ b/tools/nfs-iostat/nfsiostat.man -@@ -38,6 +38,61 @@ If one or more - .I - names are specified, statistics for only these mount points will - be displayed. Otherwise, all NFS mount points on the client are listed. -+.TP -+The meaning of each column of \fBnfsiostat\fR's output is the following: -+.RS 8 -+- \fBop/s\fR -+.RS -+This is the number of operations per second. -+.RS -+.RE -+.RE -+.RE -+.RS 8 -+- \fBrpc bklog\fR -+.RS -+This is the length of the backlog queue. -+.RE -+.RE -+.RE -+.RS 8 -+- \fBkB/s\fR -+.RS -+This is the number of kB written/read per second. -+.RE -+.RE -+.RE -+.RS 8 -+- \fBkB/op\fR -+.RS -+This is the number of kB written/read per each operation. -+.RE -+.RE -+.RE -+.RS 8 -+- \fBretrans\fR -+.RS -+This is the number of retransmissions. -+.RE -+.RE -+.RE -+.RS 8 -+- \fBavg RTT (ms)\fR -+.RS -+This is the duration from the time that client's kernel sends the RPC request until the time it receives the reply. -+.RE -+.RE -+.RE -+.RS 8 -+- \fBavg exe (ms)\fR -+.RS -+This is the duration from the time that NFS client does the RPC request to its kernel until the RPC request is completed, this includes the RTT time above. -+.RE -+.RE -+.RE -+.TP -+Note that if an interval is used as argument to \fBnfsiostat\fR, then the diffrence from previous interval will be displayed, otherwise the results will be from the time that the share was mounted. -+ - .SH OPTIONS - .TP - .B \-a " or " \-\-attr -diff --git a/utils/gssd/Makefile.am b/utils/gssd/Makefile.am -index a9a3e42..af59791 100644 ---- a/utils/gssd/Makefile.am -+++ b/utils/gssd/Makefile.am -@@ -18,11 +18,13 @@ COMMON_SRCS = \ - context_lucid.c \ - gss_util.c \ - gss_oids.c \ -+ gss_names.c \ - err_util.c \ - \ - context.h \ - err_util.h \ - gss_oids.h \ -+ gss_names.h \ - gss_util.h - - gssd_SOURCES = \ -diff --git a/utils/gssd/gss_names.c b/utils/gssd/gss_names.c -new file mode 100644 -index 0000000..047069d ---- /dev/null -+++ b/utils/gssd/gss_names.c -@@ -0,0 +1,138 @@ -+/* -+ Copyright (c) 2000 The Regents of the University of Michigan. -+ All rights reserved. -+ -+ Copyright (c) 2002 Bruce Fields -+ -+ Redistribution and use in source and binary forms, with or without -+ modification, are permitted provided that the following conditions -+ are met: -+ -+ 1. Redistributions of source code must retain the above copyright -+ notice, this list of conditions and the following disclaimer. -+ 2. Redistributions in binary form must reproduce the above copyright -+ notice, this list of conditions and the following disclaimer in the -+ documentation and/or other materials provided with the distribution. -+ 3. Neither the name of the University nor the names of its -+ contributors may be used to endorse or promote products derived -+ from this software without specific prior written permission. -+ -+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+*/ -+ -+#ifdef HAVE_CONFIG_H -+#include -+#endif /* HAVE_CONFIG_H */ -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "svcgssd.h" -+#include "gss_util.h" -+#include "err_util.h" -+#include "context.h" -+#include "misc.h" -+#include "gss_oids.h" -+#include "svcgssd_krb5.h" -+ -+static int -+get_krb5_hostbased_name(gss_buffer_desc *name, char **hostbased_name) -+{ -+ char *p, *sname = NULL; -+ if (strchr(name->value, '@') && strchr(name->value, '/')) { -+ if ((sname = calloc(name->length, 1)) == NULL) { -+ printerr(0, "ERROR: get_krb5_hostbased_name failed " -+ "to allocate %d bytes\n", name->length); -+ return -1; -+ } -+ /* read in name and instance and replace '/' with '@' */ -+ sscanf(name->value, "%[^@]", sname); -+ p = strrchr(sname, '/'); -+ if (p == NULL) { /* The '@' preceeded the '/' */ -+ free(sname); -+ return -1; -+ } -+ *p = '@'; -+ } -+ *hostbased_name = sname; -+ return 0; -+} -+ -+int -+get_hostbased_client_name(gss_name_t client_name, gss_OID mech, -+ char **hostbased_name) -+{ -+ u_int32_t maj_stat, min_stat; -+ gss_buffer_desc name; -+ gss_OID name_type = GSS_C_NO_OID; -+ char *cname; -+ int res = -1; -+ -+ *hostbased_name = NULL; /* preset in case we fail */ -+ -+ /* Get the client's gss authenticated name */ -+ maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type); -+ if (maj_stat != GSS_S_COMPLETE) { -+ pgsserr("get_hostbased_client_name: gss_display_name", -+ maj_stat, min_stat, mech); -+ goto out_err; -+ } -+ if (name.length >= 0xffff) { /* don't overflow */ -+ printerr(0, "ERROR: get_hostbased_client_name: " -+ "received gss_name is too long (%d bytes)\n", -+ name.length); -+ goto out_rel_buf; -+ } -+ -+ /* For Kerberos, transform the NT_KRB5_PRINCIPAL name to -+ * an NT_HOSTBASED_SERVICE name */ -+ if (g_OID_equal(&krb5oid, mech)) { -+ if (get_krb5_hostbased_name(&name, &cname) == 0) -+ *hostbased_name = cname; -+ } else { -+ printerr(1, "WARNING: unknown/unsupport mech OID\n"); -+ } -+ -+ res = 0; -+out_rel_buf: -+ gss_release_buffer(&min_stat, &name); -+out_err: -+ return res; -+} -+ -+void -+get_hostbased_client_buffer(gss_name_t client_name, gss_OID mech, -+ gss_buffer_t buf) -+{ -+ char *hname; -+ -+ if (!get_hostbased_client_name(client_name, mech, &hname)) { -+ buf->length = strlen(hname) + 1; -+ buf->value = hname; -+ } else { -+ buf->length = 0; -+ buf->value = NULL; -+ } -+} -diff --git a/utils/gssd/gss_names.h b/utils/gssd/gss_names.h -new file mode 100644 -index 0000000..ce182f7 ---- /dev/null -+++ b/utils/gssd/gss_names.h -@@ -0,0 +1,36 @@ -+/* -+ Copyright (c) 2000 The Regents of the University of Michigan. -+ All rights reserved. -+ -+ Copyright (c) 2002 Bruce Fields -+ -+ Redistribution and use in source and binary forms, with or without -+ modification, are permitted provided that the following conditions -+ are met: -+ -+ 1. Redistributions of source code must retain the above copyright -+ notice, this list of conditions and the following disclaimer. -+ 2. Redistributions in binary form must reproduce the above copyright -+ notice, this list of conditions and the following disclaimer in the -+ documentation and/or other materials provided with the distribution. -+ 3. Neither the name of the University nor the names of its -+ contributors may be used to endorse or promote products derived -+ from this software without specific prior written permission. -+ -+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+*/ -+ -+extern int get_hostbased_client_name(gss_name_t client_name, gss_OID mech, -+ char **hostbased_name); -+extern void get_hostbased_client_buffer(gss_name_t client_name, -+ gss_OID mech, gss_buffer_t buf); -diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c -index 611ef1a..6b8b863 100644 ---- a/utils/gssd/gssd.c -+++ b/utils/gssd/gssd.c -@@ -64,6 +64,7 @@ char *ccachesearch[GSSD_MAX_CCACHE_SEARCH + 1]; - int use_memcache = 0; - int root_uses_machine_creds = 1; - unsigned int context_timeout = 0; -+unsigned int rpc_timeout = 5; - char *preferred_realm = NULL; - int pipefds[2] = { -1, -1 }; - -@@ -105,7 +106,7 @@ main(int argc, char *argv[]) - char *progname; - - memset(ccachesearch, 0, sizeof(ccachesearch)); -- while ((opt = getopt(argc, argv, "DfvrlmnMp:k:d:t:R:")) != -1) { -+ while ((opt = getopt(argc, argv, "DfvrlmnMp:k:d:t:T:R:")) != -1) { - switch (opt) { - case 'f': - fg = 1; -@@ -143,6 +144,9 @@ main(int argc, char *argv[]) - case 't': - context_timeout = atoi(optarg); - break; -+ case 'T': -+ rpc_timeout = atoi(optarg); -+ break; - case 'R': - preferred_realm = strdup(optarg); - break; -diff --git a/utils/gssd/gssd.h b/utils/gssd/gssd.h -index 56a18d6..48f4ad8 100644 ---- a/utils/gssd/gssd.h -+++ b/utils/gssd/gssd.h -@@ -66,6 +66,7 @@ extern char *ccachesearch[]; - extern int use_memcache; - extern int root_uses_machine_creds; - extern unsigned int context_timeout; -+extern unsigned int rpc_timeout; - extern char *preferred_realm; - extern int pipefds[2]; - -diff --git a/utils/gssd/gssd.man b/utils/gssd/gssd.man -index ac13fd4..ea58fa0 100644 ---- a/utils/gssd/gssd.man -+++ b/utils/gssd/gssd.man -@@ -289,6 +289,14 @@ new kernel contexts to be negotiated after - seconds, which allows changing Kerberos tickets and identities frequently. - The default is no explicit timeout, which means the kernel context will live - the lifetime of the Kerberos service ticket used in its creation. -+.TP -+.B -T timeout -+Timeout, in seconds, to create an RPC connection with a server while -+establishing an authenticated gss context for a user. -+The default timeout is set to 5 seconds. -+If you get messages like "WARNING: can't create tcp rpc_clnt to server -+%servername% for user with uid %uid%: RPC: Remote system error - -+Connection timed out", you should consider an increase of this timeout. - .SH SEE ALSO - .BR rpc.svcgssd (8), - .BR kerberos (1), -diff --git a/utils/gssd/gssd_main_loop.c b/utils/gssd/gssd_main_loop.c -index 9970028..6946ab6 100644 ---- a/utils/gssd/gssd_main_loop.c -+++ b/utils/gssd/gssd_main_loop.c -@@ -173,6 +173,10 @@ topdirs_init_list(void) - if (ret) - goto out_err; - } -+ if (TAILQ_EMPTY(&topdirs_list)) { -+ printerr(0, "ERROR: rpc_pipefs directory '%s' is empty!\n", pipefs_dir); -+ return -1; -+ } - closedir(pipedir); - return 0; - out_err: -@@ -233,9 +237,10 @@ gssd_run() - sigaddset(&set, DNOTIFY_SIGNAL); - sigprocmask(SIG_UNBLOCK, &set, NULL); - -- if (topdirs_init_list() != 0) -- return; -- -+ if (topdirs_init_list() != 0) { -+ /* Error msg is already printed */ -+ exit(1); -+ } - init_client_list(); - - printerr(1, "beginning poll\n"); -diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c -index 33cfeb2..121feb1 100644 ---- a/utils/gssd/gssd_proc.c -+++ b/utils/gssd/gssd_proc.c -@@ -77,6 +77,7 @@ - #include "context.h" - #include "nfsrpc.h" - #include "nfslib.h" -+#include "gss_names.h" - - /* - * pollarray: -@@ -217,7 +218,7 @@ get_servername(const char *name, const struct sockaddr *sa, const char *addr) - NI_NAMEREQD); - if (err) { - printerr(0, "ERROR: unable to resolve %s to hostname: %s\n", -- addr, err == EAI_SYSTEM ? strerror(err) : -+ addr, err == EAI_SYSTEM ? strerror(errno) : - gai_strerror(err)); - return NULL; - } -@@ -681,19 +682,25 @@ parse_enctypes(char *enctypes) - return 0; - } - --static int -+static void - do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd, -- gss_buffer_desc *context_token, OM_uint32 lifetime_rec) -+ gss_buffer_desc *context_token, OM_uint32 lifetime_rec, -+ gss_buffer_desc *acceptor) - { - char *buf = NULL, *p = NULL, *end = NULL; - unsigned int timeout = context_timeout; - unsigned int buf_size = 0; - -- printerr(1, "doing downcall lifetime_rec %u\n", lifetime_rec); -+ printerr(1, "doing downcall: lifetime_rec=%u acceptor=%.*s\n", -+ lifetime_rec, acceptor->length, acceptor->value); - buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) + - sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length + -- sizeof(context_token->length) + context_token->length; -+ sizeof(context_token->length) + context_token->length + -+ sizeof(acceptor->length) + acceptor->length; - p = buf = malloc(buf_size); -+ if (!buf) -+ goto out_err; -+ - end = buf + buf_size; - - /* context_timeout set by -t option overrides context lifetime */ -@@ -704,14 +711,15 @@ do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd, - if (WRITE_BYTES(&p, end, pd->pd_seq_win)) goto out_err; - if (write_buffer(&p, end, &pd->pd_ctx_hndl)) goto out_err; - if (write_buffer(&p, end, context_token)) goto out_err; -+ if (write_buffer(&p, end, acceptor)) goto out_err; - - if (write(k5_fd, buf, p - buf) < p - buf) goto out_err; -- if (buf) free(buf); -- return 0; -+ free(buf); -+ return; - out_err: -- if (buf) free(buf); -+ free(buf); - printerr(1, "Failed to write downcall!\n"); -- return -1; -+ return; - } - - static int -@@ -842,7 +850,7 @@ create_auth_rpc_client(struct clnt_info *clp, - OM_uint32 min_stat; - char rpc_errmsg[1024]; - int protocol; -- struct timeval timeout = {5, 0}; -+ struct timeval timeout; - struct sockaddr *addr = (struct sockaddr *) &clp->addr; - socklen_t salen; - -@@ -910,6 +918,10 @@ create_auth_rpc_client(struct clnt_info *clp, - if (!populate_port(addr, salen, clp->prog, clp->vers, protocol)) - goto out_fail; - -+ /* set the timeout according to the requested valued */ -+ timeout.tv_sec = (long) rpc_timeout; -+ timeout.tv_usec = (long) 0; -+ - rpc_clnt = nfs_get_rpcclient(addr, salen, protocol, clp->prog, - clp->vers, &timeout); - if (!rpc_clnt) { -@@ -1031,6 +1043,9 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, - gss_cred_id_t gss_cred; - OM_uint32 maj_stat, min_stat, lifetime_rec; - pid_t pid; -+ gss_name_t gacceptor = GSS_C_NO_NAME; -+ gss_OID mech; -+ gss_buffer_desc acceptor = {0}; - - pid = fork(); - switch(pid) { -@@ -1171,15 +1186,24 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, - goto out_return_error; - } - -- /* Grab the context lifetime to pass to the kernel. lifetime_rec -- * is set to zero on error */ -- maj_stat = gss_inquire_context(&min_stat, pd.pd_ctx, NULL, NULL, -- &lifetime_rec, NULL, NULL, NULL, NULL); -+ /* Grab the context lifetime and acceptor name out of the ctx. */ -+ maj_stat = gss_inquire_context(&min_stat, pd.pd_ctx, NULL, &gacceptor, -+ &lifetime_rec, &mech, NULL, NULL, NULL); - -- if (maj_stat) -- printerr(1, "WARNING: Failed to inquire context for lifetme " -- "maj_stat %u\n", maj_stat); -+ if (maj_stat != GSS_S_COMPLETE) { -+ printerr(1, "WARNING: Failed to inquire context " -+ "maj_stat (0x%x)\n", maj_stat); -+ lifetime_rec = 0; -+ } else { -+ get_hostbased_client_buffer(gacceptor, mech, &acceptor); -+ gss_release_name(&min_stat, &gacceptor); -+ } - -+ /* -+ * The serialization can mean turning pd.pd_ctx into a lucid context. If -+ * that happens then the pd.pd_ctx will be unusable, so we must never -+ * try to use it after this point. -+ */ - if (serialize_context_for_kernel(&pd.pd_ctx, &token, &krb5oid, NULL)) { - printerr(0, "WARNING: Failed to serialize krb5 context for " - "user with uid %d for server %s\n", -@@ -1187,9 +1211,10 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, - goto out_return_error; - } - -- do_downcall(fd, uid, &pd, &token, lifetime_rec); -+ do_downcall(fd, uid, &pd, &token, lifetime_rec, &acceptor); - - out: -+ gss_release_buffer(&min_stat, &acceptor); - if (token.value) - free(token.value); - #ifdef HAVE_AUTHGSS_FREE_PRIVATE_DATA -diff --git a/utils/gssd/svcgssd_proc.c b/utils/gssd/svcgssd_proc.c -index 3757d51..5bdb438 100644 ---- a/utils/gssd/svcgssd_proc.c -+++ b/utils/gssd/svcgssd_proc.c -@@ -59,6 +59,7 @@ - #include "misc.h" - #include "gss_oids.h" - #include "svcgssd_krb5.h" -+#include "gss_names.h" - - extern char * mech2file(gss_OID mech); - #define SVCGSSD_CONTEXT_CHANNEL "/proc/net/rpc/auth.rpcsec.context/channel" -@@ -315,71 +316,6 @@ print_hexl(const char *description, unsigned char *cp, int length) - } - #endif - --static int --get_krb5_hostbased_name (gss_buffer_desc *name, char **hostbased_name) --{ -- char *p, *sname = NULL; -- if (strchr(name->value, '@') && strchr(name->value, '/')) { -- if ((sname = calloc(name->length, 1)) == NULL) { -- printerr(0, "ERROR: get_krb5_hostbased_name failed " -- "to allocate %d bytes\n", name->length); -- return -1; -- } -- /* read in name and instance and replace '/' with '@' */ -- sscanf(name->value, "%[^@]", sname); -- p = strrchr(sname, '/'); -- if (p == NULL) { /* The '@' preceeded the '/' */ -- free(sname); -- return -1; -- } -- *p = '@'; -- } -- *hostbased_name = sname; -- return 0; --} -- --static int --get_hostbased_client_name(gss_name_t client_name, gss_OID mech, -- char **hostbased_name) --{ -- u_int32_t maj_stat, min_stat; -- gss_buffer_desc name; -- gss_OID name_type = GSS_C_NO_OID; -- char *cname; -- int res = -1; -- -- *hostbased_name = NULL; /* preset in case we fail */ -- -- /* Get the client's gss authenticated name */ -- maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type); -- if (maj_stat != GSS_S_COMPLETE) { -- pgsserr("get_hostbased_client_name: gss_display_name", -- maj_stat, min_stat, mech); -- goto out_err; -- } -- if (name.length >= 0xffff) { /* don't overflow */ -- printerr(0, "ERROR: get_hostbased_client_name: " -- "received gss_name is too long (%d bytes)\n", -- name.length); -- goto out_rel_buf; -- } -- -- /* For Kerberos, transform the NT_KRB5_PRINCIPAL name to -- * an NT_HOSTBASED_SERVICE name */ -- if (g_OID_equal(&krb5oid, mech)) { -- if (get_krb5_hostbased_name(&name, &cname) == 0) -- *hostbased_name = cname; -- } else { -- printerr(1, "WARNING: unknown/unsupport mech OID\n"); -- } -- -- res = 0; --out_rel_buf: -- gss_release_buffer(&min_stat, &name); --out_err: -- return res; --} -- - void - handle_nullreq(FILE *f) { - /* XXX initialize to a random integer to reduce chances of unnecessary -diff --git a/utils/mount/error.c b/utils/mount/error.c -index f8fc13f..e06f598 100644 ---- a/utils/mount/error.c -+++ b/utils/mount/error.c -@@ -215,8 +215,12 @@ void mount_error(const char *spec, const char *mount_point, int error) - progname); - break; - case ENOTDIR: -- nfs_error(_("%s: mount point %s is not a directory"), -- progname, mount_point); -+ if (spec) -+ nfs_error(_("%s: mount spec %s or point %s is not a " -+ "directory"), progname, spec, mount_point); -+ else -+ nfs_error(_("%s: mount point %s is not a directory"), -+ progname, mount_point); - break; - case EBUSY: - nfs_error(_("%s: %s is busy or already mounted"), -diff --git a/utils/mount/nfsmount.conf b/utils/mount/nfsmount.conf -index 9b8ff4a..aeb3023 100644 ---- a/utils/mount/nfsmount.conf -+++ b/utils/mount/nfsmount.conf -@@ -133,3 +133,12 @@ - # RPCGSS security flavors - # [none, sys, krb5, krb5i, krb5p ] - # Sec=sys -+# -+# Allow Signals to interrupt file operations -+# Intr=True -+# -+# Specifies how the kernel manages its cache of directory -+# Lookupcache=all|none|pos|positive -+# -+# Turn of the caching of that access time -+# noatime=True -diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c -index 9a1bb27..b0cc6a8 100644 ---- a/utils/mountd/cache.c -+++ b/utils/mountd/cache.c -@@ -377,6 +377,86 @@ static char *next_mnt(void **v, char *p) - return me->mnt_dir; - } - -+/* same_path() check is two paths refer to the same directory. -+ * We don't rely on 'strcmp()' as some filesystems support case-insensitive -+ * names and we might have two different names for the one directory. -+ * Theoretically the lengths of the names could be different, but the -+ * number of components must be the same. -+ * So if the paths have the same number of components (but aren't identical) -+ * we ask the kernel if they are the same thing. -+ * By preference we use name_to_handle_at(), as the mntid it returns -+ * will distinguish between bind-mount points. If that isn't available -+ * we fall back on lstat, which is usually good enough. -+ */ -+static inline int count_slashes(char *p) -+{ -+ int cnt = 0; -+ while (*p) -+ if (*p++ == '/') -+ cnt++; -+ return cnt; -+} -+ -+static int same_path(char *child, char *parent, int len) -+{ -+ static char p[PATH_MAX]; -+ struct stat sc, sp; -+ -+ if (len <= 0) -+ len = strlen(child); -+ strncpy(p, child, len); -+ p[len] = 0; -+ if (strcmp(p, parent) == 0) -+ return 1; -+ -+ /* If number of '/' are different, they must be different */ -+ if (count_slashes(p) != count_slashes(parent)) -+ return 0; -+ -+#if HAVE_NAME_TO_HANDLE_AT -+ struct { -+ struct file_handle fh; -+ unsigned char handle[128]; -+ } fchild, fparent; -+ int mnt_child, mnt_parent; -+ -+ fchild.fh.handle_bytes = 128; -+ fparent.fh.handle_bytes = 128; -+ if (name_to_handle_at(AT_FDCWD, p, &fchild.fh, &mnt_child, 0) != 0) { -+ if (errno == ENOSYS) -+ goto fallback; -+ return 0; -+ } -+ if (name_to_handle_at(AT_FDCWD, parent, &fparent.fh, &mnt_parent, 0) != 0) -+ return 0; -+ -+ if (mnt_child != mnt_parent || -+ fchild.fh.handle_bytes != fparent.fh.handle_bytes || -+ fchild.fh.handle_type != fparent.fh.handle_type || -+ memcmp(fchild.handle, fparent.handle, -+ fchild.fh.handle_bytes) != 0) -+ return 0; -+ -+ return 1; -+fallback: -+#endif -+ -+ /* This is nearly good enough. However if a directory is -+ * bind-mounted in two places and both are exported, it -+ * could give a false positive -+ */ -+ if (lstat(p, &sc) != 0) -+ return 0; -+ if (lstat(parent, &sp) != 0) -+ return 0; -+ if (sc.st_dev != sp.st_dev) -+ return 0; -+ if (sc.st_ino != sp.st_ino) -+ return 0; -+ -+ return 1; -+} -+ - static int is_subdirectory(char *child, char *parent) - { - /* Check is child is strictly a subdirectory of -@@ -387,7 +467,7 @@ static int is_subdirectory(char *child, char *parent) - if (strcmp(parent, "/") == 0 && child[1] != 0) - return 1; - -- return (strncmp(child, parent, l) == 0 && child[l] == '/'); -+ return (same_path(child, parent, l) && child[l] == '/'); - } - - static int path_matches(nfs_export *exp, char *path) -@@ -396,7 +476,7 @@ static int path_matches(nfs_export *exp, char *path) - * exact match, or does the export have CROSSMOUNT, and path - * is a descendant? - */ -- return strcmp(path, exp->m_export.e_path) == 0 -+ return same_path(path, exp->m_export.e_path, 0) - || ((exp->m_export.e_flags & NFSEXP_CROSSMOUNT) - && is_subdirectory(path, exp->m_export.e_path)); - } -diff --git a/utils/mountd/mountd.man b/utils/mountd/mountd.man -index e59a559..a8828ae 100644 ---- a/utils/mountd/mountd.man -+++ b/utils/mountd/mountd.man -@@ -86,7 +86,7 @@ Turn on debugging. Valid kinds are: all, auth, call, general and parse. - .B \-F " or " \-\-foreground - Run in foreground (do not daemonize) - .TP --.B \-f " or " \-\-exports-file -+.B \-f export-file " or " \-\-exports-file export-file - This option specifies the exports file, listing the clients that this - server is prepared to serve and parameters to apply to each - such mount (see -@@ -101,7 +101,7 @@ Display usage message. - Set the limit of the number of open file descriptors to num. The - default is to leave the limit unchanged. - .TP --.B \-N " or " \-\-no-nfs-version -+.B \-N mountd-version " or " \-\-no-nfs-version mountd-version - This option can be used to request that - .B rpc.mountd - do not offer certain versions of NFS. The current version of -@@ -118,7 +118,7 @@ Don't advertise TCP for mount. - .B \-P - Ignored (compatibility with unfsd??). - .TP --.B \-p " or " \-\-port num -+.B \-p num " or " \-\-port num - Specifies the port number used for RPC listener sockets. - If this option is not specified, - .B rpc.mountd -@@ -132,7 +132,7 @@ This option can be used to fix the port value of - listeners when NFS MOUNT requests must traverse a firewall - between clients and servers. - .TP --.B \-H " or " \-\-ha-callout prog -+.B \-H " prog or " \-\-ha-callout prog - Specify a high availability callout program. - This program receives callouts for all MOUNT and UNMOUNT requests. - This allows -@@ -174,7 +174,7 @@ to perform a reverse lookup on each IP address and return that hostname instead. - Enabling this can have a substantial negative effect on performance - in some situations. - .TP --.BR "\-t N" " or " "\-\-num\-threads=N" -+.BR "\-t N" " or " "\-\-num\-threads=N" or " \-\-num\-threads N" - This option specifies the number of worker threads that rpc.mountd - spawns. The default is 1 thread, which is probably enough. More - threads are usually only needed for NFS servers which need to handle -@@ -184,7 +184,7 @@ your DNS server is slow or unreliable. - .B \-u " or " \-\-no-udp - Don't advertise UDP for mounting - .TP --.B \-V " or " \-\-nfs-version -+.B \-V version " or " \-\-nfs-version version - This option can be used to request that - .B rpc.mountd - offer certain versions of NFS. The current version of -diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c -index 73d6a92..03e3c81 100644 ---- a/utils/nfsd/nfsd.c -+++ b/utils/nfsd/nfsd.c -@@ -101,7 +101,7 @@ main(int argc, char **argv) - int count = NFSD_NPROC, c, i, error = 0, portnum = 0, fd, found_one; - char *p, *progname, *port, *rdma_port = NULL; - char **haddr = NULL; -- unsigned int hcounter = 0; -+ int hcounter = 0; - int socket_up = 0; - unsigned int minorvers = 0; - unsigned int minorversset = 0; -diff --git a/utils/nfsdcltrack/Makefile.am b/utils/nfsdcltrack/Makefile.am -index a860ffb..7524295 100644 ---- a/utils/nfsdcltrack/Makefile.am -+++ b/utils/nfsdcltrack/Makefile.am -@@ -1,5 +1,9 @@ - ## Process this file with automake to produce Makefile.in - -+# These binaries go in /sbin (not /usr/sbin), and that cannot be -+# overridden at config time. The kernel "knows" the /sbin name. -+sbindir = /sbin -+ - man8_MANS = nfsdcltrack.man - EXTRA_DIST = $(man8_MANS) - -diff --git a/utils/statd/callback.c b/utils/statd/callback.c -index d1cc139..bb7c590 100644 ---- a/utils/statd/callback.c -+++ b/utils/statd/callback.c -@@ -10,11 +10,13 @@ - #include - #endif - -+#include - #include - - #include "rpcmisc.h" - #include "statd.h" - #include "notlist.h" -+#include "ha-callout.h" - - /* Callback notify list. */ - /* notify_list *cbnl = NULL; ... never used */ -@@ -87,6 +89,13 @@ sm_notify_1_svc(struct stat_chge *argp, struct svc_req *rqstp) - xlog(D_CALL, "Received SM_NOTIFY from %s, state: %d", - argp->mon_name, argp->state); - -+ if (!statd_present_address(sap, ip_addr, sizeof(ip_addr))) { -+ xlog_warn("Unrecognized sender address"); -+ return ((void *) &result); -+ } -+ -+ ha_callout("sm-notify", argp->mon_name, ip_addr, argp->state); -+ - /* quick check - don't bother if we're not monitoring anyone */ - if (rtnl == NULL) { - xlog_warn("SM_NOTIFY from %s while not monitoring any hosts", -@@ -94,11 +103,6 @@ sm_notify_1_svc(struct stat_chge *argp, struct svc_req *rqstp) - return ((void *) &result); - } - -- if (!statd_present_address(sap, ip_addr, sizeof(ip_addr))) { -- xlog_warn("Unrecognized sender address"); -- return ((void *) &result); -- } -- - /* okir change: statd doesn't remove the remote host from its - * internal monitor list when receiving an SM_NOTIFY call from - * it. Lockd will want to continue monitoring the remote host -diff --git a/utils/statd/start-statd b/utils/statd/start-statd -index cde3583..dcdaf77 100644 ---- a/utils/statd/start-statd -+++ b/utils/statd/start-statd -@@ -4,8 +4,8 @@ - # /var/run/rpc.statd.pid). - # It should run statd with whatever flags are apropriate for this - # site. --PATH=/sbin:/usr/sbin --if systemctl start statd.service -+PATH="/sbin:/usr/sbin:/bin:/usr/bin" -+if systemctl start rpc-statd.service - then : - else - exec rpc.statd --no-notify -diff --git a/utils/statd/statd.man b/utils/statd/statd.man -index 896c2f8..1e5520c 100644 ---- a/utils/statd/statd.man -+++ b/utils/statd/statd.man -@@ -346,7 +346,8 @@ points due to inactivity. - .SS High-availability callouts - .B rpc.statd - can exec a special callout program during processing of --successful SM_MON, SM_UNMON, and SM_UNMON_ALL requests. -+successful SM_MON, SM_UNMON, and SM_UNMON_ALL requests, -+or when it receives SM_NOTIFY. - Such a program may be used in High Availability NFS (HA-NFS) - environments to track lock state that may need to be migrated after - a system reboot. -@@ -357,15 +358,26 @@ option. - The program is run with 3 arguments: - The first is either - .B add-client --or - .B del-client -+or -+.B sm-notify - depending on the reason for the callout. - The second is the - .I mon_name - of the monitored peer. - The third is the --.I caller_name --of the requesting lock manager. -+.I caller_name -+of the requesting lock manager for -+.B add-client -+or -+.B del-client -+, otherwise it is -+.I IP_address -+of the caller sending SM_NOTIFY. -+The forth is the -+.I state_value -+in the SM_NOTIFY request. -+ - .SS IPv6 and TI-RPC support - TI-RPC is a pre-requisite for supporting NFS on IPv6. - If TI-RPC support is built into diff --git a/nfs-utils-1.3.1-rc4.patch b/nfs-utils-1.3.1-rc4.patch deleted file mode 100644 index 1bd33b4..0000000 --- a/nfs-utils-1.3.1-rc4.patch +++ /dev/null @@ -1,1892 +0,0 @@ -diff --git a/Makefile.am b/Makefile.am -index ae7cd16..5824adc 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -54,13 +54,13 @@ install-data-hook: - touch $(DESTDIR)$(statedir)/xtab; chmod 644 $(DESTDIR)$(statedir)/xtab - touch $(DESTDIR)$(statedir)/etab; chmod 644 $(DESTDIR)$(statedir)/etab - touch $(DESTDIR)$(statedir)/rmtab; chmod 644 $(DESTDIR)$(statedir)/rmtab -- mkdir -p $(DESTDIR)$(statedir)/sm $(DESTDIR)$(statedir)/sm.bak -- touch $(DESTDIR)$(statedir)/state -- chmod go-rwx $(DESTDIR)$(statedir)/sm $(DESTDIR)$(statedir)/sm.bak $(DESTDIR)$(statedir)/state -- -chown $(statduser) $(DESTDIR)$(statedir)/sm $(DESTDIR)$(statedir)/sm.bak $(DESTDIR)$(statedir)/state -+ mkdir -p $(DESTDIR)$(statdpath)/sm $(DESTDIR)$(statdpath)/sm.bak -+ touch $(DESTDIR)$(statdpath)/state -+ chmod go-rwx $(DESTDIR)$(statdpath)/sm $(DESTDIR)$(statdpath)/sm.bak $(DESTDIR)$(statdpath)/state -+ -chown $(statduser) $(DESTDIR)$(statdpath)/sm $(DESTDIR)$(statdpath)/sm.bak $(DESTDIR)$(statdpath)/state - - uninstall-hook: - rm $(DESTDIR)$(statedir)/xtab - rm $(DESTDIR)$(statedir)/etab - rm $(DESTDIR)$(statedir)/rmtab -- rm $(DESTDIR)$(statedir)/state -+ rm $(DESTDIR)$(statdpath)/state -diff --git a/configure.ac b/configure.ac -index 7b93de6..bc48373 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -8,6 +8,7 @@ AM_INIT_AUTOMAKE - AC_PREREQ(2.59) - AC_PREFIX_DEFAULT(/usr) - AM_MAINTAINER_MODE -+AC_USE_SYSTEM_EXTENSIONS - - dnl ************************************************************* - dnl * Define the set of applicable options -@@ -247,9 +248,6 @@ AC_CHECK_FUNC([connect], , - AC_CHECK_FUNC([getaddrinfo], , - [AC_MSG_ERROR([Function 'getaddrinfo' not found.])]) - --AC_CHECK_FUNC([getrpcbynumber], , -- [AC_MSG_ERROR([Function 'getrpcbynumber' not found.])]) -- - AC_CHECK_FUNC([getservbyname], , - [AC_MSG_ERROR([Function 'getservbyname' not found.])]) - -@@ -408,11 +406,10 @@ AC_FUNC_STAT - AC_FUNC_VPRINTF - AC_CHECK_FUNCS([alarm atexit dup2 fdatasync ftruncate getcwd \ - gethostbyaddr gethostbyname gethostname getmntent \ -- getnameinfo getrpcbyname getifaddrs \ -+ getnameinfo getrpcbyname getrpcbynumber getrpcbynumber_r getifaddrs \ - gettimeofday hasmntopt inet_ntoa innetgr memset mkdir pathconf \ - ppoll realpath rmdir select socket strcasecmp strchr strdup \ -- strerror strrchr strtol strtoul sigprocmask]) -- -+ strerror strrchr strtol strtoul sigprocmask name_to_handle_at]) - - dnl ************************************************************* - dnl Check for data sizes -diff --git a/support/export/client.c b/support/export/client.c -index dbf47b9..f85e11c 100644 ---- a/support/export/client.c -+++ b/support/export/client.c -@@ -482,8 +482,12 @@ add_name(char *old, const char *add) - else - cp = cp + strlen(cp); - } -- strncpy(new, old, cp-old); -- new[cp-old] = 0; -+ if (old) { -+ strncpy(new, old, cp-old); -+ new[cp-old] = 0; -+ } else { -+ new[0] = 0; -+ } - if (cp != old && !*cp) - strcat(new, ","); - strcat(new, add); -diff --git a/support/export/hostname.c b/support/export/hostname.c -index 3e949a1..d9153e1 100644 ---- a/support/export/hostname.c -+++ b/support/export/hostname.c -@@ -91,7 +91,7 @@ host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen) - * Returns address info structure, or NULL if an error occurs. Caller - * must free the returned structure with freeaddrinfo(3). - */ --__attribute_malloc__ -+__attribute__((__malloc__)) - struct addrinfo * - host_pton(const char *paddr) - { -@@ -115,6 +115,11 @@ host_pton(const char *paddr) - * have a real AF_INET presentation address, before invoking - * getaddrinfo(3) to generate the full addrinfo list. - */ -+ if (paddr == NULL) { -+ xlog(D_GENERAL, "%s: passed a NULL presentation address", -+ __func__); -+ return NULL; -+ } - inet4 = 1; - if (inet_pton(AF_INET, paddr, &sin.sin_addr) == 0) - inet4 = 0; -@@ -123,15 +128,12 @@ host_pton(const char *paddr) - switch (error) { - case 0: - if (!inet4 && ai->ai_addr->sa_family == AF_INET) { -+ xlog(D_GENERAL, "%s: failed to convert %s", -+ __func__, paddr); - freeaddrinfo(ai); - break; - } - return ai; -- case EAI_NONAME: -- if (paddr == NULL) -- xlog(D_GENERAL, "%s: passed a NULL presentation address", -- __func__); -- break; - case EAI_SYSTEM: - xlog(D_GENERAL, "%s: failed to convert %s: (%d) %m", - __func__, paddr, errno); -@@ -153,7 +155,7 @@ host_pton(const char *paddr) - * if no information is available for @hostname. Caller must free the - * returned structure with freeaddrinfo(3). - */ --__attribute_malloc__ -+__attribute__((__malloc__)) - struct addrinfo * - host_addrinfo(const char *hostname) - { -@@ -199,7 +201,7 @@ host_addrinfo(const char *hostname) - * the string. - */ - #ifdef HAVE_GETNAMEINFO --__attribute_malloc__ -+__attribute__((__malloc__)) - char * - host_canonname(const struct sockaddr *sap) - { -@@ -234,7 +236,7 @@ host_canonname(const struct sockaddr *sap) - return strdup(buf); - } - #else /* !HAVE_GETNAMEINFO */ --__attribute_malloc__ -+__attribute__((__malloc__)) - char * - host_canonname(const struct sockaddr *sap) - { -@@ -266,7 +268,7 @@ host_canonname(const struct sockaddr *sap) - * - * Caller must free the returned structure with freeaddrinfo(3). - */ --__attribute_malloc__ -+__attribute__((__malloc__)) - struct addrinfo * - host_reliable_addrinfo(const struct sockaddr *sap) - { -@@ -313,7 +315,7 @@ out_free_hostname: - * Caller must free the returned structure with freeaddrinfo(3). - */ - #ifdef HAVE_GETNAMEINFO --__attribute_malloc__ -+__attribute__((__malloc__)) - struct addrinfo * - host_numeric_addrinfo(const struct sockaddr *sap) - { -@@ -361,7 +363,7 @@ host_numeric_addrinfo(const struct sockaddr *sap) - return ai; - } - #else /* !HAVE_GETNAMEINFO */ --__attribute_malloc__ -+__attribute__((__malloc__)) - struct addrinfo * - host_numeric_addrinfo(const struct sockaddr *sap) - { -diff --git a/support/include/conffile.h b/support/include/conffile.h -index 05ea5d2..a6d5846 100644 ---- a/support/include/conffile.h -+++ b/support/include/conffile.h -@@ -35,6 +35,7 @@ - - #include - #include -+#include - - struct conf_list_node { - TAILQ_ENTRY(conf_list_node) link; -@@ -49,7 +50,7 @@ struct conf_list { - extern char *conf_path; - - extern int conf_begin(void); --extern int conf_decode_base64(u_int8_t *, u_int32_t *, u_char *); -+extern int conf_decode_base64(uint8_t *, uint32_t *, unsigned char *); - extern int conf_end(int, int); - extern void conf_free_list(struct conf_list *); - extern struct sockaddr *conf_get_address(char *, char *); -diff --git a/support/include/exportfs.h b/support/include/exportfs.h -index 97b2327..9021fae 100644 ---- a/support/include/exportfs.h -+++ b/support/include/exportfs.h -@@ -156,15 +156,15 @@ int secinfo_addflavor(struct flav_info *, struct exportent *); - - char * host_ntop(const struct sockaddr *sap, - char *buf, const size_t buflen); --__attribute_malloc__ -+__attribute__((__malloc__)) - struct addrinfo * host_pton(const char *paddr); --__attribute_malloc__ -+__attribute__((__malloc__)) - struct addrinfo * host_addrinfo(const char *hostname); --__attribute_malloc__ -+__attribute__((__malloc__)) - char * host_canonname(const struct sockaddr *sap); --__attribute_malloc__ -+__attribute__((__malloc__)) - struct addrinfo * host_reliable_addrinfo(const struct sockaddr *sap); --__attribute_malloc__ -+__attribute__((__malloc__)) - struct addrinfo * host_numeric_addrinfo(const struct sockaddr *sap); - - int rmtab_read(void); -diff --git a/support/include/nfs/export.h b/support/include/nfs/export.h -index 1547a87..2f59e6a 100644 ---- a/support/include/nfs/export.h -+++ b/support/include/nfs/export.h -@@ -17,7 +17,8 @@ - #define NFSEXP_ALLSQUASH 0x0008 - #define NFSEXP_ASYNC 0x0010 - #define NFSEXP_GATHERED_WRITES 0x0020 --/* 40, 80, 100 unused */ -+#define NFSEXP_NOREADDIRPLUS 0x0040 -+/* 80, 100 unused */ - #define NFSEXP_NOHIDE 0x0200 - #define NFSEXP_NOSUBTREECHECK 0x0400 - #define NFSEXP_NOAUTHNLM 0x0800 -diff --git a/support/include/sockaddr.h b/support/include/sockaddr.h -index a1c30f9..446b537 100644 ---- a/support/include/sockaddr.h -+++ b/support/include/sockaddr.h -@@ -27,6 +27,7 @@ - #ifdef HAVE_LIBIO_H - #include - #endif -+#include - #include - #include - #include -diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c -index c3434d5..6b94ec0 100644 ---- a/support/nfs/conffile.c -+++ b/support/nfs/conffile.c -@@ -72,10 +72,10 @@ TAILQ_HEAD (conf_trans_head, conf_trans) conf_trans_queue; - /* - * Radix-64 Encoding. - */ --static const u_int8_t bin2asc[] -+static const uint8_t bin2asc[] - = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - --static const u_int8_t asc2bin[] = -+static const uint8_t asc2bin[] = - { - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, -@@ -109,10 +109,10 @@ LIST_HEAD (conf_bindings, conf_binding) conf_bindings[256]; - - static char *conf_addr; - --static __inline__ u_int8_t -+static __inline__ uint8_t - conf_hash(char *s) - { -- u_int8_t hash = 0; -+ uint8_t hash = 0; - - while (*s) { - hash = ((hash << 1) | (hash >> 7)) ^ tolower (*s); -@@ -603,10 +603,10 @@ cleanup: - - /* Decode a PEM encoded buffer. */ - int --conf_decode_base64 (u_int8_t *out, u_int32_t *len, u_char *buf) -+conf_decode_base64 (uint8_t *out, uint32_t *len, unsigned char *buf) - { -- u_int32_t c = 0; -- u_int8_t c1, c2, c3, c4; -+ uint32_t c = 0; -+ uint8_t c1, c2, c3, c4; - - while (*buf) { - if (*buf > 127 || (c1 = asc2bin[*buf]) == 255) -diff --git a/support/nfs/exports.c b/support/nfs/exports.c -index 819d6c4..eb782b9 100644 ---- a/support/nfs/exports.c -+++ b/support/nfs/exports.c -@@ -273,6 +273,8 @@ putexportent(struct exportent *ep) - "in" : ""); - fprintf(fp, "%sacl,", (ep->e_flags & NFSEXP_NOACL)? - "no_" : ""); -+ if (ep->e_flags & NFSEXP_NOREADDIRPLUS) -+ fprintf(fp, "nordirplus,"); - if (ep->e_flags & NFSEXP_FSID) { - fprintf(fp, "fsid=%d,", ep->e_fsid); - } -@@ -539,6 +541,8 @@ parseopts(char *cp, struct exportent *ep, int warn, int *had_subtree_opt_ptr) - clearflags(NFSEXP_ASYNC, active, ep); - else if (!strcmp(opt, "async")) - setflags(NFSEXP_ASYNC, active, ep); -+ else if (!strcmp(opt, "nordirplus")) -+ setflags(NFSEXP_NOREADDIRPLUS, active, ep); - else if (!strcmp(opt, "nohide")) - setflags(NFSEXP_NOHIDE, active, ep); - else if (!strcmp(opt, "hide")) -diff --git a/support/nfs/rpc_socket.c b/support/nfs/rpc_socket.c -index 7896cd2..2900d18 100644 ---- a/support/nfs/rpc_socket.c -+++ b/support/nfs/rpc_socket.c -@@ -106,36 +106,6 @@ static CLIENT *nfs_get_localclient(const struct sockaddr *sap, - return client; - } - --/* -- * Bind a socket using an unused ephemeral source port. -- * -- * Returns zero on success, or returns -1 on error. errno is -- * set to reflect the nature of the error. -- */ --static int nfs_bind(const int sock, const sa_family_t family) --{ -- struct sockaddr_in sin = { -- .sin_family = AF_INET, -- .sin_addr.s_addr = htonl(INADDR_ANY), -- }; -- struct sockaddr_in6 sin6 = { -- .sin6_family = AF_INET6, -- .sin6_addr = IN6ADDR_ANY_INIT, -- }; -- -- switch (family) { -- case AF_INET: -- return bind(sock, (struct sockaddr *)(char *)&sin, -- (socklen_t)sizeof(sin)); -- case AF_INET6: -- return bind(sock, (struct sockaddr *)(char *)&sin6, -- (socklen_t)sizeof(sin6)); -- } -- -- errno = EAFNOSUPPORT; -- return -1; --} -- - #ifdef HAVE_LIBTIRPC - - /* -@@ -276,7 +246,8 @@ static CLIENT *nfs_get_udpclient(const struct sockaddr *sap, - const int resvport) - { - CLIENT *client; -- int ret, sock; -+ int ret = 0; -+ int sock = 0; - #ifdef HAVE_LIBTIRPC - struct sockaddr_storage address; - const struct netbuf nbuf = { -@@ -300,15 +271,15 @@ static CLIENT *nfs_get_udpclient(const struct sockaddr *sap, - return NULL; - } - -- if (resvport) -+ if (resvport) { - ret = nfs_bindresvport(sock, sap->sa_family); -- else -- ret = nfs_bind(sock, sap->sa_family); -- if (ret < 0) { -- rpc_createerr.cf_stat = RPC_SYSTEMERROR; -- rpc_createerr.cf_error.re_errno = errno; -- (void)close(sock); -- return NULL; -+ -+ if (ret < 0) { -+ rpc_createerr.cf_stat = RPC_SYSTEMERROR; -+ rpc_createerr.cf_error.re_errno = errno; -+ (void)close(sock); -+ return NULL; -+ } - } - - if (timeout->tv_sec == -1) -@@ -358,7 +329,8 @@ static CLIENT *nfs_get_tcpclient(const struct sockaddr *sap, - const int resvport) - { - CLIENT *client; -- int ret, sock; -+ int ret = 0; -+ int sock = 0; - #ifdef HAVE_LIBTIRPC - struct sockaddr_storage address; - const struct netbuf nbuf = { -@@ -382,15 +354,15 @@ static CLIENT *nfs_get_tcpclient(const struct sockaddr *sap, - return NULL; - } - -- if (resvport) -+ if (resvport) { - ret = nfs_bindresvport(sock, sap->sa_family); -- else -- ret = nfs_bind(sock, sap->sa_family); -- if (ret < 0) { -- rpc_createerr.cf_stat = RPC_SYSTEMERROR; -- rpc_createerr.cf_error.re_errno = errno; -- (void)close(sock); -- return NULL; -+ -+ if (ret < 0) { -+ rpc_createerr.cf_stat = RPC_SYSTEMERROR; -+ rpc_createerr.cf_error.re_errno = errno; -+ (void)close(sock); -+ return NULL; -+ } - } - - if (timeout->tv_sec == -1) -diff --git a/support/nfs/svc_create.c b/support/nfs/svc_create.c -index 6b9e85b..a706f87 100644 ---- a/support/nfs/svc_create.c -+++ b/support/nfs/svc_create.c -@@ -113,7 +113,7 @@ svc_create_find_xprt(const struct sockaddr *bindaddr, const struct netconfig *nc - * - * Otherwise NULL is returned if an error occurs. - */ --__attribute_malloc__ -+__attribute__((__malloc__)) - static struct addrinfo * - svc_create_bindaddr(struct netconfig *nconf, const uint16_t port) - { -diff --git a/support/nfs/svc_socket.c b/support/nfs/svc_socket.c -index f56f310..74273b9 100644 ---- a/support/nfs/svc_socket.c -+++ b/support/nfs/svc_socket.c -@@ -25,6 +25,8 @@ - #include - #include - -+#include "config.h" -+ - #ifdef _LIBC - # include - #else -@@ -37,13 +39,20 @@ - - int getservport(u_long number, const char *proto) - { -- char rpcdata[1024], servdata[1024]; -- struct rpcent rpcbuf, *rpcp; -+ char servdata[1024]; -+ struct rpcent *rpcp; - struct servent servbuf, *servp = NULL; -- int ret; -+ int ret = 0; -+#if HAVE_GETRPCBYNUMBER_R -+ char rpcdata[1024]; -+ struct rpcent rpcbuf; - - ret = getrpcbynumber_r(number, &rpcbuf, rpcdata, sizeof rpcdata, - &rpcp); -+#else -+ rpcp = getrpcbynumber(number); -+#endif -+ - if (ret == 0 && rpcp != NULL) { - /* First try name. */ - ret = getservbyname_r(rpcp->r_name, proto, &servbuf, servdata, -diff --git a/tools/mountstats/mountstats.py b/tools/mountstats/mountstats.py -index e46105d..1fb3e2f 100644 ---- a/tools/mountstats/mountstats.py -+++ b/tools/mountstats/mountstats.py -@@ -371,7 +371,7 @@ def parse_stats_file(filename): - ms_dict = dict() - key = '' - -- f = file(filename) -+ f = open(filename) - for line in f.readlines(): - words = line.split() - if len(words) == 0: -diff --git a/tools/nfs-iostat/nfs-iostat.py b/tools/nfs-iostat/nfs-iostat.py -index 341cdbf..61d15a5 100644 ---- a/tools/nfs-iostat/nfs-iostat.py -+++ b/tools/nfs-iostat/nfs-iostat.py -@@ -213,7 +213,8 @@ class DeviceData: - # the reference to them. so we build new lists here - # for the result object. - for op in result.__rpc_data['ops']: -- result.__rpc_data[op] = map(difference, self.__rpc_data[op], old_stats.__rpc_data[op]) -+ result.__rpc_data[op] = list(map( -+ difference, self.__rpc_data[op], old_stats.__rpc_data[op])) - - # update the remaining keys we care about - result.__rpc_data['rpcsends'] -= old_stats.__rpc_data['rpcsends'] -@@ -243,27 +244,15 @@ class DeviceData: - """Print attribute cache efficiency stats - """ - nfs_stats = self.__nfs_data -- getattr_stats = self.__rpc_data['GETATTR'] -- -- if nfs_stats['inoderevalidates'] != 0: -- getattr_ops = float(getattr_stats[1]) -- opens = float(nfs_stats['vfsopen']) -- revalidates = float(nfs_stats['inoderevalidates']) - opens -- if revalidates != 0: -- ratio = ((revalidates - getattr_ops) * 100) / revalidates -- else: -- ratio = 0.0 -- -- data_invalidates = float(nfs_stats['datainvalidates']) -- attr_invalidates = float(nfs_stats['attrinvalidates']) - -- print() -- print('%d inode revalidations, hitting in cache %4.2f%% of the time' % \ -- (revalidates, ratio)) -- print('%d open operations (mandatory GETATTR requests)' % opens) -- if getattr_ops != 0: -- print('%4.2f%% of GETATTRs resulted in data cache invalidations' % \ -- ((data_invalidates * 100) / getattr_ops)) -+ print() -+ print('%d VFS opens' % (nfs_stats['vfsopen'])) -+ print('%d inoderevalidates (forced GETATTRs)' % \ -+ (nfs_stats['inoderevalidates'])) -+ print('%d page cache invalidations' % \ -+ (nfs_stats['datainvalidates'])) -+ print('%d attribute cache invalidations' % \ -+ (nfs_stats['attrinvalidates'])) - - def __print_dir_cache_stats(self, sample_time): - """Print directory stats -@@ -353,15 +342,21 @@ class DeviceData: - exe_per_op = 0.0 - - op += ':' -- print('%s' % op.lower().ljust(15), end='') -- print(' ops/s\t\t kB/s\t\t kB/op\t\tretrans\t\tavg RTT (ms)\tavg exe (ms)') -- -- print('\t\t%7.3f' % (ops / sample_time), end='') -- print('\t%7.3f' % (kilobytes / sample_time), end='') -- print('\t%7.3f' % kb_per_op, end='') -- print(' %7d (%3.1f%%)' % (retrans, retrans_percent), end='') -- print('\t%7.3f' % rtt_per_op, end='') -- print('\t%7.3f' % exe_per_op) -+ print(format(op.lower(), '<16s'), end='') -+ print(format('ops/s', '>8s'), end='') -+ print(format('kB/s', '>16s'), end='') -+ print(format('kB/op', '>16s'), end='') -+ print(format('retrans', '>16s'), end='') -+ print(format('avg RTT (ms)', '>16s'), end='') -+ print(format('avg exe (ms)', '>16s')) -+ -+ print(format((ops / sample_time), '>24.3f'), end='') -+ print(format((kilobytes / sample_time), '>16.3f'), end='') -+ print(format(kb_per_op, '>16.3f'), end='') -+ retransmits = '{0:>10.0f} ({1:>3.1f}%)'.format(retrans, retrans_percent).strip() -+ print(format(retransmits, '>16'), end='') -+ print(format(rtt_per_op, '>16.3f'), end='') -+ print(format(exe_per_op, '>16.3f')) - - def ops(self, sample_time): - sends = float(self.__rpc_data['rpcsends']) -@@ -391,9 +386,10 @@ class DeviceData: - (self.__nfs_data['export'], self.__nfs_data['mountpoint'])) - print() - -- print(' op/s\t\trpc bklog') -- print('%7.2f' % (sends / sample_time), end='') -- print('\t%7.2f' % backlog) -+ print(format('ops/s', '>16') + format('rpc bklog', '>16')) -+ print(format((sends / sample_time), '>16.3f'), end='') -+ print(format(backlog, '>16.3f')) -+ print() - - if which == 0: - self.__print_rpc_op_stats('READ', sample_time) -diff --git a/tools/nfs-iostat/nfsiostat.man b/tools/nfs-iostat/nfsiostat.man -index 3ec245d..b477a9a 100644 ---- a/tools/nfs-iostat/nfsiostat.man -+++ b/tools/nfs-iostat/nfsiostat.man -@@ -38,6 +38,61 @@ If one or more - .I - names are specified, statistics for only these mount points will - be displayed. Otherwise, all NFS mount points on the client are listed. -+.TP -+The meaning of each column of \fBnfsiostat\fR's output is the following: -+.RS 8 -+- \fBop/s\fR -+.RS -+This is the number of operations per second. -+.RS -+.RE -+.RE -+.RE -+.RS 8 -+- \fBrpc bklog\fR -+.RS -+This is the length of the backlog queue. -+.RE -+.RE -+.RE -+.RS 8 -+- \fBkB/s\fR -+.RS -+This is the number of kB written/read per second. -+.RE -+.RE -+.RE -+.RS 8 -+- \fBkB/op\fR -+.RS -+This is the number of kB written/read per each operation. -+.RE -+.RE -+.RE -+.RS 8 -+- \fBretrans\fR -+.RS -+This is the number of retransmissions. -+.RE -+.RE -+.RE -+.RS 8 -+- \fBavg RTT (ms)\fR -+.RS -+This is the duration from the time that client's kernel sends the RPC request until the time it receives the reply. -+.RE -+.RE -+.RE -+.RS 8 -+- \fBavg exe (ms)\fR -+.RS -+This is the duration from the time that NFS client does the RPC request to its kernel until the RPC request is completed, this includes the RTT time above. -+.RE -+.RE -+.RE -+.TP -+Note that if an interval is used as argument to \fBnfsiostat\fR, then the diffrence from previous interval will be displayed, otherwise the results will be from the time that the share was mounted. -+ - .SH OPTIONS - .TP - .B \-a " or " \-\-attr -diff --git a/tools/rpcdebug/rpcdebug.c b/tools/rpcdebug/rpcdebug.c -index d6e10d3..18b1622 100644 ---- a/tools/rpcdebug/rpcdebug.c -+++ b/tools/rpcdebug/rpcdebug.c -@@ -26,6 +26,7 @@ - #include - #include - #include -+#include - /* RPC debug flags - #include */ - /* NFS debug flags -diff --git a/utils/blkmapd/device-discovery.c b/utils/blkmapd/device-discovery.c -index df4627e..b52afe2 100644 ---- a/utils/blkmapd/device-discovery.c -+++ b/utils/blkmapd/device-discovery.c -@@ -77,16 +77,6 @@ struct bl_disk_path *bl_get_path(const char *filepath, - return tmp; - } - --/* Check whether valid_path is a substring(partition) of path */ --int bl_is_partition(struct bl_disk_path *valid_path, struct bl_disk_path *path) --{ -- if (!strncmp(valid_path->full_path, path->full_path, -- strlen(valid_path->full_path))) -- return 1; -- -- return 0; --} -- - /* - * For multipath devices, devices state could be PASSIVE/ACTIVE/PSEUDO, - * where PSEUDO > ACTIVE > PASSIVE. Device with highest state is used to -@@ -95,19 +85,13 @@ int bl_is_partition(struct bl_disk_path *valid_path, struct bl_disk_path *path) - * If device-mapper multipath support is a must, pseudo devices should - * exist for each multipath device. If not, active device path will be - * chosen for device creation. -- * Treat partition as invalid path. - */ --int bl_update_path(struct bl_disk_path *path, enum bl_path_state_e state, -- struct bl_disk *disk) -+int bl_update_path(enum bl_path_state_e state, struct bl_disk *disk) - { - struct bl_disk_path *valid_path = disk->valid_path; - -- if (valid_path) { -- if (valid_path->state >= state) { -- if (bl_is_partition(valid_path, path)) -- return 0; -- } -- } -+ if (valid_path && valid_path->state >= state) -+ return 0; - return 1; - } - -@@ -164,15 +148,16 @@ void bl_add_disk(char *filepath) - - dev = sb.st_rdev; - serial = bldev_read_serial(fd, filepath); -- if (dm_is_dm_major(major(dev))) -+ if (!serial) { -+ BL_LOG_ERR("%s: no serial found for %s\n", -+ __func__, filepath); -+ ap_state = BL_PATH_STATE_PASSIVE; -+ } else if (dm_is_dm_major(major(dev))) - ap_state = BL_PATH_STATE_PSEUDO; - else - ap_state = bldev_read_ap_state(fd); - close(fd); - -- if (ap_state != BL_PATH_STATE_ACTIVE) -- return; -- - for (disk = visible_disk_list; disk != NULL; disk = disk->next) { - /* Already scanned or a partition? - * XXX: if released each time, maybe not need to compare -@@ -216,7 +201,7 @@ void bl_add_disk(char *filepath) - path->next = disk->paths; - disk->paths = path; - /* check whether we need to update disk info */ -- if (bl_update_path(path, path->state, disk)) { -+ if (bl_update_path(path->state, disk)) { - disk->dev = dev; - disk->size = size; - disk->valid_path = path; -diff --git a/utils/blkmapd/device-process.c b/utils/blkmapd/device-process.c -index 5fe3dff..f53a616 100644 ---- a/utils/blkmapd/device-process.c -+++ b/utils/blkmapd/device-process.c -@@ -181,6 +181,8 @@ static int map_sig_to_device(struct bl_sig *sig, struct bl_volume *vol) - /* FIXME: should we use better algorithm for disk scan? */ - mapped = verify_sig(disk, sig); - if (mapped) { -+ BL_LOG_INFO("%s: using device %s\n", -+ __func__, disk->valid_path->full_path); - vol->param.bv_dev = disk->dev; - vol->bv_size = disk->size; - break; -diff --git a/utils/blkmapd/dm-device.c b/utils/blkmapd/dm-device.c -index 0f4f148..24ffcbf 100644 ---- a/utils/blkmapd/dm-device.c -+++ b/utils/blkmapd/dm-device.c -@@ -400,6 +400,8 @@ uint64_t dm_device_create(struct bl_volume *vols, int num_vols) - } - dev = node->bv_vols[0]->param.bv_dev; - tmp = table->params; -+ BL_LOG_INFO("%s: major %lu minor %lu", __func__, -+ MAJOR(dev), MINOR(dev)); - if (!dm_format_dev(tmp, DM_PARAMS_LEN, - MAJOR(dev), MINOR(dev))) { - free(table); -@@ -459,6 +461,8 @@ uint64_t dm_device_create(struct bl_volume *vols, int num_vols) - strcpy(table->target_type, "linear"); - tmp = table->params; - dev = node->bv_vols[i]->param.bv_dev; -+ BL_LOG_INFO("%s: major %lu minor %lu", __func__, -+ MAJOR(dev), MINOR(dev)); - if (!dm_format_dev(tmp, DM_PARAMS_LEN, - MAJOR(dev), MINOR(dev))) { - free(table); -diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c -index bf07555..e7d1ac8 100644 ---- a/utils/exportfs/exportfs.c -+++ b/utils/exportfs/exportfs.c -@@ -815,6 +815,8 @@ dump(int verbose, int export_format) - c = dumpopt(c, "no_subtree_check"); - if (ep->e_flags & NFSEXP_NOAUTHNLM) - c = dumpopt(c, "insecure_locks"); -+ if (ep->e_flags & NFSEXP_NOREADDIRPLUS) -+ c = dumpopt(c, "nordirplus"); - if (ep->e_flags & NFSEXP_NOACL) - c = dumpopt(c, "no_acl"); - if (ep->e_flags & NFSEXP_FSID) -diff --git a/utils/exportfs/exports.man b/utils/exportfs/exports.man -index e8b29df..3d974d9 100644 ---- a/utils/exportfs/exports.man -+++ b/utils/exportfs/exports.man -@@ -360,6 +360,11 @@ supported so the same configuration can be made to work on old and new - kernels alike. - - .TP -+.IR nordirplus -+This option will disable READDIRPLUS request handling. When set, -+READDIRPLUS requests from NFS clients return NFS3ERR_NOTSUPP, and -+clients fall back on READDIR. This option affects only NFSv3 clients. -+.TP - .IR refer= path@host[+host][:path@host[+host]] - A client referencing the export point will be directed to choose from - the given list an alternative location for the filesystem. -diff --git a/utils/gssd/Makefile.am b/utils/gssd/Makefile.am -index a9a3e42..af59791 100644 ---- a/utils/gssd/Makefile.am -+++ b/utils/gssd/Makefile.am -@@ -18,11 +18,13 @@ COMMON_SRCS = \ - context_lucid.c \ - gss_util.c \ - gss_oids.c \ -+ gss_names.c \ - err_util.c \ - \ - context.h \ - err_util.h \ - gss_oids.h \ -+ gss_names.h \ - gss_util.h - - gssd_SOURCES = \ -diff --git a/utils/gssd/gss_names.c b/utils/gssd/gss_names.c -new file mode 100644 -index 0000000..047069d ---- /dev/null -+++ b/utils/gssd/gss_names.c -@@ -0,0 +1,138 @@ -+/* -+ Copyright (c) 2000 The Regents of the University of Michigan. -+ All rights reserved. -+ -+ Copyright (c) 2002 Bruce Fields -+ -+ Redistribution and use in source and binary forms, with or without -+ modification, are permitted provided that the following conditions -+ are met: -+ -+ 1. Redistributions of source code must retain the above copyright -+ notice, this list of conditions and the following disclaimer. -+ 2. Redistributions in binary form must reproduce the above copyright -+ notice, this list of conditions and the following disclaimer in the -+ documentation and/or other materials provided with the distribution. -+ 3. Neither the name of the University nor the names of its -+ contributors may be used to endorse or promote products derived -+ from this software without specific prior written permission. -+ -+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+*/ -+ -+#ifdef HAVE_CONFIG_H -+#include -+#endif /* HAVE_CONFIG_H */ -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "svcgssd.h" -+#include "gss_util.h" -+#include "err_util.h" -+#include "context.h" -+#include "misc.h" -+#include "gss_oids.h" -+#include "svcgssd_krb5.h" -+ -+static int -+get_krb5_hostbased_name(gss_buffer_desc *name, char **hostbased_name) -+{ -+ char *p, *sname = NULL; -+ if (strchr(name->value, '@') && strchr(name->value, '/')) { -+ if ((sname = calloc(name->length, 1)) == NULL) { -+ printerr(0, "ERROR: get_krb5_hostbased_name failed " -+ "to allocate %d bytes\n", name->length); -+ return -1; -+ } -+ /* read in name and instance and replace '/' with '@' */ -+ sscanf(name->value, "%[^@]", sname); -+ p = strrchr(sname, '/'); -+ if (p == NULL) { /* The '@' preceeded the '/' */ -+ free(sname); -+ return -1; -+ } -+ *p = '@'; -+ } -+ *hostbased_name = sname; -+ return 0; -+} -+ -+int -+get_hostbased_client_name(gss_name_t client_name, gss_OID mech, -+ char **hostbased_name) -+{ -+ u_int32_t maj_stat, min_stat; -+ gss_buffer_desc name; -+ gss_OID name_type = GSS_C_NO_OID; -+ char *cname; -+ int res = -1; -+ -+ *hostbased_name = NULL; /* preset in case we fail */ -+ -+ /* Get the client's gss authenticated name */ -+ maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type); -+ if (maj_stat != GSS_S_COMPLETE) { -+ pgsserr("get_hostbased_client_name: gss_display_name", -+ maj_stat, min_stat, mech); -+ goto out_err; -+ } -+ if (name.length >= 0xffff) { /* don't overflow */ -+ printerr(0, "ERROR: get_hostbased_client_name: " -+ "received gss_name is too long (%d bytes)\n", -+ name.length); -+ goto out_rel_buf; -+ } -+ -+ /* For Kerberos, transform the NT_KRB5_PRINCIPAL name to -+ * an NT_HOSTBASED_SERVICE name */ -+ if (g_OID_equal(&krb5oid, mech)) { -+ if (get_krb5_hostbased_name(&name, &cname) == 0) -+ *hostbased_name = cname; -+ } else { -+ printerr(1, "WARNING: unknown/unsupport mech OID\n"); -+ } -+ -+ res = 0; -+out_rel_buf: -+ gss_release_buffer(&min_stat, &name); -+out_err: -+ return res; -+} -+ -+void -+get_hostbased_client_buffer(gss_name_t client_name, gss_OID mech, -+ gss_buffer_t buf) -+{ -+ char *hname; -+ -+ if (!get_hostbased_client_name(client_name, mech, &hname)) { -+ buf->length = strlen(hname) + 1; -+ buf->value = hname; -+ } else { -+ buf->length = 0; -+ buf->value = NULL; -+ } -+} -diff --git a/utils/gssd/gss_names.h b/utils/gssd/gss_names.h -new file mode 100644 -index 0000000..ce182f7 ---- /dev/null -+++ b/utils/gssd/gss_names.h -@@ -0,0 +1,36 @@ -+/* -+ Copyright (c) 2000 The Regents of the University of Michigan. -+ All rights reserved. -+ -+ Copyright (c) 2002 Bruce Fields -+ -+ Redistribution and use in source and binary forms, with or without -+ modification, are permitted provided that the following conditions -+ are met: -+ -+ 1. Redistributions of source code must retain the above copyright -+ notice, this list of conditions and the following disclaimer. -+ 2. Redistributions in binary form must reproduce the above copyright -+ notice, this list of conditions and the following disclaimer in the -+ documentation and/or other materials provided with the distribution. -+ 3. Neither the name of the University nor the names of its -+ contributors may be used to endorse or promote products derived -+ from this software without specific prior written permission. -+ -+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+*/ -+ -+extern int get_hostbased_client_name(gss_name_t client_name, gss_OID mech, -+ char **hostbased_name); -+extern void get_hostbased_client_buffer(gss_name_t client_name, -+ gss_OID mech, gss_buffer_t buf); -diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c -index 611ef1a..6b8b863 100644 ---- a/utils/gssd/gssd.c -+++ b/utils/gssd/gssd.c -@@ -64,6 +64,7 @@ char *ccachesearch[GSSD_MAX_CCACHE_SEARCH + 1]; - int use_memcache = 0; - int root_uses_machine_creds = 1; - unsigned int context_timeout = 0; -+unsigned int rpc_timeout = 5; - char *preferred_realm = NULL; - int pipefds[2] = { -1, -1 }; - -@@ -105,7 +106,7 @@ main(int argc, char *argv[]) - char *progname; - - memset(ccachesearch, 0, sizeof(ccachesearch)); -- while ((opt = getopt(argc, argv, "DfvrlmnMp:k:d:t:R:")) != -1) { -+ while ((opt = getopt(argc, argv, "DfvrlmnMp:k:d:t:T:R:")) != -1) { - switch (opt) { - case 'f': - fg = 1; -@@ -143,6 +144,9 @@ main(int argc, char *argv[]) - case 't': - context_timeout = atoi(optarg); - break; -+ case 'T': -+ rpc_timeout = atoi(optarg); -+ break; - case 'R': - preferred_realm = strdup(optarg); - break; -diff --git a/utils/gssd/gssd.h b/utils/gssd/gssd.h -index 56a18d6..48f4ad8 100644 ---- a/utils/gssd/gssd.h -+++ b/utils/gssd/gssd.h -@@ -66,6 +66,7 @@ extern char *ccachesearch[]; - extern int use_memcache; - extern int root_uses_machine_creds; - extern unsigned int context_timeout; -+extern unsigned int rpc_timeout; - extern char *preferred_realm; - extern int pipefds[2]; - -diff --git a/utils/gssd/gssd.man b/utils/gssd/gssd.man -index ac13fd4..ea58fa0 100644 ---- a/utils/gssd/gssd.man -+++ b/utils/gssd/gssd.man -@@ -289,6 +289,14 @@ new kernel contexts to be negotiated after - seconds, which allows changing Kerberos tickets and identities frequently. - The default is no explicit timeout, which means the kernel context will live - the lifetime of the Kerberos service ticket used in its creation. -+.TP -+.B -T timeout -+Timeout, in seconds, to create an RPC connection with a server while -+establishing an authenticated gss context for a user. -+The default timeout is set to 5 seconds. -+If you get messages like "WARNING: can't create tcp rpc_clnt to server -+%servername% for user with uid %uid%: RPC: Remote system error - -+Connection timed out", you should consider an increase of this timeout. - .SH SEE ALSO - .BR rpc.svcgssd (8), - .BR kerberos (1), -diff --git a/utils/gssd/gssd_main_loop.c b/utils/gssd/gssd_main_loop.c -index 9970028..6946ab6 100644 ---- a/utils/gssd/gssd_main_loop.c -+++ b/utils/gssd/gssd_main_loop.c -@@ -173,6 +173,10 @@ topdirs_init_list(void) - if (ret) - goto out_err; - } -+ if (TAILQ_EMPTY(&topdirs_list)) { -+ printerr(0, "ERROR: rpc_pipefs directory '%s' is empty!\n", pipefs_dir); -+ return -1; -+ } - closedir(pipedir); - return 0; - out_err: -@@ -233,9 +237,10 @@ gssd_run() - sigaddset(&set, DNOTIFY_SIGNAL); - sigprocmask(SIG_UNBLOCK, &set, NULL); - -- if (topdirs_init_list() != 0) -- return; -- -+ if (topdirs_init_list() != 0) { -+ /* Error msg is already printed */ -+ exit(1); -+ } - init_client_list(); - - printerr(1, "beginning poll\n"); -diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c -index 33cfeb2..121feb1 100644 ---- a/utils/gssd/gssd_proc.c -+++ b/utils/gssd/gssd_proc.c -@@ -77,6 +77,7 @@ - #include "context.h" - #include "nfsrpc.h" - #include "nfslib.h" -+#include "gss_names.h" - - /* - * pollarray: -@@ -217,7 +218,7 @@ get_servername(const char *name, const struct sockaddr *sa, const char *addr) - NI_NAMEREQD); - if (err) { - printerr(0, "ERROR: unable to resolve %s to hostname: %s\n", -- addr, err == EAI_SYSTEM ? strerror(err) : -+ addr, err == EAI_SYSTEM ? strerror(errno) : - gai_strerror(err)); - return NULL; - } -@@ -681,19 +682,25 @@ parse_enctypes(char *enctypes) - return 0; - } - --static int -+static void - do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd, -- gss_buffer_desc *context_token, OM_uint32 lifetime_rec) -+ gss_buffer_desc *context_token, OM_uint32 lifetime_rec, -+ gss_buffer_desc *acceptor) - { - char *buf = NULL, *p = NULL, *end = NULL; - unsigned int timeout = context_timeout; - unsigned int buf_size = 0; - -- printerr(1, "doing downcall lifetime_rec %u\n", lifetime_rec); -+ printerr(1, "doing downcall: lifetime_rec=%u acceptor=%.*s\n", -+ lifetime_rec, acceptor->length, acceptor->value); - buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) + - sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length + -- sizeof(context_token->length) + context_token->length; -+ sizeof(context_token->length) + context_token->length + -+ sizeof(acceptor->length) + acceptor->length; - p = buf = malloc(buf_size); -+ if (!buf) -+ goto out_err; -+ - end = buf + buf_size; - - /* context_timeout set by -t option overrides context lifetime */ -@@ -704,14 +711,15 @@ do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd, - if (WRITE_BYTES(&p, end, pd->pd_seq_win)) goto out_err; - if (write_buffer(&p, end, &pd->pd_ctx_hndl)) goto out_err; - if (write_buffer(&p, end, context_token)) goto out_err; -+ if (write_buffer(&p, end, acceptor)) goto out_err; - - if (write(k5_fd, buf, p - buf) < p - buf) goto out_err; -- if (buf) free(buf); -- return 0; -+ free(buf); -+ return; - out_err: -- if (buf) free(buf); -+ free(buf); - printerr(1, "Failed to write downcall!\n"); -- return -1; -+ return; - } - - static int -@@ -842,7 +850,7 @@ create_auth_rpc_client(struct clnt_info *clp, - OM_uint32 min_stat; - char rpc_errmsg[1024]; - int protocol; -- struct timeval timeout = {5, 0}; -+ struct timeval timeout; - struct sockaddr *addr = (struct sockaddr *) &clp->addr; - socklen_t salen; - -@@ -910,6 +918,10 @@ create_auth_rpc_client(struct clnt_info *clp, - if (!populate_port(addr, salen, clp->prog, clp->vers, protocol)) - goto out_fail; - -+ /* set the timeout according to the requested valued */ -+ timeout.tv_sec = (long) rpc_timeout; -+ timeout.tv_usec = (long) 0; -+ - rpc_clnt = nfs_get_rpcclient(addr, salen, protocol, clp->prog, - clp->vers, &timeout); - if (!rpc_clnt) { -@@ -1031,6 +1043,9 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, - gss_cred_id_t gss_cred; - OM_uint32 maj_stat, min_stat, lifetime_rec; - pid_t pid; -+ gss_name_t gacceptor = GSS_C_NO_NAME; -+ gss_OID mech; -+ gss_buffer_desc acceptor = {0}; - - pid = fork(); - switch(pid) { -@@ -1171,15 +1186,24 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, - goto out_return_error; - } - -- /* Grab the context lifetime to pass to the kernel. lifetime_rec -- * is set to zero on error */ -- maj_stat = gss_inquire_context(&min_stat, pd.pd_ctx, NULL, NULL, -- &lifetime_rec, NULL, NULL, NULL, NULL); -+ /* Grab the context lifetime and acceptor name out of the ctx. */ -+ maj_stat = gss_inquire_context(&min_stat, pd.pd_ctx, NULL, &gacceptor, -+ &lifetime_rec, &mech, NULL, NULL, NULL); - -- if (maj_stat) -- printerr(1, "WARNING: Failed to inquire context for lifetme " -- "maj_stat %u\n", maj_stat); -+ if (maj_stat != GSS_S_COMPLETE) { -+ printerr(1, "WARNING: Failed to inquire context " -+ "maj_stat (0x%x)\n", maj_stat); -+ lifetime_rec = 0; -+ } else { -+ get_hostbased_client_buffer(gacceptor, mech, &acceptor); -+ gss_release_name(&min_stat, &gacceptor); -+ } - -+ /* -+ * The serialization can mean turning pd.pd_ctx into a lucid context. If -+ * that happens then the pd.pd_ctx will be unusable, so we must never -+ * try to use it after this point. -+ */ - if (serialize_context_for_kernel(&pd.pd_ctx, &token, &krb5oid, NULL)) { - printerr(0, "WARNING: Failed to serialize krb5 context for " - "user with uid %d for server %s\n", -@@ -1187,9 +1211,10 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, - goto out_return_error; - } - -- do_downcall(fd, uid, &pd, &token, lifetime_rec); -+ do_downcall(fd, uid, &pd, &token, lifetime_rec, &acceptor); - - out: -+ gss_release_buffer(&min_stat, &acceptor); - if (token.value) - free(token.value); - #ifdef HAVE_AUTHGSS_FREE_PRIVATE_DATA -diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c -index 4b57141..f1ebc0d 100644 ---- a/utils/gssd/krb5_util.c -+++ b/utils/gssd/krb5_util.c -@@ -801,6 +801,8 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - char *k5err = NULL; - int tried_all = 0, tried_default = 0; - krb5_principal princ; -+ const char *notsetstr = "not set"; -+ char *adhostoverride; - - - /* Get full target hostname */ -@@ -818,13 +820,24 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - } - - /* Compute the active directory machine name HOST$ */ -- strcpy(myhostad, myhostname); -- for (i = 0; myhostad[i] != 0; ++i) { -- if (myhostad[i] == '.') break; -- myhostad[i] = toupper(myhostad[i]); -+ krb5_appdefault_string(context, "nfs", NULL, "ad_principal_name", -+ notsetstr, &adhostoverride); -+ if (strcmp(adhostoverride, notsetstr) != 0) { -+ printerr (1, -+ "AD host string overridden with \"%s\" from appdefaults\n", -+ adhostoverride); -+ /* No overflow: Windows cannot handle strings longer than 19 chars */ -+ strcpy(myhostad, adhostoverride); -+ free(adhostoverride); -+ } else { -+ strcpy(myhostad, myhostname); -+ for (i = 0; myhostad[i] != 0; ++i) { -+ if (myhostad[i] == '.') break; -+ myhostad[i] = toupper(myhostad[i]); -+ } -+ myhostad[i] = '$'; -+ myhostad[i+1] = 0; - } -- myhostad[i] = '$'; -- myhostad[i+1] = 0; - - retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname)); - if (retval) { -@@ -863,7 +876,7 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - i = 0; - realm = realmnames[i]; - -- if (strcmp (realm, preferred_realm) != 0) { -+ if (preferred_realm && strcmp (realm, preferred_realm) != 0) { - realm = preferred_realm; - /* resetting the realmnames index */ - i = -1; -diff --git a/utils/gssd/svcgssd_proc.c b/utils/gssd/svcgssd_proc.c -index 3757d51..5bdb438 100644 ---- a/utils/gssd/svcgssd_proc.c -+++ b/utils/gssd/svcgssd_proc.c -@@ -59,6 +59,7 @@ - #include "misc.h" - #include "gss_oids.h" - #include "svcgssd_krb5.h" -+#include "gss_names.h" - - extern char * mech2file(gss_OID mech); - #define SVCGSSD_CONTEXT_CHANNEL "/proc/net/rpc/auth.rpcsec.context/channel" -@@ -315,71 +316,6 @@ print_hexl(const char *description, unsigned char *cp, int length) - } - #endif - --static int --get_krb5_hostbased_name (gss_buffer_desc *name, char **hostbased_name) --{ -- char *p, *sname = NULL; -- if (strchr(name->value, '@') && strchr(name->value, '/')) { -- if ((sname = calloc(name->length, 1)) == NULL) { -- printerr(0, "ERROR: get_krb5_hostbased_name failed " -- "to allocate %d bytes\n", name->length); -- return -1; -- } -- /* read in name and instance and replace '/' with '@' */ -- sscanf(name->value, "%[^@]", sname); -- p = strrchr(sname, '/'); -- if (p == NULL) { /* The '@' preceeded the '/' */ -- free(sname); -- return -1; -- } -- *p = '@'; -- } -- *hostbased_name = sname; -- return 0; --} -- --static int --get_hostbased_client_name(gss_name_t client_name, gss_OID mech, -- char **hostbased_name) --{ -- u_int32_t maj_stat, min_stat; -- gss_buffer_desc name; -- gss_OID name_type = GSS_C_NO_OID; -- char *cname; -- int res = -1; -- -- *hostbased_name = NULL; /* preset in case we fail */ -- -- /* Get the client's gss authenticated name */ -- maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type); -- if (maj_stat != GSS_S_COMPLETE) { -- pgsserr("get_hostbased_client_name: gss_display_name", -- maj_stat, min_stat, mech); -- goto out_err; -- } -- if (name.length >= 0xffff) { /* don't overflow */ -- printerr(0, "ERROR: get_hostbased_client_name: " -- "received gss_name is too long (%d bytes)\n", -- name.length); -- goto out_rel_buf; -- } -- -- /* For Kerberos, transform the NT_KRB5_PRINCIPAL name to -- * an NT_HOSTBASED_SERVICE name */ -- if (g_OID_equal(&krb5oid, mech)) { -- if (get_krb5_hostbased_name(&name, &cname) == 0) -- *hostbased_name = cname; -- } else { -- printerr(1, "WARNING: unknown/unsupport mech OID\n"); -- } -- -- res = 0; --out_rel_buf: -- gss_release_buffer(&min_stat, &name); --out_err: -- return res; --} -- - void - handle_nullreq(FILE *f) { - /* XXX initialize to a random integer to reduce chances of unnecessary -diff --git a/utils/mount/error.c b/utils/mount/error.c -index f8fc13f..e06f598 100644 ---- a/utils/mount/error.c -+++ b/utils/mount/error.c -@@ -215,8 +215,12 @@ void mount_error(const char *spec, const char *mount_point, int error) - progname); - break; - case ENOTDIR: -- nfs_error(_("%s: mount point %s is not a directory"), -- progname, mount_point); -+ if (spec) -+ nfs_error(_("%s: mount spec %s or point %s is not a " -+ "directory"), progname, spec, mount_point); -+ else -+ nfs_error(_("%s: mount point %s is not a directory"), -+ progname, mount_point); - break; - case EBUSY: - nfs_error(_("%s: %s is busy or already mounted"), -diff --git a/utils/mount/mount.c b/utils/mount/mount.c -index eea00af..91f1087 100644 ---- a/utils/mount/mount.c -+++ b/utils/mount/mount.c -@@ -33,6 +33,7 @@ - #include - #include - #include -+#include - - #include "fstab.h" - #include "xcommon.h" -diff --git a/utils/mount/mount_libmount.c b/utils/mount/mount_libmount.c -index 701d41e..6f85dc9 100644 ---- a/utils/mount/mount_libmount.c -+++ b/utils/mount/mount_libmount.c -@@ -29,6 +29,7 @@ - #include - #include - #include -+#include - - #include - -diff --git a/utils/mount/nfsmount.conf b/utils/mount/nfsmount.conf -index 9b8ff4a..aeb3023 100644 ---- a/utils/mount/nfsmount.conf -+++ b/utils/mount/nfsmount.conf -@@ -133,3 +133,12 @@ - # RPCGSS security flavors - # [none, sys, krb5, krb5i, krb5p ] - # Sec=sys -+# -+# Allow Signals to interrupt file operations -+# Intr=True -+# -+# Specifies how the kernel manages its cache of directory -+# Lookupcache=all|none|pos|positive -+# -+# Turn of the caching of that access time -+# noatime=True -diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c -index 9a1bb27..663a52a 100644 ---- a/utils/mountd/cache.c -+++ b/utils/mountd/cache.c -@@ -377,6 +377,86 @@ static char *next_mnt(void **v, char *p) - return me->mnt_dir; - } - -+/* same_path() check is two paths refer to the same directory. -+ * We don't rely on 'strcmp()' as some filesystems support case-insensitive -+ * names and we might have two different names for the one directory. -+ * Theoretically the lengths of the names could be different, but the -+ * number of components must be the same. -+ * So if the paths have the same number of components (but aren't identical) -+ * we ask the kernel if they are the same thing. -+ * By preference we use name_to_handle_at(), as the mntid it returns -+ * will distinguish between bind-mount points. If that isn't available -+ * we fall back on lstat, which is usually good enough. -+ */ -+static inline int count_slashes(char *p) -+{ -+ int cnt = 0; -+ while (*p) -+ if (*p++ == '/') -+ cnt++; -+ return cnt; -+} -+ -+static int same_path(char *child, char *parent, int len) -+{ -+ static char p[PATH_MAX]; -+ struct stat sc, sp; -+ -+ if (len <= 0) -+ len = strlen(child); -+ strncpy(p, child, len); -+ p[len] = 0; -+ if (strcmp(p, parent) == 0) -+ return 1; -+ -+ /* If number of '/' are different, they must be different */ -+ if (count_slashes(p) != count_slashes(parent)) -+ return 0; -+ -+#if HAVE_NAME_TO_HANDLE_AT -+ struct { -+ struct file_handle fh; -+ unsigned char handle[128]; -+ } fchild, fparent; -+ int mnt_child, mnt_parent; -+ -+ fchild.fh.handle_bytes = 128; -+ fparent.fh.handle_bytes = 128; -+ if (name_to_handle_at(AT_FDCWD, p, &fchild.fh, &mnt_child, 0) != 0) { -+ if (errno == ENOSYS) -+ goto fallback; -+ return 0; -+ } -+ if (name_to_handle_at(AT_FDCWD, parent, &fparent.fh, &mnt_parent, 0) != 0) -+ return 0; -+ -+ if (mnt_child != mnt_parent || -+ fchild.fh.handle_bytes != fparent.fh.handle_bytes || -+ fchild.fh.handle_type != fparent.fh.handle_type || -+ memcmp(fchild.handle, fparent.handle, -+ fchild.fh.handle_bytes) != 0) -+ return 0; -+ -+ return 1; -+fallback: -+#endif -+ -+ /* This is nearly good enough. However if a directory is -+ * bind-mounted in two places and both are exported, it -+ * could give a false positive -+ */ -+ if (lstat(p, &sc) != 0) -+ return 0; -+ if (lstat(parent, &sp) != 0) -+ return 0; -+ if (sc.st_dev != sp.st_dev) -+ return 0; -+ if (sc.st_ino != sp.st_ino) -+ return 0; -+ -+ return 1; -+} -+ - static int is_subdirectory(char *child, char *parent) - { - /* Check is child is strictly a subdirectory of -@@ -387,7 +467,7 @@ static int is_subdirectory(char *child, char *parent) - if (strcmp(parent, "/") == 0 && child[1] != 0) - return 1; - -- return (strncmp(child, parent, l) == 0 && child[l] == '/'); -+ return (same_path(child, parent, l) && child[l] == '/'); - } - - static int path_matches(nfs_export *exp, char *path) -@@ -396,7 +476,7 @@ static int path_matches(nfs_export *exp, char *path) - * exact match, or does the export have CROSSMOUNT, and path - * is a descendant? - */ -- return strcmp(path, exp->m_export.e_path) == 0 -+ return same_path(path, exp->m_export.e_path, 0) - || ((exp->m_export.e_flags & NFSEXP_CROSSMOUNT) - && is_subdirectory(path, exp->m_export.e_path)); - } -@@ -1339,7 +1419,7 @@ static int cache_export_ent(char *domain, struct exportent *exp, char *path) - */ - struct stat stb; - size_t l = strlen(exp->e_path); -- __dev_t dev; -+ dev_t dev; - - if (strlen(path) <= l || path[l] != '/' || - strncmp(exp->e_path, path, l) != 0) -diff --git a/utils/mountd/mountd.man b/utils/mountd/mountd.man -index e59a559..a8828ae 100644 ---- a/utils/mountd/mountd.man -+++ b/utils/mountd/mountd.man -@@ -86,7 +86,7 @@ Turn on debugging. Valid kinds are: all, auth, call, general and parse. - .B \-F " or " \-\-foreground - Run in foreground (do not daemonize) - .TP --.B \-f " or " \-\-exports-file -+.B \-f export-file " or " \-\-exports-file export-file - This option specifies the exports file, listing the clients that this - server is prepared to serve and parameters to apply to each - such mount (see -@@ -101,7 +101,7 @@ Display usage message. - Set the limit of the number of open file descriptors to num. The - default is to leave the limit unchanged. - .TP --.B \-N " or " \-\-no-nfs-version -+.B \-N mountd-version " or " \-\-no-nfs-version mountd-version - This option can be used to request that - .B rpc.mountd - do not offer certain versions of NFS. The current version of -@@ -118,7 +118,7 @@ Don't advertise TCP for mount. - .B \-P - Ignored (compatibility with unfsd??). - .TP --.B \-p " or " \-\-port num -+.B \-p num " or " \-\-port num - Specifies the port number used for RPC listener sockets. - If this option is not specified, - .B rpc.mountd -@@ -132,7 +132,7 @@ This option can be used to fix the port value of - listeners when NFS MOUNT requests must traverse a firewall - between clients and servers. - .TP --.B \-H " or " \-\-ha-callout prog -+.B \-H " prog or " \-\-ha-callout prog - Specify a high availability callout program. - This program receives callouts for all MOUNT and UNMOUNT requests. - This allows -@@ -174,7 +174,7 @@ to perform a reverse lookup on each IP address and return that hostname instead. - Enabling this can have a substantial negative effect on performance - in some situations. - .TP --.BR "\-t N" " or " "\-\-num\-threads=N" -+.BR "\-t N" " or " "\-\-num\-threads=N" or " \-\-num\-threads N" - This option specifies the number of worker threads that rpc.mountd - spawns. The default is 1 thread, which is probably enough. More - threads are usually only needed for NFS servers which need to handle -@@ -184,7 +184,7 @@ your DNS server is slow or unreliable. - .B \-u " or " \-\-no-udp - Don't advertise UDP for mounting - .TP --.B \-V " or " \-\-nfs-version -+.B \-V version " or " \-\-nfs-version version - This option can be used to request that - .B rpc.mountd - offer certain versions of NFS. The current version of -diff --git a/utils/mountd/svc_run.c b/utils/mountd/svc_run.c -index 1938a67..a572441 100644 ---- a/utils/mountd/svc_run.c -+++ b/utils/mountd/svc_run.c -@@ -60,7 +60,7 @@ - void cache_set_fds(fd_set *fdset); - int cache_process_req(fd_set *readfds); - --#if LONG_MAX != INT_MAX -+#if defined(__GLIBC__) && LONG_MAX != INT_MAX - /* bug in glibc 2.3.6 and earlier, we need - * our own svc_getreqset - */ -diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c -index 73d6a92..201bb13 100644 ---- a/utils/nfsd/nfsd.c -+++ b/utils/nfsd/nfsd.c -@@ -19,6 +19,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -101,7 +102,7 @@ main(int argc, char **argv) - int count = NFSD_NPROC, c, i, error = 0, portnum = 0, fd, found_one; - char *p, *progname, *port, *rdma_port = NULL; - char **haddr = NULL; -- unsigned int hcounter = 0; -+ int hcounter = 0; - int socket_up = 0; - unsigned int minorvers = 0; - unsigned int minorversset = 0; -diff --git a/utils/nfsdcltrack/Makefile.am b/utils/nfsdcltrack/Makefile.am -index a860ffb..7524295 100644 ---- a/utils/nfsdcltrack/Makefile.am -+++ b/utils/nfsdcltrack/Makefile.am -@@ -1,5 +1,9 @@ - ## Process this file with automake to produce Makefile.in - -+# These binaries go in /sbin (not /usr/sbin), and that cannot be -+# overridden at config time. The kernel "knows" the /sbin name. -+sbindir = /sbin -+ - man8_MANS = nfsdcltrack.man - EXTRA_DIST = $(man8_MANS) - -diff --git a/utils/nfsidmap/nfsidmap.c b/utils/nfsidmap/nfsidmap.c -index 3f51b4d..e0d31e7 100644 ---- a/utils/nfsidmap/nfsidmap.c -+++ b/utils/nfsidmap/nfsidmap.c -@@ -4,6 +4,7 @@ - #include - #include - #include -+#include - - #include - #include -diff --git a/utils/nfsstat/nfsstat.c b/utils/nfsstat/nfsstat.c -index 70f8d10..298adcf 100644 ---- a/utils/nfsstat/nfsstat.c -+++ b/utils/nfsstat/nfsstat.c -@@ -336,7 +336,7 @@ main(int argc, char **argv) - - struct sigaction act = { - .sa_handler = unpause, -- .sa_flags = SA_ONESHOT, -+ .sa_flags = SA_RESETHAND, - }; - - if ((progname = strrchr(argv[0], '/'))) -@@ -569,7 +569,7 @@ print_server_stats(int opt_prt) - - print_numbers( - LABEL_srvfh -- "lookup anon ncachedir ncachedir stale\n", -+ "lookup anon ncachedir ncachenondir stale\n", - srvfhinfo + 1, 5); - } else /* < 2.4 */ - print_numbers( -diff --git a/utils/statd/callback.c b/utils/statd/callback.c -index d1cc139..bb7c590 100644 ---- a/utils/statd/callback.c -+++ b/utils/statd/callback.c -@@ -10,11 +10,13 @@ - #include - #endif - -+#include - #include - - #include "rpcmisc.h" - #include "statd.h" - #include "notlist.h" -+#include "ha-callout.h" - - /* Callback notify list. */ - /* notify_list *cbnl = NULL; ... never used */ -@@ -87,6 +89,13 @@ sm_notify_1_svc(struct stat_chge *argp, struct svc_req *rqstp) - xlog(D_CALL, "Received SM_NOTIFY from %s, state: %d", - argp->mon_name, argp->state); - -+ if (!statd_present_address(sap, ip_addr, sizeof(ip_addr))) { -+ xlog_warn("Unrecognized sender address"); -+ return ((void *) &result); -+ } -+ -+ ha_callout("sm-notify", argp->mon_name, ip_addr, argp->state); -+ - /* quick check - don't bother if we're not monitoring anyone */ - if (rtnl == NULL) { - xlog_warn("SM_NOTIFY from %s while not monitoring any hosts", -@@ -94,11 +103,6 @@ sm_notify_1_svc(struct stat_chge *argp, struct svc_req *rqstp) - return ((void *) &result); - } - -- if (!statd_present_address(sap, ip_addr, sizeof(ip_addr))) { -- xlog_warn("Unrecognized sender address"); -- return ((void *) &result); -- } -- - /* okir change: statd doesn't remove the remote host from its - * internal monitor list when receiving an SM_NOTIFY call from - * it. Lockd will want to continue monitoring the remote host -diff --git a/utils/statd/hostname.c b/utils/statd/hostname.c -index 746ecc7..c61087c 100644 ---- a/utils/statd/hostname.c -+++ b/utils/statd/hostname.c -@@ -105,7 +105,7 @@ statd_present_address(const struct sockaddr *sap, char *buf, const size_t buflen - * Look up the hostname; report exceptional errors. Caller must - * call freeaddrinfo(3) if a valid addrinfo is returned. - */ --__attribute_malloc__ -+__attribute__((__malloc__)) - static struct addrinfo * - get_addrinfo(const char *hostname, const struct addrinfo *hint) - { -@@ -184,7 +184,7 @@ get_nameinfo(const struct sockaddr *sap, - * We won't monitor peers that don't have a reverse map. The canonical - * name gives us a key for our monitor list. - */ --__attribute_malloc__ -+__attribute__((__malloc__)) - char * - statd_canonical_name(const char *hostname) - { -@@ -234,7 +234,7 @@ statd_canonical_name(const char *hostname) - * NULL if some error occurs. Caller must free the returned - * list with freeaddrinfo(3). - */ --__attribute_malloc__ -+__attribute__((__malloc__)) - static struct addrinfo * - statd_canonical_list(const char *hostname) - { -diff --git a/utils/statd/sm-notify.c b/utils/statd/sm-notify.c -index 9dbe5d9..5994b2f 100644 ---- a/utils/statd/sm-notify.c -+++ b/utils/statd/sm-notify.c -@@ -74,7 +74,7 @@ static int record_pid(void); - - static struct nsm_host * hosts = NULL; - --__attribute_malloc__ -+__attribute__((__malloc__)) - static struct addrinfo * - smn_lookup(const char *name) - { -@@ -149,7 +149,7 @@ smn_get_hostname(const struct sockaddr *sap, - * if the canonical name doesn't exist or cannot be determined. - * The caller must free the result with free(3). - */ --__attribute_malloc__ -+__attribute__((__malloc__)) - static char * - smn_verify_my_name(const char *name) - { -@@ -189,7 +189,7 @@ smn_verify_my_name(const char *name) - return retval; - } - --__attribute_malloc__ -+__attribute__((__malloc__)) - static struct nsm_host * - smn_alloc_host(const char *hostname, const char *mon_name, - const char *my_name, const time_t timestamp) -@@ -343,7 +343,7 @@ static int smn_socket(void) - * If admin specified a source address or srcport, then convert those - * to a sockaddr and return it. Otherwise, return an ANYADDR address. - */ --__attribute_malloc__ -+__attribute__((__malloc__)) - static struct addrinfo * - smn_bind_address(const char *srcaddr, const char *srcport) - { -diff --git a/utils/statd/start-statd b/utils/statd/start-statd -old mode 100644 -new mode 100755 -index cde3583..ec9383b ---- a/utils/statd/start-statd -+++ b/utils/statd/start-statd -@@ -1,12 +1,16 @@ --#!/bin/bash -p -+#!/bin/sh - # nfsmount calls this script when mounting a filesystem with locking - # enabled, but when statd does not seem to be running (based on - # /var/run/rpc.statd.pid). - # It should run statd with whatever flags are apropriate for this - # site. --PATH=/sbin:/usr/sbin --if systemctl start statd.service --then : --else -- exec rpc.statd --no-notify -+PATH="/sbin:/usr/sbin:/bin:/usr/bin" -+ -+# First try systemd if it's installed. -+if systemctl --help >/dev/null 2>&1; then -+ # Quit only if the call worked. -+ systemctl start rpc-statd.service && exit - fi -+ -+# Fall back to launching it ourselves. -+exec rpc.statd --no-notify -diff --git a/utils/statd/statd.h b/utils/statd/statd.h -index e89e666..a1d8035 100644 ---- a/utils/statd/statd.h -+++ b/utils/statd/statd.h -@@ -25,7 +25,7 @@ - extern _Bool statd_matchhostname(const char *hostname1, const char *hostname2); - extern _Bool statd_present_address(const struct sockaddr *sap, char *buf, - const size_t buflen); --__attribute_malloc__ -+__attribute__((__malloc__)) - extern char * statd_canonical_name(const char *hostname); - - extern void my_svc_run(void); -diff --git a/utils/statd/statd.man b/utils/statd/statd.man -index 896c2f8..1e5520c 100644 ---- a/utils/statd/statd.man -+++ b/utils/statd/statd.man -@@ -346,7 +346,8 @@ points due to inactivity. - .SS High-availability callouts - .B rpc.statd - can exec a special callout program during processing of --successful SM_MON, SM_UNMON, and SM_UNMON_ALL requests. -+successful SM_MON, SM_UNMON, and SM_UNMON_ALL requests, -+or when it receives SM_NOTIFY. - Such a program may be used in High Availability NFS (HA-NFS) - environments to track lock state that may need to be migrated after - a system reboot. -@@ -357,15 +358,26 @@ option. - The program is run with 3 arguments: - The first is either - .B add-client --or - .B del-client -+or -+.B sm-notify - depending on the reason for the callout. - The second is the - .I mon_name - of the monitored peer. - The third is the --.I caller_name --of the requesting lock manager. -+.I caller_name -+of the requesting lock manager for -+.B add-client -+or -+.B del-client -+, otherwise it is -+.I IP_address -+of the caller sending SM_NOTIFY. -+The forth is the -+.I state_value -+in the SM_NOTIFY request. -+ - .SS IPv6 and TI-RPC support - TI-RPC is a pre-requisite for supporting NFS on IPv6. - If TI-RPC support is built into diff --git a/nfs-utils.spec b/nfs-utils.spec index 4e21086..cde7752 100644 --- a/nfs-utils.spec +++ b/nfs-utils.spec @@ -1,8 +1,8 @@ Summary: NFS utilities and supporting clients and daemons for the kernel NFS server Name: nfs-utils URL: http://sourceforge.net/projects/nfs -Version: 1.3.0 -Release: 7.0%{?dist} +Version: 1.3.1 +Release: 0.0%{?dist} Epoch: 1 # group all 32bit related archs @@ -15,8 +15,6 @@ Source2: nfs.sysconfig Source3: nfs-utils_env.sh Source4: lockd.conf -Patch001: nfs-utils-1.3.1-rc4.patch - Patch100: nfs-utils-1.2.1-statdpath-man.patch Patch101: nfs-utils-1.2.1-exp-subtree-warn-off.patch Patch102: nfs-utils-1.2.3-sm-notify-res_init.patch @@ -56,7 +54,7 @@ Requires: libtirpc >= 0.2.3-1 libblkid libcap libmount Requires(post): systemd-units Requires(preun): systemd-units Requires(postun): systemd-units -Conflicts: gssproxy < 0.3.0-0 +Requires: gssproxy => 0.3.0-0 %description The nfs-utils package provides a daemon for the kernel NFS server and @@ -73,8 +71,6 @@ This package also contains the mount.nfs and umount.nfs program. %prep %setup -q -%patch001 -p1 - %patch100 -p1 %patch101 -p1 %patch102 -p1 @@ -233,6 +229,9 @@ fi %triggerin -- nfs-utils < 1:1.3.0-0.2 /bin/systemctl restart nfs-config >/dev/null 2>&1 || : +%triggerin -- nfs-utils < 1:1.3.0-7.1 +/bin/systemctl stop rpc-svcgssd >/dev/null 2>&1 || : + %files %defattr(-,root,root,-) %config(noreplace) /etc/sysconfig/nfs @@ -280,6 +279,10 @@ fi /sbin/umount.nfs4 %changelog +* Thu Sep 25 2014 Steve Dickson 1.3.1-0.0 +- Update to the latest upstream release: nfs-utils-1-3-1 +- Enable gssproxy to manage the GSSAPI creds on the server. + * Fri Sep 12 2014 Steve Dickson 1.3.0-7.0 - Updated to latest upstream RC release: nfs-utils-1-3-1-rc4 (bz 1108615) diff --git a/nfs.sysconfig b/nfs.sysconfig index da4e3da..34a1e06 100644 --- a/nfs.sysconfig +++ b/nfs.sysconfig @@ -24,7 +24,7 @@ RPCIDMAPDARGS="" # Optional arguments passed to rpc.gssd. See rpc.gssd(8) RPCGSSDARGS="" # Enable usage of gssproxy. See gssproxy-mech(8). -GSS_USE_PROXY="no" +GSS_USE_PROXY="yes" # # Optional arguments passed to rpc.svcgssd. See rpc.svcgssd(8) RPCSVCGSSDARGS="" diff --git a/sources b/sources index b953852..1627ef5 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -6e93a7997ca3a1eac56bf219adab72a8 nfs-utils-1.3.0.tar.xz +8de676b9ff34b8f9addc1d0800fabdf8 nfs-utils-1.3.1.tar.xz