Commit 32410577 authored by Chao Yu's avatar Chao Yu Committed by Jaegeuk Kim

f2fs: support fault injection for f2fs_kmem_cache_alloc()

This patch supports to inject fault into f2fs_kmem_cache_alloc().

Usage:
a) echo 32768 > /sys/fs/f2fs/<dev>/inject_type or
b) mount -o fault_type=32768 <dev> <mountpoint>
Signed-off-by: default avatarChao Yu <chao@kernel.org>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent 4a4fc043
...@@ -195,6 +195,7 @@ fault_type=%d Support configuring fault injection type, should be ...@@ -195,6 +195,7 @@ fault_type=%d Support configuring fault injection type, should be
FAULT_CHECKPOINT 0x000001000 FAULT_CHECKPOINT 0x000001000
FAULT_DISCARD 0x000002000 FAULT_DISCARD 0x000002000
FAULT_WRITE_IO 0x000004000 FAULT_WRITE_IO 0x000004000
FAULT_SLAB_ALLOC 0x000008000
=================== =========== =================== ===========
mode=%s Control block allocation mode which supports "adaptive" mode=%s Control block allocation mode which supports "adaptive"
and "lfs". In "lfs" mode, there should be no random and "lfs". In "lfs" mode, there should be no random
......
...@@ -475,7 +475,8 @@ static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, ...@@ -475,7 +475,8 @@ static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino,
retry: retry:
if (!e) if (!e)
new = f2fs_kmem_cache_alloc(ino_entry_slab, GFP_NOFS); new = f2fs_kmem_cache_alloc(ino_entry_slab,
GFP_NOFS, true, NULL);
radix_tree_preload(GFP_NOFS | __GFP_NOFAIL); radix_tree_preload(GFP_NOFS | __GFP_NOFAIL);
......
...@@ -28,7 +28,8 @@ static void *page_array_alloc(struct inode *inode, int nr) ...@@ -28,7 +28,8 @@ static void *page_array_alloc(struct inode *inode, int nr)
unsigned int size = sizeof(struct page *) * nr; unsigned int size = sizeof(struct page *) * nr;
if (likely(size <= sbi->page_array_slab_size)) if (likely(size <= sbi->page_array_slab_size))
return kmem_cache_zalloc(sbi->page_array_slab, GFP_NOFS); return f2fs_kmem_cache_alloc(sbi->page_array_slab,
GFP_F2FS_ZERO, false, F2FS_I_SB(inode));
return f2fs_kzalloc(sbi, size, GFP_NOFS); return f2fs_kzalloc(sbi, size, GFP_NOFS);
} }
...@@ -1228,7 +1229,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc, ...@@ -1228,7 +1229,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
fio.version = ni.version; fio.version = ni.version;
cic = kmem_cache_zalloc(cic_entry_slab, GFP_NOFS); cic = f2fs_kmem_cache_alloc(cic_entry_slab, GFP_F2FS_ZERO, false, sbi);
if (!cic) if (!cic)
goto out_put_dnode; goto out_put_dnode;
...@@ -1506,7 +1507,8 @@ struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc) ...@@ -1506,7 +1507,8 @@ struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc)
pgoff_t start_idx = start_idx_of_cluster(cc); pgoff_t start_idx = start_idx_of_cluster(cc);
int i; int i;
dic = kmem_cache_zalloc(dic_entry_slab, GFP_NOFS); dic = f2fs_kmem_cache_alloc(dic_entry_slab, GFP_F2FS_ZERO,
false, F2FS_I_SB(cc->inode));
if (!dic) if (!dic)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
......
...@@ -724,7 +724,7 @@ static void add_bio_entry(struct f2fs_sb_info *sbi, struct bio *bio, ...@@ -724,7 +724,7 @@ static void add_bio_entry(struct f2fs_sb_info *sbi, struct bio *bio,
struct f2fs_bio_info *io = sbi->write_io[DATA] + temp; struct f2fs_bio_info *io = sbi->write_io[DATA] + temp;
struct bio_entry *be; struct bio_entry *be;
be = f2fs_kmem_cache_alloc(bio_entry_slab, GFP_NOFS); be = f2fs_kmem_cache_alloc(bio_entry_slab, GFP_NOFS, true, NULL);
be->bio = bio; be->bio = bio;
bio_get(bio); bio_get(bio);
......
...@@ -83,8 +83,8 @@ int f2fs_init_casefolded_name(const struct inode *dir, ...@@ -83,8 +83,8 @@ int f2fs_init_casefolded_name(const struct inode *dir,
struct super_block *sb = dir->i_sb; struct super_block *sb = dir->i_sb;
if (IS_CASEFOLDED(dir)) { if (IS_CASEFOLDED(dir)) {
fname->cf_name.name = kmem_cache_alloc(f2fs_cf_name_slab, fname->cf_name.name = f2fs_kmem_cache_alloc(f2fs_cf_name_slab,
GFP_NOFS); GFP_NOFS, false, F2FS_SB(sb));
if (!fname->cf_name.name) if (!fname->cf_name.name)
return -ENOMEM; return -ENOMEM;
fname->cf_name.len = utf8_casefold(sb->s_encoding, fname->cf_name.len = utf8_casefold(sb->s_encoding,
......
...@@ -239,7 +239,7 @@ static struct extent_node *__attach_extent_node(struct f2fs_sb_info *sbi, ...@@ -239,7 +239,7 @@ static struct extent_node *__attach_extent_node(struct f2fs_sb_info *sbi,
{ {
struct extent_node *en; struct extent_node *en;
en = kmem_cache_alloc(extent_node_slab, GFP_ATOMIC); en = f2fs_kmem_cache_alloc(extent_node_slab, GFP_ATOMIC, false, sbi);
if (!en) if (!en)
return NULL; return NULL;
...@@ -292,7 +292,8 @@ static struct extent_tree *__grab_extent_tree(struct inode *inode) ...@@ -292,7 +292,8 @@ static struct extent_tree *__grab_extent_tree(struct inode *inode)
mutex_lock(&sbi->extent_tree_lock); mutex_lock(&sbi->extent_tree_lock);
et = radix_tree_lookup(&sbi->extent_tree_root, ino); et = radix_tree_lookup(&sbi->extent_tree_root, ino);
if (!et) { if (!et) {
et = f2fs_kmem_cache_alloc(extent_tree_slab, GFP_NOFS); et = f2fs_kmem_cache_alloc(extent_tree_slab,
GFP_NOFS, true, NULL);
f2fs_radix_tree_insert(&sbi->extent_tree_root, ino, et); f2fs_radix_tree_insert(&sbi->extent_tree_root, ino, et);
memset(et, 0, sizeof(struct extent_tree)); memset(et, 0, sizeof(struct extent_tree));
et->ino = ino; et->ino = ino;
......
...@@ -53,6 +53,7 @@ enum { ...@@ -53,6 +53,7 @@ enum {
FAULT_CHECKPOINT, FAULT_CHECKPOINT,
FAULT_DISCARD, FAULT_DISCARD,
FAULT_WRITE_IO, FAULT_WRITE_IO,
FAULT_SLAB_ALLOC,
FAULT_MAX, FAULT_MAX,
}; };
...@@ -2618,7 +2619,7 @@ static inline struct kmem_cache *f2fs_kmem_cache_create(const char *name, ...@@ -2618,7 +2619,7 @@ static inline struct kmem_cache *f2fs_kmem_cache_create(const char *name,
return kmem_cache_create(name, size, 0, SLAB_RECLAIM_ACCOUNT, NULL); return kmem_cache_create(name, size, 0, SLAB_RECLAIM_ACCOUNT, NULL);
} }
static inline void *f2fs_kmem_cache_alloc(struct kmem_cache *cachep, static inline void *f2fs_kmem_cache_alloc_nofail(struct kmem_cache *cachep,
gfp_t flags) gfp_t flags)
{ {
void *entry; void *entry;
...@@ -2629,6 +2630,20 @@ static inline void *f2fs_kmem_cache_alloc(struct kmem_cache *cachep, ...@@ -2629,6 +2630,20 @@ static inline void *f2fs_kmem_cache_alloc(struct kmem_cache *cachep,
return entry; return entry;
} }
static inline void *f2fs_kmem_cache_alloc(struct kmem_cache *cachep,
gfp_t flags, bool nofail, struct f2fs_sb_info *sbi)
{
if (nofail)
return f2fs_kmem_cache_alloc_nofail(cachep, flags);
if (time_to_inject(sbi, FAULT_SLAB_ALLOC)) {
f2fs_show_injection_info(sbi, FAULT_SLAB_ALLOC);
return NULL;
}
return kmem_cache_alloc(cachep, flags);
}
static inline bool is_inflight_io(struct f2fs_sb_info *sbi, int type) static inline bool is_inflight_io(struct f2fs_sb_info *sbi, int type)
{ {
if (get_pages(sbi, F2FS_RD_DATA) || get_pages(sbi, F2FS_RD_NODE) || if (get_pages(sbi, F2FS_RD_DATA) || get_pages(sbi, F2FS_RD_NODE) ||
......
...@@ -371,7 +371,8 @@ static struct victim_entry *attach_victim_entry(struct f2fs_sb_info *sbi, ...@@ -371,7 +371,8 @@ static struct victim_entry *attach_victim_entry(struct f2fs_sb_info *sbi,
struct atgc_management *am = &sbi->am; struct atgc_management *am = &sbi->am;
struct victim_entry *ve; struct victim_entry *ve;
ve = f2fs_kmem_cache_alloc(victim_entry_slab, GFP_NOFS); ve = f2fs_kmem_cache_alloc(victim_entry_slab,
GFP_NOFS, true, NULL);
ve->mtime = mtime; ve->mtime = mtime;
ve->segno = segno; ve->segno = segno;
...@@ -849,7 +850,8 @@ static void add_gc_inode(struct gc_inode_list *gc_list, struct inode *inode) ...@@ -849,7 +850,8 @@ static void add_gc_inode(struct gc_inode_list *gc_list, struct inode *inode)
iput(inode); iput(inode);
return; return;
} }
new_ie = f2fs_kmem_cache_alloc(f2fs_inode_entry_slab, GFP_NOFS); new_ie = f2fs_kmem_cache_alloc(f2fs_inode_entry_slab,
GFP_NOFS, true, NULL);
new_ie->inode = inode; new_ie->inode = inode;
f2fs_radix_tree_insert(&gc_list->iroot, inode->i_ino, new_ie); f2fs_radix_tree_insert(&gc_list->iroot, inode->i_ino, new_ie);
......
...@@ -162,14 +162,13 @@ static struct page *get_next_nat_page(struct f2fs_sb_info *sbi, nid_t nid) ...@@ -162,14 +162,13 @@ static struct page *get_next_nat_page(struct f2fs_sb_info *sbi, nid_t nid)
return dst_page; return dst_page;
} }
static struct nat_entry *__alloc_nat_entry(nid_t nid, bool no_fail) static struct nat_entry *__alloc_nat_entry(struct f2fs_sb_info *sbi,
nid_t nid, bool no_fail)
{ {
struct nat_entry *new; struct nat_entry *new;
if (no_fail) new = f2fs_kmem_cache_alloc(nat_entry_slab,
new = f2fs_kmem_cache_alloc(nat_entry_slab, GFP_F2FS_ZERO); GFP_F2FS_ZERO, no_fail, sbi);
else
new = kmem_cache_alloc(nat_entry_slab, GFP_F2FS_ZERO);
if (new) { if (new) {
nat_set_nid(new, nid); nat_set_nid(new, nid);
nat_reset_flag(new); nat_reset_flag(new);
...@@ -242,7 +241,8 @@ static struct nat_entry_set *__grab_nat_entry_set(struct f2fs_nm_info *nm_i, ...@@ -242,7 +241,8 @@ static struct nat_entry_set *__grab_nat_entry_set(struct f2fs_nm_info *nm_i,
head = radix_tree_lookup(&nm_i->nat_set_root, set); head = radix_tree_lookup(&nm_i->nat_set_root, set);
if (!head) { if (!head) {
head = f2fs_kmem_cache_alloc(nat_entry_set_slab, GFP_NOFS); head = f2fs_kmem_cache_alloc(nat_entry_set_slab,
GFP_NOFS, true, NULL);
INIT_LIST_HEAD(&head->entry_list); INIT_LIST_HEAD(&head->entry_list);
INIT_LIST_HEAD(&head->set_list); INIT_LIST_HEAD(&head->set_list);
...@@ -329,7 +329,8 @@ static unsigned int f2fs_add_fsync_node_entry(struct f2fs_sb_info *sbi, ...@@ -329,7 +329,8 @@ static unsigned int f2fs_add_fsync_node_entry(struct f2fs_sb_info *sbi,
unsigned long flags; unsigned long flags;
unsigned int seq_id; unsigned int seq_id;
fn = f2fs_kmem_cache_alloc(fsync_node_entry_slab, GFP_NOFS); fn = f2fs_kmem_cache_alloc(fsync_node_entry_slab,
GFP_NOFS, true, NULL);
get_page(page); get_page(page);
fn->page = page; fn->page = page;
...@@ -428,7 +429,7 @@ static void cache_nat_entry(struct f2fs_sb_info *sbi, nid_t nid, ...@@ -428,7 +429,7 @@ static void cache_nat_entry(struct f2fs_sb_info *sbi, nid_t nid,
struct f2fs_nm_info *nm_i = NM_I(sbi); struct f2fs_nm_info *nm_i = NM_I(sbi);
struct nat_entry *new, *e; struct nat_entry *new, *e;
new = __alloc_nat_entry(nid, false); new = __alloc_nat_entry(sbi, nid, false);
if (!new) if (!new)
return; return;
...@@ -451,7 +452,7 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni, ...@@ -451,7 +452,7 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
{ {
struct f2fs_nm_info *nm_i = NM_I(sbi); struct f2fs_nm_info *nm_i = NM_I(sbi);
struct nat_entry *e; struct nat_entry *e;
struct nat_entry *new = __alloc_nat_entry(ni->nid, true); struct nat_entry *new = __alloc_nat_entry(sbi, ni->nid, true);
down_write(&nm_i->nat_tree_lock); down_write(&nm_i->nat_tree_lock);
e = __lookup_nat_cache(nm_i, ni->nid); e = __lookup_nat_cache(nm_i, ni->nid);
...@@ -2252,7 +2253,7 @@ static bool add_free_nid(struct f2fs_sb_info *sbi, ...@@ -2252,7 +2253,7 @@ static bool add_free_nid(struct f2fs_sb_info *sbi,
if (unlikely(f2fs_check_nid_range(sbi, nid))) if (unlikely(f2fs_check_nid_range(sbi, nid)))
return false; return false;
i = f2fs_kmem_cache_alloc(free_nid_slab, GFP_NOFS); i = f2fs_kmem_cache_alloc(free_nid_slab, GFP_NOFS, true, NULL);
i->nid = nid; i->nid = nid;
i->state = FREE_NID; i->state = FREE_NID;
...@@ -2842,7 +2843,7 @@ static void remove_nats_in_journal(struct f2fs_sb_info *sbi) ...@@ -2842,7 +2843,7 @@ static void remove_nats_in_journal(struct f2fs_sb_info *sbi)
ne = __lookup_nat_cache(nm_i, nid); ne = __lookup_nat_cache(nm_i, nid);
if (!ne) { if (!ne) {
ne = __alloc_nat_entry(nid, true); ne = __alloc_nat_entry(sbi, nid, true);
__init_nat_entry(nm_i, ne, &raw_ne, true); __init_nat_entry(nm_i, ne, &raw_ne, true);
} }
......
...@@ -91,7 +91,8 @@ static struct fsync_inode_entry *add_fsync_inode(struct f2fs_sb_info *sbi, ...@@ -91,7 +91,8 @@ static struct fsync_inode_entry *add_fsync_inode(struct f2fs_sb_info *sbi,
goto err_out; goto err_out;
} }
entry = f2fs_kmem_cache_alloc(fsync_entry_slab, GFP_F2FS_ZERO); entry = f2fs_kmem_cache_alloc(fsync_entry_slab,
GFP_F2FS_ZERO, true, NULL);
entry->inode = inode; entry->inode = inode;
list_add_tail(&entry->list, head); list_add_tail(&entry->list, head);
......
...@@ -188,7 +188,8 @@ void f2fs_register_inmem_page(struct inode *inode, struct page *page) ...@@ -188,7 +188,8 @@ void f2fs_register_inmem_page(struct inode *inode, struct page *page)
set_page_private_atomic(page); set_page_private_atomic(page);
new = f2fs_kmem_cache_alloc(inmem_entry_slab, GFP_NOFS); new = f2fs_kmem_cache_alloc(inmem_entry_slab,
GFP_NOFS, true, NULL);
/* add atomic page indices to the list */ /* add atomic page indices to the list */
new->page = page; new->page = page;
...@@ -1001,7 +1002,7 @@ static struct discard_cmd *__create_discard_cmd(struct f2fs_sb_info *sbi, ...@@ -1001,7 +1002,7 @@ static struct discard_cmd *__create_discard_cmd(struct f2fs_sb_info *sbi,
pend_list = &dcc->pend_list[plist_idx(len)]; pend_list = &dcc->pend_list[plist_idx(len)];
dc = f2fs_kmem_cache_alloc(discard_cmd_slab, GFP_NOFS); dc = f2fs_kmem_cache_alloc(discard_cmd_slab, GFP_NOFS, true, NULL);
INIT_LIST_HEAD(&dc->list); INIT_LIST_HEAD(&dc->list);
dc->bdev = bdev; dc->bdev = bdev;
dc->lstart = lstart; dc->lstart = lstart;
...@@ -1962,7 +1963,7 @@ static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc, ...@@ -1962,7 +1963,7 @@ static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc,
if (!de) { if (!de) {
de = f2fs_kmem_cache_alloc(discard_entry_slab, de = f2fs_kmem_cache_alloc(discard_entry_slab,
GFP_F2FS_ZERO); GFP_F2FS_ZERO, true, NULL);
de->start_blkaddr = START_BLOCK(sbi, cpc->trim_start); de->start_blkaddr = START_BLOCK(sbi, cpc->trim_start);
list_add_tail(&de->list, head); list_add_tail(&de->list, head);
} }
...@@ -4099,7 +4100,8 @@ static struct page *get_next_sit_page(struct f2fs_sb_info *sbi, ...@@ -4099,7 +4100,8 @@ static struct page *get_next_sit_page(struct f2fs_sb_info *sbi,
static struct sit_entry_set *grab_sit_entry_set(void) static struct sit_entry_set *grab_sit_entry_set(void)
{ {
struct sit_entry_set *ses = struct sit_entry_set *ses =
f2fs_kmem_cache_alloc(sit_entry_set_slab, GFP_NOFS); f2fs_kmem_cache_alloc(sit_entry_set_slab,
GFP_NOFS, true, NULL);
ses->entry_cnt = 0; ses->entry_cnt = 0;
INIT_LIST_HEAD(&ses->set_list); INIT_LIST_HEAD(&ses->set_list);
......
...@@ -56,6 +56,7 @@ const char *f2fs_fault_name[FAULT_MAX] = { ...@@ -56,6 +56,7 @@ const char *f2fs_fault_name[FAULT_MAX] = {
[FAULT_CHECKPOINT] = "checkpoint error", [FAULT_CHECKPOINT] = "checkpoint error",
[FAULT_DISCARD] = "discard error", [FAULT_DISCARD] = "discard error",
[FAULT_WRITE_IO] = "write IO error", [FAULT_WRITE_IO] = "write IO error",
[FAULT_SLAB_ALLOC] = "slab alloc",
}; };
void f2fs_build_fault_attr(struct f2fs_sb_info *sbi, unsigned int rate, void f2fs_build_fault_attr(struct f2fs_sb_info *sbi, unsigned int rate,
...@@ -1300,7 +1301,8 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb) ...@@ -1300,7 +1301,8 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
{ {
struct f2fs_inode_info *fi; struct f2fs_inode_info *fi;
fi = kmem_cache_alloc(f2fs_inode_cachep, GFP_F2FS_ZERO); fi = f2fs_kmem_cache_alloc(f2fs_inode_cachep,
GFP_F2FS_ZERO, false, F2FS_SB(sb));
if (!fi) if (!fi)
return NULL; return NULL;
......
...@@ -27,7 +27,8 @@ static void *xattr_alloc(struct f2fs_sb_info *sbi, int size, bool *is_inline) ...@@ -27,7 +27,8 @@ static void *xattr_alloc(struct f2fs_sb_info *sbi, int size, bool *is_inline)
{ {
if (likely(size == sbi->inline_xattr_slab_size)) { if (likely(size == sbi->inline_xattr_slab_size)) {
*is_inline = true; *is_inline = true;
return kmem_cache_zalloc(sbi->inline_xattr_slab, GFP_NOFS); return f2fs_kmem_cache_alloc(sbi->inline_xattr_slab,
GFP_F2FS_ZERO, false, sbi);
} }
*is_inline = false; *is_inline = false;
return f2fs_kzalloc(sbi, size, GFP_NOFS); return f2fs_kzalloc(sbi, size, GFP_NOFS);
......
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