diff options
-rw-r--r-- | kernel/perf_event.c | 52 |
1 files changed, 21 insertions, 31 deletions
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 68fbf4ff6888..9a18ff28ea5b 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
@@ -1784,30 +1784,15 @@ u64 perf_event_read_value(struct perf_event *event) | |||
1784 | } | 1784 | } |
1785 | EXPORT_SYMBOL_GPL(perf_event_read_value); | 1785 | EXPORT_SYMBOL_GPL(perf_event_read_value); |
1786 | 1786 | ||
1787 | static int perf_event_read_entry(struct perf_event *event, | ||
1788 | u64 read_format, char __user *buf) | ||
1789 | { | ||
1790 | int n = 0, count = 0; | ||
1791 | u64 values[2]; | ||
1792 | |||
1793 | values[n++] = perf_event_read_value(event); | ||
1794 | if (read_format & PERF_FORMAT_ID) | ||
1795 | values[n++] = primary_event_id(event); | ||
1796 | |||
1797 | count = n * sizeof(u64); | ||
1798 | |||
1799 | if (copy_to_user(buf, values, count)) | ||
1800 | return -EFAULT; | ||
1801 | |||
1802 | return count; | ||
1803 | } | ||
1804 | |||
1805 | static int perf_event_read_group(struct perf_event *event, | 1787 | static int perf_event_read_group(struct perf_event *event, |
1806 | u64 read_format, char __user *buf) | 1788 | u64 read_format, char __user *buf) |
1807 | { | 1789 | { |
1808 | struct perf_event *leader = event->group_leader, *sub; | 1790 | struct perf_event *leader = event->group_leader, *sub; |
1809 | int n = 0, size = 0, err = -EFAULT; | 1791 | int n = 0, size = 0, ret = 0; |
1810 | u64 values[3]; | 1792 | u64 values[5]; |
1793 | u64 count; | ||
1794 | |||
1795 | count = perf_event_read_value(leader); | ||
1811 | 1796 | ||
1812 | values[n++] = 1 + leader->nr_siblings; | 1797 | values[n++] = 1 + leader->nr_siblings; |
1813 | if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { | 1798 | if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { |
@@ -1818,28 +1803,33 @@ static int perf_event_read_group(struct perf_event *event, | |||
1818 | values[n++] = leader->total_time_running + | 1803 | values[n++] = leader->total_time_running + |
1819 | atomic64_read(&leader->child_total_time_running); | 1804 | atomic64_read(&leader->child_total_time_running); |
1820 | } | 1805 | } |
1806 | values[n++] = count; | ||
1807 | if (read_format & PERF_FORMAT_ID) | ||
1808 | values[n++] = primary_event_id(leader); | ||
1821 | 1809 | ||
1822 | size = n * sizeof(u64); | 1810 | size = n * sizeof(u64); |
1823 | 1811 | ||
1824 | if (copy_to_user(buf, values, size)) | 1812 | if (copy_to_user(buf, values, size)) |
1825 | return -EFAULT; | 1813 | return -EFAULT; |
1826 | 1814 | ||
1827 | err = perf_event_read_entry(leader, read_format, buf + size); | 1815 | ret += size; |
1828 | if (err < 0) | ||
1829 | return err; | ||
1830 | |||
1831 | size += err; | ||
1832 | 1816 | ||
1833 | list_for_each_entry(sub, &leader->sibling_list, group_entry) { | 1817 | list_for_each_entry(sub, &leader->sibling_list, group_entry) { |
1834 | err = perf_event_read_entry(sub, read_format, | 1818 | n = 0; |
1835 | buf + size); | ||
1836 | if (err < 0) | ||
1837 | return err; | ||
1838 | 1819 | ||
1839 | size += err; | 1820 | values[n++] = perf_event_read_value(sub); |
1821 | if (read_format & PERF_FORMAT_ID) | ||
1822 | values[n++] = primary_event_id(sub); | ||
1823 | |||
1824 | size = n * sizeof(u64); | ||
1825 | |||
1826 | if (copy_to_user(buf + size, values, size)) | ||
1827 | return -EFAULT; | ||
1828 | |||
1829 | ret += size; | ||
1840 | } | 1830 | } |
1841 | 1831 | ||
1842 | return size; | 1832 | return ret; |
1843 | } | 1833 | } |
1844 | 1834 | ||
1845 | static int perf_event_read_one(struct perf_event *event, | 1835 | static int perf_event_read_one(struct perf_event *event, |