spu_syscalls.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /*
  2. * SPU file system -- system call stubs
  3. *
  4. * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
  5. * (C) Copyright 2006-2007, IBM Corporation
  6. *
  7. * Author: Arnd Bergmann <arndb@de.ibm.com>
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 2, or (at your option)
  12. * any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22. */
  23. #include <linux/file.h>
  24. #include <linux/fs.h>
  25. #include <linux/module.h>
  26. #include <linux/syscalls.h>
  27. #include <linux/rcupdate.h>
  28. #include <linux/binfmts.h>
  29. #include <asm/spu.h>
  30. /* protected by rcu */
  31. static struct spufs_calls *spufs_calls;
  32. #ifdef CONFIG_SPU_FS_MODULE
  33. static inline struct spufs_calls *spufs_calls_get(void)
  34. {
  35. struct spufs_calls *calls = NULL;
  36. rcu_read_lock();
  37. calls = rcu_dereference(spufs_calls);
  38. if (calls && !try_module_get(calls->owner))
  39. calls = NULL;
  40. rcu_read_unlock();
  41. return calls;
  42. }
  43. static inline void spufs_calls_put(struct spufs_calls *calls)
  44. {
  45. BUG_ON(calls != spufs_calls);
  46. /* we don't need to rcu this, as we hold a reference to the module */
  47. module_put(spufs_calls->owner);
  48. }
  49. #else /* !defined CONFIG_SPU_FS_MODULE */
  50. static inline struct spufs_calls *spufs_calls_get(void)
  51. {
  52. return spufs_calls;
  53. }
  54. static inline void spufs_calls_put(struct spufs_calls *calls) { }
  55. #endif /* CONFIG_SPU_FS_MODULE */
  56. SYSCALL_DEFINE4(spu_create, const char __user *, name, unsigned int, flags,
  57. umode_t, mode, int, neighbor_fd)
  58. {
  59. long ret;
  60. struct spufs_calls *calls;
  61. calls = spufs_calls_get();
  62. if (!calls)
  63. return -ENOSYS;
  64. if (flags & SPU_CREATE_AFFINITY_SPU) {
  65. struct fd neighbor = fdget(neighbor_fd);
  66. ret = -EBADF;
  67. if (neighbor.file) {
  68. ret = calls->create_thread(name, flags, mode, neighbor.file);
  69. fdput(neighbor);
  70. }
  71. } else
  72. ret = calls->create_thread(name, flags, mode, NULL);
  73. spufs_calls_put(calls);
  74. return ret;
  75. }
  76. asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus)
  77. {
  78. long ret;
  79. struct fd arg;
  80. struct spufs_calls *calls;
  81. calls = spufs_calls_get();
  82. if (!calls)
  83. return -ENOSYS;
  84. ret = -EBADF;
  85. arg = fdget(fd);
  86. if (arg.file) {
  87. ret = calls->spu_run(arg.file, unpc, ustatus);
  88. fdput(arg);
  89. }
  90. spufs_calls_put(calls);
  91. return ret;
  92. }
  93. #ifdef CONFIG_COREDUMP
  94. int elf_coredump_extra_notes_size(void)
  95. {
  96. struct spufs_calls *calls;
  97. int ret;
  98. calls = spufs_calls_get();
  99. if (!calls)
  100. return 0;
  101. ret = calls->coredump_extra_notes_size();
  102. spufs_calls_put(calls);
  103. return ret;
  104. }
  105. int elf_coredump_extra_notes_write(struct coredump_params *cprm)
  106. {
  107. struct spufs_calls *calls;
  108. int ret;
  109. calls = spufs_calls_get();
  110. if (!calls)
  111. return 0;
  112. ret = calls->coredump_extra_notes_write(cprm);
  113. spufs_calls_put(calls);
  114. return ret;
  115. }
  116. #endif
  117. void notify_spus_active(void)
  118. {
  119. struct spufs_calls *calls;
  120. calls = spufs_calls_get();
  121. if (!calls)
  122. return;
  123. calls->notify_spus_active();
  124. spufs_calls_put(calls);
  125. return;
  126. }
  127. int register_spu_syscalls(struct spufs_calls *calls)
  128. {
  129. if (spufs_calls)
  130. return -EBUSY;
  131. rcu_assign_pointer(spufs_calls, calls);
  132. return 0;
  133. }
  134. EXPORT_SYMBOL_GPL(register_spu_syscalls);
  135. void unregister_spu_syscalls(struct spufs_calls *calls)
  136. {
  137. BUG_ON(spufs_calls->owner != calls->owner);
  138. RCU_INIT_POINTER(spufs_calls, NULL);
  139. synchronize_rcu();
  140. }
  141. EXPORT_SYMBOL_GPL(unregister_spu_syscalls);