@@ -70,6 +70,7 @@ tests/nsm_client/nlm_sm_inter_svc.c
tests/nsm_client/nlm_sm_inter_xdr.c
utils/nfsidmap/nfsidmap
systemd/nfs-server-generator
+systemd/rpc-pipefs-generator
systemd/nfs-config.service
systemd/rpc-gssd.service
# cscope database files
@@ -42,12 +42,14 @@ EXTRA_DIST = $(unit_files) $(man5_MANS) $(man7_MANS)
unit_dir = /usr/lib/systemd/system
generator_dir = /usr/lib/systemd/system-generators
-EXTRA_PROGRAMS = nfs-server-generator
+EXTRA_PROGRAMS = nfs-server-generator rpc-pipefs-generator
genexecdir = $(generator_dir)
nfs_server_generator_LDADD = ../support/export/libexport.a \
../support/nfs/libnfs.a \
../support/misc/libmisc.a
+rpc_pipefs_generator_LDADD = ../support/nfs/libnfs.a
+
if INSTALL_SYSTEMD
genexec_PROGRAMS = nfs-server-generator
install-data-hook: $(unit_files)
new file mode 100644
@@ -0,0 +1,256 @@
+/*
+ * rpc-pipefs-generator:
+ * systemd generator to create ordering dependencies between
+ * nfs services and the rpc_pipefs mount(s)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#include "nfslib.h"
+#include "conffile.h"
+
+#define NUM_PIPEFS_USERS 3
+#define RPC_PIPEFS_DEFAULT "/var/lib/nfs/rpc_pipefs"
+char *conf_path;
+
+/*
+ * conf_name - the name as it appears (or would appear, in the case of idmapd,
+ * in the /etc/nfs.conf
+ * unit_name - the name of the systemd service unit file (minus '.service')
+ * after_local_fs - should the After= directive have local-fs.target or not
+ * generate - should a drop-in config be generated or not
+ */
+struct pipefs_user {
+ char *conf_name;
+ char *unit_name;
+ int after_local_fs;
+ int generate;
+};
+
+/*
+ * blkmapd is a placeholder for (generate=0) because it does not have nfs.conf
+ * support and because the pipefs directory cannot be overriden.
+ */
+static struct pipefs_user pipefs_users[NUM_PIPEFS_USERS] = {
+ {
+ .conf_name = "blkmapd",
+ .unit_name = "nfs-blkmap",
+ .after_local_fs = 0,
+ .generate = 0,
+ },
+ {
+ .conf_name = "gssd",
+ .unit_name = "rpc-gssd",
+ .after_local_fs = 0,
+ .generate = 1,
+ },
+ {
+ .conf_name = "idmapd",
+ .unit_name = "nfs-idmapd",
+ .after_local_fs = 1,
+ .generate = 1,
+ }
+};
+
+int systemd_len(char *path)
+{
+ char *p;
+ int len = 0;
+
+ p = path;
+ while (*p == '/')
+ p++;
+
+ if (!*p)
+ /* "/" becomes "-", otherwise leading "/" is ignored */
+ return 1;
+
+ while (*p) {
+ unsigned char c = *p++;
+
+ if (c == '/') {
+ /* multiple non-trailing slashes become '-' */
+ while (*p == '/')
+ p++;
+ if (*p)
+ len++;
+ } else if (isalnum(c) || c == ':' || c == '.' || c == '_')
+ len++;
+ else {
+ len += 4;
+ }
+ }
+
+ return len;
+}
+
+char *systemd_escape(char *path)
+{
+ char *result = NULL;
+ char *p;
+ int len;
+
+ len = systemd_len(path);
+ if (!len)
+ goto out;
+
+ result = malloc(len + strlen(".mount") + 1);
+ if (!result)
+ goto out;
+
+ p = result;
+ while (*path == '/')
+ path++;
+ if (!*path) {
+ /* "/" becomes "-", otherwise leading "/" is ignored */
+ *p++ = '-';
+ goto out_append;
+ }
+ while (*path) {
+ unsigned char c = *path++;
+
+ if (c == '/') {
+ /* multiple non-trailing slashes become '-' */
+ while (*path == '/')
+ path++;
+ if (*path)
+ *p++ = '-';
+ } else if (isalnum(c) || c == ':' || c == '.' || c == '_')
+ *p++ = c;
+ else {
+ *p++ = '\\';
+ *p++ = 'x';
+ *p++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1);
+ *p++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1);
+ }
+ }
+
+out_append:
+ sprintf(p, ".mount");
+out:
+ return result;
+}
+
+static int generate_mount_unit(const char *mountpoint, const char *unitname,
+ const char *dirname)
+{
+ char *path;
+ struct stat stb;
+ FILE *f;
+
+ path = malloc(strlen(dirname) + 1 + strlen(unitname));
+ if (!path)
+ return 1;
+ sprintf(path, "%s/%s", dirname, unitname);
+ if (stat(path, &stb) == 0)
+ return 0;
+ f = fopen(path, "w");
+ if (!f)
+ return 1;
+
+ fprintf(f, "# Automatically generated by rpc-pipefs-generator\n\n[Unit]\n");
+ fprintf(f, "Description=RPC Pipe File System\n");
+ fprintf(f, "DefaultDependencies=no\n");
+ fprintf(f, "After=systemd-tmpfiles-setup.service\n");
+ fprintf(f, "Conflicts=umount.target\n");
+ fprintf(f, "\n[Mount]\n");
+ fprintf(f, "What=sunrpc\n");
+ fprintf(f, "Where=%s\n", mountpoint);
+ fprintf(f, "Type=rpc_pipefs\n");
+
+ fclose(f);
+ return 0;
+}
+
+static
+int generate_drop_in(char *conf_name, char *unit_name,
+ const int after_local_fs, const char *dirname)
+{
+ char *path;
+ char dirbase[] = ".service.d";
+ char filebase[] = "/10-pipefs.conf";
+ char *s;
+ char *pipefs_unit;
+ FILE *f;
+ int ret = 0;
+
+ s = conf_get_str(conf_name, "pipefs-directory");
+ if (!s)
+ return 0;
+
+ if (strlen(s) == strlen(RPC_PIPEFS_DEFAULT) &&
+ strcmp(s, RPC_PIPEFS_DEFAULT) == 0)
+ return 0;
+
+ pipefs_unit = systemd_escape(s);
+ if (!pipefs_unit)
+ return 1;
+
+ ret = generate_mount_unit(s, pipefs_unit, dirname);
+ if (ret)
+ return ret;
+
+ path = malloc(strlen(dirname) + 1 + sizeof(unit_name) +
+ sizeof(dirbase) + sizeof(filebase));
+ if (!path)
+ return 2;
+ sprintf(path, "%s/%s%s", dirname, unit_name, dirbase);
+ mkdir(path, 0755);
+ strcat(path, filebase);
+ f = fopen(path, "w");
+ if (!f)
+ return 1;
+
+ fprintf(f, "# Automatically generated by rpc-pipefs-generator\n\n[Unit]\n");
+ fprintf(f, "Requires=\nRequires=");
+ fprintf(f, "%s\n", pipefs_unit);
+ fprintf(f, "After=\nAfter=");
+ fprintf(f, "%s", pipefs_unit);
+ if (after_local_fs)
+ fprintf(f, " local-fs.target");
+ fprintf(f, "\n");
+ fclose(f);
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+ struct pipefs_user p;
+ int ret;
+
+ /* Avoid using any external services */
+ xlog_syslog(0);
+
+ if (argc != 4 || argv[1][0] != '/') {
+ fprintf(stderr, "rpc-pipefs-generator: create systemd dependencies for nfs services\n");
+ fprintf(stderr, "Usage: normal-dir early-dir late-dir\n");
+ exit(1);
+ }
+
+ conf_path = NFS_CONFFILE;
+ conf_init();
+ for (i = 0; i < NUM_PIPEFS_USERS; i++) {
+ p = pipefs_users[i];
+ if (!p.generate)
+ continue;
+
+ ret = generate_drop_in(p.conf_name, p.unit_name,
+ p.after_local_fs, argv[1]);
+ if (ret)
+ exit(ret);
+ }
+
+ exit(0);
+}
@@ -1,8 +1,7 @@
[Unit]
Description=RPC security service for NFS server
DefaultDependencies=no
-Requires=var-lib-nfs-rpc_pipefs.mount
-After=var-lib-nfs-rpc_pipefs.mount local-fs.target
+After=local-fs.target
PartOf=nfs-server.service
PartOf=nfs-utils.service
The nfs.conf has config options for the pipefs mountpoint. Currently, changing these from the default also requires manually overriding the systemd unit files that are hard-coded to mount the filesystem on /var/lib/nfs/rpc_pipefs. This patch adds a generator that creates a mount unit file for the pipefs when a non-default value is specified in /etc/nfs.conf, as well as drop-in config files to override the dependencies for the systemd units using the pipefs. This patch also removes the dependency on the pipefs from the rpc-svcgssd.service unit file. rpc.svcgssd uses the sunrpc cache mechanism to exchange data with the kernel, not the pipefs. Signed-off-by: Scott Mayhew <smayhew@redhat.com> --- .gitignore | 1 + systemd/Makefile.am | 4 +- systemd/rpc-pipefs-generator.c | 256 +++++++++++++++++++++++++++++++++++++++++ systemd/rpc-svcgssd.service | 3 +- 4 files changed, 261 insertions(+), 3 deletions(-) create mode 100644 systemd/rpc-pipefs-generator.c