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 "tst_test.h"
37 #include "lapi/fcntl.h"
38 #include "lapi/splice.h"
39 #include "lapi/vmsplice.h"
40
41 #define TEST_BLOCK_SIZE (1<<17) /* 128K */
42
43 #define TESTFILE "vmsplice_test_file"
44
45 static int fd_out;
46 static char buffer[TEST_BLOCK_SIZE];
47
check_file(void)48 static void check_file(void)
49 {
50 int i;
51 char vmsplicebuffer[TEST_BLOCK_SIZE];
52
53 fd_out = SAFE_OPEN(TESTFILE, O_RDONLY);
54 SAFE_READ(1, fd_out, vmsplicebuffer, TEST_BLOCK_SIZE);
55
56 for (i = 0; i < TEST_BLOCK_SIZE; i++) {
57 if (buffer[i] != vmsplicebuffer[i])
58 break;
59 }
60
61 if (i < TEST_BLOCK_SIZE)
62 tst_res(TFAIL, "Wrong data read from the buffer at %i", i);
63 else
64 tst_res(TPASS, "Written data has been read back correctly");
65
66 SAFE_CLOSE(fd_out);
67 }
68
vmsplice_test(void)69 static void vmsplice_test(void)
70 {
71 int pipes[2];
72 long written;
73 int ret;
74 int fd_out;
75 struct iovec v;
76 loff_t offset;
77
78 v.iov_base = buffer;
79 v.iov_len = TEST_BLOCK_SIZE;
80
81 fd_out = SAFE_OPEN(TESTFILE, O_WRONLY | O_CREAT | O_TRUNC, 0644);
82 SAFE_PIPE(pipes);
83
84 struct pollfd pfd = {.fd = pipes[1], .events = POLLOUT};
85 offset = 0;
86
87 while (v.iov_len) {
88 /*
89 * in a real app you'd be more clever with poll of course,
90 * here we are basically just blocking on output room and
91 * not using the free time for anything interesting.
92 */
93 if (poll(&pfd, 1, -1) < 0)
94 tst_brk(TBROK | TERRNO, "poll() failed");
95
96 written = vmsplice(pipes[1], &v, 1, 0);
97 if (written < 0) {
98 tst_brk(TBROK | TERRNO, "vmsplice() failed");
99 } else {
100 if (written == 0) {
101 break;
102 } else {
103 v.iov_base += written;
104 v.iov_len -= written;
105 }
106 }
107
108 ret = splice(pipes[0], NULL, fd_out, &offset, written, 0);
109 if (ret < 0)
110 tst_brk(TBROK | TERRNO, "splice() failed");
111 //printf("offset = %lld\n", (long long)offset);
112 }
113
114 SAFE_CLOSE(pipes[0]);
115 SAFE_CLOSE(pipes[1]);
116 SAFE_CLOSE(fd_out);
117
118 check_file();
119 }
120
setup(void)121 static void setup(void)
122 {
123 int i;
124
125 if (tst_fs_type(".") == TST_NFS_MAGIC) {
126 tst_brk(TCONF, "Cannot do splice() "
127 "on a file located on an NFS filesystem");
128 }
129
130 for (i = 0; i < TEST_BLOCK_SIZE; i++)
131 buffer[i] = i & 0xff;
132 }
133
cleanup(void)134 static void cleanup(void)
135 {
136 if (fd_out > 0)
137 SAFE_CLOSE(fd_out);
138 }
139
140 static struct tst_test test = {
141 .setup = setup,
142 .cleanup = cleanup,
143 .test_all = vmsplice_test,
144 .needs_tmpdir = 1,
145 .min_kver = "2.6.17",
146 };
147