Merge tag 'for-5.14/io_uring-2021-06-30' of git://git.kernel.dk/linux-block
[linux-2.6-microblaze.git] / fs / squashfs / super.c
index 88cc94b..60d6951 100644 (file)
 
 #include <linux/fs.h>
 #include <linux/fs_context.h>
+#include <linux/fs_parser.h>
 #include <linux/vfs.h>
 #include <linux/slab.h>
 #include <linux/mutex.h>
+#include <linux/seq_file.h>
 #include <linux/pagemap.h>
 #include <linux/init.h>
 #include <linux/module.h>
 static struct file_system_type squashfs_fs_type;
 static const struct super_operations squashfs_super_ops;
 
+enum Opt_errors {
+       Opt_errors_continue,
+       Opt_errors_panic,
+};
+
+enum squashfs_param {
+       Opt_errors,
+};
+
+struct squashfs_mount_opts {
+       enum Opt_errors errors;
+};
+
+static const struct constant_table squashfs_param_errors[] = {
+       {"continue",   Opt_errors_continue },
+       {"panic",      Opt_errors_panic },
+       {}
+};
+
+static const struct fs_parameter_spec squashfs_fs_parameters[] = {
+       fsparam_enum("errors", Opt_errors, squashfs_param_errors),
+       {}
+};
+
+static int squashfs_parse_param(struct fs_context *fc, struct fs_parameter *param)
+{
+       struct squashfs_mount_opts *opts = fc->fs_private;
+       struct fs_parse_result result;
+       int opt;
+
+       opt = fs_parse(fc, squashfs_fs_parameters, param, &result);
+       if (opt < 0)
+               return opt;
+
+       switch (opt) {
+       case Opt_errors:
+               opts->errors = result.uint_32;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static const struct squashfs_decompressor *supported_squashfs_filesystem(
        struct fs_context *fc,
        short major, short minor, short id)
@@ -67,6 +114,7 @@ static const struct squashfs_decompressor *supported_squashfs_filesystem(
 
 static int squashfs_fill_super(struct super_block *sb, struct fs_context *fc)
 {
+       struct squashfs_mount_opts *opts = fc->fs_private;
        struct squashfs_sb_info *msblk;
        struct squashfs_super_block *sblk = NULL;
        struct inode *root;
@@ -85,6 +133,8 @@ static int squashfs_fill_super(struct super_block *sb, struct fs_context *fc)
        }
        msblk = sb->s_fs_info;
 
+       msblk->panic_on_errors = (opts->errors == Opt_errors_panic);
+
        msblk->devblksize = sb_min_blocksize(sb, SQUASHFS_DEVBLK_SIZE);
        msblk->devblksize_log2 = ffz(~msblk->devblksize);
 
@@ -350,18 +400,52 @@ static int squashfs_get_tree(struct fs_context *fc)
 
 static int squashfs_reconfigure(struct fs_context *fc)
 {
+       struct super_block *sb = fc->root->d_sb;
+       struct squashfs_sb_info *msblk = sb->s_fs_info;
+       struct squashfs_mount_opts *opts = fc->fs_private;
+
        sync_filesystem(fc->root->d_sb);
        fc->sb_flags |= SB_RDONLY;
+
+       msblk->panic_on_errors = (opts->errors == Opt_errors_panic);
+
        return 0;
 }
 
+static void squashfs_free_fs_context(struct fs_context *fc)
+{
+       kfree(fc->fs_private);
+}
+
 static const struct fs_context_operations squashfs_context_ops = {
        .get_tree       = squashfs_get_tree,
+       .free           = squashfs_free_fs_context,
+       .parse_param    = squashfs_parse_param,
        .reconfigure    = squashfs_reconfigure,
 };
 
+static int squashfs_show_options(struct seq_file *s, struct dentry *root)
+{
+       struct super_block *sb = root->d_sb;
+       struct squashfs_sb_info *msblk = sb->s_fs_info;
+
+       if (msblk->panic_on_errors)
+               seq_puts(s, ",errors=panic");
+       else
+               seq_puts(s, ",errors=continue");
+
+       return 0;
+}
+
 static int squashfs_init_fs_context(struct fs_context *fc)
 {
+       struct squashfs_mount_opts *opts;
+
+       opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+       if (!opts)
+               return -ENOMEM;
+
+       fc->fs_private = opts;
        fc->ops = &squashfs_context_ops;
        return 0;
 }
@@ -481,6 +565,7 @@ static struct file_system_type squashfs_fs_type = {
        .owner = THIS_MODULE,
        .name = "squashfs",
        .init_fs_context = squashfs_init_fs_context,
+       .parameters = squashfs_fs_parameters,
        .kill_sb = kill_block_super,
        .fs_flags = FS_REQUIRES_DEV
 };
@@ -491,6 +576,7 @@ static const struct super_operations squashfs_super_ops = {
        .free_inode = squashfs_free_inode,
        .statfs = squashfs_statfs,
        .put_super = squashfs_put_super,
+       .show_options = squashfs_show_options,
 };
 
 module_init(init_squashfs_fs);