• 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 
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