On Mon, Mar 17, 2025 at 12:15:29AM +0530, Ritesh Harjani (IBM) wrote: > 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@xxxxxxxxx/T/#u > > Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@xxxxxxxxx> Just out of curiosity, is there a manpage change for xfs_io.8 that goes with this new subcommand? --D > --- > configure.ac | 1 + > include/builddefs.in | 1 + > io/Makefile | 5 +++ > io/cachestat.c | 77 +++++++++++++++++++++++++++++++++++++++++++ > io/init.c | 1 + > io/io.h | 6 ++++ > m4/package_libcdev.m4 | 19 +++++++++++ > 7 files changed, 110 insertions(+) > create mode 100644 io/cachestat.c > > 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..9edf3f9a > --- /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 <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, §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 <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 > -- > 2.48.1 > >