[Devel] [PATCH vz10 v4 2/2] selftests: cgroup: test numa migration of lruvecs

Pavel Tikhomirov ptikhomirov at virtuozzo.com
Mon Dec 8 08:53:51 MSK 2025


> +static int thp_shmem_control(bool do_set)
> +{
> +	static char thp_shmem_control_str[PAGE_SIZE];
> +
> +	int fd;
> +	size_t len;
> +	ssize_t count;
> +	char *control;
> +	char control_buf[PAGE_SIZE];
> +	int ret = EXIT_SUCCESS;
> +	static const char *delim = "[]";
> +	static const char *advise = "advise";
> +
> +	fd = open("/sys/kernel/mm/transparent_hugepage/shmem_enabled", O_RDWR);
> +	if (fd < 0) {
> +		ksft_perror("failed to open thp control");
> +		return EXIT_FAILURE;
> +	}
> +
> +	if (do_set) {
> +		if (strlen(thp_shmem_control_str) != 0) {
> +			ksft_print_msg("thp control has already been set\n");
> +			goto out;
> +
> +		}
> +		count = read(fd, control_buf, PAGE_SIZE - 1);
> +		if (count < 0) {
> +			ksft_perror("failed to read thp control");
> +			ret = EXIT_FAILURE;
> +			goto out;
> +		};
> +		control_buf[count] = '\0';
> +
> +		control = strtok(control_buf, delim);
> +		if (control_buf[0] != '[')

After we call strtok on control_buf, we should not use control_buf anymore as strtok man suggests that strtok can modify the first argument, and we can see there something which was not there originally.

> +			control = strtok(NULL, delim);
> +
> +		len = strlen(advise);
> +		if (write(fd, advise, len) != len) {
> +			ksft_print_msg("failed to write thp control");
> +			ret = EXIT_FAILURE;
> +			goto out;
> +		}
> +		strncpy(thp_shmem_control_str, control, PAGE_SIZE - 1);
> +	} else {
...
> +static void verify_stats(struct test_context *ctx, const char *cgroup,
> +			 const char *stat)
> +{
> +	int parsed_nodes;
> +	int n;
> +	size_t per_node;
> +	size_t node_stat[NUMA_NUM_NODES];
> +	int ret = EXIT_SUCCESS;
> +	int retries_left = 100; /* 10s */
> +
> +	EXPAND_CTX(ctx);
> +retry:
> +	retries_left--;
> +	memset(node_stat, 0, node_count * sizeof(size_t));
> +
> +	parsed_nodes = parse_memory_numa_stat(ctx, cgroup, stat, node_stat);
> +	ASSERT_EQ(node_count, parsed_nodes)
> +		ksft_print_msg("failed to parse numa stat\n");
> +
> +	/* values_close() does not work well with 0 */
> +	if (node_stat[src_node] > file_size / 100 * 15) {
> +		if (retries_left > 0) {
> +			usleep(100000); /* 100ms */
> +			goto retry;
> +		}
> +		ksft_print_msg("too much memory left on node%i\n",
> +				src_node);
> +		ret = EXIT_FAILURE;
> +		goto dump_stat;
> +	}
> +
> +	per_node = file_size / dst_count;
> +	for (n = 0; n < numa_max_possible_node(); n++) {
> +		if (numa_bitmask_isbitset(dst_mask, n) &&
> +		!values_close(node_stat[n], per_node, 15)) {
> +			if (retries_left > 0) {
> +				usleep(100000); /* 100ms */
> +				goto retry;
> +			}
> +			ksft_print_msg("not enough memory moved to node%i\n", n);
> +			ret = EXIT_FAILURE;
> +		}
> +	}
> +
> +dump_stat:
> +	if (ret != EXIT_SUCCESS) {
> +		ksft_print_msg("size=%li\n", file_size);

%zu for size_t

> +		dump_memory_numa_stat(node_stat);
> +	}
> +
> +	ASSERT_EQ(EXIT_SUCCESS, ret);
> +}
> +

-- 
Best regards, Pavel Tikhomirov
Senior Software Developer, Virtuozzo.



More information about the Devel mailing list