Re: [f2fs-dev] [PATCH v2] f2fs: correct removexattr behavior for null valued extended attribute
On 2018/1/20 12:24, Jaegeuk Kim wrote: > On 01/17, Chao Yu wrote: >> Hi Jaegeuk, >> >> Forgot to merge this patch? ;) > > Weird. I didn't get this patch before. I'm sure it has been sent to f2fs mailing list, may be it's been junked? Anyway, I just resent it for Daeho Jeong, please check it. > Is this a full patch? > >> >> On 2018/1/10 10:24, Daeho Jeong wrote: >>> __vfs_removexattr() transfers "NULL" value to the setxattr handler of >>> the f2fs filesystem in order to remove the extended attribute. But, >>> __f2fs_setxattr() just ignores the removal request when the value of >>> the extended attribute is already NULL. We have to remove the extended >>> attribute itself even if the value of that is already NULL. >>> >>> We can reporduce this bug with the below: >>> >>> 1. touch file >>> 2. setfattr -n "user.foo" file >>> 3. setfattr -x "user.foo" file >>> 4. getfattr -d file user.foo >>> >>> Signed-off-by: Daeho Jeong>>> Signed-off-by: Youngjin Gil >>> Tested-by: Hobin Woo >>> Tested-by: Chao Yu >>> Reviewed-by: Chao Yu >>> --- >>> fs/f2fs/xattr.c | 2 +- >>> 1 file changed, 1 insertion(+), 1 deletion(-) >>> >>> diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c >>> index ec8961e..2776618 100644 >>> --- a/fs/f2fs/xattr.c >>> +++ b/fs/f2fs/xattr.c >>> @@ -598,7 +598,7 @@ static int __f2fs_setxattr(struct inode *inode, int >>> index, >>> goto exit; >>> } >>> >>> - if (f2fs_xattr_value_same(here, value, size)) >>> + if (value && f2fs_xattr_value_same(here, value, size)) >>> goto exit; >>> } else if ((flags & XATTR_REPLACE)) { >>> error = -ENODATA; >>> > > -- > Check out the vibrant tech community on one of the world's most > engaging tech sites, Slashdot.org! http://sdm.link/slashdot > ___ > Linux-f2fs-devel mailing list > Linux-f2fs-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel > -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH] f2fs: correct removexattr behavior for null valued extended attribute
From: Daeho Jeong__vfs_removexattr() transfers "NULL" value to the setxattr handler of the f2fs filesystem in order to remove the extended attribute. But, __f2fs_setxattr() just ignores the removal request when the value of the extended attribute is already NULL. We have to remove the extended attribute itself even if the value of that is already NULL. We can reporduce this bug with the below: 1. touch file 2. setfattr -n "user.foo" file 3. setfattr -x "user.foo" file 4. getfattr -d file > user.foo Signed-off-by: Daeho Jeong Signed-off-by: Youngjin Gil Tested-by: Hobin Woo Tested-by: Chao Yu Reviewed-by: Chao Yu Signed-off-by: Chao Yu --- fs/f2fs/xattr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c index 600162f4ddbf..ae2dfa709f5d 100644 --- a/fs/f2fs/xattr.c +++ b/fs/f2fs/xattr.c @@ -600,7 +600,7 @@ static int __f2fs_setxattr(struct inode *inode, int index, goto exit; } - if (f2fs_xattr_value_same(here, value, size)) + if (value && f2fs_xattr_value_same(here, value, size)) goto exit; } else if ((flags & XATTR_REPLACE)) { error = -ENODATA; -- 2.14.1.145.gb3622a4ee -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
Re: [f2fs-dev] [PATCH RFC] f2fs: add PRE2 to mark segments free to one checkpoint but obsolete to the other
Hi Weichao, On 2018/1/20 7:29, Weichao Guo wrote: > Currently, we set prefree segments as free ones after writing > a checkpoint, then believe the segments could be used safely. > However, if a sudden power-off coming and the newer checkpoint > corrupted due to hardware issues at the same time, we will try > to use the old checkpoint and may face an inconsistent file > system status. IIUC, you mean: 1. write nodes into segment x; 2. write checkpoint A; 3. remove nodes in segment x; 4. write checkpoint B; 5. issue discard or write datas into segment x; 6. sudden power-cut But after reboot, we found checkpoint B is corrupted due to hardware, and then start to use checkpoint A, but nodes in segment x recorded as valid data in checkpoint A has been overcovered in step 5), so we will encounter inconsistent meta data, right? Thanks, > > How about add an PRE2 status for prefree segments, and make > sure the segments could be used safely to both checkpoints? > Or any better solutions? Or this is not a problem? > > Look forward to your comments! > > Signed-off-by: Weichao Guo> --- > fs/f2fs/gc.c | 11 +-- > fs/f2fs/segment.c | 21 ++--- > fs/f2fs/segment.h | 6 ++ > 3 files changed, 33 insertions(+), 5 deletions(-) > > diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c > index 33e7969..153e3ea 100644 > --- a/fs/f2fs/gc.c > +++ b/fs/f2fs/gc.c > @@ -1030,7 +1030,12 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, >* threshold, we can make them free by checkpoint. Then, we >* secure free segments which doesn't need fggc any more. >*/ > - if (prefree_segments(sbi)) { > + if (prefree_segments(sbi) || prefree2_segments(sbi)) { > + ret = write_checkpoint(sbi, ); > + if (ret) > + goto stop; > + } > + if (has_not_enough_free_secs(sbi, 0, 0) && > prefree2_segments(sbi)) { > ret = write_checkpoint(sbi, ); > if (ret) > goto stop; > @@ -1063,8 +1068,10 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, > goto gc_more; > } > > - if (gc_type == FG_GC) > + if (gc_type == FG_GC) { > + ret = write_checkpoint(sbi, ); > ret = write_checkpoint(sbi, ); > + } > } > stop: > SIT_I(sbi)->last_victim[ALLOC_NEXT] = 0; > diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c > index 2e8e054d..9dec445 100644 > --- a/fs/f2fs/segment.c > +++ b/fs/f2fs/segment.c > @@ -1606,7 +1606,7 @@ static void set_prefree_as_free_segments(struct > f2fs_sb_info *sbi) > unsigned int segno; > > mutex_lock(_i->seglist_lock); > - for_each_set_bit(segno, dirty_i->dirty_segmap[PRE], MAIN_SEGS(sbi)) > + for_each_set_bit(segno, dirty_i->dirty_segmap[PRE2], MAIN_SEGS(sbi)) > __set_test_and_free(sbi, segno); > mutex_unlock(_i->seglist_lock); > } > @@ -1617,13 +1617,17 @@ void clear_prefree_segments(struct f2fs_sb_info *sbi, > struct cp_control *cpc) > struct list_head *head = >entry_list; > struct discard_entry *entry, *this; > struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); > - unsigned long *prefree_map = dirty_i->dirty_segmap[PRE]; > + unsigned long *prefree_map; > unsigned int start = 0, end = -1; > unsigned int secno, start_segno; > bool force = (cpc->reason & CP_DISCARD); > + int phase = 0; > + enum dirty_type dirty_type = PRE2; > > mutex_lock(_i->seglist_lock); > > +next_step: > + prefree_map = dirty_i->dirty_segmap[dirty_type]; > while (1) { > int i; > start = find_next_bit(prefree_map, MAIN_SEGS(sbi), end + 1); > @@ -1635,7 +1639,7 @@ void clear_prefree_segments(struct f2fs_sb_info *sbi, > struct cp_control *cpc) > for (i = start; i < end; i++) > clear_bit(i, prefree_map); > > - dirty_i->nr_dirty[PRE] -= end - start; > + dirty_i->nr_dirty[dirty_type] -= end - start; > > if (!test_opt(sbi, DISCARD)) > continue; > @@ -1663,6 +1667,16 @@ void clear_prefree_segments(struct f2fs_sb_info *sbi, > struct cp_control *cpc) > else > end = start - 1; > } > + if (phase == 0) { > + /* status change: PRE -> PRE2 */ > + for_each_set_bit(segno, dirty_i->dirty_segmap[PRE], > MAIN_SEGS(sbi)) > + if (!test_and_set_bit(segno, prefree_map)) > + dirty_i->nr_dirty[PRE2]++; > + > + phase = 1; > + dirty_type = PRE; > + goto next_step; > + } > mutex_unlock(_i->seglist_lock); > > /* send small discards */ > @@ -2245,6 +2259,7 @@ static void
[f2fs-dev] [PATCH 1/2] f2fs: allow to recover node blocks given updated checkpoint
If fsck.f2fs changes crc, we have no way to recover some inode blocks by roll- forward recovery. Let's relax the condition to recover them. Signed-off-by: Jaegeuk Kim--- fs/f2fs/node.h | 7 --- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h index 0ee3e5ff49a3..15280eeb24ea 100644 --- a/fs/f2fs/node.h +++ b/fs/f2fs/node.h @@ -305,10 +305,11 @@ static inline bool is_recoverable_dnode(struct page *page) struct f2fs_checkpoint *ckpt = F2FS_CKPT(F2FS_P_SB(page)); __u64 cp_ver = cur_cp_version(ckpt); - if (__is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG)) + if (__is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG)) { cp_ver |= (cur_cp_crc(ckpt) << 32); - - return cp_ver == cpver_of_node(page); + return cp_ver == cpver_of_node(page); + } + return (cp_ver << 32) == (cpver_of_node(page) << 32); } /* -- 2.15.0.531.g2ccb3012c9-goog -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH 2/2] f2fs: recover some i_inline flags
This fixes lost i_inline flags during roll-forward. Signed-off-by: Jaegeuk Kim--- fs/f2fs/recovery.c | 9 + 1 file changed, 9 insertions(+) diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index cbeef73bc4dd..2354f1e05e19 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -211,6 +211,15 @@ static void recover_inode(struct inode *inode, struct page *page) F2FS_I(inode)->i_advise = raw->i_advise; + if (raw->i_inline & F2FS_PIN_FILE) + set_inode_flag(inode, FI_PIN_FILE); + if (raw->i_inline & F2FS_DATA_EXIST) + set_inode_flag(inode, FI_DATA_EXIST); + else + clear_inode_flag(inode, FI_DATA_EXIST); + if (!(raw->i_inline & F2FS_INLINE_DOTS)) + clear_inode_flag(inode, FI_INLINE_DOTS); + if (file_enc_name(inode)) name = ""; else -- 2.15.0.531.g2ccb3012c9-goog -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
Re: [f2fs-dev] [PATCH v2] f2fs: correct removexattr behavior for null valued extended attribute
On 01/17, Chao Yu wrote: > Hi Jaegeuk, > > Forgot to merge this patch? ;) Weird. I didn't get this patch before. Is this a full patch? > > On 2018/1/10 10:24, Daeho Jeong wrote: > > __vfs_removexattr() transfers "NULL" value to the setxattr handler of > > the f2fs filesystem in order to remove the extended attribute. But, > > __f2fs_setxattr() just ignores the removal request when the value of > > the extended attribute is already NULL. We have to remove the extended > > attribute itself even if the value of that is already NULL. > > > > We can reporduce this bug with the below: > > > > 1. touch file > > 2. setfattr -n "user.foo" file > > 3. setfattr -x "user.foo" file > > 4. getfattr -d file > >> user.foo > > > > Signed-off-by: Daeho Jeong> > Signed-off-by: Youngjin Gil > > Tested-by: Hobin Woo > > Tested-by: Chao Yu > > Reviewed-by: Chao Yu > > --- > > fs/f2fs/xattr.c | 2 +- > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c > > index ec8961e..2776618 100644 > > --- a/fs/f2fs/xattr.c > > +++ b/fs/f2fs/xattr.c > > @@ -598,7 +598,7 @@ static int __f2fs_setxattr(struct inode *inode, int > > index, > > goto exit; > > } > > > > - if (f2fs_xattr_value_same(here, value, size)) > > + if (value && f2fs_xattr_value_same(here, value, size)) > > goto exit; > > } else if ((flags & XATTR_REPLACE)) { > > error = -ENODATA; > > -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
Re: [f2fs-dev] [PATCH RFC] f2fs: add PRE2 to mark segments free to one checkpoint but obsolete to the other
Hi Weichao, On 2018/1/19 23:47, guoweichao wrote: A critical case is using the free segments as data segments which are previously node segments to the old checkpoint. With fault injecting of the newer CP pack, fsck can find errors when checking the sanity of nid. Sorry to interrupt because I'm just curious about this scenario and the detail. As far as I know, if the whole blocks in a segment become invalid, the segment will become PREFREE, and then if a checkpoint is followed, we can reuse this segment or discard the whole segment safely after this checkpoint was done (I think It makes sure that this segment is certainly FREE and not reused in this checkpoint). If the segment in the old checkpoint is a node segment, and node blocks in the segment are all invalid until the new checkpoint. It seems no danger to reuse the FREE node segment as a data segment in the next checkpoint? or something related to SPOR? In my mind f2fs-tools ignores POR node chain... Thanks, On 2018/1/20 7:29, Weichao Guo wrote: Currently, we set prefree segments as free ones after writing a checkpoint, then believe the segments could be used safely. However, if a sudden power-off coming and the newer checkpoint corrupted due to hardware issues at the same time, we will try to use the old checkpoint and may face an inconsistent file system status. How about add an PRE2 status for prefree segments, and make sure the segments could be used safely to both checkpoints? Or any better solutions? Or this is not a problem? Look forward to your comments! Signed-off-by: Weichao Guo--- fs/f2fs/gc.c | 11 +-- fs/f2fs/segment.c | 21 ++--- fs/f2fs/segment.h | 6 ++ 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 33e7969..153e3ea 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -1030,7 +1030,12 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, * threshold, we can make them free by checkpoint. Then, we * secure free segments which doesn't need fggc any more. */ - if (prefree_segments(sbi)) { + if (prefree_segments(sbi) || prefree2_segments(sbi)) { + ret = write_checkpoint(sbi, ); + if (ret) + goto stop; + } + if (has_not_enough_free_secs(sbi, 0, 0) && prefree2_segments(sbi)) { ret = write_checkpoint(sbi, ); if (ret) goto stop; @@ -1063,8 +1068,10 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, goto gc_more; } - if (gc_type == FG_GC) + if (gc_type == FG_GC) { + ret = write_checkpoint(sbi, ); ret = write_checkpoint(sbi, ); + } } stop: SIT_I(sbi)->last_victim[ALLOC_NEXT] = 0; diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 2e8e054d..9dec445 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1606,7 +1606,7 @@ static void set_prefree_as_free_segments(struct f2fs_sb_info *sbi) unsigned int segno; mutex_lock(_i->seglist_lock); - for_each_set_bit(segno, dirty_i->dirty_segmap[PRE], MAIN_SEGS(sbi)) + for_each_set_bit(segno, dirty_i->dirty_segmap[PRE2], MAIN_SEGS(sbi)) __set_test_and_free(sbi, segno); mutex_unlock(_i->seglist_lock); } @@ -1617,13 +1617,17 @@ void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc) struct list_head *head = >entry_list; struct discard_entry *entry, *this; struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); - unsigned long *prefree_map = dirty_i->dirty_segmap[PRE]; + unsigned long *prefree_map; unsigned int start = 0, end = -1; unsigned int secno, start_segno; bool force = (cpc->reason & CP_DISCARD); + int phase = 0; + enum dirty_type dirty_type = PRE2; mutex_lock(_i->seglist_lock); +next_step: + prefree_map = dirty_i->dirty_segmap[dirty_type]; while (1) { int i; start = find_next_bit(prefree_map, MAIN_SEGS(sbi), end + 1); @@ -1635,7 +1639,7 @@ void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc) for (i = start; i < end; i++) clear_bit(i, prefree_map); - dirty_i->nr_dirty[PRE] -= end - start; + dirty_i->nr_dirty[dirty_type] -= end - start; if (!test_opt(sbi, DISCARD)) continue; @@ -1663,6 +1667,16 @@ void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc) else end = start - 1; } + if (phase == 0) { + /* status change: PRE -> PRE2 */ + for_each_set_bit(segno,
Re: [f2fs-dev] [PATCH RFC] f2fs: add PRE2 to mark segments free to one checkpoint but obsolete to the other
A critical case is using the free segments as data segments which are previously node segments to the old checkpoint. With fault injecting of the newer CP pack, fsck can find errors when checking the sanity of nid. On 2018/1/20 7:29, Weichao Guo wrote: > Currently, we set prefree segments as free ones after writing > a checkpoint, then believe the segments could be used safely. > However, if a sudden power-off coming and the newer checkpoint > corrupted due to hardware issues at the same time, we will try > to use the old checkpoint and may face an inconsistent file > system status. > > How about add an PRE2 status for prefree segments, and make > sure the segments could be used safely to both checkpoints? > Or any better solutions? Or this is not a problem? > > Look forward to your comments! > > Signed-off-by: Weichao Guo> --- > fs/f2fs/gc.c | 11 +-- > fs/f2fs/segment.c | 21 ++--- > fs/f2fs/segment.h | 6 ++ > 3 files changed, 33 insertions(+), 5 deletions(-) > > diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c > index 33e7969..153e3ea 100644 > --- a/fs/f2fs/gc.c > +++ b/fs/f2fs/gc.c > @@ -1030,7 +1030,12 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, >* threshold, we can make them free by checkpoint. Then, we >* secure free segments which doesn't need fggc any more. >*/ > - if (prefree_segments(sbi)) { > + if (prefree_segments(sbi) || prefree2_segments(sbi)) { > + ret = write_checkpoint(sbi, ); > + if (ret) > + goto stop; > + } > + if (has_not_enough_free_secs(sbi, 0, 0) && > prefree2_segments(sbi)) { > ret = write_checkpoint(sbi, ); > if (ret) > goto stop; > @@ -1063,8 +1068,10 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, > goto gc_more; > } > > - if (gc_type == FG_GC) > + if (gc_type == FG_GC) { > + ret = write_checkpoint(sbi, ); > ret = write_checkpoint(sbi, ); > + } > } > stop: > SIT_I(sbi)->last_victim[ALLOC_NEXT] = 0; > diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c > index 2e8e054d..9dec445 100644 > --- a/fs/f2fs/segment.c > +++ b/fs/f2fs/segment.c > @@ -1606,7 +1606,7 @@ static void set_prefree_as_free_segments(struct > f2fs_sb_info *sbi) > unsigned int segno; > > mutex_lock(_i->seglist_lock); > - for_each_set_bit(segno, dirty_i->dirty_segmap[PRE], MAIN_SEGS(sbi)) > + for_each_set_bit(segno, dirty_i->dirty_segmap[PRE2], MAIN_SEGS(sbi)) > __set_test_and_free(sbi, segno); > mutex_unlock(_i->seglist_lock); > } > @@ -1617,13 +1617,17 @@ void clear_prefree_segments(struct f2fs_sb_info *sbi, > struct cp_control *cpc) > struct list_head *head = >entry_list; > struct discard_entry *entry, *this; > struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); > - unsigned long *prefree_map = dirty_i->dirty_segmap[PRE]; > + unsigned long *prefree_map; > unsigned int start = 0, end = -1; > unsigned int secno, start_segno; > bool force = (cpc->reason & CP_DISCARD); > + int phase = 0; > + enum dirty_type dirty_type = PRE2; > > mutex_lock(_i->seglist_lock); > > +next_step: > + prefree_map = dirty_i->dirty_segmap[dirty_type]; > while (1) { > int i; > start = find_next_bit(prefree_map, MAIN_SEGS(sbi), end + 1); > @@ -1635,7 +1639,7 @@ void clear_prefree_segments(struct f2fs_sb_info *sbi, > struct cp_control *cpc) > for (i = start; i < end; i++) > clear_bit(i, prefree_map); > > - dirty_i->nr_dirty[PRE] -= end - start; > + dirty_i->nr_dirty[dirty_type] -= end - start; > > if (!test_opt(sbi, DISCARD)) > continue; > @@ -1663,6 +1667,16 @@ void clear_prefree_segments(struct f2fs_sb_info *sbi, > struct cp_control *cpc) > else > end = start - 1; > } > + if (phase == 0) { > + /* status change: PRE -> PRE2 */ > + for_each_set_bit(segno, dirty_i->dirty_segmap[PRE], > MAIN_SEGS(sbi)) > + if (!test_and_set_bit(segno, prefree_map)) > + dirty_i->nr_dirty[PRE2]++; > + > + phase = 1; > + dirty_type = PRE; > + goto next_step; > + } > mutex_unlock(_i->seglist_lock); > > /* send small discards */ > @@ -2245,6 +2259,7 @@ static void change_curseg(struct f2fs_sb_info *sbi, int > type) > > mutex_lock(_i->seglist_lock); > __remove_dirty_segment(sbi, new_segno, PRE); > + __remove_dirty_segment(sbi, new_segno, PRE2); > __remove_dirty_segment(sbi, new_segno, DIRTY); >
[f2fs-dev] [PATCH RFC] f2fs: add PRE2 to mark segments free to one checkpoint but obsolete to the other
Currently, we set prefree segments as free ones after writing a checkpoint, then believe the segments could be used safely. However, if a sudden power-off coming and the newer checkpoint corrupted due to hardware issues at the same time, we will try to use the old checkpoint and may face an inconsistent file system status. How about add an PRE2 status for prefree segments, and make sure the segments could be used safely to both checkpoints? Or any better solutions? Or this is not a problem? Look forward to your comments! Signed-off-by: Weichao Guo--- fs/f2fs/gc.c | 11 +-- fs/f2fs/segment.c | 21 ++--- fs/f2fs/segment.h | 6 ++ 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 33e7969..153e3ea 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -1030,7 +1030,12 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, * threshold, we can make them free by checkpoint. Then, we * secure free segments which doesn't need fggc any more. */ - if (prefree_segments(sbi)) { + if (prefree_segments(sbi) || prefree2_segments(sbi)) { + ret = write_checkpoint(sbi, ); + if (ret) + goto stop; + } + if (has_not_enough_free_secs(sbi, 0, 0) && prefree2_segments(sbi)) { ret = write_checkpoint(sbi, ); if (ret) goto stop; @@ -1063,8 +1068,10 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, goto gc_more; } - if (gc_type == FG_GC) + if (gc_type == FG_GC) { + ret = write_checkpoint(sbi, ); ret = write_checkpoint(sbi, ); + } } stop: SIT_I(sbi)->last_victim[ALLOC_NEXT] = 0; diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 2e8e054d..9dec445 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1606,7 +1606,7 @@ static void set_prefree_as_free_segments(struct f2fs_sb_info *sbi) unsigned int segno; mutex_lock(_i->seglist_lock); - for_each_set_bit(segno, dirty_i->dirty_segmap[PRE], MAIN_SEGS(sbi)) + for_each_set_bit(segno, dirty_i->dirty_segmap[PRE2], MAIN_SEGS(sbi)) __set_test_and_free(sbi, segno); mutex_unlock(_i->seglist_lock); } @@ -1617,13 +1617,17 @@ void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc) struct list_head *head = >entry_list; struct discard_entry *entry, *this; struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); - unsigned long *prefree_map = dirty_i->dirty_segmap[PRE]; + unsigned long *prefree_map; unsigned int start = 0, end = -1; unsigned int secno, start_segno; bool force = (cpc->reason & CP_DISCARD); + int phase = 0; + enum dirty_type dirty_type = PRE2; mutex_lock(_i->seglist_lock); +next_step: + prefree_map = dirty_i->dirty_segmap[dirty_type]; while (1) { int i; start = find_next_bit(prefree_map, MAIN_SEGS(sbi), end + 1); @@ -1635,7 +1639,7 @@ void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc) for (i = start; i < end; i++) clear_bit(i, prefree_map); - dirty_i->nr_dirty[PRE] -= end - start; + dirty_i->nr_dirty[dirty_type] -= end - start; if (!test_opt(sbi, DISCARD)) continue; @@ -1663,6 +1667,16 @@ void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc) else end = start - 1; } + if (phase == 0) { + /* status change: PRE -> PRE2 */ + for_each_set_bit(segno, dirty_i->dirty_segmap[PRE], MAIN_SEGS(sbi)) + if (!test_and_set_bit(segno, prefree_map)) + dirty_i->nr_dirty[PRE2]++; + + phase = 1; + dirty_type = PRE; + goto next_step; + } mutex_unlock(_i->seglist_lock); /* send small discards */ @@ -2245,6 +2259,7 @@ static void change_curseg(struct f2fs_sb_info *sbi, int type) mutex_lock(_i->seglist_lock); __remove_dirty_segment(sbi, new_segno, PRE); + __remove_dirty_segment(sbi, new_segno, PRE2); __remove_dirty_segment(sbi, new_segno, DIRTY); mutex_unlock(_i->seglist_lock); diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index 71a2aaa..f702726 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -263,6 +263,7 @@ enum dirty_type { DIRTY_COLD_NODE,/* dirty segments assigned as cold node logs */ DIRTY, /* to count # of dirty segments */ PRE,