aboutsummaryrefslogtreecommitdiffstats
path: root/fs/f2fs/segment.c
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk.kim@samsung.com>2014-04-15 00:57:55 -0400
committerJaegeuk Kim <jaegeuk.kim@samsung.com>2014-05-06 21:21:54 -0400
commit1e87a78d95ecea7a989349860feb42db3e4b7db5 (patch)
tree77e8a24c621760c18ee7cf599ad93fd92744032f /fs/f2fs/segment.c
parentb270ad6f0aedd27bdc689fc15f26bc650a59b12b (diff)
f2fs: avoid to conduct roll-forward due to the remained garbage blocks
The f2fs always scans the next chain of direct node blocks. But some garbage blocks are able to be remained due to no discard support or SSR triggers. This occasionally wreaks recovering wrong inodes that were used or BUG_ONs due to reallocating node ids as follows. When mount this f2fs image: http://linuxtesting.org/downloads/f2fs_fault_image.zip BUG_ON is triggered in f2fs driver (messages below are generated on kernel 3.13.2; for other kernels output is similar): kernel BUG at fs/f2fs/node.c:215! Call Trace: [<ffffffffa032ebad>] recover_inode_page+0x1fd/0x3e0 [f2fs] [<ffffffff811446e7>] ? __lock_page+0x67/0x70 [<ffffffff81089990>] ? autoremove_wake_function+0x50/0x50 [<ffffffffa0337788>] recover_fsync_data+0x1398/0x15d0 [f2fs] [<ffffffff812b9e5c>] ? selinux_d_instantiate+0x1c/0x20 [<ffffffff811cb20b>] ? d_instantiate+0x5b/0x80 [<ffffffffa0321044>] f2fs_fill_super+0xb04/0xbf0 [f2fs] [<ffffffff811b861e>] ? mount_bdev+0x7e/0x210 [<ffffffff811b8769>] mount_bdev+0x1c9/0x210 [<ffffffffa0320540>] ? validate_superblock+0x210/0x210 [f2fs] [<ffffffffa031cf8d>] f2fs_mount+0x1d/0x30 [f2fs] [<ffffffff811b9497>] mount_fs+0x47/0x1c0 [<ffffffff81166e00>] ? __alloc_percpu+0x10/0x20 [<ffffffff811d4032>] vfs_kern_mount+0x72/0x110 [<ffffffff811d6763>] do_mount+0x493/0x910 [<ffffffff811615cb>] ? strndup_user+0x5b/0x80 [<ffffffff811d6c70>] SyS_mount+0x90/0xe0 [<ffffffff8166f8d9>] system_call_fastpath+0x16/0x1b Found by Linux File System Verification project (linuxtesting.org). Reported-by: Andrey Tsyvarev <tsyvarev@ispras.ru> Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
Diffstat (limited to 'fs/f2fs/segment.c')
-rw-r--r--fs/f2fs/segment.c17
1 files changed, 15 insertions, 2 deletions
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 1e264e761f71..9993f94848fc 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -335,13 +335,26 @@ static void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno)
335 mutex_unlock(&dirty_i->seglist_lock); 335 mutex_unlock(&dirty_i->seglist_lock);
336} 336}
337 337
338static void f2fs_issue_discard(struct f2fs_sb_info *sbi, 338static int f2fs_issue_discard(struct f2fs_sb_info *sbi,
339 block_t blkstart, block_t blklen) 339 block_t blkstart, block_t blklen)
340{ 340{
341 sector_t start = SECTOR_FROM_BLOCK(sbi, blkstart); 341 sector_t start = SECTOR_FROM_BLOCK(sbi, blkstart);
342 sector_t len = SECTOR_FROM_BLOCK(sbi, blklen); 342 sector_t len = SECTOR_FROM_BLOCK(sbi, blklen);
343 blkdev_issue_discard(sbi->sb->s_bdev, start, len, GFP_NOFS, 0);
344 trace_f2fs_issue_discard(sbi->sb, blkstart, blklen); 343 trace_f2fs_issue_discard(sbi->sb, blkstart, blklen);
344 return blkdev_issue_discard(sbi->sb->s_bdev, start, len, GFP_NOFS, 0);
345}
346
347void discard_next_dnode(struct f2fs_sb_info *sbi)
348{
349 struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
350 block_t blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);
351
352 if (f2fs_issue_discard(sbi, blkaddr, 1)) {
353 struct page *page = grab_meta_page(sbi, blkaddr);
354 /* zero-filled page */
355 set_page_dirty(page);
356 f2fs_put_page(page, 1);
357 }
345} 358}
346 359
347static void add_discard_addrs(struct f2fs_sb_info *sbi, 360static void add_discard_addrs(struct f2fs_sb_info *sbi,