From 575f6f8ef2abe8552af96e42c65d70964db53563 Mon Sep 17 00:00:00 2001 From: Zhan Xusheng Date: Tue, 23 Jun 2026 15:26:41 +0800 Subject: f2fs: don't drop the top folio order in the f2fs_iostat tracepoint The f2fs_iostat tracepoint stores the per-order read folio counts in a fixed-size array and prints a fixed number of buckets, both hardcoded to 11. The sysfs iostat accounting array is instead sized by NR_PAGE_ORDERS (= MAX_PAGE_ORDER + 1), which is not always 11: arm64 16K pages -> MAX_PAGE_ORDER 11 -> NR_PAGE_ORDERS 12 arm64 64K pages -> MAX_PAGE_ORDER 13 -> NR_PAGE_ORDERS 14 f2fs enables large folios for immutable, non-compressed files, and the read folio order is bounded by MAX_PAGECACHE_ORDER, i.e. min(MAX_XAS_ORDER, PREFERRED_MAX_PAGECACHE_ORDER). With THP enabled this reaches order 11 on 16K/64K base-page kernels (MAX_XAS_ORDER caps it at 11). So an order-11 read folio is possible there and is accounted into index 11 of the array. On those configurations the sysfs file reports the order-11 count correctly, but the tracepoint silently drops it: the memcpy is capped at min(NR_PAGE_ORDERS, 11), so index 11 is never copied and the trace disagrees with sysfs. There is no memory-safety issue, only the order-11 bucket missing from the trace; 4K-page kernels (NR_PAGE_ORDERS == 11, max order <= 9) are unaffected. Size the array and the printed buckets by a ceiling that covers the largest possible NR_PAGE_ORDERS (14) with headroom, and add a BUILD_BUG_ON() so any future growth of NR_PAGE_ORDERS fails the build loudly instead of silently truncating again. The human-readable "order=count" output is preserved. Fixes: cb8ff3ead9a3 ("f2fs: add page-order information for large folio reads in iostat") Cc: stable@vger.kernel.org Signed-off-by: Zhan Xusheng Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- include/trace/events/f2fs.h | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index 270c1a2c24c4..1dd9fc5afc46 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h @@ -2114,6 +2114,14 @@ DEFINE_EVENT(f2fs_zip_end, f2fs_decompress_pages_end, ); #ifdef CONFIG_F2FS_IOSTAT +/* + * Number of read folio order buckets emitted by the f2fs_iostat tracepoint. + * TP_printk() cannot loop, so the field count is fixed here and must be >= + * the largest possible NR_PAGE_ORDERS (14 on arm64 with 64K pages). The + * BUILD_BUG_ON() in f2fs_update_read_folio_count() enforces this. + */ +#define F2FS_IOSTAT_RD_FOLIO_ORDERS 16 + TRACE_EVENT(f2fs_iostat, TP_PROTO(struct f2fs_sb_info *sbi, unsigned long long *iostat, @@ -2151,7 +2159,7 @@ TRACE_EVENT(f2fs_iostat, __field(unsigned long long, fs_mrio) __field(unsigned long long, fs_discard) __field(unsigned long long, fs_reset_zone) - __array(unsigned long long, read_folio_count, 11) + __array(unsigned long long, read_folio_count, F2FS_IOSTAT_RD_FOLIO_ORDERS) ), TP_fast_assign( @@ -2186,7 +2194,8 @@ TRACE_EVENT(f2fs_iostat, __entry->fs_reset_zone = iostat[FS_ZONE_RESET_IO]; memset(__entry->read_folio_count, 0, sizeof(__entry->read_folio_count)); memcpy(__entry->read_folio_count, read_folio_count, - sizeof(unsigned long long) * min_t(int, NR_PAGE_ORDERS, 11)); + sizeof(unsigned long long) * + min_t(int, NR_PAGE_ORDERS, F2FS_IOSTAT_RD_FOLIO_ORDERS)); ), TP_printk("dev = (%d,%d), " @@ -2201,7 +2210,8 @@ TRACE_EVENT(f2fs_iostat, "fs [data=%llu, (gc_data=%llu, cdata=%llu), " "node=%llu, meta=%llu], " "read_folio_count [0=%llu, 1=%llu, 2=%llu, 3=%llu, 4=%llu, " - "5=%llu, 6=%llu, 7=%llu, 8=%llu, 9=%llu, 10=%llu]", + "5=%llu, 6=%llu, 7=%llu, 8=%llu, 9=%llu, 10=%llu, 11=%llu, " + "12=%llu, 13=%llu, 14=%llu, 15=%llu]", show_dev(__entry->dev), __entry->app_wio, __entry->app_dio, __entry->app_bio, __entry->app_mio, __entry->app_bcdio, __entry->app_mcdio, __entry->fs_dio, __entry->fs_cdio, @@ -2218,7 +2228,9 @@ TRACE_EVENT(f2fs_iostat, __entry->read_folio_count[4], __entry->read_folio_count[5], __entry->read_folio_count[6], __entry->read_folio_count[7], __entry->read_folio_count[8], __entry->read_folio_count[9], - __entry->read_folio_count[10]) + __entry->read_folio_count[10], __entry->read_folio_count[11], + __entry->read_folio_count[12], __entry->read_folio_count[13], + __entry->read_folio_count[14], __entry->read_folio_count[15]) ); #ifndef __F2FS_IOSTAT_LATENCY_TYPE -- cgit v1.2.3 From eae3faf210bdc69181be717ce90437eadc6b3c80 Mon Sep 17 00:00:00 2001 From: Daeho Jeong Date: Wed, 5 Aug 2026 18:48:13 -0700 Subject: f2fs: support dynamic reserve/release for device aliasing This patch adds a dynamic management feature to the existing device aliasing functionality. It allows users to dynamically reserve or release specific devices from the filesystem's free pool at runtime through new ioctls. To support this, three new ioctls are introduced: - F2FS_IOC_RESERVE_DEV_ALIAS: This reclaims the space occupied by a device aliasing file. It first performs a capacity check, resets GC victim information for the target range, marks the segments as in-use to prevent new allocations, and then triggers GC to migrate existing valid data out of the range. Finally, it reserves these blocks in the SIT to effectively exclude the device from the usable capacity. - F2FS_IOC_RELEASE_DEV_ALIAS: This releases the reserved space of a previously reserved device aliasing file. It truncates the blocks associated with the file, which makes them available for general filesystem allocation again. - F2FS_IOC_GET_DEV_ALIAS_STATUS: This retrieves the current aliasing status of a device aliasing file, returning whether the file is released (inactive alias) or reserved (active alias, with blocks fully allocated on the device). Signed-off-by: Daeho Jeong Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- include/uapi/linux/f2fs.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include') diff --git a/include/uapi/linux/f2fs.h b/include/uapi/linux/f2fs.h index 795e26258355..4409ada2fecb 100644 --- a/include/uapi/linux/f2fs.h +++ b/include/uapi/linux/f2fs.h @@ -45,6 +45,9 @@ #define F2FS_IOC_START_ATOMIC_REPLACE _IO(F2FS_IOCTL_MAGIC, 25) #define F2FS_IOC_GET_DEV_ALIAS_FILE _IOR(F2FS_IOCTL_MAGIC, 26, __u32) #define F2FS_IOC_IO_PRIO _IOW(F2FS_IOCTL_MAGIC, 27, __u32) +#define F2FS_IOC_RESERVE_DEV_ALIAS _IO(F2FS_IOCTL_MAGIC, 28) +#define F2FS_IOC_RELEASE_DEV_ALIAS _IO(F2FS_IOCTL_MAGIC, 29) +#define F2FS_IOC_GET_DEV_ALIAS_STATUS _IOR(F2FS_IOCTL_MAGIC, 30, __u32) /* * should be same as XFS_IOC_GOINGDOWN. @@ -70,6 +73,10 @@ enum { F2FS_IOPRIO_MAX, }; +/* for F2FS_IOC_GET_DEV_ALIAS_STATUS */ +#define F2FS_DEV_ALIAS_STATUS_RELEASED 0 +#define F2FS_DEV_ALIAS_STATUS_RESERVED 1 + struct f2fs_gc_range { __u32 sync; __u64 start; -- cgit v1.2.3 From 46d4246d8dcde75aff707976cddc546f22184cac Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Mon, 17 Aug 2026 11:19:16 +0000 Subject: f2fs: use f2fs_{down, up}_(read, write}_trace() for nat_tree_lock Under heavy workloads or during background GC/fallocate operations, nat_tree_lock can experience high lock contention between background readers (e.g. f2fs_get_node_info() in gc_data_segment) and writers (e.g. flush_nat_entries, set_node_addr, shrinker). [375067.327986][T13777] schedule+0x4c/0x114 [375067.327997][T13777] f2fs_get_node_info+0x438/0x5c4 [375067.328002][T13777] f2fs_get_inode_page+0x1e0/0x3f0 [375067.328013][T13777] f2fs_iget+0x88/0x1180 [375067.328024][T13777] f2fs_lookup+0x168/0x3a8 [375067.328035][T13777] path_openat+0xa28/0x1b04 [375067.328046][T13777] do_filp_open+0xac/0x130 [375067.328056][T13777] do_sys_openat2+0x140/0x21c [375067.328066][T13777] __arm64_sys_openat+0x70/0x9c [375067.330299][T13777] schedule+0x4c/0x114 [375067.330310][T13777] schedule_preempt_disabled+0x24/0x40 [375067.330321][T13777] rwsem_down_write_slowpath+0x3b4/0x9d0 [375067.330332][T13777] down_write+0x98/0x170 [375067.330343][T13777] set_node_addr+0x74/0x4b4 [375067.330354][T13777] f2fs_new_node_page+0xb0/0x280 [375067.330444][T13777] f2fs_new_inode_page+0x3c/0x64 [375067.330455][T13777] f2fs_init_inode_metadata+0x4c/0x47c [375067.330461][T13777] f2fs_add_regular_entry+0x258/0x5b8 [375067.330471][T13777] f2fs_add_dentry+0x100/0x158 [375067.330476][T13777] f2fs_do_add_link+0x84/0x140 [375067.330487][T13777] f2fs_create+0xec/0x250 [375067.331759][T13777] schedule+0x4c/0x114 [375067.331770][T13777] f2fs_down_read+0x9c/0xc4 [375067.331781][T13777] f2fs_need_inode_block_update+0x20/0x10c [375067.331792][T13777] f2fs_do_sync_file+0x478/0x830 [375067.331802][T13777] f2fs_sync_file+0x2c/0x40 This patch converts nat_tree_lock to use the f2fs_{down,up}_{read,write}_trace infrastructure. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- include/trace/events/f2fs.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index 1dd9fc5afc46..d53be932df01 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h @@ -191,7 +191,8 @@ TRACE_DEFINE_ENUM(CP_PHASE_FINISH_CHECKPOINT); { LOCK_NAME_NODE_WRITE, "node_write" }, \ { LOCK_NAME_GC_LOCK, "gc_lock" }, \ { LOCK_NAME_CP_GLOBAL, "cp_global" }, \ - { LOCK_NAME_IO_RWSEM, "io_rwsem" }) + { LOCK_NAME_IO_RWSEM, "io_rwsem" }, \ + { LOCK_NAME_NAT_TREE_LOCK, "nat_tree_lock" }) struct f2fs_sb_info; struct f2fs_io_info; -- cgit v1.2.3