Re: [f2fs-dev] [PATCH RESEND 5/5] f2fs: add ioctl to export read extent cache to userspace for debug
Yongpeng Yang <[email protected]>
| Newsgroups | net.sourceforge.lists.linux-f2fs-devel |
|---|---|
| Message-ID | <SEZPR02MB56627B7C417379E9209FF87799E22@SEZPR02MB5662.apcprd02.prod.outlook.com> |
On 6/15/26 11:51 PM, Jaegeuk Kim via Linux-f2fs-devel wrote: > On 06/15, Chao Yu via Linux-f2fs-devel wrote: >> On 6/12/26 19:58, Yongpeng Yang wrote: >>> From: Yongpeng Yang <[email protected]> >>> >>> Add F2FS_IOC_GET_READ_CACHE_EXTENTS ioctl that allows userspace to >>> retrieve all cached read extents for a given file. This uses a two-call >>> pattern similar to fiemap: the first call with ext_count=0 queries the >>> node_count, and the second call fetches the actual extent entries. >> >> It looks a little bit heavy to maintain a debug purpose ioctl interface. >> >> Maybe set ino via sysfs and dump extent cache via procfs? only enabled >> if F2FS_CHECK_FS=y? >> >> Jaegeuk, do you have any suggestion? > > Agreed, and even not sure we need sysfs or procfs. Can we dump the extents > via fsck? It is indeed quite heavy. Our primary goal here is debugging inode extent trees, and fsck cannot meet this requirement. If we rely on procfs or sysfs interfaces, we would have to open dedicated files within sysfs.c, which feels like an inappropriate approach. Thanks Yongpeng, > >> >> Thanks, >> >>> >>> Signed-off-by: Yongpeng Yang <[email protected]> >>> --- >>> fs/f2fs/extent_cache.c | 70 +++++++++++++++++++++++++++++++++++++++ >>> fs/f2fs/f2fs.h | 3 ++ >>> fs/f2fs/file.c | 11 ++++++ >>> include/uapi/linux/f2fs.h | 21 ++++++++++++ >>> 4 files changed, 105 insertions(+) >>> >>> diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c >>> index e141ffb64e5f..0c10d5639d68 100644 >>> --- a/fs/f2fs/extent_cache.c >>> +++ b/fs/f2fs/extent_cache.c >>> @@ -14,6 +14,7 @@ >>> >>> #include <linux/fs.h> >>> #include <linux/f2fs_fs.h> >>> +#include <uapi/linux/f2fs.h> >>> >>> #include "f2fs.h" >>> #include "node.h" >>> @@ -1267,6 +1268,75 @@ static void __init_extent_tree_info(struct extent_tree_info *eti) >>> atomic_set(&eti->total_ext_node, 0); >>> } >>> >>> +int f2fs_get_read_cache_extents(struct inode *inode, >>> + struct f2fs_read_cache_extent __user *uarg) >>> +{ >>> + struct extent_tree *et = F2FS_I(inode)->extent_tree[EX_READ]; >>> + struct f2fs_cache_extent_info *kbuf = NULL; >>> + struct f2fs_cache_extent_info largest = {}; >>> + struct rb_node *node; >>> + struct extent_node *en; >>> + unsigned int capacity, count = 0; >>> + __u32 flags = 0; >>> + int ret = 0; >>> + >>> + if (get_user(capacity, &uarg->ext_count)) >>> + return -EFAULT; >>> + >>> + if (is_inode_flag_set(inode, FI_NO_EXTENT)) >>> + flags |= F2FS_EXT_FL_NO_EXTENT; >>> + >>> + if (!et || (flags & F2FS_EXT_FL_NO_EXTENT)) { >>> + if (put_user(0U, &uarg->ext_count) || >>> + put_user(flags, &uarg->flags) || >>> + put_user(0U, &uarg->node_count)) >>> + return -EFAULT; >>> + return 0; >>> + } >>> + >>> + if (capacity) { >>> + kbuf = f2fs_kvmalloc(F2FS_I_SB(inode), capacity * sizeof(*kbuf), GFP_KERNEL); >>> + if (!kbuf) >>> + return -ENOMEM; >>> + } >>> + >>> + read_lock(&et->lock); >>> + >>> + largest.fofs = et->largest.fofs; >>> + largest.blk = et->largest.blk; >>> + largest.len = et->largest.len; >>> + largest.last_access_mode = et->largest.last_access_mode; >>> + >>> + for (node = rb_first_cached(&et->root); node; node = rb_next(node)) { >>> + if (count >= capacity) >>> + break; >>> + en = rb_entry(node, struct extent_node, rb_node); >>> + >>> + kbuf[count].fofs = en->ei.fofs; >>> + kbuf[count].blk = en->ei.blk; >>> + kbuf[count].len = en->ei.len; >>> + kbuf[count].last_access_mode = en->ei.last_access_mode; >>> + count++; >>> + } >>> + >>> + read_unlock(&et->lock); >>> + >>> + if (count && copy_to_user(uarg->extents, kbuf, >>> + count * sizeof(*kbuf))) { >>> + ret = -EFAULT; >>> + goto out; >>> + } >>> + >>> + if (put_user(count, &uarg->ext_count) || >>> + put_user(flags, &uarg->flags) || >>> + put_user((u32)atomic_read(&et->node_cnt), &uarg->node_count) || >>> + copy_to_user(&uarg->largest, &largest, sizeof(largest))) >>> + ret = -EFAULT; >>> +out: >>> + kvfree(kbuf); >>> + return ret; >>> +} >>> + >>> void f2fs_init_extent_cache_info(struct f2fs_sb_info *sbi) >>> { >>> __init_extent_tree_info(&sbi->extent_tree[EX_READ]); >>> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h >>> index 1588b64d04a3..69641fc31c51 100644 >>> --- a/fs/f2fs/f2fs.h >>> +++ b/fs/f2fs/f2fs.h >>> @@ -26,6 +26,7 @@ >>> #include <linux/part_stat.h> >>> #include <linux/rw_hint.h> >>> >>> +#include <uapi/linux/f2fs.h> >>> #include <linux/fscrypt.h> >>> #include <linux/fsverity.h> >>> >>> @@ -4590,6 +4591,8 @@ 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, >>> enum extent_access_mode access_mode); >>> +int f2fs_get_read_cache_extents(struct inode *inode, >>> + struct f2fs_read_cache_extent __user *uarg); >>> 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 a3a5d499eadf..66ec9927d667 100644 >>> --- a/fs/f2fs/file.c >>> +++ b/fs/f2fs/file.c >>> @@ -3672,6 +3672,14 @@ static int f2fs_ioc_precache_extents(struct file *filp) >>> return f2fs_precache_extents(file_inode(filp)); >>> } >>> >>> +static int f2fs_ioc_get_read_cache_extents(struct file *filp, unsigned long arg) >>> +{ >>> + struct inode *inode = file_inode(filp); >>> + >>> + return f2fs_get_read_cache_extents(inode, >>> + (struct f2fs_read_cache_extent __user *)arg); >>> +} >>> + >>> static int f2fs_ioc_resize_fs(struct file *filp, unsigned long arg) >>> { >>> struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(filp)); >>> @@ -4744,6 +4752,8 @@ static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) >>> return f2fs_ioc_get_dev_alias_file(filp, arg); >>> case F2FS_IOC_IO_PRIO: >>> return f2fs_ioc_io_prio(filp, arg); >>> + case F2FS_IOC_GET_READ_CACHE_EXTENTS: >>> + return f2fs_ioc_get_read_cache_extents(filp, arg); >>> default: >>> return -ENOTTY; >>> } >>> @@ -5506,6 +5516,7 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) >>> case F2FS_IOC_COMPRESS_FILE: >>> case F2FS_IOC_GET_DEV_ALIAS_FILE: >>> case F2FS_IOC_IO_PRIO: >>> + case F2FS_IOC_GET_READ_CACHE_EXTENTS: >>> break; >>> default: >>> return -ENOIOCTLCMD; >>> diff --git a/include/uapi/linux/f2fs.h b/include/uapi/linux/f2fs.h >>> index 795e26258355..6ff9003bc030 100644 >>> --- a/include/uapi/linux/f2fs.h >>> +++ b/include/uapi/linux/f2fs.h >>> @@ -45,6 +45,8 @@ >>> #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_GET_READ_CACHE_EXTENTS _IOWR(F2FS_IOCTL_MAGIC, 28, \ >>> + struct f2fs_read_cache_extent) >>> >>> /* >>> * should be same as XFS_IOC_GOINGDOWN. >>> @@ -104,4 +106,23 @@ struct f2fs_comp_option { >>> __u8 log_cluster_size; >>> }; >>> >>> +struct f2fs_cache_extent_info { >>> + __u32 fofs; /* start file offset in blocks */ >>> + __u32 blk; /* start block address */ >>> + __u32 len; /* length in blocks */ >>> + __u32 last_access_mode; /* last access mode of extent_node */ >>> +}; >>> + >>> +/* flags for f2fs_read_cache_extent */ >>> +#define F2FS_EXT_FL_NO_EXTENT 0x1 /* extent cache disabled for this inode */ >>> + >>> +struct f2fs_read_cache_extent { >>> + __u32 ext_count; /* in: array capacity; out: mapped extent count */ >>> + __u32 flags; /* out: status flags */ >>> + __u32 node_count; /* out: total extent nodes in tree */ >>> + __u32 reserved; >>> + struct f2fs_cache_extent_info largest; /* out: largest extent */ >>> + struct f2fs_cache_extent_info extents[]; /* out: extent array */ >>> +}; >>> + >>> #endif /* _UAPI_LINUX_F2FS_H */ >> >> >> >> _______________________________________________ >> Linux-f2fs-devel mailing list >> [email protected] >> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel > > > _______________________________________________ > Linux-f2fs-devel mailing list > [email protected] > https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel _______________________________________________ Linux-f2fs-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel