Blob Blame Raw
diff --git a/support/include/conffile.h b/support/include/conffile.h
index ce7aa21..05ea5d2 100644
--- a/support/include/conffile.h
+++ b/support/include/conffile.h
@@ -54,7 +54,7 @@ extern int      conf_end(int, int);
 extern void     conf_free_list(struct conf_list *);
 extern struct sockaddr *conf_get_address(char *, char *);
 extern struct conf_list *conf_get_list(char *, char *);
-extern struct conf_list *conf_get_tag_list(char *);
+extern struct conf_list *conf_get_tag_list(char *, char *);
 extern int      conf_get_num(char *, char *, int);
 extern char    *conf_get_str(char *, char *);
 extern char    *conf_get_section(char *, char *, char *);
diff --git a/support/include/nfs/nfs.h b/support/include/nfs/nfs.h
index 174c2dd..38db5b5 100644
--- a/support/include/nfs/nfs.h
+++ b/support/include/nfs/nfs.h
@@ -15,6 +15,10 @@
 #define NFSD_MINVERS 2
 #define NFSD_MAXVERS 4
 
+#define NFS4_MINMINOR 1
+#define NFS4_MAXMINOR 2
+#define NFS4_VERDEFAULT  0x1  /* minor verion 1 */
+
 struct nfs_fh_len {
 	int		fh_size;
 	u_int8_t	fh_handle[NFS3_FHSIZE];
@@ -52,6 +56,7 @@ struct nfs_fh_old {
 #define NFSCTL_UDPISSET(_cltbits)     ((_cltbits) & NFSCTL_UDPBIT) 
 #define NFSCTL_TCPISSET(_cltbits)     ((_cltbits) & NFSCTL_TCPBIT) 
 
+#define NFSCTL_VERDEFAULT (0xc)       /* versions 3 and 4 */
 #define NFSCTL_VERSET(_cltbits, _v)   ((_cltbits) |= (1 << ((_v) - 1))) 
 #define NFSCTL_UDPSET(_cltbits)       ((_cltbits) |= NFSCTL_UDPBIT)
 #define NFSCTL_TCPSET(_cltbits)       ((_cltbits) |= NFSCTL_TCPBIT)
diff --git a/support/include/nfsrpc.h b/support/include/nfsrpc.h
index a0b80e1..1bfae7a 100644
--- a/support/include/nfsrpc.h
+++ b/support/include/nfsrpc.h
@@ -156,6 +156,11 @@ extern unsigned long	nfs_pmap_getport(const struct sockaddr_in *,
 				const struct timeval *);
 
 /*
+ * Use nfs_pmap_getport to see if statd is running locally
+ */
+extern int nfs_probe_statd(void);
+
+/*
  * Contact a remote RPC service to discover whether it is responding
  * to requests.
  */
diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c
index 5015e94..c3434d5 100644
--- a/support/nfs/conffile.c
+++ b/support/nfs/conffile.c
@@ -565,7 +565,7 @@ cleanup:
 }
 
 struct conf_list *
-conf_get_tag_list(char *section)
+conf_get_tag_list(char *section, char *arg)
 {
 	struct conf_list *list = 0;
 	struct conf_list_node *node;
@@ -579,6 +579,8 @@ conf_get_tag_list(char *section)
 	cb = LIST_FIRST(&conf_bindings[conf_hash (section)]);
 	for (; cb; cb = LIST_NEXT(cb, link)) {
 		if (strcasecmp (section, cb->section) == 0) {
+			if (arg != NULL && strcasecmp(arg, cb->arg) != 0)
+				continue;
 			list->cnt++;
 			node = calloc(1, sizeof *node);
 			if (!node)
diff --git a/support/nfs/exports.c b/support/nfs/exports.c
index dea040f..d3160d3 100644
--- a/support/nfs/exports.c
+++ b/support/nfs/exports.c
@@ -63,6 +63,7 @@ static int	parsesquash(char *list, int **idp, int *lenp, char **ep);
 static int	parsenum(char **cpp);
 static void	freesquash(void);
 static void	syntaxerr(char *msg);
+static struct flav_info *find_flavor(char *name);
 
 void
 setexportent(char *fname, char *type)
@@ -196,11 +197,38 @@ getexportent(int fromkernel, int fromexports)
 	return &ee;
 }
 
+static const struct secinfo_flag_displaymap {
+	unsigned int flag;
+	const char *set;
+	const char *unset;
+} secinfo_flag_displaymap[] = {
+	{ NFSEXP_READONLY, "ro", "rw" },
+	{ NFSEXP_INSECURE_PORT, "insecure", "secure" },
+	{ NFSEXP_ROOTSQUASH, "root_squash", "no_root_squash" },
+	{ NFSEXP_ALLSQUASH, "all_squash", "no_all_squash" },
+	{ 0, NULL, NULL }
+};
+
+static void secinfo_flags_show(FILE *fp, unsigned int flags, unsigned int mask)
+{
+	const struct secinfo_flag_displaymap *p;
+
+	for (p = &secinfo_flag_displaymap[0]; p->flag != 0; p++) {
+		if (!(mask & p->flag))
+			continue;
+		fprintf(fp, ",%s", (flags & p->flag) ? p->set : p->unset);
+	}
+}
+
 void secinfo_show(FILE *fp, struct exportent *ep)
 {
+	const struct export_features *ef;
 	struct sec_entry *p1, *p2;
-	int flags;
 
+	ef = get_export_features();
+
+	if (ep->e_secinfo[0].flav == NULL)
+		secinfo_addflavor(find_flavor("sys"), ep);
 	for (p1=ep->e_secinfo; p1->flav; p1=p2) {
 
 		fprintf(fp, ",sec=%s", p1->flav->flavour);
@@ -208,12 +236,7 @@ void secinfo_show(FILE *fp, struct exportent *ep)
 								p2++) {
 			fprintf(fp, ":%s", p2->flav->flavour);
 		}
-		flags = p1->flags;
-		fprintf(fp, ",%s", (flags & NFSEXP_READONLY) ? "ro" : "rw");
-		fprintf(fp, ",%sroot_squash", (flags & NFSEXP_ROOTSQUASH)?
-				"" : "no_");
-		fprintf(fp, ",%sall_squash", (flags & NFSEXP_ALLSQUASH)?
-				"" : "no_");
+		secinfo_flags_show(fp, p1->flags, ef->secinfo_flags);
 	}
 }
 
@@ -643,8 +666,6 @@ bad_option:
 			cp++;
 	}
 
-	if (ep->e_secinfo[0].flav == NULL)
-		secinfo_addflavor(find_flavor("sys"), ep);
 	fix_pseudoflavor_flags(ep);
 	ep->e_squids = squids;
 	ep->e_sqgids = sqgids;
diff --git a/support/nfs/getport.c b/support/nfs/getport.c
index 3331ad4..081594c 100644
--- a/support/nfs/getport.c
+++ b/support/nfs/getport.c
@@ -1102,3 +1102,25 @@ unsigned long nfs_pmap_getport(const struct sockaddr_in *sin,
 
 	return port;
 }
+
+static const char *nfs_ns_pgmtbl[] = {
+        "status",
+        NULL,
+};
+
+/*
+ * nfs_probe_statd - use nfs_pmap_getport to see if statd is running locally
+ *
+ * Returns non-zero if statd is running locally.
+ */
+int nfs_probe_statd(void)
+{
+        struct sockaddr_in addr = {
+                .sin_family             = AF_INET,
+                .sin_addr.s_addr        = htonl(INADDR_LOOPBACK),
+        };
+        rpcprog_t program = nfs_getrpcbyname(NSMPROG, nfs_ns_pgmtbl);
+
+        return nfs_getport_ping((struct sockaddr *)(char *)&addr, sizeof(addr),
+                                program, (rpcvers_t)1, IPPROTO_UDP);
+}
diff --git a/tools/mountstats/mountstats.py b/tools/mountstats/mountstats.py
index b95b71d..3f5fea5 100644
--- a/tools/mountstats/mountstats.py
+++ b/tools/mountstats/mountstats.py
@@ -53,7 +53,7 @@ class DeviceData:
             if words[6].find('nfs') != -1:
                 self.__nfs_data['statvers'] = words[7]
         elif words[0] == 'age:':
-            self.__nfs_data['age'] = long(words[1])
+            self.__nfs_data['age'] = int(words[1])
         elif words[0] == 'opts:':
             self.__nfs_data['mountoptions'] = ''.join(words[1:]).split(',')
         elif words[0] == 'caps:':
@@ -91,12 +91,12 @@ class DeviceData:
             self.__nfs_data['shortwrites'] = int(words[22])
             self.__nfs_data['delay'] = int(words[23])
         elif words[0] == 'bytes:':
-            self.__nfs_data['normalreadbytes'] = long(words[1])
-            self.__nfs_data['normalwritebytes'] = long(words[2])
-            self.__nfs_data['directreadbytes'] = long(words[3])
-            self.__nfs_data['directwritebytes'] = long(words[4])
-            self.__nfs_data['serverreadbytes'] = long(words[5])
-            self.__nfs_data['serverwritebytes'] = long(words[6])
+            self.__nfs_data['normalreadbytes'] = int(words[1])
+            self.__nfs_data['normalwritebytes'] = int(words[2])
+            self.__nfs_data['directreadbytes'] = int(words[3])
+            self.__nfs_data['directwritebytes'] = int(words[4])
+            self.__nfs_data['serverreadbytes'] = int(words[5])
+            self.__nfs_data['serverwritebytes'] = int(words[6])
 
     def __parse_rpc_line(self, words):
         if words[0] == 'RPC':
@@ -110,8 +110,8 @@ class DeviceData:
                 self.__rpc_data['rpcsends'] = int(words[4])
                 self.__rpc_data['rpcreceives'] = int(words[5])
                 self.__rpc_data['badxids'] = int(words[6])
-                self.__rpc_data['inflightsends'] = long(words[7])
-                self.__rpc_data['backlogutil'] = long(words[8])
+                self.__rpc_data['inflightsends'] = int(words[7])
+                self.__rpc_data['backlogutil'] = int(words[8])
             elif words[1] == 'tcp':
                 self.__rpc_data['port'] = words[2]
                 self.__rpc_data['bind_count'] = int(words[3])
@@ -121,7 +121,7 @@ class DeviceData:
                 self.__rpc_data['rpcsends'] = int(words[7])
                 self.__rpc_data['rpcreceives'] = int(words[8])
                 self.__rpc_data['badxids'] = int(words[9])
-                self.__rpc_data['inflightsends'] = long(words[10])
+                self.__rpc_data['inflightsends'] = int(words[10])
                 self.__rpc_data['backlogutil'] = int(words[11])
             elif words[1] == 'rdma':
                 self.__rpc_data['port'] = words[2]
@@ -148,7 +148,7 @@ class DeviceData:
         else:
             op = words[0][:-1]
             self.__rpc_data['ops'] += [op]
-            self.__rpc_data[op] = [long(word) for word in words[1:]]
+            self.__rpc_data[op] = [int(word) for word in words[1:]]
 
     def parse_stats(self, lines):
         """Turn a list of lines from a mount stat file into a 
@@ -179,81 +179,81 @@ class DeviceData:
     def display_nfs_options(self):
         """Pretty-print the NFS options
         """
-        print 'Stats for %s mounted on %s:' % \
-            (self.__nfs_data['export'], self.__nfs_data['mountpoint'])
-
-        print '  NFS mount options: %s' % ','.join(self.__nfs_data['mountoptions'])
-        print '  NFS server capabilities: %s' % ','.join(self.__nfs_data['servercapabilities'])
-        if self.__nfs_data.has_key('nfsv4flags'):
-            print '  NFSv4 capability flags: %s' % ','.join(self.__nfs_data['nfsv4flags'])
-        if self.__nfs_data.has_key('pseudoflavor'):
-            print '  NFS security flavor: %d  pseudoflavor: %d' % \
-                (self.__nfs_data['flavor'], self.__nfs_data['pseudoflavor'])
+        print('Stats for %s mounted on %s:' % \
+            (self.__nfs_data['export'], self.__nfs_data['mountpoint']))
+
+        print('  NFS mount options: %s' % ','.join(self.__nfs_data['mountoptions']))
+        print('  NFS server capabilities: %s' % ','.join(self.__nfs_data['servercapabilities']))
+        if 'nfsv4flags' in self.__nfs_data:
+            print('  NFSv4 capability flags: %s' % ','.join(self.__nfs_data['nfsv4flags']))
+        if 'pseudoflavor' in self.__nfs_data:
+            print('  NFS security flavor: %d  pseudoflavor: %d' % \
+                (self.__nfs_data['flavor'], self.__nfs_data['pseudoflavor']))
         else:
-            print '  NFS security flavor: %d' % self.__nfs_data['flavor']
+            print('  NFS security flavor: %d' % self.__nfs_data['flavor'])
 
     def display_nfs_events(self):
         """Pretty-print the NFS event counters
         """
-        print
-        print 'Cache events:'
-        print '  data cache invalidated %d times' % self.__nfs_data['datainvalidates']
-        print '  attribute cache invalidated %d times' % self.__nfs_data['attrinvalidates']
-        print '  inodes synced %d times' % self.__nfs_data['syncinodes']
-        print
-        print 'VFS calls:'
-        print '  VFS requested %d inode revalidations' % self.__nfs_data['inoderevalidates']
-        print '  VFS requested %d dentry revalidations' % self.__nfs_data['dentryrevalidates']
-        print
-        print '  VFS called nfs_readdir() %d times' % self.__nfs_data['vfsreaddir']
-        print '  VFS called nfs_lookup() %d times' % self.__nfs_data['vfslookup']
-        print '  VFS called nfs_permission() %d times' % self.__nfs_data['vfspermission']
-        print '  VFS called nfs_file_open() %d times' % self.__nfs_data['vfsopen']
-        print '  VFS called nfs_file_flush() %d times' % self.__nfs_data['vfsflush']
-        print '  VFS called nfs_lock() %d times' % self.__nfs_data['vfslock']
-        print '  VFS called nfs_fsync() %d times' % self.__nfs_data['vfsfsync']
-        print '  VFS called nfs_file_release() %d times' % self.__nfs_data['vfsrelease']
-        print
-        print 'VM calls:'
-        print '  VFS called nfs_readpage() %d times' % self.__nfs_data['vfsreadpage']
-        print '  VFS called nfs_readpages() %d times' % self.__nfs_data['vfsreadpages']
-        print '  VFS called nfs_writepage() %d times' % self.__nfs_data['vfswritepage']
-        print '  VFS called nfs_writepages() %d times' % self.__nfs_data['vfswritepages']
-        print
-        print 'Generic NFS counters:'
-        print '  File size changing operations:'
-        print '    truncating SETATTRs: %d  extending WRITEs: %d' % \
-            (self.__nfs_data['setattrtrunc'], self.__nfs_data['extendwrite'])
-        print '  %d silly renames' % self.__nfs_data['sillyrenames']
-        print '  short reads: %d  short writes: %d' % \
-            (self.__nfs_data['shortreads'], self.__nfs_data['shortwrites'])
-        print '  NFSERR_DELAYs from server: %d' % self.__nfs_data['delay']
+        print()
+        print('Cache events:')
+        print('  data cache invalidated %d times' % self.__nfs_data['datainvalidates'])
+        print('  attribute cache invalidated %d times' % self.__nfs_data['attrinvalidates'])
+        print('  inodes synced %d times' % self.__nfs_data['syncinodes'])
+        print()
+        print('VFS calls:')
+        print('  VFS requested %d inode revalidations' % self.__nfs_data['inoderevalidates'])
+        print('  VFS requested %d dentry revalidations' % self.__nfs_data['dentryrevalidates'])
+        print()
+        print('  VFS called nfs_readdir() %d times' % self.__nfs_data['vfsreaddir'])
+        print('  VFS called nfs_lookup() %d times' % self.__nfs_data['vfslookup'])
+        print('  VFS called nfs_permission() %d times' % self.__nfs_data['vfspermission'])
+        print('  VFS called nfs_file_open() %d times' % self.__nfs_data['vfsopen'])
+        print('  VFS called nfs_file_flush() %d times' % self.__nfs_data['vfsflush'])
+        print('  VFS called nfs_lock() %d times' % self.__nfs_data['vfslock'])
+        print('  VFS called nfs_fsync() %d times' % self.__nfs_data['vfsfsync'])
+        print('  VFS called nfs_file_release() %d times' % self.__nfs_data['vfsrelease'])
+        print()
+        print('VM calls:')
+        print('  VFS called nfs_readpage() %d times' % self.__nfs_data['vfsreadpage'])
+        print('  VFS called nfs_readpages() %d times' % self.__nfs_data['vfsreadpages'])
+        print('  VFS called nfs_writepage() %d times' % self.__nfs_data['vfswritepage'])
+        print('  VFS called nfs_writepages() %d times' % self.__nfs_data['vfswritepages'])
+        print()
+        print('Generic NFS counters:')
+        print('  File size changing operations:')
+        print('    truncating SETATTRs: %d  extending WRITEs: %d' % \
+            (self.__nfs_data['setattrtrunc'], self.__nfs_data['extendwrite']))
+        print('  %d silly renames' % self.__nfs_data['sillyrenames'])
+        print('  short reads: %d  short writes: %d' % \
+            (self.__nfs_data['shortreads'], self.__nfs_data['shortwrites']))
+        print('  NFSERR_DELAYs from server: %d' % self.__nfs_data['delay'])
 
     def display_nfs_bytes(self):
         """Pretty-print the NFS event counters
         """
-        print
-        print 'NFS byte counts:'
-        print '  applications read %d bytes via read(2)' % self.__nfs_data['normalreadbytes']
-        print '  applications wrote %d bytes via write(2)' % self.__nfs_data['normalwritebytes']
-        print '  applications read %d bytes via O_DIRECT read(2)' % self.__nfs_data['directreadbytes']
-        print '  applications wrote %d bytes via O_DIRECT write(2)' % self.__nfs_data['directwritebytes']
-        print '  client read %d bytes via NFS READ' % self.__nfs_data['serverreadbytes']
-        print '  client wrote %d bytes via NFS WRITE' % self.__nfs_data['serverwritebytes']
+        print()
+        print('NFS byte counts:')
+        print('  applications read %d bytes via read(2)' % self.__nfs_data['normalreadbytes'])
+        print('  applications wrote %d bytes via write(2)' % self.__nfs_data['normalwritebytes'])
+        print('  applications read %d bytes via O_DIRECT read(2)' % self.__nfs_data['directreadbytes'])
+        print('  applications wrote %d bytes via O_DIRECT write(2)' % self.__nfs_data['directwritebytes'])
+        print('  client read %d bytes via NFS READ' % self.__nfs_data['serverreadbytes'])
+        print('  client wrote %d bytes via NFS WRITE' % self.__nfs_data['serverwritebytes'])
 
     def display_rpc_generic_stats(self):
         """Pretty-print the generic RPC stats
         """
         sends = self.__rpc_data['rpcsends']
 
-        print
-        print 'RPC statistics:'
+        print()
+        print('RPC statistics:')
 
-        print '  %d RPC requests sent, %d RPC replies received (%d XIDs not found)' % \
-            (sends, self.__rpc_data['rpcreceives'], self.__rpc_data['badxids'])
+        print('  %d RPC requests sent, %d RPC replies received (%d XIDs not found)' % \
+            (sends, self.__rpc_data['rpcreceives'], self.__rpc_data['badxids']))
         if sends != 0:
-            print '  average backlog queue length: %d' % \
-                (float(self.__rpc_data['backlogutil']) / sends)
+            print('  average backlog queue length: %d' % \
+                (float(self.__rpc_data['backlogutil']) / sends))
 
     def display_rpc_op_stats(self):
         """Pretty-print the per-op stats
@@ -261,23 +261,23 @@ class DeviceData:
         sends = self.__rpc_data['rpcsends']
 
         # XXX: these should be sorted by 'count'
-        print
+        print()
         for op in self.__rpc_data['ops']:
             stats = self.__rpc_data[op]
             count = stats[0]
             retrans = stats[1] - count
             if count != 0:
-                print '%s:' % op
-                print '\t%d ops (%d%%)' % \
-                    (count, ((count * 100) / sends)),
-                print '\t%d retrans (%d%%)' % (retrans, ((retrans * 100) / count)),
-                print '\t%d major timeouts' % stats[2]
-                print '\tavg bytes sent per op: %d\tavg bytes received per op: %d' % \
-                    (stats[3] / count, stats[4] / count)
-                print '\tbacklog wait: %f' % (float(stats[5]) / count),
-                print '\tRTT: %f' % (float(stats[6]) / count),
-                print '\ttotal execute time: %f (milliseconds)' % \
-                    (float(stats[7]) / count)
+                print('%s:' % op)
+                print('\t%d ops (%d%%)' % \
+                    (count, ((count * 100) / sends)), end=' ')
+                print('\t%d retrans (%d%%)' % (retrans, ((retrans * 100) / count)), end=' ')
+                print('\t%d major timeouts' % stats[2])
+                print('\tavg bytes sent per op: %d\tavg bytes received per op: %d' % \
+                    (stats[3] / count, stats[4] / count))
+                print('\tbacklog wait: %f' % (float(stats[5]) / count), end=' ')
+                print('\tRTT: %f' % (float(stats[6]) / count), end=' ')
+                print('\ttotal execute time: %f (milliseconds)' % \
+                    (float(stats[7]) / count))
 
     def compare_iostats(self, old_stats):
         """Return the difference between two sets of stats
@@ -285,9 +285,9 @@ class DeviceData:
         result = DeviceData()
 
         # copy self into result
-        for key, value in self.__nfs_data.iteritems():
+        for key, value in self.__nfs_data.items():
             result.__nfs_data[key] = value
-        for key, value in self.__rpc_data.iteritems():
+        for key, value in self.__rpc_data.items():
             result.__rpc_data[key] = value
 
         # compute the difference of each item in the list
@@ -295,7 +295,7 @@ 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']
@@ -312,17 +312,17 @@ class DeviceData:
         if sample_time == 0:
             sample_time = float(self.__nfs_data['age'])
 
-        print
-        print '%s mounted on %s:' % \
-            (self.__nfs_data['export'], self.__nfs_data['mountpoint'])
+        print()
+        print('%s mounted on %s:' % \
+            (self.__nfs_data['export'], self.__nfs_data['mountpoint']))
 
-        print '\top/s\trpc bklog'
-        print '\t%.2f' % (sends / sample_time), 
+        print('\top/s\trpc bklog')
+        print('\t%.2f' % (sends / sample_time), end=' ')
         if sends != 0:
-            print '\t%.2f' % \
-                ((float(self.__rpc_data['backlogutil']) / sends) / sample_time)
+            print('\t%.2f' % \
+                ((float(self.__rpc_data['backlogutil']) / sends) / sample_time))
         else:
-            print '\t0.00'
+            print('\t0.00')
 
         # reads:  ops/s, kB/s, avg rtt, and avg exe
         # XXX: include avg xfer size and retransmits?
@@ -332,15 +332,15 @@ class DeviceData:
         rtt = float(read_rpc_stats[6])
         exe = float(read_rpc_stats[7])
 
-        print '\treads:\tops/s\t\tkB/s\t\tavg RTT (ms)\tavg exe (ms)'
-        print '\t\t%.2f' % (ops / sample_time),
-        print '\t\t%.2f' % (kilobytes / sample_time),
+        print('\treads:\tops/s\t\tkB/s\t\tavg RTT (ms)\tavg exe (ms)')
+        print('\t\t%.2f' % (ops / sample_time), end=' ')
+        print('\t\t%.2f' % (kilobytes / sample_time), end=' ')
         if ops != 0:
-            print '\t\t%.2f' % (rtt / ops),
-            print '\t\t%.2f' % (exe / ops)
+            print('\t\t%.2f' % (rtt / ops), end=' ')
+            print('\t\t%.2f' % (exe / ops))
         else:
-            print '\t\t0.00',
-            print '\t\t0.00'
+            print('\t\t0.00', end=' ')
+            print('\t\t0.00')
 
         # writes:  ops/s, kB/s, avg rtt, and avg exe
         # XXX: include avg xfer size and retransmits?
@@ -350,15 +350,15 @@ class DeviceData:
         rtt = float(write_rpc_stats[6])
         exe = float(write_rpc_stats[7])
 
-        print '\twrites:\tops/s\t\tkB/s\t\tavg RTT (ms)\tavg exe (ms)'
-        print '\t\t%.2f' % (ops / sample_time),
-        print '\t\t%.2f' % (kilobytes / sample_time),
+        print('\twrites:\tops/s\t\tkB/s\t\tavg RTT (ms)\tavg exe (ms)')
+        print('\t\t%.2f' % (ops / sample_time), end=' ')
+        print('\t\t%.2f' % (kilobytes / sample_time), end=' ')
         if ops != 0:
-            print '\t\t%.2f' % (rtt / ops),
-            print '\t\t%.2f' % (exe / ops)
+            print('\t\t%.2f' % (rtt / ops), end=' ')
+            print('\t\t%.2f' % (exe / ops))
         else:
-            print '\t\t0.00',
-            print '\t\t0.00'
+            print('\t\t0.00', end=' ')
+            print('\t\t0.00')
 
 def parse_stats_file(filename):
     """pop the contents of a mountstats file into a dictionary,
@@ -388,18 +388,18 @@ def parse_stats_file(filename):
     return ms_dict
 
 def print_mountstats_help(name):
-    print 'usage: %s [ options ] <mount point>' % name
-    print
-    print ' Version %s' % Mountstats_version
-    print
-    print ' Display NFS client per-mount statistics.'
-    print
-    print '  --version    display the version of this command'
-    print '  --nfs        display only the NFS statistics'
-    print '  --rpc        display only the RPC statistics'
-    print '  --start      sample and save statistics'
-    print '  --end        resample statistics and compare them with saved'
-    print
+    print('usage: %s [ options ] <mount point>' % name)
+    print()
+    print(' Version %s' % Mountstats_version)
+    print()
+    print(' Display NFS client per-mount statistics.')
+    print()
+    print('  --version    display the version of this command')
+    print('  --nfs        display only the NFS statistics')
+    print('  --rpc        display only the RPC statistics')
+    print('  --start      sample and save statistics')
+    print('  --end        resample statistics and compare them with saved')
+    print()
 
 def mountstats_command():
     """Mountstats command
@@ -414,7 +414,7 @@ def mountstats_command():
             return
 
         if arg in ['-v', '--version', 'version']:
-            print '%s version %s' % (sys.argv[0], Mountstats_version)
+            print('%s version %s' % (sys.argv[0], Mountstats_version))
             sys.exit(0)
 
         if arg in ['-n', '--nfs']:
@@ -426,10 +426,10 @@ def mountstats_command():
             continue
 
         if arg in ['-s', '--start']:
-            raise Exception, 'Sampling is not yet implemented'
+            raise Exception('Sampling is not yet implemented')
 
         if arg in ['-e', '--end']:
-            raise Exception, 'Sampling is not yet implemented'
+            raise Exception('Sampling is not yet implemented')
 
         if arg == sys.argv[0]:
             continue
@@ -448,14 +448,14 @@ def mountstats_command():
 
     for mp in mountpoints:
         if mp not in mountstats:
-            print 'Statistics for mount point %s not found' % mp
+            print('Statistics for mount point %s not found' % mp)
             continue
 
         stats = DeviceData()
         stats.parse_stats(mountstats[mp])
 
         if not stats.is_nfs_mountpoint():
-            print 'Mount point %s exists but is not an NFS mount' % mp
+            print('Mount point %s exists but is not an NFS mount' % mp)
             continue
 
         if nfs_only:
@@ -472,37 +472,37 @@ def mountstats_command():
            stats.display_rpc_op_stats()
 
 def print_nfsstat_help(name):
-    print 'usage: %s [ options ]' % name
-    print
-    print ' Version %s' % Mountstats_version
-    print
-    print ' nfsstat-like program that uses NFS client per-mount statistics.'
-    print
+    print('usage: %s [ options ]' % name)
+    print()
+    print(' Version %s' % Mountstats_version)
+    print()
+    print(' nfsstat-like program that uses NFS client per-mount statistics.')
+    print()
 
 def nfsstat_command():
     print_nfsstat_help(prog)
 
 def print_iostat_help(name):
-    print 'usage: %s [ <interval> [ <count> ] ] [ <mount point> ] ' % name
-    print
-    print ' Version %s' % Mountstats_version
-    print
-    print ' iostat-like program to display NFS client per-mount statistics.'
-    print
-    print ' The <interval> parameter specifies the amount of time in seconds between'
-    print ' each report.  The first report contains statistics for the time since each'
-    print ' file system was mounted.  Each subsequent report contains statistics'
-    print ' collected during the interval since the previous report.'
-    print
-    print ' If the <count> parameter is specified, the value of <count> determines the'
-    print ' number of reports generated at <interval> seconds apart.  If the interval'
-    print ' parameter is specified without the <count> parameter, the command generates'
-    print ' reports continuously.'
-    print
-    print ' If one or more <mount point> names are specified, statistics for only these'
-    print ' mount points will be displayed.  Otherwise, all NFS mount points on the'
-    print ' client are listed.'
-    print
+    print('usage: %s [ <interval> [ <count> ] ] [ <mount point> ] ' % name)
+    print()
+    print(' Version %s' % Mountstats_version)
+    print()
+    print(' iostat-like program to display NFS client per-mount statistics.')
+    print()
+    print(' The <interval> parameter specifies the amount of time in seconds between')
+    print(' each report.  The first report contains statistics for the time since each')
+    print(' file system was mounted.  Each subsequent report contains statistics')
+    print(' collected during the interval since the previous report.')
+    print()
+    print(' If the <count> parameter is specified, the value of <count> determines the')
+    print(' number of reports generated at <interval> seconds apart.  If the interval')
+    print(' parameter is specified without the <count> parameter, the command generates')
+    print(' reports continuously.')
+    print()
+    print(' If one or more <mount point> names are specified, statistics for only these')
+    print(' mount points will be displayed.  Otherwise, all NFS mount points on the')
+    print(' client are listed.')
+    print()
 
 def print_iostat_summary(old, new, devices, time):
     for device in devices:
@@ -530,7 +530,7 @@ def iostat_command():
             return
 
         if arg in ['-v', '--version', 'version']:
-            print '%s version %s' % (sys.argv[0], Mountstats_version)
+            print('%s version %s' % (sys.argv[0], Mountstats_version))
             return
 
         if arg == sys.argv[0]:
@@ -543,14 +543,14 @@ def iostat_command():
             if interval > 0:
                 interval_seen = True
             else:
-                print 'Illegal <interval> value'
+                print('Illegal <interval> value')
                 return
         elif not count_seen:
             count = int(arg)
             if count > 0:
                 count_seen = True
             else:
-                print 'Illegal <count> value'
+                print('Illegal <count> value')
                 return
 
     # make certain devices contains only NFS mount points
@@ -563,13 +563,13 @@ def iostat_command():
                 check += [device]
         devices = check
     else:
-        for device, descr in mountstats.iteritems():
+        for device, descr in mountstats.items():
             stats = DeviceData()
             stats.parse_stats(descr)
             if stats.is_nfs_mountpoint():
                 devices += [device]
     if len(devices) == 0:
-        print 'No NFS mount points were found'
+        print('No NFS mount points were found')
         return
 
     old_mountstats = None
@@ -608,7 +608,7 @@ try:
     elif prog == 'ms-iostat':
         iostat_command()
 except KeyboardInterrupt:
-    print 'Caught ^C... exiting'
+    print('Caught ^C... exiting')
     sys.exit(1)
 
 sys.exit(0)
diff --git a/tools/nfs-iostat/nfs-iostat.py b/tools/nfs-iostat/nfs-iostat.py
index dfbef87..341cdbf 100644
--- a/tools/nfs-iostat/nfs-iostat.py
+++ b/tools/nfs-iostat/nfs-iostat.py
@@ -95,7 +95,7 @@ class DeviceData:
             if words[6] == 'nfs':
                 self.__nfs_data['statvers'] = words[7]
         elif words[0] == 'age:':
-            self.__nfs_data['age'] = long(words[1])
+            self.__nfs_data['age'] = int(words[1])
         elif words[0] == 'opts:':
             self.__nfs_data['mountoptions'] = ''.join(words[1:]).split(',')
         elif words[0] == 'caps:':
@@ -116,7 +116,7 @@ class DeviceData:
         elif words[0] == 'bytes:':
             i = 1
             for key in NfsByteCounters:
-                self.__nfs_data[key] = long(words[i])
+                self.__nfs_data[key] = int(words[i])
                 i += 1
 
     def __parse_rpc_line(self, words):
@@ -131,8 +131,8 @@ class DeviceData:
                 self.__rpc_data['rpcsends'] = int(words[4])
                 self.__rpc_data['rpcreceives'] = int(words[5])
                 self.__rpc_data['badxids'] = int(words[6])
-                self.__rpc_data['inflightsends'] = long(words[7])
-                self.__rpc_data['backlogutil'] = long(words[8])
+                self.__rpc_data['inflightsends'] = int(words[7])
+                self.__rpc_data['backlogutil'] = int(words[8])
             elif words[1] == 'tcp':
                 self.__rpc_data['port'] = words[2]
                 self.__rpc_data['bind_count'] = int(words[3])
@@ -142,8 +142,8 @@ class DeviceData:
                 self.__rpc_data['rpcsends'] = int(words[7])
                 self.__rpc_data['rpcreceives'] = int(words[8])
                 self.__rpc_data['badxids'] = int(words[9])
-                self.__rpc_data['inflightsends'] = long(words[10])
-                self.__rpc_data['backlogutil'] = long(words[11])
+                self.__rpc_data['inflightsends'] = int(words[10])
+                self.__rpc_data['backlogutil'] = int(words[11])
             elif words[1] == 'rdma':
                 self.__rpc_data['port'] = words[2]
                 self.__rpc_data['bind_count'] = int(words[3])
@@ -169,7 +169,7 @@ class DeviceData:
         else:
             op = words[0][:-1]
             self.__rpc_data['ops'] += [op]
-            self.__rpc_data[op] = [long(word) for word in words[1:]]
+            self.__rpc_data[op] = [int(word) for word in words[1:]]
 
     def parse_stats(self, lines):
         """Turn a list of lines from a mount stat file into a 
@@ -271,7 +271,7 @@ class DeviceData:
         nfs_stats = self.__nfs_data
         lookup_ops = self.__rpc_data['LOOKUP'][0]
         readdir_ops = self.__rpc_data['READDIR'][0]
-        if self.__rpc_data.has_key('READDIRPLUS'):
+        if 'READDIRPLUS' in self.__rpc_data:
             readdir_ops += self.__rpc_data['READDIRPLUS'][0]
 
         dentry_revals = nfs_stats['dentryrevalidates']
@@ -330,7 +330,7 @@ class DeviceData:
     def __print_rpc_op_stats(self, op, sample_time):
         """Print generic stats for one RPC op
         """
-        if not self.__rpc_data.has_key(op):
+        if op not in self.__rpc_data:
             return
 
         rpc_stats = self.__rpc_data[op]
@@ -353,14 +353,14 @@ class DeviceData:
             exe_per_op = 0.0
 
         op += ':'
-        print('%s' % op.lower().ljust(15))
+        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))
-        print('\t%7.3f' % (kilobytes / sample_time))
-        print('\t%7.3f' % kb_per_op)
-        print(' %7d (%3.1f%%)' % (retrans, retrans_percent))
-        print('\t%7.3f' % rtt_per_op)
+        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)
 
     def ops(self, sample_time):
