All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/3] Series short description
@ 2018-01-18 21:47 Chuck Lever
  2018-01-18 21:47 ` [PATCH v2 2/3] mountd: Solder in support for NFS basic junctions Chuck Lever
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Chuck Lever @ 2018-01-18 21:47 UTC (permalink / raw)
  To: linux-nfs

Still UNTESTED, but at least it builds.

A while back I announced the deprecation of fedfs-utils. There were
a handful of components in fedfs-utils that we decided to keep. One
of those keepers was the "nfsref" command. (The other was autofs
support for /nfs4, which I hope Ian Kent is making progress on ;-)

This series introduces "nfsref" to nfs-utils, minus the overhead of
the LDAP / FedFS machinery, and it builds support for NFS basic
junctions into mountd, replacing the need to install a plug-in DLL
from fedfs-utils.

I didn't apply a lot of brain cells to this port, so it's perhaps a
little larger than it needs to be. Still, it achieves a completely
LDAP-free implementation that resides 100% in nfs-utils. I'm
interested in comments about the approach before I do more testing
and refinement.

 ./configure --enable-junction --enable-caps

is needed before building.


Changes since RFC (v1):
Patch 2/3 in the original series added the libnfsjunct.so DLL to
nfs-utils. Series v2 instead replaces 2/3 with a patch that puts
support for junctions into mountd without the need for a DLL.

---

Chuck Lever (3):
      Add LDAP-free version of libjunction to nfs-utils
      mountd: Solder in support for NFS basic junctions
      Add LDAP-free 'nfsref' command


 aclocal/libxml2.m4                   |   15 
 configure.ac                         |   17 
 support/Makefile.am                  |    4 
 support/include/Makefile.am          |    2 
 support/include/fedfs_admin.h        |  342 +++++++
 support/include/junction.h           |  124 +++
 support/junction/Makefile.am         |   34 +
 support/junction/display.c           |  159 +++
 support/junction/export-cache.c      |  118 +++
 support/junction/junction-internal.h |  121 +++
 support/junction/junction.c          |  494 +++++++++++
 support/junction/locations.c         |  131 +++
 support/junction/nfs.c               | 1564 ++++++++++++++++++++++++++++++++++
 support/junction/path.c              |  345 ++++++++
 support/junction/xml.c               |  401 +++++++++
 utils/Makefile.am                    |    4 
 utils/mountd/Makefile.am             |    8 
 utils/mountd/cache.c                 |  189 ++--
 utils/nfsref/Makefile.am             |   39 +
 utils/nfsref/add.c                   |  271 ++++++
 utils/nfsref/lookup.c                |  211 +++++
 utils/nfsref/nfsref.c                |  188 ++++
 utils/nfsref/nfsref.h                |   47 +
 utils/nfsref/nfsref.man              |  180 ++++
 utils/nfsref/remove.c                |  145 +++
 25 files changed, 5049 insertions(+), 104 deletions(-)
 create mode 100644 aclocal/libxml2.m4
 create mode 100644 support/include/fedfs_admin.h
 create mode 100644 support/include/junction.h
 create mode 100644 support/junction/Makefile.am
 create mode 100644 support/junction/display.c
 create mode 100644 support/junction/export-cache.c
 create mode 100644 support/junction/junction-internal.h
 create mode 100644 support/junction/junction.c
 create mode 100644 support/junction/locations.c
 create mode 100644 support/junction/nfs.c
 create mode 100644 support/junction/path.c
 create mode 100644 support/junction/xml.c
 create mode 100644 utils/nfsref/Makefile.am
 create mode 100644 utils/nfsref/add.c
 create mode 100644 utils/nfsref/lookup.c
 create mode 100644 utils/nfsref/nfsref.c
 create mode 100644 utils/nfsref/nfsref.h
 create mode 100644 utils/nfsref/nfsref.man
 create mode 100644 utils/nfsref/remove.c

--
Chuck Lever

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 2/3] mountd: Solder in support for NFS basic junctions
  2018-01-18 21:47 [PATCH v2 0/3] Series short description Chuck Lever
@ 2018-01-18 21:47 ` Chuck Lever
  2018-01-18 21:47 ` [PATCH v2 3/3] Add LDAP-free 'nfsref' command Chuck Lever
  2018-01-26 19:26 ` [PATCH v2 0/3] Series short description Steve Dickson
  2 siblings, 0 replies; 6+ messages in thread
From: Chuck Lever @ 2018-01-18 21:47 UTC (permalink / raw)
  To: linux-nfs

This patch does two things:

1. Reverts ab74900ff59e ("mountd: Support junction management
plug-ins")

2. Re-implements support for NFS basic junctions directly in mountd

So no more support for FedFS junctions, and no more need to have a
dynamically load component installed from another package.

The downside is that mountd has to be linked with libxml2 to get
this support. Thus to make the use of libxml2 optional, built-in
support for junctions is enabled only when --enable-junction is
specified on the command line.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 configure.ac             |    5 -
 utils/mountd/Makefile.am |    8 ++
 utils/mountd/cache.c     |  189 ++++++++++++++++++++++------------------------
 3 files changed, 98 insertions(+), 104 deletions(-)

diff --git a/configure.ac b/configure.ac
index 8e7f036..d2e48a5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -308,8 +308,6 @@ AC_CHECK_FUNC([getservbyname], ,
 
 AC_CHECK_LIB([crypt], [crypt], [LIBCRYPT="-lcrypt"])
 
-AC_CHECK_LIB([dl], [dlclose], [LIBDL="-ldl"])
-
 if test "$enable_nfsv4" = yes; then
   dnl check for libevent libraries and headers
   AC_LIBEVENT
@@ -372,7 +370,6 @@ AC_SUBST(LIBSOCKET)
 AC_SUBST(LIBCRYPT)
 AC_SUBST(LIBBSD)
 AC_SUBST(LIBBLKID)
-AC_SUBST(LIBDL)
 
 if test "$enable_libmount" = yes; then
    AC_CHECK_LIB(mount, mnt_context_do_mount, [LIBMOUNT="-lmount"], AC_MSG_ERROR([libmount needed]))
@@ -466,7 +463,7 @@ AC_CHECK_HEADERS([arpa/inet.h fcntl.h libintl.h limits.h \
                  stdlib.h string.h sys/file.h sys/ioctl.h sys/mount.h \
                  sys/param.h sys/socket.h sys/time.h sys/vfs.h \
                  syslog.h unistd.h com_err.h et/com_err.h \
-                 ifaddrs.h nfs-plugin.h libio.h])
+                 ifaddrs.h libio.h])
 
 dnl *************************************************************
 dnl Checks for typedefs, structures, and compiler characteristics
diff --git a/utils/mountd/Makefile.am b/utils/mountd/Makefile.am
index 153a90a..73eeb3f 100644
--- a/utils/mountd/Makefile.am
+++ b/utils/mountd/Makefile.am
@@ -1,5 +1,10 @@
 ## Process this file with automake to produce Makefile.in
 
+OPTLIBS		=
+if CONFIG_JUNCTION
+OPTLIBS		+= ../../support/junction/libjunction.la $(LIBXML2)
+endif
+
 man8_MANS	= mountd.man
 EXTRA_DIST	= $(man8_MANS)
 
@@ -13,7 +18,8 @@ mountd_SOURCES = mountd.c mount_dispatch.c auth.c rmtab.c cache.c \
 mountd_LDADD = ../../support/export/libexport.a \
 	       ../../support/nfs/libnfs.la \
 	       ../../support/misc/libmisc.a \
-	       $(LIBBSD) $(LIBWRAP) $(LIBNSL) $(LIBBLKID) $(LIBDL) $(LIBTIRPC)
+	       $(OPTLIBS) \
+	       $(LIBBSD) $(LIBWRAP) $(LIBNSL) $(LIBBLKID) $(LIBTIRPC)
 mountd_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS) \
 		  -I$(top_builddir)/support/include \
 		  -I$(top_srcdir)/support/export
diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c
index e49300d..6f42512 100644
--- a/utils/mountd/cache.c
+++ b/utils/mountd/cache.c
@@ -976,10 +976,15 @@ lookup_export(char *dom, char *path, struct addrinfo *ai)
 	return found;
 }
 
