Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

f2fs: run discard jobs when put_super

When we umount f2fs, we need to avoid long delay due to discard commands, which
is actually taking tens of seconds, if storage is very slow on UNMAP. So, this
patch introduces timeout-based work on it.

By default, let me give 5 seconds for discard.

Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>

+27 -3
+7
Documentation/ABI/testing/sysfs-fs-f2fs
··· 86 86 The unit size is one block, now only support configuring in range 87 87 of [1, 512]. 88 88 89 + What: /sys/fs/f2fs/<disk>/umount_discard_timeout 90 + Date: January 2019 91 + Contact: "Jaegeuk Kim" <jaegeuk@kernel.org> 92 + Description: 93 + Set timeout to issue discard commands during umount. 94 + Default: 5 secs 95 + 89 96 What: /sys/fs/f2fs/<disk>/max_victim_search 90 97 Date: January 2014 91 98 Contact: "Jaegeuk Kim" <jaegeuk.kim@samsung.com>
+4 -1
fs/f2fs/f2fs.h
··· 191 191 #define DEF_CP_INTERVAL 60 /* 60 secs */ 192 192 #define DEF_IDLE_INTERVAL 5 /* 5 secs */ 193 193 #define DEF_DISABLE_INTERVAL 5 /* 5 secs */ 194 + #define DEF_UMOUNT_DISCARD_TIMEOUT 5 /* 5 secs */ 194 195 195 196 struct cp_control { 196 197 int reason; ··· 311 310 bool sync; /* submit discard with REQ_SYNC flag */ 312 311 bool ordered; /* issue discard by lba order */ 313 312 unsigned int granularity; /* discard granularity */ 313 + int timeout; /* discard timeout for put_super */ 314 314 }; 315 315 316 316 struct discard_cmd_control { ··· 1112 1110 DISCARD_TIME, 1113 1111 GC_TIME, 1114 1112 DISABLE_TIME, 1113 + UMOUNT_DISCARD_TIMEOUT, 1115 1114 MAX_TIME, 1116 1115 }; 1117 1116 ··· 3009 3006 bool f2fs_is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr); 3010 3007 void f2fs_drop_discard_cmd(struct f2fs_sb_info *sbi); 3011 3008 void f2fs_stop_discard_thread(struct f2fs_sb_info *sbi); 3012 - bool f2fs_wait_discard_bios(struct f2fs_sb_info *sbi); 3009 + bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi); 3013 3010 void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi, 3014 3011 struct cp_control *cpc); 3015 3012 void f2fs_dirty_to_prefree(struct f2fs_sb_info *sbi);
+10 -1
fs/f2fs/segment.c
··· 1037 1037 1038 1038 dpolicy->max_requests = DEF_MAX_DISCARD_REQUEST; 1039 1039 dpolicy->io_aware_gran = MAX_PLIST_NUM; 1040 + dpolicy->timeout = 0; 1040 1041 1041 1042 if (discard_type == DPOLICY_BG) { 1042 1043 dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME; ··· 1425 1424 int i, issued = 0; 1426 1425 bool io_interrupted = false; 1427 1426 1427 + if (dpolicy->timeout != 0) 1428 + f2fs_update_time(sbi, dpolicy->timeout); 1429 + 1428 1430 for (i = MAX_PLIST_NUM - 1; i >= 0; i--) { 1431 + if (dpolicy->timeout != 0 && 1432 + f2fs_time_over(sbi, dpolicy->timeout)) 1433 + break; 1434 + 1429 1435 if (i + 1 < dpolicy->granularity) 1430 1436 break; 1431 1437 ··· 1619 1611 } 1620 1612 1621 1613 /* This comes from f2fs_put_super */ 1622 - bool f2fs_wait_discard_bios(struct f2fs_sb_info *sbi) 1614 + bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi) 1623 1615 { 1624 1616 struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; 1625 1617 struct discard_policy dpolicy; ··· 1627 1619 1628 1620 __init_discard_policy(sbi, &dpolicy, DPOLICY_UMOUNT, 1629 1621 dcc->discard_granularity); 1622 + dpolicy.timeout = UMOUNT_DISCARD_TIMEOUT; 1630 1623 __issue_discard_cmd(sbi, &dpolicy); 1631 1624 dropped = __drop_discard_cmd(sbi); 1632 1625
+3 -1
fs/f2fs/super.c
··· 1048 1048 } 1049 1049 1050 1050 /* be sure to wait for any on-going discard commands */ 1051 - dropped = f2fs_wait_discard_bios(sbi); 1051 + dropped = f2fs_issue_discard_timeout(sbi); 1052 1052 1053 1053 if ((f2fs_hw_support_discard(sbi) || f2fs_hw_should_discard(sbi)) && 1054 1054 !sbi->discard_blks && !dropped) { ··· 2706 2706 sbi->interval_time[DISCARD_TIME] = DEF_IDLE_INTERVAL; 2707 2707 sbi->interval_time[GC_TIME] = DEF_IDLE_INTERVAL; 2708 2708 sbi->interval_time[DISABLE_TIME] = DEF_DISABLE_INTERVAL; 2709 + sbi->interval_time[UMOUNT_DISCARD_TIMEOUT] = 2710 + DEF_UMOUNT_DISCARD_TIMEOUT; 2709 2711 clear_sbi_flag(sbi, SBI_NEED_FSCK); 2710 2712 2711 2713 for (i = 0; i < NR_COUNT_TYPE; i++)
+3
fs/f2fs/sysfs.c
··· 426 426 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, discard_idle_interval, 427 427 interval_time[DISCARD_TIME]); 428 428 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_idle_interval, interval_time[GC_TIME]); 429 + F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, 430 + umount_discard_timeout, interval_time[UMOUNT_DISCARD_TIMEOUT]); 429 431 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, iostat_enable, iostat_enable); 430 432 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, readdir_ra, readdir_ra); 431 433 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold); ··· 485 483 ATTR_LIST(idle_interval), 486 484 ATTR_LIST(discard_idle_interval), 487 485 ATTR_LIST(gc_idle_interval), 486 + ATTR_LIST(umount_discard_timeout), 488 487 ATTR_LIST(iostat_enable), 489 488 ATTR_LIST(readdir_ra), 490 489 ATTR_LIST(gc_pin_file_thresh),