f2fs: support fault injection for f2fs_kmem_cache_alloc()
authorChao Yu <chao@kernel.org>
Mon, 9 Aug 2021 00:24:48 +0000 (08:24 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Tue, 17 Aug 2021 18:59:05 +0000 (11:59 -0700)
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: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
13 files changed:
Documentation/filesystems/f2fs.rst
fs/f2fs/checkpoint.c
fs/f2fs/compress.c
fs/f2fs/data.c
fs/f2fs/dir.c
fs/f2fs/extent_cache.c
fs/f2fs/f2fs.h
fs/f2fs/gc.c
fs/f2fs/node.c
fs/f2fs/recovery.c
fs/f2fs/segment.c
fs/f2fs/super.c
fs/f2fs/xattr.c

index 9b0517d900637266efd766f448fa77bb947d3d7a..21d40e3cfd7a2637b7733106a675d0b53aa17da6 100644 (file)
@@ -195,6 +195,7 @@ fault_type=%d                Support configuring fault injection type, should be
                         FAULT_CHECKPOINT         0x000001000
                         FAULT_DISCARD            0x000002000
                         FAULT_WRITE_IO           0x000004000
+                        FAULT_SLAB_ALLOC         0x000008000
                         ===================      ===========
 mode=%s                         Control block allocation mode which supports "adaptive"
                         and "lfs". In "lfs" mode, there should be no random
index 5b6ddeae1107c5e7de665aae2677a22ef7b15fcc..41960c55c343691caa5c65df4edaead09028e47d 100644 (file)
@@ -475,7 +475,8 @@ static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino,
 
 retry:
        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);
 
index 7dbfd6965b97103bbf3ad3e7edbae59e05ef4bf2..afb79480c6a336a5a8a7177d5301a324339b5462 100644 (file)
@@ -28,7 +28,8 @@ static void *page_array_alloc(struct inode *inode, int nr)
        unsigned int size = sizeof(struct page *) * nr;
 
        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);
 }
 
@@ -1228,7 +1229,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
 
        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)
                goto out_put_dnode;
 
@@ -1506,7 +1507,8 @@ struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc)
        pgoff_t start_idx = start_idx_of_cluster(cc);
        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)
                return ERR_PTR(-ENOMEM);
 
index cec0848067254fc0b10c9e670c7f0fe3ca86e531..12cd636031376e632652391e063c975a88daf425 100644 (file)
@@ -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 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;
        bio_get(bio);
 