-#ifdef HAVE_NFS_PLUGIN_H
-#include <dlfcn.h>
-#include <link.h>
-#include <nfs-plugin.h>
+#ifdef CONFIG_JUNCTION
+
+#include "junction.h"
+
+struct nfs_fsloc_set {
+	int			 ns_ttl;
+	struct nfs_fsloc	*ns_current;
+	struct nfs_fsloc	*ns_list;
+};
 
 /*
  * Find the export entry for the parent of "pathname".
@@ -1035,13 +1040,39 @@ out_default:
 	return mkexportent("*", "/", "insecure");
 }
 
+static int get_next_location(struct nfs_fsloc_set *locset,
+		char **hostname, char **export_path, int *ttl)
+{
+	char *hostname_tmp, *export_path_tmp;
+	struct nfs_fsloc *fsloc;
+
+	if (locset->ns_current == NULL)
+		return ENOENT;
+	fsloc = locset->ns_current;
+
+	hostname_tmp = strdup(fsloc->nfl_hostname);
+	if (hostname_tmp == NULL)
+		return ENOMEM;
+
+	if (nsdb_path_array_to_posix(fsloc->nfl_rootpath,
+					&export_path_tmp)) {
+		free(hostname_tmp);
+		return EINVAL;
+	}
+
+	*hostname = hostname_tmp;
+	*export_path = export_path_tmp;
+	*ttl = locset->ns_ttl;
+	locset->ns_current = locset->ns_current->nfl_next;
+	return 0;
+}
+
 /*
  * Walk through a set of FS locations and build an e_fslocdata string.
  * Returns true if all went to plan; otherwise, false.
  */
