nfs-utils/nfs-utils-1.3.1-rc3.patch
Steve Dickson 5bcbe4c025 Updated to latest upstream RC release: nfs-utils-1-3-1-rc2
Signed-off-by: Steve Dickson <steved@redhat.com>
2014-07-25 12:33:53 -04:00

1087 lines
35 KiB
Diff

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 <mount point>
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 <bfields@UMICH.EDU>
+
+ 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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <rpc/rpc.h>
+
+#include <pwd.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <nfsidmap.h>
+#include <nfslib.h>
+#include <time.h>
+
+#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 <bfields@UMICH.EDU>
+
+ 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 <config.h>
#endif
+#include <unistd.h>
#include <netdb.h>
#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