@@ -392,7 +392,7 @@ class DeviceData:
         print()
 
         print('   op/s\t\trpc bklog')
-        print('%7.2f' % (sends / sample_time))
+        print('%7.2f' % (sends / sample_time), end='')
         print('\t%7.2f' % backlog)
 
         if which == 0:
@@ -405,7 +405,7 @@ class DeviceData:
         elif which == 2:
             self.__print_rpc_op_stats('LOOKUP', sample_time)
             self.__print_rpc_op_stats('READDIR', sample_time)
-            if self.__rpc_data.has_key('READDIRPLUS'):
+            if 'READDIRPLUS' in self.__rpc_data:
                 self.__print_rpc_op_stats('READDIRPLUS', sample_time)
             self.__print_dir_cache_stats(sample_time)
         elif which == 3:
@@ -413,6 +413,8 @@ class DeviceData:
             self.__print_rpc_op_stats('WRITE', sample_time)
             self.__print_page_stats(sample_time)
 
+        sys.stdout.flush()
+
 #
 # Functions
 #
@@ -450,7 +452,7 @@ def print_iostat_summary(old, new, devices, time, options):
     if old:
         # Trim device list to only include intersection of old and new data,
         # this addresses umounts due to autofs mountpoints
-        devicelist = filter(lambda x:x in devices,old)
+        devicelist = [x for x in old if x in devices]
     else:
         devicelist = devices
 
diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c
index 9f79541..4331697 100644
--- a/utils/exportfs/exportfs.c
+++ b/utils/exportfs/exportfs.c
@@ -420,7 +420,7 @@ static int test_export(char *path, int with_fsid)
 	char buf[1024];
 	int fd, n;
 
-	sprintf(buf, "-test-client- %s 3 %d -1 -1 0\n",
+	sprintf(buf, "-test-client- %s 3 %d 65534 65534 0\n",
 		path,
 		with_fsid ? NFSEXP_FSID : 0);
 	fd = open("/proc/net/rpc/nfsd.export/channel", O_WRONLY);
diff --git a/utils/exportfs/exports.man b/utils/exportfs/exports.man
index bc1de73..58c0f66 100644
--- a/utils/exportfs/exports.man
+++ b/utils/exportfs/exports.man
@@ -39,7 +39,7 @@ the export name using a backslash followed by the character code as three
 octal digits.
 .PP
 To apply changes to this file, run
-.BR exportfs \-ra
+.BR "exportfs \-ra"
 or restart the NFS server.
 .PP
 .SS Machine Name Formats
diff --git a/utils/gssd/gssd.man b/utils/gssd/gssd.man
index 1df75c5..ac13fd4 100644
--- a/utils/gssd/gssd.man
+++ b/utils/gssd/gssd.man
@@ -195,11 +195,28 @@ option when starting
 .BR rpc.gssd .
 .SH OPTIONS
 .TP
-.B -D
-DNS Reverse lookups are not used for determining the
-server names pass to GSSAPI. This option will reverses that and forces 
-the use of DNS Reverse resolution of the server's IP address to 
-retrieve the server name to use in GSAPI authentication.
+.B \-D
+The server name passed to GSSAPI for authentication is normally the
+name exactly as requested.  e.g. for NFS
+it is the server name in the "servername:/path" mount request.  Only if this
+servername appears to be an IP address (IPv4 or IPv6) or an
+unqualified name (no dots) will a reverse DNS lookup
+will be performed to get the canoncial server name.
+
+If
+.B \-D
+is present, a reverse DNS lookup will
+.I always
+be used, even if the server name looks like a canonical name.  So it
+is needed if partially qualified, or non canonical names are regularly
+used.
+
+Using
+.B \-D
+can introduce a security vulnerability, so it is recommended that
+.B \-D
+not be used, and that canonical names always be used when requesting
+services.
 .TP
 .B -f
 Runs
diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
index af1844c..e58c341 100644
--- a/utils/gssd/gssd_proc.c
+++ b/utils/gssd/gssd_proc.c
@@ -67,7 +67,6 @@
 #include <errno.h>
 #include <gssapi/gssapi.h>
 #include <netdb.h>
-#include <ctype.h>
 
 #include "gssd.h"
 #include "err_util.h"
@@ -176,7 +175,6 @@ get_servername(const char *name, const struct sockaddr *sa, const char *addr)
 	char			*hostname;
 	char			hbuf[NI_MAXHOST];
 	unsigned char		buf[sizeof(struct in6_addr)];
-	int			servername = 0;
 
 	if (avoid_dns) {
 		/*
@@ -184,15 +182,18 @@ get_servername(const char *name, const struct sockaddr *sa, const char *addr)
 		 * If it is an IP address, do the DNS lookup otherwise
 		 * skip the DNS lookup.
 		 */
-		servername = 0;
-		if (strchr(name, '.') && inet_pton(AF_INET, name, buf) == 1)
-			servername = 1; /* IPv4 */
-		else if (strchr(name, ':') && inet_pton(AF_INET6, name, buf) == 1)
-			servername = 1; /* or IPv6 */
-
-		if (servername) {
+		int is_fqdn = 1;
+		if (strchr(name, '.') == NULL)
+			is_fqdn = 0; /* local name */
+		else if (inet_pton(AF_INET, name, buf) == 1)
+			is_fqdn = 0; /* IPv4 address */
+		else if (inet_pton(AF_INET6, name, buf) == 1)
+			is_fqdn = 0; /* IPv6 addrss */
+
+		if (is_fqdn) {
 			return strdup(name);
 		}
+		/* Sorry, cannot avoid dns after all */
 	}
 
 	switch (sa->sa_family) {
@@ -466,8 +467,9 @@ process_clnt_dir(char *dir, char *pdir)
 	}
 	sprintf(clp->dirname, "%s/%s", pdir, dir);
 	if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) {
-		printerr(0, "ERROR: can't open %s: %s\n",
-			 clp->dirname, strerror(errno));
+		if (errno != ENOENT)
+			printerr(0, "ERROR: can't open %s: %s\n",
+				 clp->dirname, strerror(errno));
 		goto fail_destroy_client;
 	}
 	fcntl(clp->dir_fd, F_SETSIG, DNOTIFY_SIGNAL);
@@ -523,7 +525,7 @@ update_old_clients(struct dirent **namelist, int size, char *pdir)
 		/* only compare entries in the global list that are from the
 		 * same pipefs parent directory as "pdir"
 		 */
-		if (strncmp(clp->dirname, pdir, strlen(pdir)) != 0) continue;
+		if (strcmp(clp->dirname, pdir) != 0) continue;
 
 		stillhere = 0;
 		for (i=0; i < size; i++) {
@@ -820,6 +822,7 @@ set_port:
  */
 static int
 create_auth_rpc_client(struct clnt_info *clp,
+		       char *tgtname,
 		       CLIENT **clnt_return,
 		       AUTH **auth_return,
 		       uid_t uid,
@@ -924,14 +927,16 @@ create_auth_rpc_client(struct clnt_info *clp,
 			 clnt_spcreateerror(rpc_errmsg));
 		goto out_fail;
 	}
+	if (!tgtname)
+		tgtname = clp->servicename;
 
-	printerr(2, "creating context with server %s\n", clp->servicename);
-	auth = authgss_create_default(rpc_clnt, clp->servicename, &sec);
+	printerr(2, "creating context with server %s\n", tgtname);
+	auth = authgss_create_default(rpc_clnt, tgtname, &sec);
 	if (!auth) {
 		/* Our caller should print appropriate message */
 		printerr(2, "WARNING: Failed to create krb5 context for "
 			    "user with uid %d for server %s\n",
-			 uid, clp->servername);
+			 uid, tgtname);
 		goto out_fail;
 	}
 
@@ -1013,7 +1018,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
 		/* Try first to acquire credentials directly via GSSAPI */
 		err = gssd_acquire_user_cred(uid, &gss_cred);
 		if (!err)
-			create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
+			create_resp = create_auth_rpc_client(clp, tgtname, &rpc_clnt, &auth, uid,
 							     AUTHTYPE_KRB5, gss_cred);
 		/* if create_auth_rplc_client fails try the traditional method of
 		 * trolling for credentials */
@@ -1022,7 +1027,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
 			if (err == -EKEYEXPIRED)
 				downcall_err = -EKEYEXPIRED;
 			else if (!err)
-				create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
+				create_resp = create_auth_rpc_client(clp, tgtname, &rpc_clnt, &auth, uid,
 							     AUTHTYPE_KRB5, GSS_C_NO_CREDENTIAL);
 		}
 	}
