1 /******************************************************************************
2 *
3 * Copyright (c) International Business Machines Corp., 2006
4 * Author Yi Yang <yyangcdl@cn.ibm.com>
5 * Copyright (c) 2014 Cyril Hrubis <chrubis@suse.cz>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 * the GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 *
21 * DESCRIPTION
22 * This test case will verify basic function of vmsplice
23 * added by kernel 2.6.17 or up.
24 *
25 *****************************************************************************/
26
27 #define _GNU_SOURCE
28
29 #include <errno.h>
30 #include <string.h>
31 #include <signal.h>
32 #include <sys/types.h>
33 #include <fcntl.h>
34 #include <sys/poll.h>
35
36 #include "test.h"
37 #include "linux_syscall_numbers.h"
38 #include "safe_macros.h"
39 #include "lapi/fcntl.h"
40 #include "lapi/splice.h"
41 #include "lapi/vmsplice.h"
42
43 #define TEST_BLOCK_SIZE (1<<17) /* 128K */
44
45 static void vmsplice_test(void);
46 static void setup(void);
47 static void cleanup(void);
48
49 #define TESTFILE "vmsplice_test_file"
50
51 static int fd_out;
52 static char buffer[TEST_BLOCK_SIZE];
53
54 char *TCID = "vmsplice01";
55 int TST_TOTAL = 1;
56
main(int ac,char ** av)57 int main(int ac, char **av)
58 {
59 int lc;
60
61 tst_parse_opts(ac, av, NULL, NULL);
62
63 setup();
64
65 for (lc = 0; TEST_LOOPING(lc); lc++)
66 vmsplice_test();
67
68 cleanup();
69 tst_exit();
70 }
71
check_file(void)72 static void check_file(void)
73 {
74 int i;
75 char vmsplicebuffer[TEST_BLOCK_SIZE];
76
77 fd_out = SAFE_OPEN(cleanup, TESTFILE, O_RDONLY);
78 SAFE_READ(cleanup, 1, fd_out, vmsplicebuffer, TEST_BLOCK_SIZE);
79
80 for (i = 0; i < TEST_BLOCK_SIZE; i++) {
81 if (buffer[i] != vmsplicebuffer[i])
82 break;
83 }
84
85 if (i < TEST_BLOCK_SIZE)
86 tst_resm(TFAIL, "Wrong data read from the buffer at %i", i);
87 else
88 tst_resm(TPASS, "Written data has been read back correctly");
89
90 close(fd_out);
91 fd_out = 0;
92 }
93
vmsplice_test(void)94 static void vmsplice_test(void)
95 {
96 int pipes[2];
97 long written;
98 int ret;
99 int fd_out;
100 struct iovec v;
101 loff_t offset;
102
103 v.iov_base = buffer;
104 v.iov_len = TEST_BLOCK_SIZE;
105
106 SAFE_PIPE(cleanup, pipes);
107 fd_out = SAFE_OPEN(cleanup, TESTFILE, O_WRONLY | O_CREAT | O_TRUNC, 0644);
108
109 struct pollfd pfd = {.fd = pipes[1], .events = POLLOUT};
110 offset = 0;
111
112 while (v.iov_len) {
113 /*
114 * in a real app you'd be more clever with poll of course,
115 * here we are basically just blocking on output room and
116 * not using the free time for anything interesting.
117 */
118 if (poll(&pfd, 1, -1) < 0)
119 tst_brkm(TBROK | TERRNO, cleanup, "poll() failed");
120
121 written = vmsplice(pipes[1], &v, 1, 0);
122 if (written < 0) {
123 tst_brkm(TBROK | TERRNO, cleanup, "vmsplice() failed");
124 } else {
125 if (written == 0) {
126 break;
127 } else {
128 v.iov_base += written;
129 v.iov_len -= written;
130 }
131 }
132
133 ret = splice(pipes[0], NULL, fd_out, &offset, written, 0);
134 if (ret < 0)
135 tst_brkm(TBROK | TERRNO, cleanup, "splice() failed");
136 //printf("offset = %lld\n", (long long)offset);
137 }
138
139 close(pipes[0]);
140 close(pipes[1]);
141 close(fd_out);
142 fd_out = 0;
143
144 check_file();
145 }
146
setup(void)147 static void setup(void)
148 {
149 int i;
150
151 if ((tst_kvercmp(2, 6, 17)) < 0) {
152 tst_brkm(TCONF, NULL,
153 "The vmsplice is supported 2.6.17 and newer");
154 }
155
156 tst_sig(NOFORK, DEF_HANDLER, cleanup);
157
158 tst_tmpdir();
159
160 if (tst_fs_type(cleanup, ".") == TST_NFS_MAGIC) {
161 tst_brkm(TCONF, cleanup, "Cannot do splice() "
162 "on a file located on an NFS filesystem");
163 }
164
165 for (i = 0; i < TEST_BLOCK_SIZE; i++)
166 buffer[i] = i & 0xff;
167
168 TEST_PAUSE;
169 }
170
cleanup(void)171 static void cleanup(void)
172 {
173 if (fd_out > 0 && close(fd_out))
174 tst_resm(TWARN, "Failed to close fd_out");
175
176 tst_rmdir();
177 }
178