[prev in list] [next in list] [prev in thread] [next in thread] 

List:       linux-nfsv4
Subject:    [PATCH 2/5] nfs-utils - Dynamic Pseudo Root - Release 6
From:       Steve Dickson <SteveD () redhat ! com>
Date:       2009-09-23 20:02:59
Message-ID: 4ABA7EF3.5070804 () RedHat ! com
[Download RAW message or body]

commit 6e929b2289559f44a06c7ed022dbf779ca97cb99
Author: Steve Dickson <steved@redhat.com>
Date:   Wed Sep 23 15:15:43 2009 -0400

    The routines needed to support dynamic pseudo roots.
    
    Signed-off-by: Steve Dickson <steved@redhat.com>

diff --git a/support/include/v4root.h b/support/include/v4root.h
new file mode 100644
index 0000000..43b1d2e
--- /dev/null
+++ b/support/include/v4root.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2009 Red Hat <nfs@redhat.com>
+ * support/include/v4root.h
+ *
+ * Support routines for dynamic pseudo roots.
+ *
+ */
+
+#ifndef V4ROOT_H
+#define V4ROOT_H
+
+extern int v4root_needed;
+
+extern struct exportent *v4root_chkroot(int , unsigned int , char *);
+extern struct exportent *v4root_export(char *, int);
+extern struct exportent *v4root_create(char *, nfs_export *, int);
+extern void v4root_free(struct exportent *);
+extern void v4root_unset(void), v4root_set(void);
+
+#endif /* V4ROOT_H */
diff --git a/utils/mountd/Makefile.am b/utils/mountd/Makefile.am
index 1e76cf8..eba81fc 100644
--- a/utils/mountd/Makefile.am
+++ b/utils/mountd/Makefile.am
@@ -8,7 +8,7 @@ KPREFIX		= @kprefix@
 sbin_PROGRAMS	= mountd
 
 mountd_SOURCES = mountd.c mount_dispatch.c auth.c rmtab.c cache.c \
-		 svc_run.c fsloc.c mountd.h
+		 svc_run.c fsloc.c v4root.c mountd.h
 mountd_LDADD = ../../support/export/libexport.a \
 	       ../../support/nfs/libnfs.a \
 	       ../../support/misc/libmisc.a \