@@ -1033,8 +1038,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
 			int success = 0;
 			do {
 				gssd_refresh_krb5_machine_credential(clp->servername,
-								     NULL, service,
-								     tgtname);
+								     NULL, service);
 				/*
 				 * Get a list of credential cache names and try each
 				 * of them until one works or we've tried them all
@@ -1047,7 +1051,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
 				}
 				for (ccname = credlist; ccname && *ccname; ccname++) {
 					gssd_setup_krb5_machine_gss_ccache(*ccname);
-					if ((create_auth_rpc_client(clp, &rpc_clnt,
+					if ((create_auth_rpc_client(clp, tgtname, &rpc_clnt,
 								    &auth, uid,
 								    AUTHTYPE_KRB5,
 								    GSS_C_NO_CREDENTIAL)) == 0) {
diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c
index 6275dd8..c6e52fd 100644
--- a/utils/gssd/krb5_util.c
+++ b/utils/gssd/krb5_util.c
@@ -231,7 +231,7 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname,
 				continue;
 			}
 			if (uid == 0 && !root_uses_machine_creds && 
-				strstr(namelist[i]->d_name, "_machine_")) {
+				strstr(namelist[i]->d_name, "machine_")) {
 				printerr(3, "CC '%s' not available to root\n",
 					 statname);
 				free(namelist[i]);
@@ -825,8 +825,10 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname,
 	myhostad[i+1] = 0;
 
 	retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname));
-	if (retval)
-		goto out;
+	if (retval) {
+		/* Don't use myhostname */
+		myhostname[0] = 0;
+	}
 
 	code = krb5_get_default_realm(context, &default_realm);
 	if (code) {
@@ -852,11 +854,19 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname,
 	}
 
 	/*
-	 * Try the "appropriate" realm first, and if nothing found for that
-	 * realm, try the default realm (if it hasn't already been tried).
+	 * Make sure the preferred_realm, which may have been explicitly set
+	 * on the command line, is tried first. If nothing is found go on with
+	 * the host and local default realm (if that hasn't already been tried).
 	 */
 	i = 0;
 	realm = realmnames[i];
