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 | <SEZPR02MB5662D6AB72C58571F587934899E02@SEZPR02MB5662.apcprd02.prod.outlook.com> |
On 6/20/26 3:05 PM, Chao Yu via Linux-f2fs-devel wrote: > On 6/19/26 22:56, Yongpeng Yang wrote: >> >> 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. > > call access() in userspace application or touch in script to load inode via > lookup() first, then access sysfs and procfs node? Thanks for the suggestion, this is more lightweight. I'll modify it in v2 patch. Thanks Yongpeng, > > Thanks, > >> >> 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 _______________________________________________ Linux-f2fs-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel