From: Ritesh Harjani (IBM) Date: Sun, 16 Mar 2025 18:45:29 +0000 (+0530) Subject: xfs_io: Add cachestat syscall support X-Git-Tag: v6.14.0~13 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2d5aa51bee121208da9c11be6d14c463c5661d26;p=thirdparty%2Fxfsprogs-dev.git xfs_io: Add cachestat syscall support 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) Reviewed-by: Andrey Albershteyn [aalbersh remove [] from command arguments help] --- diff --git a/configure.ac b/configure.ac index 8c76f398..f039bc91 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/include/builddefs.in b/include/builddefs.in index 82840ec7..fe2a7824 100644 --- a/include/builddefs.in +++ b/include/builddefs.in @@ -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@ diff --git a/io/Makefile b/io/Makefile index 14a3fe20..444e2d6a 100644 --- a/io/Makefile +++ b/io/Makefile @@ -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 index 00000000..f0604dd5 --- /dev/null +++ b/io/cachestat.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "command.h" +#include "input.h" +#include "init.h" +#include "io.h" +#include +#include +#include + +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, §size); + 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); +} + diff --git a/io/init.c b/io/init.c index 4831deae..49e9e7cb 100644 --- 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 d9906558..259c0349 100644 --- 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); diff --git a/m4/package_libcdev.m4 b/m4/package_libcdev.m4 index 4ef7e8f6..af9da812 100644 --- a/m4/package_libcdev.m4 +++ b/m4/package_libcdev.m4 @@ -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 +#include +#include + ]], [[ +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