Pull ia64-clocksource into release branch
[pandora-kernel.git] / arch / powerpc / platforms / cell / spufs / inode.c
index 8079983..f37460e 100644 (file)
@@ -36,6 +36,7 @@
 #include <asm/prom.h>
 #include <asm/semaphore.h>
 #include <asm/spu.h>
+#include <asm/spu_priv1.h>
 #include <asm/uaccess.h>
 
 #include "spufs.h"
@@ -54,6 +55,7 @@ spufs_alloc_inode(struct super_block *sb)
 
        ei->i_gang = NULL;
        ei->i_ctx = NULL;
+       ei->i_openers = 0;
 
        return &ei->vfs_inode;
 }
@@ -69,10 +71,7 @@ spufs_init_once(void *p, struct kmem_cache * cachep, unsigned long flags)
 {
        struct spufs_inode_info *ei = p;
 
-       if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-           SLAB_CTOR_CONSTRUCTOR) {
-               inode_init_once(&ei->vfs_inode);
-       }
+       inode_init_once(&ei->vfs_inode);
 }
 
 static struct inode *
@@ -178,7 +177,7 @@ static int spufs_rmdir(struct inode *parent, struct dentry *dir)
 static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files,
                          int mode, struct spu_context *ctx)
 {
-       struct dentry *dentry;
+       struct dentry *dentry, *tmp;
        int ret;
 
        while (files->name && files->name[0]) {
@@ -194,7 +193,20 @@ static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files,
        }
        return 0;
 out:
-       spufs_prune_dir(dir);
+       /*
+        * remove all children from dir. dir->inode is not set so don't
+        * just simply use spufs_prune_dir() and panic afterwards :)
+        * dput() looks like it will do the right thing:
+        * - dec parent's ref counter
+        * - remove child from parent's child list
+        * - free child's inode if possible
+        * - free child
+        */
+       list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) {
+               dput(dentry);
+       }
+
+       shrink_dcache_parent(dir);
        return ret;
 }
 
@@ -220,10 +232,6 @@ static int spufs_dir_close(struct inode *inode, struct file *file)
        return dcache_dir_close(inode, file);
 }
 
-const struct inode_operations spufs_dir_inode_operations = {
-       .lookup = simple_lookup,
-};
-
 const struct file_operations spufs_context_fops = {
        .open           = dcache_dir_open,
        .release        = spufs_dir_close,
@@ -257,7 +265,7 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
                goto out_iput;
 
        ctx->flags = flags;
-       inode->i_op = &spufs_dir_inode_operations;
+       inode->i_op = &simple_dir_inode_operations;
        inode->i_fop = &simple_dir_operations;
        if (flags & SPU_CREATE_NOSCHED)
                ret = spufs_fill_dir(dentry, spufs_dir_nosched_contents,
@@ -275,6 +283,7 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
        goto out;
 
 out_free_ctx:
+       spu_forget(ctx);
        put_spu_context(ctx);
 out_iput:
        iput(inode);
@@ -350,37 +359,6 @@ out:
        return ret;
 }
 
-static int spufs_rmgang(struct inode *root, struct dentry *dir)
-{
-       /* FIXME: this fails if the dir is not empty,
-                 which causes a leak of gangs. */
-       return simple_rmdir(root, dir);
-}
-
-static int spufs_gang_close(struct inode *inode, struct file *file)
-{
-       struct inode *parent;
-       struct dentry *dir;
-       int ret;
-
-       dir = file->f_path.dentry;
-       parent = dir->d_parent->d_inode;
-
-       ret = spufs_rmgang(parent, dir);
-       WARN_ON(ret);
-
-       return dcache_dir_close(inode, file);
-}
-
-const struct file_operations spufs_gang_fops = {
-       .open           = dcache_dir_open,
-       .release        = spufs_gang_close,
-       .llseek         = dcache_dir_lseek,
-       .read           = generic_read_dir,
-       .readdir        = dcache_readdir,
-       .fsync          = simple_sync_file,
-};
-
 static int
 spufs_mkgang(struct inode *dir, struct dentry *dentry, int mode)
 {
@@ -404,11 +382,10 @@ spufs_mkgang(struct inode *dir, struct dentry *dentry, int mode)
        if (!gang)
                goto out_iput;
 
-       inode->i_op = &spufs_dir_inode_operations;
+       inode->i_op = &simple_dir_inode_operations;
        inode->i_fop = &simple_dir_operations;
 
        d_instantiate(dentry, inode);
-       dget(dentry);
        dir->i_nlink++;
        dentry->d_inode->i_nlink++;
        return ret;
@@ -438,7 +415,7 @@ static int spufs_gang_open(struct dentry *dentry, struct vfsmount *mnt)
                goto out;
        }
 
-       filp->f_op = &spufs_gang_fops;
+       filp->f_op = &simple_dir_operations;
        fd_install(ret, filp);
 out:
        return ret;
@@ -459,8 +436,10 @@ static int spufs_create_gang(struct inode *inode,
         * in error path of *_open().
         */
        ret = spufs_gang_open(dget(dentry), mntget(mnt));
-       if (ret < 0)
-               WARN_ON(spufs_rmgang(inode, dentry));
+       if (ret < 0) {
+               int err = simple_rmdir(inode, dentry);
+               WARN_ON(err);
+       }
 
 out:
        mutex_unlock(&inode->i_mutex);
@@ -520,13 +499,14 @@ out:
 
 /* File system initialization */
 enum {
-       Opt_uid, Opt_gid, Opt_err,
+       Opt_uid, Opt_gid, Opt_mode, Opt_err,
 };
 
 static match_table_t spufs_tokens = {
-       { Opt_uid, "uid=%d" },
-       { Opt_gid, "gid=%d" },
-       { Opt_err, NULL  },
+       { Opt_uid,  "uid=%d" },
+       { Opt_gid,  "gid=%d" },
+       { Opt_mode, "mode=%o" },
+       { Opt_err,   NULL  },
 };
 
 static int
@@ -553,6 +533,11 @@ spufs_parse_options(char *options, struct inode *root)
                                return 0;
                        root->i_gid = option;
                        break;
+               case Opt_mode:
+                       if (match_octal(&args[0], &option))
+                               return 0;
+                       root->i_mode = option | S_IFDIR;
+                       break;
                default:
                        return 0;
                }
@@ -560,6 +545,11 @@ spufs_parse_options(char *options, struct inode *root)
        return 1;
 }
 
