[POWERPC] cell: Unify spufs syscall path
authorJeremy Kerr <jk@ozlabs.org>
Wed, 19 Sep 2007 04:38:12 +0000 (14:38 +1000)
committerPaul Mackerras <paulus@samba.org>
Wed, 19 Sep 2007 05:12:16 +0000 (15:12 +1000)
At present, a built-in spufs will not use the spufs_calls callbacks, but
directly call sys_spu_create.  This saves us an indirect branch, but
means we have duplicated functions - one for CONFIG_SPU_FS=y and one for
=m.

This change unifies the spufs syscall path, and provides access to the
spufs_calls structure through a get/put pair.  At present, the only user
of the spufs_calls structure is spu_syscalls.c, but this will facilitate
adding the coredump calls later.

Everyone likes numbers, right?  Here's a before/after comparison with
CONFIG_SPU_FS=y, doing spu_create(); close(); 64k times.

Before:
[jk@cell ~]$ time ./spu_create
performing 65536 spu_create calls

real    0m24.075s
user    0m0.146s
sys     0m23.925s

After:
[jk@cell ~]$ time ./spu_create
performing 65536 spu_create calls

real    0m24.777s
user    0m0.141s
sys     0m24.631s

So, we're adding around 11us per syscall, at the benefit of having
only one syscall path.

Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
arch/powerpc/platforms/cell/Makefile
arch/powerpc/platforms/cell/spu_syscalls.c
arch/powerpc/platforms/cell/spufs/spufs.h
arch/powerpc/platforms/cell/spufs/syscalls.c
include/asm-powerpc/spu.h

index f88a7c76f2964f08e8771f7670f58fd14f726496..40f78e908953dfaf20e222b593e54707703204f6 100644 (file)
@@ -13,15 +13,13 @@ obj-$(CONFIG_PPC_CELL_NATIVE)               += smp.o
 endif
 
 # needed only when building loadable spufs.ko
-spufs-modular-$(CONFIG_SPU_FS)         += spu_syscalls.o
 spu-priv1-$(CONFIG_PPC_CELL_NATIVE)    += spu_priv1_mmio.o
 
 spu-manage-$(CONFIG_PPC_CELLEB)                += spu_manage.o
 spu-manage-$(CONFIG_PPC_CELL_NATIVE)   += spu_manage.o
 
 obj-$(CONFIG_SPU_BASE)                 += spu_callbacks.o spu_base.o \
-                                          spu_coredump.o \
-                                          $(spufs-modular-m) \
+                                          spu_coredump.o spu_syscalls.o \
                                           $(spu-priv1-y) \
                                           $(spu-manage-y) \
                                           spufs/
index 027ac32cc63659c8c2af89270041742dcb96e345..c0238dd9ff2763943ab3168cbe41747f96140092 100644 (file)
 #include <linux/file.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, 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)) {
-               if (flags & SPU_CREATE_AFFINITY_SPU) {
-                       neighbor = fget_light(neighbor_fd, &fput_needed);
-                       ret = -EBADF;
-                       if (neighbor) {
-                               ret = spufs_calls.create_thread(name, flags,
-                                                               mode, neighbor);
-                               fput_light(neighbor, fput_needed);
-                       }
-               }
-               else {
-                       ret = spufs_calls.create_thread(name, flags,
-                                                       mode, NULL);
+       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);
                }
-               module_put(owner);
-       }
+       } else
+               ret = calls->create_thread(name, flags, mode, NULL);
+
+       spufs_calls_put(calls);
        return ret;
 }
 
@@ -66,37 +94,37 @@ 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 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);
index 2bfdeb8ea8bd0ab028d1f472046c643bfe7c3fc4..3dbffebb3cef996d4d4b89675a22c055a95f5014 100644 (file)
@@ -200,6 +200,7 @@ extern struct tree_descr spufs_dir_contents[];
 extern struct tree_descr spufs_dir_nosched_contents[];
 
 /* system call implementation */
+extern struct spufs_calls spufs_calls;
 long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *status);
 long spufs_create(struct nameidata *nd, unsigned int flags,
                        mode_t mode, struct file *filp);
index 936e0a8af3a957938b038de123692aa58b3b8b04..22b138dc335cace7c705a1c8ece1c14223441bda 100644 (file)
@@ -58,24 +58,6 @@ out:
        return ret;
 }
 
-#ifndef MODULE
-asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus)
-{
-       int fput_needed;
-       struct file *filp;
-       long ret;
-
-       ret = -EBADF;
-       filp = fget_light(fd, &fput_needed);
-       if (filp) {
-               ret = do_spu_run(filp, unpc, ustatus);
-               fput_light(filp, fput_needed);
-       }
-
-       return ret;
-}
-#endif
-
 static long do_spu_create(const char __user *pathname, unsigned int flags,
                mode_t mode, struct file *neighbor)
 {
@@ -99,30 +81,6 @@ static long do_spu_create(const char __user *pathname, unsigned int flags,
        return ret;
 }
 
-#ifndef MODULE
-asmlinkage long sys_spu_create(const char __user *pathname, unsigned int flags,
-                               mode_t mode, int neighbor_fd)
-{
-       int fput_needed;
-       struct file *neighbor;
-       long ret;
-
-       if (flags & SPU_CREATE_AFFINITY_SPU) {
-               ret = -EBADF;
-               neighbor = fget_light(neighbor_fd, &fput_needed);
-               if (neighbor) {
-                       ret = do_spu_create(pathname, flags, mode, neighbor);
-                       fput_light(neighbor, fput_needed);
-               }
-       }
-       else {
-               ret = do_spu_create(pathname, flags, mode, NULL);
-       }
-
-       return ret;
-}
-#endif
-
 struct spufs_calls spufs_calls = {
        .create_thread = do_spu_create,
        .spu_run = do_spu_run,
index 5bde3980bf496d3e8336565f71402d7296ec8beb..383ecfdf7eb0bbace8ececb883a01d72223932c2 100644 (file)
@@ -238,14 +238,14 @@ extern long spu_sys_callback(struct spu_syscall_block *s);
 
 /* syscalls implemented in spufs */
 struct file;
-extern struct spufs_calls {
+struct spufs_calls {
        asmlinkage long (*create_thread)(const char __user *name,
                                        unsigned int flags, mode_t mode,
                                        struct file *neighbor);
        asmlinkage long (*spu_run)(struct file *filp, __u32 __user *unpc,
                                                __u32 __user *ustatus);
        struct module *owner;
-} spufs_calls;
+};
 
 /* coredump calls implemented in spufs */
 struct spu_coredump_calls {
@@ -274,18 +274,8 @@ struct spu_coredump_calls {
 #define SPU_CREATE_FLAG_ALL            0x003f /* mask of all valid flags */
 
 
-#ifdef CONFIG_SPU_FS_MODULE
 int register_spu_syscalls(struct spufs_calls *calls);
 void unregister_spu_syscalls(struct spufs_calls *calls);
-#else
-static inline int register_spu_syscalls(struct spufs_calls *calls)
-{
-       return 0;
-}
-static inline void unregister_spu_syscalls(struct spufs_calls *calls)
-{
-}
-#endif /* MODULE */
 
 int register_arch_coredump_calls(struct spu_coredump_calls *calls);
 void unregister_arch_coredump_calls(struct spu_coredump_calls *calls);