Skip to content

Commit 7141912

Browse files
chaseyuJaegeuk Kim
authored andcommitted
f2fs: give priority to select unpinned section for foreground GC
Previously, during foreground GC, if victims contain data of pinned file, it will fail migration of the data, and meanwhile i_gc_failures of that pinned file may increase, and when it exceeds threshold, GC will unpin the file, result in breaking pinfile's semantics. In order to mitigate such condition, let's record and skip section which has pinned file's data and give priority to select unpinned one. Signed-off-by: Chao Yu <chao.yu@oppo.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
1 parent 6b8beca commit 7141912

3 files changed

Lines changed: 82 additions & 14 deletions

File tree

fs/f2fs/gc.c

Lines changed: 71 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,54 @@ static void release_victim_entry(struct f2fs_sb_info *sbi)
646646
f2fs_bug_on(sbi, !list_empty(&am->victim_list));
647647
}
648648

649+
static bool f2fs_pin_section(struct f2fs_sb_info *sbi, unsigned int segno)
650+
{
651+
struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
652+
unsigned int secno = GET_SEC_FROM_SEG(sbi, segno);
653+
654+
if (!dirty_i->enable_pin_section)
655+
return false;
656+
if (!test_and_set_bit(secno, dirty_i->pinned_secmap))
657+
dirty_i->pinned_secmap_cnt++;
658+
return true;
659+
}
660+
661+
static bool f2fs_pinned_section_exists(struct dirty_seglist_info *dirty_i)
662+
{
663+
return dirty_i->pinned_secmap_cnt;
664+
}
665+
666+
static bool f2fs_section_is_pinned(struct dirty_seglist_info *dirty_i,
667+
unsigned int secno)
668+
{
669+
return dirty_i->enable_pin_section &&
670+
f2fs_pinned_section_exists(dirty_i) &&
671+
test_bit(secno, dirty_i->pinned_secmap);
672+
}
673+
674+
static void f2fs_unpin_all_sections(struct f2fs_sb_info *sbi, bool enable)
675+
{
676+
unsigned int bitmap_size = f2fs_bitmap_size(MAIN_SECS(sbi));
677+
678+
if (f2fs_pinned_section_exists(DIRTY_I(sbi))) {
679+
memset(DIRTY_I(sbi)->pinned_secmap, 0, bitmap_size);
680+
DIRTY_I(sbi)->pinned_secmap_cnt = 0;
681+
}
682+
DIRTY_I(sbi)->enable_pin_section = enable;
683+
}
684+
685+
static int f2fs_gc_pinned_control(struct inode *inode, int gc_type,
686+
unsigned int segno)
687+
{
688+
if (!f2fs_is_pinned_file(inode))
689+
return 0;
690+
if (gc_type != FG_GC)
691+
return -EBUSY;
692+
if (!f2fs_pin_section(F2FS_I_SB(inode), segno))
693+
f2fs_pin_file_control(inode, true);
694+
return -EAGAIN;
695+
}
696+
649697
/*
650698
* This function is called from two paths.
651699
* One is garbage collection and the other is SSR segment selection.
@@ -787,6 +835,9 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
787835
if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap))
788836
goto next;
789837

838+
if (gc_type == FG_GC && f2fs_section_is_pinned(dirty_i, secno))
839+
goto next;
840+
790841
if (is_atgc) {
791842
add_victim_entry(sbi, &p, segno);
792843
goto next;
@@ -1201,12 +1252,9 @@ static int move_data_block(struct inode *inode, block_t bidx,
12011252
goto out;
12021253
}
12031254

1204-
if (f2fs_is_pinned_file(inode)) {
1205-
if (gc_type == FG_GC)
1206-
f2fs_pin_file_control(inode, true);
1207-
err = -EAGAIN;
1255+
err = f2fs_gc_pinned_control(inode, gc_type, segno);
1256+
if (err)
12081257
goto out;
1209-
}
12101258

12111259
set_new_dnode(&dn, inode, NULL, NULL, 0);
12121260
err = f2fs_get_dnode_of_data(&dn, bidx, LOOKUP_NODE);
@@ -1351,12 +1399,9 @@ static int move_data_page(struct inode *inode, block_t bidx, int gc_type,
13511399
err = -EAGAIN;
13521400
goto out;
13531401
}
1354-
if (f2fs_is_pinned_file(inode)) {
1355-
if (gc_type == FG_GC)
1356-
f2fs_pin_file_control(inode, true);
1357-
err = -EAGAIN;
1402+
err = f2fs_gc_pinned_control(inode, gc_type, segno);
1403+
if (err)
13581404
goto out;
1359-
}
13601405

13611406
if (gc_type == BG_GC) {
13621407
if (PageWriteback(page)) {
@@ -1476,14 +1521,15 @@ static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
14761521
ofs_in_node = le16_to_cpu(entry->ofs_in_node);
14771522

14781523
if (phase == 3) {
1524+
int err;
1525+
14791526
inode = f2fs_iget(sb, dni.ino);
14801527
if (IS_ERR(inode) || is_bad_inode(inode) ||
14811528
special_file(inode->i_mode))
14821529
continue;
14831530

1484-
if (is_inode_flag_set(inode, FI_PIN_FILE) &&
1485-
gc_type == FG_GC) {
1486-
f2fs_pin_file_control(inode, true);
1531+
err = f2fs_gc_pinned_control(inode, gc_type, segno);
1532+
if (err == -EAGAIN) {
14871533
iput(inode);
14881534
return submitted;
14891535
}
@@ -1766,9 +1812,17 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync,
17661812
ret = -EINVAL;
17671813
goto stop;
17681814
}
1815+
retry:
17691816
ret = __get_victim(sbi, &segno, gc_type);
1770-
if (ret)
1817+
if (ret) {
1818+
/* allow to search victim from sections has pinned data */
1819+
if (ret == -ENODATA && gc_type == FG_GC &&
1820+
f2fs_pinned_section_exists(DIRTY_I(sbi))) {
1821+
f2fs_unpin_all_sections(sbi, false);
1822+
goto retry;
1823+
}
17711824
goto stop;
1825+
}
17721826