+
+	if (strcmp (realm, preferred_realm) != 0) {
+		realm = preferred_realm;
+		/* resetting the realmnames index */
+		i = -1;
+	}
+
 	while (1) {
 		if (realm == NULL) {
 			tried_all = 1;
@@ -883,6 +893,8 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname,
 								myhostad,
 								NULL);
 			} else {
+				if (!myhostname[0])
+					continue;
 				snprintf(spn, sizeof(spn), "%s/%s@%s",
 					 svcnames[j], myhostname, realm);
 				code = krb5_build_principal_ext(context, &princ,
@@ -1137,7 +1149,7 @@ gssd_get_krb5_machine_cred_list(char ***list)
 		if (ple->ccname) {
 			/* Make sure cred is up-to-date before returning it */
 			retval = gssd_refresh_krb5_machine_credential(NULL, ple,
-				NULL, NULL);
+				NULL);
 			if (retval)
 				continue;
 			if (i + 1 > listsize) {
@@ -1228,15 +1240,14 @@ gssd_destroy_krb5_machine_creds(void)
 int
 gssd_refresh_krb5_machine_credential(char *hostname,
 				     struct gssd_k5_kt_princ *ple, 
-					 char *service,
-					 char *tgtname)
+					 char *service)
 {
 	krb5_error_code code = 0;
 	krb5_context context;
 	krb5_keytab kt = NULL;;
 	int retval = 0;
 	char *k5err = NULL;
-	const char *svcnames[5] = { "$", "root", "nfs", "host", NULL };
+	const char *svcnames[] = { "$", "root", "nfs", "host", NULL };
 
 	/*
 	 * If a specific service name was specified, use it.
@@ -1268,10 +1279,7 @@ gssd_refresh_krb5_machine_credential(char *hostname,
 	if (ple == NULL) {
 		krb5_keytab_entry kte;
 
-		if (tgtname == NULL)
-			tgtname = hostname;
-
-		code = find_keytab_entry(context, kt, tgtname, &kte, svcnames);
+		code = find_keytab_entry(context, kt, hostname, &kte, svcnames);
 		if (code) {
 			printerr(0, "ERROR: %s: no usable keytab entry found "
 				 "in keytab %s for connection with host %s\n",
diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h
index eed1294..3f0723e 100644
--- a/utils/gssd/krb5_util.h
+++ b/utils/gssd/krb5_util.h
@@ -31,8 +31,7 @@ void gssd_setup_krb5_machine_gss_ccache(char *servername);
 void gssd_destroy_krb5_machine_creds(void);
 int  gssd_refresh_krb5_machine_credential(char *hostname,
 					  struct gssd_k5_kt_princ *ple, 
-					  char *service,
-					  char *tgtname);
+					  char *service);
 char *gssd_k5_err_msg(krb5_context context, krb5_error_code code);
 void gssd_k5_get_default_realm(char **def_realm);
 
diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c
index beba9c4..b6c6231 100644
--- a/utils/idmapd/idmapd.c
+++ b/utils/idmapd/idmapd.c
@@ -502,7 +502,7 @@ nfsdcb(int UNUSED(fd), short which, void *data)
 	struct idmap_client *ic = data;
 	struct idmap_msg im;
 	u_char buf[IDMAP_MAXMSGSZ + 1];
-	size_t len;
+	ssize_t len;
 	ssize_t bsiz;
 	char *bp, typebuf[IDMAP_MAXMSGSZ],
 		buf1[IDMAP_MAXMSGSZ], authbuf[IDMAP_MAXMSGSZ], *p;
@@ -511,10 +511,14 @@ nfsdcb(int UNUSED(fd), short which, void *data)
 	if (which != EV_READ)
 		goto out;
 
-	if ((len = read(ic->ic_fd, buf, sizeof(buf))) <= 0) {
+	len = read(ic->ic_fd, buf, sizeof(buf));
+	if (len == 0)
+		/* No upcall to read; not necessarily a problem: */
+		return;
+	if (len < 0) {
 		xlog_warn("nfsdcb: read(%s) failed: errno %d (%s)",
-			     ic->ic_path, len?errno:0, 
-			     len?strerror(errno):"End of File");
+			     ic->ic_path, errno,
+			     strerror(errno));
 		nfsdreopen_one(ic);
 		return;
 	}
diff --git a/utils/mount/configfile.c b/utils/mount/configfile.c
index 6f2ee75..68b9f93 100644
--- a/utils/mount/configfile.c
+++ b/utils/mount/configfile.c
@@ -73,6 +73,8 @@ struct mnt_alias {
 };
 int mnt_alias_sz = (sizeof(mnt_alias_tab)/sizeof(mnt_alias_tab[0]));
 
+static int strict;
+
 /*
  * See if the option is an alias, if so return the 
  * real mount option along with the argument type.
@@ -286,7 +288,7 @@ conf_parse_mntopts(char *section, char *arg, char *opts)
 	char *nvalue, *ptr;
 	int argtype;
 
-	list = conf_get_tag_list(section);
+	list = conf_get_tag_list(section, arg);
 	TAILQ_FOREACH(node, &list->fields, link) {
 		/*
 		 * Do not overwrite options if already exists 
@@ -310,7 +312,15 @@ conf_parse_mntopts(char *section, char *arg, char *opts)
 		if (strcasecmp(value, "false") == 0) {
 			if (argtype != MNT_NOARG)
 				snprintf(buf, BUFSIZ, "no%s", field);
+			else if (strcasecmp(field, "bg") == 0)
+				snprintf(buf, BUFSIZ, "fg");
+			else if (strcasecmp(field, "fg") == 0)
+				snprintf(buf, BUFSIZ, "bg");
+			else if (strcasecmp(field, "sloppy") == 0)
+				strict = 1;
 		} else if (strcasecmp(value, "true") == 0) {
+			if ((strcasecmp(field, "sloppy") == 0) && strict)
+				continue;
 			snprintf(buf, BUFSIZ, "%s", field);
 		} else {
 			nvalue = strdup(value);
@@ -345,6 +355,7 @@ char *conf_get_mntopts(char *spec, char *mount_point,
 	char *ptr, *server, *config_opts;
 	int optlen = 0;
 
+	strict = 0;
 	SLIST_INIT(&head);
 	list_size = 0;
 	/*
diff --git a/utils/mount/network.c b/utils/mount/network.c
index 4be48cd..e2cdcaf 100644
--- a/utils/mount/network.c
+++ b/utils/mount/network.c
@@ -65,11 +65,6 @@ extern int nfs_mount_data_version;
 extern char *progname;
 extern int verbose;
 
-static const char *nfs_ns_pgmtbl[] = {
-	"status",
-	NULL,
-};
-
 static const char *nfs_mnt_pgmtbl[] = {
 	"mount",
 	"mountd",
@@ -761,18 +756,6 @@ int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server)
 					&nfs_server->pmap);
 }
 
-static int nfs_probe_statd(void)
-{
-	struct sockaddr_in addr = {
-		.sin_family		= AF_INET,
-		.sin_addr.s_addr	= htonl(INADDR_LOOPBACK),
-	};
-	rpcprog_t program = nfs_getrpcbyname(NSMPROG, nfs_ns_pgmtbl);
-
-	return nfs_getport_ping(SAFE_SOCKADDR(&addr), sizeof(addr),
-				program, (rpcvers_t)1, IPPROTO_UDP);
-}
-
 /**
  * start_statd - attempt to start rpc.statd
  *
diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man
index a8ec46c..2a42b93 100644
--- a/utils/mount/nfs.man
+++ b/utils/mount/nfs.man
@@ -84,6 +84,20 @@ in
 .SS "Options supported by all versions"
 These options are valid to use with any NFS version.
 .TP 1.5i
+.BI nfsvers= n
+The NFS protocol version number used to contact the server's NFS service.
+If the server does not support the requested version, the mount request 
+fails.
+If this option is not specified, the client negotiates a suitable version 
+with
+the server, trying version 4 first, version 3 second, and version 2 last.
+.TP 1.5i
+.BI vers= n
+This option is an alternative to the
+.B nfsvers
+option.
+It is included for compatibility with other operating systems
+.TP 1.5i
 .BR soft " / " hard
 Determines the recovery behavior of the NFS client
 after an NFS request times out.
@@ -621,18 +635,6 @@ Using this option ensures that
 reports the proper maximum component length to applications
 in such cases.
 .TP 1.5i
-.BI nfsvers= n
-The NFS protocol version number used to contact the server's NFS service.
-If the server does not support the requested version, the mount request fails.
-If this option is not specified, the client negotiates a suitable version with
-the server, trying version 4 first, version 3 second, and version 2 last.
-.TP 1.5i
-.BI vers= n
-This option is an alternative to the
-.B nfsvers
-option.
-It is included for compatibility with other operating systems.
-.TP 1.5i
 .BR lock " / " nolock
 Selects whether to use the NLM sideband protocol to lock files on the server.
 If neither option is specified (or if
diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c
index 737927c..517aa62 100644
--- a/utils/mountd/cache.c
+++ b/utils/mountd/cache.c
@@ -347,20 +347,26 @@ static char *next_mnt(void **v, char *p)
 
 static int is_subdirectory(char *child, char *parent)
 {
+	/* Check is child is strictly a subdirectory of
+	 * parent or a more distant descendant.
+	 */
 	size_t l = strlen(parent);
 
-	if (strcmp(parent, "/") == 0)
+	if (strcmp(parent, "/") == 0 && child[1] != 0)
 		return 1;
 
-	return strcmp(child, parent) == 0
-		|| (strncmp(child, parent, l) == 0 && child[l] == '/');
+	return (strncmp(child, parent, l) == 0 && child[l] == '/');
 }
 
 static int path_matches(nfs_export *exp, char *path)
 {
-	if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT)
-		return is_subdirectory(path, exp->m_export.e_path);
-	return strcmp(path, exp->m_export.e_path) == 0;
+	/* Does the path match the export?  I.e. is it an
+	 * exact match, or does the export have CROSSMOUNT, and path
+	 * is a descendant?
+	 */
+	return strcmp(path, exp->m_export.e_path) == 0
+		|| ((exp->m_export.e_flags & NFSEXP_CROSSMOUNT)
+		    && is_subdirectory(path, exp->m_export.e_path));
 }
 
 static int
