1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * SPU file system -- system call stubs 4 * 5 * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 6 * (C) Copyright 2006-2007, IBM Corporation 7 * 8 * Author: Arnd Bergmann <arndb@de.ibm.com> 9 */ 10 #include <linux/file.h> 11 #include <linux/fs.h> 12 #include <linux/module.h> 13 #include <linux/syscalls.h> 14 #include <linux/rcupdate.h> 15 #include <linux/binfmts.h> 16 17 #include <asm/spu.h> 18 19 /* protected by rcu */ 20 static struct spufs_calls *spufs_calls; 21 22 #ifdef CONFIG_SPU_FS_MODULE 23 24 static inline struct spufs_calls *spufs_calls_get(void) 25 { 26 struct spufs_calls *calls = NULL; 27 28 rcu_read_lock(); 29 calls = rcu_dereference(spufs_calls); 30 if (calls && !try_module_get(calls->owner)) 31 calls = NULL; 32 rcu_read_unlock(); 33 34 return calls; 35 } 36 37 static inline void spufs_calls_put(struct spufs_calls *calls) 38 { 39 BUG_ON(calls != spufs_calls); 40 41 /* we don't need to rcu this, as we hold a reference to the module */ 42 module_put(spufs_calls->owner); 43 } 44 45 #else /* !defined CONFIG_SPU_FS_MODULE */ 46 47 static inline struct spufs_calls *spufs_calls_get(void) 48 { 49 return spufs_calls; 50 } 51 52 static inline void spufs_calls_put(struct spufs_calls *calls) { } 53 54 #endif /* CONFIG_SPU_FS_MODULE */ 55 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 62 calls = spufs_calls_get(); 63 if (!calls) 64 return -ENOSYS; 65 66 if (flags & SPU_CREATE_AFFINITY_SPU) { 67 struct fd neighbor = fdget(neighbor_fd); 68 ret = -EBADF; 69 if (fd_file(neighbor)) { 70 ret = calls->create_thread(name, flags, mode, fd_file(neighbor)); 71 fdput(neighbor); 72 } 73 } else 74 ret = calls->create_thread(name, flags, mode, NULL); 75 76 spufs_calls_put(calls); 77 return ret; 78 } 79 80 SYSCALL_DEFINE3(spu_run,int, fd, __u32 __user *, unpc, __u32 __user *, ustatus) 81 { 82 long ret; 83 struct fd arg; 84 struct spufs_calls *calls; 85 86 calls = spufs_calls_get(); 87 if (!calls) 88 return -ENOSYS; 89 90 ret = -EBADF; 91 arg = fdget(fd); 92 if (fd_file(arg)) { 93 ret = calls->spu_run(fd_file(arg), unpc, ustatus); 94 fdput(arg); 95 } 96 97 spufs_calls_put(calls); 98 return ret; 99 } 100 101 #ifdef CONFIG_COREDUMP 102 int elf_coredump_extra_notes_size(void) 103 { 104 struct spufs_calls *calls; 105 int ret; 106 107 calls = spufs_calls_get(); 108 if (!calls) 109 return 0; 110 111 ret = calls->coredump_extra_notes_size(); 112 113 spufs_calls_put(calls); 114 115 return ret; 116 } 117 118 int elf_coredump_extra_notes_write(struct coredump_params *cprm) 119 { 120 struct spufs_calls *calls; 121 int ret; 122 123 calls = spufs_calls_get(); 124 if (!calls) 125 return 0; 126 127 ret = calls->coredump_extra_notes_write(cprm); 128 129 spufs_calls_put(calls); 130 131 return ret; 132 } 133 #endif 134 135 void notify_spus_active(void) 136 { 137 struct spufs_calls *calls; 138 139 calls = spufs_calls_get(); 140 if (!calls) 141 return; 142 143 calls->notify_spus_active(); 144 spufs_calls_put(calls); 145 146 return; 147 } 148 149 int register_spu_syscalls(struct spufs_calls *calls) 150 { 151 if (spufs_calls) 152 return -EBUSY; 153 154 rcu_assign_pointer(spufs_calls, calls); 155 return 0; 156 } 157 EXPORT_SYMBOL_GPL(register_spu_syscalls); 158 159 void unregister_spu_syscalls(struct spufs_calls *calls) 160 { 161 BUG_ON(spufs_calls->owner != calls->owner); 162 RCU_INIT_POINTER(spufs_calls, NULL); 163 synchronize_rcu(); 164 } 165 EXPORT_SYMBOL_GPL(unregister_spu_syscalls); 166