Whamcloud - gitweb
LU-14034 hsm: add PID file handling to lhsmtool_posix 53/40253/9
authorJohn L. Hammond <jhammond@whamcloud.com>
Tue, 29 Dec 2020 02:10:31 +0000 (21:10 -0500)
committerOleg Drokin <green@whamcloud.com>
Fri, 22 Jan 2021 21:53:21 +0000 (21:53 +0000)
Add pid-file handling to lhsmtool_posix to prevent accidentally
running concurrent instances of the copytool. (Multiple instances are
still allowed if you do not use PID files or use separate files.)

Use the PID file to avoid needing libtool when stopping, continuing,
or killing the copytool from test scripts.

Remove unnecessary libtool usage from test scripts.

Signed-off-by: John L. Hammond <jhammond@whamcloud.com>
Change-Id: I4f012a88c58f3a86a731df3b7d35ff32db047c2d
Reviewed-on: https://review.whamcloud.com/40253
Tested-by: Maloo <maloo@whamcloud.com>
Tested-by: jenkins <devops@whamcloud.com>
Reviewed-by: James Simmons <jsimmons@infradead.org>
Reviewed-by: Ben Evans <beevans@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
debian/control
debian/control.main
lustre.spec.in
lustre/tests/conf-sanity.sh
lustre/tests/sanity-hsm.sh
lustre/tests/test-framework.sh
lustre/utils/Makefile.am
lustre/utils/lhsmtool_posix.c
lustre/utils/pid_file.c [new file with mode: 0644]
lustre/utils/pid_file.h [new file with mode: 0644]

index b7b07c8..77a22a2 100644 (file)
@@ -84,7 +84,7 @@ Package: lustre-tests
 Section: utils
 Architecture: i386 armhf powerpc ppc64el amd64 ia64 arm64
 Priority: optional
-Depends: lustre-iokit (= ${binary:Version}), lustre-dev (= ${binary:Version}), attr, rsync, perl, lsof, libtool, libtool-bin, mpi-default-bin, selinux-utils
+Depends: lustre-iokit (= ${binary:Version}), lustre-dev (= ${binary:Version}), attr, rsync, perl, lsof, mpi-default-bin, selinux-utils
 Description: Test suite for the Lustre filesystem
  Lustre is a scalable, secure, robust, highly-available cluster file system.
  This release is maintained by Whamcloud and available from
index b7b07c8..77a22a2 100644 (file)
@@ -84,7 +84,7 @@ Package: lustre-tests
 Section: utils
 Architecture: i386 armhf powerpc ppc64el amd64 ia64 arm64
 Priority: optional
-Depends: lustre-iokit (= ${binary:Version}), lustre-dev (= ${binary:Version}), attr, rsync, perl, lsof, libtool, libtool-bin, mpi-default-bin, selinux-utils
+Depends: lustre-iokit (= ${binary:Version}), lustre-dev (= ${binary:Version}), attr, rsync, perl, lsof, mpi-default-bin, selinux-utils
 Description: Test suite for the Lustre filesystem
  Lustre is a scalable, secure, robust, highly-available cluster file system.
  This release is maintained by Whamcloud and available from
index 8c9c400..ef29b67 100644 (file)
@@ -346,7 +346,7 @@ Requires: lustre-devel = %{version}
 Requires: %{requires_kmod_name} = %{requires_kmod_version}
 Requires: %{requires_kmod_tests_name} = %{requires_kmod_version}
 %endif
-Requires: attr, rsync, perl, lsof, libtool, /usr/bin/getconf
+Requires: attr, rsync, perl, lsof, /usr/bin/getconf
 %if %{with mpi}
 %if %{mpi_name} == "mpich"
 BuildRequires: mpich-devel
index a51f003..a4bc3b8 100644 (file)
@@ -9039,7 +9039,7 @@ test_125()
 
                echo "Before: ${facet} ${device} ${pre_max_sectors} ${max_hw_sectors}"
 
-               do_facet ${facet} "libtool execute l_tunedisk ${device}"
+               do_facet ${facet} "l_tunedisk ${device}"
 
                # Value after l_tunedisk
                local post_max_sectors=$(get_max_sectors_kb ${facet} ${device})
