Skip to content

Commit de6a908

Browse files
captain5050acmel
authored andcommitted
perf comm: Fix comm_str__put() for reference count checking
Searching for the entry in the array needs to avoid the intermediate pointer with reference count checking. Refactor the array removal to binary search for the entry. Change the array to hold an entry with a reference count (so the intermediate pointer can work) and remove from the array when the reference count on a comm_str falls to 1. Fixes: 13ca628 ("perf comm: Add reference count checking to 'struct comm_str'") Signed-off-by: Ian Rogers <[email protected]> Cc: Adrian Hunter <[email protected]> Cc: Alexander Shishkin <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: James Clark <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Kan Liang <[email protected]> Cc: Leo Yan <[email protected]> Cc: Mark Rutland <[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 90f01af commit de6a908

File tree

1 file changed

+31
-14
lines changed

1 file changed

+31
-14
lines changed

tools/perf/util/comm.c

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ static struct comm_strs {
1919
int capacity;
2020
} _comm_strs;
2121

22+
static void comm_strs__remove_if_last(struct comm_str *cs);
23+
2224
static void comm_strs__init(void)
2325
{
2426
init_rwsem(&_comm_strs.lock);
@@ -58,22 +60,15 @@ static struct comm_str *comm_str__get(struct comm_str *cs)
5860

5961
static void comm_str__put(struct comm_str *cs)
6062
{
61-
if (cs && refcount_dec_and_test(comm_str__refcnt(cs))) {
62-
struct comm_strs *comm_strs = comm_strs__get();
63-
int i;
63+
if (!cs)
64+
return;
6465

65-
down_write(&comm_strs->lock);
66-
for (i = 0; i < comm_strs->num_strs; i++) {
67-
if (comm_strs->strs[i] == cs)
68-
break;
69-
}
70-
for (; i < comm_strs->num_strs - 1; i++)
71-
comm_strs->strs[i] = comm_strs->strs[i + 1];
72-
73-
comm_strs->num_strs--;
74-
up_write(&comm_strs->lock);
66+
if (refcount_dec_and_test(comm_str__refcnt(cs))) {
7567
RC_CHK_FREE(cs);
7668
} else {
69+
if (refcount_read(comm_str__refcnt(cs)) == 1)
70+
comm_strs__remove_if_last(cs);
71+
7772
RC_CHK_PUT(cs);
7873
}
7974
}
@@ -107,6 +102,28 @@ static int comm_str__search(const void *_key, const void *_member)
107102
return strcmp(key, comm_str__str(member));
108103
}
109104

105+
static void comm_strs__remove_if_last(struct comm_str *cs)
106+
{
107+
struct comm_strs *comm_strs = comm_strs__get();
108+
109+
down_write(&comm_strs->lock);
110+
/*
111+
* Are there only references from the array, if so remove the array
112+
* reference under the write lock so that we don't race with findnew.
113+
*/
114+
if (refcount_read(comm_str__refcnt(cs)) == 1) {
115+
struct comm_str **entry;
116+
117+
entry = bsearch(comm_str__str(cs), comm_strs->strs, comm_strs->num_strs,
118+
sizeof(struct comm_str *), comm_str__search);
119+
comm_str__put(*entry);
120+
for (int i = entry - comm_strs->strs; i < comm_strs->num_strs - 1; i++)
121+
comm_strs->strs[i] = comm_strs->strs[i + 1];
122+
comm_strs->num_strs--;
123+
}
124+
up_write(&comm_strs->lock);
125+
}
126+
110127
static struct comm_str *__comm_strs__find(struct comm_strs *comm_strs, const char *str)
111128
{
112129
struct comm_str **result;
@@ -158,7 +175,7 @@ static struct comm_str *comm_strs__findnew(const char *str)
158175
}
159176
}
160177
up_write(&comm_strs->lock);
161-
return result;
178+
return comm_str__get(result);
162179
}
163180

164181
struct comm *comm__new(const char *str, u64 timestamp, bool exec)

0 commit comments

Comments
 (0)