aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2009-11-20 16:19:56 -0500
committerIngo Molnar <mingo@elte.hu>2009-11-21 08:11:40 -0500
commit6f10581aeaa5543a3b7a8c7a87a064375ec357f8 (patch)
tree57b94ae6f96d8a2e12bd8537a54b75d652636e00 /kernel
parent59ed446f792cc07d37b1536b9c4664d14e25e425 (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.c20
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 }
1847unlock:
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}