4 * (C) Copyright 2006 IBM Corp.
6 * Author: Dwayne Grant McConnell <decimal@us.ibm.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include <linux/elf.h>
24 #include <linux/file.h>
25 #include <linux/fdtable.h>
27 #include <linux/gfp.h>
28 #include <linux/list.h>
29 #include <linux/syscalls.h>
31 #include <asm/uaccess.h>
35 static ssize_t
do_coredump_read(int num
, struct spu_context
*ctx
, void *buffer
,
36 size_t size
, loff_t
*off
)
41 if (spufs_coredump_read
[num
].read
)
42 return spufs_coredump_read
[num
].read(ctx
, buffer
, size
, off
);
44 data
= spufs_coredump_read
[num
].get(ctx
);
45 ret
= snprintf(buffer
, size
, "0x%.16llx", data
);
48 return ++ret
; /* count trailing NULL */
52 * These are the only things you should do on a core-file: use only these
53 * functions to write out all the necessary info.
55 static int spufs_dump_write(struct file
*file
, const void *addr
, int nr
, loff_t
*foffset
)
57 unsigned long limit
= rlimit(RLIMIT_CORE
);
60 if (*foffset
+ nr
> limit
)
63 written
= file
->f_op
->write(file
, addr
, nr
, &file
->f_pos
);
72 static int spufs_dump_align(struct file
*file
, char *buf
, loff_t new_off
,
77 size
= min((loff_t
)PAGE_SIZE
, new_off
- *foffset
);
81 while (rc
== 0 && new_off
> *foffset
) {
82 size
= min((loff_t
)PAGE_SIZE
, new_off
- *foffset
);
83 rc
= spufs_dump_write(file
, buf
, size
, foffset
);
89 static int spufs_ctx_note_size(struct spu_context
*ctx
, int dfd
)
95 for (i
= 0; spufs_coredump_read
[i
].name
!= NULL
; i
++) {
96 name
= spufs_coredump_read
[i
].name
;
97 sz
= spufs_coredump_read
[i
].size
;
99 sprintf(fullname
, "SPU/%d/%s", dfd
, name
);
101 total
+= sizeof(struct elf_note
);
102 total
+= roundup(strlen(fullname
) + 1, 4);
103 total
+= roundup(sz
, 4);
109 static int match_context(const void *v
, struct file
*file
, unsigned fd
)
111 struct spu_context
*ctx
;
112 if (file
->f_op
!= &spufs_context_fops
)
114 ctx
= SPUFS_I(file_inode(file
))->i_ctx
;
115 if (ctx
->flags
& SPU_CREATE_NOSCHED
)
121 * The additional architecture-specific notes for Cell are various
122 * context files in the spu context.
124 * This function iterates over all open file descriptors and sees
125 * if they are a directory in spufs. In that case we use spufs
126 * internal functionality to dump them without needing to actually
130 * descriptor table is not shared, so files can't change or go away.
132 static struct spu_context
*coredump_next_context(int *fd
)
135 int n
= iterate_fd(current
->files
, *fd
, match_context
, NULL
);
140 return SPUFS_I(file_inode(file
))->i_ctx
;
143 int spufs_coredump_extra_notes_size(void)
145 struct spu_context
*ctx
;
146 int size
= 0, rc
, fd
;
149 while ((ctx
= coredump_next_context(&fd
)) != NULL
) {
150 rc
= spu_acquire_saved(ctx
);
153 rc
= spufs_ctx_note_size(ctx
, fd
);
154 spu_release_saved(ctx
);
160 /* start searching the next fd next time */
167 static int spufs_arch_write_note(struct spu_context
*ctx
, int i
,
168 struct file
*file
, int dfd
, loff_t
*foffset
)
171 int sz
, rc
, nread
, total
= 0;
172 const int bufsz
= PAGE_SIZE
;
174 char fullname
[80], *buf
;
177 buf
= (void *)get_zeroed_page(GFP_KERNEL
);
181 name
= spufs_coredump_read
[i
].name
;
182 sz
= spufs_coredump_read
[i
].size
;
184 sprintf(fullname
, "SPU/%d/%s", dfd
, name
);
185 en
.n_namesz
= strlen(fullname
) + 1;
189 rc
= spufs_dump_write(file
, &en
, sizeof(en
), foffset
);
193 rc
= spufs_dump_write(file
, fullname
, en
.n_namesz
, foffset
);
197 rc
= spufs_dump_align(file
, buf
, roundup(*foffset
, 4), foffset
);
202 nread
= do_coredump_read(i
, ctx
, buf
, bufsz
, &pos
);
204 rc
= spufs_dump_write(file
, buf
, nread
, foffset
);
209 } while (nread
== bufsz
&& total
< sz
);
216 rc
= spufs_dump_align(file
, buf
, roundup(*foffset
- total
+ sz
, 4),
220 free_page((unsigned long)buf
);
224 int spufs_coredump_extra_notes_write(struct file
*file
, loff_t
*foffset
)
226 struct spu_context
*ctx
;
230 while ((ctx
= coredump_next_context(&fd
)) != NULL
) {
231 rc
= spu_acquire_saved(ctx
);
235 for (j
= 0; spufs_coredump_read
[j
].name
!= NULL
; j
++) {
236 rc
= spufs_arch_write_note(ctx
, j
, file
, fd
, foffset
);
238 spu_release_saved(ctx
);
243 spu_release_saved(ctx
);
245 /* start searching the next fd next time */