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
55 #ifndef OFF_T
56 #define OFF_T off_t
57 #endif /* Not def: OFF_T */
58
59 TCID_DEFINE(sendfile09);
60
61 static char *in_file = "in";
62 static char *out_file = "out";
63 static int fd;
64 static int in_fd;
65 static int out_fd;
66
67 static void cleanup(void);
68 static void setup(void);
69
70 #define ONE_GB (INT64_C(1) << 30)
71
72 static struct test_case_t {
73 char *desc;
74 OFF_T offset;
75 int64_t count;
76 int64_t exp_retval;
77 int64_t exp_updated_offset;
78 } testcases[] = {
79 { "Test sendfile(2) with offset at 0",
80 0, ONE_GB, ONE_GB, ONE_GB},
81 { "Test sendfile(2) with offset at 3GB",
82 3*ONE_GB, ONE_GB, ONE_GB, 4*ONE_GB}
83 };
84
85 static int TST_TOTAL = ARRAY_SIZE(testcases);
86
do_sendfile(struct test_case_t * t)87 void do_sendfile(struct test_case_t *t)
88 {
89 off_t before_pos, after_pos;
90
91 out_fd = SAFE_OPEN(cleanup, out_file, O_WRONLY);
92 in_fd = SAFE_OPEN(cleanup, in_file, O_RDONLY);
93 before_pos = SAFE_LSEEK(cleanup, in_fd, 0, SEEK_CUR);
94
95 TEST(sendfile(out_fd, in_fd, &t->offset, t->count));
96 if (TEST_RETURN == -1)
97 tst_brkm(TBROK | TTERRNO, cleanup, "sendfile(2) failed");
98
99 after_pos = SAFE_LSEEK(cleanup, in_fd, 0, SEEK_CUR);
100
101 if (TEST_RETURN != t->exp_retval) {
102 tst_resm(TFAIL, "sendfile(2) failed to return "
103 "expected value, expected: %" PRId64 ", "
104 "got: %ld", t->exp_retval,
105 TEST_RETURN);
106 } else if (t->offset != t->exp_updated_offset) {
107 tst_resm(TFAIL, "sendfile(2) failed to update "
108 "OFFSET parameter to expected value, "
109 "expected: %" PRId64 ", got: %" PRId64,
110 t->exp_updated_offset,
111 (int64_t) t->offset);
112 } else if (before_pos != after_pos) {
113 tst_resm(TFAIL, "sendfile(2) updated the file position "
114 " of in_fd unexpectedly, expected file position: %"
115 PRId64 ", " " actual file position %" PRId64,
116 (int64_t) before_pos, (int64_t) after_pos);
117 } else {
118 tst_resm(TPASS, "%s", t->desc);
119 }
120
121 close(in_fd);
122 close(out_fd);
123 }
124
125 /*
126 * setup() - performs all ONE TIME setup for this test.
127 */
setup(void)128 void setup(void)
129 {
130 int i;
131
132 tst_sig(FORK, DEF_HANDLER, cleanup);
133 TEST_PAUSE;
134
135 /* make a temporary directory and cd to it */
136 tst_tmpdir();
137
138 if (!tst_fs_has_free(NULL, ".", 5, TST_GB))
139 tst_brkm(TCONF, cleanup, "sendfile(2) on large file"
140 " needs 5G free space.");
141
142 /* create a 4G file */
143 fd = SAFE_CREAT(cleanup, in_file, 00700);
144 for (i = 1; i <= (4 * 1024); i++) {
145 SAFE_LSEEK(cleanup, fd, 1024 * 1024 - 1, SEEK_CUR);
146 SAFE_WRITE(cleanup, 1, fd, "C", 1);
147 }
148 close(fd);
149
150 fd = SAFE_CREAT(cleanup, out_file, 00700);
151 close(fd);
152 }
153
cleanup(void)154 void cleanup(void)
155 {
156 if (fd > 0)
157 close(fd);
158
159 if (in_fd > 0)
160 close(in_fd);
161
162 if (out_fd > 0)
163 close(out_fd);
164
165 tst_rmdir();
166 }
167
main(int ac,char ** av)168 int main(int ac, char **av)
169 {
170 int i;
171 int lc;
172
173 #if __WORDSIZE == 32
174 tst_brkm(TCONF, NULL, "This test is only for 64bit");
175 #endif
176
177 if (tst_kvercmp(2, 6, 33) < 0) {
178 tst_resm(TINFO, "sendfile(2) on large file "
179 "skipped for kernels < 2.6.33");
180 return 0;
181 }
182
183 tst_parse_opts(ac, av, NULL, NULL);
184
185 setup();
186
187 /*
188 * The following loop checks looping state if -c option given
189 */
190 for (lc = 0; TEST_LOOPING(lc); lc++) {
191 tst_count = 0;
192 for (i = 0; i < TST_TOTAL; ++i)
193 do_sendfile(&testcases[i]);
194 }
195
196 cleanup();
197 tst_exit();
198 }
199