Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0b54fb84 authored by Jaegeuk Kim's avatar Jaegeuk Kim
Browse files

f2fs: factor out discard command info into discard_cmd_control



This patch adds discard_cmd_control with the existing discarding controls.

Reviewed-by: default avatarChao Yu <yuchao0@huawei.com>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent d4adb30f
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -196,6 +196,8 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
	/* build merge flush thread */
	if (SM_I(sbi)->fcc_info)
		si->cache_mem += sizeof(struct flush_cmd_control);
	if (SM_I(sbi)->dcc_info)
		si->cache_mem += sizeof(struct discard_cmd_control);

	/* free nids */
	si->cache_mem += (NM_I(sbi)->nid_cnt[FREE_NID_LIST] +
+10 −6
Original line number Diff line number Diff line
@@ -189,6 +189,13 @@ struct discard_cmd {
	struct bio *bio;		/* bio */
};

struct discard_cmd_control {
	struct list_head discard_entry_list;	/* 4KB discard entry list */
	int nr_discards;			/* # of discards in the list */
	struct list_head discard_cmd_list;	/* discard cmd list */
	int max_discards;			/* max. discards to be issued */
};

/* for the list of fsync inodes, used only during recovery */
struct fsync_inode_entry {
	struct list_head list;	/* list head */
@@ -632,12 +639,6 @@ struct f2fs_sm_info {
	/* a threshold to reclaim prefree segments */
	unsigned int rec_prefree_segments;

	/* for small discard management */
	struct list_head discard_entry_list;	/* 4KB discard entry list */
	struct list_head discard_cmd_list;	/* discard cmd list */
	int nr_discards;			/* # of discards in the list */
	int max_discards;			/* max. discards to be issued */

	/* for batched trimming */
	unsigned int trim_sections;		/* # of sections to trim */

@@ -649,6 +650,9 @@ struct f2fs_sm_info {

	/* for flush command control */
	struct flush_cmd_control *fcc_info;

	/* for discard command control */
	struct discard_cmd_control *dcc_info;
};

/*
+53 −15
Original line number Diff line number Diff line
@@ -631,7 +631,8 @@ static void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno)
static struct discard_cmd *__add_discard_cmd(struct f2fs_sb_info *sbi,
			struct bio *bio, block_t lstart, block_t len)
{
	struct list_head *wait_list = &(SM_I(sbi)->discard_cmd_list);
	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
	struct list_head *cmd_list = &(dcc->discard_cmd_list);
	struct discard_cmd *dc;

	dc = f2fs_kmem_cache_alloc(discard_cmd_slab, GFP_NOFS);
@@ -640,7 +641,7 @@ static struct discard_cmd *__add_discard_cmd(struct f2fs_sb_info *sbi,
	dc->lstart = lstart;
	dc->len = len;
	init_completion(&dc->wait);
	list_add_tail(&dc->list, wait_list);
	list_add_tail(&dc->list, cmd_list);

	return dc;
}
@@ -648,7 +649,8 @@ static struct discard_cmd *__add_discard_cmd(struct f2fs_sb_info *sbi,
/* This should be covered by global mutex, &sit_i->sentry_lock */
void f2fs_wait_discard_bio(struct f2fs_sb_info *sbi, block_t blkaddr)
{
	struct list_head *wait_list = &(SM_I(sbi)->discard_cmd_list);
	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
	struct list_head *wait_list = &(dcc->discard_cmd_list);
	struct discard_cmd *dc, *tmp;

	list_for_each_entry_safe(dc, tmp, wait_list, list) {
@@ -817,7 +819,7 @@ static void __add_discard_entry(struct f2fs_sb_info *sbi,
		struct cp_control *cpc, struct seg_entry *se,
		unsigned int start, unsigned int end)
{
	struct list_head *head = &SM_I(sbi)->discard_entry_list;
	struct list_head *head = &SM_I(sbi)->dcc_info->discard_entry_list;
	struct discard_entry *new, *last;

	if (!list_empty(head)) {
@@ -835,7 +837,7 @@ static void __add_discard_entry(struct f2fs_sb_info *sbi,
	new->len = end - start;
	list_add_tail(&new->list, head);
done:
	SM_I(sbi)->nr_discards += end - start;
	SM_I(sbi)->dcc_info->nr_discards += end - start;
}

static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc,
@@ -857,7 +859,8 @@ static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc,

	if (!force) {
		if (!test_opt(sbi, DISCARD) || !se->valid_blocks ||
		    SM_I(sbi)->nr_discards >= SM_I(sbi)->max_discards)
			SM_I(sbi)->dcc_info->nr_discards >=
				SM_I(sbi)->dcc_info->max_discards)
			return false;
	}

@@ -866,7 +869,8 @@ static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc,
		dmap[i] = force ? ~ckpt_map[i] & ~discard_map[i] :
				(cur_map[i] ^ ckpt_map[i]) & ckpt_map[i];

	while (force || SM_I(sbi)->nr_discards <= SM_I(sbi)->max_discards) {
	while (force || SM_I(sbi)->dcc_info->nr_discards <=
				SM_I(sbi)->dcc_info->max_discards) {
		start = __find_rev_next_bit(dmap, max_blocks, end + 1);
		if (start >= max_blocks)
			break;
@@ -886,7 +890,7 @@ static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc,

void release_discard_addrs(struct f2fs_sb_info *sbi)
{
	struct list_head *head = &(SM_I(sbi)->discard_entry_list);
	struct list_head *head = &(SM_I(sbi)->dcc_info->discard_entry_list);
	struct discard_entry *entry, *this;

	/* drop caches */
@@ -912,7 +916,7 @@ static void set_prefree_as_free_segments(struct f2fs_sb_info *sbi)

void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc)
{
	struct list_head *head = &(SM_I(sbi)->discard_entry_list);
	struct list_head *head = &(SM_I(sbi)->dcc_info->discard_entry_list);
	struct discard_entry *entry, *this;
	struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
	struct blk_plug plug;
@@ -972,13 +976,47 @@ void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc)
		cpc->trimmed += entry->len;
skip:
		list_del(&entry->list);
		SM_I(sbi)->nr_discards -= entry->len;
		SM_I(sbi)->dcc_info->nr_discards -= entry->len;
		kmem_cache_free(discard_entry_slab, entry);
	}

	blk_finish_plug(&plug);
}

int create_discard_cmd_control(struct f2fs_sb_info *sbi)
{
	struct discard_cmd_control *dcc;
	int err = 0;

	if (SM_I(sbi)->dcc_info) {
		dcc = SM_I(sbi)->dcc_info;
		goto init_thread;
	}

	dcc = kzalloc(sizeof(struct discard_cmd_control), GFP_KERNEL);
	if (!dcc)
		return -ENOMEM;

	INIT_LIST_HEAD(&dcc->discard_entry_list);
	INIT_LIST_HEAD(&dcc->discard_cmd_list);
	dcc->nr_discards = 0;
	dcc->max_discards = 0;

	SM_I(sbi)->dcc_info = dcc;
init_thread:
	return err;
}

void destroy_discard_cmd_control(struct f2fs_sb_info *sbi, bool free)
{
	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;

	if (free) {
		kfree(dcc);
		SM_I(sbi)->dcc_info = NULL;
	}
}

static bool __mark_sit_entry_dirty(struct f2fs_sb_info *sbi, unsigned int segno)
{
	struct sit_info *sit_i = SIT_I(sbi);
@@ -2708,11 +2746,6 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
	sm_info->min_ipu_util = DEF_MIN_IPU_UTIL;
	sm_info->min_fsync_blocks = DEF_MIN_FSYNC_BLOCKS;

	INIT_LIST_HEAD(&sm_info->discard_entry_list);
	INIT_LIST_HEAD(&sm_info->discard_cmd_list);
	sm_info->nr_discards = 0;
	sm_info->max_discards = 0;

	sm_info->trim_sections = DEF_BATCHED_TRIM_SECTIONS;

	INIT_LIST_HEAD(&sm_info->sit_entry_set);
@@ -2723,6 +2756,10 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
			return err;
	}

	err = create_discard_cmd_control(sbi);
	if (err)
		return err;

	err = build_sit_info(sbi);
	if (err)
		return err;
@@ -2844,6 +2881,7 @@ void destroy_segment_manager(struct f2fs_sb_info *sbi)
	if (!sm_info)
		return;
	destroy_flush_cmd_control(sbi, true);
	destroy_discard_cmd_control(sbi, true);
	destroy_dirty_segmap(sbi);
	destroy_curseg(sbi);
	destroy_free_segmap(sbi);
+4 −1
Original line number Diff line number Diff line
@@ -145,6 +145,7 @@ static match_table_t f2fs_tokens = {
enum {
	GC_THREAD,	/* struct f2fs_gc_thread */
	SM_INFO,	/* struct f2fs_sm_info */
	DCC_INFO,	/* struct discard_cmd_control */
	NM_INFO,	/* struct f2fs_nm_info */
	F2FS_SBI,	/* struct f2fs_sb_info */
#ifdef CONFIG_F2FS_FAULT_INJECTION
@@ -168,6 +169,8 @@ static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type)
		return (unsigned char *)sbi->gc_thread;
	else if (struct_type == SM_INFO)
		return (unsigned char *)SM_I(sbi);
	else if (struct_type == DCC_INFO)
		return (unsigned char *)SM_I(sbi)->dcc_info;
	else if (struct_type == NM_INFO)
		return (unsigned char *)NM_I(sbi);
	else if (struct_type == F2FS_SBI)
@@ -283,7 +286,7 @@ F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_max_sleep_time, max_sleep_time);
F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_no_gc_sleep_time, no_gc_sleep_time);
F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_idle, gc_idle);
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments);
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, max_small_discards, max_discards);
F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_small_discards, max_discards);
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, batched_trim_sections, trim_sections);
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, ipu_policy, ipu_policy);
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util);