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? > > 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
