xref: /linux/arch/powerpc/platforms/cell/spufs/inode.c (revision f2d40141d5d90b882e2c35b226f9244a63b82b6e)
1de6cc651SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
24ac91378SJan Blunck 
367207b96SArnd Bergmann /*
467207b96SArnd Bergmann  * SPU file system
567207b96SArnd Bergmann  *
667207b96SArnd Bergmann  * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
767207b96SArnd Bergmann  *
867207b96SArnd Bergmann  * Author: Arnd Bergmann <arndb@de.ibm.com>
967207b96SArnd Bergmann  */
1067207b96SArnd Bergmann 
1167207b96SArnd Bergmann #include <linux/file.h>
1267207b96SArnd Bergmann #include <linux/fs.h>
13d2e0981cSDavid Howells #include <linux/fs_context.h>
14d2e0981cSDavid Howells #include <linux/fs_parser.h>
15826be063SChristoph Hellwig #include <linux/fsnotify.h>
1667207b96SArnd Bergmann #include <linux/backing-dev.h>
1767207b96SArnd Bergmann #include <linux/init.h>
1867207b96SArnd Bergmann #include <linux/ioctl.h>
1967207b96SArnd Bergmann #include <linux/module.h>
20346f4d3cSArnd Bergmann #include <linux/mount.h>
2167207b96SArnd Bergmann #include <linux/namei.h>
2267207b96SArnd Bergmann #include <linux/pagemap.h>
2367207b96SArnd Bergmann #include <linux/poll.h>
24e6f6390aSChristophe Leroy #include <linux/of.h>
25e41d12f5SChristoph Hellwig #include <linux/seq_file.h>
2667207b96SArnd Bergmann #include <linux/slab.h>
2767207b96SArnd Bergmann 
2867207b96SArnd Bergmann #include <asm/spu.h>
29ccf17e9dSJeremy Kerr #include <asm/spu_priv1.h>
307c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
3167207b96SArnd Bergmann 
3267207b96SArnd Bergmann #include "spufs.h"
3367207b96SArnd Bergmann 
342c3e4787SJeremy Kerr struct spufs_sb_info {
35d2e0981cSDavid Howells 	bool debug;
362c3e4787SJeremy Kerr };
372c3e4787SJeremy Kerr 
38e18b890bSChristoph Lameter static struct kmem_cache *spufs_inode_cache;
39c6730ed4SJeremy Kerr char *isolated_loader;
408b0d3121SSebastian Siewior static int isolated_loader_size;
4167207b96SArnd Bergmann 
422c3e4787SJeremy Kerr static struct spufs_sb_info *spufs_get_sb_info(struct super_block *sb)
432c3e4787SJeremy Kerr {
442c3e4787SJeremy Kerr 	return sb->s_fs_info;
452c3e4787SJeremy Kerr }
462c3e4787SJeremy Kerr 
4767207b96SArnd Bergmann static struct inode *
4867207b96SArnd Bergmann spufs_alloc_inode(struct super_block *sb)
4967207b96SArnd Bergmann {
5067207b96SArnd Bergmann 	struct spufs_inode_info *ei;
5167207b96SArnd Bergmann 
52e94b1766SChristoph Lameter 	ei = kmem_cache_alloc(spufs_inode_cache, GFP_KERNEL);
5367207b96SArnd Bergmann 	if (!ei)
5467207b96SArnd Bergmann 		return NULL;
556263203eSArnd Bergmann 
566263203eSArnd Bergmann 	ei->i_gang = NULL;
576263203eSArnd Bergmann 	ei->i_ctx = NULL;
5843c2bbd9SChristoph Hellwig 	ei->i_openers = 0;
596263203eSArnd Bergmann 
6067207b96SArnd Bergmann 	return &ei->vfs_inode;
6167207b96SArnd Bergmann }
6267207b96SArnd Bergmann 
636d0e0d0bSAl Viro static void spufs_free_inode(struct inode *inode)
6467207b96SArnd Bergmann {
6567207b96SArnd Bergmann 	kmem_cache_free(spufs_inode_cache, SPUFS_I(inode));
6667207b96SArnd Bergmann }
6767207b96SArnd Bergmann 
6867207b96SArnd Bergmann static void
6951cc5068SAlexey Dobriyan spufs_init_once(void *p)
7067207b96SArnd Bergmann {
7167207b96SArnd Bergmann 	struct spufs_inode_info *ei = p;
7267207b96SArnd Bergmann 
7367207b96SArnd Bergmann 	inode_init_once(&ei->vfs_inode);
7467207b96SArnd Bergmann }
7567207b96SArnd Bergmann 
7667207b96SArnd Bergmann static struct inode *
77c6684b26SAl Viro spufs_new_inode(struct super_block *sb, umode_t mode)
7867207b96SArnd Bergmann {
7967207b96SArnd Bergmann 	struct inode *inode;
8067207b96SArnd Bergmann 
8167207b96SArnd Bergmann 	inode = new_inode(sb);
8267207b96SArnd Bergmann 	if (!inode)
8367207b96SArnd Bergmann 		goto out;
8467207b96SArnd Bergmann 
856747e832SMichael Ellerman 	inode->i_ino = get_next_ino();
8667207b96SArnd Bergmann 	inode->i_mode = mode;
871330deb0SDavid Howells 	inode->i_uid = current_fsuid();
881330deb0SDavid Howells 	inode->i_gid = current_fsgid();
89078cd827SDeepa Dinamani 	inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
9067207b96SArnd Bergmann out:
9167207b96SArnd Bergmann 	return inode;
9267207b96SArnd Bergmann }
9367207b96SArnd Bergmann 
9467207b96SArnd Bergmann static int
95c1632a0fSChristian Brauner spufs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
96549c7297SChristian Brauner 	      struct iattr *attr)
9767207b96SArnd Bergmann {
9875c3cfa8SDavid Howells 	struct inode *inode = d_inode(dentry);
9967207b96SArnd Bergmann 
10067207b96SArnd Bergmann 	if ((attr->ia_valid & ATTR_SIZE) &&
10167207b96SArnd Bergmann 	    (attr->ia_size != inode->i_size))
10267207b96SArnd Bergmann 		return -EINVAL;
103c1632a0fSChristian Brauner 	setattr_copy(&nop_mnt_idmap, inode, attr);
1041025774cSChristoph Hellwig 	mark_inode_dirty(inode);
1051025774cSChristoph Hellwig 	return 0;
10667207b96SArnd Bergmann }
10767207b96SArnd Bergmann 
10867207b96SArnd Bergmann 
10967207b96SArnd Bergmann static int
11067207b96SArnd Bergmann spufs_new_file(struct super_block *sb, struct dentry *dentry,
111c6684b26SAl Viro 		const struct file_operations *fops, umode_t mode,
11223d893f5SJeremy Kerr 		size_t size, struct spu_context *ctx)
11367207b96SArnd Bergmann {
1146e1d5dccSAlexey Dobriyan 	static const struct inode_operations spufs_file_iops = {
11567207b96SArnd Bergmann 		.setattr = spufs_setattr,
11667207b96SArnd Bergmann 	};
11767207b96SArnd Bergmann 	struct inode *inode;
11867207b96SArnd Bergmann 	int ret;
11967207b96SArnd Bergmann 
12067207b96SArnd Bergmann 	ret = -ENOSPC;
12167207b96SArnd Bergmann 	inode = spufs_new_inode(sb, S_IFREG | mode);
12267207b96SArnd Bergmann 	if (!inode)
12367207b96SArnd Bergmann 		goto out;
12467207b96SArnd Bergmann 
12567207b96SArnd Bergmann 	ret = 0;
12667207b96SArnd Bergmann 	inode->i_op = &spufs_file_iops;
12767207b96SArnd Bergmann 	inode->i_fop = fops;
12823d893f5SJeremy Kerr 	inode->i_size = size;
1298e18e294STheodore Ts'o 	inode->i_private = SPUFS_I(inode)->i_ctx = get_spu_context(ctx);
13067207b96SArnd Bergmann 	d_add(dentry, inode);
13167207b96SArnd Bergmann out:
13267207b96SArnd Bergmann 	return ret;
13367207b96SArnd Bergmann }
13467207b96SArnd Bergmann 
13567207b96SArnd Bergmann static void
1360f3f63a4SAl Viro spufs_evict_inode(struct inode *inode)
13767207b96SArnd Bergmann {
1386263203eSArnd Bergmann 	struct spufs_inode_info *ei = SPUFS_I(inode);
139dbd5768fSJan Kara 	clear_inode(inode);
1406263203eSArnd Bergmann 	if (ei->i_ctx)
1416263203eSArnd Bergmann 		put_spu_context(ei->i_ctx);
1426263203eSArnd Bergmann 	if (ei->i_gang)
1436263203eSArnd Bergmann 		put_spu_gang(ei->i_gang);
14467207b96SArnd Bergmann }
14567207b96SArnd Bergmann 
1463f51dd91SArnd Bergmann static void spufs_prune_dir(struct dentry *dir)
1473f51dd91SArnd Bergmann {
1483f51dd91SArnd Bergmann 	struct dentry *dentry, *tmp;
1496263203eSArnd Bergmann 
1505955102cSAl Viro 	inode_lock(d_inode(dir));
151946e51f2SAl Viro 	list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child) {
1523f51dd91SArnd Bergmann 		spin_lock(&dentry->d_lock);
153dc3f4198SAl Viro 		if (simple_positive(dentry)) {
154dc0474beSNick Piggin 			dget_dlock(dentry);
1553f51dd91SArnd Bergmann 			__d_drop(dentry);
1563f51dd91SArnd Bergmann 			spin_unlock(&dentry->d_lock);
15775c3cfa8SDavid Howells 			simple_unlink(d_inode(dir), dentry);
158b5c84bf6SNick Piggin 			/* XXX: what was dcache_lock protecting here? Other
159da502956SNick Piggin 			 * filesystems (IB, configfs) release dcache_lock
160da502956SNick Piggin 			 * before unlink */
1613f51dd91SArnd Bergmann 			dput(dentry);
1623f51dd91SArnd Bergmann 		} else {
1633f51dd91SArnd Bergmann 			spin_unlock(&dentry->d_lock);
1643f51dd91SArnd Bergmann 		}
1653f51dd91SArnd Bergmann 	}
1663f51dd91SArnd Bergmann 	shrink_dcache_parent(dir);
1675955102cSAl Viro 	inode_unlock(d_inode(dir));
1683f51dd91SArnd Bergmann }
1693f51dd91SArnd Bergmann 
1706263203eSArnd Bergmann /* Caller must hold parent->i_mutex */
1716263203eSArnd Bergmann static int spufs_rmdir(struct inode *parent, struct dentry *dir)
1723f51dd91SArnd Bergmann {
1733f51dd91SArnd Bergmann 	/* remove all entries */
17467cba9fdSAl Viro 	int res;
1756263203eSArnd Bergmann 	spufs_prune_dir(dir);
176c443acabSJeremy Kerr 	d_drop(dir);
17767cba9fdSAl Viro 	res = simple_rmdir(parent, dir);
17867cba9fdSAl Viro 	/* We have to give up the mm_struct */
17975c3cfa8SDavid Howells 	spu_forget(SPUFS_I(d_inode(dir))->i_ctx);
18067cba9fdSAl Viro 	return res;
1813f51dd91SArnd Bergmann }
1823f51dd91SArnd Bergmann 
18374254647SJeremy Kerr static int spufs_fill_dir(struct dentry *dir,
184c6684b26SAl Viro 		const struct spufs_tree_descr *files, umode_t mode,
18574254647SJeremy Kerr 		struct spu_context *ctx)
18667207b96SArnd Bergmann {
18767207b96SArnd Bergmann 	while (files->name && files->name[0]) {
1882248b87eSAl Viro 		int ret;
1892248b87eSAl Viro 		struct dentry *dentry = d_alloc_name(dir, files->name);
19067207b96SArnd Bergmann 		if (!dentry)
1912248b87eSAl Viro 			return -ENOMEM;
19267207b96SArnd Bergmann 		ret = spufs_new_file(dir->d_sb, dentry, files->ops,
19323d893f5SJeremy Kerr 					files->mode & mode, files->size, ctx);
19467207b96SArnd Bergmann 		if (ret)
1952248b87eSAl Viro 			return ret;
19667207b96SArnd Bergmann 		files++;
19767207b96SArnd Bergmann 	}
19867207b96SArnd Bergmann 	return 0;
19967207b96SArnd Bergmann }
20067207b96SArnd Bergmann 
20167207b96SArnd Bergmann static int spufs_dir_close(struct inode *inode, struct file *file)
20267207b96SArnd Bergmann {
2036263203eSArnd Bergmann 	struct inode *parent;
2046263203eSArnd Bergmann 	struct dentry *dir;
20567207b96SArnd Bergmann 	int ret;
20667207b96SArnd Bergmann 
207b4d1ab58SJosef Sipek 	dir = file->f_path.dentry;
20875c3cfa8SDavid Howells 	parent = d_inode(dir->d_parent);
209c8ca0633SArnd Bergmann 
2105955102cSAl Viro 	inode_lock_nested(parent, I_MUTEX_PARENT);
2116263203eSArnd Bergmann 	ret = spufs_rmdir(parent, dir);
2125955102cSAl Viro 	inode_unlock(parent);
21367207b96SArnd Bergmann 	WARN_ON(ret);
214c8ca0633SArnd Bergmann 
21567207b96SArnd Bergmann 	return dcache_dir_close(inode, file);
21667207b96SArnd Bergmann }
21767207b96SArnd Bergmann 
2185dfe4c96SArjan van de Ven const struct file_operations spufs_context_fops = {
21967207b96SArnd Bergmann 	.open		= dcache_dir_open,
22067207b96SArnd Bergmann 	.release	= spufs_dir_close,
22167207b96SArnd Bergmann 	.llseek		= dcache_dir_lseek,
22267207b96SArnd Bergmann 	.read		= generic_read_dir,
2234e82901cSAl Viro 	.iterate_shared	= dcache_readdir,
2241b061d92SChristoph Hellwig 	.fsync		= noop_fsync,
22567207b96SArnd Bergmann };
226bf1ab978SDwayne Grant McConnell EXPORT_SYMBOL_GPL(spufs_context_fops);
22767207b96SArnd Bergmann 
22867207b96SArnd Bergmann static int
2299add11daSArnd Bergmann spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
230c6684b26SAl Viro 		umode_t mode)
23167207b96SArnd Bergmann {
23267207b96SArnd Bergmann 	int ret;
23367207b96SArnd Bergmann 	struct inode *inode;
23467207b96SArnd Bergmann 	struct spu_context *ctx;
23567207b96SArnd Bergmann 
23667207b96SArnd Bergmann 	inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR);
23767207b96SArnd Bergmann 	if (!inode)
2382248b87eSAl Viro 		return -ENOSPC;
23967207b96SArnd Bergmann 
240*f2d40141SChristian Brauner 	inode_init_owner(&nop_mnt_idmap, inode, dir, mode | S_IFDIR);
2416263203eSArnd Bergmann 	ctx = alloc_spu_context(SPUFS_I(dir)->i_gang); /* XXX gang */
24267207b96SArnd Bergmann 	SPUFS_I(inode)->i_ctx = ctx;
2432248b87eSAl Viro 	if (!ctx) {
2442248b87eSAl Viro 		iput(inode);
2452248b87eSAl Viro 		return -ENOSPC;
2462248b87eSAl Viro 	}
24767207b96SArnd Bergmann 
2489add11daSArnd Bergmann 	ctx->flags = flags;
249b8c295f9SJeremy Kerr 	inode->i_op = &simple_dir_inode_operations;
25067207b96SArnd Bergmann 	inode->i_fop = &simple_dir_operations;
2512248b87eSAl Viro 
2525955102cSAl Viro 	inode_lock(inode);
2532248b87eSAl Viro 
2542248b87eSAl Viro 	dget(dentry);
2552248b87eSAl Viro 	inc_nlink(dir);
2562248b87eSAl Viro 	inc_nlink(inode);
2572248b87eSAl Viro 
2582248b87eSAl Viro 	d_instantiate(dentry, inode);
2592248b87eSAl Viro 
2605737edd1SMark Nutter 	if (flags & SPU_CREATE_NOSCHED)
2615737edd1SMark Nutter 		ret = spufs_fill_dir(dentry, spufs_dir_nosched_contents,
2625737edd1SMark Nutter 					 mode, ctx);
2635737edd1SMark Nutter 	else
26467207b96SArnd Bergmann 		ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx);
2655737edd1SMark Nutter 
2662248b87eSAl Viro 	if (!ret && spufs_get_sb_info(dir->i_sb)->debug)
2672c3e4787SJeremy Kerr 		ret = spufs_fill_dir(dentry, spufs_dir_debug_contents,
2682c3e4787SJeremy Kerr 				mode, ctx);
2692c3e4787SJeremy Kerr 
2702c3e4787SJeremy Kerr 	if (ret)
2712248b87eSAl Viro 		spufs_rmdir(dir, dentry);
2722c3e4787SJeremy Kerr 
2735955102cSAl Viro 	inode_unlock(inode);
27467207b96SArnd Bergmann 
27567207b96SArnd Bergmann 	return ret;
27667207b96SArnd Bergmann }
27767207b96SArnd Bergmann 
27820f45ad5SAl Viro static int spufs_context_open(const struct path *path)
279346f4d3cSArnd Bergmann {
280346f4d3cSArnd Bergmann 	int ret;
281346f4d3cSArnd Bergmann 	struct file *filp;
282346f4d3cSArnd Bergmann 
2836b9cdf39SYann Droneaud 	ret = get_unused_fd_flags(0);
284bf349a44SAl Viro 	if (ret < 0)
285bf349a44SAl Viro 		return ret;
286346f4d3cSArnd Bergmann 
287765927b2SAl Viro 	filp = dentry_open(path, O_RDONLY, current_cred());
288346f4d3cSArnd Bergmann 	if (IS_ERR(filp)) {
289346f4d3cSArnd Bergmann 		put_unused_fd(ret);
290bf349a44SAl Viro 		return PTR_ERR(filp);
291346f4d3cSArnd Bergmann 	}
292346f4d3cSArnd Bergmann 
293346f4d3cSArnd Bergmann 	filp->f_op = &spufs_context_fops;
294346f4d3cSArnd Bergmann 	fd_install(ret, filp);
295346f4d3cSArnd Bergmann 	return ret;
296346f4d3cSArnd Bergmann }
297346f4d3cSArnd Bergmann 
2988e68e2f2SArnd Bergmann static struct spu_context *
2998e68e2f2SArnd Bergmann spufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
3008e68e2f2SArnd Bergmann 						struct file *filp)
3018e68e2f2SArnd Bergmann {
30258119068SAndre Detsch 	struct spu_context *tmp, *neighbor, *err;
3038e68e2f2SArnd Bergmann 	int count, node;
3048e68e2f2SArnd Bergmann 	int aff_supp;
3058e68e2f2SArnd Bergmann 
3068e68e2f2SArnd Bergmann 	aff_supp = !list_empty(&(list_entry(cbe_spu_info[0].spus.next,
3078e68e2f2SArnd Bergmann 					struct spu, cbe_list))->aff_list);
3088e68e2f2SArnd Bergmann 
3098e68e2f2SArnd Bergmann 	if (!aff_supp)
3108e68e2f2SArnd Bergmann 		return ERR_PTR(-EINVAL);
3118e68e2f2SArnd Bergmann 
3128e68e2f2SArnd Bergmann 	if (flags & SPU_CREATE_GANG)
3138e68e2f2SArnd Bergmann 		return ERR_PTR(-EINVAL);
3148e68e2f2SArnd Bergmann 
3158e68e2f2SArnd Bergmann 	if (flags & SPU_CREATE_AFFINITY_MEM &&
3168e68e2f2SArnd Bergmann 	    gang->aff_ref_ctx &&
3178e68e2f2SArnd Bergmann 	    gang->aff_ref_ctx->flags & SPU_CREATE_AFFINITY_MEM)
3188e68e2f2SArnd Bergmann 		return ERR_PTR(-EEXIST);
3198e68e2f2SArnd Bergmann 
3208e68e2f2SArnd Bergmann 	if (gang->aff_flags & AFF_MERGED)
3218e68e2f2SArnd Bergmann 		return ERR_PTR(-EBUSY);
3228e68e2f2SArnd Bergmann 
3238e68e2f2SArnd Bergmann 	neighbor = NULL;
3248e68e2f2SArnd Bergmann 	if (flags & SPU_CREATE_AFFINITY_SPU) {
3258e68e2f2SArnd Bergmann 		if (!filp || filp->f_op != &spufs_context_fops)
3268e68e2f2SArnd Bergmann 			return ERR_PTR(-EINVAL);
3278e68e2f2SArnd Bergmann 
3288e68e2f2SArnd Bergmann 		neighbor = get_spu_context(
329496ad9aaSAl Viro 				SPUFS_I(file_inode(filp))->i_ctx);
3308e68e2f2SArnd Bergmann 
3318e68e2f2SArnd Bergmann 		if (!list_empty(&neighbor->aff_list) && !(neighbor->aff_head) &&
3328e68e2f2SArnd Bergmann 		    !list_is_last(&neighbor->aff_list, &gang->aff_list_head) &&
3338e68e2f2SArnd Bergmann 		    !list_entry(neighbor->aff_list.next, struct spu_context,
33458119068SAndre Detsch 		    aff_list)->aff_head) {
33558119068SAndre Detsch 			err = ERR_PTR(-EEXIST);
33658119068SAndre Detsch 			goto out_put_neighbor;
33758119068SAndre Detsch 		}
3388e68e2f2SArnd Bergmann 
33958119068SAndre Detsch 		if (gang != neighbor->gang) {
34058119068SAndre Detsch 			err = ERR_PTR(-EINVAL);
34158119068SAndre Detsch 			goto out_put_neighbor;
34258119068SAndre Detsch 		}
3438e68e2f2SArnd Bergmann 
3448e68e2f2SArnd Bergmann 		count = 1;
3458e68e2f2SArnd Bergmann 		list_for_each_entry(tmp, &gang->aff_list_head, aff_list)
3468e68e2f2SArnd Bergmann 			count++;
3478e68e2f2SArnd Bergmann 		if (list_empty(&neighbor->aff_list))
3488e68e2f2SArnd Bergmann 			count++;
3498e68e2f2SArnd Bergmann 
3508e68e2f2SArnd Bergmann 		for (node = 0; node < MAX_NUMNODES; node++) {
3518e68e2f2SArnd Bergmann 			if ((cbe_spu_info[node].n_spus - atomic_read(
3528e68e2f2SArnd Bergmann 				&cbe_spu_info[node].reserved_spus)) >= count)
3538e68e2f2SArnd Bergmann 				break;
3548e68e2f2SArnd Bergmann 		}
3558e68e2f2SArnd Bergmann 
35658119068SAndre Detsch 		if (node == MAX_NUMNODES) {
35758119068SAndre Detsch 			err = ERR_PTR(-EEXIST);
35858119068SAndre Detsch 			goto out_put_neighbor;
35958119068SAndre Detsch 		}
3608e68e2f2SArnd Bergmann 	}
3618e68e2f2SArnd Bergmann 
3628e68e2f2SArnd Bergmann 	return neighbor;
36358119068SAndre Detsch 
36458119068SAndre Detsch out_put_neighbor:
36558119068SAndre Detsch 	put_spu_context(neighbor);
36658119068SAndre Detsch 	return err;
3678e68e2f2SArnd Bergmann }
3688e68e2f2SArnd Bergmann 
3698e68e2f2SArnd Bergmann static void
3708e68e2f2SArnd Bergmann spufs_set_affinity(unsigned int flags, struct spu_context *ctx,
3718e68e2f2SArnd Bergmann 					struct spu_context *neighbor)
3728e68e2f2SArnd Bergmann {
3738e68e2f2SArnd Bergmann 	if (flags & SPU_CREATE_AFFINITY_MEM)
3748e68e2f2SArnd Bergmann 		ctx->gang->aff_ref_ctx = ctx;
3758e68e2f2SArnd Bergmann 
3768e68e2f2SArnd Bergmann 	if (flags & SPU_CREATE_AFFINITY_SPU) {
3778e68e2f2SArnd Bergmann 		if (list_empty(&neighbor->aff_list)) {
3788e68e2f2SArnd Bergmann 			list_add_tail(&neighbor->aff_list,
3798e68e2f2SArnd Bergmann 				&ctx->gang->aff_list_head);
3808e68e2f2SArnd Bergmann 			neighbor->aff_head = 1;
3818e68e2f2SArnd Bergmann 		}
3828e68e2f2SArnd Bergmann 
3838e68e2f2SArnd Bergmann 		if (list_is_last(&neighbor->aff_list, &ctx->gang->aff_list_head)
3848e68e2f2SArnd Bergmann 		    || list_entry(neighbor->aff_list.next, struct spu_context,
3858e68e2f2SArnd Bergmann 							aff_list)->aff_head) {
3868e68e2f2SArnd Bergmann 			list_add(&ctx->aff_list, &neighbor->aff_list);
3878e68e2f2SArnd Bergmann 		} else  {
3888e68e2f2SArnd Bergmann 			list_add_tail(&ctx->aff_list, &neighbor->aff_list);
3898e68e2f2SArnd Bergmann 			if (neighbor->aff_head) {
3908e68e2f2SArnd Bergmann 				neighbor->aff_head = 0;
3918e68e2f2SArnd Bergmann 				ctx->aff_head = 1;
3928e68e2f2SArnd Bergmann 			}
3938e68e2f2SArnd Bergmann 		}
3948e68e2f2SArnd Bergmann 
3958e68e2f2SArnd Bergmann 		if (!ctx->gang->aff_ref_ctx)
3968e68e2f2SArnd Bergmann 			ctx->gang->aff_ref_ctx = ctx;
3978e68e2f2SArnd Bergmann 	}
3988e68e2f2SArnd Bergmann }
3998e68e2f2SArnd Bergmann 
4008e68e2f2SArnd Bergmann static int
4018e68e2f2SArnd Bergmann spufs_create_context(struct inode *inode, struct dentry *dentry,
402c6684b26SAl Viro 			struct vfsmount *mnt, int flags, umode_t mode,
4038e68e2f2SArnd Bergmann 			struct file *aff_filp)
4046263203eSArnd Bergmann {
4056263203eSArnd Bergmann 	int ret;
4068e68e2f2SArnd Bergmann 	int affinity;
4078e68e2f2SArnd Bergmann 	struct spu_gang *gang;
4088e68e2f2SArnd Bergmann 	struct spu_context *neighbor;
409765927b2SAl Viro 	struct path path = {.mnt = mnt, .dentry = dentry};
4106263203eSArnd Bergmann 
4115737edd1SMark Nutter 	if ((flags & SPU_CREATE_NOSCHED) &&
4125737edd1SMark Nutter 	    !capable(CAP_SYS_NICE))
4131ba44cc9SAl Viro 		return -EPERM;
4145737edd1SMark Nutter 
4155737edd1SMark Nutter 	if ((flags & (SPU_CREATE_NOSCHED | SPU_CREATE_ISOLATE))
4165737edd1SMark Nutter 	    == SPU_CREATE_ISOLATE)
4171ba44cc9SAl Viro 		return -EINVAL;
4185737edd1SMark Nutter 
419bd2e5f82SJeremy Kerr 	if ((flags & SPU_CREATE_ISOLATE) && !isolated_loader)
4201ba44cc9SAl Viro 		return -ENODEV;
421bd2e5f82SJeremy Kerr 
4228e68e2f2SArnd Bergmann 	gang = NULL;
4238e68e2f2SArnd Bergmann 	neighbor = NULL;
4248e68e2f2SArnd Bergmann 	affinity = flags & (SPU_CREATE_AFFINITY_MEM | SPU_CREATE_AFFINITY_SPU);
4258e68e2f2SArnd Bergmann 	if (affinity) {
4268e68e2f2SArnd Bergmann 		gang = SPUFS_I(inode)->i_gang;
4278e68e2f2SArnd Bergmann 		if (!gang)
4281ba44cc9SAl Viro 			return -EINVAL;
4298e68e2f2SArnd Bergmann 		mutex_lock(&gang->aff_mutex);
4308e68e2f2SArnd Bergmann 		neighbor = spufs_assert_affinity(flags, gang, aff_filp);
4318e68e2f2SArnd Bergmann 		if (IS_ERR(neighbor)) {
4328e68e2f2SArnd Bergmann 			ret = PTR_ERR(neighbor);
4338e68e2f2SArnd Bergmann 			goto out_aff_unlock;
4348e68e2f2SArnd Bergmann 		}
4358e68e2f2SArnd Bergmann 	}
4368e68e2f2SArnd Bergmann 
43757ad583fSRussell Currey 	ret = spufs_mkdir(inode, dentry, flags, mode & 0777);
4386263203eSArnd Bergmann 	if (ret)
4398e68e2f2SArnd Bergmann 		goto out_aff_unlock;
4408e68e2f2SArnd Bergmann 
44158119068SAndre Detsch 	if (affinity) {
44275c3cfa8SDavid Howells 		spufs_set_affinity(flags, SPUFS_I(d_inode(dentry))->i_ctx,
4438e68e2f2SArnd Bergmann 								neighbor);
44458119068SAndre Detsch 		if (neighbor)
44558119068SAndre Detsch 			put_spu_context(neighbor);
44658119068SAndre Detsch 	}
4476263203eSArnd Bergmann 
448765927b2SAl Viro 	ret = spufs_context_open(&path);
44966ec7b2cSAl Viro 	if (ret < 0)
4506263203eSArnd Bergmann 		WARN_ON(spufs_rmdir(inode, dentry));
4516263203eSArnd Bergmann 
4528e68e2f2SArnd Bergmann out_aff_unlock:
4538e68e2f2SArnd Bergmann 	if (affinity)
4548e68e2f2SArnd Bergmann 		mutex_unlock(&gang->aff_mutex);
4556263203eSArnd Bergmann 	return ret;
4566263203eSArnd Bergmann }
4576263203eSArnd Bergmann 
4586263203eSArnd Bergmann static int
459c6684b26SAl Viro spufs_mkgang(struct inode *dir, struct dentry *dentry, umode_t mode)
4606263203eSArnd Bergmann {
4616263203eSArnd Bergmann 	int ret;
4626263203eSArnd Bergmann 	struct inode *inode;
4636263203eSArnd Bergmann 	struct spu_gang *gang;
4646263203eSArnd Bergmann 
4656263203eSArnd Bergmann 	ret = -ENOSPC;
4666263203eSArnd Bergmann 	inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR);
4676263203eSArnd Bergmann 	if (!inode)
4686263203eSArnd Bergmann 		goto out;
4696263203eSArnd Bergmann 
4706263203eSArnd Bergmann 	ret = 0;
471*f2d40141SChristian Brauner 	inode_init_owner(&nop_mnt_idmap, inode, dir, mode | S_IFDIR);
4726263203eSArnd Bergmann 	gang = alloc_spu_gang();
4736263203eSArnd Bergmann 	SPUFS_I(inode)->i_ctx = NULL;
4746263203eSArnd Bergmann 	SPUFS_I(inode)->i_gang = gang;
47554a94fcfSDan Carpenter 	if (!gang) {
47654a94fcfSDan Carpenter 		ret = -ENOMEM;
4776263203eSArnd Bergmann 		goto out_iput;
47854a94fcfSDan Carpenter 	}
4796263203eSArnd Bergmann 
480b8c295f9SJeremy Kerr 	inode->i_op = &simple_dir_inode_operations;
4816263203eSArnd Bergmann 	inode->i_fop = &simple_dir_operations;
4826263203eSArnd Bergmann 
4836263203eSArnd Bergmann 	d_instantiate(dentry, inode);
484ba0b996dSJeremy Kerr 	inc_nlink(dir);
48575c3cfa8SDavid Howells 	inc_nlink(d_inode(dentry));
4866263203eSArnd Bergmann 	return ret;
4876263203eSArnd Bergmann 
4886263203eSArnd Bergmann out_iput:
4896263203eSArnd Bergmann 	iput(inode);
4906263203eSArnd Bergmann out:
4916263203eSArnd Bergmann 	return ret;
4926263203eSArnd Bergmann }
4936263203eSArnd Bergmann 
49420f45ad5SAl Viro static int spufs_gang_open(const struct path *path)
4956263203eSArnd Bergmann {
4966263203eSArnd Bergmann 	int ret;
4976263203eSArnd Bergmann 	struct file *filp;
4986263203eSArnd Bergmann 
4996b9cdf39SYann Droneaud 	ret = get_unused_fd_flags(0);
500bf349a44SAl Viro 	if (ret < 0)
501bf349a44SAl Viro 		return ret;
5026263203eSArnd Bergmann 
503bf349a44SAl Viro 	/*
504bf349a44SAl Viro 	 * get references for dget and mntget, will be released
505bf349a44SAl Viro 	 * in error path of *_open().
506bf349a44SAl Viro 	 */
507765927b2SAl Viro 	filp = dentry_open(path, O_RDONLY, current_cred());
5086263203eSArnd Bergmann 	if (IS_ERR(filp)) {
5096263203eSArnd Bergmann 		put_unused_fd(ret);
510bf349a44SAl Viro 		return PTR_ERR(filp);
5116263203eSArnd Bergmann 	}
5126263203eSArnd Bergmann 
513877907d3SJeremy Kerr 	filp->f_op = &simple_dir_operations;
5146263203eSArnd Bergmann 	fd_install(ret, filp);
5156263203eSArnd Bergmann 	return ret;
5166263203eSArnd Bergmann }
5176263203eSArnd Bergmann 
5186263203eSArnd Bergmann static int spufs_create_gang(struct inode *inode,
5196263203eSArnd Bergmann 			struct dentry *dentry,
520c6684b26SAl Viro 			struct vfsmount *mnt, umode_t mode)
5216263203eSArnd Bergmann {
522765927b2SAl Viro 	struct path path = {.mnt = mnt, .dentry = dentry};
5236263203eSArnd Bergmann 	int ret;
5246263203eSArnd Bergmann 
52557ad583fSRussell Currey 	ret = spufs_mkgang(inode, dentry, mode & 0777);
5261ba44cc9SAl Viro 	if (!ret) {
527765927b2SAl Viro 		ret = spufs_gang_open(&path);
528877907d3SJeremy Kerr 		if (ret < 0) {
529877907d3SJeremy Kerr 			int err = simple_rmdir(inode, dentry);
530877907d3SJeremy Kerr 			WARN_ON(err);
531877907d3SJeremy Kerr 		}
5321ba44cc9SAl Viro 	}
5336263203eSArnd Bergmann 	return ret;
5346263203eSArnd Bergmann }
5356263203eSArnd Bergmann 
5366263203eSArnd Bergmann 
537346f4d3cSArnd Bergmann static struct file_system_type spufs_type;
538346f4d3cSArnd Bergmann 
53920f45ad5SAl Viro long spufs_create(const struct path *path, struct dentry *dentry,
540c6684b26SAl Viro 		unsigned int flags, umode_t mode, struct file *filp)
54167207b96SArnd Bergmann {
54275c3cfa8SDavid Howells 	struct inode *dir = d_inode(path->dentry);
54367207b96SArnd Bergmann 	int ret;
54467207b96SArnd Bergmann 
5456263203eSArnd Bergmann 	/* check if we are on spufs */
5461ba10681SAl Viro 	if (path->dentry->d_sb->s_type != &spufs_type)
54725b2692aSAl Viro 		return -EINVAL;
54867207b96SArnd Bergmann 
5496263203eSArnd Bergmann 	/* don't accept undefined flags */
5509add11daSArnd Bergmann 	if (flags & (~SPU_CREATE_FLAG_ALL))
55125b2692aSAl Viro 		return -EINVAL;
552c9832948Sarnd@arndb.de 
5536263203eSArnd Bergmann 	/* only threads can be underneath a gang */
55425b2692aSAl Viro 	if (path->dentry != path->dentry->d_sb->s_root)
55525b2692aSAl Viro 		if ((flags & SPU_CREATE_GANG) || !SPUFS_I(dir)->i_gang)
55625b2692aSAl Viro 			return -EINVAL;
5576263203eSArnd Bergmann 
558ce3b0f8dSAl Viro 	mode &= ~current_umask();
55967207b96SArnd Bergmann 
5606263203eSArnd Bergmann 	if (flags & SPU_CREATE_GANG)
56125b2692aSAl Viro 		ret = spufs_create_gang(dir, dentry, path->mnt, mode);
5626263203eSArnd Bergmann 	else
56325b2692aSAl Viro 		ret = spufs_create_context(dir, dentry, path->mnt, flags, mode,
5644ac91378SJan Blunck 					    filp);
565826be063SChristoph Hellwig 	if (ret >= 0)
56625b2692aSAl Viro 		fsnotify_mkdir(dir, dentry);
56767207b96SArnd Bergmann 
56867207b96SArnd Bergmann 	return ret;
56967207b96SArnd Bergmann }
57067207b96SArnd Bergmann 
57167207b96SArnd Bergmann /* File system initialization */
572d2e0981cSDavid Howells struct spufs_fs_context {
573d2e0981cSDavid Howells 	kuid_t	uid;
574d2e0981cSDavid Howells 	kgid_t	gid;
575d2e0981cSDavid Howells 	umode_t	mode;
57667207b96SArnd Bergmann };
57767207b96SArnd Bergmann 
578d2e0981cSDavid Howells enum {
579d2e0981cSDavid Howells 	Opt_uid, Opt_gid, Opt_mode, Opt_debug,
580d2e0981cSDavid Howells };
581d2e0981cSDavid Howells 
582d7167b14SAl Viro static const struct fs_parameter_spec spufs_fs_parameters[] = {
583d2e0981cSDavid Howells 	fsparam_u32	("gid",				Opt_gid),
584d2e0981cSDavid Howells 	fsparam_u32oct	("mode",			Opt_mode),
585d2e0981cSDavid Howells 	fsparam_u32	("uid",				Opt_uid),
586d2e0981cSDavid Howells 	fsparam_flag	("debug",			Opt_debug),
587d2e0981cSDavid Howells 	{}
588d2e0981cSDavid Howells };
589d2e0981cSDavid Howells 
590a66ca414SDavid Howells static int spufs_show_options(struct seq_file *m, struct dentry *root)
591a66ca414SDavid Howells {
592a66ca414SDavid Howells 	struct spufs_sb_info *sbi = spufs_get_sb_info(root->d_sb);
593a66ca414SDavid Howells 	struct inode *inode = root->d_inode;
594a66ca414SDavid Howells 
595a66ca414SDavid Howells 	if (!uid_eq(inode->i_uid, GLOBAL_ROOT_UID))
596a66ca414SDavid Howells 		seq_printf(m, ",uid=%u",
597a66ca414SDavid Howells 			   from_kuid_munged(&init_user_ns, inode->i_uid));
598a66ca414SDavid Howells 	if (!gid_eq(inode->i_gid, GLOBAL_ROOT_GID))
599a66ca414SDavid Howells 		seq_printf(m, ",gid=%u",
600a66ca414SDavid Howells 			   from_kgid_munged(&init_user_ns, inode->i_gid));
601a66ca414SDavid Howells 	if ((inode->i_mode & S_IALLUGO) != 0775)
602a66ca414SDavid Howells 		seq_printf(m, ",mode=%o", inode->i_mode);
603a66ca414SDavid Howells 	if (sbi->debug)
604a66ca414SDavid Howells 		seq_puts(m, ",debug");
605a66ca414SDavid Howells 	return 0;
606a66ca414SDavid Howells }
607a66ca414SDavid Howells 
608d2e0981cSDavid Howells static int spufs_parse_param(struct fs_context *fc, struct fs_parameter *param)
60967207b96SArnd Bergmann {
610d2e0981cSDavid Howells 	struct spufs_fs_context *ctx = fc->fs_private;
611d2e0981cSDavid Howells 	struct spufs_sb_info *sbi = fc->s_fs_info;
612d2e0981cSDavid Howells 	struct fs_parse_result result;
613d2e0981cSDavid Howells 	kuid_t uid;
614d2e0981cSDavid Howells 	kgid_t gid;
615d2e0981cSDavid Howells 	int opt;
61667207b96SArnd Bergmann 
617d7167b14SAl Viro 	opt = fs_parse(fc, spufs_fs_parameters, param, &result);
618d2e0981cSDavid Howells 	if (opt < 0)
619d2e0981cSDavid Howells 		return opt;
62067207b96SArnd Bergmann 
621d2e0981cSDavid Howells 	switch (opt) {
62267207b96SArnd Bergmann 	case Opt_uid:
623d2e0981cSDavid Howells 		uid = make_kuid(current_user_ns(), result.uint_32);
624d2e0981cSDavid Howells 		if (!uid_valid(uid))
625d2e0981cSDavid Howells 			return invalf(fc, "Unknown uid");
626d2e0981cSDavid Howells 		ctx->uid = uid;
62767207b96SArnd Bergmann 		break;
62867207b96SArnd Bergmann 	case Opt_gid:
629d2e0981cSDavid Howells 		gid = make_kgid(current_user_ns(), result.uint_32);
630d2e0981cSDavid Howells 		if (!gid_valid(gid))
631d2e0981cSDavid Howells 			return invalf(fc, "Unknown gid");
632d2e0981cSDavid Howells 		ctx->gid = gid;
63367207b96SArnd Bergmann 		break;
634f11f5ee7SJeremy Kerr 	case Opt_mode:
635d2e0981cSDavid Howells 		ctx->mode = result.uint_32 & S_IALLUGO;
636f11f5ee7SJeremy Kerr 		break;
6372c3e4787SJeremy Kerr 	case Opt_debug:
638d2e0981cSDavid Howells 		sbi->debug = true;
6392c3e4787SJeremy Kerr 		break;
640d2e0981cSDavid Howells 	}
641d2e0981cSDavid Howells 
64267207b96SArnd Bergmann 	return 0;
64367207b96SArnd Bergmann }
64467207b96SArnd Bergmann 
645db1384b4SAkinobu Mita static void spufs_exit_isolated_loader(void)
646db1384b4SAkinobu Mita {
6478b0d3121SSebastian Siewior 	free_pages((unsigned long) isolated_loader,
6488b0d3121SSebastian Siewior 			get_order(isolated_loader_size));
649db1384b4SAkinobu Mita }
650db1384b4SAkinobu Mita 
6517c1ab16bSNick Child static void __init
6520afacde3Sarnd@arndb.de spufs_init_isolated_loader(void)
6530afacde3Sarnd@arndb.de {
6540afacde3Sarnd@arndb.de 	struct device_node *dn;
6550afacde3Sarnd@arndb.de 	const char *loader;
6560afacde3Sarnd@arndb.de 	int size;
6570afacde3Sarnd@arndb.de 
6580afacde3Sarnd@arndb.de 	dn = of_find_node_by_path("/spu-isolation");
6590afacde3Sarnd@arndb.de 	if (!dn)
6600afacde3Sarnd@arndb.de 		return;
6610afacde3Sarnd@arndb.de 
662e2eb6392SStephen Rothwell 	loader = of_get_property(dn, "loader", &size);
6636ac059daSMiaoqian Lin 	of_node_put(dn);
6640afacde3Sarnd@arndb.de 	if (!loader)
6650afacde3Sarnd@arndb.de 		return;
6660afacde3Sarnd@arndb.de 
6678b0d3121SSebastian Siewior 	/* the loader must be align on a 16 byte boundary */
6688b0d3121SSebastian Siewior 	isolated_loader = (char *)__get_free_pages(GFP_KERNEL, get_order(size));
6690afacde3Sarnd@arndb.de 	if (!isolated_loader)
6700afacde3Sarnd@arndb.de 		return;
6710afacde3Sarnd@arndb.de 
6728b0d3121SSebastian Siewior 	isolated_loader_size = size;
6730afacde3Sarnd@arndb.de 	memcpy(isolated_loader, loader, size);
6740afacde3Sarnd@arndb.de 	printk(KERN_INFO "spufs: SPU isolation mode enabled\n");
6750afacde3Sarnd@arndb.de }
6760afacde3Sarnd@arndb.de 
677d2e0981cSDavid Howells static int spufs_create_root(struct super_block *sb, struct fs_context *fc)
6788b3d6663SArnd Bergmann {
679d2e0981cSDavid Howells 	struct spufs_fs_context *ctx = fc->fs_private;
68067207b96SArnd Bergmann 	struct inode *inode;
68167207b96SArnd Bergmann 
6828f18a158SArnd Bergmann 	if (!spu_management_ops)
683d2e0981cSDavid Howells 		return -ENODEV;
6848f18a158SArnd Bergmann 
685d2e0981cSDavid Howells 	inode = spufs_new_inode(sb, S_IFDIR | ctx->mode);
68667207b96SArnd Bergmann 	if (!inode)
687d2e0981cSDavid Howells 		return -ENOMEM;
68867207b96SArnd Bergmann 
689d2e0981cSDavid Howells 	inode->i_uid = ctx->uid;
690d2e0981cSDavid Howells 	inode->i_gid = ctx->gid;
691b8c295f9SJeremy Kerr 	inode->i_op = &simple_dir_inode_operations;
69267207b96SArnd Bergmann 	inode->i_fop = &simple_dir_operations;
69367207b96SArnd Bergmann 	SPUFS_I(inode)->i_ctx = NULL;
694e2ed6e4dSJeremy Kerr 	inc_nlink(inode);
69567207b96SArnd Bergmann 
69648fde701SAl Viro 	sb->s_root = d_make_root(inode);
69767207b96SArnd Bergmann 	if (!sb->s_root)
698d2e0981cSDavid Howells 		return -ENOMEM;
69967207b96SArnd Bergmann 	return 0;
70067207b96SArnd Bergmann }
70167207b96SArnd Bergmann 
702d2e0981cSDavid Howells static const struct super_operations spufs_ops = {
70367207b96SArnd Bergmann 	.alloc_inode	= spufs_alloc_inode,
7046d0e0d0bSAl Viro 	.free_inode	= spufs_free_inode,
70567207b96SArnd Bergmann 	.statfs		= simple_statfs,
7060f3f63a4SAl Viro 	.evict_inode	= spufs_evict_inode,
707a66ca414SDavid Howells 	.show_options	= spufs_show_options,
70867207b96SArnd Bergmann };
70967207b96SArnd Bergmann 
710d2e0981cSDavid Howells static int spufs_fill_super(struct super_block *sb, struct fs_context *fc)
711d2e0981cSDavid Howells {
71267207b96SArnd Bergmann 	sb->s_maxbytes = MAX_LFS_FILESIZE;
71309cbfeafSKirill A. Shutemov 	sb->s_blocksize = PAGE_SIZE;
71409cbfeafSKirill A. Shutemov 	sb->s_blocksize_bits = PAGE_SHIFT;
71567207b96SArnd Bergmann 	sb->s_magic = SPUFS_MAGIC;
716d2e0981cSDavid Howells 	sb->s_op = &spufs_ops;
71767207b96SArnd Bergmann 
718d2e0981cSDavid Howells 	return spufs_create_root(sb, fc);
71967207b96SArnd Bergmann }
72067207b96SArnd Bergmann 
721d2e0981cSDavid Howells static int spufs_get_tree(struct fs_context *fc)
72267207b96SArnd Bergmann {
723d2e0981cSDavid Howells 	return get_tree_single(fc, spufs_fill_super);
724d2e0981cSDavid Howells }
725d2e0981cSDavid Howells 
726d2e0981cSDavid Howells static void spufs_free_fc(struct fs_context *fc)
727d2e0981cSDavid Howells {
728d2e0981cSDavid Howells 	kfree(fc->s_fs_info);
729d2e0981cSDavid Howells }
730d2e0981cSDavid Howells 
731d2e0981cSDavid Howells static const struct fs_context_operations spufs_context_ops = {
732d2e0981cSDavid Howells 	.free		= spufs_free_fc,
733d2e0981cSDavid Howells 	.parse_param	= spufs_parse_param,
734d2e0981cSDavid Howells 	.get_tree	= spufs_get_tree,
735d2e0981cSDavid Howells };
736d2e0981cSDavid Howells 
737d2e0981cSDavid Howells static int spufs_init_fs_context(struct fs_context *fc)
738d2e0981cSDavid Howells {
739d2e0981cSDavid Howells 	struct spufs_fs_context *ctx;
740d2e0981cSDavid Howells 	struct spufs_sb_info *sbi;
741d2e0981cSDavid Howells 
742d2e0981cSDavid Howells 	ctx = kzalloc(sizeof(struct spufs_fs_context), GFP_KERNEL);
743d2e0981cSDavid Howells 	if (!ctx)
744d2e0981cSDavid Howells 		goto nomem;
745d2e0981cSDavid Howells 
746d2e0981cSDavid Howells 	sbi = kzalloc(sizeof(struct spufs_sb_info), GFP_KERNEL);
747d2e0981cSDavid Howells 	if (!sbi)
748d2e0981cSDavid Howells 		goto nomem_ctx;
749d2e0981cSDavid Howells 
750d2e0981cSDavid Howells 	ctx->uid = current_uid();
751d2e0981cSDavid Howells 	ctx->gid = current_gid();
752d2e0981cSDavid Howells 	ctx->mode = 0755;
753d2e0981cSDavid Howells 
7542272905aSEmmanuel Nicolet 	fc->fs_private = ctx;
755d2e0981cSDavid Howells 	fc->s_fs_info = sbi;
756d2e0981cSDavid Howells 	fc->ops = &spufs_context_ops;
757d2e0981cSDavid Howells 	return 0;
758d2e0981cSDavid Howells 
759d2e0981cSDavid Howells nomem_ctx:
760d2e0981cSDavid Howells 	kfree(ctx);
761d2e0981cSDavid Howells nomem:
762d2e0981cSDavid Howells 	return -ENOMEM;
76367207b96SArnd Bergmann }
76467207b96SArnd Bergmann 
76567207b96SArnd Bergmann static struct file_system_type spufs_type = {
76667207b96SArnd Bergmann 	.owner = THIS_MODULE,
76767207b96SArnd Bergmann 	.name = "spufs",
768d2e0981cSDavid Howells 	.init_fs_context = spufs_init_fs_context,
769d7167b14SAl Viro 	.parameters	= spufs_fs_parameters,
77067207b96SArnd Bergmann 	.kill_sb = kill_litter_super,
77167207b96SArnd Bergmann };
7727f78e035SEric W. Biederman MODULE_ALIAS_FS("spufs");
77367207b96SArnd Bergmann 
774e78b47a5SArnd Bergmann static int __init spufs_init(void)
77567207b96SArnd Bergmann {
77667207b96SArnd Bergmann 	int ret;
777bf1ab978SDwayne Grant McConnell 
778ccf17e9dSJeremy Kerr 	ret = -ENODEV;
779ccf17e9dSJeremy Kerr 	if (!spu_management_ops)
780ccf17e9dSJeremy Kerr 		goto out;
781ccf17e9dSJeremy Kerr 
78267207b96SArnd Bergmann 	ret = -ENOMEM;
78367207b96SArnd Bergmann 	spufs_inode_cache = kmem_cache_create("spufs_inode_cache",
78467207b96SArnd Bergmann 			sizeof(struct spufs_inode_info), 0,
7855d097056SVladimir Davydov 			SLAB_HWCACHE_ALIGN|SLAB_ACCOUNT, spufs_init_once);
78667207b96SArnd Bergmann 
78767207b96SArnd Bergmann 	if (!spufs_inode_cache)
78867207b96SArnd Bergmann 		goto out;
789c99c1994SAkinobu Mita 	ret = spu_sched_init();
79067207b96SArnd Bergmann 	if (ret)
79167207b96SArnd Bergmann 		goto out_cache;
79267207b96SArnd Bergmann 	ret = register_spu_syscalls(&spufs_calls);
79367207b96SArnd Bergmann 	if (ret)
794640045a1SAl Viro 		goto out_sched;
795640045a1SAl Viro 	ret = register_filesystem(&spufs_type);
796640045a1SAl Viro 	if (ret)
797640045a1SAl Viro 		goto out_syscalls;
7980afacde3Sarnd@arndb.de 
7990afacde3Sarnd@arndb.de 	spufs_init_isolated_loader();
800bf1ab978SDwayne Grant McConnell 
80167207b96SArnd Bergmann 	return 0;
802c99c1994SAkinobu Mita 
803640045a1SAl Viro out_syscalls:
804640045a1SAl Viro 	unregister_spu_syscalls(&spufs_calls);
805c99c1994SAkinobu Mita out_sched:
806c99c1994SAkinobu Mita 	spu_sched_exit();
80767207b96SArnd Bergmann out_cache:
80867207b96SArnd Bergmann 	kmem_cache_destroy(spufs_inode_cache);
80967207b96SArnd Bergmann out:
81067207b96SArnd Bergmann 	return ret;
81167207b96SArnd Bergmann }
81267207b96SArnd Bergmann module_init(spufs_init);
81367207b96SArnd Bergmann 
814e78b47a5SArnd Bergmann static void __exit spufs_exit(void)
81567207b96SArnd Bergmann {
8168b3d6663SArnd Bergmann 	spu_sched_exit();
817db1384b4SAkinobu Mita 	spufs_exit_isolated_loader();
81867207b96SArnd Bergmann 	unregister_spu_syscalls(&spufs_calls);
81967207b96SArnd Bergmann 	unregister_filesystem(&spufs_type);
82067207b96SArnd Bergmann 	kmem_cache_destroy(spufs_inode_cache);
82167207b96SArnd Bergmann }
82267207b96SArnd Bergmann module_exit(spufs_exit);
82367207b96SArnd Bergmann 
82467207b96SArnd Bergmann MODULE_LICENSE("GPL");
82567207b96SArnd Bergmann MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>");
82667207b96SArnd Bergmann 
827