Skip to content

Commit 26b5a07

Browse files
Sheng YongJaegeuk Kim
authored andcommitted
f2fs: cleanup dirty pages if recover failed
During recover, we will try to create new dentries for inodes with dentry_mark. But if the parent is missing (e.g. killed by fsck), recover will break. But those recovered dirty pages are not cleanup. This will hit f2fs_bug_on: [ 53.519566] F2FS-fs (loop0): Found nat_bits in checkpoint [ 53.539354] F2FS-fs (loop0): recover_inode: ino = 5, name = file, inline = 3 [ 53.539402] F2FS-fs (loop0): recover_dentry: ino = 5, name = file, dir = 0, err = -2 [ 53.545760] F2FS-fs (loop0): Cannot recover all fsync data errno=-2 [ 53.546105] F2FS-fs (loop0): access invalid blkaddr:4294967295 [ 53.546171] WARNING: CPU: 1 PID: 1798 at fs/f2fs/checkpoint.c:163 f2fs_is_valid_blkaddr+0x26c/0x320 [ 53.546174] Modules linked in: [ 53.546183] CPU: 1 PID: 1798 Comm: mount Not tainted 4.19.0-rc2+ #1 [ 53.546186] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006 [ 53.546191] RIP: 0010:f2fs_is_valid_blkaddr+0x26c/0x320 [ 53.546195] Code: 85 bb 00 00 00 48 89 df 88 44 24 07 e8 ad a8 db ff 48 8b 3b 44 89 e1 48 c7 c2 40 03 72 a9 48 c7 c6 e0 01 72 a9 e8 84 3c ff ff <0f> 0b 0f b6 44 24 07 e9 8a 00 00 00 48 8d bf 38 01 00 00 e8 7c a8 [ 53.546201] RSP: 0018:ffff88006c067768 EFLAGS: 00010282 [ 53.546208] RAX: 0000000000000000 RBX: ffff880068844200 RCX: ffffffffa83e1a33 [ 53.546211] RDX: 0000000000000000 RSI: 0000000000000008 RDI: ffff88006d51e590 [ 53.546215] RBP: 0000000000000005 R08: ffffed000daa3cb3 R09: ffffed000daa3cb3 [ 53.546218] R10: 0000000000000001 R11: ffffed000daa3cb2 R12: 00000000ffffffff [ 53.546221] R13: ffff88006a1f8000 R14: 0000000000000200 R15: 0000000000000009 [ 53.546226] FS: 00007fb2f3646840(0000) GS:ffff88006d500000(0000) knlGS:0000000000000000 [ 53.546229] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 53.546234] CR2: 00007f0fd77f0008 CR3: 00000000687e6002 CR4: 00000000000206e0 [ 53.546237] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 53.546240] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 53.546242] Call Trace: [ 53.546248] f2fs_submit_page_bio+0x95/0x740 [ 53.546253] read_node_page+0x161/0x1e0 [ 53.546271] ? truncate_node+0x650/0x650 [ 53.546283] ? add_to_page_cache_lru+0x12c/0x170 [ 53.546288] ? pagecache_get_page+0x262/0x2d0 [ 53.546292] __get_node_page+0x200/0x660 [ 53.546302] f2fs_update_inode_page+0x4a/0x160 [ 53.546306] f2fs_write_inode+0x86/0xb0 [ 53.546317] __writeback_single_inode+0x49c/0x620 [ 53.546322] writeback_single_inode+0xe4/0x1e0 [ 53.546326] sync_inode_metadata+0x93/0xd0 [ 53.546330] ? sync_inode+0x10/0x10 [ 53.546342] ? do_raw_spin_unlock+0xed/0x100 [ 53.546347] f2fs_sync_inode_meta+0xe0/0x130 [ 53.546351] f2fs_fill_super+0x287d/0x2d10 [ 53.546367] ? vsnprintf+0x742/0x7a0 [ 53.546372] ? f2fs_commit_super+0x180/0x180 [ 53.546379] ? up_write+0x20/0x40 [ 53.546385] ? set_blocksize+0x5f/0x140 [ 53.546391] ? f2fs_commit_super+0x180/0x180 [ 53.546402] mount_bdev+0x181/0x200 [ 53.546406] mount_fs+0x94/0x180 [ 53.546411] vfs_kern_mount+0x6c/0x1e0 [ 53.546415] do_mount+0xe5e/0x1510 [ 53.546420] ? fs_reclaim_release+0x9/0x30 [ 53.546424] ? copy_mount_string+0x20/0x20 [ 53.546428] ? fs_reclaim_acquire+0xd/0x30 [ 53.546435] ? __might_sleep+0x2c/0xc0 [ 53.546440] ? ___might_sleep+0x53/0x170 [ 53.546453] ? __might_fault+0x4c/0x60 [ 53.546468] ? _copy_from_user+0x95/0xa0 [ 53.546474] ? memdup_user+0x39/0x60 [ 53.546478] ksys_mount+0x88/0xb0 [ 53.546482] __x64_sys_mount+0x5d/0x70 [ 53.546495] do_syscall_64+0x65/0x130 [ 53.546503] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [ 53.547639] ---[ end trace b804d1ea2fec893e ]--- So if recover fails, we need to drop all recovered data. Signed-off-by: Sheng Yong <shengyong1@huawei.com> Reviewed-by: Chao Yu <yuchao0@huawei.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
1 parent 1e78e8b commit 26b5a07

