diff --git a/nfs-utils-1.2.0-spnfsd-01.patch b/nfs-utils-1.2.0-spnfsd-01.patch new file mode 100644 index 0000000..5026a2a --- /dev/null +++ b/nfs-utils-1.2.0-spnfsd-01.patch @@ -0,0 +1,2979 @@ +diff -up nfs-utils-1.2.0/support/include/nfs/nfs.h.orig nfs-utils-1.2.0/support/include/nfs/nfs.h +--- nfs-utils-1.2.0/support/include/nfs/nfs.h.orig 2009-08-27 14:20:07.284736000 -0400 ++++ nfs-utils-1.2.0/support/include/nfs/nfs.h 2009-08-27 14:21:30.937192000 -0400 +@@ -41,6 +41,7 @@ struct nfs_fh_old { + #define NFSCTL_GETFH 6 /* get an fh (used by mountd) */ + #define NFSCTL_GETFD 7 /* get an fh by path (used by mountd) */ + #define NFSCTL_GETFS 8 /* get an fh by path with max size (used by mountd) */ ++#define NFSCTL_FD2FH 9 /* get a fh from a fd */ + + #define NFSCTL_UDPBIT (1 << (17 - 1)) + #define NFSCTL_TCPBIT (1 << (18 - 1)) +@@ -130,6 +131,11 @@ struct nfsctl_fsparm { + int gd_maxlen; + }; + ++/* FD2FH */ ++struct nfsctl_fd2fh { ++ int fd; ++}; ++ + /* + * This is the argument union. + */ +@@ -143,6 +149,7 @@ struct nfsctl_arg { + struct nfsctl_fhparm u_getfh; + struct nfsctl_fdparm u_getfd; + struct nfsctl_fsparm u_getfs; ++ struct nfsctl_fd2fh u_fd2fh; + } u; + #define ca_svc u.u_svc + #define ca_client u.u_client +@@ -151,6 +158,7 @@ struct nfsctl_arg { + #define ca_getfh u.u_getfh + #define ca_getfd u.u_getfd + #define ca_getfs u.u_getfs ++#define ca_fd2fh u.u_fd2fh + #define ca_authd u.u_authd + }; + +diff -up nfs-utils-1.2.0/utils/Makefile.am.orig nfs-utils-1.2.0/utils/Makefile.am +--- nfs-utils-1.2.0/utils/Makefile.am.orig 2009-06-02 10:43:05.000000000 -0400 ++++ nfs-utils-1.2.0/utils/Makefile.am 2009-08-27 14:21:30.941191000 -0400 +@@ -6,6 +6,10 @@ if CONFIG_NFSV4 + OPTDIRS += idmapd + endif + ++if CONFIG_NFSV4 ++OPTDIRS += spnfsd ++endif ++ + if CONFIG_GSS + OPTDIRS += gssd + endif +diff -up /dev/null nfs-utils-1.2.0/utils/spnfsd/atomicio.c +--- /dev/null 2009-08-25 05:54:53.623006579 -0400 ++++ nfs-utils-1.2.0/utils/spnfsd/atomicio.c 2009-08-27 14:21:30.944196000 -0400 +@@ -0,0 +1,63 @@ ++/* ++ * Copyright (c) 2002 Marius Aamodt Eriksen ++ * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include ++#include ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif /* HAVE_CONFIG_H */ ++ ++/* ++ * ensure all of data on socket comes through. f==read || f==write ++ */ ++ssize_t ++atomicio(f, fd, _s, n) ++ ssize_t (*f) (); ++ int fd; ++ void *_s; ++ size_t n; ++{ ++ char *s = _s; ++ ssize_t res, pos = 0; ++ ++ while (n > pos) { ++ res = (f) (fd, s + pos, n - pos); ++ switch (res) { ++ case -1: ++ if (errno == EINTR || errno == EAGAIN) ++ continue; ++ case 0: ++ if (pos != 0) ++ return (pos); ++ return (res); ++ default: ++ pos += res; ++ } ++ } ++ return (pos); ++} +diff -up /dev/null nfs-utils-1.2.0/utils/spnfsd/cfg.c +--- /dev/null 2009-08-25 05:54:53.623006579 -0400 ++++ nfs-utils-1.2.0/utils/spnfsd/cfg.c 2009-08-27 14:21:30.950191000 -0400 +@@ -0,0 +1,893 @@ ++/* $OpenBSD: conf.c,v 1.55 2003/06/03 14:28:16 ho Exp $ */ ++/* $EOM: conf.c,v 1.48 2000/12/04 02:04:29 angelos Exp $ */ ++ ++/* ++ * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. ++ * Copyright (c) 2000, 2001, 2002 H�kan Olsson. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* ++ * This code was written under funding by Ericsson Radio Systems. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cfg.h" ++ ++static void conf_load_defaults (int); ++#if 0 ++static int conf_find_trans_xf (int, char *); ++#endif ++ ++size_t strlcpy(char *, const char *, size_t); ++ ++struct conf_trans { ++ TAILQ_ENTRY (conf_trans) link; ++ int trans; ++ enum conf_op { CONF_SET, CONF_REMOVE, CONF_REMOVE_SECTION } op; ++ char *section; ++ char *tag; ++ char *value; ++ int override; ++ int is_default; ++}; ++ ++TAILQ_HEAD (conf_trans_head, conf_trans) conf_trans_queue; ++ ++/* ++ * Radix-64 Encoding. ++ */ ++const u_int8_t bin2asc[] ++ = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; ++ ++const u_int8_t asc2bin[] = ++{ ++ 255, 255, 255, 255, 255, 255, 255, 255, ++ 255, 255, 255, 255, 255, 255, 255, 255, ++ 255, 255, 255, 255, 255, 255, 255, 255, ++ 255, 255, 255, 255, 255, 255, 255, 255, ++ 255, 255, 255, 255, 255, 255, 255, 255, ++ 255, 255, 255, 62, 255, 255, 255, 63, ++ 52, 53, 54, 55, 56, 57, 58, 59, ++ 60, 61, 255, 255, 255, 255, 255, 255, ++ 255, 0, 1, 2, 3, 4, 5, 6, ++ 7, 8, 9, 10, 11, 12, 13, 14, ++ 15, 16, 17, 18, 19, 20, 21, 22, ++ 23, 24, 25, 255, 255, 255, 255, 255, ++ 255, 26, 27, 28, 29, 30, 31, 32, ++ 33, 34, 35, 36, 37, 38, 39, 40, ++ 41, 42, 43, 44, 45, 46, 47, 48, ++ 49, 50, 51, 255, 255, 255, 255, 255 ++}; ++ ++struct conf_binding { ++ LIST_ENTRY (conf_binding) link; ++ char *section; ++ char *tag; ++ char *value; ++ int is_default; ++}; ++ ++char *conf_path; ++LIST_HEAD (conf_bindings, conf_binding) conf_bindings[256]; ++ ++static char *conf_addr; ++ ++static __inline__ u_int8_t ++conf_hash (char *s) ++{ ++ u_int8_t hash = 0; ++ ++ while (*s) ++ { ++ hash = ((hash << 1) | (hash >> 7)) ^ tolower (*s); ++ s++; ++ } ++ return hash; ++} ++ ++/* ++ * Insert a tag-value combination from LINE (the equal sign is at POS) ++ */ ++static int ++conf_remove_now (char *section, char *tag) ++{ ++ struct conf_binding *cb, *next; ++ ++ for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb; cb = next) ++ { ++ next = LIST_NEXT (cb, link); ++ if (strcasecmp (cb->section, section) == 0 ++ && strcasecmp (cb->tag, tag) == 0) ++ { ++ LIST_REMOVE (cb, link); ++ warnx("[%s]:%s->%s removed", section, tag, cb->value); ++ free (cb->section); ++ free (cb->tag); ++ free (cb->value); ++ free (cb); ++ return 0; ++ } ++ } ++ return 1; ++} ++ ++static int ++conf_remove_section_now (char *section) ++{ ++ struct conf_binding *cb, *next; ++ int unseen = 1; ++ ++ for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb; cb = next) ++ { ++ next = LIST_NEXT (cb, link); ++ if (strcasecmp (cb->section, section) == 0) ++ { ++ unseen = 0; ++ LIST_REMOVE (cb, link); ++ warnx("[%s]:%s->%s removed", section, cb->tag, cb->value); ++ free (cb->section); ++ free (cb->tag); ++ free (cb->value); ++ free (cb); ++ } ++ } ++ return unseen; ++} ++ ++/* ++ * Insert a tag-value combination from LINE (the equal sign is at POS) ++ * into SECTION of our configuration database. ++ */ ++static int ++conf_set_now (char *section, char *tag, char *value, int override, ++ int is_default) ++{ ++ struct conf_binding *node = 0; ++ ++ if (override) ++ conf_remove_now (section, tag); ++ else if (conf_get_str (section, tag)) ++ { ++ if (!is_default) ++ warnx("conf_set: duplicate tag [%s]:%s, ignoring...\n", section, tag); ++ return 1; ++ } ++ ++ node = calloc (1, sizeof *node); ++ if (!node) ++ { ++ warnx("conf_set: calloc (1, %lu) failed", (unsigned long)sizeof *node); ++ return 1; ++ } ++ node->section = strdup (section); ++ node->tag = strdup (tag); ++ node->value = strdup (value); ++ node->is_default = is_default; ++ ++ LIST_INSERT_HEAD (&conf_bindings[conf_hash (section)], node, link); ++ return 0; ++} ++ ++/* ++ * Parse the line LINE of SZ bytes. Skip Comments, recognize section ++ * headers and feed tag-value pairs into our configuration database. ++ */ ++static void ++conf_parse_line (int trans, char *line, size_t sz) ++{ ++ char *val; ++ size_t i; ++ int j; ++ static char *section = 0; ++ static int ln = 0; ++ ++ ln++; ++ ++ /* Lines starting with '#' or ';' are comments. */ ++ if (*line == '#' || *line == ';') ++ return; ++ ++ /* '[section]' parsing... */ ++ if (*line == '[') ++ { ++ for (i = 1; i < sz; i++) ++ if (line[i] == ']') ++ break; ++ if (section) ++ free (section); ++ if (i == sz) ++ { ++ warnx("conf_parse_line: %d:" ++ "non-matched ']', ignoring until next section", ln); ++ section = 0; ++ return; ++ } ++ section = malloc (i); ++ if (!section) ++ { ++ warnx("conf_parse_line: %d: malloc (%lu) failed", ln, ++ (unsigned long)i); ++ return; ++ } ++ strlcpy (section, line + 1, i); ++ return; ++ } ++ ++ /* Deal with assignments. */ ++ for (i = 0; i < sz; i++) ++ if (line[i] == '=') ++ { ++ /* If no section, we are ignoring the lines. */ ++ if (!section) ++ { ++ warnx("conf_parse_line: %d: ignoring line due to no section", ln); ++ return; ++ } ++ line[strcspn (line, " \t=")] = '\0'; ++ val = line + i + 1 + strspn (line + i + 1, " \t"); ++ /* Skip trailing whitespace, if any */ ++ for (j = sz - (val - line) - 1; j > 0 && isspace (val[j]); j--) ++ val[j] = '\0'; ++ /* XXX Perhaps should we not ignore errors? */ ++ conf_set (trans, section, line, val, 0, 0); ++ return; ++ } ++ ++ /* Other non-empty lines are weird. */ ++ i = strspn (line, " \t"); ++ if (line[i]) ++ warnx("conf_parse_line: %d: syntax error", ln); ++ ++ return; ++} ++ ++/* Parse the mapped configuration file. */ ++static void ++conf_parse (int trans, char *buf, size_t sz) ++{ ++ char *cp = buf; ++ char *bufend = buf + sz; ++ char *line; ++ ++ line = cp; ++ while (cp < bufend) ++ { ++ if (*cp == '\n') ++ { ++ /* Check for escaped newlines. */ ++ if (cp > buf && *(cp - 1) == '\\') ++ *(cp - 1) = *cp = ' '; ++ else ++ { ++ *cp = '\0'; ++ conf_parse_line (trans, line, cp - line); ++ line = cp + 1; ++ } ++ } ++ cp++; ++ } ++ if (cp != line) ++ warnx("conf_parse: last line non-terminated, ignored."); ++} ++ ++static void ++conf_load_defaults (int tr) ++{ ++ /* No defaults */ ++ return; ++} ++ ++void ++conf_init (void) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) ++ LIST_INIT (&conf_bindings[i]); ++ TAILQ_INIT (&conf_trans_queue); ++ conf_reinit (); ++} ++ ++/* Open the config file and map it into our address space, then parse it. */ ++void ++conf_reinit (void) ++{ ++ struct conf_binding *cb = 0; ++ int fd, trans; ++ unsigned int i; ++ size_t sz; ++ char *new_conf_addr = 0; ++ struct stat sb; ++ ++ if ((stat (conf_path, &sb) == 0) || (errno != ENOENT)) ++ { ++ sz = sb.st_size; ++ fd = open (conf_path, O_RDONLY, 0); ++ if (fd == -1) ++ { ++ warnx("conf_reinit: open (\"%s\", O_RDONLY) failed", conf_path); ++ return; ++ } ++ ++ new_conf_addr = malloc (sz); ++ if (!new_conf_addr) ++ { ++ warnx("conf_reinit: malloc (%lu) failed", (unsigned long)sz); ++ goto fail; ++ } ++ ++ /* XXX I assume short reads won't happen here. */ ++ if (read (fd, new_conf_addr, sz) != (int)sz) ++ { ++ warnx("conf_reinit: read (%d, %p, %lu) failed", ++ fd, new_conf_addr, (unsigned long)sz); ++ goto fail; ++ } ++ close (fd); ++ ++ trans = conf_begin (); ++ ++ /* XXX Should we not care about errors and rollback? */ ++ conf_parse (trans, new_conf_addr, sz); ++ } ++ else ++ trans = conf_begin (); ++ ++ /* Load default configuration values. */ ++ conf_load_defaults (trans); ++ ++ /* Free potential existing configuration. */ ++ if (conf_addr) ++ { ++ for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) ++ for (cb = LIST_FIRST (&conf_bindings[i]); cb; ++ cb = LIST_FIRST (&conf_bindings[i])) ++ conf_remove_now (cb->section, cb->tag); ++ free (conf_addr); ++ } ++ ++ conf_end (trans, 1); ++ conf_addr = new_conf_addr; ++ return; ++ ++ fail: ++ if (new_conf_addr) ++ free (new_conf_addr); ++ close (fd); ++} ++ ++/* ++ * Return the numeric value denoted by TAG in section SECTION or DEF ++ * if that tag does not exist. ++ */ ++int ++conf_get_num (char *section, char *tag, int def) ++{ ++ char *value = conf_get_str (section, tag); ++ ++ if (value) ++ return atoi (value); ++ return def; ++} ++ ++/* Validate X according to the range denoted by TAG in section SECTION. */ ++int ++conf_match_num (char *section, char *tag, int x) ++{ ++ char *value = conf_get_str (section, tag); ++ int val, min, max, n; ++ ++ if (!value) ++ return 0; ++ n = sscanf (value, "%d,%d:%d", &val, &min, &max); ++ switch (n) ++ { ++ case 1: ++ warnx("conf_match_num: %s:%s %d==%d?", section, tag, val, x); ++ return x == val; ++ case 3: ++ warnx("conf_match_num: %s:%s %d<=%d<=%d?", section, tag, min, x, max); ++ return min <= x && max >= x; ++ default: ++ warnx("conf_match_num: section %s tag %s: invalid number spec %s", ++ section, tag, value); ++ } ++ return 0; ++} ++ ++/* Return the string value denoted by TAG in section SECTION. */ ++char * ++conf_get_str (char *section, char *tag) ++{ ++ struct conf_binding *cb; ++ ++ for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb; ++ cb = LIST_NEXT (cb, link)) ++ if (strcasecmp (section, cb->section) == 0 ++ && strcasecmp (tag, cb->tag) == 0) ++ { ++ return cb->value; ++ } ++ return 0; ++} ++ ++/* ++ * Build a list of string values out of the comma separated value denoted by ++ * TAG in SECTION. ++ */ ++struct conf_list * ++conf_get_list (char *section, char *tag) ++{ ++ char *liststr = 0, *p, *field, *t; ++ struct conf_list *list = 0; ++ struct conf_list_node *node; ++ ++ list = malloc (sizeof *list); ++ if (!list) ++ goto cleanup; ++ TAILQ_INIT (&list->fields); ++ list->cnt = 0; ++ liststr = conf_get_str (section, tag); ++ if (!liststr) ++ goto cleanup; ++ liststr = strdup (liststr); ++ if (!liststr) ++ goto cleanup; ++ p = liststr; ++ while ((field = strsep (&p, ",")) != NULL) ++ { ++ /* Skip leading whitespace */ ++ while (isspace (*field)) ++ field++; ++ /* Skip trailing whitespace */ ++ if (p) ++ for (t = p - 1; t > field && isspace (*t); t--) ++ *t = '\0'; ++ if (*field == '\0') ++ { ++ warnx("conf_get_list: empty field, ignoring..."); ++ continue; ++ } ++ list->cnt++; ++ node = calloc (1, sizeof *node); ++ if (!node) ++ goto cleanup; ++ node->field = strdup (field); ++ if (!node->field) { ++ free(node); ++ goto cleanup; ++ } ++ TAILQ_INSERT_TAIL (&list->fields, node, link); ++ } ++ free (liststr); ++ return list; ++ ++ cleanup: ++ if (list) ++ conf_free_list (list); ++ if (liststr) ++ free (liststr); ++ return 0; ++} ++ ++struct conf_list * ++conf_get_tag_list (char *section) ++{ ++ struct conf_list *list = 0; ++ struct conf_list_node *node; ++ struct conf_binding *cb; ++ ++ list = malloc (sizeof *list); ++ if (!list) ++ goto cleanup; ++ TAILQ_INIT (&list->fields); ++ list->cnt = 0; ++ for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb; ++ cb = LIST_NEXT (cb, link)) ++ if (strcasecmp (section, cb->section) == 0) ++ { ++ list->cnt++; ++ node = calloc (1, sizeof *node); ++ if (!node) ++ goto cleanup; ++ node->field = strdup (cb->tag); ++ if (!node->field) { ++ free(node); ++ goto cleanup; ++ } ++ TAILQ_INSERT_TAIL (&list->fields, node, link); ++ } ++ return list; ++ ++ cleanup: ++ if (list) ++ conf_free_list (list); ++ return 0; ++} ++ ++/* Decode a PEM encoded buffer. */ ++int ++conf_decode_base64 (u_int8_t *out, u_int32_t *len, u_char *buf) ++{ ++ u_int32_t c = 0; ++ u_int8_t c1, c2, c3, c4; ++ ++ while (*buf) ++ { ++ if (*buf > 127 || (c1 = asc2bin[*buf]) == 255) ++ return 0; ++ buf++; ++ ++ if (*buf > 127 || (c2 = asc2bin[*buf]) == 255) ++ return 0; ++ buf++; ++ ++ if (*buf == '=') ++ { ++ c3 = c4 = 0; ++ c++; ++ ++ /* Check last four bit */ ++ if (c2 & 0xF) ++ return 0; ++ ++ if (strcmp ((char *)buf, "==") == 0) ++ buf++; ++ else ++ return 0; ++ } ++ else if (*buf > 127 || (c3 = asc2bin[*buf]) == 255) ++ return 0; ++ else ++ { ++ if (*++buf == '=') ++ { ++ c4 = 0; ++ c += 2; ++ ++ /* Check last two bit */ ++ if (c3 & 3) ++ return 0; ++ ++ if (strcmp ((char *)buf, "=")) ++ return 0; ++ ++ } ++ else if (*buf > 127 || (c4 = asc2bin[*buf]) == 255) ++ return 0; ++ else ++ c += 3; ++ } ++ ++ buf++; ++ *out++ = (c1 << 2) | (c2 >> 4); ++ *out++ = (c2 << 4) | (c3 >> 2); ++ *out++ = (c3 << 6) | c4; ++ } ++ ++ *len = c; ++ return 1; ++ ++} ++ ++void ++conf_free_list (struct conf_list *list) ++{ ++ struct conf_list_node *node = TAILQ_FIRST (&list->fields); ++ ++ while (node) ++ { ++ TAILQ_REMOVE (&list->fields, node, link); ++ if (node->field) ++ free (node->field); ++ free (node); ++ node = TAILQ_FIRST (&list->fields); ++ } ++ free (list); ++} ++ ++int ++conf_begin (void) ++{ ++ static int seq = 0; ++ ++ return ++seq; ++} ++ ++static struct conf_trans * ++conf_trans_node (int transaction, enum conf_op op) ++{ ++ struct conf_trans *node; ++ ++ node = calloc (1, sizeof *node); ++ if (!node) ++ { ++ warnx("conf_trans_node: calloc (1, %lu) failed", ++ (unsigned long)sizeof *node); ++ return 0; ++ } ++ node->trans = transaction; ++ node->op = op; ++ TAILQ_INSERT_TAIL (&conf_trans_queue, node, link); ++ return node; ++} ++ ++/* Queue a set operation. */ ++int ++conf_set (int transaction, char *section, char *tag, char *value, int override, ++ int is_default) ++{ ++ struct conf_trans *node; ++ ++ node = conf_trans_node (transaction, CONF_SET); ++ if (!node) ++ return 1; ++ node->section = strdup (section); ++ if (!node->section) ++ { ++ warnx("conf_set: strdup (\"%s\") failed", section); ++ goto fail; ++ } ++ node->tag = strdup (tag); ++ if (!node->tag) ++ { ++ warnx("conf_set: strdup (\"%s\") failed", tag); ++ goto fail; ++ } ++ node->value = strdup (value); ++ if (!node->value) ++ { ++ warnx("conf_set: strdup (\"%s\") failed", value); ++ goto fail; ++ } ++ node->override = override; ++ node->is_default = is_default; ++ return 0; ++ ++ fail: ++ if (node->tag) ++ free (node->tag); ++ if (node->section) ++ free (node->section); ++ if (node) ++ free (node); ++ return 1; ++} ++ ++/* Queue a remove operation. */ ++int ++conf_remove (int transaction, char *section, char *tag) ++{ ++ struct conf_trans *node; ++ ++ node = conf_trans_node (transaction, CONF_REMOVE); ++ if (!node) ++ goto fail; ++ node->section = strdup (section); ++ if (!node->section) ++ { ++ warnx("conf_remove: strdup (\"%s\") failed", section); ++ goto fail; ++ } ++ node->tag = strdup (tag); ++ if (!node->tag) ++ { ++ warnx("conf_remove: strdup (\"%s\") failed", tag); ++ goto fail; ++ } ++ return 0; ++ ++ fail: ++ if (node && node->section) ++ free (node->section); ++ if (node) ++ free (node); ++ return 1; ++} ++ ++/* Queue a remove section operation. */ ++int ++conf_remove_section (int transaction, char *section) ++{ ++ struct conf_trans *node; ++ ++ node = conf_trans_node (transaction, CONF_REMOVE_SECTION); ++ if (!node) ++ goto fail; ++ node->section = strdup (section); ++ if (!node->section) ++ { ++ warnx("conf_remove_section: strdup (\"%s\") failed", section); ++ goto fail; ++ } ++ return 0; ++ ++ fail: ++ if (node) ++ free (node); ++ return 1; ++} ++ ++/* Execute all queued operations for this transaction. Cleanup. */ ++int ++conf_end (int transaction, int commit) ++{ ++ struct conf_trans *node, *next; ++ ++ for (node = TAILQ_FIRST (&conf_trans_queue); node; node = next) ++ { ++ next = TAILQ_NEXT (node, link); ++ if (node->trans == transaction) ++ { ++ if (commit) ++ switch (node->op) ++ { ++ case CONF_SET: ++ conf_set_now (node->section, node->tag, node->value, ++ node->override, node->is_default); ++ break; ++ case CONF_REMOVE: ++ conf_remove_now (node->section, node->tag); ++ break; ++ case CONF_REMOVE_SECTION: ++ conf_remove_section_now (node->section); ++ break; ++ default: ++ warnx("conf_end: unknown operation: %d", node->op); ++ } ++ TAILQ_REMOVE (&conf_trans_queue, node, link); ++ if (node->section) ++ free (node->section); ++ if (node->tag) ++ free (node->tag); ++ if (node->value) ++ free (node->value); ++ free (node); ++ } ++ } ++ return 0; ++} ++ ++/* ++ * Dump running configuration upon SIGUSR1. ++ * Configuration is "stored in reverse order", so reverse it again. ++ */ ++struct dumper { ++ char *s, *v; ++ struct dumper *next; ++}; ++ ++static void ++conf_report_dump (struct dumper *node) ++{ ++ /* Recursive, cleanup when we're done. */ ++ ++ if (node->next) ++ conf_report_dump (node->next); ++ ++ if (node->v) ++ warnx("%s=\t%s", node->s, node->v); ++ else if (node->s) ++ { ++ warnx("%s", node->s); ++ if (strlen (node->s) > 0) ++ free (node->s); ++ } ++ ++ free (node); ++} ++ ++void ++conf_report (void) ++{ ++ struct conf_binding *cb, *last = 0; ++ unsigned int i, len; ++ char *current_section = (char *)0; ++ struct dumper *dumper, *dnode; ++ ++ dumper = dnode = (struct dumper *)calloc (1, sizeof *dumper); ++ if (!dumper) ++ goto mem_fail; ++ ++ warnx("conf_report: dumping running configuration"); ++ ++ for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) ++ for (cb = LIST_FIRST (&conf_bindings[i]); cb; ++ cb = LIST_NEXT (cb, link)) ++ { ++ if (!cb->is_default) ++ { ++ /* Dump this entry. */ ++ if (!current_section || strcmp (cb->section, current_section)) ++ { ++ if (current_section) ++ { ++ len = strlen (current_section) + 3; ++ dnode->s = malloc (len); ++ if (!dnode->s) ++ goto mem_fail; ++ ++ snprintf (dnode->s, len, "[%s]", current_section); ++ dnode->next ++ = (struct dumper *)calloc (1, sizeof (struct dumper)); ++ dnode = dnode->next; ++ if (!dnode) ++ goto mem_fail; ++ ++ dnode->s = ""; ++ dnode->next ++ = (struct dumper *)calloc (1, sizeof (struct dumper)); ++ dnode = dnode->next; ++ if (!dnode) ++ goto mem_fail; ++ } ++ current_section = cb->section; ++ } ++ dnode->s = cb->tag; ++ dnode->v = cb->value; ++ dnode->next = (struct dumper *)calloc (1, sizeof (struct dumper)); ++ dnode = dnode->next; ++ if (!dnode) ++ goto mem_fail; ++ last = cb; ++ } ++ } ++ ++ if (last) ++ { ++ len = strlen (last->section) + 3; ++ dnode->s = malloc (len); ++ if (!dnode->s) ++ goto mem_fail; ++ snprintf (dnode->s, len, "[%s]", last->section); ++ } ++ ++ conf_report_dump (dumper); ++ ++ return; ++ ++ mem_fail: ++ warnx("conf_report: malloc/calloc failed"); ++ while ((dnode = dumper) != 0) ++ { ++ dumper = dumper->next; ++ if (dnode->s) ++ free (dnode->s); ++ free (dnode); ++ } ++ return; ++} +diff -up /dev/null nfs-utils-1.2.0/utils/spnfsd/cfg.h +--- /dev/null 2009-08-25 05:54:53.623006579 -0400 ++++ nfs-utils-1.2.0/utils/spnfsd/cfg.h 2009-08-27 14:21:30.954191000 -0400 +@@ -0,0 +1,67 @@ ++/* $OpenBSD: conf.h,v 1.30 2004/06/25 20:25:34 hshoexer Exp $ */ ++/* $EOM: conf.h,v 1.13 2000/09/18 00:01:47 ho Exp $ */ ++ ++/* ++ * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved. ++ * Copyright (c) 2000, 2003 H�kan Olsson. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* ++ * This code was written under funding by Ericsson Radio Systems. ++ */ ++ ++#ifndef _CONF_H_ ++#define _CONF_H_ ++ ++#include "queue.h" ++ ++struct conf_list_node { ++ TAILQ_ENTRY(conf_list_node) link; ++ char *field; ++}; ++ ++struct conf_list { ++ size_t cnt; ++ TAILQ_HEAD(conf_list_fields_head, conf_list_node) fields; ++}; ++ ++extern char *conf_path; ++ ++extern int conf_begin(void); ++extern int conf_decode_base64(u_int8_t *, u_int32_t *, u_char *); ++extern int conf_end(int, int); ++extern void conf_free_list(struct conf_list *); ++extern struct sockaddr *conf_get_address(char *, char *); ++extern struct conf_list *conf_get_list(char *, char *); ++extern struct conf_list *conf_get_tag_list(char *); ++extern int conf_get_num(char *, char *, int); ++extern char *conf_get_str(char *, char *); ++extern void conf_init(void); ++extern int conf_match_num(char *, char *, int); ++extern void conf_reinit(void); ++extern int conf_remove(int, char *, char *); ++extern int conf_remove_section(int, char *); ++extern int conf_set(int, char *, char *, char *, int, int); ++extern void conf_report(void); ++ ++#endif /* _CONF_H_ */ +diff -up /dev/null nfs-utils-1.2.0/utils/spnfsd/Makefile.am +--- /dev/null 2009-08-25 05:54:53.623006579 -0400 ++++ nfs-utils-1.2.0/utils/spnfsd/Makefile.am 2009-08-27 14:21:30.958191000 -0400 +@@ -0,0 +1,71 @@ ++## Process this file with automake to produce Makefile.in ++ ++man5_MANS = spnfsd.conf.man ++man8_MANS = spnfsd.man ++ ++RPCPREFIX = ++KPREFIX = @kprefix@ ++sbin_PROGRAMS = spnfsd ++ ++EXTRA_DIST = \ ++ $(man5_MANS) \ ++ $(man8_MANS) \ ++ spnfsd.conf ++ ++spnfsd_SOURCES = \ ++ atomicio.c \ ++ spnfsd_ops.c \ ++ cfg.c \ ++ spnfsd.c \ ++ strlcat.c \ ++ strlcpy.c \ ++ \ ++ cfg.h \ ++ spnfsd.h \ ++ spnfsd_queue.h \ ++ queue.h ++ ++spnfsd_LDADD = -levent ../../support/nfs/libnfs.a ++ ++MAINTAINERCLEANFILES = Makefile.in ++ ++####################################################################### ++# The following allows the current practice of having ++# daemons renamed during the install to include RPCPREFIX ++# and the KPREFIX ++# This could all be done much easier with program_transform_name ++# ( program_transform_name = s/^/$(RPCPREFIX)$(KPREFIX)/ ) ++# but that also renames the man pages, which the current ++# practice does not do. ++install-exec-hook: ++ (cd $(DESTDIR)$(sbindir) && \ ++ for p in $(sbin_PROGRAMS); do \ ++ mv -f $$p$(EXEEXT) $(RPCPREFIX)$(KPREFIX)$$p$(EXEEXT) ;\ ++ done) ++uninstall-hook: ++ (cd $(DESTDIR)$(sbindir) && \ ++ for p in $(sbin_PROGRAMS); do \ ++ rm -f $(RPCPREFIX)$(KPREFIX)$$p$(EXEEXT) ;\ ++ done) ++ ++ ++# XXX This makes some assumptions about what automake does. ++# XXX But there is no install-man-hook or install-man-local. ++install-man: install-man5 install-man8 install-man-links ++uninstall-man: uninstall-man5 uninstall-man8 uninstall-man-links ++ ++install-man-links: ++ (cd $(DESTDIR)$(man8dir) && \ ++ for m in $(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS); do \ ++ inst=`echo $$m | sed -e 's/man$$/8/'`; \ ++ rm -f $(RPCPREFIX)$$inst ; \ ++ $(LN_S) $$inst $(RPCPREFIX)$$inst ; \ ++ done) ++ ++uninstall-man-links: ++ (cd $(DESTDIR)$(man8dir) && \ ++ for m in $(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS); do \ ++ inst=`echo $$m | sed -e 's/man$$/8/'`; \ ++ rm -f $(RPCPREFIX)$$inst ; \ ++ done) ++ +diff -up /dev/null nfs-utils-1.2.0/utils/spnfsd/makestatic +--- /dev/null 2009-08-25 05:54:53.623006579 -0400 ++++ nfs-utils-1.2.0/utils/spnfsd/makestatic 2009-08-27 14:21:30.962191000 -0400 +@@ -0,0 +1 @@ ++gcc -static -Wall -pipe -g -O2 -o spnfsd atomicio.o spnfsd_ops.o cfg.o spnfsd.o strlcat.o strlcpy.o /usr/lib/libevent.a ../../support/nfs/libnfs.a +diff -up /dev/null nfs-utils-1.2.0/utils/spnfsd/nfsd4_spnfs.h +--- /dev/null 2009-08-25 05:54:53.623006579 -0400 ++++ nfs-utils-1.2.0/utils/spnfsd/nfsd4_spnfs.h 2009-08-27 14:21:30.966191000 -0400 +@@ -0,0 +1,234 @@ ++/* ++ * include/linux/nfsd4_spnfs.h ++ * ++ * spNFS - simple pNFS implementation with userspace daemon ++ * ++ */ ++ ++ ++#ifndef NFS_SPNFS_H ++#define NFS_SPNFS_H ++ ++ ++#ifdef __KERNEL__ ++#include "sunrpc/svc.h" ++#include "nfsd/nfsfh.h" ++#else ++#include ++#endif /* __KERNEL__ */ ++ ++#define SPNFS_STATUS_INVALIDMSG 0x01 ++#define SPNFS_STATUS_AGAIN 0x02 ++#define SPNFS_STATUS_FAIL 0x04 ++#define SPNFS_STATUS_SUCCESS 0x08 ++ ++#define SPNFS_TYPE_LAYOUTGET 0x01 ++#define SPNFS_TYPE_LAYOUTCOMMIT 0x02 ++#define SPNFS_TYPE_LAYOUTRETURN 0x03 ++#define SPNFS_TYPE_GETDEVICELIST 0x04 ++#define SPNFS_TYPE_GETDEVICEINFO 0x05 ++#define SPNFS_TYPE_SETATTR 0x06 ++#define SPNFS_TYPE_OPEN 0x07 ++#define SPNFS_TYPE_CLOSE 0x08 ++#define SPNFS_TYPE_CREATE 0x09 ++#define SPNFS_TYPE_REMOVE 0x0a ++#define SPNFS_TYPE_COMMIT 0x0b ++ ++#define SPNFS_MAX_DATA_SERVERS 2 ++#define SPNFS_MAX_LAYOUT 8 ++ ++/* layout */ ++struct spnfs_msg_layoutget_args { ++ unsigned long inode; ++}; ++ ++struct spnfs_filelayout_list { ++ u_int32_t dev_id; ++ u_int32_t dev_index; ++ u_int32_t fh_len; ++ unsigned char fh_val[128]; /* DMXXX fix this const */ ++}; ++ ++struct spnfs_msg_layoutget_res { ++ int status; ++ u_int64_t stripe_size; ++ u_int32_t stripe_type; ++ u_int32_t layout_count; ++ struct spnfs_filelayout_list flist[SPNFS_MAX_LAYOUT]; ++}; ++ ++/* layoutcommit */ ++struct spnfs_msg_layoutcommit_args { ++ unsigned long inode; ++ u_int64_t file_size; ++}; ++ ++struct spnfs_msg_layoutcommit_res { ++ int status; ++}; ++ ++/* layoutreturn */ ++/* No op for the daemon */ ++/* ++struct spnfs_msg_layoutreturn_args { ++}; ++ ++struct spnfs_msg_layoutreturn_res { ++}; ++*/ ++ ++/* getdevicelist */ ++struct spnfs_msg_getdevicelist_args { ++ unsigned long inode; ++}; ++ ++struct spnfs_getdevicelist_dev { ++ u_int32_t devid; ++ char netid[5]; ++ char addr[29]; ++}; ++ ++struct spnfs_msg_getdevicelist_res { ++ int status; ++ int count; ++ struct spnfs_getdevicelist_dev dlist[SPNFS_MAX_DATA_SERVERS]; ++}; ++ ++/* getdeviceinfo */ ++struct spnfs_msg_getdeviceinfo_args { ++ u_int32_t devid; ++}; ++ ++struct spnfs_msg_getdeviceinfo_res { ++ int status; ++ struct spnfs_getdevicelist_dev dinfo; ++}; ++ ++/* setattr */ ++struct spnfs_msg_setattr_args { ++ unsigned long inode; ++ int file_size; ++}; ++ ++struct spnfs_msg_setattr_res { ++ int status; ++}; ++ ++/* open */ ++struct spnfs_msg_open_args { ++ unsigned long inode; ++ int create; ++ int createmode; ++ int truncate; ++}; ++ ++struct spnfs_msg_open_res { ++ int status; ++}; ++ ++/* close */ ++/* No op for daemon */ ++struct spnfs_msg_close_args { ++ int x; ++}; ++ ++struct spnfs_msg_close_res { ++ int y; ++}; ++ ++/* create */ ++/* ++struct spnfs_msg_create_args { ++ int x; ++}; ++ ++struct spnfs_msg_create_res { ++ int y; ++}; ++*/ ++ ++/* remove */ ++struct spnfs_msg_remove_args { ++ unsigned long inode; ++}; ++ ++struct spnfs_msg_remove_res { ++ int status; ++}; ++ ++/* commit */ ++/* ++struct spnfs_msg_commit_args { ++ int x; ++}; ++ ++struct spnfs_msg_commit_res { ++ int y; ++}; ++*/ ++ ++/* bundle args and responses */ ++union spnfs_msg_args { ++ struct spnfs_msg_layoutget_args layoutget_args; ++ struct spnfs_msg_layoutcommit_args layoutcommit_args; ++// struct spnfs_msg_layoutreturn_args layoutreturn_args; ++ struct spnfs_msg_getdevicelist_args getdevicelist_args; ++ struct spnfs_msg_getdeviceinfo_args getdeviceinfo_args; ++ struct spnfs_msg_setattr_args setattr_args; ++ struct spnfs_msg_open_args open_args; ++ struct spnfs_msg_close_args close_args; ++// struct spnfs_msg_create_args create_args; ++ struct spnfs_msg_remove_args remove_args; ++// struct spnfs_msg_commit_args commit_args; ++}; ++ ++union spnfs_msg_res { ++ struct spnfs_msg_layoutget_res layoutget_res; ++ struct spnfs_msg_layoutcommit_res layoutcommit_res; ++// struct spnfs_msg_layoutreturn_res layoutreturn_res; ++ struct spnfs_msg_getdevicelist_res getdevicelist_res; ++ struct spnfs_msg_getdeviceinfo_res getdeviceinfo_res; ++ struct spnfs_msg_setattr_res setattr_res; ++ struct spnfs_msg_open_res open_res; ++ struct spnfs_msg_close_res close_res; ++// struct spnfs_msg_create_res create_res; ++ struct spnfs_msg_remove_res remove_res; ++// struct spnfs_msg_commit_res commit_res; ++}; ++ ++/* a spnfs message, args and response */ ++struct spnfs_msg { ++ unsigned char im_type; ++ unsigned char im_status; ++ union spnfs_msg_args im_args; ++ union spnfs_msg_res im_res; ++}; ++ ++#ifdef __KERNEL__ ++ ++/* pipe mgmt structure. messages flow through here */ ++struct spnfs { ++ char spnfs_path[48]; /* path to pipe */ ++ struct dentry *spnfs_dentry; /* dentry for pipe */ ++ wait_queue_head_t spnfs_wq; ++ struct spnfs_msg spnfs_im; /* spnfs message */ ++ struct mutex spnfs_lock; /* Serializes upcalls */ ++ struct mutex spnfs_plock; ++}; ++ ++int spnfs_layout_type(void); ++int spnfs_layoutget(struct inode *, void *); ++int spnfs_layoutcomit(void); ++int spnfs_layoutreturn(void); ++int spnfs_getdevicelist(struct super_block *, void *); ++int spnfs_getdeviceinfo(void); ++int spnfs_setattr(void); ++int spnfs_open(struct inode *, void *); ++ ++int nfsd_spnfs_new(void); ++void nfsd_spnfs_delete(void); ++int spnfs_upcall(struct spnfs *, struct spnfs_msg *, union spnfs_msg_res *); ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* NFS_SPNFS_H */ +diff -up /dev/null nfs-utils-1.2.0/utils/spnfsd/queue.h +--- /dev/null 2009-08-25 05:54:53.623006579 -0400 ++++ nfs-utils-1.2.0/utils/spnfsd/queue.h 2009-08-27 14:21:30.971191000 -0400 +@@ -0,0 +1,499 @@ ++/* $OpenBSD: queue.h,v 1.22 2001/06/23 04:39:35 angelos Exp $ */ ++/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ ++ ++/* ++ * Copyright (c) 1991, 1993 ++ * The Regents of the University of California. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the University nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * @(#)queue.h 8.5 (Berkeley) 8/20/94 ++ */ ++ ++#ifndef _SYS_QUEUE_H_ ++#define _SYS_QUEUE_H_ ++ ++/* ++ * This file defines five types of data structures: singly-linked lists, ++ * lists, simple queues, tail queues, and circular queues. ++ * ++ * ++ * A singly-linked list is headed by a single forward pointer. The elements ++ * are singly linked for minimum space and pointer manipulation overhead at ++ * the expense of O(n) removal for arbitrary elements. New elements can be ++ * added to the list after an existing element or at the head of the list. ++ * Elements being removed from the head of the list should use the explicit ++ * macro for this purpose for optimum efficiency. A singly-linked list may ++ * only be traversed in the forward direction. Singly-linked lists are ideal ++ * for applications with large datasets and few or no removals or for ++ * implementing a LIFO queue. ++ * ++ * A list is headed by a single forward pointer (or an array of forward ++ * pointers for a hash table header). The elements are doubly linked ++ * so that an arbitrary element can be removed without a need to ++ * traverse the list. New elements can be added to the list before ++ * or after an existing element or at the head of the list. A list ++ * may only be traversed in the forward direction. ++ * ++ * A simple queue is headed by a pair of pointers, one the head of the ++ * list and the other to the tail of the list. The elements are singly ++ * linked to save space, so elements can only be removed from the ++ * head of the list. New elements can be added to the list before or after ++ * an existing element, at the head of the list, or at the end of the ++ * list. A simple queue may only be traversed in the forward direction. ++ * ++ * A tail queue is headed by a pair of pointers, one to the head of the ++ * list and the other to the tail of the list. The elements are doubly ++ * linked so that an arbitrary element can be removed without a need to ++ * traverse the list. New elements can be added to the list before or ++ * after an existing element, at the head of the list, or at the end of ++ * the list. A tail queue may be traversed in either direction. ++ * ++ * A circle queue is headed by a pair of pointers, one to the head of the ++ * list and the other to the tail of the list. The elements are doubly ++ * linked so that an arbitrary element can be removed without a need to ++ * traverse the list. New elements can be added to the list before or after ++ * an existing element, at the head of the list, or at the end of the list. ++ * A circle queue may be traversed in either direction, but has a more ++ * complex end of list detection. ++ * ++ * For details on the use of these macros, see the queue(3) manual page. ++ */ ++ ++/* ++ * Singly-linked List definitions. ++ */ ++#define SLIST_HEAD(name, type) \ ++struct name { \ ++ struct type *slh_first; /* first element */ \ ++} ++ ++#define SLIST_HEAD_INITIALIZER(head) \ ++ { NULL } ++ ++#define SLIST_ENTRY(type) \ ++struct { \ ++ struct type *sle_next; /* next element */ \ ++} ++ ++/* ++ * Singly-linked List access methods. ++ */ ++#define SLIST_FIRST(head) ((head)->slh_first) ++#define SLIST_END(head) NULL ++#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) ++#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) ++ ++#define SLIST_FOREACH(var, head, field) \ ++ for((var) = SLIST_FIRST(head); \ ++ (var) != SLIST_END(head); \ ++ (var) = SLIST_NEXT(var, field)) ++ ++/* ++ * Singly-linked List functions. ++ */ ++#define SLIST_INIT(head) { \ ++ SLIST_FIRST(head) = SLIST_END(head); \ ++} ++ ++#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ ++ (elm)->field.sle_next = (slistelm)->field.sle_next; \ ++ (slistelm)->field.sle_next = (elm); \ ++} while (0) ++ ++#define SLIST_INSERT_HEAD(head, elm, field) do { \ ++ (elm)->field.sle_next = (head)->slh_first; \ ++ (head)->slh_first = (elm); \ ++} while (0) ++ ++#define SLIST_REMOVE_HEAD(head, field) do { \ ++ (head)->slh_first = (head)->slh_first->field.sle_next; \ ++} while (0) ++ ++#define SLIST_REMOVE(head, elm, type, field) do { \ ++ if ((head)->slh_first == (elm)) { \ ++ SLIST_REMOVE_HEAD((head), field); \ ++ } \ ++ else { \ ++ struct type *curelm = (head)->slh_first; \ ++ while( curelm->field.sle_next != (elm) ) \ ++ curelm = curelm->field.sle_next; \ ++ curelm->field.sle_next = \ ++ curelm->field.sle_next->field.sle_next; \ ++ } \ ++} while (0) ++ ++/* ++ * List definitions. ++ */ ++#define LIST_HEAD(name, type) \ ++struct name { \ ++ struct type *lh_first; /* first element */ \ ++} ++ ++#define LIST_HEAD_INITIALIZER(head) \ ++ { NULL } ++ ++#define LIST_ENTRY(type) \ ++struct { \ ++ struct type *le_next; /* next element */ \ ++ struct type **le_prev; /* address of previous next element */ \ ++} ++ ++/* ++ * List access methods ++ */ ++#define LIST_FIRST(head) ((head)->lh_first) ++#define LIST_END(head) NULL ++#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) ++#define LIST_NEXT(elm, field) ((elm)->field.le_next) ++ ++#define LIST_FOREACH(var, head, field) \ ++ for((var) = LIST_FIRST(head); \ ++ (var)!= LIST_END(head); \ ++ (var) = LIST_NEXT(var, field)) ++ ++/* ++ * List functions. ++ */ ++#define LIST_INIT(head) do { \ ++ LIST_FIRST(head) = LIST_END(head); \ ++} while (0) ++ ++#define LIST_INSERT_AFTER(listelm, elm, field) do { \ ++ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ ++ (listelm)->field.le_next->field.le_prev = \ ++ &(elm)->field.le_next; \ ++ (listelm)->field.le_next = (elm); \ ++ (elm)->field.le_prev = &(listelm)->field.le_next; \ ++} while (0) ++ ++#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ ++ (elm)->field.le_prev = (listelm)->field.le_prev; \ ++ (elm)->field.le_next = (listelm); \ ++ *(listelm)->field.le_prev = (elm); \ ++ (listelm)->field.le_prev = &(elm)->field.le_next; \ ++} while (0) ++ ++#define LIST_INSERT_HEAD(head, elm, field) do { \ ++ if (((elm)->field.le_next = (head)->lh_first) != NULL) \ ++ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ ++ (head)->lh_first = (elm); \ ++ (elm)->field.le_prev = &(head)->lh_first; \ ++} while (0) ++ ++#define LIST_REMOVE(elm, field) do { \ ++ if ((elm)->field.le_next != NULL) \ ++ (elm)->field.le_next->field.le_prev = \ ++ (elm)->field.le_prev; \ ++ *(elm)->field.le_prev = (elm)->field.le_next; \ ++} while (0) ++ ++#define LIST_REPLACE(elm, elm2, field) do { \ ++ if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ ++ (elm2)->field.le_next->field.le_prev = \ ++ &(elm2)->field.le_next; \ ++ (elm2)->field.le_prev = (elm)->field.le_prev; \ ++ *(elm2)->field.le_prev = (elm2); \ ++} while (0) ++ ++/* ++ * Simple queue definitions. ++ */ ++#define SIMPLEQ_HEAD(name, type) \ ++struct name { \ ++ struct type *sqh_first; /* first element */ \ ++ struct type **sqh_last; /* addr of last next element */ \ ++} ++ ++#define SIMPLEQ_HEAD_INITIALIZER(head) \ ++ { NULL, &(head).sqh_first } ++ ++#define SIMPLEQ_ENTRY(type) \ ++struct { \ ++ struct type *sqe_next; /* next element */ \ ++} ++ ++/* ++ * Simple queue access methods. ++ */ ++#define SIMPLEQ_FIRST(head) ((head)->sqh_first) ++#define SIMPLEQ_END(head) NULL ++#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) ++#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) ++ ++#define SIMPLEQ_FOREACH(var, head, field) \ ++ for((var) = SIMPLEQ_FIRST(head); \ ++ (var) != SIMPLEQ_END(head); \ ++ (var) = SIMPLEQ_NEXT(var, field)) ++ ++/* ++ * Simple queue functions. ++ */ ++#define SIMPLEQ_INIT(head) do { \ ++ (head)->sqh_first = NULL; \ ++ (head)->sqh_last = &(head)->sqh_first; \ ++} while (0) ++ ++#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ ++ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ ++ (head)->sqh_last = &(elm)->field.sqe_next; \ ++ (head)->sqh_first = (elm); \ ++} while (0) ++ ++#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ ++ (elm)->field.sqe_next = NULL; \ ++ *(head)->sqh_last = (elm); \ ++ (head)->sqh_last = &(elm)->field.sqe_next; \ ++} while (0) ++ ++#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ ++ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ ++ (head)->sqh_last = &(elm)->field.sqe_next; \ ++ (listelm)->field.sqe_next = (elm); \ ++} while (0) ++ ++#define SIMPLEQ_REMOVE_HEAD(head, elm, field) do { \ ++ if (((head)->sqh_first = (elm)->field.sqe_next) == NULL) \ ++ (head)->sqh_last = &(head)->sqh_first; \ ++} while (0) ++ ++/* ++ * Tail queue definitions. ++ */ ++#define TAILQ_HEAD(name, type) \ ++struct name { \ ++ struct type *tqh_first; /* first element */ \ ++ struct type **tqh_last; /* addr of last next element */ \ ++} ++ ++#define TAILQ_HEAD_INITIALIZER(head) \ ++ { NULL, &(head).tqh_first } ++ ++#define TAILQ_ENTRY(type) \ ++struct { \ ++ struct type *tqe_next; /* next element */ \ ++ struct type **tqe_prev; /* address of previous next element */ \ ++} ++ ++/* ++ * tail queue access methods ++ */ ++#define TAILQ_FIRST(head) ((head)->tqh_first) ++#define TAILQ_END(head) NULL ++#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) ++#define TAILQ_LAST(head, headname) \ ++ (*(((struct headname *)((head)->tqh_last))->tqh_last)) ++/* XXX */ ++#define TAILQ_PREV(elm, headname, field) \ ++ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) ++#define TAILQ_EMPTY(head) \ ++ (TAILQ_FIRST(head) == TAILQ_END(head)) ++ ++#define TAILQ_FOREACH(var, head, field) \ ++ for((var) = TAILQ_FIRST(head); \ ++ (var) != TAILQ_END(head); \ ++ (var) = TAILQ_NEXT(var, field)) ++ ++#define TAILQ_FOREACH_REVERSE(var, head, field, headname) \ ++ for((var) = TAILQ_LAST(head, headname); \ ++ (var) != TAILQ_END(head); \ ++ (var) = TAILQ_PREV(var, headname, field)) ++ ++/* ++ * Tail queue functions. ++ */ ++#define TAILQ_INIT(head) do { \ ++ (head)->tqh_first = NULL; \ ++ (head)->tqh_last = &(head)->tqh_first; \ ++} while (0) ++ ++#define TAILQ_INSERT_HEAD(head, elm, field) do { \ ++ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ ++ (head)->tqh_first->field.tqe_prev = \ ++ &(elm)->field.tqe_next; \ ++ else \ ++ (head)->tqh_last = &(elm)->field.tqe_next; \ ++ (head)->tqh_first = (elm); \ ++ (elm)->field.tqe_prev = &(head)->tqh_first; \ ++} while (0) ++ ++#define TAILQ_INSERT_TAIL(head, elm, field) do { \ ++ (elm)->field.tqe_next = NULL; \ ++ (elm)->field.tqe_prev = (head)->tqh_last; \ ++ *(head)->tqh_last = (elm); \ ++ (head)->tqh_last = &(elm)->field.tqe_next; \ ++} while (0) ++ ++#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ ++ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ ++ (elm)->field.tqe_next->field.tqe_prev = \ ++ &(elm)->field.tqe_next; \ ++ else \ ++ (head)->tqh_last = &(elm)->field.tqe_next; \ ++ (listelm)->field.tqe_next = (elm); \ ++ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ ++} while (0) ++ ++#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ ++ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ ++ (elm)->field.tqe_next = (listelm); \ ++ *(listelm)->field.tqe_prev = (elm); \ ++ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ ++} while (0) ++ ++#define TAILQ_REMOVE(head, elm, field) do { \ ++ if (((elm)->field.tqe_next) != NULL) \ ++ (elm)->field.tqe_next->field.tqe_prev = \ ++ (elm)->field.tqe_prev; \ ++ else \ ++ (head)->tqh_last = (elm)->field.tqe_prev; \ ++ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ ++} while (0) ++ ++#define TAILQ_REPLACE(head, elm, elm2, field) do { \ ++ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ ++ (elm2)->field.tqe_next->field.tqe_prev = \ ++ &(elm2)->field.tqe_next; \ ++ else \ ++ (head)->tqh_last = &(elm2)->field.tqe_next; \ ++ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ ++ *(elm2)->field.tqe_prev = (elm2); \ ++} while (0) ++ ++/* ++ * Circular queue definitions. ++ */ ++#define CIRCLEQ_HEAD(name, type) \ ++struct name { \ ++ struct type *cqh_first; /* first element */ \ ++ struct type *cqh_last; /* last element */ \ ++} ++ ++#define CIRCLEQ_HEAD_INITIALIZER(head) \ ++ { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } ++ ++#define CIRCLEQ_ENTRY(type) \ ++struct { \ ++ struct type *cqe_next; /* next element */ \ ++ struct type *cqe_prev; /* previous element */ \ ++} ++ ++/* ++ * Circular queue access methods ++ */ ++#define CIRCLEQ_FIRST(head) ((head)->cqh_first) ++#define CIRCLEQ_LAST(head) ((head)->cqh_last) ++#define CIRCLEQ_END(head) ((void *)(head)) ++#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) ++#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) ++#define CIRCLEQ_EMPTY(head) \ ++ (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) ++ ++#define CIRCLEQ_FOREACH(var, head, field) \ ++ for((var) = CIRCLEQ_FIRST(head); \ ++ (var) != CIRCLEQ_END(head); \ ++ (var) = CIRCLEQ_NEXT(var, field)) ++ ++#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ ++ for((var) = CIRCLEQ_LAST(head); \ ++ (var) != CIRCLEQ_END(head); \ ++ (var) = CIRCLEQ_PREV(var, field)) ++ ++/* ++ * Circular queue functions. ++ */ ++#define CIRCLEQ_INIT(head) do { \ ++ (head)->cqh_first = CIRCLEQ_END(head); \ ++ (head)->cqh_last = CIRCLEQ_END(head); \ ++} while (0) ++ ++#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ ++ (elm)->field.cqe_next = (listelm)->field.cqe_next; \ ++ (elm)->field.cqe_prev = (listelm); \ ++ if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ ++ (head)->cqh_last = (elm); \ ++ else \ ++ (listelm)->field.cqe_next->field.cqe_prev = (elm); \ ++ (listelm)->field.cqe_next = (elm); \ ++} while (0) ++ ++#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ ++ (elm)->field.cqe_next = (listelm); \ ++ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ ++ if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ ++ (head)->cqh_first = (elm); \ ++ else \ ++ (listelm)->field.cqe_prev->field.cqe_next = (elm); \ ++ (listelm)->field.cqe_prev = (elm); \ ++} while (0) ++ ++#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ ++ (elm)->field.cqe_next = (head)->cqh_first; \ ++ (elm)->field.cqe_prev = CIRCLEQ_END(head); \ ++ if ((head)->cqh_last == CIRCLEQ_END(head)) \ ++ (head)->cqh_last = (elm); \ ++ else \ ++ (head)->cqh_first->field.cqe_prev = (elm); \ ++ (head)->cqh_first = (elm); \ ++} while (0) ++ ++#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ ++ (elm)->field.cqe_next = CIRCLEQ_END(head); \ ++ (elm)->field.cqe_prev = (head)->cqh_last; \ ++ if ((head)->cqh_first == CIRCLEQ_END(head)) \ ++ (head)->cqh_first = (elm); \ ++ else \ ++ (head)->cqh_last->field.cqe_next = (elm); \ ++ (head)->cqh_last = (elm); \ ++} while (0) ++ ++#define CIRCLEQ_REMOVE(head, elm, field) do { \ ++ if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ ++ (head)->cqh_last = (elm)->field.cqe_prev; \ ++ else \ ++ (elm)->field.cqe_next->field.cqe_prev = \ ++ (elm)->field.cqe_prev; \ ++ if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ ++ (head)->cqh_first = (elm)->field.cqe_next; \ ++ else \ ++ (elm)->field.cqe_prev->field.cqe_next = \ ++ (elm)->field.cqe_next; \ ++} while (0) ++ ++#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ ++ if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ ++ CIRCLEQ_END(head)) \ ++ (head).cqh_last = (elm2); \ ++ else \ ++ (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ ++ if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ ++ CIRCLEQ_END(head)) \ ++ (head).cqh_first = (elm2); \ ++ else \ ++ (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ ++} while (0) ++ ++#endif /* !_SYS_QUEUE_H_ */ +diff -up /dev/null nfs-utils-1.2.0/utils/spnfsd/spnfsd.conf.man +--- /dev/null 2009-08-25 05:54:53.623006579 -0400 ++++ nfs-utils-1.2.0/utils/spnfsd/spnfsd.conf.man 2009-08-27 14:25:34.315153000 -0400 +@@ -0,0 +1 @@ ++Hello world!! +diff -up /dev/null nfs-utils-1.2.0/utils/spnfsd/spnfsd.conf +--- /dev/null 2009-08-25 05:54:53.623006579 -0400 ++++ nfs-utils-1.2.0/utils/spnfsd/spnfsd.conf 2009-08-27 14:21:30.975192000 -0400 +@@ -0,0 +1,21 @@ ++[General] ++ ++Verbosity = 1 ++Stripe-size = 8192 ++Dense-striping = 0 ++Pipefs-Directory = /var/lib/nfs/rpc_pipefs ++DS-Mount-Directory = /spnfs ++ ++[DataServers] ++ ++NumDS = 2 ++ ++DS1_IP = 172.16.28.134 ++DS1_PORT = 2049 ++DS1_ROOT = /pnfs ++DS1_DEVID = 1 ++ ++DS2_IP = 172.16.28.141 ++DS2_PORT = 2049 ++DS2_ROOT = /pnfs ++DS2_DEVID = 2 +diff -up /dev/null nfs-utils-1.2.0/utils/spnfsd/spnfsd.c +--- /dev/null 2009-08-25 05:54:53.623006579 -0400 ++++ nfs-utils-1.2.0/utils/spnfsd/spnfsd.c 2009-08-27 14:21:30.979194000 -0400 +@@ -0,0 +1,552 @@ ++/* ++ * spnfsd.c ++ * ++ * Userland daemon for spNFS. ++ * ++ * Copyright (c) 2002 The Regents of the University of Michigan. ++ * All rights reserved. ++ * ++ * Marius Aamodt Eriksen ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the University nor the names of its ++ * contributors may be used to endorse or promote products derived ++ * from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif /* HAVE_CONFIG_H */ ++ ++#include "cfg.h" ++#include "queue.h" ++#include "nfslib.h" ++ ++#include "nfsd4_spnfs.h" ++#include "spnfsd.h" ++ ++#ifndef PIPEFS_DIR ++#define PIPEFS_DIR "/var/lib/nfs/rpc_pipefs/" ++#endif ++ ++#ifndef DSMOUNT_DIR ++#define DSMOUNT_DIR "/spnfs" ++#endif ++ ++/* From Niels */ ++#define CONF_SAVE(w, f) do { \ ++ char *p = f; \ ++ if (p != NULL) \ ++ (w) = p; \ ++} while (0) ++ ++struct spnfs_client { ++ int sc_fd; ++ char sc_path[PATH_MAX]; /* DM: full path to spnfs pipe */ ++ struct event sc_event; ++}; ++ ++static void spnfscb(int, short, void *); ++static int do_mounts(void); ++ ++static void spnfs_msg_handler(struct spnfs_client *, struct spnfs_msg *); ++static void send_invalid_msg(int); ++ ++size_t strlcat(char *, const char *, size_t); ++size_t strlcpy(char *, const char *, size_t); ++ssize_t atomicio(ssize_t (*)(), int, void *, size_t); ++void mydaemon(int, int); ++void release_parent(); ++static int read_config(); ++static void dump_config(); ++ ++int verbose = 0; ++int stripesize = DEFAULT_STRIPE_SIZE; ++int densestriping = 0; ++int num_ds; ++struct dserver dataservers[SPNFS_MAX_DATA_SERVERS]; ++char dsmountdir[PATH_MAX]; ++ ++static int cache_entry_expiration = 0; ++static char pipefsdir[PATH_MAX]; ++static char pipefspath[PATH_MAX]; ++ ++/* SPNFS */ ++struct spnfs_client sc; ++ ++/* Used by cfg.c */ ++char *conf_path; ++ ++static void ++msg_format(char *rtnbuff, int rtnbuffsize, int errval, ++ const char *fmt, va_list args) ++{ ++ char buff[1024]; ++ int n; ++ ++ vsnprintf(buff, sizeof(buff), fmt, args); ++ ++ if ((n = strlen(buff)) > 0 && buff[n-1] == '\n') ++ buff[--n] = '\0'; ++ ++ snprintf(rtnbuff, rtnbuffsize, "%s: %s", buff, strerror(errval)); ++} ++ ++void ++spnfsd_warn(const char *fmt, ...) ++{ ++ int errval = errno; /* save this! */ ++ char buff[1024]; ++ va_list args; ++ ++ va_start(args, fmt); ++ msg_format(buff, sizeof(buff), errval, fmt, args); ++ va_end(args); ++ ++ syslog(LOG_WARNING, "%s", buff); ++} ++ ++void ++spnfsd_warnx(const char *fmt, ...) ++{ ++ va_list args; ++ ++ va_start(args, fmt); ++ vsyslog(LOG_WARNING, fmt, args); ++ va_end(args); ++} ++ ++void ++spnfsd_err(int eval, const char *fmt, ...) ++{ ++ int errval = errno; /* save this! */ ++ char buff[1024]; ++ va_list args; ++ ++ va_start(args, fmt); ++ msg_format(buff, sizeof(buff), errval, fmt, args); ++ va_end(args); ++ ++ syslog(LOG_ERR, "%s", buff); ++ exit(eval); ++} ++ ++void ++spnfsd_errx(int eval, const char *fmt, ...) ++{ ++ va_list args; ++ ++ va_start(args, fmt); ++ vsyslog(LOG_ERR, fmt, args); ++ va_end(args); ++ exit(eval); ++} ++ ++int ++main(int argc, char **argv) ++{ ++ int opt, fg = 0; ++ char *progname; ++ struct stat sb; ++ int err; ++ extern int nfsservctl(); ++ ++ if ((err = nfsservctl(222, NULL, NULL)) != 0) ++ if (errno != EEXIST) { ++ spnfsd_errx(1, "kernel init failed (%s)", ++ strerror(errno)); ++ ++ perror("spnfsd: nfsservctl"); ++ } ++ ++ conf_path = _PATH_SPNFSDCONF; ++ strlcpy(pipefsdir, PIPEFS_DIR, sizeof(pipefsdir)); ++ strlcpy(dsmountdir, DSMOUNT_DIR, sizeof(dsmountdir)); ++ strlcpy(sc.sc_path, PIPEFS_DIR, sizeof(sc.sc_path)); ++ ++ if ((progname = strrchr(argv[0], '/'))) ++ progname++; ++ else ++ progname = argv[0]; ++ ++ openlog(progname, LOG_PID, LOG_DAEMON); ++ ++#define GETOPTSTR "vfd:p:U:G:c:CS" ++ opterr=0; /* Turn off error messages */ ++ while ((opt = getopt(argc, argv, GETOPTSTR)) != -1) { ++ if (opt == 'c') ++ conf_path = optarg; ++ if (opt == '?') { ++ if (strchr(GETOPTSTR, optopt)) ++ errx(1, "'-%c' option requires an argument.", optopt); ++ else ++ errx(1, "'-%c' is an invalid argument.", optopt); ++ } ++ } ++ optind = 1; ++ ++ if (stat(conf_path, &sb) == -1 &&(errno == ENOENT || errno == EACCES)) { ++ warn("Skipping configuration file \"%s\"", conf_path); ++ conf_path = NULL; ++ } else { ++ conf_init(); ++ if (read_config() != 0) ++ spnfsd_err(1, "Invalid config file\n"); ++ if (verbose) ++ dump_config(); ++ } ++ ++ while ((opt = getopt(argc, argv, GETOPTSTR)) != -1) ++ switch (opt) { ++ case 'v': ++ verbose++; ++ break; ++ case 'f': ++ fg = 1; ++ break; ++ case 'p': ++ strlcpy(pipefsdir, optarg, sizeof(pipefsdir)); ++ strlcpy(sc.sc_path, optarg, sizeof(sc.sc_path)); ++ break; ++ default: ++ break; ++ } ++ ++ strncat(pipefsdir, "/nfs", sizeof(pipefsdir)); ++ strncat(sc.sc_path, "/nfs/spnfs", sizeof(sc.sc_path)); ++ memcpy(pipefspath, sc.sc_path, sizeof(pipefspath)); ++ ++ signal(SIGHUP, send_invalid_msg); ++ ++ if (do_mounts() != 0) ++ spnfsd_err(1, "Mounting DSs failed\n"); ++ ++ ++/* DMXXX in case I forget -f while testing... */ ++fg = 1; ++ if (!fg) ++ mydaemon(0, 0); ++ ++ event_init(); ++ ++ if (verbose > 0) ++ spnfsd_warnx("Expiration time is %d seconds.", ++ cache_entry_expiration); ++ ++ if ((sc.sc_fd = open(sc.sc_path, O_RDWR, 0)) == -1) { ++ perror("spnfsd open file"); ++ } else { ++ event_set(&sc.sc_event, sc.sc_fd, EV_READ, spnfscb, &sc); ++ event_add(&sc.sc_event, NULL); ++ } ++ ++ release_parent(); ++ ++ if (event_dispatch() < 0) ++ spnfsd_errx(1, "main: event_dispatch returns errno %d (%s)", ++ errno, strerror(errno)); ++ /* NOTREACHED */ ++ return 1; ++} ++ ++static void ++spnfs_msg_handler(struct spnfs_client *scp, struct spnfs_msg *im) ++{ ++ int err; ++ ++ switch (im->im_type) { ++ case SPNFS_TYPE_LAYOUTGET: ++ err = spnfsd_layoutget(im); ++ break; ++ case SPNFS_TYPE_LAYOUTCOMMIT: ++ err = spnfsd_layoutcommit(im); ++ break; ++ case SPNFS_TYPE_LAYOUTRETURN: ++ err = spnfsd_layoutreturn(im); ++ break; ++ case SPNFS_TYPE_GETDEVICELIST: ++ err = spnfsd_getdevicelist(im); ++ break; ++ case SPNFS_TYPE_GETDEVICEINFO: ++ err = spnfsd_getdeviceinfo(im); ++ break; ++ case SPNFS_TYPE_SETATTR: ++ err = spnfsd_setattr(im); ++ break; ++ case SPNFS_TYPE_OPEN: ++ err = spnfsd_open(im); ++ break; ++ case SPNFS_TYPE_CLOSE: ++ err = spnfsd_close(im); ++ break; ++ case SPNFS_TYPE_CREATE: ++ err = spnfsd_create(im); ++ break; ++ case SPNFS_TYPE_REMOVE: ++ err = spnfsd_remove(im); ++ break; ++ case SPNFS_TYPE_COMMIT: ++ err = spnfsd_commit(im); ++ break; ++ default: ++ spnfsd_warnx("spnfs_msg_handler: Invalid msg type (%d) in message", ++ im->im_type); ++ im->im_status |= SPNFS_STATUS_INVALIDMSG; ++ err = -EINVAL; ++ break; ++ } ++} ++ ++static void ++spnfscb(int fd, short which, void *data) ++{ ++ struct spnfs_client *scp = data; ++ struct spnfs_msg im; ++ int rval; ++ ++ if (which != EV_READ) ++ goto out; ++ ++ if (atomicio(read, scp->sc_fd, &im, sizeof(im)) != sizeof(im)) { ++ if (verbose > 0) ++ spnfsd_warn("spnfscb: read(%s)", scp->sc_path); ++ if (errno == EPIPE) ++ return; ++ goto out; ++ } ++ ++ spnfs_msg_handler(scp, &im); ++ ++ /* XXX: I don't like ignoring this error in the id->name case, ++ * but we've never returned it, and I need to check that the client ++ * can handle it gracefully before starting to return it now. */ ++ ++ if (im.im_status == SPNFS_STATUS_FAIL) ++ im.im_status = SPNFS_STATUS_SUCCESS; ++ ++printf("before atomicio write\n"); ++printf("writing %d bytes\n", sizeof(im)); ++ if ((rval=atomicio(write, scp->sc_fd, &im, sizeof(im))) != sizeof(im)) { ++printf("spnfscb: incomplete write %d of %d bytes\n", rval, sizeof(im)); ++printf("atomicio write error\n"); ++ spnfsd_warn("spnfscb: write(%s)", scp->sc_path); ++ } ++ ++printf("after atomicio write\n"); ++out: ++printf("spnfscb out\n"); ++ event_add(&scp->sc_event, NULL); ++} ++ ++/* ++ * mydaemon creates a pipe between the partent and child ++ * process. The parent process will wait until the ++ * child dies or writes a '1' on the pipe signaling ++ * that it started successfully. ++ */ ++int pipefds[2] = { -1, -1}; ++ ++void ++mydaemon(int nochdir, int noclose) ++{ ++ int pid, status, tempfd; ++ ++ if (pipe(pipefds) < 0) ++ err(1, "mydaemon: pipe() failed: errno %d", errno); ++ ++ if ((pid = fork ()) < 0) ++ err(1, "mydaemon: fork() failed: errno %d", errno); ++ ++ if (pid != 0) { ++ /* ++ * Parent. Wait for status from child. ++ */ ++ close(pipefds[1]); ++ if (read(pipefds[0], &status, 1) != 1) ++ exit(1); ++ exit (0); ++ } ++ /* Child. */ ++ close(pipefds[0]); ++ setsid (); ++ if (nochdir == 0) { ++ if (chdir ("/") == -1) ++ err(1, "mydaemon: chdir() failed: errno %d", errno); ++ } ++ ++ while (pipefds[1] <= 2) { ++ pipefds[1] = dup(pipefds[1]); ++ if (pipefds[1] < 0) ++ err(1, "mydaemon: dup() failed: errno %d", errno); ++ } ++ ++ if (noclose == 0) { ++ tempfd = open("/dev/null", O_RDWR); ++ if (tempfd < 0) ++ tempfd = open("/", O_RDONLY); ++ if (tempfd >= 0) { ++ dup2(tempfd, 0); ++ dup2(tempfd, 1); ++ dup2(tempfd, 2); ++ closeall(3); ++ } else ++ closeall(0); ++ } ++ ++ return; ++} ++ ++void ++release_parent() ++{ ++ int status; ++ ++ if (pipefds[1] > 0) { ++ write(pipefds[1], &status, 1); ++ close(pipefds[1]); ++ pipefds[1] = -1; ++ } ++} ++ ++static int ++read_config() ++{ ++ char *xpipefsdir = NULL; ++ char *xdsmountdir = NULL; ++ int ds; ++ char ipstr[20], portstr[20], rootstr[20], devidstr[20]; ++ ++ verbose = conf_get_num("General", "Verbosity", 0); ++ stripesize = conf_get_num("General", "Stripe-size",DEFAULT_STRIPE_SIZE); ++ densestriping = conf_get_num("General", "Dense-striping", 0); ++ CONF_SAVE(xpipefsdir, conf_get_str("General", "Pipefs-Directory")); ++ if (xpipefsdir != NULL) ++ strlcpy(pipefsdir, xpipefsdir, sizeof(pipefsdir)); ++ CONF_SAVE(xdsmountdir, conf_get_str("General", "DS-Mount-Directory")); ++ if (xdsmountdir != NULL) ++ strlcpy(dsmountdir, xdsmountdir, sizeof(dsmountdir)); ++ num_ds = conf_get_num("DataServers", "NumDS", 0); ++ if (num_ds < 1 || num_ds > SPNFS_MAX_DATA_SERVERS) ++ spnfsd_err(1, "Invalid number of data servers in config: %d\n", ++ num_ds); ++ for (ds = 1; ds <= num_ds ; ds++) { ++ sprintf(ipstr, "DS%d_IP", ds); ++ sprintf(portstr, "DS%d_PORT", ds); ++ sprintf(rootstr, "DS%d_ROOT", ds); ++ sprintf(devidstr, "DS%d_DEVID", ds); ++ CONF_SAVE(dataservers[ds-1].ds_ip, ++ conf_get_str("DataServers", ipstr)); ++ if (dataservers[ds-1].ds_ip == NULL) ++ spnfsd_err(1, "Missing IP for DS%d\n", ds); ++ dataservers[ds-1].ds_port = ++ conf_get_num("DataServers", portstr, DEFAULT_DS_PORT); ++ CONF_SAVE(dataservers[ds-1].ds_path, ++ conf_get_str("DataServers", rootstr)); ++ if (dataservers[ds-1].ds_ip == NULL) ++ spnfsd_err(1, "Missing IP for DS%d\n", ds); ++ dataservers[ds-1].ds_devid = ++ conf_get_num("DataServers", devidstr, -1); ++ if (dataservers[ds-1].ds_devid < 0) ++ spnfsd_err(1, "Missing or invalid DEVID for DS%d\n", ds); ++ } ++ ++ return 0; ++} ++ ++static void ++dump_config() ++{ ++ int ds; ++ ++ printf("Verbosity: %d\n", verbose); ++ printf("Stripe size: %d\n", stripesize); ++ printf("Dense striping: %d\n", densestriping); ++ printf("Number of data servers: %d\n", num_ds); ++ ++ for (ds = 0 ; ds < num_ds ; ds++) { ++ printf("DS%d IP: %s\n", ds+1, dataservers[ds].ds_ip); ++ printf("DS%d PORT: %d\n", ds+1, dataservers[ds].ds_port); ++ printf("DS%d ROOT: %s\n", ds+1, dataservers[ds].ds_path); ++ printf("DS%d DEVID: %d\n", ds+1, dataservers[ds].ds_devid); ++ } ++} ++ ++static int ++do_mounts() ++{ ++ int ds; ++ char cmd[1024]; ++ ++ return 0; ++ for (ds = 0 ; ds < num_ds ; ds++) { ++ sprintf(cmd, "mkdir -p %s/%s", dsmountdir, ++ dataservers[ds].ds_ip); ++ system(cmd); ++ sprintf(cmd, "mount -t nfs4 %s:%s %s/%s", ++ dataservers[ds].ds_ip, dataservers[ds].ds_path, ++ dsmountdir, dataservers[ds].ds_ip); ++ system(cmd); ++ } ++} ++ ++static void ++send_invalid_msg(int signum) ++{ ++ struct spnfs_msg im; ++ int fd, rval; ++ ++ im.im_status = SPNFS_STATUS_FAIL; ++ ++ if ((fd = open(pipefspath, O_RDWR, 0)) == -1) { ++ perror("spnfsd open pipe"); ++ } else { ++ if ((rval=atomicio(write, fd, &im, sizeof(im))) != sizeof(im)) { ++ spnfsd_warn("send_invalid_msg: write(%s)", pipefspath); ++ } ++ } ++} +diff -up /dev/null nfs-utils-1.2.0/utils/spnfsd/spnfsd.h +--- /dev/null 2009-08-25 05:54:53.623006579 -0400 ++++ nfs-utils-1.2.0/utils/spnfsd/spnfsd.h 2009-08-27 14:21:30.984191000 -0400 +@@ -0,0 +1,47 @@ ++/* ++ * spnfsd.h ++ * ++ * spNFS - simple pNFS implementation with userspace daemon ++ * ++ */ ++ ++#ifndef _PATH_SPNFSDCONF ++#define _PATH_SPNFSDCONF "/etc/spnfsd.conf" ++#endif ++ ++#ifndef DEFAULT_STRIPE_SIZE ++#define DEFAULT_STRIPE_SIZE 4096 ++#endif ++ ++#ifndef DEFAULT_DS_PORT ++#define DEFAULT_DS_PORT 2049 ++#endif ++ ++struct dserver { ++ char *ds_ip; ++ int ds_port; ++ char *ds_path; ++ int ds_devid; ++}; ++ ++/* DMXXX future struct for whole config */ ++struct spnfsd_config { ++ int verbose; ++ int stripesize; ++ int densestriping; ++ int num_ds; ++ struct dserver dataservers[SPNFS_MAX_DATA_SERVERS]; ++}; ++ ++int spnfsd_layoutget(struct spnfs_msg *); ++int spnfsd_layoutcommit(struct spnfs_msg *); ++int spnfsd_layoutreturn(struct spnfs_msg *); ++int spnfsd_getdevicelist(struct spnfs_msg *); ++int spnfsd_getdeviceinfo(struct spnfs_msg *); ++int spnfsd_setattr(struct spnfs_msg *); ++int spnfsd_open(struct spnfs_msg *); ++int spnfsd_close(struct spnfs_msg *); ++int spnfsd_create(struct spnfs_msg *); ++int spnfsd_remove(struct spnfs_msg *); ++int spnfsd_commit(struct spnfs_msg *); ++int spnfsd_getfh(char *, unsigned char *, unsigned int *); +diff -up /dev/null nfs-utils-1.2.0/utils/spnfsd/spnfsd.man +--- /dev/null 2009-08-25 05:54:53.623006579 -0400 ++++ nfs-utils-1.2.0/utils/spnfsd/spnfsd.man 2009-08-27 14:25:40.912694000 -0400 +@@ -0,0 +1 @@ ++Hello World! +diff -up /dev/null nfs-utils-1.2.0/utils/spnfsd/spnfsd_ops.c +--- /dev/null 2009-08-25 05:54:53.623006579 -0400 ++++ nfs-utils-1.2.0/utils/spnfsd/spnfsd_ops.c 2009-08-27 14:21:30.988194000 -0400 +@@ -0,0 +1,266 @@ ++#include "nfsd4_spnfs.h" ++#include "spnfsd.h" ++#include "nfs/nfs.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++extern int stripesize; ++extern int densestriping; ++extern int num_ds; ++extern char dsmountdir[]; ++extern struct dserver dataservers[SPNFS_MAX_DATA_SERVERS]; ++size_t strlcat(char *, const char *, size_t); ++size_t strlcpy(char *, const char *, size_t); ++ ++int ++spnfsd_layoutget(struct spnfs_msg *im) ++{ ++ int ds; ++ int rc; ++ char fullpath[1024]; /* MSXXX */ ++ ++ im->im_status = SPNFS_STATUS_SUCCESS; ++ im->im_res.layoutget_res.status = 0; ++ im->im_res.layoutget_res.stripe_size = stripesize; ++ if (densestriping) ++ im->im_res.layoutget_res.stripe_type = 2; /* DMXXX enum */ ++ else ++ im->im_res.layoutget_res.stripe_type = 1; /* DMXXX ^^^^ */ ++ im->im_res.layoutget_res.layout_count = num_ds; ++ ++ for (ds = 0 ; ds < num_ds ; ds++) { ++ im->im_res.layoutget_res.flist[ds].dev_id = ++ dataservers[ds].ds_devid; ++ im->im_res.layoutget_res.flist[ds].dev_index = ds; ++ memset(im->im_res.layoutget_res.flist[ds].fh_val, 0, 128); /*DMXXX*/ ++ sprintf(fullpath, "%s/%s/%ld", ++ dsmountdir, dataservers[ds].ds_ip, ++ im->im_args.layoutget_args.inode); ++ rc = spnfsd_getfh(fullpath, ++ im->im_res.layoutget_res.flist[ds].fh_val, ++ &im->im_res.layoutget_res.flist[ds].fh_len); ++ if (rc < 0) { ++ /* MSXXX needs error msg/handling */ ++ im->im_res.layoutget_res.status = ENOENT; ++ return -1; ++ } ++ ++ /* ++ * MSXXX another hack...fix the hardcoding. ++ * The fh's fsid_type is incremented by 5 to get ++ * around stateid checking. ++ */ ++ im->im_res.layoutget_res.flist[ds].fh_val[2] += 5; ++ } ++ ++ return 0; ++} ++ ++int ++spnfsd_layoutcommit(struct spnfs_msg *im) ++{ ++ char basename[1024]; /* DMXXX */ ++ char fullpath[1024]; /* DMXXX */ ++ int ds; ++ ++ im->im_status = SPNFS_STATUS_SUCCESS; ++ im->im_res.layoutcommit_res.status = 0; ++ sprintf(basename, "%ld", im->im_args.layoutcommit_args.inode); ++ ++ for (ds = 0 ; ds < num_ds ; ds++) { ++ sprintf(fullpath, "%s/%s/%s", dsmountdir, ++ dataservers[ds].ds_ip, basename); ++ truncate(fullpath, im->im_args.layoutcommit_args.file_size); ++ } ++ ++ return 0; ++} ++ ++int ++spnfsd_layoutreturn(struct spnfs_msg *im) ++{ ++ return 0; ++} ++ ++int ++spnfsd_getdevicelist(struct spnfs_msg *im) ++{ ++ int ds; ++ ++ im->im_status = SPNFS_STATUS_SUCCESS; ++ im->im_res.getdevicelist_res.status = 0; ++ im->im_res.getdevicelist_res.count = num_ds; ++ for (ds = 0 ; ds < num_ds ; ds++) { ++ im->im_res.getdevicelist_res.dlist[ds].devid = ++ dataservers[ds].ds_devid; ++ memset(im->im_res.getdevicelist_res.dlist[ds].netid, 0, 5); ++ strlcpy(im->im_res.getdevicelist_res.dlist[ds].netid, "tcp", 4); ++ sprintf(im->im_res.getdevicelist_res.dlist[ds].addr, "%s.%d.%d", ++ dataservers[ds].ds_ip, ++ dataservers[ds].ds_port >> 8, ++ dataservers[ds].ds_port & 0xff); ++ } ++ ++ return 0; ++} ++ ++int ++spnfsd_getdeviceinfo(struct spnfs_msg *im) ++{ ++ int ds; ++ ++ im->im_status = SPNFS_STATUS_SUCCESS; ++ im->im_res.getdeviceinfo_res.status = ENODEV; ++ for (ds = 0 ; ds < num_ds ; ds++) { ++ if (dataservers[ds].ds_devid == ++ im->im_args.getdeviceinfo_args.devid) { ++ im->im_res.getdeviceinfo_res.dinfo.devid = ++ dataservers[ds].ds_devid; ++ memset(im->im_res.getdeviceinfo_res.dinfo.netid, ++ 0, 5); ++ strlcpy(im->im_res.getdeviceinfo_res.dinfo.netid, ++ "tcp", 4); ++ sprintf(im->im_res.getdeviceinfo_res.dinfo.addr, ++ "%s.%d.%d", ++ dataservers[ds].ds_ip, ++ dataservers[ds].ds_port >> 8, ++ dataservers[ds].ds_port & 0xff); ++ im->im_res.getdeviceinfo_res.status = 0; ++ break; ++ } ++ } ++ ++ return 0; ++} ++ ++int ++spnfsd_setattr(struct spnfs_msg *im) ++{ ++ char basename[1024]; /* DMXXX */ ++ char fullpath[1024]; /* DMXXX */ ++ int ds; ++ ++ im->im_status = SPNFS_STATUS_SUCCESS; ++ im->im_res.setattr_res.status = 0; ++ sprintf(basename, "%ld", im->im_args.setattr_args.inode); ++ ++ for (ds = 0 ; ds < num_ds ; ds++) { ++ sprintf(fullpath, "%s/%s/%s", dsmountdir, ++ dataservers[ds].ds_ip, basename); ++ truncate(fullpath, im->im_args.setattr_args.file_size); ++ } ++ ++ return 0; ++} ++ ++int ++spnfsd_open(struct spnfs_msg *im) ++{ ++ char basename[1024]; /* DMXXX */ ++ char fullpath[1024]; /* DMXXX */ ++ char dirpath[1024]; /* DMXXX */ ++ int ds; ++ int fd, status; ++ struct stat buf; ++ ++ im->im_status = SPNFS_STATUS_SUCCESS; ++ im->im_res.open_res.status = 0; ++ sprintf(basename, "%ld", im->im_args.open_args.inode); ++ ++ for (ds = 0 ; ds < num_ds ; ds++) { ++ sprintf(dirpath, "%s/%s", dsmountdir, ++ dataservers[ds].ds_ip); ++ sprintf(fullpath, "%s/%s", dirpath, basename); ++ status = stat(dirpath, &buf); ++ im->im_res.open_res.status = errno; ++ if (status != 0) { ++ perror(dirpath); ++ break; ++ } ++ if ((fd = open(fullpath, O_WRONLY|O_CREAT, 0777)) < 0) { ++ perror(fullpath); ++ im->im_res.open_res.status = errno; ++ break; ++ } else { ++ im->im_res.open_res.status = 0; ++ close(fd); ++ } ++ } ++ ++ return im->im_res.open_res.status; ++} ++ ++int ++spnfsd_close(struct spnfs_msg *im) ++{ ++ im->im_status = SPNFS_STATUS_SUCCESS; ++ printf("spnfsd_close received: %d\n", im->im_args.close_args.x); ++ im->im_res.close_res.y = 7331; ++ return 0; ++} ++ ++int ++spnfsd_create(struct spnfs_msg *im) ++{ ++ return 0; ++} ++ ++int ++spnfsd_remove(struct spnfs_msg *im) ++{ ++ char basename[1024]; /* DMXXX */ ++ char fullpath[1024]; /* DMXXX */ ++ int ds; ++ ++ im->im_status = SPNFS_STATUS_SUCCESS; ++ im->im_res.remove_res.status = 0; ++ sprintf(basename, "%ld", im->im_args.remove_args.inode); ++ ++ for (ds = 0 ; ds < num_ds ; ds++) { ++ sprintf(fullpath, "%s/%s/%s", dsmountdir, ++ dataservers[ds].ds_ip, basename); ++ unlink(fullpath); ++ } ++ ++ return 0; ++} ++ ++int ++spnfsd_commit(struct spnfs_msg *im) ++{ ++ return 0; ++} ++ ++int ++spnfsd_getfh(char *path, unsigned char *fh_val, unsigned int *fh_len) ++{ ++ int fd, err; ++ struct nfsctl_arg arg; ++ unsigned char res[130]; /* XXX align this to proper structure */ ++ extern int nfsservctl(); ++ ++ if ((fd = open(path, O_RDONLY)) < 0) { ++ perror(path); ++ return -1; ++ } ++ ++ arg.ca_fd2fh.fd = fd; ++ if ((err = nfsservctl(NFSCTL_FD2FH, &arg, res)) < 0) { ++ close(fd); ++ return -1; ++ } ++ ++ /* XXX use proper structure */ ++ *fh_len = (short)res[0]; ++ memcpy(fh_val, &res[2], *fh_len); ++ ++ close(fd); ++ return 0; ++} +diff -up /dev/null nfs-utils-1.2.0/utils/spnfsd/strlcat.c +--- /dev/null 2009-08-25 05:54:53.623006579 -0400 ++++ nfs-utils-1.2.0/utils/spnfsd/strlcat.c 2009-08-27 14:21:30.993191000 -0400 +@@ -0,0 +1,77 @@ ++/* $OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $ */ ++ ++/* ++ * Copyright (c) 1998 Todd C. Miller ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ++ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; ++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR ++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#if defined(LIBC_SCCS) && !defined(lint) ++static char *rcsid = "$OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $"; ++#endif /* LIBC_SCCS and not lint */ ++ ++#include ++#include ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif /* HAVE_CONFIG_H */ ++ ++/* ++ * Appends src to string dst of size siz (unlike strncat, siz is the ++ * full size of dst, not space left). At most siz-1 characters ++ * will be copied. Always NUL terminates (unless siz <= strlen(dst)). ++ * Returns strlen(src) + MIN(siz, strlen(initial dst)). ++ * If retval >= siz, truncation occurred. ++ */ ++size_t ++strlcat(dst, src, siz) ++ char *dst; ++ const char *src; ++ size_t siz; ++{ ++ register char *d = dst; ++ register const char *s = src; ++ register size_t n = siz; ++ size_t dlen; ++ ++ /* Find the end of dst and adjust bytes left but don't go past end */ ++ while (n-- != 0 && *d != '\0') ++ d++; ++ dlen = d - dst; ++ n = siz - dlen; ++ ++ if (n == 0) ++ return(dlen + strlen(s)); ++ while (*s != '\0') { ++ if (n != 1) { ++ *d++ = *s; ++ n--; ++ } ++ s++; ++ } ++ *d = '\0'; ++ ++ return(dlen + (s - src)); /* count does not include NUL */ ++} +diff -up /dev/null nfs-utils-1.2.0/utils/spnfsd/strlcpy.c +--- /dev/null 2009-08-25 05:54:53.623006579 -0400 ++++ nfs-utils-1.2.0/utils/spnfsd/strlcpy.c 2009-08-27 14:21:30.997191000 -0400 +@@ -0,0 +1,73 @@ ++/* $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $ */ ++ ++/* ++ * Copyright (c) 1998 Todd C. Miller ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ++ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; ++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR ++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#if defined(LIBC_SCCS) && !defined(lint) ++static char *rcsid = "$OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $"; ++#endif /* LIBC_SCCS and not lint */ ++ ++#include ++#include ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif /* HAVE_CONFIG_H */ ++ ++/* ++ * Copy src to string dst of size siz. At most siz-1 characters ++ * will be copied. Always NUL terminates (unless siz == 0). ++ * Returns strlen(src); if retval >= siz, truncation occurred. ++ */ ++size_t ++strlcpy(dst, src, siz) ++ char *dst; ++ const char *src; ++ size_t siz; ++{ ++ register char *d = dst; ++ register const char *s = src; ++ register size_t n = siz; ++ ++ /* Copy as many bytes as will fit */ ++ if (n != 0 && --n != 0) { ++ do { ++ if ((*d++ = *s++) == 0) ++ break; ++ } while (--n != 0); ++ } ++ ++ /* Not enough room in dst, add NUL and traverse rest of src */ ++ if (n == 0) { ++ if (siz != 0) ++ *d = '\0'; /* NUL-terminate dst */ ++ while (*s++) ++ ; ++ } ++ ++ return(s - src - 1); /* count does not include NUL */ ++} diff --git a/nfs-utils-1.2.0-spnfsd-02.patch b/nfs-utils-1.2.0-spnfsd-02.patch new file mode 100644 index 0000000..3e9cd0b --- /dev/null +++ b/nfs-utils-1.2.0-spnfsd-02.patch @@ -0,0 +1,27 @@ +commit 6c94024a32470ab20a61268a3d81d1212cedafbc +Author: Mike Sager +Date: Mon Nov 19 18:36:09 2007 -0800 + + Added spnfsd to configure.ac + + Signed-off-by: Mike Sager + +diff -up nfs-utils-1.2.0/configure.ac.orig nfs-utils-1.2.0/configure.ac +--- nfs-utils-1.2.0/configure.ac.orig 2009-08-27 12:02:59.335782000 -0400 ++++ nfs-utils-1.2.0/configure.ac 2009-08-27 13:42:37.126103000 -0400 +@@ -65,6 +65,7 @@ AC_ARG_ENABLE(nfsv4, + if test "$enable_nfsv4" = yes; then + AC_DEFINE(NFS4_SUPPORTED, 1, [Define this if you want NFSv4 support compiled in]) + IDMAPD=idmapd ++ SPNFSD=spnfsd + else + enable_nfsv4= + IDMAPD= +@@ -409,6 +410,7 @@ AC_CONFIG_FILES([ + utils/exportfs/Makefile + utils/gssd/Makefile + utils/idmapd/Makefile ++ utils/spnfsd/Makefile + utils/mount/Makefile + utils/mountd/Makefile + utils/nfsd/Makefile diff --git a/nfs-utils-1.2.0-spnfsd-03.patch b/nfs-utils-1.2.0-spnfsd-03.patch new file mode 100644 index 0000000..ae8a0af --- /dev/null +++ b/nfs-utils-1.2.0-spnfsd-03.patch @@ -0,0 +1,24 @@ +commit 76d0c6f17a2e1e1c8efa84d67619c34d8884af51 +Author: Dan Muntz +Date: Mon Nov 26 13:40:19 2007 -0800 + + Add explicit chmod 777 of stripe files as workaround for non-root users. + + Signed-off-by: Dan Muntz + Signed-off-by: Mike Sager + +diff --git a/utils/spnfsd/spnfsd_ops.c b/utils/spnfsd/spnfsd_ops.c +index cec4840..bd5486d 100644 +--- a/utils/spnfsd/spnfsd_ops.c ++++ b/utils/spnfsd/spnfsd_ops.c +@@ -189,6 +189,10 @@ spnfsd_open(struct spnfs_msg *im) + im->im_res.open_res.status = errno; + break; + } else { ++ if (fchmod(fd, 0777) != 0) { ++ /* DM: we'll consider this non-fatal for now */ ++ perror("chmod stripe"); ++ } + im->im_res.open_res.status = 0; + close(fd); + } diff --git a/nfs-utils-1.2.0-spnfsd-04.patch b/nfs-utils-1.2.0-spnfsd-04.patch new file mode 100644 index 0000000..c84c505 --- /dev/null +++ b/nfs-utils-1.2.0-spnfsd-04.patch @@ -0,0 +1,169 @@ +commit d2e73153b64ab7a11442810bf42b8e72f1601ccf +Author: Dan Muntz +Date: Wed Dec 12 13:18:07 2007 -0800 + + add licensing comments and remove some printfs from spnfsd.c + + Signed-off-by: Dan Muntz + Signed-off-by: Mike Sager + +diff --git a/utils/spnfsd/makestatic b/utils/spnfsd/makestatic +index 4b7067f..5eec53c 100755 +--- a/utils/spnfsd/makestatic ++++ b/utils/spnfsd/makestatic +@@ -1 +1,23 @@ ++/****************************************************************************** ++ ++(c) 2007 Network Appliance, Inc. All Rights Reserved. ++ ++Network Appliance provides this source code under the GPL v2 License. ++The GPL v2 license is available at ++http://opensource.org/licenses/gpl-license.php. ++ ++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR ++CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ++EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ++PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ++PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ ++******************************************************************************/ ++ + gcc -static -Wall -pipe -g -O2 -o spnfsd atomicio.o spnfsd_ops.o cfg.o spnfsd.o strlcat.o strlcpy.o /usr/lib/libevent.a ../../support/nfs/libnfs.a +diff --git a/utils/spnfsd/nfsd4_spnfs.h b/utils/spnfsd/nfsd4_spnfs.h +index 634544f..99edae3 100644 +--- a/utils/spnfsd/nfsd4_spnfs.h ++++ b/utils/spnfsd/nfsd4_spnfs.h +@@ -4,7 +4,27 @@ + * spNFS - simple pNFS implementation with userspace daemon + * + */ +- ++/****************************************************************************** ++ ++(c) 2007 Network Appliance, Inc. All Rights Reserved. ++ ++Network Appliance provides this source code under the GPL v2 License. ++The GPL v2 license is available at ++http://opensource.org/licenses/gpl-license.php. ++ ++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR ++CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ++EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ++PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ++PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ ++******************************************************************************/ + + #ifndef NFS_SPNFS_H + #define NFS_SPNFS_H +diff --git a/utils/spnfsd/spnfsd.c b/utils/spnfsd/spnfsd.c +index 90e66ba..276b0c3 100644 +--- a/utils/spnfsd/spnfsd.c ++++ b/utils/spnfsd/spnfsd.c +@@ -1,7 +1,13 @@ + /* + * spnfsd.c +- * + * Userland daemon for spNFS. ++ * Based heavily on idmapd.c ++ * ++ */ ++/* ++ * idmapd.c ++ * ++ * Userland daemon for idmap. + * + * Copyright (c) 2002 The Regents of the University of Michigan. + * All rights reserved. +@@ -369,17 +375,11 @@ spnfscb(int fd, short which, void *data) + if (im.im_status == SPNFS_STATUS_FAIL) + im.im_status = SPNFS_STATUS_SUCCESS; + +-printf("before atomicio write\n"); +-printf("writing %d bytes\n", sizeof(im)); + if ((rval=atomicio(write, scp->sc_fd, &im, sizeof(im))) != sizeof(im)) { +-printf("spnfscb: incomplete write %d of %d bytes\n", rval, sizeof(im)); +-printf("atomicio write error\n"); + spnfsd_warn("spnfscb: write(%s)", scp->sc_path); + } + +-printf("after atomicio write\n"); + out: +-printf("spnfscb out\n"); + event_add(&scp->sc_event, NULL); + } + +diff --git a/utils/spnfsd/spnfsd.h b/utils/spnfsd/spnfsd.h +index dcea3e6..9df6cd8 100644 +--- a/utils/spnfsd/spnfsd.h ++++ b/utils/spnfsd/spnfsd.h +@@ -4,6 +4,27 @@ + * spNFS - simple pNFS implementation with userspace daemon + * + */ ++/****************************************************************************** ++ ++(c) 2007 Network Appliance, Inc. All Rights Reserved. ++ ++Network Appliance provides this source code under the GPL v2 License. ++The GPL v2 license is available at ++http://opensource.org/licenses/gpl-license.php. ++ ++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR ++CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ++EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ++PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ++PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ ++******************************************************************************/ + + #ifndef _PATH_SPNFSDCONF + #define _PATH_SPNFSDCONF "/etc/spnfsd.conf" +diff --git a/utils/spnfsd/spnfsd_ops.c b/utils/spnfsd/spnfsd_ops.c +index bd5486d..56bd185 100644 +--- a/utils/spnfsd/spnfsd_ops.c ++++ b/utils/spnfsd/spnfsd_ops.c +@@ -1,3 +1,25 @@ ++/****************************************************************************** ++ ++(c) 2007 Network Appliance, Inc. All Rights Reserved. ++ ++Network Appliance provides this source code under the GPL v2 License. ++The GPL v2 license is available at ++http://opensource.org/licenses/gpl-license.php. ++ ++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR ++CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ++EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ++PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ++PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ ++******************************************************************************/ ++ + #include "nfsd4_spnfs.h" + #include "spnfsd.h" + #include "nfs/nfs.h" diff --git a/nfs-utils-1.2.0-spnfsd-05.patch b/nfs-utils-1.2.0-spnfsd-05.patch new file mode 100644 index 0000000..5a5cb8d --- /dev/null +++ b/nfs-utils-1.2.0-spnfsd-05.patch @@ -0,0 +1,412 @@ +commit f5beeb9bad08970329dd47371e829e31da79e5f3 +Author: Mike Sager +Date: Sun Jan 27 17:11:07 2008 -0800 + + Update device ops to reflect latest draft and interface changes + + 1. Change spnfs getdevlist handling into iterative interface to reflect + export ops changes + + 2. Update device ops per draft 13 + + 3. Fix code that was written when a data server was thought to be a device + + Signed-off-by: Mike Sager + +diff --git a/utils/spnfsd/nfsd4_spnfs.h b/utils/spnfsd/nfsd4_spnfs.h +index 99edae3..7619c75 100644 +--- a/utils/spnfsd/nfsd4_spnfs.h ++++ b/utils/spnfsd/nfsd4_spnfs.h +@@ -4,6 +4,7 @@ + * spNFS - simple pNFS implementation with userspace daemon + * + */ ++ + /****************************************************************************** + + (c) 2007 Network Appliance, Inc. All Rights Reserved. +@@ -31,6 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + #ifdef __KERNEL__ ++#include "exportfs.h" + #include "sunrpc/svc.h" + #include "nfsd/nfsfh.h" + #else +@@ -45,17 +47,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + #define SPNFS_TYPE_LAYOUTGET 0x01 + #define SPNFS_TYPE_LAYOUTCOMMIT 0x02 + #define SPNFS_TYPE_LAYOUTRETURN 0x03 +-#define SPNFS_TYPE_GETDEVICELIST 0x04 ++#define SPNFS_TYPE_GETDEVICEITER 0x04 + #define SPNFS_TYPE_GETDEVICEINFO 0x05 + #define SPNFS_TYPE_SETATTR 0x06 + #define SPNFS_TYPE_OPEN 0x07 + #define SPNFS_TYPE_CLOSE 0x08 + #define SPNFS_TYPE_CREATE 0x09 + #define SPNFS_TYPE_REMOVE 0x0a +-#define SPNFS_TYPE_COMMIT 0x0b ++#define SPNFS_TYPE_COMMIT 0x0b + +-#define SPNFS_MAX_DATA_SERVERS 2 +-#define SPNFS_MAX_LAYOUT 8 ++#define SPNFS_MAX_DEVICES 1 ++#define SPNFS_MAX_DATA_SERVERS 2 ++#define SPNFS_MAX_LAYOUT 8 + + /* layout */ + struct spnfs_msg_layoutget_args { +@@ -64,9 +67,9 @@ struct spnfs_msg_layoutget_args { + + struct spnfs_filelayout_list { + u_int32_t dev_id; +- u_int32_t dev_index; +- u_int32_t fh_len; +- unsigned char fh_val[128]; /* DMXXX fix this const */ ++ u_int32_t ds_index; ++ u_int32_t fh_len; ++ unsigned char fh_val[128]; /* DMXXX fix this const */ + }; + + struct spnfs_msg_layoutget_res { +@@ -97,31 +100,41 @@ struct spnfs_msg_layoutreturn_res { + }; + */ + +-/* getdevicelist */ +-struct spnfs_msg_getdevicelist_args { ++/* getdeviceiter */ ++struct spnfs_msg_getdeviceiter_args { + unsigned long inode; ++ u_int64_t cookie; ++ u_int64_t verf; + }; + +-struct spnfs_getdevicelist_dev { ++struct spnfs_msg_getdeviceiter_res { ++ int status; + u_int32_t devid; ++ u_int64_t cookie; ++ u_int64_t verf; ++ u_int32_t eof; ++}; ++ ++/* getdeviceinfo */ ++struct spnfs_data_server { ++ u_int32_t dsid; + char netid[5]; + char addr[29]; + }; + +-struct spnfs_msg_getdevicelist_res { +- int status; +- int count; +- struct spnfs_getdevicelist_dev dlist[SPNFS_MAX_DATA_SERVERS]; ++struct spnfs_device { ++ u_int32_t devid; ++ int dscount; ++ struct spnfs_data_server dslist[SPNFS_MAX_DATA_SERVERS]; + }; + +-/* getdeviceinfo */ + struct spnfs_msg_getdeviceinfo_args { + u_int32_t devid; + }; + + struct spnfs_msg_getdeviceinfo_res { + int status; +- struct spnfs_getdevicelist_dev dinfo; ++ struct spnfs_device devinfo; + }; + + /* setattr */ +@@ -191,29 +204,41 @@ struct spnfs_msg_commit_res { + union spnfs_msg_args { + struct spnfs_msg_layoutget_args layoutget_args; + struct spnfs_msg_layoutcommit_args layoutcommit_args; +-// struct spnfs_msg_layoutreturn_args layoutreturn_args; +- struct spnfs_msg_getdevicelist_args getdevicelist_args; +- struct spnfs_msg_getdeviceinfo_args getdeviceinfo_args; ++/* ++ struct spnfs_msg_layoutreturn_args layoutreturn_args; ++*/ ++ struct spnfs_msg_getdeviceiter_args getdeviceiter_args; ++ struct spnfs_msg_getdeviceinfo_args getdeviceinfo_args; + struct spnfs_msg_setattr_args setattr_args; + struct spnfs_msg_open_args open_args; + struct spnfs_msg_close_args close_args; +-// struct spnfs_msg_create_args create_args; ++/* ++ struct spnfs_msg_create_args create_args; ++*/ + struct spnfs_msg_remove_args remove_args; +-// struct spnfs_msg_commit_args commit_args; ++/* ++ struct spnfs_msg_commit_args commit_args; ++*/ + }; + + union spnfs_msg_res { + struct spnfs_msg_layoutget_res layoutget_res; + struct spnfs_msg_layoutcommit_res layoutcommit_res; +-// struct spnfs_msg_layoutreturn_res layoutreturn_res; +- struct spnfs_msg_getdevicelist_res getdevicelist_res; +- struct spnfs_msg_getdeviceinfo_res getdeviceinfo_res; ++/* ++ struct spnfs_msg_layoutreturn_res layoutreturn_res; ++*/ ++ struct spnfs_msg_getdeviceiter_res getdeviceiter_res; ++ struct spnfs_msg_getdeviceinfo_res getdeviceinfo_res; + struct spnfs_msg_setattr_res setattr_res; + struct spnfs_msg_open_res open_res; + struct spnfs_msg_close_res close_res; +-// struct spnfs_msg_create_res create_res; ++/* ++ struct spnfs_msg_create_res create_res; ++*/ + struct spnfs_msg_remove_res remove_res; +-// struct spnfs_msg_commit_res commit_res; ++/* ++ struct spnfs_msg_commit_res commit_res; ++*/ + }; + + /* a spnfs message, args and response */ +@@ -238,16 +263,19 @@ struct spnfs { + + int spnfs_layout_type(void); + int spnfs_layoutget(struct inode *, void *); +-int spnfs_layoutcomit(void); +-int spnfs_layoutreturn(void); +-int spnfs_getdevicelist(struct super_block *, void *); +-int spnfs_getdeviceinfo(void); ++int spnfs_layoutcommit(void); ++int spnfs_layoutreturn(struct inode *, void *); ++int spnfs_getdeviceiter(struct super_block *, struct pnfs_deviter_arg *); ++int spnfs_getdeviceinfo(struct super_block *, struct pnfs_devinfo_arg *); + int spnfs_setattr(void); + int spnfs_open(struct inode *, void *); ++int spnfs_get_state(struct inode *, void *, void *); ++int spnfs_remove(unsigned long ino); + + int nfsd_spnfs_new(void); + void nfsd_spnfs_delete(void); + int spnfs_upcall(struct spnfs *, struct spnfs_msg *, union spnfs_msg_res *); ++int spnfs_enabled(void); + + #endif /* __KERNEL__ */ + +diff --git a/utils/spnfsd/spnfsd.c b/utils/spnfsd/spnfsd.c +index 276b0c3..f7bae84 100644 +--- a/utils/spnfsd/spnfsd.c ++++ b/utils/spnfsd/spnfsd.c +@@ -114,6 +114,7 @@ static void dump_config(); + int verbose = 0; + int stripesize = DEFAULT_STRIPE_SIZE; + int densestriping = 0; ++int num_dev = 1; /* XXX no multiple device support yet */ + int num_ds; + struct dserver dataservers[SPNFS_MAX_DATA_SERVERS]; + char dsmountdir[PATH_MAX]; +@@ -315,8 +316,8 @@ spnfs_msg_handler(struct spnfs_client *scp, struct spnfs_msg *im) + case SPNFS_TYPE_LAYOUTRETURN: + err = spnfsd_layoutreturn(im); + break; +- case SPNFS_TYPE_GETDEVICELIST: +- err = spnfsd_getdevicelist(im); ++ case SPNFS_TYPE_GETDEVICEITER: ++ err = spnfsd_getdeviceiter(im); + break; + case SPNFS_TYPE_GETDEVICEINFO: + err = spnfsd_getdeviceinfo(im); +@@ -459,7 +460,7 @@ read_config() + char *xpipefsdir = NULL; + char *xdsmountdir = NULL; + int ds; +- char ipstr[20], portstr[20], rootstr[20], devidstr[20]; ++ char ipstr[20], portstr[20], rootstr[20], dsidstr[20]; + + verbose = conf_get_num("General", "Verbosity", 0); + stripesize = conf_get_num("General", "Stripe-size",DEFAULT_STRIPE_SIZE); +@@ -478,7 +479,7 @@ read_config() + sprintf(ipstr, "DS%d_IP", ds); + sprintf(portstr, "DS%d_PORT", ds); + sprintf(rootstr, "DS%d_ROOT", ds); +- sprintf(devidstr, "DS%d_DEVID", ds); ++ sprintf(dsidstr, "DS%d_ID", ds); + CONF_SAVE(dataservers[ds-1].ds_ip, + conf_get_str("DataServers", ipstr)); + if (dataservers[ds-1].ds_ip == NULL) +@@ -489,10 +490,10 @@ read_config() + conf_get_str("DataServers", rootstr)); + if (dataservers[ds-1].ds_ip == NULL) + spnfsd_err(1, "Missing IP for DS%d\n", ds); +- dataservers[ds-1].ds_devid = +- conf_get_num("DataServers", devidstr, -1); +- if (dataservers[ds-1].ds_devid < 0) +- spnfsd_err(1, "Missing or invalid DEVID for DS%d\n", ds); ++ dataservers[ds-1].ds_id = ++ conf_get_num("DataServers", dsidstr, -1); ++ if (dataservers[ds-1].ds_id < 0) ++ spnfsd_err(1, "Missing or invalid ID for DS%d\n", ds); + } + + return 0; +@@ -512,7 +513,7 @@ dump_config() + printf("DS%d IP: %s\n", ds+1, dataservers[ds].ds_ip); + printf("DS%d PORT: %d\n", ds+1, dataservers[ds].ds_port); + printf("DS%d ROOT: %s\n", ds+1, dataservers[ds].ds_path); +- printf("DS%d DEVID: %d\n", ds+1, dataservers[ds].ds_devid); ++ printf("DS%d DSID: %d\n", ds+1, dataservers[ds].ds_id); + } + } + +diff --git a/utils/spnfsd/spnfsd.conf b/utils/spnfsd/spnfsd.conf +index 0839c11..57621fc 100644 +--- a/utils/spnfsd/spnfsd.conf ++++ b/utils/spnfsd/spnfsd.conf +@@ -13,9 +13,9 @@ NumDS = 2 + DS1_IP = 172.16.28.134 + DS1_PORT = 2049 + DS1_ROOT = /pnfs +-DS1_DEVID = 1 ++DS1_ID = 1 + + DS2_IP = 172.16.28.141 + DS2_PORT = 2049 + DS2_ROOT = /pnfs +-DS2_DEVID = 2 ++DS2_ID = 2 +diff --git a/utils/spnfsd/spnfsd.h b/utils/spnfsd/spnfsd.h +index 9df6cd8..05029e9 100644 +--- a/utils/spnfsd/spnfsd.h ++++ b/utils/spnfsd/spnfsd.h +@@ -42,7 +42,7 @@ struct dserver { + char *ds_ip; + int ds_port; + char *ds_path; +- int ds_devid; ++ int ds_id; + }; + + /* DMXXX future struct for whole config */ +@@ -57,7 +57,7 @@ struct spnfsd_config { + int spnfsd_layoutget(struct spnfs_msg *); + int spnfsd_layoutcommit(struct spnfs_msg *); + int spnfsd_layoutreturn(struct spnfs_msg *); +-int spnfsd_getdevicelist(struct spnfs_msg *); ++int spnfsd_getdeviceiter(struct spnfs_msg *); + int spnfsd_getdeviceinfo(struct spnfs_msg *); + int spnfsd_setattr(struct spnfs_msg *); + int spnfsd_open(struct spnfs_msg *); +diff --git a/utils/spnfsd/spnfsd_ops.c b/utils/spnfsd/spnfsd_ops.c +index 56bd185..81ad102 100644 +--- a/utils/spnfsd/spnfsd_ops.c ++++ b/utils/spnfsd/spnfsd_ops.c +@@ -36,6 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + extern int stripesize; + extern int densestriping; + extern int num_ds; ++extern int num_dev; + extern char dsmountdir[]; + extern struct dserver dataservers[SPNFS_MAX_DATA_SERVERS]; + size_t strlcat(char *, const char *, size_t); +@@ -58,9 +59,8 @@ spnfsd_layoutget(struct spnfs_msg *im) + im->im_res.layoutget_res.layout_count = num_ds; + + for (ds = 0 ; ds < num_ds ; ds++) { +- im->im_res.layoutget_res.flist[ds].dev_id = +- dataservers[ds].ds_devid; +- im->im_res.layoutget_res.flist[ds].dev_index = ds; ++ im->im_res.layoutget_res.flist[ds].dev_id = 1; /* XXX */ ++ im->im_res.layoutget_res.flist[ds].ds_index = ds; + memset(im->im_res.layoutget_res.flist[ds].fh_val, 0, 128); /*DMXXX*/ + sprintf(fullpath, "%s/%s/%ld", + dsmountdir, dataservers[ds].ds_ip, +@@ -112,22 +112,20 @@ spnfsd_layoutreturn(struct spnfs_msg *im) + } + + int +-spnfsd_getdevicelist(struct spnfs_msg *im) ++spnfsd_getdeviceiter(struct spnfs_msg *im) + { +- int ds; +- + im->im_status = SPNFS_STATUS_SUCCESS; +- im->im_res.getdevicelist_res.status = 0; +- im->im_res.getdevicelist_res.count = num_ds; +- for (ds = 0 ; ds < num_ds ; ds++) { +- im->im_res.getdevicelist_res.dlist[ds].devid = +- dataservers[ds].ds_devid; +- memset(im->im_res.getdevicelist_res.dlist[ds].netid, 0, 5); +- strlcpy(im->im_res.getdevicelist_res.dlist[ds].netid, "tcp", 4); +- sprintf(im->im_res.getdevicelist_res.dlist[ds].addr, "%s.%d.%d", +- dataservers[ds].ds_ip, +- dataservers[ds].ds_port >> 8, +- dataservers[ds].ds_port & 0xff); ++ im->im_res.getdeviceiter_res.status = 0; ++ ++ /* verifier ignored for now */ ++ if (im->im_args.getdeviceiter_args.cookie >= num_dev) ++ im->im_res.getdeviceiter_res.eof = 1; ++ else { ++ /* XXX just hardcoded for now...fix this */ ++ im->im_res.getdeviceiter_res.devid = 1; ++ im->im_res.getdeviceiter_res.cookie = im->im_args.getdeviceiter_args.cookie + 1; ++ im->im_res.getdeviceiter_res.verf = 0; ++ im->im_res.getdeviceiter_res.eof = 0; + } + + return 0; +@@ -136,27 +134,34 @@ spnfsd_getdevicelist(struct spnfs_msg *im) + int + spnfsd_getdeviceinfo(struct spnfs_msg *im) + { ++ struct spnfs_device *devp; ++ struct spnfs_data_server *dsp; ++ u_int32_t devid; + int ds; + + im->im_status = SPNFS_STATUS_SUCCESS; +- im->im_res.getdeviceinfo_res.status = ENODEV; ++ im->im_res.getdeviceinfo_res.status = 0; ++ ++ devid = im->im_args.getdeviceinfo_args.devid; ++ ++ /* XXX fix this if/when we support multiple devices */ ++ if (devid != 1) { ++ im->im_res.getdeviceinfo_res.status = ENODEV; ++ return -1; ++ } ++ ++ devp = &im->im_res.getdeviceinfo_res.devinfo; ++ devp->dscount = num_ds; ++ + for (ds = 0 ; ds < num_ds ; ds++) { +- if (dataservers[ds].ds_devid == +- im->im_args.getdeviceinfo_args.devid) { +- im->im_res.getdeviceinfo_res.dinfo.devid = +- dataservers[ds].ds_devid; +- memset(im->im_res.getdeviceinfo_res.dinfo.netid, +- 0, 5); +- strlcpy(im->im_res.getdeviceinfo_res.dinfo.netid, +- "tcp", 4); +- sprintf(im->im_res.getdeviceinfo_res.dinfo.addr, +- "%s.%d.%d", +- dataservers[ds].ds_ip, +- dataservers[ds].ds_port >> 8, +- dataservers[ds].ds_port & 0xff); +- im->im_res.getdeviceinfo_res.status = 0; +- break; +- } ++ dsp = &devp->dslist[ds]; ++ dsp->dsid = dataservers[ds].ds_id; ++ memset(dsp->netid, 0, 5); ++ strlcpy(dsp->netid, "tcp", 4); ++ sprintf(dsp->addr, "%s.%d.%d", ++ dataservers[ds].ds_ip, ++ dataservers[ds].ds_port >> 8, ++ dataservers[ds].ds_port & 0xff); + } + + return 0; diff --git a/nfs-utils-1.2.0-spnfsd-06.patch b/nfs-utils-1.2.0-spnfsd-06.patch new file mode 100644 index 0000000..03cd74f --- /dev/null +++ b/nfs-utils-1.2.0-spnfsd-06.patch @@ -0,0 +1,92 @@ +commit 4c0c700c85cdd097af5d9be2e452d4027e430d0f +Author: Mike Sager +Date: Thu Feb 7 20:19:03 2008 -0800 + + Update layoutget per draft 13 + + Also, change spnfs layoutget handling to reflect generic pnfs interface + changes + + Signed-off-by: Mike Sager + +diff --git a/utils/spnfsd/nfsd4_spnfs.h b/utils/spnfsd/nfsd4_spnfs.h +index 7619c75..4b3ce7f 100644 +--- a/utils/spnfsd/nfsd4_spnfs.h ++++ b/utils/spnfsd/nfsd4_spnfs.h +@@ -58,7 +58,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + #define SPNFS_MAX_DEVICES 1 + #define SPNFS_MAX_DATA_SERVERS 2 +-#define SPNFS_MAX_LAYOUT 8 + + /* layout */ + struct spnfs_msg_layoutget_args { +@@ -66,18 +65,17 @@ struct spnfs_msg_layoutget_args { + }; + + struct spnfs_filelayout_list { +- u_int32_t dev_id; +- u_int32_t ds_index; + u_int32_t fh_len; + unsigned char fh_val[128]; /* DMXXX fix this const */ + }; + + struct spnfs_msg_layoutget_res { + int status; ++ u_int32_t dev_id; + u_int64_t stripe_size; + u_int32_t stripe_type; +- u_int32_t layout_count; +- struct spnfs_filelayout_list flist[SPNFS_MAX_LAYOUT]; ++ u_int32_t stripe_count; ++ struct spnfs_filelayout_list flist[SPNFS_MAX_DATA_SERVERS]; + }; + + /* layoutcommit */ +@@ -262,7 +260,7 @@ struct spnfs { + }; + + int spnfs_layout_type(void); +-int spnfs_layoutget(struct inode *, void *); ++int spnfs_layoutget(struct inode *, struct pnfs_layoutget_arg *); + int spnfs_layoutcommit(void); + int spnfs_layoutreturn(struct inode *, void *); + int spnfs_getdeviceiter(struct super_block *, struct pnfs_deviter_arg *); +diff --git a/utils/spnfsd/spnfsd_ops.c b/utils/spnfsd/spnfsd_ops.c +index 81ad102..645c9eb 100644 +--- a/utils/spnfsd/spnfsd_ops.c ++++ b/utils/spnfsd/spnfsd_ops.c +@@ -51,16 +51,15 @@ spnfsd_layoutget(struct spnfs_msg *im) + + im->im_status = SPNFS_STATUS_SUCCESS; + im->im_res.layoutget_res.status = 0; ++ im->im_res.layoutget_res.dev_id = 1; /* XXX */ + im->im_res.layoutget_res.stripe_size = stripesize; + if (densestriping) +- im->im_res.layoutget_res.stripe_type = 2; /* DMXXX enum */ ++ im->im_res.layoutget_res.stripe_type = 1; /* DMXXX enum */ + else +- im->im_res.layoutget_res.stripe_type = 1; /* DMXXX ^^^^ */ +- im->im_res.layoutget_res.layout_count = num_ds; ++ im->im_res.layoutget_res.stripe_type = 0; /* DMXXX ^^^^ */ ++ im->im_res.layoutget_res.stripe_count = num_ds; + + for (ds = 0 ; ds < num_ds ; ds++) { +- im->im_res.layoutget_res.flist[ds].dev_id = 1; /* XXX */ +- im->im_res.layoutget_res.flist[ds].ds_index = ds; + memset(im->im_res.layoutget_res.flist[ds].fh_val, 0, 128); /*DMXXX*/ + sprintf(fullpath, "%s/%s/%ld", + dsmountdir, dataservers[ds].ds_ip, +@@ -76,10 +75,10 @@ spnfsd_layoutget(struct spnfs_msg *im) + + /* + * MSXXX another hack...fix the hardcoding. +- * The fh's fsid_type is incremented by 5 to get ++ * The fh's fsid_type is incremented by 8 to get + * around stateid checking. + */ +- im->im_res.layoutget_res.flist[ds].fh_val[2] += 5; ++ im->im_res.layoutget_res.flist[ds].fh_val[2] += 8; + } + + return 0; diff --git a/nfs-utils-1.2.0-spnfsd-07.patch b/nfs-utils-1.2.0-spnfsd-07.patch new file mode 100644 index 0000000..c47a55e --- /dev/null +++ b/nfs-utils-1.2.0-spnfsd-07.patch @@ -0,0 +1,91 @@ +commit 6880a92de04cf0d4d606d27d1da60aeff11f8df4 +Author: Mike Sager +Date: Fri Feb 15 03:02:07 2008 -0800 + + Update to draft 19. + + Even though a device id is now 128 bits, the userspace portion is only + concerned with the rightmost 64 bits for now. The leftmost 64 bits + appear to be destined to become an fsid. The generic pnfs layer is + hardcoding this to 0 for the moment. Wait and see how this plays out + before deciding if anything needs to be done in userspace. + + Signed-off-by: Mike Sager + +diff --git a/utils/spnfsd/nfsd4_spnfs.h b/utils/spnfsd/nfsd4_spnfs.h +index 4b3ce7f..6516ab3 100644 +--- a/utils/spnfsd/nfsd4_spnfs.h ++++ b/utils/spnfsd/nfsd4_spnfs.h +@@ -71,7 +71,7 @@ struct spnfs_filelayout_list { + + struct spnfs_msg_layoutget_res { + int status; +- u_int32_t dev_id; ++ u_int64_t devid; + u_int64_t stripe_size; + u_int32_t stripe_type; + u_int32_t stripe_count; +@@ -107,7 +107,7 @@ struct spnfs_msg_getdeviceiter_args { + + struct spnfs_msg_getdeviceiter_res { + int status; +- u_int32_t devid; ++ u_int64_t devid; + u_int64_t cookie; + u_int64_t verf; + u_int32_t eof; +@@ -121,13 +121,13 @@ struct spnfs_data_server { + }; + + struct spnfs_device { +- u_int32_t devid; ++ u_int64_t devid; + int dscount; + struct spnfs_data_server dslist[SPNFS_MAX_DATA_SERVERS]; + }; + + struct spnfs_msg_getdeviceinfo_args { +- u_int32_t devid; ++ u_int64_t devid; + }; + + struct spnfs_msg_getdeviceinfo_res { +diff --git a/utils/spnfsd/spnfsd.h b/utils/spnfsd/spnfsd.h +index 05029e9..e8527e7 100644 +--- a/utils/spnfsd/spnfsd.h ++++ b/utils/spnfsd/spnfsd.h +@@ -39,9 +39,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + #endif + + struct dserver { +- char *ds_ip; +- int ds_port; +- char *ds_path; ++ char *ds_ip; ++ int ds_port; ++ char *ds_path; + int ds_id; + }; + +diff --git a/utils/spnfsd/spnfsd_ops.c b/utils/spnfsd/spnfsd_ops.c +index 645c9eb..e3adadd 100644 +--- a/utils/spnfsd/spnfsd_ops.c ++++ b/utils/spnfsd/spnfsd_ops.c +@@ -51,7 +51,7 @@ spnfsd_layoutget(struct spnfs_msg *im) + + im->im_status = SPNFS_STATUS_SUCCESS; + im->im_res.layoutget_res.status = 0; +- im->im_res.layoutget_res.dev_id = 1; /* XXX */ ++ im->im_res.layoutget_res.devid = 1; /* XXX */ + im->im_res.layoutget_res.stripe_size = stripesize; + if (densestriping) + im->im_res.layoutget_res.stripe_type = 1; /* DMXXX enum */ +@@ -145,7 +145,7 @@ spnfsd_getdeviceinfo(struct spnfs_msg *im) + + /* XXX fix this if/when we support multiple devices */ + if (devid != 1) { +- im->im_res.getdeviceinfo_res.status = ENODEV; ++ im->im_res.getdeviceinfo_res.status = -ENOENT; + return -1; + } + diff --git a/nfs-utils-1.2.0-spnfsd-08.patch b/nfs-utils-1.2.0-spnfsd-08.patch new file mode 100644 index 0000000..eec11df --- /dev/null +++ b/nfs-utils-1.2.0-spnfsd-08.patch @@ -0,0 +1,266 @@ +commit dfa1f714caaed32ebe64ae9c4f8678e6c56bce5d +Author: Dan Muntz +Date: Tue May 6 16:45:09 2008 -0700 + + Add read/write-through-MDS for spNFS + + Signed-off-by: Dan Muntz + +diff --git a/utils/spnfsd/nfsd4_spnfs.h b/utils/spnfsd/nfsd4_spnfs.h +index 6516ab3..fc6bd9a 100644 +--- a/utils/spnfsd/nfsd4_spnfs.h ++++ b/utils/spnfsd/nfsd4_spnfs.h +@@ -55,9 +55,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + #define SPNFS_TYPE_CREATE 0x09 + #define SPNFS_TYPE_REMOVE 0x0a + #define SPNFS_TYPE_COMMIT 0x0b ++#define SPNFS_TYPE_READ 0x0c ++#define SPNFS_TYPE_WRITE 0x0d + + #define SPNFS_MAX_DEVICES 1 + #define SPNFS_MAX_DATA_SERVERS 2 ++#define SPNFS_MAX_IO 2048 + + /* layout */ + struct spnfs_msg_layoutget_args { +@@ -198,6 +201,30 @@ struct spnfs_msg_commit_res { + }; + */ + ++/* read */ ++struct spnfs_msg_read_args { ++ unsigned long inode; ++ loff_t offset; ++ unsigned long len; ++}; ++ ++struct spnfs_msg_read_res { ++ int status; ++ char data[SPNFS_MAX_IO]; ++}; ++ ++/* write */ ++struct spnfs_msg_write_args { ++ unsigned long inode; ++ loff_t offset; ++ unsigned long len; ++ char data[SPNFS_MAX_IO]; ++}; ++ ++struct spnfs_msg_write_res { ++ int status; ++}; ++ + /* bundle args and responses */ + union spnfs_msg_args { + struct spnfs_msg_layoutget_args layoutget_args; +@@ -217,6 +244,8 @@ union spnfs_msg_args { + /* + struct spnfs_msg_commit_args commit_args; + */ ++ struct spnfs_msg_read_args read_args; ++ struct spnfs_msg_write_args write_args; + }; + + union spnfs_msg_res { +@@ -237,6 +266,8 @@ union spnfs_msg_res { + /* + struct spnfs_msg_commit_res commit_res; + */ ++ struct spnfs_msg_read_res read_res; ++ struct spnfs_msg_write_res write_res; + }; + + /* a spnfs message, args and response */ +@@ -268,7 +299,9 @@ int spnfs_getdeviceinfo(struct super_block *, struct pnfs_devinfo_arg *); + int spnfs_setattr(void); + int spnfs_open(struct inode *, void *); + int spnfs_get_state(struct inode *, void *, void *); +-int spnfs_remove(unsigned long ino); ++int spnfs_remove(unsigned long); ++int spnfs_read(unsigned long, loff_t, unsigned long *, int, struct svc_rqst *); ++int spnfs_write(unsigned long, loff_t, size_t, int, struct svc_rqst *); + + int nfsd_spnfs_new(void); + void nfsd_spnfs_delete(void); +diff --git a/utils/spnfsd/spnfsd.c b/utils/spnfsd/spnfsd.c +index f7bae84..fc9113d 100644 +--- a/utils/spnfsd/spnfsd.c ++++ b/utils/spnfsd/spnfsd.c +@@ -40,6 +40,8 @@ + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + ++#define _LARGEFILE64_SOURCE ++#define _FILE_OFFSET_BITS 64 + #include + #include + #include +@@ -340,6 +342,12 @@ spnfs_msg_handler(struct spnfs_client *scp, struct spnfs_msg *im) + case SPNFS_TYPE_COMMIT: + err = spnfsd_commit(im); + break; ++ case SPNFS_TYPE_READ: ++ err = spnfsd_read(im); ++ break; ++ case SPNFS_TYPE_WRITE: ++ err = spnfsd_write(im); ++ break; + default: + spnfsd_warnx("spnfs_msg_handler: Invalid msg type (%d) in message", + im->im_type); +diff --git a/utils/spnfsd/spnfsd.h b/utils/spnfsd/spnfsd.h +index e8527e7..e05c272 100644 +--- a/utils/spnfsd/spnfsd.h ++++ b/utils/spnfsd/spnfsd.h +@@ -65,4 +65,6 @@ int spnfsd_close(struct spnfs_msg *); + int spnfsd_create(struct spnfs_msg *); + int spnfsd_remove(struct spnfs_msg *); + int spnfsd_commit(struct spnfs_msg *); ++int spnfsd_read(struct spnfs_msg *); ++int spnfsd_write(struct spnfs_msg *); + int spnfsd_getfh(char *, unsigned char *, unsigned int *); +diff --git a/utils/spnfsd/spnfsd_ops.c b/utils/spnfsd/spnfsd_ops.c +index e3adadd..5099c00 100644 +--- a/utils/spnfsd/spnfsd_ops.c ++++ b/utils/spnfsd/spnfsd_ops.c +@@ -20,6 +20,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ******************************************************************************/ + ++#define _LARGEFILE64_SOURCE ++#define _FILE_OFFSET_BITS 64 + #include "nfsd4_spnfs.h" + #include "spnfsd.h" + #include "nfs/nfs.h" +@@ -265,6 +267,130 @@ spnfsd_remove(struct spnfs_msg *im) + int + spnfsd_commit(struct spnfs_msg *im) + { ++ im->im_status = SPNFS_STATUS_SUCCESS; ++ return 0; ++} ++ ++int ++min (unsigned int x, unsigned int y) ++{ ++ if (xim_args.read_args.inode; ++ loff_t offset = im->im_args.read_args.offset; ++ unsigned long len = im->im_args.read_args.len; ++ int ds, iolen; ++ loff_t soffset; ++ int bufoffset = 0; ++ char fullpath[1024]; /* DMXXX */ ++ int fd, err; ++ int completed = 0; ++ ++ im->im_status = SPNFS_STATUS_SUCCESS; ++ im->im_res.read_res.status = 0; ++ if (len > SPNFS_MAX_IO) { ++ im->im_res.read_res.status = -1; ++ return 0; ++ } ++ while (len > 0) { ++ ds = (offset / stripesize) % num_ds; ++ if (densestriping == 0) ++ soffset = offset; ++ else ++ soffset = (offset / num_ds) + (offset % stripesize); ++ iolen = min(len, stripesize - (offset % stripesize)); ++ ++ sprintf(fullpath, "%s/%s/%ld", dsmountdir, ++ dataservers[ds].ds_ip, inode); ++ fd = open(fullpath, O_RDONLY); ++ if (fd < 0) { ++ perror(fullpath); ++ im->im_res.read_res.status = -errno; ++ return 0; /* DMXXX */ ++ } ++ /* DM: add some error checking */ ++ lseek64(fd, offset, SEEK_SET); ++ err = read(fd, ++ (void *)(im->im_res.read_res.data+bufoffset), iolen); ++ close(fd); ++ if (err < 0) { ++ perror("read"); ++ im->im_res.read_res.status = -errno; ++ return 0; /* DMXXX */ ++ } ++ ++ if (err == 0) ++ break; ++ iolen = err; /* number of bytes read */ ++ completed += iolen; ++ len -= iolen; ++ offset += iolen; ++ bufoffset += iolen; ++ } ++ im->im_res.read_res.status = completed; ++ ++ return 0; ++} ++ ++int ++spnfsd_write(struct spnfs_msg *im) ++{ ++ unsigned long inode = im->im_args.write_args.inode; ++ loff_t offset = im->im_args.write_args.offset; ++ size_t len = im->im_args.write_args.len; ++ char *wbuf = im->im_args.write_args.data; ++ int ds, iolen; ++ loff_t soffset; ++ int bufoffset = 0; ++ char fullpath[1024]; /* DMXXX */ ++ int fd, err; ++ int completed = 0; ++ ++ im->im_status = SPNFS_STATUS_SUCCESS; ++ im->im_res.write_res.status = 0; ++ if (len > SPNFS_MAX_IO) { ++ printf("write length > SPNFS_MAX_IO\n"); ++ im->im_res.write_res.status = -1; ++ return 0; ++ } ++ while (len > 0) { ++ ds = (offset / stripesize) % num_ds; ++ if (densestriping == 0) ++ soffset = offset; ++ else ++ soffset = (offset / num_ds) + (offset % stripesize); ++ iolen = min(len, stripesize - (offset % stripesize)); ++ ++ sprintf(fullpath, "%s/%s/%ld", dsmountdir, ++ dataservers[ds].ds_ip, inode); ++ fd = open(fullpath, O_WRONLY); ++ if (fd < 0) { ++ perror(fullpath); ++ im->im_res.write_res.status = -errno; ++ return 0; /* DMXXX */ ++ } ++ /* DM: add some error checking */ ++ lseek64(fd, offset, SEEK_SET); ++ err = write(fd, (void *)(wbuf+bufoffset), iolen); ++ close(fd); ++ if (err < 0) { ++ perror("write"); ++ im->im_res.write_res.status = -errno; ++ return 0; /* DMXXX */ ++ } ++ ++ iolen = err; /* number of bytes read */ ++ completed += iolen; ++ len -= iolen; ++ offset += iolen; ++ bufoffset += iolen; ++ } ++ im->im_res.write_res.status = completed; + return 0; + } + diff --git a/nfs-utils-1.2.0-spnfsd-09.patch b/nfs-utils-1.2.0-spnfsd-09.patch new file mode 100644 index 0000000..ee57e84 --- /dev/null +++ b/nfs-utils-1.2.0-spnfsd-09.patch @@ -0,0 +1,37 @@ +commit 372650b7f45ca612c7908cbec91d87d7f9c5184a +Author: Dan Muntz +Date: Tue Jun 3 15:44:07 2008 -0700 + + Update utils for I/O through MDS, and increased number of DSs + + Signed-off-by: Dan Muntz + +diff --git a/utils/spnfsd/nfsd4_spnfs.h b/utils/spnfsd/nfsd4_spnfs.h +index fc6bd9a..d2b8356 100644 +--- a/utils/spnfsd/nfsd4_spnfs.h ++++ b/utils/spnfsd/nfsd4_spnfs.h +@@ -59,7 +59,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + #define SPNFS_TYPE_WRITE 0x0d + + #define SPNFS_MAX_DEVICES 1 +-#define SPNFS_MAX_DATA_SERVERS 2 ++#define SPNFS_MAX_DATA_SERVERS 16 + #define SPNFS_MAX_IO 2048 + + /* layout */ +@@ -298,6 +298,7 @@ int spnfs_getdeviceiter(struct super_block *, struct pnfs_deviter_arg *); + int spnfs_getdeviceinfo(struct super_block *, struct pnfs_devinfo_arg *); + int spnfs_setattr(void); + int spnfs_open(struct inode *, void *); ++int spnfs_close(struct inode *); + int spnfs_get_state(struct inode *, void *, void *); + int spnfs_remove(unsigned long); + int spnfs_read(unsigned long, loff_t, unsigned long *, int, struct svc_rqst *); +@@ -307,6 +308,7 @@ int nfsd_spnfs_new(void); + void nfsd_spnfs_delete(void); + int spnfs_upcall(struct spnfs *, struct spnfs_msg *, union spnfs_msg_res *); + int spnfs_enabled(void); ++int nfs4_spnfs_propagate_open(struct super_block *, struct svc_fh *, void *); + + #endif /* __KERNEL__ */ + diff --git a/nfs-utils-1.2.0-spnfsd-10.patch b/nfs-utils-1.2.0-spnfsd-10.patch new file mode 100644 index 0000000..43d83bf --- /dev/null +++ b/nfs-utils-1.2.0-spnfsd-10.patch @@ -0,0 +1,21 @@ +commit 300e5106d9626120fd7c411c4ed723498aaca8b9 +Author: Dan Muntz +Date: Thu Jun 12 15:44:17 2008 -0700 + + Reduce size of I/O buffer as a temporary workaround for stack overflow issue. + + Signed-off-by: Dan Muntz + +diff --git a/utils/spnfsd/nfsd4_spnfs.h b/utils/spnfsd/nfsd4_spnfs.h +index d2b8356..b459e30 100644 +--- a/utils/spnfsd/nfsd4_spnfs.h ++++ b/utils/spnfsd/nfsd4_spnfs.h +@@ -60,7 +60,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + #define SPNFS_MAX_DEVICES 1 + #define SPNFS_MAX_DATA_SERVERS 16 +-#define SPNFS_MAX_IO 2048 ++#define SPNFS_MAX_IO 512 + + /* layout */ + struct spnfs_msg_layoutget_args { diff --git a/nfs-utils-1.2.0-spnfsd-installrules.patch b/nfs-utils-1.2.0-spnfsd-installrules.patch new file mode 100644 index 0000000..d7c3ead --- /dev/null +++ b/nfs-utils-1.2.0-spnfsd-installrules.patch @@ -0,0 +1,48 @@ +diff -up nfs-utils-1.2.0/utils/spnfsd/Makefile.am.orig nfs-utils-1.2.0/utils/spnfsd/Makefile.am +--- nfs-utils-1.2.0/utils/spnfsd/Makefile.am.orig 2009-08-27 14:31:56.046010000 -0400 ++++ nfs-utils-1.2.0/utils/spnfsd/Makefile.am 2009-08-27 14:46:41.763597000 -0400 +@@ -28,44 +28,3 @@ spnfsd_SOURCES = \ + spnfsd_LDADD = -levent ../../support/nfs/libnfs.a + + MAINTAINERCLEANFILES = Makefile.in +- +-####################################################################### +-# The following allows the current practice of having +-# daemons renamed during the install to include RPCPREFIX +-# and the KPREFIX +-# This could all be done much easier with program_transform_name +-# ( program_transform_name = s/^/$(RPCPREFIX)$(KPREFIX)/ ) +-# but that also renames the man pages, which the current +-# practice does not do. +-install-exec-hook: +- (cd $(DESTDIR)$(sbindir) && \ +- for p in $(sbin_PROGRAMS); do \ +- mv -f $$p$(EXEEXT) $(RPCPREFIX)$(KPREFIX)$$p$(EXEEXT) ;\ +- done) +-uninstall-hook: +- (cd $(DESTDIR)$(sbindir) && \ +- for p in $(sbin_PROGRAMS); do \ +- rm -f $(RPCPREFIX)$(KPREFIX)$$p$(EXEEXT) ;\ +- done) +- +- +-# XXX This makes some assumptions about what automake does. +-# XXX But there is no install-man-hook or install-man-local. +-install-man: install-man5 install-man8 install-man-links +-uninstall-man: uninstall-man5 uninstall-man8 uninstall-man-links +- +-install-man-links: +- (cd $(DESTDIR)$(man8dir) && \ +- for m in $(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS); do \ +- inst=`echo $$m | sed -e 's/man$$/8/'`; \ +- rm -f $(RPCPREFIX)$$inst ; \ +- $(LN_S) $$inst $(RPCPREFIX)$$inst ; \ +- done) +- +-uninstall-man-links: +- (cd $(DESTDIR)$(man8dir) && \ +- for m in $(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS); do \ +- inst=`echo $$m | sed -e 's/man$$/8/'`; \ +- rm -f $(RPCPREFIX)$$inst ; \ +- done) +- diff --git a/nfs-utils.spec b/nfs-utils.spec index 8c0f31f..604caf6 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: 10%{?dist} +Release: 10.pnfs%{?dist} Epoch: 1 # group all 32bit related archs @@ -29,6 +29,20 @@ Patch103: nfs-utils-1.2.1-rc4.patch Patch200: nfs-utils-1.2.0-proots-rel5.patch +Patch300: pnfs-exports.patch + +Patch401: nfs-utils-1.2.0-spnfsd-01.patch +Patch402: nfs-utils-1.2.0-spnfsd-02.patch +Patch403: nfs-utils-1.2.0-spnfsd-03.patch +Patch404: nfs-utils-1.2.0-spnfsd-04.patch +Patch405: nfs-utils-1.2.0-spnfsd-05.patch +Patch406: nfs-utils-1.2.0-spnfsd-06.patch +Patch407: nfs-utils-1.2.0-spnfsd-07.patch +Patch408: nfs-utils-1.2.0-spnfsd-08.patch +Patch409: nfs-utils-1.2.0-spnfsd-09.patch +Patch410: nfs-utils-1.2.0-spnfsd-10.patch +Patch411: nfs-utils-1.2.0-spnfsd-installrules.patch + Group: System Environment/Daemons Provides: exportfs = %{epoch}:%{version}-%{release} Provides: nfsstat = %{epoch}:%{version}-%{release} @@ -46,6 +60,7 @@ Provides: umount.nfs = %{epoch}:%{version}-%{release} Provides: umount.nfs4 = %{epoch}:%{version}-%{release} Provides: sm-notify = %{epoch}:%{version}-%{release} Provides: start-statd = %{epoch}:%{version}-%{release} +Provides: spnfsd = %{epoch}:%{version}-%{release} License: MIT and GPLv2 and GPLv2+ and BSD Buildroot: %{_tmppath}/%{name}-%{version}-root @@ -83,9 +98,25 @@ This package also contains the mount.nfs and umount.nfs program. %patch101 -p1 %patch102 -p1 %patch103 -p1 - +# proot bits %patch200 -p1 +# pnfs bits +%patch300 -p1 + +# spnfsd bits +%patch401 -p1 +%patch402 -p1 +%patch403 -p1 +%patch404 -p1 +%patch405 -p1 +%patch406 -p1 +%patch407 -p1 +%patch408 -p1 +%patch409 -p1 +%patch410 -p1 +%patch411 -p1 + # Remove .orig files find . -name "*.orig" | xargs rm -f @@ -239,6 +270,7 @@ fi /usr/sbin/rpcdebug /usr/sbin/rpc.mountd /usr/sbin/rpc.nfsd +/usr/sbin/spnfsd /usr/sbin/showmount /usr/sbin/rpc.idmapd /usr/sbin/rpc.gssd @@ -256,6 +288,10 @@ fi %attr(4755,root,root) /sbin/umount.nfs4 %changelog +* Thu Aug 27 2009 Steve Dickson 1.2.0-10.pnfs +- Added in the pnfs export bits. +- Added in the spnfsd daemon + * Mon Aug 17 2009 Steve Dickson 1.2.0-10 - Added upstream 1.2.1-rc4 patch - Fix bug when both crossmnt diff --git a/pnfs-exports.patch b/pnfs-exports.patch new file mode 100644 index 0000000..e5f228c --- /dev/null +++ b/pnfs-exports.patch @@ -0,0 +1,64 @@ +diff -up nfs-utils-1.2.0/support/include/nfslib.h.orig nfs-utils-1.2.0/support/include/nfslib.h +--- nfs-utils-1.2.0/support/include/nfslib.h.orig 2009-08-27 11:56:15.475380000 -0400 ++++ nfs-utils-1.2.0/support/include/nfslib.h 2009-08-27 11:56:32.497258000 -0400 +@@ -90,6 +90,7 @@ struct exportent { + char * e_uuid; + void * e_v4root; + struct sec_entry e_secinfo[SECFLAVOR_COUNT+1]; ++ int e_pnfs; + }; + + struct rmtabent { +diff -up nfs-utils-1.2.0/support/nfs/exports.c.orig nfs-utils-1.2.0/support/nfs/exports.c +--- nfs-utils-1.2.0/support/nfs/exports.c.orig 2009-08-27 11:57:57.945647000 -0400 ++++ nfs-utils-1.2.0/support/nfs/exports.c 2009-08-27 11:59:22.231103000 -0400 +@@ -293,6 +293,8 @@ putexportent(struct exportent *ep) + } + fprintf(fp, "anonuid=%d,anongid=%d", ep->e_anonuid, ep->e_anongid); + secinfo_show(fp, ep); ++ if (ep->e_pnfs) ++ fprintf(fp, ",pnfs"); + fprintf(fp, ")\n"); + } + +@@ -343,6 +345,7 @@ mkexportent(char *hname, char *path, cha + ee.e_fslocmethod = FSLOC_NONE; + ee.e_fslocdata = NULL; + ee.e_secinfo[0].flav = NULL; ++ ee.e_pnfs = 0; + ee.e_nsquids = 0; + ee.e_nsqgids = 0; + ee.e_uuid = NULL; +@@ -552,6 +555,8 @@ parseopts(char *cp, struct exportent *ep + ep->e_flags &= ~NFSEXP_NOACL; + else if (strcmp(opt, "no_acl") == 0) + ep->e_flags |= NFSEXP_NOACL; ++ else if (strcmp(opt, "pnfs") == 0) ++ ep->e_pnfs = 1; + else if (strncmp(opt, "anonuid=", 8) == 0) { + char *oe; + ep->e_anonuid = strtol(opt+8, &oe, 10); +diff -up nfs-utils-1.2.0/utils/exportfs/exportfs.c.orig nfs-utils-1.2.0/utils/exportfs/exportfs.c +--- nfs-utils-1.2.0/utils/exportfs/exportfs.c.orig 2009-06-02 10:43:05.000000000 -0400 ++++ nfs-utils-1.2.0/utils/exportfs/exportfs.c 2009-08-27 12:00:05.139293000 -0400 +@@ -523,6 +523,8 @@ dump(int verbose) + #endif + } + secinfo_show(stdout, ep); ++ if (ep->e_pnfs) ++ c = dumpopt(c, ",pnfs"); + printf("%c\n", (c != '(')? ')' : ' '); + } + } +diff -up nfs-utils-1.2.0/utils/mountd/cache.c.orig nfs-utils-1.2.0/utils/mountd/cache.c +--- nfs-utils-1.2.0/utils/mountd/cache.c.orig 2009-08-27 11:54:17.895168000 -0400 ++++ nfs-utils-1.2.0/utils/mountd/cache.c 2009-08-27 12:01:40.547995000 -0400 +@@ -609,6 +609,8 @@ static int dump_to_cache(FILE *f, char * + qword_printint(f, exp->e_anonuid); + qword_printint(f, exp->e_anongid); + qword_printint(f, exp->e_fsid); ++ if (exp->e_pnfs == 1) ++ qword_print(f, "pnfs"); + write_fsloc(f, exp, path); + write_secinfo(f, exp, flag_mask); + if (exp->e_uuid == NULL || different_fs) {