diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-11-20 16:19:56 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-11-21 08:11:40 -0500 |
commit | 6f10581aeaa5543a3b7a8c7a87a064375ec357f8 (patch) | |
tree | 57b94ae6f96d8a2e12bd8537a54b75d652636e00 /kernel | |
parent | 59ed446f792cc07d37b1536b9c4664d14e25e425 (diff) |
perf: Fix locking for PERF_FORMAT_GROUP
We should hold event->child_mutex when iterating the inherited
counters, we should hold ctx->mutex when iterating siblings.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <20091120212509.251030114@chello.nl>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/perf_event.c | 20 |
1 files changed, 13 insertions, 7 deletions
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 80f40da9a01e..3ede0981f4ac 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
@@ -1782,6 +1782,7 @@ u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running) | |||
1782 | *enabled = 0; | 1782 | *enabled = 0; |
1783 | *running = 0; | 1783 | *running = 0; |
1784 | 1784 | ||
1785 | mutex_lock(&event->child_mutex); | ||
1785 | total += perf_event_read(event); | 1786 | total += perf_event_read(event); |
1786 | *enabled += event->total_time_enabled + | 1787 | *enabled += event->total_time_enabled + |
1787 | atomic64_read(&event->child_total_time_enabled); | 1788 | atomic64_read(&event->child_total_time_enabled); |
@@ -1793,6 +1794,7 @@ u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running) | |||
1793 | *enabled += child->total_time_enabled; | 1794 | *enabled += child->total_time_enabled; |
1794 | *running += child->total_time_running; | 1795 | *running += child->total_time_running; |
1795 | } | 1796 | } |
1797 | mutex_unlock(&event->child_mutex); | ||
1796 | 1798 | ||
1797 | return total; | 1799 | return total; |
1798 | } | 1800 | } |
@@ -1802,10 +1804,12 @@ static int perf_event_read_group(struct perf_event *event, | |||
1802 | u64 read_format, char __user *buf) | 1804 | u64 read_format, char __user *buf) |
1803 | { | 1805 | { |
1804 | struct perf_event *leader = event->group_leader, *sub; | 1806 | struct perf_event *leader = event->group_leader, *sub; |
1805 | int n = 0, size = 0, ret = 0; | 1807 | int n = 0, size = 0, ret = -EFAULT; |
1808 | struct perf_event_context *ctx = leader->ctx; | ||
1806 | u64 values[5]; | 1809 | u64 values[5]; |
1807 | u64 count, enabled, running; | 1810 | u64 count, enabled, running; |
1808 | 1811 | ||
1812 | mutex_lock(&ctx->mutex); | ||
1809 | count = perf_event_read_value(leader, &enabled, &running); | 1813 | count = perf_event_read_value(leader, &enabled, &running); |
1810 | 1814 | ||
1811 | values[n++] = 1 + leader->nr_siblings; | 1815 | values[n++] = 1 + leader->nr_siblings; |
@@ -1820,9 +1824,9 @@ static int perf_event_read_group(struct perf_event *event, | |||
1820 | size = n * sizeof(u64); | 1824 | size = n * sizeof(u64); |
1821 | 1825 | ||
1822 | if (copy_to_user(buf, values, size)) | 1826 | if (copy_to_user(buf, values, size)) |
1823 | return -EFAULT; | 1827 | goto unlock; |
1824 | 1828 | ||
1825 | ret += size; | 1829 | ret = size; |
1826 | 1830 | ||
1827 | list_for_each_entry(sub, &leader->sibling_list, group_entry) { | 1831 | list_for_each_entry(sub, &leader->sibling_list, group_entry) { |
1828 | n = 0; | 1832 | n = 0; |
@@ -1833,11 +1837,15 @@ static int perf_event_read_group(struct perf_event *event, | |||
1833 | 1837 | ||
1834 | size = n * sizeof(u64); | 1838 | size = n * sizeof(u64); |
1835 | 1839 | ||
1836 | if (copy_to_user(buf + size, values, size)) | 1840 | if (copy_to_user(buf + size, values, size)) { |
1837 | return -EFAULT; | 1841 | ret = -EFAULT; |
1842 | goto unlock; | ||
1843 | } | ||
1838 | 1844 | ||
1839 | ret += size; | 1845 | ret += size; |
1840 | } | 1846 | } |
1847 | unlock: | ||
1848 | mutex_unlock(&ctx->mutex); | ||
1841 | 1849 | ||
1842 | return ret; | 1850 | return ret; |
1843 | } | 1851 | } |
@@ -1884,12 +1892,10 @@ perf_read_hw(struct perf_event *event, char __user *buf, size_t count) | |||
1884 | return -ENOSPC; | 1892 | return -ENOSPC; |
1885 | 1893 | ||
1886 | WARN_ON_ONCE(event->ctx->parent_ctx); | 1894 | WARN_ON_ONCE(event->ctx->parent_ctx); |
1887 | mutex_lock(&event->child_mutex); | ||
1888 | if (read_format & PERF_FORMAT_GROUP) | 1895 | if (read_format & PERF_FORMAT_GROUP) |
1889 | ret = perf_event_read_group(event, read_format, buf); | 1896 | ret = perf_event_read_group(event, read_format, buf); |
1890 | else | 1897 | else |
1891 | ret = perf_event_read_one(event, read_format, buf); | 1898 | ret = perf_event_read_one(event, read_format, buf); |
1892 | mutex_unlock(&event->child_mutex); | ||
1893 | 1899 | ||
1894 | return ret; | 1900 | return ret; |
1895 | } | 1901 | } |