diff --git a/nfs-utils.spec b/nfs-utils.spec index c5eaab7..33f1285 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.3 -Release: 2%{?dist} +Release: 2.pnfs%{?dist} Epoch: 1 # group all 32bit related archs @@ -26,7 +26,7 @@ Patch101: nfs-utils-1.2.2-statdpath.patch Patch102: nfs-utils-1.2.1-exp-subtree-warn-off.patch Patch103: nfs-utils-1.2.3-sm-notify-res_init.patch -Patch200: pnfs-nfs-utils-1-2-3.patch +Patch200: pnfs-utils-1-2-4-rc1.patch Patch201: nfs-utils-1.2.3-blkmapd-init.patch Group: System Environment/Daemons @@ -131,7 +131,7 @@ install -m 644 utils/mount/nfsmount.conf $RPM_BUILD_ROOT/etc install -m 755 utils/blkmapd/etc/initd/initd.redhat \ $RPM_BUILD_ROOT/etc/rc.d/init.d/blkmapd -install -m 644 %{SOURCE16} $RPM_BUILD_ROOT/etc/modprobe.d/nfsv41 +install -m 644 %{SOURCE16} $RPM_BUILD_ROOT/etc/modprobe.d/nfsv41.conf mkdir -p $RPM_BUILD_ROOT/var/lib/nfs/rpc_pipefs @@ -274,6 +274,9 @@ fi %config(noreplace) /etc/modprobe.d/nfsv41 %changelog +* Tue Nov 9 2010 Steve Dickson 1.2.3-2.pnfs +- Updated to latest upstream release: pnfs-utils-1-2-4-rc1 + * Fri Oct 15 2010 Steve Dickson 1.2.3-2 - Initscripts do not conform to LSB specification (bz 621562) - sm-notify needs to call res_init() before each try (bz 625531) diff --git a/pnfs-nfs-utils-1-2-3.patch b/pnfs-nfs-utils-1-2-3.patch deleted file mode 100644 index cb81fbe..0000000 --- a/pnfs-nfs-utils-1-2-3.patch +++ /dev/null @@ -1,5670 +0,0 @@ -diff -up nfs-utils-1.2.3/configure.ac.orig nfs-utils-1.2.3/configure.ac ---- nfs-utils-1.2.3/configure.ac.orig 2010-10-04 15:47:06.581340251 -0400 -+++ nfs-utils-1.2.3/configure.ac 2010-10-04 15:48:00.049475138 -0400 -@@ -72,11 +72,15 @@ AC_ARG_ENABLE(nfsv4, - enable_nfsv4=yes) - if test "$enable_nfsv4" = yes; then - AC_DEFINE(NFS4_SUPPORTED, 1, [Define this if you want NFSv4 support compiled in]) -+ BLKMAPD=blkmapd - IDMAPD=idmapd -+ SPNFSD=spnfsd - else - enable_nfsv4= -+ BLKMAPD= - IDMAPD= - fi -+ AC_SUBST(BLKMAPD) - AC_SUBST(IDMAPD) - AC_SUBST(enable_nfsv4) - AM_CONDITIONAL(CONFIG_NFSV4, [test "$enable_nfsv4" = "yes"]) -@@ -439,9 +443,11 @@ AC_CONFIG_FILES([ - tools/mountstats/Makefile - tools/nfs-iostat/Makefile - utils/Makefile -+ utils/blkmapd/Makefile - utils/exportfs/Makefile - utils/gssd/Makefile - utils/idmapd/Makefile -+ utils/spnfsd/Makefile - utils/mount/Makefile - utils/mountd/Makefile - utils/nfsd/Makefile -diff -up nfs-utils-1.2.3/support/include/nfslib.h.orig nfs-utils-1.2.3/support/include/nfslib.h ---- nfs-utils-1.2.3/support/include/nfslib.h.orig 2010-09-28 08:24:16.000000000 -0400 -+++ nfs-utils-1.2.3/support/include/nfslib.h 2010-10-04 15:48:00.069391711 -0400 -@@ -89,6 +89,7 @@ struct exportent { - char * e_fslocdata; - char * e_uuid; - struct sec_entry e_secinfo[SECFLAVOR_COUNT+1]; -+ int e_pnfs; - }; - - struct rmtabent { -diff -up nfs-utils-1.2.3/support/include/nfs/nfs.h.orig nfs-utils-1.2.3/support/include/nfs/nfs.h ---- nfs-utils-1.2.3/support/include/nfs/nfs.h.orig 2010-09-28 08:24:16.000000000 -0400 -+++ nfs-utils-1.2.3/support/include/nfs/nfs.h 2010-10-04 15:48:00.050474882 -0400 -@@ -47,6 +47,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)) -@@ -136,6 +137,11 @@ struct nfsctl_fsparm { - int gd_maxlen; - }; - -+/* FD2FH */ -+struct nfsctl_fd2fh { -+ int fd; -+}; -+ - /* - * This is the argument union. - */ -@@ -149,6 +155,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 -@@ -157,6 +164,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.3/support/nfs/exports.c.orig nfs-utils-1.2.3/support/nfs/exports.c ---- nfs-utils-1.2.3/support/nfs/exports.c.orig 2010-10-04 15:47:06.589340404 -0400 -+++ nfs-utils-1.2.3/support/nfs/exports.c 2010-10-04 15:48:00.070350101 -0400 -@@ -107,6 +107,7 @@ static void init_exportent (struct expor - ee->e_nsquids = 0; - ee->e_nsqgids = 0; - ee->e_uuid = NULL; -+ ee->e_pnfs = 0; - } - - struct exportent * -@@ -299,6 +300,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"); - } - -@@ -557,6 +560,10 @@ parseopts(char *cp, struct exportent *ep - clearflags(NFSEXP_NOACL, active, ep); - else if (strcmp(opt, "no_acl") == 0) - setflags(NFSEXP_NOACL, active, ep); -+ else if (strcmp(opt, "pnfs") == 0) -+ ep->e_pnfs = 1; -+ else if (strcmp(opt, "no_pnfs") == 0) -+ ep->e_pnfs = 0; - else if (strncmp(opt, "anonuid=", 8) == 0) { - char *oe; - ep->e_anonuid = strtol(opt+8, &oe, 10); -diff -up nfs-utils-1.2.3/utils/blkmapd/atomicio.c.orig nfs-utils-1.2.3/utils/blkmapd/atomicio.c ---- nfs-utils-1.2.3/utils/blkmapd/atomicio.c.orig 2010-10-04 15:48:00.071418550 -0400 -+++ nfs-utils-1.2.3/utils/blkmapd/atomicio.c 2010-10-04 15:48:00.071418550 -0400 -@@ -0,0 +1,54 @@ -+/* -+ * 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 -+ -+/* -+ * ensure all of data on socket comes through. f==read || f==write -+ */ -+ssize_t atomicio(ssize_t(*f) (int, void *, size_t), 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 nfs-utils-1.2.3/utils/blkmapd/cfg.c.orig nfs-utils-1.2.3/utils/blkmapd/cfg.c ---- nfs-utils-1.2.3/utils/blkmapd/cfg.c.orig 2010-10-04 15:48:00.072379352 -0400 -+++ nfs-utils-1.2.3/utils/blkmapd/cfg.c 2010-10-04 15:48:00.072379352 -0400 -@@ -0,0 +1,248 @@ -+/* -+ * Copyright (c) 2010 EMC Corporation, Haiying Tang -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "device-discovery.h" -+#include "cfg.h" -+ -+char *conf_path = "/etc/blkmapd.conf"; -+ -+struct scan_root_list *scan_root_list_head; -+ -+void bl_release_list(void) -+{ -+ struct scan_root_list *root = scan_root_list_head; -+ struct scan_device_list *disk; -+ -+ while (root) { -+ disk = root->disk; -+ while (disk) { -+ root->disk = disk->next; -+ free(disk->name); -+ free(disk); -+ disk = root->disk; -+ } -+ scan_root_list_head = root->next; -+ free(root->name); -+ free(root); -+ root = scan_root_list_head; -+ } -+} -+ -+struct scan_root_list *bl_alloc_root_list(char *name, int all_disk) -+{ -+ struct scan_root_list *root; -+ -+ root = malloc(sizeof(struct scan_root_list)); -+ if (!root) -+ goto nomem; -+ -+ root->name = strdup(name); -+ if (!root->name) -+ goto nomem; -+ root->next = scan_root_list_head; -+ root->all_disk = all_disk; -+ scan_root_list_head = root; -+ return root; -+ -+ nomem: -+ BL_LOG_ERR("%s: Out of memory!\n", __func__); -+ if (root) -+ free(root); -+ return NULL; -+} -+ -+struct scan_device_list *bl_alloc_device_list(struct scan_root_list *root, -+ char *name) -+{ -+ struct scan_device_list *device; -+ -+ device = malloc(sizeof(struct scan_device_list)); -+ if (!device) -+ goto nomem; -+ -+ device->name = strdup(name); -+ if (!device->name) -+ goto nomem; -+ device->next = root->disk; -+ root->disk = device; -+ return device; -+ -+ nomem: -+ BL_LOG_ERR("%s: Out of memory!\n", __func__); -+ if (device) -+ free(device); -+ return NULL; -+} -+ -+struct scan_device_list *bl_insert_device_list(struct scan_root_list *root, -+ char *name) -+{ -+ struct scan_device_list *device = root->disk; -+ -+ /* Check whether this device has been inserted */ -+ while (device) { -+ if (device->name && !strcmp(device->name, name)) -+ return device; -+ device = device->next; -+ } -+ -+ return bl_alloc_device_list(root, name); -+} -+ -+struct scan_root_list *bl_insert_root_list(char *name, int all_disk) -+{ -+ struct scan_root_list *root = scan_root_list_head; -+ -+ /* Check whether this root has been inserted */ -+ while (root) { -+ if (root->name && !strcmp(root->name, name)) -+ return root; -+ root = root->next; -+ } -+ -+ return bl_alloc_root_list(name, all_disk); -+} -+ -+int bl_parse_line(char *line, struct scan_root_list **bl_root) -+{ -+ char *root, *device, *end; -+ -+ root = strdup(line); -+ end = root + strlen(line); -+ -+ /* Skip comments */ -+ if (*root == '#') -+ return 0; -+ -+ /* Trim leading space */ -+ while (*root != '\0' && isspace(*root)) -+ root++; -+ if (*root == '\0') -+ return 0; -+ -+ /* Trim trailing space and set "end" to last char */ -+ while ((isspace(*end) || (*end == '\0')) && (end > root)) -+ end--; -+ -+ /* For lines ending with '/' or '/','*': add as a dir root */ -+ if ((*end == '/') || -+ ((*end == '*') && (end - root >= 1) && (*(end - 1) == '/'))) { -+ if (*end == '*') -+ end--; -+ if (*end == '/') -+ end--; -+ *(end + 1) = '\0'; -+ *bl_root = bl_insert_root_list(root, 1); -+ return 0; -+ } -+ -+ /* Other lines: add as a device */ -+ device = end; -+ while ((*device != '/') && (device > root)) -+ device--; -+ if (device == root) { -+ BL_LOG_ERR("%s: invalid config line\n", __func__); -+ return -1; -+ } -+ *device = '\0'; -+ *bl_root = bl_insert_root_list(root, 0); -+ if (*bl_root == NULL) -+ return -ENOMEM; -+ if (*end == '*') -+ end--; -+ *(end + 1) = '\0'; -+ if (bl_insert_device_list(*bl_root, device + 1) == NULL) -+ return -ENOMEM; -+ -+ return 0; -+} -+ -+int bl_set_default_conf(void) -+{ -+ struct scan_root_list *root = NULL; -+ int rv; -+ -+ bl_release_list(); -+ rv = bl_parse_line("/dev/sd*", &root); -+ if (rv < 0) -+ return rv; -+ rv = bl_parse_line("/dev/mapper/", &root); -+ return rv; -+} -+ -+int bl_parse_conf(char *buf) -+{ -+ char *tmp = buf, *line = buf, *end = buf + strlen(buf); -+ struct scan_root_list *bl_root = NULL; -+ int rv; -+ -+ while (tmp < end) { -+ if (*tmp == '\n') { -+ *tmp = '\0'; -+ rv = bl_parse_line(line, &bl_root); -+ if (rv < 0) -+ return rv; -+ line = tmp + 1; -+ } -+ tmp++; -+ } -+ -+ return 0; -+} -+ -+int bl_cfg_init(void) -+{ -+ struct scan_root_list *root = NULL; -+ FILE *f = NULL; -+ char buf[PATH_MAX]; -+ int rv = 0; -+ -+ f = fopen(conf_path, "r"); -+ if (f == NULL) -+ rv = bl_set_default_conf(); -+ else { -+ while (fgets(buf, sizeof buf, f) != NULL) { -+ rv = bl_parse_line(buf, &root); -+ if (rv < 0) -+ break; -+ } -+ } -+ if (!scan_root_list_head) -+ rv = -EINVAL; -+ -+ if (f) -+ fclose(f); -+ return rv; -+} -diff -up nfs-utils-1.2.3/utils/blkmapd/cfg.h.orig nfs-utils-1.2.3/utils/blkmapd/cfg.h ---- nfs-utils-1.2.3/utils/blkmapd/cfg.h.orig 2010-10-04 15:48:00.072379352 -0400 -+++ nfs-utils-1.2.3/utils/blkmapd/cfg.h 2010-10-04 15:48:00.072379352 -0400 -@@ -0,0 +1,47 @@ -+/* -+ * bl-cfg.h -+ * -+ * Copyright (c) 2010 EMC Corporation, Haiying Tang -+ * 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. -+ */ -+#ifndef BL_CFG_H -+#define BL_CFG_H -+ -+extern char *conf_path; -+extern struct scan_root_list *scan_root_list_head; -+ -+struct scan_device_list { -+ struct scan_device_list *next; -+ char *name; -+}; -+ -+struct scan_root_list { -+ struct scan_root_list *next; -+ unsigned int all_disk; -+ char *name; -+ struct scan_device_list *disk; -+}; -+ -+int bl_cfg_init(void); -+ -+#endif -diff -up nfs-utils-1.2.3/utils/blkmapd/device-discovery.c.orig nfs-utils-1.2.3/utils/blkmapd/device-discovery.c ---- nfs-utils-1.2.3/utils/blkmapd/device-discovery.c.orig 2010-10-04 15:48:00.073350775 -0400 -+++ nfs-utils-1.2.3/utils/blkmapd/device-discovery.c 2010-10-04 15:48:00.073350775 -0400 -@@ -0,0 +1,502 @@ -+/* -+ * device-discovery.c: main function, discovering device and processing -+ * pipe request from kernel. -+ * -+ * Copyright (c) 2010 EMC Corporation, Haiying Tang -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "device-discovery.h" -+#include "cfg.h" -+ -+#define BL_PIPE_FILE "/var/lib/nfs/rpc_pipefs/bl_device_pipe" -+#define PID_FILE "/var/run/blkmapd.pid" -+ -+struct bl_disk *visible_disk_list; -+ -+struct bl_disk_path *bl_get_path(const char *filepath, -+ struct bl_disk_path *paths) -+{ -+ struct bl_disk_path *tmp = paths; -+ while (tmp) { -+ if (!strcmp(tmp->full_path, filepath)) -+ break; -+ tmp = tmp->next; -+ } -+ return tmp; -+} -+ -+/* Check whether valid_path is a substring(partition) of path */ -+int bl_is_partition(struct bl_disk_path *valid_path, struct bl_disk_path *path) -+{ -+ if (!strncmp(valid_path->full_path, path->full_path, -+ strlen(valid_path->full_path))) -+ return 1; -+ -+ return 0; -+} -+ -+/* -+ * For multipath devices, devices state could be PASSIVE/ACTIVE/PSEUDO, -+ * where PSEUDO > ACTIVE > PASSIVE. Device with highest state is used to -+ * create pseudo device. So if state is higher, the device path needs to -+ * be updated. -+ * If device-mapper multipath support is a must, pseudo devices should -+ * exist for each multipath device. If not, active device path will be -+ * chosen for device creation. -+ * Treat partition as invalid path. -+ */ -+int bl_update_path(struct bl_disk_path *path, enum bl_path_state_e state, -+ struct bl_disk *disk) -+{ -+ struct bl_disk_path *valid_path = disk->valid_path; -+ -+ if (valid_path) { -+ if (valid_path->state >= state) { -+ if (bl_is_partition(valid_path, path)) -+ return 0; -+ } -+ } -+ return 1; -+} -+ -+void bl_release_disk(void) -+{ -+ struct bl_disk *disk; -+ struct bl_disk_path *path = NULL; -+ -+ while (visible_disk_list) { -+ disk = visible_disk_list; -+ path = disk->paths; -+ while (path) { -+ disk->paths = path->next; -+ free(path->full_path); -+ free(path); -+ path = disk->paths; -+ } -+ if (disk->serial) -+ free(disk->serial); -+ visible_disk_list = disk->next; -+ free(disk); -+ } -+} -+ -+void bl_add_disk(char *filepath) -+{ -+ struct bl_disk *disk = NULL; -+ int fd = 0; -+ struct stat sb; -+ off_t size = 0; -+ struct bl_serial *serial = NULL; -+ enum bl_path_state_e ap_state = BL_PATH_STATE_PASSIVE; -+ struct bl_disk_path *diskpath = NULL, *path = NULL; -+ dev_t dev; -+ -+ BL_LOG_ERR("%s: %s\n", __func__, filepath); -+ -+ fd = open(filepath, O_RDONLY | O_LARGEFILE); -+ if (fd < 0) -+ return; -+ -+ if (fstat(fd, &sb)) { -+ close(fd); -+ return; -+ } -+ -+ if (!sb.st_size) -+ ioctl(fd, BLKGETSIZE, &size); -+ else -+ size = sb.st_size; -+ -+ if (!size) { -+ close(fd); -+ return; -+ } -+ -+ dev = sb.st_rdev; -+ serial = bldev_read_serial(fd, filepath); -+ -+ for (disk = visible_disk_list; disk != NULL; disk = disk->next) { -+ /* Already scanned or a partition? -+ * XXX: if released each time, maybe not need to compare -+ */ -+ if ((serial->len == disk->serial->len) && -+ !memcmp(serial->data, disk->serial->data, serial->len)) { -+ diskpath = bl_get_path(filepath, disk->paths); -+ break; -+ } -+ } -+ -+ if (disk && diskpath) { -+ close(fd); -+ return; -+ } -+ -+ bldev_read_ap_state(fd, &ap_state); -+ close(fd); -+ -+ /* -+ * Not sure how to identify a pseudo device created by -+ * device-mapper, so leave /dev/mapper for now. -+ */ -+ if (strncmp(filepath, "/dev/mapper", 11) == 0) -+ ap_state = BL_PATH_STATE_PSEUDO; -+ -+ /* add path */ -+ path = malloc(sizeof(struct bl_disk_path)); -+ if (!path) { -+ BL_LOG_ERR("%s: Out of memory!\n", __func__); -+ goto out_err; -+ } -+ path->next = NULL; -+ path->state = ap_state; -+ path->full_path = strdup(filepath); -+ if (!path->full_path) -+ goto out_err; -+ -+ if (!disk) { /* add disk */ -+ disk = malloc(sizeof(struct bl_disk)); -+ if (!disk) { -+ BL_LOG_ERR("%s: Out of memory!\n", __func__); -+ goto out_err; -+ } -+ disk->next = visible_disk_list; -+ disk->dev = dev; -+ disk->size = size; -+ disk->serial = serial; -+ disk->valid_path = path; -+ disk->paths = path; -+ visible_disk_list = disk; -+ } else { -+ path->next = disk->paths; -+ disk->paths = path; -+ /* check whether we need to update disk info */ -+ if (bl_update_path(path, path->state, disk)) { -+ disk->dev = dev; -+ disk->size = size; -+ disk->valid_path = path; -+ } -+ } -+ return; -+ -+ out_err: -+ if (path) { -+ if (path->full_path) -+ free(path->full_path); -+ free(path); -+ } -+ return; -+} -+ -+void bl_devicescan(const char *filename, struct scan_root_list *root) -+{ -+ /* scan all disks */ -+ char filepath[PATH_MAX]; -+ struct scan_device_list *device; -+ -+ if (!strcmp(filename, ".") || !strcmp(filename, "..")) -+ return; -+ -+ memset(filepath, 0, sizeof(filepath)); -+ if (strlen(filename) < (PATH_MAX - strlen(root->name) - 2)) -+ sprintf(filepath, "%s/%s", root->name, filename); -+ else { -+ BL_LOG_ERR("%s: name too long\n", __func__); -+ return; -+ } -+ if (root->all_disk) -+ goto valid; -+ -+ device = root->disk; -+ while (device) { -+ /* If device->name is a subset of filename, this disk should be -+ * valid for scanning. -+ * For example, device->name is "sd", filename is "sda". -+ */ -+ if (device->name -+ && !memcmp(filename, device->name, strlen(device->name))) -+ goto valid; -+ device = device->next; -+ } -+ -+ return; -+ -+ valid: -+ /* -+ * sg device is not a real device, but a device created according -+ * to each scsi device. It won't be used for pseudo device creation. -+ * I moved it here, so that sg devices will not be scanned. -+ */ -+ if (!strncmp(filepath, "/dev/sg", 7)) -+ return; -+ bl_add_disk(filepath); -+ return; -+} -+ -+int bl_discover_devices(void) -+{ -+ DIR *dir; -+ struct dirent *dp; -+ struct scan_root_list *root = scan_root_list_head; -+ -+ /* release previous list */ -+ bl_release_disk(); -+ -+ /* scan all disks */ -+ while (root) { -+ dir = opendir(root->name); -+ if (dir == NULL) { -+ root = root->next; -+ continue; -+ } -+ -+ while ((dp = readdir(dir)) != NULL) -+ bl_devicescan(dp->d_name, root); -+ -+ root = root->next; -+ closedir(dir); -+ } -+ -+ return 0; -+} -+ -+/* process kernel request -+ * return 0: request processed, and no more request waiting; -+ * return 1: request processed, and more requests waiting; -+ * return < 0: error -+ */ -+int bl_disk_inquiry_process(int fd) -+{ -+ int ret = 0; -+ struct pipefs_hdr *head = NULL, *tmp; -+ char *buf = NULL; -+ uint32_t major, minor; -+ uint16_t buflen; -+ unsigned int len = 0; -+ -+ head = calloc(1, sizeof(struct pipefs_hdr)); -+ if (!head) { -+ BL_LOG_ERR("%s: Out of memory!\n", __func__); -+ return -ENOMEM; -+ } -+ -+ /* read request */ -+ if (atomicio(read, fd, head, sizeof(*head)) != sizeof(*head)) { -+ /* Note that an error in this or the next read is pretty -+ * catastrophic, as there is no good way to resync into -+ * the pipe's stream. -+ */ -+ BL_LOG_ERR("Read pipefs head error!\n"); -+ ret = -EIO; -+ goto out; -+ } -+ -+ buflen = head->totallen - sizeof(*head); -+ buf = malloc(buflen); -+ if (!buf) { -+ BL_LOG_ERR("%s: Out of memory!\n", __func__); -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ if (atomicio(read, fd, buf, buflen) != buflen) { -+ BL_LOG_ERR("Read pipefs content error!\n"); -+ ret = -EIO; -+ goto out; -+ } -+ -+ head->status = BL_DEVICE_REQUEST_PROC; -+ switch (head->type) { -+ case BL_DEVICE_MOUNT: -+ if (!process_deviceinfo(buf, buflen, &major, &minor)) { -+ head->status = BL_DEVICE_REQUEST_ERR; -+ goto out; -+ } -+ tmp = realloc(head, sizeof(major) + sizeof(minor) + -+ sizeof(struct pipefs_hdr)); -+ if (!tmp) { -+ BL_LOG_ERR("%s: Out of memory!\n", __func__); -+ ret = -ENOMEM; -+ goto out; -+ } -+ head = tmp; -+ memcpy((void *)head + sizeof(struct pipefs_hdr), -+ &major, sizeof(major)); -+ memcpy((void *)head + sizeof(struct pipefs_hdr) + sizeof(major), -+ &minor, sizeof(minor)); -+ len = sizeof(major) + sizeof(minor); -+ break; -+ case BL_DEVICE_UMOUNT: -+ if (!dm_device_remove_all((uint64_t *) buf)) -+ head->status = BL_DEVICE_REQUEST_ERR; -+ bl_discover_devices(); -+ break; -+ default: -+ head->status = BL_DEVICE_REQUEST_ERR; -+ } -+ -+ head->totallen = sizeof(struct pipefs_hdr) + len; -+ /* write to pipefs */ -+ if (atomicio((void *)write, fd, head, head->totallen) -+ != head->totallen) { -+ BL_LOG_ERR("Write pipefs error!\n"); -+ ret = -EIO; -+ } -+ -+ out: -+ if (buf) -+ free(buf); -+ if (head) -+ free(head); -+ return ret; -+} -+ -+/* TODO: set bl_process_stop to 1 in command */ -+unsigned int bl_process_stop; -+ -+int bl_run_disk_inquiry_process(int fd) -+{ -+ fd_set rset; -+ struct timeval tv; -+ int ret; -+ -+ bl_process_stop = 0; -+ -+ for (;;) { -+ if (bl_process_stop) -+ return 1; -+ FD_ZERO(&rset); -+ FD_SET(fd, &rset); -+ ret = 0; -+ tv.tv_sec = BL_DEVICE_DISCOVERY_INTERVAL; -+ switch (select(fd + 1, &rset, NULL, NULL, &tv)) { -+ case -1: -+ if (errno == EINTR) -+ continue; -+ else { -+ ret = -errno; -+ goto out; -+ } -+ case 0: -+ goto out; -+ default: -+ if (FD_ISSET(fd, &rset)) -+ ret = bl_disk_inquiry_process(fd); -+ } -+ } -+ out: -+ return ret; -+} -+ -+/* Daemon */ -+int main(int argc, char **argv) -+{ -+ int fd, opt, fg = 0, ret = 1; -+ struct stat statbuf; -+ char pidbuf[64]; -+ -+ while ((opt = getopt(argc, argv, "c:f")) != -1) { -+ switch (opt) { -+ case 'c': -+ conf_path = optarg; -+ break; -+ case 'f': -+ fg = 1; -+ break; -+ } -+ } -+ -+ if (!stat(PID_FILE, &statbuf)) { -+ fprintf(stderr, "Pid file already existed\n"); -+ return -1; -+ } -+ -+ if (!fg && daemon(0, 0) != 0) { -+ fprintf(stderr, "Daemonize failed\n"); -+ return -1; -+ } -+ -+ openlog("blkmapd", LOG_PID, 0); -+ fd = open(PID_FILE, O_WRONLY | O_CREAT, 0644); -+ if (fd < 0) { -+ BL_LOG_ERR("Create pid file failed\n"); -+ return -1; -+ } -+ -+ if (lockf(fd, F_TLOCK, 0) < 0) { -+ BL_LOG_ERR("Lock pid file failed\n"); -+ close(fd); -+ return -1; -+ } -+ ftruncate(fd, 0); -+ sprintf(pidbuf, "%d\n", getpid()); -+ write(fd, pidbuf, strlen(pidbuf)); -+ -+ /* open pipe file */ -+ fd = open(BL_PIPE_FILE, O_RDWR); -+ if (fd < 0) { -+ BL_LOG_ERR("open pipe file error\n"); -+ return -1; -+ } -+ -+ ret = bl_cfg_init(); -+ if (ret < 0) { -+ if (ret == -ENOENT) -+ BL_LOG_WARNING("Config file not exist, use default\n"); -+ else { -+ BL_LOG_ERR("Open/read Block pNFS config file error\n"); -+ return -1; -+ } -+ } -+ -+ while (1) { -+ /* discover device when needed */ -+ bl_discover_devices(); -+ -+ ret = bl_run_disk_inquiry_process(fd); -+ if (ret < 0) { -+ /* what should we do with process error? */ -+ BL_LOG_ERR("inquiry process return %d\n", ret); -+ } -+ } -+ close(fd); -+ return ret; -+} -diff -up nfs-utils-1.2.3/utils/blkmapd/device-discovery.h.orig nfs-utils-1.2.3/utils/blkmapd/device-discovery.h ---- nfs-utils-1.2.3/utils/blkmapd/device-discovery.h.orig 2010-10-04 15:48:00.073350775 -0400 -+++ nfs-utils-1.2.3/utils/blkmapd/device-discovery.h 2010-10-04 15:48:00.073350775 -0400 -@@ -0,0 +1,162 @@ -+/* -+ * bl-device-discovery.h -+ * -+ * Copyright (c) 2010 EMC Corporation, Haiying Tang -+ * 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. -+ */ -+#ifndef BL_DEVICE_DISCOVERY_H -+#define BL_DEVICE_DISCOVERY_H -+ -+#define BL_DEVICE_DISCOVERY_INTERVAL 60 -+ -+#include -+#include -+ -+enum blk_vol_type { -+ BLOCK_VOLUME_SIMPLE = 0, /* maps to a single LU */ -+ BLOCK_VOLUME_SLICE = 1, /* slice of another volume */ -+ BLOCK_VOLUME_CONCAT = 2, /* concatenation of multiple volumes */ -+ BLOCK_VOLUME_STRIPE = 3, /* striped across multiple volumes */ -+ BLOCK_VOLUME_PSEUDO = 4, -+}; -+ -+/* All disk offset/lengths are stored in 512-byte sectors */ -+struct bl_volume { -+ uint32_t bv_type; -+ off_t bv_size; -+ struct bl_volume **bv_vols; -+ int bv_vol_n; -+ union { -+ dev_t bv_dev; /* for BLOCK_VOLUME_SIMPLE(PSEUDO) */ -+ off_t bv_stripe_unit; /* for BLOCK_VOLUME_STRIPE(CONCAT) */ -+ off_t bv_offset; /* for BLOCK_VOLUME_SLICE */ -+ } param; -+}; -+ -+struct bl_sig_comp { -+ int64_t bs_offset; /* In bytes */ -+ uint32_t bs_length; /* In bytes */ -+ char *bs_string; -+}; -+ -+/* Maximum number of signatures components in a simple volume */ -+# define BLOCK_MAX_SIG_COMP 16 -+ -+struct bl_sig { -+ int si_num_comps; -+ struct bl_sig_comp si_comps[BLOCK_MAX_SIG_COMP]; -+}; -+ -+/* -+ * Multipath support: ACTIVE or PSEUDO device is valid, -+ * PASSIVE is a standby for ACTIVE. -+ */ -+enum bl_path_state_e { -+ BL_PATH_STATE_PASSIVE = 1, -+ BL_PATH_STATE_ACTIVE = 2, -+ BL_PATH_STATE_PSEUDO = 3, -+}; -+ -+struct bl_serial { -+ int len; -+ char *data; -+}; -+ -+struct bl_disk_path { -+ struct bl_disk_path *next; -+ char *full_path; -+ enum bl_path_state_e state; -+}; -+ -+struct bl_disk { -+ struct bl_disk *next; -+ struct bl_serial *serial; -+ dev_t dev; -+ off_t size; -+ struct bl_disk_path *valid_path; -+ struct bl_disk_path *paths; -+}; -+ -+struct bl_dev_id { -+ unsigned char type; -+ unsigned char ids; -+ unsigned char reserve; -+ unsigned char len; -+ char data[0]; -+}; -+ -+struct pipefs_hdr { -+ uint32_t msgid; -+ uint8_t type; -+ uint8_t flags; -+ uint16_t totallen; /* length of entire message, including hdr */ -+ uint32_t status; -+}; -+ -+#define BL_DEVICE_UMOUNT 0x0 /* Umount--delete devices */ -+#define BL_DEVICE_MOUNT 0x1 /* Mount--create devices */ -+#define BL_DEVICE_REQUEST_INIT 0x0 /* Start request */ -+#define BL_DEVICE_REQUEST_PROC 0x1 /* User process succeeds */ -+#define BL_DEVICE_REQUEST_ERR 0x2 /* User process fails */ -+ -+uint32_t *blk_overflow(uint32_t * p, uint32_t * end, size_t nbytes); -+ -+#define BLK_READBUF(p, e, nbytes) do { \ -+ p = blk_overflow(p, e, nbytes); \ -+ if (!p) {\ -+ goto out_err;\ -+ } \ -+} while (0) -+ -+#define READ32(x) (x) = ntohl(*p++) -+ -+#define READ64(x) do { \ -+ (x) = (uint64_t)ntohl(*p++) << 32; \ -+ (x) |= ntohl(*p++); \ -+} while (0) -+ -+#define READ_SECTOR(x) do { \ -+ READ64(tmp); \ -+ if (tmp & 0x1ff) { \ -+ goto out_err; \ -+ } \ -+ (x) = tmp >> 9; \ -+} while (0) -+ -+extern struct bl_disk *visible_disk_list; -+uint64_t dm_device_create(struct bl_volume *vols, int num_vols); -+int dm_device_remove_all(uint64_t *dev); -+uint64_t process_deviceinfo(const char *dev_addr_buf, -+ unsigned int dev_addr_len, -+ uint32_t *major, uint32_t *minor); -+ -+extern ssize_t atomicio(ssize_t(*f) (int, void *, size_t), -+ int fd, void *_s, size_t n); -+extern struct bl_serial *bldev_read_serial(int fd, const char *filename); -+extern void bldev_read_ap_state(int fd, enum bl_path_state_e *ap_state_out); -+extern int bl_discover_devices(void); -+ -+#define BL_LOG_WARNING(fmt...) syslog(LOG_WARNING, fmt) -+#define BL_LOG_ERR(fmt...) syslog(LOG_ERR, fmt) -+#define BL_LOG_DEBUG(fmt...) syslog(LOG_DEBUG, fmt) -+#endif -diff -up nfs-utils-1.2.3/utils/blkmapd/device-inq.c.orig nfs-utils-1.2.3/utils/blkmapd/device-inq.c ---- nfs-utils-1.2.3/utils/blkmapd/device-inq.c.orig 2010-10-04 15:48:00.074563030 -0400 -+++ nfs-utils-1.2.3/utils/blkmapd/device-inq.c 2010-10-04 15:48:00.074563030 -0400 -@@ -0,0 +1,235 @@ -+/* -+ * device-inq.c: inquire SCSI device information. -+ * -+ * Copyright (c) 2010 EMC Corporation, Haiying Tang -+ * All rights reserved. -+ * -+ * This program refers to "SCSI Primary Commands - 3 (SPC-3) -+ * at http://www.t10.org and sg_inq.c in sg3_utils-1.26 for -+ * Linux OS SCSI subsystem, by D. Gilbert. -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "device-discovery.h" -+ -+#define DEF_ALLOC_LEN 255 -+#define MX_ALLOC_LEN (0xc000 + 0x80) -+ -+struct bl_serial *bl_create_scsi_string(int len, const char *bytes) -+{ -+ struct bl_serial *s; -+ s = malloc(sizeof(*s) + len); -+ if (s) { -+ s->data = (char *)&s[1]; -+ s->len = len; -+ memcpy(s->data, bytes, len); -+ } -+ return s; -+} -+ -+void bl_free_scsi_string(struct bl_serial *str) -+{ -+ if (str) -+ free(str); -+} -+ -+#define sg_io_ok(io_hdr) \ -+ ((((io_hdr).status & 0x7e) == 0) && \ -+ ((io_hdr).host_status == 0) && \ -+ (((io_hdr).driver_status & 0x0f) == 0)) -+ -+static int sg_timeout = 1 * 1000; -+ -+static int bldev_inquire_page(int fd, int page, char *buffer, int len) -+{ -+ unsigned char cmd[] = { INQUIRY, 0, 0, 0, 0, 0 }; -+ unsigned char sense_b[28]; -+ struct sg_io_hdr io_hdr; -+ if (page >= 0) { -+ cmd[1] = 1; -+ cmd[2] = page; -+ } -+ cmd[3] = (unsigned char)((len >> 8) & 0xff); -+ cmd[4] = (unsigned char)(len & 0xff); -+ -+ memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); -+ io_hdr.interface_id = 'S'; -+ io_hdr.cmd_len = sizeof(cmd); -+ io_hdr.mx_sb_len = sizeof(sense_b); -+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; -+ io_hdr.dxfer_len = len; -+ io_hdr.dxferp = buffer; -+ io_hdr.cmdp = cmd; -+ io_hdr.sbp = sense_b; -+ io_hdr.timeout = sg_timeout; -+ if (ioctl(fd, SG_IO, &io_hdr) < 0) -+ return -1; -+ -+ if (sg_io_ok(io_hdr)) -+ return 0; -+ return -1; -+} -+ -+int bldev_inquire_pages(int fd, int page, char **buffer) -+{ -+ int status = 0; -+ char *tmp; -+ int len; -+ -+ *buffer = calloc(DEF_ALLOC_LEN, sizeof(char)); -+ if (!*buffer) { -+ BL_LOG_ERR("%s: Out of memory!\n", __func__); -+ return -ENOMEM; -+ } -+ -+ status = bldev_inquire_page(fd, page, *buffer, DEF_ALLOC_LEN); -+ if (status) -+ goto out; -+ -+ status = -1; -+ if ((*(*buffer + 1) & 0xff) != page) -+ goto out; -+ -+ len = (*(*buffer + 2) << 8) + *(*buffer + 3) + 4; -+ if (len > MX_ALLOC_LEN) { -+ BL_LOG_ERR("SCSI response length too long: %d\n", len); -+ goto out; -+ } -+ if (len > DEF_ALLOC_LEN) { -+ tmp = realloc(*buffer, len); -+ if (!tmp) { -+ BL_LOG_ERR("%s: Out of memory!\n", __func__); -+ status = -ENOMEM; -+ goto out; -+ } -+ *buffer = tmp; -+ status = bldev_inquire_page(fd, page, *buffer, len); -+ if (status) -+ goto out; -+ } -+ status = 0; -+ out: -+ return status; -+} -+ -+/* For EMC multipath devices, use VPD page (0xc0) to get status. -+ * For other devices, return ACTIVE for now -+ */ -+void bldev_read_ap_state(int fd, enum bl_path_state_e *ap_state_out) -+{ -+ int status = 0; -+ char *buffer; -+ -+ *ap_state_out = BL_PATH_STATE_ACTIVE; -+ -+ status = bldev_inquire_pages(fd, 0xc0, &buffer); -+ if (status) -+ goto out; -+ -+ if (buffer[4] < 0x02) -+ *ap_state_out = BL_PATH_STATE_PASSIVE; -+ out: -+ if (buffer) -+ free(buffer); -+ return; -+} -+ -+struct bl_serial *bldev_read_serial(int fd, const char *filename) -+{ -+ struct bl_serial *serial_out = NULL; -+ int status = 0, pos, len; -+ char *buffer; -+ struct bl_dev_id *dev_root, *dev_id; -+ unsigned int current_id = 0; -+ -+ status = bldev_inquire_pages(fd, 0x83, &buffer); -+ if (status) -+ goto out; -+ -+ dev_root = (struct bl_dev_id *)buffer; -+ -+ pos = 0; -+ current_id = 0; -+ len = dev_root->len; -+ while (pos < (len - sizeof(struct bl_dev_id) + sizeof(unsigned char))) { -+ dev_id = (struct bl_dev_id *)&(dev_root->data[pos]); -+ if ((dev_id->ids & 0xf) < current_id) -+ continue; -+ switch (dev_id->ids & 0xf) { -+ /* We process SCSI ID with four ID cases: 0, 1, 2 and 3. -+ * When more than one ID is available, priority is -+ * 3>2>1>0. -+ */ -+ case 2: /* EUI-64 based */ -+ if ((dev_id->len != 8) && (dev_id->len != 12) && -+ (dev_id->len != 16)) { -+ BL_LOG_ERR("EUI-64 only decodes 8, " -+ "12 and 16\n"); -+ break; -+ } -+ case 3: /* NAA */ -+ /* TODO: NAA validity judgement too complicated, -+ * so just ingore it here. -+ */ -+ if ((dev_id->type & 0xf) != 1) { -+ BL_LOG_ERR("Binary code_set expected\n"); -+ break; -+ } -+ case 0: /* vendor specific */ -+ case 1: /* T10 vendor identification */ -+ current_id = dev_id->ids & 0xf; -+ if (serial_out) -+ bl_free_scsi_string(serial_out); -+ serial_out = bl_create_scsi_string(dev_id->len, -+ dev_id->data); -+ break; -+ default: -+ break; -+ } -+ if (current_id == 3) -+ break; -+ pos += (dev_id->len + sizeof(struct bl_dev_id) - -+ sizeof(unsigned char)); -+ } -+ out: -+ if (!serial_out) -+ serial_out = bl_create_scsi_string(strlen(filename), filename); -+ if (buffer) -+ free(buffer); -+ return serial_out; -+} -diff -up nfs-utils-1.2.3/utils/blkmapd/device-process.c.orig nfs-utils-1.2.3/utils/blkmapd/device-process.c ---- nfs-utils-1.2.3/utils/blkmapd/device-process.c.orig 2010-10-04 15:48:00.075557769 -0400 -+++ nfs-utils-1.2.3/utils/blkmapd/device-process.c 2010-10-04 15:48:00.075557769 -0400 -@@ -0,0 +1,394 @@ -+/* -+ * device-process.c: detailed processing of device information sent -+ * from kernel. -+ * -+ * Copyright (c) 2006 The Regents of the University of Michigan. -+ * All rights reserved. -+ * -+ * Andy Adamson -+ * Fred Isaman -+ * -+ * Copyright (c) 2010 EMC Corporation, Haiying Tang -+ * -+ * Used codes in linux/fs/nfs/blocklayout/blocklayoutdev.c. -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "device-discovery.h" -+ -+uint32_t *blk_overflow(uint32_t * p, uint32_t * end, size_t nbytes) -+{ -+ uint32_t *q = p + ((nbytes + 3) >> 2); -+ if (q > end || q < p) -+ return NULL; -+ return p; -+} -+ -+static int decode_blk_signature(uint32_t **pp, uint32_t *end, -+ struct bl_sig *sig) -+{ -+ int i, tmp; -+ uint32_t *p = *pp; -+ -+ BLK_READBUF(p, end, 4); -+ READ32(sig->si_num_comps); -+ if (sig->si_num_comps == 0) { -+ BL_LOG_ERR("0 components in sig\n"); -+ goto out_err; -+ } -+ if (sig->si_num_comps >= BLOCK_MAX_SIG_COMP) { -+ BL_LOG_ERR("number of sig comps %i >= BLOCK_MAX_SIG_COMP\n", -+ sig->si_num_comps); -+ goto out_err; -+ } -+ for (i = 0; i < sig->si_num_comps; i++) { -+ BLK_READBUF(p, end, 12); -+ READ64(sig->si_comps[i].bs_offset); -+ READ32(tmp); -+ sig->si_comps[i].bs_length = tmp; -+ BLK_READBUF(p, end, tmp); -+ /* Note we rely here on fact that sig is used immediately -+ * for mapping, then thrown away. -+ */ -+ sig->si_comps[i].bs_string = (char *)p; -+ BL_LOG_ERR("%s: si_comps[%d]: bs_length %d, bs_string %s\n", -+ __func__, i, sig->si_comps[i].bs_length, -+ sig->si_comps[i].bs_string); -+ p += ((tmp + 3) >> 2); -+ } -+ *pp = p; -+ return 0; -+ out_err: -+ return -EIO; -+} -+ -+/* Read signature from device -+ * return 0: read successfully -+ * return -1: error -+ */ -+int -+read_cmp_blk_sig(const char *dev_name, struct bl_sig_comp *comp, -+ int64_t bs_offset) -+{ -+ int fd, ret = -1; -+ char *sig = NULL; -+ -+ fd = open(dev_name, O_RDONLY | O_LARGEFILE); -+ if (fd < 0) { -+ BL_LOG_ERR("%s could not be opened for read\n", dev_name); -+ goto error; -+ } -+ -+ sig = (char *)malloc(comp->bs_length); -+ if (!sig) { -+ BL_LOG_ERR("%s: Out of memory\n", __func__); -+ goto error; -+ } -+ -+ if (lseek64(fd, bs_offset, SEEK_SET) == -1) { -+ BL_LOG_ERR("File %s lseek error\n", dev_name); -+ goto error; -+ } -+ -+ if (atomicio(read, fd, sig, comp->bs_length) != comp->bs_length) { -+ BL_LOG_ERR("File %s read error\n", dev_name); -+ goto error; -+ } -+ -+ BL_LOG_ERR -+ ("%s: %s sig: %s, bs_string: %s, bs_length: %d, bs_offset: %lld\n", -+ __func__, dev_name, sig, comp->bs_string, comp->bs_length, -+ (long long)bs_offset); -+ ret = memcmp(sig, comp->bs_string, comp->bs_length); -+ -+ error: -+ if (sig) -+ free(sig); -+ if (fd >= 0) -+ close(fd); -+ return ret; -+} -+ -+/* -+ * All signatures in sig must be found on disk for verification. -+ * Returns True if sig matches, False otherwise. -+ */ -+static int verify_sig(struct bl_disk *disk, struct bl_sig *sig) -+{ -+ struct bl_sig_comp *comp; -+ int i, ret; -+ int64_t bs_offset; -+ -+ for (i = 0; i < sig->si_num_comps; i++) { -+ comp = &sig->si_comps[i]; -+ bs_offset = comp->bs_offset; -+ if (bs_offset < 0) -+ bs_offset += (((int64_t) disk->size) << 9); -+ BL_LOG_ERR("%s: bs_offset: %lld\n", -+ __func__, (long long) bs_offset); -+ ret = read_cmp_blk_sig(disk->valid_path->full_path, -+ comp, bs_offset); -+ if (ret) -+ return 0; -+ } -+ return 1; -+} -+ -+/* -+ * map_sig_to_device() -+ * Given a signature, walk the list of visible disks searching for -+ * a match. Returns True if mapping was done, False otherwise. -+ * -+ * While we're at it, fill in the vol->bv_size. -+ */ -+static int map_sig_to_device(struct bl_sig *sig, struct bl_volume *vol) -+{ -+ int mapped = 0; -+ struct bl_disk *disk = visible_disk_list; -+ char *filepath = 0; -+ struct bl_disk *lolDisk = disk; -+ -+ while (lolDisk) { -+ BL_LOG_ERR("%s: visible_disk_list: %s\n", __func__, -+ lolDisk->valid_path->full_path); -+ lolDisk = lolDisk->next; -+ } -+ -+ /* scan disk list to find out match device */ -+ while (disk) { -+ /* FIXME: should we use better algorithm for disk scan? */ -+ mapped = verify_sig(disk, sig); -+ if (mapped) { -+ vol->param.bv_dev = disk->dev; -+ filepath = disk->valid_path->full_path; -+ vol->bv_size = disk->size; -+ break; -+ } -+ disk = disk->next; -+ } -+ return mapped; -+} -+ -+/* We are given an array of XDR encoded array indices, each of which should -+ * refer to a previously decoded device. Translate into a list of pointers -+ * to the appropriate pnfs_blk_volume's. -+ */ -+static int set_vol_array(uint32_t **pp, uint32_t *end, -+ struct bl_volume *vols, int working) -+{ -+ int i, index; -+ uint32_t *p = *pp; -+ struct bl_volume **array = vols[working].bv_vols; -+ for (i = 0; i < vols[working].bv_vol_n; i++) { -+ BLK_READBUF(p, end, 4); -+ READ32(index); -+ if ((index < 0) || (index >= working)) { -+ BL_LOG_ERR("set_vol_array: Id %i out of range\n", -+ index); -+ goto out_err; -+ } -+ array[i] = &vols[index]; -+ } -+ *pp = p; -+ return 0; -+ out_err: -+ return -EIO; -+} -+ -+static uint64_t sum_subvolume_sizes(struct bl_volume *vol) -+{ -+ int i; -+ uint64_t sum = 0; -+ for (i = 0; i < vol->bv_vol_n; i++) -+ sum += vol->bv_vols[i]->bv_size; -+ return sum; -+} -+ -+static int decode_blk_volume(uint32_t **pp, uint32_t *end, -+ struct bl_volume *vols, int i, int *array_cnt) -+{ -+ int status = 0, j; -+ struct bl_sig sig; -+ uint32_t *p = *pp; -+ struct bl_volume *vol = &vols[i]; -+ uint64_t tmp, tmp_size; -+ div_t d; -+ -+ BLK_READBUF(p, end, 4); -+ READ32(vol->bv_type); -+ switch (vol->bv_type) { -+ case BLOCK_VOLUME_SIMPLE: -+ *array_cnt = 0; -+ status = decode_blk_signature(&p, end, &sig); -+ if (status) -+ return status; -+ status = map_sig_to_device(&sig, vol); -+ if (!status) { -+ BL_LOG_ERR("Could not find disk for device\n"); -+ return -ENXIO; -+ } -+ status = 0; -+ break; -+ case BLOCK_VOLUME_SLICE: -+ BLK_READBUF(p, end, 16); -+ READ_SECTOR(vol->param.bv_offset); -+ READ_SECTOR(vol->bv_size); -+ *array_cnt = vol->bv_vol_n = 1; -+ status = set_vol_array(&p, end, vols, i); -+ break; -+ case BLOCK_VOLUME_STRIPE: -+ BLK_READBUF(p, end, 8); -+ READ_SECTOR(vol->param.bv_stripe_unit); -+ off_t chunksize = vol->param.bv_stripe_unit; -+ if ((chunksize == 0) || -+ ((chunksize & (chunksize - 1)) != 0) || -+ (chunksize < (PAGE_SIZE >> 9))) -+ return -EIO; -+ BLK_READBUF(p, end, 4); -+ READ32(vol->bv_vol_n); -+ if (!vol->bv_vol_n) -+ return -EIO; -+ *array_cnt = vol->bv_vol_n; -+ status = set_vol_array(&p, end, vols, i); -+ if (status) -+ return status; -+ for (j = 1; j < vol->bv_vol_n; j++) { -+ if (vol->bv_vols[j]->bv_size != -+ vol->bv_vols[0]->bv_size) { -+ BL_LOG_ERR("varying subvol size\n"); -+ return -EIO; -+ } -+ } -+ /* Make sure total size only includes addressable areas */ -+ tmp_size = vol->bv_vols[0]->bv_size; -+ d = div(tmp_size, (uint32_t) vol->param.bv_stripe_unit); -+ tmp_size = d.quot; -+ vol->bv_size = tmp_size * vol->param.bv_stripe_unit; -+ break; -+ case BLOCK_VOLUME_CONCAT: -+ BLK_READBUF(p, end, 4); -+ READ32(vol->bv_vol_n); -+ if (!vol->bv_vol_n) -+ return -EIO; -+ *array_cnt = vol->bv_vol_n; -+ status = set_vol_array(&p, end, vols, i); -+ if (status) -+ return status; -+ vol->bv_size = sum_subvolume_sizes(vol); -+ break; -+ default: -+ BL_LOG_ERR("Unknown volume type %i\n", vol->bv_type); -+ out_err: -+ return -EIO; -+ } -+ *pp = p; -+ return status; -+} -+ -+uint64_t process_deviceinfo(const char *dev_addr_buf, -+ unsigned int dev_addr_len, -+ uint32_t *major, uint32_t *minor) -+{ -+ int num_vols, i, status, count; -+ uint32_t *p, *end; -+ struct bl_volume *vols = NULL, **arrays = NULL, **arrays_ptr = NULL; -+ uint64_t dev = 0; -+ int tried = 0; -+ -+ restart: -+ p = (uint32_t *) dev_addr_buf; -+ end = (uint32_t *) ((char *)p + dev_addr_len); -+ /* Decode block volume */ -+ BLK_READBUF(p, end, 4); -+ READ32(num_vols); -+ if (num_vols <= 0) { -+ BL_LOG_WARNING("Error: number of vols: %d\n", num_vols); -+ goto out_err; -+ } -+ -+ vols = (struct bl_volume *)malloc(num_vols * sizeof(struct bl_volume)); -+ if (!vols) { -+ BL_LOG_ERR("%s: Out of memory\n", __func__); -+ goto out_err; -+ } -+ -+ /* Each volume in vols array needs its own array. Save time by -+ * allocating them all in one large hunk. Because each volume -+ * array can only reference previous volumes, and because once -+ * a concat or stripe references a volume, it may never be -+ * referenced again, the volume arrays are guaranteed to fit -+ * in the suprisingly small space allocated. -+ */ -+ arrays = -+ (struct bl_volume **)malloc(num_vols * 2 * -+ sizeof(struct bl_volume *)); -+ if (!arrays) { -+ BL_LOG_ERR("%s: Out of memory\n", __func__); -+ goto out_err; -+ } -+ -+ arrays_ptr = arrays; -+ -+ for (i = 0; i < num_vols; i++) { -+ vols[i].bv_vols = arrays_ptr; -+ status = decode_blk_volume(&p, end, vols, i, &count); -+ if (status == -ENXIO && (tried <= 5)) { -+ sleep(1); -+ BL_LOG_DEBUG("%s: discover again!\n", __func__); -+ bl_discover_devices(); -+ tried++; -+ free(vols); -+ free(arrays); -+ goto restart; -+ } -+ if (status) -+ goto out_err; -+ arrays_ptr += count; -+ } -+ -+ if (p != end) { -+ BL_LOG_ERR("p is not equal to end!\n"); -+ goto out_err; -+ } -+ -+ dev = dm_device_create(vols, num_vols); -+ *major = MAJOR(dev); -+ *minor = MINOR(dev); -+ out_err: -+ if (vols) -+ free(vols); -+ if (arrays) -+ free(arrays); -+ return dev; -+} -diff -up nfs-utils-1.2.3/utils/blkmapd/dm-device.c.orig nfs-utils-1.2.3/utils/blkmapd/dm-device.c ---- nfs-utils-1.2.3/utils/blkmapd/dm-device.c.orig 2010-10-04 15:48:00.075557769 -0400 -+++ nfs-utils-1.2.3/utils/blkmapd/dm-device.c 2010-10-04 15:48:00.076394449 -0400 -@@ -0,0 +1,509 @@ -+/* -+ * dm-device.c: create or remove device via device mapper API. -+ * -+ * Copyright (c) 2010 EMC Corporation, Haiying Tang -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include "device-discovery.h" -+ -+#define DM_DEV_NAME_LEN 256 -+ -+#ifndef DM_MAX_TYPE_NAME -+#define DM_MAX_TYPE_NAME 16 -+#endif -+ -+#define DM_PARAMS_LEN 512 /* XXX: is this enough for target? */ -+#define DM_DIR "/dev/mapper" -+#define DM_DIR_LEN12 -+#define TYPE_HAS_DEV(type) ((type == BLOCK_VOLUME_SIMPLE) || \ -+ (type == BLOCK_VOLUME_PSEUDO)) -+ -+struct bl_dm_table { -+ uint64_t offset; -+ uint64_t size; -+ char target_type[DM_MAX_TYPE_NAME]; -+ char params[DM_PARAMS_LEN]; -+ struct bl_dm_table *next; -+}; -+ -+struct bl_dm_tree { -+ uint64_t dev; -+ struct dm_tree *tree; -+ struct bl_dm_tree *next; -+}; -+ -+static inline struct bl_dm_table *bl_dm_table_alloc(void) -+{ -+ return (struct bl_dm_table *)calloc(1, sizeof(struct bl_dm_table)); -+} -+ -+void bl_dm_table_free(struct bl_dm_table *bl_table_head) -+{ -+ struct bl_dm_table *p = bl_table_head; -+ while (bl_table_head) { -+ p = bl_table_head->next; -+ free(bl_table_head); -+ bl_table_head = p; -+ } -+} -+ -+void add_to_bl_dm_table(struct bl_dm_table **bl_table_head, -+ struct bl_dm_table *table) -+{ -+ struct bl_dm_table *pre; -+ if (!*bl_table_head) { -+ *bl_table_head = table; -+ return; -+ } -+ pre = *bl_table_head; -+ while (pre->next) -+ pre = pre->next; -+ pre->next = table; -+ return; -+} -+ -+struct bl_dm_tree *bl_tree_head; -+ -+struct bl_dm_tree *find_bl_dm_tree(uint64_t dev) -+{ -+ struct bl_dm_tree *p = bl_tree_head; -+ while (p) { -+ if (p->dev == dev) -+ return p; -+ p = p->next; -+ } -+ return NULL; -+} -+ -+void del_from_bl_dm_tree(uint64_t dev) -+{ -+ struct bl_dm_tree *pre = bl_tree_head; -+ struct bl_dm_tree *p; -+ -+ p = pre; -+ while (p) { -+ if (p->dev == dev) { -+ pre->next = p->next; -+ if (p == bl_tree_head) -+ bl_tree_head = bl_tree_head->next; -+ free(p); -+ break; -+ } -+ pre = p; -+ p = pre->next; -+ } -+} -+ -+void add_to_bl_dm_tree(struct bl_dm_tree *tree) -+{ -+ struct bl_dm_tree *pre; -+ if (!bl_tree_head) { -+ bl_tree_head = tree; -+ return; -+ } -+ pre = bl_tree_head; -+ while (pre->next) -+ pre = pre->next; -+ pre->next = tree; -+ return; -+} -+ -+/* Create device via device mapper -+ * return 0 when creation failed -+ * return dev no for created device -+ */ -+uint64_t dm_single_device_create(const char *dev_name, struct bl_dm_table * p) -+{ -+ struct dm_task *dmt; -+ struct dm_info dminfo; -+ int ret = 0; -+ -+ dmt = dm_task_create(DM_DEVICE_CREATE); -+ if (!dmt) { -+ BL_LOG_ERR("Create dm_task for %s failed\n", dev_name); -+ return 0; -+ } -+ ret = dm_task_set_name(dmt, dev_name); -+ if (!ret) -+ goto err_out; -+ -+ while (p) { -+ ret = dm_task_add_target(dmt, p->offset, p->size, -+ p->target_type, p->params); -+ if (!ret) -+ goto err_out; -+ p = p->next; -+ } -+ -+ ret = dm_task_run(dmt) && -+ dm_task_get_info(dmt, &dminfo) && dminfo.exists; -+ -+ if (!ret) -+ goto err_out; -+ -+ dm_task_update_nodes(); -+ -+ err_out: -+ dm_task_destroy(dmt); -+ -+ if (!ret) { -+ BL_LOG_ERR("Create device %s failed\n", dev_name); -+ return 0; -+ } -+ return MKDEV(dminfo.major, dminfo.minor); -+} -+ -+int dm_device_remove_byname(const char *dev_name) -+{ -+ struct dm_task *dmt; -+ int ret = 0; -+ -+ dmt = dm_task_create(DM_DEVICE_REMOVE); -+ if (!dmt) -+ return -ENODEV; -+ -+ ret = dm_task_set_name(dmt, dev_name) && dm_task_run(dmt); -+ -+ dm_task_update_nodes(); -+ -+ if (dmt) -+ dm_task_destroy(dmt); -+ -+ return ret; -+} -+ -+int dm_device_remove(uint64_t dev) -+{ -+ struct dm_task *dmt; -+ struct dm_names *dmnames; -+ char *names = NULL; -+ int ret = -1; -+ -+ /* Look for dev_name via dev, if dev_name could be transferred here, -+ we could jump to DM_DEVICE_REMOVE directly */ -+ dmt = dm_task_create(DM_DEVICE_LIST); -+ if (!dmt) { -+ BL_LOG_ERR("dm_task creation failed\n"); -+ return -ENODEV; -+ } -+ -+ ret = dm_task_run(dmt); -+ if (!ret) { -+ BL_LOG_ERR("dm_task_run failed\n"); -+ goto error; -+ } -+ -+ dmnames = dm_task_get_names(dmt); -+ if (!dmnames || !dmnames->dev) { -+ BL_LOG_ERR("dm_task_get_names failed\n"); -+ goto error; -+ } -+ -+ do { -+ if (dmnames->dev == dev) { -+ names = dmnames->name; -+ break; -+ } -+ dmnames = (void *)dmnames + dmnames->next; -+ } while (dmnames); -+ -+ if (!names) { -+ BL_LOG_ERR("Could not find device\n"); -+ goto error; -+ } -+ -+ dm_task_update_nodes(); -+ -+ error: -+ dm_task_destroy(dmt); -+ -+ /* Start to remove device */ -+ if (names) -+ ret = dm_device_remove_byname(names); -+ return ret; -+} -+ -+static unsigned long dev_count; -+ -+void dm_devicelist_remove(unsigned long start, unsigned long end) -+{ -+ char dev_name[DM_DEV_NAME_LEN]; -+ unsigned long count; -+ -+ if ((start >= dev_count) || (end <= 1) || (start >= end - 1)) -+ return; -+ -+ for (count = end - 1; count > start; count--) { -+ sprintf(dev_name, "pnfs_vol_%lu", count - 1); -+ dm_device_remove_byname(dev_name); -+ } -+ -+ return; -+} -+ -+void bl_dm_remove_tree(uint64_t dev) -+{ -+ struct bl_dm_tree *p; -+ -+ p = find_bl_dm_tree(dev); -+ if (!p) -+ return; -+ -+ dm_tree_free(p->tree); -+ del_from_bl_dm_tree(dev); -+} -+ -+void bl_dm_create_tree(uint64_t dev) -+{ -+ struct dm_tree *tree; -+ struct bl_dm_tree *bl_tree; -+ -+ bl_tree = find_bl_dm_tree(dev); -+ if (bl_tree) -+ return; /* XXX: error? */ -+ -+ tree = dm_tree_create(); -+ if (!tree) -+ return; -+ -+ if (!dm_tree_add_dev(tree, MAJOR(dev), MINOR(dev))) { -+ dm_tree_free(tree); -+ return; -+ } -+ -+ bl_tree = malloc(sizeof(struct bl_dm_tree)); -+ if (!bl_tree) { -+ dm_tree_free(tree); -+ return; -+ } -+ -+ bl_tree->dev = dev; -+ bl_tree->tree = tree; -+ bl_tree->next = NULL; -+ add_to_bl_dm_tree(bl_tree); -+ -+ return; -+} -+ -+uint64_t dm_device_nametodev(char *dev_name) -+{ -+ struct dm_task *dmt; -+ int ret = 0; -+ struct dm_info dminfo; -+ -+ dmt = dm_task_create(DM_DEVICE_INFO); -+ if (!dmt) -+ return -ENODEV; -+ -+ ret = dm_task_set_name(dmt, dev_name) && -+ dm_task_run(dmt) && dm_task_get_info(dmt, &dminfo); -+ -+ if (dmt) -+ dm_task_destroy(dmt); -+ -+ if (!ret) -+ return 0; -+ -+ return MKDEV(dminfo.major, dminfo.minor); -+} -+ -+int dm_device_remove_all(uint64_t *dev) -+{ -+ struct bl_dm_tree *p; -+ struct dm_tree_node *node; -+ const char *uuid; -+ int ret = 0; -+ uint32_t major, minor; -+ uint64_t bl_dev; -+ -+ memcpy(&major, dev, sizeof(uint32_t)); -+ memcpy(&minor, (void *)dev + sizeof(uint32_t), sizeof(uint32_t)); -+ bl_dev = MKDEV(major, minor); -+ p = find_bl_dm_tree(bl_dev); -+ if (!p) -+ return ret; -+ -+ node = dm_tree_find_node(p->tree, MAJOR(bl_dev), MINOR(bl_dev)); -+ if (!node) -+ return ret; -+ -+ uuid = dm_tree_node_get_uuid(node); -+ if (!uuid) -+ return ret; -+ -+ dm_device_remove(bl_dev); -+ ret = dm_tree_deactivate_children(node, uuid, strlen(uuid)); -+ dm_task_update_nodes(); -+ bl_dm_remove_tree(bl_dev); -+ return ret; -+} -+ -+/* TODO: check the value for DM_DEV_NAME_LEN, DM_TYPE_LEN, DM_PARAMS_LEN */ -+uint64_t dm_device_create(struct bl_volume *vols, int num_vols) -+{ -+ uint64_t size, dev = 0; -+ unsigned long count = dev_count; -+ int number = 0, i, pos; -+ struct bl_volume *node; -+ char *tmp; -+ struct bl_dm_table *table = NULL; -+ struct bl_dm_table *bl_table_head = NULL; -+ unsigned int len; -+ char *dev_name = NULL; -+ /* Create pseudo device here */ -+ while (number < num_vols) { -+ node = &vols[number]; -+ switch (node->bv_type) { -+ case BLOCK_VOLUME_SIMPLE: -+ /* Do not need to create device here */ -+ dev = node->param.bv_dev; -+ goto continued; -+ case BLOCK_VOLUME_SLICE: -+ table = bl_dm_table_alloc(); -+ if (!table) -+ goto out; -+ table->offset = 0; -+ table->size = node->bv_size; -+ strcpy(table->target_type, "linear"); -+ if (!TYPE_HAS_DEV(node->bv_vols[0]->bv_type)) { -+ free(table); -+ goto out; -+ } -+ dev = node->bv_vols[0]->param.bv_dev; -+ tmp = table->params; -+ if (!dm_format_dev(tmp, DM_PARAMS_LEN, -+ MAJOR(dev), MINOR(dev))) { -+ free(table); -+ goto out; -+ } -+ tmp += strlen(tmp); -+ sprintf(tmp, " %lu", node->param.bv_offset); -+ add_to_bl_dm_table(&bl_table_head, table); -+ break; -+ case BLOCK_VOLUME_STRIPE: -+ table = bl_dm_table_alloc(); -+ if (!table) -+ goto out; -+ table->offset = 0; -+ table->size = node->bv_size; -+ strcpy(table->target_type, "striped"); -+ sprintf(table->params, "%d %lu %n", node->bv_vol_n, -+ node->param.bv_stripe_unit, &pos); -+ /* Repeatedly copy subdev to params */ -+ tmp = table->params + pos; -+ len = DM_PARAMS_LEN - pos; -+ for (i = 0; i < node->bv_vol_n; i++) { -+ if (!TYPE_HAS_DEV(node->bv_vols[i]->bv_type)) { -+ free(table); -+ goto out; -+ } -+ dev = node->bv_vols[i]->param.bv_dev; -+ if (!dm_format_dev(tmp, len, MAJOR(dev), -+ MINOR(dev))) { -+ free(table); -+ goto out; -+ } -+ pos = strlen(tmp); -+ tmp += pos; -+ len -= pos; -+ sprintf(tmp, " %d ", 0); -+ tmp += 3; -+ len -= 3; -+ } -+ add_to_bl_dm_table(&bl_table_head, table); -+ break; -+ case BLOCK_VOLUME_CONCAT: -+ size = 0; -+ for (i = 0; i < node->bv_vol_n; i++) { -+ table = bl_dm_table_alloc(); -+ if (!table) -+ goto out; -+ table->offset = size; -+ table->size = node->bv_vols[i]->bv_size; -+ if (!TYPE_HAS_DEV(node->bv_vols[i]->bv_type)) { -+ free(table); -+ goto out; -+ } -+ strcpy(table->target_type, "linear"); -+ tmp = table->params; -+ dev = node->bv_vols[i]->param.bv_dev; -+ if (!dm_format_dev(tmp, DM_PARAMS_LEN, -+ MAJOR(dev), MINOR(dev))) { -+ free(table); -+ goto out; -+ } -+ tmp += strlen(tmp); -+ sprintf(tmp, " %d", 0); -+ size += table->size; -+ add_to_bl_dm_table(&bl_table_head, table); -+ } -+ break; -+ default: -+ /* Delete previous temporary devices */ -+ dm_devicelist_remove(count, dev_count); -+ goto out; -+ } /* end of swtich */ -+ /* Create dev_name here. Name of device is pnfs_vol_XXX */ -+ if (dev_name) -+ free(dev_name); -+ dev_name = (char *)calloc(DM_DEV_NAME_LEN, sizeof(char)); -+ if (!dev_name) { -+ BL_LOG_ERR("%s: Out of memory\n", __func__); -+ goto out; -+ } -+ sprintf(dev_name, "pnfs_vol_%lu", dev_count++); -+ -+ dev = dm_single_device_create(dev_name, bl_table_head); -+ if (!dev) { -+ /* Delete previous temporary devices */ -+ dm_devicelist_remove(count, dev_count); -+ goto out; -+ } -+ node->param.bv_dev = dev; -+ /* TODO: extend use with PSEUDO later */ -+ node->bv_type = BLOCK_VOLUME_PSEUDO; -+ continued: -+ number++; -+ if (bl_table_head) -+ bl_dm_table_free(bl_table_head); -+ bl_table_head = NULL; -+ } -+ out: -+ if (bl_table_head) -+ bl_dm_table_free(bl_table_head); -+ bl_table_head = NULL; -+ if (dev) -+ bl_dm_create_tree(dev); -+ if (dev_name) -+ free(dev_name); -+ return dev; -+} -diff -up nfs-utils-1.2.3/utils/blkmapd/etc/blkmapd.conf.orig nfs-utils-1.2.3/utils/blkmapd/etc/blkmapd.conf ---- nfs-utils-1.2.3/utils/blkmapd/etc/blkmapd.conf.orig 2010-10-04 15:48:00.076394449 -0400 -+++ nfs-utils-1.2.3/utils/blkmapd/etc/blkmapd.conf 2010-10-04 15:48:00.076394449 -0400 -@@ -0,0 +1,10 @@ -+# This is an example config file -+ -+# Look at all /dev/sd* devices -+# /dev/sd or /dev/sd* -+/dev/sd* -+ -+# Look at all /dev/mapper/* devices -+# /dev/mapper/* or -+# /dev/mapper/ -+/dev/mapper/* -diff -up nfs-utils-1.2.3/utils/blkmapd/etc/initd/initd.redhat.orig nfs-utils-1.2.3/utils/blkmapd/etc/initd/initd.redhat ---- nfs-utils-1.2.3/utils/blkmapd/etc/initd/initd.redhat.orig 2010-10-04 15:48:00.076394449 -0400 -+++ nfs-utils-1.2.3/utils/blkmapd/etc/initd/initd.redhat 2010-10-04 15:48:00.077339793 -0400 -@@ -0,0 +1,76 @@ -+#!/bin/sh -+# -+# description: Starts and stops the iSCSI initiator -+# -+# processname: blkmapd -+# pidfile: /var/run/blkmapd.pid -+# config: /etc/blkmapd.conf -+ -+# Source function library. -+if [ -f /etc/init.d/functions ] ; then -+ . /etc/init.d/functions -+elif [ -f /etc/rc.d/init.d/functions ] ; then -+ . /etc/rc.d/init.d/functions -+else -+ exit 0 -+fi -+ -+PATH=/sbin:/bin:/usr/sbin:/usr/bin -+ -+RETVAL=0 -+ -+start() -+{ -+ echo -n $"Starting pNFS block-layout device discovery service: " -+ modprobe -q blocklayoutdriver -+ daemon /usr/sbin/blkmapd -+ RETVAL=$? -+ if [ $RETVAL -eq 0 ]; then -+ touch /var/lock/subsys/blkmapd -+ fi -+ echo -+ return $RETVAL -+} -+ -+stop() -+{ -+ echo -n $"Stopping pNFS block-layout device discovery service: " -+ killproc blkmapd 2> /dev/null -+ rm -f /var/run/blkmapd.pid -+ RETVAL=$? -+ [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/blkmapd -+ if [ $RETVAL -eq 0 ]; then -+ echo_success -+ else -+ echo_failure -+ fi -+ echo -+ return $RETVAL -+} -+ -+restart() -+{ -+ stop -+ start -+} -+ -+case "$1" in -+ start) -+ start -+ ;; -+ stop) -+ stop -+ ;; -+ restart) -+ stop -+ start -+ ;; -+ status) -+ status blkmapd -+ ;; -+ *) -+ echo $"Usage: $0 {start|stop|restart|status}" -+ exit 1 -+esac -+ -+exit $RETVAL -diff -up nfs-utils-1.2.3/utils/blkmapd/Makefile.am.orig nfs-utils-1.2.3/utils/blkmapd/Makefile.am ---- nfs-utils-1.2.3/utils/blkmapd/Makefile.am.orig 2010-10-04 15:48:00.071418550 -0400 -+++ nfs-utils-1.2.3/utils/blkmapd/Makefile.am 2010-10-04 15:48:00.071418550 -0400 -@@ -0,0 +1,22 @@ -+## Process this file with automake to produce Makefile.in -+ -+#man8_MANS = blkmapd.man -+ -+AM_CFLAGS += -D_LARGEFILE64_SOURCE -+sbin_PROGRAMS = blkmapd -+ -+blkmapd_SOURCES = \ -+ atomicio.c \ -+ cfg.c \ -+ device-discovery.c \ -+ device-inq.c \ -+ device-process.c \ -+ dm-device.c \ -+ \ -+ cfg.h \ -+ device-discovery.h -+ -+blkmapd_LDADD = -ldevmapper ../../support/nfs/libnfs.a -+ -+MAINTAINERCLEANFILES = Makefile.in -+ -diff -up nfs-utils-1.2.3/utils/exportfs/exportfs.c.orig nfs-utils-1.2.3/utils/exportfs/exportfs.c ---- nfs-utils-1.2.3/utils/exportfs/exportfs.c.orig 2010-09-28 08:24:16.000000000 -0400 -+++ nfs-utils-1.2.3/utils/exportfs/exportfs.c 2010-10-04 15:48:00.077339793 -0400 -@@ -577,6 +577,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.3/utils/Makefile.am.orig nfs-utils-1.2.3/utils/Makefile.am ---- nfs-utils-1.2.3/utils/Makefile.am.orig 2010-09-28 08:24:16.000000000 -0400 -+++ nfs-utils-1.2.3/utils/Makefile.am 2010-10-04 15:48:00.070350101 -0400 -@@ -4,6 +4,8 @@ OPTDIRS = - - if CONFIG_NFSV4 - OPTDIRS += idmapd -+OPTDIRS += spnfsd -+OPTDIRS += blkmapd - endif - - if CONFIG_GSS -diff -up nfs-utils-1.2.3/utils/mountd/cache.c.orig nfs-utils-1.2.3/utils/mountd/cache.c ---- nfs-utils-1.2.3/utils/mountd/cache.c.orig 2010-09-28 08:24:16.000000000 -0400 -+++ nfs-utils-1.2.3/utils/mountd/cache.c 2010-10-04 15:48:00.078357497 -0400 -@@ -653,6 +653,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); - write_secinfo(f, exp, flag_mask); - if (exp->e_uuid == NULL || different_fs) { -diff -up nfs-utils-1.2.3/utils/spnfsd/atomicio.c.orig nfs-utils-1.2.3/utils/spnfsd/atomicio.c ---- nfs-utils-1.2.3/utils/spnfsd/atomicio.c.orig 2010-10-04 15:48:00.079379348 -0400 -+++ nfs-utils-1.2.3/utils/spnfsd/atomicio.c 2010-10-04 15:48:00.079379348 -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 nfs-utils-1.2.3/utils/spnfsd/cfg.c.orig nfs-utils-1.2.3/utils/spnfsd/cfg.c ---- nfs-utils-1.2.3/utils/spnfsd/cfg.c.orig 2010-10-04 15:48:00.080414616 -0400 -+++ nfs-utils-1.2.3/utils/spnfsd/cfg.c 2010-10-04 15:48:00.080414616 -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 nfs-utils-1.2.3/utils/spnfsd/cfg.h.orig nfs-utils-1.2.3/utils/spnfsd/cfg.h ---- nfs-utils-1.2.3/utils/spnfsd/cfg.h.orig 2010-10-04 15:48:00.080414616 -0400 -+++ nfs-utils-1.2.3/utils/spnfsd/cfg.h 2010-10-04 15:48:00.080414616 -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 nfs-utils-1.2.3/utils/spnfsd/Makefile.am.orig nfs-utils-1.2.3/utils/spnfsd/Makefile.am ---- nfs-utils-1.2.3/utils/spnfsd/Makefile.am.orig 2010-10-04 15:48:00.078357497 -0400 -+++ nfs-utils-1.2.3/utils/spnfsd/Makefile.am 2010-10-04 15:48:00.078357497 -0400 -@@ -0,0 +1,30 @@ -+## Process this file with automake to produce Makefile.in -+ -+man5_MANS = -+man8_MANS = -+ -+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 -diff -up nfs-utils-1.2.3/utils/spnfsd/makestatic.orig nfs-utils-1.2.3/utils/spnfsd/makestatic ---- nfs-utils-1.2.3/utils/spnfsd/makestatic.orig 2010-10-04 15:48:00.081429548 -0400 -+++ nfs-utils-1.2.3/utils/spnfsd/makestatic 2010-10-04 15:48:00.081429548 -0400 -@@ -0,0 +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 -up nfs-utils-1.2.3/utils/spnfsd/nfsd4_spnfs.h.orig nfs-utils-1.2.3/utils/spnfsd/nfsd4_spnfs.h ---- nfs-utils-1.2.3/utils/spnfsd/nfsd4_spnfs.h.orig 2010-10-04 15:48:00.081429548 -0400 -+++ nfs-utils-1.2.3/utils/spnfsd/nfsd4_spnfs.h 2010-10-04 15:48:00.081429548 -0400 -@@ -0,0 +1,334 @@ -+/* -+ * include/linux/nfsd4_spnfs.h -+ * -+ * 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 -+ -+ -+#ifdef __KERNEL__ -+#include "exportfs.h" -+#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_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_READ 0x0c -+#define SPNFS_TYPE_WRITE 0x0d -+ -+#define SPNFS_MAX_DEVICES 1 -+#define SPNFS_MAX_DATA_SERVERS 16 -+#define SPNFS_MAX_IO 512 -+ -+/* layout */ -+struct spnfs_msg_layoutget_args { -+ unsigned long inode; -+ unsigned long generation; -+}; -+ -+struct spnfs_filelayout_list { -+ u_int32_t fh_len; -+ unsigned char fh_val[128]; /* DMXXX fix this const */ -+}; -+ -+struct spnfs_msg_layoutget_res { -+ int status; -+ u_int64_t devid; -+ u_int64_t stripe_size; -+ u_int32_t stripe_type; -+ u_int32_t stripe_count; -+ struct spnfs_filelayout_list flist[SPNFS_MAX_DATA_SERVERS]; -+}; -+ -+/* layoutcommit */ -+struct spnfs_msg_layoutcommit_args { -+ unsigned long inode; -+ unsigned long generation; -+ 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 { -+}; -+*/ -+ -+/* getdeviceiter */ -+struct spnfs_msg_getdeviceiter_args { -+ unsigned long inode; -+ u_int64_t cookie; -+ u_int64_t verf; -+}; -+ -+struct spnfs_msg_getdeviceiter_res { -+ int status; -+ u_int64_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_device { -+ u_int64_t devid; -+ int dscount; -+ struct spnfs_data_server dslist[SPNFS_MAX_DATA_SERVERS]; -+}; -+ -+struct spnfs_msg_getdeviceinfo_args { -+ u_int64_t devid; -+}; -+ -+struct spnfs_msg_getdeviceinfo_res { -+ int status; -+ struct spnfs_device devinfo; -+}; -+ -+/* setattr */ -+struct spnfs_msg_setattr_args { -+ unsigned long inode; -+ unsigned long generation; -+ int file_size; -+}; -+ -+struct spnfs_msg_setattr_res { -+ int status; -+}; -+ -+/* open */ -+struct spnfs_msg_open_args { -+ unsigned long inode; -+ unsigned long generation; -+ 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; -+ unsigned long generation; -+}; -+ -+struct spnfs_msg_remove_res { -+ int status; -+}; -+ -+/* commit */ -+/* -+struct spnfs_msg_commit_args { -+ int x; -+}; -+ -+struct spnfs_msg_commit_res { -+ int y; -+}; -+*/ -+ -+/* read */ -+struct spnfs_msg_read_args { -+ unsigned long inode; -+ unsigned long generation; -+ 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; -+ unsigned long generation; -+ 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; -+ struct spnfs_msg_layoutcommit_args layoutcommit_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_remove_args remove_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 { -+ struct spnfs_msg_layoutget_res layoutget_res; -+ struct spnfs_msg_layoutcommit_res layoutcommit_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_remove_res remove_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 */ -+struct spnfs_msg { -+ unsigned char im_type; -+ unsigned char im_status; -+ union spnfs_msg_args im_args; -+ union spnfs_msg_res im_res; -+}; -+ -+/* spnfs configuration info */ -+struct spnfs_config { -+ unsigned char dense_striping; -+ int stripe_size; -+ int num_ds; -+ char ds_dir[SPNFS_MAX_DATA_SERVERS][80]; /* XXX */ -+}; -+ -+#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 *, struct pnfs_layoutget_arg *); -+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_close(struct inode *); -+int spnfs_get_state(struct inode *, void *, void *); -+int spnfs_remove(unsigned long, unsigned long); -+int spnfs_read(struct inode *, loff_t, unsigned long *, int, struct svc_rqst *); -+int spnfs_write(struct inode *, loff_t, size_t, int, struct svc_rqst *); -+int spnfs_getfh(int, struct nfs_fh *); -+int spnfs_test_layoutrecall(char *); -+int spnfs_layoutrecall(struct inode *, int); -+ -+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 *); -+int spnfs_init_proc(void); -+ -+#endif /* __KERNEL__ */ -+ -+#endif /* NFS_SPNFS_H */ -diff -up nfs-utils-1.2.3/utils/spnfsd/queue.h.orig nfs-utils-1.2.3/utils/spnfsd/queue.h ---- nfs-utils-1.2.3/utils/spnfsd/queue.h.orig 2010-10-04 15:48:00.082454595 -0400 -+++ nfs-utils-1.2.3/utils/spnfsd/queue.h 2010-10-04 15:48:00.082454595 -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 nfs-utils-1.2.3/utils/spnfsd/spnfsd.conf.orig nfs-utils-1.2.3/utils/spnfsd/spnfsd.conf ---- nfs-utils-1.2.3/utils/spnfsd/spnfsd.conf.orig 2010-10-04 15:48:00.083419957 -0400 -+++ nfs-utils-1.2.3/utils/spnfsd/spnfsd.conf 2010-10-04 15:48:00.083419957 -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_ID = 1 -+ -+DS2_IP = 172.16.28.141 -+DS2_PORT = 2049 -+DS2_ROOT = /pnfs -+DS2_ID = 2 -diff -up nfs-utils-1.2.3/utils/spnfsd/spnfsd.c.orig nfs-utils-1.2.3/utils/spnfsd/spnfsd.c ---- nfs-utils-1.2.3/utils/spnfsd/spnfsd.c.orig 2010-10-04 15:48:00.083419957 -0400 -+++ nfs-utils-1.2.3/utils/spnfsd/spnfsd.c 2010-10-04 15:48:00.083419957 -0400 -@@ -0,0 +1,578 @@ -+/* -+ * 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. -+ * -+ * 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. -+ */ -+ -+#define _LARGEFILE64_SOURCE -+#define _FILE_OFFSET_BITS 64 -+#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_dev = 1; /* XXX no multiple device support yet */ -+int num_ds; -+struct dserver dataservers[SPNFS_MAX_DATA_SERVERS]; -+char dsmountdir[PATH_MAX]; -+struct spnfs_config spnfs_config; -+ -+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 rc, fd, cmd = 1; -+ int i; -+ -+ fd = open("/proc/fs/spnfs/ctl", O_WRONLY); -+ if (fd < 0) -+ spnfsd_errx(1, "kernel init failed (%s)", strerror(errno)); -+ rc = write(fd, &cmd, sizeof(int)); -+ if (rc < 0 && errno != EEXIST) -+ spnfsd_errx(1, "kernel init failed (%s)", strerror(errno)); -+ close(fd); -+ -+ 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)); -+ -+ spnfs_config.stripe_size = stripesize; -+ spnfs_config.dense_striping = densestriping; -+ spnfs_config.num_ds = num_ds; -+ -+ for (i = 0; i < num_ds; i++) -+ sprintf(spnfs_config.ds_dir[i], "%s/%s", -+ dsmountdir, dataservers[i].ds_ip); -+ -+ fd = open("/proc/fs/spnfs/config", O_WRONLY); -+ if (fd < 0) -+ spnfsd_errx(1, "error creating config (%s)", strerror(errno)); -+ rc = write(fd, &spnfs_config, sizeof(struct spnfs_config)); -+ if (rc < 0 && errno != EEXIST) -+ spnfsd_errx(1, "error writing config (%s)", strerror(errno)); -+ close(fd); -+ -+ 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_GETDEVICEITER: -+ err = spnfsd_getdeviceiter(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; -+ 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); -+ 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; -+ -+ if ((rval=atomicio(write, scp->sc_fd, &im, sizeof(im))) != sizeof(im)) { -+ spnfsd_warn("spnfscb: write(%s)", scp->sc_path); -+ } -+ -+out: -+ 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], dsidstr[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(dsidstr, "DS%d_ID", 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_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; -+} -+ -+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 DSID: %d\n", ds+1, dataservers[ds].ds_id); -+ } -+} -+ -+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 nfs-utils-1.2.3/utils/spnfsd/spnfsd.h.orig nfs-utils-1.2.3/utils/spnfsd/spnfsd.h ---- nfs-utils-1.2.3/utils/spnfsd/spnfsd.h.orig 2010-10-04 15:48:00.084495938 -0400 -+++ nfs-utils-1.2.3/utils/spnfsd/spnfsd.h 2010-10-04 15:48:00.084495938 -0400 -@@ -0,0 +1,70 @@ -+/* -+ * spnfsd.h -+ * -+ * 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" -+#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_id; -+}; -+ -+/* 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_getdeviceiter(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_read(struct spnfs_msg *); -+int spnfsd_write(struct spnfs_msg *); -+int spnfsd_getfh(char *, unsigned char *, unsigned int *); -diff -up nfs-utils-1.2.3/utils/spnfsd/spnfsd_ops.c.orig nfs-utils-1.2.3/utils/spnfsd/spnfsd_ops.c ---- nfs-utils-1.2.3/utils/spnfsd/spnfsd_ops.c.orig 2010-10-04 15:48:00.084495938 -0400 -+++ nfs-utils-1.2.3/utils/spnfsd/spnfsd_ops.c 2010-10-04 15:48:00.085512992 -0400 -@@ -0,0 +1,439 @@ -+/****************************************************************************** -+ -+(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. -+ -+******************************************************************************/ -+ -+#define _LARGEFILE64_SOURCE -+#define _FILE_OFFSET_BITS 64 -+#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 int num_dev; -+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.devid = 1; /* XXX */ -+ im->im_res.layoutget_res.stripe_size = stripesize; -+ if (densestriping) -+ im->im_res.layoutget_res.stripe_type = 1; /* DMXXX enum */ -+ else -+ 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++) { -+ memset(im->im_res.layoutget_res.flist[ds].fh_val, 0, 128); /*DMXXX*/ -+ sprintf(fullpath, "%s/%s/%lu.%lu", -+ dsmountdir, dataservers[ds].ds_ip, -+ im->im_args.layoutget_args.inode, -+ im->im_args.layoutget_args.generation); -+ 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 8 to get -+ * around stateid checking. -+ */ -+ im->im_res.layoutget_res.flist[ds].fh_val[2] += 8; -+ } -+ -+ 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, "%lu.%lu", im->im_args.layoutcommit_args.inode, -+ im->im_args.layoutcommit_args.generation); -+ -+ 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_getdeviceiter(struct spnfs_msg *im) -+{ -+ im->im_status = SPNFS_STATUS_SUCCESS; -+ 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; -+} -+ -+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 = 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 = -ENOENT; -+ return -1; -+ } -+ -+ devp = &im->im_res.getdeviceinfo_res.devinfo; -+ devp->dscount = num_ds; -+ -+ for (ds = 0 ; ds < num_ds ; ds++) { -+ 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; -+} -+ -+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, "%lu.%lu", im->im_args.setattr_args.inode, -+ im->im_args.setattr_args.generation); -+ -+ 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, "%lu.%lu", im->im_args.open_args.inode, -+ im->im_args.open_args.generation); -+ -+ 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 { -+ 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); -+ } -+ } -+ -+ 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, "%lu.%lu", im->im_args.remove_args.inode, -+ im->im_args.remove_args.generation); -+ -+ 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) -+{ -+ im->im_status = SPNFS_STATUS_SUCCESS; -+ return 0; -+} -+ -+int -+min (unsigned int x, unsigned int y) -+{ -+ if (xim_args.read_args.inode; -+ unsigned long generation = im->im_args.read_args.generation; -+ 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/%lu.%lu", dsmountdir, -+ dataservers[ds].ds_ip, inode, generation); -+ 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; -+ unsigned long generation = im->im_args.write_args.generation; -+ 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/%lu.%lu", dsmountdir, -+ dataservers[ds].ds_ip, inode, generation); -+ 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; -+} -+ -+int -+spnfsd_getfh(char *path, unsigned char *fh_val, unsigned int *fh_len) -+{ -+ int fd, proc_fd; -+ unsigned char res[130]; /* XXX align this to proper structure */ -+ extern void spnfsd_errx(int, const char *, ...); -+ -+ /* -+ * hack to make sure there's an active data structure for this -+ * inode in the nfs client kernel space -+ */ -+ if ((fd = open(path, O_RDONLY)) < 0) { -+ perror(path); -+ return -1; -+ } -+ -+ /* fd to fh conversion */ -+ proc_fd = open("/proc/fs/spnfs/getfh", O_RDWR); -+ if (proc_fd < 0) { -+ spnfsd_errx(1, "open getfh failed (%s)", strerror(errno)); -+ } -+ if (write(proc_fd, &fd, sizeof(int)) < 0) { -+ spnfsd_errx(1, "write getfh failed (%s)", strerror(errno)); -+ } -+ if (read(proc_fd, res, 130) <= 0) { -+ spnfsd_errx(1, "read getfh failed (%s)", strerror(errno)); -+ } -+ close(proc_fd); -+ -+ /* XXX use proper structure */ -+ *fh_len = (short)res[0]; -+ memcpy(fh_val, &res[2], *fh_len); -+ -+ close(fd); -+ return 0; -+} -diff -up nfs-utils-1.2.3/utils/spnfsd/strlcat.c.orig nfs-utils-1.2.3/utils/spnfsd/strlcat.c ---- nfs-utils-1.2.3/utils/spnfsd/strlcat.c.orig 2010-10-04 15:48:00.085512992 -0400 -+++ nfs-utils-1.2.3/utils/spnfsd/strlcat.c 2010-10-04 15:48:00.085512992 -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 nfs-utils-1.2.3/utils/spnfsd/strlcpy.c.orig nfs-utils-1.2.3/utils/spnfsd/strlcpy.c ---- nfs-utils-1.2.3/utils/spnfsd/strlcpy.c.orig 2010-10-04 15:48:00.086338923 -0400 -+++ nfs-utils-1.2.3/utils/spnfsd/strlcpy.c 2010-10-04 15:48:00.086338923 -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/pnfs-utils-1-2-4-rc1.patch b/pnfs-utils-1-2-4-rc1.patch new file mode 100644 index 0000000..2349e45 --- /dev/null +++ b/pnfs-utils-1-2-4-rc1.patch @@ -0,0 +1,5269 @@ +diff -up nfs-utils-1.2.3/configure.ac.orig nfs-utils-1.2.3/configure.ac +--- nfs-utils-1.2.3/configure.ac.orig 2010-11-09 11:45:19.849588000 -0500 ++++ nfs-utils-1.2.3/configure.ac 2010-11-09 11:45:37.237104000 -0500 +@@ -72,11 +72,15 @@ AC_ARG_ENABLE(nfsv4, + enable_nfsv4=yes) + if test "$enable_nfsv4" = yes; then + AC_DEFINE(NFS4_SUPPORTED, 1, [Define this if you want NFSv4 support compiled in]) ++ BLKMAPD=blkmapd + IDMAPD=idmapd ++ SPNFSD=spnfsd + else + enable_nfsv4= ++ BLKMAPD= + IDMAPD= + fi ++ AC_SUBST(BLKMAPD) + AC_SUBST(IDMAPD) + AC_SUBST(enable_nfsv4) + AM_CONDITIONAL(CONFIG_NFSV4, [test "$enable_nfsv4" = "yes"]) +@@ -439,9 +443,11 @@ AC_CONFIG_FILES([ + tools/mountstats/Makefile + tools/nfs-iostat/Makefile + utils/Makefile ++ utils/blkmapd/Makefile + utils/exportfs/Makefile + utils/gssd/Makefile + utils/idmapd/Makefile ++ utils/spnfsd/Makefile + utils/mount/Makefile + utils/mountd/Makefile + utils/nfsd/Makefile +diff -up nfs-utils-1.2.3/support/include/nfslib.h.orig nfs-utils-1.2.3/support/include/nfslib.h +--- nfs-utils-1.2.3/support/include/nfslib.h.orig 2010-11-09 11:45:19.728584000 -0500 ++++ nfs-utils-1.2.3/support/include/nfslib.h 2010-11-09 11:45:37.247102000 -0500 +@@ -89,6 +89,7 @@ struct exportent { + char * e_fslocdata; + char * e_uuid; + struct sec_entry e_secinfo[SECFLAVOR_COUNT+1]; ++ int e_pnfs; + }; + + struct rmtabent { +diff -up nfs-utils-1.2.3/support/include/nfs/nfs.h.orig nfs-utils-1.2.3/support/include/nfs/nfs.h +--- nfs-utils-1.2.3/support/include/nfs/nfs.h.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/support/include/nfs/nfs.h 2010-11-09 11:45:37.242105000 -0500 +@@ -47,6 +47,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)) +@@ -136,6 +137,11 @@ struct nfsctl_fsparm { + int gd_maxlen; + }; + ++/* FD2FH */ ++struct nfsctl_fd2fh { ++ int fd; ++}; ++ + /* + * This is the argument union. + */ +@@ -149,6 +155,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 +@@ -157,6 +164,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.3/support/nfs/exports.c.orig nfs-utils-1.2.3/support/nfs/exports.c +--- nfs-utils-1.2.3/support/nfs/exports.c.orig 2010-11-09 11:45:19.864588000 -0500 ++++ nfs-utils-1.2.3/support/nfs/exports.c 2010-11-09 11:45:37.253103000 -0500 +@@ -107,6 +107,7 @@ static void init_exportent (struct expor + ee->e_nsquids = 0; + ee->e_nsqgids = 0; + ee->e_uuid = NULL; ++ ee->e_pnfs = 0; + } + + struct exportent * +@@ -299,6 +300,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"); + } + +@@ -559,6 +562,10 @@ parseopts(char *cp, struct exportent *ep + clearflags(NFSEXP_NOACL, active, ep); + else if (strcmp(opt, "no_acl") == 0) + setflags(NFSEXP_NOACL, active, ep); ++ else if (strcmp(opt, "pnfs") == 0) ++ ep->e_pnfs = 1; ++ else if (strcmp(opt, "no_pnfs") == 0) ++ ep->e_pnfs = 0; + else if (strncmp(opt, "anonuid=", 8) == 0) { + char *oe; + ep->e_anonuid = strtol(opt+8, &oe, 10); +diff -up nfs-utils-1.2.3/utils/blkmapd/device-discovery.c.orig nfs-utils-1.2.3/utils/blkmapd/device-discovery.c +--- nfs-utils-1.2.3/utils/blkmapd/device-discovery.c.orig 2010-11-09 11:45:37.266108000 -0500 ++++ nfs-utils-1.2.3/utils/blkmapd/device-discovery.c 2010-11-09 11:45:37.268108000 -0500 +@@ -0,0 +1,476 @@ ++/* ++ * device-discovery.c: main function, discovering device and processing ++ * pipe request from kernel. ++ * ++ * Copyright (c) 2010 EMC Corporation, Haiying Tang ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "device-discovery.h" ++ ++#define BL_PIPE_FILE "/var/lib/nfs/rpc_pipefs/bl_device_pipe" ++#define PID_FILE "/var/run/blkmapd.pid" ++ ++struct bl_disk *visible_disk_list; ++ ++struct bl_disk_path *bl_get_path(const char *filepath, ++ struct bl_disk_path *paths) ++{ ++ struct bl_disk_path *tmp = paths; ++ ++ while (tmp) { ++ if (!strcmp(tmp->full_path, filepath)) ++ break; ++ tmp = tmp->next; ++ } ++ return tmp; ++} ++ ++/* Check whether valid_path is a substring(partition) of path */ ++int bl_is_partition(struct bl_disk_path *valid_path, struct bl_disk_path *path) ++{ ++ if (!strncmp(valid_path->full_path, path->full_path, ++ strlen(valid_path->full_path))) ++ return 1; ++ ++ return 0; ++} ++ ++/* ++ * For multipath devices, devices state could be PASSIVE/ACTIVE/PSEUDO, ++ * where PSEUDO > ACTIVE > PASSIVE. Device with highest state is used to ++ * create pseudo device. So if state is higher, the device path needs to ++ * be updated. ++ * If device-mapper multipath support is a must, pseudo devices should ++ * exist for each multipath device. If not, active device path will be ++ * chosen for device creation. ++ * Treat partition as invalid path. ++ */ ++int bl_update_path(struct bl_disk_path *path, enum bl_path_state_e state, ++ struct bl_disk *disk) ++{ ++ struct bl_disk_path *valid_path = disk->valid_path; ++ ++ if (valid_path) { ++ if (valid_path->state >= state) { ++ if (bl_is_partition(valid_path, path)) ++ return 0; ++ } ++ } ++ return 1; ++} ++ ++void bl_release_disk(void) ++{ ++ struct bl_disk *disk; ++ struct bl_disk_path *path = NULL; ++ ++ while (visible_disk_list) { ++ disk = visible_disk_list; ++ path = disk->paths; ++ while (path) { ++ disk->paths = path->next; ++ free(path->full_path); ++ free(path); ++ path = disk->paths; ++ } ++ if (disk->serial) ++ free(disk->serial); ++ visible_disk_list = disk->next; ++ free(disk); ++ } ++} ++ ++void bl_add_disk(char *filepath) ++{ ++ struct bl_disk *disk = NULL; ++ int fd = 0; ++ struct stat sb; ++ off_t size = 0; ++ struct bl_serial *serial = NULL; ++ enum bl_path_state_e ap_state; ++ struct bl_disk_path *diskpath = NULL, *path = NULL; ++ dev_t dev; ++ ++ fd = open(filepath, O_RDONLY | O_LARGEFILE); ++ if (fd < 0) ++ return; ++ ++ if (fstat(fd, &sb)) { ++ close(fd); ++ return; ++ } ++ ++ if (!sb.st_size) ++ ioctl(fd, BLKGETSIZE, &size); ++ else ++ size = sb.st_size; ++ ++ if (!size) { ++ close(fd); ++ return; ++ } ++ ++ dev = sb.st_rdev; ++ serial = bldev_read_serial(fd, filepath); ++ ap_state = bldev_read_ap_state(fd); ++ close(fd); ++ ++ if (ap_state == BL_PATH_STATE_PASSIVE) ++ return; ++ ++ for (disk = visible_disk_list; disk != NULL; disk = disk->next) { ++ /* Already scanned or a partition? ++ * XXX: if released each time, maybe not need to compare ++ */ ++ if ((serial->len == disk->serial->len) && ++ !memcmp(serial->data, disk->serial->data, serial->len)) { ++ diskpath = bl_get_path(filepath, disk->paths); ++ break; ++ } ++ } ++ ++ if (disk && diskpath) ++ return; ++ ++ BL_LOG_INFO("%s: %s\n", __func__, filepath); ++ ++ /* ++ * Not sure how to identify a pseudo device created by ++ * device-mapper, so leave /dev/mapper for now. ++ */ ++ if (strncmp(filepath, "/dev/mapper", 11) == 0) ++ ap_state = BL_PATH_STATE_PSEUDO; ++ ++ /* add path */ ++ path = malloc(sizeof(struct bl_disk_path)); ++ if (!path) { ++ BL_LOG_ERR("%s: Out of memory!\n", __func__); ++ goto out_err; ++ } ++ path->next = NULL; ++ path->state = ap_state; ++ path->full_path = strdup(filepath); ++ if (!path->full_path) ++ goto out_err; ++ ++ if (!disk) { /* add disk */ ++ disk = malloc(sizeof(struct bl_disk)); ++ if (!disk) { ++ BL_LOG_ERR("%s: Out of memory!\n", __func__); ++ goto out_err; ++ } ++ disk->next = visible_disk_list; ++ disk->dev = dev; ++ disk->size = size; ++ disk->serial = serial; ++ disk->valid_path = path; ++ disk->paths = path; ++ visible_disk_list = disk; ++ } else { ++ path->next = disk->paths; ++ disk->paths = path; ++ /* check whether we need to update disk info */ ++ if (bl_update_path(path, path->state, disk)) { ++ disk->dev = dev; ++ disk->size = size; ++ disk->valid_path = path; ++ } ++ } ++ return; ++ ++ out_err: ++ if (path) { ++ if (path->full_path) ++ free(path->full_path); ++ free(path); ++ } ++ return; ++} ++ ++int bl_discover_devices(void) ++{ ++ FILE *f; ++ int n; ++ char buf[PATH_MAX], devname[PATH_MAX], fulldevname[PATH_MAX]; ++ ++ /* release previous list */ ++ bl_release_disk(); ++ ++ /* scan all block devices */ ++ f = fopen("/proc/partitions", "r"); ++ if (f == NULL) ++ return 0; ++ ++ while (1) { ++ if (fgets(buf, sizeof buf, f) == NULL) ++ break; ++ n = sscanf(buf, "%*d %*d %*d %31s", devname); ++ if (n != 1) ++ continue; ++ snprintf(fulldevname, sizeof fulldevname, "/sys/block/%s", ++ devname); ++ if (access(fulldevname, F_OK) < 0) ++ continue; ++ snprintf(fulldevname, sizeof fulldevname, "/dev/%s", devname); ++ bl_add_disk(fulldevname); ++ } ++ ++ fclose(f); ++ ++ return 0; ++} ++ ++/* process kernel request ++ * return 0: request processed, and no more request waiting; ++ * return 1: request processed, and more requests waiting; ++ * return < 0: error ++ */ ++int bl_disk_inquiry_process(int fd) ++{ ++ int ret = 0; ++ struct pipefs_hdr *head = NULL, *tmp; ++ char *buf = NULL; ++ uint32_t major, minor; ++ uint16_t buflen; ++ unsigned int len = 0; ++ ++ head = calloc(1, sizeof(struct pipefs_hdr)); ++ if (!head) { ++ BL_LOG_ERR("%s: Out of memory!\n", __func__); ++ return -ENOMEM; ++ } ++ ++ /* read request */ ++ if (atomicio(read, fd, head, sizeof(*head)) != sizeof(*head)) { ++ /* Note that an error in this or the next read is pretty ++ * catastrophic, as there is no good way to resync into ++ * the pipe's stream. ++ */ ++ BL_LOG_ERR("Read pipefs head error!\n"); ++ ret = -EIO; ++ goto out; ++ } ++ ++ buflen = head->totallen - sizeof(*head); ++ buf = malloc(buflen); ++ if (!buf) { ++ BL_LOG_ERR("%s: Out of memory!\n", __func__); ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ if (atomicio(read, fd, buf, buflen) != buflen) { ++ BL_LOG_ERR("Read pipefs content error!\n"); ++ ret = -EIO; ++ goto out; ++ } ++ ++ head->status = BL_DEVICE_REQUEST_PROC; ++ switch (head->type) { ++ case BL_DEVICE_MOUNT: ++ /* ++ * It shouldn't be necessary to discover devices here, since ++ * process_deviceinfo() will re-discover if it can't find ++ * the devices it needs. But in the case of multipath ++ * devices (ones that appear more than once, for example an ++ * active and a standby LUN), this will re-order them in the ++ * correct priority. ++ */ ++ bl_discover_devices(); ++ if (!process_deviceinfo(buf, buflen, &major, &minor)) { ++ head->status = BL_DEVICE_REQUEST_ERR; ++ break; ++ } ++ tmp = realloc(head, sizeof(major) + sizeof(minor) + ++ sizeof(struct pipefs_hdr)); ++ if (!tmp) { ++ BL_LOG_ERR("%s: Out of memory!\n", __func__); ++ ret = -ENOMEM; ++ goto out; ++ } ++ head = tmp; ++ memcpy((void *)head + sizeof(struct pipefs_hdr), ++ &major, sizeof(major)); ++ memcpy((void *)head + sizeof(struct pipefs_hdr) + sizeof(major), ++ &minor, sizeof(minor)); ++ len = sizeof(major) + sizeof(minor); ++ break; ++ case BL_DEVICE_UMOUNT: ++ if (!dm_device_remove_all((uint64_t *) buf)) ++ head->status = BL_DEVICE_REQUEST_ERR; ++ break; ++ default: ++ head->status = BL_DEVICE_REQUEST_ERR; ++ break; ++ } ++ ++ head->totallen = sizeof(struct pipefs_hdr) + len; ++ /* write to pipefs */ ++ if (atomicio((void *)write, fd, head, head->totallen) ++ != head->totallen) { ++ BL_LOG_ERR("Write pipefs error!\n"); ++ ret = -EIO; ++ } ++ ++ out: ++ if (buf) ++ free(buf); ++ if (head) ++ free(head); ++ return ret; ++} ++ ++/* TODO: set bl_process_stop to 1 in command */ ++unsigned int bl_process_stop; ++ ++int bl_run_disk_inquiry_process(int fd) ++{ ++ fd_set rset; ++ int ret; ++ ++ bl_process_stop = 0; ++ ++ for (;;) { ++ if (bl_process_stop) ++ return 1; ++ FD_ZERO(&rset); ++ FD_SET(fd, &rset); ++ ret = 0; ++ switch (select(fd + 1, &rset, NULL, NULL, NULL)) { ++ case -1: ++ if (errno == EINTR) ++ continue; ++ else { ++ ret = -errno; ++ goto out; ++ } ++ case 0: ++ goto out; ++ default: ++ if (FD_ISSET(fd, &rset)) ++ ret = bl_disk_inquiry_process(fd); ++ } ++ } ++ out: ++ return ret; ++} ++ ++/* Daemon */ ++int main(int argc, char **argv) ++{ ++ int fd, pidfd = -1, opt, dflag = 0, fg = 0, ret = 1; ++ struct stat statbuf; ++ char pidbuf[64]; ++ ++ while ((opt = getopt(argc, argv, "df")) != -1) { ++ switch (opt) { ++ case 'd': ++ dflag = 1; ++ break; ++ case 'f': ++ fg = 1; ++ break; ++ } ++ } ++ ++ if (fg) { ++ openlog("blkmapd", LOG_PERROR, 0); ++ } else { ++ if (!stat(PID_FILE, &statbuf)) { ++ fprintf(stderr, "Pid file %s already existed\n", PID_FILE); ++ exit(1); ++ } ++ ++ if (daemon(0, 0) != 0) { ++ fprintf(stderr, "Daemonize failed\n"); ++ exit(1); ++ } ++ ++ openlog("blkmapd", LOG_PID, 0); ++ pidfd = open(PID_FILE, O_WRONLY | O_CREAT, 0644); ++ if (pidfd < 0) { ++ BL_LOG_ERR("Create pid file %s failed\n", PID_FILE); ++ exit(1); ++ } ++ ++ if (lockf(pidfd, F_TLOCK, 0) < 0) { ++ BL_LOG_ERR("Lock pid file %s failed\n", PID_FILE); ++ close(pidfd); ++ exit(1); ++ } ++ ftruncate(pidfd, 0); ++ sprintf(pidbuf, "%d\n", getpid()); ++ write(pidfd, pidbuf, strlen(pidbuf)); ++ } ++ ++ if (dflag) { ++ bl_discover_devices(); ++ exit(0); ++ } ++ ++ /* open pipe file */ ++ fd = open(BL_PIPE_FILE, O_RDWR); ++ if (fd < 0) { ++ BL_LOG_ERR("open pipe file %s error\n", BL_PIPE_FILE); ++ exit(1); ++ } ++ ++ while (1) { ++ /* discover device when needed */ ++ bl_discover_devices(); ++ ++ ret = bl_run_disk_inquiry_process(fd); ++ if (ret < 0) { ++ /* what should we do with process error? */ ++ BL_LOG_ERR("inquiry process return %d\n", ret); ++ } ++ } ++ ++ if (pidfd >= 0) { ++ close(pidfd); ++ unlink(PID_FILE); ++ } ++ ++ exit(ret); ++} +diff -up nfs-utils-1.2.3/utils/blkmapd/device-discovery.h.orig nfs-utils-1.2.3/utils/blkmapd/device-discovery.h +--- nfs-utils-1.2.3/utils/blkmapd/device-discovery.h.orig 2010-11-09 11:45:37.271104000 -0500 ++++ nfs-utils-1.2.3/utils/blkmapd/device-discovery.h 2010-11-09 11:45:37.272112000 -0500 +@@ -0,0 +1,161 @@ ++/* ++ * bl-device-discovery.h ++ * ++ * Copyright (c) 2010 EMC Corporation, Haiying Tang ++ * 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. ++ */ ++#ifndef BL_DEVICE_DISCOVERY_H ++#define BL_DEVICE_DISCOVERY_H ++ ++#include ++#include ++ ++enum blk_vol_type { ++ BLOCK_VOLUME_SIMPLE = 0, /* maps to a single LU */ ++ BLOCK_VOLUME_SLICE = 1, /* slice of another volume */ ++ BLOCK_VOLUME_CONCAT = 2, /* concatenation of multiple volumes */ ++ BLOCK_VOLUME_STRIPE = 3, /* striped across multiple volumes */ ++ BLOCK_VOLUME_PSEUDO = 4, ++}; ++ ++/* All disk offset/lengths are stored in 512-byte sectors */ ++struct bl_volume { ++ uint32_t bv_type; ++ off_t bv_size; ++ struct bl_volume **bv_vols; ++ int bv_vol_n; ++ union { ++ dev_t bv_dev; /* for BLOCK_VOLUME_SIMPLE(PSEUDO) */ ++ off_t bv_stripe_unit; /* for BLOCK_VOLUME_STRIPE(CONCAT) */ ++ off_t bv_offset; /* for BLOCK_VOLUME_SLICE */ ++ } param; ++}; ++ ++struct bl_sig_comp { ++ int64_t bs_offset; /* In bytes */ ++ uint32_t bs_length; /* In bytes */ ++ char *bs_string; ++}; ++ ++/* Maximum number of signatures components in a simple volume */ ++# define BLOCK_MAX_SIG_COMP 16 ++ ++struct bl_sig { ++ int si_num_comps; ++ struct bl_sig_comp si_comps[BLOCK_MAX_SIG_COMP]; ++}; ++ ++/* ++ * Multipath support: ACTIVE or PSEUDO device is valid, ++ * PASSIVE is a standby for ACTIVE. ++ */ ++enum bl_path_state_e { ++ BL_PATH_STATE_PASSIVE = 1, ++ BL_PATH_STATE_ACTIVE = 2, ++ BL_PATH_STATE_PSEUDO = 3, ++}; ++ ++struct bl_serial { ++ int len; ++ char *data; ++}; ++ ++struct bl_disk_path { ++ struct bl_disk_path *next; ++ char *full_path; ++ enum bl_path_state_e state; ++}; ++ ++struct bl_disk { ++ struct bl_disk *next; ++ struct bl_serial *serial; ++ dev_t dev; ++ off_t size; ++ struct bl_disk_path *valid_path; ++ struct bl_disk_path *paths; ++}; ++ ++struct bl_dev_id { ++ unsigned char type; ++ unsigned char ids; ++ unsigned char reserve; ++ unsigned char len; ++ char data[0]; ++}; ++ ++struct pipefs_hdr { ++ uint32_t msgid; ++ uint8_t type; ++ uint8_t flags; ++ uint16_t totallen; /* length of entire message, including hdr */ ++ uint32_t status; ++}; ++ ++#define BL_DEVICE_UMOUNT 0x0 /* Umount--delete devices */ ++#define BL_DEVICE_MOUNT 0x1 /* Mount--create devices */ ++#define BL_DEVICE_REQUEST_INIT 0x0 /* Start request */ ++#define BL_DEVICE_REQUEST_PROC 0x1 /* User process succeeds */ ++#define BL_DEVICE_REQUEST_ERR 0x2 /* User process fails */ ++ ++uint32_t *blk_overflow(uint32_t * p, uint32_t * end, size_t nbytes); ++ ++#define BLK_READBUF(p, e, nbytes) do { \ ++ p = blk_overflow(p, e, nbytes); \ ++ if (!p) {\ ++ goto out_err;\ ++ } \ ++} while (0) ++ ++#define READ32(x) (x) = ntohl(*p++) ++ ++#define READ64(x) do { \ ++ (x) = (uint64_t)ntohl(*p++) << 32; \ ++ (x) |= ntohl(*p++); \ ++} while (0) ++ ++#define READ_SECTOR(x) do { \ ++ READ64(tmp); \ ++ if (tmp & 0x1ff) { \ ++ goto out_err; \ ++ } \ ++ (x) = tmp >> 9; \ ++} while (0) ++ ++extern struct bl_disk *visible_disk_list; ++uint64_t dm_device_create(struct bl_volume *vols, int num_vols); ++int dm_device_remove_all(uint64_t *dev); ++uint64_t process_deviceinfo(const char *dev_addr_buf, ++ unsigned int dev_addr_len, ++ uint32_t *major, uint32_t *minor); ++ ++extern ssize_t atomicio(ssize_t(*f) (int, void *, size_t), ++ int fd, void *_s, size_t n); ++extern struct bl_serial *bldev_read_serial(int fd, const char *filename); ++extern enum bl_path_state_e bldev_read_ap_state(int fd); ++extern int bl_discover_devices(void); ++ ++#define BL_LOG_INFO(fmt...) syslog(LOG_INFO, fmt) ++#define BL_LOG_WARNING(fmt...) syslog(LOG_WARNING, fmt) ++#define BL_LOG_ERR(fmt...) syslog(LOG_ERR, fmt) ++#define BL_LOG_DEBUG(fmt...) syslog(LOG_DEBUG, fmt) ++#endif +diff -up nfs-utils-1.2.3/utils/blkmapd/device-inq.c.orig nfs-utils-1.2.3/utils/blkmapd/device-inq.c +--- nfs-utils-1.2.3/utils/blkmapd/device-inq.c.orig 2010-11-09 11:45:37.275107000 -0500 ++++ nfs-utils-1.2.3/utils/blkmapd/device-inq.c 2010-11-09 11:45:37.277103000 -0500 +@@ -0,0 +1,232 @@ ++/* ++ * device-inq.c: inquire SCSI device information. ++ * ++ * Copyright (c) 2010 EMC Corporation, Haiying Tang ++ * All rights reserved. ++ * ++ * This program refers to "SCSI Primary Commands - 3 (SPC-3) ++ * at http://www.t10.org and sg_inq.c in sg3_utils-1.26 for ++ * Linux OS SCSI subsystem, by D. Gilbert. ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "device-discovery.h" ++ ++#define DEF_ALLOC_LEN 255 ++#define MX_ALLOC_LEN (0xc000 + 0x80) ++ ++static struct bl_serial *bl_create_scsi_string(int len, const char *bytes) ++{ ++ struct bl_serial *s; ++ ++ s = malloc(sizeof(*s) + len); ++ if (s) { ++ s->data = (char *)&s[1]; ++ s->len = len; ++ memcpy(s->data, bytes, len); ++ } ++ return s; ++} ++ ++static void bl_free_scsi_string(struct bl_serial *str) ++{ ++ if (str) ++ free(str); ++} ++ ++#define sg_io_ok(io_hdr) \ ++ ((((io_hdr).status & 0x7e) == 0) && \ ++ ((io_hdr).host_status == 0) && \ ++ (((io_hdr).driver_status & 0x0f) == 0)) ++ ++static int sg_timeout = 1 * 1000; ++ ++static int bldev_inquire_page(int fd, int page, char *buffer, int len) ++{ ++ unsigned char cmd[] = { INQUIRY, 0, 0, 0, 0, 0 }; ++ unsigned char sense_b[28]; ++ struct sg_io_hdr io_hdr; ++ if (page >= 0) { ++ cmd[1] = 1; ++ cmd[2] = page; ++ } ++ cmd[3] = (unsigned char)((len >> 8) & 0xff); ++ cmd[4] = (unsigned char)(len & 0xff); ++ ++ memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); ++ io_hdr.interface_id = 'S'; ++ io_hdr.cmd_len = sizeof(cmd); ++ io_hdr.mx_sb_len = sizeof(sense_b); ++ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; ++ io_hdr.dxfer_len = len; ++ io_hdr.dxferp = buffer; ++ io_hdr.cmdp = cmd; ++ io_hdr.sbp = sense_b; ++ io_hdr.timeout = sg_timeout; ++ if (ioctl(fd, SG_IO, &io_hdr) < 0) ++ return -1; ++ ++ if (sg_io_ok(io_hdr)) ++ return 0; ++ return -1; ++} ++ ++static int bldev_inquire_pages(int fd, int page, char **buffer) ++{ ++ int status = 0; ++ char *tmp; ++ int len; ++ ++ *buffer = calloc(DEF_ALLOC_LEN, sizeof(char)); ++ if (!*buffer) { ++ BL_LOG_ERR("%s: Out of memory!\n", __func__); ++ return -ENOMEM; ++ } ++ ++ status = bldev_inquire_page(fd, page, *buffer, DEF_ALLOC_LEN); ++ if (status) ++ goto out; ++ ++ status = -1; ++ if ((*(*buffer + 1) & 0xff) != page) ++ goto out; ++ ++ len = (*(*buffer + 2) << 8) + *(*buffer + 3) + 4; ++ if (len > MX_ALLOC_LEN) { ++ BL_LOG_ERR("SCSI response length too long: %d\n", len); ++ goto out; ++ } ++ if (len > DEF_ALLOC_LEN) { ++ tmp = realloc(*buffer, len); ++ if (!tmp) { ++ BL_LOG_ERR("%s: Out of memory!\n", __func__); ++ status = -ENOMEM; ++ goto out; ++ } ++ *buffer = tmp; ++ status = bldev_inquire_page(fd, page, *buffer, len); ++ if (status) ++ goto out; ++ } ++ status = 0; ++ out: ++ return status; ++} ++ ++/* For EMC multipath devices, use VPD page (0xc0) to get status. ++ * For other devices, return ACTIVE for now ++ */ ++extern enum bl_path_state_e bldev_read_ap_state(int fd) ++{ ++ int status = 0; ++ char *buffer = NULL; ++ enum bl_path_state_e ap_state = BL_PATH_STATE_ACTIVE; ++ ++ status = bldev_inquire_pages(fd, 0xc0, &buffer); ++ if (status) ++ goto out; ++ ++ if (buffer[4] < 0x02) ++ ap_state = BL_PATH_STATE_PASSIVE; ++ out: ++ if (buffer) ++ free(buffer); ++ return ap_state; ++} ++ ++struct bl_serial *bldev_read_serial(int fd, const char *filename) ++{ ++ struct bl_serial *serial_out = NULL; ++ int status = 0, pos, len; ++ char *buffer; ++ struct bl_dev_id *dev_root, *dev_id; ++ unsigned int current_id = 0; ++ ++ status = bldev_inquire_pages(fd, 0x83, &buffer); ++ if (status) ++ goto out; ++ ++ dev_root = (struct bl_dev_id *)buffer; ++ ++ pos = 0; ++ current_id = 0; ++ len = dev_root->len; ++ while (pos < (len - sizeof(struct bl_dev_id) + sizeof(unsigned char))) { ++ dev_id = (struct bl_dev_id *)&(dev_root->data[pos]); ++ if ((dev_id->ids & 0xf) < current_id) ++ continue; ++ switch (dev_id->ids & 0xf) { ++ /* We process SCSI ID with four ID cases: 0, 1, 2 and 3. ++ * When more than one ID is available, priority is ++ * 3>2>1>0. ++ */ ++ case 2: /* EUI-64 based */ ++ if ((dev_id->len != 8) && (dev_id->len != 12) && ++ (dev_id->len != 16)) ++ break; ++ case 3: /* NAA */ ++ /* TODO: NAA validity judgement too complicated, ++ * so just ingore it here. ++ */ ++ if ((dev_id->type & 0xf) != 1) { ++ BL_LOG_ERR("Binary code_set expected\n"); ++ break; ++ } ++ case 0: /* vendor specific */ ++ case 1: /* T10 vendor identification */ ++ current_id = dev_id->ids & 0xf; ++ if (serial_out) ++ bl_free_scsi_string(serial_out); ++ serial_out = bl_create_scsi_string(dev_id->len, ++ dev_id->data); ++ break; ++ } ++ if (current_id == 3) ++ break; ++ pos += (dev_id->len + sizeof(struct bl_dev_id) - ++ sizeof(unsigned char)); ++ } ++ out: ++ if (!serial_out) ++ serial_out = bl_create_scsi_string(strlen(filename), filename); ++ if (buffer) ++ free(buffer); ++ return serial_out; ++} +diff -up nfs-utils-1.2.3/utils/blkmapd/device-process.c.orig nfs-utils-1.2.3/utils/blkmapd/device-process.c +--- nfs-utils-1.2.3/utils/blkmapd/device-process.c.orig 2010-11-09 11:45:37.280103000 -0500 ++++ nfs-utils-1.2.3/utils/blkmapd/device-process.c 2010-11-09 11:45:37.281109000 -0500 +@@ -0,0 +1,386 @@ ++/* ++ * device-process.c: detailed processing of device information sent ++ * from kernel. ++ * ++ * Copyright (c) 2006 The Regents of the University of Michigan. ++ * All rights reserved. ++ * ++ * Andy Adamson ++ * Fred Isaman ++ * ++ * Copyright (c) 2010 EMC Corporation, Haiying Tang ++ * ++ * Used codes in linux/fs/nfs/blocklayout/blocklayoutdev.c. ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "device-discovery.h" ++ ++uint32_t *blk_overflow(uint32_t * p, uint32_t * end, size_t nbytes) ++{ ++ uint32_t *q = p + ((nbytes + 3) >> 2); ++ if (q > end || q < p) ++ return NULL; ++ return p; ++} ++ ++static int decode_blk_signature(uint32_t **pp, uint32_t *end, ++ struct bl_sig *sig) ++{ ++ int i, tmp; ++ uint32_t *p = *pp; ++ ++ BLK_READBUF(p, end, 4); ++ READ32(sig->si_num_comps); ++ if (sig->si_num_comps == 0) { ++ BL_LOG_ERR("0 components in sig\n"); ++ goto out_err; ++ } ++ if (sig->si_num_comps >= BLOCK_MAX_SIG_COMP) { ++ BL_LOG_ERR("number of sig comps %i >= BLOCK_MAX_SIG_COMP\n", ++ sig->si_num_comps); ++ goto out_err; ++ } ++ for (i = 0; i < sig->si_num_comps; i++) { ++ BLK_READBUF(p, end, 12); ++ READ64(sig->si_comps[i].bs_offset); ++ READ32(tmp); ++ sig->si_comps[i].bs_length = tmp; ++ BLK_READBUF(p, end, tmp); ++ /* Note we rely here on fact that sig is used immediately ++ * for mapping, then thrown away. ++ */ ++ sig->si_comps[i].bs_string = (char *)p; ++ BL_LOG_INFO("%s: si_comps[%d]: bs_length %d, bs_string %s\n", ++ __func__, i, sig->si_comps[i].bs_length, ++ sig->si_comps[i].bs_string); ++ p += ((tmp + 3) >> 2); ++ } ++ *pp = p; ++ return 0; ++ out_err: ++ return -EIO; ++} ++ ++/* Read signature from device ++ * return 0: read successfully ++ * return -1: error ++ */ ++int ++read_cmp_blk_sig(const char *dev_name, struct bl_sig_comp *comp, ++ int64_t bs_offset) ++{ ++ int fd, ret = -1; ++ char *sig = NULL; ++ ++ fd = open(dev_name, O_RDONLY | O_LARGEFILE); ++ if (fd < 0) { ++ BL_LOG_ERR("%s could not be opened for read\n", dev_name); ++ goto error; ++ } ++ ++ sig = (char *)malloc(comp->bs_length); ++ if (!sig) { ++ BL_LOG_ERR("%s: Out of memory\n", __func__); ++ goto error; ++ } ++ ++ if (lseek64(fd, bs_offset, SEEK_SET) == -1) { ++ BL_LOG_ERR("File %s lseek error\n", dev_name); ++ goto error; ++ } ++ ++ if (read(fd, sig, comp->bs_length) != comp->bs_length) { ++ BL_LOG_ERR("File %s read error\n", dev_name); ++ goto error; ++ } ++ ++ BL_LOG_INFO ++ ("%s: %s sig: %s, bs_string: %s, bs_length: %d, bs_offset: %lld\n", ++ __func__, dev_name, sig, comp->bs_string, comp->bs_length, ++ (long long)bs_offset); ++ ret = memcmp(sig, comp->bs_string, comp->bs_length); ++ ++ error: ++ if (sig) ++ free(sig); ++ if (fd >= 0) ++ close(fd); ++ return ret; ++} ++ ++/* ++ * All signatures in sig must be found on disk for verification. ++ * Returns True if sig matches, False otherwise. ++ */ ++static int verify_sig(struct bl_disk *disk, struct bl_sig *sig) ++{ ++ struct bl_sig_comp *comp; ++ int i, ret; ++ int64_t bs_offset; ++ ++ for (i = 0; i < sig->si_num_comps; i++) { ++ comp = &sig->si_comps[i]; ++ bs_offset = comp->bs_offset; ++ if (bs_offset < 0) ++ bs_offset += (((int64_t) disk->size) << 9); ++ BL_LOG_INFO("%s: bs_offset: %lld\n", ++ __func__, (long long) bs_offset); ++ ret = read_cmp_blk_sig(disk->valid_path->full_path, ++ comp, bs_offset); ++ if (ret) ++ return 0; ++ } ++ return 1; ++} ++ ++/* ++ * map_sig_to_device() ++ * Given a signature, walk the list of visible disks searching for ++ * a match. Returns True if mapping was done, False otherwise. ++ * ++ * While we're at it, fill in the vol->bv_size. ++ */ ++static int map_sig_to_device(struct bl_sig *sig, struct bl_volume *vol) ++{ ++ int mapped = 0; ++ struct bl_disk *disk = visible_disk_list; ++ char *filepath = 0; ++ struct bl_disk *lolDisk = disk; ++ ++ while (lolDisk) { ++ BL_LOG_INFO("%s: visible_disk_list: %s\n", __func__, ++ lolDisk->valid_path->full_path); ++ lolDisk = lolDisk->next; ++ } ++ ++ /* scan disk list to find out match device */ ++ while (disk) { ++ /* FIXME: should we use better algorithm for disk scan? */ ++ mapped = verify_sig(disk, sig); ++ if (mapped) { ++ vol->param.bv_dev = disk->dev; ++ filepath = disk->valid_path->full_path; ++ vol->bv_size = disk->size; ++ break; ++ } ++ disk = disk->next; ++ } ++ return mapped; ++} ++ ++/* We are given an array of XDR encoded array indices, each of which should ++ * refer to a previously decoded device. Translate into a list of pointers ++ * to the appropriate pnfs_blk_volume's. ++ */ ++static int set_vol_array(uint32_t **pp, uint32_t *end, ++ struct bl_volume *vols, int working) ++{ ++ int i, index; ++ uint32_t *p = *pp; ++ struct bl_volume **array = vols[working].bv_vols; ++ for (i = 0; i < vols[working].bv_vol_n; i++) { ++ BLK_READBUF(p, end, 4); ++ READ32(index); ++ if ((index < 0) || (index >= working)) { ++ BL_LOG_ERR("set_vol_array: Id %i out of range\n", ++ index); ++ goto out_err; ++ } ++ array[i] = &vols[index]; ++ } ++ *pp = p; ++ return 0; ++ out_err: ++ return -EIO; ++} ++ ++static uint64_t sum_subvolume_sizes(struct bl_volume *vol) ++{ ++ int i; ++ uint64_t sum = 0; ++ for (i = 0; i < vol->bv_vol_n; i++) ++ sum += vol->bv_vols[i]->bv_size; ++ return sum; ++} ++ ++static int decode_blk_volume(uint32_t **pp, uint32_t *end, ++ struct bl_volume *vols, int i, int *array_cnt) ++{ ++ int status = 0, j; ++ struct bl_sig sig; ++ uint32_t *p = *pp; ++ struct bl_volume *vol = &vols[i]; ++ uint64_t tmp, tmp_size; ++ div_t d; ++ ++ BLK_READBUF(p, end, 4); ++ READ32(vol->bv_type); ++ switch (vol->bv_type) { ++ case BLOCK_VOLUME_SIMPLE: ++ *array_cnt = 0; ++ status = decode_blk_signature(&p, end, &sig); ++ if (status) ++ return status; ++ status = map_sig_to_device(&sig, vol); ++ if (!status) { ++ BL_LOG_ERR("Could not find disk for device\n"); ++ return -ENXIO; ++ } ++ status = 0; ++ break; ++ case BLOCK_VOLUME_SLICE: ++ BLK_READBUF(p, end, 16); ++ READ_SECTOR(vol->param.bv_offset); ++ READ_SECTOR(vol->bv_size); ++ *array_cnt = vol->bv_vol_n = 1; ++ status = set_vol_array(&p, end, vols, i); ++ break; ++ case BLOCK_VOLUME_STRIPE: ++ BLK_READBUF(p, end, 8); ++ READ_SECTOR(vol->param.bv_stripe_unit); ++ off_t chunksize = vol->param.bv_stripe_unit; ++ if ((chunksize == 0) || ++ ((chunksize & (chunksize - 1)) != 0) || ++ (chunksize < (PAGE_SIZE >> 9))) ++ return -EIO; ++ BLK_READBUF(p, end, 4); ++ READ32(vol->bv_vol_n); ++ if (!vol->bv_vol_n) ++ return -EIO; ++ *array_cnt = vol->bv_vol_n; ++ status = set_vol_array(&p, end, vols, i); ++ if (status) ++ return status; ++ for (j = 1; j < vol->bv_vol_n; j++) { ++ if (vol->bv_vols[j]->bv_size != ++ vol->bv_vols[0]->bv_size) { ++ BL_LOG_ERR("varying subvol size\n"); ++ return -EIO; ++ } ++ } ++ /* Make sure total size only includes addressable areas */ ++ tmp_size = vol->bv_vols[0]->bv_size; ++ d = div(tmp_size, (uint32_t) vol->param.bv_stripe_unit); ++ tmp_size = d.quot; ++ vol->bv_size = tmp_size * vol->param.bv_stripe_unit; ++ break; ++ case BLOCK_VOLUME_CONCAT: ++ BLK_READBUF(p, end, 4); ++ READ32(vol->bv_vol_n); ++ if (!vol->bv_vol_n) ++ return -EIO; ++ *array_cnt = vol->bv_vol_n; ++ status = set_vol_array(&p, end, vols, i); ++ if (status) ++ return status; ++ vol->bv_size = sum_subvolume_sizes(vol); ++ break; ++ default: ++ BL_LOG_ERR("Unknown volume type %i\n", vol->bv_type); ++ out_err: ++ return -EIO; ++ } ++ *pp = p; ++ return status; ++} ++ ++uint64_t process_deviceinfo(const char *dev_addr_buf, ++ unsigned int dev_addr_len, ++ uint32_t *major, uint32_t *minor) ++{ ++ int num_vols, i, status, count; ++ uint32_t *p, *end; ++ struct bl_volume *vols = NULL, **arrays = NULL, **arrays_ptr = NULL; ++ uint64_t dev = 0; ++ ++ p = (uint32_t *) dev_addr_buf; ++ end = (uint32_t *) ((char *)p + dev_addr_len); ++ /* Decode block volume */ ++ BLK_READBUF(p, end, 4); ++ READ32(num_vols); ++ if (num_vols <= 0) { ++ BL_LOG_ERR("Error: number of vols: %d\n", num_vols); ++ goto out_err; ++ } ++ ++ vols = (struct bl_volume *)malloc(num_vols * sizeof(struct bl_volume)); ++ if (!vols) { ++ BL_LOG_ERR("%s: Out of memory\n", __func__); ++ goto out_err; ++ } ++ ++ /* Each volume in vols array needs its own array. Save time by ++ * allocating them all in one large hunk. Because each volume ++ * array can only reference previous volumes, and because once ++ * a concat or stripe references a volume, it may never be ++ * referenced again, the volume arrays are guaranteed to fit ++ * in the suprisingly small space allocated. ++ */ ++ arrays = ++ (struct bl_volume **)malloc(num_vols * 2 * ++ sizeof(struct bl_volume *)); ++ if (!arrays) { ++ BL_LOG_ERR("%s: Out of memory\n", __func__); ++ goto out_err; ++ } ++ ++ arrays_ptr = arrays; ++ ++ for (i = 0; i < num_vols; i++) { ++ vols[i].bv_vols = arrays_ptr; ++ status = decode_blk_volume(&p, end, vols, i, &count); ++ if (status) ++ goto out_err; ++ arrays_ptr += count; ++ } ++ ++ if (p != end) { ++ BL_LOG_ERR("p is not equal to end!\n"); ++ goto out_err; ++ } ++ ++ dev = dm_device_create(vols, num_vols); ++ if (dev) { ++ *major = MAJOR(dev); ++ *minor = MINOR(dev); ++ } ++ ++ out_err: ++ if (vols) ++ free(vols); ++ if (arrays) ++ free(arrays); ++ return dev; ++} +diff -up nfs-utils-1.2.3/utils/blkmapd/dm-device.c.orig nfs-utils-1.2.3/utils/blkmapd/dm-device.c +--- nfs-utils-1.2.3/utils/blkmapd/dm-device.c.orig 2010-11-09 11:45:37.284107000 -0500 ++++ nfs-utils-1.2.3/utils/blkmapd/dm-device.c 2010-11-09 11:45:37.286104000 -0500 +@@ -0,0 +1,510 @@ ++/* ++ * dm-device.c: create or remove device via device mapper API. ++ * ++ * Copyright (c) 2010 EMC Corporation, Haiying Tang ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include "device-discovery.h" ++ ++#define DM_DEV_NAME_LEN 256 ++ ++#ifndef DM_MAX_TYPE_NAME ++#define DM_MAX_TYPE_NAME 16 ++#endif ++ ++#define DM_PARAMS_LEN 512 /* XXX: is this enough for target? */ ++#define DM_DIR "/dev/mapper" ++#define DM_DIR_LEN12 ++#define TYPE_HAS_DEV(type) ((type == BLOCK_VOLUME_SIMPLE) || \ ++ (type == BLOCK_VOLUME_PSEUDO)) ++ ++struct bl_dm_table { ++ uint64_t offset; ++ uint64_t size; ++ char target_type[DM_MAX_TYPE_NAME]; ++ char params[DM_PARAMS_LEN]; ++ struct bl_dm_table *next; ++}; ++ ++struct bl_dm_tree { ++ uint64_t dev; ++ struct dm_tree *tree; ++ struct bl_dm_tree *next; ++}; ++ ++static inline struct bl_dm_table *bl_dm_table_alloc(void) ++{ ++ return (struct bl_dm_table *)calloc(1, sizeof(struct bl_dm_table)); ++} ++ ++void bl_dm_table_free(struct bl_dm_table *bl_table_head) ++{ ++ struct bl_dm_table *p = bl_table_head; ++ while (bl_table_head) { ++ p = bl_table_head->next; ++ free(bl_table_head); ++ bl_table_head = p; ++ } ++} ++ ++void add_to_bl_dm_table(struct bl_dm_table **bl_table_head, ++ struct bl_dm_table *table) ++{ ++ struct bl_dm_table *pre; ++ if (!*bl_table_head) { ++ *bl_table_head = table; ++ return; ++ } ++ pre = *bl_table_head; ++ while (pre->next) ++ pre = pre->next; ++ pre->next = table; ++ return; ++} ++ ++struct bl_dm_tree *bl_tree_head; ++ ++struct bl_dm_tree *find_bl_dm_tree(uint64_t dev) ++{ ++ struct bl_dm_tree *p = bl_tree_head; ++ while (p) { ++ if (p->dev == dev) ++ return p; ++ p = p->next; ++ } ++ return NULL; ++} ++ ++void del_from_bl_dm_tree(uint64_t dev) ++{ ++ struct bl_dm_tree *pre = bl_tree_head; ++ struct bl_dm_tree *p; ++ ++ p = pre; ++ while (p) { ++ if (p->dev == dev) { ++ pre->next = p->next; ++ if (p == bl_tree_head) ++ bl_tree_head = bl_tree_head->next; ++ free(p); ++ break; ++ } ++ pre = p; ++ p = pre->next; ++ } ++} ++ ++void add_to_bl_dm_tree(struct bl_dm_tree *tree) ++{ ++ struct bl_dm_tree *pre; ++ if (!bl_tree_head) { ++ bl_tree_head = tree; ++ return; ++ } ++ pre = bl_tree_head; ++ while (pre->next) ++ pre = pre->next; ++ pre->next = tree; ++ return; ++} ++ ++/* Create device via device mapper ++ * return 0 when creation failed ++ * return dev no for created device ++ */ ++uint64_t dm_single_device_create(const char *dev_name, struct bl_dm_table * p) ++{ ++ struct dm_task *dmt; ++ struct dm_info dminfo; ++ int ret = 0; ++ ++ dmt = dm_task_create(DM_DEVICE_CREATE); ++ if (!dmt) { ++ BL_LOG_ERR("Create dm_task for %s failed\n", dev_name); ++ return 0; ++ } ++ ret = dm_task_set_name(dmt, dev_name); ++ if (!ret) ++ goto err_out; ++ ++ while (p) { ++ ret = dm_task_add_target(dmt, p->offset, p->size, ++ p->target_type, p->params); ++ if (!ret) ++ goto err_out; ++ p = p->next; ++ } ++ ++ ret = dm_task_run(dmt) && ++ dm_task_get_info(dmt, &dminfo) && dminfo.exists; ++ ++ if (!ret) ++ goto err_out; ++ ++ dm_task_update_nodes(); ++ ++ err_out: ++ dm_task_destroy(dmt); ++ ++ if (!ret) { ++ BL_LOG_ERR("Create device %s failed\n", dev_name); ++ return 0; ++ } ++ return MKDEV(dminfo.major, dminfo.minor); ++} ++ ++int dm_device_remove_byname(const char *dev_name) ++{ ++ struct dm_task *dmt; ++ int ret = 0; ++ ++ dmt = dm_task_create(DM_DEVICE_REMOVE); ++ if (!dmt) ++ return -ENODEV; ++ ++ ret = dm_task_set_name(dmt, dev_name) && dm_task_run(dmt); ++ ++ dm_task_update_nodes(); ++ ++ if (dmt) ++ dm_task_destroy(dmt); ++ ++ return ret; ++} ++ ++int dm_device_remove(uint64_t dev) ++{ ++ struct dm_task *dmt; ++ struct dm_names *dmnames; ++ char *names = NULL; ++ int ret = -1; ++ ++ /* Look for dev_name via dev, if dev_name could be transferred here, ++ we could jump to DM_DEVICE_REMOVE directly */ ++ dmt = dm_task_create(DM_DEVICE_LIST); ++ if (!dmt) { ++ BL_LOG_ERR("dm_task creation failed\n"); ++ return -ENODEV; ++ } ++ ++ ret = dm_task_run(dmt); ++ if (!ret) { ++ BL_LOG_ERR("dm_task_run failed\n"); ++ goto error; ++ } ++ ++ dmnames = dm_task_get_names(dmt); ++ if (!dmnames || !dmnames->dev) { ++ BL_LOG_ERR("dm_task_get_names failed\n"); ++ goto error; ++ } ++ ++ do { ++ if (dmnames->dev == dev) { ++ names = dmnames->name; ++ break; ++ } ++ dmnames = (void *)dmnames + dmnames->next; ++ } while (dmnames); ++ ++ if (!names) { ++ BL_LOG_ERR("Could not find device\n"); ++ goto error; ++ } ++ ++ dm_task_update_nodes(); ++ ++ error: ++ dm_task_destroy(dmt); ++ ++ /* Start to remove device */ ++ if (names) ++ ret = dm_device_remove_byname(names); ++ return ret; ++} ++ ++static unsigned long dev_count; ++ ++void dm_devicelist_remove(unsigned long start, unsigned long end) ++{ ++ char dev_name[DM_DEV_NAME_LEN]; ++ unsigned long count; ++ ++ if ((start >= dev_count) || (end <= 1) || (start >= end - 1)) ++ return; ++ ++ for (count = end - 1; count > start; count--) { ++ sprintf(dev_name, "pnfs_vol_%lu", count - 1); ++ dm_device_remove_byname(dev_name); ++ } ++ ++ return; ++} ++ ++void bl_dm_remove_tree(uint64_t dev) ++{ ++ struct bl_dm_tree *p; ++ ++ p = find_bl_dm_tree(dev); ++ if (!p) ++ return; ++ ++ dm_tree_free(p->tree); ++ del_from_bl_dm_tree(dev); ++} ++ ++void bl_dm_create_tree(uint64_t dev) ++{ ++ struct dm_tree *tree; ++ struct bl_dm_tree *bl_tree; ++ ++ bl_tree = find_bl_dm_tree(dev); ++ if (bl_tree) ++ return; /* XXX: error? */ ++ ++ tree = dm_tree_create(); ++ if (!tree) ++ return; ++ ++ if (!dm_tree_add_dev(tree, MAJOR(dev), MINOR(dev))) { ++ dm_tree_free(tree); ++ return; ++ } ++ ++ bl_tree = malloc(sizeof(struct bl_dm_tree)); ++ if (!bl_tree) { ++ dm_tree_free(tree); ++ return; ++ } ++ ++ bl_tree->dev = dev; ++ bl_tree->tree = tree; ++ bl_tree->next = NULL; ++ add_to_bl_dm_tree(bl_tree); ++ ++ return; ++} ++ ++uint64_t dm_device_nametodev(char *dev_name) ++{ ++ struct dm_task *dmt; ++ int ret = 0; ++ struct dm_info dminfo; ++ ++ dmt = dm_task_create(DM_DEVICE_INFO); ++ if (!dmt) ++ return -ENODEV; ++ ++ ret = dm_task_set_name(dmt, dev_name) && ++ dm_task_run(dmt) && dm_task_get_info(dmt, &dminfo); ++ ++ if (dmt) ++ dm_task_destroy(dmt); ++ ++ if (!ret) ++ return 0; ++ ++ return MKDEV(dminfo.major, dminfo.minor); ++} ++ ++int dm_device_remove_all(uint64_t *dev) ++{ ++ struct bl_dm_tree *p; ++ struct dm_tree_node *node; ++ const char *uuid; ++ int ret = 0; ++ uint32_t major, minor; ++ uint64_t bl_dev; ++ ++ memcpy(&major, dev, sizeof(uint32_t)); ++ memcpy(&minor, (void *)dev + sizeof(uint32_t), sizeof(uint32_t)); ++ bl_dev = MKDEV(major, minor); ++ p = find_bl_dm_tree(bl_dev); ++ if (!p) ++ return ret; ++ ++ node = dm_tree_find_node(p->tree, MAJOR(bl_dev), MINOR(bl_dev)); ++ if (!node) ++ return ret; ++ ++ uuid = dm_tree_node_get_uuid(node); ++ if (!uuid) ++ return ret; ++ ++ dm_device_remove(bl_dev); ++ ret = dm_tree_deactivate_children(node, uuid, strlen(uuid)); ++ dm_task_update_nodes(); ++ bl_dm_remove_tree(bl_dev); ++ return ret; ++} ++ ++/* TODO: check the value for DM_DEV_NAME_LEN, DM_TYPE_LEN, DM_PARAMS_LEN */ ++uint64_t dm_device_create(struct bl_volume *vols, int num_vols) ++{ ++ uint64_t size, dev = 0; ++ unsigned long count = dev_count; ++ int number = 0, i, pos; ++ struct bl_volume *node; ++ char *tmp; ++ struct bl_dm_table *table = NULL; ++ struct bl_dm_table *bl_table_head = NULL; ++ unsigned int len; ++ char *dev_name = NULL; ++ ++ /* Create pseudo device here */ ++ while (number < num_vols) { ++ node = &vols[number]; ++ switch (node->bv_type) { ++ case BLOCK_VOLUME_SIMPLE: ++ /* Do not need to create device here */ ++ dev = node->param.bv_dev; ++ goto continued; ++ case BLOCK_VOLUME_SLICE: ++ table = bl_dm_table_alloc(); ++ if (!table) ++ goto out; ++ table->offset = 0; ++ table->size = node->bv_size; ++ strcpy(table->target_type, "linear"); ++ if (!TYPE_HAS_DEV(node->bv_vols[0]->bv_type)) { ++ free(table); ++ goto out; ++ } ++ dev = node->bv_vols[0]->param.bv_dev; ++ tmp = table->params; ++ if (!dm_format_dev(tmp, DM_PARAMS_LEN, ++ MAJOR(dev), MINOR(dev))) { ++ free(table); ++ goto out; ++ } ++ tmp += strlen(tmp); ++ sprintf(tmp, " %lu", node->param.bv_offset); ++ add_to_bl_dm_table(&bl_table_head, table); ++ break; ++ case BLOCK_VOLUME_STRIPE: ++ table = bl_dm_table_alloc(); ++ if (!table) ++ goto out; ++ table->offset = 0; ++ table->size = node->bv_size; ++ strcpy(table->target_type, "striped"); ++ sprintf(table->params, "%d %lu %n", node->bv_vol_n, ++ node->param.bv_stripe_unit, &pos); ++ /* Repeatedly copy subdev to params */ ++ tmp = table->params + pos; ++ len = DM_PARAMS_LEN - pos; ++ for (i = 0; i < node->bv_vol_n; i++) { ++ if (!TYPE_HAS_DEV(node->bv_vols[i]->bv_type)) { ++ free(table); ++ goto out; ++ } ++ dev = node->bv_vols[i]->param.bv_dev; ++ if (!dm_format_dev(tmp, len, MAJOR(dev), ++ MINOR(dev))) { ++ free(table); ++ goto out; ++ } ++ pos = strlen(tmp); ++ tmp += pos; ++ len -= pos; ++ sprintf(tmp, " %d ", 0); ++ tmp += 3; ++ len -= 3; ++ } ++ add_to_bl_dm_table(&bl_table_head, table); ++ break; ++ case BLOCK_VOLUME_CONCAT: ++ size = 0; ++ for (i = 0; i < node->bv_vol_n; i++) { ++ table = bl_dm_table_alloc(); ++ if (!table) ++ goto out; ++ table->offset = size; ++ table->size = node->bv_vols[i]->bv_size; ++ if (!TYPE_HAS_DEV(node->bv_vols[i]->bv_type)) { ++ free(table); ++ goto out; ++ } ++ strcpy(table->target_type, "linear"); ++ tmp = table->params; ++ dev = node->bv_vols[i]->param.bv_dev; ++ if (!dm_format_dev(tmp, DM_PARAMS_LEN, ++ MAJOR(dev), MINOR(dev))) { ++ free(table); ++ goto out; ++ } ++ tmp += strlen(tmp); ++ sprintf(tmp, " %d", 0); ++ size += table->size; ++ add_to_bl_dm_table(&bl_table_head, table); ++ } ++ break; ++ default: ++ /* Delete previous temporary devices */ ++ dm_devicelist_remove(count, dev_count); ++ goto out; ++ } /* end of swtich */ ++ /* Create dev_name here. Name of device is pnfs_vol_XXX */ ++ if (dev_name) ++ free(dev_name); ++ dev_name = (char *)calloc(DM_DEV_NAME_LEN, sizeof(char)); ++ if (!dev_name) { ++ BL_LOG_ERR("%s: Out of memory\n", __func__); ++ goto out; ++ } ++ sprintf(dev_name, "pnfs_vol_%lu", dev_count++); ++ ++ dev = dm_single_device_create(dev_name, bl_table_head); ++ if (!dev) { ++ /* Delete previous temporary devices */ ++ dm_devicelist_remove(count, dev_count); ++ goto out; ++ } ++ node->param.bv_dev = dev; ++ /* TODO: extend use with PSEUDO later */ ++ node->bv_type = BLOCK_VOLUME_PSEUDO; ++ continued: ++ number++; ++ if (bl_table_head) ++ bl_dm_table_free(bl_table_head); ++ bl_table_head = NULL; ++ } ++ out: ++ if (bl_table_head) ++ bl_dm_table_free(bl_table_head); ++ bl_table_head = NULL; ++ if (dev) ++ bl_dm_create_tree(dev); ++ if (dev_name) ++ free(dev_name); ++ return dev; ++} +diff -up nfs-utils-1.2.3/utils/blkmapd/etc/blkmapd.conf.orig nfs-utils-1.2.3/utils/blkmapd/etc/blkmapd.conf +--- nfs-utils-1.2.3/utils/blkmapd/etc/blkmapd.conf.orig 2010-11-09 11:45:37.289112000 -0500 ++++ nfs-utils-1.2.3/utils/blkmapd/etc/blkmapd.conf 2010-11-09 11:45:37.291107000 -0500 +@@ -0,0 +1,10 @@ ++# This is an example config file ++ ++# Look at all /dev/sd* devices ++# /dev/sd or /dev/sd* ++/dev/sd* ++ ++# Look at all /dev/mapper/* devices ++# /dev/mapper/* or ++# /dev/mapper/ ++/dev/mapper/* +diff -up nfs-utils-1.2.3/utils/blkmapd/etc/initd/initd.redhat.orig nfs-utils-1.2.3/utils/blkmapd/etc/initd/initd.redhat +--- nfs-utils-1.2.3/utils/blkmapd/etc/initd/initd.redhat.orig 2010-11-09 11:45:37.295103000 -0500 ++++ nfs-utils-1.2.3/utils/blkmapd/etc/initd/initd.redhat 2010-11-09 11:45:37.296112000 -0500 +@@ -0,0 +1,76 @@ ++#!/bin/sh ++# ++# description: Starts and stops the iSCSI initiator ++# ++# processname: blkmapd ++# pidfile: /var/run/blkmapd.pid ++# config: /etc/blkmapd.conf ++ ++# Source function library. ++if [ -f /etc/init.d/functions ] ; then ++ . /etc/init.d/functions ++elif [ -f /etc/rc.d/init.d/functions ] ; then ++ . /etc/rc.d/init.d/functions ++else ++ exit 0 ++fi ++ ++PATH=/sbin:/bin:/usr/sbin:/usr/bin ++ ++RETVAL=0 ++ ++start() ++{ ++ echo -n $"Starting pNFS block-layout device discovery service: " ++ modprobe -q blocklayoutdriver ++ daemon /usr/sbin/blkmapd ++ RETVAL=$? ++ if [ $RETVAL -eq 0 ]; then ++ touch /var/lock/subsys/blkmapd ++ fi ++ echo ++ return $RETVAL ++} ++ ++stop() ++{ ++ echo -n $"Stopping pNFS block-layout device discovery service: " ++ killproc blkmapd 2> /dev/null ++ rm -f /var/run/blkmapd.pid ++ RETVAL=$? ++ [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/blkmapd ++ if [ $RETVAL -eq 0 ]; then ++ echo_success ++ else ++ echo_failure ++ fi ++ echo ++ return $RETVAL ++} ++ ++restart() ++{ ++ stop ++ start ++} ++ ++case "$1" in ++ start) ++ start ++ ;; ++ stop) ++ stop ++ ;; ++ restart) ++ stop ++ start ++ ;; ++ status) ++ status blkmapd ++ ;; ++ *) ++ echo $"Usage: $0 {start|stop|restart|status}" ++ exit 1 ++esac ++ ++exit $RETVAL +diff -up nfs-utils-1.2.3/utils/blkmapd/Makefile.am.orig nfs-utils-1.2.3/utils/blkmapd/Makefile.am +--- nfs-utils-1.2.3/utils/blkmapd/Makefile.am.orig 2010-11-09 11:45:37.262108000 -0500 ++++ nfs-utils-1.2.3/utils/blkmapd/Makefile.am 2010-11-09 11:45:37.264103000 -0500 +@@ -0,0 +1,19 @@ ++## Process this file with automake to produce Makefile.in ++ ++#man8_MANS = blkmapd.man ++ ++AM_CFLAGS += -D_LARGEFILE64_SOURCE ++sbin_PROGRAMS = blkmapd ++ ++blkmapd_SOURCES = \ ++ device-discovery.c \ ++ device-inq.c \ ++ device-process.c \ ++ dm-device.c \ ++ \ ++ device-discovery.h ++ ++blkmapd_LDADD = -ldevmapper ../../support/nfs/libnfs.a ++ ++MAINTAINERCLEANFILES = Makefile.in ++ +diff -up nfs-utils-1.2.3/utils/exportfs/exportfs.c.orig nfs-utils-1.2.3/utils/exportfs/exportfs.c +--- nfs-utils-1.2.3/utils/exportfs/exportfs.c.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/utils/exportfs/exportfs.c 2010-11-09 11:45:37.301107000 -0500 +@@ -577,6 +577,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.3/utils/Makefile.am.orig nfs-utils-1.2.3/utils/Makefile.am +--- nfs-utils-1.2.3/utils/Makefile.am.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/utils/Makefile.am 2010-11-09 11:45:37.258105000 -0500 +@@ -4,6 +4,8 @@ OPTDIRS = + + if CONFIG_NFSV4 + OPTDIRS += idmapd ++OPTDIRS += spnfsd ++OPTDIRS += blkmapd + endif + + if CONFIG_GSS +diff -up nfs-utils-1.2.3/utils/mountd/cache.c.orig nfs-utils-1.2.3/utils/mountd/cache.c +--- nfs-utils-1.2.3/utils/mountd/cache.c.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/utils/mountd/cache.c 2010-11-09 11:45:37.307104000 -0500 +@@ -653,6 +653,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); + write_secinfo(f, exp, flag_mask); + if (exp->e_uuid == NULL || different_fs) { +diff -up nfs-utils-1.2.3/utils/spnfsd/atomicio.c.orig nfs-utils-1.2.3/utils/spnfsd/atomicio.c +--- nfs-utils-1.2.3/utils/spnfsd/atomicio.c.orig 2010-11-09 11:45:37.316104000 -0500 ++++ nfs-utils-1.2.3/utils/spnfsd/atomicio.c 2010-11-09 11:45:37.317110000 -0500 +@@ -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 nfs-utils-1.2.3/utils/spnfsd/cfg.c.orig nfs-utils-1.2.3/utils/spnfsd/cfg.c +--- nfs-utils-1.2.3/utils/spnfsd/cfg.c.orig 2010-11-09 11:45:37.320106000 -0500 ++++ nfs-utils-1.2.3/utils/spnfsd/cfg.c 2010-11-09 11:45:37.322106000 -0500 +@@ -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 nfs-utils-1.2.3/utils/spnfsd/cfg.h.orig nfs-utils-1.2.3/utils/spnfsd/cfg.h +--- nfs-utils-1.2.3/utils/spnfsd/cfg.h.orig 2010-11-09 11:45:37.324108000 -0500 ++++ nfs-utils-1.2.3/utils/spnfsd/cfg.h 2010-11-09 11:45:37.326105000 -0500 +@@ -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 nfs-utils-1.2.3/utils/spnfsd/Makefile.am.orig nfs-utils-1.2.3/utils/spnfsd/Makefile.am +--- nfs-utils-1.2.3/utils/spnfsd/Makefile.am.orig 2010-11-09 11:45:37.311109000 -0500 ++++ nfs-utils-1.2.3/utils/spnfsd/Makefile.am 2010-11-09 11:45:37.313108000 -0500 +@@ -0,0 +1,30 @@ ++## Process this file with automake to produce Makefile.in ++ ++man5_MANS = ++man8_MANS = ++ ++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 +diff -up nfs-utils-1.2.3/utils/spnfsd/makestatic.orig nfs-utils-1.2.3/utils/spnfsd/makestatic +--- nfs-utils-1.2.3/utils/spnfsd/makestatic.orig 2010-11-09 11:45:37.328108000 -0500 ++++ nfs-utils-1.2.3/utils/spnfsd/makestatic 2010-11-09 11:45:37.330105000 -0500 +@@ -0,0 +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 -up nfs-utils-1.2.3/utils/spnfsd/nfsd4_spnfs.h.orig nfs-utils-1.2.3/utils/spnfsd/nfsd4_spnfs.h +--- nfs-utils-1.2.3/utils/spnfsd/nfsd4_spnfs.h.orig 2010-11-09 11:45:37.332108000 -0500 ++++ nfs-utils-1.2.3/utils/spnfsd/nfsd4_spnfs.h 2010-11-09 11:45:37.334106000 -0500 +@@ -0,0 +1,334 @@ ++/* ++ * include/linux/nfsd4_spnfs.h ++ * ++ * 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 ++ ++ ++#ifdef __KERNEL__ ++#include "exportfs.h" ++#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_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_READ 0x0c ++#define SPNFS_TYPE_WRITE 0x0d ++ ++#define SPNFS_MAX_DEVICES 1 ++#define SPNFS_MAX_DATA_SERVERS 16 ++#define SPNFS_MAX_IO 512 ++ ++/* layout */ ++struct spnfs_msg_layoutget_args { ++ unsigned long inode; ++ unsigned long generation; ++}; ++ ++struct spnfs_filelayout_list { ++ u_int32_t fh_len; ++ unsigned char fh_val[128]; /* DMXXX fix this const */ ++}; ++ ++struct spnfs_msg_layoutget_res { ++ int status; ++ u_int64_t devid; ++ u_int64_t stripe_size; ++ u_int32_t stripe_type; ++ u_int32_t stripe_count; ++ struct spnfs_filelayout_list flist[SPNFS_MAX_DATA_SERVERS]; ++}; ++ ++/* layoutcommit */ ++struct spnfs_msg_layoutcommit_args { ++ unsigned long inode; ++ unsigned long generation; ++ 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 { ++}; ++*/ ++ ++/* getdeviceiter */ ++struct spnfs_msg_getdeviceiter_args { ++ unsigned long inode; ++ u_int64_t cookie; ++ u_int64_t verf; ++}; ++ ++struct spnfs_msg_getdeviceiter_res { ++ int status; ++ u_int64_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_device { ++ u_int64_t devid; ++ int dscount; ++ struct spnfs_data_server dslist[SPNFS_MAX_DATA_SERVERS]; ++}; ++ ++struct spnfs_msg_getdeviceinfo_args { ++ u_int64_t devid; ++}; ++ ++struct spnfs_msg_getdeviceinfo_res { ++ int status; ++ struct spnfs_device devinfo; ++}; ++ ++/* setattr */ ++struct spnfs_msg_setattr_args { ++ unsigned long inode; ++ unsigned long generation; ++ int file_size; ++}; ++ ++struct spnfs_msg_setattr_res { ++ int status; ++}; ++ ++/* open */ ++struct spnfs_msg_open_args { ++ unsigned long inode; ++ unsigned long generation; ++ 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; ++ unsigned long generation; ++}; ++ ++struct spnfs_msg_remove_res { ++ int status; ++}; ++ ++/* commit */ ++/* ++struct spnfs_msg_commit_args { ++ int x; ++}; ++ ++struct spnfs_msg_commit_res { ++ int y; ++}; ++*/ ++ ++/* read */ ++struct spnfs_msg_read_args { ++ unsigned long inode; ++ unsigned long generation; ++ 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; ++ unsigned long generation; ++ 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; ++ struct spnfs_msg_layoutcommit_args layoutcommit_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_remove_args remove_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 { ++ struct spnfs_msg_layoutget_res layoutget_res; ++ struct spnfs_msg_layoutcommit_res layoutcommit_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_remove_res remove_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 */ ++struct spnfs_msg { ++ unsigned char im_type; ++ unsigned char im_status; ++ union spnfs_msg_args im_args; ++ union spnfs_msg_res im_res; ++}; ++ ++/* spnfs configuration info */ ++struct spnfs_config { ++ unsigned char dense_striping; ++ int stripe_size; ++ int num_ds; ++ char ds_dir[SPNFS_MAX_DATA_SERVERS][80]; /* XXX */ ++}; ++ ++#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 *, struct pnfs_layoutget_arg *); ++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_close(struct inode *); ++int spnfs_get_state(struct inode *, void *, void *); ++int spnfs_remove(unsigned long, unsigned long); ++int spnfs_read(struct inode *, loff_t, unsigned long *, int, struct svc_rqst *); ++int spnfs_write(struct inode *, loff_t, size_t, int, struct svc_rqst *); ++int spnfs_getfh(int, struct nfs_fh *); ++int spnfs_test_layoutrecall(char *); ++int spnfs_layoutrecall(struct inode *, int); ++ ++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 *); ++int spnfs_init_proc(void); ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* NFS_SPNFS_H */ +diff -up nfs-utils-1.2.3/utils/spnfsd/queue.h.orig nfs-utils-1.2.3/utils/spnfsd/queue.h +--- nfs-utils-1.2.3/utils/spnfsd/queue.h.orig 2010-11-09 11:45:37.338104000 -0500 ++++ nfs-utils-1.2.3/utils/spnfsd/queue.h 2010-11-09 11:45:37.340106000 -0500 +@@ -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 nfs-utils-1.2.3/utils/spnfsd/spnfsd.conf.orig nfs-utils-1.2.3/utils/spnfsd/spnfsd.conf +--- nfs-utils-1.2.3/utils/spnfsd/spnfsd.conf.orig 2010-11-09 11:45:37.347108000 -0500 ++++ nfs-utils-1.2.3/utils/spnfsd/spnfsd.conf 2010-11-09 11:45:37.349108000 -0500 +@@ -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_ID = 1 ++ ++DS2_IP = 172.16.28.141 ++DS2_PORT = 2049 ++DS2_ROOT = /pnfs ++DS2_ID = 2 +diff -up nfs-utils-1.2.3/utils/spnfsd/spnfsd.c.orig nfs-utils-1.2.3/utils/spnfsd/spnfsd.c +--- nfs-utils-1.2.3/utils/spnfsd/spnfsd.c.orig 2010-11-09 11:45:37.343104000 -0500 ++++ nfs-utils-1.2.3/utils/spnfsd/spnfsd.c 2010-11-09 11:45:37.344111000 -0500 +@@ -0,0 +1,578 @@ ++/* ++ * 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. ++ * ++ * 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. ++ */ ++ ++#define _LARGEFILE64_SOURCE ++#define _FILE_OFFSET_BITS 64 ++#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_dev = 1; /* XXX no multiple device support yet */ ++int num_ds; ++struct dserver dataservers[SPNFS_MAX_DATA_SERVERS]; ++char dsmountdir[PATH_MAX]; ++struct spnfs_config spnfs_config; ++ ++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 rc, fd, cmd = 1; ++ int i; ++ ++ fd = open("/proc/fs/spnfs/ctl", O_WRONLY); ++ if (fd < 0) ++ spnfsd_errx(1, "kernel init failed (%s)", strerror(errno)); ++ rc = write(fd, &cmd, sizeof(int)); ++ if (rc < 0 && errno != EEXIST) ++ spnfsd_errx(1, "kernel init failed (%s)", strerror(errno)); ++ close(fd); ++ ++ 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)); ++ ++ spnfs_config.stripe_size = stripesize; ++ spnfs_config.dense_striping = densestriping; ++ spnfs_config.num_ds = num_ds; ++ ++ for (i = 0; i < num_ds; i++) ++ sprintf(spnfs_config.ds_dir[i], "%s/%s", ++ dsmountdir, dataservers[i].ds_ip); ++ ++ fd = open("/proc/fs/spnfs/config", O_WRONLY); ++ if (fd < 0) ++ spnfsd_errx(1, "error creating config (%s)", strerror(errno)); ++ rc = write(fd, &spnfs_config, sizeof(struct spnfs_config)); ++ if (rc < 0 && errno != EEXIST) ++ spnfsd_errx(1, "error writing config (%s)", strerror(errno)); ++ close(fd); ++ ++ 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_GETDEVICEITER: ++ err = spnfsd_getdeviceiter(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; ++ 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); ++ 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; ++ ++ if ((rval=atomicio(write, scp->sc_fd, &im, sizeof(im))) != sizeof(im)) { ++ spnfsd_warn("spnfscb: write(%s)", scp->sc_path); ++ } ++ ++out: ++ 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], dsidstr[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(dsidstr, "DS%d_ID", 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_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; ++} ++ ++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 DSID: %d\n", ds+1, dataservers[ds].ds_id); ++ } ++} ++ ++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 nfs-utils-1.2.3/utils/spnfsd/spnfsd.h.orig nfs-utils-1.2.3/utils/spnfsd/spnfsd.h +--- nfs-utils-1.2.3/utils/spnfsd/spnfsd.h.orig 2010-11-09 11:45:37.351109000 -0500 ++++ nfs-utils-1.2.3/utils/spnfsd/spnfsd.h 2010-11-09 11:45:37.353106000 -0500 +@@ -0,0 +1,70 @@ ++/* ++ * spnfsd.h ++ * ++ * 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" ++#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_id; ++}; ++ ++/* 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_getdeviceiter(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_read(struct spnfs_msg *); ++int spnfsd_write(struct spnfs_msg *); ++int spnfsd_getfh(char *, unsigned char *, unsigned int *); +diff -up nfs-utils-1.2.3/utils/spnfsd/spnfsd_ops.c.orig nfs-utils-1.2.3/utils/spnfsd/spnfsd_ops.c +--- nfs-utils-1.2.3/utils/spnfsd/spnfsd_ops.c.orig 2010-11-09 11:45:37.368106000 -0500 ++++ nfs-utils-1.2.3/utils/spnfsd/spnfsd_ops.c 2010-11-09 11:45:37.370107000 -0500 +@@ -0,0 +1,439 @@ ++/****************************************************************************** ++ ++(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. ++ ++******************************************************************************/ ++ ++#define _LARGEFILE64_SOURCE ++#define _FILE_OFFSET_BITS 64 ++#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 int num_dev; ++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.devid = 1; /* XXX */ ++ im->im_res.layoutget_res.stripe_size = stripesize; ++ if (densestriping) ++ im->im_res.layoutget_res.stripe_type = 1; /* DMXXX enum */ ++ else ++ 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++) { ++ memset(im->im_res.layoutget_res.flist[ds].fh_val, 0, 128); /*DMXXX*/ ++ sprintf(fullpath, "%s/%s/%lu.%lu", ++ dsmountdir, dataservers[ds].ds_ip, ++ im->im_args.layoutget_args.inode, ++ im->im_args.layoutget_args.generation); ++ 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 8 to get ++ * around stateid checking. ++ */ ++ im->im_res.layoutget_res.flist[ds].fh_val[2] += 8; ++ } ++ ++ 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, "%lu.%lu", im->im_args.layoutcommit_args.inode, ++ im->im_args.layoutcommit_args.generation); ++ ++ 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_getdeviceiter(struct spnfs_msg *im) ++{ ++ im->im_status = SPNFS_STATUS_SUCCESS; ++ 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; ++} ++ ++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 = 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 = -ENOENT; ++ return -1; ++ } ++ ++ devp = &im->im_res.getdeviceinfo_res.devinfo; ++ devp->dscount = num_ds; ++ ++ for (ds = 0 ; ds < num_ds ; ds++) { ++ 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; ++} ++ ++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, "%lu.%lu", im->im_args.setattr_args.inode, ++ im->im_args.setattr_args.generation); ++ ++ 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, "%lu.%lu", im->im_args.open_args.inode, ++ im->im_args.open_args.generation); ++ ++ 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 { ++ 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); ++ } ++ } ++ ++ 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, "%lu.%lu", im->im_args.remove_args.inode, ++ im->im_args.remove_args.generation); ++ ++ 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) ++{ ++ im->im_status = SPNFS_STATUS_SUCCESS; ++ return 0; ++} ++ ++int ++min (unsigned int x, unsigned int y) ++{ ++ if (xim_args.read_args.inode; ++ unsigned long generation = im->im_args.read_args.generation; ++ 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/%lu.%lu", dsmountdir, ++ dataservers[ds].ds_ip, inode, generation); ++ 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; ++ unsigned long generation = im->im_args.write_args.generation; ++ 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/%lu.%lu", dsmountdir, ++ dataservers[ds].ds_ip, inode, generation); ++ 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; ++} ++ ++int ++spnfsd_getfh(char *path, unsigned char *fh_val, unsigned int *fh_len) ++{ ++ int fd, proc_fd; ++ unsigned char res[130]; /* XXX align this to proper structure */ ++ extern void spnfsd_errx(int, const char *, ...); ++ ++ /* ++ * hack to make sure there's an active data structure for this ++ * inode in the nfs client kernel space ++ */ ++ if ((fd = open(path, O_RDONLY)) < 0) { ++ perror(path); ++ return -1; ++ } ++ ++ /* fd to fh conversion */ ++ proc_fd = open("/proc/fs/spnfs/getfh", O_RDWR); ++ if (proc_fd < 0) { ++ spnfsd_errx(1, "open getfh failed (%s)", strerror(errno)); ++ } ++ if (write(proc_fd, &fd, sizeof(int)) < 0) { ++ spnfsd_errx(1, "write getfh failed (%s)", strerror(errno)); ++ } ++ if (read(proc_fd, res, 130) <= 0) { ++ spnfsd_errx(1, "read getfh failed (%s)", strerror(errno)); ++ } ++ close(proc_fd); ++ ++ /* XXX use proper structure */ ++ *fh_len = (short)res[0]; ++ memcpy(fh_val, &res[2], *fh_len); ++ ++ close(fd); ++ return 0; ++} +diff -up nfs-utils-1.2.3/utils/spnfsd/strlcat.c.orig nfs-utils-1.2.3/utils/spnfsd/strlcat.c +--- nfs-utils-1.2.3/utils/spnfsd/strlcat.c.orig 2010-11-09 11:45:37.373105000 -0500 ++++ nfs-utils-1.2.3/utils/spnfsd/strlcat.c 2010-11-09 11:45:37.374112000 -0500 +@@ -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 nfs-utils-1.2.3/utils/spnfsd/strlcpy.c.orig nfs-utils-1.2.3/utils/spnfsd/strlcpy.c +--- nfs-utils-1.2.3/utils/spnfsd/strlcpy.c.orig 2010-11-09 11:45:37.377105000 -0500 ++++ nfs-utils-1.2.3/utils/spnfsd/strlcpy.c 2010-11-09 11:45:37.378112000 -0500 +@@ -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 */ ++}