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 <sys/poll.h>
15
16#include "tst_test.h"
17#include "lapi/fcntl.h"
18#include "lapi/splice.h"
19#include "lapi/vmsplice.h"
20
21#define TEST_BLOCK_SIZE (1<<17)	/* 128K */
22
23#define TESTFILE "vmsplice_test_file"
24
25static int fd_out;
26static char buffer[TEST_BLOCK_SIZE];
27
28static void check_file(void)
29{
30	int i;
31	char vmsplicebuffer[TEST_BLOCK_SIZE];
32
33	fd_out = SAFE_OPEN(TESTFILE, O_RDONLY);
34	SAFE_READ(1, fd_out, vmsplicebuffer, TEST_BLOCK_SIZE);
35
36	for (i = 0; i < TEST_BLOCK_SIZE; i++) {
37		if (buffer[i] != vmsplicebuffer[i])
38			break;
39	}
40
41	if (i < TEST_BLOCK_SIZE)
42		tst_res(TFAIL, "Wrong data read from the buffer at %i", i);
43	else
44		tst_res(TPASS, "Written data has been read back correctly");
45
46	SAFE_CLOSE(fd_out);
47}
48
49static void vmsplice_test(void)
50{
51	int pipes[2];
52	long written;
53	int ret;
54	int fd_out;
55	struct iovec v;
56	loff_t offset;
57
58	v.iov_base = buffer;
59	v.iov_len = TEST_BLOCK_SIZE;
60
61	fd_out = SAFE_OPEN(TESTFILE, O_WRONLY | O_CREAT | O_TRUNC, 0644);
62	SAFE_PIPE(pipes);
63
64	struct pollfd pfd = {.fd = pipes[1], .events = POLLOUT};
65	offset = 0;
66
67	while (v.iov_len) {
68		/*
69		 * in a real app you'd be more clever with poll of course,
70		 * here we are basically just blocking on output room and
71		 * not using the free time for anything interesting.
72		 */
73		if (poll(&pfd, 1, -1) < 0)
74			tst_brk(TBROK | TERRNO, "poll() failed");
75
76		written = vmsplice(pipes[1], &v, 1, 0);
77		if (written < 0) {
78			tst_brk(TBROK | TERRNO, "vmsplice() failed");
79		} else {
80			if (written == 0) {
81				break;
82			} else {
83				v.iov_base += written;
84				v.iov_len -= written;
85			}
86		}
87
88		ret = splice(pipes[0], NULL, fd_out, &offset, written, 0);
89		if (ret < 0)
90			tst_brk(TBROK | TERRNO, "splice() failed");
91		//printf("offset = %lld\n", (long long)offset);
92	}
93
94	SAFE_CLOSE(pipes[0]);
95	SAFE_CLOSE(pipes[1]);
96	SAFE_CLOSE(fd_out);
97
98	check_file();
99}
100
101static void setup(void)
102{
103	int i;
104
105	for (i = 0; i < TEST_BLOCK_SIZE; i++)
106		buffer[i] = i & 0xff;
107}
108
109static void cleanup(void)
110{
111	if (fd_out > 0)
112		SAFE_CLOSE(fd_out);
113}
114
115static struct tst_test test = {
116	.setup = setup,
117	.cleanup = cleanup,
118	.test_all = vmsplice_test,
119	.needs_tmpdir = 1,
120	.skip_filesystems = (const char *const []) {
121		"nfs",
122		NULL
123	},
124};
125