Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 42280
b: refs/heads/master
c: bf1ab97
h: refs/heads/master
v: v3
  • Loading branch information
Dwayne Grant McConnell authored and Paul Mackerras committed Dec 4, 2006
1 parent 12f75ee commit cbca080
Show file tree
Hide file tree
Showing 12 changed files with 619 additions and 88 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 9309180f11f0107c9858a61a1ac2b04518a91080
refs/heads/master: bf1ab978be2318c5a564de9aa0f1a217b44170d4
1 change: 1 addition & 0 deletions trunk/arch/powerpc/platforms/cell/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ spufs-modular-$(CONFIG_SPU_FS) += spu_syscalls.o
spu-priv1-$(CONFIG_PPC_CELL_NATIVE) += spu_priv1_mmio.o

obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \
spu_coredump.o \
$(spufs-modular-m) \
$(spu-priv1-y) spufs/
81 changes: 81 additions & 0 deletions trunk/arch/powerpc/platforms/cell/spu_coredump.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* SPU core dump code
*
* (C) Copyright 2006 IBM Corp.
*
* Author: Dwayne Grant McConnell <decimal@us.ibm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <linux/file.h>
#include <linux/module.h>
#include <linux/syscalls.h>

#include <asm/spu.h>

static struct spu_coredump_calls spu_coredump_calls;
static DEFINE_MUTEX(spu_coredump_mutex);

int arch_notes_size(void)
{
long ret;
struct module *owner = spu_coredump_calls.owner;

ret = -ENOSYS;
mutex_lock(&spu_coredump_mutex);
if (owner && try_module_get(owner)) {
ret = spu_coredump_calls.arch_notes_size();
module_put(owner);
}
mutex_unlock(&spu_coredump_mutex);
return ret;
}

void arch_write_notes(struct file *file)
{
struct module *owner = spu_coredump_calls.owner;

mutex_lock(&spu_coredump_mutex);
if (owner && try_module_get(owner)) {
spu_coredump_calls.arch_write_notes(file);
module_put(owner);
}
mutex_unlock(&spu_coredump_mutex);
}