index 87b270a..37ebd70 100755 (executable)
@@ -84,7 +84,7 @@ CLIENT2=${CLIENT2:-$CLIENT1}
 
 search_copytools() {
        local hosts=${1:-$(facet_active_host $SINGLEAGT)}
-       do_nodesv $hosts "libtool execute pgrep -x $HSMTOOL"
+       do_nodesv $hosts "pgrep --pidfile=$HSMTOOL_PID_FILE hsmtool"
 }
 
 wait_copytools() {
@@ -148,7 +148,7 @@ fid2archive()
        local fid="$1"
 
        case "$HSMTOOL" in
-       lhsmtool_posix)
+       *lhsmtool_posix)
                printf "%s" "$(hsm_root)/*/*/*/*/*/*/$fid"
                ;;
        esac
@@ -168,9 +168,8 @@ get_copytool_event_log() {
 copytool_suspend() {
        local agents=${1:-$(facet_active_host $SINGLEAGT)}
 
-       stack_trap \
-               "do_nodesv $agents libtool execute pkill -CONT -x '$HSMTOOL' || true" EXIT
-       do_nodesv $agents "libtool execute pkill -STOP -x $HSMTOOL" || return 0
+       stack_trap "pkill_copytools $agents CONT || true" EXIT
+       pkill_copytools $agents STOP || return 0
        echo "Copytool is suspended on $agents"
 }
 
@@ -488,7 +487,8 @@ get_agent_uuid() {
 
        # Lustre mount-point is mandatory and last parameter on
        # copytool cmd-line.
-       local mntpnt=$(do_rpc_nodes $agent libtool execute ps -C $HSMTOOL -o args= |
+       local mntpnt=$(do_rpc_nodes $agent \
+                       pgrep --pidfile=$HSMTOOL_PID_FILE --list-full hsmtool |
                       awk '{print $NF}')
        [ -n "$mntpnt" ] || error "Found no Agent or with no mount-point "\
                                  "parameter"
index bee4e79..9fbce2f 100755 (executable)
@@ -10082,11 +10082,16 @@ init_agt_vars() {
        export SINGLEAGT=${SINGLEAGT:-agt1}
 
        export HSMTOOL=${HSMTOOL:-"lhsmtool_posix"}
+       export HSMTOOL_PID_FILE=${HSMTOOL_PID_FILE:-"/var/run/lhsmtool_posix.pid"}
        export HSMTOOL_VERBOSE=${HSMTOOL_VERBOSE:-""}
        export HSMTOOL_UPDATE_INTERVAL=${HSMTOOL_UPDATE_INTERVAL:=""}
        export HSMTOOL_EVENT_FIFO=${HSMTOOL_EVENT_FIFO:=""}
        export HSMTOOL_TESTDIR
 
+       if ! [[ $HSMTOOL =~ hsmtool ]]; then
+               echo "HSMTOOL = '$HSMTOOL' does not contain 'hsmtool', GLWT" >&2
+       fi
+
        HSM_ARCHIVE_NUMBER=2
 
        # The test only support up to 10 MDTs
@@ -10119,10 +10124,17 @@ get_mdt_devices() {
        done
 }
 
+pkill_copytools() {
+       local hosts="$1"
+       local signal="$2"
+
+       do_nodes "$hosts" "pkill --pidfile=$HSMTOOL_PID_FILE --signal=$signal hsmtool"
+}
+
 copytool_continue() {
        local agents=${1:-$(facet_active_host $SINGLEAGT)}
 
-       do_nodesv $agents "libtool execute pkill -CONT -x $HSMTOOL" || return 0
+       pkill_copytools "$agents" CONT || return 0
        echo "Copytool is continued on $agents"
 }
 
@@ -10130,7 +10142,7 @@ kill_copytools() {
        local hosts=${1:-$(facet_active_host $SINGLEAGT)}
 
        echo "Killing existing copytools on $hosts"
-       do_nodesv $hosts "libtool execute killall -q $HSMTOOL" || true
+       pkill_copytools "$hosts" TERM || return 0
        copytool_continue "$hosts"
 }
 
@@ -10178,16 +10190,17 @@ __lhsmtool_import()
 
 __lhsmtool_setup()
 {
-       local cmd="$HSMTOOL $HSMTOOL_VERBOSE --daemon --hsm-root \"$hsm_root\""
+       local host="$(facet_host "$facet")"
+       local cmd="$HSMTOOL $HSMTOOL_VERBOSE --daemon --pid-file=$HSMTOOL_PID_FILE --hsm-root \"$hsm_root\""
        [ -n "$bandwidth" ] && cmd+=" --bandwidth $bandwidth"
        [ -n "$archive_id" ] && cmd+=" --archive $archive_id"
        [ ${#misc_options[@]} -gt 0 ] &&
                cmd+=" $(IFS=" " echo "$@")"
        cmd+=" \"$mountpoint\""
 
-       echo "Starting copytool $facet on $(facet_host $facet)"
-       stack_trap "do_facet $facet libtool execute pkill -x '$HSMTOOL' || true" EXIT
-       do_facet $facet "$cmd < /dev/null > \"$(copytool_logfile $facet)\" 2>&1"
+       echo "Starting copytool '$facet' on '$host'"
+       stack_trap "pkill_copytools $host TERM || true" EXIT
+       do_node "$host" "$cmd < /dev/null > \"$(copytool_logfile $facet)\" 2>&1"
 }
 
 hsm_root() {
index d7d7bdb..cc59389 100644 (file)
@@ -224,7 +224,7 @@ l_getidentity_SOURCES = l_getidentity.c
 l_getidentity_LDADD := $(top_builddir)/libcfs/libcfs/libcfs.la
 l_getidentity_DEPENDENCIES := $(top_builddir)/libcfs/libcfs/libcfs.la
 
-lhsmtool_posix_SOURCES = lhsmtool_posix.c
+lhsmtool_posix_SOURCES = lhsmtool_posix.c pid_file.c pid_file.h
 lhsmtool_posix_LDADD := liblustreapi.la $(PTHREAD_LIBS)
 lhsmtool_posix_DEPENDENCIES := liblustreapi.la
 
index 4f933b4..01e0fa0 100644 (file)
@@ -59,6 +59,7 @@
 #include <libcfs/util/string.h>
 #include <linux/lustre/lustre_fid.h>
 #include <lustre/lustreapi.h>
+#include "pid_file.h"
 
 /* Progress reporting period */
 #define REPORT_INTERVAL_DEFAULT 30
@@ -100,6 +101,7 @@ struct options {
        char                    *o_hsm_root;
        char                    *o_src; /* for import, or rebind */
        char                    *o_dst; /* for import, or rebind */
+       char                    *o_pid_file;
 };
 
 /* everything else is zeroed */
@@ -124,6 +126,7 @@ static int err_minor;
 
 static char cmd_name[PATH_MAX];
 static char fs_name[MAX_OBD_NAME + 1];
+static int pid_file_fd = -1;
 
 static struct hsm_copytool_private *ctdata;
 
@@ -198,6 +201,7 @@ static void usage(const char *name, int rc)
        "   -c, --chunk-size <sz>     I/O size used during data copy\n"
        "                             (unit can be used, default is MB)\n"
        "   -f, --event-fifo <path>   Write events stream to fifo\n"
+       "   -P, --pid-file=PATH       Lock and write PID to PATH\n"
        "   -p, --hsm-root <path>     Target HSM mount point\n"
        "   -q, --quiet               Produce less verbose output\n"
        "   -u, --update-interval <s> Interval between progress reports sent\n"
@@ -241,6 +245,7 @@ static int ct_parseopts(int argc, char * const *argv)
          .flag = &opt.o_copy_xattrs },
        { .val = 0,     .name = "no_xattr",     .has_arg = no_argument,
          .flag = &opt.o_copy_xattrs },
+       { .val = 'P',   .name = "pid-file",     .has_arg = required_argument },
        { .val = 'p',   .name = "hsm-root",     .has_arg = required_argument },
        { .val = 'p',   .name = "hsm_root",     .has_arg = required_argument },
        { .val = 'q',   .name = "quiet",        .has_arg = no_argument },
@@ -251,6 +256,7 @@ static int ct_parseopts(int argc, char * const *argv)
                                                .has_arg = required_argument },
        { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
        { .name = NULL } };
+
        unsigned long long value;
        unsigned long long unit;
        bool all_id = false;
@@ -265,7 +271,7 @@ static int ct_parseopts(int argc, char * const *argv)
        if (opt.o_archive_id == NULL)
                return -ENOMEM;
 repeat:
-       while ((c = getopt_long(argc, argv, "A:b:c:f:hiMp:qru:v",
+       while ((c = getopt_long(argc, argv, "A:b:c:f:hiMp:P:qru:v",
                                long_opts, NULL)) != -1) {
                switch (c) {
                case 'A': {
@@ -339,6 +345,9 @@ repeat:
                case 'M':
                        opt.o_action = CA_MAXSEQ;
                        break;
+               case 'P':
+                       opt.o_pid_file = optarg;
+                       break;
                case 'p':
                        opt.o_hsm_root = optarg;
                        break;
@@ -1872,6 +1881,15 @@ static int ct_run(void)
                }
        }
 
+       if (opt.o_pid_file != NULL) {
+               pid_file_fd = create_pid_file(opt.o_pid_file);
+               if (pid_file_fd < 0) {
+                       rc = -errno;
+                       CT_ERROR(rc, "cannot create PID file");
+                       return rc;
+               }
+       }
+
        setbuf(stdout, NULL);
 
        if (opt.o_event_fifo != NULL) {
diff --git a/lustre/utils/pid_file.c b/lustre/utils/pid_file.c
new file mode 100644 (file)
index 0000000..2d19c70
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * LGPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * LGPL HEADER END
+ *
+ * Copyright 2020, DataDirect Networks Storage.
+ */
+#include <stddef.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include "pid_file.h"
+
+int create_pid_file(const char *path)
+{
+       char buf[3 * sizeof(long long) + 2];
+       size_t buf_len;
+       int fd = -1;
+       int rc2;
+
+       fd = open(path, O_RDWR|O_CREAT|O_CLOEXEC, 0600);
+       if (fd < 0) {
+               fprintf(stderr, "%s: cannot open '%s': %s\n",
+                       program_invocation_short_name, path, strerror(errno));
+               return -1;
+       }
+
+       struct flock fl = {
+               .l_type = F_WRLCK,
+               .l_whence = SEEK_SET,
+       };
+
+       rc2 = fcntl(fd, F_SETLK, &fl);
+       if (rc2 < 0) {
+               fprintf(stderr, "%s: cannot lock '%s': %s\n",
+                       program_invocation_short_name, path, strerror(errno));
+               goto out;
+       }
+
+       rc2 = ftruncate(fd, 0);
+       if (rc2 < 0) {
+               fprintf(stderr, "%s: cannot truncate '%s': %s\n",
+                       program_invocation_short_name, path, strerror(errno));
+               goto out;
+       }
+
+       buf_len = snprintf(buf, sizeof(buf), "%lld\n", (long long)getpid());
+       rc2 = write(fd, buf, buf_len);
+       if (rc2 < 0) {
+               fprintf(stderr, "%s: cannot write '%s': %s\n",
+                       program_invocation_short_name, path, strerror(errno));
+               goto out;
+       }
+out:
+       if (rc2 < 0 && !(fd < 0)) {
+               close(fd);
+               fd = -1;
+       }
+
+       return fd;
+}
diff --git a/lustre/utils/pid_file.h b/lustre/utils/pid_file.h
new file mode 100644 (file)
index 0000000..97f5fec
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * LGPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * LGPL HEADER END
+ *
+ * Copyright 2020, DataDirect Networks Storage.
+ */
+
+#ifndef _PID_FILE_H_
+#define _PID_FILE_H_
+
+int create_pid_file(const char *path);
+
+#endif