• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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