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