Hi Jaegeuk, On 2016/9/24 7:53, Jaegeuk Kim wrote: > Hi Chao, > > The basic rule is to stop every operations once CP_ERROR_FLAG is set. > But, this patch simply breaks the rule. > For example, f2fs_write_data_page() currently exits with mapping_set_error(). > So this patch incurs missing dentry blocks in a valid checkpoint.
Yes, that's right. How about triggering checkpoint error in f2fs_stop_checkpoint? >From 7bedfe9a0e97c4deead1c7cdbfc24187f5080268 Mon Sep 17 00:00:00 2001 From: Chao Yu <yuch...@huawei.com> Date: Fri, 23 Sep 2016 06:59:04 +0800 Subject: [PATCH] f2fs: support checkpoint error injection This patch adds to support checkpoint error injection in f2fs for testing fatal error tolerance. Signed-off-by: Chao Yu <yuch...@huawei.com> --- fs/f2fs/checkpoint.c | 14 +++++++++++--- fs/f2fs/data.c | 7 ++++--- fs/f2fs/f2fs.h | 5 ++++- fs/f2fs/file.c | 8 ++++---- fs/f2fs/inode.c | 7 +++++-- fs/f2fs/super.c | 1 + 6 files changed, 29 insertions(+), 13 deletions(-) diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index d1560bb..834c8ec 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -26,8 +26,17 @@ static struct kmem_cache *ino_entry_slab; struct kmem_cache *inode_entry_slab; -void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io) +void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, + bool end_io, bool need_stop) { +#ifdef CONFIG_F2FS_FAULT_INJECTION + if (time_to_inject(FAULT_CHECKPOINT)) + need_stop = true; +#endif + + if (!need_stop) + return; + set_ckpt_flags(sbi, CP_ERROR_FLAG); sbi->sb->s_flags |= MS_RDONLY; if (!end_io) @@ -100,8 +109,7 @@ repeat: * readonly and make sure do not write checkpoint with non-uptodate * meta page. */ - if (unlikely(!PageUptodate(page))) - f2fs_stop_checkpoint(sbi, false); + f2fs_stop_checkpoint(sbi, false, !PageUptodate(page)); out: return page; } diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index a9f7436..1b00d3d 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -74,10 +74,11 @@ static void f2fs_write_end_io(struct bio *bio) fscrypt_pullback_bio_page(&page, true); - if (unlikely(bio->bi_error)) { + f2fs_stop_checkpoint(sbi, true, bio->bi_error); + + if (unlikely(bio->bi_error)) set_bit(AS_EIO, &page->mapping->flags); - f2fs_stop_checkpoint(sbi, true); - } + end_page_writeback(page); } if (atomic_dec_and_test(&sbi->nr_wb_bios) && diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index e216bc0..7bc1802 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -47,6 +47,7 @@ enum { FAULT_DIR_DEPTH, FAULT_EVICT_INODE, FAULT_IO, + FAULT_CHECKPOINT, FAULT_MAX, }; @@ -80,6 +81,8 @@ static inline bool time_to_inject(int type) return false; else if (type == FAULT_IO && !IS_FAULT_SET(type)) return false; + else if (type == FAULT_CHECKPOINT && !IS_FAULT_SET(type)) + return false; atomic_inc(&f2fs_fault.inject_ops); if (atomic_read(&f2fs_fault.inject_ops) >= f2fs_fault.inject_rate) { @@ -2115,7 +2118,7 @@ void destroy_segment_manager_caches(void); /* * checkpoint.c */ -void f2fs_stop_checkpoint(struct f2fs_sb_info *, bool); +void f2fs_stop_checkpoint(struct f2fs_sb_info *, bool, bool); struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t); struct page *get_meta_page(struct f2fs_sb_info *, pgoff_t); struct page *get_tmp_page(struct f2fs_sb_info *, pgoff_t); diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index d341a0e..57c7a64 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1720,21 +1720,21 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg) case F2FS_GOING_DOWN_FULLSYNC: sb = freeze_bdev(sb->s_bdev); if (sb && !IS_ERR(sb)) { - f2fs_stop_checkpoint(sbi, false); + f2fs_stop_checkpoint(sbi, false, true); thaw_bdev(sb->s_bdev, sb); } break; case F2FS_GOING_DOWN_METASYNC: /* do checkpoint only */ f2fs_sync_fs(sb, 1); - f2fs_stop_checkpoint(sbi, false); + f2fs_stop_checkpoint(sbi, false, true); break; case F2FS_GOING_DOWN_NOSYNC: - f2fs_stop_checkpoint(sbi, false); + f2fs_stop_checkpoint(sbi, false, true); break; case F2FS_GOING_DOWN_METAFLUSH: sync_meta_pages(sbi, META, LONG_MAX); - f2fs_stop_checkpoint(sbi, false); + f2fs_stop_checkpoint(sbi, false, true); break; default: ret = -EINVAL; diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index ac4daa5..bf53cd2 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -306,12 +306,15 @@ retry: node_page = get_node_page(sbi, inode->i_ino); if (IS_ERR(node_page)) { int err = PTR_ERR(node_page); + + f2fs_stop_checkpoint(sbi, false, + err != -ENOMEM && err != -ENOENT); + if (err == -ENOMEM) { cond_resched(); goto retry; - } else if (err != -ENOENT) { - f2fs_stop_checkpoint(sbi, false); } + f2fs_inode_synced(inode); return 0; } diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 6426855..3c49419 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -51,6 +51,7 @@ char *fault_name[FAULT_MAX] = { [FAULT_DIR_DEPTH] = "too big dir depth", [FAULT_EVICT_INODE] = "evict_inode fail", [FAULT_IO] = "IO error", + [FAULT_CHECKPOINT] = "checkpoint error", }; static void f2fs_build_fault_attr(unsigned int rate) -- 2.8.2.311.gee88674