diff options
-rw-r--r-- | include/linux/perf_counter.h | 9 | ||||
-rw-r--r-- | kernel/perf_counter.c | 41 |
2 files changed, 46 insertions, 4 deletions
diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h index c046f7d97cfa..45bdd3b95d3e 100644 --- a/include/linux/perf_counter.h +++ b/include/linux/perf_counter.h | |||
@@ -164,10 +164,11 @@ struct perf_counter_hw_event { | |||
164 | /* | 164 | /* |
165 | * Ioctls that can be done on a perf counter fd: | 165 | * Ioctls that can be done on a perf counter fd: |
166 | */ | 166 | */ |
167 | #define PERF_COUNTER_IOC_ENABLE _IOW('$', 0, u32) | 167 | #define PERF_COUNTER_IOC_ENABLE _IO ('$', 0) |
168 | #define PERF_COUNTER_IOC_DISABLE _IOW('$', 1, u32) | 168 | #define PERF_COUNTER_IOC_DISABLE _IO ('$', 1) |
169 | #define PERF_COUNTER_IOC_REFRESH _IOW('$', 2, u32) | 169 | #define PERF_COUNTER_IOC_REFRESH _IO ('$', 2) |
170 | #define PERF_COUNTER_IOC_RESET _IOW('$', 3, u32) | 170 | #define PERF_COUNTER_IOC_RESET _IO ('$', 3) |
171 | #define PERF_COUNTER_IOC_PERIOD _IOW('$', 4, u64) | ||
171 | 172 | ||
172 | enum perf_counter_ioc_flags { | 173 | enum perf_counter_ioc_flags { |
173 | PERF_IOC_FLAG_GROUP = 1U << 0, | 174 | PERF_IOC_FLAG_GROUP = 1U << 0, |
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 3f11a2bc6c79..abe2f3b6c424 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c | |||
@@ -1604,6 +1604,43 @@ static void perf_counter_for_each(struct perf_counter *counter, | |||
1604 | mutex_unlock(&counter->child_mutex); | 1604 | mutex_unlock(&counter->child_mutex); |
1605 | } | 1605 | } |
1606 | 1606 | ||
1607 | static int perf_counter_period(struct perf_counter *counter, u64 __user *arg) | ||
1608 | { | ||
1609 | struct perf_counter_context *ctx = counter->ctx; | ||
1610 | unsigned long size; | ||
1611 | int ret = 0; | ||
1612 | u64 value; | ||
1613 | |||
1614 | if (!counter->hw_event.sample_period) | ||
1615 | return -EINVAL; | ||
1616 | |||
1617 | size = copy_from_user(&value, arg, sizeof(value)); | ||
1618 | if (size != sizeof(value)) | ||
1619 | return -EFAULT; | ||
1620 | |||
1621 | if (!value) | ||
1622 | return -EINVAL; | ||
1623 | |||
1624 | spin_lock_irq(&ctx->lock); | ||
1625 | if (counter->hw_event.freq) { | ||
1626 | if (value > sysctl_perf_counter_limit) { | ||
1627 | ret = -EINVAL; | ||
1628 | goto unlock; | ||
1629 | } | ||
1630 | |||
1631 | counter->hw_event.sample_freq = value; | ||
1632 | } else { | ||
1633 | counter->hw_event.sample_period = value; | ||
1634 | counter->hw.sample_period = value; | ||
1635 | |||
1636 | perf_log_period(counter, value); | ||
1637 | } | ||
1638 | unlock: | ||
1639 | spin_unlock_irq(&ctx->lock); | ||
1640 | |||
1641 | return ret; | ||
1642 | } | ||
1643 | |||
1607 | static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 1644 | static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
1608 | { | 1645 | { |
1609 | struct perf_counter *counter = file->private_data; | 1646 | struct perf_counter *counter = file->private_data; |
@@ -1623,6 +1660,10 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
1623 | 1660 | ||
1624 | case PERF_COUNTER_IOC_REFRESH: | 1661 | case PERF_COUNTER_IOC_REFRESH: |
1625 | return perf_counter_refresh(counter, arg); | 1662 | return perf_counter_refresh(counter, arg); |
1663 | |||
1664 | case PERF_COUNTER_IOC_PERIOD: | ||
1665 | return perf_counter_period(counter, (u64 __user *)arg); | ||
1666 | |||
1626 | default: | 1667 | default: |
1627 | return -ENOTTY; | 1668 | return -ENOTTY; |
1628 | } | 1669 | } |