Skip to content

Commit 8c98be6

Browse files
olsajiriacmel
authored andcommitted
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 <[email protected]> Cc: Alexander Shishkin <[email protected]> Cc: Alexei Budankov <[email protected]> Cc: Ian Rogers <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Mark Rutland <[email protected]> Cc: Michael Petlan <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Peter Zijlstra <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 23c5831 commit 8c98be6

File tree

2 files changed

+77
-1
lines changed

2 files changed

+77
-1
lines changed

tools/perf/Documentation/perf-daemon.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ OPTIONS
4949

5050
--base=<PATH>::
5151
Base directory path. Each daemon instance is running on top
52-
of base directory.
52+
of base directory. Only one instance of server can run on
53+
top of one directory at the time.
5354

5455
All generic options are available also under commands.
5556

tools/perf/builtin-daemon.c

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22
#include <internal/lib.h>
33
#include <subcmd/parse-options.h>
44
#include <api/fd/array.h>
5+
#include <api/fs/fs.h>
56
#include <linux/zalloc.h>
67
#include <linux/string.h>
78
#include <linux/limits.h>
89
#include <linux/string.h>
910
#include <string.h>
11+
#include <sys/file.h>
1012
#include <signal.h>
1113
#include <stdlib.h>
1214
#include <time.h>
@@ -570,12 +572,18 @@ static int cmd_session_list(struct daemon *daemon, union cmd *cmd, FILE *out)
570572
/* output */
571573
csv_sep, daemon->base, SESSION_OUTPUT);
572574

575+
fprintf(out, "%c%s/%s",
576+
/* lock */
577+
csv_sep, daemon->base, "lock");
578+
573579
fprintf(out, "\n");
574580
} else {
575581
fprintf(out, "[%d:daemon] base: %s\n", getpid(), daemon->base);
576582
if (cmd->list.verbose) {
577583
fprintf(out, " output: %s/%s\n",
578584
daemon->base, SESSION_OUTPUT);
585+
fprintf(out, " lock: %s/lock\n",
586+
daemon->base);
579587
}
580588
}
581589

@@ -906,6 +914,67 @@ static int setup_config(struct daemon *daemon)
906914
return daemon->config_real ? 0 : -1;
907915
}
908916

917+
#ifndef F_TLOCK
918+
#define F_TLOCK 2
919+
920+
#include <sys/file.h>
921+
922+
static int lockf(int fd, int cmd, off_t len)
923+
{
924+
if (cmd != F_TLOCK || len != 0)
925+
return -1;
926+
927+
return flock(fd, LOCK_EX | LOCK_NB);
928+
}
929+
#endif // F_TLOCK
930+
931+
/*
932+
* Each daemon tries to create and lock BASE/lock file,
933+
* if it's successful we are sure we're the only daemon
934+
* running over the BASE.
935+
*
936+
* Once daemon is finished, file descriptor to lock file
937+
* is closed and lock is released.
938+
*/
939+
static int check_lock(struct daemon *daemon)
940+
{
941+
char path[PATH_MAX];
942+
char buf[20];
943+
int fd, pid;
944+
ssize_t len;
945+
946+
scnprintf(path, sizeof(path), "%s/lock", daemon->base);
947+
948+
fd = open(path, O_RDWR|O_CREAT|O_CLOEXEC, 0640);
949+
if (fd < 0)
950+
return -1;
951+
952+
if (lockf(fd, F_TLOCK, 0) < 0) {
953+
filename__read_int(path, &pid);
954+
fprintf(stderr, "failed: another perf daemon (pid %d) owns %s\n",
955+
pid, daemon->base);
956+
close(fd);
957+
return -1;
958+
}
959+
960+
scnprintf(buf, sizeof(buf), "%d", getpid());
961+
len = strlen(buf);
962+
963+
if (write(fd, buf, len) != len) {
964+
perror("failed: write");
965+
close(fd);
966+
return -1;
967+
}
968+
969+
if (ftruncate(fd, len)) {
970+
perror("failed: ftruncate");
971+
close(fd);
972+
return -1;
973+
}
974+
975+
return 0;
976+
}
977+
909978
static int go_background(struct daemon *daemon)
910979
{
911980
int pid, fd;
@@ -920,6 +989,9 @@ static int go_background(struct daemon *daemon)
920989
if (setsid() < 0)
921990
return -1;
922991

992+
if (check_lock(daemon))
993+
return -1;
994+
923995
umask(0);
924996

925997
if (chdir(daemon->base)) {
@@ -995,6 +1067,9 @@ static int __cmd_start(struct daemon *daemon, struct option parent_options[],
9951067
if (setup_server_config(daemon))
9961068
return -1;
9971069

1070+
if (foreground && check_lock(daemon))
1071+
return -1;
1072+
9981073
if (!foreground) {
9991074
err = go_background(daemon);
10001075
if (err) {

0 commit comments

Comments
 (0)