1*67207b96SArnd Bergmann /* 2*67207b96SArnd Bergmann * SPU file system 3*67207b96SArnd Bergmann * 4*67207b96SArnd Bergmann * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 5*67207b96SArnd Bergmann * 6*67207b96SArnd Bergmann * Author: Arnd Bergmann <arndb@de.ibm.com> 7*67207b96SArnd Bergmann * 8*67207b96SArnd Bergmann * This program is free software; you can redistribute it and/or modify 9*67207b96SArnd Bergmann * it under the terms of the GNU General Public License as published by 10*67207b96SArnd Bergmann * the Free Software Foundation; either version 2, or (at your option) 11*67207b96SArnd Bergmann * any later version. 12*67207b96SArnd Bergmann * 13*67207b96SArnd Bergmann * This program is distributed in the hope that it will be useful, 14*67207b96SArnd Bergmann * but WITHOUT ANY WARRANTY; without even the implied warranty of 15*67207b96SArnd Bergmann * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16*67207b96SArnd Bergmann * GNU General Public License for more details. 17*67207b96SArnd Bergmann * 18*67207b96SArnd Bergmann * You should have received a copy of the GNU General Public License 19*67207b96SArnd Bergmann * along with this program; if not, write to the Free Software 20*67207b96SArnd Bergmann * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21*67207b96SArnd Bergmann */ 22*67207b96SArnd Bergmann 23*67207b96SArnd Bergmann #include <linux/file.h> 24*67207b96SArnd Bergmann #include <linux/fs.h> 25*67207b96SArnd Bergmann #include <linux/backing-dev.h> 26*67207b96SArnd Bergmann #include <linux/init.h> 27*67207b96SArnd Bergmann #include <linux/ioctl.h> 28*67207b96SArnd Bergmann #include <linux/module.h> 29*67207b96SArnd Bergmann #include <linux/namei.h> 30*67207b96SArnd Bergmann #include <linux/pagemap.h> 31*67207b96SArnd Bergmann #include <linux/poll.h> 32*67207b96SArnd Bergmann #include <linux/slab.h> 33*67207b96SArnd Bergmann #include <linux/parser.h> 34*67207b96SArnd Bergmann 35*67207b96SArnd Bergmann #include <asm/io.h> 36*67207b96SArnd Bergmann #include <asm/semaphore.h> 37*67207b96SArnd Bergmann #include <asm/spu.h> 38*67207b96SArnd Bergmann #include <asm/uaccess.h> 39*67207b96SArnd Bergmann 40*67207b96SArnd Bergmann #include "spufs.h" 41*67207b96SArnd Bergmann 42*67207b96SArnd Bergmann static kmem_cache_t *spufs_inode_cache; 43*67207b96SArnd Bergmann 44*67207b96SArnd Bergmann /* Information about the backing dev, same as ramfs */ 45*67207b96SArnd Bergmann #if 0 46*67207b96SArnd Bergmann static struct backing_dev_info spufs_backing_dev_info = { 47*67207b96SArnd Bergmann .ra_pages = 0, /* No readahead */ 48*67207b96SArnd Bergmann .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK | 49*67207b96SArnd Bergmann BDI_CAP_MAP_DIRECT | BDI_CAP_MAP_COPY | BDI_CAP_READ_MAP | 50*67207b96SArnd Bergmann BDI_CAP_WRITE_MAP, 51*67207b96SArnd Bergmann }; 52*67207b96SArnd Bergmann 53*67207b96SArnd Bergmann static struct address_space_operations spufs_aops = { 54*67207b96SArnd Bergmann .readpage = simple_readpage, 55*67207b96SArnd Bergmann .prepare_write = simple_prepare_write, 56*67207b96SArnd Bergmann .commit_write = simple_commit_write, 57*67207b96SArnd Bergmann }; 58*67207b96SArnd Bergmann #endif 59*67207b96SArnd Bergmann 60*67207b96SArnd Bergmann /* Inode operations */ 61*67207b96SArnd Bergmann 62*67207b96SArnd Bergmann static struct inode * 63*67207b96SArnd Bergmann spufs_alloc_inode(struct super_block *sb) 64*67207b96SArnd Bergmann { 65*67207b96SArnd Bergmann struct spufs_inode_info *ei; 66*67207b96SArnd Bergmann 67*67207b96SArnd Bergmann ei = kmem_cache_alloc(spufs_inode_cache, SLAB_KERNEL); 68*67207b96SArnd Bergmann if (!ei) 69*67207b96SArnd Bergmann return NULL; 70*67207b96SArnd Bergmann return &ei->vfs_inode; 71*67207b96SArnd Bergmann } 72*67207b96SArnd Bergmann 73*67207b96SArnd Bergmann static void 74*67207b96SArnd Bergmann spufs_destroy_inode(struct inode *inode) 75*67207b96SArnd Bergmann { 76*67207b96SArnd Bergmann kmem_cache_free(spufs_inode_cache, SPUFS_I(inode)); 77*67207b96SArnd Bergmann } 78*67207b96SArnd Bergmann 79*67207b96SArnd Bergmann static void 80*67207b96SArnd Bergmann spufs_init_once(void *p, kmem_cache_t * cachep, unsigned long flags) 81*67207b96SArnd Bergmann { 82*67207b96SArnd Bergmann struct spufs_inode_info *ei = p; 83*67207b96SArnd Bergmann 84*67207b96SArnd Bergmann if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == 85*67207b96SArnd Bergmann SLAB_CTOR_CONSTRUCTOR) { 86*67207b96SArnd Bergmann inode_init_once(&ei->vfs_inode); 87*67207b96SArnd Bergmann } 88*67207b96SArnd Bergmann } 89*67207b96SArnd Bergmann 90*67207b96SArnd Bergmann static struct inode * 91*67207b96SArnd Bergmann spufs_new_inode(struct super_block *sb, int mode) 92*67207b96SArnd Bergmann { 93*67207b96SArnd Bergmann struct inode *inode; 94*67207b96SArnd Bergmann 95*67207b96SArnd Bergmann inode = new_inode(sb); 96*67207b96SArnd Bergmann if (!inode) 97*67207b96SArnd Bergmann goto out; 98*67207b96SArnd Bergmann 99*67207b96SArnd Bergmann inode->i_mode = mode; 100*67207b96SArnd Bergmann inode->i_uid = current->fsuid; 101*67207b96SArnd Bergmann inode->i_gid = current->fsgid; 102*67207b96SArnd Bergmann inode->i_blksize = PAGE_CACHE_SIZE; 103*67207b96SArnd Bergmann inode->i_blocks = 0; 104*67207b96SArnd Bergmann inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; 105*67207b96SArnd Bergmann out: 106*67207b96SArnd Bergmann return inode; 107*67207b96SArnd Bergmann } 108*67207b96SArnd Bergmann 109*67207b96SArnd Bergmann static int 110*67207b96SArnd Bergmann spufs_setattr(struct dentry *dentry, struct iattr *attr) 111*67207b96SArnd Bergmann { 112*67207b96SArnd Bergmann struct inode *inode = dentry->d_inode; 113*67207b96SArnd Bergmann 114*67207b96SArnd Bergmann /* dump_stack(); 115*67207b96SArnd Bergmann pr_debug("ia_size %lld, i_size:%lld\n", attr->ia_size, inode->i_size); 116*67207b96SArnd Bergmann */ 117*67207b96SArnd Bergmann if ((attr->ia_valid & ATTR_SIZE) && 118*67207b96SArnd Bergmann (attr->ia_size != inode->i_size)) 119*67207b96SArnd Bergmann return -EINVAL; 120*67207b96SArnd Bergmann return inode_setattr(inode, attr); 121*67207b96SArnd Bergmann } 122*67207b96SArnd Bergmann 123*67207b96SArnd Bergmann 124*67207b96SArnd Bergmann static int 125*67207b96SArnd Bergmann spufs_new_file(struct super_block *sb, struct dentry *dentry, 126*67207b96SArnd Bergmann struct file_operations *fops, int mode, 127*67207b96SArnd Bergmann struct spu_context *ctx) 128*67207b96SArnd Bergmann { 129*67207b96SArnd Bergmann static struct inode_operations spufs_file_iops = { 130*67207b96SArnd Bergmann .getattr = simple_getattr, 131*67207b96SArnd Bergmann .setattr = spufs_setattr, 132*67207b96SArnd Bergmann .unlink = simple_unlink, 133*67207b96SArnd Bergmann }; 134*67207b96SArnd Bergmann struct inode *inode; 135*67207b96SArnd Bergmann int ret; 136*67207b96SArnd Bergmann 137*67207b96SArnd Bergmann ret = -ENOSPC; 138*67207b96SArnd Bergmann inode = spufs_new_inode(sb, S_IFREG | mode); 139*67207b96SArnd Bergmann if (!inode) 140*67207b96SArnd Bergmann goto out; 141*67207b96SArnd Bergmann 142*67207b96SArnd Bergmann ret = 0; 143*67207b96SArnd Bergmann inode->i_op = &spufs_file_iops; 144*67207b96SArnd Bergmann inode->i_fop = fops; 145*67207b96SArnd Bergmann inode->u.generic_ip = SPUFS_I(inode)->i_ctx = get_spu_context(ctx); 146*67207b96SArnd Bergmann d_add(dentry, inode); 147*67207b96SArnd Bergmann out: 148*67207b96SArnd Bergmann return ret; 149*67207b96SArnd Bergmann } 150*67207b96SArnd Bergmann 151*67207b96SArnd Bergmann static void 152*67207b96SArnd Bergmann spufs_delete_inode(struct inode *inode) 153*67207b96SArnd Bergmann { 154*67207b96SArnd Bergmann if (SPUFS_I(inode)->i_ctx) 155*67207b96SArnd Bergmann put_spu_context(SPUFS_I(inode)->i_ctx); 156*67207b96SArnd Bergmann clear_inode(inode); 157*67207b96SArnd Bergmann } 158*67207b96SArnd Bergmann 159*67207b96SArnd Bergmann static int 160*67207b96SArnd Bergmann spufs_fill_dir(struct dentry *dir, struct tree_descr *files, 161*67207b96SArnd Bergmann int mode, struct spu_context *ctx) 162*67207b96SArnd Bergmann { 163*67207b96SArnd Bergmann struct dentry *dentry; 164*67207b96SArnd Bergmann int ret; 165*67207b96SArnd Bergmann 166*67207b96SArnd Bergmann while (files->name && files->name[0]) { 167*67207b96SArnd Bergmann ret = -ENOMEM; 168*67207b96SArnd Bergmann dentry = d_alloc_name(dir, files->name); 169*67207b96SArnd Bergmann if (!dentry) 170*67207b96SArnd Bergmann goto out; 171*67207b96SArnd Bergmann ret = spufs_new_file(dir->d_sb, dentry, files->ops, 172*67207b96SArnd Bergmann files->mode & mode, ctx); 173*67207b96SArnd Bergmann if (ret) 174*67207b96SArnd Bergmann goto out; 175*67207b96SArnd Bergmann files++; 176*67207b96SArnd Bergmann } 177*67207b96SArnd Bergmann return 0; 178*67207b96SArnd Bergmann out: 179*67207b96SArnd Bergmann // FIXME: remove all files that are left 180*67207b96SArnd Bergmann 181*67207b96SArnd Bergmann return ret; 182*67207b96SArnd Bergmann } 183*67207b96SArnd Bergmann 184*67207b96SArnd Bergmann static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry) 185*67207b96SArnd Bergmann { 186*67207b96SArnd Bergmann struct dentry *dentry; 187*67207b96SArnd Bergmann int err; 188*67207b96SArnd Bergmann 189*67207b96SArnd Bergmann spin_lock(&dcache_lock); 190*67207b96SArnd Bergmann /* remove all entries */ 191*67207b96SArnd Bergmann err = 0; 192*67207b96SArnd Bergmann list_for_each_entry(dentry, &dir_dentry->d_subdirs, d_child) { 193*67207b96SArnd Bergmann if (d_unhashed(dentry) || !dentry->d_inode) 194*67207b96SArnd Bergmann continue; 195*67207b96SArnd Bergmann atomic_dec(&dentry->d_count); 196*67207b96SArnd Bergmann spin_lock(&dentry->d_lock); 197*67207b96SArnd Bergmann __d_drop(dentry); 198*67207b96SArnd Bergmann spin_unlock(&dentry->d_lock); 199*67207b96SArnd Bergmann } 200*67207b96SArnd Bergmann spin_unlock(&dcache_lock); 201*67207b96SArnd Bergmann if (!err) { 202*67207b96SArnd Bergmann shrink_dcache_parent(dir_dentry); 203*67207b96SArnd Bergmann err = simple_rmdir(root, dir_dentry); 204*67207b96SArnd Bergmann } 205*67207b96SArnd Bergmann return err; 206*67207b96SArnd Bergmann } 207*67207b96SArnd Bergmann 208*67207b96SArnd Bergmann static int spufs_dir_close(struct inode *inode, struct file *file) 209*67207b96SArnd Bergmann { 210*67207b96SArnd Bergmann struct inode *dir; 211*67207b96SArnd Bergmann struct dentry *dentry; 212*67207b96SArnd Bergmann int ret; 213*67207b96SArnd Bergmann 214*67207b96SArnd Bergmann dentry = file->f_dentry; 215*67207b96SArnd Bergmann dir = dentry->d_parent->d_inode; 216*67207b96SArnd Bergmann down(&dir->i_sem); 217*67207b96SArnd Bergmann ret = spufs_rmdir(dir, file->f_dentry); 218*67207b96SArnd Bergmann WARN_ON(ret); 219*67207b96SArnd Bergmann up(&dir->i_sem); 220*67207b96SArnd Bergmann return dcache_dir_close(inode, file); 221*67207b96SArnd Bergmann } 222*67207b96SArnd Bergmann 223*67207b96SArnd Bergmann struct inode_operations spufs_dir_inode_operations = { 224*67207b96SArnd Bergmann .lookup = simple_lookup, 225*67207b96SArnd Bergmann }; 226*67207b96SArnd Bergmann 227*67207b96SArnd Bergmann struct file_operations spufs_autodelete_dir_operations = { 228*67207b96SArnd Bergmann .open = dcache_dir_open, 229*67207b96SArnd Bergmann .release = spufs_dir_close, 230*67207b96SArnd Bergmann .llseek = dcache_dir_lseek, 231*67207b96SArnd Bergmann .read = generic_read_dir, 232*67207b96SArnd Bergmann .readdir = dcache_readdir, 233*67207b96SArnd Bergmann .fsync = simple_sync_file, 234*67207b96SArnd Bergmann }; 235*67207b96SArnd Bergmann 236*67207b96SArnd Bergmann static int 237*67207b96SArnd Bergmann spufs_mkdir(struct inode *dir, struct dentry *dentry, int mode) 238*67207b96SArnd Bergmann { 239*67207b96SArnd Bergmann int ret; 240*67207b96SArnd Bergmann struct inode *inode; 241*67207b96SArnd Bergmann struct spu_context *ctx; 242*67207b96SArnd Bergmann 243*67207b96SArnd Bergmann ret = -ENOSPC; 244*67207b96SArnd Bergmann inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR); 245*67207b96SArnd Bergmann if (!inode) 246*67207b96SArnd Bergmann goto out; 247*67207b96SArnd Bergmann 248*67207b96SArnd Bergmann if (dir->i_mode & S_ISGID) { 249*67207b96SArnd Bergmann inode->i_gid = dir->i_gid; 250*67207b96SArnd Bergmann inode->i_mode &= S_ISGID; 251*67207b96SArnd Bergmann } 252*67207b96SArnd Bergmann ctx = alloc_spu_context(); 253*67207b96SArnd Bergmann SPUFS_I(inode)->i_ctx = ctx; 254*67207b96SArnd Bergmann if (!ctx) 255*67207b96SArnd Bergmann goto out_iput; 256*67207b96SArnd Bergmann 257*67207b96SArnd Bergmann inode->i_op = &spufs_dir_inode_operations; 258*67207b96SArnd Bergmann inode->i_fop = &simple_dir_operations; 259*67207b96SArnd Bergmann ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx); 260*67207b96SArnd Bergmann if (ret) 261*67207b96SArnd Bergmann goto out_free_ctx; 262*67207b96SArnd Bergmann 263*67207b96SArnd Bergmann d_instantiate(dentry, inode); 264*67207b96SArnd Bergmann dget(dentry); 265*67207b96SArnd Bergmann dir->i_nlink++; 266*67207b96SArnd Bergmann goto out; 267*67207b96SArnd Bergmann 268*67207b96SArnd Bergmann out_free_ctx: 269*67207b96SArnd Bergmann put_spu_context(ctx); 270*67207b96SArnd Bergmann out_iput: 271*67207b96SArnd Bergmann iput(inode); 272*67207b96SArnd Bergmann out: 273*67207b96SArnd Bergmann return ret; 274*67207b96SArnd Bergmann } 275*67207b96SArnd Bergmann 276*67207b96SArnd Bergmann long 277*67207b96SArnd Bergmann spufs_create_thread(struct nameidata *nd, const char *name, 278*67207b96SArnd Bergmann unsigned int flags, mode_t mode) 279*67207b96SArnd Bergmann { 280*67207b96SArnd Bergmann struct dentry *dentry; 281*67207b96SArnd Bergmann struct file *filp; 282*67207b96SArnd Bergmann int ret; 283*67207b96SArnd Bergmann 284*67207b96SArnd Bergmann /* need to be at the root of spufs */ 285*67207b96SArnd Bergmann ret = -EINVAL; 286*67207b96SArnd Bergmann if (nd->dentry->d_sb->s_magic != SPUFS_MAGIC || 287*67207b96SArnd Bergmann nd->dentry != nd->dentry->d_sb->s_root) 288*67207b96SArnd Bergmann goto out; 289*67207b96SArnd Bergmann 290*67207b96SArnd Bergmann dentry = lookup_create(nd, 1); 291*67207b96SArnd Bergmann ret = PTR_ERR(dentry); 292*67207b96SArnd Bergmann if (IS_ERR(dentry)) 293*67207b96SArnd Bergmann goto out_dir; 294*67207b96SArnd Bergmann 295*67207b96SArnd Bergmann ret = -EEXIST; 296*67207b96SArnd Bergmann if (dentry->d_inode) 297*67207b96SArnd Bergmann goto out_dput; 298*67207b96SArnd Bergmann 299*67207b96SArnd Bergmann mode &= ~current->fs->umask; 300*67207b96SArnd Bergmann ret = spufs_mkdir(nd->dentry->d_inode, dentry, mode & S_IRWXUGO); 301*67207b96SArnd Bergmann if (ret) 302*67207b96SArnd Bergmann goto out_dput; 303*67207b96SArnd Bergmann 304*67207b96SArnd Bergmann ret = get_unused_fd(); 305*67207b96SArnd Bergmann if (ret < 0) 306*67207b96SArnd Bergmann goto out_dput; 307*67207b96SArnd Bergmann 308*67207b96SArnd Bergmann dentry->d_inode->i_nlink++; 309*67207b96SArnd Bergmann 310*67207b96SArnd Bergmann filp = filp_open(name, O_RDONLY, mode); 311*67207b96SArnd Bergmann if (IS_ERR(filp)) { 312*67207b96SArnd Bergmann // FIXME: remove directory again 313*67207b96SArnd Bergmann put_unused_fd(ret); 314*67207b96SArnd Bergmann ret = PTR_ERR(filp); 315*67207b96SArnd Bergmann } else { 316*67207b96SArnd Bergmann filp->f_op = &spufs_autodelete_dir_operations; 317*67207b96SArnd Bergmann fd_install(ret, filp); 318*67207b96SArnd Bergmann } 319*67207b96SArnd Bergmann 320*67207b96SArnd Bergmann out_dput: 321*67207b96SArnd Bergmann dput(dentry); 322*67207b96SArnd Bergmann out_dir: 323*67207b96SArnd Bergmann up(&nd->dentry->d_inode->i_sem); 324*67207b96SArnd Bergmann out: 325*67207b96SArnd Bergmann return ret; 326*67207b96SArnd Bergmann } 327*67207b96SArnd Bergmann 328*67207b96SArnd Bergmann /* File system initialization */ 329*67207b96SArnd Bergmann enum { 330*67207b96SArnd Bergmann Opt_uid, Opt_gid, Opt_err, 331*67207b96SArnd Bergmann }; 332*67207b96SArnd Bergmann 333*67207b96SArnd Bergmann static match_table_t spufs_tokens = { 334*67207b96SArnd Bergmann { Opt_uid, "uid=%d" }, 335*67207b96SArnd Bergmann { Opt_gid, "gid=%d" }, 336*67207b96SArnd Bergmann { Opt_err, NULL }, 337*67207b96SArnd Bergmann }; 338*67207b96SArnd Bergmann 339*67207b96SArnd Bergmann static int 340*67207b96SArnd Bergmann spufs_parse_options(char *options, struct inode *root) 341*67207b96SArnd Bergmann { 342*67207b96SArnd Bergmann char *p; 343*67207b96SArnd Bergmann substring_t args[MAX_OPT_ARGS]; 344*67207b96SArnd Bergmann 345*67207b96SArnd Bergmann while ((p = strsep(&options, ",")) != NULL) { 346*67207b96SArnd Bergmann int token, option; 347*67207b96SArnd Bergmann 348*67207b96SArnd Bergmann if (!*p) 349*67207b96SArnd Bergmann continue; 350*67207b96SArnd Bergmann 351*67207b96SArnd Bergmann token = match_token(p, spufs_tokens, args); 352*67207b96SArnd Bergmann switch (token) { 353*67207b96SArnd Bergmann case Opt_uid: 354*67207b96SArnd Bergmann if (match_int(&args[0], &option)) 355*67207b96SArnd Bergmann return 0; 356*67207b96SArnd Bergmann root->i_uid = option; 357*67207b96SArnd Bergmann break; 358*67207b96SArnd Bergmann case Opt_gid: 359*67207b96SArnd Bergmann if (match_int(&args[0], &option)) 360*67207b96SArnd Bergmann return 0; 361*67207b96SArnd Bergmann root->i_gid = option; 362*67207b96SArnd Bergmann break; 363*67207b96SArnd Bergmann default: 364*67207b96SArnd Bergmann return 0; 365*67207b96SArnd Bergmann } 366*67207b96SArnd Bergmann } 367*67207b96SArnd Bergmann return 1; 368*67207b96SArnd Bergmann } 369*67207b96SArnd Bergmann 370*67207b96SArnd Bergmann static int 371*67207b96SArnd Bergmann spufs_create_root(struct super_block *sb, void *data) { 372*67207b96SArnd Bergmann struct inode *inode; 373*67207b96SArnd Bergmann int ret; 374*67207b96SArnd Bergmann 375*67207b96SArnd Bergmann ret = -ENOMEM; 376*67207b96SArnd Bergmann inode = spufs_new_inode(sb, S_IFDIR | 0775); 377*67207b96SArnd Bergmann if (!inode) 378*67207b96SArnd Bergmann goto out; 379*67207b96SArnd Bergmann 380*67207b96SArnd Bergmann inode->i_op = &spufs_dir_inode_operations; 381*67207b96SArnd Bergmann inode->i_fop = &simple_dir_operations; 382*67207b96SArnd Bergmann SPUFS_I(inode)->i_ctx = NULL; 383*67207b96SArnd Bergmann 384*67207b96SArnd Bergmann ret = -EINVAL; 385*67207b96SArnd Bergmann if (!spufs_parse_options(data, inode)) 386*67207b96SArnd Bergmann goto out_iput; 387*67207b96SArnd Bergmann 388*67207b96SArnd Bergmann ret = -ENOMEM; 389*67207b96SArnd Bergmann sb->s_root = d_alloc_root(inode); 390*67207b96SArnd Bergmann if (!sb->s_root) 391*67207b96SArnd Bergmann goto out_iput; 392*67207b96SArnd Bergmann 393*67207b96SArnd Bergmann return 0; 394*67207b96SArnd Bergmann out_iput: 395*67207b96SArnd Bergmann iput(inode); 396*67207b96SArnd Bergmann out: 397*67207b96SArnd Bergmann return ret; 398*67207b96SArnd Bergmann } 399*67207b96SArnd Bergmann 400*67207b96SArnd Bergmann static int 401*67207b96SArnd Bergmann spufs_fill_super(struct super_block *sb, void *data, int silent) 402*67207b96SArnd Bergmann { 403*67207b96SArnd Bergmann static struct super_operations s_ops = { 404*67207b96SArnd Bergmann .alloc_inode = spufs_alloc_inode, 405*67207b96SArnd Bergmann .destroy_inode = spufs_destroy_inode, 406*67207b96SArnd Bergmann .statfs = simple_statfs, 407*67207b96SArnd Bergmann .delete_inode = spufs_delete_inode, 408*67207b96SArnd Bergmann .drop_inode = generic_delete_inode, 409*67207b96SArnd Bergmann }; 410*67207b96SArnd Bergmann 411*67207b96SArnd Bergmann sb->s_maxbytes = MAX_LFS_FILESIZE; 412*67207b96SArnd Bergmann sb->s_blocksize = PAGE_CACHE_SIZE; 413*67207b96SArnd Bergmann sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 414*67207b96SArnd Bergmann sb->s_magic = SPUFS_MAGIC; 415*67207b96SArnd Bergmann sb->s_op = &s_ops; 416*67207b96SArnd Bergmann 417*67207b96SArnd Bergmann return spufs_create_root(sb, data); 418*67207b96SArnd Bergmann } 419*67207b96SArnd Bergmann 420*67207b96SArnd Bergmann static struct super_block * 421*67207b96SArnd Bergmann spufs_get_sb(struct file_system_type *fstype, int flags, 422*67207b96SArnd Bergmann const char *name, void *data) 423*67207b96SArnd Bergmann { 424*67207b96SArnd Bergmann return get_sb_single(fstype, flags, data, spufs_fill_super); 425*67207b96SArnd Bergmann } 426*67207b96SArnd Bergmann 427*67207b96SArnd Bergmann static struct file_system_type spufs_type = { 428*67207b96SArnd Bergmann .owner = THIS_MODULE, 429*67207b96SArnd Bergmann .name = "spufs", 430*67207b96SArnd Bergmann .get_sb = spufs_get_sb, 431*67207b96SArnd Bergmann .kill_sb = kill_litter_super, 432*67207b96SArnd Bergmann }; 433*67207b96SArnd Bergmann 434*67207b96SArnd Bergmann static int spufs_init(void) 435*67207b96SArnd Bergmann { 436*67207b96SArnd Bergmann int ret; 437*67207b96SArnd Bergmann ret = -ENOMEM; 438*67207b96SArnd Bergmann spufs_inode_cache = kmem_cache_create("spufs_inode_cache", 439*67207b96SArnd Bergmann sizeof(struct spufs_inode_info), 0, 440*67207b96SArnd Bergmann SLAB_HWCACHE_ALIGN, spufs_init_once, NULL); 441*67207b96SArnd Bergmann 442*67207b96SArnd Bergmann if (!spufs_inode_cache) 443*67207b96SArnd Bergmann goto out; 444*67207b96SArnd Bergmann ret = register_filesystem(&spufs_type); 445*67207b96SArnd Bergmann if (ret) 446*67207b96SArnd Bergmann goto out_cache; 447*67207b96SArnd Bergmann ret = register_spu_syscalls(&spufs_calls); 448*67207b96SArnd Bergmann if (ret) 449*67207b96SArnd Bergmann goto out_fs; 450*67207b96SArnd Bergmann return 0; 451*67207b96SArnd Bergmann out_fs: 452*67207b96SArnd Bergmann unregister_filesystem(&spufs_type); 453*67207b96SArnd Bergmann out_cache: 454*67207b96SArnd Bergmann kmem_cache_destroy(spufs_inode_cache); 455*67207b96SArnd Bergmann out: 456*67207b96SArnd Bergmann return ret; 457*67207b96SArnd Bergmann } 458*67207b96SArnd Bergmann module_init(spufs_init); 459*67207b96SArnd Bergmann 460*67207b96SArnd Bergmann static void spufs_exit(void) 461*67207b96SArnd Bergmann { 462*67207b96SArnd Bergmann unregister_spu_syscalls(&spufs_calls); 463*67207b96SArnd Bergmann unregister_filesystem(&spufs_type); 464*67207b96SArnd Bergmann kmem_cache_destroy(spufs_inode_cache); 465*67207b96SArnd Bergmann } 466*67207b96SArnd Bergmann module_exit(spufs_exit); 467*67207b96SArnd Bergmann 468*67207b96SArnd Bergmann MODULE_LICENSE("GPL"); 469*67207b96SArnd Bergmann MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>"); 470*67207b96SArnd Bergmann 471