linux/arch/powerpc/platforms/cell/spufs/coredump.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * SPU core dump code
   4 *
   5 * (C) Copyright 2006 IBM Corp.
   6 *
   7 * Author: Dwayne Grant McConnell <decimal@us.ibm.com>
   8 */
   9
  10#include <linux/elf.h>
  11#include <linux/file.h>
  12#include <linux/fdtable.h>
  13#include <linux/fs.h>
  14#include <linux/gfp.h>
  15#include <linux/list.h>
  16#include <linux/syscalls.h>
  17#include <linux/coredump.h>
  18#include <linux/binfmts.h>
  19
  20#include <linux/uaccess.h>
  21
  22#include "spufs.h"
  23
  24static ssize_t do_coredump_read(int num, struct spu_context *ctx, void *buffer,
  25                                size_t size, loff_t *off)
  26{
  27        u64 data;
  28        int ret;
  29
  30        if (spufs_coredump_read[num].read)
  31                return spufs_coredump_read[num].read(ctx, buffer, size, off);
  32
  33        data = spufs_coredump_read[num].get(ctx);
  34        ret = snprintf(buffer, size, "0x%.16llx", data);
  35        if (ret >= size)
  36                return size;
  37        return ++ret; /* count trailing NULL */
  38}
  39
  40static int spufs_ctx_note_size(struct spu_context *ctx, int dfd)
  41{
  42        int i, sz, total = 0;
  43        char *name;
  44        char fullname[80];
  45
  46        for (i = 0; spufs_coredump_read[i].name != NULL; i++) {
  47                name = spufs_coredump_read[i].name;
  48                sz = spufs_coredump_read[i].size;
  49
  50                sprintf(fullname, "SPU/%d/%s", dfd, name);
  51
  52                total += sizeof(struct elf_note);
  53                total += roundup(strlen(fullname) + 1, 4);
  54                total += roundup(sz, 4);
  55        }
  56
  57        return total;
  58}
  59
  60static int match_context(const void *v, struct file *file, unsigned fd)
  61{
  62        struct spu_context *ctx;
  63        if (file->f_op != &spufs_context_fops)
  64                return 0;
  65        ctx = SPUFS_I(file_inode(file))->i_ctx;
  66        if (ctx->flags & SPU_CREATE_NOSCHED)
  67                return 0;
  68        return fd + 1;
  69}
  70
  71/*
  72 * The additional architecture-specific notes for Cell are various
  73 * context files in the spu context.
  74 *
  75 * This function iterates over all open file descriptors and sees
  76 * if they are a directory in spufs.  In that case we use spufs
  77 * internal functionality to dump them without needing to actually
  78 * open the files.
  79 */
  80/*
  81 * descriptor table is not shared, so files can't change or go away.
  82 */
  83static struct spu_context *coredump_next_context(int *fd)
  84{
  85        struct file *file;
  86        int n = iterate_fd(current->files, *fd, match_context, NULL);
  87        if (!n)
  88                return NULL;
  89        *fd = n - 1;
  90        file = fcheck(*fd);
  91        return SPUFS_I(file_inode(file))->i_ctx;
  92}
  93
  94int spufs_coredump_extra_notes_size(void)
  95{
  96        struct spu_context *ctx;
  97        int size = 0, rc, fd;
  98
  99        fd = 0;
 100        while ((ctx = coredump_next_context(&fd)) != NULL) {
 101                rc = spu_acquire_saved(ctx);
 102                if (rc)
 103                        break;
 104                rc = spufs_ctx_note_size(ctx, fd);
 105                spu_release_saved(ctx);
 106                if (rc < 0)
 107                        break;
 108
 109                size += rc;
 110
 111                /* start searching the next fd next time */
 112                fd++;
 113        }
 114
 115        return size;
 116}
 117
 118static int spufs_arch_write_note(struct spu_context *ctx, int i,
 119                                  struct coredump_params *cprm, int dfd)
 120{
 121        loff_t pos = 0;
 122        int sz, rc, total = 0;
 123        const int bufsz = PAGE_SIZE;
 124        char *name;
 125        char fullname[80], *buf;
 126        struct elf_note en;
 127        size_t skip;
 128
 129        buf = (void *)get_zeroed_page(GFP_KERNEL);
 130        if (!buf)
 131                return -ENOMEM;
 132
 133        name = spufs_coredump_read[i].name;
 134        sz = spufs_coredump_read[i].size;
 135
 136        sprintf(fullname, "SPU/%d/%s", dfd, name);
 137        en.n_namesz = strlen(fullname) + 1;
 138        en.n_descsz = sz;
 139        en.n_type = NT_SPU;
 140
 141        if (!dump_emit(cprm, &en, sizeof(en)))
 142                goto Eio;
 143
 144        if (!dump_emit(cprm, fullname, en.n_namesz))
 145                goto Eio;
 146
 147        if (!dump_align(cprm, 4))
 148                goto Eio;
 149
 150        do {
 151                rc = do_coredump_read(i, ctx, buf, bufsz, &pos);
 152                if (rc > 0) {
 153                        if (!dump_emit(cprm, buf, rc))
 154                                goto Eio;
 155                        total += rc;
 156                }
 157        } while (rc == bufsz && total < sz);
 158
 159        if (rc < 0)
 160                goto out;
 161
 162        skip = roundup(cprm->pos - total + sz, 4) - cprm->pos;
 163        if (!dump_skip(cprm, skip))
 164                goto Eio;
 165
 166        rc = 0;
 167out:
 168        free_page((unsigned long)buf);
 169        return rc;
 170Eio:
 171        free_page((unsigned long)buf);
 172        return -EIO;
 173}
 174
 175int spufs_coredump_extra_notes_write(struct coredump_params *cprm)
 176{
 177        struct spu_context *ctx;
 178        int fd, j, rc;
 179
 180        fd = 0;
 181        while ((ctx = coredump_next_context(&fd)) != NULL) {
 182                rc = spu_acquire_saved(ctx);
 183                if (rc)
 184                        return rc;
 185
 186                for (j = 0; spufs_coredump_read[j].name != NULL; j++) {
 187                        rc = spufs_arch_write_note(ctx, j, cprm, fd);
 188                        if (rc) {
 189                                spu_release_saved(ctx);
 190                                return rc;
 191                        }
 192                }
 193
 194                spu_release_saved(ctx);
 195
 196                /* start searching the next fd next time */
 197                fd++;
 198        }
 199
 200        return 0;
 201}
 202