• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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