162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * fs/f2fs/segment.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2012 Samsung Electronics Co., Ltd.
662306a36Sopenharmony_ci *             http://www.samsung.com/
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci#include <linux/fs.h>
962306a36Sopenharmony_ci#include <linux/f2fs_fs.h>
1062306a36Sopenharmony_ci#include <linux/bio.h>
1162306a36Sopenharmony_ci#include <linux/blkdev.h>
1262306a36Sopenharmony_ci#include <linux/sched/mm.h>
1362306a36Sopenharmony_ci#include <linux/prefetch.h>
1462306a36Sopenharmony_ci#include <linux/kthread.h>
1562306a36Sopenharmony_ci#include <linux/swap.h>
1662306a36Sopenharmony_ci#include <linux/timer.h>
1762306a36Sopenharmony_ci#include <linux/freezer.h>
1862306a36Sopenharmony_ci#include <linux/sched/signal.h>
1962306a36Sopenharmony_ci#include <linux/random.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include "f2fs.h"
2262306a36Sopenharmony_ci#include "segment.h"
2362306a36Sopenharmony_ci#include "node.h"
2462306a36Sopenharmony_ci#include "gc.h"
2562306a36Sopenharmony_ci#include "iostat.h"
2662306a36Sopenharmony_ci#include <trace/events/f2fs.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define __reverse_ffz(x) __reverse_ffs(~(x))
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic struct kmem_cache *discard_entry_slab;
3162306a36Sopenharmony_cistatic struct kmem_cache *discard_cmd_slab;
3262306a36Sopenharmony_cistatic struct kmem_cache *sit_entry_set_slab;
3362306a36Sopenharmony_cistatic struct kmem_cache *revoke_entry_slab;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic unsigned long __reverse_ulong(unsigned char *str)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	unsigned long tmp = 0;
3862306a36Sopenharmony_ci	int shift = 24, idx = 0;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#if BITS_PER_LONG == 64
4162306a36Sopenharmony_ci	shift = 56;
4262306a36Sopenharmony_ci#endif
4362306a36Sopenharmony_ci	while (shift >= 0) {
4462306a36Sopenharmony_ci		tmp |= (unsigned long)str[idx++] << shift;
4562306a36Sopenharmony_ci		shift -= BITS_PER_BYTE;
4662306a36Sopenharmony_ci	}
4762306a36Sopenharmony_ci	return tmp;
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci/*
5162306a36Sopenharmony_ci * __reverse_ffs is copied from include/asm-generic/bitops/__ffs.h since
5262306a36Sopenharmony_ci * MSB and LSB are reversed in a byte by f2fs_set_bit.
5362306a36Sopenharmony_ci */
5462306a36Sopenharmony_cistatic inline unsigned long __reverse_ffs(unsigned long word)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	int num = 0;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#if BITS_PER_LONG == 64
5962306a36Sopenharmony_ci	if ((word & 0xffffffff00000000UL) == 0)
6062306a36Sopenharmony_ci		num += 32;
6162306a36Sopenharmony_ci	else
6262306a36Sopenharmony_ci		word >>= 32;
6362306a36Sopenharmony_ci#endif
6462306a36Sopenharmony_ci	if ((word & 0xffff0000) == 0)
6562306a36Sopenharmony_ci		num += 16;
6662306a36Sopenharmony_ci	else
6762306a36Sopenharmony_ci		word >>= 16;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	if ((word & 0xff00) == 0)
7062306a36Sopenharmony_ci		num += 8;
7162306a36Sopenharmony_ci	else
7262306a36Sopenharmony_ci		word >>= 8;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	if ((word & 0xf0) == 0)
7562306a36Sopenharmony_ci		num += 4;
7662306a36Sopenharmony_ci	else
7762306a36Sopenharmony_ci		word >>= 4;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	if ((word & 0xc) == 0)
8062306a36Sopenharmony_ci		num += 2;
8162306a36Sopenharmony_ci	else
8262306a36Sopenharmony_ci		word >>= 2;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	if ((word & 0x2) == 0)
8562306a36Sopenharmony_ci		num += 1;
8662306a36Sopenharmony_ci	return num;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci/*
9062306a36Sopenharmony_ci * __find_rev_next(_zero)_bit is copied from lib/find_next_bit.c because
9162306a36Sopenharmony_ci * f2fs_set_bit makes MSB and LSB reversed in a byte.
9262306a36Sopenharmony_ci * @size must be integral times of unsigned long.
9362306a36Sopenharmony_ci * Example:
9462306a36Sopenharmony_ci *                             MSB <--> LSB
9562306a36Sopenharmony_ci *   f2fs_set_bit(0, bitmap) => 1000 0000
9662306a36Sopenharmony_ci *   f2fs_set_bit(7, bitmap) => 0000 0001
9762306a36Sopenharmony_ci */
9862306a36Sopenharmony_cistatic unsigned long __find_rev_next_bit(const unsigned long *addr,
9962306a36Sopenharmony_ci			unsigned long size, unsigned long offset)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	const unsigned long *p = addr + BIT_WORD(offset);
10262306a36Sopenharmony_ci	unsigned long result = size;
10362306a36Sopenharmony_ci	unsigned long tmp;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (offset >= size)
10662306a36Sopenharmony_ci		return size;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	size -= (offset & ~(BITS_PER_LONG - 1));
10962306a36Sopenharmony_ci	offset %= BITS_PER_LONG;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	while (1) {
11262306a36Sopenharmony_ci		if (*p == 0)
11362306a36Sopenharmony_ci			goto pass;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci		tmp = __reverse_ulong((unsigned char *)p);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci		tmp &= ~0UL >> offset;
11862306a36Sopenharmony_ci		if (size < BITS_PER_LONG)
11962306a36Sopenharmony_ci			tmp &= (~0UL << (BITS_PER_LONG - size));
12062306a36Sopenharmony_ci		if (tmp)
12162306a36Sopenharmony_ci			goto found;
12262306a36Sopenharmony_cipass:
12362306a36Sopenharmony_ci		if (size <= BITS_PER_LONG)
12462306a36Sopenharmony_ci			break;
12562306a36Sopenharmony_ci		size -= BITS_PER_LONG;
12662306a36Sopenharmony_ci		offset = 0;
12762306a36Sopenharmony_ci		p++;
12862306a36Sopenharmony_ci	}
12962306a36Sopenharmony_ci	return result;
13062306a36Sopenharmony_cifound:
13162306a36Sopenharmony_ci	return result - size + __reverse_ffs(tmp);
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic unsigned long __find_rev_next_zero_bit(const unsigned long *addr,
13562306a36Sopenharmony_ci			unsigned long size, unsigned long offset)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	const unsigned long *p = addr + BIT_WORD(offset);
13862306a36Sopenharmony_ci	unsigned long result = size;
13962306a36Sopenharmony_ci	unsigned long tmp;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	if (offset >= size)
14262306a36Sopenharmony_ci		return size;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	size -= (offset & ~(BITS_PER_LONG - 1));
14562306a36Sopenharmony_ci	offset %= BITS_PER_LONG;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	while (1) {
14862306a36Sopenharmony_ci		if (*p == ~0UL)
14962306a36Sopenharmony_ci			goto pass;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci		tmp = __reverse_ulong((unsigned char *)p);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci		if (offset)
15462306a36Sopenharmony_ci			tmp |= ~0UL << (BITS_PER_LONG - offset);
15562306a36Sopenharmony_ci		if (size < BITS_PER_LONG)
15662306a36Sopenharmony_ci			tmp |= ~0UL >> size;
15762306a36Sopenharmony_ci		if (tmp != ~0UL)
15862306a36Sopenharmony_ci			goto found;
15962306a36Sopenharmony_cipass:
16062306a36Sopenharmony_ci		if (size <= BITS_PER_LONG)
16162306a36Sopenharmony_ci			break;
16262306a36Sopenharmony_ci		size -= BITS_PER_LONG;
16362306a36Sopenharmony_ci		offset = 0;
16462306a36Sopenharmony_ci		p++;
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci	return result;
16762306a36Sopenharmony_cifound:
16862306a36Sopenharmony_ci	return result - size + __reverse_ffz(tmp);
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cibool f2fs_need_SSR(struct f2fs_sb_info *sbi)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES);
17462306a36Sopenharmony_ci	int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS);
17562306a36Sopenharmony_ci	int imeta_secs = get_blocktype_secs(sbi, F2FS_DIRTY_IMETA);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	if (f2fs_lfs_mode(sbi))
17862306a36Sopenharmony_ci		return false;
17962306a36Sopenharmony_ci	if (sbi->gc_mode == GC_URGENT_HIGH)
18062306a36Sopenharmony_ci		return true;
18162306a36Sopenharmony_ci	if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
18262306a36Sopenharmony_ci		return true;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	return free_sections(sbi) <= (node_secs + 2 * dent_secs + imeta_secs +
18562306a36Sopenharmony_ci			SM_I(sbi)->min_ssr_sections + reserved_sections(sbi));
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_civoid f2fs_abort_atomic_write(struct inode *inode, bool clean)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	struct f2fs_inode_info *fi = F2FS_I(inode);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	if (!f2fs_is_atomic_file(inode))
19362306a36Sopenharmony_ci		return;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	release_atomic_write_cnt(inode);
19662306a36Sopenharmony_ci	clear_inode_flag(inode, FI_ATOMIC_COMMITTED);
19762306a36Sopenharmony_ci	clear_inode_flag(inode, FI_ATOMIC_REPLACE);
19862306a36Sopenharmony_ci	clear_inode_flag(inode, FI_ATOMIC_FILE);
19962306a36Sopenharmony_ci	stat_dec_atomic_inode(inode);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	F2FS_I(inode)->atomic_write_task = NULL;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	if (clean) {
20462306a36Sopenharmony_ci		truncate_inode_pages_final(inode->i_mapping);
20562306a36Sopenharmony_ci		f2fs_i_size_write(inode, fi->original_i_size);
20662306a36Sopenharmony_ci		fi->original_i_size = 0;
20762306a36Sopenharmony_ci	}
20862306a36Sopenharmony_ci	/* avoid stale dirty inode during eviction */
20962306a36Sopenharmony_ci	sync_inode_metadata(inode, 0);
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistatic int __replace_atomic_write_block(struct inode *inode, pgoff_t index,
21362306a36Sopenharmony_ci			block_t new_addr, block_t *old_addr, bool recover)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
21662306a36Sopenharmony_ci	struct dnode_of_data dn;
21762306a36Sopenharmony_ci	struct node_info ni;
21862306a36Sopenharmony_ci	int err;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ciretry:
22162306a36Sopenharmony_ci	set_new_dnode(&dn, inode, NULL, NULL, 0);
22262306a36Sopenharmony_ci	err = f2fs_get_dnode_of_data(&dn, index, ALLOC_NODE);
22362306a36Sopenharmony_ci	if (err) {
22462306a36Sopenharmony_ci		if (err == -ENOMEM) {
22562306a36Sopenharmony_ci			f2fs_io_schedule_timeout(DEFAULT_IO_TIMEOUT);
22662306a36Sopenharmony_ci			goto retry;
22762306a36Sopenharmony_ci		}
22862306a36Sopenharmony_ci		return err;
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	err = f2fs_get_node_info(sbi, dn.nid, &ni, false);
23262306a36Sopenharmony_ci	if (err) {
23362306a36Sopenharmony_ci		f2fs_put_dnode(&dn);
23462306a36Sopenharmony_ci		return err;
23562306a36Sopenharmony_ci	}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	if (recover) {
23862306a36Sopenharmony_ci		/* dn.data_blkaddr is always valid */
23962306a36Sopenharmony_ci		if (!__is_valid_data_blkaddr(new_addr)) {
24062306a36Sopenharmony_ci			if (new_addr == NULL_ADDR)
24162306a36Sopenharmony_ci				dec_valid_block_count(sbi, inode, 1);
24262306a36Sopenharmony_ci			f2fs_invalidate_blocks(sbi, dn.data_blkaddr);
24362306a36Sopenharmony_ci			f2fs_update_data_blkaddr(&dn, new_addr);
24462306a36Sopenharmony_ci		} else {
24562306a36Sopenharmony_ci			f2fs_replace_block(sbi, &dn, dn.data_blkaddr,
24662306a36Sopenharmony_ci				new_addr, ni.version, true, true);
24762306a36Sopenharmony_ci		}
24862306a36Sopenharmony_ci	} else {
24962306a36Sopenharmony_ci		blkcnt_t count = 1;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci		err = inc_valid_block_count(sbi, inode, &count, true);
25262306a36Sopenharmony_ci		if (err) {
25362306a36Sopenharmony_ci			f2fs_put_dnode(&dn);
25462306a36Sopenharmony_ci			return err;
25562306a36Sopenharmony_ci		}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci		*old_addr = dn.data_blkaddr;
25862306a36Sopenharmony_ci		f2fs_truncate_data_blocks_range(&dn, 1);
25962306a36Sopenharmony_ci		dec_valid_block_count(sbi, F2FS_I(inode)->cow_inode, count);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci		f2fs_replace_block(sbi, &dn, dn.data_blkaddr, new_addr,
26262306a36Sopenharmony_ci					ni.version, true, false);
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	f2fs_put_dnode(&dn);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	trace_f2fs_replace_atomic_write_block(inode, F2FS_I(inode)->cow_inode,
26862306a36Sopenharmony_ci			index, old_addr ? *old_addr : 0, new_addr, recover);
26962306a36Sopenharmony_ci	return 0;
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic void __complete_revoke_list(struct inode *inode, struct list_head *head,
27362306a36Sopenharmony_ci					bool revoke)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	struct revoke_entry *cur, *tmp;
27662306a36Sopenharmony_ci	pgoff_t start_index = 0;
27762306a36Sopenharmony_ci	bool truncate = is_inode_flag_set(inode, FI_ATOMIC_REPLACE);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	list_for_each_entry_safe(cur, tmp, head, list) {
28062306a36Sopenharmony_ci		if (revoke) {
28162306a36Sopenharmony_ci			__replace_atomic_write_block(inode, cur->index,
28262306a36Sopenharmony_ci						cur->old_addr, NULL, true);
28362306a36Sopenharmony_ci		} else if (truncate) {
28462306a36Sopenharmony_ci			f2fs_truncate_hole(inode, start_index, cur->index);
28562306a36Sopenharmony_ci			start_index = cur->index + 1;
28662306a36Sopenharmony_ci		}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci		list_del(&cur->list);
28962306a36Sopenharmony_ci		kmem_cache_free(revoke_entry_slab, cur);
29062306a36Sopenharmony_ci	}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	if (!revoke && truncate)
29362306a36Sopenharmony_ci		f2fs_do_truncate_blocks(inode, start_index * PAGE_SIZE, false);
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic int __f2fs_commit_atomic_write(struct inode *inode)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
29962306a36Sopenharmony_ci	struct f2fs_inode_info *fi = F2FS_I(inode);
30062306a36Sopenharmony_ci	struct inode *cow_inode = fi->cow_inode;
30162306a36Sopenharmony_ci	struct revoke_entry *new;
30262306a36Sopenharmony_ci	struct list_head revoke_list;
30362306a36Sopenharmony_ci	block_t blkaddr;
30462306a36Sopenharmony_ci	struct dnode_of_data dn;
30562306a36Sopenharmony_ci	pgoff_t len = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
30662306a36Sopenharmony_ci	pgoff_t off = 0, blen, index;
30762306a36Sopenharmony_ci	int ret = 0, i;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	INIT_LIST_HEAD(&revoke_list);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	while (len) {
31262306a36Sopenharmony_ci		blen = min_t(pgoff_t, ADDRS_PER_BLOCK(cow_inode), len);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci		set_new_dnode(&dn, cow_inode, NULL, NULL, 0);
31562306a36Sopenharmony_ci		ret = f2fs_get_dnode_of_data(&dn, off, LOOKUP_NODE_RA);
31662306a36Sopenharmony_ci		if (ret && ret != -ENOENT) {
31762306a36Sopenharmony_ci			goto out;
31862306a36Sopenharmony_ci		} else if (ret == -ENOENT) {
31962306a36Sopenharmony_ci			ret = 0;
32062306a36Sopenharmony_ci			if (dn.max_level == 0)
32162306a36Sopenharmony_ci				goto out;
32262306a36Sopenharmony_ci			goto next;
32362306a36Sopenharmony_ci		}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci		blen = min((pgoff_t)ADDRS_PER_PAGE(dn.node_page, cow_inode),
32662306a36Sopenharmony_ci				len);
32762306a36Sopenharmony_ci		index = off;
32862306a36Sopenharmony_ci		for (i = 0; i < blen; i++, dn.ofs_in_node++, index++) {
32962306a36Sopenharmony_ci			blkaddr = f2fs_data_blkaddr(&dn);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci			if (!__is_valid_data_blkaddr(blkaddr)) {
33262306a36Sopenharmony_ci				continue;
33362306a36Sopenharmony_ci			} else if (!f2fs_is_valid_blkaddr(sbi, blkaddr,
33462306a36Sopenharmony_ci					DATA_GENERIC_ENHANCE)) {
33562306a36Sopenharmony_ci				f2fs_put_dnode(&dn);
33662306a36Sopenharmony_ci				ret = -EFSCORRUPTED;
33762306a36Sopenharmony_ci				f2fs_handle_error(sbi,
33862306a36Sopenharmony_ci						ERROR_INVALID_BLKADDR);
33962306a36Sopenharmony_ci				goto out;
34062306a36Sopenharmony_ci			}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci			new = f2fs_kmem_cache_alloc(revoke_entry_slab, GFP_NOFS,
34362306a36Sopenharmony_ci							true, NULL);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci			ret = __replace_atomic_write_block(inode, index, blkaddr,
34662306a36Sopenharmony_ci							&new->old_addr, false);
34762306a36Sopenharmony_ci			if (ret) {
34862306a36Sopenharmony_ci				f2fs_put_dnode(&dn);
34962306a36Sopenharmony_ci				kmem_cache_free(revoke_entry_slab, new);
35062306a36Sopenharmony_ci				goto out;
35162306a36Sopenharmony_ci			}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci			f2fs_update_data_blkaddr(&dn, NULL_ADDR);
35462306a36Sopenharmony_ci			new->index = index;
35562306a36Sopenharmony_ci			list_add_tail(&new->list, &revoke_list);
35662306a36Sopenharmony_ci		}
35762306a36Sopenharmony_ci		f2fs_put_dnode(&dn);
35862306a36Sopenharmony_cinext:
35962306a36Sopenharmony_ci		off += blen;
36062306a36Sopenharmony_ci		len -= blen;
36162306a36Sopenharmony_ci	}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ciout:
36462306a36Sopenharmony_ci	if (ret) {
36562306a36Sopenharmony_ci		sbi->revoked_atomic_block += fi->atomic_write_cnt;
36662306a36Sopenharmony_ci	} else {
36762306a36Sopenharmony_ci		sbi->committed_atomic_block += fi->atomic_write_cnt;
36862306a36Sopenharmony_ci		set_inode_flag(inode, FI_ATOMIC_COMMITTED);
36962306a36Sopenharmony_ci	}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	__complete_revoke_list(inode, &revoke_list, ret ? true : false);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	return ret;
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ciint f2fs_commit_atomic_write(struct inode *inode)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
37962306a36Sopenharmony_ci	struct f2fs_inode_info *fi = F2FS_I(inode);
38062306a36Sopenharmony_ci	int err;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	err = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
38362306a36Sopenharmony_ci	if (err)
38462306a36Sopenharmony_ci		return err;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	f2fs_down_write(&fi->i_gc_rwsem[WRITE]);
38762306a36Sopenharmony_ci	f2fs_lock_op(sbi);
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	err = __f2fs_commit_atomic_write(inode);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	f2fs_unlock_op(sbi);
39262306a36Sopenharmony_ci	f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	return err;
39562306a36Sopenharmony_ci}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci/*
39862306a36Sopenharmony_ci * This function balances dirty node and dentry pages.
39962306a36Sopenharmony_ci * In addition, it controls garbage collection.
40062306a36Sopenharmony_ci */
40162306a36Sopenharmony_civoid f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	if (time_to_inject(sbi, FAULT_CHECKPOINT))
40462306a36Sopenharmony_ci		f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_FAULT_INJECT);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	/* balance_fs_bg is able to be pending */
40762306a36Sopenharmony_ci	if (need && excess_cached_nats(sbi))
40862306a36Sopenharmony_ci		f2fs_balance_fs_bg(sbi, false);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	if (!f2fs_is_checkpoint_ready(sbi))
41162306a36Sopenharmony_ci		return;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	/*
41462306a36Sopenharmony_ci	 * We should do GC or end up with checkpoint, if there are so many dirty
41562306a36Sopenharmony_ci	 * dir/node pages without enough free segments.
41662306a36Sopenharmony_ci	 */
41762306a36Sopenharmony_ci	if (has_enough_free_secs(sbi, 0, 0))
41862306a36Sopenharmony_ci		return;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	if (test_opt(sbi, GC_MERGE) && sbi->gc_thread &&
42162306a36Sopenharmony_ci				sbi->gc_thread->f2fs_gc_task) {
42262306a36Sopenharmony_ci		DEFINE_WAIT(wait);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci		prepare_to_wait(&sbi->gc_thread->fggc_wq, &wait,
42562306a36Sopenharmony_ci					TASK_UNINTERRUPTIBLE);
42662306a36Sopenharmony_ci		wake_up(&sbi->gc_thread->gc_wait_queue_head);
42762306a36Sopenharmony_ci		io_schedule();
42862306a36Sopenharmony_ci		finish_wait(&sbi->gc_thread->fggc_wq, &wait);
42962306a36Sopenharmony_ci	} else {
43062306a36Sopenharmony_ci		struct f2fs_gc_control gc_control = {
43162306a36Sopenharmony_ci			.victim_segno = NULL_SEGNO,
43262306a36Sopenharmony_ci			.init_gc_type = BG_GC,
43362306a36Sopenharmony_ci			.no_bg_gc = true,
43462306a36Sopenharmony_ci			.should_migrate_blocks = false,
43562306a36Sopenharmony_ci			.err_gc_skipped = false,
43662306a36Sopenharmony_ci			.nr_free_secs = 1 };
43762306a36Sopenharmony_ci		f2fs_down_write(&sbi->gc_lock);
43862306a36Sopenharmony_ci		stat_inc_gc_call_count(sbi, FOREGROUND);
43962306a36Sopenharmony_ci		f2fs_gc(sbi, &gc_control);
44062306a36Sopenharmony_ci	}
44162306a36Sopenharmony_ci}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_cistatic inline bool excess_dirty_threshold(struct f2fs_sb_info *sbi)
44462306a36Sopenharmony_ci{
44562306a36Sopenharmony_ci	int factor = f2fs_rwsem_is_locked(&sbi->cp_rwsem) ? 3 : 2;
44662306a36Sopenharmony_ci	unsigned int dents = get_pages(sbi, F2FS_DIRTY_DENTS);
44762306a36Sopenharmony_ci	unsigned int qdata = get_pages(sbi, F2FS_DIRTY_QDATA);
44862306a36Sopenharmony_ci	unsigned int nodes = get_pages(sbi, F2FS_DIRTY_NODES);
44962306a36Sopenharmony_ci	unsigned int meta = get_pages(sbi, F2FS_DIRTY_META);
45062306a36Sopenharmony_ci	unsigned int imeta = get_pages(sbi, F2FS_DIRTY_IMETA);
45162306a36Sopenharmony_ci	unsigned int threshold = sbi->blocks_per_seg * factor *
45262306a36Sopenharmony_ci					DEFAULT_DIRTY_THRESHOLD;
45362306a36Sopenharmony_ci	unsigned int global_threshold = threshold * 3 / 2;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	if (dents >= threshold || qdata >= threshold ||
45662306a36Sopenharmony_ci		nodes >= threshold || meta >= threshold ||
45762306a36Sopenharmony_ci		imeta >= threshold)
45862306a36Sopenharmony_ci		return true;
45962306a36Sopenharmony_ci	return dents + qdata + nodes + meta + imeta >  global_threshold;
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_civoid f2fs_balance_fs_bg(struct f2fs_sb_info *sbi, bool from_bg)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci	if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
46562306a36Sopenharmony_ci		return;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	/* try to shrink extent cache when there is no enough memory */
46862306a36Sopenharmony_ci	if (!f2fs_available_free_memory(sbi, READ_EXTENT_CACHE))
46962306a36Sopenharmony_ci		f2fs_shrink_read_extent_tree(sbi,
47062306a36Sopenharmony_ci				READ_EXTENT_CACHE_SHRINK_NUMBER);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	/* try to shrink age extent cache when there is no enough memory */
47362306a36Sopenharmony_ci	if (!f2fs_available_free_memory(sbi, AGE_EXTENT_CACHE))
47462306a36Sopenharmony_ci		f2fs_shrink_age_extent_tree(sbi,
47562306a36Sopenharmony_ci				AGE_EXTENT_CACHE_SHRINK_NUMBER);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	/* check the # of cached NAT entries */
47862306a36Sopenharmony_ci	if (!f2fs_available_free_memory(sbi, NAT_ENTRIES))
47962306a36Sopenharmony_ci		f2fs_try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	if (!f2fs_available_free_memory(sbi, FREE_NIDS))
48262306a36Sopenharmony_ci		f2fs_try_to_free_nids(sbi, MAX_FREE_NIDS);
48362306a36Sopenharmony_ci	else
48462306a36Sopenharmony_ci		f2fs_build_free_nids(sbi, false, false);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	if (excess_dirty_nats(sbi) || excess_dirty_threshold(sbi) ||
48762306a36Sopenharmony_ci		excess_prefree_segs(sbi) || !f2fs_space_for_roll_forward(sbi))
48862306a36Sopenharmony_ci		goto do_sync;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	/* there is background inflight IO or foreground operation recently */
49162306a36Sopenharmony_ci	if (is_inflight_io(sbi, REQ_TIME) ||
49262306a36Sopenharmony_ci		(!f2fs_time_over(sbi, REQ_TIME) && f2fs_rwsem_is_locked(&sbi->cp_rwsem)))
49362306a36Sopenharmony_ci		return;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	/* exceed periodical checkpoint timeout threshold */
49662306a36Sopenharmony_ci	if (f2fs_time_over(sbi, CP_TIME))
49762306a36Sopenharmony_ci		goto do_sync;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	/* checkpoint is the only way to shrink partial cached entries */
50062306a36Sopenharmony_ci	if (f2fs_available_free_memory(sbi, NAT_ENTRIES) &&
50162306a36Sopenharmony_ci		f2fs_available_free_memory(sbi, INO_ENTRIES))
50262306a36Sopenharmony_ci		return;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_cido_sync:
50562306a36Sopenharmony_ci	if (test_opt(sbi, DATA_FLUSH) && from_bg) {
50662306a36Sopenharmony_ci		struct blk_plug plug;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci		mutex_lock(&sbi->flush_lock);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci		blk_start_plug(&plug);
51162306a36Sopenharmony_ci		f2fs_sync_dirty_inodes(sbi, FILE_INODE, false);
51262306a36Sopenharmony_ci		blk_finish_plug(&plug);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci		mutex_unlock(&sbi->flush_lock);
51562306a36Sopenharmony_ci	}
51662306a36Sopenharmony_ci	stat_inc_cp_call_count(sbi, BACKGROUND);
51762306a36Sopenharmony_ci	f2fs_sync_fs(sbi->sb, 1);
51862306a36Sopenharmony_ci}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_cistatic int __submit_flush_wait(struct f2fs_sb_info *sbi,
52162306a36Sopenharmony_ci				struct block_device *bdev)
52262306a36Sopenharmony_ci{
52362306a36Sopenharmony_ci	int ret = blkdev_issue_flush(bdev);
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	trace_f2fs_issue_flush(bdev, test_opt(sbi, NOBARRIER),
52662306a36Sopenharmony_ci				test_opt(sbi, FLUSH_MERGE), ret);
52762306a36Sopenharmony_ci	if (!ret)
52862306a36Sopenharmony_ci		f2fs_update_iostat(sbi, NULL, FS_FLUSH_IO, 0);
52962306a36Sopenharmony_ci	return ret;
53062306a36Sopenharmony_ci}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_cistatic int submit_flush_wait(struct f2fs_sb_info *sbi, nid_t ino)
53362306a36Sopenharmony_ci{
53462306a36Sopenharmony_ci	int ret = 0;
53562306a36Sopenharmony_ci	int i;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	if (!f2fs_is_multi_device(sbi))
53862306a36Sopenharmony_ci		return __submit_flush_wait(sbi, sbi->sb->s_bdev);
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	for (i = 0; i < sbi->s_ndevs; i++) {
54162306a36Sopenharmony_ci		if (!f2fs_is_dirty_device(sbi, ino, i, FLUSH_INO))
54262306a36Sopenharmony_ci			continue;
54362306a36Sopenharmony_ci		ret = __submit_flush_wait(sbi, FDEV(i).bdev);
54462306a36Sopenharmony_ci		if (ret)
54562306a36Sopenharmony_ci			break;
54662306a36Sopenharmony_ci	}
54762306a36Sopenharmony_ci	return ret;
54862306a36Sopenharmony_ci}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_cistatic int issue_flush_thread(void *data)
55162306a36Sopenharmony_ci{
55262306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = data;
55362306a36Sopenharmony_ci	struct flush_cmd_control *fcc = SM_I(sbi)->fcc_info;
55462306a36Sopenharmony_ci	wait_queue_head_t *q = &fcc->flush_wait_queue;
55562306a36Sopenharmony_cirepeat:
55662306a36Sopenharmony_ci	if (kthread_should_stop())
55762306a36Sopenharmony_ci		return 0;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	if (!llist_empty(&fcc->issue_list)) {
56062306a36Sopenharmony_ci		struct flush_cmd *cmd, *next;
56162306a36Sopenharmony_ci		int ret;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci		fcc->dispatch_list = llist_del_all(&fcc->issue_list);
56462306a36Sopenharmony_ci		fcc->dispatch_list = llist_reverse_order(fcc->dispatch_list);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci		cmd = llist_entry(fcc->dispatch_list, struct flush_cmd, llnode);
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci		ret = submit_flush_wait(sbi, cmd->ino);
56962306a36Sopenharmony_ci		atomic_inc(&fcc->issued_flush);
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci		llist_for_each_entry_safe(cmd, next,
57262306a36Sopenharmony_ci					  fcc->dispatch_list, llnode) {
57362306a36Sopenharmony_ci			cmd->ret = ret;
57462306a36Sopenharmony_ci			complete(&cmd->wait);
57562306a36Sopenharmony_ci		}
57662306a36Sopenharmony_ci		fcc->dispatch_list = NULL;
57762306a36Sopenharmony_ci	}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	wait_event_interruptible(*q,
58062306a36Sopenharmony_ci		kthread_should_stop() || !llist_empty(&fcc->issue_list));
58162306a36Sopenharmony_ci	goto repeat;
58262306a36Sopenharmony_ci}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ciint f2fs_issue_flush(struct f2fs_sb_info *sbi, nid_t ino)
58562306a36Sopenharmony_ci{
58662306a36Sopenharmony_ci	struct flush_cmd_control *fcc = SM_I(sbi)->fcc_info;
58762306a36Sopenharmony_ci	struct flush_cmd cmd;
58862306a36Sopenharmony_ci	int ret;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	if (test_opt(sbi, NOBARRIER))
59162306a36Sopenharmony_ci		return 0;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	if (!test_opt(sbi, FLUSH_MERGE)) {
59462306a36Sopenharmony_ci		atomic_inc(&fcc->queued_flush);
59562306a36Sopenharmony_ci		ret = submit_flush_wait(sbi, ino);
59662306a36Sopenharmony_ci		atomic_dec(&fcc->queued_flush);
59762306a36Sopenharmony_ci		atomic_inc(&fcc->issued_flush);
59862306a36Sopenharmony_ci		return ret;
59962306a36Sopenharmony_ci	}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	if (atomic_inc_return(&fcc->queued_flush) == 1 ||
60262306a36Sopenharmony_ci	    f2fs_is_multi_device(sbi)) {
60362306a36Sopenharmony_ci		ret = submit_flush_wait(sbi, ino);
60462306a36Sopenharmony_ci		atomic_dec(&fcc->queued_flush);
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci		atomic_inc(&fcc->issued_flush);
60762306a36Sopenharmony_ci		return ret;
60862306a36Sopenharmony_ci	}
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	cmd.ino = ino;
61162306a36Sopenharmony_ci	init_completion(&cmd.wait);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	llist_add(&cmd.llnode, &fcc->issue_list);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	/*
61662306a36Sopenharmony_ci	 * update issue_list before we wake up issue_flush thread, this
61762306a36Sopenharmony_ci	 * smp_mb() pairs with another barrier in ___wait_event(), see
61862306a36Sopenharmony_ci	 * more details in comments of waitqueue_active().
61962306a36Sopenharmony_ci	 */
62062306a36Sopenharmony_ci	smp_mb();
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	if (waitqueue_active(&fcc->flush_wait_queue))
62362306a36Sopenharmony_ci		wake_up(&fcc->flush_wait_queue);
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	if (fcc->f2fs_issue_flush) {
62662306a36Sopenharmony_ci		wait_for_completion(&cmd.wait);
62762306a36Sopenharmony_ci		atomic_dec(&fcc->queued_flush);
62862306a36Sopenharmony_ci	} else {
62962306a36Sopenharmony_ci		struct llist_node *list;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci		list = llist_del_all(&fcc->issue_list);
63262306a36Sopenharmony_ci		if (!list) {
63362306a36Sopenharmony_ci			wait_for_completion(&cmd.wait);
63462306a36Sopenharmony_ci			atomic_dec(&fcc->queued_flush);
63562306a36Sopenharmony_ci		} else {
63662306a36Sopenharmony_ci			struct flush_cmd *tmp, *next;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci			ret = submit_flush_wait(sbi, ino);
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci			llist_for_each_entry_safe(tmp, next, list, llnode) {
64162306a36Sopenharmony_ci				if (tmp == &cmd) {
64262306a36Sopenharmony_ci					cmd.ret = ret;
64362306a36Sopenharmony_ci					atomic_dec(&fcc->queued_flush);
64462306a36Sopenharmony_ci					continue;
64562306a36Sopenharmony_ci				}
64662306a36Sopenharmony_ci				tmp->ret = ret;
64762306a36Sopenharmony_ci				complete(&tmp->wait);
64862306a36Sopenharmony_ci			}
64962306a36Sopenharmony_ci		}
65062306a36Sopenharmony_ci	}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	return cmd.ret;
65362306a36Sopenharmony_ci}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ciint f2fs_create_flush_cmd_control(struct f2fs_sb_info *sbi)
65662306a36Sopenharmony_ci{
65762306a36Sopenharmony_ci	dev_t dev = sbi->sb->s_bdev->bd_dev;
65862306a36Sopenharmony_ci	struct flush_cmd_control *fcc;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	if (SM_I(sbi)->fcc_info) {
66162306a36Sopenharmony_ci		fcc = SM_I(sbi)->fcc_info;
66262306a36Sopenharmony_ci		if (fcc->f2fs_issue_flush)
66362306a36Sopenharmony_ci			return 0;
66462306a36Sopenharmony_ci		goto init_thread;
66562306a36Sopenharmony_ci	}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	fcc = f2fs_kzalloc(sbi, sizeof(struct flush_cmd_control), GFP_KERNEL);
66862306a36Sopenharmony_ci	if (!fcc)
66962306a36Sopenharmony_ci		return -ENOMEM;
67062306a36Sopenharmony_ci	atomic_set(&fcc->issued_flush, 0);
67162306a36Sopenharmony_ci	atomic_set(&fcc->queued_flush, 0);
67262306a36Sopenharmony_ci	init_waitqueue_head(&fcc->flush_wait_queue);
67362306a36Sopenharmony_ci	init_llist_head(&fcc->issue_list);
67462306a36Sopenharmony_ci	SM_I(sbi)->fcc_info = fcc;
67562306a36Sopenharmony_ci	if (!test_opt(sbi, FLUSH_MERGE))
67662306a36Sopenharmony_ci		return 0;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ciinit_thread:
67962306a36Sopenharmony_ci	fcc->f2fs_issue_flush = kthread_run(issue_flush_thread, sbi,
68062306a36Sopenharmony_ci				"f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev));
68162306a36Sopenharmony_ci	if (IS_ERR(fcc->f2fs_issue_flush)) {
68262306a36Sopenharmony_ci		int err = PTR_ERR(fcc->f2fs_issue_flush);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci		fcc->f2fs_issue_flush = NULL;
68562306a36Sopenharmony_ci		return err;
68662306a36Sopenharmony_ci	}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	return 0;
68962306a36Sopenharmony_ci}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_civoid f2fs_destroy_flush_cmd_control(struct f2fs_sb_info *sbi, bool free)
69262306a36Sopenharmony_ci{
69362306a36Sopenharmony_ci	struct flush_cmd_control *fcc = SM_I(sbi)->fcc_info;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	if (fcc && fcc->f2fs_issue_flush) {
69662306a36Sopenharmony_ci		struct task_struct *flush_thread = fcc->f2fs_issue_flush;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci		fcc->f2fs_issue_flush = NULL;
69962306a36Sopenharmony_ci		kthread_stop(flush_thread);
70062306a36Sopenharmony_ci	}
70162306a36Sopenharmony_ci	if (free) {
70262306a36Sopenharmony_ci		kfree(fcc);
70362306a36Sopenharmony_ci		SM_I(sbi)->fcc_info = NULL;
70462306a36Sopenharmony_ci	}
70562306a36Sopenharmony_ci}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ciint f2fs_flush_device_cache(struct f2fs_sb_info *sbi)
70862306a36Sopenharmony_ci{
70962306a36Sopenharmony_ci	int ret = 0, i;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	if (!f2fs_is_multi_device(sbi))
71262306a36Sopenharmony_ci		return 0;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	if (test_opt(sbi, NOBARRIER))
71562306a36Sopenharmony_ci		return 0;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	for (i = 1; i < sbi->s_ndevs; i++) {
71862306a36Sopenharmony_ci		int count = DEFAULT_RETRY_IO_COUNT;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci		if (!f2fs_test_bit(i, (char *)&sbi->dirty_device))
72162306a36Sopenharmony_ci			continue;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci		do {
72462306a36Sopenharmony_ci			ret = __submit_flush_wait(sbi, FDEV(i).bdev);
72562306a36Sopenharmony_ci			if (ret)
72662306a36Sopenharmony_ci				f2fs_io_schedule_timeout(DEFAULT_IO_TIMEOUT);
72762306a36Sopenharmony_ci		} while (ret && --count);
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci		if (ret) {
73062306a36Sopenharmony_ci			f2fs_stop_checkpoint(sbi, false,
73162306a36Sopenharmony_ci					STOP_CP_REASON_FLUSH_FAIL);
73262306a36Sopenharmony_ci			break;
73362306a36Sopenharmony_ci		}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci		spin_lock(&sbi->dev_lock);
73662306a36Sopenharmony_ci		f2fs_clear_bit(i, (char *)&sbi->dirty_device);
73762306a36Sopenharmony_ci		spin_unlock(&sbi->dev_lock);
73862306a36Sopenharmony_ci	}
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	return ret;
74162306a36Sopenharmony_ci}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_cistatic void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
74462306a36Sopenharmony_ci		enum dirty_type dirty_type)
74562306a36Sopenharmony_ci{
74662306a36Sopenharmony_ci	struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	/* need not be added */
74962306a36Sopenharmony_ci	if (IS_CURSEG(sbi, segno))
75062306a36Sopenharmony_ci		return;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	if (!test_and_set_bit(segno, dirty_i->dirty_segmap[dirty_type]))
75362306a36Sopenharmony_ci		dirty_i->nr_dirty[dirty_type]++;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	if (dirty_type == DIRTY) {
75662306a36Sopenharmony_ci		struct seg_entry *sentry = get_seg_entry(sbi, segno);
75762306a36Sopenharmony_ci		enum dirty_type t = sentry->type;
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci		if (unlikely(t >= DIRTY)) {
76062306a36Sopenharmony_ci			f2fs_bug_on(sbi, 1);
76162306a36Sopenharmony_ci			return;
76262306a36Sopenharmony_ci		}
76362306a36Sopenharmony_ci		if (!test_and_set_bit(segno, dirty_i->dirty_segmap[t]))
76462306a36Sopenharmony_ci			dirty_i->nr_dirty[t]++;
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci		if (__is_large_section(sbi)) {
76762306a36Sopenharmony_ci			unsigned int secno = GET_SEC_FROM_SEG(sbi, segno);
76862306a36Sopenharmony_ci			block_t valid_blocks =
76962306a36Sopenharmony_ci				get_valid_blocks(sbi, segno, true);
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci			f2fs_bug_on(sbi, unlikely(!valid_blocks ||
77262306a36Sopenharmony_ci					valid_blocks == CAP_BLKS_PER_SEC(sbi)));
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci			if (!IS_CURSEC(sbi, secno))
77562306a36Sopenharmony_ci				set_bit(secno, dirty_i->dirty_secmap);
77662306a36Sopenharmony_ci		}
77762306a36Sopenharmony_ci	}
77862306a36Sopenharmony_ci}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_cistatic void __remove_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
78162306a36Sopenharmony_ci		enum dirty_type dirty_type)
78262306a36Sopenharmony_ci{
78362306a36Sopenharmony_ci	struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
78462306a36Sopenharmony_ci	block_t valid_blocks;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	if (test_and_clear_bit(segno, dirty_i->dirty_segmap[dirty_type]))
78762306a36Sopenharmony_ci		dirty_i->nr_dirty[dirty_type]--;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	if (dirty_type == DIRTY) {
79062306a36Sopenharmony_ci		struct seg_entry *sentry = get_seg_entry(sbi, segno);
79162306a36Sopenharmony_ci		enum dirty_type t = sentry->type;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci		if (test_and_clear_bit(segno, dirty_i->dirty_segmap[t]))
79462306a36Sopenharmony_ci			dirty_i->nr_dirty[t]--;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci		valid_blocks = get_valid_blocks(sbi, segno, true);
79762306a36Sopenharmony_ci		if (valid_blocks == 0) {
79862306a36Sopenharmony_ci			clear_bit(GET_SEC_FROM_SEG(sbi, segno),
79962306a36Sopenharmony_ci						dirty_i->victim_secmap);
80062306a36Sopenharmony_ci#ifdef CONFIG_F2FS_CHECK_FS
80162306a36Sopenharmony_ci			clear_bit(segno, SIT_I(sbi)->invalid_segmap);
80262306a36Sopenharmony_ci#endif
80362306a36Sopenharmony_ci		}
80462306a36Sopenharmony_ci		if (__is_large_section(sbi)) {
80562306a36Sopenharmony_ci			unsigned int secno = GET_SEC_FROM_SEG(sbi, segno);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci			if (!valid_blocks ||
80862306a36Sopenharmony_ci					valid_blocks == CAP_BLKS_PER_SEC(sbi)) {
80962306a36Sopenharmony_ci				clear_bit(secno, dirty_i->dirty_secmap);
81062306a36Sopenharmony_ci				return;
81162306a36Sopenharmony_ci			}
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci			if (!IS_CURSEC(sbi, secno))
81462306a36Sopenharmony_ci				set_bit(secno, dirty_i->dirty_secmap);
81562306a36Sopenharmony_ci		}
81662306a36Sopenharmony_ci	}
81762306a36Sopenharmony_ci}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci/*
82062306a36Sopenharmony_ci * Should not occur error such as -ENOMEM.
82162306a36Sopenharmony_ci * Adding dirty entry into seglist is not critical operation.
82262306a36Sopenharmony_ci * If a given segment is one of current working segments, it won't be added.
82362306a36Sopenharmony_ci */
82462306a36Sopenharmony_cistatic void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno)
82562306a36Sopenharmony_ci{
82662306a36Sopenharmony_ci	struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
82762306a36Sopenharmony_ci	unsigned short valid_blocks, ckpt_valid_blocks;
82862306a36Sopenharmony_ci	unsigned int usable_blocks;
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	if (segno == NULL_SEGNO || IS_CURSEG(sbi, segno))
83162306a36Sopenharmony_ci		return;
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	usable_blocks = f2fs_usable_blks_in_seg(sbi, segno);
83462306a36Sopenharmony_ci	mutex_lock(&dirty_i->seglist_lock);
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	valid_blocks = get_valid_blocks(sbi, segno, false);
83762306a36Sopenharmony_ci	ckpt_valid_blocks = get_ckpt_valid_blocks(sbi, segno, false);
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	if (valid_blocks == 0 && (!is_sbi_flag_set(sbi, SBI_CP_DISABLED) ||
84062306a36Sopenharmony_ci		ckpt_valid_blocks == usable_blocks)) {
84162306a36Sopenharmony_ci		__locate_dirty_segment(sbi, segno, PRE);
84262306a36Sopenharmony_ci		__remove_dirty_segment(sbi, segno, DIRTY);
84362306a36Sopenharmony_ci	} else if (valid_blocks < usable_blocks) {
84462306a36Sopenharmony_ci		__locate_dirty_segment(sbi, segno, DIRTY);
84562306a36Sopenharmony_ci	} else {
84662306a36Sopenharmony_ci		/* Recovery routine with SSR needs this */
84762306a36Sopenharmony_ci		__remove_dirty_segment(sbi, segno, DIRTY);
84862306a36Sopenharmony_ci	}
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	mutex_unlock(&dirty_i->seglist_lock);
85162306a36Sopenharmony_ci}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci/* This moves currently empty dirty blocks to prefree. Must hold seglist_lock */
85462306a36Sopenharmony_civoid f2fs_dirty_to_prefree(struct f2fs_sb_info *sbi)
85562306a36Sopenharmony_ci{
85662306a36Sopenharmony_ci	struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
85762306a36Sopenharmony_ci	unsigned int segno;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	mutex_lock(&dirty_i->seglist_lock);
86062306a36Sopenharmony_ci	for_each_set_bit(segno, dirty_i->dirty_segmap[DIRTY], MAIN_SEGS(sbi)) {
86162306a36Sopenharmony_ci		if (get_valid_blocks(sbi, segno, false))
86262306a36Sopenharmony_ci			continue;
86362306a36Sopenharmony_ci		if (IS_CURSEG(sbi, segno))
86462306a36Sopenharmony_ci			continue;
86562306a36Sopenharmony_ci		__locate_dirty_segment(sbi, segno, PRE);
86662306a36Sopenharmony_ci		__remove_dirty_segment(sbi, segno, DIRTY);
86762306a36Sopenharmony_ci	}
86862306a36Sopenharmony_ci	mutex_unlock(&dirty_i->seglist_lock);
86962306a36Sopenharmony_ci}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ciblock_t f2fs_get_unusable_blocks(struct f2fs_sb_info *sbi)
87262306a36Sopenharmony_ci{
87362306a36Sopenharmony_ci	int ovp_hole_segs =
87462306a36Sopenharmony_ci		(overprovision_segments(sbi) - reserved_segments(sbi));
87562306a36Sopenharmony_ci	block_t ovp_holes = ovp_hole_segs << sbi->log_blocks_per_seg;
87662306a36Sopenharmony_ci	struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
87762306a36Sopenharmony_ci	block_t holes[2] = {0, 0};	/* DATA and NODE */
87862306a36Sopenharmony_ci	block_t unusable;
87962306a36Sopenharmony_ci	struct seg_entry *se;
88062306a36Sopenharmony_ci	unsigned int segno;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	mutex_lock(&dirty_i->seglist_lock);
88362306a36Sopenharmony_ci	for_each_set_bit(segno, dirty_i->dirty_segmap[DIRTY], MAIN_SEGS(sbi)) {
88462306a36Sopenharmony_ci		se = get_seg_entry(sbi, segno);
88562306a36Sopenharmony_ci		if (IS_NODESEG(se->type))
88662306a36Sopenharmony_ci			holes[NODE] += f2fs_usable_blks_in_seg(sbi, segno) -
88762306a36Sopenharmony_ci							se->valid_blocks;
88862306a36Sopenharmony_ci		else
88962306a36Sopenharmony_ci			holes[DATA] += f2fs_usable_blks_in_seg(sbi, segno) -
89062306a36Sopenharmony_ci							se->valid_blocks;
89162306a36Sopenharmony_ci	}
89262306a36Sopenharmony_ci	mutex_unlock(&dirty_i->seglist_lock);
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	unusable = max(holes[DATA], holes[NODE]);
89562306a36Sopenharmony_ci	if (unusable > ovp_holes)
89662306a36Sopenharmony_ci		return unusable - ovp_holes;
89762306a36Sopenharmony_ci	return 0;
89862306a36Sopenharmony_ci}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ciint f2fs_disable_cp_again(struct f2fs_sb_info *sbi, block_t unusable)
90162306a36Sopenharmony_ci{
90262306a36Sopenharmony_ci	int ovp_hole_segs =
90362306a36Sopenharmony_ci		(overprovision_segments(sbi) - reserved_segments(sbi));
90462306a36Sopenharmony_ci	if (unusable > F2FS_OPTION(sbi).unusable_cap)
90562306a36Sopenharmony_ci		return -EAGAIN;
90662306a36Sopenharmony_ci	if (is_sbi_flag_set(sbi, SBI_CP_DISABLED_QUICK) &&
90762306a36Sopenharmony_ci		dirty_segments(sbi) > ovp_hole_segs)
90862306a36Sopenharmony_ci		return -EAGAIN;
90962306a36Sopenharmony_ci	return 0;
91062306a36Sopenharmony_ci}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci/* This is only used by SBI_CP_DISABLED */
91362306a36Sopenharmony_cistatic unsigned int get_free_segment(struct f2fs_sb_info *sbi)
91462306a36Sopenharmony_ci{
91562306a36Sopenharmony_ci	struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
91662306a36Sopenharmony_ci	unsigned int segno = 0;
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	mutex_lock(&dirty_i->seglist_lock);
91962306a36Sopenharmony_ci	for_each_set_bit(segno, dirty_i->dirty_segmap[DIRTY], MAIN_SEGS(sbi)) {
92062306a36Sopenharmony_ci		if (get_valid_blocks(sbi, segno, false))
92162306a36Sopenharmony_ci			continue;
92262306a36Sopenharmony_ci		if (get_ckpt_valid_blocks(sbi, segno, false))
92362306a36Sopenharmony_ci			continue;
92462306a36Sopenharmony_ci		mutex_unlock(&dirty_i->seglist_lock);
92562306a36Sopenharmony_ci		return segno;
92662306a36Sopenharmony_ci	}
92762306a36Sopenharmony_ci	mutex_unlock(&dirty_i->seglist_lock);
92862306a36Sopenharmony_ci	return NULL_SEGNO;
92962306a36Sopenharmony_ci}
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_cistatic struct discard_cmd *__create_discard_cmd(struct f2fs_sb_info *sbi,
93262306a36Sopenharmony_ci		struct block_device *bdev, block_t lstart,
93362306a36Sopenharmony_ci		block_t start, block_t len)
93462306a36Sopenharmony_ci{
93562306a36Sopenharmony_ci	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
93662306a36Sopenharmony_ci	struct list_head *pend_list;
93762306a36Sopenharmony_ci	struct discard_cmd *dc;
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	f2fs_bug_on(sbi, !len);
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	pend_list = &dcc->pend_list[plist_idx(len)];
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	dc = f2fs_kmem_cache_alloc(discard_cmd_slab, GFP_NOFS, true, NULL);
94462306a36Sopenharmony_ci	INIT_LIST_HEAD(&dc->list);
94562306a36Sopenharmony_ci	dc->bdev = bdev;
94662306a36Sopenharmony_ci	dc->di.lstart = lstart;
94762306a36Sopenharmony_ci	dc->di.start = start;
94862306a36Sopenharmony_ci	dc->di.len = len;
94962306a36Sopenharmony_ci	dc->ref = 0;
95062306a36Sopenharmony_ci	dc->state = D_PREP;
95162306a36Sopenharmony_ci	dc->queued = 0;
95262306a36Sopenharmony_ci	dc->error = 0;
95362306a36Sopenharmony_ci	init_completion(&dc->wait);
95462306a36Sopenharmony_ci	list_add_tail(&dc->list, pend_list);
95562306a36Sopenharmony_ci	spin_lock_init(&dc->lock);
95662306a36Sopenharmony_ci	dc->bio_ref = 0;
95762306a36Sopenharmony_ci	atomic_inc(&dcc->discard_cmd_cnt);
95862306a36Sopenharmony_ci	dcc->undiscard_blks += len;
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	return dc;
96162306a36Sopenharmony_ci}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_cistatic bool f2fs_check_discard_tree(struct f2fs_sb_info *sbi)
96462306a36Sopenharmony_ci{
96562306a36Sopenharmony_ci#ifdef CONFIG_F2FS_CHECK_FS
96662306a36Sopenharmony_ci	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
96762306a36Sopenharmony_ci	struct rb_node *cur = rb_first_cached(&dcc->root), *next;
96862306a36Sopenharmony_ci	struct discard_cmd *cur_dc, *next_dc;
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	while (cur) {
97162306a36Sopenharmony_ci		next = rb_next(cur);
97262306a36Sopenharmony_ci		if (!next)
97362306a36Sopenharmony_ci			return true;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci		cur_dc = rb_entry(cur, struct discard_cmd, rb_node);
97662306a36Sopenharmony_ci		next_dc = rb_entry(next, struct discard_cmd, rb_node);
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci		if (cur_dc->di.lstart + cur_dc->di.len > next_dc->di.lstart) {
97962306a36Sopenharmony_ci			f2fs_info(sbi, "broken discard_rbtree, "
98062306a36Sopenharmony_ci				"cur(%u, %u) next(%u, %u)",
98162306a36Sopenharmony_ci				cur_dc->di.lstart, cur_dc->di.len,
98262306a36Sopenharmony_ci				next_dc->di.lstart, next_dc->di.len);
98362306a36Sopenharmony_ci			return false;
98462306a36Sopenharmony_ci		}
98562306a36Sopenharmony_ci		cur = next;
98662306a36Sopenharmony_ci	}
98762306a36Sopenharmony_ci#endif
98862306a36Sopenharmony_ci	return true;
98962306a36Sopenharmony_ci}
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_cistatic struct discard_cmd *__lookup_discard_cmd(struct f2fs_sb_info *sbi,
99262306a36Sopenharmony_ci						block_t blkaddr)
99362306a36Sopenharmony_ci{
99462306a36Sopenharmony_ci	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
99562306a36Sopenharmony_ci	struct rb_node *node = dcc->root.rb_root.rb_node;
99662306a36Sopenharmony_ci	struct discard_cmd *dc;
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	while (node) {
99962306a36Sopenharmony_ci		dc = rb_entry(node, struct discard_cmd, rb_node);
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci		if (blkaddr < dc->di.lstart)
100262306a36Sopenharmony_ci			node = node->rb_left;
100362306a36Sopenharmony_ci		else if (blkaddr >= dc->di.lstart + dc->di.len)
100462306a36Sopenharmony_ci			node = node->rb_right;
100562306a36Sopenharmony_ci		else
100662306a36Sopenharmony_ci			return dc;
100762306a36Sopenharmony_ci	}
100862306a36Sopenharmony_ci	return NULL;
100962306a36Sopenharmony_ci}
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_cistatic struct discard_cmd *__lookup_discard_cmd_ret(struct rb_root_cached *root,
101262306a36Sopenharmony_ci				block_t blkaddr,
101362306a36Sopenharmony_ci				struct discard_cmd **prev_entry,
101462306a36Sopenharmony_ci				struct discard_cmd **next_entry,
101562306a36Sopenharmony_ci				struct rb_node ***insert_p,
101662306a36Sopenharmony_ci				struct rb_node **insert_parent)
101762306a36Sopenharmony_ci{
101862306a36Sopenharmony_ci	struct rb_node **pnode = &root->rb_root.rb_node;
101962306a36Sopenharmony_ci	struct rb_node *parent = NULL, *tmp_node;
102062306a36Sopenharmony_ci	struct discard_cmd *dc;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	*insert_p = NULL;
102362306a36Sopenharmony_ci	*insert_parent = NULL;
102462306a36Sopenharmony_ci	*prev_entry = NULL;
102562306a36Sopenharmony_ci	*next_entry = NULL;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	if (RB_EMPTY_ROOT(&root->rb_root))
102862306a36Sopenharmony_ci		return NULL;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	while (*pnode) {
103162306a36Sopenharmony_ci		parent = *pnode;
103262306a36Sopenharmony_ci		dc = rb_entry(*pnode, struct discard_cmd, rb_node);
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci		if (blkaddr < dc->di.lstart)
103562306a36Sopenharmony_ci			pnode = &(*pnode)->rb_left;
103662306a36Sopenharmony_ci		else if (blkaddr >= dc->di.lstart + dc->di.len)
103762306a36Sopenharmony_ci			pnode = &(*pnode)->rb_right;
103862306a36Sopenharmony_ci		else
103962306a36Sopenharmony_ci			goto lookup_neighbors;
104062306a36Sopenharmony_ci	}
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	*insert_p = pnode;
104362306a36Sopenharmony_ci	*insert_parent = parent;
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	dc = rb_entry(parent, struct discard_cmd, rb_node);
104662306a36Sopenharmony_ci	tmp_node = parent;
104762306a36Sopenharmony_ci	if (parent && blkaddr > dc->di.lstart)
104862306a36Sopenharmony_ci		tmp_node = rb_next(parent);
104962306a36Sopenharmony_ci	*next_entry = rb_entry_safe(tmp_node, struct discard_cmd, rb_node);
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	tmp_node = parent;
105262306a36Sopenharmony_ci	if (parent && blkaddr < dc->di.lstart)
105362306a36Sopenharmony_ci		tmp_node = rb_prev(parent);
105462306a36Sopenharmony_ci	*prev_entry = rb_entry_safe(tmp_node, struct discard_cmd, rb_node);
105562306a36Sopenharmony_ci	return NULL;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_cilookup_neighbors:
105862306a36Sopenharmony_ci	/* lookup prev node for merging backward later */
105962306a36Sopenharmony_ci	tmp_node = rb_prev(&dc->rb_node);
106062306a36Sopenharmony_ci	*prev_entry = rb_entry_safe(tmp_node, struct discard_cmd, rb_node);
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	/* lookup next node for merging frontward later */
106362306a36Sopenharmony_ci	tmp_node = rb_next(&dc->rb_node);
106462306a36Sopenharmony_ci	*next_entry = rb_entry_safe(tmp_node, struct discard_cmd, rb_node);
106562306a36Sopenharmony_ci	return dc;
106662306a36Sopenharmony_ci}
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_cistatic void __detach_discard_cmd(struct discard_cmd_control *dcc,
106962306a36Sopenharmony_ci							struct discard_cmd *dc)
107062306a36Sopenharmony_ci{
107162306a36Sopenharmony_ci	if (dc->state == D_DONE)
107262306a36Sopenharmony_ci		atomic_sub(dc->queued, &dcc->queued_discard);
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	list_del(&dc->list);
107562306a36Sopenharmony_ci	rb_erase_cached(&dc->rb_node, &dcc->root);
107662306a36Sopenharmony_ci	dcc->undiscard_blks -= dc->di.len;
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	kmem_cache_free(discard_cmd_slab, dc);
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	atomic_dec(&dcc->discard_cmd_cnt);
108162306a36Sopenharmony_ci}
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_cistatic void __remove_discard_cmd(struct f2fs_sb_info *sbi,
108462306a36Sopenharmony_ci							struct discard_cmd *dc)
108562306a36Sopenharmony_ci{
108662306a36Sopenharmony_ci	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
108762306a36Sopenharmony_ci	unsigned long flags;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	trace_f2fs_remove_discard(dc->bdev, dc->di.start, dc->di.len);
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	spin_lock_irqsave(&dc->lock, flags);
109262306a36Sopenharmony_ci	if (dc->bio_ref) {
109362306a36Sopenharmony_ci		spin_unlock_irqrestore(&dc->lock, flags);
109462306a36Sopenharmony_ci		return;
109562306a36Sopenharmony_ci	}
109662306a36Sopenharmony_ci	spin_unlock_irqrestore(&dc->lock, flags);
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	f2fs_bug_on(sbi, dc->ref);
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	if (dc->error == -EOPNOTSUPP)
110162306a36Sopenharmony_ci		dc->error = 0;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	if (dc->error)
110462306a36Sopenharmony_ci		printk_ratelimited(
110562306a36Sopenharmony_ci			"%sF2FS-fs (%s): Issue discard(%u, %u, %u) failed, ret: %d",
110662306a36Sopenharmony_ci			KERN_INFO, sbi->sb->s_id,
110762306a36Sopenharmony_ci			dc->di.lstart, dc->di.start, dc->di.len, dc->error);
110862306a36Sopenharmony_ci	__detach_discard_cmd(dcc, dc);
110962306a36Sopenharmony_ci}
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_cistatic void f2fs_submit_discard_endio(struct bio *bio)
111262306a36Sopenharmony_ci{
111362306a36Sopenharmony_ci	struct discard_cmd *dc = (struct discard_cmd *)bio->bi_private;
111462306a36Sopenharmony_ci	unsigned long flags;
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	spin_lock_irqsave(&dc->lock, flags);
111762306a36Sopenharmony_ci	if (!dc->error)
111862306a36Sopenharmony_ci		dc->error = blk_status_to_errno(bio->bi_status);
111962306a36Sopenharmony_ci	dc->bio_ref--;
112062306a36Sopenharmony_ci	if (!dc->bio_ref && dc->state == D_SUBMIT) {
112162306a36Sopenharmony_ci		dc->state = D_DONE;
112262306a36Sopenharmony_ci		complete_all(&dc->wait);
112362306a36Sopenharmony_ci	}
112462306a36Sopenharmony_ci	spin_unlock_irqrestore(&dc->lock, flags);
112562306a36Sopenharmony_ci	bio_put(bio);
112662306a36Sopenharmony_ci}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_cistatic void __check_sit_bitmap(struct f2fs_sb_info *sbi,
112962306a36Sopenharmony_ci				block_t start, block_t end)
113062306a36Sopenharmony_ci{
113162306a36Sopenharmony_ci#ifdef CONFIG_F2FS_CHECK_FS
113262306a36Sopenharmony_ci	struct seg_entry *sentry;
113362306a36Sopenharmony_ci	unsigned int segno;
113462306a36Sopenharmony_ci	block_t blk = start;
113562306a36Sopenharmony_ci	unsigned long offset, size, max_blocks = sbi->blocks_per_seg;
113662306a36Sopenharmony_ci	unsigned long *map;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	while (blk < end) {
113962306a36Sopenharmony_ci		segno = GET_SEGNO(sbi, blk);
114062306a36Sopenharmony_ci		sentry = get_seg_entry(sbi, segno);
114162306a36Sopenharmony_ci		offset = GET_BLKOFF_FROM_SEG0(sbi, blk);
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci		if (end < START_BLOCK(sbi, segno + 1))
114462306a36Sopenharmony_ci			size = GET_BLKOFF_FROM_SEG0(sbi, end);
114562306a36Sopenharmony_ci		else
114662306a36Sopenharmony_ci			size = max_blocks;
114762306a36Sopenharmony_ci		map = (unsigned long *)(sentry->cur_valid_map);
114862306a36Sopenharmony_ci		offset = __find_rev_next_bit(map, size, offset);
114962306a36Sopenharmony_ci		f2fs_bug_on(sbi, offset != size);
115062306a36Sopenharmony_ci		blk = START_BLOCK(sbi, segno + 1);
115162306a36Sopenharmony_ci	}
115262306a36Sopenharmony_ci#endif
115362306a36Sopenharmony_ci}
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_cistatic void __init_discard_policy(struct f2fs_sb_info *sbi,
115662306a36Sopenharmony_ci				struct discard_policy *dpolicy,
115762306a36Sopenharmony_ci				int discard_type, unsigned int granularity)
115862306a36Sopenharmony_ci{
115962306a36Sopenharmony_ci	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	/* common policy */
116262306a36Sopenharmony_ci	dpolicy->type = discard_type;
116362306a36Sopenharmony_ci	dpolicy->sync = true;
116462306a36Sopenharmony_ci	dpolicy->ordered = false;
116562306a36Sopenharmony_ci	dpolicy->granularity = granularity;
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	dpolicy->max_requests = dcc->max_discard_request;
116862306a36Sopenharmony_ci	dpolicy->io_aware_gran = dcc->discard_io_aware_gran;
116962306a36Sopenharmony_ci	dpolicy->timeout = false;
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	if (discard_type == DPOLICY_BG) {
117262306a36Sopenharmony_ci		dpolicy->min_interval = dcc->min_discard_issue_time;
117362306a36Sopenharmony_ci		dpolicy->mid_interval = dcc->mid_discard_issue_time;
117462306a36Sopenharmony_ci		dpolicy->max_interval = dcc->max_discard_issue_time;
117562306a36Sopenharmony_ci		dpolicy->io_aware = true;
117662306a36Sopenharmony_ci		dpolicy->sync = false;
117762306a36Sopenharmony_ci		dpolicy->ordered = true;
117862306a36Sopenharmony_ci		if (utilization(sbi) > dcc->discard_urgent_util) {
117962306a36Sopenharmony_ci			dpolicy->granularity = MIN_DISCARD_GRANULARITY;
118062306a36Sopenharmony_ci			if (atomic_read(&dcc->discard_cmd_cnt))
118162306a36Sopenharmony_ci				dpolicy->max_interval =
118262306a36Sopenharmony_ci					dcc->min_discard_issue_time;
118362306a36Sopenharmony_ci		}
118462306a36Sopenharmony_ci	} else if (discard_type == DPOLICY_FORCE) {
118562306a36Sopenharmony_ci		dpolicy->min_interval = dcc->min_discard_issue_time;
118662306a36Sopenharmony_ci		dpolicy->mid_interval = dcc->mid_discard_issue_time;
118762306a36Sopenharmony_ci		dpolicy->max_interval = dcc->max_discard_issue_time;
118862306a36Sopenharmony_ci		dpolicy->io_aware = false;
118962306a36Sopenharmony_ci	} else if (discard_type == DPOLICY_FSTRIM) {
119062306a36Sopenharmony_ci		dpolicy->io_aware = false;
119162306a36Sopenharmony_ci	} else if (discard_type == DPOLICY_UMOUNT) {
119262306a36Sopenharmony_ci		dpolicy->io_aware = false;
119362306a36Sopenharmony_ci		/* we need to issue all to keep CP_TRIMMED_FLAG */
119462306a36Sopenharmony_ci		dpolicy->granularity = MIN_DISCARD_GRANULARITY;
119562306a36Sopenharmony_ci		dpolicy->timeout = true;
119662306a36Sopenharmony_ci	}
119762306a36Sopenharmony_ci}
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_cistatic void __update_discard_tree_range(struct f2fs_sb_info *sbi,
120062306a36Sopenharmony_ci				struct block_device *bdev, block_t lstart,
120162306a36Sopenharmony_ci				block_t start, block_t len);
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEV_ZONED
120462306a36Sopenharmony_cistatic void __submit_zone_reset_cmd(struct f2fs_sb_info *sbi,
120562306a36Sopenharmony_ci				   struct discard_cmd *dc, blk_opf_t flag,
120662306a36Sopenharmony_ci				   struct list_head *wait_list,
120762306a36Sopenharmony_ci				   unsigned int *issued)
120862306a36Sopenharmony_ci{
120962306a36Sopenharmony_ci	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
121062306a36Sopenharmony_ci	struct block_device *bdev = dc->bdev;
121162306a36Sopenharmony_ci	struct bio *bio = bio_alloc(bdev, 0, REQ_OP_ZONE_RESET | flag, GFP_NOFS);
121262306a36Sopenharmony_ci	unsigned long flags;
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	trace_f2fs_issue_reset_zone(bdev, dc->di.start);
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	spin_lock_irqsave(&dc->lock, flags);
121762306a36Sopenharmony_ci	dc->state = D_SUBMIT;
121862306a36Sopenharmony_ci	dc->bio_ref++;
121962306a36Sopenharmony_ci	spin_unlock_irqrestore(&dc->lock, flags);
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	if (issued)
122262306a36Sopenharmony_ci		(*issued)++;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	atomic_inc(&dcc->queued_discard);
122562306a36Sopenharmony_ci	dc->queued++;
122662306a36Sopenharmony_ci	list_move_tail(&dc->list, wait_list);
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	/* sanity check on discard range */
122962306a36Sopenharmony_ci	__check_sit_bitmap(sbi, dc->di.lstart, dc->di.lstart + dc->di.len);
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	bio->bi_iter.bi_sector = SECTOR_FROM_BLOCK(dc->di.start);
123262306a36Sopenharmony_ci	bio->bi_private = dc;
123362306a36Sopenharmony_ci	bio->bi_end_io = f2fs_submit_discard_endio;
123462306a36Sopenharmony_ci	submit_bio(bio);
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	atomic_inc(&dcc->issued_discard);
123762306a36Sopenharmony_ci	f2fs_update_iostat(sbi, NULL, FS_ZONE_RESET_IO, dc->di.len * F2FS_BLKSIZE);
123862306a36Sopenharmony_ci}
123962306a36Sopenharmony_ci#endif
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci/* this function is copied from blkdev_issue_discard from block/blk-lib.c */
124262306a36Sopenharmony_cistatic int __submit_discard_cmd(struct f2fs_sb_info *sbi,
124362306a36Sopenharmony_ci				struct discard_policy *dpolicy,
124462306a36Sopenharmony_ci				struct discard_cmd *dc, int *issued)
124562306a36Sopenharmony_ci{
124662306a36Sopenharmony_ci	struct block_device *bdev = dc->bdev;
124762306a36Sopenharmony_ci	unsigned int max_discard_blocks =
124862306a36Sopenharmony_ci			SECTOR_TO_BLOCK(bdev_max_discard_sectors(bdev));
124962306a36Sopenharmony_ci	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
125062306a36Sopenharmony_ci	struct list_head *wait_list = (dpolicy->type == DPOLICY_FSTRIM) ?
125162306a36Sopenharmony_ci					&(dcc->fstrim_list) : &(dcc->wait_list);
125262306a36Sopenharmony_ci	blk_opf_t flag = dpolicy->sync ? REQ_SYNC : 0;
125362306a36Sopenharmony_ci	block_t lstart, start, len, total_len;
125462306a36Sopenharmony_ci	int err = 0;
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	if (dc->state != D_PREP)
125762306a36Sopenharmony_ci		return 0;
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	if (is_sbi_flag_set(sbi, SBI_NEED_FSCK))
126062306a36Sopenharmony_ci		return 0;
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEV_ZONED
126362306a36Sopenharmony_ci	if (f2fs_sb_has_blkzoned(sbi) && bdev_is_zoned(bdev)) {
126462306a36Sopenharmony_ci		int devi = f2fs_bdev_index(sbi, bdev);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci		if (devi < 0)
126762306a36Sopenharmony_ci			return -EINVAL;
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci		if (f2fs_blkz_is_seq(sbi, devi, dc->di.start)) {
127062306a36Sopenharmony_ci			__submit_zone_reset_cmd(sbi, dc, flag,
127162306a36Sopenharmony_ci						wait_list, issued);
127262306a36Sopenharmony_ci			return 0;
127362306a36Sopenharmony_ci		}
127462306a36Sopenharmony_ci	}
127562306a36Sopenharmony_ci#endif
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	trace_f2fs_issue_discard(bdev, dc->di.start, dc->di.len);
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	lstart = dc->di.lstart;
128062306a36Sopenharmony_ci	start = dc->di.start;
128162306a36Sopenharmony_ci	len = dc->di.len;
128262306a36Sopenharmony_ci	total_len = len;
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	dc->di.len = 0;
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	while (total_len && *issued < dpolicy->max_requests && !err) {
128762306a36Sopenharmony_ci		struct bio *bio = NULL;
128862306a36Sopenharmony_ci		unsigned long flags;
128962306a36Sopenharmony_ci		bool last = true;
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci		if (len > max_discard_blocks) {
129262306a36Sopenharmony_ci			len = max_discard_blocks;
129362306a36Sopenharmony_ci			last = false;
129462306a36Sopenharmony_ci		}
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci		(*issued)++;
129762306a36Sopenharmony_ci		if (*issued == dpolicy->max_requests)
129862306a36Sopenharmony_ci			last = true;
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci		dc->di.len += len;
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci		if (time_to_inject(sbi, FAULT_DISCARD)) {
130362306a36Sopenharmony_ci			err = -EIO;
130462306a36Sopenharmony_ci		} else {
130562306a36Sopenharmony_ci			err = __blkdev_issue_discard(bdev,
130662306a36Sopenharmony_ci					SECTOR_FROM_BLOCK(start),
130762306a36Sopenharmony_ci					SECTOR_FROM_BLOCK(len),
130862306a36Sopenharmony_ci					GFP_NOFS, &bio);
130962306a36Sopenharmony_ci		}
131062306a36Sopenharmony_ci		if (err) {
131162306a36Sopenharmony_ci			spin_lock_irqsave(&dc->lock, flags);
131262306a36Sopenharmony_ci			if (dc->state == D_PARTIAL)
131362306a36Sopenharmony_ci				dc->state = D_SUBMIT;
131462306a36Sopenharmony_ci			spin_unlock_irqrestore(&dc->lock, flags);
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci			break;
131762306a36Sopenharmony_ci		}
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci		f2fs_bug_on(sbi, !bio);
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci		/*
132262306a36Sopenharmony_ci		 * should keep before submission to avoid D_DONE
132362306a36Sopenharmony_ci		 * right away
132462306a36Sopenharmony_ci		 */
132562306a36Sopenharmony_ci		spin_lock_irqsave(&dc->lock, flags);
132662306a36Sopenharmony_ci		if (last)
132762306a36Sopenharmony_ci			dc->state = D_SUBMIT;
132862306a36Sopenharmony_ci		else
132962306a36Sopenharmony_ci			dc->state = D_PARTIAL;
133062306a36Sopenharmony_ci		dc->bio_ref++;
133162306a36Sopenharmony_ci		spin_unlock_irqrestore(&dc->lock, flags);
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci		atomic_inc(&dcc->queued_discard);
133462306a36Sopenharmony_ci		dc->queued++;
133562306a36Sopenharmony_ci		list_move_tail(&dc->list, wait_list);
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci		/* sanity check on discard range */
133862306a36Sopenharmony_ci		__check_sit_bitmap(sbi, lstart, lstart + len);
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci		bio->bi_private = dc;
134162306a36Sopenharmony_ci		bio->bi_end_io = f2fs_submit_discard_endio;
134262306a36Sopenharmony_ci		bio->bi_opf |= flag;
134362306a36Sopenharmony_ci		submit_bio(bio);
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci		atomic_inc(&dcc->issued_discard);
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci		f2fs_update_iostat(sbi, NULL, FS_DISCARD_IO, len * F2FS_BLKSIZE);
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci		lstart += len;
135062306a36Sopenharmony_ci		start += len;
135162306a36Sopenharmony_ci		total_len -= len;
135262306a36Sopenharmony_ci		len = total_len;
135362306a36Sopenharmony_ci	}
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	if (!err && len) {
135662306a36Sopenharmony_ci		dcc->undiscard_blks -= len;
135762306a36Sopenharmony_ci		__update_discard_tree_range(sbi, bdev, lstart, start, len);
135862306a36Sopenharmony_ci	}
135962306a36Sopenharmony_ci	return err;
136062306a36Sopenharmony_ci}
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_cistatic void __insert_discard_cmd(struct f2fs_sb_info *sbi,
136362306a36Sopenharmony_ci				struct block_device *bdev, block_t lstart,
136462306a36Sopenharmony_ci				block_t start, block_t len)
136562306a36Sopenharmony_ci{
136662306a36Sopenharmony_ci	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
136762306a36Sopenharmony_ci	struct rb_node **p = &dcc->root.rb_root.rb_node;
136862306a36Sopenharmony_ci	struct rb_node *parent = NULL;
136962306a36Sopenharmony_ci	struct discard_cmd *dc;
137062306a36Sopenharmony_ci	bool leftmost = true;
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	/* look up rb tree to find parent node */
137362306a36Sopenharmony_ci	while (*p) {
137462306a36Sopenharmony_ci		parent = *p;
137562306a36Sopenharmony_ci		dc = rb_entry(parent, struct discard_cmd, rb_node);
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci		if (lstart < dc->di.lstart) {
137862306a36Sopenharmony_ci			p = &(*p)->rb_left;
137962306a36Sopenharmony_ci		} else if (lstart >= dc->di.lstart + dc->di.len) {
138062306a36Sopenharmony_ci			p = &(*p)->rb_right;
138162306a36Sopenharmony_ci			leftmost = false;
138262306a36Sopenharmony_ci		} else {
138362306a36Sopenharmony_ci			f2fs_bug_on(sbi, 1);
138462306a36Sopenharmony_ci		}
138562306a36Sopenharmony_ci	}
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	dc = __create_discard_cmd(sbi, bdev, lstart, start, len);
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	rb_link_node(&dc->rb_node, parent, p);
139062306a36Sopenharmony_ci	rb_insert_color_cached(&dc->rb_node, &dcc->root, leftmost);
139162306a36Sopenharmony_ci}
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_cistatic void __relocate_discard_cmd(struct discard_cmd_control *dcc,
139462306a36Sopenharmony_ci						struct discard_cmd *dc)
139562306a36Sopenharmony_ci{
139662306a36Sopenharmony_ci	list_move_tail(&dc->list, &dcc->pend_list[plist_idx(dc->di.len)]);
139762306a36Sopenharmony_ci}
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_cistatic void __punch_discard_cmd(struct f2fs_sb_info *sbi,
140062306a36Sopenharmony_ci				struct discard_cmd *dc, block_t blkaddr)
140162306a36Sopenharmony_ci{
140262306a36Sopenharmony_ci	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
140362306a36Sopenharmony_ci	struct discard_info di = dc->di;
140462306a36Sopenharmony_ci	bool modified = false;
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	if (dc->state == D_DONE || dc->di.len == 1) {
140762306a36Sopenharmony_ci		__remove_discard_cmd(sbi, dc);
140862306a36Sopenharmony_ci		return;
140962306a36Sopenharmony_ci	}
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	dcc->undiscard_blks -= di.len;
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	if (blkaddr > di.lstart) {
141462306a36Sopenharmony_ci		dc->di.len = blkaddr - dc->di.lstart;
141562306a36Sopenharmony_ci		dcc->undiscard_blks += dc->di.len;
141662306a36Sopenharmony_ci		__relocate_discard_cmd(dcc, dc);
141762306a36Sopenharmony_ci		modified = true;
141862306a36Sopenharmony_ci	}
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	if (blkaddr < di.lstart + di.len - 1) {
142162306a36Sopenharmony_ci		if (modified) {
142262306a36Sopenharmony_ci			__insert_discard_cmd(sbi, dc->bdev, blkaddr + 1,
142362306a36Sopenharmony_ci					di.start + blkaddr + 1 - di.lstart,
142462306a36Sopenharmony_ci					di.lstart + di.len - 1 - blkaddr);
142562306a36Sopenharmony_ci		} else {
142662306a36Sopenharmony_ci			dc->di.lstart++;
142762306a36Sopenharmony_ci			dc->di.len--;
142862306a36Sopenharmony_ci			dc->di.start++;
142962306a36Sopenharmony_ci			dcc->undiscard_blks += dc->di.len;
143062306a36Sopenharmony_ci			__relocate_discard_cmd(dcc, dc);
143162306a36Sopenharmony_ci		}
143262306a36Sopenharmony_ci	}
143362306a36Sopenharmony_ci}
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_cistatic void __update_discard_tree_range(struct f2fs_sb_info *sbi,
143662306a36Sopenharmony_ci				struct block_device *bdev, block_t lstart,
143762306a36Sopenharmony_ci				block_t start, block_t len)
143862306a36Sopenharmony_ci{
143962306a36Sopenharmony_ci	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
144062306a36Sopenharmony_ci	struct discard_cmd *prev_dc = NULL, *next_dc = NULL;
144162306a36Sopenharmony_ci	struct discard_cmd *dc;
144262306a36Sopenharmony_ci	struct discard_info di = {0};
144362306a36Sopenharmony_ci	struct rb_node **insert_p = NULL, *insert_parent = NULL;
144462306a36Sopenharmony_ci	unsigned int max_discard_blocks =
144562306a36Sopenharmony_ci			SECTOR_TO_BLOCK(bdev_max_discard_sectors(bdev));
144662306a36Sopenharmony_ci	block_t end = lstart + len;
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci	dc = __lookup_discard_cmd_ret(&dcc->root, lstart,
144962306a36Sopenharmony_ci				&prev_dc, &next_dc, &insert_p, &insert_parent);
145062306a36Sopenharmony_ci	if (dc)
145162306a36Sopenharmony_ci		prev_dc = dc;
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	if (!prev_dc) {
145462306a36Sopenharmony_ci		di.lstart = lstart;
145562306a36Sopenharmony_ci		di.len = next_dc ? next_dc->di.lstart - lstart : len;
145662306a36Sopenharmony_ci		di.len = min(di.len, len);
145762306a36Sopenharmony_ci		di.start = start;
145862306a36Sopenharmony_ci	}
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	while (1) {
146162306a36Sopenharmony_ci		struct rb_node *node;
146262306a36Sopenharmony_ci		bool merged = false;
146362306a36Sopenharmony_ci		struct discard_cmd *tdc = NULL;
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci		if (prev_dc) {
146662306a36Sopenharmony_ci			di.lstart = prev_dc->di.lstart + prev_dc->di.len;
146762306a36Sopenharmony_ci			if (di.lstart < lstart)
146862306a36Sopenharmony_ci				di.lstart = lstart;
146962306a36Sopenharmony_ci			if (di.lstart >= end)
147062306a36Sopenharmony_ci				break;
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci			if (!next_dc || next_dc->di.lstart > end)
147362306a36Sopenharmony_ci				di.len = end - di.lstart;
147462306a36Sopenharmony_ci			else
147562306a36Sopenharmony_ci				di.len = next_dc->di.lstart - di.lstart;
147662306a36Sopenharmony_ci			di.start = start + di.lstart - lstart;
147762306a36Sopenharmony_ci		}
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci		if (!di.len)
148062306a36Sopenharmony_ci			goto next;
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci		if (prev_dc && prev_dc->state == D_PREP &&
148362306a36Sopenharmony_ci			prev_dc->bdev == bdev &&
148462306a36Sopenharmony_ci			__is_discard_back_mergeable(&di, &prev_dc->di,
148562306a36Sopenharmony_ci							max_discard_blocks)) {
148662306a36Sopenharmony_ci			prev_dc->di.len += di.len;
148762306a36Sopenharmony_ci			dcc->undiscard_blks += di.len;
148862306a36Sopenharmony_ci			__relocate_discard_cmd(dcc, prev_dc);
148962306a36Sopenharmony_ci			di = prev_dc->di;
149062306a36Sopenharmony_ci			tdc = prev_dc;
149162306a36Sopenharmony_ci			merged = true;
149262306a36Sopenharmony_ci		}
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci		if (next_dc && next_dc->state == D_PREP &&
149562306a36Sopenharmony_ci			next_dc->bdev == bdev &&
149662306a36Sopenharmony_ci			__is_discard_front_mergeable(&di, &next_dc->di,
149762306a36Sopenharmony_ci							max_discard_blocks)) {
149862306a36Sopenharmony_ci			next_dc->di.lstart = di.lstart;
149962306a36Sopenharmony_ci			next_dc->di.len += di.len;
150062306a36Sopenharmony_ci			next_dc->di.start = di.start;
150162306a36Sopenharmony_ci			dcc->undiscard_blks += di.len;
150262306a36Sopenharmony_ci			__relocate_discard_cmd(dcc, next_dc);
150362306a36Sopenharmony_ci			if (tdc)
150462306a36Sopenharmony_ci				__remove_discard_cmd(sbi, tdc);
150562306a36Sopenharmony_ci			merged = true;
150662306a36Sopenharmony_ci		}
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci		if (!merged)
150962306a36Sopenharmony_ci			__insert_discard_cmd(sbi, bdev,
151062306a36Sopenharmony_ci						di.lstart, di.start, di.len);
151162306a36Sopenharmony_ci next:
151262306a36Sopenharmony_ci		prev_dc = next_dc;
151362306a36Sopenharmony_ci		if (!prev_dc)
151462306a36Sopenharmony_ci			break;
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci		node = rb_next(&prev_dc->rb_node);
151762306a36Sopenharmony_ci		next_dc = rb_entry_safe(node, struct discard_cmd, rb_node);
151862306a36Sopenharmony_ci	}
151962306a36Sopenharmony_ci}
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEV_ZONED
152262306a36Sopenharmony_cistatic void __queue_zone_reset_cmd(struct f2fs_sb_info *sbi,
152362306a36Sopenharmony_ci		struct block_device *bdev, block_t blkstart, block_t lblkstart,
152462306a36Sopenharmony_ci		block_t blklen)
152562306a36Sopenharmony_ci{
152662306a36Sopenharmony_ci	trace_f2fs_queue_reset_zone(bdev, blkstart);
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	mutex_lock(&SM_I(sbi)->dcc_info->cmd_lock);
152962306a36Sopenharmony_ci	__insert_discard_cmd(sbi, bdev, lblkstart, blkstart, blklen);
153062306a36Sopenharmony_ci	mutex_unlock(&SM_I(sbi)->dcc_info->cmd_lock);
153162306a36Sopenharmony_ci}
153262306a36Sopenharmony_ci#endif
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_cistatic void __queue_discard_cmd(struct f2fs_sb_info *sbi,
153562306a36Sopenharmony_ci		struct block_device *bdev, block_t blkstart, block_t blklen)
153662306a36Sopenharmony_ci{
153762306a36Sopenharmony_ci	block_t lblkstart = blkstart;
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	if (!f2fs_bdev_support_discard(bdev))
154062306a36Sopenharmony_ci		return;
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	trace_f2fs_queue_discard(bdev, blkstart, blklen);
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	if (f2fs_is_multi_device(sbi)) {
154562306a36Sopenharmony_ci		int devi = f2fs_target_device_index(sbi, blkstart);
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci		blkstart -= FDEV(devi).start_blk;
154862306a36Sopenharmony_ci	}
154962306a36Sopenharmony_ci	mutex_lock(&SM_I(sbi)->dcc_info->cmd_lock);
155062306a36Sopenharmony_ci	__update_discard_tree_range(sbi, bdev, lblkstart, blkstart, blklen);
155162306a36Sopenharmony_ci	mutex_unlock(&SM_I(sbi)->dcc_info->cmd_lock);
155262306a36Sopenharmony_ci}
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_cistatic void __issue_discard_cmd_orderly(struct f2fs_sb_info *sbi,
155562306a36Sopenharmony_ci		struct discard_policy *dpolicy, int *issued)
155662306a36Sopenharmony_ci{
155762306a36Sopenharmony_ci	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
155862306a36Sopenharmony_ci	struct discard_cmd *prev_dc = NULL, *next_dc = NULL;
155962306a36Sopenharmony_ci	struct rb_node **insert_p = NULL, *insert_parent = NULL;
156062306a36Sopenharmony_ci	struct discard_cmd *dc;
156162306a36Sopenharmony_ci	struct blk_plug plug;
156262306a36Sopenharmony_ci	bool io_interrupted = false;
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	mutex_lock(&dcc->cmd_lock);
156562306a36Sopenharmony_ci	dc = __lookup_discard_cmd_ret(&dcc->root, dcc->next_pos,
156662306a36Sopenharmony_ci				&prev_dc, &next_dc, &insert_p, &insert_parent);
156762306a36Sopenharmony_ci	if (!dc)
156862306a36Sopenharmony_ci		dc = next_dc;
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci	blk_start_plug(&plug);
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci	while (dc) {
157362306a36Sopenharmony_ci		struct rb_node *node;
157462306a36Sopenharmony_ci		int err = 0;
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci		if (dc->state != D_PREP)
157762306a36Sopenharmony_ci			goto next;
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci		if (dpolicy->io_aware && !is_idle(sbi, DISCARD_TIME)) {
158062306a36Sopenharmony_ci			io_interrupted = true;
158162306a36Sopenharmony_ci			break;
158262306a36Sopenharmony_ci		}
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci		dcc->next_pos = dc->di.lstart + dc->di.len;
158562306a36Sopenharmony_ci		err = __submit_discard_cmd(sbi, dpolicy, dc, issued);
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci		if (*issued >= dpolicy->max_requests)
158862306a36Sopenharmony_ci			break;
158962306a36Sopenharmony_cinext:
159062306a36Sopenharmony_ci		node = rb_next(&dc->rb_node);
159162306a36Sopenharmony_ci		if (err)
159262306a36Sopenharmony_ci			__remove_discard_cmd(sbi, dc);
159362306a36Sopenharmony_ci		dc = rb_entry_safe(node, struct discard_cmd, rb_node);
159462306a36Sopenharmony_ci	}
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	blk_finish_plug(&plug);
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	if (!dc)
159962306a36Sopenharmony_ci		dcc->next_pos = 0;
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci	mutex_unlock(&dcc->cmd_lock);
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	if (!(*issued) && io_interrupted)
160462306a36Sopenharmony_ci		*issued = -1;
160562306a36Sopenharmony_ci}
160662306a36Sopenharmony_cistatic unsigned int __wait_all_discard_cmd(struct f2fs_sb_info *sbi,
160762306a36Sopenharmony_ci					struct discard_policy *dpolicy);
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_cistatic int __issue_discard_cmd(struct f2fs_sb_info *sbi,
161062306a36Sopenharmony_ci					struct discard_policy *dpolicy)
161162306a36Sopenharmony_ci{
161262306a36Sopenharmony_ci	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
161362306a36Sopenharmony_ci	struct list_head *pend_list;
161462306a36Sopenharmony_ci	struct discard_cmd *dc, *tmp;
161562306a36Sopenharmony_ci	struct blk_plug plug;
161662306a36Sopenharmony_ci	int i, issued;
161762306a36Sopenharmony_ci	bool io_interrupted = false;
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci	if (dpolicy->timeout)
162062306a36Sopenharmony_ci		f2fs_update_time(sbi, UMOUNT_DISCARD_TIMEOUT);
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ciretry:
162362306a36Sopenharmony_ci	issued = 0;
162462306a36Sopenharmony_ci	for (i = MAX_PLIST_NUM - 1; i >= 0; i--) {
162562306a36Sopenharmony_ci		if (dpolicy->timeout &&
162662306a36Sopenharmony_ci				f2fs_time_over(sbi, UMOUNT_DISCARD_TIMEOUT))
162762306a36Sopenharmony_ci			break;
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci		if (i + 1 < dpolicy->granularity)
163062306a36Sopenharmony_ci			break;
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci		if (i + 1 < dcc->max_ordered_discard && dpolicy->ordered) {
163362306a36Sopenharmony_ci			__issue_discard_cmd_orderly(sbi, dpolicy, &issued);
163462306a36Sopenharmony_ci			return issued;
163562306a36Sopenharmony_ci		}
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci		pend_list = &dcc->pend_list[i];
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci		mutex_lock(&dcc->cmd_lock);
164062306a36Sopenharmony_ci		if (list_empty(pend_list))
164162306a36Sopenharmony_ci			goto next;
164262306a36Sopenharmony_ci		if (unlikely(dcc->rbtree_check))
164362306a36Sopenharmony_ci			f2fs_bug_on(sbi, !f2fs_check_discard_tree(sbi));
164462306a36Sopenharmony_ci		blk_start_plug(&plug);
164562306a36Sopenharmony_ci		list_for_each_entry_safe(dc, tmp, pend_list, list) {
164662306a36Sopenharmony_ci			f2fs_bug_on(sbi, dc->state != D_PREP);
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci			if (dpolicy->timeout &&
164962306a36Sopenharmony_ci				f2fs_time_over(sbi, UMOUNT_DISCARD_TIMEOUT))
165062306a36Sopenharmony_ci				break;
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci			if (dpolicy->io_aware && i < dpolicy->io_aware_gran &&
165362306a36Sopenharmony_ci						!is_idle(sbi, DISCARD_TIME)) {
165462306a36Sopenharmony_ci				io_interrupted = true;
165562306a36Sopenharmony_ci				break;
165662306a36Sopenharmony_ci			}
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci			__submit_discard_cmd(sbi, dpolicy, dc, &issued);
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci			if (issued >= dpolicy->max_requests)
166162306a36Sopenharmony_ci				break;
166262306a36Sopenharmony_ci		}
166362306a36Sopenharmony_ci		blk_finish_plug(&plug);
166462306a36Sopenharmony_cinext:
166562306a36Sopenharmony_ci		mutex_unlock(&dcc->cmd_lock);
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci		if (issued >= dpolicy->max_requests || io_interrupted)
166862306a36Sopenharmony_ci			break;
166962306a36Sopenharmony_ci	}
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci	if (dpolicy->type == DPOLICY_UMOUNT && issued) {
167262306a36Sopenharmony_ci		__wait_all_discard_cmd(sbi, dpolicy);
167362306a36Sopenharmony_ci		goto retry;
167462306a36Sopenharmony_ci	}
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	if (!issued && io_interrupted)
167762306a36Sopenharmony_ci		issued = -1;
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	return issued;
168062306a36Sopenharmony_ci}
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_cistatic bool __drop_discard_cmd(struct f2fs_sb_info *sbi)
168362306a36Sopenharmony_ci{
168462306a36Sopenharmony_ci	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
168562306a36Sopenharmony_ci	struct list_head *pend_list;
168662306a36Sopenharmony_ci	struct discard_cmd *dc, *tmp;
168762306a36Sopenharmony_ci	int i;
168862306a36Sopenharmony_ci	bool dropped = false;
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	mutex_lock(&dcc->cmd_lock);
169162306a36Sopenharmony_ci	for (i = MAX_PLIST_NUM - 1; i >= 0; i--) {
169262306a36Sopenharmony_ci		pend_list = &dcc->pend_list[i];
169362306a36Sopenharmony_ci		list_for_each_entry_safe(dc, tmp, pend_list, list) {
169462306a36Sopenharmony_ci			f2fs_bug_on(sbi, dc->state != D_PREP);
169562306a36Sopenharmony_ci			__remove_discard_cmd(sbi, dc);
169662306a36Sopenharmony_ci			dropped = true;
169762306a36Sopenharmony_ci		}
169862306a36Sopenharmony_ci	}
169962306a36Sopenharmony_ci	mutex_unlock(&dcc->cmd_lock);
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	return dropped;
170262306a36Sopenharmony_ci}
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_civoid f2fs_drop_discard_cmd(struct f2fs_sb_info *sbi)
170562306a36Sopenharmony_ci{
170662306a36Sopenharmony_ci	__drop_discard_cmd(sbi);
170762306a36Sopenharmony_ci}
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_cistatic unsigned int __wait_one_discard_bio(struct f2fs_sb_info *sbi,
171062306a36Sopenharmony_ci							struct discard_cmd *dc)
171162306a36Sopenharmony_ci{
171262306a36Sopenharmony_ci	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
171362306a36Sopenharmony_ci	unsigned int len = 0;
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	wait_for_completion_io(&dc->wait);
171662306a36Sopenharmony_ci	mutex_lock(&dcc->cmd_lock);
171762306a36Sopenharmony_ci	f2fs_bug_on(sbi, dc->state != D_DONE);
171862306a36Sopenharmony_ci	dc->ref--;
171962306a36Sopenharmony_ci	if (!dc->ref) {
172062306a36Sopenharmony_ci		if (!dc->error)
172162306a36Sopenharmony_ci			len = dc->di.len;
172262306a36Sopenharmony_ci		__remove_discard_cmd(sbi, dc);
172362306a36Sopenharmony_ci	}
172462306a36Sopenharmony_ci	mutex_unlock(&dcc->cmd_lock);
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	return len;
172762306a36Sopenharmony_ci}
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_cistatic unsigned int __wait_discard_cmd_range(struct f2fs_sb_info *sbi,
173062306a36Sopenharmony_ci						struct discard_policy *dpolicy,
173162306a36Sopenharmony_ci						block_t start, block_t end)
173262306a36Sopenharmony_ci{
173362306a36Sopenharmony_ci	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
173462306a36Sopenharmony_ci	struct list_head *wait_list = (dpolicy->type == DPOLICY_FSTRIM) ?
173562306a36Sopenharmony_ci					&(dcc->fstrim_list) : &(dcc->wait_list);
173662306a36Sopenharmony_ci	struct discard_cmd *dc = NULL, *iter, *tmp;
173762306a36Sopenharmony_ci	unsigned int trimmed = 0;
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_cinext:
174062306a36Sopenharmony_ci	dc = NULL;
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci	mutex_lock(&dcc->cmd_lock);
174362306a36Sopenharmony_ci	list_for_each_entry_safe(iter, tmp, wait_list, list) {
174462306a36Sopenharmony_ci		if (iter->di.lstart + iter->di.len <= start ||
174562306a36Sopenharmony_ci					end <= iter->di.lstart)
174662306a36Sopenharmony_ci			continue;
174762306a36Sopenharmony_ci		if (iter->di.len < dpolicy->granularity)
174862306a36Sopenharmony_ci			continue;
174962306a36Sopenharmony_ci		if (iter->state == D_DONE && !iter->ref) {
175062306a36Sopenharmony_ci			wait_for_completion_io(&iter->wait);
175162306a36Sopenharmony_ci			if (!iter->error)
175262306a36Sopenharmony_ci				trimmed += iter->di.len;
175362306a36Sopenharmony_ci			__remove_discard_cmd(sbi, iter);
175462306a36Sopenharmony_ci		} else {
175562306a36Sopenharmony_ci			iter->ref++;
175662306a36Sopenharmony_ci			dc = iter;
175762306a36Sopenharmony_ci			break;
175862306a36Sopenharmony_ci		}
175962306a36Sopenharmony_ci	}
176062306a36Sopenharmony_ci	mutex_unlock(&dcc->cmd_lock);
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci	if (dc) {
176362306a36Sopenharmony_ci		trimmed += __wait_one_discard_bio(sbi, dc);
176462306a36Sopenharmony_ci		goto next;
176562306a36Sopenharmony_ci	}
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	return trimmed;
176862306a36Sopenharmony_ci}
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_cistatic unsigned int __wait_all_discard_cmd(struct f2fs_sb_info *sbi,
177162306a36Sopenharmony_ci						struct discard_policy *dpolicy)
177262306a36Sopenharmony_ci{
177362306a36Sopenharmony_ci	struct discard_policy dp;
177462306a36Sopenharmony_ci	unsigned int discard_blks;
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	if (dpolicy)
177762306a36Sopenharmony_ci		return __wait_discard_cmd_range(sbi, dpolicy, 0, UINT_MAX);
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci	/* wait all */
178062306a36Sopenharmony_ci	__init_discard_policy(sbi, &dp, DPOLICY_FSTRIM, MIN_DISCARD_GRANULARITY);
178162306a36Sopenharmony_ci	discard_blks = __wait_discard_cmd_range(sbi, &dp, 0, UINT_MAX);
178262306a36Sopenharmony_ci	__init_discard_policy(sbi, &dp, DPOLICY_UMOUNT, MIN_DISCARD_GRANULARITY);
178362306a36Sopenharmony_ci	discard_blks += __wait_discard_cmd_range(sbi, &dp, 0, UINT_MAX);
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	return discard_blks;
178662306a36Sopenharmony_ci}
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci/* This should be covered by global mutex, &sit_i->sentry_lock */
178962306a36Sopenharmony_cistatic void f2fs_wait_discard_bio(struct f2fs_sb_info *sbi, block_t blkaddr)
179062306a36Sopenharmony_ci{
179162306a36Sopenharmony_ci	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
179262306a36Sopenharmony_ci	struct discard_cmd *dc;
179362306a36Sopenharmony_ci	bool need_wait = false;
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	mutex_lock(&dcc->cmd_lock);
179662306a36Sopenharmony_ci	dc = __lookup_discard_cmd(sbi, blkaddr);
179762306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEV_ZONED
179862306a36Sopenharmony_ci	if (dc && f2fs_sb_has_blkzoned(sbi) && bdev_is_zoned(dc->bdev)) {
179962306a36Sopenharmony_ci		int devi = f2fs_bdev_index(sbi, dc->bdev);
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci		if (devi < 0) {
180262306a36Sopenharmony_ci			mutex_unlock(&dcc->cmd_lock);
180362306a36Sopenharmony_ci			return;
180462306a36Sopenharmony_ci		}
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci		if (f2fs_blkz_is_seq(sbi, devi, dc->di.start)) {
180762306a36Sopenharmony_ci			/* force submit zone reset */
180862306a36Sopenharmony_ci			if (dc->state == D_PREP)
180962306a36Sopenharmony_ci				__submit_zone_reset_cmd(sbi, dc, REQ_SYNC,
181062306a36Sopenharmony_ci							&dcc->wait_list, NULL);
181162306a36Sopenharmony_ci			dc->ref++;
181262306a36Sopenharmony_ci			mutex_unlock(&dcc->cmd_lock);
181362306a36Sopenharmony_ci			/* wait zone reset */
181462306a36Sopenharmony_ci			__wait_one_discard_bio(sbi, dc);
181562306a36Sopenharmony_ci			return;
181662306a36Sopenharmony_ci		}
181762306a36Sopenharmony_ci	}
181862306a36Sopenharmony_ci#endif
181962306a36Sopenharmony_ci	if (dc) {
182062306a36Sopenharmony_ci		if (dc->state == D_PREP) {
182162306a36Sopenharmony_ci			__punch_discard_cmd(sbi, dc, blkaddr);
182262306a36Sopenharmony_ci		} else {
182362306a36Sopenharmony_ci			dc->ref++;
182462306a36Sopenharmony_ci			need_wait = true;
182562306a36Sopenharmony_ci		}
182662306a36Sopenharmony_ci	}
182762306a36Sopenharmony_ci	mutex_unlock(&dcc->cmd_lock);
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	if (need_wait)
183062306a36Sopenharmony_ci		__wait_one_discard_bio(sbi, dc);
183162306a36Sopenharmony_ci}
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_civoid f2fs_stop_discard_thread(struct f2fs_sb_info *sbi)
183462306a36Sopenharmony_ci{
183562306a36Sopenharmony_ci	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci	if (dcc && dcc->f2fs_issue_discard) {
183862306a36Sopenharmony_ci		struct task_struct *discard_thread = dcc->f2fs_issue_discard;
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci		dcc->f2fs_issue_discard = NULL;
184162306a36Sopenharmony_ci		kthread_stop(discard_thread);
184262306a36Sopenharmony_ci	}
184362306a36Sopenharmony_ci}
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci/**
184662306a36Sopenharmony_ci * f2fs_issue_discard_timeout() - Issue all discard cmd within UMOUNT_DISCARD_TIMEOUT
184762306a36Sopenharmony_ci * @sbi: the f2fs_sb_info data for discard cmd to issue
184862306a36Sopenharmony_ci *
184962306a36Sopenharmony_ci * When UMOUNT_DISCARD_TIMEOUT is exceeded, all remaining discard commands will be dropped
185062306a36Sopenharmony_ci *
185162306a36Sopenharmony_ci * Return true if issued all discard cmd or no discard cmd need issue, otherwise return false.
185262306a36Sopenharmony_ci */
185362306a36Sopenharmony_cibool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi)
185462306a36Sopenharmony_ci{
185562306a36Sopenharmony_ci	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
185662306a36Sopenharmony_ci	struct discard_policy dpolicy;
185762306a36Sopenharmony_ci	bool dropped;
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci	if (!atomic_read(&dcc->discard_cmd_cnt))
186062306a36Sopenharmony_ci		return true;
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	__init_discard_policy(sbi, &dpolicy, DPOLICY_UMOUNT,
186362306a36Sopenharmony_ci					dcc->discard_granularity);
186462306a36Sopenharmony_ci	__issue_discard_cmd(sbi, &dpolicy);
186562306a36Sopenharmony_ci	dropped = __drop_discard_cmd(sbi);
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	/* just to make sure there is no pending discard commands */
186862306a36Sopenharmony_ci	__wait_all_discard_cmd(sbi, NULL);
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	f2fs_bug_on(sbi, atomic_read(&dcc->discard_cmd_cnt));
187162306a36Sopenharmony_ci	return !dropped;
187262306a36Sopenharmony_ci}
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_cistatic int issue_discard_thread(void *data)
187562306a36Sopenharmony_ci{
187662306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = data;
187762306a36Sopenharmony_ci	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
187862306a36Sopenharmony_ci	wait_queue_head_t *q = &dcc->discard_wait_queue;
187962306a36Sopenharmony_ci	struct discard_policy dpolicy;
188062306a36Sopenharmony_ci	unsigned int wait_ms = dcc->min_discard_issue_time;
188162306a36Sopenharmony_ci	int issued;
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci	set_freezable();
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci	do {
188662306a36Sopenharmony_ci		wait_event_interruptible_timeout(*q,
188762306a36Sopenharmony_ci				kthread_should_stop() || freezing(current) ||
188862306a36Sopenharmony_ci				dcc->discard_wake,
188962306a36Sopenharmony_ci				msecs_to_jiffies(wait_ms));
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci		if (sbi->gc_mode == GC_URGENT_HIGH ||
189262306a36Sopenharmony_ci			!f2fs_available_free_memory(sbi, DISCARD_CACHE))
189362306a36Sopenharmony_ci			__init_discard_policy(sbi, &dpolicy, DPOLICY_FORCE,
189462306a36Sopenharmony_ci						MIN_DISCARD_GRANULARITY);
189562306a36Sopenharmony_ci		else
189662306a36Sopenharmony_ci			__init_discard_policy(sbi, &dpolicy, DPOLICY_BG,
189762306a36Sopenharmony_ci						dcc->discard_granularity);
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci		if (dcc->discard_wake)
190062306a36Sopenharmony_ci			dcc->discard_wake = false;
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci		/* clean up pending candidates before going to sleep */
190362306a36Sopenharmony_ci		if (atomic_read(&dcc->queued_discard))
190462306a36Sopenharmony_ci			__wait_all_discard_cmd(sbi, NULL);
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci		if (try_to_freeze())
190762306a36Sopenharmony_ci			continue;
190862306a36Sopenharmony_ci		if (f2fs_readonly(sbi->sb))
190962306a36Sopenharmony_ci			continue;
191062306a36Sopenharmony_ci		if (kthread_should_stop())
191162306a36Sopenharmony_ci			return 0;
191262306a36Sopenharmony_ci		if (is_sbi_flag_set(sbi, SBI_NEED_FSCK) ||
191362306a36Sopenharmony_ci			!atomic_read(&dcc->discard_cmd_cnt)) {
191462306a36Sopenharmony_ci			wait_ms = dpolicy.max_interval;
191562306a36Sopenharmony_ci			continue;
191662306a36Sopenharmony_ci		}
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci		sb_start_intwrite(sbi->sb);
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci		issued = __issue_discard_cmd(sbi, &dpolicy);
192162306a36Sopenharmony_ci		if (issued > 0) {
192262306a36Sopenharmony_ci			__wait_all_discard_cmd(sbi, &dpolicy);
192362306a36Sopenharmony_ci			wait_ms = dpolicy.min_interval;
192462306a36Sopenharmony_ci		} else if (issued == -1) {
192562306a36Sopenharmony_ci			wait_ms = f2fs_time_to_wait(sbi, DISCARD_TIME);
192662306a36Sopenharmony_ci			if (!wait_ms)
192762306a36Sopenharmony_ci				wait_ms = dpolicy.mid_interval;
192862306a36Sopenharmony_ci		} else {
192962306a36Sopenharmony_ci			wait_ms = dpolicy.max_interval;
193062306a36Sopenharmony_ci		}
193162306a36Sopenharmony_ci		if (!atomic_read(&dcc->discard_cmd_cnt))
193262306a36Sopenharmony_ci			wait_ms = dpolicy.max_interval;
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci		sb_end_intwrite(sbi->sb);
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci	} while (!kthread_should_stop());
193762306a36Sopenharmony_ci	return 0;
193862306a36Sopenharmony_ci}
193962306a36Sopenharmony_ci
194062306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEV_ZONED
194162306a36Sopenharmony_cistatic int __f2fs_issue_discard_zone(struct f2fs_sb_info *sbi,
194262306a36Sopenharmony_ci		struct block_device *bdev, block_t blkstart, block_t blklen)
194362306a36Sopenharmony_ci{
194462306a36Sopenharmony_ci	sector_t sector, nr_sects;
194562306a36Sopenharmony_ci	block_t lblkstart = blkstart;
194662306a36Sopenharmony_ci	int devi = 0;
194762306a36Sopenharmony_ci	u64 remainder = 0;
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci	if (f2fs_is_multi_device(sbi)) {
195062306a36Sopenharmony_ci		devi = f2fs_target_device_index(sbi, blkstart);
195162306a36Sopenharmony_ci		if (blkstart < FDEV(devi).start_blk ||
195262306a36Sopenharmony_ci		    blkstart > FDEV(devi).end_blk) {
195362306a36Sopenharmony_ci			f2fs_err(sbi, "Invalid block %x", blkstart);
195462306a36Sopenharmony_ci			return -EIO;
195562306a36Sopenharmony_ci		}
195662306a36Sopenharmony_ci		blkstart -= FDEV(devi).start_blk;
195762306a36Sopenharmony_ci	}
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci	/* For sequential zones, reset the zone write pointer */
196062306a36Sopenharmony_ci	if (f2fs_blkz_is_seq(sbi, devi, blkstart)) {
196162306a36Sopenharmony_ci		sector = SECTOR_FROM_BLOCK(blkstart);
196262306a36Sopenharmony_ci		nr_sects = SECTOR_FROM_BLOCK(blklen);
196362306a36Sopenharmony_ci		div64_u64_rem(sector, bdev_zone_sectors(bdev), &remainder);
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci		if (remainder || nr_sects != bdev_zone_sectors(bdev)) {
196662306a36Sopenharmony_ci			f2fs_err(sbi, "(%d) %s: Unaligned zone reset attempted (block %x + %x)",
196762306a36Sopenharmony_ci				 devi, sbi->s_ndevs ? FDEV(devi).path : "",
196862306a36Sopenharmony_ci				 blkstart, blklen);
196962306a36Sopenharmony_ci			return -EIO;
197062306a36Sopenharmony_ci		}
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci		if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) {
197362306a36Sopenharmony_ci			trace_f2fs_issue_reset_zone(bdev, blkstart);
197462306a36Sopenharmony_ci			return blkdev_zone_mgmt(bdev, REQ_OP_ZONE_RESET,
197562306a36Sopenharmony_ci						sector, nr_sects, GFP_NOFS);
197662306a36Sopenharmony_ci		}
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci		__queue_zone_reset_cmd(sbi, bdev, blkstart, lblkstart, blklen);
197962306a36Sopenharmony_ci		return 0;
198062306a36Sopenharmony_ci	}
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci	/* For conventional zones, use regular discard if supported */
198362306a36Sopenharmony_ci	__queue_discard_cmd(sbi, bdev, lblkstart, blklen);
198462306a36Sopenharmony_ci	return 0;
198562306a36Sopenharmony_ci}
198662306a36Sopenharmony_ci#endif
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_cistatic int __issue_discard_async(struct f2fs_sb_info *sbi,
198962306a36Sopenharmony_ci		struct block_device *bdev, block_t blkstart, block_t blklen)
199062306a36Sopenharmony_ci{
199162306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEV_ZONED
199262306a36Sopenharmony_ci	if (f2fs_sb_has_blkzoned(sbi) && bdev_is_zoned(bdev))
199362306a36Sopenharmony_ci		return __f2fs_issue_discard_zone(sbi, bdev, blkstart, blklen);
199462306a36Sopenharmony_ci#endif
199562306a36Sopenharmony_ci	__queue_discard_cmd(sbi, bdev, blkstart, blklen);
199662306a36Sopenharmony_ci	return 0;
199762306a36Sopenharmony_ci}
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_cistatic int f2fs_issue_discard(struct f2fs_sb_info *sbi,
200062306a36Sopenharmony_ci				block_t blkstart, block_t blklen)
200162306a36Sopenharmony_ci{
200262306a36Sopenharmony_ci	sector_t start = blkstart, len = 0;
200362306a36Sopenharmony_ci	struct block_device *bdev;
200462306a36Sopenharmony_ci	struct seg_entry *se;
200562306a36Sopenharmony_ci	unsigned int offset;
200662306a36Sopenharmony_ci	block_t i;
200762306a36Sopenharmony_ci	int err = 0;
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci	bdev = f2fs_target_device(sbi, blkstart, NULL);
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_ci	for (i = blkstart; i < blkstart + blklen; i++, len++) {
201262306a36Sopenharmony_ci		if (i != start) {
201362306a36Sopenharmony_ci			struct block_device *bdev2 =
201462306a36Sopenharmony_ci				f2fs_target_device(sbi, i, NULL);
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci			if (bdev2 != bdev) {
201762306a36Sopenharmony_ci				err = __issue_discard_async(sbi, bdev,
201862306a36Sopenharmony_ci						start, len);
201962306a36Sopenharmony_ci				if (err)
202062306a36Sopenharmony_ci					return err;
202162306a36Sopenharmony_ci				bdev = bdev2;
202262306a36Sopenharmony_ci				start = i;
202362306a36Sopenharmony_ci				len = 0;
202462306a36Sopenharmony_ci			}
202562306a36Sopenharmony_ci		}
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci		se = get_seg_entry(sbi, GET_SEGNO(sbi, i));
202862306a36Sopenharmony_ci		offset = GET_BLKOFF_FROM_SEG0(sbi, i);
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci		if (f2fs_block_unit_discard(sbi) &&
203162306a36Sopenharmony_ci				!f2fs_test_and_set_bit(offset, se->discard_map))
203262306a36Sopenharmony_ci			sbi->discard_blks--;
203362306a36Sopenharmony_ci	}
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_ci	if (len)
203662306a36Sopenharmony_ci		err = __issue_discard_async(sbi, bdev, start, len);
203762306a36Sopenharmony_ci	return err;
203862306a36Sopenharmony_ci}
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_cistatic bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc,
204162306a36Sopenharmony_ci							bool check_only)
204262306a36Sopenharmony_ci{
204362306a36Sopenharmony_ci	int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long);
204462306a36Sopenharmony_ci	int max_blocks = sbi->blocks_per_seg;
204562306a36Sopenharmony_ci	struct seg_entry *se = get_seg_entry(sbi, cpc->trim_start);
204662306a36Sopenharmony_ci	unsigned long *cur_map = (unsigned long *)se->cur_valid_map;
204762306a36Sopenharmony_ci	unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map;
204862306a36Sopenharmony_ci	unsigned long *discard_map = (unsigned long *)se->discard_map;
204962306a36Sopenharmony_ci	unsigned long *dmap = SIT_I(sbi)->tmp_map;
205062306a36Sopenharmony_ci	unsigned int start = 0, end = -1;
205162306a36Sopenharmony_ci	bool force = (cpc->reason & CP_DISCARD);
205262306a36Sopenharmony_ci	struct discard_entry *de = NULL;
205362306a36Sopenharmony_ci	struct list_head *head = &SM_I(sbi)->dcc_info->entry_list;
205462306a36Sopenharmony_ci	int i;
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	if (se->valid_blocks == max_blocks || !f2fs_hw_support_discard(sbi) ||
205762306a36Sopenharmony_ci			!f2fs_block_unit_discard(sbi))
205862306a36Sopenharmony_ci		return false;
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci	if (!force) {
206162306a36Sopenharmony_ci		if (!f2fs_realtime_discard_enable(sbi) || !se->valid_blocks ||
206262306a36Sopenharmony_ci			SM_I(sbi)->dcc_info->nr_discards >=
206362306a36Sopenharmony_ci				SM_I(sbi)->dcc_info->max_discards)
206462306a36Sopenharmony_ci			return false;
206562306a36Sopenharmony_ci	}
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci	/* SIT_VBLOCK_MAP_SIZE should be multiple of sizeof(unsigned long) */
206862306a36Sopenharmony_ci	for (i = 0; i < entries; i++)
206962306a36Sopenharmony_ci		dmap[i] = force ? ~ckpt_map[i] & ~discard_map[i] :
207062306a36Sopenharmony_ci				(cur_map[i] ^ ckpt_map[i]) & ckpt_map[i];
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci	while (force || SM_I(sbi)->dcc_info->nr_discards <=
207362306a36Sopenharmony_ci				SM_I(sbi)->dcc_info->max_discards) {
207462306a36Sopenharmony_ci		start = __find_rev_next_bit(dmap, max_blocks, end + 1);
207562306a36Sopenharmony_ci		if (start >= max_blocks)
207662306a36Sopenharmony_ci			break;
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_ci		end = __find_rev_next_zero_bit(dmap, max_blocks, start + 1);
207962306a36Sopenharmony_ci		if (force && start && end != max_blocks
208062306a36Sopenharmony_ci					&& (end - start) < cpc->trim_minlen)
208162306a36Sopenharmony_ci			continue;
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_ci		if (check_only)
208462306a36Sopenharmony_ci			return true;
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci		if (!de) {
208762306a36Sopenharmony_ci			de = f2fs_kmem_cache_alloc(discard_entry_slab,
208862306a36Sopenharmony_ci						GFP_F2FS_ZERO, true, NULL);
208962306a36Sopenharmony_ci			de->start_blkaddr = START_BLOCK(sbi, cpc->trim_start);
209062306a36Sopenharmony_ci			list_add_tail(&de->list, head);
209162306a36Sopenharmony_ci		}
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci		for (i = start; i < end; i++)
209462306a36Sopenharmony_ci			__set_bit_le(i, (void *)de->discard_map);
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_ci		SM_I(sbi)->dcc_info->nr_discards += end - start;
209762306a36Sopenharmony_ci	}
209862306a36Sopenharmony_ci	return false;
209962306a36Sopenharmony_ci}
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_cistatic void release_discard_addr(struct discard_entry *entry)
210262306a36Sopenharmony_ci{
210362306a36Sopenharmony_ci	list_del(&entry->list);
210462306a36Sopenharmony_ci	kmem_cache_free(discard_entry_slab, entry);
210562306a36Sopenharmony_ci}
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_civoid f2fs_release_discard_addrs(struct f2fs_sb_info *sbi)
210862306a36Sopenharmony_ci{
210962306a36Sopenharmony_ci	struct list_head *head = &(SM_I(sbi)->dcc_info->entry_list);
211062306a36Sopenharmony_ci	struct discard_entry *entry, *this;
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci	/* drop caches */
211362306a36Sopenharmony_ci	list_for_each_entry_safe(entry, this, head, list)
211462306a36Sopenharmony_ci		release_discard_addr(entry);
211562306a36Sopenharmony_ci}
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_ci/*
211862306a36Sopenharmony_ci * Should call f2fs_clear_prefree_segments after checkpoint is done.
211962306a36Sopenharmony_ci */
212062306a36Sopenharmony_cistatic void set_prefree_as_free_segments(struct f2fs_sb_info *sbi)
212162306a36Sopenharmony_ci{
212262306a36Sopenharmony_ci	struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
212362306a36Sopenharmony_ci	unsigned int segno;
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_ci	mutex_lock(&dirty_i->seglist_lock);
212662306a36Sopenharmony_ci	for_each_set_bit(segno, dirty_i->dirty_segmap[PRE], MAIN_SEGS(sbi))
212762306a36Sopenharmony_ci		__set_test_and_free(sbi, segno, false);
212862306a36Sopenharmony_ci	mutex_unlock(&dirty_i->seglist_lock);
212962306a36Sopenharmony_ci}
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_civoid f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi,
213262306a36Sopenharmony_ci						struct cp_control *cpc)
213362306a36Sopenharmony_ci{
213462306a36Sopenharmony_ci	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
213562306a36Sopenharmony_ci	struct list_head *head = &dcc->entry_list;
213662306a36Sopenharmony_ci	struct discard_entry *entry, *this;
213762306a36Sopenharmony_ci	struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
213862306a36Sopenharmony_ci	unsigned long *prefree_map = dirty_i->dirty_segmap[PRE];
213962306a36Sopenharmony_ci	unsigned int start = 0, end = -1;
214062306a36Sopenharmony_ci	unsigned int secno, start_segno;
214162306a36Sopenharmony_ci	bool force = (cpc->reason & CP_DISCARD);
214262306a36Sopenharmony_ci	bool section_alignment = F2FS_OPTION(sbi).discard_unit ==
214362306a36Sopenharmony_ci						DISCARD_UNIT_SECTION;
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci	if (f2fs_lfs_mode(sbi) && __is_large_section(sbi))
214662306a36Sopenharmony_ci		section_alignment = true;
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_ci	mutex_lock(&dirty_i->seglist_lock);
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	while (1) {
215162306a36Sopenharmony_ci		int i;
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci		if (section_alignment && end != -1)
215462306a36Sopenharmony_ci			end--;
215562306a36Sopenharmony_ci		start = find_next_bit(prefree_map, MAIN_SEGS(sbi), end + 1);
215662306a36Sopenharmony_ci		if (start >= MAIN_SEGS(sbi))
215762306a36Sopenharmony_ci			break;
215862306a36Sopenharmony_ci		end = find_next_zero_bit(prefree_map, MAIN_SEGS(sbi),
215962306a36Sopenharmony_ci								start + 1);
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci		if (section_alignment) {
216262306a36Sopenharmony_ci			start = rounddown(start, sbi->segs_per_sec);
216362306a36Sopenharmony_ci			end = roundup(end, sbi->segs_per_sec);
216462306a36Sopenharmony_ci		}
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci		for (i = start; i < end; i++) {
216762306a36Sopenharmony_ci			if (test_and_clear_bit(i, prefree_map))
216862306a36Sopenharmony_ci				dirty_i->nr_dirty[PRE]--;
216962306a36Sopenharmony_ci		}
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci		if (!f2fs_realtime_discard_enable(sbi))
217262306a36Sopenharmony_ci			continue;
217362306a36Sopenharmony_ci
217462306a36Sopenharmony_ci		if (force && start >= cpc->trim_start &&
217562306a36Sopenharmony_ci					(end - 1) <= cpc->trim_end)
217662306a36Sopenharmony_ci			continue;
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_ci		/* Should cover 2MB zoned device for zone-based reset */
217962306a36Sopenharmony_ci		if (!f2fs_sb_has_blkzoned(sbi) &&
218062306a36Sopenharmony_ci		    (!f2fs_lfs_mode(sbi) || !__is_large_section(sbi))) {
218162306a36Sopenharmony_ci			f2fs_issue_discard(sbi, START_BLOCK(sbi, start),
218262306a36Sopenharmony_ci				(end - start) << sbi->log_blocks_per_seg);
218362306a36Sopenharmony_ci			continue;
218462306a36Sopenharmony_ci		}
218562306a36Sopenharmony_cinext:
218662306a36Sopenharmony_ci		secno = GET_SEC_FROM_SEG(sbi, start);
218762306a36Sopenharmony_ci		start_segno = GET_SEG_FROM_SEC(sbi, secno);
218862306a36Sopenharmony_ci		if (!IS_CURSEC(sbi, secno) &&
218962306a36Sopenharmony_ci			!get_valid_blocks(sbi, start, true))
219062306a36Sopenharmony_ci			f2fs_issue_discard(sbi, START_BLOCK(sbi, start_segno),
219162306a36Sopenharmony_ci				sbi->segs_per_sec << sbi->log_blocks_per_seg);
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_ci		start = start_segno + sbi->segs_per_sec;
219462306a36Sopenharmony_ci		if (start < end)
219562306a36Sopenharmony_ci			goto next;
219662306a36Sopenharmony_ci		else
219762306a36Sopenharmony_ci			end = start - 1;
219862306a36Sopenharmony_ci	}
219962306a36Sopenharmony_ci	mutex_unlock(&dirty_i->seglist_lock);
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_ci	if (!f2fs_block_unit_discard(sbi))
220262306a36Sopenharmony_ci		goto wakeup;
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci	/* send small discards */
220562306a36Sopenharmony_ci	list_for_each_entry_safe(entry, this, head, list) {
220662306a36Sopenharmony_ci		unsigned int cur_pos = 0, next_pos, len, total_len = 0;
220762306a36Sopenharmony_ci		bool is_valid = test_bit_le(0, entry->discard_map);
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_cifind_next:
221062306a36Sopenharmony_ci		if (is_valid) {
221162306a36Sopenharmony_ci			next_pos = find_next_zero_bit_le(entry->discard_map,
221262306a36Sopenharmony_ci					sbi->blocks_per_seg, cur_pos);
221362306a36Sopenharmony_ci			len = next_pos - cur_pos;
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ci			if (f2fs_sb_has_blkzoned(sbi) ||
221662306a36Sopenharmony_ci			    (force && len < cpc->trim_minlen))
221762306a36Sopenharmony_ci				goto skip;
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci			f2fs_issue_discard(sbi, entry->start_blkaddr + cur_pos,
222062306a36Sopenharmony_ci									len);
222162306a36Sopenharmony_ci			total_len += len;
222262306a36Sopenharmony_ci		} else {
222362306a36Sopenharmony_ci			next_pos = find_next_bit_le(entry->discard_map,
222462306a36Sopenharmony_ci					sbi->blocks_per_seg, cur_pos);
222562306a36Sopenharmony_ci		}
222662306a36Sopenharmony_ciskip:
222762306a36Sopenharmony_ci		cur_pos = next_pos;
222862306a36Sopenharmony_ci		is_valid = !is_valid;
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci		if (cur_pos < sbi->blocks_per_seg)
223162306a36Sopenharmony_ci			goto find_next;
223262306a36Sopenharmony_ci
223362306a36Sopenharmony_ci		release_discard_addr(entry);
223462306a36Sopenharmony_ci		dcc->nr_discards -= total_len;
223562306a36Sopenharmony_ci	}
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ciwakeup:
223862306a36Sopenharmony_ci	wake_up_discard_thread(sbi, false);
223962306a36Sopenharmony_ci}
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_ciint f2fs_start_discard_thread(struct f2fs_sb_info *sbi)
224262306a36Sopenharmony_ci{
224362306a36Sopenharmony_ci	dev_t dev = sbi->sb->s_bdev->bd_dev;
224462306a36Sopenharmony_ci	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
224562306a36Sopenharmony_ci	int err = 0;
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_ci	if (!f2fs_realtime_discard_enable(sbi))
224862306a36Sopenharmony_ci		return 0;
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci	dcc->f2fs_issue_discard = kthread_run(issue_discard_thread, sbi,
225162306a36Sopenharmony_ci				"f2fs_discard-%u:%u", MAJOR(dev), MINOR(dev));
225262306a36Sopenharmony_ci	if (IS_ERR(dcc->f2fs_issue_discard)) {
225362306a36Sopenharmony_ci		err = PTR_ERR(dcc->f2fs_issue_discard);
225462306a36Sopenharmony_ci		dcc->f2fs_issue_discard = NULL;
225562306a36Sopenharmony_ci	}
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_ci	return err;
225862306a36Sopenharmony_ci}
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_cistatic int create_discard_cmd_control(struct f2fs_sb_info *sbi)
226162306a36Sopenharmony_ci{
226262306a36Sopenharmony_ci	struct discard_cmd_control *dcc;
226362306a36Sopenharmony_ci	int err = 0, i;
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci	if (SM_I(sbi)->dcc_info) {
226662306a36Sopenharmony_ci		dcc = SM_I(sbi)->dcc_info;
226762306a36Sopenharmony_ci		goto init_thread;
226862306a36Sopenharmony_ci	}
226962306a36Sopenharmony_ci
227062306a36Sopenharmony_ci	dcc = f2fs_kzalloc(sbi, sizeof(struct discard_cmd_control), GFP_KERNEL);
227162306a36Sopenharmony_ci	if (!dcc)
227262306a36Sopenharmony_ci		return -ENOMEM;
227362306a36Sopenharmony_ci
227462306a36Sopenharmony_ci	dcc->discard_io_aware_gran = MAX_PLIST_NUM;
227562306a36Sopenharmony_ci	dcc->discard_granularity = DEFAULT_DISCARD_GRANULARITY;
227662306a36Sopenharmony_ci	dcc->max_ordered_discard = DEFAULT_MAX_ORDERED_DISCARD_GRANULARITY;
227762306a36Sopenharmony_ci	if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SEGMENT)
227862306a36Sopenharmony_ci		dcc->discard_granularity = sbi->blocks_per_seg;
227962306a36Sopenharmony_ci	else if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SECTION)
228062306a36Sopenharmony_ci		dcc->discard_granularity = BLKS_PER_SEC(sbi);
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci	INIT_LIST_HEAD(&dcc->entry_list);
228362306a36Sopenharmony_ci	for (i = 0; i < MAX_PLIST_NUM; i++)
228462306a36Sopenharmony_ci		INIT_LIST_HEAD(&dcc->pend_list[i]);
228562306a36Sopenharmony_ci	INIT_LIST_HEAD(&dcc->wait_list);
228662306a36Sopenharmony_ci	INIT_LIST_HEAD(&dcc->fstrim_list);
228762306a36Sopenharmony_ci	mutex_init(&dcc->cmd_lock);
228862306a36Sopenharmony_ci	atomic_set(&dcc->issued_discard, 0);
228962306a36Sopenharmony_ci	atomic_set(&dcc->queued_discard, 0);
229062306a36Sopenharmony_ci	atomic_set(&dcc->discard_cmd_cnt, 0);
229162306a36Sopenharmony_ci	dcc->nr_discards = 0;
229262306a36Sopenharmony_ci	dcc->max_discards = MAIN_SEGS(sbi) << sbi->log_blocks_per_seg;
229362306a36Sopenharmony_ci	dcc->max_discard_request = DEF_MAX_DISCARD_REQUEST;
229462306a36Sopenharmony_ci	dcc->min_discard_issue_time = DEF_MIN_DISCARD_ISSUE_TIME;
229562306a36Sopenharmony_ci	dcc->mid_discard_issue_time = DEF_MID_DISCARD_ISSUE_TIME;
229662306a36Sopenharmony_ci	dcc->max_discard_issue_time = DEF_MAX_DISCARD_ISSUE_TIME;
229762306a36Sopenharmony_ci	dcc->discard_urgent_util = DEF_DISCARD_URGENT_UTIL;
229862306a36Sopenharmony_ci	dcc->undiscard_blks = 0;
229962306a36Sopenharmony_ci	dcc->next_pos = 0;
230062306a36Sopenharmony_ci	dcc->root = RB_ROOT_CACHED;
230162306a36Sopenharmony_ci	dcc->rbtree_check = false;
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci	init_waitqueue_head(&dcc->discard_wait_queue);
230462306a36Sopenharmony_ci	SM_I(sbi)->dcc_info = dcc;
230562306a36Sopenharmony_ciinit_thread:
230662306a36Sopenharmony_ci	err = f2fs_start_discard_thread(sbi);
230762306a36Sopenharmony_ci	if (err) {
230862306a36Sopenharmony_ci		kfree(dcc);
230962306a36Sopenharmony_ci		SM_I(sbi)->dcc_info = NULL;
231062306a36Sopenharmony_ci	}
231162306a36Sopenharmony_ci
231262306a36Sopenharmony_ci	return err;
231362306a36Sopenharmony_ci}
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_cistatic void destroy_discard_cmd_control(struct f2fs_sb_info *sbi)
231662306a36Sopenharmony_ci{
231762306a36Sopenharmony_ci	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci	if (!dcc)
232062306a36Sopenharmony_ci		return;
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci	f2fs_stop_discard_thread(sbi);
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_ci	/*
232562306a36Sopenharmony_ci	 * Recovery can cache discard commands, so in error path of
232662306a36Sopenharmony_ci	 * fill_super(), it needs to give a chance to handle them.
232762306a36Sopenharmony_ci	 */
232862306a36Sopenharmony_ci	f2fs_issue_discard_timeout(sbi);
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci	kfree(dcc);
233162306a36Sopenharmony_ci	SM_I(sbi)->dcc_info = NULL;
233262306a36Sopenharmony_ci}
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_cistatic bool __mark_sit_entry_dirty(struct f2fs_sb_info *sbi, unsigned int segno)
233562306a36Sopenharmony_ci{
233662306a36Sopenharmony_ci	struct sit_info *sit_i = SIT_I(sbi);
233762306a36Sopenharmony_ci
233862306a36Sopenharmony_ci	if (!__test_and_set_bit(segno, sit_i->dirty_sentries_bitmap)) {
233962306a36Sopenharmony_ci		sit_i->dirty_sentries++;
234062306a36Sopenharmony_ci		return false;
234162306a36Sopenharmony_ci	}
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci	return true;
234462306a36Sopenharmony_ci}
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_cistatic void __set_sit_entry_type(struct f2fs_sb_info *sbi, int type,
234762306a36Sopenharmony_ci					unsigned int segno, int modified)
234862306a36Sopenharmony_ci{
234962306a36Sopenharmony_ci	struct seg_entry *se = get_seg_entry(sbi, segno);
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ci	se->type = type;
235262306a36Sopenharmony_ci	if (modified)
235362306a36Sopenharmony_ci		__mark_sit_entry_dirty(sbi, segno);
235462306a36Sopenharmony_ci}
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_cistatic inline unsigned long long get_segment_mtime(struct f2fs_sb_info *sbi,
235762306a36Sopenharmony_ci								block_t blkaddr)
235862306a36Sopenharmony_ci{
235962306a36Sopenharmony_ci	unsigned int segno = GET_SEGNO(sbi, blkaddr);
236062306a36Sopenharmony_ci
236162306a36Sopenharmony_ci	if (segno == NULL_SEGNO)
236262306a36Sopenharmony_ci		return 0;
236362306a36Sopenharmony_ci	return get_seg_entry(sbi, segno)->mtime;
236462306a36Sopenharmony_ci}
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_cistatic void update_segment_mtime(struct f2fs_sb_info *sbi, block_t blkaddr,
236762306a36Sopenharmony_ci						unsigned long long old_mtime)
236862306a36Sopenharmony_ci{
236962306a36Sopenharmony_ci	struct seg_entry *se;
237062306a36Sopenharmony_ci	unsigned int segno = GET_SEGNO(sbi, blkaddr);
237162306a36Sopenharmony_ci	unsigned long long ctime = get_mtime(sbi, false);
237262306a36Sopenharmony_ci	unsigned long long mtime = old_mtime ? old_mtime : ctime;
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_ci	if (segno == NULL_SEGNO)
237562306a36Sopenharmony_ci		return;
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_ci	se = get_seg_entry(sbi, segno);
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci	if (!se->mtime)
238062306a36Sopenharmony_ci		se->mtime = mtime;
238162306a36Sopenharmony_ci	else
238262306a36Sopenharmony_ci		se->mtime = div_u64(se->mtime * se->valid_blocks + mtime,
238362306a36Sopenharmony_ci						se->valid_blocks + 1);
238462306a36Sopenharmony_ci
238562306a36Sopenharmony_ci	if (ctime > SIT_I(sbi)->max_mtime)
238662306a36Sopenharmony_ci		SIT_I(sbi)->max_mtime = ctime;
238762306a36Sopenharmony_ci}
238862306a36Sopenharmony_ci
238962306a36Sopenharmony_cistatic void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
239062306a36Sopenharmony_ci{
239162306a36Sopenharmony_ci	struct seg_entry *se;
239262306a36Sopenharmony_ci	unsigned int segno, offset;
239362306a36Sopenharmony_ci	long int new_vblocks;
239462306a36Sopenharmony_ci	bool exist;
239562306a36Sopenharmony_ci#ifdef CONFIG_F2FS_CHECK_FS
239662306a36Sopenharmony_ci	bool mir_exist;
239762306a36Sopenharmony_ci#endif
239862306a36Sopenharmony_ci
239962306a36Sopenharmony_ci	segno = GET_SEGNO(sbi, blkaddr);
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_ci	se = get_seg_entry(sbi, segno);
240262306a36Sopenharmony_ci	new_vblocks = se->valid_blocks + del;
240362306a36Sopenharmony_ci	offset = GET_BLKOFF_FROM_SEG0(sbi, blkaddr);
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_ci	f2fs_bug_on(sbi, (new_vblocks < 0 ||
240662306a36Sopenharmony_ci			(new_vblocks > f2fs_usable_blks_in_seg(sbi, segno))));
240762306a36Sopenharmony_ci
240862306a36Sopenharmony_ci	se->valid_blocks = new_vblocks;
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci	/* Update valid block bitmap */
241162306a36Sopenharmony_ci	if (del > 0) {
241262306a36Sopenharmony_ci		exist = f2fs_test_and_set_bit(offset, se->cur_valid_map);
241362306a36Sopenharmony_ci#ifdef CONFIG_F2FS_CHECK_FS
241462306a36Sopenharmony_ci		mir_exist = f2fs_test_and_set_bit(offset,
241562306a36Sopenharmony_ci						se->cur_valid_map_mir);
241662306a36Sopenharmony_ci		if (unlikely(exist != mir_exist)) {
241762306a36Sopenharmony_ci			f2fs_err(sbi, "Inconsistent error when setting bitmap, blk:%u, old bit:%d",
241862306a36Sopenharmony_ci				 blkaddr, exist);
241962306a36Sopenharmony_ci			f2fs_bug_on(sbi, 1);
242062306a36Sopenharmony_ci		}
242162306a36Sopenharmony_ci#endif
242262306a36Sopenharmony_ci		if (unlikely(exist)) {
242362306a36Sopenharmony_ci			f2fs_err(sbi, "Bitmap was wrongly set, blk:%u",
242462306a36Sopenharmony_ci				 blkaddr);
242562306a36Sopenharmony_ci			f2fs_bug_on(sbi, 1);
242662306a36Sopenharmony_ci			se->valid_blocks--;
242762306a36Sopenharmony_ci			del = 0;
242862306a36Sopenharmony_ci		}
242962306a36Sopenharmony_ci
243062306a36Sopenharmony_ci		if (f2fs_block_unit_discard(sbi) &&
243162306a36Sopenharmony_ci				!f2fs_test_and_set_bit(offset, se->discard_map))
243262306a36Sopenharmony_ci			sbi->discard_blks--;
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_ci		/*
243562306a36Sopenharmony_ci		 * SSR should never reuse block which is checkpointed
243662306a36Sopenharmony_ci		 * or newly invalidated.
243762306a36Sopenharmony_ci		 */
243862306a36Sopenharmony_ci		if (!is_sbi_flag_set(sbi, SBI_CP_DISABLED)) {
243962306a36Sopenharmony_ci			if (!f2fs_test_and_set_bit(offset, se->ckpt_valid_map))
244062306a36Sopenharmony_ci				se->ckpt_valid_blocks++;
244162306a36Sopenharmony_ci		}
244262306a36Sopenharmony_ci	} else {
244362306a36Sopenharmony_ci		exist = f2fs_test_and_clear_bit(offset, se->cur_valid_map);
244462306a36Sopenharmony_ci#ifdef CONFIG_F2FS_CHECK_FS
244562306a36Sopenharmony_ci		mir_exist = f2fs_test_and_clear_bit(offset,
244662306a36Sopenharmony_ci						se->cur_valid_map_mir);
244762306a36Sopenharmony_ci		if (unlikely(exist != mir_exist)) {
244862306a36Sopenharmony_ci			f2fs_err(sbi, "Inconsistent error when clearing bitmap, blk:%u, old bit:%d",
244962306a36Sopenharmony_ci				 blkaddr, exist);
245062306a36Sopenharmony_ci			f2fs_bug_on(sbi, 1);
245162306a36Sopenharmony_ci		}
245262306a36Sopenharmony_ci#endif
245362306a36Sopenharmony_ci		if (unlikely(!exist)) {
245462306a36Sopenharmony_ci			f2fs_err(sbi, "Bitmap was wrongly cleared, blk:%u",
245562306a36Sopenharmony_ci				 blkaddr);
245662306a36Sopenharmony_ci			f2fs_bug_on(sbi, 1);
245762306a36Sopenharmony_ci			se->valid_blocks++;
245862306a36Sopenharmony_ci			del = 0;
245962306a36Sopenharmony_ci		} else if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
246062306a36Sopenharmony_ci			/*
246162306a36Sopenharmony_ci			 * If checkpoints are off, we must not reuse data that
246262306a36Sopenharmony_ci			 * was used in the previous checkpoint. If it was used
246362306a36Sopenharmony_ci			 * before, we must track that to know how much space we
246462306a36Sopenharmony_ci			 * really have.
246562306a36Sopenharmony_ci			 */
246662306a36Sopenharmony_ci			if (f2fs_test_bit(offset, se->ckpt_valid_map)) {
246762306a36Sopenharmony_ci				spin_lock(&sbi->stat_lock);
246862306a36Sopenharmony_ci				sbi->unusable_block_count++;
246962306a36Sopenharmony_ci				spin_unlock(&sbi->stat_lock);
247062306a36Sopenharmony_ci			}
247162306a36Sopenharmony_ci		}
247262306a36Sopenharmony_ci
247362306a36Sopenharmony_ci		if (f2fs_block_unit_discard(sbi) &&
247462306a36Sopenharmony_ci			f2fs_test_and_clear_bit(offset, se->discard_map))
247562306a36Sopenharmony_ci			sbi->discard_blks++;
247662306a36Sopenharmony_ci	}
247762306a36Sopenharmony_ci	if (!f2fs_test_bit(offset, se->ckpt_valid_map))
247862306a36Sopenharmony_ci		se->ckpt_valid_blocks += del;
247962306a36Sopenharmony_ci
248062306a36Sopenharmony_ci	__mark_sit_entry_dirty(sbi, segno);
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci	/* update total number of valid blocks to be written in ckpt area */
248362306a36Sopenharmony_ci	SIT_I(sbi)->written_valid_blocks += del;
248462306a36Sopenharmony_ci
248562306a36Sopenharmony_ci	if (__is_large_section(sbi))
248662306a36Sopenharmony_ci		get_sec_entry(sbi, segno)->valid_blocks += del;
248762306a36Sopenharmony_ci}
248862306a36Sopenharmony_ci
248962306a36Sopenharmony_civoid f2fs_invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr)
249062306a36Sopenharmony_ci{
249162306a36Sopenharmony_ci	unsigned int segno = GET_SEGNO(sbi, addr);
249262306a36Sopenharmony_ci	struct sit_info *sit_i = SIT_I(sbi);
249362306a36Sopenharmony_ci
249462306a36Sopenharmony_ci	f2fs_bug_on(sbi, addr == NULL_ADDR);
249562306a36Sopenharmony_ci	if (addr == NEW_ADDR || addr == COMPRESS_ADDR)
249662306a36Sopenharmony_ci		return;
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	f2fs_invalidate_internal_cache(sbi, addr);
249962306a36Sopenharmony_ci
250062306a36Sopenharmony_ci	/* add it into sit main buffer */
250162306a36Sopenharmony_ci	down_write(&sit_i->sentry_lock);
250262306a36Sopenharmony_ci
250362306a36Sopenharmony_ci	update_segment_mtime(sbi, addr, 0);
250462306a36Sopenharmony_ci	update_sit_entry(sbi, addr, -1);
250562306a36Sopenharmony_ci
250662306a36Sopenharmony_ci	/* add it into dirty seglist */
250762306a36Sopenharmony_ci	locate_dirty_segment(sbi, segno);
250862306a36Sopenharmony_ci
250962306a36Sopenharmony_ci	up_write(&sit_i->sentry_lock);
251062306a36Sopenharmony_ci}
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_cibool f2fs_is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr)
251362306a36Sopenharmony_ci{
251462306a36Sopenharmony_ci	struct sit_info *sit_i = SIT_I(sbi);
251562306a36Sopenharmony_ci	unsigned int segno, offset;
251662306a36Sopenharmony_ci	struct seg_entry *se;
251762306a36Sopenharmony_ci	bool is_cp = false;
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_ci	if (!__is_valid_data_blkaddr(blkaddr))
252062306a36Sopenharmony_ci		return true;
252162306a36Sopenharmony_ci
252262306a36Sopenharmony_ci	down_read(&sit_i->sentry_lock);
252362306a36Sopenharmony_ci
252462306a36Sopenharmony_ci	segno = GET_SEGNO(sbi, blkaddr);
252562306a36Sopenharmony_ci	se = get_seg_entry(sbi, segno);
252662306a36Sopenharmony_ci	offset = GET_BLKOFF_FROM_SEG0(sbi, blkaddr);
252762306a36Sopenharmony_ci
252862306a36Sopenharmony_ci	if (f2fs_test_bit(offset, se->ckpt_valid_map))
252962306a36Sopenharmony_ci		is_cp = true;
253062306a36Sopenharmony_ci
253162306a36Sopenharmony_ci	up_read(&sit_i->sentry_lock);
253262306a36Sopenharmony_ci
253362306a36Sopenharmony_ci	return is_cp;
253462306a36Sopenharmony_ci}
253562306a36Sopenharmony_ci
253662306a36Sopenharmony_cistatic unsigned short f2fs_curseg_valid_blocks(struct f2fs_sb_info *sbi, int type)
253762306a36Sopenharmony_ci{
253862306a36Sopenharmony_ci	struct curseg_info *curseg = CURSEG_I(sbi, type);
253962306a36Sopenharmony_ci
254062306a36Sopenharmony_ci	if (sbi->ckpt->alloc_type[type] == SSR)
254162306a36Sopenharmony_ci		return sbi->blocks_per_seg;
254262306a36Sopenharmony_ci	return curseg->next_blkoff;
254362306a36Sopenharmony_ci}
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_ci/*
254662306a36Sopenharmony_ci * Calculate the number of current summary pages for writing
254762306a36Sopenharmony_ci */
254862306a36Sopenharmony_ciint f2fs_npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra)
254962306a36Sopenharmony_ci{
255062306a36Sopenharmony_ci	int valid_sum_count = 0;
255162306a36Sopenharmony_ci	int i, sum_in_page;
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ci	for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
255462306a36Sopenharmony_ci		if (sbi->ckpt->alloc_type[i] != SSR && for_ra)
255562306a36Sopenharmony_ci			valid_sum_count +=
255662306a36Sopenharmony_ci				le16_to_cpu(F2FS_CKPT(sbi)->cur_data_blkoff[i]);
255762306a36Sopenharmony_ci		else
255862306a36Sopenharmony_ci			valid_sum_count += f2fs_curseg_valid_blocks(sbi, i);
255962306a36Sopenharmony_ci	}
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci	sum_in_page = (PAGE_SIZE - 2 * SUM_JOURNAL_SIZE -
256262306a36Sopenharmony_ci			SUM_FOOTER_SIZE) / SUMMARY_SIZE;
256362306a36Sopenharmony_ci	if (valid_sum_count <= sum_in_page)
256462306a36Sopenharmony_ci		return 1;
256562306a36Sopenharmony_ci	else if ((valid_sum_count - sum_in_page) <=
256662306a36Sopenharmony_ci		(PAGE_SIZE - SUM_FOOTER_SIZE) / SUMMARY_SIZE)
256762306a36Sopenharmony_ci		return 2;
256862306a36Sopenharmony_ci	return 3;
256962306a36Sopenharmony_ci}
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci/*
257262306a36Sopenharmony_ci * Caller should put this summary page
257362306a36Sopenharmony_ci */
257462306a36Sopenharmony_cistruct page *f2fs_get_sum_page(struct f2fs_sb_info *sbi, unsigned int segno)
257562306a36Sopenharmony_ci{
257662306a36Sopenharmony_ci	if (unlikely(f2fs_cp_error(sbi)))
257762306a36Sopenharmony_ci		return ERR_PTR(-EIO);
257862306a36Sopenharmony_ci	return f2fs_get_meta_page_retry(sbi, GET_SUM_BLOCK(sbi, segno));
257962306a36Sopenharmony_ci}
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_civoid f2fs_update_meta_page(struct f2fs_sb_info *sbi,
258262306a36Sopenharmony_ci					void *src, block_t blk_addr)
258362306a36Sopenharmony_ci{
258462306a36Sopenharmony_ci	struct page *page = f2fs_grab_meta_page(sbi, blk_addr);
258562306a36Sopenharmony_ci
258662306a36Sopenharmony_ci	memcpy(page_address(page), src, PAGE_SIZE);
258762306a36Sopenharmony_ci	set_page_dirty(page);
258862306a36Sopenharmony_ci	f2fs_put_page(page, 1);
258962306a36Sopenharmony_ci}
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_cistatic void write_sum_page(struct f2fs_sb_info *sbi,
259262306a36Sopenharmony_ci			struct f2fs_summary_block *sum_blk, block_t blk_addr)
259362306a36Sopenharmony_ci{
259462306a36Sopenharmony_ci	f2fs_update_meta_page(sbi, (void *)sum_blk, blk_addr);
259562306a36Sopenharmony_ci}
259662306a36Sopenharmony_ci
259762306a36Sopenharmony_cistatic void write_current_sum_page(struct f2fs_sb_info *sbi,
259862306a36Sopenharmony_ci						int type, block_t blk_addr)
259962306a36Sopenharmony_ci{
260062306a36Sopenharmony_ci	struct curseg_info *curseg = CURSEG_I(sbi, type);
260162306a36Sopenharmony_ci	struct page *page = f2fs_grab_meta_page(sbi, blk_addr);
260262306a36Sopenharmony_ci	struct f2fs_summary_block *src = curseg->sum_blk;
260362306a36Sopenharmony_ci	struct f2fs_summary_block *dst;
260462306a36Sopenharmony_ci
260562306a36Sopenharmony_ci	dst = (struct f2fs_summary_block *)page_address(page);
260662306a36Sopenharmony_ci	memset(dst, 0, PAGE_SIZE);
260762306a36Sopenharmony_ci
260862306a36Sopenharmony_ci	mutex_lock(&curseg->curseg_mutex);
260962306a36Sopenharmony_ci
261062306a36Sopenharmony_ci	down_read(&curseg->journal_rwsem);
261162306a36Sopenharmony_ci	memcpy(&dst->journal, curseg->journal, SUM_JOURNAL_SIZE);
261262306a36Sopenharmony_ci	up_read(&curseg->journal_rwsem);
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ci	memcpy(dst->entries, src->entries, SUM_ENTRY_SIZE);
261562306a36Sopenharmony_ci	memcpy(&dst->footer, &src->footer, SUM_FOOTER_SIZE);
261662306a36Sopenharmony_ci
261762306a36Sopenharmony_ci	mutex_unlock(&curseg->curseg_mutex);
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ci	set_page_dirty(page);
262062306a36Sopenharmony_ci	f2fs_put_page(page, 1);
262162306a36Sopenharmony_ci}
262262306a36Sopenharmony_ci
262362306a36Sopenharmony_cistatic int is_next_segment_free(struct f2fs_sb_info *sbi,
262462306a36Sopenharmony_ci				struct curseg_info *curseg, int type)
262562306a36Sopenharmony_ci{
262662306a36Sopenharmony_ci	unsigned int segno = curseg->segno + 1;
262762306a36Sopenharmony_ci	struct free_segmap_info *free_i = FREE_I(sbi);
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci	if (segno < MAIN_SEGS(sbi) && segno % sbi->segs_per_sec)
263062306a36Sopenharmony_ci		return !test_bit(segno, free_i->free_segmap);
263162306a36Sopenharmony_ci	return 0;
263262306a36Sopenharmony_ci}
263362306a36Sopenharmony_ci
263462306a36Sopenharmony_ci/*
263562306a36Sopenharmony_ci * Find a new segment from the free segments bitmap to right order
263662306a36Sopenharmony_ci * This function should be returned with success, otherwise BUG
263762306a36Sopenharmony_ci */
263862306a36Sopenharmony_cistatic void get_new_segment(struct f2fs_sb_info *sbi,
263962306a36Sopenharmony_ci			unsigned int *newseg, bool new_sec, int dir)
264062306a36Sopenharmony_ci{
264162306a36Sopenharmony_ci	struct free_segmap_info *free_i = FREE_I(sbi);
264262306a36Sopenharmony_ci	unsigned int segno, secno, zoneno;
264362306a36Sopenharmony_ci	unsigned int total_zones = MAIN_SECS(sbi) / sbi->secs_per_zone;
264462306a36Sopenharmony_ci	unsigned int hint = GET_SEC_FROM_SEG(sbi, *newseg);
264562306a36Sopenharmony_ci	unsigned int old_zoneno = GET_ZONE_FROM_SEG(sbi, *newseg);
264662306a36Sopenharmony_ci	unsigned int left_start = hint;
264762306a36Sopenharmony_ci	bool init = true;
264862306a36Sopenharmony_ci	int go_left = 0;
264962306a36Sopenharmony_ci	int i;
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_ci	spin_lock(&free_i->segmap_lock);
265262306a36Sopenharmony_ci
265362306a36Sopenharmony_ci	if (!new_sec && ((*newseg + 1) % sbi->segs_per_sec)) {
265462306a36Sopenharmony_ci		segno = find_next_zero_bit(free_i->free_segmap,
265562306a36Sopenharmony_ci			GET_SEG_FROM_SEC(sbi, hint + 1), *newseg + 1);
265662306a36Sopenharmony_ci		if (segno < GET_SEG_FROM_SEC(sbi, hint + 1))
265762306a36Sopenharmony_ci			goto got_it;
265862306a36Sopenharmony_ci	}
265962306a36Sopenharmony_cifind_other_zone:
266062306a36Sopenharmony_ci	secno = find_next_zero_bit(free_i->free_secmap, MAIN_SECS(sbi), hint);
266162306a36Sopenharmony_ci	if (secno >= MAIN_SECS(sbi)) {
266262306a36Sopenharmony_ci		if (dir == ALLOC_RIGHT) {
266362306a36Sopenharmony_ci			secno = find_first_zero_bit(free_i->free_secmap,
266462306a36Sopenharmony_ci							MAIN_SECS(sbi));
266562306a36Sopenharmony_ci			f2fs_bug_on(sbi, secno >= MAIN_SECS(sbi));
266662306a36Sopenharmony_ci		} else {
266762306a36Sopenharmony_ci			go_left = 1;
266862306a36Sopenharmony_ci			left_start = hint - 1;
266962306a36Sopenharmony_ci		}
267062306a36Sopenharmony_ci	}
267162306a36Sopenharmony_ci	if (go_left == 0)
267262306a36Sopenharmony_ci		goto skip_left;
267362306a36Sopenharmony_ci
267462306a36Sopenharmony_ci	while (test_bit(left_start, free_i->free_secmap)) {
267562306a36Sopenharmony_ci		if (left_start > 0) {
267662306a36Sopenharmony_ci			left_start--;
267762306a36Sopenharmony_ci			continue;
267862306a36Sopenharmony_ci		}
267962306a36Sopenharmony_ci		left_start = find_first_zero_bit(free_i->free_secmap,
268062306a36Sopenharmony_ci							MAIN_SECS(sbi));
268162306a36Sopenharmony_ci		f2fs_bug_on(sbi, left_start >= MAIN_SECS(sbi));
268262306a36Sopenharmony_ci		break;
268362306a36Sopenharmony_ci	}
268462306a36Sopenharmony_ci	secno = left_start;
268562306a36Sopenharmony_ciskip_left:
268662306a36Sopenharmony_ci	segno = GET_SEG_FROM_SEC(sbi, secno);
268762306a36Sopenharmony_ci	zoneno = GET_ZONE_FROM_SEC(sbi, secno);
268862306a36Sopenharmony_ci
268962306a36Sopenharmony_ci	/* give up on finding another zone */
269062306a36Sopenharmony_ci	if (!init)
269162306a36Sopenharmony_ci		goto got_it;
269262306a36Sopenharmony_ci	if (sbi->secs_per_zone == 1)
269362306a36Sopenharmony_ci		goto got_it;
269462306a36Sopenharmony_ci	if (zoneno == old_zoneno)
269562306a36Sopenharmony_ci		goto got_it;
269662306a36Sopenharmony_ci	if (dir == ALLOC_LEFT) {
269762306a36Sopenharmony_ci		if (!go_left && zoneno + 1 >= total_zones)
269862306a36Sopenharmony_ci			goto got_it;
269962306a36Sopenharmony_ci		if (go_left && zoneno == 0)
270062306a36Sopenharmony_ci			goto got_it;
270162306a36Sopenharmony_ci	}
270262306a36Sopenharmony_ci	for (i = 0; i < NR_CURSEG_TYPE; i++)
270362306a36Sopenharmony_ci		if (CURSEG_I(sbi, i)->zone == zoneno)
270462306a36Sopenharmony_ci			break;
270562306a36Sopenharmony_ci
270662306a36Sopenharmony_ci	if (i < NR_CURSEG_TYPE) {
270762306a36Sopenharmony_ci		/* zone is in user, try another */
270862306a36Sopenharmony_ci		if (go_left)
270962306a36Sopenharmony_ci			hint = zoneno * sbi->secs_per_zone - 1;
271062306a36Sopenharmony_ci		else if (zoneno + 1 >= total_zones)
271162306a36Sopenharmony_ci			hint = 0;
271262306a36Sopenharmony_ci		else
271362306a36Sopenharmony_ci			hint = (zoneno + 1) * sbi->secs_per_zone;
271462306a36Sopenharmony_ci		init = false;
271562306a36Sopenharmony_ci		goto find_other_zone;
271662306a36Sopenharmony_ci	}
271762306a36Sopenharmony_cigot_it:
271862306a36Sopenharmony_ci	/* set it as dirty segment in free segmap */
271962306a36Sopenharmony_ci	f2fs_bug_on(sbi, test_bit(segno, free_i->free_segmap));
272062306a36Sopenharmony_ci	__set_inuse(sbi, segno);
272162306a36Sopenharmony_ci	*newseg = segno;
272262306a36Sopenharmony_ci	spin_unlock(&free_i->segmap_lock);
272362306a36Sopenharmony_ci}
272462306a36Sopenharmony_ci
272562306a36Sopenharmony_cistatic void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified)
272662306a36Sopenharmony_ci{
272762306a36Sopenharmony_ci	struct curseg_info *curseg = CURSEG_I(sbi, type);
272862306a36Sopenharmony_ci	struct summary_footer *sum_footer;
272962306a36Sopenharmony_ci	unsigned short seg_type = curseg->seg_type;
273062306a36Sopenharmony_ci
273162306a36Sopenharmony_ci	curseg->inited = true;
273262306a36Sopenharmony_ci	curseg->segno = curseg->next_segno;
273362306a36Sopenharmony_ci	curseg->zone = GET_ZONE_FROM_SEG(sbi, curseg->segno);
273462306a36Sopenharmony_ci	curseg->next_blkoff = 0;
273562306a36Sopenharmony_ci	curseg->next_segno = NULL_SEGNO;
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_ci	sum_footer = &(curseg->sum_blk->footer);
273862306a36Sopenharmony_ci	memset(sum_footer, 0, sizeof(struct summary_footer));
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_ci	sanity_check_seg_type(sbi, seg_type);
274162306a36Sopenharmony_ci
274262306a36Sopenharmony_ci	if (IS_DATASEG(seg_type))
274362306a36Sopenharmony_ci		SET_SUM_TYPE(sum_footer, SUM_TYPE_DATA);
274462306a36Sopenharmony_ci	if (IS_NODESEG(seg_type))
274562306a36Sopenharmony_ci		SET_SUM_TYPE(sum_footer, SUM_TYPE_NODE);
274662306a36Sopenharmony_ci	__set_sit_entry_type(sbi, seg_type, curseg->segno, modified);
274762306a36Sopenharmony_ci}
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_cistatic unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type)
275062306a36Sopenharmony_ci{
275162306a36Sopenharmony_ci	struct curseg_info *curseg = CURSEG_I(sbi, type);
275262306a36Sopenharmony_ci	unsigned short seg_type = curseg->seg_type;
275362306a36Sopenharmony_ci
275462306a36Sopenharmony_ci	sanity_check_seg_type(sbi, seg_type);
275562306a36Sopenharmony_ci	if (f2fs_need_rand_seg(sbi))
275662306a36Sopenharmony_ci		return get_random_u32_below(MAIN_SECS(sbi) * sbi->segs_per_sec);
275762306a36Sopenharmony_ci
275862306a36Sopenharmony_ci	/* if segs_per_sec is large than 1, we need to keep original policy. */
275962306a36Sopenharmony_ci	if (__is_large_section(sbi))
276062306a36Sopenharmony_ci		return curseg->segno;
276162306a36Sopenharmony_ci
276262306a36Sopenharmony_ci	/* inmem log may not locate on any segment after mount */
276362306a36Sopenharmony_ci	if (!curseg->inited)
276462306a36Sopenharmony_ci		return 0;
276562306a36Sopenharmony_ci
276662306a36Sopenharmony_ci	if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
276762306a36Sopenharmony_ci		return 0;
276862306a36Sopenharmony_ci
276962306a36Sopenharmony_ci	if (test_opt(sbi, NOHEAP) &&
277062306a36Sopenharmony_ci		(seg_type == CURSEG_HOT_DATA || IS_NODESEG(seg_type)))
277162306a36Sopenharmony_ci		return 0;
277262306a36Sopenharmony_ci
277362306a36Sopenharmony_ci	if (SIT_I(sbi)->last_victim[ALLOC_NEXT])
277462306a36Sopenharmony_ci		return SIT_I(sbi)->last_victim[ALLOC_NEXT];
277562306a36Sopenharmony_ci
277662306a36Sopenharmony_ci	/* find segments from 0 to reuse freed segments */
277762306a36Sopenharmony_ci	if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_REUSE)
277862306a36Sopenharmony_ci		return 0;
277962306a36Sopenharmony_ci
278062306a36Sopenharmony_ci	return curseg->segno;
278162306a36Sopenharmony_ci}
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_ci/*
278462306a36Sopenharmony_ci * Allocate a current working segment.
278562306a36Sopenharmony_ci * This function always allocates a free segment in LFS manner.
278662306a36Sopenharmony_ci */
278762306a36Sopenharmony_cistatic void new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec)
278862306a36Sopenharmony_ci{
278962306a36Sopenharmony_ci	struct curseg_info *curseg = CURSEG_I(sbi, type);
279062306a36Sopenharmony_ci	unsigned short seg_type = curseg->seg_type;
279162306a36Sopenharmony_ci	unsigned int segno = curseg->segno;
279262306a36Sopenharmony_ci	int dir = ALLOC_LEFT;
279362306a36Sopenharmony_ci
279462306a36Sopenharmony_ci	if (curseg->inited)
279562306a36Sopenharmony_ci		write_sum_page(sbi, curseg->sum_blk,
279662306a36Sopenharmony_ci				GET_SUM_BLOCK(sbi, segno));
279762306a36Sopenharmony_ci	if (seg_type == CURSEG_WARM_DATA || seg_type == CURSEG_COLD_DATA)
279862306a36Sopenharmony_ci		dir = ALLOC_RIGHT;
279962306a36Sopenharmony_ci
280062306a36Sopenharmony_ci	if (test_opt(sbi, NOHEAP))
280162306a36Sopenharmony_ci		dir = ALLOC_RIGHT;
280262306a36Sopenharmony_ci
280362306a36Sopenharmony_ci	segno = __get_next_segno(sbi, type);
280462306a36Sopenharmony_ci	get_new_segment(sbi, &segno, new_sec, dir);
280562306a36Sopenharmony_ci	curseg->next_segno = segno;
280662306a36Sopenharmony_ci	reset_curseg(sbi, type, 1);
280762306a36Sopenharmony_ci	curseg->alloc_type = LFS;
280862306a36Sopenharmony_ci	if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK)
280962306a36Sopenharmony_ci		curseg->fragment_remained_chunk =
281062306a36Sopenharmony_ci				get_random_u32_inclusive(1, sbi->max_fragment_chunk);
281162306a36Sopenharmony_ci}
281262306a36Sopenharmony_ci
281362306a36Sopenharmony_cistatic int __next_free_blkoff(struct f2fs_sb_info *sbi,
281462306a36Sopenharmony_ci					int segno, block_t start)
281562306a36Sopenharmony_ci{
281662306a36Sopenharmony_ci	struct seg_entry *se = get_seg_entry(sbi, segno);
281762306a36Sopenharmony_ci	int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long);
281862306a36Sopenharmony_ci	unsigned long *target_map = SIT_I(sbi)->tmp_map;
281962306a36Sopenharmony_ci	unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map;
282062306a36Sopenharmony_ci	unsigned long *cur_map = (unsigned long *)se->cur_valid_map;
282162306a36Sopenharmony_ci	int i;
282262306a36Sopenharmony_ci
282362306a36Sopenharmony_ci	for (i = 0; i < entries; i++)
282462306a36Sopenharmony_ci		target_map[i] = ckpt_map[i] | cur_map[i];
282562306a36Sopenharmony_ci
282662306a36Sopenharmony_ci	return __find_rev_next_zero_bit(target_map, sbi->blocks_per_seg, start);
282762306a36Sopenharmony_ci}
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_cistatic int f2fs_find_next_ssr_block(struct f2fs_sb_info *sbi,
283062306a36Sopenharmony_ci		struct curseg_info *seg)
283162306a36Sopenharmony_ci{
283262306a36Sopenharmony_ci	return __next_free_blkoff(sbi, seg->segno, seg->next_blkoff + 1);
283362306a36Sopenharmony_ci}
283462306a36Sopenharmony_ci
283562306a36Sopenharmony_cibool f2fs_segment_has_free_slot(struct f2fs_sb_info *sbi, int segno)
283662306a36Sopenharmony_ci{
283762306a36Sopenharmony_ci	return __next_free_blkoff(sbi, segno, 0) < sbi->blocks_per_seg;
283862306a36Sopenharmony_ci}
283962306a36Sopenharmony_ci
284062306a36Sopenharmony_ci/*
284162306a36Sopenharmony_ci * This function always allocates a used segment(from dirty seglist) by SSR
284262306a36Sopenharmony_ci * manner, so it should recover the existing segment information of valid blocks
284362306a36Sopenharmony_ci */
284462306a36Sopenharmony_cistatic void change_curseg(struct f2fs_sb_info *sbi, int type)
284562306a36Sopenharmony_ci{
284662306a36Sopenharmony_ci	struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
284762306a36Sopenharmony_ci	struct curseg_info *curseg = CURSEG_I(sbi, type);
284862306a36Sopenharmony_ci	unsigned int new_segno = curseg->next_segno;
284962306a36Sopenharmony_ci	struct f2fs_summary_block *sum_node;
285062306a36Sopenharmony_ci	struct page *sum_page;
285162306a36Sopenharmony_ci
285262306a36Sopenharmony_ci	write_sum_page(sbi, curseg->sum_blk, GET_SUM_BLOCK(sbi, curseg->segno));
285362306a36Sopenharmony_ci
285462306a36Sopenharmony_ci	__set_test_and_inuse(sbi, new_segno);
285562306a36Sopenharmony_ci
285662306a36Sopenharmony_ci	mutex_lock(&dirty_i->seglist_lock);
285762306a36Sopenharmony_ci	__remove_dirty_segment(sbi, new_segno, PRE);
285862306a36Sopenharmony_ci	__remove_dirty_segment(sbi, new_segno, DIRTY);
285962306a36Sopenharmony_ci	mutex_unlock(&dirty_i->seglist_lock);
286062306a36Sopenharmony_ci
286162306a36Sopenharmony_ci	reset_curseg(sbi, type, 1);
286262306a36Sopenharmony_ci	curseg->alloc_type = SSR;
286362306a36Sopenharmony_ci	curseg->next_blkoff = __next_free_blkoff(sbi, curseg->segno, 0);
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci	sum_page = f2fs_get_sum_page(sbi, new_segno);
286662306a36Sopenharmony_ci	if (IS_ERR(sum_page)) {
286762306a36Sopenharmony_ci		/* GC won't be able to use stale summary pages by cp_error */
286862306a36Sopenharmony_ci		memset(curseg->sum_blk, 0, SUM_ENTRY_SIZE);
286962306a36Sopenharmony_ci		return;
287062306a36Sopenharmony_ci	}
287162306a36Sopenharmony_ci	sum_node = (struct f2fs_summary_block *)page_address(sum_page);
287262306a36Sopenharmony_ci	memcpy(curseg->sum_blk, sum_node, SUM_ENTRY_SIZE);
287362306a36Sopenharmony_ci	f2fs_put_page(sum_page, 1);
287462306a36Sopenharmony_ci}
287562306a36Sopenharmony_ci
287662306a36Sopenharmony_cistatic int get_ssr_segment(struct f2fs_sb_info *sbi, int type,
287762306a36Sopenharmony_ci				int alloc_mode, unsigned long long age);
287862306a36Sopenharmony_ci
287962306a36Sopenharmony_cistatic void get_atssr_segment(struct f2fs_sb_info *sbi, int type,
288062306a36Sopenharmony_ci					int target_type, int alloc_mode,
288162306a36Sopenharmony_ci					unsigned long long age)
288262306a36Sopenharmony_ci{
288362306a36Sopenharmony_ci	struct curseg_info *curseg = CURSEG_I(sbi, type);
288462306a36Sopenharmony_ci
288562306a36Sopenharmony_ci	curseg->seg_type = target_type;
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_ci	if (get_ssr_segment(sbi, type, alloc_mode, age)) {
288862306a36Sopenharmony_ci		struct seg_entry *se = get_seg_entry(sbi, curseg->next_segno);
288962306a36Sopenharmony_ci
289062306a36Sopenharmony_ci		curseg->seg_type = se->type;
289162306a36Sopenharmony_ci		change_curseg(sbi, type);
289262306a36Sopenharmony_ci	} else {
289362306a36Sopenharmony_ci		/* allocate cold segment by default */
289462306a36Sopenharmony_ci		curseg->seg_type = CURSEG_COLD_DATA;
289562306a36Sopenharmony_ci		new_curseg(sbi, type, true);
289662306a36Sopenharmony_ci	}
289762306a36Sopenharmony_ci	stat_inc_seg_type(sbi, curseg);
289862306a36Sopenharmony_ci}
289962306a36Sopenharmony_ci
290062306a36Sopenharmony_cistatic void __f2fs_init_atgc_curseg(struct f2fs_sb_info *sbi)
290162306a36Sopenharmony_ci{
290262306a36Sopenharmony_ci	struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_ALL_DATA_ATGC);
290362306a36Sopenharmony_ci
290462306a36Sopenharmony_ci	if (!sbi->am.atgc_enabled)
290562306a36Sopenharmony_ci		return;
290662306a36Sopenharmony_ci
290762306a36Sopenharmony_ci	f2fs_down_read(&SM_I(sbi)->curseg_lock);
290862306a36Sopenharmony_ci
290962306a36Sopenharmony_ci	mutex_lock(&curseg->curseg_mutex);
291062306a36Sopenharmony_ci	down_write(&SIT_I(sbi)->sentry_lock);
291162306a36Sopenharmony_ci
291262306a36Sopenharmony_ci	get_atssr_segment(sbi, CURSEG_ALL_DATA_ATGC, CURSEG_COLD_DATA, SSR, 0);
291362306a36Sopenharmony_ci
291462306a36Sopenharmony_ci	up_write(&SIT_I(sbi)->sentry_lock);
291562306a36Sopenharmony_ci	mutex_unlock(&curseg->curseg_mutex);
291662306a36Sopenharmony_ci
291762306a36Sopenharmony_ci	f2fs_up_read(&SM_I(sbi)->curseg_lock);
291862306a36Sopenharmony_ci
291962306a36Sopenharmony_ci}
292062306a36Sopenharmony_civoid f2fs_init_inmem_curseg(struct f2fs_sb_info *sbi)
292162306a36Sopenharmony_ci{
292262306a36Sopenharmony_ci	__f2fs_init_atgc_curseg(sbi);
292362306a36Sopenharmony_ci}
292462306a36Sopenharmony_ci
292562306a36Sopenharmony_cistatic void __f2fs_save_inmem_curseg(struct f2fs_sb_info *sbi, int type)
292662306a36Sopenharmony_ci{
292762306a36Sopenharmony_ci	struct curseg_info *curseg = CURSEG_I(sbi, type);
292862306a36Sopenharmony_ci
292962306a36Sopenharmony_ci	mutex_lock(&curseg->curseg_mutex);
293062306a36Sopenharmony_ci	if (!curseg->inited)
293162306a36Sopenharmony_ci		goto out;
293262306a36Sopenharmony_ci
293362306a36Sopenharmony_ci	if (get_valid_blocks(sbi, curseg->segno, false)) {
293462306a36Sopenharmony_ci		write_sum_page(sbi, curseg->sum_blk,
293562306a36Sopenharmony_ci				GET_SUM_BLOCK(sbi, curseg->segno));
293662306a36Sopenharmony_ci	} else {
293762306a36Sopenharmony_ci		mutex_lock(&DIRTY_I(sbi)->seglist_lock);
293862306a36Sopenharmony_ci		__set_test_and_free(sbi, curseg->segno, true);
293962306a36Sopenharmony_ci		mutex_unlock(&DIRTY_I(sbi)->seglist_lock);
294062306a36Sopenharmony_ci	}
294162306a36Sopenharmony_ciout:
294262306a36Sopenharmony_ci	mutex_unlock(&curseg->curseg_mutex);
294362306a36Sopenharmony_ci}
294462306a36Sopenharmony_ci
294562306a36Sopenharmony_civoid f2fs_save_inmem_curseg(struct f2fs_sb_info *sbi)
294662306a36Sopenharmony_ci{
294762306a36Sopenharmony_ci	__f2fs_save_inmem_curseg(sbi, CURSEG_COLD_DATA_PINNED);
294862306a36Sopenharmony_ci
294962306a36Sopenharmony_ci	if (sbi->am.atgc_enabled)
295062306a36Sopenharmony_ci		__f2fs_save_inmem_curseg(sbi, CURSEG_ALL_DATA_ATGC);
295162306a36Sopenharmony_ci}
295262306a36Sopenharmony_ci
295362306a36Sopenharmony_cistatic void __f2fs_restore_inmem_curseg(struct f2fs_sb_info *sbi, int type)
295462306a36Sopenharmony_ci{
295562306a36Sopenharmony_ci	struct curseg_info *curseg = CURSEG_I(sbi, type);
295662306a36Sopenharmony_ci
295762306a36Sopenharmony_ci	mutex_lock(&curseg->curseg_mutex);
295862306a36Sopenharmony_ci	if (!curseg->inited)
295962306a36Sopenharmony_ci		goto out;
296062306a36Sopenharmony_ci	if (get_valid_blocks(sbi, curseg->segno, false))
296162306a36Sopenharmony_ci		goto out;
296262306a36Sopenharmony_ci
296362306a36Sopenharmony_ci	mutex_lock(&DIRTY_I(sbi)->seglist_lock);
296462306a36Sopenharmony_ci	__set_test_and_inuse(sbi, curseg->segno);
296562306a36Sopenharmony_ci	mutex_unlock(&DIRTY_I(sbi)->seglist_lock);
296662306a36Sopenharmony_ciout:
296762306a36Sopenharmony_ci	mutex_unlock(&curseg->curseg_mutex);
296862306a36Sopenharmony_ci}
296962306a36Sopenharmony_ci
297062306a36Sopenharmony_civoid f2fs_restore_inmem_curseg(struct f2fs_sb_info *sbi)
297162306a36Sopenharmony_ci{
297262306a36Sopenharmony_ci	__f2fs_restore_inmem_curseg(sbi, CURSEG_COLD_DATA_PINNED);
297362306a36Sopenharmony_ci
297462306a36Sopenharmony_ci	if (sbi->am.atgc_enabled)
297562306a36Sopenharmony_ci		__f2fs_restore_inmem_curseg(sbi, CURSEG_ALL_DATA_ATGC);
297662306a36Sopenharmony_ci}
297762306a36Sopenharmony_ci
297862306a36Sopenharmony_cistatic int get_ssr_segment(struct f2fs_sb_info *sbi, int type,
297962306a36Sopenharmony_ci				int alloc_mode, unsigned long long age)
298062306a36Sopenharmony_ci{
298162306a36Sopenharmony_ci	struct curseg_info *curseg = CURSEG_I(sbi, type);
298262306a36Sopenharmony_ci	unsigned segno = NULL_SEGNO;
298362306a36Sopenharmony_ci	unsigned short seg_type = curseg->seg_type;
298462306a36Sopenharmony_ci	int i, cnt;
298562306a36Sopenharmony_ci	bool reversed = false;
298662306a36Sopenharmony_ci
298762306a36Sopenharmony_ci	sanity_check_seg_type(sbi, seg_type);
298862306a36Sopenharmony_ci
298962306a36Sopenharmony_ci	/* f2fs_need_SSR() already forces to do this */
299062306a36Sopenharmony_ci	if (!f2fs_get_victim(sbi, &segno, BG_GC, seg_type, alloc_mode, age)) {
299162306a36Sopenharmony_ci		curseg->next_segno = segno;
299262306a36Sopenharmony_ci		return 1;
299362306a36Sopenharmony_ci	}
299462306a36Sopenharmony_ci
299562306a36Sopenharmony_ci	/* For node segments, let's do SSR more intensively */
299662306a36Sopenharmony_ci	if (IS_NODESEG(seg_type)) {
299762306a36Sopenharmony_ci		if (seg_type >= CURSEG_WARM_NODE) {
299862306a36Sopenharmony_ci			reversed = true;
299962306a36Sopenharmony_ci			i = CURSEG_COLD_NODE;
300062306a36Sopenharmony_ci		} else {
300162306a36Sopenharmony_ci			i = CURSEG_HOT_NODE;
300262306a36Sopenharmony_ci		}
300362306a36Sopenharmony_ci		cnt = NR_CURSEG_NODE_TYPE;
300462306a36Sopenharmony_ci	} else {
300562306a36Sopenharmony_ci		if (seg_type >= CURSEG_WARM_DATA) {
300662306a36Sopenharmony_ci			reversed = true;
300762306a36Sopenharmony_ci			i = CURSEG_COLD_DATA;
300862306a36Sopenharmony_ci		} else {
300962306a36Sopenharmony_ci			i = CURSEG_HOT_DATA;
301062306a36Sopenharmony_ci		}
301162306a36Sopenharmony_ci		cnt = NR_CURSEG_DATA_TYPE;
301262306a36Sopenharmony_ci	}
301362306a36Sopenharmony_ci
301462306a36Sopenharmony_ci	for (; cnt-- > 0; reversed ? i-- : i++) {
301562306a36Sopenharmony_ci		if (i == seg_type)
301662306a36Sopenharmony_ci			continue;
301762306a36Sopenharmony_ci		if (!f2fs_get_victim(sbi, &segno, BG_GC, i, alloc_mode, age)) {
301862306a36Sopenharmony_ci			curseg->next_segno = segno;
301962306a36Sopenharmony_ci			return 1;
302062306a36Sopenharmony_ci		}
302162306a36Sopenharmony_ci	}
302262306a36Sopenharmony_ci
302362306a36Sopenharmony_ci	/* find valid_blocks=0 in dirty list */
302462306a36Sopenharmony_ci	if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
302562306a36Sopenharmony_ci		segno = get_free_segment(sbi);
302662306a36Sopenharmony_ci		if (segno != NULL_SEGNO) {
302762306a36Sopenharmony_ci			curseg->next_segno = segno;
302862306a36Sopenharmony_ci			return 1;
302962306a36Sopenharmony_ci		}
303062306a36Sopenharmony_ci	}
303162306a36Sopenharmony_ci	return 0;
303262306a36Sopenharmony_ci}
303362306a36Sopenharmony_ci
303462306a36Sopenharmony_cistatic bool need_new_seg(struct f2fs_sb_info *sbi, int type)
303562306a36Sopenharmony_ci{
303662306a36Sopenharmony_ci	struct curseg_info *curseg = CURSEG_I(sbi, type);
303762306a36Sopenharmony_ci
303862306a36Sopenharmony_ci	if (!is_set_ckpt_flags(sbi, CP_CRC_RECOVERY_FLAG) &&
303962306a36Sopenharmony_ci	    curseg->seg_type == CURSEG_WARM_NODE)
304062306a36Sopenharmony_ci		return true;
304162306a36Sopenharmony_ci	if (curseg->alloc_type == LFS &&
304262306a36Sopenharmony_ci	    is_next_segment_free(sbi, curseg, type) &&
304362306a36Sopenharmony_ci	    likely(!is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
304462306a36Sopenharmony_ci		return true;
304562306a36Sopenharmony_ci	if (!f2fs_need_SSR(sbi) || !get_ssr_segment(sbi, type, SSR, 0))
304662306a36Sopenharmony_ci		return true;
304762306a36Sopenharmony_ci	return false;
304862306a36Sopenharmony_ci}
304962306a36Sopenharmony_ci
305062306a36Sopenharmony_civoid f2fs_allocate_segment_for_resize(struct f2fs_sb_info *sbi, int type,
305162306a36Sopenharmony_ci					unsigned int start, unsigned int end)
305262306a36Sopenharmony_ci{
305362306a36Sopenharmony_ci	struct curseg_info *curseg = CURSEG_I(sbi, type);
305462306a36Sopenharmony_ci	unsigned int segno;
305562306a36Sopenharmony_ci
305662306a36Sopenharmony_ci	f2fs_down_read(&SM_I(sbi)->curseg_lock);
305762306a36Sopenharmony_ci	mutex_lock(&curseg->curseg_mutex);
305862306a36Sopenharmony_ci	down_write(&SIT_I(sbi)->sentry_lock);
305962306a36Sopenharmony_ci
306062306a36Sopenharmony_ci	segno = CURSEG_I(sbi, type)->segno;
306162306a36Sopenharmony_ci	if (segno < start || segno > end)
306262306a36Sopenharmony_ci		goto unlock;
306362306a36Sopenharmony_ci
306462306a36Sopenharmony_ci	if (f2fs_need_SSR(sbi) && get_ssr_segment(sbi, type, SSR, 0))
306562306a36Sopenharmony_ci		change_curseg(sbi, type);
306662306a36Sopenharmony_ci	else
306762306a36Sopenharmony_ci		new_curseg(sbi, type, true);
306862306a36Sopenharmony_ci
306962306a36Sopenharmony_ci	stat_inc_seg_type(sbi, curseg);
307062306a36Sopenharmony_ci
307162306a36Sopenharmony_ci	locate_dirty_segment(sbi, segno);
307262306a36Sopenharmony_ciunlock:
307362306a36Sopenharmony_ci	up_write(&SIT_I(sbi)->sentry_lock);
307462306a36Sopenharmony_ci
307562306a36Sopenharmony_ci	if (segno != curseg->segno)
307662306a36Sopenharmony_ci		f2fs_notice(sbi, "For resize: curseg of type %d: %u ==> %u",
307762306a36Sopenharmony_ci			    type, segno, curseg->segno);
307862306a36Sopenharmony_ci
307962306a36Sopenharmony_ci	mutex_unlock(&curseg->curseg_mutex);
308062306a36Sopenharmony_ci	f2fs_up_read(&SM_I(sbi)->curseg_lock);
308162306a36Sopenharmony_ci}
308262306a36Sopenharmony_ci
308362306a36Sopenharmony_cistatic void __allocate_new_segment(struct f2fs_sb_info *sbi, int type,
308462306a36Sopenharmony_ci						bool new_sec, bool force)
308562306a36Sopenharmony_ci{
308662306a36Sopenharmony_ci	struct curseg_info *curseg = CURSEG_I(sbi, type);
308762306a36Sopenharmony_ci	unsigned int old_segno;
308862306a36Sopenharmony_ci
308962306a36Sopenharmony_ci	if (!force && curseg->inited &&
309062306a36Sopenharmony_ci	    !curseg->next_blkoff &&
309162306a36Sopenharmony_ci	    !get_valid_blocks(sbi, curseg->segno, new_sec) &&
309262306a36Sopenharmony_ci	    !get_ckpt_valid_blocks(sbi, curseg->segno, new_sec))
309362306a36Sopenharmony_ci		return;
309462306a36Sopenharmony_ci
309562306a36Sopenharmony_ci	old_segno = curseg->segno;
309662306a36Sopenharmony_ci	new_curseg(sbi, type, true);
309762306a36Sopenharmony_ci	stat_inc_seg_type(sbi, curseg);
309862306a36Sopenharmony_ci	locate_dirty_segment(sbi, old_segno);
309962306a36Sopenharmony_ci}
310062306a36Sopenharmony_ci
310162306a36Sopenharmony_civoid f2fs_allocate_new_section(struct f2fs_sb_info *sbi, int type, bool force)
310262306a36Sopenharmony_ci{
310362306a36Sopenharmony_ci	f2fs_down_read(&SM_I(sbi)->curseg_lock);
310462306a36Sopenharmony_ci	down_write(&SIT_I(sbi)->sentry_lock);
310562306a36Sopenharmony_ci	__allocate_new_segment(sbi, type, true, force);
310662306a36Sopenharmony_ci	up_write(&SIT_I(sbi)->sentry_lock);
310762306a36Sopenharmony_ci	f2fs_up_read(&SM_I(sbi)->curseg_lock);
310862306a36Sopenharmony_ci}
310962306a36Sopenharmony_ci
311062306a36Sopenharmony_civoid f2fs_allocate_new_segments(struct f2fs_sb_info *sbi)
311162306a36Sopenharmony_ci{
311262306a36Sopenharmony_ci	int i;
311362306a36Sopenharmony_ci
311462306a36Sopenharmony_ci	f2fs_down_read(&SM_I(sbi)->curseg_lock);
311562306a36Sopenharmony_ci	down_write(&SIT_I(sbi)->sentry_lock);
311662306a36Sopenharmony_ci	for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++)
311762306a36Sopenharmony_ci		__allocate_new_segment(sbi, i, false, false);
311862306a36Sopenharmony_ci	up_write(&SIT_I(sbi)->sentry_lock);
311962306a36Sopenharmony_ci	f2fs_up_read(&SM_I(sbi)->curseg_lock);
312062306a36Sopenharmony_ci}
312162306a36Sopenharmony_ci
312262306a36Sopenharmony_cibool f2fs_exist_trim_candidates(struct f2fs_sb_info *sbi,
312362306a36Sopenharmony_ci						struct cp_control *cpc)
312462306a36Sopenharmony_ci{
312562306a36Sopenharmony_ci	__u64 trim_start = cpc->trim_start;
312662306a36Sopenharmony_ci	bool has_candidate = false;
312762306a36Sopenharmony_ci
312862306a36Sopenharmony_ci	down_write(&SIT_I(sbi)->sentry_lock);
312962306a36Sopenharmony_ci	for (; cpc->trim_start <= cpc->trim_end; cpc->trim_start++) {
313062306a36Sopenharmony_ci		if (add_discard_addrs(sbi, cpc, true)) {
313162306a36Sopenharmony_ci			has_candidate = true;
313262306a36Sopenharmony_ci			break;
313362306a36Sopenharmony_ci		}
313462306a36Sopenharmony_ci	}
313562306a36Sopenharmony_ci	up_write(&SIT_I(sbi)->sentry_lock);
313662306a36Sopenharmony_ci
313762306a36Sopenharmony_ci	cpc->trim_start = trim_start;
313862306a36Sopenharmony_ci	return has_candidate;
313962306a36Sopenharmony_ci}
314062306a36Sopenharmony_ci
314162306a36Sopenharmony_cistatic unsigned int __issue_discard_cmd_range(struct f2fs_sb_info *sbi,
314262306a36Sopenharmony_ci					struct discard_policy *dpolicy,
314362306a36Sopenharmony_ci					unsigned int start, unsigned int end)
314462306a36Sopenharmony_ci{
314562306a36Sopenharmony_ci	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
314662306a36Sopenharmony_ci	struct discard_cmd *prev_dc = NULL, *next_dc = NULL;
314762306a36Sopenharmony_ci	struct rb_node **insert_p = NULL, *insert_parent = NULL;
314862306a36Sopenharmony_ci	struct discard_cmd *dc;
314962306a36Sopenharmony_ci	struct blk_plug plug;
315062306a36Sopenharmony_ci	int issued;
315162306a36Sopenharmony_ci	unsigned int trimmed = 0;
315262306a36Sopenharmony_ci
315362306a36Sopenharmony_cinext:
315462306a36Sopenharmony_ci	issued = 0;
315562306a36Sopenharmony_ci
315662306a36Sopenharmony_ci	mutex_lock(&dcc->cmd_lock);
315762306a36Sopenharmony_ci	if (unlikely(dcc->rbtree_check))
315862306a36Sopenharmony_ci		f2fs_bug_on(sbi, !f2fs_check_discard_tree(sbi));
315962306a36Sopenharmony_ci
316062306a36Sopenharmony_ci	dc = __lookup_discard_cmd_ret(&dcc->root, start,
316162306a36Sopenharmony_ci				&prev_dc, &next_dc, &insert_p, &insert_parent);
316262306a36Sopenharmony_ci	if (!dc)
316362306a36Sopenharmony_ci		dc = next_dc;
316462306a36Sopenharmony_ci
316562306a36Sopenharmony_ci	blk_start_plug(&plug);
316662306a36Sopenharmony_ci
316762306a36Sopenharmony_ci	while (dc && dc->di.lstart <= end) {
316862306a36Sopenharmony_ci		struct rb_node *node;
316962306a36Sopenharmony_ci		int err = 0;
317062306a36Sopenharmony_ci
317162306a36Sopenharmony_ci		if (dc->di.len < dpolicy->granularity)
317262306a36Sopenharmony_ci			goto skip;
317362306a36Sopenharmony_ci
317462306a36Sopenharmony_ci		if (dc->state != D_PREP) {
317562306a36Sopenharmony_ci			list_move_tail(&dc->list, &dcc->fstrim_list);
317662306a36Sopenharmony_ci			goto skip;
317762306a36Sopenharmony_ci		}
317862306a36Sopenharmony_ci
317962306a36Sopenharmony_ci		err = __submit_discard_cmd(sbi, dpolicy, dc, &issued);
318062306a36Sopenharmony_ci
318162306a36Sopenharmony_ci		if (issued >= dpolicy->max_requests) {
318262306a36Sopenharmony_ci			start = dc->di.lstart + dc->di.len;
318362306a36Sopenharmony_ci
318462306a36Sopenharmony_ci			if (err)
318562306a36Sopenharmony_ci				__remove_discard_cmd(sbi, dc);
318662306a36Sopenharmony_ci
318762306a36Sopenharmony_ci			blk_finish_plug(&plug);
318862306a36Sopenharmony_ci			mutex_unlock(&dcc->cmd_lock);
318962306a36Sopenharmony_ci			trimmed += __wait_all_discard_cmd(sbi, NULL);
319062306a36Sopenharmony_ci			f2fs_io_schedule_timeout(DEFAULT_IO_TIMEOUT);
319162306a36Sopenharmony_ci			goto next;
319262306a36Sopenharmony_ci		}
319362306a36Sopenharmony_ciskip:
319462306a36Sopenharmony_ci		node = rb_next(&dc->rb_node);
319562306a36Sopenharmony_ci		if (err)
319662306a36Sopenharmony_ci			__remove_discard_cmd(sbi, dc);
319762306a36Sopenharmony_ci		dc = rb_entry_safe(node, struct discard_cmd, rb_node);
319862306a36Sopenharmony_ci
319962306a36Sopenharmony_ci		if (fatal_signal_pending(current))
320062306a36Sopenharmony_ci			break;
320162306a36Sopenharmony_ci	}
320262306a36Sopenharmony_ci
320362306a36Sopenharmony_ci	blk_finish_plug(&plug);
320462306a36Sopenharmony_ci	mutex_unlock(&dcc->cmd_lock);
320562306a36Sopenharmony_ci
320662306a36Sopenharmony_ci	return trimmed;
320762306a36Sopenharmony_ci}
320862306a36Sopenharmony_ci
320962306a36Sopenharmony_ciint f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
321062306a36Sopenharmony_ci{
321162306a36Sopenharmony_ci	__u64 start = F2FS_BYTES_TO_BLK(range->start);
321262306a36Sopenharmony_ci	__u64 end = start + F2FS_BYTES_TO_BLK(range->len) - 1;
321362306a36Sopenharmony_ci	unsigned int start_segno, end_segno;
321462306a36Sopenharmony_ci	block_t start_block, end_block;
321562306a36Sopenharmony_ci	struct cp_control cpc;
321662306a36Sopenharmony_ci	struct discard_policy dpolicy;
321762306a36Sopenharmony_ci	unsigned long long trimmed = 0;
321862306a36Sopenharmony_ci	int err = 0;
321962306a36Sopenharmony_ci	bool need_align = f2fs_lfs_mode(sbi) && __is_large_section(sbi);
322062306a36Sopenharmony_ci
322162306a36Sopenharmony_ci	if (start >= MAX_BLKADDR(sbi) || range->len < sbi->blocksize)
322262306a36Sopenharmony_ci		return -EINVAL;
322362306a36Sopenharmony_ci
322462306a36Sopenharmony_ci	if (end < MAIN_BLKADDR(sbi))
322562306a36Sopenharmony_ci		goto out;
322662306a36Sopenharmony_ci
322762306a36Sopenharmony_ci	if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) {
322862306a36Sopenharmony_ci		f2fs_warn(sbi, "Found FS corruption, run fsck to fix.");
322962306a36Sopenharmony_ci		return -EFSCORRUPTED;
323062306a36Sopenharmony_ci	}
323162306a36Sopenharmony_ci
323262306a36Sopenharmony_ci	/* start/end segment number in main_area */
323362306a36Sopenharmony_ci	start_segno = (start <= MAIN_BLKADDR(sbi)) ? 0 : GET_SEGNO(sbi, start);
323462306a36Sopenharmony_ci	end_segno = (end >= MAX_BLKADDR(sbi)) ? MAIN_SEGS(sbi) - 1 :
323562306a36Sopenharmony_ci						GET_SEGNO(sbi, end);
323662306a36Sopenharmony_ci	if (need_align) {
323762306a36Sopenharmony_ci		start_segno = rounddown(start_segno, sbi->segs_per_sec);
323862306a36Sopenharmony_ci		end_segno = roundup(end_segno + 1, sbi->segs_per_sec) - 1;
323962306a36Sopenharmony_ci	}
324062306a36Sopenharmony_ci
324162306a36Sopenharmony_ci	cpc.reason = CP_DISCARD;
324262306a36Sopenharmony_ci	cpc.trim_minlen = max_t(__u64, 1, F2FS_BYTES_TO_BLK(range->minlen));
324362306a36Sopenharmony_ci	cpc.trim_start = start_segno;
324462306a36Sopenharmony_ci	cpc.trim_end = end_segno;
324562306a36Sopenharmony_ci
324662306a36Sopenharmony_ci	if (sbi->discard_blks == 0)
324762306a36Sopenharmony_ci		goto out;
324862306a36Sopenharmony_ci
324962306a36Sopenharmony_ci	f2fs_down_write(&sbi->gc_lock);
325062306a36Sopenharmony_ci	stat_inc_cp_call_count(sbi, TOTAL_CALL);
325162306a36Sopenharmony_ci	err = f2fs_write_checkpoint(sbi, &cpc);
325262306a36Sopenharmony_ci	f2fs_up_write(&sbi->gc_lock);
325362306a36Sopenharmony_ci	if (err)
325462306a36Sopenharmony_ci		goto out;
325562306a36Sopenharmony_ci
325662306a36Sopenharmony_ci	/*
325762306a36Sopenharmony_ci	 * We filed discard candidates, but actually we don't need to wait for
325862306a36Sopenharmony_ci	 * all of them, since they'll be issued in idle time along with runtime
325962306a36Sopenharmony_ci	 * discard option. User configuration looks like using runtime discard
326062306a36Sopenharmony_ci	 * or periodic fstrim instead of it.
326162306a36Sopenharmony_ci	 */
326262306a36Sopenharmony_ci	if (f2fs_realtime_discard_enable(sbi))
326362306a36Sopenharmony_ci		goto out;
326462306a36Sopenharmony_ci
326562306a36Sopenharmony_ci	start_block = START_BLOCK(sbi, start_segno);
326662306a36Sopenharmony_ci	end_block = START_BLOCK(sbi, end_segno + 1);
326762306a36Sopenharmony_ci
326862306a36Sopenharmony_ci	__init_discard_policy(sbi, &dpolicy, DPOLICY_FSTRIM, cpc.trim_minlen);
326962306a36Sopenharmony_ci	trimmed = __issue_discard_cmd_range(sbi, &dpolicy,
327062306a36Sopenharmony_ci					start_block, end_block);
327162306a36Sopenharmony_ci
327262306a36Sopenharmony_ci	trimmed += __wait_discard_cmd_range(sbi, &dpolicy,
327362306a36Sopenharmony_ci					start_block, end_block);
327462306a36Sopenharmony_ciout:
327562306a36Sopenharmony_ci	if (!err)
327662306a36Sopenharmony_ci		range->len = F2FS_BLK_TO_BYTES(trimmed);
327762306a36Sopenharmony_ci	return err;
327862306a36Sopenharmony_ci}
327962306a36Sopenharmony_ci
328062306a36Sopenharmony_ciint f2fs_rw_hint_to_seg_type(enum rw_hint hint)
328162306a36Sopenharmony_ci{
328262306a36Sopenharmony_ci	switch (hint) {
328362306a36Sopenharmony_ci	case WRITE_LIFE_SHORT:
328462306a36Sopenharmony_ci		return CURSEG_HOT_DATA;
328562306a36Sopenharmony_ci	case WRITE_LIFE_EXTREME:
328662306a36Sopenharmony_ci		return CURSEG_COLD_DATA;
328762306a36Sopenharmony_ci	default:
328862306a36Sopenharmony_ci		return CURSEG_WARM_DATA;
328962306a36Sopenharmony_ci	}
329062306a36Sopenharmony_ci}
329162306a36Sopenharmony_ci
329262306a36Sopenharmony_cistatic int __get_segment_type_2(struct f2fs_io_info *fio)
329362306a36Sopenharmony_ci{
329462306a36Sopenharmony_ci	if (fio->type == DATA)
329562306a36Sopenharmony_ci		return CURSEG_HOT_DATA;
329662306a36Sopenharmony_ci	else
329762306a36Sopenharmony_ci		return CURSEG_HOT_NODE;
329862306a36Sopenharmony_ci}
329962306a36Sopenharmony_ci
330062306a36Sopenharmony_cistatic int __get_segment_type_4(struct f2fs_io_info *fio)
330162306a36Sopenharmony_ci{
330262306a36Sopenharmony_ci	if (fio->type == DATA) {
330362306a36Sopenharmony_ci		struct inode *inode = fio->page->mapping->host;
330462306a36Sopenharmony_ci
330562306a36Sopenharmony_ci		if (S_ISDIR(inode->i_mode))
330662306a36Sopenharmony_ci			return CURSEG_HOT_DATA;
330762306a36Sopenharmony_ci		else
330862306a36Sopenharmony_ci			return CURSEG_COLD_DATA;
330962306a36Sopenharmony_ci	} else {
331062306a36Sopenharmony_ci		if (IS_DNODE(fio->page) && is_cold_node(fio->page))
331162306a36Sopenharmony_ci			return CURSEG_WARM_NODE;
331262306a36Sopenharmony_ci		else
331362306a36Sopenharmony_ci			return CURSEG_COLD_NODE;
331462306a36Sopenharmony_ci	}
331562306a36Sopenharmony_ci}
331662306a36Sopenharmony_ci
331762306a36Sopenharmony_cistatic int __get_age_segment_type(struct inode *inode, pgoff_t pgofs)
331862306a36Sopenharmony_ci{
331962306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
332062306a36Sopenharmony_ci	struct extent_info ei = {};
332162306a36Sopenharmony_ci
332262306a36Sopenharmony_ci	if (f2fs_lookup_age_extent_cache(inode, pgofs, &ei)) {
332362306a36Sopenharmony_ci		if (!ei.age)
332462306a36Sopenharmony_ci			return NO_CHECK_TYPE;
332562306a36Sopenharmony_ci		if (ei.age <= sbi->hot_data_age_threshold)
332662306a36Sopenharmony_ci			return CURSEG_HOT_DATA;
332762306a36Sopenharmony_ci		if (ei.age <= sbi->warm_data_age_threshold)
332862306a36Sopenharmony_ci			return CURSEG_WARM_DATA;
332962306a36Sopenharmony_ci		return CURSEG_COLD_DATA;
333062306a36Sopenharmony_ci	}
333162306a36Sopenharmony_ci	return NO_CHECK_TYPE;
333262306a36Sopenharmony_ci}
333362306a36Sopenharmony_ci
333462306a36Sopenharmony_cistatic int __get_segment_type_6(struct f2fs_io_info *fio)
333562306a36Sopenharmony_ci{
333662306a36Sopenharmony_ci	if (fio->type == DATA) {
333762306a36Sopenharmony_ci		struct inode *inode = fio->page->mapping->host;
333862306a36Sopenharmony_ci		int type;
333962306a36Sopenharmony_ci
334062306a36Sopenharmony_ci		if (is_inode_flag_set(inode, FI_ALIGNED_WRITE))
334162306a36Sopenharmony_ci			return CURSEG_COLD_DATA_PINNED;
334262306a36Sopenharmony_ci
334362306a36Sopenharmony_ci		if (page_private_gcing(fio->page)) {
334462306a36Sopenharmony_ci			if (fio->sbi->am.atgc_enabled &&
334562306a36Sopenharmony_ci				(fio->io_type == FS_DATA_IO) &&
334662306a36Sopenharmony_ci				(fio->sbi->gc_mode != GC_URGENT_HIGH))
334762306a36Sopenharmony_ci				return CURSEG_ALL_DATA_ATGC;
334862306a36Sopenharmony_ci			else
334962306a36Sopenharmony_ci				return CURSEG_COLD_DATA;
335062306a36Sopenharmony_ci		}
335162306a36Sopenharmony_ci		if (file_is_cold(inode) || f2fs_need_compress_data(inode))
335262306a36Sopenharmony_ci			return CURSEG_COLD_DATA;
335362306a36Sopenharmony_ci
335462306a36Sopenharmony_ci		type = __get_age_segment_type(inode, fio->page->index);
335562306a36Sopenharmony_ci		if (type != NO_CHECK_TYPE)
335662306a36Sopenharmony_ci			return type;
335762306a36Sopenharmony_ci
335862306a36Sopenharmony_ci		if (file_is_hot(inode) ||
335962306a36Sopenharmony_ci				is_inode_flag_set(inode, FI_HOT_DATA) ||
336062306a36Sopenharmony_ci				f2fs_is_cow_file(inode))
336162306a36Sopenharmony_ci			return CURSEG_HOT_DATA;
336262306a36Sopenharmony_ci		return f2fs_rw_hint_to_seg_type(inode->i_write_hint);
336362306a36Sopenharmony_ci	} else {
336462306a36Sopenharmony_ci		if (IS_DNODE(fio->page))
336562306a36Sopenharmony_ci			return is_cold_node(fio->page) ? CURSEG_WARM_NODE :
336662306a36Sopenharmony_ci						CURSEG_HOT_NODE;
336762306a36Sopenharmony_ci		return CURSEG_COLD_NODE;
336862306a36Sopenharmony_ci	}
336962306a36Sopenharmony_ci}
337062306a36Sopenharmony_ci
337162306a36Sopenharmony_cistatic int __get_segment_type(struct f2fs_io_info *fio)
337262306a36Sopenharmony_ci{
337362306a36Sopenharmony_ci	int type = 0;
337462306a36Sopenharmony_ci
337562306a36Sopenharmony_ci	switch (F2FS_OPTION(fio->sbi).active_logs) {
337662306a36Sopenharmony_ci	case 2:
337762306a36Sopenharmony_ci		type = __get_segment_type_2(fio);
337862306a36Sopenharmony_ci		break;
337962306a36Sopenharmony_ci	case 4:
338062306a36Sopenharmony_ci		type = __get_segment_type_4(fio);
338162306a36Sopenharmony_ci		break;
338262306a36Sopenharmony_ci	case 6:
338362306a36Sopenharmony_ci		type = __get_segment_type_6(fio);
338462306a36Sopenharmony_ci		break;
338562306a36Sopenharmony_ci	default:
338662306a36Sopenharmony_ci		f2fs_bug_on(fio->sbi, true);
338762306a36Sopenharmony_ci	}
338862306a36Sopenharmony_ci
338962306a36Sopenharmony_ci	if (IS_HOT(type))
339062306a36Sopenharmony_ci		fio->temp = HOT;
339162306a36Sopenharmony_ci	else if (IS_WARM(type))
339262306a36Sopenharmony_ci		fio->temp = WARM;
339362306a36Sopenharmony_ci	else
339462306a36Sopenharmony_ci		fio->temp = COLD;
339562306a36Sopenharmony_ci	return type;
339662306a36Sopenharmony_ci}
339762306a36Sopenharmony_ci
339862306a36Sopenharmony_cistatic void f2fs_randomize_chunk(struct f2fs_sb_info *sbi,
339962306a36Sopenharmony_ci		struct curseg_info *seg)
340062306a36Sopenharmony_ci{
340162306a36Sopenharmony_ci	/* To allocate block chunks in different sizes, use random number */
340262306a36Sopenharmony_ci	if (--seg->fragment_remained_chunk > 0)
340362306a36Sopenharmony_ci		return;
340462306a36Sopenharmony_ci
340562306a36Sopenharmony_ci	seg->fragment_remained_chunk =
340662306a36Sopenharmony_ci		get_random_u32_inclusive(1, sbi->max_fragment_chunk);
340762306a36Sopenharmony_ci	seg->next_blkoff +=
340862306a36Sopenharmony_ci		get_random_u32_inclusive(1, sbi->max_fragment_hole);
340962306a36Sopenharmony_ci}
341062306a36Sopenharmony_ci
341162306a36Sopenharmony_civoid f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
341262306a36Sopenharmony_ci		block_t old_blkaddr, block_t *new_blkaddr,
341362306a36Sopenharmony_ci		struct f2fs_summary *sum, int type,
341462306a36Sopenharmony_ci		struct f2fs_io_info *fio)
341562306a36Sopenharmony_ci{
341662306a36Sopenharmony_ci	struct sit_info *sit_i = SIT_I(sbi);
341762306a36Sopenharmony_ci	struct curseg_info *curseg = CURSEG_I(sbi, type);
341862306a36Sopenharmony_ci	unsigned long long old_mtime;
341962306a36Sopenharmony_ci	bool from_gc = (type == CURSEG_ALL_DATA_ATGC);
342062306a36Sopenharmony_ci	struct seg_entry *se = NULL;
342162306a36Sopenharmony_ci	bool segment_full = false;
342262306a36Sopenharmony_ci
342362306a36Sopenharmony_ci	f2fs_down_read(&SM_I(sbi)->curseg_lock);
342462306a36Sopenharmony_ci
342562306a36Sopenharmony_ci	mutex_lock(&curseg->curseg_mutex);
342662306a36Sopenharmony_ci	down_write(&sit_i->sentry_lock);
342762306a36Sopenharmony_ci
342862306a36Sopenharmony_ci	if (from_gc) {
342962306a36Sopenharmony_ci		f2fs_bug_on(sbi, GET_SEGNO(sbi, old_blkaddr) == NULL_SEGNO);
343062306a36Sopenharmony_ci		se = get_seg_entry(sbi, GET_SEGNO(sbi, old_blkaddr));
343162306a36Sopenharmony_ci		sanity_check_seg_type(sbi, se->type);
343262306a36Sopenharmony_ci		f2fs_bug_on(sbi, IS_NODESEG(se->type));
343362306a36Sopenharmony_ci	}
343462306a36Sopenharmony_ci	*new_blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);
343562306a36Sopenharmony_ci
343662306a36Sopenharmony_ci	f2fs_bug_on(sbi, curseg->next_blkoff >= sbi->blocks_per_seg);
343762306a36Sopenharmony_ci
343862306a36Sopenharmony_ci	f2fs_wait_discard_bio(sbi, *new_blkaddr);
343962306a36Sopenharmony_ci
344062306a36Sopenharmony_ci	curseg->sum_blk->entries[curseg->next_blkoff] = *sum;
344162306a36Sopenharmony_ci	if (curseg->alloc_type == SSR) {
344262306a36Sopenharmony_ci		curseg->next_blkoff = f2fs_find_next_ssr_block(sbi, curseg);
344362306a36Sopenharmony_ci	} else {
344462306a36Sopenharmony_ci		curseg->next_blkoff++;
344562306a36Sopenharmony_ci		if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK)
344662306a36Sopenharmony_ci			f2fs_randomize_chunk(sbi, curseg);
344762306a36Sopenharmony_ci	}
344862306a36Sopenharmony_ci	if (curseg->next_blkoff >= f2fs_usable_blks_in_seg(sbi, curseg->segno))
344962306a36Sopenharmony_ci		segment_full = true;
345062306a36Sopenharmony_ci	stat_inc_block_count(sbi, curseg);
345162306a36Sopenharmony_ci
345262306a36Sopenharmony_ci	if (from_gc) {
345362306a36Sopenharmony_ci		old_mtime = get_segment_mtime(sbi, old_blkaddr);
345462306a36Sopenharmony_ci	} else {
345562306a36Sopenharmony_ci		update_segment_mtime(sbi, old_blkaddr, 0);
345662306a36Sopenharmony_ci		old_mtime = 0;
345762306a36Sopenharmony_ci	}
345862306a36Sopenharmony_ci	update_segment_mtime(sbi, *new_blkaddr, old_mtime);
345962306a36Sopenharmony_ci
346062306a36Sopenharmony_ci	/*
346162306a36Sopenharmony_ci	 * SIT information should be updated before segment allocation,
346262306a36Sopenharmony_ci	 * since SSR needs latest valid block information.
346362306a36Sopenharmony_ci	 */
346462306a36Sopenharmony_ci	update_sit_entry(sbi, *new_blkaddr, 1);
346562306a36Sopenharmony_ci	if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO)
346662306a36Sopenharmony_ci		update_sit_entry(sbi, old_blkaddr, -1);
346762306a36Sopenharmony_ci
346862306a36Sopenharmony_ci	/*
346962306a36Sopenharmony_ci	 * If the current segment is full, flush it out and replace it with a
347062306a36Sopenharmony_ci	 * new segment.
347162306a36Sopenharmony_ci	 */
347262306a36Sopenharmony_ci	if (segment_full) {
347362306a36Sopenharmony_ci		if (from_gc) {
347462306a36Sopenharmony_ci			get_atssr_segment(sbi, type, se->type,
347562306a36Sopenharmony_ci						AT_SSR, se->mtime);
347662306a36Sopenharmony_ci		} else {
347762306a36Sopenharmony_ci			if (need_new_seg(sbi, type))
347862306a36Sopenharmony_ci				new_curseg(sbi, type, false);
347962306a36Sopenharmony_ci			else
348062306a36Sopenharmony_ci				change_curseg(sbi, type);
348162306a36Sopenharmony_ci			stat_inc_seg_type(sbi, curseg);
348262306a36Sopenharmony_ci		}
348362306a36Sopenharmony_ci	}
348462306a36Sopenharmony_ci	/*
348562306a36Sopenharmony_ci	 * segment dirty status should be updated after segment allocation,
348662306a36Sopenharmony_ci	 * so we just need to update status only one time after previous
348762306a36Sopenharmony_ci	 * segment being closed.
348862306a36Sopenharmony_ci	 */
348962306a36Sopenharmony_ci	locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr));
349062306a36Sopenharmony_ci	locate_dirty_segment(sbi, GET_SEGNO(sbi, *new_blkaddr));
349162306a36Sopenharmony_ci
349262306a36Sopenharmony_ci	if (IS_DATASEG(curseg->seg_type))
349362306a36Sopenharmony_ci		atomic64_inc(&sbi->allocated_data_blocks);
349462306a36Sopenharmony_ci
349562306a36Sopenharmony_ci	up_write(&sit_i->sentry_lock);
349662306a36Sopenharmony_ci
349762306a36Sopenharmony_ci	if (page && IS_NODESEG(curseg->seg_type)) {
349862306a36Sopenharmony_ci		fill_node_footer_blkaddr(page, NEXT_FREE_BLKADDR(sbi, curseg));
349962306a36Sopenharmony_ci
350062306a36Sopenharmony_ci		f2fs_inode_chksum_set(sbi, page);
350162306a36Sopenharmony_ci	}
350262306a36Sopenharmony_ci
350362306a36Sopenharmony_ci	if (fio) {
350462306a36Sopenharmony_ci		struct f2fs_bio_info *io;
350562306a36Sopenharmony_ci
350662306a36Sopenharmony_ci		if (F2FS_IO_ALIGNED(sbi))
350762306a36Sopenharmony_ci			fio->retry = 0;
350862306a36Sopenharmony_ci
350962306a36Sopenharmony_ci		INIT_LIST_HEAD(&fio->list);
351062306a36Sopenharmony_ci		fio->in_list = 1;
351162306a36Sopenharmony_ci		io = sbi->write_io[fio->type] + fio->temp;
351262306a36Sopenharmony_ci		spin_lock(&io->io_lock);
351362306a36Sopenharmony_ci		list_add_tail(&fio->list, &io->io_list);
351462306a36Sopenharmony_ci		spin_unlock(&io->io_lock);
351562306a36Sopenharmony_ci	}
351662306a36Sopenharmony_ci
351762306a36Sopenharmony_ci	mutex_unlock(&curseg->curseg_mutex);
351862306a36Sopenharmony_ci
351962306a36Sopenharmony_ci	f2fs_up_read(&SM_I(sbi)->curseg_lock);
352062306a36Sopenharmony_ci}
352162306a36Sopenharmony_ci
352262306a36Sopenharmony_civoid f2fs_update_device_state(struct f2fs_sb_info *sbi, nid_t ino,
352362306a36Sopenharmony_ci					block_t blkaddr, unsigned int blkcnt)
352462306a36Sopenharmony_ci{
352562306a36Sopenharmony_ci	if (!f2fs_is_multi_device(sbi))
352662306a36Sopenharmony_ci		return;
352762306a36Sopenharmony_ci
352862306a36Sopenharmony_ci	while (1) {
352962306a36Sopenharmony_ci		unsigned int devidx = f2fs_target_device_index(sbi, blkaddr);
353062306a36Sopenharmony_ci		unsigned int blks = FDEV(devidx).end_blk - blkaddr + 1;
353162306a36Sopenharmony_ci
353262306a36Sopenharmony_ci		/* update device state for fsync */
353362306a36Sopenharmony_ci		f2fs_set_dirty_device(sbi, ino, devidx, FLUSH_INO);
353462306a36Sopenharmony_ci
353562306a36Sopenharmony_ci		/* update device state for checkpoint */
353662306a36Sopenharmony_ci		if (!f2fs_test_bit(devidx, (char *)&sbi->dirty_device)) {
353762306a36Sopenharmony_ci			spin_lock(&sbi->dev_lock);
353862306a36Sopenharmony_ci			f2fs_set_bit(devidx, (char *)&sbi->dirty_device);
353962306a36Sopenharmony_ci			spin_unlock(&sbi->dev_lock);
354062306a36Sopenharmony_ci		}
354162306a36Sopenharmony_ci
354262306a36Sopenharmony_ci		if (blkcnt <= blks)
354362306a36Sopenharmony_ci			break;
354462306a36Sopenharmony_ci		blkcnt -= blks;
354562306a36Sopenharmony_ci		blkaddr += blks;
354662306a36Sopenharmony_ci	}
354762306a36Sopenharmony_ci}
354862306a36Sopenharmony_ci
354962306a36Sopenharmony_cistatic void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)
355062306a36Sopenharmony_ci{
355162306a36Sopenharmony_ci	int type = __get_segment_type(fio);
355262306a36Sopenharmony_ci	bool keep_order = (f2fs_lfs_mode(fio->sbi) && type == CURSEG_COLD_DATA);
355362306a36Sopenharmony_ci
355462306a36Sopenharmony_ci	if (keep_order)
355562306a36Sopenharmony_ci		f2fs_down_read(&fio->sbi->io_order_lock);
355662306a36Sopenharmony_cireallocate:
355762306a36Sopenharmony_ci	f2fs_allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr,
355862306a36Sopenharmony_ci			&fio->new_blkaddr, sum, type, fio);
355962306a36Sopenharmony_ci	if (GET_SEGNO(fio->sbi, fio->old_blkaddr) != NULL_SEGNO)
356062306a36Sopenharmony_ci		f2fs_invalidate_internal_cache(fio->sbi, fio->old_blkaddr);
356162306a36Sopenharmony_ci
356262306a36Sopenharmony_ci	/* writeout dirty page into bdev */
356362306a36Sopenharmony_ci	f2fs_submit_page_write(fio);
356462306a36Sopenharmony_ci	if (fio->retry) {
356562306a36Sopenharmony_ci		fio->old_blkaddr = fio->new_blkaddr;
356662306a36Sopenharmony_ci		goto reallocate;
356762306a36Sopenharmony_ci	}
356862306a36Sopenharmony_ci
356962306a36Sopenharmony_ci	f2fs_update_device_state(fio->sbi, fio->ino, fio->new_blkaddr, 1);
357062306a36Sopenharmony_ci
357162306a36Sopenharmony_ci	if (keep_order)
357262306a36Sopenharmony_ci		f2fs_up_read(&fio->sbi->io_order_lock);
357362306a36Sopenharmony_ci}
357462306a36Sopenharmony_ci
357562306a36Sopenharmony_civoid f2fs_do_write_meta_page(struct f2fs_sb_info *sbi, struct page *page,
357662306a36Sopenharmony_ci					enum iostat_type io_type)
357762306a36Sopenharmony_ci{
357862306a36Sopenharmony_ci	struct f2fs_io_info fio = {
357962306a36Sopenharmony_ci		.sbi = sbi,
358062306a36Sopenharmony_ci		.type = META,
358162306a36Sopenharmony_ci		.temp = HOT,
358262306a36Sopenharmony_ci		.op = REQ_OP_WRITE,
358362306a36Sopenharmony_ci		.op_flags = REQ_SYNC | REQ_META | REQ_PRIO,
358462306a36Sopenharmony_ci		.old_blkaddr = page->index,
358562306a36Sopenharmony_ci		.new_blkaddr = page->index,
358662306a36Sopenharmony_ci		.page = page,
358762306a36Sopenharmony_ci		.encrypted_page = NULL,
358862306a36Sopenharmony_ci		.in_list = 0,
358962306a36Sopenharmony_ci	};
359062306a36Sopenharmony_ci
359162306a36Sopenharmony_ci	if (unlikely(page->index >= MAIN_BLKADDR(sbi)))
359262306a36Sopenharmony_ci		fio.op_flags &= ~REQ_META;
359362306a36Sopenharmony_ci
359462306a36Sopenharmony_ci	set_page_writeback(page);
359562306a36Sopenharmony_ci	f2fs_submit_page_write(&fio);
359662306a36Sopenharmony_ci
359762306a36Sopenharmony_ci	stat_inc_meta_count(sbi, page->index);
359862306a36Sopenharmony_ci	f2fs_update_iostat(sbi, NULL, io_type, F2FS_BLKSIZE);
359962306a36Sopenharmony_ci}
360062306a36Sopenharmony_ci
360162306a36Sopenharmony_civoid f2fs_do_write_node_page(unsigned int nid, struct f2fs_io_info *fio)
360262306a36Sopenharmony_ci{
360362306a36Sopenharmony_ci	struct f2fs_summary sum;
360462306a36Sopenharmony_ci
360562306a36Sopenharmony_ci	set_summary(&sum, nid, 0, 0);
360662306a36Sopenharmony_ci	do_write_page(&sum, fio);
360762306a36Sopenharmony_ci
360862306a36Sopenharmony_ci	f2fs_update_iostat(fio->sbi, NULL, fio->io_type, F2FS_BLKSIZE);
360962306a36Sopenharmony_ci}
361062306a36Sopenharmony_ci
361162306a36Sopenharmony_civoid f2fs_outplace_write_data(struct dnode_of_data *dn,
361262306a36Sopenharmony_ci					struct f2fs_io_info *fio)
361362306a36Sopenharmony_ci{
361462306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = fio->sbi;
361562306a36Sopenharmony_ci	struct f2fs_summary sum;
361662306a36Sopenharmony_ci
361762306a36Sopenharmony_ci	f2fs_bug_on(sbi, dn->data_blkaddr == NULL_ADDR);
361862306a36Sopenharmony_ci	if (fio->io_type == FS_DATA_IO || fio->io_type == FS_CP_DATA_IO)
361962306a36Sopenharmony_ci		f2fs_update_age_extent_cache(dn);
362062306a36Sopenharmony_ci	set_summary(&sum, dn->nid, dn->ofs_in_node, fio->version);
362162306a36Sopenharmony_ci	do_write_page(&sum, fio);
362262306a36Sopenharmony_ci	f2fs_update_data_blkaddr(dn, fio->new_blkaddr);
362362306a36Sopenharmony_ci
362462306a36Sopenharmony_ci	f2fs_update_iostat(sbi, dn->inode, fio->io_type, F2FS_BLKSIZE);
362562306a36Sopenharmony_ci}
362662306a36Sopenharmony_ci
362762306a36Sopenharmony_ciint f2fs_inplace_write_data(struct f2fs_io_info *fio)
362862306a36Sopenharmony_ci{
362962306a36Sopenharmony_ci	int err;
363062306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = fio->sbi;
363162306a36Sopenharmony_ci	unsigned int segno;
363262306a36Sopenharmony_ci
363362306a36Sopenharmony_ci	fio->new_blkaddr = fio->old_blkaddr;
363462306a36Sopenharmony_ci	/* i/o temperature is needed for passing down write hints */
363562306a36Sopenharmony_ci	__get_segment_type(fio);
363662306a36Sopenharmony_ci
363762306a36Sopenharmony_ci	segno = GET_SEGNO(sbi, fio->new_blkaddr);
363862306a36Sopenharmony_ci
363962306a36Sopenharmony_ci	if (!IS_DATASEG(get_seg_entry(sbi, segno)->type)) {
364062306a36Sopenharmony_ci		set_sbi_flag(sbi, SBI_NEED_FSCK);
364162306a36Sopenharmony_ci		f2fs_warn(sbi, "%s: incorrect segment(%u) type, run fsck to fix.",
364262306a36Sopenharmony_ci			  __func__, segno);
364362306a36Sopenharmony_ci		err = -EFSCORRUPTED;
364462306a36Sopenharmony_ci		f2fs_handle_error(sbi, ERROR_INCONSISTENT_SUM_TYPE);
364562306a36Sopenharmony_ci		goto drop_bio;
364662306a36Sopenharmony_ci	}
364762306a36Sopenharmony_ci
364862306a36Sopenharmony_ci	if (f2fs_cp_error(sbi)) {
364962306a36Sopenharmony_ci		err = -EIO;
365062306a36Sopenharmony_ci		goto drop_bio;
365162306a36Sopenharmony_ci	}
365262306a36Sopenharmony_ci
365362306a36Sopenharmony_ci	if (fio->post_read)
365462306a36Sopenharmony_ci		f2fs_truncate_meta_inode_pages(sbi, fio->new_blkaddr, 1);
365562306a36Sopenharmony_ci
365662306a36Sopenharmony_ci	stat_inc_inplace_blocks(fio->sbi);
365762306a36Sopenharmony_ci
365862306a36Sopenharmony_ci	if (fio->bio && !IS_F2FS_IPU_NOCACHE(sbi))
365962306a36Sopenharmony_ci		err = f2fs_merge_page_bio(fio);
366062306a36Sopenharmony_ci	else
366162306a36Sopenharmony_ci		err = f2fs_submit_page_bio(fio);
366262306a36Sopenharmony_ci	if (!err) {
366362306a36Sopenharmony_ci		f2fs_update_device_state(fio->sbi, fio->ino,
366462306a36Sopenharmony_ci						fio->new_blkaddr, 1);
366562306a36Sopenharmony_ci		f2fs_update_iostat(fio->sbi, fio->page->mapping->host,
366662306a36Sopenharmony_ci						fio->io_type, F2FS_BLKSIZE);
366762306a36Sopenharmony_ci	}
366862306a36Sopenharmony_ci
366962306a36Sopenharmony_ci	return err;
367062306a36Sopenharmony_cidrop_bio:
367162306a36Sopenharmony_ci	if (fio->bio && *(fio->bio)) {
367262306a36Sopenharmony_ci		struct bio *bio = *(fio->bio);
367362306a36Sopenharmony_ci
367462306a36Sopenharmony_ci		bio->bi_status = BLK_STS_IOERR;
367562306a36Sopenharmony_ci		bio_endio(bio);
367662306a36Sopenharmony_ci		*(fio->bio) = NULL;
367762306a36Sopenharmony_ci	}
367862306a36Sopenharmony_ci	return err;
367962306a36Sopenharmony_ci}
368062306a36Sopenharmony_ci
368162306a36Sopenharmony_cistatic inline int __f2fs_get_curseg(struct f2fs_sb_info *sbi,
368262306a36Sopenharmony_ci						unsigned int segno)
368362306a36Sopenharmony_ci{
368462306a36Sopenharmony_ci	int i;
368562306a36Sopenharmony_ci
368662306a36Sopenharmony_ci	for (i = CURSEG_HOT_DATA; i < NO_CHECK_TYPE; i++) {
368762306a36Sopenharmony_ci		if (CURSEG_I(sbi, i)->segno == segno)
368862306a36Sopenharmony_ci			break;
368962306a36Sopenharmony_ci	}
369062306a36Sopenharmony_ci	return i;
369162306a36Sopenharmony_ci}
369262306a36Sopenharmony_ci
369362306a36Sopenharmony_civoid f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
369462306a36Sopenharmony_ci				block_t old_blkaddr, block_t new_blkaddr,
369562306a36Sopenharmony_ci				bool recover_curseg, bool recover_newaddr,
369662306a36Sopenharmony_ci				bool from_gc)
369762306a36Sopenharmony_ci{
369862306a36Sopenharmony_ci	struct sit_info *sit_i = SIT_I(sbi);
369962306a36Sopenharmony_ci	struct curseg_info *curseg;
370062306a36Sopenharmony_ci	unsigned int segno, old_cursegno;
370162306a36Sopenharmony_ci	struct seg_entry *se;
370262306a36Sopenharmony_ci	int type;
370362306a36Sopenharmony_ci	unsigned short old_blkoff;
370462306a36Sopenharmony_ci	unsigned char old_alloc_type;
370562306a36Sopenharmony_ci
370662306a36Sopenharmony_ci	segno = GET_SEGNO(sbi, new_blkaddr);
370762306a36Sopenharmony_ci	se = get_seg_entry(sbi, segno);
370862306a36Sopenharmony_ci	type = se->type;
370962306a36Sopenharmony_ci
371062306a36Sopenharmony_ci	f2fs_down_write(&SM_I(sbi)->curseg_lock);
371162306a36Sopenharmony_ci
371262306a36Sopenharmony_ci	if (!recover_curseg) {
371362306a36Sopenharmony_ci		/* for recovery flow */
371462306a36Sopenharmony_ci		if (se->valid_blocks == 0 && !IS_CURSEG(sbi, segno)) {
371562306a36Sopenharmony_ci			if (old_blkaddr == NULL_ADDR)
371662306a36Sopenharmony_ci				type = CURSEG_COLD_DATA;
371762306a36Sopenharmony_ci			else
371862306a36Sopenharmony_ci				type = CURSEG_WARM_DATA;
371962306a36Sopenharmony_ci		}
372062306a36Sopenharmony_ci	} else {
372162306a36Sopenharmony_ci		if (IS_CURSEG(sbi, segno)) {
372262306a36Sopenharmony_ci			/* se->type is volatile as SSR allocation */
372362306a36Sopenharmony_ci			type = __f2fs_get_curseg(sbi, segno);
372462306a36Sopenharmony_ci			f2fs_bug_on(sbi, type == NO_CHECK_TYPE);
372562306a36Sopenharmony_ci		} else {
372662306a36Sopenharmony_ci			type = CURSEG_WARM_DATA;
372762306a36Sopenharmony_ci		}
372862306a36Sopenharmony_ci	}
372962306a36Sopenharmony_ci
373062306a36Sopenharmony_ci	f2fs_bug_on(sbi, !IS_DATASEG(type));
373162306a36Sopenharmony_ci	curseg = CURSEG_I(sbi, type);
373262306a36Sopenharmony_ci
373362306a36Sopenharmony_ci	mutex_lock(&curseg->curseg_mutex);
373462306a36Sopenharmony_ci	down_write(&sit_i->sentry_lock);
373562306a36Sopenharmony_ci
373662306a36Sopenharmony_ci	old_cursegno = curseg->segno;
373762306a36Sopenharmony_ci	old_blkoff = curseg->next_blkoff;
373862306a36Sopenharmony_ci	old_alloc_type = curseg->alloc_type;
373962306a36Sopenharmony_ci
374062306a36Sopenharmony_ci	/* change the current segment */
374162306a36Sopenharmony_ci	if (segno != curseg->segno) {
374262306a36Sopenharmony_ci		curseg->next_segno = segno;
374362306a36Sopenharmony_ci		change_curseg(sbi, type);
374462306a36Sopenharmony_ci	}
374562306a36Sopenharmony_ci
374662306a36Sopenharmony_ci	curseg->next_blkoff = GET_BLKOFF_FROM_SEG0(sbi, new_blkaddr);
374762306a36Sopenharmony_ci	curseg->sum_blk->entries[curseg->next_blkoff] = *sum;
374862306a36Sopenharmony_ci
374962306a36Sopenharmony_ci	if (!recover_curseg || recover_newaddr) {
375062306a36Sopenharmony_ci		if (!from_gc)
375162306a36Sopenharmony_ci			update_segment_mtime(sbi, new_blkaddr, 0);
375262306a36Sopenharmony_ci		update_sit_entry(sbi, new_blkaddr, 1);
375362306a36Sopenharmony_ci	}
375462306a36Sopenharmony_ci	if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) {
375562306a36Sopenharmony_ci		f2fs_invalidate_internal_cache(sbi, old_blkaddr);
375662306a36Sopenharmony_ci		if (!from_gc)
375762306a36Sopenharmony_ci			update_segment_mtime(sbi, old_blkaddr, 0);
375862306a36Sopenharmony_ci		update_sit_entry(sbi, old_blkaddr, -1);
375962306a36Sopenharmony_ci	}
376062306a36Sopenharmony_ci
376162306a36Sopenharmony_ci	locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr));
376262306a36Sopenharmony_ci	locate_dirty_segment(sbi, GET_SEGNO(sbi, new_blkaddr));
376362306a36Sopenharmony_ci
376462306a36Sopenharmony_ci	locate_dirty_segment(sbi, old_cursegno);
376562306a36Sopenharmony_ci
376662306a36Sopenharmony_ci	if (recover_curseg) {
376762306a36Sopenharmony_ci		if (old_cursegno != curseg->segno) {
376862306a36Sopenharmony_ci			curseg->next_segno = old_cursegno;
376962306a36Sopenharmony_ci			change_curseg(sbi, type);
377062306a36Sopenharmony_ci		}
377162306a36Sopenharmony_ci		curseg->next_blkoff = old_blkoff;
377262306a36Sopenharmony_ci		curseg->alloc_type = old_alloc_type;
377362306a36Sopenharmony_ci	}
377462306a36Sopenharmony_ci
377562306a36Sopenharmony_ci	up_write(&sit_i->sentry_lock);
377662306a36Sopenharmony_ci	mutex_unlock(&curseg->curseg_mutex);
377762306a36Sopenharmony_ci	f2fs_up_write(&SM_I(sbi)->curseg_lock);
377862306a36Sopenharmony_ci}
377962306a36Sopenharmony_ci
378062306a36Sopenharmony_civoid f2fs_replace_block(struct f2fs_sb_info *sbi, struct dnode_of_data *dn,
378162306a36Sopenharmony_ci				block_t old_addr, block_t new_addr,
378262306a36Sopenharmony_ci				unsigned char version, bool recover_curseg,
378362306a36Sopenharmony_ci				bool recover_newaddr)
378462306a36Sopenharmony_ci{
378562306a36Sopenharmony_ci	struct f2fs_summary sum;
378662306a36Sopenharmony_ci
378762306a36Sopenharmony_ci	set_summary(&sum, dn->nid, dn->ofs_in_node, version);
378862306a36Sopenharmony_ci
378962306a36Sopenharmony_ci	f2fs_do_replace_block(sbi, &sum, old_addr, new_addr,
379062306a36Sopenharmony_ci					recover_curseg, recover_newaddr, false);
379162306a36Sopenharmony_ci
379262306a36Sopenharmony_ci	f2fs_update_data_blkaddr(dn, new_addr);
379362306a36Sopenharmony_ci}
379462306a36Sopenharmony_ci
379562306a36Sopenharmony_civoid f2fs_wait_on_page_writeback(struct page *page,
379662306a36Sopenharmony_ci				enum page_type type, bool ordered, bool locked)
379762306a36Sopenharmony_ci{
379862306a36Sopenharmony_ci	if (PageWriteback(page)) {
379962306a36Sopenharmony_ci		struct f2fs_sb_info *sbi = F2FS_P_SB(page);
380062306a36Sopenharmony_ci
380162306a36Sopenharmony_ci		/* submit cached LFS IO */
380262306a36Sopenharmony_ci		f2fs_submit_merged_write_cond(sbi, NULL, page, 0, type);
380362306a36Sopenharmony_ci		/* submit cached IPU IO */
380462306a36Sopenharmony_ci		f2fs_submit_merged_ipu_write(sbi, NULL, page);
380562306a36Sopenharmony_ci		if (ordered) {
380662306a36Sopenharmony_ci			wait_on_page_writeback(page);
380762306a36Sopenharmony_ci			f2fs_bug_on(sbi, locked && PageWriteback(page));
380862306a36Sopenharmony_ci		} else {
380962306a36Sopenharmony_ci			wait_for_stable_page(page);
381062306a36Sopenharmony_ci		}
381162306a36Sopenharmony_ci	}
381262306a36Sopenharmony_ci}
381362306a36Sopenharmony_ci
381462306a36Sopenharmony_civoid f2fs_wait_on_block_writeback(struct inode *inode, block_t blkaddr)
381562306a36Sopenharmony_ci{
381662306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
381762306a36Sopenharmony_ci	struct page *cpage;
381862306a36Sopenharmony_ci
381962306a36Sopenharmony_ci	if (!f2fs_post_read_required(inode))
382062306a36Sopenharmony_ci		return;
382162306a36Sopenharmony_ci
382262306a36Sopenharmony_ci	if (!__is_valid_data_blkaddr(blkaddr))
382362306a36Sopenharmony_ci		return;
382462306a36Sopenharmony_ci
382562306a36Sopenharmony_ci	cpage = find_lock_page(META_MAPPING(sbi), blkaddr);
382662306a36Sopenharmony_ci	if (cpage) {
382762306a36Sopenharmony_ci		f2fs_wait_on_page_writeback(cpage, DATA, true, true);
382862306a36Sopenharmony_ci		f2fs_put_page(cpage, 1);
382962306a36Sopenharmony_ci	}
383062306a36Sopenharmony_ci}
383162306a36Sopenharmony_ci
383262306a36Sopenharmony_civoid f2fs_wait_on_block_writeback_range(struct inode *inode, block_t blkaddr,
383362306a36Sopenharmony_ci								block_t len)
383462306a36Sopenharmony_ci{
383562306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
383662306a36Sopenharmony_ci	block_t i;
383762306a36Sopenharmony_ci
383862306a36Sopenharmony_ci	if (!f2fs_post_read_required(inode))
383962306a36Sopenharmony_ci		return;
384062306a36Sopenharmony_ci
384162306a36Sopenharmony_ci	for (i = 0; i < len; i++)
384262306a36Sopenharmony_ci		f2fs_wait_on_block_writeback(inode, blkaddr + i);
384362306a36Sopenharmony_ci
384462306a36Sopenharmony_ci	f2fs_truncate_meta_inode_pages(sbi, blkaddr, len);
384562306a36Sopenharmony_ci}
384662306a36Sopenharmony_ci
384762306a36Sopenharmony_cistatic int read_compacted_summaries(struct f2fs_sb_info *sbi)
384862306a36Sopenharmony_ci{
384962306a36Sopenharmony_ci	struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
385062306a36Sopenharmony_ci	struct curseg_info *seg_i;
385162306a36Sopenharmony_ci	unsigned char *kaddr;
385262306a36Sopenharmony_ci	struct page *page;
385362306a36Sopenharmony_ci	block_t start;
385462306a36Sopenharmony_ci	int i, j, offset;
385562306a36Sopenharmony_ci
385662306a36Sopenharmony_ci	start = start_sum_block(sbi);
385762306a36Sopenharmony_ci
385862306a36Sopenharmony_ci	page = f2fs_get_meta_page(sbi, start++);
385962306a36Sopenharmony_ci	if (IS_ERR(page))
386062306a36Sopenharmony_ci		return PTR_ERR(page);
386162306a36Sopenharmony_ci	kaddr = (unsigned char *)page_address(page);
386262306a36Sopenharmony_ci
386362306a36Sopenharmony_ci	/* Step 1: restore nat cache */
386462306a36Sopenharmony_ci	seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA);
386562306a36Sopenharmony_ci	memcpy(seg_i->journal, kaddr, SUM_JOURNAL_SIZE);
386662306a36Sopenharmony_ci
386762306a36Sopenharmony_ci	/* Step 2: restore sit cache */
386862306a36Sopenharmony_ci	seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA);
386962306a36Sopenharmony_ci	memcpy(seg_i->journal, kaddr + SUM_JOURNAL_SIZE, SUM_JOURNAL_SIZE);
387062306a36Sopenharmony_ci	offset = 2 * SUM_JOURNAL_SIZE;
387162306a36Sopenharmony_ci
387262306a36Sopenharmony_ci	/* Step 3: restore summary entries */
387362306a36Sopenharmony_ci	for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
387462306a36Sopenharmony_ci		unsigned short blk_off;
387562306a36Sopenharmony_ci		unsigned int segno;
387662306a36Sopenharmony_ci
387762306a36Sopenharmony_ci		seg_i = CURSEG_I(sbi, i);
387862306a36Sopenharmony_ci		segno = le32_to_cpu(ckpt->cur_data_segno[i]);
387962306a36Sopenharmony_ci		blk_off = le16_to_cpu(ckpt->cur_data_blkoff[i]);
388062306a36Sopenharmony_ci		seg_i->next_segno = segno;
388162306a36Sopenharmony_ci		reset_curseg(sbi, i, 0);
388262306a36Sopenharmony_ci		seg_i->alloc_type = ckpt->alloc_type[i];
388362306a36Sopenharmony_ci		seg_i->next_blkoff = blk_off;
388462306a36Sopenharmony_ci
388562306a36Sopenharmony_ci		if (seg_i->alloc_type == SSR)
388662306a36Sopenharmony_ci			blk_off = sbi->blocks_per_seg;
388762306a36Sopenharmony_ci
388862306a36Sopenharmony_ci		for (j = 0; j < blk_off; j++) {
388962306a36Sopenharmony_ci			struct f2fs_summary *s;
389062306a36Sopenharmony_ci
389162306a36Sopenharmony_ci			s = (struct f2fs_summary *)(kaddr + offset);
389262306a36Sopenharmony_ci			seg_i->sum_blk->entries[j] = *s;
389362306a36Sopenharmony_ci			offset += SUMMARY_SIZE;
389462306a36Sopenharmony_ci			if (offset + SUMMARY_SIZE <= PAGE_SIZE -
389562306a36Sopenharmony_ci						SUM_FOOTER_SIZE)
389662306a36Sopenharmony_ci				continue;
389762306a36Sopenharmony_ci
389862306a36Sopenharmony_ci			f2fs_put_page(page, 1);
389962306a36Sopenharmony_ci			page = NULL;
390062306a36Sopenharmony_ci
390162306a36Sopenharmony_ci			page = f2fs_get_meta_page(sbi, start++);
390262306a36Sopenharmony_ci			if (IS_ERR(page))
390362306a36Sopenharmony_ci				return PTR_ERR(page);
390462306a36Sopenharmony_ci			kaddr = (unsigned char *)page_address(page);
390562306a36Sopenharmony_ci			offset = 0;
390662306a36Sopenharmony_ci		}
390762306a36Sopenharmony_ci	}
390862306a36Sopenharmony_ci	f2fs_put_page(page, 1);
390962306a36Sopenharmony_ci	return 0;
391062306a36Sopenharmony_ci}
391162306a36Sopenharmony_ci
391262306a36Sopenharmony_cistatic int read_normal_summaries(struct f2fs_sb_info *sbi, int type)
391362306a36Sopenharmony_ci{
391462306a36Sopenharmony_ci	struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
391562306a36Sopenharmony_ci	struct f2fs_summary_block *sum;
391662306a36Sopenharmony_ci	struct curseg_info *curseg;
391762306a36Sopenharmony_ci	struct page *new;
391862306a36Sopenharmony_ci	unsigned short blk_off;
391962306a36Sopenharmony_ci	unsigned int segno = 0;
392062306a36Sopenharmony_ci	block_t blk_addr = 0;
392162306a36Sopenharmony_ci	int err = 0;
392262306a36Sopenharmony_ci
392362306a36Sopenharmony_ci	/* get segment number and block addr */
392462306a36Sopenharmony_ci	if (IS_DATASEG(type)) {
392562306a36Sopenharmony_ci		segno = le32_to_cpu(ckpt->cur_data_segno[type]);
392662306a36Sopenharmony_ci		blk_off = le16_to_cpu(ckpt->cur_data_blkoff[type -
392762306a36Sopenharmony_ci							CURSEG_HOT_DATA]);
392862306a36Sopenharmony_ci		if (__exist_node_summaries(sbi))
392962306a36Sopenharmony_ci			blk_addr = sum_blk_addr(sbi, NR_CURSEG_PERSIST_TYPE, type);
393062306a36Sopenharmony_ci		else
393162306a36Sopenharmony_ci			blk_addr = sum_blk_addr(sbi, NR_CURSEG_DATA_TYPE, type);
393262306a36Sopenharmony_ci	} else {
393362306a36Sopenharmony_ci		segno = le32_to_cpu(ckpt->cur_node_segno[type -
393462306a36Sopenharmony_ci							CURSEG_HOT_NODE]);
393562306a36Sopenharmony_ci		blk_off = le16_to_cpu(ckpt->cur_node_blkoff[type -
393662306a36Sopenharmony_ci							CURSEG_HOT_NODE]);
393762306a36Sopenharmony_ci		if (__exist_node_summaries(sbi))
393862306a36Sopenharmony_ci			blk_addr = sum_blk_addr(sbi, NR_CURSEG_NODE_TYPE,
393962306a36Sopenharmony_ci							type - CURSEG_HOT_NODE);
394062306a36Sopenharmony_ci		else
394162306a36Sopenharmony_ci			blk_addr = GET_SUM_BLOCK(sbi, segno);
394262306a36Sopenharmony_ci	}
394362306a36Sopenharmony_ci
394462306a36Sopenharmony_ci	new = f2fs_get_meta_page(sbi, blk_addr);
394562306a36Sopenharmony_ci	if (IS_ERR(new))
394662306a36Sopenharmony_ci		return PTR_ERR(new);
394762306a36Sopenharmony_ci	sum = (struct f2fs_summary_block *)page_address(new);
394862306a36Sopenharmony_ci
394962306a36Sopenharmony_ci	if (IS_NODESEG(type)) {
395062306a36Sopenharmony_ci		if (__exist_node_summaries(sbi)) {
395162306a36Sopenharmony_ci			struct f2fs_summary *ns = &sum->entries[0];
395262306a36Sopenharmony_ci			int i;
395362306a36Sopenharmony_ci
395462306a36Sopenharmony_ci			for (i = 0; i < sbi->blocks_per_seg; i++, ns++) {
395562306a36Sopenharmony_ci				ns->version = 0;
395662306a36Sopenharmony_ci				ns->ofs_in_node = 0;
395762306a36Sopenharmony_ci			}
395862306a36Sopenharmony_ci		} else {
395962306a36Sopenharmony_ci			err = f2fs_restore_node_summary(sbi, segno, sum);
396062306a36Sopenharmony_ci			if (err)
396162306a36Sopenharmony_ci				goto out;
396262306a36Sopenharmony_ci		}
396362306a36Sopenharmony_ci	}
396462306a36Sopenharmony_ci
396562306a36Sopenharmony_ci	/* set uncompleted segment to curseg */
396662306a36Sopenharmony_ci	curseg = CURSEG_I(sbi, type);
396762306a36Sopenharmony_ci	mutex_lock(&curseg->curseg_mutex);
396862306a36Sopenharmony_ci
396962306a36Sopenharmony_ci	/* update journal info */
397062306a36Sopenharmony_ci	down_write(&curseg->journal_rwsem);
397162306a36Sopenharmony_ci	memcpy(curseg->journal, &sum->journal, SUM_JOURNAL_SIZE);
397262306a36Sopenharmony_ci	up_write(&curseg->journal_rwsem);
397362306a36Sopenharmony_ci
397462306a36Sopenharmony_ci	memcpy(curseg->sum_blk->entries, sum->entries, SUM_ENTRY_SIZE);
397562306a36Sopenharmony_ci	memcpy(&curseg->sum_blk->footer, &sum->footer, SUM_FOOTER_SIZE);
397662306a36Sopenharmony_ci	curseg->next_segno = segno;
397762306a36Sopenharmony_ci	reset_curseg(sbi, type, 0);
397862306a36Sopenharmony_ci	curseg->alloc_type = ckpt->alloc_type[type];
397962306a36Sopenharmony_ci	curseg->next_blkoff = blk_off;
398062306a36Sopenharmony_ci	mutex_unlock(&curseg->curseg_mutex);
398162306a36Sopenharmony_ciout:
398262306a36Sopenharmony_ci	f2fs_put_page(new, 1);
398362306a36Sopenharmony_ci	return err;
398462306a36Sopenharmony_ci}
398562306a36Sopenharmony_ci
398662306a36Sopenharmony_cistatic int restore_curseg_summaries(struct f2fs_sb_info *sbi)
398762306a36Sopenharmony_ci{
398862306a36Sopenharmony_ci	struct f2fs_journal *sit_j = CURSEG_I(sbi, CURSEG_COLD_DATA)->journal;
398962306a36Sopenharmony_ci	struct f2fs_journal *nat_j = CURSEG_I(sbi, CURSEG_HOT_DATA)->journal;
399062306a36Sopenharmony_ci	int type = CURSEG_HOT_DATA;
399162306a36Sopenharmony_ci	int err;
399262306a36Sopenharmony_ci
399362306a36Sopenharmony_ci	if (is_set_ckpt_flags(sbi, CP_COMPACT_SUM_FLAG)) {
399462306a36Sopenharmony_ci		int npages = f2fs_npages_for_summary_flush(sbi, true);
399562306a36Sopenharmony_ci
399662306a36Sopenharmony_ci		if (npages >= 2)
399762306a36Sopenharmony_ci			f2fs_ra_meta_pages(sbi, start_sum_block(sbi), npages,
399862306a36Sopenharmony_ci							META_CP, true);
399962306a36Sopenharmony_ci
400062306a36Sopenharmony_ci		/* restore for compacted data summary */
400162306a36Sopenharmony_ci		err = read_compacted_summaries(sbi);
400262306a36Sopenharmony_ci		if (err)
400362306a36Sopenharmony_ci			return err;
400462306a36Sopenharmony_ci		type = CURSEG_HOT_NODE;
400562306a36Sopenharmony_ci	}
400662306a36Sopenharmony_ci
400762306a36Sopenharmony_ci	if (__exist_node_summaries(sbi))
400862306a36Sopenharmony_ci		f2fs_ra_meta_pages(sbi,
400962306a36Sopenharmony_ci				sum_blk_addr(sbi, NR_CURSEG_PERSIST_TYPE, type),
401062306a36Sopenharmony_ci				NR_CURSEG_PERSIST_TYPE - type, META_CP, true);
401162306a36Sopenharmony_ci
401262306a36Sopenharmony_ci	for (; type <= CURSEG_COLD_NODE; type++) {
401362306a36Sopenharmony_ci		err = read_normal_summaries(sbi, type);
401462306a36Sopenharmony_ci		if (err)
401562306a36Sopenharmony_ci			return err;
401662306a36Sopenharmony_ci	}
401762306a36Sopenharmony_ci
401862306a36Sopenharmony_ci	/* sanity check for summary blocks */
401962306a36Sopenharmony_ci	if (nats_in_cursum(nat_j) > NAT_JOURNAL_ENTRIES ||
402062306a36Sopenharmony_ci			sits_in_cursum(sit_j) > SIT_JOURNAL_ENTRIES) {
402162306a36Sopenharmony_ci		f2fs_err(sbi, "invalid journal entries nats %u sits %u",
402262306a36Sopenharmony_ci			 nats_in_cursum(nat_j), sits_in_cursum(sit_j));
402362306a36Sopenharmony_ci		return -EINVAL;
402462306a36Sopenharmony_ci	}
402562306a36Sopenharmony_ci
402662306a36Sopenharmony_ci	return 0;
402762306a36Sopenharmony_ci}
402862306a36Sopenharmony_ci
402962306a36Sopenharmony_cistatic void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr)
403062306a36Sopenharmony_ci{
403162306a36Sopenharmony_ci	struct page *page;
403262306a36Sopenharmony_ci	unsigned char *kaddr;
403362306a36Sopenharmony_ci	struct f2fs_summary *summary;
403462306a36Sopenharmony_ci	struct curseg_info *seg_i;
403562306a36Sopenharmony_ci	int written_size = 0;
403662306a36Sopenharmony_ci	int i, j;
403762306a36Sopenharmony_ci
403862306a36Sopenharmony_ci	page = f2fs_grab_meta_page(sbi, blkaddr++);
403962306a36Sopenharmony_ci	kaddr = (unsigned char *)page_address(page);
404062306a36Sopenharmony_ci	memset(kaddr, 0, PAGE_SIZE);
404162306a36Sopenharmony_ci
404262306a36Sopenharmony_ci	/* Step 1: write nat cache */
404362306a36Sopenharmony_ci	seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA);
404462306a36Sopenharmony_ci	memcpy(kaddr, seg_i->journal, SUM_JOURNAL_SIZE);
404562306a36Sopenharmony_ci	written_size += SUM_JOURNAL_SIZE;
404662306a36Sopenharmony_ci
404762306a36Sopenharmony_ci	/* Step 2: write sit cache */
404862306a36Sopenharmony_ci	seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA);
404962306a36Sopenharmony_ci	memcpy(kaddr + written_size, seg_i->journal, SUM_JOURNAL_SIZE);
405062306a36Sopenharmony_ci	written_size += SUM_JOURNAL_SIZE;
405162306a36Sopenharmony_ci
405262306a36Sopenharmony_ci	/* Step 3: write summary entries */
405362306a36Sopenharmony_ci	for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
405462306a36Sopenharmony_ci		seg_i = CURSEG_I(sbi, i);
405562306a36Sopenharmony_ci		for (j = 0; j < f2fs_curseg_valid_blocks(sbi, i); j++) {
405662306a36Sopenharmony_ci			if (!page) {
405762306a36Sopenharmony_ci				page = f2fs_grab_meta_page(sbi, blkaddr++);
405862306a36Sopenharmony_ci				kaddr = (unsigned char *)page_address(page);
405962306a36Sopenharmony_ci				memset(kaddr, 0, PAGE_SIZE);
406062306a36Sopenharmony_ci				written_size = 0;
406162306a36Sopenharmony_ci			}
406262306a36Sopenharmony_ci			summary = (struct f2fs_summary *)(kaddr + written_size);
406362306a36Sopenharmony_ci			*summary = seg_i->sum_blk->entries[j];
406462306a36Sopenharmony_ci			written_size += SUMMARY_SIZE;
406562306a36Sopenharmony_ci
406662306a36Sopenharmony_ci			if (written_size + SUMMARY_SIZE <= PAGE_SIZE -
406762306a36Sopenharmony_ci							SUM_FOOTER_SIZE)
406862306a36Sopenharmony_ci				continue;
406962306a36Sopenharmony_ci
407062306a36Sopenharmony_ci			set_page_dirty(page);
407162306a36Sopenharmony_ci			f2fs_put_page(page, 1);
407262306a36Sopenharmony_ci			page = NULL;
407362306a36Sopenharmony_ci		}
407462306a36Sopenharmony_ci	}
407562306a36Sopenharmony_ci	if (page) {
407662306a36Sopenharmony_ci		set_page_dirty(page);
407762306a36Sopenharmony_ci		f2fs_put_page(page, 1);
407862306a36Sopenharmony_ci	}
407962306a36Sopenharmony_ci}
408062306a36Sopenharmony_ci
408162306a36Sopenharmony_cistatic void write_normal_summaries(struct f2fs_sb_info *sbi,
408262306a36Sopenharmony_ci					block_t blkaddr, int type)
408362306a36Sopenharmony_ci{
408462306a36Sopenharmony_ci	int i, end;
408562306a36Sopenharmony_ci
408662306a36Sopenharmony_ci	if (IS_DATASEG(type))
408762306a36Sopenharmony_ci		end = type + NR_CURSEG_DATA_TYPE;
408862306a36Sopenharmony_ci	else
408962306a36Sopenharmony_ci		end = type + NR_CURSEG_NODE_TYPE;
409062306a36Sopenharmony_ci
409162306a36Sopenharmony_ci	for (i = type; i < end; i++)
409262306a36Sopenharmony_ci		write_current_sum_page(sbi, i, blkaddr + (i - type));
409362306a36Sopenharmony_ci}
409462306a36Sopenharmony_ci
409562306a36Sopenharmony_civoid f2fs_write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk)
409662306a36Sopenharmony_ci{
409762306a36Sopenharmony_ci	if (is_set_ckpt_flags(sbi, CP_COMPACT_SUM_FLAG))
409862306a36Sopenharmony_ci		write_compacted_summaries(sbi, start_blk);
409962306a36Sopenharmony_ci	else
410062306a36Sopenharmony_ci		write_normal_summaries(sbi, start_blk, CURSEG_HOT_DATA);
410162306a36Sopenharmony_ci}
410262306a36Sopenharmony_ci
410362306a36Sopenharmony_civoid f2fs_write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk)
410462306a36Sopenharmony_ci{
410562306a36Sopenharmony_ci	write_normal_summaries(sbi, start_blk, CURSEG_HOT_NODE);
410662306a36Sopenharmony_ci}
410762306a36Sopenharmony_ci
410862306a36Sopenharmony_ciint f2fs_lookup_journal_in_cursum(struct f2fs_journal *journal, int type,
410962306a36Sopenharmony_ci					unsigned int val, int alloc)
411062306a36Sopenharmony_ci{
411162306a36Sopenharmony_ci	int i;
411262306a36Sopenharmony_ci
411362306a36Sopenharmony_ci	if (type == NAT_JOURNAL) {
411462306a36Sopenharmony_ci		for (i = 0; i < nats_in_cursum(journal); i++) {
411562306a36Sopenharmony_ci			if (le32_to_cpu(nid_in_journal(journal, i)) == val)
411662306a36Sopenharmony_ci				return i;
411762306a36Sopenharmony_ci		}
411862306a36Sopenharmony_ci		if (alloc && __has_cursum_space(journal, 1, NAT_JOURNAL))
411962306a36Sopenharmony_ci			return update_nats_in_cursum(journal, 1);
412062306a36Sopenharmony_ci	} else if (type == SIT_JOURNAL) {
412162306a36Sopenharmony_ci		for (i = 0; i < sits_in_cursum(journal); i++)
412262306a36Sopenharmony_ci			if (le32_to_cpu(segno_in_journal(journal, i)) == val)
412362306a36Sopenharmony_ci				return i;
412462306a36Sopenharmony_ci		if (alloc && __has_cursum_space(journal, 1, SIT_JOURNAL))
412562306a36Sopenharmony_ci			return update_sits_in_cursum(journal, 1);
412662306a36Sopenharmony_ci	}
412762306a36Sopenharmony_ci	return -1;
412862306a36Sopenharmony_ci}
412962306a36Sopenharmony_ci
413062306a36Sopenharmony_cistatic struct page *get_current_sit_page(struct f2fs_sb_info *sbi,
413162306a36Sopenharmony_ci					unsigned int segno)
413262306a36Sopenharmony_ci{
413362306a36Sopenharmony_ci	return f2fs_get_meta_page(sbi, current_sit_addr(sbi, segno));
413462306a36Sopenharmony_ci}
413562306a36Sopenharmony_ci
413662306a36Sopenharmony_cistatic struct page *get_next_sit_page(struct f2fs_sb_info *sbi,
413762306a36Sopenharmony_ci					unsigned int start)
413862306a36Sopenharmony_ci{
413962306a36Sopenharmony_ci	struct sit_info *sit_i = SIT_I(sbi);
414062306a36Sopenharmony_ci	struct page *page;
414162306a36Sopenharmony_ci	pgoff_t src_off, dst_off;
414262306a36Sopenharmony_ci
414362306a36Sopenharmony_ci	src_off = current_sit_addr(sbi, start);
414462306a36Sopenharmony_ci	dst_off = next_sit_addr(sbi, src_off);
414562306a36Sopenharmony_ci
414662306a36Sopenharmony_ci	page = f2fs_grab_meta_page(sbi, dst_off);
414762306a36Sopenharmony_ci	seg_info_to_sit_page(sbi, page, start);
414862306a36Sopenharmony_ci
414962306a36Sopenharmony_ci	set_page_dirty(page);
415062306a36Sopenharmony_ci	set_to_next_sit(sit_i, start);
415162306a36Sopenharmony_ci
415262306a36Sopenharmony_ci	return page;
415362306a36Sopenharmony_ci}
415462306a36Sopenharmony_ci
415562306a36Sopenharmony_cistatic struct sit_entry_set *grab_sit_entry_set(void)
415662306a36Sopenharmony_ci{
415762306a36Sopenharmony_ci	struct sit_entry_set *ses =
415862306a36Sopenharmony_ci			f2fs_kmem_cache_alloc(sit_entry_set_slab,
415962306a36Sopenharmony_ci						GFP_NOFS, true, NULL);
416062306a36Sopenharmony_ci
416162306a36Sopenharmony_ci	ses->entry_cnt = 0;
416262306a36Sopenharmony_ci	INIT_LIST_HEAD(&ses->set_list);
416362306a36Sopenharmony_ci	return ses;
416462306a36Sopenharmony_ci}
416562306a36Sopenharmony_ci
416662306a36Sopenharmony_cistatic void release_sit_entry_set(struct sit_entry_set *ses)
416762306a36Sopenharmony_ci{
416862306a36Sopenharmony_ci	list_del(&ses->set_list);
416962306a36Sopenharmony_ci	kmem_cache_free(sit_entry_set_slab, ses);
417062306a36Sopenharmony_ci}
417162306a36Sopenharmony_ci
417262306a36Sopenharmony_cistatic void adjust_sit_entry_set(struct sit_entry_set *ses,
417362306a36Sopenharmony_ci						struct list_head *head)
417462306a36Sopenharmony_ci{
417562306a36Sopenharmony_ci	struct sit_entry_set *next = ses;
417662306a36Sopenharmony_ci
417762306a36Sopenharmony_ci	if (list_is_last(&ses->set_list, head))
417862306a36Sopenharmony_ci		return;
417962306a36Sopenharmony_ci
418062306a36Sopenharmony_ci	list_for_each_entry_continue(next, head, set_list)
418162306a36Sopenharmony_ci		if (ses->entry_cnt <= next->entry_cnt) {
418262306a36Sopenharmony_ci			list_move_tail(&ses->set_list, &next->set_list);
418362306a36Sopenharmony_ci			return;
418462306a36Sopenharmony_ci		}
418562306a36Sopenharmony_ci
418662306a36Sopenharmony_ci	list_move_tail(&ses->set_list, head);
418762306a36Sopenharmony_ci}
418862306a36Sopenharmony_ci
418962306a36Sopenharmony_cistatic void add_sit_entry(unsigned int segno, struct list_head *head)
419062306a36Sopenharmony_ci{
419162306a36Sopenharmony_ci	struct sit_entry_set *ses;
419262306a36Sopenharmony_ci	unsigned int start_segno = START_SEGNO(segno);
419362306a36Sopenharmony_ci
419462306a36Sopenharmony_ci	list_for_each_entry(ses, head, set_list) {
419562306a36Sopenharmony_ci		if (ses->start_segno == start_segno) {
419662306a36Sopenharmony_ci			ses->entry_cnt++;
419762306a36Sopenharmony_ci			adjust_sit_entry_set(ses, head);
419862306a36Sopenharmony_ci			return;
419962306a36Sopenharmony_ci		}
420062306a36Sopenharmony_ci	}
420162306a36Sopenharmony_ci
420262306a36Sopenharmony_ci	ses = grab_sit_entry_set();
420362306a36Sopenharmony_ci
420462306a36Sopenharmony_ci	ses->start_segno = start_segno;
420562306a36Sopenharmony_ci	ses->entry_cnt++;
420662306a36Sopenharmony_ci	list_add(&ses->set_list, head);
420762306a36Sopenharmony_ci}
420862306a36Sopenharmony_ci
420962306a36Sopenharmony_cistatic void add_sits_in_set(struct f2fs_sb_info *sbi)
421062306a36Sopenharmony_ci{
421162306a36Sopenharmony_ci	struct f2fs_sm_info *sm_info = SM_I(sbi);
421262306a36Sopenharmony_ci	struct list_head *set_list = &sm_info->sit_entry_set;
421362306a36Sopenharmony_ci	unsigned long *bitmap = SIT_I(sbi)->dirty_sentries_bitmap;
421462306a36Sopenharmony_ci	unsigned int segno;
421562306a36Sopenharmony_ci
421662306a36Sopenharmony_ci	for_each_set_bit(segno, bitmap, MAIN_SEGS(sbi))
421762306a36Sopenharmony_ci		add_sit_entry(segno, set_list);
421862306a36Sopenharmony_ci}
421962306a36Sopenharmony_ci
422062306a36Sopenharmony_cistatic void remove_sits_in_journal(struct f2fs_sb_info *sbi)
422162306a36Sopenharmony_ci{
422262306a36Sopenharmony_ci	struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
422362306a36Sopenharmony_ci	struct f2fs_journal *journal = curseg->journal;
422462306a36Sopenharmony_ci	int i;
422562306a36Sopenharmony_ci
422662306a36Sopenharmony_ci	down_write(&curseg->journal_rwsem);
422762306a36Sopenharmony_ci	for (i = 0; i < sits_in_cursum(journal); i++) {
422862306a36Sopenharmony_ci		unsigned int segno;
422962306a36Sopenharmony_ci		bool dirtied;
423062306a36Sopenharmony_ci
423162306a36Sopenharmony_ci		segno = le32_to_cpu(segno_in_journal(journal, i));
423262306a36Sopenharmony_ci		dirtied = __mark_sit_entry_dirty(sbi, segno);
423362306a36Sopenharmony_ci
423462306a36Sopenharmony_ci		if (!dirtied)
423562306a36Sopenharmony_ci			add_sit_entry(segno, &SM_I(sbi)->sit_entry_set);
423662306a36Sopenharmony_ci	}
423762306a36Sopenharmony_ci	update_sits_in_cursum(journal, -i);
423862306a36Sopenharmony_ci	up_write(&curseg->journal_rwsem);
423962306a36Sopenharmony_ci}
424062306a36Sopenharmony_ci
424162306a36Sopenharmony_ci/*
424262306a36Sopenharmony_ci * CP calls this function, which flushes SIT entries including sit_journal,
424362306a36Sopenharmony_ci * and moves prefree segs to free segs.
424462306a36Sopenharmony_ci */
424562306a36Sopenharmony_civoid f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
424662306a36Sopenharmony_ci{
424762306a36Sopenharmony_ci	struct sit_info *sit_i = SIT_I(sbi);
424862306a36Sopenharmony_ci	unsigned long *bitmap = sit_i->dirty_sentries_bitmap;
424962306a36Sopenharmony_ci	struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
425062306a36Sopenharmony_ci	struct f2fs_journal *journal = curseg->journal;
425162306a36Sopenharmony_ci	struct sit_entry_set *ses, *tmp;
425262306a36Sopenharmony_ci	struct list_head *head = &SM_I(sbi)->sit_entry_set;
425362306a36Sopenharmony_ci	bool to_journal = !is_sbi_flag_set(sbi, SBI_IS_RESIZEFS);
425462306a36Sopenharmony_ci	struct seg_entry *se;
425562306a36Sopenharmony_ci
425662306a36Sopenharmony_ci	down_write(&sit_i->sentry_lock);
425762306a36Sopenharmony_ci
425862306a36Sopenharmony_ci	if (!sit_i->dirty_sentries)
425962306a36Sopenharmony_ci		goto out;
426062306a36Sopenharmony_ci
426162306a36Sopenharmony_ci	/*
426262306a36Sopenharmony_ci	 * add and account sit entries of dirty bitmap in sit entry
426362306a36Sopenharmony_ci	 * set temporarily
426462306a36Sopenharmony_ci	 */
426562306a36Sopenharmony_ci	add_sits_in_set(sbi);
426662306a36Sopenharmony_ci
426762306a36Sopenharmony_ci	/*
426862306a36Sopenharmony_ci	 * if there are no enough space in journal to store dirty sit
426962306a36Sopenharmony_ci	 * entries, remove all entries from journal and add and account
427062306a36Sopenharmony_ci	 * them in sit entry set.
427162306a36Sopenharmony_ci	 */
427262306a36Sopenharmony_ci	if (!__has_cursum_space(journal, sit_i->dirty_sentries, SIT_JOURNAL) ||
427362306a36Sopenharmony_ci								!to_journal)
427462306a36Sopenharmony_ci		remove_sits_in_journal(sbi);
427562306a36Sopenharmony_ci
427662306a36Sopenharmony_ci	/*
427762306a36Sopenharmony_ci	 * there are two steps to flush sit entries:
427862306a36Sopenharmony_ci	 * #1, flush sit entries to journal in current cold data summary block.
427962306a36Sopenharmony_ci	 * #2, flush sit entries to sit page.
428062306a36Sopenharmony_ci	 */
428162306a36Sopenharmony_ci	list_for_each_entry_safe(ses, tmp, head, set_list) {
428262306a36Sopenharmony_ci		struct page *page = NULL;
428362306a36Sopenharmony_ci		struct f2fs_sit_block *raw_sit = NULL;
428462306a36Sopenharmony_ci		unsigned int start_segno = ses->start_segno;
428562306a36Sopenharmony_ci		unsigned int end = min(start_segno + SIT_ENTRY_PER_BLOCK,
428662306a36Sopenharmony_ci						(unsigned long)MAIN_SEGS(sbi));
428762306a36Sopenharmony_ci		unsigned int segno = start_segno;
428862306a36Sopenharmony_ci
428962306a36Sopenharmony_ci		if (to_journal &&
429062306a36Sopenharmony_ci			!__has_cursum_space(journal, ses->entry_cnt, SIT_JOURNAL))
429162306a36Sopenharmony_ci			to_journal = false;
429262306a36Sopenharmony_ci
429362306a36Sopenharmony_ci		if (to_journal) {
429462306a36Sopenharmony_ci			down_write(&curseg->journal_rwsem);
429562306a36Sopenharmony_ci		} else {
429662306a36Sopenharmony_ci			page = get_next_sit_page(sbi, start_segno);
429762306a36Sopenharmony_ci			raw_sit = page_address(page);
429862306a36Sopenharmony_ci		}
429962306a36Sopenharmony_ci
430062306a36Sopenharmony_ci		/* flush dirty sit entries in region of current sit set */
430162306a36Sopenharmony_ci		for_each_set_bit_from(segno, bitmap, end) {
430262306a36Sopenharmony_ci			int offset, sit_offset;
430362306a36Sopenharmony_ci
430462306a36Sopenharmony_ci			se = get_seg_entry(sbi, segno);
430562306a36Sopenharmony_ci#ifdef CONFIG_F2FS_CHECK_FS
430662306a36Sopenharmony_ci			if (memcmp(se->cur_valid_map, se->cur_valid_map_mir,
430762306a36Sopenharmony_ci						SIT_VBLOCK_MAP_SIZE))
430862306a36Sopenharmony_ci				f2fs_bug_on(sbi, 1);
430962306a36Sopenharmony_ci#endif
431062306a36Sopenharmony_ci
431162306a36Sopenharmony_ci			/* add discard candidates */
431262306a36Sopenharmony_ci			if (!(cpc->reason & CP_DISCARD)) {
431362306a36Sopenharmony_ci				cpc->trim_start = segno;
431462306a36Sopenharmony_ci				add_discard_addrs(sbi, cpc, false);
431562306a36Sopenharmony_ci			}
431662306a36Sopenharmony_ci
431762306a36Sopenharmony_ci			if (to_journal) {
431862306a36Sopenharmony_ci				offset = f2fs_lookup_journal_in_cursum(journal,
431962306a36Sopenharmony_ci							SIT_JOURNAL, segno, 1);
432062306a36Sopenharmony_ci				f2fs_bug_on(sbi, offset < 0);
432162306a36Sopenharmony_ci				segno_in_journal(journal, offset) =
432262306a36Sopenharmony_ci							cpu_to_le32(segno);
432362306a36Sopenharmony_ci				seg_info_to_raw_sit(se,
432462306a36Sopenharmony_ci					&sit_in_journal(journal, offset));
432562306a36Sopenharmony_ci				check_block_count(sbi, segno,
432662306a36Sopenharmony_ci					&sit_in_journal(journal, offset));
432762306a36Sopenharmony_ci			} else {
432862306a36Sopenharmony_ci				sit_offset = SIT_ENTRY_OFFSET(sit_i, segno);
432962306a36Sopenharmony_ci				seg_info_to_raw_sit(se,
433062306a36Sopenharmony_ci						&raw_sit->entries[sit_offset]);
433162306a36Sopenharmony_ci				check_block_count(sbi, segno,
433262306a36Sopenharmony_ci						&raw_sit->entries[sit_offset]);
433362306a36Sopenharmony_ci			}
433462306a36Sopenharmony_ci
433562306a36Sopenharmony_ci			__clear_bit(segno, bitmap);
433662306a36Sopenharmony_ci			sit_i->dirty_sentries--;
433762306a36Sopenharmony_ci			ses->entry_cnt--;
433862306a36Sopenharmony_ci		}
433962306a36Sopenharmony_ci
434062306a36Sopenharmony_ci		if (to_journal)
434162306a36Sopenharmony_ci			up_write(&curseg->journal_rwsem);
434262306a36Sopenharmony_ci		else
434362306a36Sopenharmony_ci			f2fs_put_page(page, 1);
434462306a36Sopenharmony_ci
434562306a36Sopenharmony_ci		f2fs_bug_on(sbi, ses->entry_cnt);
434662306a36Sopenharmony_ci		release_sit_entry_set(ses);
434762306a36Sopenharmony_ci	}
434862306a36Sopenharmony_ci
434962306a36Sopenharmony_ci	f2fs_bug_on(sbi, !list_empty(head));
435062306a36Sopenharmony_ci	f2fs_bug_on(sbi, sit_i->dirty_sentries);
435162306a36Sopenharmony_ciout:
435262306a36Sopenharmony_ci	if (cpc->reason & CP_DISCARD) {
435362306a36Sopenharmony_ci		__u64 trim_start = cpc->trim_start;
435462306a36Sopenharmony_ci
435562306a36Sopenharmony_ci		for (; cpc->trim_start <= cpc->trim_end; cpc->trim_start++)
435662306a36Sopenharmony_ci			add_discard_addrs(sbi, cpc, false);
435762306a36Sopenharmony_ci
435862306a36Sopenharmony_ci		cpc->trim_start = trim_start;
435962306a36Sopenharmony_ci	}
436062306a36Sopenharmony_ci	up_write(&sit_i->sentry_lock);
436162306a36Sopenharmony_ci
436262306a36Sopenharmony_ci	set_prefree_as_free_segments(sbi);
436362306a36Sopenharmony_ci}
436462306a36Sopenharmony_ci
436562306a36Sopenharmony_cistatic int build_sit_info(struct f2fs_sb_info *sbi)
436662306a36Sopenharmony_ci{
436762306a36Sopenharmony_ci	struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
436862306a36Sopenharmony_ci	struct sit_info *sit_i;
436962306a36Sopenharmony_ci	unsigned int sit_segs, start;
437062306a36Sopenharmony_ci	char *src_bitmap, *bitmap;
437162306a36Sopenharmony_ci	unsigned int bitmap_size, main_bitmap_size, sit_bitmap_size;
437262306a36Sopenharmony_ci	unsigned int discard_map = f2fs_block_unit_discard(sbi) ? 1 : 0;
437362306a36Sopenharmony_ci
437462306a36Sopenharmony_ci	/* allocate memory for SIT information */
437562306a36Sopenharmony_ci	sit_i = f2fs_kzalloc(sbi, sizeof(struct sit_info), GFP_KERNEL);
437662306a36Sopenharmony_ci	if (!sit_i)
437762306a36Sopenharmony_ci		return -ENOMEM;
437862306a36Sopenharmony_ci
437962306a36Sopenharmony_ci	SM_I(sbi)->sit_info = sit_i;
438062306a36Sopenharmony_ci
438162306a36Sopenharmony_ci	sit_i->sentries =
438262306a36Sopenharmony_ci		f2fs_kvzalloc(sbi, array_size(sizeof(struct seg_entry),
438362306a36Sopenharmony_ci					      MAIN_SEGS(sbi)),
438462306a36Sopenharmony_ci			      GFP_KERNEL);
438562306a36Sopenharmony_ci	if (!sit_i->sentries)
438662306a36Sopenharmony_ci		return -ENOMEM;
438762306a36Sopenharmony_ci
438862306a36Sopenharmony_ci	main_bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi));
438962306a36Sopenharmony_ci	sit_i->dirty_sentries_bitmap = f2fs_kvzalloc(sbi, main_bitmap_size,
439062306a36Sopenharmony_ci								GFP_KERNEL);
439162306a36Sopenharmony_ci	if (!sit_i->dirty_sentries_bitmap)
439262306a36Sopenharmony_ci		return -ENOMEM;
439362306a36Sopenharmony_ci
439462306a36Sopenharmony_ci#ifdef CONFIG_F2FS_CHECK_FS
439562306a36Sopenharmony_ci	bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * (3 + discard_map);
439662306a36Sopenharmony_ci#else
439762306a36Sopenharmony_ci	bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * (2 + discard_map);
439862306a36Sopenharmony_ci#endif
439962306a36Sopenharmony_ci	sit_i->bitmap = f2fs_kvzalloc(sbi, bitmap_size, GFP_KERNEL);
440062306a36Sopenharmony_ci	if (!sit_i->bitmap)
440162306a36Sopenharmony_ci		return -ENOMEM;
440262306a36Sopenharmony_ci
440362306a36Sopenharmony_ci	bitmap = sit_i->bitmap;
440462306a36Sopenharmony_ci
440562306a36Sopenharmony_ci	for (start = 0; start < MAIN_SEGS(sbi); start++) {
440662306a36Sopenharmony_ci		sit_i->sentries[start].cur_valid_map = bitmap;
440762306a36Sopenharmony_ci		bitmap += SIT_VBLOCK_MAP_SIZE;
440862306a36Sopenharmony_ci
440962306a36Sopenharmony_ci		sit_i->sentries[start].ckpt_valid_map = bitmap;
441062306a36Sopenharmony_ci		bitmap += SIT_VBLOCK_MAP_SIZE;
441162306a36Sopenharmony_ci
441262306a36Sopenharmony_ci#ifdef CONFIG_F2FS_CHECK_FS
441362306a36Sopenharmony_ci		sit_i->sentries[start].cur_valid_map_mir = bitmap;
441462306a36Sopenharmony_ci		bitmap += SIT_VBLOCK_MAP_SIZE;
441562306a36Sopenharmony_ci#endif
441662306a36Sopenharmony_ci
441762306a36Sopenharmony_ci		if (discard_map) {
441862306a36Sopenharmony_ci			sit_i->sentries[start].discard_map = bitmap;
441962306a36Sopenharmony_ci			bitmap += SIT_VBLOCK_MAP_SIZE;
442062306a36Sopenharmony_ci		}
442162306a36Sopenharmony_ci	}
442262306a36Sopenharmony_ci
442362306a36Sopenharmony_ci	sit_i->tmp_map = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
442462306a36Sopenharmony_ci	if (!sit_i->tmp_map)
442562306a36Sopenharmony_ci		return -ENOMEM;
442662306a36Sopenharmony_ci
442762306a36Sopenharmony_ci	if (__is_large_section(sbi)) {
442862306a36Sopenharmony_ci		sit_i->sec_entries =
442962306a36Sopenharmony_ci			f2fs_kvzalloc(sbi, array_size(sizeof(struct sec_entry),
443062306a36Sopenharmony_ci						      MAIN_SECS(sbi)),
443162306a36Sopenharmony_ci				      GFP_KERNEL);
443262306a36Sopenharmony_ci		if (!sit_i->sec_entries)
443362306a36Sopenharmony_ci			return -ENOMEM;
443462306a36Sopenharmony_ci	}
443562306a36Sopenharmony_ci
443662306a36Sopenharmony_ci	/* get information related with SIT */
443762306a36Sopenharmony_ci	sit_segs = le32_to_cpu(raw_super->segment_count_sit) >> 1;
443862306a36Sopenharmony_ci
443962306a36Sopenharmony_ci	/* setup SIT bitmap from ckeckpoint pack */
444062306a36Sopenharmony_ci	sit_bitmap_size = __bitmap_size(sbi, SIT_BITMAP);
444162306a36Sopenharmony_ci	src_bitmap = __bitmap_ptr(sbi, SIT_BITMAP);
444262306a36Sopenharmony_ci
444362306a36Sopenharmony_ci	sit_i->sit_bitmap = kmemdup(src_bitmap, sit_bitmap_size, GFP_KERNEL);
444462306a36Sopenharmony_ci	if (!sit_i->sit_bitmap)
444562306a36Sopenharmony_ci		return -ENOMEM;
444662306a36Sopenharmony_ci
444762306a36Sopenharmony_ci#ifdef CONFIG_F2FS_CHECK_FS
444862306a36Sopenharmony_ci	sit_i->sit_bitmap_mir = kmemdup(src_bitmap,
444962306a36Sopenharmony_ci					sit_bitmap_size, GFP_KERNEL);
445062306a36Sopenharmony_ci	if (!sit_i->sit_bitmap_mir)
445162306a36Sopenharmony_ci		return -ENOMEM;
445262306a36Sopenharmony_ci
445362306a36Sopenharmony_ci	sit_i->invalid_segmap = f2fs_kvzalloc(sbi,
445462306a36Sopenharmony_ci					main_bitmap_size, GFP_KERNEL);
445562306a36Sopenharmony_ci	if (!sit_i->invalid_segmap)
445662306a36Sopenharmony_ci		return -ENOMEM;
445762306a36Sopenharmony_ci#endif
445862306a36Sopenharmony_ci
445962306a36Sopenharmony_ci	sit_i->sit_base_addr = le32_to_cpu(raw_super->sit_blkaddr);
446062306a36Sopenharmony_ci	sit_i->sit_blocks = sit_segs << sbi->log_blocks_per_seg;
446162306a36Sopenharmony_ci	sit_i->written_valid_blocks = 0;
446262306a36Sopenharmony_ci	sit_i->bitmap_size = sit_bitmap_size;
446362306a36Sopenharmony_ci	sit_i->dirty_sentries = 0;
446462306a36Sopenharmony_ci	sit_i->sents_per_block = SIT_ENTRY_PER_BLOCK;
446562306a36Sopenharmony_ci	sit_i->elapsed_time = le64_to_cpu(sbi->ckpt->elapsed_time);
446662306a36Sopenharmony_ci	sit_i->mounted_time = ktime_get_boottime_seconds();
446762306a36Sopenharmony_ci	init_rwsem(&sit_i->sentry_lock);
446862306a36Sopenharmony_ci	return 0;
446962306a36Sopenharmony_ci}
447062306a36Sopenharmony_ci
447162306a36Sopenharmony_cistatic int build_free_segmap(struct f2fs_sb_info *sbi)
447262306a36Sopenharmony_ci{
447362306a36Sopenharmony_ci	struct free_segmap_info *free_i;
447462306a36Sopenharmony_ci	unsigned int bitmap_size, sec_bitmap_size;
447562306a36Sopenharmony_ci
447662306a36Sopenharmony_ci	/* allocate memory for free segmap information */
447762306a36Sopenharmony_ci	free_i = f2fs_kzalloc(sbi, sizeof(struct free_segmap_info), GFP_KERNEL);
447862306a36Sopenharmony_ci	if (!free_i)
447962306a36Sopenharmony_ci		return -ENOMEM;
448062306a36Sopenharmony_ci
448162306a36Sopenharmony_ci	SM_I(sbi)->free_info = free_i;
448262306a36Sopenharmony_ci
448362306a36Sopenharmony_ci	bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi));
448462306a36Sopenharmony_ci	free_i->free_segmap = f2fs_kvmalloc(sbi, bitmap_size, GFP_KERNEL);
448562306a36Sopenharmony_ci	if (!free_i->free_segmap)
448662306a36Sopenharmony_ci		return -ENOMEM;
448762306a36Sopenharmony_ci
448862306a36Sopenharmony_ci	sec_bitmap_size = f2fs_bitmap_size(MAIN_SECS(sbi));
448962306a36Sopenharmony_ci	free_i->free_secmap = f2fs_kvmalloc(sbi, sec_bitmap_size, GFP_KERNEL);
449062306a36Sopenharmony_ci	if (!free_i->free_secmap)
449162306a36Sopenharmony_ci		return -ENOMEM;
449262306a36Sopenharmony_ci
449362306a36Sopenharmony_ci	/* set all segments as dirty temporarily */
449462306a36Sopenharmony_ci	memset(free_i->free_segmap, 0xff, bitmap_size);
449562306a36Sopenharmony_ci	memset(free_i->free_secmap, 0xff, sec_bitmap_size);
449662306a36Sopenharmony_ci
449762306a36Sopenharmony_ci	/* init free segmap information */
449862306a36Sopenharmony_ci	free_i->start_segno = GET_SEGNO_FROM_SEG0(sbi, MAIN_BLKADDR(sbi));
449962306a36Sopenharmony_ci	free_i->free_segments = 0;
450062306a36Sopenharmony_ci	free_i->free_sections = 0;
450162306a36Sopenharmony_ci	spin_lock_init(&free_i->segmap_lock);
450262306a36Sopenharmony_ci	return 0;
450362306a36Sopenharmony_ci}
450462306a36Sopenharmony_ci
450562306a36Sopenharmony_cistatic int build_curseg(struct f2fs_sb_info *sbi)
450662306a36Sopenharmony_ci{
450762306a36Sopenharmony_ci	struct curseg_info *array;
450862306a36Sopenharmony_ci	int i;
450962306a36Sopenharmony_ci
451062306a36Sopenharmony_ci	array = f2fs_kzalloc(sbi, array_size(NR_CURSEG_TYPE,
451162306a36Sopenharmony_ci					sizeof(*array)), GFP_KERNEL);
451262306a36Sopenharmony_ci	if (!array)
451362306a36Sopenharmony_ci		return -ENOMEM;
451462306a36Sopenharmony_ci
451562306a36Sopenharmony_ci	SM_I(sbi)->curseg_array = array;
451662306a36Sopenharmony_ci
451762306a36Sopenharmony_ci	for (i = 0; i < NO_CHECK_TYPE; i++) {
451862306a36Sopenharmony_ci		mutex_init(&array[i].curseg_mutex);
451962306a36Sopenharmony_ci		array[i].sum_blk = f2fs_kzalloc(sbi, PAGE_SIZE, GFP_KERNEL);
452062306a36Sopenharmony_ci		if (!array[i].sum_blk)
452162306a36Sopenharmony_ci			return -ENOMEM;
452262306a36Sopenharmony_ci		init_rwsem(&array[i].journal_rwsem);
452362306a36Sopenharmony_ci		array[i].journal = f2fs_kzalloc(sbi,
452462306a36Sopenharmony_ci				sizeof(struct f2fs_journal), GFP_KERNEL);
452562306a36Sopenharmony_ci		if (!array[i].journal)
452662306a36Sopenharmony_ci			return -ENOMEM;
452762306a36Sopenharmony_ci		if (i < NR_PERSISTENT_LOG)
452862306a36Sopenharmony_ci			array[i].seg_type = CURSEG_HOT_DATA + i;
452962306a36Sopenharmony_ci		else if (i == CURSEG_COLD_DATA_PINNED)
453062306a36Sopenharmony_ci			array[i].seg_type = CURSEG_COLD_DATA;
453162306a36Sopenharmony_ci		else if (i == CURSEG_ALL_DATA_ATGC)
453262306a36Sopenharmony_ci			array[i].seg_type = CURSEG_COLD_DATA;
453362306a36Sopenharmony_ci		array[i].segno = NULL_SEGNO;
453462306a36Sopenharmony_ci		array[i].next_blkoff = 0;
453562306a36Sopenharmony_ci		array[i].inited = false;
453662306a36Sopenharmony_ci	}
453762306a36Sopenharmony_ci	return restore_curseg_summaries(sbi);
453862306a36Sopenharmony_ci}
453962306a36Sopenharmony_ci
454062306a36Sopenharmony_cistatic int build_sit_entries(struct f2fs_sb_info *sbi)
454162306a36Sopenharmony_ci{
454262306a36Sopenharmony_ci	struct sit_info *sit_i = SIT_I(sbi);
454362306a36Sopenharmony_ci	struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
454462306a36Sopenharmony_ci	struct f2fs_journal *journal = curseg->journal;
454562306a36Sopenharmony_ci	struct seg_entry *se;
454662306a36Sopenharmony_ci	struct f2fs_sit_entry sit;
454762306a36Sopenharmony_ci	int sit_blk_cnt = SIT_BLK_CNT(sbi);
454862306a36Sopenharmony_ci	unsigned int i, start, end;
454962306a36Sopenharmony_ci	unsigned int readed, start_blk = 0;
455062306a36Sopenharmony_ci	int err = 0;
455162306a36Sopenharmony_ci	block_t sit_valid_blocks[2] = {0, 0};
455262306a36Sopenharmony_ci
455362306a36Sopenharmony_ci	do {
455462306a36Sopenharmony_ci		readed = f2fs_ra_meta_pages(sbi, start_blk, BIO_MAX_VECS,
455562306a36Sopenharmony_ci							META_SIT, true);
455662306a36Sopenharmony_ci
455762306a36Sopenharmony_ci		start = start_blk * sit_i->sents_per_block;
455862306a36Sopenharmony_ci		end = (start_blk + readed) * sit_i->sents_per_block;
455962306a36Sopenharmony_ci
456062306a36Sopenharmony_ci		for (; start < end && start < MAIN_SEGS(sbi); start++) {
456162306a36Sopenharmony_ci			struct f2fs_sit_block *sit_blk;
456262306a36Sopenharmony_ci			struct page *page;
456362306a36Sopenharmony_ci
456462306a36Sopenharmony_ci			se = &sit_i->sentries[start];
456562306a36Sopenharmony_ci			page = get_current_sit_page(sbi, start);
456662306a36Sopenharmony_ci			if (IS_ERR(page))
456762306a36Sopenharmony_ci				return PTR_ERR(page);
456862306a36Sopenharmony_ci			sit_blk = (struct f2fs_sit_block *)page_address(page);
456962306a36Sopenharmony_ci			sit = sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, start)];
457062306a36Sopenharmony_ci			f2fs_put_page(page, 1);
457162306a36Sopenharmony_ci
457262306a36Sopenharmony_ci			err = check_block_count(sbi, start, &sit);
457362306a36Sopenharmony_ci			if (err)
457462306a36Sopenharmony_ci				return err;
457562306a36Sopenharmony_ci			seg_info_from_raw_sit(se, &sit);
457662306a36Sopenharmony_ci
457762306a36Sopenharmony_ci			if (se->type >= NR_PERSISTENT_LOG) {
457862306a36Sopenharmony_ci				f2fs_err(sbi, "Invalid segment type: %u, segno: %u",
457962306a36Sopenharmony_ci							se->type, start);
458062306a36Sopenharmony_ci				f2fs_handle_error(sbi,
458162306a36Sopenharmony_ci						ERROR_INCONSISTENT_SUM_TYPE);
458262306a36Sopenharmony_ci				return -EFSCORRUPTED;
458362306a36Sopenharmony_ci			}
458462306a36Sopenharmony_ci
458562306a36Sopenharmony_ci			sit_valid_blocks[SE_PAGETYPE(se)] += se->valid_blocks;
458662306a36Sopenharmony_ci
458762306a36Sopenharmony_ci			if (f2fs_block_unit_discard(sbi)) {
458862306a36Sopenharmony_ci				/* build discard map only one time */
458962306a36Sopenharmony_ci				if (is_set_ckpt_flags(sbi, CP_TRIMMED_FLAG)) {
459062306a36Sopenharmony_ci					memset(se->discard_map, 0xff,
459162306a36Sopenharmony_ci						SIT_VBLOCK_MAP_SIZE);
459262306a36Sopenharmony_ci				} else {
459362306a36Sopenharmony_ci					memcpy(se->discard_map,
459462306a36Sopenharmony_ci						se->cur_valid_map,
459562306a36Sopenharmony_ci						SIT_VBLOCK_MAP_SIZE);
459662306a36Sopenharmony_ci					sbi->discard_blks +=
459762306a36Sopenharmony_ci						sbi->blocks_per_seg -
459862306a36Sopenharmony_ci						se->valid_blocks;
459962306a36Sopenharmony_ci				}
460062306a36Sopenharmony_ci			}
460162306a36Sopenharmony_ci
460262306a36Sopenharmony_ci			if (__is_large_section(sbi))
460362306a36Sopenharmony_ci				get_sec_entry(sbi, start)->valid_blocks +=
460462306a36Sopenharmony_ci							se->valid_blocks;
460562306a36Sopenharmony_ci		}
460662306a36Sopenharmony_ci		start_blk += readed;
460762306a36Sopenharmony_ci	} while (start_blk < sit_blk_cnt);
460862306a36Sopenharmony_ci
460962306a36Sopenharmony_ci	down_read(&curseg->journal_rwsem);
461062306a36Sopenharmony_ci	for (i = 0; i < sits_in_cursum(journal); i++) {
461162306a36Sopenharmony_ci		unsigned int old_valid_blocks;
461262306a36Sopenharmony_ci
461362306a36Sopenharmony_ci		start = le32_to_cpu(segno_in_journal(journal, i));
461462306a36Sopenharmony_ci		if (start >= MAIN_SEGS(sbi)) {
461562306a36Sopenharmony_ci			f2fs_err(sbi, "Wrong journal entry on segno %u",
461662306a36Sopenharmony_ci				 start);
461762306a36Sopenharmony_ci			err = -EFSCORRUPTED;
461862306a36Sopenharmony_ci			f2fs_handle_error(sbi, ERROR_CORRUPTED_JOURNAL);
461962306a36Sopenharmony_ci			break;
462062306a36Sopenharmony_ci		}
462162306a36Sopenharmony_ci
462262306a36Sopenharmony_ci		se = &sit_i->sentries[start];
462362306a36Sopenharmony_ci		sit = sit_in_journal(journal, i);
462462306a36Sopenharmony_ci
462562306a36Sopenharmony_ci		old_valid_blocks = se->valid_blocks;
462662306a36Sopenharmony_ci
462762306a36Sopenharmony_ci		sit_valid_blocks[SE_PAGETYPE(se)] -= old_valid_blocks;
462862306a36Sopenharmony_ci
462962306a36Sopenharmony_ci		err = check_block_count(sbi, start, &sit);
463062306a36Sopenharmony_ci		if (err)
463162306a36Sopenharmony_ci			break;
463262306a36Sopenharmony_ci		seg_info_from_raw_sit(se, &sit);
463362306a36Sopenharmony_ci
463462306a36Sopenharmony_ci		if (se->type >= NR_PERSISTENT_LOG) {
463562306a36Sopenharmony_ci			f2fs_err(sbi, "Invalid segment type: %u, segno: %u",
463662306a36Sopenharmony_ci							se->type, start);
463762306a36Sopenharmony_ci			err = -EFSCORRUPTED;
463862306a36Sopenharmony_ci			f2fs_handle_error(sbi, ERROR_INCONSISTENT_SUM_TYPE);
463962306a36Sopenharmony_ci			break;
464062306a36Sopenharmony_ci		}
464162306a36Sopenharmony_ci
464262306a36Sopenharmony_ci		sit_valid_blocks[SE_PAGETYPE(se)] += se->valid_blocks;
464362306a36Sopenharmony_ci
464462306a36Sopenharmony_ci		if (f2fs_block_unit_discard(sbi)) {
464562306a36Sopenharmony_ci			if (is_set_ckpt_flags(sbi, CP_TRIMMED_FLAG)) {
464662306a36Sopenharmony_ci				memset(se->discard_map, 0xff, SIT_VBLOCK_MAP_SIZE);
464762306a36Sopenharmony_ci			} else {
464862306a36Sopenharmony_ci				memcpy(se->discard_map, se->cur_valid_map,
464962306a36Sopenharmony_ci							SIT_VBLOCK_MAP_SIZE);
465062306a36Sopenharmony_ci				sbi->discard_blks += old_valid_blocks;
465162306a36Sopenharmony_ci				sbi->discard_blks -= se->valid_blocks;
465262306a36Sopenharmony_ci			}
465362306a36Sopenharmony_ci		}
465462306a36Sopenharmony_ci
465562306a36Sopenharmony_ci		if (__is_large_section(sbi)) {
465662306a36Sopenharmony_ci			get_sec_entry(sbi, start)->valid_blocks +=
465762306a36Sopenharmony_ci							se->valid_blocks;
465862306a36Sopenharmony_ci			get_sec_entry(sbi, start)->valid_blocks -=
465962306a36Sopenharmony_ci							old_valid_blocks;
466062306a36Sopenharmony_ci		}
466162306a36Sopenharmony_ci	}
466262306a36Sopenharmony_ci	up_read(&curseg->journal_rwsem);
466362306a36Sopenharmony_ci
466462306a36Sopenharmony_ci	if (err)
466562306a36Sopenharmony_ci		return err;
466662306a36Sopenharmony_ci
466762306a36Sopenharmony_ci	if (sit_valid_blocks[NODE] != valid_node_count(sbi)) {
466862306a36Sopenharmony_ci		f2fs_err(sbi, "SIT is corrupted node# %u vs %u",
466962306a36Sopenharmony_ci			 sit_valid_blocks[NODE], valid_node_count(sbi));
467062306a36Sopenharmony_ci		f2fs_handle_error(sbi, ERROR_INCONSISTENT_NODE_COUNT);
467162306a36Sopenharmony_ci		return -EFSCORRUPTED;
467262306a36Sopenharmony_ci	}
467362306a36Sopenharmony_ci
467462306a36Sopenharmony_ci	if (sit_valid_blocks[DATA] + sit_valid_blocks[NODE] >
467562306a36Sopenharmony_ci				valid_user_blocks(sbi)) {
467662306a36Sopenharmony_ci		f2fs_err(sbi, "SIT is corrupted data# %u %u vs %u",
467762306a36Sopenharmony_ci			 sit_valid_blocks[DATA], sit_valid_blocks[NODE],
467862306a36Sopenharmony_ci			 valid_user_blocks(sbi));
467962306a36Sopenharmony_ci		f2fs_handle_error(sbi, ERROR_INCONSISTENT_BLOCK_COUNT);
468062306a36Sopenharmony_ci		return -EFSCORRUPTED;
468162306a36Sopenharmony_ci	}
468262306a36Sopenharmony_ci
468362306a36Sopenharmony_ci	return 0;
468462306a36Sopenharmony_ci}
468562306a36Sopenharmony_ci
468662306a36Sopenharmony_cistatic void init_free_segmap(struct f2fs_sb_info *sbi)
468762306a36Sopenharmony_ci{
468862306a36Sopenharmony_ci	unsigned int start;
468962306a36Sopenharmony_ci	int type;
469062306a36Sopenharmony_ci	struct seg_entry *sentry;
469162306a36Sopenharmony_ci
469262306a36Sopenharmony_ci	for (start = 0; start < MAIN_SEGS(sbi); start++) {
469362306a36Sopenharmony_ci		if (f2fs_usable_blks_in_seg(sbi, start) == 0)
469462306a36Sopenharmony_ci			continue;
469562306a36Sopenharmony_ci		sentry = get_seg_entry(sbi, start);
469662306a36Sopenharmony_ci		if (!sentry->valid_blocks)
469762306a36Sopenharmony_ci			__set_free(sbi, start);
469862306a36Sopenharmony_ci		else
469962306a36Sopenharmony_ci			SIT_I(sbi)->written_valid_blocks +=
470062306a36Sopenharmony_ci						sentry->valid_blocks;
470162306a36Sopenharmony_ci	}
470262306a36Sopenharmony_ci
470362306a36Sopenharmony_ci	/* set use the current segments */
470462306a36Sopenharmony_ci	for (type = CURSEG_HOT_DATA; type <= CURSEG_COLD_NODE; type++) {
470562306a36Sopenharmony_ci		struct curseg_info *curseg_t = CURSEG_I(sbi, type);
470662306a36Sopenharmony_ci
470762306a36Sopenharmony_ci		__set_test_and_inuse(sbi, curseg_t->segno);
470862306a36Sopenharmony_ci	}
470962306a36Sopenharmony_ci}
471062306a36Sopenharmony_ci
471162306a36Sopenharmony_cistatic void init_dirty_segmap(struct f2fs_sb_info *sbi)
471262306a36Sopenharmony_ci{
471362306a36Sopenharmony_ci	struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
471462306a36Sopenharmony_ci	struct free_segmap_info *free_i = FREE_I(sbi);
471562306a36Sopenharmony_ci	unsigned int segno = 0, offset = 0, secno;
471662306a36Sopenharmony_ci	block_t valid_blocks, usable_blks_in_seg;
471762306a36Sopenharmony_ci
471862306a36Sopenharmony_ci	while (1) {
471962306a36Sopenharmony_ci		/* find dirty segment based on free segmap */
472062306a36Sopenharmony_ci		segno = find_next_inuse(free_i, MAIN_SEGS(sbi), offset);
472162306a36Sopenharmony_ci		if (segno >= MAIN_SEGS(sbi))
472262306a36Sopenharmony_ci			break;
472362306a36Sopenharmony_ci		offset = segno + 1;
472462306a36Sopenharmony_ci		valid_blocks = get_valid_blocks(sbi, segno, false);
472562306a36Sopenharmony_ci		usable_blks_in_seg = f2fs_usable_blks_in_seg(sbi, segno);
472662306a36Sopenharmony_ci		if (valid_blocks == usable_blks_in_seg || !valid_blocks)
472762306a36Sopenharmony_ci			continue;
472862306a36Sopenharmony_ci		if (valid_blocks > usable_blks_in_seg) {
472962306a36Sopenharmony_ci			f2fs_bug_on(sbi, 1);
473062306a36Sopenharmony_ci			continue;
473162306a36Sopenharmony_ci		}
473262306a36Sopenharmony_ci		mutex_lock(&dirty_i->seglist_lock);
473362306a36Sopenharmony_ci		__locate_dirty_segment(sbi, segno, DIRTY);
473462306a36Sopenharmony_ci		mutex_unlock(&dirty_i->seglist_lock);
473562306a36Sopenharmony_ci	}
473662306a36Sopenharmony_ci
473762306a36Sopenharmony_ci	if (!__is_large_section(sbi))
473862306a36Sopenharmony_ci		return;
473962306a36Sopenharmony_ci
474062306a36Sopenharmony_ci	mutex_lock(&dirty_i->seglist_lock);
474162306a36Sopenharmony_ci	for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) {
474262306a36Sopenharmony_ci		valid_blocks = get_valid_blocks(sbi, segno, true);
474362306a36Sopenharmony_ci		secno = GET_SEC_FROM_SEG(sbi, segno);
474462306a36Sopenharmony_ci
474562306a36Sopenharmony_ci		if (!valid_blocks || valid_blocks == CAP_BLKS_PER_SEC(sbi))
474662306a36Sopenharmony_ci			continue;
474762306a36Sopenharmony_ci		if (IS_CURSEC(sbi, secno))
474862306a36Sopenharmony_ci			continue;
474962306a36Sopenharmony_ci		set_bit(secno, dirty_i->dirty_secmap);
475062306a36Sopenharmony_ci	}
475162306a36Sopenharmony_ci	mutex_unlock(&dirty_i->seglist_lock);
475262306a36Sopenharmony_ci}
475362306a36Sopenharmony_ci
475462306a36Sopenharmony_cistatic int init_victim_secmap(struct f2fs_sb_info *sbi)
475562306a36Sopenharmony_ci{
475662306a36Sopenharmony_ci	struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
475762306a36Sopenharmony_ci	unsigned int bitmap_size = f2fs_bitmap_size(MAIN_SECS(sbi));
475862306a36Sopenharmony_ci
475962306a36Sopenharmony_ci	dirty_i->victim_secmap = f2fs_kvzalloc(sbi, bitmap_size, GFP_KERNEL);
476062306a36Sopenharmony_ci	if (!dirty_i->victim_secmap)
476162306a36Sopenharmony_ci		return -ENOMEM;
476262306a36Sopenharmony_ci
476362306a36Sopenharmony_ci	dirty_i->pinned_secmap = f2fs_kvzalloc(sbi, bitmap_size, GFP_KERNEL);
476462306a36Sopenharmony_ci	if (!dirty_i->pinned_secmap)
476562306a36Sopenharmony_ci		return -ENOMEM;
476662306a36Sopenharmony_ci
476762306a36Sopenharmony_ci	dirty_i->pinned_secmap_cnt = 0;
476862306a36Sopenharmony_ci	dirty_i->enable_pin_section = true;
476962306a36Sopenharmony_ci	return 0;
477062306a36Sopenharmony_ci}
477162306a36Sopenharmony_ci
477262306a36Sopenharmony_cistatic int build_dirty_segmap(struct f2fs_sb_info *sbi)
477362306a36Sopenharmony_ci{
477462306a36Sopenharmony_ci	struct dirty_seglist_info *dirty_i;
477562306a36Sopenharmony_ci	unsigned int bitmap_size, i;
477662306a36Sopenharmony_ci
477762306a36Sopenharmony_ci	/* allocate memory for dirty segments list information */
477862306a36Sopenharmony_ci	dirty_i = f2fs_kzalloc(sbi, sizeof(struct dirty_seglist_info),
477962306a36Sopenharmony_ci								GFP_KERNEL);
478062306a36Sopenharmony_ci	if (!dirty_i)
478162306a36Sopenharmony_ci		return -ENOMEM;
478262306a36Sopenharmony_ci
478362306a36Sopenharmony_ci	SM_I(sbi)->dirty_info = dirty_i;
478462306a36Sopenharmony_ci	mutex_init(&dirty_i->seglist_lock);
478562306a36Sopenharmony_ci
478662306a36Sopenharmony_ci	bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi));
478762306a36Sopenharmony_ci
478862306a36Sopenharmony_ci	for (i = 0; i < NR_DIRTY_TYPE; i++) {
478962306a36Sopenharmony_ci		dirty_i->dirty_segmap[i] = f2fs_kvzalloc(sbi, bitmap_size,
479062306a36Sopenharmony_ci								GFP_KERNEL);
479162306a36Sopenharmony_ci		if (!dirty_i->dirty_segmap[i])
479262306a36Sopenharmony_ci			return -ENOMEM;
479362306a36Sopenharmony_ci	}
479462306a36Sopenharmony_ci
479562306a36Sopenharmony_ci	if (__is_large_section(sbi)) {
479662306a36Sopenharmony_ci		bitmap_size = f2fs_bitmap_size(MAIN_SECS(sbi));
479762306a36Sopenharmony_ci		dirty_i->dirty_secmap = f2fs_kvzalloc(sbi,
479862306a36Sopenharmony_ci						bitmap_size, GFP_KERNEL);
479962306a36Sopenharmony_ci		if (!dirty_i->dirty_secmap)
480062306a36Sopenharmony_ci			return -ENOMEM;
480162306a36Sopenharmony_ci	}
480262306a36Sopenharmony_ci
480362306a36Sopenharmony_ci	init_dirty_segmap(sbi);
480462306a36Sopenharmony_ci	return init_victim_secmap(sbi);
480562306a36Sopenharmony_ci}
480662306a36Sopenharmony_ci
480762306a36Sopenharmony_cistatic int sanity_check_curseg(struct f2fs_sb_info *sbi)
480862306a36Sopenharmony_ci{
480962306a36Sopenharmony_ci	int i;
481062306a36Sopenharmony_ci
481162306a36Sopenharmony_ci	/*
481262306a36Sopenharmony_ci	 * In LFS/SSR curseg, .next_blkoff should point to an unused blkaddr;
481362306a36Sopenharmony_ci	 * In LFS curseg, all blkaddr after .next_blkoff should be unused.
481462306a36Sopenharmony_ci	 */
481562306a36Sopenharmony_ci	for (i = 0; i < NR_PERSISTENT_LOG; i++) {
481662306a36Sopenharmony_ci		struct curseg_info *curseg = CURSEG_I(sbi, i);
481762306a36Sopenharmony_ci		struct seg_entry *se = get_seg_entry(sbi, curseg->segno);
481862306a36Sopenharmony_ci		unsigned int blkofs = curseg->next_blkoff;
481962306a36Sopenharmony_ci
482062306a36Sopenharmony_ci		if (f2fs_sb_has_readonly(sbi) &&
482162306a36Sopenharmony_ci			i != CURSEG_HOT_DATA && i != CURSEG_HOT_NODE)
482262306a36Sopenharmony_ci			continue;
482362306a36Sopenharmony_ci
482462306a36Sopenharmony_ci		sanity_check_seg_type(sbi, curseg->seg_type);
482562306a36Sopenharmony_ci
482662306a36Sopenharmony_ci		if (curseg->alloc_type != LFS && curseg->alloc_type != SSR) {
482762306a36Sopenharmony_ci			f2fs_err(sbi,
482862306a36Sopenharmony_ci				 "Current segment has invalid alloc_type:%d",
482962306a36Sopenharmony_ci				 curseg->alloc_type);
483062306a36Sopenharmony_ci			f2fs_handle_error(sbi, ERROR_INVALID_CURSEG);
483162306a36Sopenharmony_ci			return -EFSCORRUPTED;
483262306a36Sopenharmony_ci		}
483362306a36Sopenharmony_ci
483462306a36Sopenharmony_ci		if (f2fs_test_bit(blkofs, se->cur_valid_map))
483562306a36Sopenharmony_ci			goto out;
483662306a36Sopenharmony_ci
483762306a36Sopenharmony_ci		if (curseg->alloc_type == SSR)
483862306a36Sopenharmony_ci			continue;
483962306a36Sopenharmony_ci
484062306a36Sopenharmony_ci		for (blkofs += 1; blkofs < sbi->blocks_per_seg; blkofs++) {
484162306a36Sopenharmony_ci			if (!f2fs_test_bit(blkofs, se->cur_valid_map))
484262306a36Sopenharmony_ci				continue;
484362306a36Sopenharmony_ciout:
484462306a36Sopenharmony_ci			f2fs_err(sbi,
484562306a36Sopenharmony_ci				 "Current segment's next free block offset is inconsistent with bitmap, logtype:%u, segno:%u, type:%u, next_blkoff:%u, blkofs:%u",
484662306a36Sopenharmony_ci				 i, curseg->segno, curseg->alloc_type,
484762306a36Sopenharmony_ci				 curseg->next_blkoff, blkofs);
484862306a36Sopenharmony_ci			f2fs_handle_error(sbi, ERROR_INVALID_CURSEG);
484962306a36Sopenharmony_ci			return -EFSCORRUPTED;
485062306a36Sopenharmony_ci		}
485162306a36Sopenharmony_ci	}
485262306a36Sopenharmony_ci	return 0;
485362306a36Sopenharmony_ci}
485462306a36Sopenharmony_ci
485562306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEV_ZONED
485662306a36Sopenharmony_ci
485762306a36Sopenharmony_cistatic int check_zone_write_pointer(struct f2fs_sb_info *sbi,
485862306a36Sopenharmony_ci				    struct f2fs_dev_info *fdev,
485962306a36Sopenharmony_ci				    struct blk_zone *zone)
486062306a36Sopenharmony_ci{
486162306a36Sopenharmony_ci	unsigned int wp_segno, wp_blkoff, zone_secno, zone_segno, segno;
486262306a36Sopenharmony_ci	block_t zone_block, wp_block, last_valid_block;
486362306a36Sopenharmony_ci	unsigned int log_sectors_per_block = sbi->log_blocksize - SECTOR_SHIFT;
486462306a36Sopenharmony_ci	int i, s, b, ret;
486562306a36Sopenharmony_ci	struct seg_entry *se;
486662306a36Sopenharmony_ci
486762306a36Sopenharmony_ci	if (zone->type != BLK_ZONE_TYPE_SEQWRITE_REQ)
486862306a36Sopenharmony_ci		return 0;
486962306a36Sopenharmony_ci
487062306a36Sopenharmony_ci	wp_block = fdev->start_blk + (zone->wp >> log_sectors_per_block);
487162306a36Sopenharmony_ci	wp_segno = GET_SEGNO(sbi, wp_block);
487262306a36Sopenharmony_ci	wp_blkoff = wp_block - START_BLOCK(sbi, wp_segno);
487362306a36Sopenharmony_ci	zone_block = fdev->start_blk + (zone->start >> log_sectors_per_block);
487462306a36Sopenharmony_ci	zone_segno = GET_SEGNO(sbi, zone_block);
487562306a36Sopenharmony_ci	zone_secno = GET_SEC_FROM_SEG(sbi, zone_segno);
487662306a36Sopenharmony_ci
487762306a36Sopenharmony_ci	if (zone_segno >= MAIN_SEGS(sbi))
487862306a36Sopenharmony_ci		return 0;
487962306a36Sopenharmony_ci
488062306a36Sopenharmony_ci	/*
488162306a36Sopenharmony_ci	 * Skip check of zones cursegs point to, since
488262306a36Sopenharmony_ci	 * fix_curseg_write_pointer() checks them.
488362306a36Sopenharmony_ci	 */
488462306a36Sopenharmony_ci	for (i = 0; i < NO_CHECK_TYPE; i++)
488562306a36Sopenharmony_ci		if (zone_secno == GET_SEC_FROM_SEG(sbi,
488662306a36Sopenharmony_ci						   CURSEG_I(sbi, i)->segno))
488762306a36Sopenharmony_ci			return 0;
488862306a36Sopenharmony_ci
488962306a36Sopenharmony_ci	/*
489062306a36Sopenharmony_ci	 * Get last valid block of the zone.
489162306a36Sopenharmony_ci	 */
489262306a36Sopenharmony_ci	last_valid_block = zone_block - 1;
489362306a36Sopenharmony_ci	for (s = sbi->segs_per_sec - 1; s >= 0; s--) {
489462306a36Sopenharmony_ci		segno = zone_segno + s;
489562306a36Sopenharmony_ci		se = get_seg_entry(sbi, segno);
489662306a36Sopenharmony_ci		for (b = sbi->blocks_per_seg - 1; b >= 0; b--)
489762306a36Sopenharmony_ci			if (f2fs_test_bit(b, se->cur_valid_map)) {
489862306a36Sopenharmony_ci				last_valid_block = START_BLOCK(sbi, segno) + b;
489962306a36Sopenharmony_ci				break;
490062306a36Sopenharmony_ci			}
490162306a36Sopenharmony_ci		if (last_valid_block >= zone_block)
490262306a36Sopenharmony_ci			break;
490362306a36Sopenharmony_ci	}
490462306a36Sopenharmony_ci
490562306a36Sopenharmony_ci	/*
490662306a36Sopenharmony_ci	 * The write pointer matches with the valid blocks or
490762306a36Sopenharmony_ci	 * already points to the end of the zone.
490862306a36Sopenharmony_ci	 */
490962306a36Sopenharmony_ci	if ((last_valid_block + 1 == wp_block) ||
491062306a36Sopenharmony_ci			(zone->wp == zone->start + zone->len))
491162306a36Sopenharmony_ci		return 0;
491262306a36Sopenharmony_ci
491362306a36Sopenharmony_ci	if (last_valid_block + 1 == zone_block) {
491462306a36Sopenharmony_ci		/*
491562306a36Sopenharmony_ci		 * If there is no valid block in the zone and if write pointer
491662306a36Sopenharmony_ci		 * is not at zone start, reset the write pointer.
491762306a36Sopenharmony_ci		 */
491862306a36Sopenharmony_ci		f2fs_notice(sbi,
491962306a36Sopenharmony_ci			    "Zone without valid block has non-zero write "
492062306a36Sopenharmony_ci			    "pointer. Reset the write pointer: wp[0x%x,0x%x]",
492162306a36Sopenharmony_ci			    wp_segno, wp_blkoff);
492262306a36Sopenharmony_ci		ret = __f2fs_issue_discard_zone(sbi, fdev->bdev, zone_block,
492362306a36Sopenharmony_ci					zone->len >> log_sectors_per_block);
492462306a36Sopenharmony_ci		if (ret)
492562306a36Sopenharmony_ci			f2fs_err(sbi, "Discard zone failed: %s (errno=%d)",
492662306a36Sopenharmony_ci				 fdev->path, ret);
492762306a36Sopenharmony_ci
492862306a36Sopenharmony_ci		return ret;
492962306a36Sopenharmony_ci	}
493062306a36Sopenharmony_ci
493162306a36Sopenharmony_ci	/*
493262306a36Sopenharmony_ci	 * If there are valid blocks and the write pointer doesn't
493362306a36Sopenharmony_ci	 * match with them, we need to report the inconsistency and
493462306a36Sopenharmony_ci	 * fill the zone till the end to close the zone. This inconsistency
493562306a36Sopenharmony_ci	 * does not cause write error because the zone will not be selected
493662306a36Sopenharmony_ci	 * for write operation until it get discarded.
493762306a36Sopenharmony_ci	 */
493862306a36Sopenharmony_ci	f2fs_notice(sbi, "Valid blocks are not aligned with write pointer: "
493962306a36Sopenharmony_ci		    "valid block[0x%x,0x%x] wp[0x%x,0x%x]",
494062306a36Sopenharmony_ci		    GET_SEGNO(sbi, last_valid_block),
494162306a36Sopenharmony_ci		    GET_BLKOFF_FROM_SEG0(sbi, last_valid_block),
494262306a36Sopenharmony_ci		    wp_segno, wp_blkoff);
494362306a36Sopenharmony_ci
494462306a36Sopenharmony_ci	ret = blkdev_zone_mgmt(fdev->bdev, REQ_OP_ZONE_FINISH,
494562306a36Sopenharmony_ci				zone->start, zone->len, GFP_NOFS);
494662306a36Sopenharmony_ci	if (ret == -EOPNOTSUPP) {
494762306a36Sopenharmony_ci		ret = blkdev_issue_zeroout(fdev->bdev, zone->wp,
494862306a36Sopenharmony_ci					zone->len - (zone->wp - zone->start),
494962306a36Sopenharmony_ci					GFP_NOFS, 0);
495062306a36Sopenharmony_ci		if (ret)
495162306a36Sopenharmony_ci			f2fs_err(sbi, "Fill up zone failed: %s (errno=%d)",
495262306a36Sopenharmony_ci					fdev->path, ret);
495362306a36Sopenharmony_ci	} else if (ret) {
495462306a36Sopenharmony_ci		f2fs_err(sbi, "Finishing zone failed: %s (errno=%d)",
495562306a36Sopenharmony_ci				fdev->path, ret);
495662306a36Sopenharmony_ci	}
495762306a36Sopenharmony_ci
495862306a36Sopenharmony_ci	return ret;
495962306a36Sopenharmony_ci}
496062306a36Sopenharmony_ci
496162306a36Sopenharmony_cistatic struct f2fs_dev_info *get_target_zoned_dev(struct f2fs_sb_info *sbi,
496262306a36Sopenharmony_ci						  block_t zone_blkaddr)
496362306a36Sopenharmony_ci{
496462306a36Sopenharmony_ci	int i;
496562306a36Sopenharmony_ci
496662306a36Sopenharmony_ci	for (i = 0; i < sbi->s_ndevs; i++) {
496762306a36Sopenharmony_ci		if (!bdev_is_zoned(FDEV(i).bdev))
496862306a36Sopenharmony_ci			continue;
496962306a36Sopenharmony_ci		if (sbi->s_ndevs == 1 || (FDEV(i).start_blk <= zone_blkaddr &&
497062306a36Sopenharmony_ci				zone_blkaddr <= FDEV(i).end_blk))
497162306a36Sopenharmony_ci			return &FDEV(i);
497262306a36Sopenharmony_ci	}
497362306a36Sopenharmony_ci
497462306a36Sopenharmony_ci	return NULL;
497562306a36Sopenharmony_ci}
497662306a36Sopenharmony_ci
497762306a36Sopenharmony_cistatic int report_one_zone_cb(struct blk_zone *zone, unsigned int idx,
497862306a36Sopenharmony_ci			      void *data)
497962306a36Sopenharmony_ci{
498062306a36Sopenharmony_ci	memcpy(data, zone, sizeof(struct blk_zone));
498162306a36Sopenharmony_ci	return 0;
498262306a36Sopenharmony_ci}
498362306a36Sopenharmony_ci
498462306a36Sopenharmony_cistatic int fix_curseg_write_pointer(struct f2fs_sb_info *sbi, int type)
498562306a36Sopenharmony_ci{
498662306a36Sopenharmony_ci	struct curseg_info *cs = CURSEG_I(sbi, type);
498762306a36Sopenharmony_ci	struct f2fs_dev_info *zbd;
498862306a36Sopenharmony_ci	struct blk_zone zone;
498962306a36Sopenharmony_ci	unsigned int cs_section, wp_segno, wp_blkoff, wp_sector_off;
499062306a36Sopenharmony_ci	block_t cs_zone_block, wp_block;
499162306a36Sopenharmony_ci	unsigned int log_sectors_per_block = sbi->log_blocksize - SECTOR_SHIFT;
499262306a36Sopenharmony_ci	sector_t zone_sector;
499362306a36Sopenharmony_ci	int err;
499462306a36Sopenharmony_ci
499562306a36Sopenharmony_ci	cs_section = GET_SEC_FROM_SEG(sbi, cs->segno);
499662306a36Sopenharmony_ci	cs_zone_block = START_BLOCK(sbi, GET_SEG_FROM_SEC(sbi, cs_section));
499762306a36Sopenharmony_ci
499862306a36Sopenharmony_ci	zbd = get_target_zoned_dev(sbi, cs_zone_block);
499962306a36Sopenharmony_ci	if (!zbd)
500062306a36Sopenharmony_ci		return 0;
500162306a36Sopenharmony_ci
500262306a36Sopenharmony_ci	/* report zone for the sector the curseg points to */
500362306a36Sopenharmony_ci	zone_sector = (sector_t)(cs_zone_block - zbd->start_blk)
500462306a36Sopenharmony_ci		<< log_sectors_per_block;
500562306a36Sopenharmony_ci	err = blkdev_report_zones(zbd->bdev, zone_sector, 1,
500662306a36Sopenharmony_ci				  report_one_zone_cb, &zone);
500762306a36Sopenharmony_ci	if (err != 1) {
500862306a36Sopenharmony_ci		f2fs_err(sbi, "Report zone failed: %s errno=(%d)",
500962306a36Sopenharmony_ci			 zbd->path, err);
501062306a36Sopenharmony_ci		return err;
501162306a36Sopenharmony_ci	}
501262306a36Sopenharmony_ci
501362306a36Sopenharmony_ci	if (zone.type != BLK_ZONE_TYPE_SEQWRITE_REQ)
501462306a36Sopenharmony_ci		return 0;
501562306a36Sopenharmony_ci
501662306a36Sopenharmony_ci	wp_block = zbd->start_blk + (zone.wp >> log_sectors_per_block);
501762306a36Sopenharmony_ci	wp_segno = GET_SEGNO(sbi, wp_block);
501862306a36Sopenharmony_ci	wp_blkoff = wp_block - START_BLOCK(sbi, wp_segno);
501962306a36Sopenharmony_ci	wp_sector_off = zone.wp & GENMASK(log_sectors_per_block - 1, 0);
502062306a36Sopenharmony_ci
502162306a36Sopenharmony_ci	if (cs->segno == wp_segno && cs->next_blkoff == wp_blkoff &&
502262306a36Sopenharmony_ci		wp_sector_off == 0)
502362306a36Sopenharmony_ci		return 0;
502462306a36Sopenharmony_ci
502562306a36Sopenharmony_ci	f2fs_notice(sbi, "Unaligned curseg[%d] with write pointer: "
502662306a36Sopenharmony_ci		    "curseg[0x%x,0x%x] wp[0x%x,0x%x]",
502762306a36Sopenharmony_ci		    type, cs->segno, cs->next_blkoff, wp_segno, wp_blkoff);
502862306a36Sopenharmony_ci
502962306a36Sopenharmony_ci	f2fs_notice(sbi, "Assign new section to curseg[%d]: "
503062306a36Sopenharmony_ci		    "curseg[0x%x,0x%x]", type, cs->segno, cs->next_blkoff);
503162306a36Sopenharmony_ci
503262306a36Sopenharmony_ci	f2fs_allocate_new_section(sbi, type, true);
503362306a36Sopenharmony_ci
503462306a36Sopenharmony_ci	/* check consistency of the zone curseg pointed to */
503562306a36Sopenharmony_ci	if (check_zone_write_pointer(sbi, zbd, &zone))
503662306a36Sopenharmony_ci		return -EIO;
503762306a36Sopenharmony_ci
503862306a36Sopenharmony_ci	/* check newly assigned zone */
503962306a36Sopenharmony_ci	cs_section = GET_SEC_FROM_SEG(sbi, cs->segno);
504062306a36Sopenharmony_ci	cs_zone_block = START_BLOCK(sbi, GET_SEG_FROM_SEC(sbi, cs_section));
504162306a36Sopenharmony_ci
504262306a36Sopenharmony_ci	zbd = get_target_zoned_dev(sbi, cs_zone_block);
504362306a36Sopenharmony_ci	if (!zbd)
504462306a36Sopenharmony_ci		return 0;
504562306a36Sopenharmony_ci
504662306a36Sopenharmony_ci	zone_sector = (sector_t)(cs_zone_block - zbd->start_blk)
504762306a36Sopenharmony_ci		<< log_sectors_per_block;
504862306a36Sopenharmony_ci	err = blkdev_report_zones(zbd->bdev, zone_sector, 1,
504962306a36Sopenharmony_ci				  report_one_zone_cb, &zone);
505062306a36Sopenharmony_ci	if (err != 1) {
505162306a36Sopenharmony_ci		f2fs_err(sbi, "Report zone failed: %s errno=(%d)",
505262306a36Sopenharmony_ci			 zbd->path, err);
505362306a36Sopenharmony_ci		return err;
505462306a36Sopenharmony_ci	}
505562306a36Sopenharmony_ci
505662306a36Sopenharmony_ci	if (zone.type != BLK_ZONE_TYPE_SEQWRITE_REQ)
505762306a36Sopenharmony_ci		return 0;
505862306a36Sopenharmony_ci
505962306a36Sopenharmony_ci	if (zone.wp != zone.start) {
506062306a36Sopenharmony_ci		f2fs_notice(sbi,
506162306a36Sopenharmony_ci			    "New zone for curseg[%d] is not yet discarded. "
506262306a36Sopenharmony_ci			    "Reset the zone: curseg[0x%x,0x%x]",
506362306a36Sopenharmony_ci			    type, cs->segno, cs->next_blkoff);
506462306a36Sopenharmony_ci		err = __f2fs_issue_discard_zone(sbi, zbd->bdev,	cs_zone_block,
506562306a36Sopenharmony_ci					zone.len >> log_sectors_per_block);
506662306a36Sopenharmony_ci		if (err) {
506762306a36Sopenharmony_ci			f2fs_err(sbi, "Discard zone failed: %s (errno=%d)",
506862306a36Sopenharmony_ci				 zbd->path, err);
506962306a36Sopenharmony_ci			return err;
507062306a36Sopenharmony_ci		}
507162306a36Sopenharmony_ci	}
507262306a36Sopenharmony_ci
507362306a36Sopenharmony_ci	return 0;
507462306a36Sopenharmony_ci}
507562306a36Sopenharmony_ci
507662306a36Sopenharmony_ciint f2fs_fix_curseg_write_pointer(struct f2fs_sb_info *sbi)
507762306a36Sopenharmony_ci{
507862306a36Sopenharmony_ci	int i, ret;
507962306a36Sopenharmony_ci
508062306a36Sopenharmony_ci	for (i = 0; i < NR_PERSISTENT_LOG; i++) {
508162306a36Sopenharmony_ci		ret = fix_curseg_write_pointer(sbi, i);
508262306a36Sopenharmony_ci		if (ret)
508362306a36Sopenharmony_ci			return ret;
508462306a36Sopenharmony_ci	}
508562306a36Sopenharmony_ci
508662306a36Sopenharmony_ci	return 0;
508762306a36Sopenharmony_ci}
508862306a36Sopenharmony_ci
508962306a36Sopenharmony_cistruct check_zone_write_pointer_args {
509062306a36Sopenharmony_ci	struct f2fs_sb_info *sbi;
509162306a36Sopenharmony_ci	struct f2fs_dev_info *fdev;
509262306a36Sopenharmony_ci};
509362306a36Sopenharmony_ci
509462306a36Sopenharmony_cistatic int check_zone_write_pointer_cb(struct blk_zone *zone, unsigned int idx,
509562306a36Sopenharmony_ci				      void *data)
509662306a36Sopenharmony_ci{
509762306a36Sopenharmony_ci	struct check_zone_write_pointer_args *args;
509862306a36Sopenharmony_ci
509962306a36Sopenharmony_ci	args = (struct check_zone_write_pointer_args *)data;
510062306a36Sopenharmony_ci
510162306a36Sopenharmony_ci	return check_zone_write_pointer(args->sbi, args->fdev, zone);
510262306a36Sopenharmony_ci}
510362306a36Sopenharmony_ci
510462306a36Sopenharmony_ciint f2fs_check_write_pointer(struct f2fs_sb_info *sbi)
510562306a36Sopenharmony_ci{
510662306a36Sopenharmony_ci	int i, ret;
510762306a36Sopenharmony_ci	struct check_zone_write_pointer_args args;
510862306a36Sopenharmony_ci
510962306a36Sopenharmony_ci	for (i = 0; i < sbi->s_ndevs; i++) {
511062306a36Sopenharmony_ci		if (!bdev_is_zoned(FDEV(i).bdev))
511162306a36Sopenharmony_ci			continue;
511262306a36Sopenharmony_ci
511362306a36Sopenharmony_ci		args.sbi = sbi;
511462306a36Sopenharmony_ci		args.fdev = &FDEV(i);
511562306a36Sopenharmony_ci		ret = blkdev_report_zones(FDEV(i).bdev, 0, BLK_ALL_ZONES,
511662306a36Sopenharmony_ci					  check_zone_write_pointer_cb, &args);
511762306a36Sopenharmony_ci		if (ret < 0)
511862306a36Sopenharmony_ci			return ret;
511962306a36Sopenharmony_ci	}
512062306a36Sopenharmony_ci
512162306a36Sopenharmony_ci	return 0;
512262306a36Sopenharmony_ci}
512362306a36Sopenharmony_ci
512462306a36Sopenharmony_ci/*
512562306a36Sopenharmony_ci * Return the number of usable blocks in a segment. The number of blocks
512662306a36Sopenharmony_ci * returned is always equal to the number of blocks in a segment for
512762306a36Sopenharmony_ci * segments fully contained within a sequential zone capacity or a
512862306a36Sopenharmony_ci * conventional zone. For segments partially contained in a sequential
512962306a36Sopenharmony_ci * zone capacity, the number of usable blocks up to the zone capacity
513062306a36Sopenharmony_ci * is returned. 0 is returned in all other cases.
513162306a36Sopenharmony_ci */
513262306a36Sopenharmony_cistatic inline unsigned int f2fs_usable_zone_blks_in_seg(
513362306a36Sopenharmony_ci			struct f2fs_sb_info *sbi, unsigned int segno)
513462306a36Sopenharmony_ci{
513562306a36Sopenharmony_ci	block_t seg_start, sec_start_blkaddr, sec_cap_blkaddr;
513662306a36Sopenharmony_ci	unsigned int secno;
513762306a36Sopenharmony_ci
513862306a36Sopenharmony_ci	if (!sbi->unusable_blocks_per_sec)
513962306a36Sopenharmony_ci		return sbi->blocks_per_seg;
514062306a36Sopenharmony_ci
514162306a36Sopenharmony_ci	secno = GET_SEC_FROM_SEG(sbi, segno);
514262306a36Sopenharmony_ci	seg_start = START_BLOCK(sbi, segno);
514362306a36Sopenharmony_ci	sec_start_blkaddr = START_BLOCK(sbi, GET_SEG_FROM_SEC(sbi, secno));
514462306a36Sopenharmony_ci	sec_cap_blkaddr = sec_start_blkaddr + CAP_BLKS_PER_SEC(sbi);
514562306a36Sopenharmony_ci
514662306a36Sopenharmony_ci	/*
514762306a36Sopenharmony_ci	 * If segment starts before zone capacity and spans beyond
514862306a36Sopenharmony_ci	 * zone capacity, then usable blocks are from seg start to
514962306a36Sopenharmony_ci	 * zone capacity. If the segment starts after the zone capacity,
515062306a36Sopenharmony_ci	 * then there are no usable blocks.
515162306a36Sopenharmony_ci	 */
515262306a36Sopenharmony_ci	if (seg_start >= sec_cap_blkaddr)
515362306a36Sopenharmony_ci		return 0;
515462306a36Sopenharmony_ci	if (seg_start + sbi->blocks_per_seg > sec_cap_blkaddr)
515562306a36Sopenharmony_ci		return sec_cap_blkaddr - seg_start;
515662306a36Sopenharmony_ci
515762306a36Sopenharmony_ci	return sbi->blocks_per_seg;
515862306a36Sopenharmony_ci}
515962306a36Sopenharmony_ci#else
516062306a36Sopenharmony_ciint f2fs_fix_curseg_write_pointer(struct f2fs_sb_info *sbi)
516162306a36Sopenharmony_ci{
516262306a36Sopenharmony_ci	return 0;
516362306a36Sopenharmony_ci}
516462306a36Sopenharmony_ci
516562306a36Sopenharmony_ciint f2fs_check_write_pointer(struct f2fs_sb_info *sbi)
516662306a36Sopenharmony_ci{
516762306a36Sopenharmony_ci	return 0;
516862306a36Sopenharmony_ci}
516962306a36Sopenharmony_ci
517062306a36Sopenharmony_cistatic inline unsigned int f2fs_usable_zone_blks_in_seg(struct f2fs_sb_info *sbi,
517162306a36Sopenharmony_ci							unsigned int segno)
517262306a36Sopenharmony_ci{
517362306a36Sopenharmony_ci	return 0;
517462306a36Sopenharmony_ci}
517562306a36Sopenharmony_ci
517662306a36Sopenharmony_ci#endif
517762306a36Sopenharmony_ciunsigned int f2fs_usable_blks_in_seg(struct f2fs_sb_info *sbi,
517862306a36Sopenharmony_ci					unsigned int segno)
517962306a36Sopenharmony_ci{
518062306a36Sopenharmony_ci	if (f2fs_sb_has_blkzoned(sbi))
518162306a36Sopenharmony_ci		return f2fs_usable_zone_blks_in_seg(sbi, segno);
518262306a36Sopenharmony_ci
518362306a36Sopenharmony_ci	return sbi->blocks_per_seg;
518462306a36Sopenharmony_ci}
518562306a36Sopenharmony_ci
518662306a36Sopenharmony_ciunsigned int f2fs_usable_segs_in_sec(struct f2fs_sb_info *sbi,
518762306a36Sopenharmony_ci					unsigned int segno)
518862306a36Sopenharmony_ci{
518962306a36Sopenharmony_ci	if (f2fs_sb_has_blkzoned(sbi))
519062306a36Sopenharmony_ci		return CAP_SEGS_PER_SEC(sbi);
519162306a36Sopenharmony_ci
519262306a36Sopenharmony_ci	return sbi->segs_per_sec;
519362306a36Sopenharmony_ci}
519462306a36Sopenharmony_ci
519562306a36Sopenharmony_ci/*
519662306a36Sopenharmony_ci * Update min, max modified time for cost-benefit GC algorithm
519762306a36Sopenharmony_ci */
519862306a36Sopenharmony_cistatic void init_min_max_mtime(struct f2fs_sb_info *sbi)
519962306a36Sopenharmony_ci{
520062306a36Sopenharmony_ci	struct sit_info *sit_i = SIT_I(sbi);
520162306a36Sopenharmony_ci	unsigned int segno;
520262306a36Sopenharmony_ci
520362306a36Sopenharmony_ci	down_write(&sit_i->sentry_lock);
520462306a36Sopenharmony_ci
520562306a36Sopenharmony_ci	sit_i->min_mtime = ULLONG_MAX;
520662306a36Sopenharmony_ci
520762306a36Sopenharmony_ci	for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) {
520862306a36Sopenharmony_ci		unsigned int i;
520962306a36Sopenharmony_ci		unsigned long long mtime = 0;
521062306a36Sopenharmony_ci
521162306a36Sopenharmony_ci		for (i = 0; i < sbi->segs_per_sec; i++)
521262306a36Sopenharmony_ci			mtime += get_seg_entry(sbi, segno + i)->mtime;
521362306a36Sopenharmony_ci
521462306a36Sopenharmony_ci		mtime = div_u64(mtime, sbi->segs_per_sec);
521562306a36Sopenharmony_ci
521662306a36Sopenharmony_ci		if (sit_i->min_mtime > mtime)
521762306a36Sopenharmony_ci			sit_i->min_mtime = mtime;
521862306a36Sopenharmony_ci	}
521962306a36Sopenharmony_ci	sit_i->max_mtime = get_mtime(sbi, false);
522062306a36Sopenharmony_ci	sit_i->dirty_max_mtime = 0;
522162306a36Sopenharmony_ci	up_write(&sit_i->sentry_lock);
522262306a36Sopenharmony_ci}
522362306a36Sopenharmony_ci
522462306a36Sopenharmony_ciint f2fs_build_segment_manager(struct f2fs_sb_info *sbi)
522562306a36Sopenharmony_ci{
522662306a36Sopenharmony_ci	struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
522762306a36Sopenharmony_ci	struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
522862306a36Sopenharmony_ci	struct f2fs_sm_info *sm_info;
522962306a36Sopenharmony_ci	int err;
523062306a36Sopenharmony_ci
523162306a36Sopenharmony_ci	sm_info = f2fs_kzalloc(sbi, sizeof(struct f2fs_sm_info), GFP_KERNEL);
523262306a36Sopenharmony_ci	if (!sm_info)
523362306a36Sopenharmony_ci		return -ENOMEM;
523462306a36Sopenharmony_ci
523562306a36Sopenharmony_ci	/* init sm info */
523662306a36Sopenharmony_ci	sbi->sm_info = sm_info;
523762306a36Sopenharmony_ci	sm_info->seg0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr);
523862306a36Sopenharmony_ci	sm_info->main_blkaddr = le32_to_cpu(raw_super->main_blkaddr);
523962306a36Sopenharmony_ci	sm_info->segment_count = le32_to_cpu(raw_super->segment_count);
524062306a36Sopenharmony_ci	sm_info->reserved_segments = le32_to_cpu(ckpt->rsvd_segment_count);
524162306a36Sopenharmony_ci	sm_info->ovp_segments = le32_to_cpu(ckpt->overprov_segment_count);
524262306a36Sopenharmony_ci	sm_info->main_segments = le32_to_cpu(raw_super->segment_count_main);
524362306a36Sopenharmony_ci	sm_info->ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr);
524462306a36Sopenharmony_ci	sm_info->rec_prefree_segments = sm_info->main_segments *
524562306a36Sopenharmony_ci					DEF_RECLAIM_PREFREE_SEGMENTS / 100;
524662306a36Sopenharmony_ci	if (sm_info->rec_prefree_segments > DEF_MAX_RECLAIM_PREFREE_SEGMENTS)
524762306a36Sopenharmony_ci		sm_info->rec_prefree_segments = DEF_MAX_RECLAIM_PREFREE_SEGMENTS;
524862306a36Sopenharmony_ci
524962306a36Sopenharmony_ci	if (!f2fs_lfs_mode(sbi))
525062306a36Sopenharmony_ci		sm_info->ipu_policy = BIT(F2FS_IPU_FSYNC);
525162306a36Sopenharmony_ci	sm_info->min_ipu_util = DEF_MIN_IPU_UTIL;
525262306a36Sopenharmony_ci	sm_info->min_fsync_blocks = DEF_MIN_FSYNC_BLOCKS;
525362306a36Sopenharmony_ci	sm_info->min_seq_blocks = sbi->blocks_per_seg;
525462306a36Sopenharmony_ci	sm_info->min_hot_blocks = DEF_MIN_HOT_BLOCKS;
525562306a36Sopenharmony_ci	sm_info->min_ssr_sections = reserved_sections(sbi);
525662306a36Sopenharmony_ci
525762306a36Sopenharmony_ci	INIT_LIST_HEAD(&sm_info->sit_entry_set);
525862306a36Sopenharmony_ci
525962306a36Sopenharmony_ci	init_f2fs_rwsem(&sm_info->curseg_lock);
526062306a36Sopenharmony_ci
526162306a36Sopenharmony_ci	err = f2fs_create_flush_cmd_control(sbi);
526262306a36Sopenharmony_ci	if (err)
526362306a36Sopenharmony_ci		return err;
526462306a36Sopenharmony_ci
526562306a36Sopenharmony_ci	err = create_discard_cmd_control(sbi);
526662306a36Sopenharmony_ci	if (err)
526762306a36Sopenharmony_ci		return err;
526862306a36Sopenharmony_ci
526962306a36Sopenharmony_ci	err = build_sit_info(sbi);
527062306a36Sopenharmony_ci	if (err)
527162306a36Sopenharmony_ci		return err;
527262306a36Sopenharmony_ci	err = build_free_segmap(sbi);
527362306a36Sopenharmony_ci	if (err)
527462306a36Sopenharmony_ci		return err;
527562306a36Sopenharmony_ci	err = build_curseg(sbi);
527662306a36Sopenharmony_ci	if (err)
527762306a36Sopenharmony_ci		return err;
527862306a36Sopenharmony_ci
527962306a36Sopenharmony_ci	/* reinit free segmap based on SIT */
528062306a36Sopenharmony_ci	err = build_sit_entries(sbi);
528162306a36Sopenharmony_ci	if (err)
528262306a36Sopenharmony_ci		return err;
528362306a36Sopenharmony_ci
528462306a36Sopenharmony_ci	init_free_segmap(sbi);
528562306a36Sopenharmony_ci	err = build_dirty_segmap(sbi);
528662306a36Sopenharmony_ci	if (err)
528762306a36Sopenharmony_ci		return err;
528862306a36Sopenharmony_ci
528962306a36Sopenharmony_ci	err = sanity_check_curseg(sbi);
529062306a36Sopenharmony_ci	if (err)
529162306a36Sopenharmony_ci		return err;
529262306a36Sopenharmony_ci
529362306a36Sopenharmony_ci	init_min_max_mtime(sbi);
529462306a36Sopenharmony_ci	return 0;
529562306a36Sopenharmony_ci}
529662306a36Sopenharmony_ci
529762306a36Sopenharmony_cistatic void discard_dirty_segmap(struct f2fs_sb_info *sbi,
529862306a36Sopenharmony_ci		enum dirty_type dirty_type)
529962306a36Sopenharmony_ci{
530062306a36Sopenharmony_ci	struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
530162306a36Sopenharmony_ci
530262306a36Sopenharmony_ci	mutex_lock(&dirty_i->seglist_lock);
530362306a36Sopenharmony_ci	kvfree(dirty_i->dirty_segmap[dirty_type]);
530462306a36Sopenharmony_ci	dirty_i->nr_dirty[dirty_type] = 0;
530562306a36Sopenharmony_ci	mutex_unlock(&dirty_i->seglist_lock);
530662306a36Sopenharmony_ci}
530762306a36Sopenharmony_ci
530862306a36Sopenharmony_cistatic void destroy_victim_secmap(struct f2fs_sb_info *sbi)
530962306a36Sopenharmony_ci{
531062306a36Sopenharmony_ci	struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
531162306a36Sopenharmony_ci
531262306a36Sopenharmony_ci	kvfree(dirty_i->pinned_secmap);
531362306a36Sopenharmony_ci	kvfree(dirty_i->victim_secmap);
531462306a36Sopenharmony_ci}
531562306a36Sopenharmony_ci
531662306a36Sopenharmony_cistatic void destroy_dirty_segmap(struct f2fs_sb_info *sbi)
531762306a36Sopenharmony_ci{
531862306a36Sopenharmony_ci	struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
531962306a36Sopenharmony_ci	int i;
532062306a36Sopenharmony_ci
532162306a36Sopenharmony_ci	if (!dirty_i)
532262306a36Sopenharmony_ci		return;
532362306a36Sopenharmony_ci
532462306a36Sopenharmony_ci	/* discard pre-free/dirty segments list */
532562306a36Sopenharmony_ci	for (i = 0; i < NR_DIRTY_TYPE; i++)
532662306a36Sopenharmony_ci		discard_dirty_segmap(sbi, i);
532762306a36Sopenharmony_ci
532862306a36Sopenharmony_ci	if (__is_large_section(sbi)) {
532962306a36Sopenharmony_ci		mutex_lock(&dirty_i->seglist_lock);
533062306a36Sopenharmony_ci		kvfree(dirty_i->dirty_secmap);
533162306a36Sopenharmony_ci		mutex_unlock(&dirty_i->seglist_lock);
533262306a36Sopenharmony_ci	}
533362306a36Sopenharmony_ci
533462306a36Sopenharmony_ci	destroy_victim_secmap(sbi);
533562306a36Sopenharmony_ci	SM_I(sbi)->dirty_info = NULL;
533662306a36Sopenharmony_ci	kfree(dirty_i);
533762306a36Sopenharmony_ci}
533862306a36Sopenharmony_ci
533962306a36Sopenharmony_cistatic void destroy_curseg(struct f2fs_sb_info *sbi)
534062306a36Sopenharmony_ci{
534162306a36Sopenharmony_ci	struct curseg_info *array = SM_I(sbi)->curseg_array;
534262306a36Sopenharmony_ci	int i;
534362306a36Sopenharmony_ci
534462306a36Sopenharmony_ci	if (!array)
534562306a36Sopenharmony_ci		return;
534662306a36Sopenharmony_ci	SM_I(sbi)->curseg_array = NULL;
534762306a36Sopenharmony_ci	for (i = 0; i < NR_CURSEG_TYPE; i++) {
534862306a36Sopenharmony_ci		kfree(array[i].sum_blk);
534962306a36Sopenharmony_ci		kfree(array[i].journal);
535062306a36Sopenharmony_ci	}
535162306a36Sopenharmony_ci	kfree(array);
535262306a36Sopenharmony_ci}
535362306a36Sopenharmony_ci
535462306a36Sopenharmony_cistatic void destroy_free_segmap(struct f2fs_sb_info *sbi)
535562306a36Sopenharmony_ci{
535662306a36Sopenharmony_ci	struct free_segmap_info *free_i = SM_I(sbi)->free_info;
535762306a36Sopenharmony_ci
535862306a36Sopenharmony_ci	if (!free_i)
535962306a36Sopenharmony_ci		return;
536062306a36Sopenharmony_ci	SM_I(sbi)->free_info = NULL;
536162306a36Sopenharmony_ci	kvfree(free_i->free_segmap);
536262306a36Sopenharmony_ci	kvfree(free_i->free_secmap);
536362306a36Sopenharmony_ci	kfree(free_i);
536462306a36Sopenharmony_ci}
536562306a36Sopenharmony_ci
536662306a36Sopenharmony_cistatic void destroy_sit_info(struct f2fs_sb_info *sbi)
536762306a36Sopenharmony_ci{
536862306a36Sopenharmony_ci	struct sit_info *sit_i = SIT_I(sbi);
536962306a36Sopenharmony_ci
537062306a36Sopenharmony_ci	if (!sit_i)
537162306a36Sopenharmony_ci		return;
537262306a36Sopenharmony_ci
537362306a36Sopenharmony_ci	if (sit_i->sentries)
537462306a36Sopenharmony_ci		kvfree(sit_i->bitmap);
537562306a36Sopenharmony_ci	kfree(sit_i->tmp_map);
537662306a36Sopenharmony_ci
537762306a36Sopenharmony_ci	kvfree(sit_i->sentries);
537862306a36Sopenharmony_ci	kvfree(sit_i->sec_entries);
537962306a36Sopenharmony_ci	kvfree(sit_i->dirty_sentries_bitmap);
538062306a36Sopenharmony_ci
538162306a36Sopenharmony_ci	SM_I(sbi)->sit_info = NULL;
538262306a36Sopenharmony_ci	kvfree(sit_i->sit_bitmap);
538362306a36Sopenharmony_ci#ifdef CONFIG_F2FS_CHECK_FS
538462306a36Sopenharmony_ci	kvfree(sit_i->sit_bitmap_mir);
538562306a36Sopenharmony_ci	kvfree(sit_i->invalid_segmap);
538662306a36Sopenharmony_ci#endif
538762306a36Sopenharmony_ci	kfree(sit_i);
538862306a36Sopenharmony_ci}
538962306a36Sopenharmony_ci
539062306a36Sopenharmony_civoid f2fs_destroy_segment_manager(struct f2fs_sb_info *sbi)
539162306a36Sopenharmony_ci{
539262306a36Sopenharmony_ci	struct f2fs_sm_info *sm_info = SM_I(sbi);
539362306a36Sopenharmony_ci
539462306a36Sopenharmony_ci	if (!sm_info)
539562306a36Sopenharmony_ci		return;
539662306a36Sopenharmony_ci	f2fs_destroy_flush_cmd_control(sbi, true);
539762306a36Sopenharmony_ci	destroy_discard_cmd_control(sbi);
539862306a36Sopenharmony_ci	destroy_dirty_segmap(sbi);
539962306a36Sopenharmony_ci	destroy_curseg(sbi);
540062306a36Sopenharmony_ci	destroy_free_segmap(sbi);
540162306a36Sopenharmony_ci	destroy_sit_info(sbi);
540262306a36Sopenharmony_ci	sbi->sm_info = NULL;
540362306a36Sopenharmony_ci	kfree(sm_info);
540462306a36Sopenharmony_ci}
540562306a36Sopenharmony_ci
540662306a36Sopenharmony_ciint __init f2fs_create_segment_manager_caches(void)
540762306a36Sopenharmony_ci{
540862306a36Sopenharmony_ci	discard_entry_slab = f2fs_kmem_cache_create("f2fs_discard_entry",
540962306a36Sopenharmony_ci			sizeof(struct discard_entry));
541062306a36Sopenharmony_ci	if (!discard_entry_slab)
541162306a36Sopenharmony_ci		goto fail;
541262306a36Sopenharmony_ci
541362306a36Sopenharmony_ci	discard_cmd_slab = f2fs_kmem_cache_create("f2fs_discard_cmd",
541462306a36Sopenharmony_ci			sizeof(struct discard_cmd));
541562306a36Sopenharmony_ci	if (!discard_cmd_slab)
541662306a36Sopenharmony_ci		goto destroy_discard_entry;
541762306a36Sopenharmony_ci
541862306a36Sopenharmony_ci	sit_entry_set_slab = f2fs_kmem_cache_create("f2fs_sit_entry_set",
541962306a36Sopenharmony_ci			sizeof(struct sit_entry_set));
542062306a36Sopenharmony_ci	if (!sit_entry_set_slab)
542162306a36Sopenharmony_ci		goto destroy_discard_cmd;
542262306a36Sopenharmony_ci
542362306a36Sopenharmony_ci	revoke_entry_slab = f2fs_kmem_cache_create("f2fs_revoke_entry",
542462306a36Sopenharmony_ci			sizeof(struct revoke_entry));
542562306a36Sopenharmony_ci	if (!revoke_entry_slab)
542662306a36Sopenharmony_ci		goto destroy_sit_entry_set;
542762306a36Sopenharmony_ci	return 0;
542862306a36Sopenharmony_ci
542962306a36Sopenharmony_cidestroy_sit_entry_set:
543062306a36Sopenharmony_ci	kmem_cache_destroy(sit_entry_set_slab);
543162306a36Sopenharmony_cidestroy_discard_cmd:
543262306a36Sopenharmony_ci	kmem_cache_destroy(discard_cmd_slab);
543362306a36Sopenharmony_cidestroy_discard_entry:
543462306a36Sopenharmony_ci	kmem_cache_destroy(discard_entry_slab);
543562306a36Sopenharmony_cifail:
543662306a36Sopenharmony_ci	return -ENOMEM;
543762306a36Sopenharmony_ci}
543862306a36Sopenharmony_ci
543962306a36Sopenharmony_civoid f2fs_destroy_segment_manager_caches(void)
544062306a36Sopenharmony_ci{
544162306a36Sopenharmony_ci	kmem_cache_destroy(sit_entry_set_slab);
544262306a36Sopenharmony_ci	kmem_cache_destroy(discard_cmd_slab);
544362306a36Sopenharmony_ci	kmem_cache_destroy(discard_entry_slab);
544462306a36Sopenharmony_ci	kmem_cache_destroy(revoke_entry_slab);
544562306a36Sopenharmony_ci}
5446