The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH v2 1/2] f2fs: unify add/remove ino entry API for all ino types
@ 2026-08-09  1:26 Chao Yu
  2026-08-09  1:26 ` [PATCH v2 2/2] f2fs: reduce memory footprint of ino management Chao Yu
  2026-08-12 20:30 ` [f2fs-dev] [PATCH v2 1/2] f2fs: unify add/remove ino entry API for all ino types patchwork-bot+f2fs
  0 siblings, 2 replies; 3+ messages in thread
From: Chao Yu @ 2026-08-09  1:26 UTC (permalink / raw)
  To: jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu

- Call f2fs_add_ino_entry() and f2fs_remove_ino_entry() for ORPHAN_INO
- introduce __f2fs_add_ino_entry() to wrap __add_ino_entry(), so that
both f2fs_add_ino_entry() and f2fs_set_dirty_device() will call
__f2fs_add_ino_entry().

So, after this change:

		add			delete			lookup
ORPHAN_INO	f2fs_add_ino_entry	f2fs_remove_ino_entry	N/A
FLUSH_INO	f2fs_set_dirty_device	f2fs_remove_ino_entry	f2fs_is_dirty_device
APPEND_INO	f2fs_add_ino_entry	f2fs_remove_ino_entry	f2fs_exist_written_data
UPDATA_INO	f2fs_add_ino_entry	f2fs_remove_ino_entry	f2fs_exist_written_data
TRANS_DIR_INO	f2fs_add_ino_entry	N/A			f2fs_exist_written_data
XATTR_DIR_INO	f2fs_add_ino_entry	N/A			f2fs_exist_written_data

Signed-off-by: Chao Yu <chao@kernel.org>
---
 fs/f2fs/checkpoint.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index 4413eccb5ecb..eb2f955b1e2a 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -775,10 +775,16 @@ static void f2fs_wait_for_inode_record(struct f2fs_sb_info *sbi, int mode)
 	flush_workqueue(sbi->evict_wq);
 }
 
-void f2fs_add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
+static void __f2fs_add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino,
+					unsigned int devidx, int type)
 {
 	/* add new dirty ino entry into list */
-	__add_ino_entry(sbi, ino, 0, type);
+	__add_ino_entry(sbi, ino, devidx, type);
+}
+
+void f2fs_add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
+{
+	__f2fs_add_ino_entry(sbi, ino, 0, type);
 }
 
 void f2fs_remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
@@ -823,7 +829,7 @@ void f2fs_release_ino_entry(struct f2fs_sb_info *sbi, bool all)
 void f2fs_set_dirty_device(struct f2fs_sb_info *sbi, nid_t ino,
 					unsigned int devidx, int type)
 {
-	__add_ino_entry(sbi, ino, devidx, type);
+	__f2fs_add_ino_entry(sbi, ino, devidx, type);
 }
 
 bool f2fs_is_dirty_device(struct f2fs_sb_info *sbi, nid_t ino,
@@ -875,14 +881,14 @@ void f2fs_release_orphan_inode(struct f2fs_sb_info *sbi)
 void f2fs_add_orphan_inode(struct inode *inode)
 {
 	/* add new orphan ino entry into list */
-	__add_ino_entry(F2FS_I_SB(inode), inode->i_ino, 0, ORPHAN_INO);
+	f2fs_add_ino_entry(F2FS_I_SB(inode), inode->i_ino, ORPHAN_INO);
 	f2fs_update_inode_page(inode);
 }
 
 void f2fs_remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
 {
 	/* remove orphan entry from orphan list */
-	__remove_ino_entry(sbi, ino, ORPHAN_INO);
+	f2fs_remove_ino_entry(sbi, ino, ORPHAN_INO);
 }
 
 static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH v2 2/2] f2fs: reduce memory footprint of ino management
  2026-08-09  1:26 [PATCH v2 1/2] f2fs: unify add/remove ino entry API for all ino types Chao Yu
