diff options
Diffstat (limited to 'arch/ia64/kernel/perfmon.c')
| -rw-r--r-- | arch/ia64/kernel/perfmon.c | 225 | 
1 files changed, 102 insertions, 123 deletions
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 7fbb51e10bb..7714a97b010 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -867,7 +867,7 @@ pfm_rvfree(void *mem, unsigned long size)  }  static pfm_context_t * -pfm_context_alloc(void) +pfm_context_alloc(int ctx_flags)  {  	pfm_context_t *ctx; @@ -878,6 +878,46 @@ pfm_context_alloc(void)  	ctx = kzalloc(sizeof(pfm_context_t), GFP_KERNEL);  	if (ctx) {  		DPRINT(("alloc ctx @%p\n", ctx)); + +		/* +		 * init context protection lock +		 */ +		spin_lock_init(&ctx->ctx_lock); + +		/* +		 * context is unloaded +		 */ +		ctx->ctx_state = PFM_CTX_UNLOADED; + +		/* +		 * initialization of context's flags +		 */ +		ctx->ctx_fl_block       = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0; +		ctx->ctx_fl_system      = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0; +		ctx->ctx_fl_no_msg      = (ctx_flags & PFM_FL_OVFL_NO_MSG) ? 1: 0; +		/* +		 * will move to set properties +		 * ctx->ctx_fl_excl_idle   = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0; +		 */ + +		/* +		 * init restart semaphore to locked +		 */ +		init_completion(&ctx->ctx_restart_done); + +		/* +		 * activation is used in SMP only +		 */ +		ctx->ctx_last_activation = PFM_INVALID_ACTIVATION; +		SET_LAST_CPU(ctx, -1); + +		/* +		 * initialize notification message queue +		 */ +		ctx->ctx_msgq_head = ctx->ctx_msgq_tail = 0; +		init_waitqueue_head(&ctx->ctx_msgq_wait); +		init_waitqueue_head(&ctx->ctx_zombieq); +  	}  	return ctx;  } @@ -1824,11 +1864,6 @@ pfm_flush(struct file *filp, fl_owner_t id)  	 * invoked after, it will find an empty queue and no  	 * signal will be sent. In both case, we are safe  	 */ -	if (filp->f_flags & FASYNC) { -		DPRINT(("cleaning up async_queue=%p\n", ctx->ctx_async_queue)); -		pfm_do_fasync (-1, filp, ctx, 0); -	} -  	PROTECT_CTX(ctx, flags);  	state     = ctx->ctx_state; @@ -1959,6 +1994,11 @@ pfm_close(struct inode *inode, struct file *filp)  		return -EBADF;  	} +	if (filp->f_flags & FASYNC) { +		DPRINT(("cleaning up async_queue=%p\n", ctx->ctx_async_queue)); +		pfm_do_fasync(-1, filp, ctx, 0); +	} +  	PROTECT_CTX(ctx, flags);  	state     = ctx->ctx_state; @@ -2165,28 +2205,21 @@ static struct dentry_operations pfmfs_dentry_operations = {  }; -static int -pfm_alloc_fd(struct file **cfile) +static struct file * +pfm_alloc_file(pfm_context_t *ctx)  { -	int fd, ret = 0; -	struct file *file = NULL; -	struct inode * inode; +	struct file *file; +	struct inode *inode; +	struct dentry *dentry;  	char name[32];  	struct qstr this; -	fd = get_unused_fd(); -	if (fd < 0) return -ENFILE; - -	ret = -ENFILE; - -	file = get_empty_filp(); -	if (!file) goto out; -  	/*  	 * allocate a new inode  	 */  	inode = new_inode(pfmfs_mnt->mnt_sb); -	if (!inode) goto out; +	if (!inode) +		return ERR_PTR(-ENOMEM);  	DPRINT(("new inode ino=%ld @%p\n", inode->i_ino, inode)); @@ -2199,59 +2232,28 @@ pfm_alloc_fd(struct file **cfile)  	this.len  = strlen(name);  	this.hash = inode->i_ino; -	ret = -ENOMEM; -  	/*  	 * allocate a new dcache entry  	 */ -	file->f_path.dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this); -	if (!file->f_path.dentry) goto out; +	dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this); +	if (!dentry) { +		iput(inode); +		return ERR_PTR(-ENOMEM); +	} -	file->f_path.dentry->d_op = &pfmfs_dentry_operations; +	dentry->d_op = &pfmfs_dentry_operations; +	d_add(dentry, inode); -	d_add(file->f_path.dentry, inode); -	file->f_path.mnt = mntget(pfmfs_mnt); -	file->f_mapping = inode->i_mapping; +	file = alloc_file(pfmfs_mnt, dentry, FMODE_READ, &pfm_file_ops); +	if (!file) { +		dput(dentry); +		return ERR_PTR(-ENFILE); +	} -	file->f_op    = &pfm_file_ops; -	file->f_mode  = FMODE_READ;  	file->f_flags = O_RDONLY; -	file->f_pos   = 0; - -	/* -	 * may have to delay until context is attached? -	 */ -	fd_install(fd, file); - -	/* -	 * the file structure we will use -	 */ -	*cfile = file; +	file->private_data = ctx; -	return fd; -out: -	if (file) put_filp(file); -	put_unused_fd(fd); -	return ret; -} - -static void -pfm_free_fd(int fd, struct file *file) -{ -	struct files_struct *files = current->files; -	struct fdtable *fdt; - -	/*  -	 * there ie no fd_uninstall(), so we do it here -	 */ -	spin_lock(&files->file_lock); -	fdt = files_fdtable(files); -	rcu_assign_pointer(fdt->fd[fd], NULL); -	spin_unlock(&files->file_lock); - -	if (file) -		put_filp(file); -	put_unused_fd(fd); +	return file;  }  static int @@ -2475,6 +2477,7 @@ pfm_setup_buffer_fmt(struct task_struct *task, struct file *filp, pfm_context_t  	/* link buffer format and context */  	ctx->ctx_buf_fmt = fmt; +	ctx->ctx_fl_is_sampling = 1; /* assume record() is defined */  	/*  	 * check if buffer format wants to use perfmon buffer allocation/mapping service @@ -2669,78 +2672,45 @@ pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg  {  	pfarg_context_t *req = (pfarg_context_t *)arg;  	struct file *filp; +	struct path path;  	int ctx_flags; +	int fd;  	int ret;  	/* let's check the arguments first */  	ret = pfarg_is_sane(current, req); -	if (ret < 0) return ret; +	if (ret < 0) +		return ret;  	ctx_flags = req->ctx_flags;  	ret = -ENOMEM; -	ctx = pfm_context_alloc(); -	if (!ctx) goto error; +	fd = get_unused_fd(); +	if (fd < 0) +		return fd; -	ret = pfm_alloc_fd(&filp); -	if (ret < 0) goto error_file; +	ctx = pfm_context_alloc(ctx_flags); +	if (!ctx) +		goto error; -	req->ctx_fd = ctx->ctx_fd = ret; +	filp = pfm_alloc_file(ctx); +	if (IS_ERR(filp)) { +		ret = PTR_ERR(filp); +		goto error_file; +	} -	/* -	 * attach context to file -	 */ -	filp->private_data = ctx; +	req->ctx_fd = ctx->ctx_fd = fd;  	/*  	 * does the user want to sample?  	 */  	if (pfm_uuid_cmp(req->ctx_smpl_buf_id, pfm_null_uuid)) {  		ret = pfm_setup_buffer_fmt(current, filp, ctx, ctx_flags, 0, req); -		if (ret) goto buffer_error; +		if (ret) +			goto buffer_error;  	} -	/* -	 * init context protection lock -	 */ -	spin_lock_init(&ctx->ctx_lock); - -	/* -	 * context is unloaded -	 */ -	ctx->ctx_state = PFM_CTX_UNLOADED; - -	/* -	 * initialization of context's flags -	 */ -	ctx->ctx_fl_block       = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0; -	ctx->ctx_fl_system      = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0; -	ctx->ctx_fl_is_sampling = ctx->ctx_buf_fmt ? 1 : 0; /* assume record() is defined */ -	ctx->ctx_fl_no_msg      = (ctx_flags & PFM_FL_OVFL_NO_MSG) ? 1: 0; -	/* -	 * will move to set properties -	 * ctx->ctx_fl_excl_idle   = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0; -	 */ - -	/* -	 * init restart semaphore to locked -	 */ -	init_completion(&ctx->ctx_restart_done); - -	/* -	 * activation is used in SMP only -	 */ -	ctx->ctx_last_activation = PFM_INVALID_ACTIVATION; -	SET_LAST_CPU(ctx, -1); - -	/* -	 * initialize notification message queue -	 */ -	ctx->ctx_msgq_head = ctx->ctx_msgq_tail = 0; -	init_waitqueue_head(&ctx->ctx_msgq_wait); -	init_waitqueue_head(&ctx->ctx_zombieq); -  	DPRINT(("ctx=%p flags=0x%x system=%d notify_block=%d excl_idle=%d no_msg=%d ctx_fd=%d \n",  		ctx,  		ctx_flags, @@ -2755,10 +2725,14 @@ pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg  	 */  	pfm_reset_pmu_state(ctx); +	fd_install(fd, filp); +  	return 0;  buffer_error: -	pfm_free_fd(ctx->ctx_fd, filp); +	path = filp->f_path; +	put_filp(filp); +	path_put(&path);  	if (ctx->ctx_buf_fmt) {  		pfm_buf_fmt_exit(ctx->ctx_buf_fmt, current, NULL, regs); @@ -2767,6 +2741,7 @@ error_file:  	pfm_context_free(ctx);  error: +	put_unused_fd(fd);  	return ret;  } @@ -5038,12 +5013,13 @@ pfm_context_force_terminate(pfm_context_t *ctx, struct pt_regs *regs)  }  static int pfm_ovfl_notify_user(pfm_context_t *ctx, unsigned long ovfl_pmds); +   /*    * pfm_handle_work() can be called with interrupts enabled    * (TIF_NEED_RESCHED) or disabled. The down_interruptible    * call may sleep, therefore we must re-enable interrupts    * to avoid deadlocks. It is safe to do so because this function -  * is called ONLY when returning to user level (PUStk=1), in which case +  * is called ONLY when returning to user level (pUStk=1), in which case    * there is no risk of kernel stack overflow due to deep    * interrupt nesting.    */ @@ -5059,7 +5035,8 @@ pfm_handle_work(void)  	ctx = PFM_GET_CTX(current);  	if (ctx == NULL) { -		printk(KERN_ERR "perfmon: [%d] has no PFM context\n", task_pid_nr(current)); +		printk(KERN_ERR "perfmon: [%d] has no PFM context\n", +			task_pid_nr(current));  		return;  	} @@ -5083,11 +5060,12 @@ pfm_handle_work(void)  	/*  	 * must be done before we check for simple-reset mode  	 */ -	if (ctx->ctx_fl_going_zombie || ctx->ctx_state == PFM_CTX_ZOMBIE) goto do_zombie; - +	if (ctx->ctx_fl_going_zombie || ctx->ctx_state == PFM_CTX_ZOMBIE) +		goto do_zombie;  	//if (CTX_OVFL_NOBLOCK(ctx)) goto skip_blocking; -	if (reason == PFM_TRAP_REASON_RESET) goto skip_blocking; +	if (reason == PFM_TRAP_REASON_RESET) +		goto skip_blocking;  	/*  	 * restore interrupt mask to what it was on entry. @@ -5135,7 +5113,8 @@ do_zombie:  	/*  	 * in case of interruption of down() we don't restart anything  	 */ -	if (ret < 0) goto nothing_to_do; +	if (ret < 0) +		goto nothing_to_do;  skip_blocking:  	pfm_resume_after_ovfl(ctx, ovfl_regs, regs);  |