mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-08-09 06:14:34 +02:00
The cgroup utility code defines a local PAGE_SIZE macro hardcoded to 4096, which is used primarily as a generic buffer size for reading cgroup and proc files. This naming is misleading because the value has nothing to do with the actual page size of the system. On architectures with larger pages (e.g., 64K on arm64 or ppc64), the name suggests a relationship that does not exist. Additionally, the name can shadow or conflict with PAGE_SIZE definitions from system headers, leading to confusion or subtle bugs. To resolve this, rename the macro to BUF_SIZE to accurately reflect its purpose as a general I/O buffer size. Furthermore, test_memcontrol currently relies on this hardcoded 4K value to stride through memory and trigger page faults. Update this logic to use the actual system page size dynamically. This micro-optimizes the memory faulting process by ensuring it iterates correctly and efficiently based on the underlying architecture's true page size. (This part from Waiman) Link: https://lore.kernel.org/20260424040059.12940-5-li.wang@linux.dev Signed-off-by: Li Wang <li.wang@linux.dev> Signed-off-by: Waiman Long <longman@redhat.com> Acked-by: Nhat Pham <nphamcs@gmail.com> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Michal Hocko <mhocko@kernel.org> Cc: Michal Koutný <mkoutny@suse.com> Cc: Muchun Song <muchun.song@linux.dev> Cc: Tejun Heo <tj@kernel.org> Cc: Roman Gushchin <roman.gushchin@linux.dev> Cc: Shakeel Butt <shakeel.butt@linux.dev> Cc: Yosry Ahmed <yosryahmed@google.com> Cc: Chengming Zhou <chengming.zhou@linux.dev> Cc: Jiayuan Chen <jiayuan.chen@linux.dev> Cc: Yosry Ahmed <yosry@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
101 lines
3.9 KiB
C
101 lines
3.9 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
|
|
#ifndef BUF_SIZE
|
|
#define BUF_SIZE 4096
|
|
#endif
|
|
|
|
#define MB(x) (x << 20)
|
|
|
|
#define USEC_PER_SEC 1000000L
|
|
#define NSEC_PER_SEC 1000000000L
|
|
|
|
#define TEST_UID 65534 /* usually nobody, any !root is fine */
|
|
|
|
#define CG_THREADS_FILE (!cg_test_v1_named ? "cgroup.threads" : "tasks")
|
|
#define CG_NAMED_NAME "selftest"
|
|
#define CG_PATH_FORMAT (!cg_test_v1_named ? "0::%s" : (":name=" CG_NAMED_NAME ":%s"))
|
|
|
|
#define DEFAULT_WAIT_INTERVAL_US (100 * 1000) /* 100 ms */
|
|
|
|
/*
|
|
* Checks if two given values differ by less than err% of their sum.
|
|
*/
|
|
static inline int values_close(long a, long b, int err)
|
|
{
|
|
return labs(a - b) <= (a + b) / 100 * err;
|
|
}
|
|
|
|
/*
|
|
* Checks if two given values differ by less than err% of their sum and assert
|
|
* with detailed debug info if not.
|
|
*/
|
|
static inline int values_close_report(long a, long b, int err)
|
|
{
|
|
long diff = labs(a - b);
|
|
long limit = (a + b) / 100 * err;
|
|
double actual_err = (a + b) ? (100.0 * diff / (a + b)) : 0.0;
|
|
int close = diff <= limit;
|
|
|
|
if (!close)
|
|
fprintf(stderr,
|
|
"[FAIL] actual=%ld expected=%ld | diff=%ld | limit=%ld | "
|
|
"tolerance=%d%% | actual_error=%.2f%%\n",
|
|
a, b, diff, limit, err, actual_err);
|
|
|
|
return close;
|
|
}
|
|
|
|
extern ssize_t read_text(const char *path, char *buf, size_t max_len);
|
|
extern ssize_t write_text(const char *path, char *buf, ssize_t len);
|
|
|
|
extern int cg_find_controller_root(char *root, size_t len, const char *controller);
|
|
extern int cg_find_unified_root(char *root, size_t len, bool *nsdelegate);
|
|
extern char *cg_name(const char *root, const char *name);
|
|
extern char *cg_name_indexed(const char *root, const char *name, int index);
|
|
extern char *cg_control(const char *cgroup, const char *control);
|
|
extern int cg_create(const char *cgroup);
|
|
extern int cg_destroy(const char *cgroup);
|
|
extern int cg_read(const char *cgroup, const char *control,
|
|
char *buf, size_t len);
|
|
extern int cg_read_strcmp(const char *cgroup, const char *control,
|
|
const char *expected);
|
|
extern int cg_read_strcmp_wait(const char *cgroup, const char *control,
|
|
const char *expected);
|
|
extern int cg_read_strstr(const char *cgroup, const char *control,
|
|
const char *needle);
|
|
extern long cg_read_long(const char *cgroup, const char *control);
|
|
extern long cg_read_long_fd(int fd);
|
|
long cg_read_key_long(const char *cgroup, const char *control, const char *key);
|
|
long cg_read_key_long_poll(const char *cgroup, const char *control,
|
|
const char *key, long expected, int retries,
|
|
useconds_t wait_interval_us);
|
|
extern long cg_read_lc(const char *cgroup, const char *control);
|
|
extern int cg_write(const char *cgroup, const char *control, char *buf);
|
|
extern int cg_open(const char *cgroup, const char *control, int flags);
|
|
int cg_write_numeric(const char *cgroup, const char *control, long value);
|
|
extern int cg_run(const char *cgroup,
|
|
int (*fn)(const char *cgroup, void *arg),
|
|
void *arg);
|
|
extern int cg_enter(const char *cgroup, int pid);
|
|
extern int cg_enter_current(const char *cgroup);
|
|
extern int cg_enter_current_thread(const char *cgroup);
|
|
extern int cg_run_nowait(const char *cgroup,
|
|
int (*fn)(const char *cgroup, void *arg),
|
|
void *arg);
|
|
extern int cg_wait_for_proc_count(const char *cgroup, int count);
|
|
extern int cg_killall(const char *cgroup);
|
|
int proc_mount_contains(const char *option);
|
|
int cgroup_feature(const char *feature);
|
|
extern ssize_t proc_read_text(int pid, bool thread, const char *item, char *buf, size_t size);
|
|
extern int proc_read_strstr(int pid, bool thread, const char *item, const char *needle);
|
|
extern pid_t clone_into_cgroup(int cgroup_fd);
|
|
extern int clone_reap(pid_t pid, int options);
|
|
extern int clone_into_cgroup_run_wait(const char *cgroup);
|
|
extern int dirfd_open_opath(const char *dir);
|
|
extern int cg_prepare_for_wait(const char *cgroup);
|
|
extern int memcg_prepare_for_wait(const char *cgroup);
|
|
extern int cg_wait_for(int fd);
|
|
extern bool cg_test_v1_named;
|