Commit 9c07b3b3 authored by Chao Yu's avatar Chao Yu Committed by Greg Kroah-Hartman

staging: erofs: introduce error injection infrastructure

This patch introduces error injection infrastructure, with it, we can
inject error in any kernel exported common functions which erofs used,
so that it can force erofs running into error paths, it turns out that
tests can cover real rare paths more easily to find bugs.
Reviewed-by: default avatarGao Xiang <gaoxiang25@huawei.com>
Signed-off-by: default avatarChao Yu <yuchao0@huawei.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d5beb31b
...@@ -71,3 +71,9 @@ config EROFS_FS_USE_VM_MAP_RAM ...@@ -71,3 +71,9 @@ config EROFS_FS_USE_VM_MAP_RAM
If you don't know what these are, say N. If you don't know what these are, say N.
config EROFS_FAULT_INJECTION
bool "EROFS fault injection facility"
depends on EROFS_FS
help
Test EROFS to inject faults such as ENOMEM, EIO, and so on.
If unsure, say N.
...@@ -113,6 +113,7 @@ static int read_inode(struct inode *inode, void *data) ...@@ -113,6 +113,7 @@ static int read_inode(struct inode *inode, void *data)
static int fill_inline_data(struct inode *inode, void *data, unsigned m_pofs) static int fill_inline_data(struct inode *inode, void *data, unsigned m_pofs)
{ {
struct erofs_vnode *vi = EROFS_V(inode); struct erofs_vnode *vi = EROFS_V(inode);
struct erofs_sb_info *sbi = EROFS_I_SB(inode);
int mode = vi->data_mapping_mode; int mode = vi->data_mapping_mode;
DBG_BUGON(mode >= EROFS_INODE_LAYOUT_MAX); DBG_BUGON(mode >= EROFS_INODE_LAYOUT_MAX);
...@@ -123,7 +124,7 @@ static int fill_inline_data(struct inode *inode, void *data, unsigned m_pofs) ...@@ -123,7 +124,7 @@ static int fill_inline_data(struct inode *inode, void *data, unsigned m_pofs)
/* fast symlink (following ext4) */ /* fast symlink (following ext4) */
if (S_ISLNK(inode->i_mode) && inode->i_size < PAGE_SIZE) { if (S_ISLNK(inode->i_mode) && inode->i_size < PAGE_SIZE) {
char *lnk = kmalloc(inode->i_size + 1, GFP_KERNEL); char *lnk = erofs_kmalloc(sbi, inode->i_size + 1, GFP_KERNEL);
if (unlikely(lnk == NULL)) if (unlikely(lnk == NULL))
return -ENOMEM; return -ENOMEM;
......
...@@ -42,6 +42,22 @@ ...@@ -42,6 +42,22 @@
#define DBG_BUGON(...) ((void)0) #define DBG_BUGON(...) ((void)0)
#endif #endif
#ifdef CONFIG_EROFS_FAULT_INJECTION
enum {
FAULT_KMALLOC,
FAULT_MAX,
};
extern char *erofs_fault_name[FAULT_MAX];
#define IS_FAULT_SET(fi, type) ((fi)->inject_type & (1 << (type)))
struct erofs_fault_info {
atomic_t inject_ops;
unsigned int inject_rate;
unsigned int inject_type;
};
#endif
/* EROFS_SUPER_MAGIC_V1 to represent the whole file system */ /* EROFS_SUPER_MAGIC_V1 to represent the whole file system */
#define EROFS_SUPER_MAGIC EROFS_SUPER_MAGIC_V1 #define EROFS_SUPER_MAGIC EROFS_SUPER_MAGIC_V1
...@@ -70,14 +86,55 @@ struct erofs_sb_info { ...@@ -70,14 +86,55 @@ struct erofs_sb_info {
char *dev_name; char *dev_name;
unsigned int mount_opt; unsigned int mount_opt;
#ifdef CONFIG_EROFS_FAULT_INJECTION
struct erofs_fault_info fault_info; /* For fault injection */
#endif
}; };
#ifdef CONFIG_EROFS_FAULT_INJECTION
#define erofs_show_injection_info(type) \
infoln("inject %s in %s of %pS", erofs_fault_name[type], \
__func__, __builtin_return_address(0))
static inline bool time_to_inject(struct erofs_sb_info *sbi, int type)
{
struct erofs_fault_info *ffi = &sbi->fault_info;
if (!ffi->inject_rate)
return false;
if (!IS_FAULT_SET(ffi, type))
return false;
atomic_inc(&ffi->inject_ops);
if (atomic_read(&ffi->inject_ops) >= ffi->inject_rate) {
atomic_set(&ffi->inject_ops, 0);
return true;
}
return false;
}
#endif
static inline void *erofs_kmalloc(struct erofs_sb_info *sbi,
size_t size, gfp_t flags)
{
#ifdef CONFIG_EROFS_FAULT_INJECTION
if (time_to_inject(sbi, FAULT_KMALLOC)) {
erofs_show_injection_info(FAULT_KMALLOC);
return NULL;
}
#endif
return kmalloc(size, flags);
}
#define EROFS_SB(sb) ((struct erofs_sb_info *)(sb)->s_fs_info) #define EROFS_SB(sb) ((struct erofs_sb_info *)(sb)->s_fs_info)
#define EROFS_I_SB(inode) ((struct erofs_sb_info *)(inode)->i_sb->s_fs_info) #define EROFS_I_SB(inode) ((struct erofs_sb_info *)(inode)->i_sb->s_fs_info)
/* Mount flags set via mount options or defaults */ /* Mount flags set via mount options or defaults */
#define EROFS_MOUNT_XATTR_USER 0x00000010 #define EROFS_MOUNT_XATTR_USER 0x00000010
#define EROFS_MOUNT_POSIX_ACL 0x00000020 #define EROFS_MOUNT_POSIX_ACL 0x00000020
#define EROFS_MOUNT_FAULT_INJECTION 0x00000040
#define clear_opt(sbi, option) ((sbi)->mount_opt &= ~EROFS_MOUNT_##option) #define clear_opt(sbi, option) ((sbi)->mount_opt &= ~EROFS_MOUNT_##option)
#define set_opt(sbi, option) ((sbi)->mount_opt |= EROFS_MOUNT_##option) #define set_opt(sbi, option) ((sbi)->mount_opt |= EROFS_MOUNT_##option)
......
...@@ -129,6 +129,26 @@ static int superblock_read(struct super_block *sb) ...@@ -129,6 +129,26 @@ static int superblock_read(struct super_block *sb)
return ret; return ret;
} }
#ifdef CONFIG_EROFS_FAULT_INJECTION
char *erofs_fault_name[FAULT_MAX] = {
[FAULT_KMALLOC] = "kmalloc",
};
static void erofs_build_fault_attr(struct erofs_sb_info *sbi,
unsigned int rate)
{
struct erofs_fault_info *ffi = &sbi->fault_info;
if (rate) {
atomic_set(&ffi->inject_ops, 0);
ffi->inject_rate = rate;
ffi->inject_type = (1 << FAULT_MAX) - 1;
} else {
memset(ffi, 0, sizeof(struct erofs_fault_info));
}
}
#endif
static void default_options(struct erofs_sb_info *sbi) static void default_options(struct erofs_sb_info *sbi)
{ {
#ifdef CONFIG_EROFS_FS_XATTR #ifdef CONFIG_EROFS_FS_XATTR
...@@ -145,6 +165,7 @@ enum { ...@@ -145,6 +165,7 @@ enum {
Opt_nouser_xattr, Opt_nouser_xattr,
Opt_acl, Opt_acl,
Opt_noacl, Opt_noacl,
Opt_fault_injection,
Opt_err Opt_err
}; };
...@@ -153,6 +174,7 @@ static match_table_t erofs_tokens = { ...@@ -153,6 +174,7 @@ static match_table_t erofs_tokens = {
{Opt_nouser_xattr, "nouser_xattr"}, {Opt_nouser_xattr, "nouser_xattr"},
{Opt_acl, "acl"}, {Opt_acl, "acl"},
{Opt_noacl, "noacl"}, {Opt_noacl, "noacl"},
{Opt_fault_injection, "fault_injection=%u"},
{Opt_err, NULL} {Opt_err, NULL}
}; };
...@@ -160,6 +182,7 @@ static int parse_options(struct super_block *sb, char *options) ...@@ -160,6 +182,7 @@ static int parse_options(struct super_block *sb, char *options)
{ {
substring_t args[MAX_OPT_ARGS]; substring_t args[MAX_OPT_ARGS];
char *p; char *p;
int arg = 0;
if (!options) if (!options)
return 0; return 0;
...@@ -204,6 +227,16 @@ static int parse_options(struct super_block *sb, char *options) ...@@ -204,6 +227,16 @@ static int parse_options(struct super_block *sb, char *options)
infoln("noacl options not supported"); infoln("noacl options not supported");
break; break;
#endif #endif
case Opt_fault_injection:
if (args->from && match_int(args, &arg))
return -EINVAL;
#ifdef CONFIG_EROFS_FAULT_INJECTION
erofs_build_fault_attr(EROFS_SB(sb), arg);
set_opt(EROFS_SB(sb), FAULT_INJECTION);
#else
infoln("FAULT_INJECTION was not selected");
#endif
break;
default: default:
errln("Unrecognized mount option \"%s\" " errln("Unrecognized mount option \"%s\" "
"or missing value", p); "or missing value", p);
...@@ -452,6 +485,11 @@ static int erofs_show_options(struct seq_file *seq, struct dentry *root) ...@@ -452,6 +485,11 @@ static int erofs_show_options(struct seq_file *seq, struct dentry *root)
seq_puts(seq, ",acl"); seq_puts(seq, ",acl");
else else
seq_puts(seq, ",noacl"); seq_puts(seq, ",noacl");
#endif
#ifdef CONFIG_EROFS_FAULT_INJECTION
if (test_opt(sbi, FAULT_INJECTION))
seq_printf(seq, ",fault_injection=%u",
sbi->fault_info.inject_rate);
#endif #endif
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment