blob: dad26f9e43402cb5df7917e5190468a670e8933c [file] [log] [blame]
Han Pingtiana0645202014-07-14 08:58:48 +02001/*
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>
Han Pingtiana0645202014-07-14 08:58:48 +020052#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
59TCID_DEFINE(sendfile09);
60
61static char *in_file = "in";
62static char *out_file = "out";
63static int fd;
64static int in_fd;
65static int out_fd;
66
67static void cleanup(void);
68static void setup(void);
69
70#define ONE_GB (INT64_C(1) << 30)
71
72static 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
85static int TST_TOTAL = ARRAY_SIZE(testcases);
86
87void 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 */
128void 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
154void cleanup(void)
155{
Han Pingtiana0645202014-07-14 08:58:48 +0200156 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
168int main(int ac, char **av)
169{
170 int i;
171 int lc;
172 const char *msg;
173
174#if __WORDSIZE == 32
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 if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL)
185 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
186
187 setup();
188
189 /*
190 * The following loop checks looping state if -c option given
191 */
192 for (lc = 0; TEST_LOOPING(lc); lc++) {
193 tst_count = 0;
194 for (i = 0; i < TST_TOTAL; ++i)
195 do_sendfile(&testcases[i]);
196 }
197
198 cleanup();
199 tst_exit();
200}