Skip to content

Commit

Permalink
perf daemon: Allow only one daemon over base directory
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Jiri Olsa authored and Arnaldo Carvalho de Melo committed Feb 11, 2021
1 parent 23c5831 commit 8c98be6
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 1 deletion.
3 changes: 2 additions & 1 deletion tools/perf/Documentation/perf-daemon.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
75 changes: 75 additions & 0 deletions tools/perf/builtin-daemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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;
Expand All @@ -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)) {
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit 8c98be6

Please sign in to comment.