svn commit: r335234 - in head/usr.sbin: . pnfsdsfile
Rick Macklem
rmacklem at FreeBSD.org
Fri Jun 15 19:35:10 UTC 2018
Author: rmacklem
Date: Fri Jun 15 19:35:08 2018
New Revision: 335234
URL: https://svnweb.freebsd.org/changeset/base/335234
Log:
Add a command the displays and modifies the pNFS server's extended attribute.
This command allows a sysadmin to display or modify the pnfsd.dsfile extended
attribute used by the pNFS MDS server in various ways.
Its main use is to set a DS's IP address to 0.0.0.0 when that DS has failed,
so that it will not be used for the file when brought back online after
being repaired.
Added:
head/usr.sbin/pnfsdsfile/
head/usr.sbin/pnfsdsfile/Makefile (contents, props changed)
head/usr.sbin/pnfsdsfile/pnfsdsfile.8 (contents, props changed)
head/usr.sbin/pnfsdsfile/pnfsdsfile.c (contents, props changed)
Modified:
head/usr.sbin/Makefile
Modified: head/usr.sbin/Makefile
==============================================================================
--- head/usr.sbin/Makefile Fri Jun 15 19:19:36 2018 (r335233)
+++ head/usr.sbin/Makefile Fri Jun 15 19:35:08 2018 (r335234)
@@ -59,6 +59,7 @@ SUBDIR= adduser \
nologin \
pciconf \
periodic \
+ pnfsdsfile \
pnfsdskill \
powerd \
prometheus_sysctl_exporter \
Added: head/usr.sbin/pnfsdsfile/Makefile
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/usr.sbin/pnfsdsfile/Makefile Fri Jun 15 19:35:08 2018 (r335234)
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+PROG= pnfsdsfile
+MAN= pnfsdsfile.8
+
+.include <bsd.prog.mk>
Added: head/usr.sbin/pnfsdsfile/pnfsdsfile.8
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/usr.sbin/pnfsdsfile/pnfsdsfile.8 Fri Jun 15 19:35:08 2018 (r335234)
@@ -0,0 +1,133 @@
+.\" Copyright (c) 2017 Rick Macklem
+.\"
+.\" 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 March 11, 2018
+.Dt PNFSDSFILE 8
+.Os
+.Sh NAME
+.Nm pnfsdsfile
+.Nd display
+a pNFS data storage file's location(s) and/or modify the
+.Dq pnfsd.dsfile
+extended attribute for them
+.Sh SYNOPSIS
+.Nm
+.Op Fl qz
+.Op Fl s Ar dshostname
+.Op Fl c Ar old-dshostname,new-dshostname
+.Op Fl r Ar dshostname
+.Ar mdsfile
+.Sh DESCRIPTION
+The
+.Nm
+command displays the data storage file's location(s) for a pNFS service and/or
+modifies the
+.Dq pnfsd.dsfile
+extended attribute on the
+.Ar mdsfile .
+A pNFS service maintains a data storage file for each regular file on
+the MetaData Server (MDS) on one or more of the Data Servers (DS).
+If mirroring is enabled, the data storage file will be on more that one of the DSs.
+Unless command options are specified, this command displays the location(s)
+of the data storage file for the MDS file
+.Ar mdsfile .
+It must be used on the MDS and the
+.Ar mdsfile
+must be a file on the exported local file system and not an NFSv4.1 mount.
+This information is stored in the
+.Dq pnfsd.dsfile
+extended attribute for this
+.Ar mdsfile .
+The command line options allow the information in the
+.Dq pnfsd.dsfile
+extended attribute to be changed.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl q
+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 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 mirroring is enabled and the
+.Ar dshostname
+DS is disabled, so that it can be re-enabled once it is repaired.
+This needs to be done for all files in the exported MDS tree where
+the data may not be up-to-date on the repaired DS when it is re-enabled.
+After being re-enabled, the command
+.Xr pnfsdscopymr 1
+with the
+.Dq -r
+option
+will be used to copy the the file's data to this repaired 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 <top-level-exported-directory-on-MDS>
+.br
+# find . -type f -exec pnfsdsfile -q -r nfsv4-data3 {} \\;
+.El
+.Sh SEE ALSO
+.Xr find 1 ,
+.Xr getaddrinfo 3 ,
+.Xr nfsv4 4 ,
+.Xr pnfs 4 ,
+.Xr nfsd 8 ,
+.Xr pnfsdscopymr 8 ,
+.Xr pnfsdskill 8
+.Sh HISTORY
+The
+.Nm
+command appeared in FreeBSD12.
Added: head/usr.sbin/pnfsdsfile/pnfsdsfile.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/usr.sbin/pnfsdsfile/pnfsdsfile.c Fri Jun 15 19:35:08 2018 (r335234)
@@ -0,0 +1,330 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2017 Rick Macklem
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <getopt.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/extattr.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <fs/nfs/nfskpiport.h>
+#include <fs/nfs/nfsproto.h>
+#include <fs/nfs/nfs.h>
+#include <fs/nfs/nfsrvstate.h>
+
+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, xattrsize2;
+
+ zerods = 0;
+ zerofh = 0;
+ quiet = 0;
+ dosetxattr = 0;
+ res = NULL;
+ newres = NULL;
+ cp = 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);
+ xattrsize2 = mirrorcnt * sizeof(struct pnfsdsfile);
+ if (mirrorcnt < 1 || xattrsize != xattrsize2)
+ 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) {
+ if (ad->ai_addr->sa_family == AF_INET &&
+ sin->sin_family == AF_INET &&
+ ad->ai_addrlen >= sizeof(adsin)) {
+ memcpy(&adsin, ad->ai_addr,
+ sizeof(adsin));
+ if (sin->sin_addr.s_addr ==
+ adsin.sin_addr.s_addr)
+ break;
+ }
+ if (ad->ai_addr->sa_family == AF_INET6 &&
+ sin6->sin6_family == AF_INET6 &&
+ ad->ai_addrlen >= sizeof(adsin6)) {
+ memcpy(&adsin6, ad->ai_addr,
+ sizeof(adsin6));
+ if (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) {
+ if (ad->ai_addr->sa_family == AF_INET &&
+ sin->sin_family == AF_INET &&
+ ad->ai_addrlen >= sizeof(adsin)) {
+ memcpy(&adsin, ad->ai_addr,
+ sizeof(adsin));
+ if (sin->sin_addr.s_addr ==
+ adsin.sin_addr.s_addr)
+ break;
+ }
+ if (ad->ai_addr->sa_family == AF_INET6 &&
+ sin6->sin6_family == AF_INET6 &&
+ ad->ai_addrlen >= sizeof(adsin6)) {
+ memcpy(&adsin6, ad->ai_addr,
+ sizeof(adsin6));
+ if (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) {
+ if (ad->ai_addr->sa_family == AF_INET &&
+ sin->sin_family == AF_INET &&
+ ad->ai_addrlen >= sizeof(adsin)) {
+ memcpy(&adsin, ad->ai_addr,
+ sizeof(adsin));
+ if (sin->sin_addr.s_addr ==
+ adsin.sin_addr.s_addr)
+ break;
+ }
+ if (ad->ai_addr->sa_family == AF_INET6 &&
+ sin6->sin6_family == AF_INET6 &&
+ ad->ai_addrlen >= sizeof(adsin6)) {
+ memcpy(&adsin6, ad->ai_addr,
+ sizeof(adsin6));
+ if (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 <old dshostname> <new dshostname>] "
+ "[-r/--zerods <dshostname>] "
+ "[-s/--ds <dshostname>] "
+ "<filename>\n");
+ exit(1);
+}
+
More information about the svn-src-head
mailing list