Skip to content

Commit 239e551

Browse files
committed
trace-cmd: Fix the looping to clear triggers and filters
The resetting of filters and triggers did a loop on each trigger and filter till it was cleared. The point being, it removed one trigger or filter at a time. This could cause an infinite loop due to some triggers requiring an "ordering" of removal. When histograms are used with synthetic events, one histogram will be attached to another histogram, and the remove of the first histogram will fail to be removed if the second histogram is still using it. As the code would just keep iterating on the same trigger file, and that file would never be cleared due to the histogram dependency, it went into an infinite loop. Instead of a loop that would read the file and try to remove the first trigger, read the entire file at once, then try removing the each of the the triggers that was read one at a time. After all have been attempted to be removed, re-read the file. If the file still has data, take note, and continue to the other files. After processing all the files, check to see how many files still had data, then loop through all the files again, doing the same thing, but only do it the number of times that there was content in the files, as that should remove all the triggers no matter what the dependency is. We could optimize this by only reseting the files that still had data in it, but that would require making full copy of the event_iter then running on that. As this doesn't happen much, doing a full scan again shoudn't be too much of an issue. But if it becomes one, then the optimization can still happen later. Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
1 parent 59b40fd commit 239e551

1 file changed

Lines changed: 115 additions & 84 deletions

File tree

tracecmd/trace-record.c

Lines changed: 115 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1899,44 +1899,6 @@ enum {
18991899
STATE_COPY,
19001900
};
19011901

1902-
static int find_trigger(const char *file, char *buf, int size, int fields)
1903-
{
1904-
FILE *fp;
1905-
int state = STATE_NEWLINE;
1906-
int ch;
1907-
int len = 0;
1908-
1909-
fp = fopen(file, "r");
1910-
if (!fp)
1911-
return 0;
1912-
1913-
while ((ch = fgetc(fp)) != EOF) {
1914-
if (ch == '\n') {
1915-
if (state == STATE_COPY)
1916-
break;
1917-
state = STATE_NEWLINE;
1918-
continue;
1919-
}
1920-
if (state == STATE_SKIP)
1921-
continue;
1922-
if (state == STATE_NEWLINE && ch == '#') {
1923-
state = STATE_SKIP;
1924-
continue;
1925-
}
1926-
if (state == STATE_COPY && ch == ':' && --fields < 1)
1927-
break;
1928-
1929-
state = STATE_COPY;
1930-
buf[len++] = ch;
1931-
if (len == size - 1)
1932-
break;
1933-
}
1934-
buf[len] = 0;
1935-
fclose(fp);
1936-
1937-
return len;
1938-
}
1939-
19401902
static char *read_file(const char *file)
19411903
{
19421904
char stbuf[BUFSIZ];
@@ -2056,34 +2018,63 @@ static void write_trigger(const char *file, const char *trigger)
20562018
show_error(file, "trigger");
20572019
}
20582020

2059-
static void write_func_filter(const char *file, const char *trigger)
2060-
{
2061-
if (write_file(file, trigger) < 0)
2062-
show_error(file, "function filter");
2063-
}
2064-
2065-
static void clear_trigger(const char *file)
2021+
static int clear_trigger(const char *file)
20662022
{
20672023
char trigger[BUFSIZ];
2024+
char *save = NULL;
2025+
char *line;
2026+
char *buf;
20682027
int len;
2028+
int ret;
2029+
2030+
buf = read_file(file);
2031+
if (!buf) {
2032+
perror(file);
2033+
return 0;
2034+
}
20692035

20702036
trigger[0] = '!';
20712037

2038+
for (line = strtok_r(buf, "\n", &save); line; line = strtok_r(NULL, "\n", &save)) {
2039+
if (line[0] == '#')
2040+
continue;
2041+
len = strlen(line);
2042+
if (len > BUFSIZ - 2)
2043+
len = BUFSIZ - 2;
2044+
strncpy(trigger + 1, line, len);
2045+
trigger[len + 1] = '\0';
2046+
/* We don't want any filters or extra on the line */
2047+
strtok(trigger, " ");
2048+
write_file(file, trigger);
2049+
}
2050+
2051+
free(buf);
2052+
20722053
/*
2073-
* To delete a trigger, we need to write a '!trigger'
2074-
* to the file for each trigger.
2054+
* Some triggers have an order in removing them.
2055+
* They will not be removed if done in the wrong order.
20752056
*/
2076-
do {
2077-
len = find_trigger(file, trigger+1, BUFSIZ-1, 3);
2078-
if (len)
2079-
write_trigger(file, trigger);
2080-
} while (len);
2057+
buf = read_file(file);
2058+
if (!buf)
2059+
return 0;
2060+
2061+
ret = 0;
2062+
for (line = strtok(buf, "\n"); line; line = strtok(NULL, "\n")) {
2063+
if (line[0] == '#')
2064+
continue;
2065+
ret = 1;
2066+
break;
2067+
}
2068+
free(buf);
2069+
return ret;
20812070
}
20822071

