📄 inode.c
字号:
/* * SPU file system * * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 * * Author: Arnd Bergmann <arndb@de.ibm.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include <linux/file.h>#include <linux/fs.h>#include <linux/backing-dev.h>#include <linux/init.h>#include <linux/ioctl.h>#include <linux/module.h>#include <linux/mount.h>#include <linux/namei.h>#include <linux/pagemap.h>#include <linux/poll.h>#include <linux/slab.h>#include <linux/parser.h>#include <asm/prom.h>#include <asm/semaphore.h>#include <asm/spu.h>#include <asm/spu_priv1.h>#include <asm/uaccess.h>#include "spufs.h"static struct kmem_cache *spufs_inode_cache;char *isolated_loader;static int isolated_loader_size;static struct inode *spufs_alloc_inode(struct super_block *sb){ struct spufs_inode_info *ei; ei = kmem_cache_alloc(spufs_inode_cache, GFP_KERNEL); if (!ei) return NULL; ei->i_gang = NULL; ei->i_ctx = NULL; ei->i_openers = 0; return &ei->vfs_inode;}static voidspufs_destroy_inode(struct inode *inode){ kmem_cache_free(spufs_inode_cache, SPUFS_I(inode));}static voidspufs_init_once(struct kmem_cache *cachep, void *p){ struct spufs_inode_info *ei = p; inode_init_once(&ei->vfs_inode);}static struct inode *spufs_new_inode(struct super_block *sb, int mode){ struct inode *inode; inode = new_inode(sb); if (!inode) goto out; inode->i_mode = mode; inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;out: return inode;}static intspufs_setattr(struct dentry *dentry, struct iattr *attr){ struct inode *inode = dentry->d_inode; if ((attr->ia_valid & ATTR_SIZE) && (attr->ia_size != inode->i_size)) return -EINVAL; return inode_setattr(inode, attr);}static intspufs_new_file(struct super_block *sb, struct dentry *dentry, const struct file_operations *fops, int mode, struct spu_context *ctx){ static struct inode_operations spufs_file_iops = { .setattr = spufs_setattr, }; struct inode *inode; int ret; ret = -ENOSPC; inode = spufs_new_inode(sb, S_IFREG | mode); if (!inode) goto out; ret = 0; inode->i_op = &spufs_file_iops; inode->i_fop = fops; inode->i_private = SPUFS_I(inode)->i_ctx = get_spu_context(ctx); d_add(dentry, inode);out: return ret;}static voidspufs_delete_inode(struct inode *inode){ struct spufs_inode_info *ei = SPUFS_I(inode); if (ei->i_ctx) put_spu_context(ei->i_ctx); if (ei->i_gang) put_spu_gang(ei->i_gang); clear_inode(inode);}static void spufs_prune_dir(struct dentry *dir){ struct dentry *dentry, *tmp; mutex_lock(&dir->d_inode->i_mutex); list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) { spin_lock(&dcache_lock); spin_lock(&dentry->d_lock); if (!(d_unhashed(dentry)) && dentry->d_inode) { dget_locked(dentry); __d_drop(dentry); spin_unlock(&dentry->d_lock); simple_unlink(dir->d_inode, dentry); spin_unlock(&dcache_lock); dput(dentry); } else { spin_unlock(&dentry->d_lock); spin_unlock(&dcache_lock); } } shrink_dcache_parent(dir); mutex_unlock(&dir->d_inode->i_mutex);}/* Caller must hold parent->i_mutex */static int spufs_rmdir(struct inode *parent, struct dentry *dir){ /* remove all entries */ spufs_prune_dir(dir); d_drop(dir); return simple_rmdir(parent, dir);}static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files, int mode, struct spu_context *ctx){ struct dentry *dentry, *tmp; int ret; while (files->name && files->name[0]) { ret = -ENOMEM; dentry = d_alloc_name(dir, files->name); if (!dentry) goto out; ret = spufs_new_file(dir->d_sb, dentry, files->ops, files->mode & mode, ctx); if (ret) goto out; files++; } return 0;out: /* * remove all children from dir. dir->inode is not set so don't * just simply use spufs_prune_dir() and panic afterwards :) * dput() looks like it will do the right thing: * - dec parent's ref counter * - remove child from parent's child list * - free child's inode if possible * - free child */ list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) { dput(dentry); } shrink_dcache_parent(dir); return ret;}static int spufs_dir_close(struct inode *inode, struct file *file){ struct spu_context *ctx; struct inode *parent; struct dentry *dir; int ret; dir = file->f_path.dentry; parent = dir->d_parent->d_inode; ctx = SPUFS_I(dir->d_inode)->i_ctx; mutex_lock(&parent->i_mutex); ret = spufs_rmdir(parent, dir); mutex_unlock(&parent->i_mutex); WARN_ON(ret); /* We have to give up the mm_struct */ spu_forget(ctx); return dcache_dir_close(inode, file);}const struct file_operations spufs_context_fops = { .open = dcache_dir_open, .release = spufs_dir_close, .llseek = dcache_dir_lseek, .read = generic_read_dir, .readdir = dcache_readdir, .fsync = simple_sync_file,};EXPORT_SYMBOL_GPL(spufs_context_fops);static intspufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags, int mode){ int ret; struct inode *inode; struct spu_context *ctx; ret = -ENOSPC; inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR); if (!inode) goto out; if (dir->i_mode & S_ISGID) { inode->i_gid = dir->i_gid; inode->i_mode &= S_ISGID; } ctx = alloc_spu_context(SPUFS_I(dir)->i_gang); /* XXX gang */ SPUFS_I(inode)->i_ctx = ctx; if (!ctx) goto out_iput; ctx->flags = flags; inode->i_op = &simple_dir_inode_operations; inode->i_fop = &simple_dir_operations; if (flags & SPU_CREATE_NOSCHED) ret = spufs_fill_dir(dentry, spufs_dir_nosched_contents, mode, ctx); else ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx); if (ret) goto out_free_ctx; d_instantiate(dentry, inode); dget(dentry); dir->i_nlink++; dentry->d_inode->i_nlink++; goto out;out_free_ctx: spu_forget(ctx); put_spu_context(ctx);out_iput: iput(inode);out: return ret;}static int spufs_context_open(struct dentry *dentry, struct vfsmount *mnt){ int ret; struct file *filp; ret = get_unused_fd(); if (ret < 0) { dput(dentry); mntput(mnt); goto out; } filp = dentry_open(dentry, mnt, O_RDONLY); if (IS_ERR(filp)) { put_unused_fd(ret); ret = PTR_ERR(filp); goto out; } filp->f_op = &spufs_context_fops; fd_install(ret, filp);out: return ret;}static struct spu_context *spufs_assert_affinity(unsigned int flags, struct spu_gang *gang, struct file *filp){ struct spu_context *tmp, *neighbor; int count, node; int aff_supp; aff_supp = !list_empty(&(list_entry(cbe_spu_info[0].spus.next, struct spu, cbe_list))->aff_list); if (!aff_supp) return ERR_PTR(-EINVAL); if (flags & SPU_CREATE_GANG) return ERR_PTR(-EINVAL); if (flags & SPU_CREATE_AFFINITY_MEM && gang->aff_ref_ctx && gang->aff_ref_ctx->flags & SPU_CREATE_AFFINITY_MEM) return ERR_PTR(-EEXIST); if (gang->aff_flags & AFF_MERGED) return ERR_PTR(-EBUSY); neighbor = NULL; if (flags & SPU_CREATE_AFFINITY_SPU) { if (!filp || filp->f_op != &spufs_context_fops) return ERR_PTR(-EINVAL); neighbor = get_spu_context( SPUFS_I(filp->f_dentry->d_inode)->i_ctx); if (!list_empty(&neighbor->aff_list) && !(neighbor->aff_head) && !list_is_last(&neighbor->aff_list, &gang->aff_list_head) && !list_entry(neighbor->aff_list.next, struct spu_context, aff_list)->aff_head) return ERR_PTR(-EEXIST); if (gang != neighbor->gang) return ERR_PTR(-EINVAL); count = 1; list_for_each_entry(tmp, &gang->aff_list_head, aff_list) count++; if (list_empty(&neighbor->aff_list)) count++; for (node = 0; node < MAX_NUMNODES; node++) { if ((cbe_spu_info[node].n_spus - atomic_read( &cbe_spu_info[node].reserved_spus)) >= count) break; } if (node == MAX_NUMNODES) return ERR_PTR(-EEXIST); } return neighbor;}static voidspufs_set_affinity(unsigned int flags, struct spu_context *ctx, struct spu_context *neighbor){ if (flags & SPU_CREATE_AFFINITY_MEM) ctx->gang->aff_ref_ctx = ctx; if (flags & SPU_CREATE_AFFINITY_SPU) { if (list_empty(&neighbor->aff_list)) { list_add_tail(&neighbor->aff_list, &ctx->gang->aff_list_head); neighbor->aff_head = 1; } if (list_is_last(&neighbor->aff_list, &ctx->gang->aff_list_head) || list_entry(neighbor->aff_list.next, struct spu_context, aff_list)->aff_head) { list_add(&ctx->aff_list, &neighbor->aff_list); } else { list_add_tail(&ctx->aff_list, &neighbor->aff_list); if (neighbor->aff_head) { neighbor->aff_head = 0; ctx->aff_head = 1; } } if (!ctx->gang->aff_ref_ctx) ctx->gang->aff_ref_ctx = ctx; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -