Skip to content

Commit 68d0569

Browse files
chaseyuJaegeuk Kim
authored andcommitted
f2fs: fix to detect recoverable inode during dryrun of find_fsync_dnodes()
mkfs.f2fs -f /dev/vdd mount /dev/vdd /mnt/f2fs touch /mnt/f2fs/foo sync # avoid CP_UMOUNT_FLAG in last f2fs_checkpoint.ckpt_flags touch /mnt/f2fs/bar f2fs_io fsync /mnt/f2fs/bar f2fs_io shutdown 2 /mnt/f2fs umount /mnt/f2fs blockdev --setro /dev/vdd mount /dev/vdd /mnt/f2fs mount: /mnt/f2fs: WARNING: source write-protected, mounted read-only. For the case if we create and fsync a new inode before sudden power-cut, without norecovery or disable_roll_forward mount option, the following mount will succeed w/o recovering last fsynced inode. The problem here is that we only check inode_list list after find_fsync_dnodes() in f2fs_recover_fsync_data() to find out whether there is recoverable data in the iamge, but there is a missed case, if last fsynced inode is not existing in last checkpoint, then, we will fail to get its inode due to nat of inode node is not existing in last checkpoint, so the inode won't be linked in inode_list. Let's detect such case in dyrun mode to fix this issue. After this change, mount will fail as expected below: mount: /mnt/f2fs: cannot mount /dev/vdd read-only. dmesg(1) may have more information after failed mount system call. demsg: F2FS-fs (vdd): Need to recover fsync data, but write access unavailable, please try mount w/ disable_roll_forward or norecovery Cc: stable@kernel.org Fixes: 6781eab ("f2fs: give -EINVAL for norecovery and rw mount") Signed-off-by: Chao Yu <chao@kernel.org> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
1 parent 01fba45 commit 68d0569

1 file changed

Lines changed: 12 additions & 8 deletions

File tree

fs/f2fs/recovery.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ static int sanity_check_node_chain(struct f2fs_sb_info *sbi, block_t blkaddr,
399399
}
400400

401401
static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head,
402-
bool check_only)
402+
bool check_only, bool *new_inode)
403403
{
404404
struct curseg_info *curseg;
405405
block_t blkaddr, blkaddr_fast;
@@ -447,16 +447,19 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head,
447447
quota_inode = true;
448448
}
449449

450-
/*
451-
* CP | dnode(F) | inode(DF)
452-
* For this case, we should not give up now.
453-
*/
454450
entry = add_fsync_inode(sbi, head, ino_of_node(folio),
455451
quota_inode);
456452
if (IS_ERR(entry)) {
457453
err = PTR_ERR(entry);
458-
if (err == -ENOENT)
454+
/*
455+
* CP | dnode(F) | inode(DF)
456+
* For this case, we should not give up now.
457+
*/
458+
if (err == -ENOENT) {
459+
if (check_only)
460+
*new_inode = true;
459461
goto next;
462+
}
460463
f2fs_folio_put(folio, true);
461464
break;
462465
}
@@ -875,6 +878,7 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
875878
int ret = 0;
876879
unsigned long s_flags = sbi->sb->s_flags;
877880
bool need_writecp = false;
881+
bool new_inode = false;
878882

879883
f2fs_notice(sbi, "f2fs_recover_fsync_data: recovery fsync data, "
880884
"check_only: %d", check_only);
@@ -890,8 +894,8 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
890894
f2fs_down_write(&sbi->cp_global_sem);
891895

892896
/* step #1: find fsynced inode numbers */
893-
err = find_fsync_dnodes(sbi, &inode_list, check_only);
894-
if (err || list_empty(&inode_list))
897+
err = find_fsync_dnodes(sbi, &inode_list, check_only, &new_inode);
898+
if (err < 0 || (list_empty(&inode_list) && (!check_only || !new_inode)))
895899
goto skip;
896900

897901
if (check_only) {

0 commit comments

Comments
 (0)