]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_io: Add cachestat syscall support
authorRitesh Harjani (IBM) <ritesh.list@gmail.com>
Sun, 16 Mar 2025 18:45:29 +0000 (00:15 +0530)
committerAndrey Albershteyn <aalbersh@kernel.org>
Mon, 31 Mar 2025 09:45:04 +0000 (11:45 +0200)
This adds -c "cachestat off len" command which uses cachestat() syscall
[1]. This can provide following pagecache detail for a file.

- no. of cached pages,
- no. of dirty pages,
- no. of pages marked for writeback,
- no. of evicted pages,
- no. of recently evicted pages

[1]: https://lore.kernel.org/all/20230503013608.2431726-3-nphamcs@gmail.com/T/#u

Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
Reviewed-by: Andrey Albershteyn <aalbersh@kernel.org>
[aalbersh remove [] from command arguments help]

configure.ac
include/builddefs.in
io/Makefile
io/cachestat.c [new file with mode: 0644]
io/init.c
io/io.h
m4/package_libcdev.m4

index 8c76f398d30a3e10e4cb72cbfbdee446da3ad1a5..f039bc9128fa4b11588ee9de9eded3c7904bec62 100644 (file)
@@ -154,6 +154,7 @@ AC_PACKAGE_NEED_RCU_INIT
 
 AC_HAVE_PWRITEV2
 AC_HAVE_COPY_FILE_RANGE
+AC_HAVE_CACHESTAT
 AC_NEED_INTERNAL_FSXATTR
 AC_NEED_INTERNAL_FSCRYPT_ADD_KEY_ARG
 AC_NEED_INTERNAL_FSCRYPT_POLICY_V2
index 82840ec7fd3adbcc1f1fefc76ad2e3f02cb87e07..fe2a7824a8653fd480564ee775bdeeac2be2f679 100644 (file)
@@ -95,6 +95,7 @@ HAVE_ZIPPED_MANPAGES = @have_zipped_manpages@
 
 HAVE_PWRITEV2 = @have_pwritev2@
 HAVE_COPY_FILE_RANGE = @have_copy_file_range@
+HAVE_CACHESTAT = @have_cachestat@
 NEED_INTERNAL_FSXATTR = @need_internal_fsxattr@
 NEED_INTERNAL_FSCRYPT_ADD_KEY_ARG = @need_internal_fscrypt_add_key_arg@
 NEED_INTERNAL_FSCRYPT_POLICY_V2 = @need_internal_fscrypt_policy_v2@
index 14a3fe2054f9b5c3f6b150b6cfc79530bcdb71ec..444e2d6a557d5d49e3fe7e91b9a9391f1b2b384f 100644 (file)
@@ -61,6 +61,11 @@ CFILES += copy_file_range.c
 LCFLAGS += -DHAVE_COPY_FILE_RANGE
 endif
 
+ifeq ($(HAVE_CACHESTAT),yes)
+CFILES += cachestat.c
+LCFLAGS += -DHAVE_CACHESTAT
+endif
+
 ifeq ($(ENABLE_EDITLINE),yes)
 LLDLIBS += $(LIBEDITLINE) $(LIBTERMCAP)
 endif
