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>
30 #include <linux/coredump.h>
31 #include <linux/binfmts.h>
33 #include <asm/uaccess.h>
37 static ssize_t
do_coredump_read(int num
, struct spu_context
*ctx
, void *buffer
,
38 size_t size
, loff_t
*off
)
43 if (spufs_coredump_read
[num
].read
)
44 return spufs_coredump_read
[num
].read(ctx
, buffer
, size
, off
);
46 data
= spufs_coredump_read
[num
].get(ctx
);
47 ret
= snprintf(buffer
, size
, "0x%.16llx", data
);
50 return ++ret
; /* count trailing NULL */
53 static int spufs_ctx_note_size(struct spu_context
*ctx
, int dfd
)
59 for (i
= 0; spufs_coredump_read
[i
].name
!= NULL
; i
++) {
60 name
= spufs_coredump_read
[i
].name
;
61 sz
= spufs_coredump_read
[i
].size
;
63 sprintf(fullname
, "SPU/%d/%s", dfd
, name
);
65 total
+= sizeof(struct elf_note
);
66 total
+= roundup(strlen(fullname
) + 1, 4);
67 total
+= roundup(sz
, 4);
73 static int match_context(const void *v
, struct file
*file
, unsigned fd
)
75 struct spu_context
*ctx
;
76 if (file
->f_op
!= &spufs_context_fops
)
78 ctx
= SPUFS_I(file_inode(file
))->i_ctx
;
79 if (ctx
->flags
& SPU_CREATE_NOSCHED
)
85 * The additional architecture-specific notes for Cell are various
86 * context files in the spu context.
88 * This function iterates over all open file descriptors and sees
89 * if they are a directory in spufs. In that case we use spufs
90 * internal functionality to dump them without needing to actually
94 * descriptor table is not shared, so files can't change or go away.
96 static struct spu_context
*coredump_next_context(int *fd
)
99 int n
= iterate_fd(current
->files
, *fd
, match_context
, NULL
);
104 return SPUFS_I(file_inode(file
))->i_ctx
;
107 int spufs_coredump_extra_notes_size(void)
109 struct spu_context
*ctx
;
110 int size
= 0, rc
, fd
;
113 while ((ctx
= coredump_next_context(&fd
)) != NULL
) {
114 rc
= spu_acquire_saved(ctx
);
117 rc
= spufs_ctx_note_size(ctx
, fd
);
118 spu_release_saved(ctx
);
124 /* start searching the next fd next time */
131 static int spufs_arch_write_note(struct spu_context
*ctx
, int i
,
132 struct coredump_params
*cprm
, int dfd
)
135 int sz
, rc
, total
= 0;
136 const int bufsz
= PAGE_SIZE
;
138 char fullname
[80], *buf
;
141 buf
= (void *)get_zeroed_page(GFP_KERNEL
);
145 name
= spufs_coredump_read
[i
].name
;
146 sz
= spufs_coredump_read
[i
].size
;
148 sprintf(fullname
, "SPU/%d/%s", dfd
, name
);
149 en
.n_namesz
= strlen(fullname
) + 1;
153 if (!dump_emit(cprm
, &en
, sizeof(en
)))
156 if (!dump_emit(cprm
, fullname
, en
.n_namesz
))
159 if (!dump_align(cprm
, 4))
163 rc
= do_coredump_read(i
, ctx
, buf
, bufsz
, &pos
);
165 if (!dump_emit(cprm
, buf
, rc
))
169 } while (rc
== bufsz
&& total
< sz
);
175 roundup(cprm
->written
- total
+ sz
, 4) - cprm
->written
))
178 free_page((unsigned long)buf
);
181 free_page((unsigned long)buf
);
185 int spufs_coredump_extra_notes_write(struct coredump_params
*cprm
)
187 struct spu_context
*ctx
;
191 while ((ctx
= coredump_next_context(&fd
)) != NULL
) {
192 rc
= spu_acquire_saved(ctx
);
196 for (j
= 0; spufs_coredump_read
[j
].name
!= NULL
; j
++) {
197 rc
= spufs_arch_write_note(ctx
, j
, cprm
, fd
);
199 spu_release_saved(ctx
);
204 spu_release_saved(ctx
);
206 /* start searching the next fd next time */