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

