]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/powerpc/platforms/cell/spu_syscalls.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[linux-2.6-omap-h63xx.git] / arch / powerpc / platforms / cell / spu_syscalls.c
index 261b507a901afb1f389f51186063a9dcc2156c48..a9438b719fe8ba38e53f48f4e2106e1e81746cc0 100644 (file)
@@ -2,6 +2,7 @@
  * SPU file system -- system call stubs
  *
  * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ * (C) Copyright 2006-2007, IBM Corporation
  *
  * Author: Arnd Bergmann <arndb@de.ibm.com>
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 #include <linux/file.h>
+#include <linux/fs.h>
 #include <linux/module.h>
 #include <linux/syscalls.h>
+#include <linux/rcupdate.h>
 
 #include <asm/spu.h>
 
-struct spufs_calls spufs_calls = {
-       .owner = NULL,
-};
+/* protected by rcu */
+static struct spufs_calls *spufs_calls;
 
-/* These stub syscalls are needed to have the actual implementation
- * within a loadable module. When spufs is built into the kernel,
- * this file is not used and the syscalls directly enter the fs code */
+#ifdef CONFIG_SPU_FS_MODULE
+
+static inline struct spufs_calls *spufs_calls_get(void)
+{
+       struct spufs_calls *calls = NULL;
+
+       rcu_read_lock();
+       calls = rcu_dereference(spufs_calls);
+       if (calls && !try_module_get(calls->owner))
+               calls = NULL;
+       rcu_read_unlock();
+
+       return calls;
+}
+
+static inline void spufs_calls_put(struct spufs_calls *calls)
+{
+       BUG_ON(calls != spufs_calls);
+
+       /* we don't need to rcu this, as we hold a reference to the module */
+       module_put(spufs_calls->owner);
+}
+
+#else /* !defined CONFIG_SPU_FS_MODULE */
+
+static inline struct spufs_calls *spufs_calls_get(void)
+{
+       return spufs_calls;
+}
+
+static inline void spufs_calls_put(struct spufs_calls *calls) { }
+
+#endif /* CONFIG_SPU_FS_MODULE */
 
 asmlinkage long sys_spu_create(const char __user *name,
-               unsigned int flags, mode_t mode)
+               unsigned int flags, mode_t mode, int neighbor_fd)
 {
        long ret;
-       struct module *owner = spufs_calls.owner;
+       struct file *neighbor;
+       int fput_needed;
+       struct spufs_calls *calls;
 
-       ret = -ENOSYS;
-       if (owner && try_module_get(owner)) {
-               ret = spufs_calls.create_thread(name, flags, mode);
-               module_put(owner);
-       }
+       calls = spufs_calls_get();
+       if (!calls)
+               return -ENOSYS;
+
+       if (flags & SPU_CREATE_AFFINITY_SPU) {
+               ret = -EBADF;
+               neighbor = fget_light(neighbor_fd, &fput_needed);
+               if (neighbor) {
+                       ret = calls->create_thread(name, flags, mode, neighbor);
+                       fput_light(neighbor, fput_needed);
+               }
+       } else
+               ret = calls->create_thread(name, flags, mode, NULL);
+
+       spufs_calls_put(calls);
        return ret;
 }
 
@@ -52,37 +96,69 @@ asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus)
        long ret;
        struct file *filp;
        int fput_needed;
-       struct module *owner = spufs_calls.owner;
+       struct spufs_calls *calls;
 
-       ret = -ENOSYS;
-       if (owner && try_module_get(owner)) {
-               ret = -EBADF;
-               filp = fget_light(fd, &fput_needed);
-               if (filp) {
-                       ret = spufs_calls.spu_run(filp, unpc, ustatus);
-                       fput_light(filp, fput_needed);
-               }
-               module_put(owner);
+       calls = spufs_calls_get();
+       if (!calls)
+               return -ENOSYS;
+
+       ret = -EBADF;
+       filp = fget_light(fd, &fput_needed);
+       if (filp) {
+               ret = calls->spu_run(filp, unpc, ustatus);
+               fput_light(filp, fput_needed);
        }
+
+       spufs_calls_put(calls);
+       return ret;
+}
+
+int elf_coredump_extra_notes_size(void)
+{
+       struct spufs_calls *calls;
+       int ret;
+
+       calls = spufs_calls_get();
+       if (!calls)
+               return 0;
+
+       ret = calls->coredump_extra_notes_size();
+
+       spufs_calls_put(calls);
+
+       return ret;
+}
+
+int elf_coredump_extra_notes_write(struct file *file, loff_t *foffset)
+{
+       struct spufs_calls *calls;
+       int ret;
+
+       calls = spufs_calls_get();
+       if (!calls)
+               return 0;
+
+       ret = calls->coredump_extra_notes_write(file, foffset);
+
+       spufs_calls_put(calls);
+
        return ret;
 }
 
 int register_spu_syscalls(struct spufs_calls *calls)
 {
-       if (spufs_calls.owner)
+       if (spufs_calls)
                return -EBUSY;
 
-       spufs_calls.create_thread = calls->create_thread;
-       spufs_calls.spu_run = calls->spu_run;
-       smp_mb();
-       spufs_calls.owner = calls->owner;
+       rcu_assign_pointer(spufs_calls, calls);
        return 0;
 }
 EXPORT_SYMBOL_GPL(register_spu_syscalls);
 
 void unregister_spu_syscalls(struct spufs_calls *calls)
 {
-       BUG_ON(spufs_calls.owner != calls->owner);
-       spufs_calls.owner = NULL;
+       BUG_ON(spufs_calls->owner != calls->owner);
+       rcu_assign_pointer(spufs_calls, NULL);
+       synchronize_rcu();
 }
 EXPORT_SYMBOL_GPL(unregister_spu_syscalls);