PageRenderTime 17ms CodeModel.GetById 2ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

/arch/powerpc/platforms/cell/spufs/coredump.c

http://github.com/mirrors/linux
C | 201 lines | 144 code | 35 blank | 22 comment | 29 complexity | b49639ee759c5c69f180fd44d1c10143 MD5 | raw file
  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}