1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) International Business Machines Corp., 2006
4 * Copyright (c) 2014 Cyril Hrubis <chrubis@suse.cz>
5 * Author: Yi Yang <yyangcdl@cn.ibm.com>
6 */
7
8 #define _GNU_SOURCE
9
10 #include <errno.h>
11 #include <string.h>
12 #include <signal.h>
13 #include <sys/types.h>
14 #include <fcntl.h>
15 #include <sys/poll.h>
16
17 #include "tst_test.h"
18 #include "lapi/fcntl.h"
19 #include "lapi/splice.h"
20 #include "lapi/vmsplice.h"
21
22 #define TEST_BLOCK_SIZE (1<<17) /* 128K */
23
24 #define TESTFILE "vmsplice_test_file"
25
26 static int fd_out;
27 static char buffer[TEST_BLOCK_SIZE];
28
check_file(void)29 static void check_file(void)
30 {
31 int i;
32 char vmsplicebuffer[TEST_BLOCK_SIZE];
33
34 fd_out = SAFE_OPEN(TESTFILE, O_RDONLY);
35 SAFE_READ(1, fd_out, vmsplicebuffer, TEST_BLOCK_SIZE);
36
37 for (i = 0; i < TEST_BLOCK_SIZE; i++) {
38 if (buffer[i] != vmsplicebuffer[i])
39 break;
40 }
41
42 if (i < TEST_BLOCK_SIZE)
43 tst_res(TFAIL, "Wrong data read from the buffer at %i", i);
44 else
45 tst_res(TPASS, "Written data has been read back correctly");
46
47 SAFE_CLOSE(fd_out);
48 }
49
vmsplice_test(void)50 static void vmsplice_test(void)
51 {
52 int pipes[2];
53 long written;
54 int ret;
55 int fd_out;
56 struct iovec v;
57 loff_t offset;
58
59 v.iov_base = buffer;
60 v.iov_len = TEST_BLOCK_SIZE;
61
62 fd_out = SAFE_OPEN(TESTFILE, O_WRONLY | O_CREAT | O_TRUNC, 0644);
63 SAFE_PIPE(pipes);
64
65 struct pollfd pfd = {.fd = pipes[1], .events = POLLOUT};
66 offset = 0;
67
68 while (v.iov_len) {
69 /*
70 * in a real app you'd be more clever with poll of course,
71 * here we are basically just blocking on output room and
72 * not using the free time for anything interesting.
73 */
74 if (poll(&pfd, 1, -1) < 0)
75 tst_brk(TBROK | TERRNO, "poll() failed");
76
77 written = vmsplice(pipes[1], &v, 1, 0);
78 if (written < 0) {
79 tst_brk(TBROK | TERRNO, "vmsplice() failed");
80 } else {
81 if (written == 0) {
82 break;
83 } else {
84 v.iov_base += written;
85 v.iov_len -= written;
86 }
87 }
88
89 ret = splice(pipes[0], NULL, fd_out, &offset, written, 0);
90 if (ret < 0)
91 tst_brk(TBROK | TERRNO, "splice() failed");
92 //printf("offset = %lld\n", (long long)offset);
93 }
94
95 SAFE_CLOSE(pipes[0]);
96 SAFE_CLOSE(pipes[1]);
97 SAFE_CLOSE(fd_out);
98
99 check_file();
100 }
101
setup(void)102 static void setup(void)
103 {
104 int i;
105
106 if (tst_fs_type(".") == TST_NFS_MAGIC) {
107 tst_brk(TCONF, "Cannot do splice() "
108 "on a file located on an NFS filesystem");
109 }
110
111 for (i = 0; i < TEST_BLOCK_SIZE; i++)
112 buffer[i] = i & 0xff;
113 }
114
cleanup(void)115 static void cleanup(void)
116 {
117 if (fd_out > 0)
118 SAFE_CLOSE(fd_out);
119 }
120
121 static struct tst_test test = {
122 .setup = setup,
123 .cleanup = cleanup,
124 .test_all = vmsplice_test,
125 .needs_tmpdir = 1,
126 .min_kver = "2.6.17",
127 };
128