X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=arch%2Fpowerpc%2Fplatforms%2Fcell%2Fspufs%2Fcoredump.c;h=af116aadba105674617cb97e514996797501dc5c;hb=2a5f2e3e6cd1ce9fb3f8b186b6bc9aa1f1497a92;hp=c65b7178e77b741f65be0ecb5603c5db51050842;hpb=d464fb441071a3d65bde2264c5f97f9ca47ce5c3;p=linux-2.6 diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c index c65b7178e7..af116aadba 100644 --- a/arch/powerpc/platforms/cell/spufs/coredump.c +++ b/arch/powerpc/platforms/cell/spufs/coredump.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -51,24 +52,38 @@ static ssize_t do_coredump_read(int num, struct spu_context *ctx, void *buffer, * These are the only things you should do on a core-file: use only these * functions to write out all the necessary info. */ -static int spufs_dump_write(struct file *file, const void *addr, int nr) +static int spufs_dump_write(struct file *file, const void *addr, int nr, loff_t *foffset) { - return file->f_op->write(file, addr, nr, &file->f_pos) == nr; -} + unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; + ssize_t written; -static int spufs_dump_seek(struct file *file, loff_t off) -{ - if (file->f_op->llseek) { - if (file->f_op->llseek(file, off, 0) != off) - return 0; - } else - file->f_pos = off; - return 1; + if (*foffset + nr > limit) + return -EIO; + + written = file->f_op->write(file, addr, nr, &file->f_pos); + *foffset += written; + + if (written != nr) + return -EIO; + + return 0; } -static u64 ctx_ls_size(struct spu_context *ctx) +static int spufs_dump_align(struct file *file, char *buf, loff_t new_off, + loff_t *foffset) { - return ctx->csa.priv2.spu_lslr_RW + 1; + int rc, size; + + size = min((loff_t)PAGE_SIZE, new_off - *foffset); + memset(buf, 0, size); + + rc = 0; + while (rc == 0 && new_off > *foffset) { + size = min((loff_t)PAGE_SIZE, new_off - *foffset); + rc = spufs_dump_write(file, buf, size, foffset); + } + + return rc; } static int spufs_ctx_note_size(struct spu_context *ctx, int dfd) @@ -77,7 +92,7 @@ static int spufs_ctx_note_size(struct spu_context *ctx, int dfd) char *name; char fullname[80]; - for (i = 0; spufs_coredump_read[i].name; i++) { + for (i = 0; spufs_coredump_read[i].name != NULL; i++) { name = spufs_coredump_read[i].name; sz = spufs_coredump_read[i].size; @@ -85,10 +100,7 @@ static int spufs_ctx_note_size(struct spu_context *ctx, int dfd) total += sizeof(struct elf_note); total += roundup(strlen(fullname) + 1, 4); - if (!strcmp(name, "mem")) - total += roundup(ctx_ls_size(ctx), 4); - else - total += roundup(sz, 4); + total += roundup(sz, 4); } return total; @@ -122,38 +134,41 @@ static struct spu_context *coredump_next_context(int *fd) if (ctx->flags & SPU_CREATE_NOSCHED) continue; - /* start searching the next fd next time we're called */ - (*fd)++; break; } return ctx; } -static int spufs_arch_notes_size(void) +int spufs_coredump_extra_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 = spu_acquire_saved(ctx); + if (rc) + break; rc = spufs_ctx_note_size(ctx, fd); spu_release_saved(ctx); if (rc < 0) break; size += rc; + + /* start searching the next fd next time */ + fd++; } return size; } -static void spufs_arch_write_note(struct spu_context *ctx, int i, - struct file *file, int dfd) +static int spufs_arch_write_note(struct spu_context *ctx, int i, + struct file *file, int dfd, loff_t *foffset) { loff_t pos = 0; - int sz, rc, total = 0; + int sz, rc, nread, total = 0; const int bufsz = PAGE_SIZE; char *name; char fullname[80], *buf; @@ -161,60 +176,75 @@ static void spufs_arch_write_note(struct spu_context *ctx, int i, buf = (void *)get_zeroed_page(GFP_KERNEL); if (!buf) - return; + return -ENOMEM; name = spufs_coredump_read[i].name; - - if (!strcmp(name, "mem")) - sz = ctx_ls_size(ctx); - else - sz = spufs_coredump_read[i].size; + sz = spufs_coredump_read[i].size; sprintf(fullname, "SPU/%d/%s", dfd, name); en.n_namesz = strlen(fullname) + 1; en.n_descsz = sz; en.n_type = NT_SPU; - if (!spufs_dump_write(file, &en, sizeof(en))) + rc = spufs_dump_write(file, &en, sizeof(en), foffset); + if (rc) goto out; - if (!spufs_dump_write(file, fullname, en.n_namesz)) + + rc = spufs_dump_write(file, fullname, en.n_namesz, foffset); + if (rc) goto out; - if (!spufs_dump_seek(file, roundup((unsigned long)file->f_pos, 4))) + + rc = spufs_dump_align(file, buf, roundup(*foffset, 4), foffset); + if (rc) goto out; do { - rc = do_coredump_read(i, ctx, buf, bufsz, &pos); - if (rc > 0) { - if (!spufs_dump_write(file, buf, rc)) + nread = do_coredump_read(i, ctx, buf, bufsz, &pos); + if (nread > 0) { + rc = spufs_dump_write(file, buf, nread, foffset); + if (rc) goto out; - total += rc; + total += nread; } - } while (rc == bufsz && total < sz); + } while (nread == bufsz && total < sz); + + if (nread < 0) { + rc = nread; + goto out; + } + + rc = spufs_dump_align(file, buf, roundup(*foffset - total + sz, 4), + foffset); - spufs_dump_seek(file, roundup((unsigned long)file->f_pos - - total + sz, 4)); out: free_page((unsigned long)buf); + return rc; } -static void spufs_arch_write_notes(struct file *file) +int spufs_coredump_extra_notes_write(struct file *file, loff_t *foffset) { struct spu_context *ctx; - int fd, j; + int fd, j, rc; fd = 0; while ((ctx = coredump_next_context(&fd)) != NULL) { - spu_acquire_saved(ctx); - - for (j = 0; j < spufs_coredump_num_notes; j++) - spufs_arch_write_note(ctx, j, file, fd); + rc = spu_acquire_saved(ctx); + if (rc) + return rc; + + for (j = 0; spufs_coredump_read[j].name != NULL; j++) { + rc = spufs_arch_write_note(ctx, j, file, fd, foffset); + if (rc) { + spu_release_saved(ctx); + return rc; + } + } spu_release_saved(ctx); + + /* start searching the next fd next time */ + fd++; } -} -struct spu_coredump_calls spufs_coredump_calls = { - .arch_notes_size = spufs_arch_notes_size, - .arch_write_notes = spufs_arch_write_notes, - .owner = THIS_MODULE, -}; + return 0; +}