@ 2026-08-09  1:26 ` Chao Yu
  2026-08-12 20:30 ` [f2fs-dev] [PATCH v2 1/2] f2fs: unify add/remove ino entry API for all ino types patchwork-bot+f2fs
  1 sibling, 0 replies; 3+ messages in thread
From: Chao Yu @ 2026-08-09  1:26 UTC (permalink / raw)
  To: jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu

Currently, ino entries for APPEND_INO, UPDATE_INO, TRANS_DIR_INO, and
XATTR_DIR_INO allocate a 'struct ino_entry' slab object and attach it to
both a list and a radix tree solely for existence checks via
f2fs_exist_written_data().

Since these ino types only track binary existence status, we can embed
the information directly into radix tree value entries as a bitmap:

- The Linux radix tree/XArray supports in-place value entries via
  xa_mk_value() / xa_to_value(), which tag the least significant bit
  to store an unallocated integer value of BITS_PER_XA_VALUE bits
  (BITS_PER_LONG - 1) directly in the slot pointer.
- For each inode, (ino / BITS_PER_XA_VALUE) serves as the radix tree
  slot index, and (ino % BITS_PER_XA_VALUE) is used as the bit offset
  within the slot's bitmap.

For example, when tracking ino = 7:
- Before: Allocate a 'struct ino_entry' ({ .ino = 7 }), insert its
  pointer into the radix tree at index = 7, and link it to im->ino_list.
- After: Compute slot_index = 7 / BITS_PER_XA_VALUE (index 0) and
  bit_offset = 7 % BITS_PER_XA_VALUE (bit 7), then set bit 7 in the
  value entry via xa_mk_value(bitmap) at index 0, without allocating
  a slab object or linking to a list.

Additionally:
- In-place slot updates are performed via radix_tree_replace_slot(), and
  slots are deleted with radix_tree_delete() once the bitmap is zeroed.
- Reorder the ino list enum so ORPHAN_INO and FLUSH_INO (which still
  require struct ino_entry and list traversal) remain separated, while
  bitmap-based trees are torn down using xa_destroy().

This eliminates 'struct ino_entry' slab allocations and linked-list
tracking for these ino types, significantly reducing memory consumption.

Signed-off-by: Chao Yu <chao@kernel.org>
---
v2:
- fix to call __remove_ino_entry correctly for FLUSH_INO
 fs/f2fs/checkpoint.c | 99 ++++++++++++++++++++++++++++++++++++++++----
 fs/f2fs/f2fs.h       |  6 ++-
 2 files changed, 95 insertions(+), 10 deletions(-)

diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index eb2f955b1e2a..f81ba8cc861a 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -766,6 +766,64 @@ static void __remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
 	spin_unlock(&im->ino_lock);
 }
 
