From faa7f39a28c1f07546023bbe5ddf437d9b0745f9 Mon Sep 17 00:00:00 2001 From: Steve Dickson Date: Sep 23 2009 20:09:06 +0000 Subject: Updated to the latest pseudo root release (rel6) --- diff --git a/nfs-utils-1.2.0-v4root-rel6.patch b/nfs-utils-1.2.0-v4root-rel6.patch new file mode 100644 index 0000000..20856bc --- /dev/null +++ b/nfs-utils-1.2.0-v4root-rel6.patch @@ -0,0 +1,716 @@ +diff --git a/support/export/xtab.c b/support/export/xtab.c +index 3b1dcce..2a43193 100644 +--- a/support/export/xtab.c ++++ b/support/export/xtab.c +@@ -19,7 +19,9 @@ + #include "exportfs.h" + #include "xio.h" + #include "xlog.h" ++#include "v4root.h" + ++int v4root_needed; + static void cond_rename(char *newfile, char *oldfile); + + static int +@@ -36,6 +38,8 @@ xtab_read(char *xtab, char *lockfn, int is_export) + if ((lockid = xflock(lockfn, "r")) < 0) + return 0; + setexportent(xtab, "r"); ++ if (is_export == 1) ++ v4root_needed = 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 +52,8 @@ xtab_read(char *xtab, char *lockfn, int is_export) + case 1: + exp->m_xtabent = 1; + exp->m_mayexport = 1; ++ if ((xp->e_flags & NFSEXP_FSID) && xp->e_fsid == 0) ++ v4root_needed = 0; + break; + case 2: + exp->m_exported = -1;/* may be exported */ +diff --git a/support/include/exportfs.h b/support/include/exportfs.h +index a5cf482..1ad41e2 100644 +--- a/support/include/exportfs.h ++++ b/support/include/exportfs.h +@@ -12,6 +12,17 @@ + #include + #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/nfs/export.h b/support/include/nfs/export.h +index f7a99ba..76953ac 100644 +--- a/support/include/nfs/export.h ++++ b/support/include/nfs/export.h +@@ -24,6 +24,7 @@ + #define NFSEXP_FSID 0x2000 + #define NFSEXP_CROSSMOUNT 0x4000 + #define NFSEXP_NOACL 0x8000 /* reserved for possible ACL related use */ +-#define NFSEXP_ALLFLAGS 0xFFFF ++#define NFSEXP_V4ROOT 0x10000 ++#define NFSEXP_ALLFLAGS 0x1FFFF + + #endif /* _NSF_EXPORT_H */ +diff --git a/support/include/nfslib.h b/support/include/nfslib.h +index 537a31e..e4777dd 100644 +--- a/support/include/nfslib.h ++++ b/support/include/nfslib.h +@@ -88,6 +88,7 @@ struct exportent { + int e_fslocmethod; + char * e_fslocdata; + char * e_uuid; ++ void * e_v4root; + struct sec_entry e_secinfo[SECFLAVOR_COUNT+1]; + }; + +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 ++ * 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/auth.c b/utils/mountd/auth.c +index 575f207..041a745 100644 +--- a/utils/mountd/auth.c ++++ b/utils/mountd/auth.c +@@ -20,6 +20,7 @@ + #include "exportfs.h" + #include "mountd.h" + #include "xmalloc.h" ++#include "v4root.h" + + enum auth_error + { +@@ -98,10 +99,13 @@ auth_reload() + last_inode = stb.st_ino; + } + ++ v4root_unset(); + export_freeall(); + memset(&my_client, 0, sizeof(my_client)); + xtab_export_read(); + check_useipaddr(); ++ v4root_set(); ++ + ++counter; + + return counter; +diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c +index e4e2f22..d631570 100644 +--- a/utils/mountd/cache.c ++++ b/utils/mountd/cache.c +@@ -32,23 +32,12 @@ + #include "xmalloc.h" + #include "fsloc.h" + #include "pseudoflavors.h" ++#include "v4root.h" + + #ifdef USE_BLKID + #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. +@@ -135,6 +124,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; +@@ -391,6 +382,12 @@ void nfsd_fh(FILE *f) + + auth_reload(); + ++ /* Check to see if the kenel is looking for the pseudo root */ ++ 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; +@@ -511,7 +508,23 @@ void nfsd_fh(FILE *f) + */ + goto out; + } ++ if (!found) { ++ /* ++ * See if this is a pesudo export ++ */ ++ switch(fsidtype) { ++ case FSID_UUID4_INUM: ++ case FSID_UUID8: ++ case FSID_UUID16: ++ case FSID_UUID16_INUM: ++ found = v4root_export(fhuuid, uuidlen); ++ break; ++ } ++ if (found) ++ found_path = strdup(found->e_path); ++ } + ++found: + if (found) + if (cache_export_ent(dom, found, found_path) < 0) + found = 0; +@@ -629,6 +642,7 @@ void nfsd_export(FILE *f) + int found_type = 0; + struct in_addr addr; + struct hostent *he = NULL; ++ struct exportent *v4root = NULL; + + + if (readline(fileno(f), &lbuf, &lbuflen) != 1) +@@ -663,10 +677,18 @@ void nfsd_export(FILE *f) + path[l] == '/' && + is_mountpoint(path))) + /* ok */; +- else ++ else { ++ /* See if the path is part of the psuedo root */ ++ if (v4root_needed && !v4root) ++ v4root = v4root_create(path, exp, TRUE); + continue; +- } else if (strcmp(path, exp->m_export.e_path) != 0) ++ } ++ } else if (strcmp(path, exp->m_export.e_path) != 0) { ++ /* See if the path is part of the psuedo root */ ++ if (v4root_needed && !v4root) ++ v4root = v4root_create(path, exp, TRUE); + continue; ++ } + if (use_ipaddr) { + if (he == NULL) { + if (!inet_aton(dom, &addr)) +@@ -705,17 +727,28 @@ void nfsd_export(FILE *f) + } + + if (found) { ++ xlog(D_CALL, "nfsd_export: found: path %s", path); + if (dump_to_cache(f, dom, path, &found->m_export) < 0) { + xlog(L_WARNING, + "Cannot export %s, possibly unsupported filesystem" + " or fsid= required", path); + dump_to_cache(f, dom, path, NULL); + } +- } else { ++ } else if (v4root) { ++ xlog(D_CALL, "nfsd_export: vroot: path %s", path); ++ dump_to_cache(f, dom, path, v4root); ++ found = (nfs_export *)v4root; ++ } else { + dump_to_cache(f, dom, path, NULL); + } + out: +- xlog(D_CALL, "nfsd_export: found %p path %s", found, path ? path : NULL); ++ /* ++ * If a psuedo export was create and its not needed ++ * free it up. ++ */ ++ if (v4root && found != (nfs_export *)v4root) ++ v4root_free(v4root); ++ + if (dom) free(dom); + if (path) free(path); + if (he) free(he); +@@ -743,7 +776,9 @@ void cache_open(void) + if (!manage_gids && cachelist[i].cache_handle == auth_unix_gid) + continue; + sprintf(path, "/proc/net/rpc/%s/channel", cachelist[i].cache_name); +- cachelist[i].f = fopen(path, "r+"); ++ if ((cachelist[i].f = fopen(path, "r+")) == NULL) ++ xlog(L_ERROR, "cache_open: Unable to open '%s': errno %d (%s)", ++ path, errno, strerror(errno)); + } + } + +diff --git a/utils/mountd/v4root.c b/utils/mountd/v4root.c +new file mode 100644 +index 0000000..8de2ab6 +--- /dev/null ++++ b/utils/mountd/v4root.c +@@ -0,0 +1,420 @@ ++/* ++ * Copyright (C) 2009 Red Hat ++ * ++ * support/export/v4root.c ++ * ++ * Routines used to support NFSv4 pseudo roots ++ * ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#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); ++static int v4root_support(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; ++} ++/* ++ * Make sure the kernel has pseudo root support. ++ */ ++static int ++v4root_support() ++{ ++ static int kernel_support = -1; ++ char *ptr, version[64]; ++ int major, minor; ++ FILE *fp; ++ ++ if (kernel_support != -1) ++ return kernel_support; ++ ++ kernel_support = 0; ++ fp = fopen("/proc/fs/nfsd/exports", "r"); ++ if (fp == NULL) ++ goto out; ++ ++ ptr = fgets(version, 64, fp); ++ fclose(fp); ++ if (ptr == NULL) ++ goto out; ++ ++ while(*ptr && isdigit(*ptr) == 0) ++ ptr++; ++ if (*ptr == '\0') ++ goto out; ++ ++ major = minor = 0; ++ sscanf(ptr, " %d.%d",&major, &minor); ++ if (major >= 1 && minor >= 2) ++ kernel_support = 1; ++out: ++ if (!kernel_support) { ++ xlog(L_WARNING, "Kernel does not have pseudo root support."); ++ xlog(L_WARNING, "NFS v4 mounts will be disabled unless fsid=0"); ++ xlog(L_WARNING, "is specfied in /etc/exports file."); ++ } ++ ++ return kernel_support; ++} ++/* ++ * 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; ++ ++ if (!v4root_support()) ++ 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); ++ } ++} diff --git a/nfs-utils.spec b/nfs-utils.spec index ab1935f..db50685 100644 --- a/nfs-utils.spec +++ b/nfs-utils.spec @@ -2,7 +2,7 @@ Summary: NFS utilities and supporting clients and daemons for the kernel NFS ser Name: nfs-utils URL: http://sourceforge.net/projects/nfs Version: 1.2.0 -Release: 11%{?dist} +Release: 12%{?dist} Epoch: 1 # group all 32bit related archs @@ -28,7 +28,7 @@ Patch102: nfs-utils-1.2.1-rc3.patch Patch103: nfs-utils-1.2.1-rc4.patch Patch104: nfs-utils-1.2.1-rc5.patch -Patch200: nfs-utils-1.2.0-proots-rel5.patch +Patch200: nfs-utils-1.2.0-v4root-rel6.patch Group: System Environment/Daemons Provides: exportfs = %{epoch}:%{version}-%{release} @@ -258,6 +258,9 @@ fi %attr(4755,root,root) /sbin/umount.nfs4 %changelog +* Wed Sep 23 2009 Steve Dickson 1.2.0-12 +- Updated to the latest pseudo root release (rel6). + * Tue Sep 15 2009 Steve Dickson 1.2.0-11 - Added upstream 1.2.1-rc5 patch - Added --sort --list functionality to nfs-iostat.py