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 30 #include <asm/spu.h> 31 32 /* protected by rcu */ 33 static struct spufs_calls *spufs_calls; 34 35 #ifdef CONFIG_SPU_FS_MODULE 36 37 static inline struct spufs_calls *spufs_calls_get(void) 38 { 39 struct spufs_calls *calls = NULL; 40 41 rcu_read_lock(); 42 calls = rcu_dereference(spufs_calls); 43 if (calls && !try_module_get(calls->owner)) 44 calls = NULL; 45 rcu_read_unlock(); 46 47 return calls; 48 } 49 50 static inline void spufs_calls_put(struct spufs_calls *calls) 51 { 52 BUG_ON(calls != spufs_calls); 53 54 /* we don't need to rcu this, as we hold a reference to the module */ 55 module_put(spufs_calls->owner); 56 } 57 58 #else /* !defined CONFIG_SPU_FS_MODULE */ 59 60 static inline struct spufs_calls *spufs_calls_get(void) 61 { 62 return spufs_calls; 63 } 64 65 static inline void spufs_calls_put(struct spufs_calls *calls) { } 66 67 #endif /* CONFIG_SPU_FS_MODULE */ 68 69 SYSCALL_DEFINE4(spu_create, const char __user *, name, unsigned int, flags, 70 umode_t, mode, int, neighbor_fd) 71 { 72 long ret; 73 struct spufs_calls *calls; 74 75 calls = spufs_calls_get(); 76 if (!calls) 77 return -ENOSYS; 78 79 if (flags & SPU_CREATE_AFFINITY_SPU) { 80 struct fd neighbor = fdget(neighbor_fd); 81 ret = -EBADF; 82 if (neighbor.file) { 83 ret = calls->create_thread(name, flags, mode, neighbor.file); 84 fdput(neighbor); 85 } 86 } else 87 ret = calls->create_thread(name, flags, mode, NULL); 88 89 spufs_calls_put(calls); 90 return ret; 91 } 92 93 asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus) 94 { 95 long ret; 96 struct fd arg; 97 struct spufs_calls *calls; 98 99 calls = spufs_calls_get(); 100 if (!calls) 101 return -ENOSYS; 102 103 ret = -EBADF; 104 arg = fdget(fd); 105 if (arg.file) { 106 ret = calls->spu_run(arg.file, unpc, ustatus); 107 fdput(arg); 108 } 109 110 spufs_calls_put(calls); 111 return ret; 112 } 113 114 int elf_coredump_extra_notes_size(void) 115 { 116 struct spufs_calls *calls; 117 int ret; 118 119 calls = spufs_calls_get(); 120 if (!calls) 121 return 0; 122 123 ret = calls->coredump_extra_notes_size(); 124 125 spufs_calls_put(calls); 126 127 return ret; 128 } 129 130 int elf_coredump_extra_notes_write(struct coredump_params *cprm) 131 { 132 struct spufs_calls *calls; 133 int ret; 134 135 calls = spufs_calls_get(); 136 if (!calls) 137 return 0; 138 139 ret = calls->coredump_extra_notes_write(cprm); 140 141 spufs_calls_put(calls); 142 143 return ret; 144 } 145 146 void notify_spus_active(void) 147 { 148 struct spufs_calls *calls; 149 150 calls = spufs_calls_get(); 151 if (!calls) 152 return; 153 154 calls->notify_spus_active(); 155 spufs_calls_put(calls); 156 157 return; 158 } 159 160 int register_spu_syscalls(struct spufs_calls *calls) 161 { 162 if (spufs_calls) 163 return -EBUSY; 164 165 rcu_assign_pointer(spufs_calls, calls); 166 return 0; 167 } 168 EXPORT_SYMBOL_GPL(register_spu_syscalls); 169 170 void unregister_spu_syscalls(struct spufs_calls *calls) 171 { 172 BUG_ON(spufs_calls->owner != calls->owner); 173 RCU_INIT_POINTER(spufs_calls, NULL); 174 synchronize_rcu(); 175 } 176 EXPORT_SYMBOL_GPL(unregister_spu_syscalls); 177