1 From: Tony Jones <tonyj@suse.de>
2 Subject: switch to ioctl interface for perfmon2
5 Patch accepted from SGI (bnc#430298, FATE #303968) added 12 new syscalls.
6 Since these have not been accepted upstream, we don't want to have to
7 support them. Decision was made to switch to a ioctl based interface.
9 Signed-off-by: Tony Jones <tonyj@suse.de>
12 include/linux/syscalls.h | 23 ---
14 perfmon/perfmon_control.c | 310 ++++++++++++++++++++++++++++++++++++++++++++++
15 perfmon/perfmon_init.c | 3
16 perfmon/perfmon_priv.h | 25 +++
17 5 files changed, 340 insertions(+), 24 deletions(-)
19 --- a/include/linux/syscalls.h
20 +++ b/include/linux/syscalls.h
21 @@ -697,27 +697,4 @@ asmlinkage long sys_pipe(int __user *);
23 int kernel_execve(const char *filename, char *const argv[], char *const envp[]);
25 -asmlinkage long sys_pfm_create_context(struct pfarg_ctx __user *ureq,
26 - void __user *uarg, size_t smpl_size);
27 -asmlinkage long sys_pfm_write_pmcs(int fd, struct pfarg_pmc __user *ureq,
29 -asmlinkage long sys_pfm_write_pmds(int fd, struct pfarg_pmd __user *ureq,
31 -asmlinkage long sys_pfm_read_pmds(int fd, struct pfarg_pmd __user *ureq,
33 -asmlinkage long sys_pfm_restart(int fd);
34 -asmlinkage long sys_pfm_stop(int fd);
35 -asmlinkage long sys_pfm_start(int fd, struct pfarg_start __user *ureq);
36 -asmlinkage long sys_pfm_load_context(int fd, struct pfarg_load __user *ureq);
37 -asmlinkage long sys_pfm_unload_context(int fd);
38 -asmlinkage long sys_pfm_delete_evtsets(int fd,
39 - struct pfarg_setinfo __user *ureq,
41 -asmlinkage long sys_pfm_create_evtsets(int fd,
42 - struct pfarg_setdesc __user *ureq,
44 -asmlinkage long sys_pfm_getinfo_evtsets(int fd,
45 - struct pfarg_setinfo __user *ureq,
49 --- a/perfmon/Makefile
50 +++ b/perfmon/Makefile
51 @@ -7,6 +7,7 @@ obj-y = perfmon_init.o perfmon_rw.o perf
52 perfmon_file.o perfmon_ctxsw.o perfmon_intr.o \
53 perfmon_dfl_smpl.o perfmon_sets.o perfmon_hotplug.o \
54 perfmon_msg.o perfmon_smpl.o perfmon_attach.o \
55 - perfmon_activate.o perfmon_ctx.o perfmon_fmt.o
56 + perfmon_activate.o perfmon_ctx.o perfmon_fmt.o \
59 obj-$(CONFIG_PERFMON_DEBUG_FS) += perfmon_debugfs.o
61 +++ b/perfmon/perfmon_control.c
64 + * perfmon_control.c: perfmon2 ioctl interface
66 + * This file implements an ioctl interface alternative replacing the
67 + * following syscalls:
69 + * sys_pfm_create_context
70 + * sys_pfm_write_pmcs
71 + * sys_pfm_write_pmds
73 + * sys_pfm_load_context
77 + * sys_pfm_create_evtsets
78 + * sys_pfm_getinfo_evtsets
79 + * sys_pfm_delete_evtsets
80 + * sys_pfm_unload_context
84 + * Tony Jones <tonyj@suse.de>
86 + * Copyright (c) 2008 Novell Inc
87 + * Contributed by Tony Jones <tonyj@suse.de>
89 + * This program is free software; you can redistribute it and/or
90 + * modify it under the terms of version 2 of the GNU General Public
91 + * License as published by the Free Software Foundation.
93 + * This program is distributed in the hope that it will be useful,
94 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
95 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
96 + * General Public License for more details.
98 + * You should have received a copy of the GNU General Public License
99 + * along with this program; if not, write to the Free Software
100 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
104 +#include <linux/kernel.h>
105 +#include <linux/module.h>
106 +#include <linux/proc_fs.h>
107 +#include <linux/uaccess.h>
108 +#include <linux/miscdevice.h>
109 +#include <linux/perfmon_kern.h>
110 +#include "perfmon_priv.h"
111 +#include <linux/device.h>
112 +#include <linux/compat.h>
114 +/* elements arranged to ensure current padding for 32/64bit */
115 +struct pfm_control_init {
116 + __u64 req; /* struct pfarg_ctx* */
117 + __u64 fmt_name; /* char* */
118 + __u64 fmt_arg; /* void* */
119 + __u64 fmt_size; /* size_t */
122 +struct pfm_control_arglist {
123 + __s32 fd; /* int */
124 + __s32 count; /* int */
125 + __u64 req; /* void* */
128 +struct pfm_control_argptr {
129 + __u64 req; /* void* */
130 + __s32 fd; /* int */
134 +struct pfm_control_fd {
135 + __s32 fd; /* int */
140 + struct pfm_control_init init;
141 + struct pfm_control_arglist arglist;
142 + struct pfm_control_argptr argptr;
143 + struct pfm_control_fd fd;
146 +#ifdef CONFIG_COMPAT
147 +#define _PTR(p) (compat ? compat_ptr(p) : (void*)p)
149 +#define _PTR(p) (unsigned long)(p)
152 +static long pfm_control_create_context(union pfm_control *cdata, int compat)
154 + struct pfm_control_init *d = &cdata->init;
156 + return sys_pfm_create_context((struct pfarg_ctx *)_PTR(d->req),
157 + (char *)_PTR(d->fmt_name),
158 + (void *)_PTR(d->fmt_arg),
159 + (size_t)d->fmt_size);
162 +static long pfm_control_write_pmcs(union pfm_control *cdata, int compat)
164 + struct pfm_control_arglist *d = &cdata->arglist;
166 + return sys_pfm_write_pmcs(d->fd,
167 + (struct pfarg_pmc __user *)_PTR(d->req),
171 +static long pfm_control_write_pmds(union pfm_control *cdata, int compat)
173 + struct pfm_control_arglist *d = &cdata->arglist;
175 + return sys_pfm_write_pmds(d->fd,
176 + (struct pfarg_pmd __user *)_PTR(d->req),
180 +static long pfm_control_read_pmds(union pfm_control *cdata, int compat)
182 + struct pfm_control_arglist *d = &cdata->arglist;
184 + return sys_pfm_read_pmds(d->fd,
185 + (struct pfarg_pmd __user *)_PTR(d->req),
189 +static long pfm_control_load_context(union pfm_control *cdata, int compat)
191 + struct pfm_control_argptr *d = &cdata->argptr;
193 + return sys_pfm_load_context(d->fd,
194 + (struct pfarg_load __user *)_PTR(d->req));
197 +static long pfm_control_start(union pfm_control *cdata, int compat)
199 + struct pfm_control_argptr *d = &cdata->argptr;
201 + return sys_pfm_start(d->fd, (struct pfarg_start __user *)_PTR(d->req));
204 +static long pfm_control_stop(union pfm_control *cdata, int compat)
206 + struct pfm_control_fd *d = &cdata->fd;
208 + return sys_pfm_stop(d->fd);
211 +static long pfm_control_restart(union pfm_control *cdata, int compat)
213 + struct pfm_control_fd *d = &cdata->fd;
215 + return sys_pfm_restart(d->fd);
218 +static long pfm_control_create_evtsets(union pfm_control *cdata, int compat)
220 + struct pfm_control_arglist *d = &cdata->arglist;
222 + return sys_pfm_create_evtsets(d->fd,
223 + (struct pfarg_setdesc __user *)_PTR(d->req),
227 +static long pfm_control_getinfo_evtsets(union pfm_control *cdata, int compat)
229 + struct pfm_control_arglist *d = &cdata->arglist;
231 + return sys_pfm_getinfo_evtsets(d->fd,
232 + (struct pfarg_setinfo __user *)_PTR(d->req),
236 +static long pfm_control_delete_evtsets(union pfm_control *cdata, int compat)
238 + struct pfm_control_arglist *d = &cdata->arglist;
240 + return sys_pfm_delete_evtsets(d->fd,
241 + (struct pfarg_setinfo __user *)_PTR(d->req),
245 +static long pfm_control_unload_context(union pfm_control *cdata, int compat)
247 + struct pfm_control_fd *d = &cdata->fd;
249 + return sys_pfm_unload_context(d->fd);
252 +#define PFM_CONTROL_COUNT ARRAY_SIZE(pfm_control_tab)
253 +#define PFM_CMD(func, elem) {func, sizeof(struct elem)}
255 +struct pfm_control_elem {
256 + long (*func)(union pfm_control *, int compat);
260 +static struct pfm_control_elem pfm_control_tab[] = {
261 + PFM_CMD(pfm_control_create_context, pfm_control_init),
262 + PFM_CMD(pfm_control_write_pmcs, pfm_control_arglist),
263 + PFM_CMD(pfm_control_write_pmds, pfm_control_arglist),
264 + PFM_CMD(pfm_control_read_pmds, pfm_control_arglist),
265 + PFM_CMD(pfm_control_load_context, pfm_control_argptr),
266 + PFM_CMD(pfm_control_start, pfm_control_argptr),
267 + PFM_CMD(pfm_control_stop, pfm_control_fd),
268 + PFM_CMD(pfm_control_restart, pfm_control_fd),
269 + PFM_CMD(pfm_control_create_evtsets, pfm_control_arglist),
270 + PFM_CMD(pfm_control_getinfo_evtsets, pfm_control_arglist),
271 + PFM_CMD(pfm_control_delete_evtsets, pfm_control_arglist),
272 + PFM_CMD(pfm_control_unload_context, pfm_control_fd),
275 +static int __pfm_control_ioctl(struct inode *inode, struct file *file,
276 + unsigned int cmd, unsigned long arg,
279 + union pfm_control cdata;
282 + if (perfmon_disabled)
287 + if (unlikely(op < 0 || op >= PFM_CONTROL_COUNT ||
288 + pfm_control_tab[op].func == NULL)) {
289 + PFM_ERR("Invalid control request %d", op);
293 + if (_IOC_SIZE(cmd) != pfm_control_tab[op].size) {
294 + PFM_ERR("Invalid control request %d, size %d, expected %lu\n",
295 + op, _IOC_SIZE(cmd),
296 + (unsigned long)pfm_control_tab[op].size);
300 + if (_IOC_TYPE(cmd) != 0 || _IOC_DIR(cmd) != _IOC_WRITE)
303 + if (copy_from_user(&cdata, (void*)arg, pfm_control_tab[op].size) != 0)
306 + rc = pfm_control_tab[op].func(&cdata, compat);
310 +static int pfm_control_ioctl(struct inode *inode, struct file *file,
311 + unsigned int cmd, unsigned long arg)
313 + return __pfm_control_ioctl(inode, file, cmd, arg, 0);
316 +#ifdef CONFIG_COMPAT
317 +static long compat_pfm_control_ioctl(struct file *file,
318 + unsigned int cmd, unsigned long arg)
320 + return __pfm_control_ioctl(file->f_dentry->d_inode, file, cmd, arg, 1);
324 +static const struct file_operations pfm_control_operations = {
325 + .owner = THIS_MODULE,
326 + .ioctl = pfm_control_ioctl,
327 +#ifdef CONFIG_COMPAT
328 + .compat_ioctl = compat_pfm_control_ioctl,
332 +#ifdef USE_MISC_REGISTER
333 +static struct miscdevice pfm_misc_device = {
334 + .minor = MISC_DYNAMIC_MINOR,
335 + .name = "perfmonctl",
336 + .fops = &pfm_control_operations
340 +int __init pfm_init_control(void)
343 +#ifndef USE_MISC_REGISTER
344 + static struct class *pfm_class;
345 + struct device *dev;
349 +#ifdef USE_MISC_REGISTER
350 + ret = misc_register(&pfm_misc_device);
352 + PFM_ERR("Failed to create perfmon control file. Error %d\n", ret);
355 + major = register_chrdev(0, "perfmon", &pfm_control_operations);
357 + PFM_ERR("Failed to register_chardev %d\n", major);
360 + pfm_class = class_create(THIS_MODULE, "perfmon");
361 + if (IS_ERR(pfm_class)) {
362 + PFM_ERR("Failed to class_create %ld\n", PTR_ERR(pfm_class));
365 + dev = device_create(pfm_class, NULL, MKDEV(major,0), NULL, "perfmonctl");
367 + PFM_ERR("Failed to device_create %ld\n", PTR_ERR(dev));
373 --- a/perfmon/perfmon_init.c
374 +++ b/perfmon/perfmon_init.c
375 @@ -104,6 +104,9 @@ int __init pfm_init(void)
376 if (pfm_init_sysfs())
379 + if (pfm_init_control())
380 + goto error_disable;
382 /* not critical, so no error checking */
385 --- a/perfmon/perfmon_priv.h
386 +++ b/perfmon/perfmon_priv.h
387 @@ -158,6 +158,7 @@ static inline void pfm_check_save_prev_c
390 int pfm_init_fs(void);
391 +int pfm_init_control(void);
393 int pfm_init_hotplug(void);
395 @@ -177,6 +178,30 @@ static inline void pfm_post_work(struct
396 #define PFM_PMC_STK_ARG PFM_ARCH_PMC_STK_ARG
397 #define PFM_PMD_STK_ARG PFM_ARCH_PMD_STK_ARG
399 +/* these used to be in linux/syscalls.h, now accessed via ioctl interface */
400 +asmlinkage long sys_pfm_create_context(struct pfarg_ctx __user *ureq,
401 + char __user *fmt_name,
402 + void __user *fmt_uarg, size_t fmt_size);
403 +asmlinkage long sys_pfm_write_pmcs(int fd, struct pfarg_pmc __user *ureq,
405 +asmlinkage long sys_pfm_write_pmds(int fd, struct pfarg_pmd __user *ureq,
407 +asmlinkage long sys_pfm_read_pmds(int fd, struct pfarg_pmd __user *ureq,
409 +asmlinkage long sys_pfm_restart(int fd);
410 +asmlinkage long sys_pfm_stop(int fd);
411 +asmlinkage long sys_pfm_start(int fd, struct pfarg_start __user *ureq);
412 +asmlinkage long sys_pfm_load_context(int fd, struct pfarg_load __user *ureq);
413 +asmlinkage long sys_pfm_unload_context(int fd);
414 +asmlinkage long sys_pfm_delete_evtsets(int fd,
415 + struct pfarg_setinfo __user *ureq,
417 +asmlinkage long sys_pfm_create_evtsets(int fd,
418 + struct pfarg_setdesc __user *ureq,
420 +asmlinkage long sys_pfm_getinfo_evtsets(int fd,
421 + struct pfarg_setinfo __user *ureq,
423 #endif /* CONFIG_PERFMON */
425 #endif /* __PERFMON_PRIV_H__ */