perfmon2 minimal: context creation
PATCH 16/21 perfmon2 minimal: context creation
This patch adds perfmon2 context management functions to create and destroy a perfmon context which encapsulates the entire PMU state.
Signed-off-by Stephane Eranian <[email protected]>
--
perfmon/perfmon_ctx.c +177 -0
@@ -162,3 +162,180 @@ }return 0 ; } + +/** +* pfm_ctx_permissions - check authorization to create new context +* @ctx_flags: context flags passed by user +* +* check for permissions to create a context. +* +* A sysadmin may decide to restrict creation of per-thread +* context to a group of users using the group id via +* /sys/kernel/perfmon/task_group +* +* Once we identify a user level package which can be used +* to grant/revoke Linux capabilites at login via PAM, we will +* be able to use capabilities. We would also need to increase +* the size of cap_t to support more than 32 capabilities (it +* is currently defined as u32 and 32 capabilities are alrady +* defined). +*/ +static inline int pfm_ctx_permissions (u32 ctx_flags) +{ +if (pfm_controls.task_group !=PFM_GROUP_PERM_ANY + && !in_group_p (pfm_controls.task_group)) { +PFM_DBG ("user group not allowed to create a task context" ); +return -EPERM ; + } +return 0 ; +} + +/** +* pfm_create_initial_set - create initial set from __pfm_c reate_context +* @ctx: context to atatched the set to +*/ +static void pfm_create_initial_set (struct pfm_context *ctx) +{ +struct pfm_event_set *set; +u64 *impl_pmcs; +u16 i, max_pmc; + + set = ctx->active_set; + max_pmc = pfm_pmu_conf->regs.max_pmc; + impl_pmcs = pfm_pmu_conf->regs.pmcs; + +/* +* install default values for all PMC registers +*/ +for (i =0 ; i < max_pmc; i++) { +if (test_bit (i,cast_ulp (impl_pmcs))) { + set->pmcs[i] = pfm_pmu_conf->pmc_desc[i].dfl_val; +PFM_DBG ("pmc%u=0x%llx" , + i, + (unsigned long long )set->pmcs[i]); + } + } +/* +* PMD registers are set to 0 when the event set is allocated, +* hence we do not need to explicitly initialize them. +* +* For virtual PMD registers (i.e., those tied to a SW resource) +* their value becomes meaningful once the context is attached. +*/ +} + +/** +* __pfm_create_context - allocate and initialize a perfmon context +* @ctx_flags : user context flags +* +* function used to allocate a new context. A context is allocated along +* with the default event set. If a sampling format is used, the buffer +* may be allocated and initialized. +* +* The file descriptor identifying the context is allocated and returned +* to caller. +* +* This function operates with no locks and interrupts are enabled. +* return: +* >=0: the file descriptor to identify the context +* <0 : the error code +*/ +int __pfm_create_context (__u32 ctx_flags) +{ +struct pfm_context *ctx; +struct file *filp =NULL ; +int fd =0 , ret = -EINVAL ; + +if (!pfm_pmu_conf) +return -ENOSYS ; + +/* no context flags supported yet */ +if (ctx_flags) + goto error_alloc; + + ret =pfm_ctx_permissions (ctx_flags); +if (ret <0 ) + goto error_alloc; + +/* +* we can use GFP_KERNEL and potentially sleep because we do +* not hold any lock at this point. +*/ +might_sleep (); + ret = -ENOMEM ; + ctx =kmem_cache_zalloc (pfm_ctx_cachep,GFP_KERNEL ); +if (!ctx) + goto error_alloc; + +PFM_DBG ("alloc ctx @0x%p" , ctx); + + ctx->active_set = &ctx->_set0; + +spin_lock_init (&ctx->lock); + + ret =pfm_pmu_acquire (); +if (ret) + goto error_file; +/* +* check if PMU is usable +*/ +if (!(pfm_pmu_conf->regs.num_pmcs && pfm_pmu_conf->regs.num_pmcs)) { +PFM_DBG ("no usable PMU registers" ); + ret = -EBUSY ; + goto error_file; + } + + ret = -ENFILE ; + fd =pfm_alloc_fd (&filp); +if (fd <0 ) + goto error_file; + +/* +* context is unloaded +*/ + ctx->state =PFM_CTX_UNLOADED ; + +/* +* initialize arch-specific section +* must be done before fmt_init() +*/ + ret =pfm_arch_context_create (ctx, ctx_flags); +if (ret) + goto error_set; + + ret = -ENOMEM ; + +/* +* add initial set +*/ +pfm_create_initial_set (ctx); + + filp->private_data = ctx; + + ctx->last_act =PFM_INVALID_ACTIVATION ; + ctx->last_cpu =-1 ; + +PFM_DBG ("flags=0x%x fd=%d" , ctx_flags, fd); + +/* +* we defer the fd_install until we are certain the call succeeded +* to ensure we do not have to undo its effect. Neither put_filp() +* nor put_unused_fd() undoes the effect of fd_install(). +*/ +fd_install (fd, filp); + +return fd; + +error_set: +put_filp (filp); +put_unused_fd (fd); +error_file: +/* +* calls the right *_put() functions +* calls pfm_release_pmu() +*/ +pfm_free_context (ctx); +return ret; +error_alloc: +return ret; +}
perfmon/perfmon_priv.h +3 -0
@@ -55,6 +55,7 @@int pfm_init_sysfs (void ); +int __pfm_create_context (__u32 ctx_flags);void pfm_free_context (struct pfm_context *ctx);int __pfm_stop (struct pfm_context *ctx);
@@ -63,6 +64,8 @@int __pfm_load_context (struct pfm_context *ctx,struct task_struct *task);int __pfm_unload_context (struct pfm_context *ctx); +int pfm_alloc_fd (struct file **cfile); +ssize_t pfm_sysfs_res_show (char *buf,size_t sz,int what);int pfm_pmu_acquire (void );
perfmon/perfmon_file.c +212 -0
221 lines not on this page · raw message