Index: projects/pnfs-planb-server/usr.bin/pnfsdscopymr/pnfsdscopymr.c =================================================================== --- projects/pnfs-planb-server/usr.bin/pnfsdscopymr/pnfsdscopymr.c (revision 334645) +++ projects/pnfs-planb-server/usr.bin/pnfsdscopymr/pnfsdscopymr.c (revision 334646) @@ -1,305 +1,304 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2017 Rick Macklem - * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void usage(void); static struct option longopts[] = { { "migrate", required_argument, NULL, 'm' }, { "mirror", required_argument, NULL, 'r' }, { NULL, 0, NULL, 0 } }; /* * This program creates a copy of the file's (first argument) data on the * new/recovering DS mirror. If the file is already on the new/recovering * DS, it will simply exit(0). */ int main(int argc, char *argv[]) { struct nfsd_pnfsd_args pnfsdarg; struct pnfsdsfile dsfile[NFSDEV_MAXMIRRORS]; struct stat sb; struct statfs sf; struct addrinfo hints, *res, *nres; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; ssize_t xattrsize; size_t mirlen; int ch, fnd, fndzero, i, migrateit, mirrorcnt, mirrorit, ret; int mirrorlevel; char host[MNAMELEN + NI_MAXHOST + 2], *cp; if (geteuid() != 0) errx(1, "Must be run as root/su"); mirrorit = migrateit = 0; pnfsdarg.dspath = pnfsdarg.curdspath = NULL; while ((ch = getopt_long(argc, argv, "m:r:", longopts, NULL)) != -1) { switch (ch) { case 'm': /* Migrate the file from the second DS to the first. */ if (mirrorit != 0) errx(1, "-r and -m are mutually exclusive"); migrateit = 1; pnfsdarg.curdspath = optarg; break; case 'r': /* Mirror the file on the specified DS. */ if (migrateit != 0) errx(1, "-r and -m are mutually exclusive"); mirrorit = 1; pnfsdarg.dspath = optarg; break; default: usage(); } } argc -= optind; argv += optind; if (migrateit != 0) { if (argc != 2) usage(); pnfsdarg.dspath = *argv++; } else if (argc != 1) usage(); /* Get the pNFS service's mirror level. */ mirlen = sizeof(mirrorlevel); ret = sysctlbyname("vfs.nfs.pnfsmirror", &mirrorlevel, &mirlen, NULL, 0); if (ret < 0) errx(1, "Can't get vfs.nfs.pnfsmirror"); if (pnfsdarg.dspath != NULL && pnfsdarg.curdspath != NULL && strcmp(pnfsdarg.dspath, pnfsdarg.curdspath) == 0) errx(1, "Can't migrate to same server"); /* * The host address and directory where the data storage file is * located is in the extended attribute "pnfsd.dsfile". */ xattrsize = extattr_get_file(*argv, EXTATTR_NAMESPACE_SYSTEM, "pnfsd.dsfile", dsfile, sizeof(dsfile)); mirrorcnt = xattrsize / sizeof(struct pnfsdsfile); if (mirrorcnt < 1 || xattrsize != mirrorcnt * sizeof(struct pnfsdsfile)) errx(1, "Can't get extattr pnfsd.dsfile for %s", *argv); /* See if there is a 0.0.0.0 entry. */ fndzero = 0; for (i = 0; i < mirrorcnt; i++) { if (dsfile[i].dsf_sin.sin_family == AF_INET && dsfile[i].dsf_sin.sin_addr.s_addr == 0) fndzero = 1; } /* If already mirrored for default case, just exit(0); */ if (mirrorit == 0 && migrateit == 0 && (mirrorlevel < 2 || (fndzero == 0 && mirrorcnt >= mirrorlevel) || (fndzero != 0 && mirrorcnt > mirrorlevel))) exit(0); /* For the "-r" case, there must be a 0.0.0.0 entry. */ if (mirrorit != 0 && (fndzero == 0 || mirrorlevel < 2 || mirrorcnt < 2 || mirrorcnt > mirrorlevel)) exit(0); /* For pnfsdarg.dspath set, if it is already in list, just exit(0); */ if (pnfsdarg.dspath != NULL) { /* Check the dspath to see that it's an NFS mount. */ if (stat(pnfsdarg.dspath, &sb) < 0) errx(1, "Can't stat %s", pnfsdarg.dspath); if (!S_ISDIR(sb.st_mode)) errx(1, "%s is not a directory", pnfsdarg.dspath); if (statfs(pnfsdarg.dspath, &sf) < 0) errx(1, "Can't fsstat %s", pnfsdarg.dspath); if (strcmp(sf.f_fstypename, "nfs") != 0) errx(1, "%s is not an NFS mount", pnfsdarg.dspath); if (strcmp(sf.f_mntonname, pnfsdarg.dspath) != 0) errx(1, "%s is not the mounted-on dir for the new DS", pnfsdarg.dspath); /* * Check the IP address of the NFS server against the entrie(s) * in the extended attribute. */ strlcpy(host, sf.f_mntfromname, sizeof(host)); cp = strchr(host, ':'); if (cp == NULL) errx(1, "No : in mount %s", host); *cp = '\0'; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if (getaddrinfo(host, NULL, &hints, &res) != 0) errx(1, "Can't get address for %s", host); for (i = 0; i < mirrorcnt; i++) { nres = res; while (nres != NULL) { if (dsfile[i].dsf_sin.sin_family == nres->ai_family) { /* * If there is already an entry for this * DS, just exit(0), since copying isn't * required. */ if (nres->ai_family == AF_INET) { sin = (struct sockaddr_in *) nres->ai_addr; if (sin->sin_addr.s_addr == dsfile[i].dsf_sin.sin_addr.s_addr) exit(0); } else if (nres->ai_family == AF_INET6) { sin6 = (struct sockaddr_in6 *) nres->ai_addr; if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &dsfile[i].dsf_sin6.sin6_addr)) exit(0); } } nres = nres->ai_next; } } freeaddrinfo(res); } /* For "-m", the pnfsdarg.curdspath must be in the list. */ if (pnfsdarg.curdspath != NULL) { /* Check pnfsdarg.curdspath to see that it's an NFS mount. */ if (stat(pnfsdarg.curdspath, &sb) < 0) errx(1, "Can't stat %s", pnfsdarg.curdspath); if (!S_ISDIR(sb.st_mode)) errx(1, "%s is not a directory", pnfsdarg.curdspath); if (statfs(pnfsdarg.curdspath, &sf) < 0) errx(1, "Can't fsstat %s", pnfsdarg.curdspath); if (strcmp(sf.f_fstypename, "nfs") != 0) errx(1, "%s is not an NFS mount", pnfsdarg.curdspath); if (strcmp(sf.f_mntonname, pnfsdarg.curdspath) != 0) errx(1, "%s is not the mounted-on dir of the cur DS", pnfsdarg.curdspath); /* * Check the IP address of the NFS server against the entrie(s) * in the extended attribute. */ strlcpy(host, sf.f_mntfromname, sizeof(host)); cp = strchr(host, ':'); if (cp == NULL) errx(1, "No : in mount %s", host); *cp = '\0'; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if (getaddrinfo(host, NULL, &hints, &res) != 0) errx(1, "Can't get address for %s", host); fnd = 0; for (i = 0; i < mirrorcnt && fnd == 0; i++) { nres = res; while (nres != NULL) { if (dsfile[i].dsf_sin.sin_family == nres->ai_family) { /* * Note if the entry is found. */ if (nres->ai_family == AF_INET) { sin = (struct sockaddr_in *) nres->ai_addr; if (sin->sin_addr.s_addr == dsfile[i].dsf_sin.sin_addr.s_addr) { fnd = 1; break; } } else if (nres->ai_family == AF_INET6) { sin6 = (struct sockaddr_in6 *) nres->ai_addr; if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &dsfile[i].dsf_sin6.sin6_addr)) { fnd = 1; break; } } } nres = nres->ai_next; } } freeaddrinfo(res); /* * If not found just exit(0), since it is not on the * source DS. */ if (fnd == 0) exit(0); } /* Do the copy via the nfssvc() syscall. */ pnfsdarg.op = PNFSDOP_COPYMR; pnfsdarg.mdspath = *argv; ret = nfssvc(NFSSVC_PNFSDS, &pnfsdarg); if (ret < 0 && errno != EEXIST) err(1, "Copymr failed args %s, %s", argv[1], argv[2]); exit(0); } static void usage(void) { fprintf(stderr, "pnfsdscopymr [-r recovered-DS-mounted-on-path] " "[-m soure-DS-mounted-on-path destination-DS-mounted-on-path] " "mds-filename"); exit(1); } Index: projects/pnfs-planb-server/usr.bin/pnfsdsfile/pnfsdsfile.c =================================================================== --- projects/pnfs-planb-server/usr.bin/pnfsdsfile/pnfsdsfile.c (revision 334645) +++ projects/pnfs-planb-server/usr.bin/pnfsdsfile/pnfsdsfile.c (revision 334646) @@ -1,311 +1,310 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2017 Rick Macklem - * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void usage(void); static struct option longopts[] = { { "changeds", required_argument, NULL, 'c' }, { "quiet", no_argument, NULL, 'q' }, { "zerods", required_argument, NULL, 'r' }, { "ds", required_argument, NULL, 's' }, { "zerofh", no_argument, NULL, 'z' }, { NULL, 0, NULL, 0 } }; /* * This program displays the location information of a data storage file * for a given file on a MetaData Server (MDS) in a pNFS service. This program * must be run on the MDS and the file argument must be a file in a local * file system that has been exported for the pNFS service. */ int main(int argc, char *argv[]) { struct addrinfo *res, *ad, *newres; struct sockaddr_in *sin, *adsin; struct sockaddr_in6 *sin6, *adsin6; char hostn[2 * NI_MAXHOST + 2], *cp; struct pnfsdsfile dsfile[NFSDEV_MAXMIRRORS]; int ch, dosetxattr, i, mirrorcnt, quiet, zerods, zerofh; in_port_t tport; ssize_t xattrsize; zerods = 0; zerofh = 0; quiet = 0; dosetxattr = 0; res = NULL; newres = NULL; while ((ch = getopt_long(argc, argv, "c:qr:s:z", longopts, NULL)) != -1) { switch (ch) { case 'c': /* Replace the first DS server with the second one. */ if (zerofh != 0 || zerods != 0) errx(1, "-c, -r and -z are mutually " "exclusive"); if (res != NULL) errx(1, "-c and -s are mutually exclusive"); strlcpy(hostn, optarg, 2 * NI_MAXHOST + 2); cp = strchr(hostn, ','); if (cp == NULL) errx(1, "Bad -c argument %s", hostn); *cp = '\0'; if (getaddrinfo(hostn, NULL, NULL, &res) != 0) errx(1, "Can't get IP# for %s", hostn); *cp++ = ','; if (getaddrinfo(cp, NULL, NULL, &newres) != 0) errx(1, "Can't get IP# for %s", cp); break; case 'q': quiet = 1; break; case 'r': /* Reset the DS server in a mirror with 0.0.0.0. */ if (zerofh != 0 || res != NULL || newres != NULL) errx(1, "-r and -s, -z or -c are mutually " "exclusive"); zerods = 1; /* Translate the server name to an IP address. */ if (getaddrinfo(optarg, NULL, NULL, &res) != 0) errx(1, "Can't get IP# for %s", optarg); break; case 's': if (res != NULL) errx(1, "-s, -c and -r are mutually " "exclusive"); /* Translate the server name to an IP address. */ if (getaddrinfo(optarg, NULL, NULL, &res) != 0) errx(1, "Can't get IP# for %s", optarg); break; case 'z': if (newres != NULL || zerods != 0) errx(1, "-c, -r and -z are mutually " "exclusive"); zerofh = 1; break; default: usage(); } } argc -= optind; if (argc != 1) usage(); argv += optind; /* * The host address and directory where the data storage file is * located is in the extended attribute "pnfsd.dsfile". */ xattrsize = extattr_get_file(*argv, EXTATTR_NAMESPACE_SYSTEM, "pnfsd.dsfile", dsfile, sizeof(dsfile)); mirrorcnt = xattrsize / sizeof(struct pnfsdsfile); if (mirrorcnt < 1 || xattrsize != mirrorcnt * sizeof(struct pnfsdsfile)) err(1, "Can't get extattr pnfsd.dsfile for %s", *argv); if (quiet == 0) printf("%s:\t", *argv); for (i = 0; i < mirrorcnt; i++) { if (i > 0 && quiet == 0) printf("\t"); /* Do the zerofh option. You must be root. */ if (zerofh != 0) { if (geteuid() != 0) errx(1, "Must be root/su to zerofh"); /* * Do it for the server specified by -s/--ds or all * servers, if -s/--ds was not specified. */ sin = &dsfile[i].dsf_sin; sin6 = &dsfile[i].dsf_sin6; ad = res; while (ad != NULL) { adsin = (struct sockaddr_in *)ad->ai_addr; adsin6 = (struct sockaddr_in6 *)ad->ai_addr; if (adsin->sin_family == sin->sin_family) { if (sin->sin_family == AF_INET && sin->sin_addr.s_addr == adsin->sin_addr.s_addr) break; else if (sin->sin_family == AF_INET6 && IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &adsin6->sin6_addr)) break; } ad = ad->ai_next; } if (res == NULL || ad != NULL) { memset(&dsfile[i].dsf_fh, 0, sizeof(fhandle_t)); dosetxattr = 1; } } /* Do the zerods option. You must be root. */ if (zerods != 0 && mirrorcnt > 1) { if (geteuid() != 0) errx(1, "Must be root/su to zerods"); /* * Do it for the server specified. */ sin = &dsfile[i].dsf_sin; sin6 = &dsfile[i].dsf_sin6; ad = res; while (ad != NULL) { adsin = (struct sockaddr_in *)ad->ai_addr; adsin6 = (struct sockaddr_in6 *)ad->ai_addr; if (adsin->sin_family == sin->sin_family) { if (sin->sin_family == AF_INET && sin->sin_addr.s_addr == adsin->sin_addr.s_addr) break; else if (sin->sin_family == AF_INET6 && IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &adsin6->sin6_addr)) break; } ad = ad->ai_next; } if (ad != NULL) { sin->sin_family = AF_INET; sin->sin_len = sizeof(*sin); sin->sin_port = 0; sin->sin_addr.s_addr = 0; dosetxattr = 1; } } /* Do the -c option to replace the DS host address. */ if (newres != NULL) { if (geteuid() != 0) errx(1, "Must be root/su to replace the host" " addr"); /* * Check that the old host address matches. */ sin = &dsfile[i].dsf_sin; sin6 = &dsfile[i].dsf_sin6; ad = res; while (ad != NULL) { adsin = (struct sockaddr_in *)ad->ai_addr; adsin6 = (struct sockaddr_in6 *)ad->ai_addr; if (adsin->sin_family == sin->sin_family) { if (sin->sin_family == AF_INET && sin->sin_addr.s_addr == adsin->sin_addr.s_addr) break; else if (sin->sin_family == AF_INET6 && IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &adsin6->sin6_addr)) break; } ad = ad->ai_next; } if (ad != NULL) { if (sin->sin_family == AF_INET) tport = sin->sin_port; else tport = sin6->sin6_port; /* * We have a match, so replace it with the first * AF_INET or AF_INET6 address in the newres * list. */ while (newres->ai_addr->sa_family != AF_INET && newres->ai_addr->sa_family != AF_INET6) { newres = newres->ai_next; if (newres == NULL) errx(1, "Hostname %s has no" " IP#", cp); } if (newres->ai_addr->sa_family == AF_INET) { memcpy(sin, newres->ai_addr, sizeof(*sin)); sin->sin_port = tport; } else if (newres->ai_addr->sa_family == AF_INET6) { memcpy(sin6, newres->ai_addr, sizeof(*sin6)); sin6->sin6_port = tport; } dosetxattr = 1; } } if (quiet == 0) { /* Translate the IP address to a hostname. */ if (getnameinfo((struct sockaddr *)&dsfile[i].dsf_sin, dsfile[i].dsf_sin.sin_len, hostn, sizeof(hostn), NULL, 0, 0) < 0) err(1, "Can't get hostname"); printf("%s\tds%d/%s", hostn, dsfile[i].dsf_dir, dsfile[i].dsf_filename); } } if (quiet == 0) printf("\n"); if (dosetxattr != 0 && extattr_set_file(*argv, EXTATTR_NAMESPACE_SYSTEM, "pnfsd.dsfile", dsfile, xattrsize) != xattrsize) err(1, "Can't set pnfsd.dsfile"); } static void usage(void) { fprintf(stderr, "pnfsdsfile [-q/--quiet] [-z/--zerofh] " "[-c/--changeds ] " "[-r/--zerods ] " "[-s/--ds ] " "\n"); exit(1); } Index: projects/pnfs-planb-server/usr.bin/pnfsdskill/pnfsdskill.c =================================================================== --- projects/pnfs-planb-server/usr.bin/pnfsdskill/pnfsdskill.c (revision 334645) +++ projects/pnfs-planb-server/usr.bin/pnfsdskill/pnfsdskill.c (revision 334646) @@ -1,77 +1,76 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2017 Rick Macklem - * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include static void usage(void); /* * This program disables use of a DS mirror. The "dspath" command line * argument must be an exact match for the mounted-on path of the DS. * It should be done before any forced dismount is performed on the path * and should work even when the mount point is hung. */ int main(int argc, char *argv[]) { struct nfsd_pnfsd_args pnfsdarg; if (argc != 2) usage(); if (geteuid() != 0) errx(1, "Must be run as root/su"); pnfsdarg.op = PNFSDOP_DELDSSERVER; pnfsdarg.dspath = argv[1]; if (nfssvc(NFSSVC_PNFSDS, &pnfsdarg) < 0) err(1, "Can't kill %s", argv[1]); } static void usage(void) { fprintf(stderr, "pnfsdsfile [filepath]\n"); exit(1); }