#include <linux/init.h>
#include <linux/ioctl.h>
#include <linux/module.h>
+#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/pagemap.h>
#include <linux/poll.h>
clear_inode(inode);
}
-static int
-spufs_fill_dir(struct dentry *dir, struct tree_descr *files,
- int mode, struct spu_context *ctx)
-{
- struct dentry *dentry;
- int ret;
-
- while (files->name && files->name[0]) {
- ret = -ENOMEM;
- dentry = d_alloc_name(dir, files->name);
- if (!dentry)
- goto out;
- ret = spufs_new_file(dir->d_sb, dentry, files->ops,
- files->mode & mode, ctx);
- if (ret)
- goto out;
- files++;
- }
- return 0;
-out:
- // FIXME: remove all files that are left
-
- return ret;
-}
-
-static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry)
+static void spufs_prune_dir(struct dentry *dir)
{
struct dentry *dentry, *tmp;
- struct spu_context *ctx;
-
- /* remove all entries */
- down(&root->i_sem);
- down(&dir_dentry->d_inode->i_sem);
- list_for_each_entry_safe(dentry, tmp, &dir_dentry->d_subdirs, d_child) {
+ down(&dir->d_inode->i_sem);
+ list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child) {
spin_lock(&dcache_lock);
spin_lock(&dentry->d_lock);
if (!(d_unhashed(dentry)) && dentry->d_inode) {
dget_locked(dentry);
__d_drop(dentry);
spin_unlock(&dentry->d_lock);
- simple_unlink(dir_dentry->d_inode, dentry);
+ simple_unlink(dir->d_inode, dentry);
spin_unlock(&dcache_lock);
dput(dentry);
} else {
spin_unlock(&dcache_lock);
}
}
- shrink_dcache_parent(dir_dentry);
- up(&dir_dentry->d_inode->i_sem);
+ shrink_dcache_parent(dir);
+ up(&dir->d_inode->i_sem);
+}
+
+static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry)
+{
+ struct spu_context *ctx;
+
+ /* remove all entries */
+ down(&root->i_sem);
+ spufs_prune_dir(dir_dentry);
up(&root->i_sem);
/* We have to give up the mm_struct */
return simple_rmdir(root, dir_dentry);
}
+static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files,
+ int mode, struct spu_context *ctx)
+{
+ struct dentry *dentry;
+ int ret;
+
+ while (files->name && files->name[0]) {
+ ret = -ENOMEM;
+ dentry = d_alloc_name(dir, files->name);
+ if (!dentry)
+ goto out;
+ ret = spufs_new_file(dir->d_sb, dentry, files->ops,
+ files->mode & mode, ctx);
+ if (ret)
+ goto out;
+ files++;
+ }
+ return 0;
+out:
+ spufs_prune_dir(dir);
+ return ret;
+}
+
static int spufs_dir_close(struct inode *inode, struct file *file)
{
struct inode *dir;
d_instantiate(dentry, inode);
dget(dentry);
dir->i_nlink++;
+ dentry->d_inode->i_nlink++;
goto out;
out_free_ctx:
return ret;
}
-long
-spufs_create_thread(struct nameidata *nd, const char *name,
- unsigned int flags, mode_t mode)
+static int spufs_context_open(struct dentry *dentry, struct vfsmount *mnt)
{
- struct dentry *dentry;
+ int ret;
struct file *filp;
+
+ ret = get_unused_fd();
+ if (ret < 0) {
+ dput(dentry);
+ mntput(mnt);
+ goto out;
+ }
+
+ filp = dentry_open(dentry, mnt, O_RDONLY);
+ if (IS_ERR(filp)) {
+ put_unused_fd(ret);
+ ret = PTR_ERR(filp);
+ goto out;
+ }
+
+ filp->f_op = &spufs_context_fops;
+ fd_install(ret, filp);
+out:
+ return ret;
+}
+
+static struct file_system_type spufs_type;
+
+long spufs_create_thread(struct nameidata *nd,
+ unsigned int flags, mode_t mode)
+{
+ struct dentry *dentry;
int ret;
/* need to be at the root of spufs */
ret = -EINVAL;
- if (nd->dentry->d_sb->s_magic != SPUFS_MAGIC ||
- nd->dentry != nd->dentry->d_sb->s_root)
+ if (nd->dentry->d_sb->s_type != &spufs_type ||
+ nd->dentry != nd->dentry->d_sb->s_root)
goto out;
dentry = lookup_create(nd, 1);
if (ret)
goto out_dput;
- ret = get_unused_fd();
+ /*
+ * get references for dget and mntget, will be released
+ * in error path of *_open().
+ */
+ ret = spufs_context_open(dget(dentry), mntget(nd->mnt));
if (ret < 0)
- goto out_dput;
-
- dentry->d_inode->i_nlink++;
-
- filp = filp_open(name, O_RDONLY, mode);
- if (IS_ERR(filp)) {
- // FIXME: remove directory again
- put_unused_fd(ret);
- ret = PTR_ERR(filp);
- } else {
- filp->f_op = &spufs_context_fops;
- fd_install(ret, filp);
- }
+ spufs_rmdir(nd->dentry->d_inode, dentry);
out_dput:
dput(dentry);