.. | .. |
---|
| 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"); |
---|