spu_syscalls.c (3155B)
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 */ 20static struct spufs_calls *spufs_calls; 21 22#ifdef CONFIG_SPU_FS_MODULE 23 24static 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 37static 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 47static inline struct spufs_calls *spufs_calls_get(void) 48{ 49 return spufs_calls; 50} 51 52static inline void spufs_calls_put(struct spufs_calls *calls) { } 53 54#endif /* CONFIG_SPU_FS_MODULE */ 55 56SYSCALL_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 (neighbor.file) { 70 ret = calls->create_thread(name, flags, mode, neighbor.file); 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 80SYSCALL_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 (arg.file) { 93 ret = calls->spu_run(arg.file, unpc, ustatus); 94 fdput(arg); 95 } 96 97 spufs_calls_put(calls); 98 return ret; 99} 100 101#ifdef CONFIG_COREDUMP 102int 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 118int 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 135void 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 149int 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} 157EXPORT_SYMBOL_GPL(register_spu_syscalls); 158 159void 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} 165EXPORT_SYMBOL_GPL(unregister_spu_syscalls);