diff options
author | Michael Ellerman <michael@ellerman.id.au> | 2007-09-19 00:38:12 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-09-19 01:12:19 -0400 |
commit | 7af1443a9d319132087e1e9a3984b94c6998835c (patch) | |
tree | a38fbc03da6201e89a9e850115433df724eba7a4 | |
parent | e55014923e65e4ee8e477a1212381cca0125f3aa (diff) |
[POWERPC] spufs: Handle errors in SPU coredump code, and support coredump to a pipe
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 <michael@ellerman.id.au>
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r-- | arch/powerpc/platforms/cell/spu_syscalls.c | 8 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/coredump.c | 89 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/spufs.h | 2 | ||||
-rw-r--r-- | 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 b0117a7c6100..a9438b719fe8 100644 --- a/arch/powerpc/platforms/cell/spu_syscalls.c +++ b/arch/powerpc/platforms/cell/spu_syscalls.c | |||
@@ -132,19 +132,17 @@ int elf_coredump_extra_notes_size(void) | |||
132 | int elf_coredump_extra_notes_write(struct file *file, loff_t *foffset) | 132 | int elf_coredump_extra_notes_write(struct file *file, loff_t *foffset) |
133 | { | 133 | { |
134 | struct spufs_calls *calls; | 134 | struct spufs_calls *calls; |
135 | int ret; | ||
135 | 136 | ||
136 | calls = spufs_calls_get(); | 137 | calls = spufs_calls_get(); |
137 | if (!calls) | 138 | if (!calls) |
138 | return 0; | 139 | return 0; |
139 | 140 | ||
140 | calls->coredump_extra_notes_write(file); | 141 | ret = calls->coredump_extra_notes_write(file, foffset); |
141 | 142 | ||
142 | spufs_calls_put(calls); | 143 | spufs_calls_put(calls); |
143 | 144 | ||
144 | /* Fudge foffset for now */ | 145 | return ret; |
145 | *foffset = file->f_pos; | ||
146 | |||
147 | return 0; | ||
148 | } | 146 | } |
149 | 147 | ||
150 | int register_spu_syscalls(struct spufs_calls *calls) | 148 | 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 6c20e44dba63..6b8aef6d7e68 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, | |||
51 | * These are the only things you should do on a core-file: use only these | 51 | * These are the only things you should do on a core-file: use only these |
52 | * functions to write out all the necessary info. | 52 | * functions to write out all the necessary info. |
53 | */ | 53 | */ |
54 | static int spufs_dump_write(struct file *file, const void *addr, int nr) | 54 | static int spufs_dump_write(struct file *file, const void *addr, int nr, loff_t *foffset) |
55 | { | 55 | { |
56 | return file->f_op->write(file, addr, nr, &file->f_pos) == nr; | 56 | ssize_t written; |
57 | |||
58 | written = file->f_op->write(file, addr, nr, &file->f_pos); | ||
59 | *foffset += written; | ||
60 | |||
61 | if (written != nr) | ||
62 | return -EIO; | ||
63 | |||
64 | return 0; | ||
57 | } | 65 | } |
58 | 66 | ||
59 | static int spufs_dump_seek(struct file *file, loff_t off) | 67 | static int spufs_dump_align(struct file *file, char *buf, loff_t new_off, |
68 | loff_t *foffset) | ||
60 | { | 69 | { |
61 | if (file->f_op->llseek) { | 70 | int rc, size; |
62 | if (file->f_op->llseek(file, off, 0) != off) | 71 | |
63 | return 0; | 72 | size = min((loff_t)PAGE_SIZE, new_off - *foffset); |
64 | } else | 73 | memset(buf, 0, size); |
65 | file->f_pos = off; | 74 | |
66 | return 1; | 75 | rc = 0; |
76 | while (rc == 0 && new_off > *foffset) { | ||
77 | size = min((loff_t)PAGE_SIZE, new_off - *foffset); | ||
78 | rc = spufs_dump_write(file, buf, size, foffset); | ||
79 | } | ||
80 | |||
81 | return rc; | ||
67 | } | 82 | } |
68 | 83 | ||
69 | static int spufs_ctx_note_size(struct spu_context *ctx, int dfd) | 84 | static int spufs_ctx_note_size(struct spu_context *ctx, int dfd) |
@@ -141,11 +156,11 @@ int spufs_coredump_extra_notes_size(void) | |||
141 | return size; | 156 | return size; |
142 | } | 157 | } |
143 | 158 | ||
144 | static void spufs_arch_write_note(struct spu_context *ctx, int i, | 159 | static int spufs_arch_write_note(struct spu_context *ctx, int i, |
145 | struct file *file, int dfd) | 160 | struct file *file, int dfd, loff_t *foffset) |
146 | { | 161 | { |
147 | loff_t pos = 0; | 162 | loff_t pos = 0; |
148 | int sz, rc, total = 0; | 163 | int sz, rc, nread, total = 0; |
149 | const int bufsz = PAGE_SIZE; | 164 | const int bufsz = PAGE_SIZE; |
150 | char *name; | 165 | char *name; |
151 | char fullname[80], *buf; | 166 | char fullname[80], *buf; |
@@ -153,7 +168,7 @@ static void spufs_arch_write_note(struct spu_context *ctx, int i, | |||
153 | 168 | ||
154 | buf = (void *)get_zeroed_page(GFP_KERNEL); | 169 | buf = (void *)get_zeroed_page(GFP_KERNEL); |
155 | if (!buf) | 170 | if (!buf) |
156 | return; | 171 | return -ENOMEM; |
157 | 172 | ||
158 | name = spufs_coredump_read[i].name; | 173 | name = spufs_coredump_read[i].name; |
159 | sz = spufs_coredump_read[i].size; | 174 | sz = spufs_coredump_read[i].size; |
@@ -163,40 +178,60 @@ static void spufs_arch_write_note(struct spu_context *ctx, int i, | |||
163 | en.n_descsz = sz; | 178 | en.n_descsz = sz; |
164 | en.n_type = NT_SPU; | 179 | en.n_type = NT_SPU; |
165 | 180 | ||
166 | if (!spufs_dump_write(file, &en, sizeof(en))) | 181 | rc = spufs_dump_write(file, &en, sizeof(en), foffset); |
182 | if (rc) | ||
167 | goto out; | 183 | goto out; |
168 | if (!spufs_dump_write(file, fullname, en.n_namesz)) | 184 | |
185 | rc = spufs_dump_write(file, fullname, en.n_namesz, foffset); | ||
186 | if (rc) | ||
169 | goto out; | 187 | goto out; |
170 | if (!spufs_dump_seek(file, roundup((unsigned long)file->f_pos, 4))) | 188 | |
189 | rc = spufs_dump_align(file, buf, roundup(*foffset, 4), foffset); | ||
190 | if (rc) | ||
171 | goto out; | 191 | goto out; |
172 | 192 | ||
173 | do { | 193 | do { |
174 | rc = do_coredump_read(i, ctx, buf, bufsz, &pos); | 194 | nread = do_coredump_read(i, ctx, buf, bufsz, &pos); |
175 | if (rc > 0) { | 195 | if (nread > 0) { |
176 | if (!spufs_dump_write(file, buf, rc)) | 196 | rc = spufs_dump_write(file, buf, nread, foffset); |
197 | if (rc) | ||
177 | goto out; | 198 | goto out; |
178 | total += rc; | 199 | total += nread; |
179 | } | 200 | } |
180 | } while (rc == bufsz && total < sz); | 201 | } while (nread == bufsz && total < sz); |
202 | |||
203 | if (nread < 0) { | ||
204 | rc = nread; | ||
205 | goto out; | ||
206 | } | ||
207 | |||
208 | rc = spufs_dump_align(file, buf, roundup(*foffset - total + sz, 4), | ||
209 | foffset); | ||
181 | 210 | ||
182 | spufs_dump_seek(file, roundup((unsigned long)file->f_pos | ||
183 | - total + sz, 4)); | ||
184 | out: | 211 | out: |
185 | free_page((unsigned long)buf); | 212 | free_page((unsigned long)buf); |
213 | return rc; | ||
186 | } | 214 | } |
187 | 215 | ||
188 | void spufs_coredump_extra_notes_write(struct file *file) | 216 | int spufs_coredump_extra_notes_write(struct file *file, loff_t *foffset) |
189 | { | 217 | { |
190 | struct spu_context *ctx; | 218 | struct spu_context *ctx; |
191 | int fd, j; | 219 | int fd, j, rc; |
192 | 220 | ||
193 | fd = 0; | 221 | fd = 0; |
194 | while ((ctx = coredump_next_context(&fd)) != NULL) { | 222 | while ((ctx = coredump_next_context(&fd)) != NULL) { |
195 | spu_acquire_saved(ctx); | 223 | spu_acquire_saved(ctx); |
196 | 224 | ||
197 | for (j = 0; spufs_coredump_read[j].name != NULL; j++) | 225 | for (j = 0; spufs_coredump_read[j].name != NULL; j++) { |
198 | spufs_arch_write_note(ctx, j, file, fd); | 226 | rc = spufs_arch_write_note(ctx, j, file, fd, foffset); |
227 | if (rc) { | ||
228 | spu_release_saved(ctx); | ||
229 | return rc; | ||
230 | } | ||
231 | } | ||
199 | 232 | ||
200 | spu_release_saved(ctx); | 233 | spu_release_saved(ctx); |
201 | } | 234 | } |
235 | |||
236 | return 0; | ||
202 | } | 237 | } |
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index c7b4e035de48..ca47b991bda5 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h | |||
@@ -206,7 +206,7 @@ long spufs_create(struct nameidata *nd, unsigned int flags, | |||
206 | mode_t mode, struct file *filp); | 206 | mode_t mode, struct file *filp); |
207 | /* ELF coredump callbacks for writing SPU ELF notes */ | 207 | /* ELF coredump callbacks for writing SPU ELF notes */ |
208 | extern int spufs_coredump_extra_notes_size(void); | 208 | extern int spufs_coredump_extra_notes_size(void); |
209 | extern void spufs_coredump_extra_notes_write(struct file *file); | 209 | extern int spufs_coredump_extra_notes_write(struct file *file, loff_t *foffset); |
210 | 210 | ||
211 | extern const struct file_operations spufs_context_fops; | 211 | extern const struct file_operations spufs_context_fops; |
212 | 212 | ||
diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index f1b10a187987..b1accce77bb5 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h | |||
@@ -245,7 +245,7 @@ struct spufs_calls { | |||
245 | long (*spu_run)(struct file *filp, __u32 __user *unpc, | 245 | long (*spu_run)(struct file *filp, __u32 __user *unpc, |
246 | __u32 __user *ustatus); | 246 | __u32 __user *ustatus); |
247 | int (*coredump_extra_notes_size)(void); | 247 | int (*coredump_extra_notes_size)(void); |
248 | void (*coredump_extra_notes_write)(struct file *file); | 248 | int (*coredump_extra_notes_write)(struct file *file, loff_t *foffset); |
249 | struct module *owner; | 249 | struct module *owner; |
250 | }; | 250 | }; |
251 | 251 | ||