diff options
Diffstat (limited to 'kernel/perf_event.c')
-rw-r--r-- | kernel/perf_event.c | 282 |
1 files changed, 195 insertions, 87 deletions
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 0f86feb6db0c..9d0b5c665883 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/percpu.h> | 20 | #include <linux/percpu.h> |
21 | #include <linux/ptrace.h> | 21 | #include <linux/ptrace.h> |
22 | #include <linux/vmstat.h> | 22 | #include <linux/vmstat.h> |
23 | #include <linux/vmalloc.h> | ||
23 | #include <linux/hardirq.h> | 24 | #include <linux/hardirq.h> |
24 | #include <linux/rculist.h> | 25 | #include <linux/rculist.h> |
25 | #include <linux/uaccess.h> | 26 | #include <linux/uaccess.h> |
@@ -1030,14 +1031,10 @@ void __perf_event_sched_out(struct perf_event_context *ctx, | |||
1030 | update_context_time(ctx); | 1031 | update_context_time(ctx); |
1031 | 1032 | ||
1032 | perf_disable(); | 1033 | perf_disable(); |
1033 | if (ctx->nr_active) { | 1034 | if (ctx->nr_active) |
1034 | list_for_each_entry(event, &ctx->group_list, group_entry) { | 1035 | list_for_each_entry(event, &ctx->group_list, group_entry) |
1035 | if (event != event->group_leader) | 1036 | group_sched_out(event, cpuctx, ctx); |
1036 | event_sched_out(event, cpuctx, ctx); | 1037 | |
1037 | else | ||
1038 | group_sched_out(event, cpuctx, ctx); | ||
1039 | } | ||
1040 | } | ||
1041 | perf_enable(); | 1038 | perf_enable(); |
1042 | out: | 1039 | out: |
1043 | spin_unlock(&ctx->lock); | 1040 | spin_unlock(&ctx->lock); |
@@ -1258,12 +1255,8 @@ __perf_event_sched_in(struct perf_event_context *ctx, | |||
1258 | if (event->cpu != -1 && event->cpu != cpu) | 1255 | if (event->cpu != -1 && event->cpu != cpu) |
1259 | continue; | 1256 | continue; |
1260 | 1257 | ||
1261 | if (event != event->group_leader) | 1258 | if (group_can_go_on(event, cpuctx, 1)) |
1262 | event_sched_in(event, cpuctx, ctx, cpu); | 1259 | group_sched_in(event, cpuctx, ctx, cpu); |
1263 | else { | ||
1264 | if (group_can_go_on(event, cpuctx, 1)) | ||
1265 | group_sched_in(event, cpuctx, ctx, cpu); | ||
1266 | } | ||
1267 | 1260 | ||
1268 | /* | 1261 | /* |
1269 | * If this pinned group hasn't been scheduled, | 1262 | * If this pinned group hasn't been scheduled, |
@@ -1291,15 +1284,9 @@ __perf_event_sched_in(struct perf_event_context *ctx, | |||
1291 | if (event->cpu != -1 && event->cpu != cpu) | 1284 | if (event->cpu != -1 && event->cpu != cpu) |
1292 | continue; | 1285 | continue; |
1293 | 1286 | ||
1294 | if (event != event->group_leader) { | 1287 | if (group_can_go_on(event, cpuctx, can_add_hw)) |
1295 | if (event_sched_in(event, cpuctx, ctx, cpu)) | 1288 | if (group_sched_in(event, cpuctx, ctx, cpu)) |
1296 | can_add_hw = 0; | 1289 | can_add_hw = 0; |
1297 | } else { | ||
1298 | if (group_can_go_on(event, cpuctx, can_add_hw)) { | ||
1299 | if (group_sched_in(event, cpuctx, ctx, cpu)) | ||
1300 | can_add_hw = 0; | ||
1301 | } | ||
1302 | } | ||
1303 | } | 1290 | } |
1304 | perf_enable(); | 1291 | perf_enable(); |
1305 | out: | 1292 | out: |
@@ -2105,49 +2092,31 @@ unlock: | |||
2105 | rcu_read_unlock(); | 2092 | rcu_read_unlock(); |
2106 | } | 2093 | } |
2107 | 2094 | ||
2108 | static int perf_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | 2095 | static unsigned long perf_data_size(struct perf_mmap_data *data) |
2109 | { | 2096 | { |
2110 | struct perf_event *event = vma->vm_file->private_data; | 2097 | return data->nr_pages << (PAGE_SHIFT + data->data_order); |
2111 | struct perf_mmap_data *data; | 2098 | } |
2112 | int ret = VM_FAULT_SIGBUS; | ||
2113 | |||
2114 | if (vmf->flags & FAULT_FLAG_MKWRITE) { | ||
2115 | if (vmf->pgoff == 0) | ||
2116 | ret = 0; | ||
2117 | return ret; | ||
2118 | } | ||
2119 | |||
2120 | rcu_read_lock(); | ||
2121 | data = rcu_dereference(event->data); | ||
2122 | if (!data) | ||
2123 | goto unlock; | ||
2124 | |||
2125 | if (vmf->pgoff == 0) { | ||
2126 | vmf->page = virt_to_page(data->user_page); | ||
2127 | } else { | ||
2128 | int nr = vmf->pgoff - 1; | ||
2129 | |||
2130 | if ((unsigned)nr > data->nr_pages) | ||
2131 | goto unlock; | ||
2132 | 2099 | ||
2133 | if (vmf->flags & FAULT_FLAG_WRITE) | 2100 | #ifndef CONFIG_PERF_USE_VMALLOC |
2134 | goto unlock; | ||
2135 | 2101 | ||
2136 | vmf->page = virt_to_page(data->data_pages[nr]); | 2102 | /* |
2137 | } | 2103 | * Back perf_mmap() with regular GFP_KERNEL-0 pages. |
2104 | */ | ||
2138 | 2105 | ||
2139 | get_page(vmf->page); | 2106 | static struct page * |
2140 | vmf->page->mapping = vma->vm_file->f_mapping; | 2107 | perf_mmap_to_page(struct perf_mmap_data *data, unsigned long pgoff) |
2141 | vmf->page->index = vmf->pgoff; | 2108 | { |
2109 | if (pgoff > data->nr_pages) | ||
2110 | return NULL; | ||
2142 | 2111 | ||
2143 | ret = 0; | 2112 | if (pgoff == 0) |
2144 | unlock: | 2113 | return virt_to_page(data->user_page); |
2145 | rcu_read_unlock(); | ||
2146 | 2114 | ||
2147 | return ret; | 2115 | return virt_to_page(data->data_pages[pgoff - 1]); |
2148 | } | 2116 | } |
2149 | 2117 | ||
2150 | static int perf_mmap_data_alloc(struct perf_event *event, int nr_pages) | 2118 | static struct perf_mmap_data * |
2119 | perf_mmap_data_alloc(struct perf_event *event, int nr_pages) | ||
2151 | { | 2120 | { |
2152 | struct perf_mmap_data *data; | 2121 | struct perf_mmap_data *data; |
2153 | unsigned long size; | 2122 | unsigned long size; |
@@ -2172,19 +2141,10 @@ static int perf_mmap_data_alloc(struct perf_event *event, int nr_pages) | |||
2172 | goto fail_data_pages; | 2141 | goto fail_data_pages; |
2173 | } | 2142 | } |
2174 | 2143 | ||
2144 | data->data_order = 0; | ||
2175 | data->nr_pages = nr_pages; | 2145 | data->nr_pages = nr_pages; |
2176 | atomic_set(&data->lock, -1); | ||
2177 | |||
2178 | if (event->attr.watermark) { | ||
2179 | data->watermark = min_t(long, PAGE_SIZE * nr_pages, | ||
2180 | event->attr.wakeup_watermark); | ||
2181 | } | ||
2182 | if (!data->watermark) | ||
2183 | data->watermark = max(PAGE_SIZE, PAGE_SIZE * nr_pages / 4); | ||
2184 | 2146 | ||
2185 | rcu_assign_pointer(event->data, data); | 2147 | return data; |
2186 | |||
2187 | return 0; | ||
2188 | 2148 | ||
2189 | fail_data_pages: | 2149 | fail_data_pages: |
2190 | for (i--; i >= 0; i--) | 2150 | for (i--; i >= 0; i--) |
@@ -2196,7 +2156,7 @@ fail_user_page: | |||
2196 | kfree(data); | 2156 | kfree(data); |
2197 | 2157 | ||
2198 | fail: | 2158 | fail: |
2199 | return -ENOMEM; | 2159 | return NULL; |
2200 | } | 2160 | } |
2201 | 2161 | ||
2202 | static void perf_mmap_free_page(unsigned long addr) | 2162 | static void perf_mmap_free_page(unsigned long addr) |
@@ -2207,28 +2167,169 @@ static void perf_mmap_free_page(unsigned long addr) | |||
2207 | __free_page(page); | 2167 | __free_page(page); |
2208 | } | 2168 | } |
2209 | 2169 | ||
2210 | static void __perf_mmap_data_free(struct rcu_head *rcu_head) | 2170 | static void perf_mmap_data_free(struct perf_mmap_data *data) |
2211 | { | 2171 | { |
2212 | struct perf_mmap_data *data; | ||
2213 | int i; | 2172 | int i; |
2214 | 2173 | ||
2215 | data = container_of(rcu_head, struct perf_mmap_data, rcu_head); | ||
2216 | |||
2217 | perf_mmap_free_page((unsigned long)data->user_page); | 2174 | perf_mmap_free_page((unsigned long)data->user_page); |
2218 | for (i = 0; i < data->nr_pages; i++) | 2175 | for (i = 0; i < data->nr_pages; i++) |
2219 | perf_mmap_free_page((unsigned long)data->data_pages[i]); | 2176 | perf_mmap_free_page((unsigned long)data->data_pages[i]); |
2177 | } | ||
2178 | |||
2179 | #else | ||
2180 | |||
2181 | /* | ||
2182 | * Back perf_mmap() with vmalloc memory. | ||
2183 | * | ||
2184 | * Required for architectures that have d-cache aliasing issues. | ||
2185 | */ | ||
2186 | |||
2187 | static struct page * | ||
2188 | perf_mmap_to_page(struct perf_mmap_data *data, unsigned long pgoff) | ||
2189 | { | ||
2190 | if (pgoff > (1UL << data->data_order)) | ||
2191 | return NULL; | ||
2192 | |||
2193 | return vmalloc_to_page((void *)data->user_page + pgoff * PAGE_SIZE); | ||
2194 | } | ||
2195 | |||
2196 | static void perf_mmap_unmark_page(void *addr) | ||
2197 | { | ||
2198 | struct page *page = vmalloc_to_page(addr); | ||
2199 | |||
2200 | page->mapping = NULL; | ||
2201 | } | ||
2202 | |||
2203 | static void perf_mmap_data_free_work(struct work_struct *work) | ||
2204 | { | ||
2205 | struct perf_mmap_data *data; | ||
2206 | void *base; | ||
2207 | int i, nr; | ||
2208 | |||
2209 | data = container_of(work, struct perf_mmap_data, work); | ||
2210 | nr = 1 << data->data_order; | ||
2211 | |||
2212 | base = data->user_page; | ||
2213 | for (i = 0; i < nr + 1; i++) | ||
2214 | perf_mmap_unmark_page(base + (i * PAGE_SIZE)); | ||
2215 | |||
2216 | vfree(base); | ||
2217 | } | ||
2220 | 2218 | ||
2219 | static void perf_mmap_data_free(struct perf_mmap_data *data) | ||
2220 | { | ||
2221 | schedule_work(&data->work); | ||
2222 | } | ||
2223 | |||
2224 | static struct perf_mmap_data * | ||
2225 | perf_mmap_data_alloc(struct perf_event *event, int nr_pages) | ||
2226 | { | ||
2227 | struct perf_mmap_data *data; | ||
2228 | unsigned long size; | ||
2229 | void *all_buf; | ||
2230 | |||
2231 | WARN_ON(atomic_read(&event->mmap_count)); | ||
2232 | |||
2233 | size = sizeof(struct perf_mmap_data); | ||
2234 | size += sizeof(void *); | ||
2235 | |||
2236 | data = kzalloc(size, GFP_KERNEL); | ||
2237 | if (!data) | ||
2238 | goto fail; | ||
2239 | |||
2240 | INIT_WORK(&data->work, perf_mmap_data_free_work); | ||
2241 | |||
2242 | all_buf = vmalloc_user((nr_pages + 1) * PAGE_SIZE); | ||
2243 | if (!all_buf) | ||
2244 | goto fail_all_buf; | ||
2245 | |||
2246 | data->user_page = all_buf; | ||
2247 | data->data_pages[0] = all_buf + PAGE_SIZE; | ||
2248 | data->data_order = ilog2(nr_pages); | ||
2249 | data->nr_pages = 1; | ||
2250 | |||
2251 | return data; | ||
2252 | |||
2253 | fail_all_buf: | ||
2254 | kfree(data); | ||
2255 | |||
2256 | fail: | ||
2257 | return NULL; | ||
2258 | } | ||
2259 | |||
2260 | #endif | ||
2261 | |||
2262 | static int perf_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | ||
2263 | { | ||
2264 | struct perf_event *event = vma->vm_file->private_data; | ||
2265 | struct perf_mmap_data *data; | ||
2266 | int ret = VM_FAULT_SIGBUS; | ||
2267 | |||
2268 | if (vmf->flags & FAULT_FLAG_MKWRITE) { | ||
2269 | if (vmf->pgoff == 0) | ||
2270 | ret = 0; | ||
2271 | return ret; | ||
2272 | } | ||
2273 | |||
2274 | rcu_read_lock(); | ||
2275 | data = rcu_dereference(event->data); | ||
2276 | if (!data) | ||
2277 | goto unlock; | ||
2278 | |||
2279 | if (vmf->pgoff && (vmf->flags & FAULT_FLAG_WRITE)) | ||
2280 | goto unlock; | ||
2281 | |||
2282 | vmf->page = perf_mmap_to_page(data, vmf->pgoff); | ||
2283 | if (!vmf->page) | ||
2284 | goto unlock; | ||
2285 | |||
2286 | get_page(vmf->page); | ||
2287 | vmf->page->mapping = vma->vm_file->f_mapping; | ||
2288 | vmf->page->index = vmf->pgoff; | ||
2289 | |||
2290 | ret = 0; | ||
2291 | unlock: | ||
2292 | rcu_read_unlock(); | ||
2293 | |||
2294 | return ret; | ||
2295 | } | ||
2296 | |||
2297 | static void | ||
2298 | perf_mmap_data_init(struct perf_event *event, struct perf_mmap_data *data) | ||
2299 | { | ||
2300 | long max_size = perf_data_size(data); | ||
2301 | |||
2302 | atomic_set(&data->lock, -1); | ||
2303 | |||
2304 | if (event->attr.watermark) { | ||
2305 | data->watermark = min_t(long, max_size, | ||
2306 | event->attr.wakeup_watermark); | ||
2307 | } | ||
2308 | |||
2309 | if (!data->watermark) | ||
2310 | data->watermark = max_t(long, PAGE_SIZE, max_size / 2); | ||
2311 | |||
2312 | |||
2313 | rcu_assign_pointer(event->data, data); | ||
2314 | } | ||
2315 | |||
2316 | static void perf_mmap_data_free_rcu(struct rcu_head *rcu_head) | ||
2317 | { | ||
2318 | struct perf_mmap_data *data; | ||
2319 | |||
2320 | data = container_of(rcu_head, struct perf_mmap_data, rcu_head); | ||
2321 | perf_mmap_data_free(data); | ||
2221 | kfree(data); | 2322 | kfree(data); |
2222 | } | 2323 | } |
2223 | 2324 | ||
2224 | static void perf_mmap_data_free(struct perf_event *event) | 2325 | static void perf_mmap_data_release(struct perf_event *event) |
2225 | { | 2326 | { |
2226 | struct perf_mmap_data *data = event->data; | 2327 | struct perf_mmap_data *data = event->data; |
2227 | 2328 | ||
2228 | WARN_ON(atomic_read(&event->mmap_count)); | 2329 | WARN_ON(atomic_read(&event->mmap_count)); |
2229 | 2330 | ||
2230 | rcu_assign_pointer(event->data, NULL); | 2331 | rcu_assign_pointer(event->data, NULL); |
2231 | call_rcu(&data->rcu_head, __perf_mmap_data_free); | 2332 | call_rcu(&data->rcu_head, perf_mmap_data_free_rcu); |
2232 | } | 2333 | } |
2233 | 2334 | ||
2234 | static void perf_mmap_open(struct vm_area_struct *vma) | 2335 | static void perf_mmap_open(struct vm_area_struct *vma) |
@@ -2244,11 +2345,12 @@ static void perf_mmap_close(struct vm_area_struct *vma) | |||
2244 | 2345 | ||
2245 | WARN_ON_ONCE(event->ctx->parent_ctx); | 2346 | WARN_ON_ONCE(event->ctx->parent_ctx); |
2246 | if (atomic_dec_and_mutex_lock(&event->mmap_count, &event->mmap_mutex)) { | 2347 | if (atomic_dec_and_mutex_lock(&event->mmap_count, &event->mmap_mutex)) { |
2348 | unsigned long size = perf_data_size(event->data); | ||
2247 | struct user_struct *user = current_user(); | 2349 | struct user_struct *user = current_user(); |
2248 | 2350 | ||
2249 | atomic_long_sub(event->data->nr_pages + 1, &user->locked_vm); | 2351 | atomic_long_sub((size >> PAGE_SHIFT) + 1, &user->locked_vm); |
2250 | vma->vm_mm->locked_vm -= event->data->nr_locked; | 2352 | vma->vm_mm->locked_vm -= event->data->nr_locked; |
2251 | perf_mmap_data_free(event); | 2353 | perf_mmap_data_release(event); |
2252 | mutex_unlock(&event->mmap_mutex); | 2354 | mutex_unlock(&event->mmap_mutex); |
2253 | } | 2355 | } |
2254 | } | 2356 | } |
@@ -2266,6 +2368,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) | |||
2266 | unsigned long user_locked, user_lock_limit; | 2368 | unsigned long user_locked, user_lock_limit; |
2267 | struct user_struct *user = current_user(); | 2369 | struct user_struct *user = current_user(); |
2268 | unsigned long locked, lock_limit; | 2370 | unsigned long locked, lock_limit; |
2371 | struct perf_mmap_data *data; | ||
2269 | unsigned long vma_size; | 2372 | unsigned long vma_size; |
2270 | unsigned long nr_pages; | 2373 | unsigned long nr_pages; |
2271 | long user_extra, extra; | 2374 | long user_extra, extra; |
@@ -2328,10 +2431,15 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) | |||
2328 | } | 2431 | } |
2329 | 2432 | ||
2330 | WARN_ON(event->data); | 2433 | WARN_ON(event->data); |
2331 | ret = perf_mmap_data_alloc(event, nr_pages); | 2434 | |
2332 | if (ret) | 2435 | data = perf_mmap_data_alloc(event, nr_pages); |
2436 | ret = -ENOMEM; | ||
2437 | if (!data) | ||
2333 | goto unlock; | 2438 | goto unlock; |
2334 | 2439 | ||
2440 | ret = 0; | ||
2441 | perf_mmap_data_init(event, data); | ||
2442 | |||
2335 | atomic_set(&event->mmap_count, 1); | 2443 | atomic_set(&event->mmap_count, 1); |
2336 | atomic_long_add(user_extra, &user->locked_vm); | 2444 | atomic_long_add(user_extra, &user->locked_vm); |
2337 | vma->vm_mm->locked_vm += extra; | 2445 | vma->vm_mm->locked_vm += extra; |
@@ -2519,7 +2627,7 @@ static bool perf_output_space(struct perf_mmap_data *data, unsigned long tail, | |||
2519 | if (!data->writable) | 2627 | if (!data->writable) |
2520 | return true; | 2628 | return true; |
2521 | 2629 | ||
2522 | mask = (data->nr_pages << PAGE_SHIFT) - 1; | 2630 | mask = perf_data_size(data) - 1; |
2523 | 2631 | ||
2524 | offset = (offset - tail) & mask; | 2632 | offset = (offset - tail) & mask; |
2525 | head = (head - tail) & mask; | 2633 | head = (head - tail) & mask; |
@@ -2624,7 +2732,7 @@ void perf_output_copy(struct perf_output_handle *handle, | |||
2624 | const void *buf, unsigned int len) | 2732 | const void *buf, unsigned int len) |
2625 | { | 2733 | { |
2626 | unsigned int pages_mask; | 2734 | unsigned int pages_mask; |
2627 | unsigned int offset; | 2735 | unsigned long offset; |
2628 | unsigned int size; | 2736 | unsigned int size; |
2629 | void **pages; | 2737 | void **pages; |
2630 | 2738 | ||
@@ -2633,12 +2741,14 @@ void perf_output_copy(struct perf_output_handle *handle, | |||
2633 | pages = handle->data->data_pages; | 2741 | pages = handle->data->data_pages; |
2634 | 2742 | ||
2635 | do { | 2743 | do { |
2636 | unsigned int page_offset; | 2744 | unsigned long page_offset; |
2745 | unsigned long page_size; | ||
2637 | int nr; | 2746 | int nr; |
2638 | 2747 | ||
2639 | nr = (offset >> PAGE_SHIFT) & pages_mask; | 2748 | nr = (offset >> PAGE_SHIFT) & pages_mask; |
2640 | page_offset = offset & (PAGE_SIZE - 1); | 2749 | page_size = 1UL << (handle->data->data_order + PAGE_SHIFT); |
2641 | size = min_t(unsigned int, PAGE_SIZE - page_offset, len); | 2750 | page_offset = offset & (page_size - 1); |
2751 | size = min_t(unsigned int, page_size - page_offset, len); | ||
2642 | 2752 | ||
2643 | memcpy(pages[nr] + page_offset, buf, size); | 2753 | memcpy(pages[nr] + page_offset, buf, size); |
2644 | 2754 | ||
@@ -4781,9 +4891,7 @@ int perf_event_init_task(struct task_struct *child) | |||
4781 | * We dont have to disable NMIs - we are only looking at | 4891 | * We dont have to disable NMIs - we are only looking at |
4782 | * the list, not manipulating it: | 4892 | * the list, not manipulating it: |
4783 | */ | 4893 | */ |
4784 | list_for_each_entry_rcu(event, &parent_ctx->event_list, event_entry) { | 4894 | list_for_each_entry(event, &parent_ctx->group_list, group_entry) { |
4785 | if (event != event->group_leader) | ||
4786 | continue; | ||
4787 | 4895 | ||
4788 | if (!event->attr.inherit) { | 4896 | if (!event->attr.inherit) { |
4789 | inherited_all = 0; | 4897 | inherited_all = 0; |