summaryrefslogtreecommitdiff
path: root/core/nfs-utils/nfs-utils-1.3.1-rc2.patch
diff options
context:
space:
mode:
Diffstat (limited to 'core/nfs-utils/nfs-utils-1.3.1-rc2.patch')
-rw-r--r--core/nfs-utils/nfs-utils-1.3.1-rc2.patch674
1 files changed, 674 insertions, 0 deletions
diff --git a/core/nfs-utils/nfs-utils-1.3.1-rc2.patch b/core/nfs-utils/nfs-utils-1.3.1-rc2.patch
new file mode 100644
index 000000000..d883ff939
--- /dev/null
+++ b/core/nfs-utils/nfs-utils-1.3.1-rc2.patch
@@ -0,0 +1,674 @@
+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 <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_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 <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