The dso cache is accessed during dwarf callchain unwind and it might
be processed concurrently when multi-thread report is enabled.
Protect it under dso->lock.

Signed-off-by: Namhyung Kim <namhy...@kernel.org>
---
 tools/perf/util/dso.c | 41 ++++++++++++++++++++++++++++++++---------
 1 file changed, 32 insertions(+), 9 deletions(-)

diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 3da75816b8f8..9555b1772fb5 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -443,10 +443,12 @@ bool dso__data_status_seen(struct dso *dso, enum 
dso_data_status_seen by)
 }
 
 static void
-dso_cache__free(struct rb_root *root)
+dso_cache__free(struct dso *dso)
 {
+       struct rb_root *root = &dso->data.cache;
        struct rb_node *next = rb_first(root);
 
+       pthread_mutex_lock(&dso->lock);
        while (next) {
                struct dso_cache *cache;
 
@@ -455,14 +457,17 @@ dso_cache__free(struct rb_root *root)
                rb_erase(&cache->rb_node, root);
                free(cache);
        }
+       pthread_mutex_unlock(&dso->lock);
 }
 
-static struct dso_cache *dso_cache__find(const struct rb_root *root, u64 
offset)
+static struct dso_cache *dso_cache__find(struct dso *dso, u64 offset)
 {
+       const struct rb_root *root = &dso->data.cache;
        struct rb_node * const *p = &root->rb_node;
        const struct rb_node *parent = NULL;
        struct dso_cache *cache;
 
+       pthread_mutex_lock(&dso->lock);
        while (*p != NULL) {
                u64 end;
 
@@ -475,19 +480,24 @@ static struct dso_cache *dso_cache__find(const struct 
rb_root *root, u64 offset)
                else if (offset >= end)
                        p = &(*p)->rb_right;
                else
-                       return cache;
+                       goto out;
        }
-       return NULL;
+       cache = NULL;
+out:
+       pthread_mutex_unlock(&dso->lock);
+       return cache;
 }
 
-static void
-dso_cache__insert(struct rb_root *root, struct dso_cache *new)
+static struct dso_cache *
+dso_cache__insert(struct dso *dso, struct dso_cache *new)
 {
+       struct rb_root *root = &dso->data.cache;
        struct rb_node **p = &root->rb_node;
        struct rb_node *parent = NULL;
        struct dso_cache *cache;
        u64 offset = new->offset;
 
+       pthread_mutex_lock(&dso->lock);
        while (*p != NULL) {
                u64 end;
 
@@ -499,10 +509,17 @@ dso_cache__insert(struct rb_root *root, struct dso_cache 
*new)
                        p = &(*p)->rb_left;
                else if (offset >= end)
                        p = &(*p)->rb_right;
+               else
+                       goto out;
        }
 
        rb_link_node(&new->rb_node, parent, p);
        rb_insert_color(&new->rb_node, root);
+
+       cache = NULL;
+out:
+       pthread_mutex_unlock(&dso->lock);
+       return cache;
 }
 
 static ssize_t
@@ -520,6 +537,7 @@ static ssize_t
 dso_cache__read(struct dso *dso, u64 offset, u8 *data, ssize_t size)
 {
        struct dso_cache *cache;
+       struct dso_cache *old;
        ssize_t ret;
 
        do {
@@ -543,7 +561,12 @@ dso_cache__read(struct dso *dso, u64 offset, u8 *data, 
ssize_t size)
 
                cache->offset = cache_offset;
                cache->size   = ret;
-               dso_cache__insert(&dso->data.cache, cache);
+               old = dso_cache__insert(dso, cache);
+               if (old) {
+                       /* we lose the race */
+                       free(cache);
+                       cache = old;
+               }
 
                ret = dso_cache__memcpy(cache, offset, data, size);
 
@@ -560,7 +583,7 @@ static ssize_t dso_cache_read(struct dso *dso, u64 offset,
 {
        struct dso_cache *cache;
 
-       cache = dso_cache__find(&dso->data.cache, offset);
+       cache = dso_cache__find(dso, offset);
        if (cache)
                return dso_cache__memcpy(cache, offset, data, size);
        else
@@ -915,7 +938,7 @@ void dso__delete(struct dso *dso)
        }
 
        dso__data_close(dso);
-       dso_cache__free(&dso->data.cache);
+       dso_cache__free(dso);
        dso__free_a2l(dso);
        zfree(&dso->symsrc_filename);
        pthread_mutex_destroy(&dso->lock);
-- 
2.1.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to