summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJiri Olsa <jolsa@kernel.org>2021-02-08 21:08:57 +0100
committerArnaldo Carvalho de Melo <acme@redhat.com>2021-02-11 10:16:56 -0300
commit8c98be6c36a1798557a6792bcc158768865132e8 (patch)
treed9662ad9f0899dd184ab789dcc26f543aea7a89d
parent23c5831e2e040f7a044743a2e6e060426d579d7f (diff)
perf daemon: Allow only one daemon over base directory
Add 'lock' file under daemon base and flock it, so only one perf daemon can run on top of it. Each daemon tries to create and lock BASE/lock file, if it's successful we are sure we're the only daemon running over the BASE. Once daemon is finished, file descriptor to lock file is closed and lock is released. Example: # cat ~/.perfconfig [daemon] base=/opt/perfdata [session-cycles] run = -m 10M -e cycles --overwrite --switch-output -a [session-sched] run = -m 20M -e sched:* --overwrite --switch-output -a Starting the daemon: # perf daemon start And try once more: # perf daemon start failed: another perf daemon (pid 775594) owns /opt/perfdata will end up with an error, because there's already one running on top of /opt/perfdata. Committer notes: Provide lockf(F_TLOCK) when not available, i.e. transform: lockf(fd, F_TLOCK, 0); into: flock(fd, LOCK_EX | LOCK_NB); Which should be equivalent. Noticed when cross building to some odd Android NDK. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Alexei Budankov <abudankov@huawei.com> Cc: Ian Rogers <irogers@google.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Michael Petlan <mpetlan@redhat.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: https://lore.kernel.org/r/20210208200908.1019149-14-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/Documentation/perf-daemon.txt3
-rw-r--r--tools/perf/builtin-daemon.c75
2 files changed, 77 insertions, 1 deletions
diff --git a/tools/perf/Documentation/perf-daemon.txt b/tools/perf/Documentation/perf-daemon.txt
index 94d5e09a1e17..3c9e265858b2 100644
--- a/tools/perf/Documentation/perf-daemon.txt
+++ b/tools/perf/Documentation/perf-daemon.txt
@@ -49,7 +49,8 @@ OPTIONS
--base=<PATH>::
Base directory path. Each daemon instance is running on top
- of base directory.
+ of base directory. Only one instance of server can run on
+ top of one directory at the time.
All generic options are available also under commands.
diff --git a/tools/perf/builtin-daemon.c b/tools/perf/builtin-daemon.c
index 324ce43e8ab1..2890573540f7 100644
--- a/tools/perf/builtin-daemon.c
+++ b/tools/perf/builtin-daemon.c
@@ -2,11 +2,13 @@
#include <internal/lib.h>
#include <subcmd/parse-options.h>
#include <api/fd/array.h>
+#include <api/fs/fs.h>
#include <linux/zalloc.h>
#include <linux/string.h>
#include <linux/limits.h>
#include <linux/string.h>
#include <string.h>
+#include <sys/file.h>
#include <signal.h>
#include <stdlib.h>
#include <time.h>
@@ -570,12 +572,18 @@ static int cmd_session_list(struct daemon *daemon, union cmd *cmd, FILE *out)
/* output */
csv_sep, daemon->base, SESSION_OUTPUT);
+ fprintf(out, "%c%s/%s",
+ /* lock */
+ csv_sep, daemon->base, "lock");
+
fprintf(out, "\n");
} else {
fprintf(out, "[%d:daemon] base: %s\n", getpid(), daemon->base);
if (cmd->list.verbose) {
fprintf(out, " output: %s/%s\n",
daemon->base, SESSION_OUTPUT);
+ fprintf(out, " lock: %s/lock\n",
+ daemon->base);
}
}
@@ -906,6 +914,67 @@ static int setup_config(struct daemon *daemon)
return daemon->config_real ? 0 : -1;
}
+#ifndef F_TLOCK
+#define F_TLOCK 2
+
+#include <sys/file.h>
+
+static int lockf(int fd, int cmd, off_t len)
+{
+ if (cmd != F_TLOCK || len != 0)
+ return -1;
+
+ return flock(fd, LOCK_EX | LOCK_NB);
+}
+#endif // F_TLOCK
+
+/*
+ * Each daemon tries to create and lock BASE/lock file,
+ * if it's successful we are sure we're the only daemon
+ * running over the BASE.
+ *
+ * Once daemon is finished, file descriptor to lock file
+ * is closed and lock is released.
+ */
+static int check_lock(struct daemon *daemon)
+{
+ char path[PATH_MAX];
+ char buf[20];
+ int fd, pid;
+ ssize_t len;
+
+ scnprintf(path, sizeof(path), "%s/lock", daemon->base);
+
+ fd = open(path, O_RDWR|O_CREAT|O_CLOEXEC, 0640);
+ if (fd < 0)
+ return -1;
+
+ if (lockf(fd, F_TLOCK, 0) < 0) {
+ filename__read_int(path, &pid);
+ fprintf(stderr, "failed: another perf daemon (pid %d) owns %s\n",
+ pid, daemon->base);
+ close(fd);
+ return -1;
+ }
+
+ scnprintf(buf, sizeof(buf), "%d", getpid());
+ len = strlen(buf);
+
+ if (write(fd, buf, len) != len) {
+ perror("failed: write");
+ close(fd);
+ return -1;
+ }
+
+ if (ftruncate(fd, len)) {
+ perror("failed: ftruncate");
+ close(fd);
+ return -1;
+ }
+
+ return 0;
+}
+
static int go_background(struct daemon *daemon)
{
int pid, fd;
@@ -920,6 +989,9 @@ static int go_background(struct daemon *daemon)
if (setsid() < 0)
return -1;
+ if (check_lock(daemon))
+ return -1;
+
umask(0);
if (chdir(daemon->base)) {
@@ -995,6 +1067,9 @@ static int __cmd_start(struct daemon *daemon, struct option parent_options[],
if (setup_server_config(daemon))
return -1;
+ if (foreground && check_lock(daemon))
+ return -1;
+
if (!foreground) {
err = go_background(daemon);
if (err) {