@@ -369,15 +375,13 @@ export_matches(nfs_export *exp, char *dom, char *path, struct addrinfo *ai)
 	return path_matches(exp, path) && client_matches(exp, dom, ai);
 }
 
-/* True iff e1 is a child of e2 and e2 has crossmnt set: */
+/* True iff e1 is a child of e2 (or descendant) and e2 has crossmnt set: */
 static bool subexport(struct exportent *e1, struct exportent *e2)
 {
 	char *p1 = e1->e_path, *p2 = e2->e_path;
-	size_t l2 = strlen(p2);
 
 	return e2->e_flags & NFSEXP_CROSSMOUNT
-		&& strncmp(p1, p2, l2) == 0
-		&& p1[l2] == '/';
+		&& is_subdirectory(p1, p2);
 }
 
 struct parsed_fsid {
diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c
index e87c0a9..6db92f0 100644
--- a/utils/nfsd/nfsd.c
+++ b/utils/nfsd/nfsd.c
@@ -99,8 +99,8 @@ main(int argc, char **argv)
 	char *p, *progname, *port;
 	char *haddr = NULL;
 	int	socket_up = 0;
-	int minorvers41 = 0;	/* nfsv4 minor version */
-	unsigned int versbits = NFSCTL_ALLBITS;
+	int minorvers = NFS4_VERDEFAULT;	/* nfsv4 minor version */
+	unsigned int versbits = NFSCTL_VERDEFAULT;
 	unsigned int protobits = NFSCTL_ALLBITS;
 	unsigned int proto4 = 0;
 	unsigned int proto6 = 0;
@@ -160,11 +160,11 @@ main(int argc, char **argv)
 			case 4:
 				if (*p == '.') {
 					int i = atoi(p+1);
-					if (i != 1) {
+					if (i > 2) {
 						fprintf(stderr, "%s: unsupported minor version\n", optarg);
 						exit(1);
 					}
-					minorvers41 = -1;
+					NFSCTL_VERUNSET(minorvers, i);
 					break;
 				}
 			case 3:
@@ -181,11 +181,11 @@ main(int argc, char **argv)
 			case 4:
 				if (*p == '.') {
 					int i = atoi(p+1);
-					if (i != 1) {
+					if (i > 2) {
 						fprintf(stderr, "%s: unsupported minor version\n", optarg);
 						exit(1);
 					}
-					minorvers41 = 1;
+					NFSCTL_VERSET(minorvers, i);
 					break;
 				}
 			case 3:
@@ -282,7 +282,7 @@ main(int argc, char **argv)
 	 * registered with rpcbind. Note that on older kernels w/o the right
 	 * interfaces, these are a no-op.
 	 */
-	nfssvc_setvers(versbits, minorvers41);
+	nfssvc_setvers(versbits, minorvers);
  
 	error = nfssvc_set_sockets(AF_INET, proto4, haddr, port);
 	if (!error)
diff --git a/utils/nfsd/nfssvc.c b/utils/nfsd/nfssvc.c
index 683008e..8b85846 100644
--- a/utils/nfsd/nfssvc.c
+++ b/utils/nfsd/nfssvc.c
@@ -269,7 +269,7 @@ nfssvc_set_sockets(const int family, const unsigned int protobits,
 }
 
 void
-nfssvc_setvers(unsigned int ctlbits, int minorvers41)
+nfssvc_setvers(unsigned int ctlbits, int minorvers)
 {
 	int fd, n, off;
 	char *ptr;
@@ -280,9 +280,12 @@ nfssvc_setvers(unsigned int ctlbits, int minorvers41)
 	if (fd < 0)
 		return;
 
-	if (minorvers41)
-		off += snprintf(ptr+off, sizeof(buf) - off, "%c4.1",
-				minorvers41 > 0 ? '+' : '-');
+	for (n = NFS4_MINMINOR; n <= NFS4_MAXMINOR; n++) {
+		if (NFSCTL_VERISSET(minorvers, n)) 
+			off += snprintf(ptr+off, sizeof(buf) - off, "+4.%d ", n);
+		else			
+			off += snprintf(ptr+off, sizeof(buf) - off, "-4.%d ", n);
+	}
 	for (n = NFSD_MINVERS; n <= NFSD_MAXVERS; n++) {
 		if (NFSCTL_VERISSET(ctlbits, n))
 		    off += snprintf(ptr+off, sizeof(buf) - off, "+%d ", n);
diff --git a/utils/nfsdcltrack/nfsdcltrack.man b/utils/nfsdcltrack/nfsdcltrack.man
index 47007df..6940788 100644
--- a/utils/nfsdcltrack/nfsdcltrack.man
+++ b/utils/nfsdcltrack/nfsdcltrack.man
@@ -1,53 +1,3 @@
-.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16)
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings.  \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote.  \*(C+ will
-.\" give a nicer C++.  Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available.  \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-.    ds -- \(*W-
-.    ds PI pi
-.    if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-.    if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\"  diablo 12 pitch
-.    ds L" ""
-.    ds R" ""
-.    ds C` ""
-.    ds C' ""
-'br\}
-.el\{\
-.    ds -- \|\(em\|
-.    ds PI \(*p
-.    ds L" ``
-.    ds R" ''
-'br\}
-.\"
-.\" Escape single quotes in literal strings from groff's Unicode transform.
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
-.\" entries marked with X<> in POD.  Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
 .ie \nF \{\
 .    de IX
 .    tm Index:\\$1\t\\n%\t"\\$2"
@@ -59,70 +9,6 @@
 .    de IX
 ..
 .\}
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear.  Run.  Save yourself.  No user-serviceable parts.
-.    \" fudge factors for nroff and troff
-.if n \{\
-.    ds #H 0
-.    ds #V .8m
-.    ds #F .3m
-.    ds #[ \f1
-.    ds #] \fP
-.\}
-.if t \{\
-.    ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-.    ds #V .6m
-.    ds #F 0
-.    ds #[ \&
-.    ds #] \&
-.\}
-.    \" simple accents for nroff and troff
-.if n \{\
-.    ds ' \&
-.    ds ` \&
-.    ds ^ \&
-.    ds , \&
-.    ds ~ ~
-.    ds /
-.\}
-.if t \{\
-.    ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-.    ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-.    ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-.    ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-.    ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-.    ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-.    \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-.    \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-.    \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-.    ds : e
-.    ds 8 ss
-.    ds o a
-.    ds d- d\h'-1'\(ga
-.    ds D- D\h'-1'\(hy
-.    ds th \o'bp'
-.    ds Th \o'LP'
-.    ds ae ae
-.    ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
 .IX Title "NFSDCLTRACK 8"
 .TH NFSDCLTRACK 8 "2012-10-24" "" ""
 .\" For nroff, turn off justification.  Always turn off hyphenation; it makes
diff --git a/utils/nfsidmap/Makefile.am b/utils/nfsidmap/Makefile.am
index c0675c4..737a219 100644
--- a/utils/nfsidmap/Makefile.am
+++ b/utils/nfsidmap/Makefile.am
@@ -1,9 +1,10 @@
 ## Process this file with automake to produce Makefile.in
 
 man8_MANS = nfsidmap.man
-
 sbin_PROGRAMS	= nfsidmap
+
 nfsidmap_SOURCES = nfsidmap.c
 nfsidmap_LDADD = $(LIBNFSIDMAP) -lkeyutils ../../support/nfs/libnfs.a
 
 MAINTAINERCLEANFILES = Makefile.in
+EXTRA_DIST = id_resolver.conf
diff --git a/utils/nfsidmap/id_resolver.conf b/utils/nfsidmap/id_resolver.conf
new file mode 100644
index 0000000..2c156c6
--- /dev/null
+++ b/utils/nfsidmap/id_resolver.conf
@@ -0,0 +1 @@
+create	id_resolver	*	*	/usr/sbin/nfsidmap -t 600 %k %d
diff --git a/utils/statd/statd.c b/utils/statd/statd.c
index 652546c..8c51bcc 100644
--- a/utils/statd/statd.c
+++ b/utils/statd/statd.c
@@ -28,6 +28,7 @@
 
 #include "statd.h"
 #include "nfslib.h"
+#include "nfsrpc.h"
 #include "nsm.h"
 
 /* Socket operations */
@@ -237,6 +238,12 @@ int main (int argc, char **argv)
 	/* Set hostname */
 	MY_NAME = NULL;
 
+	/* Refuse to start if another statd is running */
+	if (nfs_probe_statd()) {
+		fprintf(stderr, "Statd service already running!\n");
+		exit(1);
+	}
+
 	/* Process command line switches */
 	while ((arg = getopt_long(argc, argv, "h?vVFNH:dn:p:o:P:L", longopts, NULL)) != EOF) {
 		switch (arg) {