Skip to content

Commit 176740b

Browse files
Jaegeuk KimHashcode
authored andcommitted
f2fs: clarify and enhance the f2fs_gc flow
This patch makes clearer the ambiguous f2fs_gc flow as follows. 1. Remove intermediate checkpoint condition during f2fs_gc (i.e., should_do_checkpoint() and GC_BLOCKED) 2. Remove unnecessary return values of f2fs_gc because of #1. (i.e., GC_NODE, GC_OK, etc) 3. Simplify write_checkpoint() because of #2. 4. Clarify the main f2fs_gc flow. o monitor how many freed sections during one iteration of do_garbage_collect(). o do GC more without checkpoints if we can't get enough free sections. o do checkpoint once we've got enough free sections through forground GCs. 5. Adopt thread-logging (Slack-Space-Recycle) scheme more aggressively on data log types. See. get_ssr_segement() Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
1 parent cd24284 commit 176740b

File tree

9 files changed

+72
-105
lines changed

9 files changed

+72
-105
lines changed

fs/f2fs/checkpoint.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi)
539539
/*
540540
* Freeze all the FS-operations for checkpoint.
541541
*/
542-
void block_operations(struct f2fs_sb_info *sbi)
542+
static void block_operations(struct f2fs_sb_info *sbi)
543543
{
544544
int t;
545545
struct writeback_control wbc = {
@@ -722,15 +722,13 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
722722
/*
723723
* We guarantee that this checkpoint procedure should not fail.
724724
*/
725-
void write_checkpoint(struct f2fs_sb_info *sbi, bool blocked, bool is_umount)
725+
void write_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
726726
{
727727
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
728728
unsigned long long ckpt_ver;
729729

730-
if (!blocked) {
731-
mutex_lock(&sbi->cp_mutex);
732-
block_operations(sbi);
733-
}
730+
mutex_lock(&sbi->cp_mutex);
731+
block_operations(sbi);
734732

735733
f2fs_submit_bio(sbi, DATA, true);
736734
f2fs_submit_bio(sbi, NODE, true);

fs/f2fs/f2fs.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -975,8 +975,7 @@ int get_valid_checkpoint(struct f2fs_sb_info *);
975975
void set_dirty_dir_page(struct inode *, struct page *);
976976
void remove_dirty_dir_inode(struct inode *);
977977
void sync_dirty_dir_inodes(struct f2fs_sb_info *);
978-
void block_operations(struct f2fs_sb_info *);
979-
void write_checkpoint(struct f2fs_sb_info *, bool, bool);
978+
void write_checkpoint(struct f2fs_sb_info *, bool);
980979
void init_orphan_info(struct f2fs_sb_info *);
981980
int __init create_checkpoint_caches(void);
982981
void destroy_checkpoint_caches(void);

fs/f2fs/gc.c

Lines changed: 41 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ static int gc_thread_func(void *data)
7878

7979
sbi->bg_gc++;
8080

81-
if (f2fs_gc(sbi) == GC_NONE)
81+
/* if return value is not zero, no victim was selected */
82+
if (f2fs_gc(sbi))
8283
wait_ms = GC_THREAD_NOGC_SLEEP_TIME;
8384
else if (wait_ms == GC_THREAD_NOGC_SLEEP_TIME)
8485
wait_ms = GC_THREAD_MAX_SLEEP_TIME;
@@ -360,15 +361,15 @@ static int check_valid_map(struct f2fs_sb_info *sbi,
360361
sentry = get_seg_entry(sbi, segno);
361362
ret = f2fs_test_bit(offset, sentry->cur_valid_map);
362363
mutex_unlock(&sit_i->sentry_lock);
363-
return ret ? GC_OK : GC_NEXT;
364+
return ret;
364365
}
365366

366367
/*
367368
* This function compares node address got in summary with that in NAT.
368369
* On validity, copy that node with cold status, otherwise (invalid node)
369370
* ignore that.
370371
*/
371-
static int gc_node_segment(struct f2fs_sb_info *sbi,
372+
static void gc_node_segment(struct f2fs_sb_info *sbi,
372373
struct f2fs_summary *sum, unsigned int segno, int gc_type)
373374
{
374375
bool initial = true;
@@ -380,21 +381,12 @@ static int gc_node_segment(struct f2fs_sb_info *sbi,
380381
for (off = 0; off < sbi->blocks_per_seg; off++, entry++) {
381382
nid_t nid = le32_to_cpu(entry->nid);
382383
struct page *node_page;
383-
int err;
384384

385-
/*
386-
* It makes sure that free segments are able to write
387-
* all the dirty node pages before CP after this CP.
388-
* So let's check the space of dirty node pages.
389-
*/
390-
if (should_do_checkpoint(sbi)) {
391-
mutex_lock(&sbi->cp_mutex);
392-
block_operations(sbi);
393-
return GC_BLOCKED;
394-
}
385+
/* stop BG_GC if there is not enough free sections. */
386+
if (gc_type == BG_GC && has_not_enough_free_secs(sbi, 0))
387+
return;
395388

396-
err = check_valid_map(sbi, segno, off);
397-
if (err == GC_NEXT)
389+
if (check_valid_map(sbi, segno, off) == 0)
398390
continue;
399391

400392
if (initial) {
@@ -424,7 +416,6 @@ static int gc_node_segment(struct f2fs_sb_info *sbi,
424416
};
425417
sync_node_pages(sbi, 0, &wbc);
426418
}
427-
return GC_DONE;
428419
}
429420

430421
/*
@@ -467,22 +458,22 @@ static int check_dnode(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
467458

468459
node_page = get_node_page(sbi, nid);
469460
if (IS_ERR(node_page))
470-
return GC_NEXT;
461+
return 0;
471462

472463
get_node_info(sbi, nid, dni);
473464

474465
if (sum->version != dni->version) {
475466
f2fs_put_page(node_page, 1);
476-
return GC_NEXT;
467+
return 0;
477468
}
478469

479470
*nofs = ofs_of_node(node_page);
480471
source_blkaddr = datablock_addr(node_page, ofs_in_node);
481472
f2fs_put_page(node_page, 1);
482473

483474
if (source_blkaddr != blkaddr)
484-
return GC_NEXT;
485-
return GC_OK;
475+
return 0;
476+
return 1;
486477
}
487478

488479
static void move_data_page(struct inode *inode, struct page *page, int gc_type)
@@ -523,13 +514,13 @@ static void move_data_page(struct inode *inode, struct page *page, int gc_type)
523514
* If the parent node is not valid or the data block address is different,
524515
* the victim data block is ignored.
525516
*/
526-
static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
517+
static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
527518
struct list_head *ilist, unsigned int segno, int gc_type)
528519
{
529520
struct super_block *sb = sbi->sb;
530521
struct f2fs_summary *entry;
531522
block_t start_addr;
532-
int err, off;
523+
int off;
533524
int phase = 0;
534525

535526
start_addr = START_BLOCK(sbi, segno);
@@ -543,20 +534,11 @@ static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
543534
unsigned int ofs_in_node, nofs;
544535
block_t start_bidx;
545536

546-
/*
547-
* It makes sure that free segments are able to write
548-
* all the dirty node pages before CP after this CP.
549-
* So let's check the space of dirty node pages.
550-
*/
551-
if (should_do_checkpoint(sbi)) {
552-
mutex_lock(&sbi->cp_mutex);
553-
block_operations(sbi);
554-
err = GC_BLOCKED;
555-
goto stop;
556-
}
537+
/* stop BG_GC if there is not enough free sections. */
538+
if (gc_type == BG_GC && has_not_enough_free_secs(sbi, 0))
539+
return;
557540

558-
err = check_valid_map(sbi, segno, off);
559-
if (err == GC_NEXT)
541+
if (check_valid_map(sbi, segno, off) == 0)
560542
continue;
561543

562544
if (phase == 0) {
@@ -565,8 +547,7 @@ static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
565547
}
566548

567549
/* Get an inode by ino with checking validity */
568-
err = check_dnode(sbi, entry, &dni, start_addr + off, &nofs);
569-
if (err == GC_NEXT)
550+
if (check_dnode(sbi, entry, &dni, start_addr + off, &nofs) == 0)
570551
continue;
571552

572553
if (phase == 1) {
@@ -606,11 +587,9 @@ static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
606587
}
607588
if (++phase < 4)
608589
goto next_step;
609-
err = GC_DONE;
610-
stop:
590+
611591
if (gc_type == FG_GC)
612592
f2fs_submit_bio(sbi, DATA, true);
613-
return err;
614593
}
615594

616595
static int __get_victim(struct f2fs_sb_info *sbi, unsigned int *victim,
@@ -624,17 +603,16 @@ static int __get_victim(struct f2fs_sb_info *sbi, unsigned int *victim,
624603
return ret;
625604
}
626605

627-
static int do_garbage_collect(struct f2fs_sb_info *sbi, unsigned int segno,
606+
static void do_garbage_collect(struct f2fs_sb_info *sbi, unsigned int segno,
628607
struct list_head *ilist, int gc_type)
629608
{
630609
struct page *sum_page;
631610
struct f2fs_summary_block *sum;
632-
int ret = GC_DONE;
633611

634612
/* read segment summary of victim */
635613
sum_page = get_sum_page(sbi, segno);
636614
if (IS_ERR(sum_page))
637-
return GC_ERROR;
615+
return;
638616

639617
/*
640618
* CP needs to lock sum_page. In this time, we don't need
@@ -646,58 +624,55 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, unsigned int segno,
646624

647625
switch (GET_SUM_TYPE((&sum->footer))) {
648626
case SUM_TYPE_NODE:
649-
ret = gc_node_segment(sbi, sum->entries, segno, gc_type);
627+
gc_node_segment(sbi, sum->entries, segno, gc_type);
650628
break;
651629
case SUM_TYPE_DATA:
652-
ret = gc_data_segment(sbi, sum->entries, ilist, segno, gc_type);
630+
gc_data_segment(sbi, sum->entries, ilist, segno, gc_type);
653631
break;
654632
}
655633
stat_inc_seg_count(sbi, GET_SUM_TYPE((&sum->footer)));
656634
stat_inc_call_count(sbi->stat_info);
657635

658636
f2fs_put_page(sum_page, 0);
659-
return ret;
660637
}
661638

662639
int f2fs_gc(struct f2fs_sb_info *sbi)
663640
{
664641
struct list_head ilist;
665642
unsigned int segno, i;
666643
int gc_type = BG_GC;
667-
int gc_status = GC_NONE;
644+
int nfree = 0;
645+
int ret = -1;
668646

669647
INIT_LIST_HEAD(&ilist);
670648
gc_more:
671649
if (!(sbi->sb->s_flags & MS_ACTIVE))
672650
goto stop;
673651

674-
if (gc_type == BG_GC && has_not_enough_free_secs(sbi))
652+
if (gc_type == BG_GC && has_not_enough_free_secs(sbi, nfree))
675653
gc_type = FG_GC;
676654

677655
if (!__get_victim(sbi, &segno, gc_type, NO_CHECK_TYPE))
678656
goto stop;
657+
ret = 0;
679658

680-
for (i = 0; i < sbi->segs_per_sec; i++) {
681-
/*
682-
* do_garbage_collect will give us three gc_status:
683-
* GC_ERROR, GC_DONE, and GC_BLOCKED.
684-
* If GC is finished uncleanly, we have to return
685-
* the victim to dirty segment list.
686-
*/
687-
gc_status = do_garbage_collect(sbi, segno + i, &ilist, gc_type);
688-
if (gc_status != GC_DONE)
689-
break;
690-
}
691-
if (has_not_enough_free_secs(sbi)) {
692-
write_checkpoint(sbi, (gc_status == GC_BLOCKED), false);
693-
if (has_not_enough_free_secs(sbi))
694-
goto gc_more;
695-
}
659+
for (i = 0; i < sbi->segs_per_sec; i++)
660+
do_garbage_collect(sbi, segno + i, &ilist, gc_type);
661+
662+
if (gc_type == FG_GC &&
663+
get_valid_blocks(sbi, segno, sbi->segs_per_sec) == 0)
664+
nfree++;
665+
666+
if (has_not_enough_free_secs(sbi, nfree))
667+
goto gc_more;
668+
669+
if (gc_type == FG_GC)
670+
write_checkpoint(sbi, false);
696671
stop:
697672
mutex_unlock(&sbi->gc_mutex);
698673

699674
put_gc_inode(&ilist);
700-
return gc_status;
675+
return ret;
701676
}
702677

703678
void build_gc_manager(struct f2fs_sb_info *sbi)

fs/f2fs/gc.h

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,6 @@
2222
/* Search max. number of dirty segments to select a victim segment */
2323
#define MAX_VICTIM_SEARCH 20
2424

25-
enum {
26-
GC_NONE = 0,
27-
GC_ERROR,
28-
GC_OK,
29-
GC_NEXT,
30-
GC_BLOCKED,
31-
GC_DONE,
32-
};
33-
3425
struct f2fs_gc_kthread {
3526
struct task_struct *f2fs_gc_task;
3627
wait_queue_head_t gc_wait_queue_head;
@@ -103,10 +94,3 @@ static inline int is_idle(struct f2fs_sb_info *sbi)
10394
struct request_list *rl = &q->rq;
10495
return !(rl->count[BLK_RW_SYNC]) && !(rl->count[BLK_RW_ASYNC]);
10596
}
106-
107-
static inline bool should_do_checkpoint(struct f2fs_sb_info *sbi)
108-
{
109-
int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES);
110-
int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS);
111-
return free_sections(sbi) <= (node_secs + 2 * dent_secs + 2);
112-
}

fs/f2fs/node.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1135,7 +1135,7 @@ static int f2fs_write_node_pages(struct address_space *mapping,
11351135

11361136
/* First check balancing cached NAT entries */
11371137
if (try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK)) {
1138-
write_checkpoint(sbi, false, false);
1138+
write_checkpoint(sbi, false);
11391139
return 0;
11401140
}
11411141

fs/f2fs/recovery.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,5 +371,5 @@ void recover_fsync_data(struct f2fs_sb_info *sbi)
371371
out:
372372
destroy_fsync_dnodes(sbi, &inode_list);
373373
kmem_cache_destroy(fsync_entry_slab);
374-
write_checkpoint(sbi, false, false);
374+
write_checkpoint(sbi, false);
375375
}

fs/f2fs/segment.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi)
2929
* We should do GC or end up with checkpoint, if there are so many dirty
3030
* dir/node pages without enough free segments.
3131
*/
32-
if (has_not_enough_free_secs(sbi)) {
32+
if (has_not_enough_free_secs(sbi, 0)) {
3333
mutex_lock(&sbi->gc_mutex);
3434
f2fs_gc(sbi);
3535
}
@@ -308,7 +308,7 @@ static unsigned int check_prefree_segments(struct f2fs_sb_info *sbi,
308308
* If there is not enough reserved sections,
309309
* we should not reuse prefree segments.
310310
*/
311-
if (has_not_enough_free_secs(sbi))
311+
if (has_not_enough_free_secs(sbi, 0))
312312
return NULL_SEGNO;
313313

314314
/*
@@ -536,6 +536,23 @@ static void change_curseg(struct f2fs_sb_info *sbi, int type, bool reuse)
536536
}
537537
}
538538

539+
static int get_ssr_segment(struct f2fs_sb_info *sbi, int type)
540+
{
541+
struct curseg_info *curseg = CURSEG_I(sbi, type);
542+
const struct victim_selection *v_ops = DIRTY_I(sbi)->v_ops;
543+
544+
if (IS_NODESEG(type) || !has_not_enough_free_secs(sbi, 0))
545+
return v_ops->get_victim(sbi,
546+
&(curseg)->next_segno, BG_GC, type, SSR);
547+
548+
/* For data segments, let's do SSR more intensively */
549+
for (; type >= CURSEG_HOT_DATA; type--)
550+
if (v_ops->get_victim(sbi, &(curseg)->next_segno,
551+
BG_GC, type, SSR))
552+
return 1;
553+
return 0;
554+
}
555+
539556
/*
540557
* flush out current segment and replace it with new segment
541558
* This function should be returned with success, otherwise BUG

fs/f2fs/segment.h

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -450,21 +450,15 @@ static inline bool need_SSR(struct f2fs_sb_info *sbi)
450450
return (free_sections(sbi) < overprovision_sections(sbi));
451451
}
452452

453-
static inline int get_ssr_segment(struct f2fs_sb_info *sbi, int type)
454-
{
455-
struct curseg_info *curseg = CURSEG_I(sbi, type);
456-
return DIRTY_I(sbi)->v_ops->get_victim(sbi,
457-
&(curseg)->next_segno, BG_GC, type, SSR);
458-
}
459-
460-
static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi)
453+
static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, int freed)
461454
{
462455
int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES);
463456
int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS);
457+
464458
if (sbi->por_doing)
465459
return false;
466460

467-
return (free_sections(sbi) <= (node_secs + 2 * dent_secs +
461+
return ((free_sections(sbi) + freed) <= (node_secs + 2 * dent_secs +
468462
reserved_sections(sbi)));
469463
}
470464

0 commit comments

Comments
 (0)