squashfs: add option to panic on errors
Add an errors=panic mount option to make squashfs trigger a panic when errors are encountered, similar to several other filesystems. This allows a kernel dump to be saved using which the corruption can be analysed and debugged. Inspired by a pre-fs_context patch by Anton Eliasson. Link: https://lkml.kernel.org/r/20210527125019.14511-1-vincent.whitchurch@axis.com Signed-off-by: Vincent Whitchurch <vincent.whitchurch@axis.com> Signed-off-by: Phillip Lougher <phillip@squashfs.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
d98e4d9541
commit
10dde05b89
@ -226,8 +226,11 @@ out_free_bio:
|
||||
bio_free_pages(bio);
|
||||
bio_put(bio);
|
||||
out:
|
||||
if (res < 0)
|
||||
if (res < 0) {
|
||||
ERROR("Failed to read block 0x%llx: %d\n", index, res);
|
||||
if (msblk->panic_on_errors)
|
||||
panic("squashfs read failed");
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -65,5 +65,6 @@ struct squashfs_sb_info {
|
||||
unsigned int fragments;
|
||||
int xattr_ids;
|
||||
unsigned int ids;
|
||||
bool panic_on_errors;
|
||||
};
|
||||
#endif
|
||||
|
@ -18,9 +18,11 @@
|
||||
|
||||
#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>
|
||||
@ -37,6 +39,51 @@
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user