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 */ 33static struct spufs_calls *spufs_calls; 34 35#ifdef CONFIG_SPU_FS_MODULE 36 37static 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 50static 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 60static inline struct spufs_calls *spufs_calls_get(void) 61{ 62 return spufs_calls; 63} 64 65static inline void spufs_calls_put(struct spufs_calls *calls) { } 66 67#endif /* CONFIG_SPU_FS_MODULE */ 68 69SYSCALL_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 93asmlinkage 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#ifdef CONFIG_COREDUMP 115int elf_coredump_extra_notes_size(void) 116{ 117 struct spufs_calls *calls; 118 int ret; 119 120 calls = spufs_calls_get(); 121 if (!calls) 122 return 0; 123 124 ret = calls->coredump_extra_notes_size(); 125 126 spufs_calls_put(calls); 127 128 return ret; 129} 130 131int elf_coredump_extra_notes_write(struct coredump_params *cprm) 132{ 133 struct spufs_calls *calls; 134 int ret; 135 136 calls = spufs_calls_get(); 137 if (!calls) 138 return 0; 139 140 ret = calls->coredump_extra_notes_write(cprm); 141 142 spufs_calls_put(calls); 143 144 return ret; 145} 146#endif 147 148void notify_spus_active(void) 149{ 150 struct spufs_calls *calls; 151 152 calls = spufs_calls_get(); 153 if (!calls) 154 return; 155 156 calls->notify_spus_active(); 157 spufs_calls_put(calls); 158 159 return; 160} 161 162int register_spu_syscalls(struct spufs_calls *calls) 163{ 164 if (spufs_calls) 165 return -EBUSY; 166 167 rcu_assign_pointer(spufs_calls, calls); 168 return 0; 169} 170EXPORT_SYMBOL_GPL(register_spu_syscalls); 171 172void unregister_spu_syscalls(struct spufs_calls *calls) 173{ 174 BUG_ON(spufs_calls->owner != calls->owner); 175 RCU_INIT_POINTER(spufs_calls, NULL); 176 synchronize_rcu(); 177} 178EXPORT_SYMBOL_GPL(unregister_spu_syscalls); 179