From: Chao Yu via Linux-f2fs-devel <linux-f2fs-devel@lists.sourceforge.net>
To: Yongpeng Yang <yangyongpeng.storage@gmail.com>,
Jaegeuk Kim <jaegeuk@kernel.org>
Cc: Yongpeng Yang <yangyongpeng@xiaomi.com>,
Yongpeng Yang <monty_pavel@sina.com>,
linux-f2fs-devel@lists.sourceforge.net
Subject: Re: [f2fs-dev] [PATCH RESEND 4/5] f2fs: add extent_access_mode to track extent cache access patterns
Date: Mon, 15 Jun 2026 20:05:45 +0800 [thread overview]
Message-ID: <b2560939-82ef-4d1b-82fd-fa90388c3316@kernel.org> (raw)
In-Reply-To: <20260612115839.2065903-5-yangyongpeng.storage@gmail.com>
On 6/12/26 19:58, Yongpeng Yang wrote:
> From: Yongpeng Yang <yangyongpeng@xiaomi.com>
>
> Introduce enum extent_access_mode to classify how each extent node
> is accessed or created (READ, WRITE, PRECACHE, TRUNCATE, LARGEST).
> This metadata optimize LRU eviction decisions:
Can you please give some numbers for this change?
>
> 1. Extents only accessed as the largest extent (never read-hit) are
> deprioritized in the LRU list since reads can still use the largest
> extent directly.
>
> 2. Sparse single-block write extents that were never merged are moved
> to the head of LRU for earlier reclaim, preserving extents with
> better continuity and higher read-hit probability.
>
> Signed-off-by: Yongpeng Yang <yangyongpeng@xiaomi.com>
> ---
> fs/f2fs/data.c | 4 ++--
> fs/f2fs/extent_cache.c | 29 ++++++++++++++++++++++++++++-
> fs/f2fs/f2fs.h | 14 +++++++++++++-
> fs/f2fs/file.c | 6 ++++--
> 4 files changed, 47 insertions(+), 6 deletions(-)
>
> diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
> index 9c6440a7db0e..2d38135005fe 100644
> --- a/fs/f2fs/data.c
> +++ b/fs/f2fs/data.c
> @@ -1873,7 +1873,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int flag)
>
> f2fs_update_read_extent_cache_range(&dn,
> start_pgofs, map->m_pblk + ofs,
> - map->m_len - ofs);
> + map->m_len - ofs, EX_ACCESS_PRECACHE);
> }
> }
>
> @@ -1919,7 +1919,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int flag)
> if (map->m_len > ofs)
> f2fs_update_read_extent_cache_range(&dn,
> start_pgofs, map->m_pblk + ofs,
> - map->m_len - ofs);
> + map->m_len - ofs, EX_ACCESS_PRECACHE);
> }
> if (map->m_next_extent)
> *map->m_next_extent = is_hole ? pgofs + 1 : pgofs;
> diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c
> index 82d84c4e98b2..e141ffb64e5f 100644
> --- a/fs/f2fs/extent_cache.c
> +++ b/fs/f2fs/extent_cache.c
> @@ -142,6 +142,7 @@ static void __try_update_largest_extent(struct extent_tree *et,
> if (en->ei.len <= et->largest.len)
> return;
>
> + en->ei.last_access_mode = EX_ACCESS_LARGEST;
> et->largest = en->ei;
> et->largest_updated = true;
> }
> @@ -518,6 +519,7 @@ static bool __lookup_extent_tree(struct inode *inode, pgoff_t pgofs,
> stat_inc_rbtree_node_hit(sbi, type);
>
> *ei = en->ei;
> + en->ei.last_access_mode = EX_ACCESS_READ;
> spin_lock(&eti->extent_lock);
> if (!list_empty(&en->list)) {
> list_move_tail(&en->list, &eti->extent_list);
> @@ -624,6 +626,21 @@ static struct extent_node *__insert_extent_tree(struct f2fs_sb_info *sbi,
>
> /* update in global extent list */
> spin_lock(&eti->extent_lock);
> + /*
> + * 1. For the largest extent, if subsequent writes are not merged into
> + * it, the write path will most likely not use the largest extent_node,
> + * while read requests can still access the mapping through the largest
> + * extent.
> + *
> + * 2. For sparse writes, if the extent length is 1 and no extent merging
> + * occurs, this extent should be reclaimed with higher priority to avoid
> + * evicting extents with better continuity and higher read-hit.
> + */
> + if (et->type == EX_READ && et->cached_en &&
> + (et->cached_en->ei.last_access_mode == EX_ACCESS_LARGEST ||
> + (et->cached_en->ei.len == 1 &&
> + et->cached_en->ei.last_access_mode == EX_ACCESS_WRITE)))
> + list_move(&et->cached_en->list, &eti->extent_list);
> list_add_tail(&en->list, &eti->extent_list);
> et->cached_en = en;
> spin_unlock(&eti->extent_lock);
> @@ -747,6 +764,8 @@ static void __update_extent_tree_range(struct inode *inode,
> if (fofs > dei.fofs && (type != EX_READ ||
> fofs - dei.fofs >= F2FS_MIN_EXTENT_LEN)) {
> en->ei.len = fofs - en->ei.fofs;
> + if (type == EX_READ)
> + en->ei.last_access_mode = EX_ACCESS_TRUNCATE;
> prev_en = en;
> parts = 1;
> }
> @@ -761,6 +780,8 @@ static void __update_extent_tree_range(struct inode *inode,
> end - dei.fofs + dei.blk, false,
> dei.age, dei.last_blocks,
> type);
> + if (type == EX_READ)
> + ei.last_access_mode = EX_ACCESS_TRUNCATE;
> en1 = __insert_extent_tree(sbi, et, &ei,
> NULL, NULL, true);
> next_en = en1;
> @@ -770,6 +791,8 @@ static void __update_extent_tree_range(struct inode *inode,
> en->ei.blk + (end - dei.fofs), true,
> dei.age, dei.last_blocks,
> type);
> + if (type == EX_READ)
> + en->ei.last_access_mode = EX_ACCESS_TRUNCATE;
> next_en = en;
> }
> parts++;
> @@ -808,6 +831,7 @@ static void __update_extent_tree_range(struct inode *inode,
> if (tei->blk) {
> __set_extent_info(&ei, fofs, len, tei->blk, false,
> 0, 0, EX_READ);
> + ei.last_access_mode = tei->last_access_mode;
> if (!__try_merge_extent_node(sbi, et, &ei, prev_en, next_en))
> __insert_extent_tree(sbi, et, &ei,
> insert_p, insert_parent, leftmost);
> @@ -978,6 +1002,7 @@ static void __update_extent_cache(struct dnode_of_data *dn, enum extent_type typ
> ei.blk = NULL_ADDR;
> else
> ei.blk = dn->data_blkaddr;
> + ei.last_access_mode = EX_ACCESS_WRITE;
> } else if (type == EX_BLOCK_AGE) {
> if (__get_new_block_age(dn->inode, &ei, dn->data_blkaddr))
> return;
> @@ -1091,12 +1116,14 @@ void f2fs_update_read_extent_cache(struct dnode_of_data *dn)
> }
>
> void f2fs_update_read_extent_cache_range(struct dnode_of_data *dn,
> - pgoff_t fofs, block_t blkaddr, unsigned int len)
> + pgoff_t fofs, block_t blkaddr, unsigned int len,
> + enum extent_access_mode access_mode)
> {
> struct extent_info ei = {
> .fofs = fofs,
> .len = len,
> .blk = blkaddr,
> + .last_access_mode = access_mode,
> };
>
> if (!__may_extent_tree(dn->inode, EX_READ))
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index fffb516b78f4..1588b64d04a3 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -763,6 +763,15 @@ enum extent_type {
> NR_EXTENT_CACHES,
> };
>
> +/* extent acces mode for cache hit or extent add */
> +enum extent_access_mode {
> + EX_ACCESS_READ,
> + EX_ACCESS_WRITE,
> + EX_ACCESS_PRECACHE,
> + EX_ACCESS_TRUNCATE,
> + EX_ACCESS_LARGEST,
> +};
> +
> /*
> * Reserved value to mark invalid age extents, hence valid block range
> * from 0 to ULLONG_MAX-1
> @@ -781,6 +790,8 @@ struct extent_info {
> /* physical extent length of compressed blocks */
> unsigned int c_len;
> #endif
> + /* record last access mode */
> + enum extent_access_mode last_access_mode;
As we know, memory is expensive, :P, I'd like to know if we can enable this
optionally if there is benefits.
Thanks,
> };
> /* block age extent_cache */
> struct {
> @@ -4577,7 +4588,8 @@ bool f2fs_lookup_read_extent_cache_block(struct inode *inode, pgoff_t index,
> block_t *blkaddr);
> void f2fs_update_read_extent_cache(struct dnode_of_data *dn);
> void f2fs_update_read_extent_cache_range(struct dnode_of_data *dn,
> - pgoff_t fofs, block_t blkaddr, unsigned int len);
> + pgoff_t fofs, block_t blkaddr, unsigned int len,
> + enum extent_access_mode access_mode);
> unsigned int f2fs_shrink_read_extent_tree(struct f2fs_sb_info *sbi,
> int nr_shrink);
>
> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> index 633e9ade654f..a3a5d499eadf 100644
> --- a/fs/f2fs/file.c
> +++ b/fs/f2fs/file.c
> @@ -733,7 +733,8 @@ void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count)
> */
> fofs = f2fs_start_bidx_of_node(ofs_of_node(dn->node_folio),
> dn->inode) + ofs;
> - f2fs_update_read_extent_cache_range(dn, fofs, 0, len);
> + f2fs_update_read_extent_cache_range(dn, fofs, 0, len,
> + EX_ACCESS_TRUNCATE);
> f2fs_update_age_extent_cache_range(dn, fofs, len);
> dec_valid_block_count(sbi, dn->inode, nr_free);
> }
> @@ -1672,7 +1673,8 @@ static int f2fs_do_zero_range(struct dnode_of_data *dn, pgoff_t start,
>
> if (index > start) {
> f2fs_update_read_extent_cache_range(dn, start, 0,
> - index - start);
> + index - start,
> + EX_ACCESS_TRUNCATE);
> f2fs_update_age_extent_cache_range(dn, start, index - start);
> }
>
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
next prev parent reply other threads:[~2026-06-15 12:06 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-12 11:58 [f2fs-dev] [PATCH RESEND 1/5] f2fs: fix extent merge failure when largest extent is not in rb-tree Yongpeng Yang
2026-06-12 11:58 ` [f2fs-dev] [PATCH RESEND 2/5] f2fs: only initialize largest extent without extent_node at inode init Yongpeng Yang
2026-06-15 11:55 ` Chao Yu via Linux-f2fs-devel
2026-06-12 11:58 ` [f2fs-dev] [PATCH RESEND 3/5] f2fs: punch largest extent instead of dropping it entirely on overlap Yongpeng Yang
2026-06-15 12:05 ` Chao Yu via Linux-f2fs-devel
2026-06-12 11:58 ` [f2fs-dev] [PATCH RESEND 4/5] f2fs: add extent_access_mode to track extent cache access patterns Yongpeng Yang
2026-06-15 12:05 ` Chao Yu via Linux-f2fs-devel [this message]
2026-06-12 11:58 ` [f2fs-dev] [PATCH RESEND 5/5] f2fs: add ioctl to export read extent cache to userspace for debug Yongpeng Yang
2026-06-15 12:20 ` Chao Yu via Linux-f2fs-devel
2026-06-15 15:51 ` Jaegeuk Kim via Linux-f2fs-devel
2026-06-15 11:26 ` [f2fs-dev] [PATCH RESEND 1/5] f2fs: fix extent merge failure when largest extent is not in rb-tree Chao Yu via Linux-f2fs-devel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=b2560939-82ef-4d1b-82fd-fa90388c3316@kernel.org \
--to=linux-f2fs-devel@lists.sourceforge.net \
--cc=chao@kernel.org \
--cc=jaegeuk@kernel.org \
--cc=monty_pavel@sina.com \
--cc=yangyongpeng.storage@gmail.com \
--cc=yangyongpeng@xiaomi.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.