Index: projects/pnfs-planb-server/usr.bin/pnfsdsfile/pnfsdsfile.1 =================================================================== --- projects/pnfs-planb-server/usr.bin/pnfsdsfile/pnfsdsfile.1 (revision 332844) +++ projects/pnfs-planb-server/usr.bin/pnfsdsfile/pnfsdsfile.1 (revision 332845) @@ -1,87 +1,120 @@ .\" 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. .\" .\" $FreeBSD$ .\" -.Dd April 1, 2017 +.Dd March 11, 2018 .Dt PNFSDSFILE 1 .Os .Sh NAME .Nm pnfsdsfile .Nd display -a pNFS data storage file location and/or modify the pnfsd.dsfile extended attribute for it +a pNFS data storage file's location(s) and/or modify the pnfsd.dsfile extended attribute for them .Sh SYNOPSIS .Nm .Op Fl qz -.Op Fl c Ar old-dshostname,new-dshostname .Op Fl s Ar dshostname -.Ar metadata_file +.Op Fl c Ar old-dshostname,new-dshostname +.Op Fl r Ar dshostname +.Ar file_on_MDS .Sh DESCRIPTION The .Nm -command displays the location of a data storage file for a pNFS service and/or +command displays the data storage file's location(s) for a pNFS service and/or modifies the pnfsd.dsfile extended attribute on the file. A pNFS service maintains a data storage file for each regular file on -the MetaData Server (MDS) on one of the Data Storage (DS) servers. -Unless command options are specified, this command displays the location +the MetaData Server(s) (MDS) on one or more of the Data Storage servers (DS). +If there is more than one DS, the DSs are a mirrored set and all of these +DSs should have copies of the +.Ar file_on_MDS +file's data. +Unless command options are specified, this command displays the location(s) of the DS file for the MDS file specified by the last command line argument. It must be used on the MDS and the -.Ar metadata_file +.Ar file_on_MDS must be a file on the exported local file system and not an NFSv4.1 mount. .Pp The following options are available: .Bl -tag -width Ds .It Fl q -This option suppresses printing of the DS file's location. +This option suppresses printing of the DS file's location(s). .It Fl z This option specifies that the file handle field of the pnfsd.dsfile extended attribute is to filled with all zero bits. This forces the pNFS MDS to do a Lookup RPC against the DS to acquire the file handle to update it. Normally this will only be necessary after the DS file has been recovered from a backup, causing the file handle to change. +.It Fl s Ar dshostname +This option can be used with +.Fl z +so that the zeroing out of the file handle is only done if the DS server +is the one specified by this option. .It Fl c Ar old-dshostname,new-dshostname This option allows a sysadmin to replace the host IP# for the DS in the pnfsd.dsfile extended attribute. The old-hostname must resolve to the IP# already in the pnfsd.dsfile extended attribute or the replacement will not be done. If the old-dshostname matches, then the IP# is replaced by the first AF_INET or AF_INET6 address that .Xr getaddrinfo 3 returns for the new-dshostname. Changing a DS server's host IP# should be avoided, but this option will allow it to be changed, if the change is unavoidable. -.It Fl s Ar dshostname -This option can be used with -.Fl z -so that the zeroing out of the file handle is only done if the DS server -is the one specified by this option. +.It Fl r Ar dshostname +This option sets the IP address of the extended attribute entry for the +.Ar dshostname +to 0.0.0.0 so that it will no longer be used. +.Pp +This is meant to be used when one of a mirrored set of DSs has been +disabled so that this DS will not be used when it is re-enabled. +This needs to be done for all files in the exported MDS tree where +the data may not be up-to-date on the recovered DS when it is re-enabled. +After being re-enabled, the command +.Xr pnfsdscopymr 1 +will be used to copy the the file's data to this DS and then update the extended +attribute to use it. +.Pp +A typical use of this will be within a +.Xr find 1 +for all regular files in the MDS's exported tree. +.sp +For example, if the disabled DS is nfsv4-data3: +.br +# cd +.br +# find . -type f -exec pnfsdsfile -q -r nfsv4-data3 {} \\; .El .Sh SEE ALSO +.Xr find 1 , +.Xr pnfsdscopymr 1 , +.Xr pnfsdskill 1 , +.Xr getaddrinfo 3 , .Xr nfsv4 4 , +.Xr pnfs 4 , .Xr nfsd 8 .Sh HISTORY The .Nm command appeared in FreeBSD12. Index: projects/pnfs-planb-server/usr.bin/pnfsdsfile/pnfsdsfile.c =================================================================== --- projects/pnfs-planb-server/usr.bin/pnfsdsfile/pnfsdsfile.c (revision 332844) +++ projects/pnfs-planb-server/usr.bin/pnfsdsfile/pnfsdsfile.c (revision 332845) @@ -1,249 +1,308 @@ /*- * 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, zerofh; + 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:qs:z", longopts, NULL)) != -1) { + 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) - errx(1, "-c and -z are mutually exclusive\n"); + if (zerofh != 0 || zerods != 0) + errx(1, "-c, -r and -z are mutually " + "exclusive\n"); + if (res != NULL) + errx(1, "-c and -s are mutually exclusive\n"); strlcpy(hostn, optarg, 2 * NI_MAXHOST + 2); cp = strchr(hostn, ','); if (cp == NULL) errx(1, "Bad -c argument %s\n", hostn); *cp = '\0'; if (getaddrinfo(hostn, NULL, NULL, &res) != 0) errx(1, "Can't get IP# for %s\n", hostn); *cp++ = ','; if (getaddrinfo(cp, NULL, NULL, &newres) != 0) errx(1, "Can't get IP# for %s\n", 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\n"); + 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\n", optarg); + break; case 's': + if (res != NULL) + errx(1, "-s, -c and -r are mutually " + "exclusive\n"); /* Translate the server name to an IP address. */ if (getaddrinfo(optarg, NULL, NULL, &res) != 0) errx(1, "Can't get IP# for %s\n", optarg); break; case 'z': - if (newres != NULL) - errx(1, "-c and -z are mutually exclusive\n"); + if (newres != NULL || zerods != 0) + errx(1, "-c, -r and -z are mutually " + "exclusive\n"); 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\n"); + if (quiet == 0) + printf("%s:\t", *argv); for (i = 0; i < mirrorcnt; i++) { - if (i > 0) - printf(" "); + 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\n"); /* * 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\n"); + + /* + * 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_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\n"); /* * 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#\n", 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\n"); 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\n"); } static void usage(void) { fprintf(stderr, "pnfsdsfile [-q/--quiet] [-z/--zerofh] " - "[-s/--ds ] \n"); + "[-c/--changeds ] " + "[-r/--zerods ] " + "[-s/--ds ] " + "\n"); exit(1); }