[LTP] [PATCH v2] cachestat01.c: Add cachestat() testcheck
Wei Gao
wegao@suse.com
Tue Sep 19 10:29:49 CEST 2023
Signed-off-by: Wei Gao <wegao@suse.com>
---
configure.ac | 1 +
include/lapi/cachestat.h | 36 +++
include/lapi/syscalls/aarch64.in | 1 +
include/lapi/syscalls/arc.in | 1 +
include/lapi/syscalls/arm.in | 1 +
include/lapi/syscalls/hppa.in | 1 +
include/lapi/syscalls/i386.in | 1 +
include/lapi/syscalls/ia64.in | 1 +
include/lapi/syscalls/powerpc.in | 1 +
include/lapi/syscalls/powerpc64.in | 1 +
include/lapi/syscalls/s390.in | 1 +
include/lapi/syscalls/s390x.in | 1 +
include/lapi/syscalls/sh.in | 1 +
include/lapi/syscalls/sparc.in | 1 +
include/lapi/syscalls/sparc64.in | 1 +
include/lapi/syscalls/x86_64.in | 1 +
runtest/syscalls | 2 +
.../kernel/syscalls/cachestat/.gitignore | 1 +
testcases/kernel/syscalls/cachestat/Makefile | 8 +
.../kernel/syscalls/cachestat/cachestat01.c | 260 ++++++++++++++++++
20 files changed, 322 insertions(+)
create mode 100644 include/lapi/cachestat.h
create mode 100644 testcases/kernel/syscalls/cachestat/.gitignore
create mode 100644 testcases/kernel/syscalls/cachestat/Makefile
create mode 100644 testcases/kernel/syscalls/cachestat/cachestat01.c
diff --git a/configure.ac b/configure.ac
index 662c4c058..4b5547b5b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -93,6 +93,7 @@ AC_CHECK_FUNCS_ONCE([ \
epoll_pwait2 \
execveat \
faccessat2 \
+ cachestat \
fallocate \
fchownat \
fsconfig \
diff --git a/include/lapi/cachestat.h b/include/lapi/cachestat.h
new file mode 100644
index 000000000..fea390849
--- /dev/null
+++ b/include/lapi/cachestat.h
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) Linux Test Project, 2003-2023
+ * Author: Wei Gao <wegao@suse.com>
+ */
+
+#ifndef CACHESTAT_H
+#define CACHESTAT_H
+
+#include "tst_test.h"
+#include "config.h"
+#include "lapi/syscalls.h"
+
+#ifndef HAVE_CACHESTAT
+struct cachestat_range {
+ __u64 off;
+ __u64 len;
+};
+
+struct cachestat {
+ __u64 nr_cache;
+ __u64 nr_dirty;
+ __u64 nr_writeback;
+ __u64 nr_evicted;
+ __u64 nr_recently_evicted;
+};
+
+int cachestat(unsigned int fd,
+ struct cachestat_range *cstat_range,
+ struct cachestat *cstat, unsigned int flags)
+{
+ return tst_syscall(__NR_cachestat, fd, cstat_range, cstat, flags);
+}
+#endif
+
+#endif /* CACHESTAT_H */
diff --git a/include/lapi/syscalls/aarch64.in b/include/lapi/syscalls/aarch64.in
index 2cb6c2d87..1c0218eae 100644
--- a/include/lapi/syscalls/aarch64.in
+++ b/include/lapi/syscalls/aarch64.in
@@ -297,4 +297,5 @@ faccessat2 439
epoll_pwait2 441
quotactl_fd 443
futex_waitv 449
+cachestat 451
_sysctl 1078
diff --git a/include/lapi/syscalls/arc.in b/include/lapi/syscalls/arc.in
index 3e2ee9061..5d7cd6ca4 100644
--- a/include/lapi/syscalls/arc.in
+++ b/include/lapi/syscalls/arc.in
@@ -317,3 +317,4 @@ faccessat2 439
epoll_pwait2 441
quotactl_fd 443
futex_waitv 449
+cachestat 451
diff --git a/include/lapi/syscalls/arm.in b/include/lapi/syscalls/arm.in
index 7bdbca533..e41a7e576 100644
--- a/include/lapi/syscalls/arm.in
+++ b/include/lapi/syscalls/arm.in
@@ -395,3 +395,4 @@ faccessat2 (__NR_SYSCALL_BASE+439)
epoll_pwait2 (__NR_SYSCALL_BASE+441)
quotactl_fd (__NR_SYSCALL_BASE+443)
futex_waitv (__NR_SYSCALL_BASE+449)
+cachestat (__NR_SYSCALL_BASE+451)
diff --git a/include/lapi/syscalls/hppa.in b/include/lapi/syscalls/hppa.in
index 8ebdafafb..2772e7334 100644
--- a/include/lapi/syscalls/hppa.in
+++ b/include/lapi/syscalls/hppa.in
@@ -44,3 +44,4 @@ faccessat2 439
epoll_pwait2 441
quotactl_fd 443
futex_waitv 449
+cachestat 451
diff --git a/include/lapi/syscalls/i386.in b/include/lapi/syscalls/i386.in
index 1472631c4..2d341182e 100644
--- a/include/lapi/syscalls/i386.in
+++ b/include/lapi/syscalls/i386.in
@@ -431,3 +431,4 @@ faccessat2 439
epoll_pwait2 441
quotactl_fd 443
futex_waitv 449
+cachestat 451
diff --git a/include/lapi/syscalls/ia64.in b/include/lapi/syscalls/ia64.in
index 0ea6e9722..141c6be51 100644
--- a/include/lapi/syscalls/ia64.in
+++ b/include/lapi/syscalls/ia64.in
@@ -344,3 +344,4 @@ faccessat2 1463
epoll_pwait2 1465
quotactl_fd 1467
futex_waitv 1473
+cachestat 1475
diff --git a/include/lapi/syscalls/powerpc.in b/include/lapi/syscalls/powerpc.in
index 545d9d3d6..67e928951 100644
--- a/include/lapi/syscalls/powerpc.in
+++ b/include/lapi/syscalls/powerpc.in
@@ -424,3 +424,4 @@ faccessat2 439
epoll_pwait2 441
quotactl_fd 443
futex_waitv 449
+cachestat 451
diff --git a/include/lapi/syscalls/powerpc64.in b/include/lapi/syscalls/powerpc64.in
index 545d9d3d6..67e928951 100644
--- a/include/lapi/syscalls/powerpc64.in
+++ b/include/lapi/syscalls/powerpc64.in
@@ -424,3 +424,4 @@ faccessat2 439
epoll_pwait2 441
quotactl_fd 443
futex_waitv 449
+cachestat 451
diff --git a/include/lapi/syscalls/s390.in b/include/lapi/syscalls/s390.in
index 7213ac5f8..b456ea408 100644
--- a/include/lapi/syscalls/s390.in
+++ b/include/lapi/syscalls/s390.in
@@ -411,3 +411,4 @@ faccessat2 439
epoll_pwait2 441
quotactl_fd 443
futex_waitv 449
+cachestat 451
diff --git a/include/lapi/syscalls/s390x.in b/include/lapi/syscalls/s390x.in
index 879012e2b..2c57eacdf 100644
--- a/include/lapi/syscalls/s390x.in
+++ b/include/lapi/syscalls/s390x.in
@@ -359,3 +359,4 @@ faccessat2 439
epoll_pwait2 441
quotactl_fd 443
futex_waitv 449
+cachestat 451
diff --git a/include/lapi/syscalls/sh.in b/include/lapi/syscalls/sh.in
index 7d5192a27..25eb9bb26 100644
--- a/include/lapi/syscalls/sh.in
+++ b/include/lapi/syscalls/sh.in
@@ -405,3 +405,4 @@ faccessat2 439
epoll_pwait2 441
quotactl_fd 443
futex_waitv 449
+cachestat 451
diff --git a/include/lapi/syscalls/sparc.in b/include/lapi/syscalls/sparc.in
index 91d2fb1c2..e934591dd 100644
--- a/include/lapi/syscalls/sparc.in
+++ b/include/lapi/syscalls/sparc.in
@@ -410,3 +410,4 @@ faccessat2 439
epoll_pwait2 441
quotactl_fd 443
futex_waitv 449
+cachestat 451
diff --git a/include/lapi/syscalls/sparc64.in b/include/lapi/syscalls/sparc64.in
index 1f2fc59b7..4c489e38d 100644
--- a/include/lapi/syscalls/sparc64.in
+++ b/include/lapi/syscalls/sparc64.in
@@ -375,3 +375,4 @@ faccessat2 439
epoll_pwait2 441
quotactl_fd 443
futex_waitv 449
+cachestat 451
diff --git a/include/lapi/syscalls/x86_64.in b/include/lapi/syscalls/x86_64.in
index dc61aa56e..4afea6019 100644
--- a/include/lapi/syscalls/x86_64.in
+++ b/include/lapi/syscalls/x86_64.in
@@ -352,6 +352,7 @@ faccessat2 439
epoll_pwait2 441
quotactl_fd 443
futex_waitv 449
+cachestat 451
rt_sigaction 512
rt_sigreturn 513
ioctl 514
diff --git a/runtest/syscalls b/runtest/syscalls
index 4fb76584f..b84b2d2ce 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -59,6 +59,8 @@ capset04 capset04
cacheflush01 cacheflush01
+cachestat01 cachestat01
+
chdir01 chdir01
chdir01A symlink01 -T chdir01
chdir04 chdir04
diff --git a/testcases/kernel/syscalls/cachestat/.gitignore b/testcases/kernel/syscalls/cachestat/.gitignore
new file mode 100644
index 000000000..870bceae4
--- /dev/null
+++ b/testcases/kernel/syscalls/cachestat/.gitignore
@@ -0,0 +1 @@
+/cachestat01
diff --git a/testcases/kernel/syscalls/cachestat/Makefile b/testcases/kernel/syscalls/cachestat/Makefile
new file mode 100644
index 000000000..49238eee0
--- /dev/null
+++ b/testcases/kernel/syscalls/cachestat/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (c) 2023 Wei Gao <wegao@suse.com>
+
+top_srcdir ?= ../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/syscalls/cachestat/cachestat01.c b/testcases/kernel/syscalls/cachestat/cachestat01.c
new file mode 100644
index 000000000..9ad432b59
--- /dev/null
+++ b/testcases/kernel/syscalls/cachestat/cachestat01.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023 Andre Przywara <andre.przywara@arm.com>
+ * Copyright (c) 2023 Wei Gao <wegao@suse.com>
+ *
+ */
+
+/*\
+ * [Description]
+ *
+ * Verify that cachestat() executes successfully
+ *
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include <unistd.h> /* _SC_PAGESIZE */
+#include <stdbool.h>
+#include <stdlib.h>
+#include "tst_test.h"
+#include "lapi/syscalls.h"
+#include "lapi/cachestat.h"
+
+#define SAFE_FREE(p) { if (p) { free(p); (p) = NULL; } }
+#define TMPFS_MAGIC 0x01021994
+#define TEST_NORMAL_FILE "tmpfilecachestat"
+#define SHM_FILE "tmpshmcstat"
+#define NUM_PAGES 4
+
+static int fd;
+static int fd_shm;
+static size_t PS;
+static size_t filesize;
+static char *data;
+static int random_fd;
+
+/*
+ * fsync() is implemented via noop_fsync() on tmpfs. This makes the fsync()
+ * test fail below, so we need to check for test file living on a tmpfs.
+ */
+static bool is_on_tmpfs(int fd)
+{
+ struct statfs statfs_buf;
+
+ if (fstatfs(fd, &statfs_buf))
+ return false;
+
+ return statfs_buf.f_type == TMPFS_MAGIC;
+}
+
+static void print_cachestat(struct cachestat *cs)
+{
+ tst_res(TINFO,
+ "Using cachestat: Cached: %llu, Dirty: %llu, Writeback: %llu, Evicted: %llu, Recently Evicted: %llu",
+ cs->nr_cache, cs->nr_dirty, cs->nr_writeback,
+ cs->nr_evicted, cs->nr_recently_evicted);
+}
+
+static const char * const dev_files[] = {
+ "/dev/zero", "/dev/null", "/dev/urandom",
+ "/proc/version", "/proc"
+};
+
+static bool write_exactly(int write_fd)
+{
+ char *cursor;
+ int remained;
+
+ remained = filesize;
+ cursor = data;
+ while (remained) {
+ ssize_t read_len = SAFE_READ(1, random_fd, cursor, remained);
+
+ if (read_len <= 0)
+ tst_brk(TBROK | TERRNO, "Unable to read from urandom.");
+
+ remained -= read_len;
+ cursor += read_len;
+ }
+
+ remained = filesize;
+ cursor = data;
+ while (remained) {
+ ssize_t write_len = SAFE_WRITE(1, write_fd, cursor, remained);
+
+ if (write_len <= 0)
+ tst_brk(TBROK | TERRNO, "Unable write random data to file.");
+
+ remained -= write_len;
+ cursor += write_len;
+ }
+
+ return true;
+}
+
+/*
+ * Open/create the file at filename, (optionally) write random data to it
+ * (exactly num_pages), then test the cachestat syscall on this file.
+ *
+ * If test_fsync == true, fsync the file, then check the number of dirty
+ * pages.
+ */
+static void test_cachestat(const char *filename, bool write_random, bool create,
+ bool test_fsync, int open_flags, mode_t open_mode)
+{
+ struct cachestat cs;
+ struct cachestat_range cs_range = { 0, filesize };
+
+ if (!fcntl(fd, F_GETFD))
+ SAFE_CLOSE(fd);
+ fd = SAFE_OPEN(filename, open_flags, open_mode);
+
+ if (write_random) {
+ if (!write_exactly(fd))
+ tst_brk(TBROK | TERRNO, "Unable to access urandom.");
+ }
+
+ TST_EXP_PASS(cachestat(fd, &cs_range, &cs, 0));
+
+ print_cachestat(&cs);
+
+ if (write_random) {
+ if (cs.nr_cache + cs.nr_evicted != NUM_PAGES) {
+ tst_brk(TBROK | TERRNO,
+ "Total number of cached and evicted pages is off.");
+ }
+ }
+
+ if (test_fsync) {
+ if (is_on_tmpfs(fd)) {
+ tst_res(TCONF, "skip fsync check on tmpfs");
+ } else if (fsync(fd)) {
+ tst_brk(TBROK | TERRNO, "fsync fails.");
+ } else {
+ TST_EXP_PASS(cachestat(fd, &cs_range, &cs, 0));
+ print_cachestat(&cs);
+ if (cs.nr_dirty) {
+ tst_brk(TBROK | TERRNO,
+ "Number of dirty should be zero after fsync.");
+ } else {
+ tst_res(TPASS, "Cachestat (after fsync) pass.");
+ }
+ }
+ }
+
+ close(fd);
+
+ if (create)
+ remove(filename);
+
+ tst_res(TPASS, "cachestat works with file %s", filename);
+}
+
+static void test_incorrect_file(void)
+{
+ TST_EXP_FAIL(cachestat(-1, NULL, NULL, 0), EBADF);
+}
+
+static void test_virtual_file(void)
+{
+ for (unsigned long i = 0; i < sizeof(dev_files) / sizeof(*dev_files); i++) {
+ const char *dev_filename = dev_files[i];
+
+ test_cachestat(dev_filename, false, false, false, O_RDONLY, 0400);
+ }
+}
+
+static void test_normal_file(void)
+{
+ test_cachestat(TEST_NORMAL_FILE, true, true, false, O_CREAT | O_RDWR, 0600);
+ test_cachestat(TEST_NORMAL_FILE, true, true, true, O_CREAT | O_RDWR, 0600);
+}
+
+static void check_cachestat_range(struct cachestat_range *ptr_cs_range, __u64 expect_num_pages)
+{
+ struct cachestat cs;
+
+ TST_EXP_PASS(cachestat(fd_shm, ptr_cs_range, &cs, 0));
+ print_cachestat(&cs);
+ if (cs.nr_cache + cs.nr_evicted != expect_num_pages) {
+ tst_brk(TFAIL | TERRNO,
+ "Total number of cached and evicted pages is off.");
+ } else {
+ tst_res(TPASS,
+ "Cachestat range check pass.");
+ }
+}
+
+static void test_share_memory(void)
+{
+
+ struct cachestat_range cs_range = { 0, filesize};
+
+ if (ftruncate(fd_shm, filesize))
+ tst_brk(TFAIL | TERRNO, "Unable to truncate shmem file.");
+
+ if (!write_exactly(fd_shm))
+ tst_brk(TFAIL | TERRNO, "Unable to write to shmem file.");
+
+ check_cachestat_range(&cs_range, NUM_PAGES);
+
+ size_t compute_len = PS * NUM_PAGES / 2;
+ unsigned long num_pages = ceil((double)NUM_PAGES / 2);
+
+ cs_range.off = PS;
+ cs_range.len = compute_len;
+ check_cachestat_range(&cs_range, num_pages);
+}
+
+static struct tcase {
+ void (*tfunc)(void);
+} tcases[] = {
+ {&test_incorrect_file},
+ {&test_virtual_file},
+ {&test_normal_file},
+ {&test_share_memory}
+};
+
+static void run(unsigned int i)
+{
+ tcases[i].tfunc();
+}
+
+
+static void setup(void)
+{
+
+ PS = sysconf(_SC_PAGESIZE);
+ filesize = NUM_PAGES * PS;
+ data = tst_alloc(filesize);
+ random_fd = SAFE_OPEN("/dev/urandom", O_RDONLY);
+
+ /* setup for test_share_memory case */
+ fd_shm = shm_open(SHM_FILE, O_CREAT | O_RDWR, 0700);
+ if (fd_shm < 0)
+ tst_brk(TFAIL | TERRNO, "Unable to create shmem file.");
+}
+
+static void cleanup(void)
+{
+ SAFE_CLOSE(random_fd);
+
+ /* cleanup for test_normal_file case*/
+ if (!fcntl(fd, F_GETFD))
+ SAFE_CLOSE(fd);
+ remove(TEST_NORMAL_FILE);
+
+ /* cleanup for test_share_memory case */
+ SAFE_CLOSE(fd_shm);
+ shm_unlink(SHM_FILE);
+}
+
+static struct tst_test test = {
+ .test = run,
+ .tcnt = ARRAY_SIZE(tcases),
+ .setup = setup,
+ .cleanup = cleanup,
+ .needs_tmpdir = 1,
+ .min_kver = "6.5.0"
+};
--
2.35.3
More information about the ltp
mailing list