diff options
-rw-r--r-- | include/linux/perf_event.h | 3 | ||||
-rw-r--r-- | kernel/perf_event.c | 54 |
2 files changed, 29 insertions, 28 deletions
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 7098ebbb3b3a..7bd17f0488f8 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
@@ -806,6 +806,9 @@ struct perf_output_handle { | |||
806 | unsigned long head; | 806 | unsigned long head; |
807 | unsigned long offset; | 807 | unsigned long offset; |
808 | unsigned long wakeup; | 808 | unsigned long wakeup; |
809 | unsigned long size; | ||
810 | void *addr; | ||
811 | int page; | ||
809 | int nmi; | 812 | int nmi; |
810 | int sample; | 813 | int sample; |
811 | }; | 814 | }; |
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 1531e0b409a5..b67549a08626 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
@@ -2961,39 +2961,30 @@ again: | |||
2961 | void perf_output_copy(struct perf_output_handle *handle, | 2961 | void perf_output_copy(struct perf_output_handle *handle, |
2962 | const void *buf, unsigned int len) | 2962 | const void *buf, unsigned int len) |
2963 | { | 2963 | { |
2964 | unsigned int pages_mask; | 2964 | handle->offset += len; |
2965 | unsigned long offset; | ||
2966 | unsigned int size; | ||
2967 | void **pages; | ||
2968 | |||
2969 | offset = handle->offset; | ||
2970 | pages_mask = handle->data->nr_pages - 1; | ||
2971 | pages = handle->data->data_pages; | ||
2972 | |||
2973 | do { | ||
2974 | unsigned long page_offset; | ||
2975 | unsigned long page_size; | ||
2976 | int nr; | ||
2977 | |||
2978 | nr = (offset >> PAGE_SHIFT) & pages_mask; | ||
2979 | page_size = 1UL << (handle->data->data_order + PAGE_SHIFT); | ||
2980 | page_offset = offset & (page_size - 1); | ||
2981 | size = min_t(unsigned int, page_size - page_offset, len); | ||
2982 | |||
2983 | memcpy(pages[nr] + page_offset, buf, size); | ||
2984 | |||
2985 | len -= size; | ||
2986 | buf += size; | ||
2987 | offset += size; | ||
2988 | } while (len); | ||
2989 | |||
2990 | handle->offset = offset; | ||
2991 | 2965 | ||
2992 | /* | 2966 | /* |
2993 | * Check we didn't copy past our reservation window, taking the | 2967 | * Check we didn't copy past our reservation window, taking the |
2994 | * possible unsigned int wrap into account. | 2968 | * possible unsigned int wrap into account. |
2995 | */ | 2969 | */ |
2996 | WARN_ON_ONCE(((long)(handle->head - handle->offset)) < 0); | 2970 | if (WARN_ON_ONCE(((long)(handle->head - handle->offset)) < 0)) |
2971 | return; | ||
2972 | |||
2973 | do { | ||
2974 | unsigned long size = min(handle->size, len); | ||
2975 | |||
2976 | memcpy(handle->addr, buf, size); | ||
2977 | |||
2978 | len -= size; | ||
2979 | handle->addr += size; | ||
2980 | handle->size -= size; | ||
2981 | if (!handle->size) { | ||
2982 | handle->page++; | ||
2983 | handle->page &= handle->data->nr_pages - 1; | ||
2984 | handle->addr = handle->data->data_pages[handle->page]; | ||
2985 | handle->size = PAGE_SIZE << handle->data->data_order; | ||
2986 | } | ||
2987 | } while (len); | ||
2997 | } | 2988 | } |
2998 | 2989 | ||
2999 | int perf_output_begin(struct perf_output_handle *handle, | 2990 | int perf_output_begin(struct perf_output_handle *handle, |
@@ -3059,6 +3050,13 @@ int perf_output_begin(struct perf_output_handle *handle, | |||
3059 | if (head - local_read(&data->wakeup) > data->watermark) | 3050 | if (head - local_read(&data->wakeup) > data->watermark) |
3060 | local_add(data->watermark, &data->wakeup); | 3051 | local_add(data->watermark, &data->wakeup); |
3061 | 3052 | ||
3053 | handle->page = handle->offset >> (PAGE_SHIFT + data->data_order); | ||
3054 | handle->page &= data->nr_pages - 1; | ||
3055 | handle->size = handle->offset & ((PAGE_SIZE << data->data_order) - 1); | ||
3056 | handle->addr = data->data_pages[handle->page]; | ||
3057 | handle->addr += handle->size; | ||
3058 | handle->size = (PAGE_SIZE << data->data_order) - handle->size; | ||
3059 | |||
3062 | if (have_lost) { | 3060 | if (have_lost) { |
3063 | lost_event.header.type = PERF_RECORD_LOST; | 3061 | lost_event.header.type = PERF_RECORD_LOST; |
3064 | lost_event.header.misc = 0; | 3062 | lost_event.header.misc = 0; |