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,


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

Reply via email to