svn commit: r332846 - projects/pnfs-planb-server/usr.bin/pnfsdscopymr
Rick Macklem
rmacklem at FreeBSD.org
Fri Apr 20 22:37:08 UTC 2018
Author: rmacklem
Date: Fri Apr 20 22:37:07 2018
New Revision: 332846
URL: https://svnweb.freebsd.org/changeset/base/332846
Log:
Add the pnfsdscopymr command that is used to copy a file to a recovered
mirrored DS.
Added:
projects/pnfs-planb-server/usr.bin/pnfsdscopymr/
projects/pnfs-planb-server/usr.bin/pnfsdscopymr/Makefile (contents, props changed)
projects/pnfs-planb-server/usr.bin/pnfsdscopymr/pnfsdscopymr.1 (contents, props changed)
projects/pnfs-planb-server/usr.bin/pnfsdscopymr/pnfsdscopymr.c (contents, props changed)
Added: projects/pnfs-planb-server/usr.bin/pnfsdscopymr/Makefile
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/pnfs-planb-server/usr.bin/pnfsdscopymr/Makefile Fri Apr 20 22:37:07 2018 (r332846)
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+PROG= pnfsdscopymr
+
+.include <bsd.prog.mk>
Added: projects/pnfs-planb-server/usr.bin/pnfsdscopymr/pnfsdscopymr.1
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/pnfs-planb-server/usr.bin/pnfsdscopymr/pnfsdscopymr.1 Fri Apr 20 22:37:07 2018 (r332846)
@@ -0,0 +1,96 @@
+.\" Copyright (c) 2018 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 March 9, 2018
+.Dt PNFSDSCOPYMR 1
+.Os
+.Sh NAME
+.Nm pnfsdscopymr
+.Nd
+makes a copy of a file's data on a recovered/new mirror data storage server (DS)
+.Sh SYNOPSIS
+.Nm
+.Ar file
+.Ar mounted_on_path_of_recovered_DS
+.Ar mounted_on_path_of_operational_DS
+.Sh DESCRIPTION
+The
+.Nm
+command copies a file's data from a operational DS to a recovered (or new)
+DS that is configured as a mirror of this operational DS.
+If the recovered/new DS is configured as a mirror of the operational DS, the
+data of the
+.Ar file
+on the MDS
+is copied to the recovered DS, unless the recovered/new DS
+already has a valid copy.
+The copy is considered valid if it exists in the extended attribute of the
+MDS file and its IP address is non-zero.
+If the
+.Ar file
+does not have the operational DS in its extended attribute or it already
+has a valid copy of the file's data, the command simply does an exit(0).
+This is done so that the command can be called on any file within the MDS's
+exported file tree safely.
+.Pp
+The first argument
+.Ar file
+is the file on the MDS, the second argument
+.Ar mounted_on_path_of_recovered_DS
+is the mounted on directory path of the recovered/new mirror and
+the third argument
+.Ar mounted_on_path_of_operational_DS
+is the mounted on directory path of a non-disabled DS that is a mirror of the
+recovered/new DS.
+The third argument is used to check if the
+.Ar file
+argument is stored on the mirror set that includes the recovered/new DS
+so that it can be used within a
+.Xr find 1 .
+.Pp
+This command must be run on the MDS and a typical usage would be as an
+argument for
+.Xr find 1
+for all regular files.
+.sp
+For example, if the recovered/new DS is mounted on /data3 and it is a
+mirror of the DS mounted on /data2:
+.br
+# cd <top-level-exported-directory-on-the-MDS>
+.br
+# find . -type f -exec pnfsdscopymr {} /data3 /data2 \\;
+.El
+.Sh SEE ALSO
+.Xr find 1 ,
+.Xr pnfsdsfile 1 ,
+.Xr pnfsdskill 1 ,
+.Xr nfsv4 4 ,
+.Xr pnfs 4 ,
+.Xr nfsd 8
+.Sh HISTORY
+The
+.Nm
+command appeared in FreeBSD12.
Added: projects/pnfs-planb-server/usr.bin/pnfsdscopymr/pnfsdscopymr.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/pnfs-planb-server/usr.bin/pnfsdscopymr/pnfsdscopymr.c Fri Apr 20 22:37:07 2018 (r332846)
@@ -0,0 +1,227 @@
+/*-
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <sys/extattr.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <nfs/nfssvc.h>
+
+#include <fs/nfs/nfsproto.h>
+#include <fs/nfs/nfskpiport.h>
+#include <fs/nfs/nfs.h>
+#include <fs/nfs/nfsrvstate.h>
+
+static void usage(void);
+
+/*
+ * 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;
+ int fnd, i, mirrorcnt, ret;
+ char host[MNAMELEN + NI_MAXHOST + 2], *cp;
+
+ if (argc != 4)
+ usage();
+ if (geteuid() != 0)
+ errx(1, "Must be run as root/su");
+
+ /*
+ * The host address and directory where the data storage file is
+ * located is in the extended attribute "pnfsd.dsfile".
+ */
+ xattrsize = extattr_get_file(argv[1], 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[1]);
+
+ /* Check the second argument to see that it is an NFS mount point. */
+ if (stat(argv[2], &sb) < 0)
+ errx(1, "Can't stat %s", argv[2]);
+ if (!S_ISDIR(sb.st_mode))
+ errx(1, "%s is not a directory", argv[2]);
+ if (statfs(argv[2], &sf) < 0)
+ errx(1, "Can't fsstat %s", argv[2]);
+ if (strcmp(sf.f_fstypename, "nfs") != 0)
+ errx(1, "%s is not an NFS mount", argv[2]);
+ if (strcmp(sf.f_mntonname, argv[2]) != 0)
+ errx(1, "%s is not the mounted-on dir for the new DS", argv[2]);
+
+ /*
+ * 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 <host>: 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);
+
+ /* Check the third argument to see that it is an NFS mount point. */
+ if (stat(argv[3], (struct stat *)&sb) < 0)
+ errx(1, "Can't stat %s", argv[3]);
+ if (!S_ISDIR(sb.st_mode))
+ errx(1, "%s is not a directory", argv[3]);
+ if (statfs(argv[3], (struct statfs *)&sf) < 0)
+ errx(1, "Can't fsstat %s", argv[3]);
+ if (strcmp(sf.f_fstypename, "nfs") != 0)
+ errx(1, "%s is not an NFS mount", argv[3]);
+ if (strcmp(sf.f_mntonname, argv[3]) != 0)
+ errx(1, "%s is not the mounted-on dir of the cur DS", argv[3]);
+
+ /*
+ * 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 <host>: 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) {
+ /*
+ * 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) {
+ 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 this file isn't stored on the
+ * current mirror and, therefore, isn't stored on this mirror set.
+ */
+ if (fnd == 0)
+ exit(0);
+
+ /* Do the copy via the nfssvc() syscall. */
+ pnfsdarg.op = PNFSDOP_COPYMR;
+ pnfsdarg.mdspath = argv[1];
+ pnfsdarg.dspath = argv[2];
+ pnfsdarg.curdspath = argv[3];
+ ret = nfssvc(NFSSVC_PNFSDS, &pnfsdarg);
+ if (ret < 0 && errno != EEXIST)
+ err(1, "Copymr failed args %s, %s, %s", argv[1], argv[2],
+ argv[3]);
+ exit(0);
+}
+
+static void
+usage(void)
+{
+
+ fprintf(stderr, "pnfsdscopymr <mds-filename> "
+ "<recovered-DS-mounted-on-path> <current-DS-mounted-on-path>\n");
+ exit(1);
+}
+
More information about the svn-src-projects
mailing list