index c250bf46ef5edce98572f06dd7439d08fba9390a..1820e9c106f7dd7f69608a7eb49c116a7be3e1e9 100644 (file)
@@ -83,8 +83,8 @@ int f2fs_init_casefolded_name(const struct inode *dir,
        struct super_block *sb = dir->i_sb;
 
        if (IS_CASEFOLDED(dir)) {
-               fname->cf_name.name = kmem_cache_alloc(f2fs_cf_name_slab,
-                                                               GFP_NOFS);
+               fname->cf_name.name = f2fs_kmem_cache_alloc(f2fs_cf_name_slab,
+                                       GFP_NOFS, false, F2FS_SB(sb));
                if (!fname->cf_name.name)
                        return -ENOMEM;
                fname->cf_name.len = utf8_casefold(sb->s_encoding,
index b120589d8517e2ecf0124f348fef9f913a32b296..866e72b29bd5ac507bbad6cbf098b2030971d94d 100644 (file)
@@ -239,7 +239,7 @@ static struct extent_node *__attach_extent_node(struct f2fs_sb_info *sbi,
 {
        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)
                return NULL;
 
@@ -292,7 +292,8 @@ static struct extent_tree *__grab_extent_tree(struct inode *inode)
        mutex_lock(&sbi->extent_tree_lock);
        et = radix_tree_lookup(&sbi->extent_tree_root, ino);
        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);
                memset(et, 0, sizeof(struct extent_tree));
                et->ino = ino;
index e97b4d8c5efc2345accca8faecf36b73786568a1..13a7cfe9b23f98bc9ed42a32c992b3812357e52a 100644 (file)
@@ -53,6 +53,7 @@ enum {
        FAULT_CHECKPOINT,
        FAULT_DISCARD,
        FAULT_WRITE_IO,
+       FAULT_SLAB_ALLOC,
        FAULT_MAX,
 };
 
@@ -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);
 }
 
-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)
 {
        void *entry;
@@ -2629,6 +2630,20 @@ static inline void *f2fs_kmem_cache_alloc(struct kmem_cache *cachep,
        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)
 {
        if (get_pages(sbi, F2FS_RD_DATA) || get_pages(sbi, F2FS_RD_NODE) ||
index 9dce446190699eae08471debd44919f0373e5dc6..3bc0f0162e31b4f76f3b5504fcda873df0bc2967 100644 (file)
@@ -371,7 +371,8 @@ static struct victim_entry *attach_victim_entry(struct f2fs_sb_info *sbi,
        struct atgc_management *am = &sbi->am;
        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->segno = segno;
@@ -849,7 +850,8 @@ static void add_gc_inode(struct gc_inode_list *gc_list, struct inode *inode)
                iput(inode);
                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;
 
        f2fs_radix_tree_insert(&gc_list->iroot, inode->i_ino, new_ie);
index 9d838a7929fb672152912133a6676928d3943d3a..161173de5a2db5c54deccfd27f8b29b4726875cf 100644 (file)
@@ -162,14 +162,13 @@ static struct page *get_next_nat_page(struct f2fs_sb_info *sbi, nid_t nid)
        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;
 
-       if (no_fail)
-               new = f2fs_kmem_cache_alloc(nat_entry_slab, GFP_F2FS_ZERO);
-       else
-               new = kmem_cache_alloc(nat_entry_slab, GFP_F2FS_ZERO);
+       new = f2fs_kmem_cache_alloc(nat_entry_slab,
+                                       GFP_F2FS_ZERO, no_fail, sbi);
        if (new) {
                nat_set_nid(new, nid);
                nat_reset_flag(new);
@@ -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);
        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->set_list);
@@ -329,7 +329,8 @@ static unsigned int f2fs_add_fsync_node_entry(struct f2fs_sb_info *sbi,
        unsigned long flags;
        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);
        fn->page = page;
@@ -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 nat_entry *new, *e;
 
-       new = __alloc_nat_entry(nid, false);
+       new = __alloc_nat_entry(sbi, nid, false);
        if (!new)
                return;
 
@@ -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 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);
        e = __lookup_nat_cache(nm_i, ni->nid);
@@ -2252,7 +2253,7 @@ static bool add_free_nid(struct f2fs_sb_info *sbi,
        if (unlikely(f2fs_check_nid_range(sbi, nid)))
                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->state = FREE_NID;
 
@@ -2842,7 +2843,7 @@ static void remove_nats_in_journal(struct f2fs_sb_info *sbi)
 
                ne = __lookup_nat_cache(nm_i, nid);
                if (!ne) {
-                       ne = __alloc_nat_entry(nid, true);
+                       ne = __alloc_nat_entry(sbi, nid, true);
                        __init_nat_entry(nm_i, ne, &raw_ne, true);
                }
 
index 695eacfe776c9d133b2476eaded910b5aa4ee79a..04655511d7f514593d388ef88bd6ac4be17b4988 100644 (file)
@@ -91,7 +91,8 @@ static struct fsync_inode_entry *add_fsync_inode(struct f2fs_sb_info *sbi,
                        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;
        list_add_tail(&entry->list, head);
 
index ca9876a6d3964d4b36cf8ad03780fc9eb06328d2..b4dd22134a73f71825dbfe282249ab48af2c7002 100644 (file)
@@ -188,7 +188,8 @@ void f2fs_register_inmem_page(struct inode *inode, struct page *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 */
        new->page = page;
@@ -1001,7 +1002,7 @@ static struct discard_cmd *__create_discard_cmd(struct f2fs_sb_info *sbi,
 
        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);
        dc->bdev = bdev;
        dc->lstart = lstart;
@@ -1962,7 +1963,7 @@ static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc,
 
                if (!de) {
                        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);
                        list_add_tail(&de->list, head);
                }
@@ -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)
 {
        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;
        INIT_LIST_HEAD(&ses->set_list);
index 9e0e3c998142462885a61235f08ce38e87e89ed5..b556ca38f0fbd04c05937b19daaae7c50e067f85 100644 (file)
@@ -56,6 +56,7 @@ const char *f2fs_fault_name[FAULT_MAX] = {
        [FAULT_CHECKPOINT]      = "checkpoint error",
        [FAULT_DISCARD]         = "discard 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,
@@ -1300,7 +1301,8 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
 {
        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)
                return NULL;
 
index c8f34decbf8e1fd24b9d093a37468ad266242e60..1d2d29dcd41ce0d3522a02abc61658097c8372f2 100644 (file)
@@ -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)) {
                *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;
        return f2fs_kzalloc(sbi, size, GFP_NOFS);