From owner-svn-src-projects@freebsd.org Tue May 29 12:43:04 2018 Return-Path: Delivered-To: svn-src-projects@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 74FECF7983D for ; Tue, 29 May 2018 12:43:04 +0000 (UTC) (envelope-from rmacklem@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 493C66805A; Tue, 29 May 2018 12:43:04 +0000 (UTC) (envelope-from rmacklem@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 2B0E41C24D; Tue, 29 May 2018 12:43:04 +0000 (UTC) (envelope-from rmacklem@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id w4TCh4uG010852; Tue, 29 May 2018 12:43:04 GMT (envelope-from rmacklem@FreeBSD.org) Received: (from rmacklem@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id w4TCh4nA010851; Tue, 29 May 2018 12:43:04 GMT (envelope-from rmacklem@FreeBSD.org) Message-Id: <201805291243.w4TCh4nA010851@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: rmacklem set sender to rmacklem@FreeBSD.org using -f From: Rick Macklem Date: Tue, 29 May 2018 12:43:04 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r334325 - projects/pnfs-planb-server/usr.bin/pnfsdscopymr X-SVN-Group: projects X-SVN-Commit-Author: rmacklem X-SVN-Commit-Paths: projects/pnfs-planb-server/usr.bin/pnfsdscopymr X-SVN-Commit-Revision: 334325 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 29 May 2018 12:43:04 -0000 Author: rmacklem Date: Tue May 29 12:43:03 2018 New Revision: 334325 URL: https://svnweb.freebsd.org/changeset/base/334325 Log: Fix up pnfsdscopymr.c for the distributed mirror handling. Also change the default to mirror to any other DS and add a "-r" option to specify the destination mirror DS. Add a new "-m" option to migrate data storage files between DSs. The man page still needs to be updated. Modified: projects/pnfs-planb-server/usr.bin/pnfsdscopymr/pnfsdscopymr.c Modified: projects/pnfs-planb-server/usr.bin/pnfsdscopymr/pnfsdscopymr.c ============================================================================== --- projects/pnfs-planb-server/usr.bin/pnfsdscopymr/pnfsdscopymr.c Tue May 29 12:32:08 2018 (r334324) +++ projects/pnfs-planb-server/usr.bin/pnfsdscopymr/pnfsdscopymr.c Tue May 29 12:43:03 2018 (r334325) @@ -30,6 +30,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -40,6 +41,8 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include #include #include #include @@ -51,6 +54,12 @@ __FBSDID("$FreeBSD$"); 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 @@ -67,152 +76,218 @@ main(int argc, char *argv[]) struct sockaddr_in *sin; struct sockaddr_in6 *sin6; ssize_t xattrsize; - int fnd, i, mirrorcnt, ret; + size_t mirlen; + int ch, fnd, fndzero, i, migrateit, mirrorcnt, mirrorit, ret; + int mirrorlevel; char host[MNAMELEN + NI_MAXHOST + 2], *cp; - if (argc != 4) - usage(); 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[1], EXTATTR_NAMESPACE_SYSTEM, + 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[1]); + errx(1, "Can't get extattr pnfsd.dsfile for %s", *argv); - /* 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 : 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); + /* See if there is a 0.0.0.0 entry. */ + fndzero = 0; 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); + 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; } - nres = nres->ai_next; } + freeaddrinfo(res); } - 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 : 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; + /* 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; + } } - } 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; } - 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); } - 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]; + pnfsdarg.mdspath = *argv; ret = nfssvc(NFSSVC_PNFSDS, &pnfsdarg); if (ret < 0 && errno != EEXIST) - err(1, "Copymr failed args %s, %s, %s", argv[1], argv[2], - argv[3]); + err(1, "Copymr failed args %s, %s", argv[1], argv[2]); exit(0); } @@ -220,8 +295,9 @@ static void usage(void) { - fprintf(stderr, "pnfsdscopymr " - " \n"); + fprintf(stderr, "pnfsdscopymr [-r recovered-DS-mounted-on-path] " + "[-m soure-DS-mounted-on-path destination-DS-mounted-on-path] " + "mds-filename"); exit(1); }