-static bool locations_to_fslocdata(struct jp_ops *ops,
-		nfs_fsloc_set_t locations, char *fslocdata,
-		size_t remaining, int *ttl)
+static bool locations_to_fslocdata(struct nfs_fsloc_set *locations,
+		char *fslocdata, size_t remaining, int *ttl)
 {
 	char *server, *last_path, *rootpath, *ptr;
 	_Bool seen = false;
@@ -1056,13 +1087,13 @@ static bool locations_to_fslocdata(struct jp_ops *ops,
 		enum jp_status status;
 		int len;
 
-		status = ops->jp_get_next_location(locations, &server,
+		status = get_next_location(locations, &server,
 							&rootpath, ttl);
-		if (status == JP_EMPTY)
+		if (status == ENOENT)
 			break;
-		if (status != JP_OK) {
+		if (status) {
 			xlog(D_GENERAL, "%s: failed to parse location: %s",
-				__func__, ops->jp_error(status));
+				__func__, strerror(status));
 			goto out_false;
 		}
 		xlog(D_GENERAL, "%s: Location: %s:%s",
@@ -1159,116 +1190,73 @@ out_nomem:
  * Walk through the set of FS locations and build an exportent.
  * Returns pointer to an exportent if "junction" refers to a junction.
  */
-static struct exportent *locations_to_export(struct jp_ops *ops,
-		nfs_fsloc_set_t locations, const char *junction,
-		struct exportent *parent)
+static struct exportent *locations_to_export(struct nfs_fsloc_set *locations,
+		const char *junction, struct exportent *parent)
 {
 	static char fslocdata[BUFSIZ];
 	int ttl;
 
 	fslocdata[0] = '\0';
-	if (!locations_to_fslocdata(ops, locations,
-					fslocdata, sizeof(fslocdata), &ttl))
+	if (!locations_to_fslocdata(locations, fslocdata, sizeof(fslocdata), &ttl))
 		return NULL;
 	return create_junction_exportent(parent, junction, fslocdata, ttl);
 }
 
-/*
- * Retrieve locations information in "junction" and dump it to the
- * kernel.  Returns pointer to an exportent if "junction" refers
- * to a junction.
- */
-static struct exportent *invoke_junction_ops(void *handle, char *dom,
-		const char *junction, struct addrinfo *ai)
+static int
+nfs_get_basic_junction(const char *junct_path, struct nfs_fsloc_set **locset)
 {
-	struct exportent *parent, *exp = NULL;
-	nfs_fsloc_set_t locations;
-	enum jp_status status;
-	struct jp_ops *ops;
-	char *error;
-
-	ops = (struct jp_ops *)dlsym(handle, "nfs_junction_ops");
-	error = dlerror();
-	if (error != NULL) {
-		xlog(D_GENERAL, "%s: dlsym(jp_junction_ops): %s",
-			__func__, error);
-		return NULL;
-	}
-#ifdef JP_API_VERSION
-	if (ops->jp_api_version != JP_API_VERSION) {
-		xlog(D_GENERAL, "%s: unrecognized junction API version: %u",
-			__func__, ops->jp_api_version);
-		return NULL;
-	}
-#endif
-	status = ops->jp_init(false);
-	if (status != JP_OK) {
-		xlog(D_GENERAL, "%s: failed to resolve %s: %s",
-			__func__, junction, ops->jp_error(status));
-		return NULL;
+	struct nfs_fsloc_set *new;
+	FedFsStatus retval;
+
+	new = calloc(1, sizeof(struct nfs_fsloc_set));
+	if (new == NULL)
+		return ENOMEM;
+
+	retval = nfs_get_locations(junct_path, &new->ns_list);
+	if (retval) {
+		nfs_free_locations(new->ns_list);
+		free(new);
+		return EINVAL;
 	}
 
-	status = ops->jp_get_locations(junction, &locations);
-	switch (status) {
-	case JP_OK:
-		break;
-	case JP_NOTJUNCTION:
+	locset->ns_current = locset->ns_list;
+	new->ns_ttl = 300;
+	*locset = new;
+	return 0;
+}
+
+static struct exportent *lookup_junction(char *dom, const char *pathname,
+		struct addrinfo *ai)
+{
+	struct exportent *parent, *exp = NULL;
+	struct nfs_fsloc_set *locations;
+	int status;
+
+	xmlInitParser();
+
+	if (nfs_is_junction(pathname)) {
 		xlog(D_GENERAL, "%s: %s is not a junction",
-			__func__, junction);
+			__func__, pathname);
 		goto out;
-	default:
+	}
+	status = nfs_get_basic_junction(pathname, &locations);
+	switch (status) {
 		xlog(L_WARNING, "Dangling junction %s: %s",
-			junction, ops->jp_error(status));
+			pathname, strerro(status));
 		goto out;
 	}
 
-	parent = lookup_parent_export(dom, junction, ai);
+	parent = lookup_parent_export(dom, pathname, ai);
 	if (parent == NULL)
 		goto out;
 
-	exp = locations_to_export(ops, locations, junction, parent);
+	exp = locations_to_export(locations, pathname, parent);
 
-	ops->jp_put_locations(locations);
+	nfs_free_locations(locset->ns_list);
+	free(locset);
 
 out:
-	ops->jp_done();
-	return exp;
-}
-
-/*
- * Load the junction plug-in, then try to resolve "pathname".
- * Returns pointer to an initialized exportent if "junction"
- * refers to a junction, or NULL if not.
- */
-static struct exportent *lookup_junction(char *dom, const char *pathname,
-		struct addrinfo *ai)
-{
-	struct exportent *exp;
-	struct link_map *map;
-	void *handle;
-
-#ifdef JP_NFSPLUGIN_SONAME
-	handle = dlopen(JP_NFSPLUGIN_SONAME, RTLD_NOW);
-#else
-	handle = dlopen("libnfsjunct.so.0", RTLD_NOW);
-#endif
-	if (handle == NULL) {
-		xlog(D_GENERAL, "%s: dlopen: %s", __func__, dlerror());
-		return NULL;
-	}
-
-	if (dlinfo(handle, RTLD_DI_LINKMAP, &map) == 0)
-		xlog(D_GENERAL, "%s: loaded plug-in %s",
-			__func__, map->l_name);
-
-	(void)dlerror();	/* Clear any error */
-
-	exp = invoke_junction_ops(handle, dom, pathname, ai);
-
-	/* We could leave it loaded to make junction resolution
-	 * faster next time.  However, if we want to replace the
-	 * library, that would require restarting mountd. */
-	(void)dlclose(handle);
+	xmlCleanupParser();
 	return exp;
 }
 
@@ -1284,13 +1272,16 @@ static void lookup_nonexport(int f, char *buf, int buflen, char *dom, char *path
 	exportent_release(eep);
 	free(eep);
 }
-#else	/* !HAVE_NFS_PLUGIN_H */
+
+#else	/* !CONFIG_JUNCTION */
+
 static void lookup_nonexport(int f, char *buf, int buflen, char *dom, char *path,
 		struct addrinfo *UNUSED(ai))
 {
 	dump_to_cache(f, buf, buflen, dom, path, NULL, 0);
 }
-#endif	/* !HAVE_NFS_PLUGIN_H */
+
+#endif	/* !CONFIG_JUNCTION */
 
 static void nfsd_export(int f)
 {


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v2 3/3] Add LDAP-free 'nfsref' command
  2018-01-18 21:47 [PATCH v2 0/3] Series short description Chuck Lever
  2018-01-18 21:47 ` [PATCH v2 2/3] mountd: Solder in support for NFS basic junctions Chuck Lever
@ 2018-01-18 21:47 ` Chuck Lever
  2018-01-26 19:26 ` [PATCH v2 0/3] Series short description Steve Dickson
  2 siblings, 0 replies; 6+ messages in thread
From: Chuck Lever @ 2018-01-18 21:47 UTC (permalink / raw)
  To: linux-nfs

The 'nfsref' command administers junctions. On an NFS server, it
can create new junctions, remove existing junctions, or display
the contents of junctions.

A man page with more details is included.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 configure.ac             |    1 
 utils/Makefile.am        |    4 +
 utils/nfsref/Makefile.am |   39 +++++++
 utils/nfsref/add.c       |  271 ++++++++++++++++++++++++++++++++++++++++++++++
 utils/nfsref/lookup.c    |  211 ++++++++++++++++++++++++++++++++++++
 utils/nfsref/nfsref.c    |  188 ++++++++++++++++++++++++++++++++
 utils/nfsref/nfsref.h    |   47 ++++++++
 utils/nfsref/nfsref.man  |  180 +++++++++++++++++++++++++++++++
 utils/nfsref/remove.c    |  145 +++++++++++++++++++++++++
 9 files changed, 1086 insertions(+)
 create mode 100644 utils/nfsref/Makefile.am
 create mode 100644 utils/nfsref/add.c
 create mode 100644 utils/nfsref/lookup.c
 create mode 100644 utils/nfsref/nfsref.c
 create mode 100644 utils/nfsref/nfsref.h
 create mode 100644 utils/nfsref/nfsref.man
 create mode 100644 utils/nfsref/remove.c

diff --git a/configure.ac b/configure.ac
index d2e48a5..fba9064 100644
--- a/configure.ac
+++ b/configure.ac
@@ -601,6 +601,7 @@ AC_CONFIG_FILES([
 	utils/mount/Makefile
 	utils/mountd/Makefile
 	utils/nfsd/Makefile
+	utils/nfsref/Makefile
 	utils/nfsstat/Makefile
 	utils/nfsidmap/Makefile
 	utils/showmount/Makefile
diff --git a/utils/Makefile.am b/utils/Makefile.am
index c75a5a0..d361aea 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -23,6 +23,10 @@ if CONFIG_NFSDCLTRACK
 OPTDIRS += nfsdcltrack
 endif
 
+if CONFIG_JUNCTION
+OPTDIRS += nfsref
+endif
+
 SUBDIRS = \
 	exportfs \
 	mountd \
diff --git a/utils/nfsref/Makefile.am b/utils/nfsref/Makefile.am
new file mode 100644
index 0000000..2b2bb53
--- /dev/null
+++ b/utils/nfsref/Makefile.am
@@ -0,0 +1,39 @@
+##
+## @file utils/nfsref/Makefile.am
+## @brief Process this file with automake to produce utils/nfsref/Makefile.in
+##
+
+##
+## Copyright 2011, 2018 Oracle.  All rights reserved.
+##
+## This file is part of nfs-utils.
+##
+## nfs-utils is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License version 2.0 as
+## published by the Free Software Foundation.
+##
+## nfs-utils is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License version 2.0 for more details.
+##
+## You should have received a copy of the GNU General Public License
+## version 2.0 along with nfs-utils.  If not, see:
+##
+##	http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+##
+
+noinst_HEADERS		= nfsref.h
+
+sbin_PROGRAMS		= nfsref
+nfsref_SOURCES		= add.c lookup.c nfsref.c remove.c
+LDADD			= $(LIBXML2) $(LIBCAP) \
+			  ../../support/nfs/libnfs.la \
+			  ../../support/junction/libjunction.la
+
+man8_MANS		= nfsref.man
+
+MAINTAINERCLEANFILES	= Makefile.in
+
+AM_CPPFLAGS		= -I. -I../../support/include
+##AM_LDFLAGS		= -Wl,--as-needed
diff --git a/utils/nfsref/add.c b/utils/nfsref/add.c
new file mode 100644
index 0000000..d5d0cf8
--- /dev/null
+++ b/utils/nfsref/add.c
@@ -0,0 +1,271 @@
+/**
+ * @file utils/nfsref/add.c
+ * @brief Add junction metadata to a local file system object
+ */
+
+/*
+ * Copyright 2011, 2018 Oracle.  All rights reserved.
+ *
+ * This file is part of nfs-utils.
+ *
+ * nfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2.0 as
+ * published by the Free Software Foundation.
+ *
+ * nfs-utils is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License version 2.0 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2.0 along with nfs-utils.  If not, see:
+ *
+ *	http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <uuid/uuid.h>
+
+#include "junction.h"
+#include "xlog.h"
+#include "nfsref.h"
+
+/**
+ * Default cache expiration for FSN information
+ */
+#define FSN_DEFAULT_TTL		(300)
+
+/**
+ * Display help message for "add" subcommand
+ *
+ * @param progname NUL-terminated C string containing name of program
+ * @return program exit status
+ */
+int
+nfsref_add_help(const char *progname)
+{
+	fprintf(stderr, " \n");
+
+	fprintf(stderr, "Usage: %s [ -t type ] add <junction path> "
+			"<server> <export> [ <server> <export> ... ]\n\n",
+		progname);
+
+	fprintf(stderr, "Add a new junction containing the specified list "
+			"of fileset locations.\n");
+	fprintf(stderr, "<junction path> is the filename of the new junction.  "
+			"<server> is the hostname\n");
+	fprintf(stderr, "or IP address of an NFS server where the fileset is "
+			"located.  <export> is the\n");
+	fprintf(stderr, "export pathname of the fileset on that server.\n\n");
+
+	fprintf(stderr, "For NFS basic junctions, the location list is stored "
+			"locally in the junction.\n");
+	fprintf(stderr, "For FedFS junctions, the location list is stored "
+			"as new FSN and FSL records\n");
+	fprintf(stderr, "on an NSDB.\n");
+
+	return EXIT_SUCCESS;
+}
+
+/**
+ * Fill in default settings for NFSv4.0 fs_locations4
+ *
+ * @param new NFS location structure to fill in
+ *
+ * See section 5.1.3.2 of the NSDB protocol draft.
+ */
+static void
+nfsref_add_fsloc_defaults(struct nfs_fsloc *new)
+{
+	new->nfl_hostport = 0;
+	new->nfl_flags.nfl_varsub = false;
+	new->nfl_currency = -1;
+	new->nfl_validfor = 0;
+	new->nfl_genflags.nfl_writable = false;
+	new->nfl_genflags.nfl_going = false;
+	new->nfl_genflags.nfl_split = true;
+	new->nfl_transflags.nfl_rdma = true;
+	new->nfl_info.nfl_simul = 0;
+	new->nfl_info.nfl_handle = 0;
+	new->nfl_info.nfl_fileid = 0;
+	new->nfl_info.nfl_writever = 0;
+	new->nfl_info.nfl_change = 0;
+	new->nfl_info.nfl_readdir = 0;
+	new->nfl_info.nfl_readrank = 0;
+	new->nfl_info.nfl_readorder = 0;
+	new->nfl_info.nfl_writerank = 0;
+	new->nfl_info.nfl_writeorder = 0;
+}
+
+/**
+ * Convert a pair of command line arguments to one nfs_fsloc structure
+ *
+ * @param server NUL-terminated C string containing file server hostname
+ * @param rootpath NUL-terminated C string containing POSIX-style export path
+ * @param fsloc OUT: NFS location structure
+ * @return a FedFsStatus code
+ *
+ * If nfsref_add_build_fsloc() returns FEDFS_OK, caller must free the
+ * returned fsloc with nfs_free_location().
+ */
+static FedFsStatus
+nfsref_add_build_fsloc(const char *server, const char *rootpath,
+		struct nfs_fsloc **fsloc)
+{
+	struct nfs_fsloc *new;
+	FedFsStatus retval;
+
+	if (server == NULL || rootpath == NULL)
+		return FEDFS_ERR_INVAL;
+
+	xlog(D_GENERAL, "%s: Building fsloc for %s:%s",
+		__func__, server, rootpath);
+
+	new = nfs_new_location();
+	if (new == NULL) {
+		xlog(D_GENERAL, "%s: No memory", __func__);
+		return FEDFS_ERR_SVRFAULT;
+	}
+
+	new->nfl_hostname = strdup(server);
+	if (new->nfl_hostname == NULL) {
+		nfs_free_location(new);
+		xlog(D_GENERAL, "%s: No memory", __func__);
+		return FEDFS_ERR_SVRFAULT;
+	}
+
+	retval = nsdb_posix_to_path_array(rootpath, &new->nfl_rootpath);
+	if (retval != FEDFS_OK) {
+		nfs_free_location(new);
+		return retval;
+	}
+
+	nfsref_add_fsloc_defaults(new);
+	*fsloc = new;
+	return FEDFS_OK;
+}
+
+/**
+ * Convert array of command line arguments to list of nfs_fsloc structures
+ *
+ * @param argv array of pointers to NUL-terminated C strings contains arguments
+ * @param optind index of "argv" where "add" subcommand arguments start
+ * @param fslocs OUT: list of NFS locations
+ * @return a FedFsStatus code
+ *
+ * If nfsref_add_build_fsloc_list() returns FEDFS_OK, caller must free the
+ * returned list of fslocs with nfs_free_locations().
+ */
+static FedFsStatus
+nfsref_add_build_fsloc_list(char **argv, int optind, struct nfs_fsloc **fslocs)
+{
+	struct nfs_fsloc *fsloc, *result = NULL;
+	FedFsStatus retval;
+	int i;
+
+	for (i = optind + 2; argv[i] != NULL; i += 2) {
+		retval = nfsref_add_build_fsloc(argv[i], argv[i + 1], &fsloc);
+		if (retval != FEDFS_OK) {
+			nfs_free_locations(result);
+			return retval;
+		}
+		if (result == NULL)
+			result = fsloc;
+		else
+			result->nfl_next = fsloc;
+	}
+	if (result == NULL)
+		return FEDFS_ERR_INVAL;
+
+	*fslocs = result;
+	return FEDFS_OK;
+}
+
+/**
+ * Add NFS locations to a junction
+ *
+ * @param junct_path NUL-terminated C string containing pathname of junction
+ * @param argv array of pointers to NUL-terminated C strings contains arguments
+ * @param optind index of "argv" where "add" subcommand arguments start
+ * @return program exit status
+ */
+static int
+nfsref_add_nfs_basic(const char *junct_path, char **argv, int optind)
+{
+	struct nfs_fsloc *fslocs = NULL;
+	FedFsStatus retval;
+
+	xlog(D_GENERAL, "%s: Adding basic junction to %s",
+		__func__, junct_path);
+
+	retval = nfsref_add_build_fsloc_list(argv, optind, &fslocs);
+	switch (retval) {
+	case FEDFS_OK:
+		break;
+	case FEDFS_ERR_INVAL:
+		xlog(L_ERROR, "Missing arguments");
+		return EXIT_FAILURE;
+	case FEDFS_ERR_SVRFAULT:
+		xlog(L_ERROR, "No memory");
+		return EXIT_FAILURE;
+	default:
+		xlog(L_ERROR, "Failed to add NFS location metadata to %s: %s",
+			junct_path, nsdb_display_fedfsstatus(retval));
+		return EXIT_FAILURE;
+	}
+
+	retval = nfs_add_junction(junct_path, fslocs);
+	nfs_free_locations(fslocs);
+	switch (retval) {
+	case FEDFS_OK:
+		break;
+	case FEDFS_ERR_EXIST:
+		xlog(L_ERROR, "%s already contains junction metadata",
+			junct_path);
+		return EXIT_FAILURE;
+	default:
+		xlog(L_ERROR, "Failed to add NFS location metadata to %s: %s",
+			junct_path, nsdb_display_fedfsstatus(retval));
+		return EXIT_FAILURE;
+	}
+
+	printf("Created junction %s\n", junct_path);
+	return EXIT_SUCCESS;
+}
+
+/**
+ * Add locations to a junction
+ *
+ * @param type type of junction to add
+ * @param junct_path NUL-terminated C string containing pathname of junction
+ * @param argv array of pointers to NUL-terminated C strings contains arguments
+ * @param optind index of "argv" where "add" subcommand arguments start
+ * @return program exit status
+ */
+int
+nfsref_add(enum nfsref_type type, const char *junct_path, char **argv, int optind)
+{
+	if (mkdir(junct_path, 0755) == -1)
+		if (errno != EEXIST) {
+			xlog(L_ERROR, "Failed to create junction object: %m");
+			return EXIT_FAILURE;
+		}
+
+	switch (type) {
+	case NFSREF_TYPE_UNSPECIFIED:
+	case NFSREF_TYPE_NFS_BASIC:
+		return nfsref_add_nfs_basic(junct_path, argv, optind);
+	default:
+		xlog(L_ERROR, "Unrecognized junction type");
+	}
+	return EXIT_FAILURE;
+}
diff --git a/utils/nfsref/lookup.c b/utils/nfsref/lookup.c
new file mode 100644
index 0000000..16fca2e
--- /dev/null
+++ b/utils/nfsref/lookup.c
@@ -0,0 +1,211 @@
+/**
+ * @file utils/nfsref/lookup.c
+ * @brief Examine junction metadata from a local file system object
+ */
+
+/*
+ * Copyright 2011, 2018 Oracle.  All rights reserved.
+ *
+ * This file is part of nfs-utils.
+ *
+ * nfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2.0 as
+ * published by the Free Software Foundation.
+ *
+ * nfs-utils is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License version 2.0 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2.0 along with nfs-utils.  If not, see:
+ *
+ *	http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <rpcsvc/nfs_prot.h>
+
+#include "junction.h"
+#include "xlog.h"
+#include "nfsref.h"
+
+/**
+ * Display help message for "lookup" subcommand
+ *
+ * @param progname NUL-terminated C string containing name of program
+ * @return program exit status
+ */
+int
+nfsref_lookup_help(const char *progname)
+{
+	fprintf(stderr, " \n");
+
+	fprintf(stderr, "Usage: %s [ -t type ] lookup <junction path>\n\n",
+		progname);
+
+	fprintf(stderr, "Display the contents of the junction at "
+			"<junction path>.  For NFS basic\n");
+	fprintf(stderr, "junctions, the local contents of the junction "
+			"are displayed.  For FedFS\n");
+	fprintf(stderr, "junctions, FSL records are retrieved from the "
+			"NSDB and displayed.\n");
+
+	return EXIT_SUCCESS;
+}
+
+/**
+ * Convert a boolean value into a displayable string constant
+ *
+ * @param value boolean value
+ * @return NUL-terminated static constant C string
+ */
+static const char *
+nfsref_lookup_display_boolean(_Bool value)
+{
+	return value ? "true" : "false";
+}
+
+/**
+ * Display a single NFS location
+ *
+ * @param fsloc pointer to an NFS location structure
+ */
+static void
+nfsref_lookup_display_nfs_location(struct nfs_fsloc *fsloc)
+{
+	char *rootpath;
+
+	if (nsdb_path_array_to_posix(fsloc->nfl_rootpath, &rootpath) == FEDFS_OK) {
+		printf("%s:%s\n", fsloc->nfl_hostname, rootpath);
+		free(rootpath);
+	} else
+		printf("%s: - Invalid root path -\n", fsloc->nfl_hostname);
+	printf("\n");
+
+	printf("\tNFS port:\t%u\n", fsloc->nfl_hostport);
+	printf("\tValid for:\t%d\n", fsloc->nfl_validfor);
+	printf("\tCurrency:\t%d\n", fsloc->nfl_currency);
+	printf("\tFlags:\t\tvarsub(%s)\n",
+		nfsref_lookup_display_boolean(fsloc->nfl_flags.nfl_varsub));
+
+	printf("\tGenFlags:\twritable(%s), going(%s), split(%s)\n",
+		nfsref_lookup_display_boolean(fsloc->nfl_genflags.nfl_writable),
+		nfsref_lookup_display_boolean(fsloc->nfl_genflags.nfl_going),
+		nfsref_lookup_display_boolean(fsloc->nfl_genflags.nfl_split));
+	printf("\tTransFlags:\trdma(%s)\n",
+		nfsref_lookup_display_boolean(fsloc->nfl_transflags.nfl_rdma));
+
+	printf("\tClass:\t\tsimul(%u), handle(%u), fileid(%u)\n",
+		fsloc->nfl_info.nfl_simul,
+		fsloc->nfl_info.nfl_handle,
+		fsloc->nfl_info.nfl_fileid);
+	printf("\tClass:\t\twritever(%u), change(%u), readdir(%u)\n",
+		fsloc->nfl_info.nfl_writever,
+		fsloc->nfl_info.nfl_change,
+		fsloc->nfl_info.nfl_readdir);
+	printf("\tRead:\t\trank(%u), order(%u)\n",
+		fsloc->nfl_info.nfl_readrank, fsloc->nfl_info.nfl_readorder);
+	printf("\tWrite:\t\trank(%u), order(%u)\n",
+		fsloc->nfl_info.nfl_writerank, fsloc->nfl_info.nfl_writeorder);
+
+	printf("\n");
+}
+
+/**
+ * Display a list of NFS locations
+ *
+ * @param fslocs list of NFS locations to display
+ */
+static void
+nfsref_lookup_display_nfs_locations(struct nfs_fsloc *fslocs)
+{
+	struct nfs_fsloc *fsloc;
+
+	for (fsloc = fslocs; fsloc != NULL; fsloc = fsloc->nfl_next)
+		nfsref_lookup_display_nfs_location(fsloc);
+}
+
+/**
+ * List NFS locations in an nfs-basic junction
+ *
+ * @param junct_path NUL-terminated C string containing pathname of junction
+ * @return program exit status
+ */
+static int
+nfsref_lookup_nfs_basic(const char *junct_path)
+{
+	struct nfs_fsloc *fslocs = NULL;
+	FedFsStatus retval;
+
+	xlog(D_GENERAL, "%s: Looking up basic junction in %s",
+		__func__, junct_path);
+
+	retval = nfs_is_junction(junct_path);
+	switch (retval) {
+	case FEDFS_OK:
+		break;
+	case FEDFS_ERR_NOTJUNCT:
+		xlog(L_ERROR, "%s is not an nfs-basic junction", junct_path);
+		return EXIT_FAILURE;
+	default:
+		xlog(L_ERROR, "Failed to access %s: %s",
+			junct_path, nsdb_display_fedfsstatus(retval));
+		return EXIT_FAILURE;
+	}
+
+	retval = nfs_get_locations(junct_path, &fslocs);
+	if (retval != FEDFS_OK) {
+		xlog(L_ERROR, "Failed to access %s: %s",
+			junct_path, nsdb_display_fedfsstatus(retval));
+		return EXIT_FAILURE;
+	}
+
+	nfsref_lookup_display_nfs_locations(fslocs);
+
+	nfs_free_locations(fslocs);
+	return EXIT_SUCCESS;
+}
+
+/**
+ * Resolve either a FedFS or NFS basic junction
+ *
+ * @param junct_path NUL-terminated C string containing pathname of junction
+ * @return program exit status
+ */
+static int
+nfsref_lookup_unspecified(const char *junct_path)
+{
+	FedFsStatus retval;
+
+	retval = nfs_is_junction(junct_path);
+	if (retval == FEDFS_OK)
+		return nfsref_lookup_nfs_basic(junct_path);
+	xlog(L_ERROR, "%s is not a junction", junct_path);
+	return EXIT_FAILURE;
+}
+
+/**
+ * Enumerate metadata of a junction
+ *
+ * @param type type of junction to add
+ * @param junct_path NUL-terminated C string containing pathname of junction
+ * @return program exit status
+ */
+int
+nfsref_lookup(enum nfsref_type type, const char *junct_path)
+{
+	switch (type) {
+	case NFSREF_TYPE_UNSPECIFIED:
+		return nfsref_lookup_unspecified(junct_path);
+	case NFSREF_TYPE_NFS_BASIC:
+		return nfsref_lookup_nfs_basic(junct_path);
+	default:
+		xlog(L_ERROR, "Unrecognized junction type");
+	}
+	return EXIT_FAILURE;
+}
diff --git a/utils/nfsref/nfsref.c b/utils/nfsref/nfsref.c
new file mode 100644
index 0000000..ff7013e
--- /dev/null
+++ b/utils/nfsref/nfsref.c
@@ -0,0 +1,188 @@
+/**
+ * @file utils/nfsref/nfsref.c
+ * @brief Manage NFS referrals
+ */
+
+/*
+ * Copyright 2011, 2018 Oracle.  All rights reserved.
+ *
+ * This file is part of nfs-utils.
+ *
+ * nfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2.0 as
+ * published by the Free Software Foundation.
+ *
+ * nfs-utils is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License version 2.0 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2.0 along with nfs-utils.  If not, see:
+ *
+ *	http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ */
+
+#include <sys/types.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <time.h>
+
+#include <locale.h>
+#include <langinfo.h>
+
+#include "junction.h"
+#include "xlog.h"
+#include "nfsref.h"
+
+/**
+ * Short form command line options
+ */
+static const char nfsref_opts[] = "?dt:";
+
+/**
+ * Long form command line options
+ */
+static const struct option nfsref_longopts[] = {
+	{ "debug", 0, NULL, 'd', },
+	{ "help", 0, NULL, '?', },
+	{ "type", 1, NULL, 't', },
+	{ NULL, 0, NULL, 0, },
+};
+
+/**
+ * Display program synopsis
+ *
+ * @param progname NUL-terminated C string containing name of program
+ */
+static void
+nfsref_usage(const char *progname)
+{
+	fprintf(stderr, "Usage: %s [ -t type ] SUBCOMMAND [ ARGUMENTS ]\n\n",
+		progname);
+
+	fprintf(stderr, "SUBCOMMAND is one of:\n");
+	fprintf(stderr, "\tadd        Add a new junction\n");
+	fprintf(stderr, "\tremove     Remove an existing junction\n");
+	fprintf(stderr, "\tlookup     Enumerate a junction\n");
+
+	fprintf(stderr, "\nUse \"%s SUBCOMMAND -?\" for details.\n", progname);
+}
+
+/**
+ * Program entry point
+ *
+ * @param argc count of command line arguments
+ * @param argv array of NUL-terminated C strings containing command line arguments
+ * @return program exit status
+ */
+int
+main(int argc, char **argv)
+{
+	char *progname, *subcommand, *junct_path;
+	enum nfsref_type type;
+	int arg, exit_status;
+	_Bool help;
+
+	(void)setlocale(LC_ALL, "");
+	(void)umask(S_IWGRP | S_IWOTH);
+
+	exit_status = EXIT_FAILURE;
+
+	/* Set the basename */
+	if ((progname = strrchr(argv[0], '/')) != NULL)
+		progname++;
+	else
+		progname = argv[0];
+
+	xlog_stderr(1);
+	xlog_syslog(0);
+	xlog_open(progname);
+
+	if (argc < 2) {
+		nfsref_usage(progname);
+		goto out;
+	}
+
+	help = false;
+	type = NFSREF_TYPE_UNSPECIFIED;
+	while ((arg = getopt_long(argc, argv, nfsref_opts,
+			nfsref_longopts, NULL)) != -1) {
+		switch (arg) {
+		case 'd':
+			xlog_config(D_ALL, 1);
+			break;
+		case 't':
+			if (strcmp(optarg, "nfs-basic") == 0)
+				type = NFSREF_TYPE_NFS_BASIC;
+			else if (strcmp(optarg, "nfs-fedfs") == 0)
+				type = NFSREF_TYPE_NFS_FEDFS;
+			else {
+				xlog(L_ERROR,
+					"Unrecognized junction type: %s",
+					optarg);
+				exit(EXIT_FAILURE);
+			}
+			break;
+		case '?':
+			help = true;
+		}
+	}
+
+	if (argc < optind + 1) {
+		nfsref_usage(progname);
+		goto out;
+	}
+
+	if (!help && geteuid() != 0) {
+		xlog(L_ERROR, "Root permission is required");
+		goto out;
+	}
+
+	subcommand = argv[optind];
+	junct_path = argv[optind + 1];
+
+	if (strcasecmp(subcommand, "add") == 0) {
+		if (help) {
+			exit_status = nfsref_add_help(progname);
+			goto out;
+		}
+		if (argc < optind + 3) {
+			xlog(L_ERROR, "Not enough positional parameters");
+			nfsref_usage(progname);
+			goto out;
+		}
+		exit_status = nfsref_add(type, junct_path, argv, optind);
+		if (exit_status == EXIT_SUCCESS)
+			(void)junction_flush_exports_cache();
+	} else if (strcasecmp(subcommand, "remove") == 0) {
+		if (help) {
+			exit_status = nfsref_remove_help(progname);
+			goto out;
+		}
+		exit_status = nfsref_remove(type, junct_path);
+		if (exit_status == EXIT_SUCCESS)
+			(void)junction_flush_exports_cache();
+	} else if (strcasecmp(subcommand, "lookup") == 0) {
+		if (help) {
+			exit_status = nfsref_lookup_help(progname);
+			goto out;
+		}
+		exit_status = nfsref_lookup(type, junct_path);
+	} else {
+		xlog(L_ERROR, "Unrecognized subcommand: %s", subcommand);
+		nfsref_usage(progname);
+	}
+
+out:
+	exit(exit_status);
+}
diff --git a/utils/nfsref/nfsref.h b/utils/nfsref/nfsref.h
new file mode 100644
index 0000000..bf0e70e
--- /dev/null
+++ b/utils/nfsref/nfsref.h
@@ -0,0 +1,47 @@
+/**
+ * @file support/nfsref/nfsref.h
+ * @brief Declarations and definitions for nfsref command line tool
+ */
+
+/*
+ * Copyright 2011, 2018 Oracle.  All rights reserved.
+ *
+ * This file is part of nfs-utils.
+ *
+ * nfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2.0 as
+ * published by the Free Software Foundation.
+ *
+ * nfs-utils is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License version 2.0 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2.0 along with nfs-utils.  If not, see:
+ *
+ *	http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ */
+
+#ifndef UTILS_NFSREF_H
+#define UTILS_NFSREF_H
+
+/**
+ * Junction types supported by the "nfsref" command
+ */
+enum nfsref_type {
+	NFSREF_TYPE_UNSPECIFIED = 1,
+	NFSREF_TYPE_NFS_BASIC,
+	NFSREF_TYPE_NFS_FEDFS
+};
+
+int	 nfsref_add(enum nfsref_type type, const char *junct_path, char **argv,
+				int optind);
+int	 nfsref_remove(enum nfsref_type type, const char *junct_path);
+int	 nfsref_lookup(enum nfsref_type type, const char *junct_path);
+
+int	 nfsref_add_help(const char *progname);
+int	 nfsref_remove_help(const char *progname);
+int	 nfsref_lookup_help(const char *progname);
+
+#endif	/* !UTILS_NFSREF_H */
diff --git a/utils/nfsref/nfsref.man b/utils/nfsref/nfsref.man
new file mode 100644
index 0000000..1261549
--- /dev/null
+++ b/utils/nfsref/nfsref.man
@@ -0,0 +1,180 @@
+.\"@(#)nfsref.8"
+.\"
+.\" @file utils/nfsref/nfsref.man
+.\" @brief man page for nfsref command
+.\"
+
+.\"
+.\" Copyright 2011, 2018 Oracle.  All rights reserved.
+.\"
+.\" This file is part of nfs-utils.
+.\"
+.\" nfs-utils is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License version 2.0 as
+.\" published by the Free Software Foundation.
+.\"
+.\" nfs-utils is distributed in the hope that it will be useful, but
+.\" WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+.\" GNU General Public License version 2.0 for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" version 2.0 along with nfs-utils.  If not, see:
+.\"
+.\"	http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+.\"
+.TH NFSREF 8 "9 Jan 2018"
+.SH NAME
+nfsref \- manage NFS referrals
+.SH SYNOPSIS
+.B nfsref
+.RB [ \-?d ]
+.RB [ \-t
+.IB type ]
+.B add
+.I pathname server export
+.RI [ " server"
+.IR export " ... ]"
+.P
+.B nfsref
+.RB [ \-?d ]
+.RB [ \-t
+.IB type ]
+.B remove
+.I pathname
+.P
+.B nfsref
+.RB [ \-?d ]
+.RB [ \-t
+.IB type ]
+.B lookup
+.I pathname
+.SH INTRODUCTION
+NFS version 4 introduces the concept of
+.I file system referrals
+to NFS.
+A file system referral is like a symbolic link on a file server
+to another file system share, possibly on another file server.
+On an NFS client, a referral behaves like an automounted directory.
+The client, under the server's direction, mounts a new NFS export
+automatically when an application first accesses that directory.
+.P
+Referrals are typically used to construct a single file name space
+across multiple file servers.
+Because file servers control the shape of the name space,
+no client configuration is required,
+and all clients see the same referral information.
+.P
+The Linux NFS server supports NFS version 4 referrals.
+Administrators can specify the
+.B refer=
+export option in
+.I /etc/exports
+to configure a list of exports from which the client can choose.
+See
+.BR exports (5)
+for details.
+.P
+.SH DESCRIPTION
+The
+.BR nfsref (8)
+command is a simple way to get started managing junction metadata.
+Other administrative commands provide richer access to junction information.
+.SS Subcommands
+Valid
+.BR nfsref (8)
+subcommands are:
+.IP "\fBadd\fP"
+Adds junction information to the directory named by
+.IR pathname .
+The named directory must already exist,
+and must not already contain junction information.
+Regular directory contents are obscured to NFS clients by this operation.
+.IP
+A list of one or more file server and export path pairs
+is also specified on the command line.
+When creating an NFS basic junction, this list is
+stored in an extended attribute of the directory.
+.IP
+If junction creation is successful, the
+.BR nfsref (8)
+command flushes the kernel's export cache
+to remove previously cached junction information.
+.IP "\fBremove\fP"
+Removes junction information from the directory named by
+.IR pathname .
+The named directory must exist,
+and must contain junction information.
+Regular directory contents are made visible to NFS clients again by this operation.
+.IP
+If junction deletion is successful, the
+.BR nfsref (8)
+command flushes the kernel's export cache
+to remove previously cached junction information.
+.IP "\fBlookup\fP"
+Displays junction information stored in the directory named by
+.IR pathname .
+The named directory must exist,
+and must contain junction information.
+.IP
+When looking up an NFS basic junction, the junction information
+in the directory is listed on
+.IR stdout .
+.SS Command line options
+.IP "\fB\-d, \-\-debug"
+Enables debugging messages during operation.
+.IP "\fB\-t, \-\-type=\fIjunction-type\fP"
+Specifies the junction type for the operation.  Valid values for
+.I junction-type
+are
+.B nfs-basic
+or
+.BR nfs-fedfs .
+.IP
+For the
+.B add
+subcommand, the default value if this option is not specified is
+.BR nfs-basic .
+For the
+.B remove
+and
+.B lookup
+subcommands, the
+.B \-\-type
+option is not required.  The
+.BR nfsref (8)
+command operates on whatever junction contents are available.
+.SH EXAMPLES
+Suppose you have two file servers,
+.I top.example.net
+and
+.IR home.example.net .
+You want all your clients to mount
+.I top.example.net:/
+and then see the files under
+.I home.example.net:/
+automatically in
+.IR top:/home .
+.P
+On
+.IR top.example.net ,
+you might issue this command as root:
+.RS
+.sp
+# mkdir /home
+.br
+# nfsref --type=nfs-basic add /home home.example.net /
+.br
+Created junction /home.
+.sp
+.RE
+.SH FILES
+.TP
+.I /etc/exports
+NFS server export table
+.SH "SEE ALSO"
+.BR exports (5)
+.sp
+RFC 5661 for a description of NFS version 4 referrals
+.SH "AUTHOR"
+Chuck Lever <chuck.lever@oracle.com>
diff --git a/utils/nfsref/remove.c b/utils/nfsref/remove.c
new file mode 100644
index 0000000..1a4e371
--- /dev/null
+++ b/utils/nfsref/remove.c
@@ -0,0 +1,145 @@
+/**
+ * @file utils/nfsref/remove.c
+ * @brief Remove junction metadata from a local file system object
+ */
+
+/*
+ * Copyright 2011, 2018 Oracle.  All rights reserved.
+ *
+ * This file is part of nfs-utils.
+ *
+ * nfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2.0 as
+ * published by the Free Software Foundation.
+ *
+ * nfs-utils is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License version 2.0 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2.0 along with nfs-utils.  If not, see:
+ *
+ *	http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <unistd.h>
+#include <errno.h>
+
+#include "junction.h"
+#include "xlog.h"
+#include "nfsref.h"
+
+/**
+ * Display help message for "remove" subcommand
+ *
+ * @param progname NUL-terminated C string containing name of program
+ * @return program exit status
+ */
+int
+nfsref_remove_help(const char *progname)
+{
+	fprintf(stderr, " \n");
+
+	fprintf(stderr, "Usage: %s [ -t type ] remove <junction path>\n\n",
+		progname);
+
+	fprintf(stderr, "Remove the junction at <junction path>.  For FedFS "
+			"junctions, FSL and FSN\n");
+	fprintf(stderr, "records are removed from the NSDB.\n");
+
+	return EXIT_SUCCESS;
+}
+
+/**
+ * Remove an NFS locations-style junction
+ *
+ * @param junct_path NUL-terminated C string containing pathname of junction
+ * @return program exit status
+ */
+static int
+nfsref_remove_nfs_basic(const char *junct_path)
+{
+	int status = EXIT_FAILURE;
+	FedFsStatus retval;
+
+	xlog(D_GENERAL, "%s: Removing FedFS junction from %s",
+		__func__, junct_path);
+
+	retval = nfs_delete_junction(junct_path);
+	switch (retval) {
+	case FEDFS_OK:
+		printf("Removed nfs-basic junction from %s\n", junct_path);
+		status = EXIT_SUCCESS;
+		break;
+	case FEDFS_ERR_NOTJUNCT:
+		xlog(L_ERROR, "%s is not an nfs-basic junction", junct_path);
+		break;
+	default:
+		xlog(L_ERROR, "Failed to delete %s: %s",
+			junct_path, nsdb_display_fedfsstatus(retval));
+	}
+
+	return status;
+}
+
+/**
+ * Remove any NFS junction information
+ *
+ * @param junct_path NUL-terminated C string containing pathname of junction
+ * @return program exit status
+ */
+static int
+nfsref_remove_unspecified(const char *junct_path)
+{
+	FedFsStatus retval;
+
+	xlog(D_GENERAL, "%s: Removing junction from %s",
+		__func__, junct_path);
+
+	retval = nfs_delete_junction(junct_path);
+	if (retval != FEDFS_OK) {
+		if (retval != FEDFS_ERR_NOTJUNCT)
+			goto out_err;
+	}
+
+	printf("Removed junction from %s\n", junct_path);
+	return EXIT_SUCCESS;
+
+out_err:
+	switch (retval) {
+	case FEDFS_ERR_NOTJUNCT:
+		xlog(L_ERROR, "No junction information found in %s", junct_path);
+		break;
+	default:
+		xlog(L_ERROR, "Failed to delete %s: %s",
+			junct_path, nsdb_display_fedfsstatus(retval));
+	}
+	return EXIT_FAILURE;
+}
+
+/**
+ * Remove an NFS junction
+ *
+ * @param type type of junction to add
+ * @param junct_path NUL-terminated C string containing pathname of junction
+ * @return program exit status
+ */
+int
+nfsref_remove(enum nfsref_type type, const char *junct_path)
+{
+	switch (type) {
+	case NFSREF_TYPE_UNSPECIFIED:
+		return nfsref_remove_unspecified(junct_path);
+	case NFSREF_TYPE_NFS_BASIC:
+		return nfsref_remove_nfs_basic(junct_path);
+	default:
+		xlog(L_ERROR, "Unrecognized junction type");
+	}
+	return EXIT_FAILURE;
+}


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v2 0/3] Series short description
  2018-01-18 21:47 [PATCH v2 0/3] Series short description Chuck Lever
  2018-01-18 21:47 ` [PATCH v2 2/3] mountd: Solder in support for NFS basic junctions Chuck Lever
  2018-01-18 21:47 ` [PATCH v2 3/3] Add LDAP-free 'nfsref' command Chuck Lever
@ 2018-01-26 19:26 ` Steve Dickson
  2018-01-26 19:28   ` Chuck Lever
  2 siblings, 1 reply; 6+ messages in thread
From: Steve Dickson @ 2018-01-26 19:26 UTC (permalink / raw)
  To: Chuck Lever, linux-nfs

Chuck,

It seems I never received the first patch (1/3) of this series

steved.  

On 01/18/2018 04:47 PM, Chuck Lever wrote:
> Still UNTESTED, but at least it builds.
> 
> A while back I announced the deprecation of fedfs-utils. There were
> a handful of components in fedfs-utils that we decided to keep. One
> of those keepers was the "nfsref" command. (The other was autofs
> support for /nfs4, which I hope Ian Kent is making progress on ;-)
> 
> This series introduces "nfsref" to nfs-utils, minus the overhead of
> the LDAP / FedFS machinery, and it builds support for NFS basic
> junctions into mountd, replacing the need to install a plug-in DLL
> from fedfs-utils.
> 
> I didn't apply a lot of brain cells to this port, so it's perhaps a
> little larger than it needs to be. Still, it achieves a completely
> LDAP-free implementation that resides 100% in nfs-utils. I'm
> interested in comments about the approach before I do more testing
> and refinement.
> 
>  ./configure --enable-junction --enable-caps
> 
> is needed before building.
> 
> 
> Changes since RFC (v1):
> Patch 2/3 in the original series added the libnfsjunct.so DLL to
> nfs-utils. Series v2 instead replaces 2/3 with a patch that puts
> support for junctions into mountd without the need for a DLL.
> 
> ---
> 
> Chuck Lever (3):
>       Add LDAP-free version of libjunction to nfs-utils
>       mountd: Solder in support for NFS basic junctions
>       Add LDAP-free 'nfsref' command
> 
> 
>  aclocal/libxml2.m4                   |   15 
>  configure.ac                         |   17 
>  support/Makefile.am                  |    4 
>  support/include/Makefile.am          |    2 
>  support/include/fedfs_admin.h        |  342 +++++++
>  support/include/junction.h           |  124 +++
>  support/junction/Makefile.am         |   34 +
>  support/junction/display.c           |  159 +++
>  support/junction/export-cache.c      |  118 +++
>  support/junction/junction-internal.h |  121 +++
>  support/junction/junction.c          |  494 +++++++++++
>  support/junction/locations.c         |  131 +++
>  support/junction/nfs.c               | 1564 ++++++++++++++++++++++++++++++++++
>  support/junction/path.c              |  345 ++++++++
>  support/junction/xml.c               |  401 +++++++++
>  utils/Makefile.am                    |    4 
>  utils/mountd/Makefile.am             |    8 
>  utils/mountd/cache.c                 |  189 ++--
>  utils/nfsref/Makefile.am             |   39 +
>  utils/nfsref/add.c                   |  271 ++++++
>  utils/nfsref/lookup.c                |  211 +++++
>  utils/nfsref/nfsref.c                |  188 ++++
>  utils/nfsref/nfsref.h                |   47 +
>  utils/nfsref/nfsref.man              |  180 ++++
>  utils/nfsref/remove.c                |  145 +++
>  25 files changed, 5049 insertions(+), 104 deletions(-)
>  create mode 100644 aclocal/libxml2.m4
>  create mode 100644 support/include/fedfs_admin.h
>  create mode 100644 support/include/junction.h
>  create mode 100644 support/junction/Makefile.am
>  create mode 100644 support/junction/display.c
>  create mode 100644 support/junction/export-cache.c
>  create mode 100644 support/junction/junction-internal.h
>  create mode 100644 support/junction/junction.c
>  create mode 100644 support/junction/locations.c
>  create mode 100644 support/junction/nfs.c
>  create mode 100644 support/junction/path.c
>  create mode 100644 support/junction/xml.c
>  create mode 100644 utils/nfsref/Makefile.am
>  create mode 100644 utils/nfsref/add.c
>  create mode 100644 utils/nfsref/lookup.c
>  create mode 100644 utils/nfsref/nfsref.c
>  create mode 100644 utils/nfsref/nfsref.h
>  create mode 100644 utils/nfsref/nfsref.man
>  create mode 100644 utils/nfsref/remove.c
> 
> --
> Chuck Lever
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2 0/3] Series short description
  2018-01-26 19:26 ` [PATCH v2 0/3] Series short description Steve Dickson
@ 2018-01-26 19:28   ` Chuck Lever
  2018-01-26 19:29     ` Steve Dickson
  0 siblings, 1 reply; 6+ messages in thread
From: Chuck Lever @ 2018-01-26 19:28 UTC (permalink / raw)
  To: Steve Dickson; +Cc: Linux NFS Mailing List



> On Jan 26, 2018, at 11:26 AM, Steve Dickson <SteveD@RedHat.com> wrote:
>=20
> Chuck,
>=20
> It seems I never received the first patch (1/3) of this series

It's the same as 1/3 of the previous version. I can post the
whole series again if you need me to.


> steved. =20
>=20
> On 01/18/2018 04:47 PM, Chuck Lever wrote:
>> Still UNTESTED, but at least it builds.
>>=20
>> A while back I announced the deprecation of fedfs-utils. There were
>> a handful of components in fedfs-utils that we decided to keep. One
>> of those keepers was the "nfsref" command. (The other was autofs
>> support for /nfs4, which I hope Ian Kent is making progress on ;-)
>>=20
>> This series introduces "nfsref" to nfs-utils, minus the overhead of
>> the LDAP / FedFS machinery, and it builds support for NFS basic
>> junctions into mountd, replacing the need to install a plug-in DLL
>> from fedfs-utils.
>>=20
>> I didn't apply a lot of brain cells to this port, so it's perhaps a
>> little larger than it needs to be. Still, it achieves a completely
>> LDAP-free implementation that resides 100% in nfs-utils. I'm
>> interested in comments about the approach before I do more testing
>> and refinement.
>>=20
>> ./configure --enable-junction --enable-caps
>>=20
>> is needed before building.
>>=20
>>=20
>> Changes since RFC (v1):
>> Patch 2/3 in the original series added the libnfsjunct.so DLL to
>> nfs-utils. Series v2 instead replaces 2/3 with a patch that puts
>> support for junctions into mountd without the need for a DLL.
>>=20
>> ---
>>=20
>> Chuck Lever (3):
>>      Add LDAP-free version of libjunction to nfs-utils
>>      mountd: Solder in support for NFS basic junctions
>>      Add LDAP-free 'nfsref' command
>>=20
>>=20
>> aclocal/libxml2.m4                   |   15=20
>> configure.ac                         |   17=20
>> support/Makefile.am                  |    4=20
>> support/include/Makefile.am          |    2=20
>> support/include/fedfs_admin.h        |  342 +++++++
>> support/include/junction.h           |  124 +++
>> support/junction/Makefile.am         |   34 +
>> support/junction/display.c           |  159 +++
>> support/junction/export-cache.c      |  118 +++
>> support/junction/junction-internal.h |  121 +++
>> support/junction/junction.c          |  494 +++++++++++
>> support/junction/locations.c         |  131 +++
>> support/junction/nfs.c               | 1564 =
++++++++++++++++++++++++++++++++++
>> support/junction/path.c              |  345 ++++++++
>> support/junction/xml.c               |  401 +++++++++
>> utils/Makefile.am                    |    4=20
>> utils/mountd/Makefile.am             |    8=20
>> utils/mountd/cache.c                 |  189 ++--
>> utils/nfsref/Makefile.am             |   39 +
>> utils/nfsref/add.c                   |  271 ++++++
>> utils/nfsref/lookup.c                |  211 +++++
>> utils/nfsref/nfsref.c                |  188 ++++
>> utils/nfsref/nfsref.h                |   47 +
>> utils/nfsref/nfsref.man              |  180 ++++
>> utils/nfsref/remove.c                |  145 +++
>> 25 files changed, 5049 insertions(+), 104 deletions(-)
>> create mode 100644 aclocal/libxml2.m4
>> create mode 100644 support/include/fedfs_admin.h
>> create mode 100644 support/include/junction.h
>> create mode 100644 support/junction/Makefile.am
>> create mode 100644 support/junction/display.c
>> create mode 100644 support/junction/export-cache.c
>> create mode 100644 support/junction/junction-internal.h
>> create mode 100644 support/junction/junction.c
>> create mode 100644 support/junction/locations.c
>> create mode 100644 support/junction/nfs.c
>> create mode 100644 support/junction/path.c
>> create mode 100644 support/junction/xml.c
>> create mode 100644 utils/nfsref/Makefile.am
>> create mode 100644 utils/nfsref/add.c
>> create mode 100644 utils/nfsref/lookup.c
>> create mode 100644 utils/nfsref/nfsref.c
>> create mode 100644 utils/nfsref/nfsref.h
>> create mode 100644 utils/nfsref/nfsref.man
>> create mode 100644 utils/nfsref/remove.c
>>=20
>> --
>> Chuck Lever
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-nfs" =
in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>=20

--
Chuck Lever




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2 0/3] Series short description
  2018-01-26 19:28   ` Chuck Lever
@ 2018-01-26 19:29     ` Steve Dickson
  0 siblings, 0 replies; 6+ messages in thread
From: Steve Dickson @ 2018-01-26 19:29 UTC (permalink / raw)
  To: Chuck Lever; +Cc: Linux NFS Mailing List



On 01/26/2018 02:28 PM, Chuck Lever wrote:
> 
> 
>> On Jan 26, 2018, at 11:26 AM, Steve Dickson <SteveD@RedHat.com> wrote:
>>
>> Chuck,
>>
>> It seems I never received the first patch (1/3) of this series
> 
> It's the same as 1/3 of the previous version. I can post the
> whole series again if you need me to.
Would you mind... tia!

steved.
> 
> 
>> steved.  
>>
>> On 01/18/2018 04:47 PM, Chuck Lever wrote:
>>> Still UNTESTED, but at least it builds.
>>>
>>> A while back I announced the deprecation of fedfs-utils. There were
>>> a handful of components in fedfs-utils that we decided to keep. One
>>> of those keepers was the "nfsref" command. (The other was autofs
>>> support for /nfs4, which I hope Ian Kent is making progress on ;-)
>>>
>>> This series introduces "nfsref" to nfs-utils, minus the overhead of
>>> the LDAP / FedFS machinery, and it builds support for NFS basic
>>> junctions into mountd, replacing the need to install a plug-in DLL
>>> from fedfs-utils.
>>>
>>> I didn't apply a lot of brain cells to this port, so it's perhaps a
>>> little larger than it needs to be. Still, it achieves a completely
>>> LDAP-free implementation that resides 100% in nfs-utils. I'm
>>> interested in comments about the approach before I do more testing
>>> and refinement.
>>>
>>> ./configure --enable-junction --enable-caps
>>>
>>> is needed before building.
>>>
>>>
>>> Changes since RFC (v1):
>>> Patch 2/3 in the original series added the libnfsjunct.so DLL to
>>> nfs-utils. Series v2 instead replaces 2/3 with a patch that puts
>>> support for junctions into mountd without the need for a DLL.
>>>
>>> ---
>>>
>>> Chuck Lever (3):
>>>      Add LDAP-free version of libjunction to nfs-utils
>>>      mountd: Solder in support for NFS basic junctions
>>>      Add LDAP-free 'nfsref' command
>>>
>>>
>>> aclocal/libxml2.m4                   |   15 
>>> configure.ac                         |   17 
>>> support/Makefile.am                  |    4 
>>> support/include/Makefile.am          |    2 
>>> support/include/fedfs_admin.h        |  342 +++++++
>>> support/include/junction.h           |  124 +++
>>> support/junction/Makefile.am         |   34 +
>>> support/junction/display.c           |  159 +++
>>> support/junction/export-cache.c      |  118 +++
>>> support/junction/junction-internal.h |  121 +++
>>> support/junction/junction.c          |  494 +++++++++++
>>> support/junction/locations.c         |  131 +++
>>> support/junction/nfs.c               | 1564 ++++++++++++++++++++++++++++++++++
>>> support/junction/path.c              |  345 ++++++++
>>> support/junction/xml.c               |  401 +++++++++
>>> utils/Makefile.am                    |    4 
>>> utils/mountd/Makefile.am             |    8 
>>> utils/mountd/cache.c                 |  189 ++--
>>> utils/nfsref/Makefile.am             |   39 +
>>> utils/nfsref/add.c                   |  271 ++++++
>>> utils/nfsref/lookup.c                |  211 +++++
>>> utils/nfsref/nfsref.c                |  188 ++++
>>> utils/nfsref/nfsref.h                |   47 +
>>> utils/nfsref/nfsref.man              |  180 ++++
>>> utils/nfsref/remove.c                |  145 +++
>>> 25 files changed, 5049 insertions(+), 104 deletions(-)
>>> create mode 100644 aclocal/libxml2.m4
>>> create mode 100644 support/include/fedfs_admin.h
>>> create mode 100644 support/include/junction.h
>>> create mode 100644 support/junction/Makefile.am
>>> create mode 100644 support/junction/display.c
>>> create mode 100644 support/junction/export-cache.c
>>> create mode 100644 support/junction/junction-internal.h
>>> create mode 100644 support/junction/junction.c
>>> create mode 100644 support/junction/locations.c
>>> create mode 100644 support/junction/nfs.c
>>> create mode 100644 support/junction/path.c
>>> create mode 100644 support/junction/xml.c
>>> create mode 100644 utils/nfsref/Makefile.am
>>> create mode 100644 utils/nfsref/add.c
>>> create mode 100644 utils/nfsref/lookup.c
>>> create mode 100644 utils/nfsref/nfsref.c
>>> create mode 100644 utils/nfsref/nfsref.h
>>> create mode 100644 utils/nfsref/nfsref.man
>>> create mode 100644 utils/nfsref/remove.c
>>>
>>> --
>>> Chuck Lever
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
>>> the body of a message to majordomo@vger.kernel.org
>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>>
> 
> --
> Chuck Lever
> 
> 
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2018-01-26 19:29 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-01-18 21:47 [PATCH v2 0/3] Series short description Chuck Lever
2018-01-18 21:47 ` [PATCH v2 2/3] mountd: Solder in support for NFS basic junctions Chuck Lever
2018-01-18 21:47 ` [PATCH v2 3/3] Add LDAP-free 'nfsref' command Chuck Lever
2018-01-26 19:26 ` [PATCH v2 0/3] Series short description Steve Dickson
2018-01-26 19:28   ` Chuck Lever
2018-01-26 19:29     ` Steve Dickson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.