Skip to content

Commit e1bb7d3

Browse files
chaseyuJaegeuk Kim
authored andcommitted
f2fs: fix to recover quota data correctly
With -O quota mkfs option, xfstests generic/417 fails due to fsck detects data corruption on quota inodes. [ASSERT] (fsck_chk_quota_files:2051) --> Quota file is missing or invalid quota file content found. The root cause is there is a hole f2fs doesn't hold quota inodes, so all recovered quota data will be dropped due to SBI_POR_DOING flag was set. - f2fs_fill_super - f2fs_recover_orphan_inodes - f2fs_enable_quota_files - f2fs_quota_off_umount <--- quota inodes were dropped ---> - f2fs_recover_fsync_data - f2fs_enable_quota_files - f2fs_quota_off_umount This patch tries to eliminate the hole by holding quota inodes during entire recovery flow as below: - f2fs_fill_super - f2fs_recover_quota_begin - f2fs_recover_orphan_inodes - f2fs_recover_fsync_data - f2fs_recover_quota_end Then, recovered quota data can be persisted after SBI_POR_DOING is cleared. Signed-off-by: Chao Yu <chao@kernel.org> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
1 parent d78dfef commit e1bb7d3

5 files changed

Lines changed: 61 additions & 38 deletions

File tree

fs/f2fs/checkpoint.c

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -713,11 +713,7 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
713713
int f2fs_recover_orphan_inodes(struct f2fs_sb_info *sbi)
714714
{
715715
block_t start_blk, orphan_blocks, i, j;
716-
unsigned int s_flags = sbi->sb->s_flags;
717716
int err = 0;
718-
#ifdef CONFIG_QUOTA
719-
int quota_enabled;
720-
#endif
721717

722718
if (!is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG))
723719
return 0;
@@ -727,18 +723,8 @@ int f2fs_recover_orphan_inodes(struct f2fs_sb_info *sbi)
727723
return 0;
728724
}
729725

730-
if (s_flags & SB_RDONLY) {
726+
if (is_sbi_flag_set(sbi, SBI_IS_WRITABLE))
731727
f2fs_info(sbi, "orphan cleanup on readonly fs");
732-
sbi->sb->s_flags &= ~SB_RDONLY;
733-
}
734-
735-
#ifdef CONFIG_QUOTA
736-
/*
737-
* Turn on quotas which were not enabled for read-only mounts if
738-
* filesystem has quota feature, so that they are updated correctly.
739-
*/
740-
quota_enabled = f2fs_enable_quota_files(sbi, s_flags & SB_RDONLY);
741-
#endif
742728

743729
start_blk = __start_cp_addr(sbi) + 1 + __cp_payload(sbi);
744730
orphan_blocks = __start_sum_addr(sbi) - 1 - __cp_payload(sbi);
@@ -772,13 +758,6 @@ int f2fs_recover_orphan_inodes(struct f2fs_sb_info *sbi)
772758
out:
773759
set_sbi_flag(sbi, SBI_IS_RECOVERED);
774760

775-
#ifdef CONFIG_QUOTA
776-
/* Turn quotas off */
777-
if (quota_enabled)
778-
f2fs_quota_off_umount(sbi->sb);
779-
#endif
780-
sbi->sb->s_flags = s_flags; /* Restore SB_RDONLY status */
781-
782761
return err;
783762
}
784763

fs/f2fs/debug.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,7 @@ static const char *s_flag[MAX_SBI_FLAG] = {
352352
[SBI_QUOTA_NEED_REPAIR] = "quota_need_repair",
353353
[SBI_IS_RESIZEFS] = "resizefs",
354354
[SBI_IS_FREEZING] = "freezefs",
355+
[SBI_IS_WRITABLE] = "writable",
355356
};
356357

