[PATCH 13/15] Handle errors in SPU coredump code, and support coredump to a pipe

2007-09-12 Thread Michael Ellerman
Rework spufs_coredump_extra_notes_write() to check for and return errors.

If we're coredumping to a pipe we can't trust file->f_pos, we need to
maintain the foffset value passed to us. The cleanest way to do this is
to have the low level write routine increment foffset when we've
successfully written.

Signed-off-by: Michael Ellerman <[EMAIL PROTECTED]>
---
 arch/powerpc/platforms/cell/spu_syscalls.c   |8 +--
 arch/powerpc/platforms/cell/spufs/coredump.c |   89 ++
 arch/powerpc/platforms/cell/spufs/spufs.h|2 +-
 include/asm-powerpc/spu.h|2 +-
 4 files changed, 67 insertions(+), 34 deletions(-)

diff --git a/arch/powerpc/platforms/cell/spu_syscalls.c 
b/arch/powerpc/platforms/cell/spu_syscalls.c
index d9b2fd2..0b69107 100644
--- a/arch/powerpc/platforms/cell/spu_syscalls.c
+++ b/arch/powerpc/platforms/cell/spu_syscalls.c
@@ -129,19 +129,17 @@ int elf_coredump_extra_notes_size(void)
 int elf_coredump_extra_notes_write(struct file *file, loff_t *foffset)
 {
struct spufs_calls *calls;
+   int ret;
 
calls = spufs_calls_get();
if (!calls)
return 0;
 
-   calls->coredump_extra_notes_write(file);
+   ret = calls->coredump_extra_notes_write(file, foffset);
 
spufs_calls_put(calls);
 
-   /* Fudge foffset for now */
-   *foffset = file->f_pos;
-
-   return 0;
+   return ret;
 }
 
 int register_spu_syscalls(struct spufs_calls *calls)
diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c 
b/arch/powerpc/platforms/cell/spufs/coredump.c
index 7395350..c3b5cd5 100644
--- a/arch/powerpc/platforms/cell/spufs/coredump.c
+++ b/arch/powerpc/platforms/cell/spufs/coredump.c
@@ -51,19 +51,34 @@ 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, >f_pos) == nr;
+   ssize_t written;
+
+   written = file->f_op->write(file, addr, nr, >f_pos);
+   *foffset += written;
+
+   if (written != nr)
+   return -EIO;
+
+   return 0;
 }
 
-static int spufs_dump_seek(struct file *file, loff_t off)
+static int spufs_dump_align(struct file *file, char *buf, loff_t new_off,
+   loff_t *foffset)
 {
-   if (file->f_op->llseek) {
-   if (file->f_op->llseek(file, off, 0) != off)
-   return 0;
-   } else
-   file->f_pos = off;
-   return 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)
@@ -141,11 +156,11 @@ int spufs_coredump_extra_notes_size(void)
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;
@@ -153,7 +168,7 @@ 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;
sz = spufs_coredump_read[i].size;
@@ -163,40 +178,60 @@ static void spufs_arch_write_note(struct spu_context 
*ctx, int i,
en.n_descsz = sz;
en.n_type = NT_SPU;
 
-   if (!spufs_dump_write(file, , sizeof(en)))
+   rc = spufs_dump_write(file, , 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, );
-   if (rc > 0) {
-   if (!spufs_dump_write(file, buf, rc))
+   nread = do_coredump_read(i, ctx, buf, bufsz, );
+   if (nread > 0) {
+   rc = 

[PATCH 13/15] Handle errors in SPU coredump code, and support coredump to a pipe

2007-09-12 Thread Michael Ellerman
Rework spufs_coredump_extra_notes_write() to check for and return errors.

If we're coredumping to a pipe we can't trust file-f_pos, we need to
maintain the foffset value passed to us. The cleanest way to do this is
to have the low level write routine increment foffset when we've
successfully written.

Signed-off-by: Michael Ellerman [EMAIL PROTECTED]
---
 arch/powerpc/platforms/cell/spu_syscalls.c   |8 +--
 arch/powerpc/platforms/cell/spufs/coredump.c |   89 ++
 arch/powerpc/platforms/cell/spufs/spufs.h|2 +-
 include/asm-powerpc/spu.h|2 +-
 4 files changed, 67 insertions(+), 34 deletions(-)

diff --git a/arch/powerpc/platforms/cell/spu_syscalls.c 
b/arch/powerpc/platforms/cell/spu_syscalls.c
index d9b2fd2..0b69107 100644
--- a/arch/powerpc/platforms/cell/spu_syscalls.c
+++ b/arch/powerpc/platforms/cell/spu_syscalls.c
@@ -129,19 +129,17 @@ int elf_coredump_extra_notes_size(void)
 int elf_coredump_extra_notes_write(struct file *file, loff_t *foffset)
 {
struct spufs_calls *calls;
+   int ret;
 
calls = spufs_calls_get();
if (!calls)
return 0;
 
-   calls-coredump_extra_notes_write(file);
+   ret = calls-coredump_extra_notes_write(file, foffset);
 
spufs_calls_put(calls);
 
-   /* Fudge foffset for now */
-   *foffset = file-f_pos;
-
-   return 0;
+   return ret;
 }
 
 int register_spu_syscalls(struct spufs_calls *calls)
diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c 
b/arch/powerpc/platforms/cell/spufs/coredump.c
index 7395350..c3b5cd5 100644
--- a/arch/powerpc/platforms/cell/spufs/coredump.c
+++ b/arch/powerpc/platforms/cell/spufs/coredump.c
@@ -51,19 +51,34 @@ 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;
+   ssize_t written;
+
+   written = file-f_op-write(file, addr, nr, file-f_pos);
+   *foffset += written;
+
+   if (written != nr)
+   return -EIO;
+
+   return 0;
 }
 
-static int spufs_dump_seek(struct file *file, loff_t off)
+static int spufs_dump_align(struct file *file, char *buf, loff_t new_off,
+   loff_t *foffset)
 {
-   if (file-f_op-llseek) {
-   if (file-f_op-llseek(file, off, 0) != off)
-   return 0;
-   } else
-   file-f_pos = off;
-   return 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)
@@ -141,11 +156,11 @@ int spufs_coredump_extra_notes_size(void)
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;
@@ -153,7 +168,7 @@ 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;
sz = spufs_coredump_read[i].size;
@@ -163,40 +178,60 @@ static void spufs_arch_write_note(struct spu_context 
*ctx, int i,
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 =