xref: /linux/arch/powerpc/platforms/cell/spufs/inode.c (revision d7167b149943e38ad610191ecbb0800c78bbced9)
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>
2467207b96SArnd Bergmann #include <linux/slab.h>
2567207b96SArnd Bergmann 
260afacde3Sarnd@arndb.de #include <asm/prom.h>
2767207b96SArnd Bergmann #include <asm/spu.h>
28ccf17e9dSJeremy Kerr #include <asm/spu_priv1.h>
297c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
3067207b96SArnd Bergmann 
3167207b96SArnd Bergmann #include "spufs.h"
3267207b96SArnd Bergmann 
332c3e4787SJeremy Kerr struct spufs_sb_info {
34d2e0981cSDavid Howells 	bool debug;
352c3e4787SJeremy Kerr };
362c3e4787SJeremy Kerr 
37e18b890bSChristoph Lameter static struct kmem_cache *spufs_inode_cache;
38c6730ed4SJeremy Kerr char *isolated_loader;
398b0d3121SSebastian Siewior static int isolated_loader_size;
4067207b96SArnd Bergmann 
412c3e4787SJeremy Kerr static struct spufs_sb_info *spufs_get_sb_info(struct super_block *sb)
422c3e4787SJeremy Kerr {
432c3e4787SJeremy Kerr 	return sb->s_fs_info;
442c3e4787SJeremy Kerr }
452c3e4787SJeremy Kerr 
4667207b96SArnd Bergmann static struct inode *
4767207b96SArnd Bergmann spufs_alloc_inode(struct super_block *sb)
4867207b96SArnd Bergmann {
4967207b96SArnd Bergmann 	struct spufs_inode_info *ei;
5067207b96SArnd Bergmann 
51e94b1766SChristoph Lameter 	ei = kmem_cache_alloc(spufs_inode_cache, GFP_KERNEL);
5267207b96SArnd Bergmann 	if (!ei)
5367207b96SArnd Bergmann 		return NULL;
546263203eSArnd Bergmann 
556263203eSArnd Bergmann 	ei->i_gang = NULL;
566263203eSArnd Bergmann 	ei->i_ctx = NULL;
5743c2bbd9SChristoph Hellwig 	ei->i_openers = 0;
586263203eSArnd Bergmann 
5967207b96SArnd Bergmann 	return &ei->vfs_inode;
6067207b96SArnd Bergmann }
6167207b96SArnd Bergmann 
626d0e0d0bSAl Viro static void spufs_free_inode(struct inode *inode)
6367207b96SArnd Bergmann {
6467207b96SArnd Bergmann 	kmem_cache_free(spufs_inode_cache, SPUFS_I(inode));
6567207b96SArnd Bergmann }
6667207b96SArnd Bergmann 
6767207b96SArnd Bergmann static void
6851cc5068SAlexey Dobriyan spufs_init_once(void *p)
6967207b96SArnd Bergmann {
7067207b96SArnd Bergmann 	struct spufs_inode_info *ei = p;
7167207b96SArnd Bergmann 
7267207b96SArnd Bergmann 	inode_init_once(&ei->vfs_inode);
7367207b96SArnd Bergmann }
7467207b96SArnd Bergmann 
7567207b96SArnd Bergmann static struct inode *
76c6684b26SAl Viro spufs_new_inode(struct super_block *sb, umode_t mode)
7767207b96SArnd Bergmann {
7867207b96SArnd Bergmann 	struct inode *inode;
7967207b96SArnd Bergmann 
8067207b96SArnd Bergmann 	inode = new_inode(sb);
8167207b96SArnd Bergmann 	if (!inode)
8267207b96SArnd Bergmann 		goto out;
8367207b96SArnd Bergmann 
846747e832SMichael Ellerman 	inode->i_ino = get_next_ino();
8567207b96SArnd Bergmann 	inode->i_mode = mode;
861330deb0SDavid Howells 	inode->i_uid = current_fsuid();
871330deb0SDavid Howells 	inode->i_gid = current_fsgid();
88078cd827SDeepa Dinamani 	inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
8967207b96SArnd Bergmann out:
9067207b96SArnd Bergmann 	return inode;
9167207b96SArnd Bergmann }
9267207b96SArnd Bergmann 
9367207b96SArnd Bergmann static int
9467207b96SArnd Bergmann spufs_setattr(struct dentry *dentry, struct iattr *attr)
9567207b96SArnd Bergmann {
9675c3cfa8SDavid Howells 	struct inode *inode = d_inode(dentry);
9767207b96SArnd Bergmann 
9867207b96SArnd Bergmann 	if ((attr->ia_valid & ATTR_SIZE) &&
9967207b96SArnd Bergmann 	    (attr->ia_size != inode->i_size))
10067207b96SArnd Bergmann 		return -EINVAL;
1011025774cSChristoph Hellwig 	setattr_copy(inode, attr);
1021025774cSChristoph Hellwig 	mark_inode_dirty(inode);
1031025774cSChristoph Hellwig 	return 0;
10467207b96SArnd Bergmann }
10567207b96SArnd Bergmann 
10667207b96SArnd Bergmann 
10767207b96SArnd Bergmann static int
10867207b96SArnd Bergmann spufs_new_file(struct super_block *sb, struct dentry *dentry,
109c6684b26SAl Viro 		const struct file_operations *fops, umode_t mode,
11023d893f5SJeremy Kerr 		size_t size, struct spu_context *ctx)
11167207b96SArnd Bergmann {
1126e1d5dccSAlexey Dobriyan 	static const struct inode_operations spufs_file_iops = {
11367207b96SArnd Bergmann 		.setattr = spufs_setattr,
11467207b96SArnd Bergmann 	};
11567207b96SArnd Bergmann 	struct inode *inode;
11667207b96SArnd Bergmann 	int ret;
11767207b96SArnd Bergmann 
11867207b96SArnd Bergmann 	ret = -ENOSPC;
11967207b96SArnd Bergmann 	inode = spufs_new_inode(sb, S_IFREG | mode);
12067207b96SArnd Bergmann 	if (!inode)
12167207b96SArnd Bergmann 		goto out;
12267207b96SArnd Bergmann 
12367207b96SArnd Bergmann 	ret = 0;
12467207b96SArnd Bergmann 	inode->i_op = &spufs_file_iops;
12567207b96SArnd Bergmann 	inode->i_fop = fops;
12623d893f5SJeremy Kerr 	inode->i_size = size;
1278e18e294STheodore Ts'o 	inode->i_private = SPUFS_I(inode)->i_ctx = get_spu_context(ctx);
12867207b96SArnd Bergmann 	d_add(dentry, inode);
12967207b96SArnd Bergmann out:
13067207b96SArnd Bergmann 	return ret;
13167207b96SArnd Bergmann }
13267207b96SArnd Bergmann 
13367207b96SArnd Bergmann static void
1340f3f63a4SAl Viro spufs_evict_inode(struct inode *inode)
13567207b96SArnd Bergmann {
1366263203eSArnd Bergmann 	struct spufs_inode_info *ei = SPUFS_I(inode);
137dbd5768fSJan Kara 	clear_inode(inode);
1386263203eSArnd Bergmann 	if (ei->i_ctx)
1396263203eSArnd Bergmann 		put_spu_context(ei->i_ctx);
1406263203eSArnd Bergmann 	if (ei->i_gang)
1416263203eSArnd Bergmann 		put_spu_gang(ei->i_gang);
14267207b96SArnd Bergmann }
14367207b96SArnd Bergmann 
1443f51dd91SArnd Bergmann static void spufs_prune_dir(struct dentry *dir)
1453f51dd91SArnd Bergmann {
1463f51dd91SArnd Bergmann 	struct dentry *dentry, *tmp;
1476263203eSArnd Bergmann 
1485955102cSAl Viro 	inode_lock(d_inode(dir));
149946e51f2SAl Viro 	list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child) {
1503f51dd91SArnd Bergmann 		spin_lock(&dentry->d_lock);
151dc3f4198SAl Viro 		if (simple_positive(dentry)) {
152dc0474beSNick Piggin 			dget_dlock(dentry);
1533f51dd91SArnd Bergmann 			__d_drop(dentry);
1543f51dd91SArnd Bergmann 			spin_unlock(&dentry->d_lock);
15575c3cfa8SDavid Howells 			simple_unlink(d_inode(dir), dentry);
156b5c84bf6SNick Piggin 			/* XXX: what was dcache_lock protecting here? Other
157da502956SNick Piggin 			 * filesystems (IB, configfs) release dcache_lock
158da502956SNick Piggin 			 * before unlink */
1593f51dd91SArnd Bergmann 			dput(dentry);
1603f51dd91SArnd Bergmann 		} else {
1613f51dd91SArnd Bergmann 			spin_unlock(&dentry->d_lock);
1623f51dd91SArnd Bergmann 		}
1633f51dd91SArnd Bergmann 	}
1643f51dd91SArnd Bergmann 	shrink_dcache_parent(dir);
1655955102cSAl Viro 	inode_unlock(d_inode(dir));
1663f51dd91SArnd Bergmann }
1673f51dd91SArnd Bergmann 
1686263203eSArnd Bergmann /* Caller must hold parent->i_mutex */
1696263203eSArnd Bergmann static int spufs_rmdir(struct inode *parent, struct dentry *dir)
1703f51dd91SArnd Bergmann {
1713f51dd91SArnd Bergmann 	/* remove all entries */
17267cba9fdSAl Viro 	int res;
1736263203eSArnd Bergmann 	spufs_prune_dir(dir);
174c443acabSJeremy Kerr 	d_drop(dir);
17567cba9fdSAl Viro 	res = simple_rmdir(parent, dir);
17667cba9fdSAl Viro 	/* We have to give up the mm_struct */
17775c3cfa8SDavid Howells 	spu_forget(SPUFS_I(d_inode(dir))->i_ctx);
17867cba9fdSAl Viro 	return res;
1793f51dd91SArnd Bergmann }
1803f51dd91SArnd Bergmann 
18174254647SJeremy Kerr static int spufs_fill_dir(struct dentry *dir,
182c6684b26SAl Viro 		const struct spufs_tree_descr *files, umode_t mode,
18374254647SJeremy Kerr 		struct spu_context *ctx)
18467207b96SArnd Bergmann {
18567207b96SArnd Bergmann 	while (files->name && files->name[0]) {
1862248b87eSAl Viro 		int ret;
1872248b87eSAl Viro 		struct dentry *dentry = d_alloc_name(dir, files->name);
18867207b96SArnd Bergmann 		if (!dentry)
1892248b87eSAl Viro 			return -ENOMEM;
19067207b96SArnd Bergmann 		ret = spufs_new_file(dir->d_sb, dentry, files->ops,
19123d893f5SJeremy Kerr 					files->mode & mode, files->size, ctx);
19267207b96SArnd Bergmann 		if (ret)
1932248b87eSAl Viro 			return ret;
19467207b96SArnd Bergmann 		files++;
19567207b96SArnd Bergmann 	}
19667207b96SArnd Bergmann 	return 0;
19767207b96SArnd Bergmann }
19867207b96SArnd Bergmann 
19967207b96SArnd Bergmann static int spufs_dir_close(struct inode *inode, struct file *file)
20067207b96SArnd Bergmann {
2016263203eSArnd Bergmann 	struct inode *parent;
2026263203eSArnd Bergmann 	struct dentry *dir;
20367207b96SArnd Bergmann 	int ret;
20467207b96SArnd Bergmann 
205b4d1ab58SJosef Sipek 	dir = file->f_path.dentry;
20675c3cfa8SDavid Howells 	parent = d_inode(dir->d_parent);
207c8ca0633SArnd Bergmann 
2085955102cSAl Viro 	inode_lock_nested(parent, I_MUTEX_PARENT);
2096263203eSArnd Bergmann 	ret = spufs_rmdir(parent, dir);
2105955102cSAl Viro 	inode_unlock(parent);
21167207b96SArnd Bergmann 	WARN_ON(ret);
212c8ca0633SArnd Bergmann 
21367207b96SArnd Bergmann 	return dcache_dir_close(inode, file);
21467207b96SArnd Bergmann }
21567207b96SArnd Bergmann 
2165dfe4c96SArjan van de Ven const struct file_operations spufs_context_fops = {
21767207b96SArnd Bergmann 	.open		= dcache_dir_open,
21867207b96SArnd Bergmann 	.release	= spufs_dir_close,
21967207b96SArnd Bergmann 	.llseek		= dcache_dir_lseek,
22067207b96SArnd Bergmann 	.read		= generic_read_dir,
2214e82901cSAl Viro 	.iterate_shared	= dcache_readdir,
2221b061d92SChristoph Hellwig 	.fsync		= noop_fsync,
22367207b96SArnd Bergmann };
224bf1ab978SDwayne Grant McConnell EXPORT_SYMBOL_GPL(spufs_context_fops);
22567207b96SArnd Bergmann 
22667207b96SArnd Bergmann static int
2279add11daSArnd Bergmann spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
228c6684b26SAl Viro 		umode_t mode)
22967207b96SArnd Bergmann {
23067207b96SArnd Bergmann 	int ret;
23167207b96SArnd Bergmann 	struct inode *inode;
23267207b96SArnd Bergmann 	struct spu_context *ctx;
23367207b96SArnd Bergmann 
23467207b96SArnd Bergmann 	inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR);
23567207b96SArnd Bergmann 	if (!inode)
2362248b87eSAl Viro 		return -ENOSPC;
23767207b96SArnd Bergmann 
23867207b96SArnd Bergmann 	if (dir->i_mode & S_ISGID) {
23967207b96SArnd Bergmann 		inode->i_gid = dir->i_gid;
24067207b96SArnd Bergmann 		inode->i_mode &= S_ISGID;
24167207b96SArnd Bergmann 	}
2426263203eSArnd Bergmann 	ctx = alloc_spu_context(SPUFS_I(dir)->i_gang); /* XXX gang */
24367207b96SArnd Bergmann 	SPUFS_I(inode)->i_ctx = ctx;
2442248b87eSAl Viro 	if (!ctx) {
2452248b87eSAl Viro 		iput(inode);
2462248b87eSAl Viro 		return -ENOSPC;
2472248b87eSAl Viro 	}
24867207b96SArnd Bergmann 
2499add11daSArnd Bergmann 	ctx->flags = flags;
250b8c295f9SJeremy Kerr 	inode->i_op = &simple_dir_inode_operations;
25167207b96SArnd Bergmann 	inode->i_fop = &simple_dir_operations;
2522248b87eSAl Viro 
2535955102cSAl Viro 	inode_lock(inode);
2542248b87eSAl Viro 
2552248b87eSAl Viro 	dget(dentry);
2562248b87eSAl Viro 	inc_nlink(dir);
2572248b87eSAl Viro 	inc_nlink(inode);
2582248b87eSAl Viro 
2592248b87eSAl Viro 	d_instantiate(dentry, inode);
2602248b87eSAl Viro 
2615737edd1SMark Nutter 	if (flags & SPU_CREATE_NOSCHED)
2625737edd1SMark Nutter 		ret = spufs_fill_dir(dentry, spufs_dir_nosched_contents,
2635737edd1SMark Nutter 					 mode, ctx);
2645737edd1SMark Nutter 	else
26567207b96SArnd Bergmann 		ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx);
2665737edd1SMark Nutter 
2672248b87eSAl Viro 	if (!ret && spufs_get_sb_info(dir->i_sb)->debug)
2682c3e4787SJeremy Kerr 		ret = spufs_fill_dir(dentry, spufs_dir_debug_contents,
2692c3e4787SJeremy Kerr 				mode, ctx);
2702c3e4787SJeremy Kerr 
2712c3e4787SJeremy Kerr 	if (ret)
2722248b87eSAl Viro 		spufs_rmdir(dir, dentry);
2732c3e4787SJeremy Kerr 
2745955102cSAl Viro 	inode_unlock(inode);
27567207b96SArnd Bergmann 
27667207b96SArnd Bergmann 	return ret;
27767207b96SArnd Bergmann }
27867207b96SArnd Bergmann 
279765927b2SAl Viro static int spufs_context_open(struct path *path)
280346f4d3cSArnd Bergmann {
281346f4d3cSArnd Bergmann 	int ret;
282346f4d3cSArnd Bergmann 	struct file *filp;
283346f4d3cSArnd Bergmann 
2846b9cdf39SYann Droneaud 	ret = get_unused_fd_flags(0);
285bf349a44SAl Viro 	if (ret < 0)
286bf349a44SAl Viro 		return ret;
287346f4d3cSArnd Bergmann 
288765927b2SAl Viro 	filp = dentry_open(path, O_RDONLY, current_cred());
289346f4d3cSArnd Bergmann 	if (IS_ERR(filp)) {
290346f4d3cSArnd Bergmann 		put_unused_fd(ret);
291bf349a44SAl Viro 		return PTR_ERR(filp);
292346f4d3cSArnd Bergmann 	}
293346f4d3cSArnd Bergmann 
294346f4d3cSArnd Bergmann 	filp->f_op = &spufs_context_fops;
295346f4d3cSArnd Bergmann 	fd_install(ret, filp);
296346f4d3cSArnd Bergmann 	return ret;
297346f4d3cSArnd Bergmann }
298346f4d3cSArnd Bergmann 
2998e68e2f2SArnd Bergmann static struct spu_context *
3008e68e2f2SArnd Bergmann spufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
3018e68e2f2SArnd Bergmann 						struct file *filp)
3028e68e2f2SArnd Bergmann {
30358119068SAndre Detsch 	struct spu_context *tmp, *neighbor, *err;
3048e68e2f2SArnd Bergmann 	int count, node;
3058e68e2f2SArnd Bergmann 	int aff_supp;
3068e68e2f2SArnd Bergmann 
3078e68e2f2SArnd Bergmann 	aff_supp = !list_empty(&(list_entry(cbe_spu_info[0].spus.next,
3088e68e2f2SArnd Bergmann 					struct spu, cbe_list))->aff_list);
3098e68e2f2SArnd Bergmann 
3108e68e2f2SArnd Bergmann 	if (!aff_supp)
3118e68e2f2SArnd Bergmann 		return ERR_PTR(-EINVAL);
3128e68e2f2SArnd Bergmann 
3138e68e2f2SArnd Bergmann 	if (flags & SPU_CREATE_GANG)
3148e68e2f2SArnd Bergmann 		return ERR_PTR(-EINVAL);
3158e68e2f2SArnd Bergmann 
3168e68e2f2SArnd Bergmann 	if (flags & SPU_CREATE_AFFINITY_MEM &&
3178e68e2f2SArnd Bergmann 	    gang->aff_ref_ctx &&
3188e68e2f2SArnd Bergmann 	    gang->aff_ref_ctx->flags & SPU_CREATE_AFFINITY_MEM)
3198e68e2f2SArnd Bergmann 		return ERR_PTR(-EEXIST);
3208e68e2f2SArnd Bergmann 
3218e68e2f2SArnd Bergmann 	if (gang->aff_flags & AFF_MERGED)
3228e68e2f2SArnd Bergmann 		return ERR_PTR(-EBUSY);
3238e68e2f2SArnd Bergmann 
3248e68e2f2SArnd Bergmann 	neighbor = NULL;
3258e68e2f2SArnd Bergmann 	if (flags & SPU_CREATE_AFFINITY_SPU) {
3268e68e2f2SArnd Bergmann 		if (!filp || filp->f_op != &spufs_context_fops)
3278e68e2f2SArnd Bergmann 			return ERR_PTR(-EINVAL);
3288e68e2f2SArnd Bergmann 
3298e68e2f2SArnd Bergmann 		neighbor = get_spu_context(
330496ad9aaSAl Viro 				SPUFS_I(file_inode(filp))->i_ctx);
3318e68e2f2SArnd Bergmann 
3328e68e2f2SArnd Bergmann 		if (!list_empty(&neighbor->aff_list) && !(neighbor->aff_head) &&
3338e68e2f2SArnd Bergmann 		    !list_is_last(&neighbor->aff_list, &gang->aff_list_head) &&
3348e68e2f2SArnd Bergmann 		    !list_entry(neighbor->aff_list.next, struct spu_context,
33558119068SAndre Detsch 		    aff_list)->aff_head) {
33658119068SAndre Detsch 			err = ERR_PTR(-EEXIST);
33758119068SAndre Detsch 			goto out_put_neighbor;
33858119068SAndre Detsch 		}
3398e68e2f2SArnd Bergmann 
34058119068SAndre Detsch 		if (gang != neighbor->gang) {
34158119068SAndre Detsch 			err = ERR_PTR(-EINVAL);
34258119068SAndre Detsch 			goto out_put_neighbor;
34358119068SAndre Detsch 		}
3448e68e2f2SArnd Bergmann 
3458e68e2f2SArnd Bergmann 		count = 1;
3468e68e2f2SArnd Bergmann 		list_for_each_entry(tmp, &gang->aff_list_head, aff_list)
3478e68e2f2SArnd Bergmann 			count++;
3488e68e2f2SArnd Bergmann 		if (list_empty(&neighbor->aff_list))
3498e68e2f2SArnd Bergmann 			count++;
3508e68e2f2SArnd Bergmann 
3518e68e2f2SArnd Bergmann 		for (node = 0; node < MAX_NUMNODES; node++) {
3528e68e2f2SArnd Bergmann 			if ((cbe_spu_info[node].n_spus - atomic_read(
3538e68e2f2SArnd Bergmann 				&cbe_spu_info[node].reserved_spus)) >= count)
3548e68e2f2SArnd Bergmann 				break;
3558e68e2f2SArnd Bergmann 		}
3568e68e2f2SArnd Bergmann 
35758119068SAndre Detsch 		if (node == MAX_NUMNODES) {
35858119068SAndre Detsch 			err = ERR_PTR(-EEXIST);
35958119068SAndre Detsch 			goto out_put_neighbor;
36058119068SAndre Detsch 		}
3618e68e2f2SArnd Bergmann 	}
3628e68e2f2SArnd Bergmann 
3638e68e2f2SArnd Bergmann 	return neighbor;
36458119068SAndre Detsch 
36558119068SAndre Detsch out_put_neighbor:
36658119068SAndre Detsch 	put_spu_context(neighbor);
36758119068SAndre Detsch 	return err;
3688e68e2f2SArnd Bergmann }
3698e68e2f2SArnd Bergmann 
3708e68e2f2SArnd Bergmann static void
3718e68e2f2SArnd Bergmann spufs_set_affinity(unsigned int flags, struct spu_context *ctx,
3728e68e2f2SArnd Bergmann 					struct spu_context *neighbor)
3738e68e2f2SArnd Bergmann {
3748e68e2f2SArnd Bergmann 	if (flags & SPU_CREATE_AFFINITY_MEM)
3758e68e2f2SArnd Bergmann 		ctx->gang->aff_ref_ctx = ctx;
3768e68e2f2SArnd Bergmann 
3778e68e2f2SArnd Bergmann 	if (flags & SPU_CREATE_AFFINITY_SPU) {
3788e68e2f2SArnd Bergmann 		if (list_empty(&neighbor->aff_list)) {
3798e68e2f2SArnd Bergmann 			list_add_tail(&neighbor->aff_list,
3808e68e2f2SArnd Bergmann 				&ctx->gang->aff_list_head);
3818e68e2f2SArnd Bergmann 			neighbor->aff_head = 1;
3828e68e2f2SArnd Bergmann 		}
3838e68e2f2SArnd Bergmann 
3848e68e2f2SArnd Bergmann 		if (list_is_last(&neighbor->aff_list, &ctx->gang->aff_list_head)
3858e68e2f2SArnd Bergmann 		    || list_entry(neighbor->aff_list.next, struct spu_context,
3868e68e2f2SArnd Bergmann 							aff_list)->aff_head) {
3878e68e2f2SArnd Bergmann 			list_add(&ctx->aff_list, &neighbor->aff_list);
3888e68e2f2SArnd Bergmann 		} else  {
3898e68e2f2SArnd Bergmann 			list_add_tail(&ctx->aff_list, &neighbor->aff_list);
3908e68e2f2SArnd Bergmann 			if (neighbor->aff_head) {
3918e68e2f2SArnd Bergmann 				neighbor->aff_head = 0;
3928e68e2f2SArnd Bergmann 				ctx->aff_head = 1;
3938e68e2f2SArnd Bergmann 			}
3948e68e2f2SArnd Bergmann 		}
3958e68e2f2SArnd Bergmann 
3968e68e2f2SArnd Bergmann 		if (!ctx->gang->aff_ref_ctx)
3978e68e2f2SArnd Bergmann 			ctx->gang->aff_ref_ctx = ctx;
3988e68e2f2SArnd Bergmann 	}
3998e68e2f2SArnd Bergmann }
4008e68e2f2SArnd Bergmann 
4018e68e2f2SArnd Bergmann static int
4028e68e2f2SArnd Bergmann spufs_create_context(struct inode *inode, struct dentry *dentry,
403c6684b26SAl Viro 			struct vfsmount *mnt, int flags, umode_t mode,
4048e68e2f2SArnd Bergmann 			struct file *aff_filp)
4056263203eSArnd Bergmann {
4066263203eSArnd Bergmann 	int ret;
4078e68e2f2SArnd Bergmann 	int affinity;
4088e68e2f2SArnd Bergmann 	struct spu_gang *gang;
4098e68e2f2SArnd Bergmann 	struct spu_context *neighbor;
410765927b2SAl Viro 	struct path path = {.mnt = mnt, .dentry = dentry};
4116263203eSArnd Bergmann 
4125737edd1SMark Nutter 	if ((flags & SPU_CREATE_NOSCHED) &&
4135737edd1SMark Nutter 	    !capable(CAP_SYS_NICE))
4141ba44cc9SAl Viro 		return -EPERM;
4155737edd1SMark Nutter 
4165737edd1SMark Nutter 	if ((flags & (SPU_CREATE_NOSCHED | SPU_CREATE_ISOLATE))
4175737edd1SMark Nutter 	    == SPU_CREATE_ISOLATE)
4181ba44cc9SAl Viro 		return -EINVAL;
4195737edd1SMark Nutter 
420bd2e5f82SJeremy Kerr 	if ((flags & SPU_CREATE_ISOLATE) && !isolated_loader)
4211ba44cc9SAl Viro 		return -ENODEV;
422bd2e5f82SJeremy Kerr 
4238e68e2f2SArnd Bergmann 	gang = NULL;
4248e68e2f2SArnd Bergmann 	neighbor = NULL;
4258e68e2f2SArnd Bergmann 	affinity = flags & (SPU_CREATE_AFFINITY_MEM | SPU_CREATE_AFFINITY_SPU);
4268e68e2f2SArnd Bergmann 	if (affinity) {
4278e68e2f2SArnd Bergmann 		gang = SPUFS_I(inode)->i_gang;
4288e68e2f2SArnd Bergmann 		if (!gang)
4291ba44cc9SAl Viro 			return -EINVAL;
4308e68e2f2SArnd Bergmann 		mutex_lock(&gang->aff_mutex);
4318e68e2f2SArnd Bergmann 		neighbor = spufs_assert_affinity(flags, gang, aff_filp);
4328e68e2f2SArnd Bergmann 		if (IS_ERR(neighbor)) {
4338e68e2f2SArnd Bergmann 			ret = PTR_ERR(neighbor);
4348e68e2f2SArnd Bergmann 			goto out_aff_unlock;
4358e68e2f2SArnd Bergmann 		}
4368e68e2f2SArnd Bergmann 	}
4378e68e2f2SArnd Bergmann 
43857ad583fSRussell Currey 	ret = spufs_mkdir(inode, dentry, flags, mode & 0777);
4396263203eSArnd Bergmann 	if (ret)
4408e68e2f2SArnd Bergmann 		goto out_aff_unlock;
4418e68e2f2SArnd Bergmann 
44258119068SAndre Detsch 	if (affinity) {
44375c3cfa8SDavid Howells 		spufs_set_affinity(flags, SPUFS_I(d_inode(dentry))->i_ctx,
4448e68e2f2SArnd Bergmann 								neighbor);
44558119068SAndre Detsch 		if (neighbor)
44658119068SAndre Detsch 			put_spu_context(neighbor);
44758119068SAndre Detsch 	}
4486263203eSArnd Bergmann 
449765927b2SAl Viro 	ret = spufs_context_open(&path);
45066ec7b2cSAl Viro 	if (ret < 0)
4516263203eSArnd Bergmann 		WARN_ON(spufs_rmdir(inode, dentry));
4526263203eSArnd Bergmann 
4538e68e2f2SArnd Bergmann out_aff_unlock:
4548e68e2f2SArnd Bergmann 	if (affinity)
4558e68e2f2SArnd Bergmann 		mutex_unlock(&gang->aff_mutex);
4566263203eSArnd Bergmann 	return ret;
4576263203eSArnd Bergmann }
4586263203eSArnd Bergmann 
4596263203eSArnd Bergmann static int
460c6684b26SAl Viro spufs_mkgang(struct inode *dir, struct dentry *dentry, umode_t mode)
4616263203eSArnd Bergmann {
4626263203eSArnd Bergmann 	int ret;
4636263203eSArnd Bergmann 	struct inode *inode;
4646263203eSArnd Bergmann 	struct spu_gang *gang;
4656263203eSArnd Bergmann 
4666263203eSArnd Bergmann 	ret = -ENOSPC;
4676263203eSArnd Bergmann 	inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR);
4686263203eSArnd Bergmann 	if (!inode)
4696263203eSArnd Bergmann 		goto out;
4706263203eSArnd Bergmann 
4716263203eSArnd Bergmann 	ret = 0;
4726263203eSArnd Bergmann 	if (dir->i_mode & S_ISGID) {
4736263203eSArnd Bergmann 		inode->i_gid = dir->i_gid;
4746263203eSArnd Bergmann 		inode->i_mode &= S_ISGID;
4756263203eSArnd Bergmann 	}
4766263203eSArnd Bergmann 	gang = alloc_spu_gang();
4776263203eSArnd Bergmann 	SPUFS_I(inode)->i_ctx = NULL;
4786263203eSArnd Bergmann 	SPUFS_I(inode)->i_gang = gang;
47954a94fcfSDan Carpenter 	if (!gang) {
48054a94fcfSDan Carpenter 		ret = -ENOMEM;
4816263203eSArnd Bergmann 		goto out_iput;
48254a94fcfSDan Carpenter 	}
4836263203eSArnd Bergmann 
484b8c295f9SJeremy Kerr 	inode->i_op = &simple_dir_inode_operations;
4856263203eSArnd Bergmann 	inode->i_fop = &simple_dir_operations;
4866263203eSArnd Bergmann 
4876263203eSArnd Bergmann 	d_instantiate(dentry, inode);
488ba0b996dSJeremy Kerr 	inc_nlink(dir);
48975c3cfa8SDavid Howells 	inc_nlink(d_inode(dentry));
4906263203eSArnd Bergmann 	return ret;
4916263203eSArnd Bergmann 
4926263203eSArnd Bergmann out_iput:
4936263203eSArnd Bergmann 	iput(inode);
4946263203eSArnd Bergmann out:
4956263203eSArnd Bergmann 	return ret;
4966263203eSArnd Bergmann }
4976263203eSArnd Bergmann 
498765927b2SAl Viro static int spufs_gang_open(struct path *path)
4996263203eSArnd Bergmann {
5006263203eSArnd Bergmann 	int ret;
5016263203eSArnd Bergmann 	struct file *filp;
5026263203eSArnd Bergmann 
5036b9cdf39SYann Droneaud 	ret = get_unused_fd_flags(0);
504bf349a44SAl Viro 	if (ret < 0)
505bf349a44SAl Viro 		return ret;
5066263203eSArnd Bergmann 
507bf349a44SAl Viro 	/*
508bf349a44SAl Viro 	 * get references for dget and mntget, will be released
509bf349a44SAl Viro 	 * in error path of *_open().
510bf349a44SAl Viro 	 */
511765927b2SAl Viro 	filp = dentry_open(path, O_RDONLY, current_cred());
5126263203eSArnd Bergmann 	if (IS_ERR(filp)) {
5136263203eSArnd Bergmann 		put_unused_fd(ret);
514bf349a44SAl Viro 		return PTR_ERR(filp);
5156263203eSArnd Bergmann 	}
5166263203eSArnd Bergmann 
517877907d3SJeremy Kerr 	filp->f_op = &simple_dir_operations;
5186263203eSArnd Bergmann 	fd_install(ret, filp);
5196263203eSArnd Bergmann 	return ret;
5206263203eSArnd Bergmann }
5216263203eSArnd Bergmann 
5226263203eSArnd Bergmann static int spufs_create_gang(struct inode *inode,
5236263203eSArnd Bergmann 			struct dentry *dentry,
524c6684b26SAl Viro 			struct vfsmount *mnt, umode_t mode)
5256263203eSArnd Bergmann {
526765927b2SAl Viro 	struct path path = {.mnt = mnt, .dentry = dentry};
5276263203eSArnd Bergmann 	int ret;
5286263203eSArnd Bergmann 
52957ad583fSRussell Currey 	ret = spufs_mkgang(inode, dentry, mode & 0777);
5301ba44cc9SAl Viro 	if (!ret) {
531765927b2SAl Viro 		ret = spufs_gang_open(&path);
532877907d3SJeremy Kerr 		if (ret < 0) {
533877907d3SJeremy Kerr 			int err = simple_rmdir(inode, dentry);
534877907d3SJeremy Kerr 			WARN_ON(err);
535877907d3SJeremy Kerr 		}
5361ba44cc9SAl Viro 	}
5376263203eSArnd Bergmann 	return ret;
5386263203eSArnd Bergmann }
5396263203eSArnd Bergmann 
5406263203eSArnd Bergmann 
541346f4d3cSArnd Bergmann static struct file_system_type spufs_type;
542346f4d3cSArnd Bergmann 
5431ba10681SAl Viro long spufs_create(struct path *path, struct dentry *dentry,
544c6684b26SAl Viro 		unsigned int flags, umode_t mode, struct file *filp)
54567207b96SArnd Bergmann {
54675c3cfa8SDavid Howells 	struct inode *dir = d_inode(path->dentry);
54767207b96SArnd Bergmann 	int ret;
54867207b96SArnd Bergmann 
5496263203eSArnd Bergmann 	/* check if we are on spufs */
5501ba10681SAl Viro 	if (path->dentry->d_sb->s_type != &spufs_type)
55125b2692aSAl Viro 		return -EINVAL;
55267207b96SArnd Bergmann 
5536263203eSArnd Bergmann 	/* don't accept undefined flags */
5549add11daSArnd Bergmann 	if (flags & (~SPU_CREATE_FLAG_ALL))
55525b2692aSAl Viro 		return -EINVAL;
556c9832948Sarnd@arndb.de 
5576263203eSArnd Bergmann 	/* only threads can be underneath a gang */
55825b2692aSAl Viro 	if (path->dentry != path->dentry->d_sb->s_root)
55925b2692aSAl Viro 		if ((flags & SPU_CREATE_GANG) || !SPUFS_I(dir)->i_gang)
56025b2692aSAl Viro 			return -EINVAL;
5616263203eSArnd Bergmann 
562ce3b0f8dSAl Viro 	mode &= ~current_umask();
56367207b96SArnd Bergmann 
5646263203eSArnd Bergmann 	if (flags & SPU_CREATE_GANG)
56525b2692aSAl Viro 		ret = spufs_create_gang(dir, dentry, path->mnt, mode);
5666263203eSArnd Bergmann 	else
56725b2692aSAl Viro 		ret = spufs_create_context(dir, dentry, path->mnt, flags, mode,
5684ac91378SJan Blunck 					    filp);
569826be063SChristoph Hellwig 	if (ret >= 0)
57025b2692aSAl Viro 		fsnotify_mkdir(dir, dentry);
57167207b96SArnd Bergmann 
57267207b96SArnd Bergmann 	return ret;
57367207b96SArnd Bergmann }
57467207b96SArnd Bergmann 
57567207b96SArnd Bergmann /* File system initialization */
576d2e0981cSDavid Howells struct spufs_fs_context {
577d2e0981cSDavid Howells 	kuid_t	uid;
578d2e0981cSDavid Howells 	kgid_t	gid;
579d2e0981cSDavid Howells 	umode_t	mode;
58067207b96SArnd Bergmann };
58167207b96SArnd Bergmann 
582d2e0981cSDavid Howells enum {
583d2e0981cSDavid Howells 	Opt_uid, Opt_gid, Opt_mode, Opt_debug,
584d2e0981cSDavid Howells };
585d2e0981cSDavid Howells 
586*d7167b14SAl Viro static const struct fs_parameter_spec spufs_fs_parameters[] = {
587d2e0981cSDavid Howells 	fsparam_u32	("gid",				Opt_gid),
588d2e0981cSDavid Howells 	fsparam_u32oct	("mode",			Opt_mode),
589d2e0981cSDavid Howells 	fsparam_u32	("uid",				Opt_uid),
590d2e0981cSDavid Howells 	fsparam_flag	("debug",			Opt_debug),
591d2e0981cSDavid Howells 	{}
592d2e0981cSDavid Howells };
593d2e0981cSDavid Howells 
594a66ca414SDavid Howells static int spufs_show_options(struct seq_file *m, struct dentry *root)
595a66ca414SDavid Howells {
596a66ca414SDavid Howells 	struct spufs_sb_info *sbi = spufs_get_sb_info(root->d_sb);
597a66ca414SDavid Howells 	struct inode *inode = root->d_inode;
598a66ca414SDavid Howells 
599a66ca414SDavid Howells 	if (!uid_eq(inode->i_uid, GLOBAL_ROOT_UID))
600a66ca414SDavid Howells 		seq_printf(m, ",uid=%u",
601a66ca414SDavid Howells 			   from_kuid_munged(&init_user_ns, inode->i_uid));
602a66ca414SDavid Howells 	if (!gid_eq(inode->i_gid, GLOBAL_ROOT_GID))
603a66ca414SDavid Howells 		seq_printf(m, ",gid=%u",
604a66ca414SDavid Howells 			   from_kgid_munged(&init_user_ns, inode->i_gid));
605a66ca414SDavid Howells 	if ((inode->i_mode & S_IALLUGO) != 0775)
606a66ca414SDavid Howells 		seq_printf(m, ",mode=%o", inode->i_mode);
607a66ca414SDavid Howells 	if (sbi->debug)
608a66ca414SDavid Howells 		seq_puts(m, ",debug");
609a66ca414SDavid Howells 	return 0;
610a66ca414SDavid Howells }
611a66ca414SDavid Howells 
612d2e0981cSDavid Howells static int spufs_parse_param(struct fs_context *fc, struct fs_parameter *param)
61367207b96SArnd Bergmann {
614d2e0981cSDavid Howells 	struct spufs_fs_context *ctx = fc->fs_private;
615d2e0981cSDavid Howells 	struct spufs_sb_info *sbi = fc->s_fs_info;
616d2e0981cSDavid Howells 	struct fs_parse_result result;
617d2e0981cSDavid Howells 	kuid_t uid;
618d2e0981cSDavid Howells 	kgid_t gid;
619d2e0981cSDavid Howells 	int opt;
62067207b96SArnd Bergmann 
621*d7167b14SAl Viro 	opt = fs_parse(fc, spufs_fs_parameters, param, &result);
622d2e0981cSDavid Howells 	if (opt < 0)
623d2e0981cSDavid Howells 		return opt;
62467207b96SArnd Bergmann 
625d2e0981cSDavid Howells 	switch (opt) {
62667207b96SArnd Bergmann 	case Opt_uid:
627d2e0981cSDavid Howells 		uid = make_kuid(current_user_ns(), result.uint_32);
628d2e0981cSDavid Howells 		if (!uid_valid(uid))
629d2e0981cSDavid Howells 			return invalf(fc, "Unknown uid");
630d2e0981cSDavid Howells 		ctx->uid = uid;
63167207b96SArnd Bergmann 		break;
63267207b96SArnd Bergmann 	case Opt_gid:
633d2e0981cSDavid Howells 		gid = make_kgid(current_user_ns(), result.uint_32);
634d2e0981cSDavid Howells 		if (!gid_valid(gid))
635d2e0981cSDavid Howells 			return invalf(fc, "Unknown gid");
636d2e0981cSDavid Howells 		ctx->gid = gid;
63767207b96SArnd Bergmann 		break;
638f11f5ee7SJeremy Kerr 	case Opt_mode:
639d2e0981cSDavid Howells 		ctx->mode = result.uint_32 & S_IALLUGO;
640f11f5ee7SJeremy Kerr 		break;
6412c3e4787SJeremy Kerr 	case Opt_debug:
642d2e0981cSDavid Howells 		sbi->debug = true;
6432c3e4787SJeremy Kerr 		break;
644d2e0981cSDavid Howells 	}
645d2e0981cSDavid Howells 
64667207b96SArnd Bergmann 	return 0;
64767207b96SArnd Bergmann }
64867207b96SArnd Bergmann 
649db1384b4SAkinobu Mita static void spufs_exit_isolated_loader(void)
650db1384b4SAkinobu Mita {
6518b0d3121SSebastian Siewior 	free_pages((unsigned long) isolated_loader,
6528b0d3121SSebastian Siewior 			get_order(isolated_loader_size));
653db1384b4SAkinobu Mita }
654db1384b4SAkinobu Mita 
6550afacde3Sarnd@arndb.de static void
6560afacde3Sarnd@arndb.de spufs_init_isolated_loader(void)
6570afacde3Sarnd@arndb.de {
6580afacde3Sarnd@arndb.de 	struct device_node *dn;
6590afacde3Sarnd@arndb.de 	const char *loader;
6600afacde3Sarnd@arndb.de 	int size;
6610afacde3Sarnd@arndb.de 
6620afacde3Sarnd@arndb.de 	dn = of_find_node_by_path("/spu-isolation");
6630afacde3Sarnd@arndb.de 	if (!dn)
6640afacde3Sarnd@arndb.de 		return;
6650afacde3Sarnd@arndb.de 
666e2eb6392SStephen Rothwell 	loader = of_get_property(dn, "loader", &size);
6670afacde3Sarnd@arndb.de 	if (!loader)
6680afacde3Sarnd@arndb.de 		return;
6690afacde3Sarnd@arndb.de 
6708b0d3121SSebastian Siewior 	/* the loader must be align on a 16 byte boundary */
6718b0d3121SSebastian Siewior 	isolated_loader = (char *)__get_free_pages(GFP_KERNEL, get_order(size));
6720afacde3Sarnd@arndb.de 	if (!isolated_loader)
6730afacde3Sarnd@arndb.de 		return;
6740afacde3Sarnd@arndb.de 
6758b0d3121SSebastian Siewior 	isolated_loader_size = size;
6760afacde3Sarnd@arndb.de 	memcpy(isolated_loader, loader, size);
6770afacde3Sarnd@arndb.de 	printk(KERN_INFO "spufs: SPU isolation mode enabled\n");
6780afacde3Sarnd@arndb.de }
6790afacde3Sarnd@arndb.de 
680d2e0981cSDavid Howells static int spufs_create_root(struct super_block *sb, struct fs_context *fc)
6818b3d6663SArnd Bergmann {
682d2e0981cSDavid Howells 	struct spufs_fs_context *ctx = fc->fs_private;
68367207b96SArnd Bergmann 	struct inode *inode;
68467207b96SArnd Bergmann 
6858f18a158SArnd Bergmann 	if (!spu_management_ops)
686d2e0981cSDavid Howells 		return -ENODEV;
6878f18a158SArnd Bergmann 
688d2e0981cSDavid Howells 	inode = spufs_new_inode(sb, S_IFDIR | ctx->mode);
68967207b96SArnd Bergmann 	if (!inode)
690d2e0981cSDavid Howells 		return -ENOMEM;
69167207b96SArnd Bergmann 
692d2e0981cSDavid Howells 	inode->i_uid = ctx->uid;
693d2e0981cSDavid Howells 	inode->i_gid = ctx->gid;
694b8c295f9SJeremy Kerr 	inode->i_op = &simple_dir_inode_operations;
69567207b96SArnd Bergmann 	inode->i_fop = &simple_dir_operations;
69667207b96SArnd Bergmann 	SPUFS_I(inode)->i_ctx = NULL;
697e2ed6e4dSJeremy Kerr 	inc_nlink(inode);
69867207b96SArnd Bergmann 
69948fde701SAl Viro 	sb->s_root = d_make_root(inode);
70067207b96SArnd Bergmann 	if (!sb->s_root)
701d2e0981cSDavid Howells 		return -ENOMEM;
70267207b96SArnd Bergmann 	return 0;
70367207b96SArnd Bergmann }
70467207b96SArnd Bergmann 
705d2e0981cSDavid Howells static const struct super_operations spufs_ops = {
70667207b96SArnd Bergmann 	.alloc_inode	= spufs_alloc_inode,
7076d0e0d0bSAl Viro 	.free_inode	= spufs_free_inode,
70867207b96SArnd Bergmann 	.statfs		= simple_statfs,
7090f3f63a4SAl Viro 	.evict_inode	= spufs_evict_inode,
710a66ca414SDavid Howells 	.show_options	= spufs_show_options,
71167207b96SArnd Bergmann };
71267207b96SArnd Bergmann 
713d2e0981cSDavid Howells static int spufs_fill_super(struct super_block *sb, struct fs_context *fc)
714d2e0981cSDavid Howells {
71567207b96SArnd Bergmann 	sb->s_maxbytes = MAX_LFS_FILESIZE;
71609cbfeafSKirill A. Shutemov 	sb->s_blocksize = PAGE_SIZE;
71709cbfeafSKirill A. Shutemov 	sb->s_blocksize_bits = PAGE_SHIFT;
71867207b96SArnd Bergmann 	sb->s_magic = SPUFS_MAGIC;
719d2e0981cSDavid Howells 	sb->s_op = &spufs_ops;
72067207b96SArnd Bergmann 
721d2e0981cSDavid Howells 	return spufs_create_root(sb, fc);
72267207b96SArnd Bergmann }
72367207b96SArnd Bergmann 
724d2e0981cSDavid Howells static int spufs_get_tree(struct fs_context *fc)
72567207b96SArnd Bergmann {
726d2e0981cSDavid Howells 	return get_tree_single(fc, spufs_fill_super);
727d2e0981cSDavid Howells }
728d2e0981cSDavid Howells 
729d2e0981cSDavid Howells static void spufs_free_fc(struct fs_context *fc)
730d2e0981cSDavid Howells {
731d2e0981cSDavid Howells 	kfree(fc->s_fs_info);
732d2e0981cSDavid Howells }
733d2e0981cSDavid Howells 
734d2e0981cSDavid Howells static const struct fs_context_operations spufs_context_ops = {
735d2e0981cSDavid Howells 	.free		= spufs_free_fc,
736d2e0981cSDavid Howells 	.parse_param	= spufs_parse_param,
737d2e0981cSDavid Howells 	.get_tree	= spufs_get_tree,
738d2e0981cSDavid Howells };
739d2e0981cSDavid Howells 
740d2e0981cSDavid Howells static int spufs_init_fs_context(struct fs_context *fc)
741d2e0981cSDavid Howells {
742d2e0981cSDavid Howells 	struct spufs_fs_context *ctx;
743d2e0981cSDavid Howells 	struct spufs_sb_info *sbi;
744d2e0981cSDavid Howells 
745d2e0981cSDavid Howells 	ctx = kzalloc(sizeof(struct spufs_fs_context), GFP_KERNEL);
746d2e0981cSDavid Howells 	if (!ctx)
747d2e0981cSDavid Howells 		goto nomem;
748d2e0981cSDavid Howells 
749d2e0981cSDavid Howells 	sbi = kzalloc(sizeof(struct spufs_sb_info), GFP_KERNEL);
750d2e0981cSDavid Howells 	if (!sbi)
751d2e0981cSDavid Howells 		goto nomem_ctx;
752d2e0981cSDavid Howells 
753d2e0981cSDavid Howells 	ctx->uid = current_uid();
754d2e0981cSDavid Howells 	ctx->gid = current_gid();
755d2e0981cSDavid Howells 	ctx->mode = 0755;
756d2e0981cSDavid Howells 
7572272905aSEmmanuel Nicolet 	fc->fs_private = ctx;
758d2e0981cSDavid Howells 	fc->s_fs_info = sbi;
759d2e0981cSDavid Howells 	fc->ops = &spufs_context_ops;
760d2e0981cSDavid Howells 	return 0;
761d2e0981cSDavid Howells 
762d2e0981cSDavid Howells nomem_ctx:
763d2e0981cSDavid Howells 	kfree(ctx);
764d2e0981cSDavid Howells nomem:
765d2e0981cSDavid Howells 	return -ENOMEM;
76667207b96SArnd Bergmann }
76767207b96SArnd Bergmann 
76867207b96SArnd Bergmann static struct file_system_type spufs_type = {
76967207b96SArnd Bergmann 	.owner = THIS_MODULE,
77067207b96SArnd Bergmann 	.name = "spufs",
771d2e0981cSDavid Howells 	.init_fs_context = spufs_init_fs_context,
772*d7167b14SAl Viro 	.parameters	= spufs_fs_parameters,
77367207b96SArnd Bergmann 	.kill_sb = kill_litter_super,
77467207b96SArnd Bergmann };
7757f78e035SEric W. Biederman MODULE_ALIAS_FS("spufs");
77667207b96SArnd Bergmann 
777e78b47a5SArnd Bergmann static int __init spufs_init(void)
77867207b96SArnd Bergmann {
77967207b96SArnd Bergmann 	int ret;
780bf1ab978SDwayne Grant McConnell 
781ccf17e9dSJeremy Kerr 	ret = -ENODEV;
782ccf17e9dSJeremy Kerr 	if (!spu_management_ops)
783ccf17e9dSJeremy Kerr 		goto out;
784ccf17e9dSJeremy Kerr 
78567207b96SArnd Bergmann 	ret = -ENOMEM;
78667207b96SArnd Bergmann 	spufs_inode_cache = kmem_cache_create("spufs_inode_cache",
78767207b96SArnd Bergmann 			sizeof(struct spufs_inode_info), 0,
7885d097056SVladimir Davydov 			SLAB_HWCACHE_ALIGN|SLAB_ACCOUNT, spufs_init_once);
78967207b96SArnd Bergmann 
79067207b96SArnd Bergmann 	if (!spufs_inode_cache)
79167207b96SArnd Bergmann 		goto out;
792c99c1994SAkinobu Mita 	ret = spu_sched_init();
79367207b96SArnd Bergmann 	if (ret)
79467207b96SArnd Bergmann 		goto out_cache;
79567207b96SArnd Bergmann 	ret = register_spu_syscalls(&spufs_calls);
79667207b96SArnd Bergmann 	if (ret)
797640045a1SAl Viro 		goto out_sched;
798640045a1SAl Viro 	ret = register_filesystem(&spufs_type);
799640045a1SAl Viro 	if (ret)
800640045a1SAl Viro 		goto out_syscalls;
8010afacde3Sarnd@arndb.de 
8020afacde3Sarnd@arndb.de 	spufs_init_isolated_loader();
803bf1ab978SDwayne Grant McConnell 
80467207b96SArnd Bergmann 	return 0;
805c99c1994SAkinobu Mita 
806640045a1SAl Viro out_syscalls:
807640045a1SAl Viro 	unregister_spu_syscalls(&spufs_calls);
808c99c1994SAkinobu Mita out_sched:
809c99c1994SAkinobu Mita 	spu_sched_exit();
81067207b96SArnd Bergmann out_cache:
81167207b96SArnd Bergmann 	kmem_cache_destroy(spufs_inode_cache);
81267207b96SArnd Bergmann out:
81367207b96SArnd Bergmann 	return ret;
81467207b96SArnd Bergmann }
81567207b96SArnd Bergmann module_init(spufs_init);
81667207b96SArnd Bergmann 
817e78b47a5SArnd Bergmann static void __exit spufs_exit(void)
81867207b96SArnd Bergmann {
8198b3d6663SArnd Bergmann 	spu_sched_exit();
820db1384b4SAkinobu Mita 	spufs_exit_isolated_loader();
82167207b96SArnd Bergmann 	unregister_spu_syscalls(&spufs_calls);
82267207b96SArnd Bergmann 	unregister_filesystem(&spufs_type);
82367207b96SArnd Bergmann 	kmem_cache_destroy(spufs_inode_cache);
82467207b96SArnd Bergmann }
82567207b96SArnd Bergmann module_exit(spufs_exit);
82667207b96SArnd Bergmann 
82767207b96SArnd Bergmann MODULE_LICENSE("GPL");
82867207b96SArnd Bergmann MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>");
82967207b96SArnd Bergmann 
830