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