+static void __set_ino_bitmap(struct f2fs_sb_info *sbi, nid_t ino, int type)
+{
+	struct inode_management *im = &sbi->im[type];
+	unsigned long index = INO_SLOT_INDEX(ino);
+	unsigned int ofs = INO_BIT_OFFSET(ino);
+	void **slot, *entry;
+	unsigned long bitmap = 0;
+	int ret;
+
+	ret = radix_tree_preload(GFP_NOFS | __GFP_NOFAIL);
+	f2fs_bug_on(sbi, ret);
+
+	spin_lock(&im->ino_lock);
+	slot = radix_tree_lookup_slot(&im->ino_root, index);
+	if (slot) {
+		entry = radix_tree_deref_slot(slot);
+		bitmap = xa_to_value(entry);
+		if (!(bitmap & (1UL << ofs))) {
+			bitmap |= (1UL << ofs);
+			entry = xa_mk_value(bitmap);
+			radix_tree_replace_slot(&im->ino_root, slot, entry);
+		}
+	} else {
+		bitmap |= (1UL << ofs);
+		entry = xa_mk_value(bitmap);
+		if (unlikely(radix_tree_insert(&im->ino_root, index, entry)))
+			f2fs_bug_on(sbi, 1);
+	}
+	spin_unlock(&im->ino_lock);
+	radix_tree_preload_end();
+}
+
+static void __clear_ino_bitmap(struct f2fs_sb_info *sbi, nid_t ino, int type)
+{
+	struct inode_management *im = &sbi->im[type];
+	unsigned long index = INO_SLOT_INDEX(ino);
+	unsigned int ofs = INO_BIT_OFFSET(ino);
+	void **slot, *entry;
+	unsigned long bitmap;
+
+	spin_lock(&im->ino_lock);
+	slot = radix_tree_lookup_slot(&im->ino_root, index);
+	if (slot) {
+		entry = radix_tree_deref_slot(slot);
+		bitmap = xa_to_value(entry);
+		if (bitmap & (1UL << ofs))
+			bitmap &= ~(1UL << ofs);
+
+		if (bitmap) {
+			entry = xa_mk_value(bitmap);
+			radix_tree_replace_slot(&im->ino_root, slot, entry);
+		} else {
+			radix_tree_delete(&im->ino_root, index);
+		}
+	}
+	spin_unlock(&im->ino_lock);
+}
+
 static void f2fs_wait_for_inode_record(struct f2fs_sb_info *sbi, int mode)
 {
 	if (mode != APPEND_INO && mode != UPDATE_INO)
@@ -778,8 +836,10 @@ static void f2fs_wait_for_inode_record(struct f2fs_sb_info *sbi, int mode)
 static void __f2fs_add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino,
 					unsigned int devidx, int type)
 {
-	/* add new dirty ino entry into list */
-	__add_ino_entry(sbi, ino, devidx, type);
+	if (type <= FLUSH_INO)
+		__add_ino_entry(sbi, ino, devidx, type);
+	else
+		__set_ino_bitmap(sbi, ino, type);
 }
 
 void f2fs_add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
@@ -789,20 +849,33 @@ void f2fs_add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
 
 void f2fs_remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
 {
-	/* remove dirty ino entry from list */
-	__remove_ino_entry(sbi, ino, type);
+	if (type <= FLUSH_INO)
+		__remove_ino_entry(sbi, ino, type);
+	else
+		__clear_ino_bitmap(sbi, ino, type);
 }
 
-/* mode should be APPEND_INO, UPDATE_INO or TRANS_DIR_INO */
+/* mode should be APPEND_INO, UPDATE_INO, TRANS_DIR_INO and XATTR_DIR_INO */
 bool f2fs_exist_written_data(struct f2fs_sb_info *sbi, nid_t ino, int mode)
 {
 	struct inode_management *im = &sbi->im[mode];
-	struct ino_entry *e;
+	unsigned long index = INO_SLOT_INDEX(ino);
+	unsigned int ofs = INO_BIT_OFFSET(ino);
+	void *entry;
+	unsigned long bitmap;
+
+	f2fs_bug_on(sbi, mode <= FLUSH_INO);
 
 	spin_lock(&im->ino_lock);
-	e = radix_tree_lookup(&im->ino_root, ino);
+	entry = radix_tree_lookup(&im->ino_root, index);
+	if (!entry) {
+		spin_unlock(&im->ino_lock);
+		return false;
+	}
+	bitmap = xa_to_value(entry);
 	spin_unlock(&im->ino_lock);
-	return e ? true : false;
+
+	return bitmap & (1UL << ofs);
 }
 
 void f2fs_release_ino_entry(struct f2fs_sb_info *sbi, bool all)
@@ -810,7 +883,7 @@ void f2fs_release_ino_entry(struct f2fs_sb_info *sbi, bool all)
 	struct ino_entry *e, *tmp;
 	int i;
 