int register_arch_coredump_calls(struct spu_coredump_calls *calls)
{
if (spu_coredump_calls.owner)
return -EBUSY;

mutex_lock(&spu_coredump_mutex);
spu_coredump_calls.arch_notes_size = calls->arch_notes_size;
spu_coredump_calls.arch_write_notes = calls->arch_write_notes;
spu_coredump_calls.owner = calls->owner;
mutex_unlock(&spu_coredump_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(register_arch_coredump_calls);

void unregister_arch_coredump_calls(struct spu_coredump_calls *calls)
{
BUG_ON(spu_coredump_calls.owner != calls->owner);

mutex_lock(&spu_coredump_mutex);
spu_coredump_calls.owner = NULL;
mutex_unlock(&spu_coredump_mutex);
}
EXPORT_SYMBOL_GPL(unregister_arch_coredump_calls);
2 changes: 1 addition & 1 deletion trunk/arch/powerpc/platforms/cell/spufs/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
obj-y += switch.o

obj-$(CONFIG_SPU_FS) += spufs.o
spufs-y += inode.o file.o context.o syscalls.o
spufs-y += inode.o file.o context.o syscalls.o coredump.o
spufs-y += sched.o backing_ops.o hw_ops.o run.o gang.o

# Rules to build switch.o with the help of SPU tool chain
Expand Down
238 changes: 238 additions & 0 deletions trunk/arch/powerpc/platforms/cell/spufs/coredump.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
/*
* SPU core dump code
*
* (C) Copyright 2006 IBM Corp.
*
* Author: Dwayne Grant McConnell <decimal@us.ibm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <linux/elf.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/syscalls.h>

#include <asm/uaccess.h>

#include "spufs.h"

struct spufs_ctx_info {
struct list_head list;
int dfd;
int memsize; /* in bytes */
struct spu_context *ctx;
};

static LIST_HEAD(ctx_info_list);

static ssize_t do_coredump_read(int num, struct spu_context *ctx, void __user *buffer,
size_t size, loff_t *off)
{
u64 data;
int ret;

if (spufs_coredump_read[num].read)
return spufs_coredump_read[num].read(ctx, buffer, size, off);

data = spufs_coredump_read[num].get(ctx);
ret = copy_to_user(buffer, &data, 8);
return ret ? -EFAULT : 8;
}

/*
* 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)
{
return file->f_op->write(file, addr, nr, &file->f_pos) == nr;
}

static int spufs_dump_seek(struct file *file, loff_t off)
{
if (file->f_op->llseek) {
if (file->f_op->llseek(file, off, 0) != off)
return 0;
} else
file->f_pos = off;
return 1;
}

static void spufs_fill_memsize(struct spufs_ctx_info *ctx_info)
{
struct spu_context *ctx;
unsigned long long lslr;

ctx = ctx_info->ctx;
lslr = ctx->csa.priv2.spu_lslr_RW;
ctx_info->memsize = lslr + 1;
}

static int spufs_ctx_note_size(struct spufs_ctx_info *ctx_info)
{
int dfd, memsize, i, sz, total = 0;
char *name;
char fullname[80];

dfd = ctx_info->dfd;
memsize = ctx_info->memsize;

for (i = 0; spufs_coredump_read[i].name; i++) {
name = spufs_coredump_read[i].name;
sz = spufs_coredump_read[i].size;

sprintf(fullname, "SPU/%d/%s", dfd, name);

total += sizeof(struct elf_note);
total += roundup(strlen(fullname) + 1, 4);
if (!strcmp(name, "mem"))
total += roundup(memsize, 4);
else
total += roundup(sz, 4);
}

return total;
}

static int spufs_add_one_context(struct file *file, int dfd)
{
struct spu_context *ctx;
struct spufs_ctx_info *ctx_info;
int size;

ctx = SPUFS_I(file->f_dentry->d_inode)->i_ctx;
if (ctx->flags & SPU_CREATE_NOSCHED)
return 0;

ctx_info = kzalloc(sizeof(*ctx_info), GFP_KERNEL);
if (unlikely(!ctx_info))
return -ENOMEM;

ctx_info->dfd = dfd;
ctx_info->ctx = ctx;

spufs_fill_memsize(ctx_info);

size = spufs_ctx_note_size(ctx_info);
list_add(&ctx_info->list, &ctx_info_list);
return size;
}

/*
* The additional architecture-specific notes for Cell are various
* context files in the spu context.
*
* This function iterates over all open file descriptors and sees
* if they are a directory in spufs. In that case we use spufs
* internal functionality to dump them without needing to actually
* open the files.
*/
static int spufs_arch_notes_size(void)
{
struct fdtable *fdt = files_fdtable(current->files);
int size = 0, fd;

for (fd = 0; fd < fdt->max_fdset && fd < fdt->max_fds; fd++) {
if (FD_ISSET(fd, fdt->open_fds)) {
struct file *file = fcheck(fd);

if (file && file->f_op == &spufs_context_fops) {
int rval = spufs_add_one_context(file, fd);
if (rval < 0)
break;
size += rval;
}
}
}

return size;
}

static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i,
struct file *file)
{
struct spu_context *ctx;
loff_t pos = 0;
int sz, dfd, rc, total = 0;
const int bufsz = 4096;
char *name;
char fullname[80], *buf;
struct elf_note en;

buf = kmalloc(bufsz, GFP_KERNEL);
if (!buf)
return;

dfd = ctx_info->dfd;
name = spufs_coredump_read[i].name;

if (!strcmp(name, "mem"))
sz = ctx_info->memsize;
else
sz = spufs_coredump_read[i].size;

ctx = ctx_info->ctx;
if (!ctx) {
return;
}

sprintf(fullname, "SPU/%d/%s", dfd, name);
en.n_namesz = strlen(fullname) + 1;
en.n_descsz = sz;
en.n_type = NT_SPU;

if (!spufs_dump_write(file, &en, sizeof(en)))
return;
if (!spufs_dump_write(file, fullname, en.n_namesz))
return;
if (!spufs_dump_seek(file, roundup((unsigned long)file->f_pos, 4)))
return;

do {
rc = do_coredump_read(i, ctx, buf, bufsz, &pos);
if (rc > 0) {
if (!spufs_dump_write(file, buf, rc))
return;
total += rc;
}
} while (rc == bufsz && total < sz);

spufs_dump_seek(file, roundup((unsigned long)file->f_pos
- total + sz, 4));
}

static void spufs_arch_write_notes(struct file *file)
{
int j;
struct spufs_ctx_info *ctx_info, *next;

list_for_each_entry_safe(ctx_info, next, &ctx_info_list, list) {
spu_acquire_saved(ctx_info->ctx);
for (j = 0; j < spufs_coredump_num_notes; j++)
spufs_arch_write_note(ctx_info, j, file);
spu_release(ctx_info->ctx);
list_del(&ctx_info->list);
kfree(ctx_info);
}
}

struct spu_coredump_calls spufs_coredump_calls = {
.arch_notes_size = spufs_arch_notes_size,
.arch_write_notes = spufs_arch_write_notes,
.owner = THIS_MODULE,
};
Loading

0 comments on commit cbca080

Please sign in to comment.