summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSwarup Laxman Kotiaklapudi <swarupkotikalapudi@gmail.com>2023-10-09 14:07:14 +0300
committerAndrew Morton <akpm@linux-foundation.org>2023-10-18 14:43:22 -0700
commit6e79b375adb38219099d7e3ccc973a7808108a3e (patch)
tree6e01ab95e33ad0f3073ab8e02ce8c8a2134216da
parent598f0ac1500d7145c696de4d38797b1dd2c651de (diff)
downloadlinux-stable-6e79b375adb38219099d7e3ccc973a7808108a3e.tar.gz
linux-stable-6e79b375adb38219099d7e3ccc973a7808108a3e.tar.bz2
linux-stable-6e79b375adb38219099d7e3ccc973a7808108a3e.zip
proc: test /proc/${pid}/statm
My original comment lied, output can be "0 A A B 0 0 0\n" (see comment in the code). I don't quite understand why get_mm_counter(mm, MM_FILEPAGES) + get_mm_counter(mm, MM_SHMEMPAGES) can stay positive but get_mm_counter(mm, MM_ANONPAGES) is always 0 after everything is unmapped but that's just me. [adobriyan@gmail.com: more or less rewritten] Link: https://lkml.kernel.org/r/0721ca69-7bb4-40aa-8d01-0c5f91e5f363@p183 Signed-off-by: Swarup Laxman Kotiaklapudi <swarupkotikalapudi@gmail.com> Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
-rw-r--r--tools/testing/selftests/proc/proc-empty-vm.c97
1 files changed, 92 insertions, 5 deletions
diff --git a/tools/testing/selftests/proc/proc-empty-vm.c b/tools/testing/selftests/proc/proc-empty-vm.c
index ee71ce52cb6a..171d46a1ac27 100644
--- a/tools/testing/selftests/proc/proc-empty-vm.c
+++ b/tools/testing/selftests/proc/proc-empty-vm.c
@@ -303,6 +303,95 @@ static int test_proc_pid_smaps_rollup(pid_t pid)
}
}
+static const char *parse_u64(const char *p, const char *const end, uint64_t *rv)
+{
+ *rv = 0;
+ for (; p != end; p += 1) {
+ if ('0' <= *p && *p <= '9') {
+ assert(!__builtin_mul_overflow(*rv, 10, rv));
+ assert(!__builtin_add_overflow(*rv, *p - '0', rv));
+ } else {
+ break;
+ }
+ }
+ assert(p != end);
+ return p;
+}
+
+/*
+ * There seems to be 2 types of valid output:
+ * "0 A A B 0 0 0\n" for dynamic exeuctables,
+ * "0 0 0 B 0 0 0\n" for static executables.
+ */
+static int test_proc_pid_statm(pid_t pid)
+{
+ char buf[4096];
+ snprintf(buf, sizeof(buf), "/proc/%u/statm", pid);
+ int fd = open(buf, O_RDONLY);
+ if (fd == -1) {
+ perror("open /proc/${pid}/statm");
+ return EXIT_FAILURE;
+ }
+
+ ssize_t rv = read(fd, buf, sizeof(buf));
+ close(fd);
+
+ assert(rv >= 0);
+ assert(rv <= sizeof(buf));
+ if (0) {
+ write(1, buf, rv);
+ }
+
+ const char *p = buf;
+ const char *const end = p + rv;
+
+ /* size */
+ assert(p != end && *p++ == '0');
+ assert(p != end && *p++ == ' ');
+
+ uint64_t resident;
+ p = parse_u64(p, end, &resident);
+ assert(p != end && *p++ == ' ');
+
+ uint64_t shared;
+ p = parse_u64(p, end, &shared);
+ assert(p != end && *p++ == ' ');
+
+ uint64_t text;
+ p = parse_u64(p, end, &text);
+ assert(p != end && *p++ == ' ');
+
+ assert(p != end && *p++ == '0');
+ assert(p != end && *p++ == ' ');
+
+ /* data */
+ assert(p != end && *p++ == '0');
+ assert(p != end && *p++ == ' ');
+
+ assert(p != end && *p++ == '0');
+ assert(p != end && *p++ == '\n');
+
+ assert(p == end);
+
+ /*
+ * "text" is "mm->end_code - mm->start_code" at execve(2) time.
+ * munmap() doesn't change it. It can be anything (just link
+ * statically). It can't be 0 because executing to this point
+ * implies at least 1 page of code.
+ */
+ assert(text > 0);
+
+ /*
+ * These two are always equal. Always 0 for statically linked
+ * executables and sometimes 0 for dynamically linked executables.
+ * There is no way to tell one from another without parsing ELF
+ * which is too much for this test.
+ */
+ assert(resident == shared);
+
+ return EXIT_SUCCESS;
+}
+
int main(void)
{
int rv = EXIT_SUCCESS;
@@ -389,11 +478,9 @@ int main(void)
if (rv == EXIT_SUCCESS) {
rv = test_proc_pid_smaps_rollup(pid);
}
- /*
- * TODO test /proc/${pid}/statm, task_statm()
- * ->start_code, ->end_code aren't updated by munmap().
- * Output can be "0 0 0 2 0 0 0\n" where "2" can be anything.
- */
+ if (rv == EXIT_SUCCESS) {
+ rv = test_proc_pid_statm(pid);
+ }
/* Cut the rope. */
int wstatus;