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