aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/cell
diff options
context:
space:
mode:
authorMichael Ellerman <michael@ellerman.id.au>2007-09-19 00:38:12 -0400
committerPaul Mackerras <paulus@samba.org>2007-09-19 01:12:19 -0400
commit7af1443a9d319132087e1e9a3984b94c6998835c (patch)
treea38fbc03da6201e89a9e850115433df724eba7a4 /arch/powerpc/platforms/cell
parente55014923e65e4ee8e477a1212381cca0125f3aa (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>
Diffstat (limited to 'arch/powerpc/platforms/cell')
-rw-r--r--arch/powerpc/platforms/cell/spu_syscalls.c8
-rw-r--r--arch/powerpc/platforms/cell/spufs/coredump.c89
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h2
3 files changed, 66 insertions, 33 deletions
diff --git a/arch/powerpc/platforms/cell/spu_syscalls.c b/arch/powerpc/platforms/cell/spu_syscalls.c
index b0117a7c610..a9438b719fe 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)
132int elf_coredump_extra_notes_write(struct file *file, loff_t *foffset) 132int 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
150int register_spu_syscalls(struct spufs_calls *calls) 148int 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 6c20e44dba6..6b8aef6d7e6 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 */
54static int spufs_dump_write(struct file *file, const void *addr, int nr) 54static 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
59static int spufs_dump_seek(struct file *file, loff_t off) 67static 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
69static int spufs_ctx_note_size(struct spu_context *ctx, int dfd) 84static 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
144static void spufs_arch_write_note(struct spu_context *ctx, int i, 159static 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));
184out: 211out:
185 free_page((unsigned long)buf); 212 free_page((unsigned long)buf);
213 return rc;
186} 214}
187 215
188void spufs_coredump_extra_notes_write(struct file *file) 216int 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 c7b4e035de4..ca47b991bda 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 */
208extern int spufs_coredump_extra_notes_size(void); 208extern int spufs_coredump_extra_notes_size(void);
209extern void spufs_coredump_extra_notes_write(struct file *file); 209extern int spufs_coredump_extra_notes_write(struct file *file, loff_t *foffset);
210 210
211extern const struct file_operations spufs_context_fops; 211extern const struct file_operations spufs_context_fops;
212 212