-	for (i = all ? ORPHAN_INO : APPEND_INO; i < MAX_INO_ENTRY; i++) {
+	for (i = all ? ORPHAN_INO : FLUSH_INO; i <= FLUSH_INO; i++) {
 		struct inode_management *im = &sbi->im[i];
 
 		f2fs_wait_for_inode_record(sbi, i);
@@ -824,6 +897,14 @@ void f2fs_release_ino_entry(struct f2fs_sb_info *sbi, bool all)
 		}
 		spin_unlock(&im->ino_lock);
 	}
+
+	for (i = APPEND_INO; i < MAX_INO_ENTRY; i++) {
+		struct inode_management *im = &sbi->im[i];
+
+		spin_lock(&im->ino_lock);
+		xa_destroy(&im->ino_root);
+		spin_unlock(&im->ino_lock);
+	}
 }
 
 void f2fs_set_dirty_device(struct f2fs_sb_info *sbi, nid_t ino,
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 160e7db0674e..5ae2d347c3ce 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -389,14 +389,18 @@ enum {
 /* for the list of ino */
 enum {
 	ORPHAN_INO,		/* for orphan ino list */
+	FLUSH_INO,		/* for multiple device flushing */
 	APPEND_INO,		/* for append ino list */
 	UPDATE_INO,		/* for update ino list */
 	TRANS_DIR_INO,		/* for transactions dir ino list */
 	XATTR_DIR_INO,		/* for xattr updated dir ino list */
-	FLUSH_INO,		/* for multiple device flushing */
 	MAX_INO_ENTRY,		/* max. list */
 };
 
+#define INO_BITS_PER_SLOT	BITS_PER_XA_VALUE
+#define INO_SLOT_INDEX(ino)	((ino) / INO_BITS_PER_SLOT)
+#define INO_BIT_OFFSET(ino)	((ino) % INO_BITS_PER_SLOT)
+
 struct ino_entry {
 	struct list_head list;		/* list head */
 	nid_t ino;			/* inode number */
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [f2fs-dev] [PATCH v2 1/2] f2fs: unify add/remove ino entry API for all ino types
  2026-08-09  1:26 [PATCH v2 1/2] f2fs: unify add/remove ino entry API for all ino types Chao Yu
  2026-08-09  1:26 ` [PATCH v2 2/2] f2fs: reduce memory footprint of ino management Chao Yu
@ 2026-08-12 20:30 ` patchwork-bot+f2fs
  1 sibling, 0 replies; 3+ messages in thread
From: patchwork-bot+f2fs @ 2026-08-12 20:30 UTC (permalink / raw)
  To: Chao Yu; +Cc: jaegeuk, linux-kernel, linux-f2fs-devel

Hello:

This series was applied to jaegeuk/f2fs.git (dev)
by Jaegeuk Kim <jaegeuk@kernel.org>:

On Sun,  9 Aug 2026 09:26:38 +0800 you wrote:
> - Call f2fs_add_ino_entry() and f2fs_remove_ino_entry() for ORPHAN_INO
> - introduce __f2fs_add_ino_entry() to wrap __add_ino_entry(), so that
> both f2fs_add_ino_entry() and f2fs_set_dirty_device() will call
> __f2fs_add_ino_entry().
> 
> So, after this change:
> 
> [...]

Here is the summary with links:
  - [f2fs-dev,v2,1/2] f2fs: unify add/remove ino entry API for all ino types
    https://git.kernel.org/jaegeuk/f2fs/c/d3915a0a356e
  - [f2fs-dev,v2,2/2] f2fs: reduce memory footprint of ino management
    https://git.kernel.org/jaegeuk/f2fs/c/798bddf3d9a3

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-08-12 20:30 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-09  1:26 [PATCH v2 1/2] f2fs: unify add/remove ino entry API for all ino types Chao Yu
2026-08-09  1:26 ` [PATCH v2 2/2] f2fs: reduce memory footprint of ino management Chao Yu
2026-08-12 20:30 ` [f2fs-dev] [PATCH v2 1/2] f2fs: unify add/remove ino entry API for all ino types patchwork-bot+f2fs

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox