read_text() issues a single read(2) and returns whatever it got, so a
caller that asks for a whole file silently gets a prefix of it instead.
For a seq_file larger than one page it never gets more than that prefix:
seq_read_iter() copies out at most one internal PAGE_SIZE buffer per call
and leaves the rest for the next read(2), no matter how much room the
caller's buffer has.

/proc/self/mounts is one of those files, so cg_find_root() only ever sees
the first 4K of the mount table.  On a machine with ~80 mounts the cgroup2
entry already sits past that limit: the file is 7177 bytes, the single
read(2) into the 40K buffer in cg_find_root() returns 4035 bytes, and the
cgroup2 line starts at offset 4953.  cg_find_root() then fails, and every
test that calls cg_find_unified_root() -- test_core, test_cpu, test_cpuset,
test_freezer, test_hugetlb_memcg, test_kill, test_kmem, test_memcontrol,
test_pids and test_zswap -- exits with SKIP "cgroup v2 isn't mounted"
without running a single test.

proc_mount_contains() searches only that same prefix, so a mount option
listed later in /proc/mounts is reported as absent, which is what the
probes in test_memcontrol and test_hugetlb_memcg are based on.

Read until the buffer is full or EOF instead.  A partial read is still
possible when max_len is too small, so callers that deliberately read a
prefix, such as cg_read_strcmp(), keep working.

Signed-off-by: Shaojie Sun <[email protected]>
---
 .../selftests/cgroup/lib/cgroup_util.c        | 35 +++++++++++++++----
 1 file changed, 29 insertions(+), 6 deletions(-)

diff --git a/tools/testing/selftests/cgroup/lib/cgroup_util.c 
b/tools/testing/selftests/cgroup/lib/cgroup_util.c
index 2596c12cd864..65cd85c467bb 100644
--- a/tools/testing/selftests/cgroup/lib/cgroup_util.c
+++ b/tools/testing/selftests/cgroup/lib/cgroup_util.c
@@ -24,20 +24,43 @@ bool cg_test_v1_named;
 /* Returns read len on success, or -errno on failure. */
 ssize_t read_text(const char *path, char *buf, size_t max_len)
 {
-       ssize_t len;
+       size_t total = 0;
+       ssize_t len, ret;
        int fd;
 
        fd = open(path, O_RDONLY);
        if (fd < 0)
                return -errno;
 
-       len = read(fd, buf, max_len - 1);
-
-       if (len >= 0)
-               buf[len] = 0;
+       /*
+        * A single read() is not enough.  procfs and sysfs are backed by
+        * seq_file, and seq_read_iter() copies out at most one internal
+        * buffer (PAGE_SIZE) per call, leaving the rest for the next read().
+        * Reading only once therefore silently drops everything past the
+        * first page, no matter how big the caller's buffer is.
+        *
+        * Loop until the buffer is full or EOF.  A full buffer still means
+        * the file may be longer than max_len, but that is now limited by
+        * the caller's buffer rather than by a page of seq_file output.
+        */
+       while (total < max_len - 1) {
+               len = read(fd, buf + total, max_len - 1 - total);
+               if (len < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       ret = -errno;
+                       goto out;
+               }
+               if (!len)
+                       break;
+               total += len;
+       }
 
+       buf[total] = 0;
+       ret = total;
+out:
        close(fd);
-       return len < 0 ? -errno : len;
+       return ret;
 }
 
 /* Returns written len on success, or -errno on failure. */
-- 
2.50.1


Reply via email to