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(fd: neighbor_fd); |
68 | ret = -EBADF; |
69 | if (neighbor.file) { |
70 | ret = calls->create_thread(name, flags, mode, neighbor.file); |
71 | fdput(fd: 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 (arg.file) { |
93 | ret = calls->spu_run(arg.file, unpc, ustatus); |
94 | fdput(fd: arg); |
95 | } |
96 | |
97 | spufs_calls_put(calls); |
98 | return ret; |
99 | } |
100 | |
101 | #ifdef CONFIG_COREDUMP |
102 | int (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 (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 | |