aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/perf_counter.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/perf_counter.c')
-rw-r--r--kernel/perf_counter.c76
1 files changed, 76 insertions, 0 deletions
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c
index ce34bff07bda..d9cfd902140e 100644
--- a/kernel/perf_counter.c
+++ b/kernel/perf_counter.c
@@ -1177,6 +1177,7 @@ static int perf_release(struct inode *inode, struct file *file)
1177 mutex_unlock(&counter->mutex); 1177 mutex_unlock(&counter->mutex);
1178 mutex_unlock(&ctx->mutex); 1178 mutex_unlock(&ctx->mutex);
1179 1179
1180 free_page(counter->user_page);
1180 free_counter(counter); 1181 free_counter(counter);
1181 put_context(ctx); 1182 put_context(ctx);
1182 1183
@@ -1346,12 +1347,87 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1346 return err; 1347 return err;
1347} 1348}
1348 1349
1350void perf_counter_update_userpage(struct perf_counter *counter)
1351{
1352 struct perf_counter_mmap_page *userpg;
1353
1354 if (!counter->user_page)
1355 return;
1356 userpg = (struct perf_counter_mmap_page *) counter->user_page;
1357
1358 ++userpg->lock;
1359 smp_wmb();
1360 userpg->index = counter->hw.idx;
1361 userpg->offset = atomic64_read(&counter->count);
1362 if (counter->state == PERF_COUNTER_STATE_ACTIVE)
1363 userpg->offset -= atomic64_read(&counter->hw.prev_count);
1364 smp_wmb();
1365 ++userpg->lock;
1366}
1367
1368static int perf_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
1369{
1370 struct perf_counter *counter = vma->vm_file->private_data;
1371
1372 if (!counter->user_page)
1373 return VM_FAULT_SIGBUS;
1374
1375 vmf->page = virt_to_page(counter->user_page);
1376 get_page(vmf->page);
1377 return 0;
1378}
1379
1380static struct vm_operations_struct perf_mmap_vmops = {
1381 .fault = perf_mmap_fault,
1382};
1383
1384static int perf_mmap(struct file *file, struct vm_area_struct *vma)
1385{
1386 struct perf_counter *counter = file->private_data;
1387 unsigned long userpg;
1388
1389 if (!(vma->vm_flags & VM_SHARED) || (vma->vm_flags & VM_WRITE))
1390 return -EINVAL;
1391 if (vma->vm_end - vma->vm_start != PAGE_SIZE)
1392 return -EINVAL;
1393
1394 /*
1395 * For now, restrict to the case of a hardware counter
1396 * on the current task.
1397 */
1398 if (is_software_counter(counter) || counter->task != current)
1399 return -EINVAL;
1400
1401 userpg = counter->user_page;
1402 if (!userpg) {
1403 userpg = get_zeroed_page(GFP_KERNEL);
1404 mutex_lock(&counter->mutex);
1405 if (counter->user_page) {
1406 free_page(userpg);
1407 userpg = counter->user_page;
1408 } else {
1409 counter->user_page = userpg;
1410 }
1411 mutex_unlock(&counter->mutex);
1412 if (!userpg)
1413 return -ENOMEM;
1414 }
1415
1416 perf_counter_update_userpage(counter);
1417
1418 vma->vm_flags &= ~VM_MAYWRITE;
1419 vma->vm_flags |= VM_RESERVED;
1420 vma->vm_ops = &perf_mmap_vmops;
1421 return 0;
1422}
1423
1349static const struct file_operations perf_fops = { 1424static const struct file_operations perf_fops = {
1350 .release = perf_release, 1425 .release = perf_release,
1351 .read = perf_read, 1426 .read = perf_read,
1352 .poll = perf_poll, 1427 .poll = perf_poll,
1353 .unlocked_ioctl = perf_ioctl, 1428 .unlocked_ioctl = perf_ioctl,
1354 .compat_ioctl = perf_ioctl, 1429 .compat_ioctl = perf_ioctl,
1430 .mmap = perf_mmap,
1355}; 1431};
1356 1432
1357/* 1433/*