[RFC,PATCH 1/4] Dynamic Pseudo Root
Steve Dickson
SteveD at redhat.com
Fri Dec 7 14:15:48 EST 2007
commit fd0c72a6c41c20c4039d9c4365f04633e09e2f9e
Author: Steve Dickson <steved at redhat.com>
Date: Thu Nov 29 15:58:04 2007 -0500
Initial attempt at creating a dynamic pseudo-root for nfs4 exports.
This will eliminate the need to define a pseudo root with
the 'fsid=0' export option allowing existing export configurations
to just work with nfs4 mounts.
Signed-off-by: Steve Dickson <steved at redhat.com>
---
support/export/Makefile.am | 2 +-
support/export/v4root.c | 201 +++++++++++++++++++++++++++++++++++++++++++
support/export/xtab.c | 5 +
support/include/Makefile.am | 2 +
support/include/execute.h | 38 ++++++++
support/include/exportfs.h | 11 +++
support/include/mounts.h | 61 +++++++++++++
support/include/nfslib.h | 3 +
support/nfs/Makefile.am | 2 +-
support/nfs/execute.c | 92 ++++++++++++++++++++
utils/mountd/auth.c | 5 +
utils/mountd/cache.c | 46 ++++++-----
utils/mountd/mountd.c | 1 +
13 files changed, 446 insertions(+), 23 deletions(-)
create mode 100644 support/export/v4root.c
create mode 100644 support/include/execute.h
create mode 100644 support/include/mounts.h
create mode 100644 support/nfs/execute.c
diff --git a/support/export/Makefile.am b/support/export/Makefile.am
index 1ea1539..8a324b1 100644
--- a/support/export/Makefile.am
+++ b/support/export/Makefile.am
@@ -11,7 +11,7 @@ EXTRA_DIST = mount.x
noinst_LIBRARIES = libexport.a
libexport_a_SOURCES = client.c export.c hostname.c nfsctl.c rmtab.c \
- xtab.c mount_clnt.c mount_xdr.c
+ xtab.c mount_clnt.c mount_xdr.c v4root.c
BUILT_SOURCES = $(GENFILES)
noinst_HEADERS = mount.h
diff --git a/support/export/v4root.c b/support/export/v4root.c
new file mode 100644
index 0000000..c91fe8d
--- /dev/null
+++ b/support/export/v4root.c
@@ -0,0 +1,201 @@
+/*
+ * support/export/v4root.c
+ *
+ * Routines that create and destroy v4 psuedo roots
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "xlog.h"
+#include "exportfs.h"
+#include "nfslib.h"
+#include "misc.h"
+#include "mounts.h"
+#include "execute.h"
+
+#ifndef _PATH_PSEUDO_ROOT
+#define _PATH_PSEUDO_ROOT NFS_STATEDIR "/v4root"
+#endif
+
+void v4root_destroy(void);
+void v4root_create(void);
+void v4root_umountall(void);
+
+int need_v4root;
+static char errbuf[BUFSIZ];
+static int v4root_mkroot(void);
+static int v4root_mkroot(void);
+
+static struct exportent pf_export = {
+ .e_hostname = "*",
+ .e_path = _PATH_PSEUDO_ROOT,
+ .m_path = _PATH_PSEUDO_ROOT,
+ .e_flags = NFSEXP_READONLY | NFSEXP_INSECURE_PORT
+ | NFSEXP_NOSUBTREECHECK | NFSEXP_FSID
+ | NFSEXP_CROSSMOUNT,
+ .e_anonuid = 65534,
+ .e_anongid = 65534,
+ .e_squids = NULL,
+ .e_nsquids = 0,
+ .e_sqgids = NULL,
+ .e_nsqgids = 0,
+ .e_fsid = 0,
+ .e_mountpoint = NULL,
+};
+static struct psuedo_ent {
+ struct exportent *export;
+ char *fh;
+} psuedo_export = {NULL, NULL};
+
+int
+v4root_mount(struct mountargs *args)
+{
+ int status;
+
+ status = mount (args->spec, args->node, args->type, args->flags, args->data);
+ if (status < 0) {
+ snprintf(errbuf, BUFSIZ, "mounting %s failed: ", args->node);
+ syserror(errbuf);
+ }
+}
+
+int
+v4root_umount(struct mountargs *args)
+{
+ int status;
+
+ if (args->flags)
+ status = umount2(args->node, args->flags);
+ else
+ status = umount(args->node);
+ if (status < 0) {
+ snprintf(errbuf, BUFSIZ, "unmounting %s failed: ", args->node);
+ syserror(errbuf);
+ }
+}
+
+/*
+ * Destroy the psuedo root
+ */
+void
+v4root_destroy()
+{
+ if (access(_PATH_PSEUDO_ROOT, F_OK) < 0)
+ return;
+
+ psuedo_export.export = NULL;
+ psuedo_export.fh = NULL;
+ lazy_umount(_PATH_PSEUDO_ROOT);
+ exec_rmdir(_PATH_PSEUDO_ROOT);
+}
+
+/*
+ * Create the psuedo root directory
+ */
+static int
+v4root_mkroot()
+{
+ struct stat sb;
+
+ if (stat(_PATH_PSEUDO_ROOT, &sb) < 0) {
+ if (errno != ENOENT) {
+ syserror(_PATH_PSEUDO_ROOT);
+ return 1;
+ }
+ if (mkdir(_PATH_PSEUDO_ROOT, 0755) < 0) {
+ syserror("Unable to create " _PATH_PSEUDO_ROOT);
+ return 1;
+ }
+ } else if (!S_ISDIR(sb.st_mode)) {
+ errno = ENOTDIR;
+ syserror(_PATH_PSEUDO_ROOT);
+ return 1;
+ }
+
+ return 0;
+}
+/*
+ * Creat the psuedo tree by running through
+ * the exports and bind mounting them to
+ * directories in the tree
+ */
+void
+v4root_create()
+{
+ nfs_export *exp, *nxt, *root;
+ char path[BUFSIZ];
+ int i;
+
+ if (!need_v4root)
+ return;
+
+ if (v4root_mkroot())
+ return;
+
+ if (!is_mountpoint(_PATH_PSEUDO_ROOT))
+ tmpfs_mount(_PATH_PSEUDO_ROOT);
+
+ for (i = 0; i < MCL_MAXTYPES; i++) {
+ for (exp = exportlist[i]; exp; exp = nxt) {
+ nxt = exp->m_next;
+ if (strcmp(exp->m_export.e_path, "/"))
+ snprintf(path, BUFSIZ, "%s/%s", _PATH_PSEUDO_ROOT,
+ exp->m_export.e_path);
+ if (!is_mountpoint(path)) {
+ exec_mkpath(path);
+ bind_mount(exp->m_export.e_path, path);
+ }
+ }
+ }
+ psuedo_export.export = &pf_export;
+}
+
+void
+v4root_umountall()
+{
+ v4root_destroy();
+}
+struct exportent *
+v4root_chkroot(int fsidtype, unsigned int fsidnum, char *fhuuid)
+{
+ struct exportent *psuedo_root = NULL;
+ char u[16];
+
+ if (psuedo_export.export == NULL)
+ return NULL;
+
+ switch(fsidtype) {
+ case FSID_NUM:
+ if (fsidnum == 0)
+ psuedo_root = psuedo_export.export;
+ break;
+ }
+
+ return psuedo_root;
+}
+char *
+v4root_maproot(char *path)
+{
+ char *mpath;
+
+ if (psuedo_export.export == NULL)
+ return NULL;
+
+ if (strstr(path, _PATH_PSEUDO_ROOT) == NULL)
+ return NULL;
+
+ if (strcmp(path, _PATH_PSEUDO_ROOT))
+ mpath = path + strlen(_PATH_PSEUDO_ROOT);
+ else
+ mpath = strlen(_PATH_PSEUDO_ROOT);
+
+ return mpath;
+}
diff --git a/support/export/xtab.c b/support/export/xtab.c
index 990113e..fee6ad2 100644
--- a/support/export/xtab.c
+++ b/support/export/xtab.c
@@ -20,6 +20,7 @@
#include "xio.h"
#include "xlog.h"
+extern int need_v4root, clean_v4root;
static void cond_rename(char *newfile, char *oldfile);
static int
@@ -36,6 +37,8 @@ xtab_read(char *xtab, int is_export)
if ((lockid = xflock(xtab, "r")) < 0)
return 0;
setexportent(xtab, "r");
+ if (is_export == 1)
+ need_v4root = 1;
while ((xp = getexportent(is_export==0, 0)) != NULL) {
if (!(exp = export_lookup(xp->e_hostname, xp->e_path, is_export != 1)) &&
!(exp = export_create(xp, is_export!=1))) {
@@ -48,6 +51,8 @@ xtab_read(char *xtab, int is_export)
case 1:
exp->m_xtabent = 1;
exp->m_mayexport = 1;
+ if ((xp->e_flags & NFSEXP_FSID) && xp->e_fsid == 0)
+ need_v4root = 0;
break;
case 2:
exp->m_exported = -1;/* may be exported */
diff --git a/support/include/Makefile.am b/support/include/Makefile.am
index 718abda..dfa3c46 100644
--- a/support/include/Makefile.am
+++ b/support/include/Makefile.am
@@ -3,9 +3,11 @@
SUBDIRS = nfs rpcsvc sys
noinst_HEADERS = \
+ execute.h \
exportfs.h \
ha-callout.h \
misc.h \
+ mounts.h \
nfs_mntent.h \
nfs_paths.h \
nfslib.h \
diff --git a/support/include/execute.h b/support/include/execute.h
new file mode 100644
index 0000000..71aa30c
--- /dev/null
+++ b/support/include/execute.h
@@ -0,0 +1,38 @@
+/*
+ * support/include/execute.h
+ *
+ * Routines that will execute random shell commands.
+ *
+ */
+
+#ifndef EXECUTE_H
+#define EXECUTE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef _RMDIR_CMD
+#define _RMDIR_CMD "/bin/rmdir"
+#endif
+
+#ifndef _MKDIR_CMD
+#define _MKDIR_CMD "/bin/mkdir"
+#endif
+
+inline int
+exec_rmdir(char *dir)
+{
+ char *const myargv[] = {_RMDIR_CMD, dir, NULL};
+
+ return execute_cmd(_RMDIR_CMD, myargv);
+}
+inline int
+exec_mkpath(char *dir)
+{
+ char *const myargv[] = {_MKDIR_CMD, "-p", dir, NULL};
+
+ return execute_cmd(_MKDIR_CMD, myargv);
+}
+
+#endif /* EXECUTE_H */
diff --git a/support/include/exportfs.h b/support/include/exportfs.h
index c1ba543..a0d612e 100644
--- a/support/include/exportfs.h
+++ b/support/include/exportfs.h
@@ -12,6 +12,17 @@
#include <netdb.h>
#include "nfslib.h"
+enum nfsd_fsid {
+ FSID_DEV = 0,
+ FSID_NUM,
+ FSID_MAJOR_MINOR,
+ FSID_ENCODE_DEV,
+ FSID_UUID4_INUM,
+ FSID_UUID8,
+ FSID_UUID16,
+ FSID_UUID16_INUM,
+};
+
enum {
MCL_FQDN = 0,
MCL_SUBNETWORK,
diff --git a/support/include/mounts.h b/support/include/mounts.h
new file mode 100644
index 0000000..4406150
--- /dev/null
+++ b/support/include/mounts.h
@@ -0,0 +1,61 @@
+/*
+ * support/include/mounts.h
+ *
+ * Routines used to mount and umount different
+ * type of filesystems.
+ *
+ */
+
+#ifndef MOUNTS_H
+#define MOUNTS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/mount.h>
+//#include "misc.h"
+
+struct mountargs {
+ const char *spec;
+ const char *node;
+ const char *type;
+ int flags;
+ void *data;
+};
+extern int v4root_mount(struct mountargs *args);
+extern int v4root_umount(struct mountargs *args);
+
+#ifndef MNT_DETACH
+#define MNT_DETACH 0x00000002 /* Just detach from the tree */
+#endif
+
+inline int
+bind_mount(char *dev, char *dir)
+{
+ struct mountargs args = {dev, dir, "bind", MS_BIND, NULL};
+
+ xlog(D_CALL, "mount --bind %s %s", dev, dir);
+
+ return v4root_mount(&args);
+}
+inline int
+tmpfs_mount(char *dir)
+{
+ struct mountargs args = {"tmpfs", dir, "tmpfs", 0, NULL};
+
+ xlog(D_CALL, "mount -t tmpfs tmpfs %s", dir);
+
+ return v4root_mount(&args);
+}
+inline int
+lazy_umount(char *dir)
+{
+ struct mountargs args = {NULL, dir, NULL, MNT_DETACH, NULL};
+
+ xlog(D_CALL, "umount -l %s", dir);
+
+ return v4root_umount(&args);
+}
+
+#endif /* MOUNTS_H */
diff --git a/support/include/nfslib.h b/support/include/nfslib.h
index 422b012..7315416 100644
--- a/support/include/nfslib.h
+++ b/support/include/nfslib.h
@@ -155,4 +155,7 @@ void closeall(int min);
int svctcp_socket (u_long __number, int __reuse);
int svcudp_socket (u_long __number, int __reuse);
+extern int execute_cmd(const char *cmd, char *const myargv[]);
+extern void syserror(char *message);
+
#endif /* NFSLIB_H */
diff --git a/support/nfs/Makefile.am b/support/nfs/Makefile.am
index 87f3949..925a0a2 100644
--- a/support/nfs/Makefile.am
+++ b/support/nfs/Makefile.am
@@ -4,7 +4,7 @@ noinst_LIBRARIES = libnfs.a
libnfs_a_SOURCES = exports.c rmtab.c xio.c rpcmisc.c rpcdispatch.c \
xlog.c xcommon.c wildmat.c nfssvc.c nfsclient.c \
nfsexport.c getfh.c nfsctl.c \
- svc_socket.c cacheio.c closeall.c nfs_mntent.c
+ svc_socket.c cacheio.c closeall.c nfs_mntent.c execute.c
MAINTAINERCLEANFILES = Makefile.in
diff --git a/support/nfs/execute.c b/support/nfs/execute.c
new file mode 100644
index 0000000..55d2d31
--- /dev/null
+++ b/support/nfs/execute.c
@@ -0,0 +1,92 @@
+#include <sys/wait.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include "xlog.h"
+
+/*
+ * Log system errors or error messages.
+ */
+void
+syserror(char *message)
+{
+ if (errno)
+ xlog(L_ERROR, "%s: errno %d (%s)", message, errno, strerror(errno));
+ else
+ xlog(L_ERROR, "Error: %s", message);
+}
+/*
+ * Log the the given argv[] if debugging is on.
+ */
+static void
+show_argv(char *msg, char *const argv[])
+{
+ char buf[BUFSIZ], *ptr;
+ int i, cc=0;
+
+ if (!xlog_enabled(D_CALL))
+ return;
+
+ ptr = buf;
+ if (msg) {
+ sprintf(ptr+cc, "%s ", msg);
+ cc = strlen(buf);
+ }
+ for (i=0; argv[i] != NULL && cc < BUFSIZ; i++) {
+ if ((cc + strlen(argv[i])) >= BUFSIZ)
+ break;
+ sprintf(ptr+cc, "%s ", argv[i]);
+ cc = strlen(buf);
+ }
+ xlog(D_CALL, "%s", buf);
+}
+/*
+ * Execute the give command using the
+ * given argv as the arguments.
+ */
+int
+execute_cmd(const char *cmd, char *const myargv[])
+{
+ int pfd[2], pid, status, cc;
+ char buf[BUFSIZ], *ch;
+
+ show_argv("executing:", myargv);
+
+ if (pipe(pfd) < 0) {
+ syserror("pipe() failed");
+ return errno;
+ }
+ switch((pid = fork())) {
+ case -1:
+ syserror("fork() failed");
+ break;
+ case 0: /* child */
+ close(pfd[0]);
+ if (dup2(pfd[1], fileno(stdout)) < 0)
+ perror("dup2(stdout)");
+ if (dup2(pfd[1], fileno(stderr)) < 0)
+ perror("dup2(stderr)");
+ close(pfd[1]);
+ execvp(cmd, myargv);
+ perror("execv");
+ _exit(255);
+ break;
+ default: /* parent */
+ status = 0;
+ close(pfd[1]);
+ waitpid(pid, &status, 0);
+ if (WIFEXITED(status) /* && (kiderr = WEXITSTATUS(status))*/ ) {
+ cc = read(pfd[0], buf, BUFSIZ);
+ if (cc > 0) {
+ if ((ch = strrchr(buf, '\n')) != NULL)
+ *ch = '\0';
+ errno = 0;
+ syserror(buf);
+ }
+ }
+ break;
+ }
+ return errno;
+}
diff --git a/utils/mountd/auth.c b/utils/mountd/auth.c
index 2bb708f..df309c9 100644
--- a/utils/mountd/auth.c
+++ b/utils/mountd/auth.c
@@ -21,6 +21,7 @@
#include "mountd.h"
#include "xmalloc.h"
+
enum auth_error
{
bad_path,
@@ -84,6 +85,7 @@ auth_reload()
static int last_fd;
static unsigned int counter;
int fd;
+ extern void v4root_destroy(), v4root_create();
if ((fd = open(_PATH_ETAB, O_RDONLY)) < 0) {
xlog(L_FATAL, "couldn't open %s", _PATH_ETAB);
@@ -98,9 +100,12 @@ auth_reload()
last_inode = stb.st_ino;
}
+
+ v4root_destroy();
export_freeall();
memset(&my_client, 0, sizeof(my_client));
xtab_export_read();
+ v4root_create();
check_useipaddr();
++counter;
diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c
index fd317cd..f367d2b 100644
--- a/utils/mountd/cache.c
+++ b/utils/mountd/cache.c
@@ -36,18 +36,6 @@
#include "blkid/blkid.h"
#endif
-
-enum nfsd_fsid {
- FSID_DEV = 0,
- FSID_NUM,
- FSID_MAJOR_MINOR,
- FSID_ENCODE_DEV,
- FSID_UUID4_INUM,
- FSID_UUID8,
- FSID_UUID16,
- FSID_UUID16_INUM,
-};
-
/*
* Support routines for text-based upcalls.
* Fields are separated by spaces.
@@ -58,7 +46,6 @@ enum nfsd_fsid {
*/
int cache_export_ent(char *domain, struct exportent *exp, char *p);
-
char *lbuf = NULL;
int lbuflen = 0;
extern int use_ipaddr;
@@ -81,6 +68,8 @@ void auth_unix_ip(FILE *f)
if (readline(fileno(f), &lbuf, &lbuflen) != 1)
return;
+ xlog(D_CALL, "auth_unix_ip: '%s'", lbuf);
+
cp = lbuf;
if (qword_get(&cp, class, 20) <= 0 ||
@@ -131,6 +120,8 @@ void auth_unix_gid(FILE *f)
if (readline(fileno(f), &lbuf, &lbuflen) != 1)
return;
+ xlog(D_CALL, "auth_unix_gid: '%s'", lbuf);
+
cp = lbuf;
if (qword_get_int(&cp, &uid) != 0)
return;
@@ -278,12 +269,14 @@ void nfsd_fh(FILE *f)
int dev_missing = 0;
int uuidlen = 0;
char *fhuuid = NULL;
+ extern struct exportent *v4root_export(void);
if (readline(fileno(f), &lbuf, &lbuflen) != 1)
return;
- cp = lbuf;
+ xlog(D_CALL, "nfsd_fh: '%s'", lbuf);
+ cp = lbuf;
dom = malloc(strlen(cp));
if (dom == NULL)
return;
@@ -365,6 +358,10 @@ void nfsd_fh(FILE *f)
auth_reload();
+ if ((found = v4root_chkroot(fsidtype, fsidnum, fhuuid))) {
+ found_path = strdup(found->e_path);
+ goto found;
+ }
/* Now determine export point for this fsid/domain */
for (i=0 ; i < MCL_MAXTYPES; i++) {
nfs_export *next_exp;
@@ -409,6 +406,7 @@ void nfsd_fh(FILE *f)
if (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) {
continue;
}
+
switch(fsidtype){
case FSID_DEV:
case FSID_MAJOR_MINOR:
@@ -438,8 +436,7 @@ void nfsd_fh(FILE *f)
if (exp->m_export.e_uuid)
get_uuid(NULL, exp->m_export.e_uuid,
uuidlen, u);
- else if (get_uuid(path, NULL,
- uuidlen, u) == 0)
+ else if (get_uuid(path, NULL, uuidlen, u) == 0)
continue;
if (memcmp(u, fhuuid, uuidlen) != 0)
@@ -471,6 +468,7 @@ void nfsd_fh(FILE *f)
}
}
}
+
if (found &&
found->e_mountpoint &&
!is_mountpoint(found->e_mountpoint[0]?
@@ -490,11 +488,12 @@ void nfsd_fh(FILE *f)
*/
goto out;
}
-
+found:
if (found)
if (cache_export_ent(dom, found, found_path) < 0)
found = 0;
+ xlog(D_CALL, "nfsd_fh: found %s", found ? found->e_path : NULL);
qword_print(f, dom);
qword_printint(f, fsidtype);
qword_printhex(f, fsid, fsidlen);
@@ -597,7 +596,7 @@ void nfsd_export(FILE *f)
char *cp;
int i;
- char *dom, *path;
+ char *dom, *path, *mpath;
nfs_export *exp, *found = NULL;
int found_type = 0;
struct in_addr addr;
@@ -607,6 +606,8 @@ void nfsd_export(FILE *f)
if (readline(fileno(f), &lbuf, &lbuflen) != 1)
return;
+ xlog(D_CALL, "nfsd_export: '%s'", lbuf);
+
cp = lbuf;
dom = malloc(strlen(cp));
path = malloc(strlen(cp));
@@ -619,6 +620,9 @@ void nfsd_export(FILE *f)
if (qword_get(&cp, path, strlen(lbuf)) <= 0)
goto out;
+ if ((mpath = v4root_maproot(path)) == NULL)
+ mpath = path;
+
auth_reload();
/* now find flags for this export point in this domain */
@@ -629,14 +633,14 @@ void nfsd_export(FILE *f)
if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT) {
/* if path is a mountpoint below e_path, then OK */
int l = strlen(exp->m_export.e_path);
- if (strcmp(path, exp->m_export.e_path) == 0 ||
- (strncmp(path, exp->m_export.e_path, l) == 0 &&
+ if (strcmp(mpath, exp->m_export.e_path) == 0 ||
+ (strncmp(mpath, exp->m_export.e_path, l) == 0 &&
path[l] == '/' &&
is_mountpoint(path)))
/* ok */;
else
continue;
- } else if (strcmp(path, exp->m_export.e_path) != 0)
+ } else if (strcmp(mpath, exp->m_export.e_path) != 0)
continue;
if (use_ipaddr) {
if (he == NULL) {
diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c
index 4a50588..a7f3592 100644
--- a/utils/mountd/mountd.c
+++ b/utils/mountd/mountd.c
@@ -169,6 +169,7 @@ killer (int sig)
kill(0, SIGTERM);
wait_for_workers();
}
+ v4root_umountall();
xlog (L_FATAL, "Caught signal %d, un-registering and exiting.", sig);
}
--
1.5.3.4
More information about the NFSv4
mailing list