diff --git a/io/cachestat.c b/io/cachestat.c
new file mode 100644 (file)
index 0000000..f0604dd
--- /dev/null
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "command.h"
+#include "input.h"
+#include "init.h"
+#include "io.h"
+#include <unistd.h>
+#include <linux/mman.h>
+#include <asm/unistd.h>
+
+static cmdinfo_t cachestat_cmd;
+
+static void print_cachestat(struct cachestat *cs)
+{
+       printf(_("Cached: %llu, Dirty: %llu, Writeback: %llu, Evicted: %llu, Recently Evicted: %llu\n"),
+                       cs->nr_cache, cs->nr_dirty, cs->nr_writeback,
+                       cs->nr_evicted, cs->nr_recently_evicted);
+}
+
+static int
+cachestat_f(int argc, char **argv)
+{
+       off_t offset = 0, length = 0;
+       size_t blocksize, sectsize;
+       struct cachestat_range cs_range;
+       struct cachestat cs;
+
+       if (argc != 3) {
+               exitcode = 1;
+               return command_usage(&cachestat_cmd);
+       }
+
+       init_cvtnum(&blocksize, &sectsize);
+       offset = cvtnum(blocksize, sectsize, argv[1]);
+       if (offset < 0) {
+               printf(_("invalid offset argument -- %s\n"), argv[1]);
+               exitcode = 1;
+               return 0;
+       }
+
+       length = cvtnum(blocksize, sectsize, argv[2]);
+       if (length < 0) {
+               printf(_("invalid length argument -- %s\n"), argv[2]);
+               exitcode = 1;
+               return 0;
+       }
+
+       cs_range.off = offset;
+       cs_range.len = length;
+
+       if (syscall(__NR_cachestat, file->fd, &cs_range, &cs, 0)) {
+               perror("cachestat");
+               exitcode = 1;
+               return 0;
+       }
+
+       print_cachestat(&cs);
+
+       return 0;
+}
+
+static cmdinfo_t cachestat_cmd = {
+       .name           = "cachestat",
+       .altname        = "cs",
+       .cfunc          = cachestat_f,
+       .argmin         = 2,
+       .argmax         = 2,
+       .flags          = CMD_NOMAP_OK | CMD_FOREIGN_OK,
+       .args           = "off len",
+       .oneline        = "find page cache pages for a given file",
+};
+
+void cachestat_init(void)
+{
+       add_command(&cachestat_cmd);
+}
+
index 4831deae1b268396523dc876fa48e4a5d627de0e..49e9e7cb88214b30ef89728ce3cfc2ad60557814 100644 (file)
--- a/io/init.c
+++ b/io/init.c
@@ -49,6 +49,7 @@ init_commands(void)
        bmap_init();
        bulkstat_init();
        copy_range_init();
+       cachestat_init();
        cowextsize_init();
        encrypt_init();
        fadvise_init();
diff --git a/io/io.h b/io/io.h
index d99065582057de77f8100002bba270beea72a587..259c034931b8d3fa3e692e4357e86f59462669b7 100644 (file)
--- a/io/io.h
+++ b/io/io.h
@@ -132,6 +132,12 @@ extern void                copy_range_init(void);
 #define copy_range_init()      do { } while (0)
 #endif
 
+#ifdef HAVE_CACHESTAT
+extern void cachestat_init(void);
+#else
+#define cachestat_init() do { } while (0)
+#endif
+
 extern void            sync_range_init(void);
 extern void            readdir_init(void);
 extern void            reflink_init(void);
index 4ef7e8f67a3ba683667781df369afacee3846aff..af9da8124dbdc8b8a5e3426a22819d9830f25af8 100644 (file)
@@ -35,6 +35,25 @@ syscall(__NR_copy_file_range, 0, 0, 0, 0, 0, 0);
     AC_SUBST(have_copy_file_range)
   ])
 
+#
+# Check if we have a cachestat system call (Linux)
+#
+AC_DEFUN([AC_HAVE_CACHESTAT],
+  [ AC_MSG_CHECKING([for cachestat])
+    AC_LINK_IFELSE(
+    [  AC_LANG_PROGRAM([[
+#include <unistd.h>
+#include <linux/mman.h>
+#include <asm/unistd.h>
+       ]], [[
+syscall(__NR_cachestat, 0, 0, 0, 0);
+       ]])
+    ], have_cachestat=yes
+       AC_MSG_RESULT(yes),
+       AC_MSG_RESULT(no))
+    AC_SUBST(have_cachestat)
+  ])
+
 #
 # Check if we need to override the system struct fsxattr with
 # the internal definition.  This /only/ happens if the system