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/nfs-iostat/nfs-iostat.py b/tools/nfs-iostat/nfs-iostat.py index 341cdbf..b324cd8 100644 --- a/tools/nfs-iostat/nfs-iostat.py +++ b/tools/nfs-iostat/nfs-iostat.py @@ -243,27 +243,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 +341,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 +385,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/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_proc.c b/utils/gssd/gssd_proc.c index 33cfeb2..40ff188 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: @@ -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 @@ -1031,6 +1039,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 +1182,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 +1207,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/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