blob: 301293fb15cc7016d14df109934e6dd923ec42c2 [file] [log] [blame]
Caspar Zhanga2339012012-07-16 17:52:08 +08001/*
2 * Copyright (c) International Business Machines Corp., 2012
3 * Copyright (c) Linux Test Project, 2012
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
Wanlong Gao4548c6c2012-10-19 18:03:36 +080017 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Caspar Zhanga2339012012-07-16 17:52:08 +080018 */
19
20#define _GNU_SOURCE
21#include <sys/types.h>
22#include <sys/uio.h>
23#include <sys/wait.h>
24#include <errno.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
29
30#include "test.h"
Caspar Zhanga2339012012-07-16 17:52:08 +080031#include "safe_macros.h"
32#include "process_vm.h"
33
34char *TCID = "process_vm_writev02";
35int TST_TOTAL = 1;
36
37#define PADDING_SIZE 10
38#define DEFAULT_CHAR 53
39
40static int sflag;
41static char *sz_opt;
42static option_t options[] = {
Wanlong Gao354ebb42012-12-07 10:10:04 +080043 {"s:", &sflag, &sz_opt},
44 {NULL, NULL, NULL}
Caspar Zhanga2339012012-07-16 17:52:08 +080045};
46
47static long bufsz;
48static int pipe_fd[2];
49static pid_t pids[2];
50static int semid;
51
52static void child_init_and_verify(void);
53static void child_write(void);
54static void setup(void);
55static void cleanup(void);
56static void help(void);
57
58int main(int argc, char **argv)
59{
60 int lc, status;
Cyril Hrubis0b9589f2014-05-27 17:40:33 +020061 const char *msg;
Caspar Zhanga2339012012-07-16 17:52:08 +080062
63 msg = parse_opts(argc, argv, options, &help);
64 if (msg != NULL)
65 tst_brkm(TBROK, tst_exit, "OPTION PARSING ERROR - %s", msg);
66
67 setup();
68 for (lc = 0; TEST_LOOPING(lc); lc++) {
Caspar Zhangd59a6592013-03-07 14:59:12 +080069 tst_count = 0;
Caspar Zhanga2339012012-07-16 17:52:08 +080070
71 if (pipe(pipe_fd) < 0)
Wanlong Gao354ebb42012-12-07 10:10:04 +080072 tst_brkm(TBROK | TERRNO, cleanup, "pipe");
Caspar Zhanga2339012012-07-16 17:52:08 +080073
74 /* the start of child_init_and_verify and child_write is
75 * already synchronized via pipe */
76 pids[0] = fork();
77 switch (pids[0]) {
78 case -1:
Wanlong Gao354ebb42012-12-07 10:10:04 +080079 tst_brkm(TBROK | TERRNO, cleanup, "fork #0");
Caspar Zhanga2339012012-07-16 17:52:08 +080080 case 0:
81 child_init_and_verify();
82 exit(0);
83 default:
84 break;
85 }
86
87 pids[1] = fork();
88 switch (pids[1]) {
89 case -1:
Wanlong Gao354ebb42012-12-07 10:10:04 +080090 tst_brkm(TBROK | TERRNO, cleanup, "fork #1");
Caspar Zhanga2339012012-07-16 17:52:08 +080091 case 0:
92 child_write();
93 exit(0);
94 }
95
96 /* wait until child_write writes into
97 * child_init_and_verify's VM */
98 if (waitpid(pids[1], &status, 0) == -1)
Wanlong Gao354ebb42012-12-07 10:10:04 +080099 tst_brkm(TBROK | TERRNO, cleanup, "waitpid");
Caspar Zhanga2339012012-07-16 17:52:08 +0800100 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
101 tst_resm(TFAIL, "child 1 returns %d", status);
102
103 /* signal child_init_and_verify to verify its VM now */
104 safe_semop(semid, 0, 1);
105
106 if (waitpid(pids[0], &status, 0) == -1)
Wanlong Gao354ebb42012-12-07 10:10:04 +0800107 tst_brkm(TBROK | TERRNO, cleanup, "waitpid");
Caspar Zhanga2339012012-07-16 17:52:08 +0800108 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
109 tst_resm(TFAIL, "child 0 returns %d", status);
110 }
111
112 cleanup();
113 tst_exit();
114}
115
116static void child_init_and_verify(void)
117{
118 unsigned char *foo;
119 char buf[bufsz];
120 long i, nr_err;
121
122 foo = SAFE_MALLOC(tst_exit, bufsz);
123 for (i = 0; i < bufsz; i++)
124 foo[i] = DEFAULT_CHAR;
125 tst_resm(TINFO, "child 0: memory allocated.");
126
127 /* passing addr of string "foo" via pipe */
128 SAFE_CLOSE(tst_exit, pipe_fd[0]);
129 snprintf(buf, bufsz, "%p", foo);
130 SAFE_WRITE(tst_exit, 1, pipe_fd[1], buf, strlen(buf));
131 SAFE_CLOSE(tst_exit, pipe_fd[1]);
132
133 /* wait until child_write() is done writing to our VM */
134 safe_semop(semid, 0, -1);
135
136 nr_err = 0;
137 for (i = 0; i < bufsz; i++) {
138 if (foo[i] != i % 256) {
139#if DEBUG
140 tst_resm(TFAIL, "child 0: expected %i, got %i for "
Wanlong Gao354ebb42012-12-07 10:10:04 +0800141 "byte seq %ld", i % 256, foo[i], i);
Caspar Zhanga2339012012-07-16 17:52:08 +0800142#endif
143 nr_err++;
144 }
145 }
146 if (nr_err)
147 tst_brkm(TFAIL, tst_exit, "child 0: got %ld incorrect bytes.",
Wanlong Gao354ebb42012-12-07 10:10:04 +0800148 nr_err);
Caspar Zhanga2339012012-07-16 17:52:08 +0800149 else
150 tst_resm(TPASS, "child 0: all bytes are expected.");
151}
152
153static void child_write(void)
154{
155 unsigned char *lp, *rp;
156 char buf[bufsz];
157 struct iovec local, remote;
158 long i;
159
160 /* get addr from pipe */
161 SAFE_CLOSE(tst_exit, pipe_fd[1]);
162 SAFE_READ(tst_exit, 0, pipe_fd[0], buf, bufsz);
163 SAFE_CLOSE(tst_exit, pipe_fd[0]);
164 if (sscanf(buf, "%p", &rp) != 1)
Wanlong Gao354ebb42012-12-07 10:10:04 +0800165 tst_brkm(TBROK | TERRNO, tst_exit, "sscanf");
Caspar Zhanga2339012012-07-16 17:52:08 +0800166
167 lp = SAFE_MALLOC(tst_exit, bufsz + PADDING_SIZE * 2);
168
169 for (i = 0; i < bufsz + PADDING_SIZE * 2; i++)
170 lp[i] = DEFAULT_CHAR;
171 for (i = 0; i < bufsz; i++)
Wanlong Gao354ebb42012-12-07 10:10:04 +0800172 lp[i + PADDING_SIZE] = i % 256;
Caspar Zhanga2339012012-07-16 17:52:08 +0800173
Wanlong Gao354ebb42012-12-07 10:10:04 +0800174 local.iov_base = lp + PADDING_SIZE;
175 local.iov_len = bufsz;
Caspar Zhanga2339012012-07-16 17:52:08 +0800176 remote.iov_base = rp;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800177 remote.iov_len = bufsz;
Caspar Zhanga2339012012-07-16 17:52:08 +0800178
179 tst_resm(TINFO, "child 2: write to the same memory location.");
180 TEST(test_process_vm_writev(pids[0], &local, 1, &remote, 1, 0));
181 if (TEST_RETURN != bufsz)
Wanlong Gao354ebb42012-12-07 10:10:04 +0800182 tst_brkm(TFAIL | TERRNO, tst_exit, "process_vm_readv");
Caspar Zhanga2339012012-07-16 17:52:08 +0800183}
184
185static void setup(void)
186{
187 tst_require_root(NULL);
188
Wanlong Gao354ebb42012-12-07 10:10:04 +0800189 bufsz =
190 sflag ? SAFE_STRTOL(NULL, sz_opt, 1, LONG_MAX - PADDING_SIZE * 2)
191 : 100000;
Caspar Zhanga2339012012-07-16 17:52:08 +0800192
193#if !defined(__NR_process_vm_readv)
194 tst_brkm(TCONF, NULL, "process_vm_writev does not exist "
Wanlong Gao354ebb42012-12-07 10:10:04 +0800195 "on your system");
Caspar Zhanga2339012012-07-16 17:52:08 +0800196#endif
197 semid = init_sem(1);
198
199 TEST_PAUSE;
200}
201
202static void cleanup(void)
203{
204 clean_sem(semid);
Caspar Zhanga2339012012-07-16 17:52:08 +0800205}
206
207static void help(void)
208{
209 printf(" -s NUM Set the size of total buffer size.\n");
210}