357358
static const char *ipu_mode_names[F2FS_IPU_MAX] = {

fs/f2fs/f2fs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,6 +1294,7 @@ enum {
12941294
SBI_QUOTA_NEED_REPAIR, /* quota file may be corrupted */
12951295
SBI_IS_RESIZEFS, /* resizefs is in process */
12961296
SBI_IS_FREEZING, /* freezefs is in process */
1297+
SBI_IS_WRITABLE, /* remove ro mountoption transiently */
12971298
MAX_SBI_FLAG,
12981299
};
12991300

fs/f2fs/recovery.c

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -825,19 +825,9 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
825825
unsigned long s_flags = sbi->sb->s_flags;
826826
bool need_writecp = false;
827827
bool fix_curseg_write_pointer = false;
828-
#ifdef CONFIG_QUOTA
829-
int quota_enabled;
830-
#endif
831828

832-
if (s_flags & SB_RDONLY) {
829+
if (is_sbi_flag_set(sbi, SBI_IS_WRITABLE))
833830
f2fs_info(sbi, "recover fsync data on readonly fs");
834-
sbi->sb->s_flags &= ~SB_RDONLY;
835-
}
836-
837-
#ifdef CONFIG_QUOTA
838-
/* Turn on quotas so that they are updated correctly */
839-
quota_enabled = f2fs_enable_quota_files(sbi, s_flags & SB_RDONLY);
840-
#endif
841831

842832
INIT_LIST_HEAD(&inode_list);
843833
INIT_LIST_HEAD(&tmp_inode_list);
@@ -909,11 +899,6 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
909899
}
910900
}
911901

912-
#ifdef CONFIG_QUOTA
913-
/* Turn quotas off */
914-
if (quota_enabled)
915-
f2fs_quota_off_umount(sbi->sb);
916-
#endif
917902
sbi->sb->s_flags = s_flags; /* Restore SB_RDONLY status */
918903

919904
return ret ? ret : err;

fs/f2fs/super.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2501,6 +2501,54 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
25012501
}
25022502

25032503
#ifdef CONFIG_QUOTA
2504+
static bool f2fs_need_recovery(struct f2fs_sb_info *sbi)
2505+
{
2506+
/* need to recovery orphan */
2507+
if (is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG))
2508+
return true;
2509+
/* need to recovery data */
2510+
if (test_opt(sbi, DISABLE_ROLL_FORWARD))
2511+
return false;
2512+
if (test_opt(sbi, NORECOVERY))
2513+
return false;
2514+
return !is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG);
2515+
}
2516+
2517+
static bool f2fs_recover_quota_begin(struct f2fs_sb_info *sbi)
2518+
{
2519+
bool readonly = f2fs_readonly(sbi->sb);
2520+
2521+
if (!f2fs_need_recovery(sbi))
2522+
return false;
2523+
2524+
/* it doesn't need to check f2fs_sb_has_readonly() */
2525+
if (f2fs_hw_is_readonly(sbi))
2526+
return false;
2527+
2528+
if (readonly) {
2529+
sbi->sb->s_flags &= ~SB_RDONLY;
2530+
set_sbi_flag(sbi, SBI_IS_WRITABLE);
2531+
}
2532+
2533+
/*
2534+
* Turn on quotas which were not enabled for read-only mounts if
2535+
* filesystem has quota feature, so that they are updated correctly.
2536+
*/
2537+
return f2fs_enable_quota_files(sbi, readonly);
2538+
}
2539+
2540+
static void f2fs_recover_quota_end(struct f2fs_sb_info *sbi,
2541+
bool quota_enabled)
2542+
{
2543+
if (quota_enabled)
2544+
f2fs_quota_off_umount(sbi->sb);
2545+
2546+
if (is_sbi_flag_set(sbi, SBI_IS_WRITABLE)) {
2547+
clear_sbi_flag(sbi, SBI_IS_WRITABLE);
2548+
sbi->sb->s_flags |= SB_RDONLY;
2549+
}
2550+
}
2551+
25042552
/* Read data from quotafile */
25052553
static ssize_t f2fs_quota_read(struct super_block *sb, int type, char *data,
25062554
size_t len, loff_t off)
@@ -4116,6 +4164,9 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
41164164
int recovery, i, valid_super_block;
41174165
struct curseg_info *seg_i;
41184166
int retry_cnt = 1;
4167+
#ifdef CONFIG_QUOTA
4168+
bool quota_enabled = false;
4169+
#endif
41194170

41204171
try_onemore:
41214172
err = -EINVAL;
@@ -4409,6 +4460,8 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
44094460
if (err)
44104461
f2fs_err(sbi, "Cannot turn on quotas: error %d", err);
44114462
}
4463+
4464+
quota_enabled = f2fs_recover_quota_begin(sbi);
44124465
#endif
44134466
/* if there are any orphan inodes, free them */
44144467
err = f2fs_recover_orphan_inodes(sbi);
@@ -4466,6 +4519,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
44664519
}
44674520
}
44684521

4522+
#ifdef CONFIG_QUOTA
4523+
f2fs_recover_quota_end(sbi, quota_enabled);
4524+
#endif
4525+
44694526
/*
44704527
* If the f2fs is not readonly and fsync data recovery succeeds,
44714528
* check zoned block devices' write pointer consistency.

0 commit comments

Comments
 (0)