+static void spufs_exit_isolated_loader(void)
+{
+       kfree(isolated_loader);
+}
+
 static void
 spufs_init_isolated_loader(void)
 {
@@ -571,7 +561,7 @@ spufs_init_isolated_loader(void)
        if (!dn)
                return;
 
-       loader = get_property(dn, "loader", &size);
+       loader = of_get_property(dn, "loader", &size);
        if (!loader)
                return;
 
@@ -590,12 +580,16 @@ spufs_create_root(struct super_block *sb, void *data)
        struct inode *inode;
        int ret;
 
+       ret = -ENODEV;
+       if (!spu_management_ops)
+               goto out;
+
        ret = -ENOMEM;
        inode = spufs_new_inode(sb, S_IFDIR | 0775);
        if (!inode)
                goto out;
 
-       inode->i_op = &spufs_dir_inode_operations;
+       inode->i_op = &simple_dir_inode_operations;
        inode->i_fop = &simple_dir_operations;
        SPUFS_I(inode)->i_ctx = NULL;
 
@@ -653,6 +647,10 @@ static int __init spufs_init(void)
 {
        int ret;
 
+       ret = -ENODEV;
+       if (!spu_management_ops)
+               goto out;
+
        ret = -ENOMEM;
        spufs_inode_cache = kmem_cache_create("spufs_inode_cache",
                        sizeof(struct spufs_inode_info), 0,
@@ -660,25 +658,29 @@ static int __init spufs_init(void)
 
        if (!spufs_inode_cache)
                goto out;
-       if (spu_sched_init() != 0) {
-               kmem_cache_destroy(spufs_inode_cache);
-               goto out;
-       }
-       ret = register_filesystem(&spufs_type);
+       ret = spu_sched_init();
        if (ret)
                goto out_cache;
+       ret = register_filesystem(&spufs_type);
+       if (ret)
+               goto out_sched;
        ret = register_spu_syscalls(&spufs_calls);
        if (ret)
                goto out_fs;
        ret = register_arch_coredump_calls(&spufs_coredump_calls);
        if (ret)
-               goto out_fs;
+               goto out_syscalls;
 
        spufs_init_isolated_loader();
 
        return 0;
+
+out_syscalls:
+       unregister_spu_syscalls(&spufs_calls);
 out_fs:
        unregister_filesystem(&spufs_type);
+out_sched:
+       spu_sched_exit();
 out_cache:
        kmem_cache_destroy(spufs_inode_cache);
 out:
@@ -689,6 +691,7 @@ module_init(spufs_init);
 static void __exit spufs_exit(void)
 {
        spu_sched_exit();
+       spufs_exit_isolated_loader();
        unregister_arch_coredump_calls(&spufs_coredump_calls);
        unregister_spu_syscalls(&spufs_calls);
        unregister_filesystem(&spufs_type);