162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci/* 462306a36Sopenharmony_ci * SPU file system 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Author: Arnd Bergmann <arndb@de.ibm.com> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/file.h> 1262306a36Sopenharmony_ci#include <linux/fs.h> 1362306a36Sopenharmony_ci#include <linux/fs_context.h> 1462306a36Sopenharmony_ci#include <linux/fs_parser.h> 1562306a36Sopenharmony_ci#include <linux/fsnotify.h> 1662306a36Sopenharmony_ci#include <linux/backing-dev.h> 1762306a36Sopenharmony_ci#include <linux/init.h> 1862306a36Sopenharmony_ci#include <linux/ioctl.h> 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include <linux/mount.h> 2162306a36Sopenharmony_ci#include <linux/namei.h> 2262306a36Sopenharmony_ci#include <linux/pagemap.h> 2362306a36Sopenharmony_ci#include <linux/poll.h> 2462306a36Sopenharmony_ci#include <linux/of.h> 2562306a36Sopenharmony_ci#include <linux/seq_file.h> 2662306a36Sopenharmony_ci#include <linux/slab.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include <asm/spu.h> 2962306a36Sopenharmony_ci#include <asm/spu_priv1.h> 3062306a36Sopenharmony_ci#include <linux/uaccess.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include "spufs.h" 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistruct spufs_sb_info { 3562306a36Sopenharmony_ci bool debug; 3662306a36Sopenharmony_ci}; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic struct kmem_cache *spufs_inode_cache; 3962306a36Sopenharmony_cichar *isolated_loader; 4062306a36Sopenharmony_cistatic int isolated_loader_size; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic struct spufs_sb_info *spufs_get_sb_info(struct super_block *sb) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci return sb->s_fs_info; 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic struct inode * 4862306a36Sopenharmony_cispufs_alloc_inode(struct super_block *sb) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci struct spufs_inode_info *ei; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci ei = kmem_cache_alloc(spufs_inode_cache, GFP_KERNEL); 5362306a36Sopenharmony_ci if (!ei) 5462306a36Sopenharmony_ci return NULL; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci ei->i_gang = NULL; 5762306a36Sopenharmony_ci ei->i_ctx = NULL; 5862306a36Sopenharmony_ci ei->i_openers = 0; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci return &ei->vfs_inode; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic void spufs_free_inode(struct inode *inode) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci kmem_cache_free(spufs_inode_cache, SPUFS_I(inode)); 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic void 6962306a36Sopenharmony_cispufs_init_once(void *p) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci struct spufs_inode_info *ei = p; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci inode_init_once(&ei->vfs_inode); 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic struct inode * 7762306a36Sopenharmony_cispufs_new_inode(struct super_block *sb, umode_t mode) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct inode *inode; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci inode = new_inode(sb); 8262306a36Sopenharmony_ci if (!inode) 8362306a36Sopenharmony_ci goto out; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci inode->i_ino = get_next_ino(); 8662306a36Sopenharmony_ci inode->i_mode = mode; 8762306a36Sopenharmony_ci inode->i_uid = current_fsuid(); 8862306a36Sopenharmony_ci inode->i_gid = current_fsgid(); 8962306a36Sopenharmony_ci inode->i_atime = inode->i_mtime = inode_set_ctime_current(inode); 9062306a36Sopenharmony_ciout: 9162306a36Sopenharmony_ci return inode; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic int 9562306a36Sopenharmony_cispufs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, 9662306a36Sopenharmony_ci struct iattr *attr) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci if ((attr->ia_valid & ATTR_SIZE) && 10162306a36Sopenharmony_ci (attr->ia_size != inode->i_size)) 10262306a36Sopenharmony_ci return -EINVAL; 10362306a36Sopenharmony_ci setattr_copy(&nop_mnt_idmap, inode, attr); 10462306a36Sopenharmony_ci mark_inode_dirty(inode); 10562306a36Sopenharmony_ci return 0; 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic int 11062306a36Sopenharmony_cispufs_new_file(struct super_block *sb, struct dentry *dentry, 11162306a36Sopenharmony_ci const struct file_operations *fops, umode_t mode, 11262306a36Sopenharmony_ci size_t size, struct spu_context *ctx) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci static const struct inode_operations spufs_file_iops = { 11562306a36Sopenharmony_ci .setattr = spufs_setattr, 11662306a36Sopenharmony_ci }; 11762306a36Sopenharmony_ci struct inode *inode; 11862306a36Sopenharmony_ci int ret; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci ret = -ENOSPC; 12162306a36Sopenharmony_ci inode = spufs_new_inode(sb, S_IFREG | mode); 12262306a36Sopenharmony_ci if (!inode) 12362306a36Sopenharmony_ci goto out; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci ret = 0; 12662306a36Sopenharmony_ci inode->i_op = &spufs_file_iops; 12762306a36Sopenharmony_ci inode->i_fop = fops; 12862306a36Sopenharmony_ci inode->i_size = size; 12962306a36Sopenharmony_ci inode->i_private = SPUFS_I(inode)->i_ctx = get_spu_context(ctx); 13062306a36Sopenharmony_ci d_add(dentry, inode); 13162306a36Sopenharmony_ciout: 13262306a36Sopenharmony_ci return ret; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic void 13662306a36Sopenharmony_cispufs_evict_inode(struct inode *inode) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci struct spufs_inode_info *ei = SPUFS_I(inode); 13962306a36Sopenharmony_ci clear_inode(inode); 14062306a36Sopenharmony_ci if (ei->i_ctx) 14162306a36Sopenharmony_ci put_spu_context(ei->i_ctx); 14262306a36Sopenharmony_ci if (ei->i_gang) 14362306a36Sopenharmony_ci put_spu_gang(ei->i_gang); 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic void spufs_prune_dir(struct dentry *dir) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci struct dentry *dentry, *tmp; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci inode_lock(d_inode(dir)); 15162306a36Sopenharmony_ci list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child) { 15262306a36Sopenharmony_ci spin_lock(&dentry->d_lock); 15362306a36Sopenharmony_ci if (simple_positive(dentry)) { 15462306a36Sopenharmony_ci dget_dlock(dentry); 15562306a36Sopenharmony_ci __d_drop(dentry); 15662306a36Sopenharmony_ci spin_unlock(&dentry->d_lock); 15762306a36Sopenharmony_ci simple_unlink(d_inode(dir), dentry); 15862306a36Sopenharmony_ci /* XXX: what was dcache_lock protecting here? Other 15962306a36Sopenharmony_ci * filesystems (IB, configfs) release dcache_lock 16062306a36Sopenharmony_ci * before unlink */ 16162306a36Sopenharmony_ci dput(dentry); 16262306a36Sopenharmony_ci } else { 16362306a36Sopenharmony_ci spin_unlock(&dentry->d_lock); 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci shrink_dcache_parent(dir); 16762306a36Sopenharmony_ci inode_unlock(d_inode(dir)); 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci/* Caller must hold parent->i_mutex */ 17162306a36Sopenharmony_cistatic int spufs_rmdir(struct inode *parent, struct dentry *dir) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci /* remove all entries */ 17462306a36Sopenharmony_ci int res; 17562306a36Sopenharmony_ci spufs_prune_dir(dir); 17662306a36Sopenharmony_ci d_drop(dir); 17762306a36Sopenharmony_ci res = simple_rmdir(parent, dir); 17862306a36Sopenharmony_ci /* We have to give up the mm_struct */ 17962306a36Sopenharmony_ci spu_forget(SPUFS_I(d_inode(dir))->i_ctx); 18062306a36Sopenharmony_ci return res; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic int spufs_fill_dir(struct dentry *dir, 18462306a36Sopenharmony_ci const struct spufs_tree_descr *files, umode_t mode, 18562306a36Sopenharmony_ci struct spu_context *ctx) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci while (files->name && files->name[0]) { 18862306a36Sopenharmony_ci int ret; 18962306a36Sopenharmony_ci struct dentry *dentry = d_alloc_name(dir, files->name); 19062306a36Sopenharmony_ci if (!dentry) 19162306a36Sopenharmony_ci return -ENOMEM; 19262306a36Sopenharmony_ci ret = spufs_new_file(dir->d_sb, dentry, files->ops, 19362306a36Sopenharmony_ci files->mode & mode, files->size, ctx); 19462306a36Sopenharmony_ci if (ret) 19562306a36Sopenharmony_ci return ret; 19662306a36Sopenharmony_ci files++; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci return 0; 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic int spufs_dir_close(struct inode *inode, struct file *file) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci struct inode *parent; 20462306a36Sopenharmony_ci struct dentry *dir; 20562306a36Sopenharmony_ci int ret; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci dir = file->f_path.dentry; 20862306a36Sopenharmony_ci parent = d_inode(dir->d_parent); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci inode_lock_nested(parent, I_MUTEX_PARENT); 21162306a36Sopenharmony_ci ret = spufs_rmdir(parent, dir); 21262306a36Sopenharmony_ci inode_unlock(parent); 21362306a36Sopenharmony_ci WARN_ON(ret); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci return dcache_dir_close(inode, file); 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ciconst struct file_operations spufs_context_fops = { 21962306a36Sopenharmony_ci .open = dcache_dir_open, 22062306a36Sopenharmony_ci .release = spufs_dir_close, 22162306a36Sopenharmony_ci .llseek = dcache_dir_lseek, 22262306a36Sopenharmony_ci .read = generic_read_dir, 22362306a36Sopenharmony_ci .iterate_shared = dcache_readdir, 22462306a36Sopenharmony_ci .fsync = noop_fsync, 22562306a36Sopenharmony_ci}; 22662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(spufs_context_fops); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic int 22962306a36Sopenharmony_cispufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags, 23062306a36Sopenharmony_ci umode_t mode) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci int ret; 23362306a36Sopenharmony_ci struct inode *inode; 23462306a36Sopenharmony_ci struct spu_context *ctx; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR); 23762306a36Sopenharmony_ci if (!inode) 23862306a36Sopenharmony_ci return -ENOSPC; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci inode_init_owner(&nop_mnt_idmap, inode, dir, mode | S_IFDIR); 24162306a36Sopenharmony_ci ctx = alloc_spu_context(SPUFS_I(dir)->i_gang); /* XXX gang */ 24262306a36Sopenharmony_ci SPUFS_I(inode)->i_ctx = ctx; 24362306a36Sopenharmony_ci if (!ctx) { 24462306a36Sopenharmony_ci iput(inode); 24562306a36Sopenharmony_ci return -ENOSPC; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci ctx->flags = flags; 24962306a36Sopenharmony_ci inode->i_op = &simple_dir_inode_operations; 25062306a36Sopenharmony_ci inode->i_fop = &simple_dir_operations; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci inode_lock(inode); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci dget(dentry); 25562306a36Sopenharmony_ci inc_nlink(dir); 25662306a36Sopenharmony_ci inc_nlink(inode); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci d_instantiate(dentry, inode); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (flags & SPU_CREATE_NOSCHED) 26162306a36Sopenharmony_ci ret = spufs_fill_dir(dentry, spufs_dir_nosched_contents, 26262306a36Sopenharmony_ci mode, ctx); 26362306a36Sopenharmony_ci else 26462306a36Sopenharmony_ci ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (!ret && spufs_get_sb_info(dir->i_sb)->debug) 26762306a36Sopenharmony_ci ret = spufs_fill_dir(dentry, spufs_dir_debug_contents, 26862306a36Sopenharmony_ci mode, ctx); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (ret) 27162306a36Sopenharmony_ci spufs_rmdir(dir, dentry); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci inode_unlock(inode); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci return ret; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic int spufs_context_open(const struct path *path) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci int ret; 28162306a36Sopenharmony_ci struct file *filp; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci ret = get_unused_fd_flags(0); 28462306a36Sopenharmony_ci if (ret < 0) 28562306a36Sopenharmony_ci return ret; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci filp = dentry_open(path, O_RDONLY, current_cred()); 28862306a36Sopenharmony_ci if (IS_ERR(filp)) { 28962306a36Sopenharmony_ci put_unused_fd(ret); 29062306a36Sopenharmony_ci return PTR_ERR(filp); 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci filp->f_op = &spufs_context_fops; 29462306a36Sopenharmony_ci fd_install(ret, filp); 29562306a36Sopenharmony_ci return ret; 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic struct spu_context * 29962306a36Sopenharmony_cispufs_assert_affinity(unsigned int flags, struct spu_gang *gang, 30062306a36Sopenharmony_ci struct file *filp) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci struct spu_context *tmp, *neighbor, *err; 30362306a36Sopenharmony_ci int count, node; 30462306a36Sopenharmony_ci int aff_supp; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci aff_supp = !list_empty(&(list_entry(cbe_spu_info[0].spus.next, 30762306a36Sopenharmony_ci struct spu, cbe_list))->aff_list); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (!aff_supp) 31062306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (flags & SPU_CREATE_GANG) 31362306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (flags & SPU_CREATE_AFFINITY_MEM && 31662306a36Sopenharmony_ci gang->aff_ref_ctx && 31762306a36Sopenharmony_ci gang->aff_ref_ctx->flags & SPU_CREATE_AFFINITY_MEM) 31862306a36Sopenharmony_ci return ERR_PTR(-EEXIST); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci if (gang->aff_flags & AFF_MERGED) 32162306a36Sopenharmony_ci return ERR_PTR(-EBUSY); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci neighbor = NULL; 32462306a36Sopenharmony_ci if (flags & SPU_CREATE_AFFINITY_SPU) { 32562306a36Sopenharmony_ci if (!filp || filp->f_op != &spufs_context_fops) 32662306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci neighbor = get_spu_context( 32962306a36Sopenharmony_ci SPUFS_I(file_inode(filp))->i_ctx); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (!list_empty(&neighbor->aff_list) && !(neighbor->aff_head) && 33262306a36Sopenharmony_ci !list_is_last(&neighbor->aff_list, &gang->aff_list_head) && 33362306a36Sopenharmony_ci !list_entry(neighbor->aff_list.next, struct spu_context, 33462306a36Sopenharmony_ci aff_list)->aff_head) { 33562306a36Sopenharmony_ci err = ERR_PTR(-EEXIST); 33662306a36Sopenharmony_ci goto out_put_neighbor; 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (gang != neighbor->gang) { 34062306a36Sopenharmony_ci err = ERR_PTR(-EINVAL); 34162306a36Sopenharmony_ci goto out_put_neighbor; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci count = 1; 34562306a36Sopenharmony_ci list_for_each_entry(tmp, &gang->aff_list_head, aff_list) 34662306a36Sopenharmony_ci count++; 34762306a36Sopenharmony_ci if (list_empty(&neighbor->aff_list)) 34862306a36Sopenharmony_ci count++; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci for (node = 0; node < MAX_NUMNODES; node++) { 35162306a36Sopenharmony_ci if ((cbe_spu_info[node].n_spus - atomic_read( 35262306a36Sopenharmony_ci &cbe_spu_info[node].reserved_spus)) >= count) 35362306a36Sopenharmony_ci break; 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (node == MAX_NUMNODES) { 35762306a36Sopenharmony_ci err = ERR_PTR(-EEXIST); 35862306a36Sopenharmony_ci goto out_put_neighbor; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci return neighbor; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ciout_put_neighbor: 36562306a36Sopenharmony_ci put_spu_context(neighbor); 36662306a36Sopenharmony_ci return err; 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic void 37062306a36Sopenharmony_cispufs_set_affinity(unsigned int flags, struct spu_context *ctx, 37162306a36Sopenharmony_ci struct spu_context *neighbor) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci if (flags & SPU_CREATE_AFFINITY_MEM) 37462306a36Sopenharmony_ci ctx->gang->aff_ref_ctx = ctx; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (flags & SPU_CREATE_AFFINITY_SPU) { 37762306a36Sopenharmony_ci if (list_empty(&neighbor->aff_list)) { 37862306a36Sopenharmony_ci list_add_tail(&neighbor->aff_list, 37962306a36Sopenharmony_ci &ctx->gang->aff_list_head); 38062306a36Sopenharmony_ci neighbor->aff_head = 1; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (list_is_last(&neighbor->aff_list, &ctx->gang->aff_list_head) 38462306a36Sopenharmony_ci || list_entry(neighbor->aff_list.next, struct spu_context, 38562306a36Sopenharmony_ci aff_list)->aff_head) { 38662306a36Sopenharmony_ci list_add(&ctx->aff_list, &neighbor->aff_list); 38762306a36Sopenharmony_ci } else { 38862306a36Sopenharmony_ci list_add_tail(&ctx->aff_list, &neighbor->aff_list); 38962306a36Sopenharmony_ci if (neighbor->aff_head) { 39062306a36Sopenharmony_ci neighbor->aff_head = 0; 39162306a36Sopenharmony_ci ctx->aff_head = 1; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (!ctx->gang->aff_ref_ctx) 39662306a36Sopenharmony_ci ctx->gang->aff_ref_ctx = ctx; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic int 40162306a36Sopenharmony_cispufs_create_context(struct inode *inode, struct dentry *dentry, 40262306a36Sopenharmony_ci struct vfsmount *mnt, int flags, umode_t mode, 40362306a36Sopenharmony_ci struct file *aff_filp) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci int ret; 40662306a36Sopenharmony_ci int affinity; 40762306a36Sopenharmony_ci struct spu_gang *gang; 40862306a36Sopenharmony_ci struct spu_context *neighbor; 40962306a36Sopenharmony_ci struct path path = {.mnt = mnt, .dentry = dentry}; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if ((flags & SPU_CREATE_NOSCHED) && 41262306a36Sopenharmony_ci !capable(CAP_SYS_NICE)) 41362306a36Sopenharmony_ci return -EPERM; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if ((flags & (SPU_CREATE_NOSCHED | SPU_CREATE_ISOLATE)) 41662306a36Sopenharmony_ci == SPU_CREATE_ISOLATE) 41762306a36Sopenharmony_ci return -EINVAL; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if ((flags & SPU_CREATE_ISOLATE) && !isolated_loader) 42062306a36Sopenharmony_ci return -ENODEV; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci gang = NULL; 42362306a36Sopenharmony_ci neighbor = NULL; 42462306a36Sopenharmony_ci affinity = flags & (SPU_CREATE_AFFINITY_MEM | SPU_CREATE_AFFINITY_SPU); 42562306a36Sopenharmony_ci if (affinity) { 42662306a36Sopenharmony_ci gang = SPUFS_I(inode)->i_gang; 42762306a36Sopenharmony_ci if (!gang) 42862306a36Sopenharmony_ci return -EINVAL; 42962306a36Sopenharmony_ci mutex_lock(&gang->aff_mutex); 43062306a36Sopenharmony_ci neighbor = spufs_assert_affinity(flags, gang, aff_filp); 43162306a36Sopenharmony_ci if (IS_ERR(neighbor)) { 43262306a36Sopenharmony_ci ret = PTR_ERR(neighbor); 43362306a36Sopenharmony_ci goto out_aff_unlock; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci ret = spufs_mkdir(inode, dentry, flags, mode & 0777); 43862306a36Sopenharmony_ci if (ret) 43962306a36Sopenharmony_ci goto out_aff_unlock; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (affinity) { 44262306a36Sopenharmony_ci spufs_set_affinity(flags, SPUFS_I(d_inode(dentry))->i_ctx, 44362306a36Sopenharmony_ci neighbor); 44462306a36Sopenharmony_ci if (neighbor) 44562306a36Sopenharmony_ci put_spu_context(neighbor); 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci ret = spufs_context_open(&path); 44962306a36Sopenharmony_ci if (ret < 0) 45062306a36Sopenharmony_ci WARN_ON(spufs_rmdir(inode, dentry)); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ciout_aff_unlock: 45362306a36Sopenharmony_ci if (affinity) 45462306a36Sopenharmony_ci mutex_unlock(&gang->aff_mutex); 45562306a36Sopenharmony_ci return ret; 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic int 45962306a36Sopenharmony_cispufs_mkgang(struct inode *dir, struct dentry *dentry, umode_t mode) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci int ret; 46262306a36Sopenharmony_ci struct inode *inode; 46362306a36Sopenharmony_ci struct spu_gang *gang; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci ret = -ENOSPC; 46662306a36Sopenharmony_ci inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR); 46762306a36Sopenharmony_ci if (!inode) 46862306a36Sopenharmony_ci goto out; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci ret = 0; 47162306a36Sopenharmony_ci inode_init_owner(&nop_mnt_idmap, inode, dir, mode | S_IFDIR); 47262306a36Sopenharmony_ci gang = alloc_spu_gang(); 47362306a36Sopenharmony_ci SPUFS_I(inode)->i_ctx = NULL; 47462306a36Sopenharmony_ci SPUFS_I(inode)->i_gang = gang; 47562306a36Sopenharmony_ci if (!gang) { 47662306a36Sopenharmony_ci ret = -ENOMEM; 47762306a36Sopenharmony_ci goto out_iput; 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci inode->i_op = &simple_dir_inode_operations; 48162306a36Sopenharmony_ci inode->i_fop = &simple_dir_operations; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci d_instantiate(dentry, inode); 48462306a36Sopenharmony_ci inc_nlink(dir); 48562306a36Sopenharmony_ci inc_nlink(d_inode(dentry)); 48662306a36Sopenharmony_ci return ret; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ciout_iput: 48962306a36Sopenharmony_ci iput(inode); 49062306a36Sopenharmony_ciout: 49162306a36Sopenharmony_ci return ret; 49262306a36Sopenharmony_ci} 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_cistatic int spufs_gang_open(const struct path *path) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci int ret; 49762306a36Sopenharmony_ci struct file *filp; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci ret = get_unused_fd_flags(0); 50062306a36Sopenharmony_ci if (ret < 0) 50162306a36Sopenharmony_ci return ret; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci /* 50462306a36Sopenharmony_ci * get references for dget and mntget, will be released 50562306a36Sopenharmony_ci * in error path of *_open(). 50662306a36Sopenharmony_ci */ 50762306a36Sopenharmony_ci filp = dentry_open(path, O_RDONLY, current_cred()); 50862306a36Sopenharmony_ci if (IS_ERR(filp)) { 50962306a36Sopenharmony_ci put_unused_fd(ret); 51062306a36Sopenharmony_ci return PTR_ERR(filp); 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci filp->f_op = &simple_dir_operations; 51462306a36Sopenharmony_ci fd_install(ret, filp); 51562306a36Sopenharmony_ci return ret; 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistatic int spufs_create_gang(struct inode *inode, 51962306a36Sopenharmony_ci struct dentry *dentry, 52062306a36Sopenharmony_ci struct vfsmount *mnt, umode_t mode) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci struct path path = {.mnt = mnt, .dentry = dentry}; 52362306a36Sopenharmony_ci int ret; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci ret = spufs_mkgang(inode, dentry, mode & 0777); 52662306a36Sopenharmony_ci if (!ret) { 52762306a36Sopenharmony_ci ret = spufs_gang_open(&path); 52862306a36Sopenharmony_ci if (ret < 0) { 52962306a36Sopenharmony_ci int err = simple_rmdir(inode, dentry); 53062306a36Sopenharmony_ci WARN_ON(err); 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci return ret; 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic struct file_system_type spufs_type; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cilong spufs_create(const struct path *path, struct dentry *dentry, 54062306a36Sopenharmony_ci unsigned int flags, umode_t mode, struct file *filp) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci struct inode *dir = d_inode(path->dentry); 54362306a36Sopenharmony_ci int ret; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci /* check if we are on spufs */ 54662306a36Sopenharmony_ci if (path->dentry->d_sb->s_type != &spufs_type) 54762306a36Sopenharmony_ci return -EINVAL; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci /* don't accept undefined flags */ 55062306a36Sopenharmony_ci if (flags & (~SPU_CREATE_FLAG_ALL)) 55162306a36Sopenharmony_ci return -EINVAL; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci /* only threads can be underneath a gang */ 55462306a36Sopenharmony_ci if (path->dentry != path->dentry->d_sb->s_root) 55562306a36Sopenharmony_ci if ((flags & SPU_CREATE_GANG) || !SPUFS_I(dir)->i_gang) 55662306a36Sopenharmony_ci return -EINVAL; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci mode &= ~current_umask(); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci if (flags & SPU_CREATE_GANG) 56162306a36Sopenharmony_ci ret = spufs_create_gang(dir, dentry, path->mnt, mode); 56262306a36Sopenharmony_ci else 56362306a36Sopenharmony_ci ret = spufs_create_context(dir, dentry, path->mnt, flags, mode, 56462306a36Sopenharmony_ci filp); 56562306a36Sopenharmony_ci if (ret >= 0) 56662306a36Sopenharmony_ci fsnotify_mkdir(dir, dentry); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci return ret; 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci/* File system initialization */ 57262306a36Sopenharmony_cistruct spufs_fs_context { 57362306a36Sopenharmony_ci kuid_t uid; 57462306a36Sopenharmony_ci kgid_t gid; 57562306a36Sopenharmony_ci umode_t mode; 57662306a36Sopenharmony_ci}; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cienum { 57962306a36Sopenharmony_ci Opt_uid, Opt_gid, Opt_mode, Opt_debug, 58062306a36Sopenharmony_ci}; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_cistatic const struct fs_parameter_spec spufs_fs_parameters[] = { 58362306a36Sopenharmony_ci fsparam_u32 ("gid", Opt_gid), 58462306a36Sopenharmony_ci fsparam_u32oct ("mode", Opt_mode), 58562306a36Sopenharmony_ci fsparam_u32 ("uid", Opt_uid), 58662306a36Sopenharmony_ci fsparam_flag ("debug", Opt_debug), 58762306a36Sopenharmony_ci {} 58862306a36Sopenharmony_ci}; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cistatic int spufs_show_options(struct seq_file *m, struct dentry *root) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci struct spufs_sb_info *sbi = spufs_get_sb_info(root->d_sb); 59362306a36Sopenharmony_ci struct inode *inode = root->d_inode; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci if (!uid_eq(inode->i_uid, GLOBAL_ROOT_UID)) 59662306a36Sopenharmony_ci seq_printf(m, ",uid=%u", 59762306a36Sopenharmony_ci from_kuid_munged(&init_user_ns, inode->i_uid)); 59862306a36Sopenharmony_ci if (!gid_eq(inode->i_gid, GLOBAL_ROOT_GID)) 59962306a36Sopenharmony_ci seq_printf(m, ",gid=%u", 60062306a36Sopenharmony_ci from_kgid_munged(&init_user_ns, inode->i_gid)); 60162306a36Sopenharmony_ci if ((inode->i_mode & S_IALLUGO) != 0775) 60262306a36Sopenharmony_ci seq_printf(m, ",mode=%o", inode->i_mode); 60362306a36Sopenharmony_ci if (sbi->debug) 60462306a36Sopenharmony_ci seq_puts(m, ",debug"); 60562306a36Sopenharmony_ci return 0; 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_cistatic int spufs_parse_param(struct fs_context *fc, struct fs_parameter *param) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci struct spufs_fs_context *ctx = fc->fs_private; 61162306a36Sopenharmony_ci struct spufs_sb_info *sbi = fc->s_fs_info; 61262306a36Sopenharmony_ci struct fs_parse_result result; 61362306a36Sopenharmony_ci kuid_t uid; 61462306a36Sopenharmony_ci kgid_t gid; 61562306a36Sopenharmony_ci int opt; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci opt = fs_parse(fc, spufs_fs_parameters, param, &result); 61862306a36Sopenharmony_ci if (opt < 0) 61962306a36Sopenharmony_ci return opt; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci switch (opt) { 62262306a36Sopenharmony_ci case Opt_uid: 62362306a36Sopenharmony_ci uid = make_kuid(current_user_ns(), result.uint_32); 62462306a36Sopenharmony_ci if (!uid_valid(uid)) 62562306a36Sopenharmony_ci return invalf(fc, "Unknown uid"); 62662306a36Sopenharmony_ci ctx->uid = uid; 62762306a36Sopenharmony_ci break; 62862306a36Sopenharmony_ci case Opt_gid: 62962306a36Sopenharmony_ci gid = make_kgid(current_user_ns(), result.uint_32); 63062306a36Sopenharmony_ci if (!gid_valid(gid)) 63162306a36Sopenharmony_ci return invalf(fc, "Unknown gid"); 63262306a36Sopenharmony_ci ctx->gid = gid; 63362306a36Sopenharmony_ci break; 63462306a36Sopenharmony_ci case Opt_mode: 63562306a36Sopenharmony_ci ctx->mode = result.uint_32 & S_IALLUGO; 63662306a36Sopenharmony_ci break; 63762306a36Sopenharmony_ci case Opt_debug: 63862306a36Sopenharmony_ci sbi->debug = true; 63962306a36Sopenharmony_ci break; 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci return 0; 64362306a36Sopenharmony_ci} 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_cistatic void spufs_exit_isolated_loader(void) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci free_pages((unsigned long) isolated_loader, 64862306a36Sopenharmony_ci get_order(isolated_loader_size)); 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_cistatic void __init 65262306a36Sopenharmony_cispufs_init_isolated_loader(void) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci struct device_node *dn; 65562306a36Sopenharmony_ci const char *loader; 65662306a36Sopenharmony_ci int size; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci dn = of_find_node_by_path("/spu-isolation"); 65962306a36Sopenharmony_ci if (!dn) 66062306a36Sopenharmony_ci return; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci loader = of_get_property(dn, "loader", &size); 66362306a36Sopenharmony_ci of_node_put(dn); 66462306a36Sopenharmony_ci if (!loader) 66562306a36Sopenharmony_ci return; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci /* the loader must be align on a 16 byte boundary */ 66862306a36Sopenharmony_ci isolated_loader = (char *)__get_free_pages(GFP_KERNEL, get_order(size)); 66962306a36Sopenharmony_ci if (!isolated_loader) 67062306a36Sopenharmony_ci return; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci isolated_loader_size = size; 67362306a36Sopenharmony_ci memcpy(isolated_loader, loader, size); 67462306a36Sopenharmony_ci printk(KERN_INFO "spufs: SPU isolation mode enabled\n"); 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_cistatic int spufs_create_root(struct super_block *sb, struct fs_context *fc) 67862306a36Sopenharmony_ci{ 67962306a36Sopenharmony_ci struct spufs_fs_context *ctx = fc->fs_private; 68062306a36Sopenharmony_ci struct inode *inode; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci if (!spu_management_ops) 68362306a36Sopenharmony_ci return -ENODEV; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci inode = spufs_new_inode(sb, S_IFDIR | ctx->mode); 68662306a36Sopenharmony_ci if (!inode) 68762306a36Sopenharmony_ci return -ENOMEM; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci inode->i_uid = ctx->uid; 69062306a36Sopenharmony_ci inode->i_gid = ctx->gid; 69162306a36Sopenharmony_ci inode->i_op = &simple_dir_inode_operations; 69262306a36Sopenharmony_ci inode->i_fop = &simple_dir_operations; 69362306a36Sopenharmony_ci SPUFS_I(inode)->i_ctx = NULL; 69462306a36Sopenharmony_ci inc_nlink(inode); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci sb->s_root = d_make_root(inode); 69762306a36Sopenharmony_ci if (!sb->s_root) 69862306a36Sopenharmony_ci return -ENOMEM; 69962306a36Sopenharmony_ci return 0; 70062306a36Sopenharmony_ci} 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_cistatic const struct super_operations spufs_ops = { 70362306a36Sopenharmony_ci .alloc_inode = spufs_alloc_inode, 70462306a36Sopenharmony_ci .free_inode = spufs_free_inode, 70562306a36Sopenharmony_ci .statfs = simple_statfs, 70662306a36Sopenharmony_ci .evict_inode = spufs_evict_inode, 70762306a36Sopenharmony_ci .show_options = spufs_show_options, 70862306a36Sopenharmony_ci}; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cistatic int spufs_fill_super(struct super_block *sb, struct fs_context *fc) 71162306a36Sopenharmony_ci{ 71262306a36Sopenharmony_ci sb->s_maxbytes = MAX_LFS_FILESIZE; 71362306a36Sopenharmony_ci sb->s_blocksize = PAGE_SIZE; 71462306a36Sopenharmony_ci sb->s_blocksize_bits = PAGE_SHIFT; 71562306a36Sopenharmony_ci sb->s_magic = SPUFS_MAGIC; 71662306a36Sopenharmony_ci sb->s_op = &spufs_ops; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci return spufs_create_root(sb, fc); 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic int spufs_get_tree(struct fs_context *fc) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci return get_tree_single(fc, spufs_fill_super); 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cistatic void spufs_free_fc(struct fs_context *fc) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci kfree(fc->s_fs_info); 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic const struct fs_context_operations spufs_context_ops = { 73262306a36Sopenharmony_ci .free = spufs_free_fc, 73362306a36Sopenharmony_ci .parse_param = spufs_parse_param, 73462306a36Sopenharmony_ci .get_tree = spufs_get_tree, 73562306a36Sopenharmony_ci}; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_cistatic int spufs_init_fs_context(struct fs_context *fc) 73862306a36Sopenharmony_ci{ 73962306a36Sopenharmony_ci struct spufs_fs_context *ctx; 74062306a36Sopenharmony_ci struct spufs_sb_info *sbi; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci ctx = kzalloc(sizeof(struct spufs_fs_context), GFP_KERNEL); 74362306a36Sopenharmony_ci if (!ctx) 74462306a36Sopenharmony_ci goto nomem; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci sbi = kzalloc(sizeof(struct spufs_sb_info), GFP_KERNEL); 74762306a36Sopenharmony_ci if (!sbi) 74862306a36Sopenharmony_ci goto nomem_ctx; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci ctx->uid = current_uid(); 75162306a36Sopenharmony_ci ctx->gid = current_gid(); 75262306a36Sopenharmony_ci ctx->mode = 0755; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci fc->fs_private = ctx; 75562306a36Sopenharmony_ci fc->s_fs_info = sbi; 75662306a36Sopenharmony_ci fc->ops = &spufs_context_ops; 75762306a36Sopenharmony_ci return 0; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_cinomem_ctx: 76062306a36Sopenharmony_ci kfree(ctx); 76162306a36Sopenharmony_cinomem: 76262306a36Sopenharmony_ci return -ENOMEM; 76362306a36Sopenharmony_ci} 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_cistatic struct file_system_type spufs_type = { 76662306a36Sopenharmony_ci .owner = THIS_MODULE, 76762306a36Sopenharmony_ci .name = "spufs", 76862306a36Sopenharmony_ci .init_fs_context = spufs_init_fs_context, 76962306a36Sopenharmony_ci .parameters = spufs_fs_parameters, 77062306a36Sopenharmony_ci .kill_sb = kill_litter_super, 77162306a36Sopenharmony_ci}; 77262306a36Sopenharmony_ciMODULE_ALIAS_FS("spufs"); 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic int __init spufs_init(void) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci int ret; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci ret = -ENODEV; 77962306a36Sopenharmony_ci if (!spu_management_ops) 78062306a36Sopenharmony_ci goto out; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci ret = -ENOMEM; 78362306a36Sopenharmony_ci spufs_inode_cache = kmem_cache_create("spufs_inode_cache", 78462306a36Sopenharmony_ci sizeof(struct spufs_inode_info), 0, 78562306a36Sopenharmony_ci SLAB_HWCACHE_ALIGN|SLAB_ACCOUNT, spufs_init_once); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci if (!spufs_inode_cache) 78862306a36Sopenharmony_ci goto out; 78962306a36Sopenharmony_ci ret = spu_sched_init(); 79062306a36Sopenharmony_ci if (ret) 79162306a36Sopenharmony_ci goto out_cache; 79262306a36Sopenharmony_ci ret = register_spu_syscalls(&spufs_calls); 79362306a36Sopenharmony_ci if (ret) 79462306a36Sopenharmony_ci goto out_sched; 79562306a36Sopenharmony_ci ret = register_filesystem(&spufs_type); 79662306a36Sopenharmony_ci if (ret) 79762306a36Sopenharmony_ci goto out_syscalls; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci spufs_init_isolated_loader(); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci return 0; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ciout_syscalls: 80462306a36Sopenharmony_ci unregister_spu_syscalls(&spufs_calls); 80562306a36Sopenharmony_ciout_sched: 80662306a36Sopenharmony_ci spu_sched_exit(); 80762306a36Sopenharmony_ciout_cache: 80862306a36Sopenharmony_ci kmem_cache_destroy(spufs_inode_cache); 80962306a36Sopenharmony_ciout: 81062306a36Sopenharmony_ci return ret; 81162306a36Sopenharmony_ci} 81262306a36Sopenharmony_cimodule_init(spufs_init); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistatic void __exit spufs_exit(void) 81562306a36Sopenharmony_ci{ 81662306a36Sopenharmony_ci spu_sched_exit(); 81762306a36Sopenharmony_ci spufs_exit_isolated_loader(); 81862306a36Sopenharmony_ci unregister_spu_syscalls(&spufs_calls); 81962306a36Sopenharmony_ci unregister_filesystem(&spufs_type); 82062306a36Sopenharmony_ci kmem_cache_destroy(spufs_inode_cache); 82162306a36Sopenharmony_ci} 82262306a36Sopenharmony_cimodule_exit(spufs_exit); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 82562306a36Sopenharmony_ciMODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>"); 82662306a36Sopenharmony_ci 827