aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/perf_event.h6
-rw-r--r--kernel/perf_event.c75
2 files changed, 80 insertions, 1 deletions
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index df9d964c15fc..fa151d49a2ee 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -744,6 +744,12 @@ extern int hw_perf_group_sched_in(struct perf_event *group_leader,
744 struct perf_cpu_context *cpuctx, 744 struct perf_cpu_context *cpuctx,
745 struct perf_event_context *ctx, int cpu); 745 struct perf_event_context *ctx, int cpu);
746extern void perf_event_update_userpage(struct perf_event *event); 746extern void perf_event_update_userpage(struct perf_event *event);
747extern int perf_event_release_kernel(struct perf_event *event);
748extern struct perf_event *
749perf_event_create_kernel_counter(struct perf_event_attr *attr,
750 int cpu,
751 pid_t pid);
752extern u64 perf_event_read_value(struct perf_event *event);
747 753
748struct perf_sample_data { 754struct perf_sample_data {
749 u64 type; 755 u64 type;
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index 12b5ec39bf97..02d4ff041b01 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -1725,6 +1725,26 @@ static int perf_release(struct inode *inode, struct file *file)
1725 return 0; 1725 return 0;
1726} 1726}
1727 1727
1728int perf_event_release_kernel(struct perf_event *event)
1729{
1730 struct perf_event_context *ctx = event->ctx;
1731
1732 WARN_ON_ONCE(ctx->parent_ctx);
1733 mutex_lock(&ctx->mutex);
1734 perf_event_remove_from_context(event);
1735 mutex_unlock(&ctx->mutex);
1736
1737 mutex_lock(&event->owner->perf_event_mutex);
1738 list_del_init(&event->owner_entry);
1739 mutex_unlock(&event->owner->perf_event_mutex);
1740 put_task_struct(event->owner);
1741
1742 free_event(event);
1743
1744 return 0;
1745}
1746EXPORT_SYMBOL_GPL(perf_event_release_kernel);
1747
1728static int perf_event_read_size(struct perf_event *event) 1748static int perf_event_read_size(struct perf_event *event)
1729{ 1749{
1730 int entry = sizeof(u64); /* value */ 1750 int entry = sizeof(u64); /* value */
@@ -1750,7 +1770,7 @@ static int perf_event_read_size(struct perf_event *event)
1750 return size; 1770 return size;
1751} 1771}
1752 1772
1753static u64 perf_event_read_value(struct perf_event *event) 1773u64 perf_event_read_value(struct perf_event *event)
1754{ 1774{
1755 struct perf_event *child; 1775 struct perf_event *child;
1756 u64 total = 0; 1776 u64 total = 0;
@@ -1761,6 +1781,7 @@ static u64 perf_event_read_value(struct perf_event *event)
1761 1781
1762 return total; 1782 return total;
1763} 1783}
1784EXPORT_SYMBOL_GPL(perf_event_read_value);
1764 1785
1765static int perf_event_read_entry(struct perf_event *event, 1786static int perf_event_read_entry(struct perf_event *event,
1766 u64 read_format, char __user *buf) 1787 u64 read_format, char __user *buf)
@@ -4638,6 +4659,58 @@ err_put_context:
4638 return err; 4659 return err;
4639} 4660}
4640 4661
4662/**
4663 * perf_event_create_kernel_counter
4664 *
4665 * @attr: attributes of the counter to create
4666 * @cpu: cpu in which the counter is bound
4667 * @pid: task to profile
4668 */
4669struct perf_event *
4670perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu,
4671 pid_t pid)
4672{
4673 struct perf_event *event;
4674 struct perf_event_context *ctx;
4675 int err;
4676
4677 /*
4678 * Get the target context (task or percpu):
4679 */
4680
4681 ctx = find_get_context(pid, cpu);
4682 if (IS_ERR(ctx))
4683 return NULL ;
4684
4685 event = perf_event_alloc(attr, cpu, ctx, NULL,
4686 NULL, GFP_KERNEL);
4687 err = PTR_ERR(event);
4688 if (IS_ERR(event))
4689 goto err_put_context;
4690
4691 event->filp = NULL;
4692 WARN_ON_ONCE(ctx->parent_ctx);
4693 mutex_lock(&ctx->mutex);
4694 perf_install_in_context(ctx, event, cpu);
4695 ++ctx->generation;
4696 mutex_unlock(&ctx->mutex);
4697
4698 event->owner = current;
4699 get_task_struct(current);
4700 mutex_lock(&current->perf_event_mutex);
4701 list_add_tail(&event->owner_entry, &current->perf_event_list);
4702 mutex_unlock(&current->perf_event_mutex);
4703
4704 return event;
4705
4706err_put_context:
4707 if (err < 0)
4708 put_ctx(ctx);
4709
4710 return NULL;
4711}
4712EXPORT_SYMBOL_GPL(perf_event_create_kernel_counter);
4713
4641/* 4714/*
4642 * inherit a event from parent task to child task: 4715 * inherit a event from parent task to child task:
4643 */ 4716 */