From: Chuck Lever <chuck.lever@oracle.com>
To: linux-nfs@vger.kernel.org
Subject: [PATCH RFC 2/3] Add LDAP-free version of libnfsjunct to nfs-utils
Date: Mon, 08 Jan 2018 16:50:07 -0500 [thread overview]
Message-ID: <20180108215007.20133.81237.stgit@manet.1015granger.net> (raw)
In-Reply-To: <20180108213356.20133.54161.stgit@manet.1015granger.net>
libnfsjunct is a dynamic library that mountd can load to enable
the Linux NFS server to support junctions. This patch moves the
non-LDAP parts of libnfsjunct into nfs-utils. This enables mountd to
continue to recognize and support NFS basic junctions.
mountd works fine whether or not there is a libnfsjunct installed
on the local system, just as it did before. Without libnfsjunct,
junctions on the NFS server appear to NFS clients like weird
directories.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
support/include/Makefile.am | 1
support/include/nfs-plugin.h | 101 ++++++++++++
support/junction/Makefile.am | 6 +
support/junction/nfs-plugin.c | 350 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 458 insertions(+)
create mode 100644 support/include/nfs-plugin.h
create mode 100644 support/junction/nfs-plugin.c
diff --git a/support/include/Makefile.am b/support/include/Makefile.am
index 11cb162..a207d21 100644
--- a/support/include/Makefile.am
+++ b/support/include/Makefile.am
@@ -9,6 +9,7 @@ noinst_HEADERS = \
ha-callout.h \
junction.h \
misc.h \
+ nfs-plugin.h \
nfs_mntent.h \
nfs_paths.h \
nfslib.h \
diff --git a/support/include/nfs-plugin.h b/support/include/nfs-plugin.h
new file mode 100644
index 0000000..33e63f3
--- /dev/null
+++ b/support/include/nfs-plugin.h
@@ -0,0 +1,101 @@
+/*
+ * @file support/include/nfs-plugin.h
+ * @brief Definition of NFS junction plug-in API
+ */
+
+/*
+ * 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
+ */
+
+/*
+ * The purpose of this API is to provide an opaque mechanism for
+ * the NFS mountd daemon to resolve NFS basic and FedFS junctions.
+ * This interface is therefore quite specific to NFS.
+ */
+
+#ifndef NFS_PLUGIN_H
+#define NFS_PLUGIN_H
+
+#include <stdint.h>
+
+__BEGIN_DECLS
+
+/**
+ * Current version of API
+ */
+#define JP_API_VERSION (1)
+
+/**
+ * NFS plug-in library soname; passed to dlopen(3)
+ */
+#define JP_NFSPLUGIN_SONAME "libnfsjunct.so.0"
+
+/**
+ * A set of NFS FS locations
+ */
+struct nfs_fsloc_set;
+typedef struct nfs_fsloc_set *nfs_fsloc_set_t;
+
+/**
+ * Junction operation status codes
+ */
+enum jp_status {
+ JP_OK = 0,
+ JP_INVAL = -1,
+ JP_ACCESS = -2,
+ JP_EXIST = -3,
+ JP_TYPE_NOT_SUPP = -4,
+ JP_OP_NOT_SUPP = -5,
+ JP_ISJUNCTION = -6,
+ JP_NOTJUNCTION = -7,
+ JP_NSDBLOCAL = -8,
+ JP_NSDBREMOTE = -9,
+ JP_MEMORY = -10,
+ JP_SYSTEM = -11,
+ JP_PARSE = -1000,
+ JP_EMPTY = -1001,
+};
+
+/**
+ * Vector of methods provided by a junction plug-in
+ */
+struct jp_ops {
+ unsigned int jp_api_version;
+
+ enum jp_status (*jp_init)(_Bool want_debugging);
+ void (*jp_done)(void);
+
+ const char * (*jp_error)(enum jp_status status);
+ void (*jp_put_locations)(nfs_fsloc_set_t locset);
+ enum jp_status (*jp_get_locations)(const char *junct_path,
+ nfs_fsloc_set_t *locset);
+ void (*jp_rewind_locations)(nfs_fsloc_set_t locset);
+ enum jp_status (*jp_get_next_location)(nfs_fsloc_set_t locset,
+ char **hostname, char **export_path,
+ int *ttl);
+};
+
+/**
+ * Load this symbol to get access to the junction API
+ */
+extern struct jp_ops nfs_junction_ops;
+
+__END_DECLS
+
+#endif /* !NFS_PLUGIN_H */
diff --git a/support/junction/Makefile.am b/support/junction/Makefile.am
index 97e7426..9494f55 100644
--- a/support/junction/Makefile.am
+++ b/support/junction/Makefile.am
@@ -29,6 +29,12 @@ noinst_LTLIBRARIES = libjunction.la
libjunction_la_SOURCES = display.c export-cache.c junction.c \
locations.c nfs.c path.c xml.c
+lib_LTLIBRARIES = libnfsjunct.la
+libnfsjunct_la_SOURCES = nfs-plugin.c
+libnfsjunct_la_LIBADD = $(LIBXML2) \
+ ../../support/nfs/libnfs.la \
+ libjunction.la
+
MAINTAINERCLEANFILES = Makefile.in
AM_CPPFLAGS = -I. -I../include -I/usr/include/libxml2
diff --git a/support/junction/nfs-plugin.c b/support/junction/nfs-plugin.c
new file mode 100644
index 0000000..61039ca
--- /dev/null
+++ b/support/junction/nfs-plugin.c
@@ -0,0 +1,350 @@
+/**
+ * @file support/junction/nfs-plugin.c
+ * @brief DLL to resolve junction information
+ */
+
+/*
+ * 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/stat.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <libxml/parser.h>
+
+#include "fedfs_admin.h"
+#include "nfs-plugin.h"
+#include "junction.h"
+
+#define VERSION "0.12.0"
+#define FEDFS_NFS_BASIC_TTL (300)
+
+struct nfs_fsloc_set {
+ int ns_ttl;
+ struct nfs_fsloc *ns_current;
+ struct nfs_fsloc *ns_list;
+};
+
+static _Bool debug = false;
+
+/**
+ * Write a debugging message to stderr
+ *
+ * @param fmt NUL-terminated C string containing output format specification
+ *
+ * NB: Caller may have already opened syslog for her own use. We can't
+ * hijack it here, so using xlog() is right out. Thus output is
+ * directed to stderr via fprintf(3).
+ */
+static void
+nfs_jp_debug(const char *fmt, ...)
+{
+ va_list args;
+
+ if (!debug)
+ return;
+
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+}
+
+/**
+ * Perform any plug-in startup processing
+ *
+ * @param want_debugging true if caller wants to enable debugging output
+ * @return a junction status code
+ */
+static enum jp_status
+nfs_jp_init(_Bool want_debugging)
+{
+ debug = want_debugging;
+ nfs_jp_debug("%s: Junction plug-in version " VERSION "\n", __func__);
+ xmlInitParser();
+ return JP_OK;
+}
+
+/**
+ * Perform any plug-in shutdown processing
+ *
+ * Nothing to be done for NFS junctions.
+ */
+static void
+nfs_jp_done(void)
+{
+ nfs_jp_debug("%s: Finishing\n", __func__);
+ xmlCleanupParser();
+ return;
+}
+
+/**
+ * Given an status code, return a pointer to a static error message
+ *
+ * @param status a junction plug-in status code
+ * @return a static NUL-terminated string
+ */
+static const char *
+nfs_jp_error(enum jp_status status)
+{
+ static char buf[128];
+
+ switch (status) {
+ case JP_OK:
+ return "Success";
+ case JP_INVAL:
+ return "Invalid parameter";
+ case JP_ACCESS:
+ return "Permission denied";
+ case JP_EXIST:
+ return "Object cannot be made into a junction";
+ case JP_TYPE_NOT_SUPP:
+ return "Junction type not supported";
+ case JP_OP_NOT_SUPP:
+ return "Junction method not supported";
+ case JP_ISJUNCTION:
+ return "Object is a junction";
+ case JP_NOTJUNCTION:
+ return "Object is not a junction";
+ case JP_NSDBLOCAL:
+ return "A local NSDB configuration error occurred";
+ case JP_NSDBREMOTE:
+ return "An error occurred on the NSDB";
+ case JP_MEMORY:
+ return "Memory allocation failure";
+ case JP_SYSTEM:
+ snprintf(buf, sizeof(buf), "System error (%d): %s",
+ status, strerror(errno));
+ return buf;
+ case JP_PARSE:
+ return "Failed to parse locations data";
+ case JP_EMPTY:
+ return "No more locations in location set";
+ }
+
+ snprintf(buf, sizeof(buf), "Unknown error (%d)", status);
+ return buf;
+}
+
+/**
+ * Release a set of NFS locations
+ *
+ * @param locset set of NFS locations to release
+ */
+static void
+nfs_jp_put_locations(nfs_fsloc_set_t locset)
+{
+ if (locset == NULL) {
+ nfs_jp_debug("%s: Invalid parameters\n", __func__);
+ return;
+ }
+
+ nfs_jp_debug("%s: Freeing location set %p, ns_list=%p\n",
+ __func__, locset, locset->ns_list);
+ nfs_free_locations(locset->ns_list);
+ free(locset);
+}
+
+/**
+ * Internal function to allocate a set of NFS locations
+ *
+ * @return dynamically allocated nfs_fsloc_set_t object
+ *
+ * If return value is non-NULL, caller must free it with
+ * nfs_jp_put_locations().
+ */
+__attribute_malloc__
+static nfs_fsloc_set_t
+nfs_jp_alloc_locations(void)
+{
+ return calloc(1, sizeof(struct nfs_fsloc_set));
+}
+
+/**
+ * Internal function to rewind a set of locations
+ *
+ * @param locset set of NFS locations to rewind
+ */
+static void
+nfs_jp_do_rewind_locations(nfs_fsloc_set_t locset)
+{
+ locset->ns_current = locset->ns_list;
+}
+
+/**
+ * Resolve NFS basic junction information into a set of NFS locations
+ *
+ * @param junct_path NUL-terminated C string containing POSIX path of junction
+ * @param locset OUT set of NFS locations
+ * @return a junction status code
+ *
+ * If this entry point returns JP_OK, the caller must free the returned
+ * set of locations by calling the jp_put_locations entry point.
+ */
+static enum jp_status
+nfs_jp_get_basic(const char *junct_path, nfs_fsloc_set_t *locset)
+{
+ nfs_fsloc_set_t new;
+ FedFsStatus retval;
+
+ new = nfs_jp_alloc_locations();
+ if (new == NULL) {
+ nfs_jp_debug("%s: No memory\n", __func__);
+ return JP_MEMORY;
+ }
+
+ retval = nfs_get_locations(junct_path, &new->ns_list);
+ if (retval != FEDFS_OK) {
+ nfs_jp_debug("%s: Failed to get locations: %s\n",
+ __func__, nsdb_display_fedfsstatus(retval));
+ nfs_jp_put_locations(new);
+ return JP_PARSE;
+ }
+
+ nfs_jp_debug("%s: Returning location set %p\n", __func__, new);
+ nfs_jp_do_rewind_locations(new);
+ new->ns_ttl = FEDFS_NFS_BASIC_TTL;
+ *locset = new;
+ return JP_OK;
+}
+
+/**
+ * Resolve junction information into a set of NFS locations
+ *
+ * @param junct_path NUL-terminated C string containing POSIX path of junction
+ * @param locset OUT set of NFS locations
+ * @return a junction status code
+ *
+ * If this entry point returns JP_OK, the caller must free the returned
+ * set of locations by calling the jp_put_locations entry point.
+ */
+static enum jp_status
+nfs_jp_get_locations(const char *junct_path, nfs_fsloc_set_t *locset)
+{
+ FedFsStatus retval;
+
+ if (junct_path == NULL || locset == NULL) {
+ nfs_jp_debug("%s: Invalid parameters\n", __func__);
+ return JP_INVAL;
+ }
+ nfs_jp_debug("%s: %s\n", __func__, junct_path);
+
+ retval = nfs_is_junction(junct_path);
+ if (retval == FEDFS_OK)
+ return nfs_jp_get_basic(junct_path, locset);
+
+ nfs_jp_debug("%s: Not a junction\n", __func__);
+ return JP_NOTJUNCTION;
+}
+
+/**
+ * Reset the current location to the first location in the list
+ *
+ * @param locset set of NFS locations
+ */
+static void
+nfs_jp_rewind_locations(nfs_fsloc_set_t locset)
+{
+ if (locset == NULL) {
+ nfs_jp_debug("%s: Invalid parameters\n", __func__);
+ return;
+ }
+
+ nfs_jp_debug("%s: Rewinding %p\n", __func__, locset);
+ nfs_jp_do_rewind_locations(locset);
+}
+
+/**
+ * Get the fileserver hostname and export path from the next location in the set
+ *
+ * @param locset set of NFS locations
+ * @param hostname OUT NUL-terminated C string containing hostname of fileserver
+ * @param export_path OUT NUL-terminated C string containing export path
+ * @param ttl OUT cache time-to-live, in seconds
+ * @return a junction status code
+ *
+ * If this entry point returns JP_OK, the caller must free the hostname
+ * and export_path strings with free(3).
+ */
+static enum jp_status
+nfs_jp_get_next_location(nfs_fsloc_set_t locset,
+ char **hostname, char **export_path, int *ttl)
+{
+ char *hostname_tmp, *export_path_tmp;
+ struct nfs_fsloc *fsloc;
+
+ if (locset == NULL || hostname == NULL ||
+ export_path == NULL || ttl == NULL) {
+ nfs_jp_debug("%s: Invalid parameters\n", __func__);
+ return JP_INVAL;
+ }
+ nfs_jp_debug("%s: locset=%p, ns_current=%p, ns_list=%p\n",
+ __func__, locset, locset->ns_current, locset->ns_list);
+
+ if (locset->ns_current == NULL) {
+ nfs_jp_debug("%s: No locations\n", __func__);
+ return JP_EMPTY;
+ }
+ fsloc = locset->ns_current;
+
+ hostname_tmp = strdup(fsloc->nfl_hostname);
+ if (hostname_tmp == NULL) {
+ nfs_jp_debug("%s: No memory\n", __func__);
+ return JP_MEMORY;
+ }
+
+ if (nsdb_path_array_to_posix(fsloc->nfl_rootpath,
+ &export_path_tmp) != FEDFS_OK) {
+ free(hostname_tmp);
+ nfs_jp_debug("%s: Failed to parse\n", __func__);
+ return JP_PARSE;
+ }
+
+ nfs_jp_debug("%s: Success; hostname=%s path=%s\n",
+ __func__, hostname_tmp, export_path_tmp);
+ *hostname = hostname_tmp;
+ *export_path = export_path_tmp;
+ *ttl = locset->ns_ttl;
+ locset->ns_current = locset->ns_current->nfl_next;
+ return JP_OK;
+}
+
+/**
+ * Vector of methods provided by this plug-in
+ */
+struct jp_ops nfs_junction_ops = {
+ .jp_api_version = JP_API_VERSION,
+ .jp_init = nfs_jp_init,
+ .jp_done = nfs_jp_done,
+ .jp_error = nfs_jp_error,
+ .jp_put_locations = nfs_jp_put_locations,
+ .jp_get_locations = nfs_jp_get_locations,
+ .jp_rewind_locations = nfs_jp_rewind_locations,
+ .jp_get_next_location = nfs_jp_get_next_location,
+};
next prev parent reply other threads:[~2018-01-08 21:50 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-01-08 21:49 [PATCH RFC 0/3] Add server-side support for junctions to nfs-utils Chuck Lever
2018-01-08 21:50 ` Chuck Lever [this message]
2018-01-08 21:50 ` [PATCH RFC 3/3] Add 'nfsref' command Chuck Lever
2018-01-09 19:21 ` [PATCH RFC 0/3] Add server-side support for junctions to nfs-utils J. Bruce Fields
2018-01-09 19:36 ` Chuck Lever
2018-01-10 17:13 ` Steve Dickson
2018-01-10 17:17 ` Bruce Fields
2018-01-10 17:26 ` Steve Dickson
2018-01-10 17:36 ` Bruce Fields
2018-01-10 19:42 ` Chuck Lever
2018-01-11 14:20 ` Steve Dickson
2018-01-11 15:17 ` Bruce Fields
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180108215007.20133.81237.stgit@manet.1015granger.net \
--to=chuck.lever@oracle.com \
--cc=linux-nfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox