]>
Commit | Line | Data |
---|---|---|
67207b96 AB |
1 | /* |
2 | * SPU file system -- system call stubs | |
3 | * | |
4 | * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 | |
48cad41f | 5 | * (C) Copyright 2006-2007, IBM Corporation |
67207b96 AB |
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> | |
e5501492 | 24 | #include <linux/fs.h> |
67207b96 AB |
25 | #include <linux/module.h> |
26 | #include <linux/syscalls.h> | |
98f06978 | 27 | #include <linux/rcupdate.h> |
67207b96 AB |
28 | |
29 | #include <asm/spu.h> | |
30 | ||
98f06978 JK |
31 | /* protected by rcu */ |
32 | static struct spufs_calls *spufs_calls; | |
67207b96 | 33 | |
98f06978 JK |
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 */ | |
67207b96 | 67 | |
1bc94226 AV |
68 | SYSCALL_DEFINE4(spu_create, const char __user *, name, unsigned int, flags, |
69 | umode_t, mode, int, neighbor_fd) | |
67207b96 AB |
70 | { |
71 | long ret; | |
98f06978 | 72 | struct spufs_calls *calls; |
67207b96 | 73 | |
98f06978 JK |
74 | calls = spufs_calls_get(); |
75 | if (!calls) | |
76 | return -ENOSYS; | |
77 | ||
78 | if (flags & SPU_CREATE_AFFINITY_SPU) { | |
2903ff01 | 79 | struct fd neighbor = fdget(neighbor_fd); |
98f06978 | 80 | ret = -EBADF; |
2903ff01 AV |
81 | if (neighbor.file) { |
82 | ret = calls->create_thread(name, flags, mode, neighbor.file); | |
83 | fdput(neighbor); | |
8e68e2f2 | 84 | } |
98f06978 JK |
85 | } else |
86 | ret = calls->create_thread(name, flags, mode, NULL); | |
87 | ||
88 | spufs_calls_put(calls); | |
67207b96 AB |
89 | return ret; |
90 | } | |
91 | ||
92 | asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus) | |
93 | { | |
94 | long ret; | |
2903ff01 | 95 | struct fd arg; |
98f06978 | 96 | struct spufs_calls *calls; |
67207b96 | 97 | |
98f06978 JK |
98 | calls = spufs_calls_get(); |
99 | if (!calls) | |
100 | return -ENOSYS; | |
101 | ||
102 | ret = -EBADF; | |
2903ff01 AV |
103 | arg = fdget(fd); |
104 | if (arg.file) { | |
105 | ret = calls->spu_run(arg.file, unpc, ustatus); | |
106 | fdput(arg); | |
67207b96 | 107 | } |
98f06978 JK |
108 | |
109 | spufs_calls_put(calls); | |
67207b96 AB |
110 | return ret; |
111 | } | |
112 | ||
e5501492 | 113 | int elf_coredump_extra_notes_size(void) |
48cad41f ME |
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 | ||
e5501492 | 129 | int elf_coredump_extra_notes_write(struct file *file, loff_t *foffset) |
48cad41f ME |
130 | { |
131 | struct spufs_calls *calls; | |
7af1443a | 132 | int ret; |
48cad41f ME |
133 | |
134 | calls = spufs_calls_get(); | |
135 | if (!calls) | |
e5501492 | 136 | return 0; |
48cad41f | 137 | |
7af1443a | 138 | ret = calls->coredump_extra_notes_write(file, foffset); |
48cad41f ME |
139 | |
140 | spufs_calls_put(calls); | |
e5501492 | 141 | |
7af1443a | 142 | return ret; |
48cad41f ME |
143 | } |
144 | ||
aed3a8c9 BN |
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 | ||
67207b96 AB |
159 | int register_spu_syscalls(struct spufs_calls *calls) |
160 | { | |
98f06978 | 161 | if (spufs_calls) |
67207b96 AB |
162 | return -EBUSY; |
163 | ||
98f06978 | 164 | rcu_assign_pointer(spufs_calls, calls); |
67207b96 AB |
165 | return 0; |
166 | } | |
167 | EXPORT_SYMBOL_GPL(register_spu_syscalls); | |
168 | ||
169 | void unregister_spu_syscalls(struct spufs_calls *calls) | |
170 | { | |
98f06978 JK |
171 | BUG_ON(spufs_calls->owner != calls->owner); |
172 | rcu_assign_pointer(spufs_calls, NULL); | |
173 | synchronize_rcu(); | |
67207b96 AB |
174 | } |
175 | EXPORT_SYMBOL_GPL(unregister_spu_syscalls); |