17731827
seg_freed = do_garbage_collect(sbi, segno, &gc_list, gc_type, force);
17741828
if (gc_type == FG_GC &&
@@ -1819,6 +1873,9 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync,
18191873
SIT_I(sbi)->last_victim[ALLOC_NEXT] = 0;
18201874
SIT_I(sbi)->last_victim[FLUSH_DEVICE] = init_segno;
18211875

1876+
if (gc_type == FG_GC)
1877+
f2fs_unpin_all_sections(sbi, true);
1878+
18221879
trace_f2fs_gc_end(sbi->sb, ret, total_freed, sec_freed,
18231880
get_pages(sbi, F2FS_DIRTY_NODES),
18241881
get_pages(sbi, F2FS_DIRTY_DENTS),

fs/f2fs/segment.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4654,6 +4654,13 @@ static int init_victim_secmap(struct f2fs_sb_info *sbi)
46544654
dirty_i->victim_secmap = f2fs_kvzalloc(sbi, bitmap_size, GFP_KERNEL);
46554655
if (!dirty_i->victim_secmap)
46564656
return -ENOMEM;
4657+
4658+
dirty_i->pinned_secmap = f2fs_kvzalloc(sbi, bitmap_size, GFP_KERNEL);
4659+
if (!dirty_i->pinned_secmap)
4660+
return -ENOMEM;
4661+
4662+
dirty_i->pinned_secmap_cnt = 0;
4663+
dirty_i->enable_pin_section = true;
46574664
return 0;
46584665
}
46594666

@@ -5242,6 +5249,7 @@ static void destroy_victim_secmap(struct f2fs_sb_info *sbi)
52425249
{
52435250
struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
52445251

5252+
kvfree(dirty_i->pinned_secmap);
52455253
kvfree(dirty_i->victim_secmap);
52465254
}
52475255

fs/f2fs/segment.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,9 @@ struct dirty_seglist_info {
295295
struct mutex seglist_lock; /* lock for segment bitmaps */
296296
int nr_dirty[NR_DIRTY_TYPE]; /* # of dirty segments */
297297
unsigned long *victim_secmap; /* background GC victims */
298+
unsigned long *pinned_secmap; /* pinned victims from foreground GC */
299+
unsigned int pinned_secmap_cnt; /* count of victims which has pinned data */
300+
bool enable_pin_section; /* enable pinning section */
298301
};
299302

300303
/* victim selection function for cleaning and SSR */

0 commit comments

Comments
 (0)