xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/cma/process_vm_readv03.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) International Business Machines  Corp., 2012
4  * Copyright (c) Linux Test Project, 2012
5  * Copyright (C) 2021 SUSE LLC Andrea Cervesato <[email protected]>
6  */
7 
8 /*\
9  * [Description]
10  *
11  * Fork two children, one child mallocs randomly sized trunks of memory
12  * and initializes them; the other child calls process_vm_readv with
13  * the remote iovecs initialized to the original process memory
14  * locations and the local iovecs initialized to randomly sized and
15  * allocated local memory locations. The second child then verifies
16  * that the data is copied correctly.
17  */
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <sys/types.h>
22 #include <sys/wait.h>
23 #include "tst_test.h"
24 #include "lapi/syscalls.h"
25 
26 #define MAX_IOVECS 1024
27 
28 static struct tcase {
29 	int bufsize;
30 	int remote_iovecs;
31 	int local_iovecs;
32 } testcases[] = {
33 	{ .bufsize = 1024, .remote_iovecs = 1024, .local_iovecs = 8 },
34 	{ .bufsize = 1024, .remote_iovecs = 512, .local_iovecs = 16 },
35 	{ .bufsize = 1024, .remote_iovecs = 256, .local_iovecs = 32 },
36 	{ .bufsize = 1024, .remote_iovecs = 128, .local_iovecs = 64 },
37 	{ .bufsize = 1024, .remote_iovecs = 64, .local_iovecs = 128 },
38 	{ .bufsize = 1024, .remote_iovecs = 32, .local_iovecs = 256 },
39 	{ .bufsize = 1024, .remote_iovecs = 16, .local_iovecs = 512 },
40 	{ .bufsize = 1024, .remote_iovecs = 8, .local_iovecs = 1024 },
41 
42 	{ .bufsize = 131072, .remote_iovecs = 1024, .local_iovecs = 8 },
43 	{ .bufsize = 131072, .remote_iovecs = 512, .local_iovecs = 16 },
44 	{ .bufsize = 131072, .remote_iovecs = 256, .local_iovecs = 32 },
45 	{ .bufsize = 131072, .remote_iovecs = 128, .local_iovecs = 64 },
46 	{ .bufsize = 131072, .remote_iovecs = 64, .local_iovecs = 128 },
47 	{ .bufsize = 131072, .remote_iovecs = 32, .local_iovecs = 256 },
48 	{ .bufsize = 131072, .remote_iovecs = 16, .local_iovecs = 512 },
49 	{ .bufsize = 131072, .remote_iovecs = 8, .local_iovecs = 1024 },
50 };
51 
52 static char **data_ptr;
53 
create_data_size(int * arr,int arr_sz,int buffsize)54 static void create_data_size(int *arr, int arr_sz, int buffsize)
55 {
56 	long bufsz_left;
57 	int i;
58 
59 	bufsz_left = buffsize;
60 	for (i = 0; i < arr_sz - 1; i++) {
61 		arr[i] = rand() % ((bufsz_left / 2) + 1);
62 		bufsz_left -= arr[i];
63 	}
64 
65 	arr[arr_sz - 1] = bufsz_left;
66 }
67 
child_alloc(const int * sizes,int nr_iovecs)68 static void child_alloc(const int *sizes, int nr_iovecs)
69 {
70 	int i, j;
71 	long count;
72 
73 	count = 0;
74 	for (i = 0; i < nr_iovecs; i++) {
75 		data_ptr[i] = sizes[i] ? SAFE_MALLOC(sizes[i]) : NULL;
76 
77 		for (j = 0; j < sizes[i]; j++) {
78 			data_ptr[i][j] = count % 256;
79 			count++;
80 		}
81 	}
82 
83 	tst_res(TINFO, "child_alloc: memory allocated and initialized");
84 
85 	TST_CHECKPOINT_WAKE_AND_WAIT(0);
86 }
87 
child_read(const int * sizes,int local_iovecs,int remote_iovecs,pid_t pid_alloc,int buffsize)88 static void child_read(const int *sizes, int local_iovecs, int remote_iovecs,
89 			 pid_t pid_alloc, int buffsize)
90 {
91 	struct iovec local[local_iovecs];
92 	struct iovec remote[remote_iovecs];
93 	int i, j;
94 	int count;
95 	int nr_error;
96 	int local_sizes[local_iovecs];
97 	unsigned char expect, actual;
98 
99 	for (i = 0; i < remote_iovecs; i++) {
100 		remote[i].iov_base = (void *)data_ptr[i];
101 		remote[i].iov_len = sizes[i];
102 	}
103 
104 	create_data_size(local_sizes, local_iovecs, buffsize);
105 	for (i = 0; i < local_iovecs; i++) {
106 		local[i].iov_base = SAFE_MALLOC(local_sizes[i]);
107 		local[i].iov_len = local_sizes[i];
108 	}
109 
110 	tst_res(TINFO, "child_read: reading string from same memory location");
111 
112 	TST_EXP_POSITIVE(tst_syscall(__NR_process_vm_readv, pid_alloc, local,
113 				     local_iovecs, remote, remote_iovecs, 0UL),
114 			 "process_vm_read()");
115 
116 	if (TST_RET != buffsize) {
117 		tst_brk(TBROK, "process_vm_readv: expected %d bytes but got %ld",
118 			buffsize, TST_RET);
119 	}
120 
121 	count = 0;
122 	nr_error = 0;
123 	for (i = 0; i < local_iovecs; i++) {
124 		for (j = 0; j < (int)local[i].iov_len; j++) {
125 			expect = count % 256;
126 			actual = ((unsigned char *)local[i].iov_base)[j];
127 			if (expect != actual)
128 				nr_error++;
129 
130 			count++;
131 		}
132 	}
133 
134 	if (nr_error)
135 		tst_brk(TFAIL, "child_read: %d incorrect bytes received", nr_error);
136 	else
137 		tst_res(TPASS, "child_read: all bytes are correctly received");
138 }
139 
setup(void)140 static void setup(void)
141 {
142 	tst_syscall(__NR_process_vm_readv, getpid(), NULL, 0UL, NULL, 0UL, 0UL);
143 
144 	data_ptr = SAFE_MMAP(NULL, sizeof(void *) * MAX_IOVECS, PROT_READ | PROT_WRITE,
145 			     MAP_SHARED | MAP_ANONYMOUS, -1, 0);
146 }
147 
cleanup(void)148 static void cleanup(void)
149 {
150 	if (data_ptr)
151 		SAFE_MUNMAP(data_ptr, sizeof(void *) * MAX_IOVECS);
152 }
153 
run(unsigned int i)154 static void run(unsigned int i)
155 {
156 	int bufsize = testcases[i].bufsize;
157 	int remote_iovecs = testcases[i].remote_iovecs;
158 	int local_iovecs = testcases[i].local_iovecs;
159 	pid_t pid_alloc;
160 	pid_t pid_read;
161 	int status;
162 	int sizes[remote_iovecs];
163 
164 	tst_res(TINFO, "bufsize=%d, remote_iovecs=%d, local_iovecs=%d", bufsize,
165 		remote_iovecs, local_iovecs);
166 
167 	create_data_size(sizes, remote_iovecs, bufsize);
168 
169 	pid_alloc = SAFE_FORK();
170 	if (!pid_alloc) {
171 		child_alloc(sizes, remote_iovecs);
172 		return;
173 	}
174 
175 	TST_CHECKPOINT_WAIT(0);
176 
177 	pid_read = SAFE_FORK();
178 	if (!pid_read) {
179 		child_read(sizes, local_iovecs, remote_iovecs, pid_alloc, bufsize);
180 		return;
181 	}
182 
183 	SAFE_WAITPID(pid_read, &status, 0);
184 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
185 		tst_res(TFAIL, "child_read: %s", tst_strstatus(status));
186 
187 	TST_CHECKPOINT_WAKE(0);
188 }
189 
190 static struct tst_test test = {
191 	.test = run,
192 	.setup = setup,
193 	.cleanup = cleanup,
194 	.forks_child = 1,
195 	.needs_checkpoints = 1,
196 	.tcnt = ARRAY_SIZE(testcases),
197 };
198