aboutsummaryrefslogtreecommitdiffstats
path: root/fs/f2fs
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk.kim@samsung.com>2013-01-24 05:56:11 -0500
committerJaegeuk Kim <jaegeuk.kim@samsung.com>2013-02-11 17:15:00 -0500
commit577e349514452fa3fcd99fd06e587b02d3d1cf28 (patch)
treefe4e86d3f56b8050c85b1f5fb76117d6e99c5aa9 /fs/f2fs
parent7d79e75f6420fc13cfe72554b3ea5afad24c8625 (diff)
f2fs: prevent checkpoint once any IO failure is detected
This patch enhances the checkpoint routine to cope with IO errors. Basically f2fs detects IO errors from end_io_write, and the errors are able to be occurred during one of data, node, and meta page writes. In the previous code, when an IO error is occurred during writes, f2fs sets a flag, CP_ERROR_FLAG, in the raw ckeckpoint buffer which will be written to disk. Afterwards, write_checkpoint() will check the flag and remount f2fs as a read-only (ro) mode. However, even once f2fs is remounted as a ro mode, dirty checkpoint pages are freely able to be written to disk by flusher or kswapd in background. In such a case, after cold reboot, f2fs would restore the checkpoint data having CP_ERROR_FLAG, resulting in disabling write_checkpoint and remounting f2fs as a ro mode again. Therefore, let's prevent any checkpoint page (meta) writes once an IO error is occurred, and remount f2fs as a ro mode right away at that moment. Reported-by: Oliver Winker <oliver@oli1170.net> Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com> Reviewed-by: Namjae Jeon <namjae.jeon@samsung.com>
Diffstat (limited to 'fs/f2fs')
-rw-r--r--fs/f2fs/checkpoint.c36
-rw-r--r--fs/f2fs/f2fs.h3
-rw-r--r--fs/f2fs/segment.c8
-rw-r--r--fs/f2fs/super.c12
4 files changed, 31 insertions, 28 deletions
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index ff3c8439af87..9c1627165039 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -72,22 +72,22 @@ static int f2fs_write_meta_page(struct page *page,
72{ 72{
73 struct inode *inode = page->mapping->host; 73 struct inode *inode = page->mapping->host;
74 struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); 74 struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
75 int err;
76 75
77 wait_on_page_writeback(page); 76 /* Should not write any meta pages, if any IO error was occurred */
78 77 if (wbc->for_reclaim ||
79 err = write_meta_page(sbi, page, wbc); 78 is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ERROR_FLAG)) {
80 if (err) { 79 dec_page_count(sbi, F2FS_DIRTY_META);
81 wbc->pages_skipped++; 80 wbc->pages_skipped++;
82 set_page_dirty(page); 81 set_page_dirty(page);
82 return AOP_WRITEPAGE_ACTIVATE;
83 } 83 }
84 84
85 dec_page_count(sbi, F2FS_DIRTY_META); 85 wait_on_page_writeback(page);
86 86
87 /* In this case, we should not unlock this page */ 87 write_meta_page(sbi, page);
88 if (err != AOP_WRITEPAGE_ACTIVATE) 88 dec_page_count(sbi, F2FS_DIRTY_META);
89 unlock_page(page); 89 unlock_page(page);
90 return err; 90 return 0;
91} 91}
92 92
93static int f2fs_write_meta_pages(struct address_space *mapping, 93static int f2fs_write_meta_pages(struct address_space *mapping,
@@ -138,7 +138,10 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
138 BUG_ON(page->mapping != mapping); 138 BUG_ON(page->mapping != mapping);
139 BUG_ON(!PageDirty(page)); 139 BUG_ON(!PageDirty(page));
140 clear_page_dirty_for_io(page); 140 clear_page_dirty_for_io(page);
141 f2fs_write_meta_page(page, &wbc); 141 if (f2fs_write_meta_page(page, &wbc)) {
142 unlock_page(page);
143 break;
144 }
142 if (nwritten++ >= nr_to_write) 145 if (nwritten++ >= nr_to_write)
143 break; 146 break;
144 } 147 }
@@ -717,13 +720,12 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
717 sbi->alloc_valid_block_count = 0; 720 sbi->alloc_valid_block_count = 0;
718 721
719 /* Here, we only have one bio having CP pack */ 722 /* Here, we only have one bio having CP pack */
720 if (is_set_ckpt_flags(ckpt, CP_ERROR_FLAG)) 723 sync_meta_pages(sbi, META_FLUSH, LONG_MAX);
721 sbi->sb->s_flags |= MS_RDONLY;
722 else
723 sync_meta_pages(sbi, META_FLUSH, LONG_MAX);
724 724
725 clear_prefree_segments(sbi); 725 if (!is_set_ckpt_flags(ckpt, CP_ERROR_FLAG)) {
726 F2FS_RESET_SB_DIRT(sbi); 726 clear_prefree_segments(sbi);
727 F2FS_RESET_SB_DIRT(sbi);
728 }
727} 729}
728 730
729/* 731/*
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index c8e2d751ef9c..f4f509766465 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -929,8 +929,7 @@ void allocate_new_segments(struct f2fs_sb_info *);
929struct page *get_sum_page(struct f2fs_sb_info *, unsigned int); 929struct page *get_sum_page(struct f2fs_sb_info *, unsigned int);
930struct bio *f2fs_bio_alloc(struct block_device *, int); 930struct bio *f2fs_bio_alloc(struct block_device *, int);
931void f2fs_submit_bio(struct f2fs_sb_info *, enum page_type, bool sync); 931void f2fs_submit_bio(struct f2fs_sb_info *, enum page_type, bool sync);
932int write_meta_page(struct f2fs_sb_info *, struct page *, 932void write_meta_page(struct f2fs_sb_info *, struct page *);
933 struct writeback_control *);
934void write_node_page(struct f2fs_sb_info *, struct page *, unsigned int, 933void write_node_page(struct f2fs_sb_info *, struct page *, unsigned int,
935 block_t, block_t *); 934 block_t, block_t *);
936void write_data_page(struct inode *, struct page *, struct dnode_of_data*, 935void write_data_page(struct inode *, struct page *, struct dnode_of_data*,
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 4b0099066582..7aa270f3538a 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -600,6 +600,7 @@ static void f2fs_end_io_write(struct bio *bio, int err)
600 if (page->mapping) 600 if (page->mapping)
601 set_bit(AS_EIO, &page->mapping->flags); 601 set_bit(AS_EIO, &page->mapping->flags);
602 set_ckpt_flags(p->sbi->ckpt, CP_ERROR_FLAG); 602 set_ckpt_flags(p->sbi->ckpt, CP_ERROR_FLAG);
603 p->sbi->sb->s_flags |= MS_RDONLY;
603 } 604 }
604 end_page_writeback(page); 605 end_page_writeback(page);
605 dec_page_count(p->sbi, F2FS_WRITEBACK); 606 dec_page_count(p->sbi, F2FS_WRITEBACK);
@@ -815,15 +816,10 @@ static void do_write_page(struct f2fs_sb_info *sbi, struct page *page,
815 mutex_unlock(&curseg->curseg_mutex); 816 mutex_unlock(&curseg->curseg_mutex);
816} 817}
817 818
818int write_meta_page(struct f2fs_sb_info *sbi, struct page *page, 819void write_meta_page(struct f2fs_sb_info *sbi, struct page *page)
819 struct writeback_control *wbc)
820{ 820{
821 if (wbc->for_reclaim)
822 return AOP_WRITEPAGE_ACTIVATE;
823
824 set_page_writeback(page); 821 set_page_writeback(page);
825 submit_write_page(sbi, page, page->index, META); 822 submit_write_page(sbi, page, page->index, META);
826 return 0;
827} 823}
828 824
829void write_node_page(struct f2fs_sb_info *sbi, struct page *page, 825void write_node_page(struct f2fs_sb_info *sbi, struct page *page,
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 37fad04c8669..117ca2a46e39 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -387,10 +387,11 @@ static int sanity_check_raw_super(struct super_block *sb,
387 return 0; 387 return 0;
388} 388}
389 389
390static int sanity_check_ckpt(struct f2fs_super_block *raw_super, 390static int sanity_check_ckpt(struct f2fs_sb_info *sbi)
391 struct f2fs_checkpoint *ckpt)
392{ 391{
393 unsigned int total, fsmeta; 392 unsigned int total, fsmeta;
393 struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
394 struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
394 395
395 total = le32_to_cpu(raw_super->segment_count); 396 total = le32_to_cpu(raw_super->segment_count);
396 fsmeta = le32_to_cpu(raw_super->segment_count_ckpt); 397 fsmeta = le32_to_cpu(raw_super->segment_count_ckpt);
@@ -401,6 +402,11 @@ static int sanity_check_ckpt(struct f2fs_super_block *raw_super,
401 402
402 if (fsmeta >= total) 403 if (fsmeta >= total)
403 return 1; 404 return 1;
405
406 if (is_set_ckpt_flags(ckpt, CP_ERROR_FLAG)) {
407 f2fs_msg(sbi->sb, KERN_ERR, "A bug case: need to run fsck");
408 return 1;
409 }
404 return 0; 410 return 0;
405} 411}
406 412
@@ -525,7 +531,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
525 531
526 /* sanity checking of checkpoint */ 532 /* sanity checking of checkpoint */
527 err = -EINVAL; 533 err = -EINVAL;
528 if (sanity_check_ckpt(raw_super, sbi->ckpt)) { 534 if (sanity_check_ckpt(sbi)) {
529 f2fs_msg(sb, KERN_ERR, "Invalid F2FS checkpoint"); 535 f2fs_msg(sb, KERN_ERR, "Invalid F2FS checkpoint");
530 goto free_cp; 536 goto free_cp;
531 } 537 }