File tree

2 files changed

+35
-12
lines changed

2 files changed

+35
-12
lines changed

fs/f2fs/recovery.c

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,12 @@ static struct fsync_inode_entry *add_fsync_inode(struct f2fs_sb_info *sbi,
9696
return ERR_PTR(err);
9797
}
9898

99-
static void del_fsync_inode(struct fsync_inode_entry *entry)
99+
static void del_fsync_inode(struct fsync_inode_entry *entry, int drop)
100100
{
101+
if (drop) {
102+
/* inode should not be recovered, drop it */
103+
f2fs_inode_synced(entry->inode);
104+
}
101105
iput(entry->inode);
102106
list_del(&entry->list);
103107
kmem_cache_free(fsync_entry_slab, entry);
@@ -338,12 +342,12 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head,
338342
return err;
339343
}
340344

341-
static void destroy_fsync_dnodes(struct list_head *head)
345+
static void destroy_fsync_dnodes(struct list_head *head, int drop)
342346
{
343347
struct fsync_inode_entry *entry, *tmp;
344348

345349
list_for_each_entry_safe(entry, tmp, head, list)
346-
del_fsync_inode(entry);
350+
del_fsync_inode(entry, drop);
347351
}
348352

349353
static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
@@ -580,7 +584,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
580584
}
581585

582586
static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
583-
struct list_head *dir_list)
587+
struct list_head *tmp_inode_list, struct list_head *dir_list)
584588
{
585589
struct curseg_info *curseg;
586590
struct page *page = NULL;
@@ -634,7 +638,7 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
634638
}
635639

636640
if (entry->blkaddr == blkaddr)
637-
del_fsync_inode(entry);
641+
list_move_tail(&entry->list, tmp_inode_list);
638642
next:
639643
/* check next segment */
640644
blkaddr = next_blkaddr_of_node(page);
@@ -647,7 +651,7 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
647651

648652
int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
649653
{
650-
struct list_head inode_list;
654+
struct list_head inode_list, tmp_inode_list;
651655
struct list_head dir_list;
652656
int err;
653657
int ret = 0;
@@ -678,6 +682,7 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
678682
}
679683

680684
INIT_LIST_HEAD(&inode_list);
685+
INIT_LIST_HEAD(&tmp_inode_list);
681686
INIT_LIST_HEAD(&dir_list);
682687

683688
/* prevent checkpoint */
@@ -696,11 +701,16 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
696701
need_writecp = true;
697702

698703
/* step #2: recover data */
699-
err = recover_data(sbi, &inode_list, &dir_list);
704+
err = recover_data(sbi, &inode_list, &tmp_inode_list, &dir_list);
700705
if (!err)
701706
f2fs_bug_on(sbi, !list_empty(&inode_list));
707+
else {
708+
/* restore s_flags to let iput() trash data */
709+
sbi->sb->s_flags = s_flags;
710+
}
702711
skip:
703-
destroy_fsync_dnodes(&inode_list);
712+
destroy_fsync_dnodes(&inode_list, err);
713+
destroy_fsync_dnodes(&tmp_inode_list, err);
704714

705715
/* truncate meta pages to be used by the recovery */
706716
truncate_inode_pages_range(META_MAPPING(sbi),
@@ -709,13 +719,13 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
709719
if (err) {
710720
truncate_inode_pages_final(NODE_MAPPING(sbi));
711721
truncate_inode_pages_final(META_MAPPING(sbi));
722+
} else {
723+
clear_sbi_flag(sbi, SBI_POR_DOING);
712724
}
713-
714-
clear_sbi_flag(sbi, SBI_POR_DOING);
715725
mutex_unlock(&sbi->cp_mutex);
716726

717727
/* let's drop all the directory inodes for clean checkpoint */
718-
destroy_fsync_dnodes(&dir_list);
728+
destroy_fsync_dnodes(&dir_list, err);
719729

720730
if (need_writecp) {
721731
set_sbi_flag(sbi, SBI_IS_RECOVERED);

fs/f2fs/super.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1991,6 +1991,19 @@ void f2fs_quota_off_umount(struct super_block *sb)
19911991
}
19921992
}
19931993

1994+
static void f2fs_truncate_quota_inode_pages(struct super_block *sb)
1995+
{
1996+
struct quota_info *dqopt = sb_dqopt(sb);
1997+
int type;
1998+
1999+
for (type = 0; type < MAXQUOTAS; type++) {
2000+
if (!dqopt->files[type])
2001+
continue;
2002+
f2fs_inode_synced(dqopt->files[type]);
2003+
}
2004+
}
2005+
2006+
19942007
static int f2fs_get_projid(struct inode *inode, kprojid_t *projid)
19952008
{
19962009
*projid = F2FS_I(inode)->i_projid;
@@ -3281,10 +3294,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
32813294

32823295
free_meta:
32833296
#ifdef CONFIG_QUOTA
3297+
f2fs_truncate_quota_inode_pages(sb);
32843298
if (f2fs_sb_has_quota_ino(sb) && !f2fs_readonly(sb))
32853299
f2fs_quota_off_umount(sbi->sb);
32863300
#endif
3287-
f2fs_sync_inode_meta(sbi);
32883301
/*
32893302
* Some dirty meta pages can be produced by f2fs_recover_orphan_inodes()
32903303
* failed by EIO. Then, iput(node_inode) can trigger balance_fs_bg()

0 commit comments

Comments
 (0)