Subject: spufs: Remove ctx_info and ctx_info_list From: Michael Ellerman Remove the ctx_info struct entirely, and also the ctx_info_list. This fixes a race where two processes can clobber each other's ctx_info structs. Instead of using the list, we just repeat the search through the file descriptor table. Signed-off-by: Michael Ellerman Signed-off-by: Arnd Bergmann --- Index: linux-2.6/arch/powerpc/platforms/cell/spufs/coredump.c =================================================================== --- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/coredump.c +++ linux-2.6/arch/powerpc/platforms/cell/spufs/coredump.c @@ -31,15 +31,6 @@ #include "spufs.h" -struct spufs_ctx_info { - struct list_head list; - int dfd; - int memsize; /* in bytes */ - struct spu_context *ctx; -}; - -static LIST_HEAD(ctx_info_list); - static ssize_t do_coredump_read(int num, struct spu_context *ctx, void __user *buffer, size_t size, loff_t *off) { @@ -73,25 +64,17 @@ static int spufs_dump_seek(struct file * return 1; } -static void spufs_fill_memsize(struct spufs_ctx_info *ctx_info) +static u64 ctx_ls_size(struct spu_context *ctx) { - struct spu_context *ctx; - unsigned long long lslr; - - ctx = ctx_info->ctx; - lslr = ctx->csa.priv2.spu_lslr_RW; - ctx_info->memsize = lslr + 1; + return ctx->csa.priv2.spu_lslr_RW + 1; } -static int spufs_ctx_note_size(struct spufs_ctx_info *ctx_info) +static int spufs_ctx_note_size(struct spu_context *ctx, int dfd) { - int dfd, memsize, i, sz, total = 0; + int i, sz, total = 0; char *name; char fullname[80]; - dfd = ctx_info->dfd; - memsize = ctx_info->memsize; - for (i = 0; spufs_coredump_read[i].name; i++) { name = spufs_coredump_read[i].name; sz = spufs_coredump_read[i].size; @@ -101,7 +84,7 @@ static int spufs_ctx_note_size(struct sp total += sizeof(struct elf_note); total += roundup(strlen(fullname) + 1, 4); if (!strcmp(name, "mem")) - total += roundup(memsize, 4); + total += roundup(ctx_ls_size(ctx), 4); else total += roundup(sz, 4); } @@ -109,30 +92,6 @@ static int spufs_ctx_note_size(struct sp return total; } -static int spufs_add_one_context(struct file *file, int dfd) -{ - struct spu_context *ctx; - struct spufs_ctx_info *ctx_info; - int size; - - ctx = SPUFS_I(file->f_dentry->d_inode)->i_ctx; - if (ctx->flags & SPU_CREATE_NOSCHED) - return 0; - - ctx_info = kzalloc(sizeof(*ctx_info), GFP_KERNEL); - if (unlikely(!ctx_info)) - return -ENOMEM; - - ctx_info->dfd = dfd; - ctx_info->ctx = ctx; - - spufs_fill_memsize(ctx_info); - - size = spufs_ctx_note_size(ctx_info); - list_add(&ctx_info->list, &ctx_info_list); - return size; -} - /* * The additional architecture-specific notes for Cell are various * context files in the spu context. @@ -142,33 +101,57 @@ static int spufs_add_one_context(struct * internal functionality to dump them without needing to actually * open the files. */ -static int spufs_arch_notes_size(void) +static struct spu_context *coredump_next_context(int *fd) { struct fdtable *fdt = files_fdtable(current->files); - int size = 0, fd; + struct file *file; + struct spu_context *ctx = NULL; - for (fd = 0; fd < fdt->max_fds; fd++) { - if (FD_ISSET(fd, fdt->open_fds)) { - struct file *file = fcheck(fd); - - if (file && file->f_op == &spufs_context_fops) { - int rval = spufs_add_one_context(file, fd); - if (rval < 0) - break; - size += rval; - } - } + for (; *fd < fdt->max_fds; (*fd)++) { + if (!FD_ISSET(*fd, fdt->open_fds)) + continue; + + file = fcheck(*fd); + + if (!file || file->f_op != &spufs_context_fops) + continue; + + ctx = SPUFS_I(file->f_dentry->d_inode)->i_ctx; + if (ctx->flags & SPU_CREATE_NOSCHED) + continue; + + /* start searching the next fd next time we're called */ + (*fd)++; + break; } - return size; + return ctx; } -static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i, - struct file *file) +static int spufs_arch_notes_size(void) { struct spu_context *ctx; + int size = 0, rc, fd; + + fd = 0; + while ((ctx = coredump_next_context(&fd)) != NULL) { + spu_acquire_saved(ctx); + rc = spufs_ctx_note_size(ctx, fd); + spu_release_saved(ctx); + if (rc < 0) + break; + + size += rc; + } + + return size; +} + +static void spufs_arch_write_note(struct spu_context *ctx, int i, + struct file *file, int dfd) +{ loff_t pos = 0; - int sz, dfd, rc, total = 0; + int sz, rc, total = 0; const int bufsz = PAGE_SIZE; char *name; char fullname[80], *buf; @@ -178,18 +161,13 @@ static void spufs_arch_write_note(struct if (!buf) return; - dfd = ctx_info->dfd; name = spufs_coredump_read[i].name; if (!strcmp(name, "mem")) - sz = ctx_info->memsize; + sz = ctx_ls_size(ctx); else sz = spufs_coredump_read[i].size; - ctx = ctx_info->ctx; - if (!ctx) - goto out; - sprintf(fullname, "SPU/%d/%s", dfd, name); en.n_namesz = strlen(fullname) + 1; en.n_descsz = sz; @@ -219,16 +197,17 @@ out: static void spufs_arch_write_notes(struct file *file) { - int j; - struct spufs_ctx_info *ctx_info, *next; + struct spu_context *ctx; + int fd, j; + + fd = 0; + while ((ctx = coredump_next_context(&fd)) != NULL) { + spu_acquire_saved(ctx); - list_for_each_entry_safe(ctx_info, next, &ctx_info_list, list) { - spu_acquire_saved(ctx_info->ctx); for (j = 0; j < spufs_coredump_num_notes; j++) - spufs_arch_write_note(ctx_info, j, file); - spu_release_saved(ctx_info->ctx); - list_del(&ctx_info->list); - kfree(ctx_info); + spufs_arch_write_note(ctx, j, file, fd); + + spu_release_saved(ctx); } }