aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAl Viro <viro@ftp.linux.org.uk>2008-05-01 17:36:36 -0400
committerTony Luck <tony.luck@intel.com>2008-05-01 17:36:36 -0400
commitf8e811b98935f702b48abc92563462a15c226eb8 (patch)
tree5446de054b7d168c118783df77577f14d4055d81 /arch
parent848376c774a941c29e4fa083d96d84a5f2190857 (diff)
[IA64] fix file and descriptor handling in perfmon
Races galore... General rule: as soon as it's in descriptor table, it's over; another thread might have started IO on it/dup2() it elsewhere/dup2() something *over* it/etc. fd_install() is the very last step one should take - it's a point of no return. Besides, the damn thing leaked on failure exits... Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/ia64/kernel/perfmon.c199
1 files changed, 87 insertions, 112 deletions
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index 7fbb51e10bbe..c1ad27de2dd2 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -867,7 +867,7 @@ pfm_rvfree(void *mem, unsigned long size)
867} 867}
868 868
869static pfm_context_t * 869static pfm_context_t *
870pfm_context_alloc(void) 870pfm_context_alloc(int ctx_flags)
871{ 871{
872 pfm_context_t *ctx; 872 pfm_context_t *ctx;
873 873
@@ -878,6 +878,46 @@ pfm_context_alloc(void)
878 ctx = kzalloc(sizeof(pfm_context_t), GFP_KERNEL); 878 ctx = kzalloc(sizeof(pfm_context_t), GFP_KERNEL);
879 if (ctx) { 879 if (ctx) {
880 DPRINT(("alloc ctx @%p\n", ctx)); 880 DPRINT(("alloc ctx @%p\n", ctx));
881
882 /*
883 * init context protection lock
884 */
885 spin_lock_init(&ctx->ctx_lock);
886
887 /*
888 * context is unloaded
889 */
890 ctx->ctx_state = PFM_CTX_UNLOADED;
891
892 /*
893 * initialization of context's flags
894 */
895 ctx->ctx_fl_block = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0;
896 ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0;
897 ctx->ctx_fl_no_msg = (ctx_flags & PFM_FL_OVFL_NO_MSG) ? 1: 0;
898 /*
899 * will move to set properties
900 * ctx->ctx_fl_excl_idle = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0;
901 */
902
903 /*
904 * init restart semaphore to locked
905 */
906 init_completion(&ctx->ctx_restart_done);
907
908 /*
909 * activation is used in SMP only
910 */
911 ctx->ctx_last_activation = PFM_INVALID_ACTIVATION;
912 SET_LAST_CPU(ctx, -1);
913
914 /*
915 * initialize notification message queue
916 */
917 ctx->ctx_msgq_head = ctx->ctx_msgq_tail = 0;
918 init_waitqueue_head(&ctx->ctx_msgq_wait);
919 init_waitqueue_head(&ctx->ctx_zombieq);
920
881 } 921 }
882 return ctx; 922 return ctx;
883} 923}
@@ -2165,28 +2205,21 @@ static struct dentry_operations pfmfs_dentry_operations = {
2165}; 2205};
2166 2206
2167 2207
2168static int 2208static struct file *
2169pfm_alloc_fd(struct file **cfile) 2209pfm_alloc_file(pfm_context_t *ctx)
2170{ 2210{
2171 int fd, ret = 0; 2211 struct file *file;
2172 struct file *file = NULL; 2212 struct inode *inode;
2173 struct inode * inode; 2213 struct dentry *dentry;
2174 char name[32]; 2214 char name[32];
2175 struct qstr this; 2215 struct qstr this;
2176 2216
2177 fd = get_unused_fd();
2178 if (fd < 0) return -ENFILE;
2179
2180 ret = -ENFILE;
2181
2182 file = get_empty_filp();
2183 if (!file) goto out;
2184
2185 /* 2217 /*
2186 * allocate a new inode 2218 * allocate a new inode
2187 */ 2219 */
2188 inode = new_inode(pfmfs_mnt->mnt_sb); 2220 inode = new_inode(pfmfs_mnt->mnt_sb);
2189 if (!inode) goto out; 2221 if (!inode)
2222 return ERR_PTR(-ENOMEM);
2190 2223
2191 DPRINT(("new inode ino=%ld @%p\n", inode->i_ino, inode)); 2224 DPRINT(("new inode ino=%ld @%p\n", inode->i_ino, inode));
2192 2225
@@ -2199,59 +2232,28 @@ pfm_alloc_fd(struct file **cfile)
2199 this.len = strlen(name); 2232 this.len = strlen(name);
2200 this.hash = inode->i_ino; 2233 this.hash = inode->i_ino;
2201 2234
2202 ret = -ENOMEM;
2203
2204 /* 2235 /*
2205 * allocate a new dcache entry 2236 * allocate a new dcache entry
2206 */ 2237 */
2207 file->f_path.dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this); 2238 dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this);
2208 if (!file->f_path.dentry) goto out; 2239 if (!dentry) {
2240 iput(inode);
2241 return ERR_PTR(-ENOMEM);
2242 }
2209 2243
2210 file->f_path.dentry->d_op = &pfmfs_dentry_operations; 2244 dentry->d_op = &pfmfs_dentry_operations;
2245 d_add(dentry, inode);
2211 2246
2212 d_add(file->f_path.dentry, inode); 2247 file = alloc_file(pfmfs_mnt, dentry, FMODE_READ, &pfm_file_ops);
2213 file->f_path.mnt = mntget(pfmfs_mnt); 2248 if (!file) {
2214 file->f_mapping = inode->i_mapping; 2249 dput(dentry);
2250 return ERR_PTR(-ENFILE);
2251 }
2215 2252
2216 file->f_op = &pfm_file_ops;
2217 file->f_mode = FMODE_READ;
2218 file->f_flags = O_RDONLY; 2253 file->f_flags = O_RDONLY;
2219 file->f_pos = 0; 2254 file->private_data = ctx;
2220
2221 /*
2222 * may have to delay until context is attached?
2223 */
2224 fd_install(fd, file);
2225
2226 /*
2227 * the file structure we will use
2228 */
2229 *cfile = file;
2230
2231 return fd;
2232out:
2233 if (file) put_filp(file);
2234 put_unused_fd(fd);
2235 return ret;
2236}
2237
2238static void
2239pfm_free_fd(int fd, struct file *file)
2240{
2241 struct files_struct *files = current->files;
2242 struct fdtable *fdt;
2243 2255
2244 /* 2256 return file;
2245 * there ie no fd_uninstall(), so we do it here
2246 */
2247 spin_lock(&files->file_lock);
2248 fdt = files_fdtable(files);
2249 rcu_assign_pointer(fdt->fd[fd], NULL);
2250 spin_unlock(&files->file_lock);
2251
2252 if (file)
2253 put_filp(file);
2254 put_unused_fd(fd);
2255} 2257}
2256 2258
2257static int 2259static int
@@ -2475,6 +2477,7 @@ pfm_setup_buffer_fmt(struct task_struct *task, struct file *filp, pfm_context_t
2475 2477
2476 /* link buffer format and context */ 2478 /* link buffer format and context */
2477 ctx->ctx_buf_fmt = fmt; 2479 ctx->ctx_buf_fmt = fmt;
2480 ctx->ctx_fl_is_sampling = 1; /* assume record() is defined */
2478 2481
2479 /* 2482 /*
2480 * check if buffer format wants to use perfmon buffer allocation/mapping service 2483 * 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
2669{ 2672{
2670 pfarg_context_t *req = (pfarg_context_t *)arg; 2673 pfarg_context_t *req = (pfarg_context_t *)arg;
2671 struct file *filp; 2674 struct file *filp;
2675 struct path path;
2672 int ctx_flags; 2676 int ctx_flags;
2677 int fd;
2673 int ret; 2678 int ret;
2674 2679
2675 /* let's check the arguments first */ 2680 /* let's check the arguments first */
2676 ret = pfarg_is_sane(current, req); 2681 ret = pfarg_is_sane(current, req);
2677 if (ret < 0) return ret; 2682 if (ret < 0)
2683 return ret;
2678 2684
2679 ctx_flags = req->ctx_flags; 2685 ctx_flags = req->ctx_flags;
2680 2686
2681 ret = -ENOMEM; 2687 ret = -ENOMEM;
2682 2688
2683 ctx = pfm_context_alloc(); 2689 fd = get_unused_fd();
2684 if (!ctx) goto error; 2690 if (fd < 0)
2691 return fd;
2685 2692
2686 ret = pfm_alloc_fd(&filp); 2693 ctx = pfm_context_alloc(ctx_flags);
2687 if (ret < 0) goto error_file; 2694 if (!ctx)
2695 goto error;
2688 2696
2689 req->ctx_fd = ctx->ctx_fd = ret; 2697 filp = pfm_alloc_file(ctx);
2698 if (IS_ERR(filp)) {
2699 ret = PTR_ERR(filp);
2700 goto error_file;
2701 }
2690 2702
2691 /* 2703 req->ctx_fd = ctx->ctx_fd = fd;
2692 * attach context to file
2693 */
2694 filp->private_data = ctx;
2695 2704
2696 /* 2705 /*
2697 * does the user want to sample? 2706 * does the user want to sample?
2698 */ 2707 */
2699 if (pfm_uuid_cmp(req->ctx_smpl_buf_id, pfm_null_uuid)) { 2708 if (pfm_uuid_cmp(req->ctx_smpl_buf_id, pfm_null_uuid)) {
2700 ret = pfm_setup_buffer_fmt(current, filp, ctx, ctx_flags, 0, req); 2709 ret = pfm_setup_buffer_fmt(current, filp, ctx, ctx_flags, 0, req);
2701 if (ret) goto buffer_error; 2710 if (ret)
2711 goto buffer_error;
2702 } 2712 }
2703 2713
2704 /*
2705 * init context protection lock
2706 */
2707 spin_lock_init(&ctx->ctx_lock);
2708
2709 /*
2710 * context is unloaded
2711 */
2712 ctx->ctx_state = PFM_CTX_UNLOADED;
2713
2714 /*
2715 * initialization of context's flags
2716 */
2717 ctx->ctx_fl_block = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0;
2718 ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0;
2719 ctx->ctx_fl_is_sampling = ctx->ctx_buf_fmt ? 1 : 0; /* assume record() is defined */
2720 ctx->ctx_fl_no_msg = (ctx_flags & PFM_FL_OVFL_NO_MSG) ? 1: 0;
2721 /*
2722 * will move to set properties
2723 * ctx->ctx_fl_excl_idle = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0;
2724 */
2725
2726 /*
2727 * init restart semaphore to locked
2728 */
2729 init_completion(&ctx->ctx_restart_done);
2730
2731 /*
2732 * activation is used in SMP only
2733 */
2734 ctx->ctx_last_activation = PFM_INVALID_ACTIVATION;
2735 SET_LAST_CPU(ctx, -1);
2736
2737 /*
2738 * initialize notification message queue
2739 */
2740 ctx->ctx_msgq_head = ctx->ctx_msgq_tail = 0;
2741 init_waitqueue_head(&ctx->ctx_msgq_wait);
2742 init_waitqueue_head(&ctx->ctx_zombieq);
2743
2744 DPRINT(("ctx=%p flags=0x%x system=%d notify_block=%d excl_idle=%d no_msg=%d ctx_fd=%d \n", 2714 DPRINT(("ctx=%p flags=0x%x system=%d notify_block=%d excl_idle=%d no_msg=%d ctx_fd=%d \n",
2745 ctx, 2715 ctx,
2746 ctx_flags, 2716 ctx_flags,
@@ -2755,10 +2725,14 @@ pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg
2755 */ 2725 */
2756 pfm_reset_pmu_state(ctx); 2726 pfm_reset_pmu_state(ctx);
2757 2727
2728 fd_install(fd, filp);
2729
2758 return 0; 2730 return 0;
2759 2731
2760buffer_error: 2732buffer_error:
2761 pfm_free_fd(ctx->ctx_fd, filp); 2733 path = filp->f_path;
2734 put_filp(filp);
2735 path_put(&path);
2762 2736
2763 if (ctx->ctx_buf_fmt) { 2737 if (ctx->ctx_buf_fmt) {
2764 pfm_buf_fmt_exit(ctx->ctx_buf_fmt, current, NULL, regs); 2738 pfm_buf_fmt_exit(ctx->ctx_buf_fmt, current, NULL, regs);
@@ -2767,6 +2741,7 @@ error_file:
2767 pfm_context_free(ctx); 2741 pfm_context_free(ctx);
2768 2742
2769error: 2743error:
2744 put_unused_fd(fd);
2770 return ret; 2745 return ret;
2771} 2746}
2772 2747