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@
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
--- /dev/null
+// 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);
+}
+
#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);
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