| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | |
|---|
| 2 | 3 | /* |
|---|
| 3 | 4 | * SPU file system |
|---|
| .. | .. |
|---|
| 5 | 6 | * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 |
|---|
| 6 | 7 | * |
|---|
| 7 | 8 | * Author: Arnd Bergmann <arndb@de.ibm.com> |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 10 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 11 | | - * the Free Software Foundation; either version 2, or (at your option) |
|---|
| 12 | | - * any later version. |
|---|
| 13 | | - * |
|---|
| 14 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 15 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 16 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 17 | | - * GNU General Public License for more details. |
|---|
| 18 | | - * |
|---|
| 19 | | - * You should have received a copy of the GNU General Public License |
|---|
| 20 | | - * along with this program; if not, write to the Free Software |
|---|
| 21 | | - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|---|
| 22 | 9 | */ |
|---|
| 23 | 10 | |
|---|
| 24 | 11 | #include <linux/file.h> |
|---|
| 25 | 12 | #include <linux/fs.h> |
|---|
| 13 | +#include <linux/fs_context.h> |
|---|
| 14 | +#include <linux/fs_parser.h> |
|---|
| 26 | 15 | #include <linux/fsnotify.h> |
|---|
| 27 | 16 | #include <linux/backing-dev.h> |
|---|
| 28 | 17 | #include <linux/init.h> |
|---|
| .. | .. |
|---|
| 33 | 22 | #include <linux/pagemap.h> |
|---|
| 34 | 23 | #include <linux/poll.h> |
|---|
| 35 | 24 | #include <linux/slab.h> |
|---|
| 36 | | -#include <linux/parser.h> |
|---|
| 37 | 25 | |
|---|
| 38 | 26 | #include <asm/prom.h> |
|---|
| 39 | 27 | #include <asm/spu.h> |
|---|
| .. | .. |
|---|
| 43 | 31 | #include "spufs.h" |
|---|
| 44 | 32 | |
|---|
| 45 | 33 | struct spufs_sb_info { |
|---|
| 46 | | - int debug; |
|---|
| 34 | + bool debug; |
|---|
| 47 | 35 | }; |
|---|
| 48 | 36 | |
|---|
| 49 | 37 | static struct kmem_cache *spufs_inode_cache; |
|---|
| .. | .. |
|---|
| 71 | 59 | return &ei->vfs_inode; |
|---|
| 72 | 60 | } |
|---|
| 73 | 61 | |
|---|
| 74 | | -static void spufs_i_callback(struct rcu_head *head) |
|---|
| 62 | +static void spufs_free_inode(struct inode *inode) |
|---|
| 75 | 63 | { |
|---|
| 76 | | - struct inode *inode = container_of(head, struct inode, i_rcu); |
|---|
| 77 | 64 | kmem_cache_free(spufs_inode_cache, SPUFS_I(inode)); |
|---|
| 78 | | -} |
|---|
| 79 | | - |
|---|
| 80 | | -static void spufs_destroy_inode(struct inode *inode) |
|---|
| 81 | | -{ |
|---|
| 82 | | - call_rcu(&inode->i_rcu, spufs_i_callback); |
|---|
| 83 | 65 | } |
|---|
| 84 | 66 | |
|---|
| 85 | 67 | static void |
|---|
| .. | .. |
|---|
| 216 | 198 | |
|---|
| 217 | 199 | static int spufs_dir_close(struct inode *inode, struct file *file) |
|---|
| 218 | 200 | { |
|---|
| 219 | | - struct spu_context *ctx; |
|---|
| 220 | 201 | struct inode *parent; |
|---|
| 221 | 202 | struct dentry *dir; |
|---|
| 222 | 203 | int ret; |
|---|
| 223 | 204 | |
|---|
| 224 | 205 | dir = file->f_path.dentry; |
|---|
| 225 | 206 | parent = d_inode(dir->d_parent); |
|---|
| 226 | | - ctx = SPUFS_I(d_inode(dir))->i_ctx; |
|---|
| 227 | 207 | |
|---|
| 228 | 208 | inode_lock_nested(parent, I_MUTEX_PARENT); |
|---|
| 229 | 209 | ret = spufs_rmdir(parent, dir); |
|---|
| .. | .. |
|---|
| 593 | 573 | } |
|---|
| 594 | 574 | |
|---|
| 595 | 575 | /* File system initialization */ |
|---|
| 596 | | -enum { |
|---|
| 597 | | - Opt_uid, Opt_gid, Opt_mode, Opt_debug, Opt_err, |
|---|
| 576 | +struct spufs_fs_context { |
|---|
| 577 | + kuid_t uid; |
|---|
| 578 | + kgid_t gid; |
|---|
| 579 | + umode_t mode; |
|---|
| 598 | 580 | }; |
|---|
| 599 | 581 | |
|---|
| 600 | | -static const match_table_t spufs_tokens = { |
|---|
| 601 | | - { Opt_uid, "uid=%d" }, |
|---|
| 602 | | - { Opt_gid, "gid=%d" }, |
|---|
| 603 | | - { Opt_mode, "mode=%o" }, |
|---|
| 604 | | - { Opt_debug, "debug" }, |
|---|
| 605 | | - { Opt_err, NULL }, |
|---|
| 582 | +enum { |
|---|
| 583 | + Opt_uid, Opt_gid, Opt_mode, Opt_debug, |
|---|
| 584 | +}; |
|---|
| 585 | + |
|---|
| 586 | +static const struct fs_parameter_spec spufs_fs_parameters[] = { |
|---|
| 587 | + fsparam_u32 ("gid", Opt_gid), |
|---|
| 588 | + fsparam_u32oct ("mode", Opt_mode), |
|---|
| 589 | + fsparam_u32 ("uid", Opt_uid), |
|---|
| 590 | + fsparam_flag ("debug", Opt_debug), |
|---|
| 591 | + {} |
|---|
| 606 | 592 | }; |
|---|
| 607 | 593 | |
|---|
| 608 | 594 | static int spufs_show_options(struct seq_file *m, struct dentry *root) |
|---|
| .. | .. |
|---|
| 623 | 609 | return 0; |
|---|
| 624 | 610 | } |
|---|
| 625 | 611 | |
|---|
| 626 | | -static int |
|---|
| 627 | | -spufs_parse_options(struct super_block *sb, char *options, struct inode *root) |
|---|
| 612 | +static int spufs_parse_param(struct fs_context *fc, struct fs_parameter *param) |
|---|
| 628 | 613 | { |
|---|
| 629 | | - char *p; |
|---|
| 630 | | - substring_t args[MAX_OPT_ARGS]; |
|---|
| 614 | + struct spufs_fs_context *ctx = fc->fs_private; |
|---|
| 615 | + struct spufs_sb_info *sbi = fc->s_fs_info; |
|---|
| 616 | + struct fs_parse_result result; |
|---|
| 617 | + kuid_t uid; |
|---|
| 618 | + kgid_t gid; |
|---|
| 619 | + int opt; |
|---|
| 631 | 620 | |
|---|
| 632 | | - while ((p = strsep(&options, ",")) != NULL) { |
|---|
| 633 | | - int token, option; |
|---|
| 621 | + opt = fs_parse(fc, spufs_fs_parameters, param, &result); |
|---|
| 622 | + if (opt < 0) |
|---|
| 623 | + return opt; |
|---|
| 634 | 624 | |
|---|
| 635 | | - if (!*p) |
|---|
| 636 | | - continue; |
|---|
| 637 | | - |
|---|
| 638 | | - token = match_token(p, spufs_tokens, args); |
|---|
| 639 | | - switch (token) { |
|---|
| 640 | | - case Opt_uid: |
|---|
| 641 | | - if (match_int(&args[0], &option)) |
|---|
| 642 | | - return 0; |
|---|
| 643 | | - root->i_uid = make_kuid(current_user_ns(), option); |
|---|
| 644 | | - if (!uid_valid(root->i_uid)) |
|---|
| 645 | | - return 0; |
|---|
| 646 | | - break; |
|---|
| 647 | | - case Opt_gid: |
|---|
| 648 | | - if (match_int(&args[0], &option)) |
|---|
| 649 | | - return 0; |
|---|
| 650 | | - root->i_gid = make_kgid(current_user_ns(), option); |
|---|
| 651 | | - if (!gid_valid(root->i_gid)) |
|---|
| 652 | | - return 0; |
|---|
| 653 | | - break; |
|---|
| 654 | | - case Opt_mode: |
|---|
| 655 | | - if (match_octal(&args[0], &option)) |
|---|
| 656 | | - return 0; |
|---|
| 657 | | - root->i_mode = option | S_IFDIR; |
|---|
| 658 | | - break; |
|---|
| 659 | | - case Opt_debug: |
|---|
| 660 | | - spufs_get_sb_info(sb)->debug = 1; |
|---|
| 661 | | - break; |
|---|
| 662 | | - default: |
|---|
| 663 | | - return 0; |
|---|
| 664 | | - } |
|---|
| 625 | + switch (opt) { |
|---|
| 626 | + case Opt_uid: |
|---|
| 627 | + uid = make_kuid(current_user_ns(), result.uint_32); |
|---|
| 628 | + if (!uid_valid(uid)) |
|---|
| 629 | + return invalf(fc, "Unknown uid"); |
|---|
| 630 | + ctx->uid = uid; |
|---|
| 631 | + break; |
|---|
| 632 | + case Opt_gid: |
|---|
| 633 | + gid = make_kgid(current_user_ns(), result.uint_32); |
|---|
| 634 | + if (!gid_valid(gid)) |
|---|
| 635 | + return invalf(fc, "Unknown gid"); |
|---|
| 636 | + ctx->gid = gid; |
|---|
| 637 | + break; |
|---|
| 638 | + case Opt_mode: |
|---|
| 639 | + ctx->mode = result.uint_32 & S_IALLUGO; |
|---|
| 640 | + break; |
|---|
| 641 | + case Opt_debug: |
|---|
| 642 | + sbi->debug = true; |
|---|
| 643 | + break; |
|---|
| 665 | 644 | } |
|---|
| 666 | | - return 1; |
|---|
| 645 | + |
|---|
| 646 | + return 0; |
|---|
| 667 | 647 | } |
|---|
| 668 | 648 | |
|---|
| 669 | 649 | static void spufs_exit_isolated_loader(void) |
|---|
| .. | .. |
|---|
| 684 | 664 | return; |
|---|
| 685 | 665 | |
|---|
| 686 | 666 | loader = of_get_property(dn, "loader", &size); |
|---|
| 667 | + of_node_put(dn); |
|---|
| 687 | 668 | if (!loader) |
|---|
| 688 | 669 | return; |
|---|
| 689 | 670 | |
|---|
| .. | .. |
|---|
| 697 | 678 | printk(KERN_INFO "spufs: SPU isolation mode enabled\n"); |
|---|
| 698 | 679 | } |
|---|
| 699 | 680 | |
|---|
| 700 | | -static int |
|---|
| 701 | | -spufs_create_root(struct super_block *sb, void *data) |
|---|
| 681 | +static int spufs_create_root(struct super_block *sb, struct fs_context *fc) |
|---|
| 702 | 682 | { |
|---|
| 683 | + struct spufs_fs_context *ctx = fc->fs_private; |
|---|
| 703 | 684 | struct inode *inode; |
|---|
| 704 | | - int ret; |
|---|
| 705 | 685 | |
|---|
| 706 | | - ret = -ENODEV; |
|---|
| 707 | 686 | if (!spu_management_ops) |
|---|
| 708 | | - goto out; |
|---|
| 687 | + return -ENODEV; |
|---|
| 709 | 688 | |
|---|
| 710 | | - ret = -ENOMEM; |
|---|
| 711 | | - inode = spufs_new_inode(sb, S_IFDIR | 0775); |
|---|
| 689 | + inode = spufs_new_inode(sb, S_IFDIR | ctx->mode); |
|---|
| 712 | 690 | if (!inode) |
|---|
| 713 | | - goto out; |
|---|
| 691 | + return -ENOMEM; |
|---|
| 714 | 692 | |
|---|
| 693 | + inode->i_uid = ctx->uid; |
|---|
| 694 | + inode->i_gid = ctx->gid; |
|---|
| 715 | 695 | inode->i_op = &simple_dir_inode_operations; |
|---|
| 716 | 696 | inode->i_fop = &simple_dir_operations; |
|---|
| 717 | 697 | SPUFS_I(inode)->i_ctx = NULL; |
|---|
| 718 | 698 | inc_nlink(inode); |
|---|
| 719 | 699 | |
|---|
| 720 | | - ret = -EINVAL; |
|---|
| 721 | | - if (!spufs_parse_options(sb, data, inode)) |
|---|
| 722 | | - goto out_iput; |
|---|
| 723 | | - |
|---|
| 724 | | - ret = -ENOMEM; |
|---|
| 725 | 700 | sb->s_root = d_make_root(inode); |
|---|
| 726 | 701 | if (!sb->s_root) |
|---|
| 727 | | - goto out; |
|---|
| 728 | | - |
|---|
| 702 | + return -ENOMEM; |
|---|
| 729 | 703 | return 0; |
|---|
| 730 | | -out_iput: |
|---|
| 731 | | - iput(inode); |
|---|
| 732 | | -out: |
|---|
| 733 | | - return ret; |
|---|
| 734 | 704 | } |
|---|
| 735 | 705 | |
|---|
| 736 | | -static int |
|---|
| 737 | | -spufs_fill_super(struct super_block *sb, void *data, int silent) |
|---|
| 706 | +static const struct super_operations spufs_ops = { |
|---|
| 707 | + .alloc_inode = spufs_alloc_inode, |
|---|
| 708 | + .free_inode = spufs_free_inode, |
|---|
| 709 | + .statfs = simple_statfs, |
|---|
| 710 | + .evict_inode = spufs_evict_inode, |
|---|
| 711 | + .show_options = spufs_show_options, |
|---|
| 712 | +}; |
|---|
| 713 | + |
|---|
| 714 | +static int spufs_fill_super(struct super_block *sb, struct fs_context *fc) |
|---|
| 738 | 715 | { |
|---|
| 739 | | - struct spufs_sb_info *info; |
|---|
| 740 | | - static const struct super_operations s_ops = { |
|---|
| 741 | | - .alloc_inode = spufs_alloc_inode, |
|---|
| 742 | | - .destroy_inode = spufs_destroy_inode, |
|---|
| 743 | | - .statfs = simple_statfs, |
|---|
| 744 | | - .evict_inode = spufs_evict_inode, |
|---|
| 745 | | - .show_options = spufs_show_options, |
|---|
| 746 | | - }; |
|---|
| 747 | | - |
|---|
| 748 | | - info = kzalloc(sizeof(*info), GFP_KERNEL); |
|---|
| 749 | | - if (!info) |
|---|
| 750 | | - return -ENOMEM; |
|---|
| 751 | | - |
|---|
| 752 | 716 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
|---|
| 753 | 717 | sb->s_blocksize = PAGE_SIZE; |
|---|
| 754 | 718 | sb->s_blocksize_bits = PAGE_SHIFT; |
|---|
| 755 | 719 | sb->s_magic = SPUFS_MAGIC; |
|---|
| 756 | | - sb->s_op = &s_ops; |
|---|
| 757 | | - sb->s_fs_info = info; |
|---|
| 720 | + sb->s_op = &spufs_ops; |
|---|
| 758 | 721 | |
|---|
| 759 | | - return spufs_create_root(sb, data); |
|---|
| 722 | + return spufs_create_root(sb, fc); |
|---|
| 760 | 723 | } |
|---|
| 761 | 724 | |
|---|
| 762 | | -static struct dentry * |
|---|
| 763 | | -spufs_mount(struct file_system_type *fstype, int flags, |
|---|
| 764 | | - const char *name, void *data) |
|---|
| 725 | +static int spufs_get_tree(struct fs_context *fc) |
|---|
| 765 | 726 | { |
|---|
| 766 | | - return mount_single(fstype, flags, data, spufs_fill_super); |
|---|
| 727 | + return get_tree_single(fc, spufs_fill_super); |
|---|
| 728 | +} |
|---|
| 729 | + |
|---|
| 730 | +static void spufs_free_fc(struct fs_context *fc) |
|---|
| 731 | +{ |
|---|
| 732 | + kfree(fc->s_fs_info); |
|---|
| 733 | +} |
|---|
| 734 | + |
|---|
| 735 | +static const struct fs_context_operations spufs_context_ops = { |
|---|
| 736 | + .free = spufs_free_fc, |
|---|
| 737 | + .parse_param = spufs_parse_param, |
|---|
| 738 | + .get_tree = spufs_get_tree, |
|---|
| 739 | +}; |
|---|
| 740 | + |
|---|
| 741 | +static int spufs_init_fs_context(struct fs_context *fc) |
|---|
| 742 | +{ |
|---|
| 743 | + struct spufs_fs_context *ctx; |
|---|
| 744 | + struct spufs_sb_info *sbi; |
|---|
| 745 | + |
|---|
| 746 | + ctx = kzalloc(sizeof(struct spufs_fs_context), GFP_KERNEL); |
|---|
| 747 | + if (!ctx) |
|---|
| 748 | + goto nomem; |
|---|
| 749 | + |
|---|
| 750 | + sbi = kzalloc(sizeof(struct spufs_sb_info), GFP_KERNEL); |
|---|
| 751 | + if (!sbi) |
|---|
| 752 | + goto nomem_ctx; |
|---|
| 753 | + |
|---|
| 754 | + ctx->uid = current_uid(); |
|---|
| 755 | + ctx->gid = current_gid(); |
|---|
| 756 | + ctx->mode = 0755; |
|---|
| 757 | + |
|---|
| 758 | + fc->fs_private = ctx; |
|---|
| 759 | + fc->s_fs_info = sbi; |
|---|
| 760 | + fc->ops = &spufs_context_ops; |
|---|
| 761 | + return 0; |
|---|
| 762 | + |
|---|
| 763 | +nomem_ctx: |
|---|
| 764 | + kfree(ctx); |
|---|
| 765 | +nomem: |
|---|
| 766 | + return -ENOMEM; |
|---|
| 767 | 767 | } |
|---|
| 768 | 768 | |
|---|
| 769 | 769 | static struct file_system_type spufs_type = { |
|---|
| 770 | 770 | .owner = THIS_MODULE, |
|---|
| 771 | 771 | .name = "spufs", |
|---|
| 772 | | - .mount = spufs_mount, |
|---|
| 772 | + .init_fs_context = spufs_init_fs_context, |
|---|
| 773 | + .parameters = spufs_fs_parameters, |
|---|
| 773 | 774 | .kill_sb = kill_litter_super, |
|---|
| 774 | 775 | }; |
|---|
| 775 | 776 | MODULE_ALIAS_FS("spufs"); |
|---|