1 /*
2 *
3 * Copyright (c) International Business Machines Corp., 2014
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc.
18 */
19 /*
20 * NAME
21 * sendfile09.c
22 *
23 * DESCRIPTION
24 * Testcase copied from sendfile02.c to test the basic functionality of
25 * the sendfile(2) system call on large file. There is a kernel bug which
26 * introduced by commit 8f9c0119d7ba and fixed by commit 5d73320a96fcc.
27 *
28 * ALGORITHM
29 * 1. call sendfile(2) with offset at 0
30 * 2. call sendfile(2) with offset at 3GB
31 *
32 * USAGE: <for command-line>
33 * sendfile09 [-c n] [-i n] [-I x] [-P x] [-t]
34 * where,
35 * -i n : Execute test n times.
36 * -I x : Execute test for x seconds.
37 * -P x : Pause for x seconds between iterations.
38 * -t : Turn on syscall timing.
39 *
40 *
41 * RESTRICTIONS
42 * Only supports 64bit systems and kernel 2.6.33 or above
43 */
44 #include <stdio.h>
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <sys/stat.h>
48 #include <sys/sendfile.h>
49 #include <sys/types.h>
50 #include <unistd.h>
51 #include <inttypes.h>
52 #include "test.h"
53 #include "safe_macros.h"
54 #include "lapi/abisize.h"
55
56 #ifndef OFF_T
57 #define OFF_T off_t
58 #endif /* Not def: OFF_T */
59
60 TCID_DEFINE(sendfile09);
61
62 static char *in_file = "in";
63 static char *out_file = "out";
64 static int fd;
65 static int in_fd;
66 static int out_fd;
67
68 static void cleanup(void);
69 static void setup(void);
70
71 #define ONE_GB (INT64_C(1) << 30)
72
73 static struct test_case_t {
74 char *desc;
75 OFF_T offset;
76 int64_t count;
77 int64_t exp_retval;
78 int64_t exp_updated_offset;
79 } testcases[] = {
80 { "Test sendfile(2) with offset at 0",
81 0, ONE_GB, ONE_GB, ONE_GB},
82 { "Test sendfile(2) with offset at 3GB",
83 3*ONE_GB, ONE_GB, ONE_GB, 4*ONE_GB}
84 };
85
86 static int TST_TOTAL = ARRAY_SIZE(testcases);
87
do_sendfile(struct test_case_t * t)88 void do_sendfile(struct test_case_t *t)
89 {
90 off_t before_pos, after_pos;
91
92 out_fd = SAFE_OPEN(cleanup, out_file, O_WRONLY);
93 in_fd = SAFE_OPEN(cleanup, in_file, O_RDONLY);
94 before_pos = SAFE_LSEEK(cleanup, in_fd, 0, SEEK_CUR);
95
96 TEST(sendfile(out_fd, in_fd, &t->offset, t->count));
97 if (TEST_RETURN == -1)
98 tst_brkm(TBROK | TTERRNO, cleanup, "sendfile(2) failed");
99
100 after_pos = SAFE_LSEEK(cleanup, in_fd, 0, SEEK_CUR);
101
102 if (TEST_RETURN != t->exp_retval) {
103 tst_resm(TFAIL, "sendfile(2) failed to return "
104 "expected value, expected: %" PRId64 ", "
105 "got: %ld", t->exp_retval,
106 TEST_RETURN);
107 } else if (t->offset != t->exp_updated_offset) {
108 tst_resm(TFAIL, "sendfile(2) failed to update "
109 "OFFSET parameter to expected value, "
110 "expected: %" PRId64 ", got: %" PRId64,
111 t->exp_updated_offset,
112 (int64_t) t->offset);
113 } else if (before_pos != after_pos) {
114 tst_resm(TFAIL, "sendfile(2) updated the file position "
115 " of in_fd unexpectedly, expected file position: %"
116 PRId64 ", " " actual file position %" PRId64,
117 (int64_t) before_pos, (int64_t) after_pos);
118 } else {
119 tst_resm(TPASS, "%s", t->desc);
120 }
121
122 close(in_fd);
123 close(out_fd);
124 }
125
126 /*
127 * setup() - performs all ONE TIME setup for this test.
128 */
setup(void)129 void setup(void)
130 {
131 int i;
132
133 tst_sig(FORK, DEF_HANDLER, cleanup);
134 TEST_PAUSE;
135
136 /* make a temporary directory and cd to it */
137 tst_tmpdir();
138
139 if (!tst_fs_has_free(NULL, ".", 5, TST_GB))
140 tst_brkm(TCONF, cleanup, "sendfile(2) on large file"
141 " needs 5G free space.");
142
143 /* create a 4G file */
144 fd = SAFE_CREAT(cleanup, in_file, 00700);
145 for (i = 1; i <= (4 * 1024); i++) {
146 SAFE_LSEEK(cleanup, fd, 1024 * 1024 - 1, SEEK_CUR);
147 SAFE_WRITE(cleanup, 1, fd, "C", 1);
148 }
149 close(fd);
150
151 fd = SAFE_CREAT(cleanup, out_file, 00700);
152 close(fd);
153 }
154
cleanup(void)155 void cleanup(void)
156 {
157 if (fd > 0)
158 close(fd);
159
160 if (in_fd > 0)
161 close(in_fd);
162
163 if (out_fd > 0)
164 close(out_fd);
165
166 tst_rmdir();
167 }
168
main(int ac,char ** av)169 int main(int ac, char **av)
170 {
171 int i;
172 int lc;
173
174 #ifdef TST_ABI32
175 tst_brkm(TCONF, NULL, "This test is only for 64bit");
176 #endif
177
178 if (tst_kvercmp(2, 6, 33) < 0) {
179 tst_resm(TINFO, "sendfile(2) on large file "
180 "skipped for kernels < 2.6.33");
181 return 0;
182 }
183
184 tst_parse_opts(ac, av, NULL, NULL);
185
186 setup();
187
188 /*
189 * The following loop checks looping state if -c option given
190 */
191 for (lc = 0; TEST_LOOPING(lc); lc++) {
192 tst_count = 0;
193 for (i = 0; i < TST_TOTAL; ++i)
194 do_sendfile(&testcases[i]);
195 }
196
197 cleanup();
198 tst_exit();
199 }
200