20832072
static void clear_func_filter(const char *file)
20842073
{
2085-
char trigger[BUFSIZ];
2074+
char filter[BUFSIZ];
20862075
struct stat st;
2076+
char *line;
2077+
char *buf;
20872078
char *p;
20882079
int len;
20892080
int ret;
@@ -2100,33 +2091,44 @@ static void clear_func_filter(const char *file)
21002091
die("opening to '%s'", file);
21012092
close(fd);
21022093

2103-
/* Now remove triggers */
2104-
trigger[0] = '!';
2094+
buf = read_file(file);
2095+
if (!buf) {
2096+
perror(file);
2097+
return;
2098+
}
2099+
2100+
/* Now remove filters */
2101+
filter[0] = '!';
21052102

21062103
/*
2107-
* To delete a trigger, we need to write a '!trigger'
2108-
* to the file for each trigger.
2104+
* To delete a filter, we need to write a '!filter'
2105+
* to the file for each filter.
21092106
*/
2110-
do {
2111-
len = find_trigger(file, trigger+1, BUFSIZ-1, 3);
2112-
if (len) {
2113-
/*
2114-
* To remove "unlimited" triggers, we must remove
2115-
* the ":unlimited" from what we write.
2116-
*/
2117-
if ((p = strstr(trigger, ":unlimited"))) {
2118-
*p = '\0';
2119-
len = p - trigger;
2120-
}
2121-
/*
2122-
* The write to this file expects white space
2123-
* at the end :-p
2124-
*/
2125-
trigger[len] = '\n';
2126-
trigger[len+1] = '\0';
2127-
write_func_filter(file, trigger);
2107+
for (line = strtok(buf, "\n"); line; line = strtok(NULL, "\n")) {
2108+
if (line[0] == '#')
2109+
continue;
2110+
len = strlen(line);
2111+
if (len > BUFSIZ - 2)
2112+
len = BUFSIZ - 2;
2113+
2114+
strncpy(filter + 1, line, len);
2115+
filter[len + 1] = '\0';
2116+
/*
2117+
* To remove "unlimited" filters, we must remove
2118+
* the ":unlimited" from what we write.
2119+
*/
2120+
if ((p = strstr(filter, ":unlimited"))) {
2121+
*p = '\0';
2122+
len = p - filter;
21282123
}
2129-
} while (len > 0);
2124+
/*
2125+
* The write to this file expects white space
2126+
* at the end :-p
2127+
*/
2128+
filter[len] = '\n';
2129+
filter[len+1] = '\0';
2130+
write_file(file, filter);
2131+
}
21302132
}
21312133

21322134
static void update_reset_triggers(void)
@@ -4435,8 +4437,8 @@ void set_buffer_size(void)
44354437
set_buffer_size_instance(instance);
44364438
}
44374439

4438-
static void
4439-
process_event_trigger(char *path, struct event_iter *iter, enum event_process *processed)
4440+
static int
4441+
process_event_trigger(char *path, struct event_iter *iter)
44404442
{
44414443
const char *system = iter->system_dent->d_name;
44424444
const char *event = iter->event_dent->d_name;
@@ -4459,27 +4461,28 @@ process_event_trigger(char *path, struct event_iter *iter, enum event_process *p
44594461
if (ret < 0)
44604462
goto out;
44614463

4462-
clear_trigger(trigger);
4464+
ret = clear_trigger(trigger);
44634465
out:
44644466
free(trigger);
44654467
free(file);
4468+
return ret;
44664469
}
44674470

44684471
static void clear_instance_triggers(struct buffer_instance *instance)
44694472
{
4473+
enum event_iter_type type;
44704474
struct event_iter *iter;
4471-
char *path;
44724475
char *system;
4473-
enum event_iter_type type;
4474-
enum event_process processed = PROCESSED_NONE;
4476+
char *path;
4477+
int retry = 0;
4478+
int ret;
44754479

44764480
path = tracefs_instance_get_file(instance->tracefs, "events");
44774481
if (!path)
44784482
die("malloc");
44794483

44804484
iter = trace_event_iter_alloc(path);
44814485

4482-
processed = PROCESSED_NONE;
44834486
system = NULL;
44844487
while ((type = trace_event_iter_next(iter, path, system))) {
44854488

@@ -4488,11 +4491,39 @@ static void clear_instance_triggers(struct buffer_instance *instance)
44884491
continue;
44894492
}
44904493

4491-
process_event_trigger(path, iter, &processed);
4494+
ret = process_event_trigger(path, iter);
4495+
if (ret > 0)
4496+
retry++;
44924497
}
44934498

44944499
trace_event_iter_free(iter);
44954500

4501+
if (retry) {
4502+
int i;
4503+
4504+
/* Order matters for some triggers */
4505+
for (i = 0; i < retry; i++) {
4506+
int tries = 0;
4507+
4508+
iter = trace_event_iter_alloc(path);
4509+
system = NULL;
4510+
while ((type = trace_event_iter_next(iter, path, system))) {
4511+
4512+
if (type == EVENT_ITER_SYSTEM) {
4513+
system = iter->system_dent->d_name;
4514+
continue;
4515+
}
4516+
4517+
ret = process_event_trigger(path, iter);
4518+
if (ret > 0)
4519+
tries++;
4520+
}
4521+
trace_event_iter_free(iter);
4522+
if (!tries)
4523+
break;
4524+
}
4525+
}
4526+
44964527
tracefs_put_tracing_file(path);
44974528
}
44984529

0 commit comments

Comments
 (0)