linux/arch/powerpc/platforms/cell/spufs/inode.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2
   3/*
   4 * SPU file system
   5 *
   6 * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
   7 *
   8 * Author: Arnd Bergmann <arndb@de.ibm.com>
   9 */
  10
  11#include <linux/file.h>
  12#include <linux/fs.h>
  13#include <linux/fsnotify.h>
  14#include <linux/backing-dev.h>
  15#include <linux/init.h>
  16#include <linux/ioctl.h>
  17#include <linux/module.h>
  18#include <linux/mount.h>
  19#include <linux/namei.h>
  20#include <linux/pagemap.h>
  21#include <linux/poll.h>
  22#include <linux/slab.h>
  23#include <linux/parser.h>
  24
  25#include <asm/prom.h>
  26#include <asm/spu.h>
  27#include <asm/spu_priv1.h>
  28#include <linux/uaccess.h>
  29
  30#include "spufs.h"
  31
  32struct spufs_sb_info {
  33        int debug;
  34};
  35
  36static struct kmem_cache *spufs_inode_cache;
  37char *isolated_loader;
  38static int isolated_loader_size;
  39
  40static struct spufs_sb_info *spufs_get_sb_info(struct super_block *sb)
  41{
  42        return sb->s_fs_info;
  43}
  44
  45static struct inode *
  46spufs_alloc_inode(struct super_block *sb)
  47{
  48        struct spufs_inode_info *ei;
  49
  50        ei = kmem_cache_alloc(spufs_inode_cache, GFP_KERNEL);
  51        if (!ei)
  52                return NULL;
  53
  54        ei->i_gang = NULL;
  55        ei->i_ctx = NULL;
  56        ei->i_openers = 0;
  57
  58        return &ei->vfs_inode;
  59}
  60
  61static void spufs_free_inode(struct inode *inode)
  62{
  63        kmem_cache_free(spufs_inode_cache, SPUFS_I(inode));
  64}
  65
  66static void
  67spufs_init_once(void *p)
  68{
  69        struct spufs_inode_info *ei = p;
  70
  71        inode_init_once(&ei->vfs_inode);
  72}
  73
  74static struct inode *
  75spufs_new_inode(struct super_block *sb, umode_t mode)
  76{
  77        struct inode *inode;
  78
  79        inode = new_inode(sb);
  80        if (!inode)
  81                goto out;
  82
  83        inode->i_ino = get_next_ino();
  84        inode->i_mode = mode;
  85        inode->i_uid = current_fsuid();
  86        inode->i_gid = current_fsgid();
  87        inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
  88out:
  89        return inode;
  90}
  91
  92static int
  93spufs_setattr(struct dentry *dentry, struct iattr *attr)
  94{
  95        struct inode *inode = d_inode(dentry);
  96
  97        if ((attr->ia_valid & ATTR_SIZE) &&
  98            (attr->ia_size != inode->i_size))
  99                return -EINVAL;
 100        setattr_copy(inode, attr);
 101        mark_inode_dirty(inode);
 102        return 0;
 103}
 104
 105
 106static int
 107spufs_new_file(struct super_block *sb, struct dentry *dentry,
 108                const struct file_operations *fops, umode_t mode,
 109                size_t size, struct spu_context *ctx)
 110{
 111        static const struct inode_operations spufs_file_iops = {
 112                .setattr = spufs_setattr,
 113        };
 114        struct inode *inode;
 115        int ret;
 116
 117        ret = -ENOSPC;
 118        inode = spufs_new_inode(sb, S_IFREG | mode);
 119        if (!inode)
 120                goto out;
 121
 122        ret = 0;
 123        inode->i_op = &spufs_file_iops;
 124        inode->i_fop = fops;
 125        inode->i_size = size;
 126        inode->i_private = SPUFS_I(inode)->i_ctx = get_spu_context(ctx);
 127        d_add(dentry, inode);
 128out:
 129        return ret;
 130}
 131
 132static void
 133spufs_evict_inode(struct inode *inode)
 134{
 135        struct spufs_inode_info *ei = SPUFS_I(inode);
 136        clear_inode(inode);
 137        if (ei->i_ctx)
 138                put_spu_context(ei->i_ctx);
 139        if (ei->i_gang)
 140                put_spu_gang(ei->i_gang);
 141}
 142
 143static void spufs_prune_dir(struct dentry *dir)
 144{
 145        struct dentry *dentry, *tmp;
 146
 147        inode_lock(d_inode(dir));
 148        list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child) {
 149                spin_lock(&dentry->d_lock);
 150                if (simple_positive(dentry)) {
 151                        dget_dlock(dentry);
 152                        __d_drop(dentry);
 153                        spin_unlock(&dentry->d_lock);
 154                        simple_unlink(d_inode(dir), dentry);
 155                        /* XXX: what was dcache_lock protecting here? Other
 156                         * filesystems (IB, configfs) release dcache_lock
 157                         * before unlink */
 158                        dput(dentry);
 159                } else {
 160                        spin_unlock(&dentry->d_lock);
 161                }
 162        }
 163        shrink_dcache_parent(dir);
 164        inode_unlock(d_inode(dir));
 165}
 166
 167/* Caller must hold parent->i_mutex */
 168static int spufs_rmdir(struct inode *parent, struct dentry *dir)
 169{
 170        /* remove all entries */
 171        int res;
 172        spufs_prune_dir(dir);
 173        d_drop(dir);
 174        res = simple_rmdir(parent, dir);
 175        /* We have to give up the mm_struct */
 176        spu_forget(SPUFS_I(d_inode(dir))->i_ctx);
 177        return res;
 178}
 179
 180static int spufs_fill_dir(struct dentry *dir,
 181                const struct spufs_tree_descr *files, umode_t mode,
 182                struct spu_context *ctx)
 183{
 184        while (files->name && files->name[0]) {
 185                int ret;
 186                struct dentry *dentry = d_alloc_name(dir, files->name);
 187                if (!dentry)
 188                        return -ENOMEM;
 189                ret = spufs_new_file(dir->d_sb, dentry, files->ops,
 190                                        files->mode & mode, files->size, ctx);
 191                if (ret)
 192                        return ret;
 193                files++;
 194        }
 195        return 0;
 196}
 197
 198static int spufs_dir_close(struct inode *inode, struct file *file)
 199{
 200        struct spu_context *ctx;
 201        struct inode *parent;
 202        struct dentry *dir;
 203        int ret;
 204
 205        dir = file->f_path.dentry;
 206        parent = d_inode(dir->d_parent);
 207        ctx = SPUFS_I(d_inode(dir))->i_ctx;
 208
 209        inode_lock_nested(parent, I_MUTEX_PARENT);
 210        ret = spufs_rmdir(parent, dir);
 211        inode_unlock(parent);
 212        WARN_ON(ret);
 213
 214        return dcache_dir_close(inode, file);
 215}
 216
 217const struct file_operations spufs_context_fops = {
 218        .open           = dcache_dir_open,
 219        .release        = spufs_dir_close,
 220        .llseek         = dcache_dir_lseek,
 221        .read           = generic_read_dir,
 222        .iterate_shared = dcache_readdir,
 223        .fsync          = noop_fsync,
 224};
 225EXPORT_SYMBOL_GPL(spufs_context_fops);
 226
 227static int
 228spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
 229                umode_t mode)
 230{
 231        int ret;
 232        struct inode *inode;
 233        struct spu_context *ctx;
 234
 235        inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR);
 236        if (!inode)
 237                return -ENOSPC;
 238
 239        if (dir->i_mode & S_ISGID) {
 240                inode->i_gid = dir->i_gid;
 241                inode->i_mode &= S_ISGID;
 242        }
 243        ctx = alloc_spu_context(SPUFS_I(dir)->i_gang); /* XXX gang */
 244        SPUFS_I(inode)->i_ctx = ctx;
 245        if (!ctx) {
 246                iput(inode);
 247                return -ENOSPC;
 248        }
 249
 250        ctx->flags = flags;
 251        inode->i_op = &simple_dir_inode_operations;
 252        inode->i_fop = &simple_dir_operations;
 253
 254        inode_lock(inode);
 255
 256        dget(dentry);
 257        inc_nlink(dir);
 258        inc_nlink(inode);
 259
 260        d_instantiate(dentry, inode);
 261
 262        if (flags & SPU_CREATE_NOSCHED)
 263                ret = spufs_fill_dir(dentry, spufs_dir_nosched_contents,
 264                                         mode, ctx);
 265        else
 266                ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx);
 267
 268        if (!ret && spufs_get_sb_info(dir->i_sb)->debug)
 269                ret = spufs_fill_dir(dentry, spufs_dir_debug_contents,
 270                                mode, ctx);
 271
 272        if (ret)
 273                spufs_rmdir(dir, dentry);
 274
 275        inode_unlock(inode);
 276
 277        return ret;
 278}
 279
 280static int spufs_context_open(struct path *path)
 281{
 282        int ret;
 283        struct file *filp;
 284
 285        ret = get_unused_fd_flags(0);
 286        if (ret < 0)
 287                return ret;
 288
 289        filp = dentry_open(path, O_RDONLY, current_cred());
 290        if (IS_ERR(filp)) {
 291                put_unused_fd(ret);
 292                return PTR_ERR(filp);
 293        }
 294
 295        filp->f_op = &spufs_context_fops;
 296        fd_install(ret, filp);
 297        return ret;
 298}
 299
 300static struct spu_context *
 301spufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
 302                                                struct file *filp)
 303{
 304        struct spu_context *tmp, *neighbor, *err;
 305        int count, node;
 306        int aff_supp;
 307
 308        aff_supp = !list_empty(&(list_entry(cbe_spu_info[0].spus.next,
 309                                        struct spu, cbe_list))->aff_list);
 310
 311        if (!aff_supp)
 312                return ERR_PTR(-EINVAL);
 313
 314        if (flags & SPU_CREATE_GANG)
 315                return ERR_PTR(-EINVAL);
 316
 317        if (flags & SPU_CREATE_AFFINITY_MEM &&
 318            gang->aff_ref_ctx &&
 319            gang->aff_ref_ctx->flags & SPU_CREATE_AFFINITY_MEM)
 320                return ERR_PTR(-EEXIST);
 321
 322        if (gang->aff_flags & AFF_MERGED)
 323                return ERR_PTR(-EBUSY);
 324
 325        neighbor = NULL;
 326        if (flags & SPU_CREATE_AFFINITY_SPU) {
 327                if (!filp || filp->f_op != &spufs_context_fops)
 328                        return ERR_PTR(-EINVAL);
 329
 330                neighbor = get_spu_context(
 331                                SPUFS_I(file_inode(filp))->i_ctx);
 332
 333                if (!list_empty(&neighbor->aff_list) && !(neighbor->aff_head) &&
 334                    !list_is_last(&neighbor->aff_list, &gang->aff_list_head) &&
 335                    !list_entry(neighbor->aff_list.next, struct spu_context,
 336                    aff_list)->aff_head) {
 337                        err = ERR_PTR(-EEXIST);
 338                        goto out_put_neighbor;
 339                }
 340
 341                if (gang != neighbor->gang) {
 342                        err = ERR_PTR(-EINVAL);
 343                        goto out_put_neighbor;
 344                }
 345
 346                count = 1;
 347                list_for_each_entry(tmp, &gang->aff_list_head, aff_list)
 348                        count++;
 349                if (list_empty(&neighbor->aff_list))
 350                        count++;
 351
 352                for (node = 0; node < MAX_NUMNODES; node++) {
 353                        if ((cbe_spu_info[node].n_spus - atomic_read(
 354                                &cbe_spu_info[node].reserved_spus)) >= count)
 355                                break;
 356                }
 357
 358                if (node == MAX_NUMNODES) {
 359                        err = ERR_PTR(-EEXIST);
 360                        goto out_put_neighbor;
 361                }
 362        }
 363
 364        return neighbor;
 365
 366out_put_neighbor:
 367        put_spu_context(neighbor);
 368        return err;
 369}
 370
 371static void
 372spufs_set_affinity(unsigned int flags, struct spu_context *ctx,
 373                                        struct spu_context *neighbor)
 374{
 375        if (flags & SPU_CREATE_AFFINITY_MEM)
 376                ctx->gang->aff_ref_ctx = ctx;
 377
 378        if (flags & SPU_CREATE_AFFINITY_SPU) {
 379                if (list_empty(&neighbor->aff_list)) {
 380                        list_add_tail(&neighbor->aff_list,
 381                                &ctx->gang->aff_list_head);
 382                        neighbor->aff_head = 1;
 383                }
 384
 385                if (list_is_last(&neighbor->aff_list, &ctx->gang->aff_list_head)
 386                    || list_entry(neighbor->aff_list.next, struct spu_context,
 387                                                        aff_list)->aff_head) {
 388                        list_add(&ctx->aff_list, &neighbor->aff_list);
 389                } else  {
 390                        list_add_tail(&ctx->aff_list, &neighbor->aff_list);
 391                        if (neighbor->aff_head) {
 392                                neighbor->aff_head = 0;
 393                                ctx->aff_head = 1;
 394                        }
 395                }
 396
 397                if (!ctx->gang->aff_ref_ctx)
 398                        ctx->gang->aff_ref_ctx = ctx;
 399        }
 400}
 401
 402static int
 403spufs_create_context(struct inode *inode, struct dentry *dentry,
 404                        struct vfsmount *mnt, int flags, umode_t mode,
 405                        struct file *aff_filp)
 406{
 407        int ret;
 408        int affinity;
 409        struct spu_gang *gang;
 410        struct spu_context *neighbor;
 411        struct path path = {.mnt = mnt, .dentry = dentry};
 412
 413        if ((flags & SPU_CREATE_NOSCHED) &&
 414            !capable(CAP_SYS_NICE))
 415                return -EPERM;
 416
 417        if ((flags & (SPU_CREATE_NOSCHED | SPU_CREATE_ISOLATE))
 418            == SPU_CREATE_ISOLATE)
 419                return -EINVAL;
 420
 421        if ((flags & SPU_CREATE_ISOLATE) && !isolated_loader)
 422                return -ENODEV;
 423
 424        gang = NULL;
 425        neighbor = NULL;
 426        affinity = flags & (SPU_CREATE_AFFINITY_MEM | SPU_CREATE_AFFINITY_SPU);
 427        if (affinity) {
 428                gang = SPUFS_I(inode)->i_gang;
 429                if (!gang)
 430                        return -EINVAL;
 431                mutex_lock(&gang->aff_mutex);
 432                neighbor = spufs_assert_affinity(flags, gang, aff_filp);
 433                if (IS_ERR(neighbor)) {
 434                        ret = PTR_ERR(neighbor);
 435                        goto out_aff_unlock;
 436                }
 437        }
 438
 439        ret = spufs_mkdir(inode, dentry, flags, mode & 0777);
 440        if (ret)
 441                goto out_aff_unlock;
 442
 443        if (affinity) {
 444                spufs_set_affinity(flags, SPUFS_I(d_inode(dentry))->i_ctx,
 445                                                                neighbor);
 446                if (neighbor)
 447                        put_spu_context(neighbor);
 448        }
 449
 450        ret = spufs_context_open(&path);
 451        if (ret < 0)
 452                WARN_ON(spufs_rmdir(inode, dentry));
 453
 454out_aff_unlock:
 455        if (affinity)
 456                mutex_unlock(&gang->aff_mutex);
 457        return ret;
 458}
 459
 460static int
 461spufs_mkgang(struct inode *dir, struct dentry *dentry, umode_t mode)
 462{
 463        int ret;
 464        struct inode *inode;
 465        struct spu_gang *gang;
 466
 467        ret = -ENOSPC;
 468        inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR);
 469        if (!inode)
 470                goto out;
 471
 472        ret = 0;
 473        if (dir->i_mode & S_ISGID) {
 474                inode->i_gid = dir->i_gid;
 475                inode->i_mode &= S_ISGID;
 476        }
 477        gang = alloc_spu_gang();
 478        SPUFS_I(inode)->i_ctx = NULL;
 479        SPUFS_I(inode)->i_gang = gang;
 480        if (!gang) {
 481                ret = -ENOMEM;
 482                goto out_iput;
 483        }
 484
 485        inode->i_op = &simple_dir_inode_operations;
 486        inode->i_fop = &simple_dir_operations;
 487
 488        d_instantiate(dentry, inode);
 489        inc_nlink(dir);
 490        inc_nlink(d_inode(dentry));
 491        return ret;
 492
 493out_iput:
 494        iput(inode);
 495out:
 496        return ret;
 497}
 498
 499static int spufs_gang_open(struct path *path)
 500{
 501        int ret;
 502        struct file *filp;
 503
 504        ret = get_unused_fd_flags(0);
 505        if (ret < 0)
 506                return ret;
 507
 508        /*
 509         * get references for dget and mntget, will be released
 510         * in error path of *_open().
 511         */
 512        filp = dentry_open(path, O_RDONLY, current_cred());
 513        if (IS_ERR(filp)) {
 514                put_unused_fd(ret);
 515                return PTR_ERR(filp);
 516        }
 517
 518        filp->f_op = &simple_dir_operations;
 519        fd_install(ret, filp);
 520        return ret;
 521}
 522
 523static int spufs_create_gang(struct inode *inode,
 524                        struct dentry *dentry,
 525                        struct vfsmount *mnt, umode_t mode)
 526{
 527        struct path path = {.mnt = mnt, .dentry = dentry};
 528        int ret;
 529
 530        ret = spufs_mkgang(inode, dentry, mode & 0777);
 531        if (!ret) {
 532                ret = spufs_gang_open(&path);
 533                if (ret < 0) {
 534                        int err = simple_rmdir(inode, dentry);
 535                        WARN_ON(err);
 536                }
 537        }
 538        return ret;
 539}
 540
 541
 542static struct file_system_type spufs_type;
 543
 544long spufs_create(struct path *path, struct dentry *dentry,
 545                unsigned int flags, umode_t mode, struct file *filp)
 546{
 547        struct inode *dir = d_inode(path->dentry);
 548        int ret;
 549
 550        /* check if we are on spufs */
 551        if (path->dentry->d_sb->s_type != &spufs_type)
 552                return -EINVAL;
 553
 554        /* don't accept undefined flags */
 555        if (flags & (~SPU_CREATE_FLAG_ALL))
 556                return -EINVAL;
 557
 558        /* only threads can be underneath a gang */
 559        if (path->dentry != path->dentry->d_sb->s_root)
 560                if ((flags & SPU_CREATE_GANG) || !SPUFS_I(dir)->i_gang)
 561                        return -EINVAL;
 562
 563        mode &= ~current_umask();
 564
 565        if (flags & SPU_CREATE_GANG)
 566                ret = spufs_create_gang(dir, dentry, path->mnt, mode);
 567        else
 568                ret = spufs_create_context(dir, dentry, path->mnt, flags, mode,
 569                                            filp);
 570        if (ret >= 0)
 571                fsnotify_mkdir(dir, dentry);
 572
 573        return ret;
 574}
 575
 576/* File system initialization */
 577enum {
 578        Opt_uid, Opt_gid, Opt_mode, Opt_debug, Opt_err,
 579};
 580
 581static const match_table_t spufs_tokens = {
 582        { Opt_uid,   "uid=%d" },
 583        { Opt_gid,   "gid=%d" },
 584        { Opt_mode,  "mode=%o" },
 585        { Opt_debug, "debug" },
 586        { Opt_err,    NULL  },
 587};
 588
 589static int spufs_show_options(struct seq_file *m, struct dentry *root)
 590{
 591        struct spufs_sb_info *sbi = spufs_get_sb_info(root->d_sb);
 592        struct inode *inode = root->d_inode;
 593
 594        if (!uid_eq(inode->i_uid, GLOBAL_ROOT_UID))
 595                seq_printf(m, ",uid=%u",
 596                           from_kuid_munged(&init_user_ns, inode->i_uid));
 597        if (!gid_eq(inode->i_gid, GLOBAL_ROOT_GID))
 598                seq_printf(m, ",gid=%u",
 599                           from_kgid_munged(&init_user_ns, inode->i_gid));
 600        if ((inode->i_mode & S_IALLUGO) != 0775)
 601                seq_printf(m, ",mode=%o", inode->i_mode);
 602        if (sbi->debug)
 603                seq_puts(m, ",debug");
 604        return 0;
 605}
 606
 607static int
 608spufs_parse_options(struct super_block *sb, char *options, struct inode *root)
 609{
 610        char *p;
 611        substring_t args[MAX_OPT_ARGS];
 612
 613        while ((p = strsep(&options, ",")) != NULL) {
 614                int token, option;
 615
 616                if (!*p)
 617                        continue;
 618
 619                token = match_token(p, spufs_tokens, args);
 620                switch (token) {
 621                case Opt_uid:
 622                        if (match_int(&args[0], &option))
 623                                return 0;
 624                        root->i_uid = make_kuid(current_user_ns(), option);
 625                        if (!uid_valid(root->i_uid))
 626                                return 0;
 627                        break;
 628                case Opt_gid:
 629                        if (match_int(&args[0], &option))
 630                                return 0;
 631                        root->i_gid = make_kgid(current_user_ns(), option);
 632                        if (!gid_valid(root->i_gid))
 633                                return 0;
 634                        break;
 635                case Opt_mode:
 636                        if (match_octal(&args[0], &option))
 637                                return 0;
 638                        root->i_mode = option | S_IFDIR;
 639                        break;
 640                case Opt_debug:
 641                        spufs_get_sb_info(sb)->debug = 1;
 642                        break;
 643                default:
 644                        return 0;
 645                }
 646        }
 647        return 1;
 648}
 649
 650static void spufs_exit_isolated_loader(void)
 651{
 652        free_pages((unsigned long) isolated_loader,
 653                        get_order(isolated_loader_size));
 654}
 655
 656static void
 657spufs_init_isolated_loader(void)
 658{
 659        struct device_node *dn;
 660        const char *loader;
 661        int size;
 662
 663        dn = of_find_node_by_path("/spu-isolation");
 664        if (!dn)
 665                return;
 666
 667        loader = of_get_property(dn, "loader", &size);
 668        if (!loader)
 669                return;
 670
 671        /* the loader must be align on a 16 byte boundary */
 672        isolated_loader = (char *)__get_free_pages(GFP_KERNEL, get_order(size));
 673        if (!isolated_loader)
 674                return;
 675
 676        isolated_loader_size = size;
 677        memcpy(isolated_loader, loader, size);
 678        printk(KERN_INFO "spufs: SPU isolation mode enabled\n");
 679}
 680
 681static int
 682spufs_create_root(struct super_block *sb, void *data)
 683{
 684        struct inode *inode;
 685        int ret;
 686
 687        ret = -ENODEV;
 688        if (!spu_management_ops)
 689                goto out;
 690
 691        ret = -ENOMEM;
 692        inode = spufs_new_inode(sb, S_IFDIR | 0775);
 693        if (!inode)
 694                goto out;
 695
 696        inode->i_op = &simple_dir_inode_operations;
 697        inode->i_fop = &simple_dir_operations;
 698        SPUFS_I(inode)->i_ctx = NULL;
 699        inc_nlink(inode);
 700
 701        ret = -EINVAL;
 702        if (!spufs_parse_options(sb, data, inode))
 703                goto out_iput;
 704
 705        ret = -ENOMEM;
 706        sb->s_root = d_make_root(inode);
 707        if (!sb->s_root)
 708                goto out;
 709
 710        return 0;
 711out_iput:
 712        iput(inode);
 713out:
 714        return ret;
 715}
 716
 717static int
 718spufs_fill_super(struct super_block *sb, void *data, int silent)
 719{
 720        struct spufs_sb_info *info;
 721        static const struct super_operations s_ops = {
 722                .alloc_inode = spufs_alloc_inode,
 723                .free_inode = spufs_free_inode,
 724                .statfs = simple_statfs,
 725                .evict_inode = spufs_evict_inode,
 726                .show_options = spufs_show_options,
 727        };
 728
 729        info = kzalloc(sizeof(*info), GFP_KERNEL);
 730        if (!info)
 731                return -ENOMEM;
 732
 733        sb->s_maxbytes = MAX_LFS_FILESIZE;
 734        sb->s_blocksize = PAGE_SIZE;
 735        sb->s_blocksize_bits = PAGE_SHIFT;
 736        sb->s_magic = SPUFS_MAGIC;
 737        sb->s_op = &s_ops;
 738        sb->s_fs_info = info;
 739
 740        return spufs_create_root(sb, data);
 741}
 742
 743static struct dentry *
 744spufs_mount(struct file_system_type *fstype, int flags,
 745                const char *name, void *data)
 746{
 747        return mount_single(fstype, flags, data, spufs_fill_super);
 748}
 749
 750static struct file_system_type spufs_type = {
 751        .owner = THIS_MODULE,
 752        .name = "spufs",
 753        .mount = spufs_mount,
 754        .kill_sb = kill_litter_super,
 755};
 756MODULE_ALIAS_FS("spufs");
 757
 758static int __init spufs_init(void)
 759{
 760        int ret;
 761
 762        ret = -ENODEV;
 763        if (!spu_management_ops)
 764                goto out;
 765
 766        ret = -ENOMEM;
 767        spufs_inode_cache = kmem_cache_create("spufs_inode_cache",
 768                        sizeof(struct spufs_inode_info), 0,
 769                        SLAB_HWCACHE_ALIGN|SLAB_ACCOUNT, spufs_init_once);
 770
 771        if (!spufs_inode_cache)
 772                goto out;
 773        ret = spu_sched_init();
 774        if (ret)
 775                goto out_cache;
 776        ret = register_spu_syscalls(&spufs_calls);
 777        if (ret)
 778                goto out_sched;
 779        ret = register_filesystem(&spufs_type);
 780        if (ret)
 781                goto out_syscalls;
 782
 783        spufs_init_isolated_loader();
 784
 785        return 0;
 786
 787out_syscalls:
 788        unregister_spu_syscalls(&spufs_calls);
 789out_sched:
 790        spu_sched_exit();
 791out_cache:
 792        kmem_cache_destroy(spufs_inode_cache);
 793out:
 794        return ret;
 795}
 796module_init(spufs_init);
 797
 798static void __exit spufs_exit(void)
 799{
 800        spu_sched_exit();
 801        spufs_exit_isolated_loader();
 802        unregister_spu_syscalls(&spufs_calls);
 803        unregister_filesystem(&spufs_type);
 804        kmem_cache_destroy(spufs_inode_cache);
 805}
 806module_exit(spufs_exit);
 807
 808MODULE_LICENSE("GPL");
 809MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>");
 810
 811