diff --git a/utils/mountd/v4root.c b/utils/mountd/v4root.c
new file mode 100644
index 0000000..4f9acb7
--- /dev/null
+++ b/utils/mountd/v4root.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2009 Red Hat <nfs@redhat.com>
+ *
+ * support/export/v4root.c
+ *
+ * Routines used to support NFSv4 pseudo roots
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/queue.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <uuid/uuid.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "xlog.h"
+#include "exportfs.h"
+#include "nfslib.h"
+#include "misc.h"
+#include "v4root.h"
+
+#ifndef _PATH_PSEUDO_ROOT
+#define _PATH_PSEUDO_ROOT		"/"
+#endif
+
+#ifndef _PSEUDO_ROOT_FSID
+#define _PSEUDO_ROOT_FSID	0
+#endif
+
+extern int get_uuid(char *path, char *uuid, int uuidlen, char *u);
+
+typedef struct _exports_t {
+	TAILQ_ENTRY(_exports_t) list;
+	char *path;
+	void *head;
+	char uuid_len;
+	char uuid[sizeof(uuid_t)];
+	struct exportent p_export;
+} exports_t;
+
+#define HASH_TABLE_SIZE 1021
+typedef struct _hash_head {
+	TAILQ_HEAD(export_list, _exports_t) h_head;
+} hash_head;
+hash_head exports_tbl[HASH_TABLE_SIZE];
+
+
+static exports_t *hash_export_lookup(char *, unsigned int);
+static void hash_export_add(struct _exports_t *, int);
+static void hash_mount_free(void);
+
+static inline unsigned int strtoint(char *str, int len)
+{
+	unsigned int n = 0;
+	int i;
+
+	for (i=0; i < len; i++)
+		n+=((int)str[i])*i;
+	return n;
+}
+static inline int hashint(unsigned int num)
+{
+	return num % HASH_TABLE_SIZE;
+}
+#define HASH(_s, _l) hashint(strtoint((_s), (_l)))
+void v4root_set(void);
+void v4root_unset(void);
+
+int v4root_needed;
+
+static nfs_export pr_export = {
+	.m_next = NULL,
+	.m_client = NULL,
+	.m_export = {
+		.e_hostname = "*",
+		.e_path = _PATH_PSEUDO_ROOT,
+		.e_flags = NFSEXP_READONLY | NFSEXP_ROOTSQUASH
+				| NFSEXP_NOSUBTREECHECK | NFSEXP_FSID
+				| NFSEXP_CROSSMOUNT | NFSEXP_V4ROOT,
+		.e_anonuid = 65534,
+		.e_anongid = 65534,
+		.e_squids = NULL,
+		.e_nsquids = 0,
+		.e_sqgids = NULL,
+		.e_nsqgids = 0,
+		.e_fsid = 0,
+		.e_mountpoint = NULL,
+	},
+	.m_exported = 0,
+	.m_xtabent = 1,
+	.m_mayexport = 1,
+	.m_changed = 0,
+	.m_warned = 0,
+};
+static nfs_export *pseudo_root;
+
+/*
+ * Return the number '/' in the path
+ */
+inline static int slash_count(char *path)
+{
+	int i, slashs=0;
+
+	for (i=0; i < strlen(path); i++) {
+			if (path[i] == '/')
+				slashs++;
+	}
+	return slashs;
+}
+
+/*
+ * Build a table of pseudo exports by running through
+ * the real export looking at the components of the path
+ * that make up the export. Those path components, if
+ * not exported, will become pseudo exports allowing them 
+ * to be found when the kernel does an upcall looking for 
+ * components of the v4 mount.
+ */
+void
+v4root_set()
+{
+	nfs_export	*exp, *nxt;
+	int	i, slcnt;
+	char *e_path, *path, *ptr, *comp;
+	char *hostname;
+
+	if (!v4root_needed)
+		return;
+
+	pseudo_root = &pr_export;
+
+	for (i = 0; i < MCL_MAXTYPES; i++) {
+		for (exp = exportlist[i].p_head; exp; exp = nxt) {
+			nxt = exp->m_next;
+			e_path = exp->m_export.e_path;
+			hostname = exp->m_export.e_hostname;
+
+			slcnt = slash_count(e_path);
+			if (slcnt == 1)
+				continue;
+			slcnt--; /* knock off the leanding '/' */
+
+			path = strdup(e_path);
+			if (path == NULL) { 
+				xlog(L_WARNING, "v4root_set: No memory for pseudo export");
+				return;
+			}
+
+			/*
+			 * Run through each component of the path to
+			 * see if a  pseudo export should be created.
+			 */
+			comp = path+1;
+			do { 
+				if ((ptr = strchr(comp, '/')) != NULL)
+					*ptr = '\0';
+
+	  			if (export_lookup(hostname, path, 0) == NULL)
+					if (v4root_create(path, exp, FALSE) == NULL) {
+						xlog(L_WARNING, 
+							"v4root_set: Unable to create pseudo export"
+							"for '%s'", path);
+						break;
+					}
+
+				if (ptr) {
+					*ptr = '/';
+					comp = ptr+1; 
+				}
+			} while (--slcnt > 0);
+			free(path);
+		}
+	}
+}
+
+/*
+ * Unset the pseudo root export
+ */
+void
+v4root_unset()
+{
+	pseudo_root = NULL;
+	hash_mount_free();
+}
+
+/*
+ * The kernel will do an upcall looking for the pseudo
+ * root via its fsid. When the wanted fsid equals 
+ * PSEUDO_ROOT_FSID return the pseudo root export.
+ */
+struct exportent *
+v4root_chkroot(int fsidtype, unsigned int fsidnum, char *fhuuid)
+{
+	struct exportent *p_export = NULL;
+
+	if (pseudo_root == NULL)
+		return NULL;
+
+	switch(fsidtype) {
+		case FSID_NUM:
+			if (fsidnum == _PSEUDO_ROOT_FSID) {
+				p_export = &pseudo_root->m_export;
+				strncpy(p_export->e_path, _PATH_PSEUDO_ROOT, 
+					NFS_MAXPATHLEN);
+			}
+			break;
+	}
+
+	return p_export;
+}
+
+/*
+ * Create a pseudo export, if one does not 
+ * already exist.
+ */
+struct exportent *
+v4root_create(char *path, nfs_export *exp, int docheck)
+{
+	static struct exportent *p_export = NULL;
+	exports_t *pexp;
+	char *epath = exp->m_export.e_path;
+	int elen, plen;
+	char uuid_len = sizeof(uuid_t);
+	char uuid[sizeof(uuid_t)];
+
+	if (pseudo_root == NULL)
+		return NULL;
+
+	if (docheck) {
+
+		/* Path needs to be a subset of e_path */
+		elen = strlen(epath);
+		plen = strlen(path);
+		if (plen >= elen)
+			return NULL;
+
+		if (memcmp(path, epath, plen) != 0)
+			return NULL;
+	}
+
+	/* Check to see if the export already exists */
+	get_uuid(path, NULL, uuid_len, uuid);
+	if ((p_export = v4root_export(uuid, uuid_len)) != NULL)
+		return p_export;
+
+	pexp = (exports_t *)malloc(sizeof(exports_t));
+	if (pexp == NULL) {
+		xlog(L_WARNING, "v4root_create: No memory for pseudo export");
+		return NULL;
+	}
+	p_export = &pexp->p_export;
+	pexp->path = strdup(path);
+	if (pexp->path == 0) {
+		xlog(L_WARNING, "v4root_create: No memory for pseudo path");
+		free(pexp);
+		return NULL;
+	}
+	pexp->uuid_len = uuid_len;
+	memcpy(pexp->uuid, uuid, uuid_len);
+
+	dupexportent(&pexp->p_export, &pr_export.m_export);
+	strcpy(p_export->e_path, path);
+	p_export->e_flags &= ~NFSEXP_FSID;
+	p_export->e_v4root = (void *)pexp;
+
+	hash_export_add(pexp, HASH(pexp->uuid, sizeof(uuid_t)));
+
+	xlog(D_CALL, "v4root_create: path '%s'", p_export->e_path);
+
+	return p_export;
+}
+
+/*
+ * Free a pseudo export
+ */
+void
+v4root_free(struct exportent *p_export)
+{
+	exports_t *pexp = (exports_t *)p_export->e_v4root;
+	hash_head *head = (hash_head *)pexp->head;
+
+	free(pexp->path);
+	TAILQ_REMOVE(&head->h_head, pexp, list);
+}
+
+/*
+ * Return a pseudo export that match the given uuid
+ */
+struct exportent *
+v4root_export(char *fhuuid, int uuidlen)
+{
+	struct exportent *p_export = NULL;
+	exports_t *pexp;
+	int len = MIN(uuidlen, sizeof(uuid_t));
+
+	if (pseudo_root == NULL)
+		return NULL;
+
+	pexp = hash_export_lookup(fhuuid, len);
+	if (pexp) {
+		p_export = &pexp->p_export;
+		xlog(D_CALL, "v4root_export: path %s", p_export->e_path);
+	}
+	return p_export;
+}
+
+/*
+ * Add pseudo export to export table
+ */
+static void hash_export_add(struct _exports_t *exp, int hash)
+{
+	hash_head *head;
+
+	head = &(exports_tbl[hash]);
+	exp->head = head;
+
+	if (TAILQ_EMPTY(&head->h_head))
+		TAILQ_INSERT_HEAD(&head->h_head, exp, list);
+	else
+		TAILQ_INSERT_TAIL(&head->h_head, exp, list);
+}
+
+/*
+ * Lookup a pseudo export using the uuid and inode number
+ */
+static exports_t *
+hash_export_lookup(char *uuid, unsigned int uuidlen)
+{
+	exports_t *pexp;
+	hash_head *head;
+	int hash = HASH(uuid, uuidlen);
+
+	head = &(exports_tbl[hash]);
+
+	TAILQ_FOREACH(pexp, &head->h_head, list) {
+		if (memcmp(pexp->uuid, uuid, uuidlen) == 0)
+			return pexp;
+	}
+	return NULL;
+
+}
+
+/*
+ * Free up pseudo export table
+ */
+static void hash_mount_free()
+{
+	hash_head *head;
+	exports_t *e1, *e2;
+	int hash;
+
+	for (hash=0; hash < HASH_TABLE_SIZE; hash++) {
+		head = &(exports_tbl[hash]);
+		if (head == NULL)
+			continue;
+		e1 = TAILQ_FIRST(&head->h_head);
+		while (e1 != NULL) {
+			free(e1->path);
+			e2 =  TAILQ_NEXT(e1, list);
+			TAILQ_REMOVE(&head->h_head, e1, list);
+			free(e1);
+			e1 = e2;
+		}
+		TAILQ_INIT(&head->h_head);
+	}
+}

_______________________________________________
NFSv4 mailing list
NFSv4@linux-nfs.org
http://linux-nfs.org/cgi-bin/mailman/listinfo/nfsv4
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic