14074Swollman// SPDX-License-Identifier: GPL-2.0-or-later
26399Swollman
34074Swollman/*
46399Swollman * SPU file system
56399Swollman *
66399Swollman * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
76399Swollman *
86399Swollman * Author: Arnd Bergmann <arndb@de.ibm.com>
96399Swollman */
106399Swollman
116399Swollman#include <linux/file.h>
126399Swollman#include <linux/fs.h>
136399Swollman#include <linux/fs_context.h>
146399Swollman#include <linux/fs_parser.h>
158876Srgrimes#include <linux/fsnotify.h>
166399Swollman#include <linux/backing-dev.h>
176399Swollman#include <linux/init.h>
186399Swollman#include <linux/ioctl.h>
196399Swollman#include <linux/module.h>
206399Swollman#include <linux/mount.h>
216399Swollman#include <linux/namei.h>
226399Swollman#include <linux/pagemap.h>
236399Swollman#include <linux/poll.h>
246399Swollman#include <linux/of.h>
256399Swollman#include <linux/seq_file.h>
266399Swollman#include <linux/slab.h>
276399Swollman
284074Swollman#include <asm/spu.h>
2950477Speter#include <asm/spu_priv1.h>
304074Swollman#include <linux/uaccess.h>
314074Swollman
324074Swollman#include "spufs.h"
334074Swollman
344074Swollmanstruct spufs_sb_info {
354074Swollman	bool debug;
364074Swollman};
374074Swollman
384074Swollmanstatic struct kmem_cache *spufs_inode_cache;
394074Swollmanchar *isolated_loader;
404074Swollmanstatic int isolated_loader_size;
414074Swollman
424074Swollmanstatic struct spufs_sb_info *spufs_get_sb_info(struct super_block *sb)
434074Swollman{
444074Swollman	return sb->s_fs_info;
454074Swollman}
464074Swollman
474074Swollmanstatic struct inode *
4812172Sphkspufs_alloc_inode(struct super_block *sb)
494074Swollman{
504074Swollman	struct spufs_inode_info *ei;
514893Swollman
52120727Ssam	ei = kmem_cache_alloc(spufs_inode_cache, GFP_KERNEL);
534074Swollman	if (!ei)
544074Swollman		return NULL;
554074Swollman
564074Swollman	ei->i_gang = NULL;
574074Swollman	ei->i_ctx = NULL;
5874454Sru	ei->i_openers = 0;
594074Swollman
6092723Salfred	return &ei->vfs_inode;
6112579Sbde}
625101Swollman
634074Swollmanstatic void spufs_free_inode(struct inode *inode)
644074Swollman{
654074Swollman	kmem_cache_free(spufs_inode_cache, SPUFS_I(inode));
664074Swollman}
674074Swollman
684074Swollmanstatic void
694074Swollmanspufs_init_once(void *p)
704074Swollman{
714074Swollman	struct spufs_inode_info *ei = p;
729470Swollman
7313581Sfenner	inode_init_once(&ei->vfs_inode);
744074Swollman}
754074Swollman
7615652Swollmanstatic struct inode *
7715652Swollmanspufs_new_inode(struct super_block *sb, umode_t mode)
7815652Swollman{
7915652Swollman	struct inode *inode;
8015652Swollman
8115652Swollman	inode = new_inode(sb);
8215652Swollman	if (!inode)
8315652Swollman		goto out;
8415652Swollman
8515652Swollman	inode->i_ino = get_next_ino();
8615652Swollman	inode->i_mode = mode;
8715652Swollman	inode->i_uid = current_fsuid();
88122921Sandre	inode->i_gid = current_fsgid();
8915652Swollman	simple_inode_init_ts(inode);
9015652Swollmanout:
9115652Swollman	return inode;
9215652Swollman}
93110656Shsu
94110656Shsustatic int
95110656Shsuspufs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
965792Swollman	      struct iattr *attr)
975792Swollman{
98122921Sandre	struct inode *inode = d_inode(dentry);
99122921Sandre
1004074Swollman	if ((attr->ia_valid & ATTR_SIZE) &&
101122922Sandre	    (attr->ia_size != inode->i_size))
10210881Swollman		return -EINVAL;
1039470Swollman	setattr_copy(&nop_mnt_idmap, inode, attr);
10413581Sfenner	mark_inode_dirty(inode);
10513581Sfenner	return 0;
10613581Sfenner}
10713581Sfenner
10813581Sfenner
10913581Sfennerstatic int
11013581Sfennerspufs_new_file(struct super_block *sb, struct dentry *dentry,
11113581Sfenner		const struct file_operations *fops, umode_t mode,
112122921Sandre		size_t size, struct spu_context *ctx)
11313581Sfenner{
11413581Sfenner	static const struct inode_operations spufs_file_iops = {
115110656Shsu		.setattr = spufs_setattr,
116110656Shsu	};
117110656Shsu	struct inode *inode;
118121770Ssam	int ret;
119121770Ssam
12013581Sfenner	ret = -ENOSPC;
121110656Shsu	inode = spufs_new_inode(sb, S_IFREG | mode);
122121770Ssam	if (!inode)
123121770Ssam		goto out;
12413581Sfenner
12513581Sfenner	ret = 0;
12674454Sru	inode->i_op = &spufs_file_iops;
12713581Sfenner	inode->i_fop = fops;
1284074Swollman	inode->i_size = size;
1294074Swollman	inode->i_private = SPUFS_I(inode)->i_ctx = get_spu_context(ctx);
1304074Swollman	d_add(dentry, inode);
1314105Swollmanout:
1324105Swollman	return ret;
1334105Swollman}
1344074Swollman
1354074Swollmanstatic void
1364074Swollmanspufs_evict_inode(struct inode *inode)
1374074Swollman{
1384074Swollman	struct spufs_inode_info *ei = SPUFS_I(inode);
1394074Swollman	clear_inode(inode);
1404074Swollman	if (ei->i_ctx)
141120727Ssam		put_spu_context(ei->i_ctx);
142110656Shsu	if (ei->i_gang)
143110656Shsu		put_spu_gang(ei->i_gang);
1445101Swollman}
1454105Swollman
1464074Swollmanstatic void spufs_prune_dir(struct dentry *dir)
1474074Swollman{
1484074Swollman	struct dentry *dentry;
1494074Swollman	struct hlist_node *n;
1504074Swollman
151110656Shsu	inode_lock(d_inode(dir));
152110656Shsu	hlist_for_each_entry_safe(dentry, n, &dir->d_children, d_sib) {
153110656Shsu		spin_lock(&dentry->d_lock);
154110656Shsu		if (simple_positive(dentry)) {
155110656Shsu			dget_dlock(dentry);
156110656Shsu			__d_drop(dentry);
157110656Shsu			spin_unlock(&dentry->d_lock);
15846381Sbillf			simple_unlink(d_inode(dir), dentry);
1594105Swollman			/* XXX: what was dcache_lock protecting here? Other
160110656Shsu			 * filesystems (IB, configfs) release dcache_lock
161110656Shsu			 * before unlink */
162110656Shsu			dput(dentry);
163110656Shsu		} else {
1644074Swollman			spin_unlock(&dentry->d_lock);
1655792Swollman		}
1664074Swollman	}
1674074Swollman	shrink_dcache_parent(dir);
1684074Swollman	inode_unlock(d_inode(dir));
1694074Swollman}
1704074Swollman
1714074Swollman/* Caller must hold parent->i_mutex */
1728876Srgrimesstatic int spufs_rmdir(struct inode *parent, struct dentry *dir)
173120727Ssam{
174120727Ssam	/* remove all entries */
175110656Shsu	int res;
176110656Shsu	spufs_prune_dir(dir);
1775792Swollman	d_drop(dir);
178110656Shsu	res = simple_rmdir(parent, dir);
1794074Swollman	/* We have to give up the mm_struct */
1804074Swollman	spu_forget(SPUFS_I(d_inode(dir))->i_ctx);
181110656Shsu	return res;
1824105Swollman}
1834074Swollman
1846399Swollmanstatic int spufs_fill_dir(struct dentry *dir,
1856399Swollman		const struct spufs_tree_descr *files, umode_t mode,
1866399Swollman		struct spu_context *ctx)
1876399Swollman{
188110656Shsu	while (files->name && files->name[0]) {
1896399Swollman		int ret;
19034961Sphk		struct dentry *dentry = d_alloc_name(dir, files->name);
1916399Swollman		if (!dentry)
192121770Ssam			return -ENOMEM;
1936399Swollman		ret = spufs_new_file(dir->d_sb, dentry, files->ops,
1944074Swollman					files->mode & mode, files->size, ctx);
1954074Swollman		if (ret)
1964893Swollman			return ret;
1974893Swollman		files++;
1985101Swollman	}
1994893Swollman	return 0;
2004893Swollman}
2016400Swollman
2024893Swollmanstatic int spufs_dir_close(struct inode *inode, struct file *file)
2034893Swollman{
2044893Swollman	struct inode *parent;
2054074Swollman	struct dentry *dir;
2065101Swollman	int ret;
2076400Swollman
2086400Swollman	dir = file->f_path.dentry;
2094074Swollman	parent = d_inode(dir->d_parent);
2104893Swollman
2114893Swollman	inode_lock_nested(parent, I_MUTEX_PARENT);
2124074Swollman	ret = spufs_rmdir(parent, dir);
2134893Swollman	inode_unlock(parent);
2144893Swollman	WARN_ON(ret);
2154893Swollman
2164893Swollman	return dcache_dir_close(inode, file);
217110656Shsu}
2184893Swollman
2194893Swollmanconst struct file_operations spufs_context_fops = {
220110656Shsu	.open		= dcache_dir_open,
221110656Shsu	.release	= spufs_dir_close,
2227170Sdg	.llseek		= dcache_dir_lseek,
2234893Swollman	.read		= generic_read_dir,
2244893Swollman	.iterate_shared	= dcache_readdir,
2254893Swollman	.fsync		= noop_fsync,
2264893Swollman};
2274893SwollmanEXPORT_SYMBOL_GPL(spufs_context_fops);
228110656Shsu
2296568Sdgstatic int
2304893Swollmanspufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
2314893Swollman		umode_t mode)
2324893Swollman{
2334893Swollman	int ret;
234110656Shsu	struct inode *inode;
235110656Shsu	struct spu_context *ctx;
236110656Shsu
237110656Shsu	inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR);
238110656Shsu	if (!inode)
2396400Swollman		return -ENOSPC;
2404893Swollman
2414893Swollman	inode_init_owner(&nop_mnt_idmap, inode, dir, mode | S_IFDIR);
2424893Swollman	ctx = alloc_spu_context(SPUFS_I(dir)->i_gang); /* XXX gang */
2434893Swollman	SPUFS_I(inode)->i_ctx = ctx;
2444893Swollman	if (!ctx) {
2454893Swollman		iput(inode);
2464074Swollman		return -ENOSPC;
2474074Swollman	}
2486399Swollman
24912296Sphk	ctx->flags = flags;
250120727Ssam	inode->i_op = &simple_dir_inode_operations;
2515792Swollman	inode->i_fop = &simple_dir_operations;
2524074Swollman
2534074Swollman	inode_lock(inode);
2544074Swollman
2554893Swollman	dget(dentry);
2564893Swollman	inc_nlink(dir);
2574893Swollman	inc_nlink(inode);
2586399Swollman
2594074Swollman	d_instantiate(dentry, inode);
2604893Swollman
2614893Swollman	if (flags & SPU_CREATE_NOSCHED)
26234961Sphk		ret = spufs_fill_dir(dentry, spufs_dir_nosched_contents,
2636400Swollman					 mode, ctx);
264108250Shsu	else
2654893Swollman		ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx);
266108250Shsu
2676399Swollman	if (!ret && spufs_get_sb_info(dir->i_sb)->debug)
2686399Swollman		ret = spufs_fill_dir(dentry, spufs_dir_debug_contents,
2696399Swollman				mode, ctx);
2706399Swollman
2716399Swollman	if (ret)
2726399Swollman		spufs_rmdir(dir, dentry);
2736399Swollman
2746399Swollman	inode_unlock(inode);
2756399Swollman
276110656Shsu	return ret;
277110656Shsu}
278110656Shsu
279110656Shsustatic int spufs_context_open(const struct path *path)
280110656Shsu{
2816399Swollman	int ret;
2826399Swollman	struct file *filp;
2836399Swollman
28434961Sphk	ret = get_unused_fd_flags(0);
28516542Snate	if (ret < 0)
2866568Sdg		return ret;
2876399Swollman
28816542Snate	filp = dentry_open(path, O_RDONLY, current_cred());
2896399Swollman	if (IS_ERR(filp)) {
2906400Swollman		put_unused_fd(ret);
291108250Shsu		return PTR_ERR(filp);
2926399Swollman	}
293108250Shsu
2946399Swollman	filp->f_op = &spufs_context_fops;
2956399Swollman	fd_install(ret, filp);
2964893Swollman	return ret;
29738128Sbde}
298120727Ssam
2994074Swollmanstatic struct spu_context *
3004074Swollmanspufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
30112933Swollman						struct file *filp)
3024893Swollman{
3034893Swollman	struct spu_context *tmp, *neighbor, *err;
3045101Swollman	int count, node;
3055101Swollman	int aff_supp;
306120727Ssam
3075101Swollman	aff_supp = !list_empty(&(list_entry(cbe_spu_info[0].spus.next,
3085101Swollman					struct spu, cbe_list))->aff_list);
3095101Swollman
3105101Swollman	if (!aff_supp)
3116400Swollman		return ERR_PTR(-EINVAL);
312108250Shsu
3135101Swollman	if (flags & SPU_CREATE_GANG)
314108250Shsu		return ERR_PTR(-EINVAL);
3154893Swollman
3164893Swollman	if (flags & SPU_CREATE_AFFINITY_MEM &&
3174074Swollman	    gang->aff_ref_ctx &&
3184074Swollman	    gang->aff_ref_ctx->flags & SPU_CREATE_AFFINITY_MEM)
3194074Swollman		return ERR_PTR(-EEXIST);
3204074Swollman
3214074Swollman	if (gang->aff_flags & AFF_MERGED)
3224074Swollman		return ERR_PTR(-EBUSY);
3234074Swollman
3244074Swollman	neighbor = NULL;
325110656Shsu	if (flags & SPU_CREATE_AFFINITY_SPU) {
3264074Swollman		if (!filp || filp->f_op != &spufs_context_fops)
3274074Swollman			return ERR_PTR(-EINVAL);
328110656Shsu
3294896Swollman		neighbor = get_spu_context(
3304896Swollman				SPUFS_I(file_inode(filp))->i_ctx);
3314074Swollman
3324074Swollman		if (!list_empty(&neighbor->aff_list) && !(neighbor->aff_head) &&
3334074Swollman		    !list_is_last(&neighbor->aff_list, &gang->aff_list_head) &&
3344074Swollman		    !list_entry(neighbor->aff_list.next, struct spu_context,
335120727Ssam		    aff_list)->aff_head) {
3364105Swollman			err = ERR_PTR(-EEXIST);
3374074Swollman			goto out_put_neighbor;
3384074Swollman		}
3394074Swollman
34022672Swollman		if (gang != neighbor->gang) {
34176469Sru			err = ERR_PTR(-EINVAL);
34276469Sru			goto out_put_neighbor;
34376469Sru		}
34476469Sru
34576469Sru		count = 1;
34676469Sru		list_for_each_entry(tmp, &gang->aff_list_head, aff_list)
34776469Sru			count++;
34822672Swollman		if (list_empty(&neighbor->aff_list))
34922672Swollman			count++;
35022672Swollman
35122672Swollman		for (node = 0; node < MAX_NUMNODES; node++) {
35276469Sru			if ((cbe_spu_info[node].n_spus - atomic_read(
35322672Swollman				&cbe_spu_info[node].reserved_spus)) >= count)
35422672Swollman				break;
35522672Swollman		}
35622672Swollman
35722672Swollman		if (node == MAX_NUMNODES) {
35822672Swollman			err = ERR_PTR(-EEXIST);
35922672Swollman			goto out_put_neighbor;
36022672Swollman		}
361121770Ssam	}
36276469Sru
36376469Sru	return neighbor;
36434914Speter
36534914Speterout_put_neighbor:
36634914Speter	put_spu_context(neighbor);
36734914Speter	return err;
36834914Speter}
36934914Speter
37034914Speterstatic void
37134914Speterspufs_set_affinity(unsigned int flags, struct spu_context *ctx,
372122921Sandre					struct spu_context *neighbor)
373121770Ssam{
374121929Ssam	if (flags & SPU_CREATE_AFFINITY_MEM)
375121929Ssam		ctx->gang->aff_ref_ctx = ctx;
37622672Swollman
37722672Swollman	if (flags & SPU_CREATE_AFFINITY_SPU) {
37822672Swollman		if (list_empty(&neighbor->aff_list)) {
37922672Swollman			list_add_tail(&neighbor->aff_list,
38076469Sru				&ctx->gang->aff_list_head);
38122672Swollman			neighbor->aff_head = 1;
38222672Swollman		}
38322672Swollman
38422672Swollman		if (list_is_last(&neighbor->aff_list, &ctx->gang->aff_list_head)
38522672Swollman		    || list_entry(neighbor->aff_list.next, struct spu_context,
38622672Swollman							aff_list)->aff_head) {
38722672Swollman			list_add(&ctx->aff_list, &neighbor->aff_list);
38822672Swollman		} else  {
38922672Swollman			list_add_tail(&ctx->aff_list, &neighbor->aff_list);
39076469Sru			if (neighbor->aff_head) {
391108250Shsu				neighbor->aff_head = 0;
39222672Swollman				ctx->aff_head = 1;
393108250Shsu			}
394120727Ssam		}
39522672Swollman
39622672Swollman		if (!ctx->gang->aff_ref_ctx)
397			ctx->gang->aff_ref_ctx = ctx;
398	}
399}
400
401static int
402spufs_create_context(struct inode *inode, struct dentry *dentry,
403			struct vfsmount *mnt, int flags, umode_t mode,
404			struct file *aff_filp)
405{
406	int ret;
407	int affinity;
408	struct spu_gang *gang;
409	struct spu_context *neighbor;
410	struct path path = {.mnt = mnt, .dentry = dentry};
411
412	if ((flags & SPU_CREATE_NOSCHED) &&
413	    !capable(CAP_SYS_NICE))
414		return -EPERM;
415
416	if ((flags & (SPU_CREATE_NOSCHED | SPU_CREATE_ISOLATE))
417	    == SPU_CREATE_ISOLATE)
418		return -EINVAL;
419
420	if ((flags & SPU_CREATE_ISOLATE) && !isolated_loader)
421		return -ENODEV;
422
423	gang = NULL;
424	neighbor = NULL;
425	affinity = flags & (SPU_CREATE_AFFINITY_MEM | SPU_CREATE_AFFINITY_SPU);
426	if (affinity) {
427		gang = SPUFS_I(inode)->i_gang;
428		if (!gang)
429			return -EINVAL;
430		mutex_lock(&gang->aff_mutex);
431		neighbor = spufs_assert_affinity(flags, gang, aff_filp);
432		if (IS_ERR(neighbor)) {
433			ret = PTR_ERR(neighbor);
434			goto out_aff_unlock;
435		}
436	}
437
438	ret = spufs_mkdir(inode, dentry, flags, mode & 0777);
439	if (ret)
440		goto out_aff_unlock;
441
442	if (affinity) {
443		spufs_set_affinity(flags, SPUFS_I(d_inode(dentry))->i_ctx,
444								neighbor);
445		if (neighbor)
446			put_spu_context(neighbor);
447	}
448
449	ret = spufs_context_open(&path);
450	if (ret < 0)
451		WARN_ON(spufs_rmdir(inode, dentry));
452
453out_aff_unlock:
454	if (affinity)
455		mutex_unlock(&gang->aff_mutex);
456	return ret;
457}
458
459static int
460spufs_mkgang(struct inode *dir, struct dentry *dentry, umode_t mode)
461{
462	int ret;
463	struct inode *inode;
464	struct spu_gang *gang;
465
466	ret = -ENOSPC;
467	inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR);
468	if (!inode)
469		goto out;
470
471	ret = 0;
472	inode_init_owner(&nop_mnt_idmap, inode, dir, mode | S_IFDIR);
473	gang = alloc_spu_gang();
474	SPUFS_I(inode)->i_ctx = NULL;
475	SPUFS_I(inode)->i_gang = gang;
476	if (!gang) {
477		ret = -ENOMEM;
478		goto out_iput;
479	}
480
481	inode->i_op = &simple_dir_inode_operations;
482	inode->i_fop = &simple_dir_operations;
483
484	d_instantiate(dentry, inode);
485	inc_nlink(dir);
486	inc_nlink(d_inode(dentry));
487	return ret;
488
489out_iput:
490	iput(inode);
491out:
492	return ret;
493}
494
495static int spufs_gang_open(const struct path *path)
496{
497	int ret;
498	struct file *filp;
499
500	ret = get_unused_fd_flags(0);
501	if (ret < 0)
502		return ret;
503
504	/*
505	 * get references for dget and mntget, will be released
506	 * in error path of *_open().
507	 */
508	filp = dentry_open(path, O_RDONLY, current_cred());
509	if (IS_ERR(filp)) {
510		put_unused_fd(ret);
511		return PTR_ERR(filp);
512	}
513
514	filp->f_op = &simple_dir_operations;
515	fd_install(ret, filp);
516	return ret;
517}
518
519static int spufs_create_gang(struct inode *inode,
520			struct dentry *dentry,
521			struct vfsmount *mnt, umode_t mode)
522{
523	struct path path = {.mnt = mnt, .dentry = dentry};
524	int ret;
525
526	ret = spufs_mkgang(inode, dentry, mode & 0777);
527	if (!ret) {
528		ret = spufs_gang_open(&path);
529		if (ret < 0) {
530			int err = simple_rmdir(inode, dentry);
531			WARN_ON(err);
532		}
533	}
534	return ret;
535}
536
537
538static struct file_system_type spufs_type;
539
540long spufs_create(const struct path *path, struct dentry *dentry,
541		unsigned int flags, umode_t mode, struct file *filp)
542{
543	struct inode *dir = d_inode(path->dentry);
544	int ret;
545
546	/* check if we are on spufs */
547	if (path->dentry->d_sb->s_type != &spufs_type)
548		return -EINVAL;
549
550	/* don't accept undefined flags */
551	if (flags & (~SPU_CREATE_FLAG_ALL))
552		return -EINVAL;
553
554	/* only threads can be underneath a gang */
555	if (path->dentry != path->dentry->d_sb->s_root)
556		if ((flags & SPU_CREATE_GANG) || !SPUFS_I(dir)->i_gang)
557			return -EINVAL;
558
559	mode &= ~current_umask();
560
561	if (flags & SPU_CREATE_GANG)
562		ret = spufs_create_gang(dir, dentry, path->mnt, mode);
563	else
564		ret = spufs_create_context(dir, dentry, path->mnt, flags, mode,
565					    filp);
566	if (ret >= 0)
567		fsnotify_mkdir(dir, dentry);
568
569	return ret;
570}
571
572/* File system initialization */
573struct spufs_fs_context {
574	kuid_t	uid;
575	kgid_t	gid;
576	umode_t	mode;
577};
578
579enum {
580	Opt_uid, Opt_gid, Opt_mode, Opt_debug,
581};
582
583static const struct fs_parameter_spec spufs_fs_parameters[] = {
584	fsparam_u32	("gid",				Opt_gid),
585	fsparam_u32oct	("mode",			Opt_mode),
586	fsparam_u32	("uid",				Opt_uid),
587	fsparam_flag	("debug",			Opt_debug),
588	{}
589};
590
591static int spufs_show_options(struct seq_file *m, struct dentry *root)
592{
593	struct spufs_sb_info *sbi = spufs_get_sb_info(root->d_sb);
594	struct inode *inode = root->d_inode;
595
596	if (!uid_eq(inode->i_uid, GLOBAL_ROOT_UID))
597		seq_printf(m, ",uid=%u",
598			   from_kuid_munged(&init_user_ns, inode->i_uid));
599	if (!gid_eq(inode->i_gid, GLOBAL_ROOT_GID))
600		seq_printf(m, ",gid=%u",
601			   from_kgid_munged(&init_user_ns, inode->i_gid));
602	if ((inode->i_mode & S_IALLUGO) != 0775)
603		seq_printf(m, ",mode=%o", inode->i_mode);
604	if (sbi->debug)
605		seq_puts(m, ",debug");
606	return 0;
607}
608
609static int spufs_parse_param(struct fs_context *fc, struct fs_parameter *param)
610{
611	struct spufs_fs_context *ctx = fc->fs_private;
612	struct spufs_sb_info *sbi = fc->s_fs_info;
613	struct fs_parse_result result;
614	kuid_t uid;
615	kgid_t gid;
616	int opt;
617
618	opt = fs_parse(fc, spufs_fs_parameters, param, &result);
619	if (opt < 0)
620		return opt;
621
622	switch (opt) {
623	case Opt_uid:
624		uid = make_kuid(current_user_ns(), result.uint_32);
625		if (!uid_valid(uid))
626			return invalf(fc, "Unknown uid");
627		ctx->uid = uid;
628		break;
629	case Opt_gid:
630		gid = make_kgid(current_user_ns(), result.uint_32);
631		if (!gid_valid(gid))
632			return invalf(fc, "Unknown gid");
633		ctx->gid = gid;
634		break;
635	case Opt_mode:
636		ctx->mode = result.uint_32 & S_IALLUGO;
637		break;
638	case Opt_debug:
639		sbi->debug = true;
640		break;
641	}
642
643	return 0;
644}
645
646static void spufs_exit_isolated_loader(void)
647{
648	free_pages((unsigned long) isolated_loader,
649			get_order(isolated_loader_size));
650}
651
652static void __init
653spufs_init_isolated_loader(void)
654{
655	struct device_node *dn;
656	const char *loader;
657	int size;
658
659	dn = of_find_node_by_path("/spu-isolation");
660	if (!dn)
661		return;
662
663	loader = of_get_property(dn, "loader", &size);
664	of_node_put(dn);
665	if (!loader)
666		return;
667
668	/* the loader must be align on a 16 byte boundary */
669	isolated_loader = (char *)__get_free_pages(GFP_KERNEL, get_order(size));
670	if (!isolated_loader)
671		return;
672
673	isolated_loader_size = size;
674	memcpy(isolated_loader, loader, size);
675	printk(KERN_INFO "spufs: SPU isolation mode enabled\n");
676}
677
678static int spufs_create_root(struct super_block *sb, struct fs_context *fc)
679{
680	struct spufs_fs_context *ctx = fc->fs_private;
681	struct inode *inode;
682
683	if (!spu_management_ops)
684		return -ENODEV;
685
686	inode = spufs_new_inode(sb, S_IFDIR | ctx->mode);
687	if (!inode)
688		return -ENOMEM;
689
690	inode->i_uid = ctx->uid;
691	inode->i_gid = ctx->gid;
692	inode->i_op = &simple_dir_inode_operations;
693	inode->i_fop = &simple_dir_operations;
694	SPUFS_I(inode)->i_ctx = NULL;
695	inc_nlink(inode);
696
697	sb->s_root = d_make_root(inode);
698	if (!sb->s_root)
699		return -ENOMEM;
700	return 0;
701}
702
703static const struct super_operations spufs_ops = {
704	.alloc_inode	= spufs_alloc_inode,
705	.free_inode	= spufs_free_inode,
706	.statfs		= simple_statfs,
707	.evict_inode	= spufs_evict_inode,
708	.show_options	= spufs_show_options,
709};
710
711static int spufs_fill_super(struct super_block *sb, struct fs_context *fc)
712{
713	sb->s_maxbytes = MAX_LFS_FILESIZE;
714	sb->s_blocksize = PAGE_SIZE;
715	sb->s_blocksize_bits = PAGE_SHIFT;
716	sb->s_magic = SPUFS_MAGIC;
717	sb->s_op = &spufs_ops;
718
719	return spufs_create_root(sb, fc);
720}
721
722static int spufs_get_tree(struct fs_context *fc)
723{
724	return get_tree_single(fc, spufs_fill_super);
725}
726
727static void spufs_free_fc(struct fs_context *fc)
728{
729	kfree(fc->s_fs_info);
730}
731
732static const struct fs_context_operations spufs_context_ops = {
733	.free		= spufs_free_fc,
734	.parse_param	= spufs_parse_param,
735	.get_tree	= spufs_get_tree,
736};
737
738static int spufs_init_fs_context(struct fs_context *fc)
739{
740	struct spufs_fs_context *ctx;
741	struct spufs_sb_info *sbi;
742
743	ctx = kzalloc(sizeof(struct spufs_fs_context), GFP_KERNEL);
744	if (!ctx)
745		goto nomem;
746
747	sbi = kzalloc(sizeof(struct spufs_sb_info), GFP_KERNEL);
748	if (!sbi)
749		goto nomem_ctx;
750
751	ctx->uid = current_uid();
752	ctx->gid = current_gid();
753	ctx->mode = 0755;
754
755	fc->fs_private = ctx;
756	fc->s_fs_info = sbi;
757	fc->ops = &spufs_context_ops;
758	return 0;
759
760nomem_ctx:
761	kfree(ctx);
762nomem:
763	return -ENOMEM;
764}
765
766static struct file_system_type spufs_type = {
767	.owner = THIS_MODULE,
768	.name = "spufs",
769	.init_fs_context = spufs_init_fs_context,
770	.parameters	= spufs_fs_parameters,
771	.kill_sb = kill_litter_super,
772};
773MODULE_ALIAS_FS("spufs");
774
775static int __init spufs_init(void)
776{
777	int ret;
778
779	ret = -ENODEV;
780	if (!spu_management_ops)
781		goto out;
782
783	ret = -ENOMEM;
784	spufs_inode_cache = kmem_cache_create("spufs_inode_cache",
785			sizeof(struct spufs_inode_info), 0,
786			SLAB_HWCACHE_ALIGN|SLAB_ACCOUNT, spufs_init_once);
787
788	if (!spufs_inode_cache)
789		goto out;
790	ret = spu_sched_init();
791	if (ret)
792		goto out_cache;
793	ret = register_spu_syscalls(&spufs_calls);
794	if (ret)
795		goto out_sched;
796	ret = register_filesystem(&spufs_type);
797	if (ret)
798		goto out_syscalls;
799
800	spufs_init_isolated_loader();
801
802	return 0;
803
804out_syscalls:
805	unregister_spu_syscalls(&spufs_calls);
806out_sched:
807	spu_sched_exit();
808out_cache:
809	kmem_cache_destroy(spufs_inode_cache);
810out:
811	return ret;
812}
813module_init(spufs_init);
814
815static void __exit spufs_exit(void)
816{
817	spu_sched_exit();
818	spufs_exit_isolated_loader();
819	unregister_spu_syscalls(&spufs_calls);
820	unregister_filesystem(&spufs_type);
821	kmem_cache_destroy(spufs_inode_cache);
822}
823module_exit(spufs_exit);
824
825MODULE_LICENSE("GPL");
826MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>");
827
828