1/******************************************************************************
2 *				 fallocate01.c
3 *	Mon Dec 24 2007
4 *	Copyright (c) International Business Machines  Corp., 2007
5 *	Emali : sharyathi@in.ibm.com
6 ******************************************************************************/
7
8/***************************************************************************
9 * This program is free software;  you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22***************************************************************************/
23
24/*****************************************************************************
25 *
26 *	OS Test - International Business Machines Corp. 2007.
27 *
28 *	TEST IDENTIFIER	: fallocate01
29 *
30 *	EXECUTED BY		: anyone
31 *
32 *	TEST TITLE		: Basic test for fallocate()
33 *
34 *	TEST CASE TOTAL	: 2
35 *
36 *	CPU ARCHITECTURES	: PPC,X86, X86_64
37 *
38 *	AUTHOR			: Sharyathi Nagesh
39 *
40 *	CO-PILOT			:
41 *
42 *	DATE STARTED		: 24/12/2007
43 *
44 *	TEST CASES
45 *	(Working of fallocate under 2 modes)
46 *	 1) DEFAULT 2)FALLOC_FL_KEEP_SIZE
47 *
48 *	INPUT SPECIFICATIONS
49 *		No input needs to be specified
50 *		  fallocate() in puts are generated randomly
51 *
52 *	OUTPUT SPECIFICATIONS
53 *		Output describing whether test cases passed or failed.
54 *
55 *	ENVIRONMENTAL NEEDS
56 *		Test Needs to be executed on file system supporting ext4
57 *   LTP {TMP} Needs to be set to such a folder
58 *
59 *	SPECIAL PROCEDURAL REQUIREMENTS
60 *		None
61 *
62 *	DETAILED DESCRIPTION
63 *		This is a test case for fallocate() system call.
64 *		This test suite tests basic working of fallocate under different modes
65 *		It trys to fallocate memory blocks and write into that block
66 *
67 *		Total 2 Test Cases :-
68 *		(1) Test Case for DEFAULT MODE
69 *		(2) Test Case for FALLOC_FL_KEEP_SIZE
70 *
71 *	Setup:
72 *		Setup file on which fallocate is to be called
73 *		Set up 2 files for each mode
74 *
75 *	Test:
76 *		Loop if the proper options are given.
77 *		Execute system call
78 *		Check return code, if system call did fail
79 *		lseek to some random location with in allocate block
80 *		write data into the locattion Report if any error encountered
81 *		PASS the test otherwise
82 *
83 *	Cleanup:
84 *		Cleanup the temporary folder
85 *
86*************************************************************************/
87
88#define _GNU_SOURCE
89
90#include <stdio.h>
91#include <stdlib.h>
92#include <endian.h>
93#include <errno.h>
94#include <sys/stat.h>
95#include <sys/types.h>
96#include <fcntl.h>
97#include <sys/syscall.h>
98#include <unistd.h>
99#include <inttypes.h>
100#include <sys/utsname.h>
101
102#include "test.h"
103#include "lapi/fallocate.h"
104#include "lapi/fcntl.h"
105
106#define BLOCKS_WRITTEN 12
107
108void get_blocksize(int);
109void populate_files(int fd);
110void runtest(int, int, loff_t);
111
112char *TCID = "fallocate01";
113char fname_mode1[255], fname_mode2[255];	/* Files used for testing */
114int fd_mode1, fd_mode2;
115int TST_TOTAL = 2;
116loff_t block_size;
117int buf_size;
118
119/******************************************************************************
120 * Performs all one time clean up for this test on successful
121 * completion,  premature exit or  failure. Closes all temporary
122 * files, removes all temporary directories exits the test with
123 * appropriate return code by calling tst_exit() function.
124******************************************************************************/
125void cleanup(void)
126{
127
128	if (close(fd_mode1) == -1)
129		tst_resm(TWARN | TERRNO, "close(%s) failed", fname_mode1);
130	if (close(fd_mode2) == -1)
131		tst_resm(TWARN | TERRNO, "close(%s) failed", fname_mode2);
132	tst_rmdir();
133}
134
135/*****************************************************************************
136 * Performs all one time setup for this test. This function is
137 * used to create temporary dirs and temporary files
138 * that may be used in the course of this test
139 ******************************************************************************/
140void setup(void)
141{
142	/* Create temporary directories */
143	TEST_PAUSE;
144
145	tst_tmpdir();
146
147	sprintf(fname_mode1, "tfile_mode1_%d", getpid());
148	fd_mode1 = open(fname_mode1, O_RDWR | O_CREAT, 0700);
149	if (fd_mode1 == -1)
150		tst_brkm(TBROK | TERRNO, cleanup, "open(%s, O_RDWR) failed",
151			 fname_mode1);
152	get_blocksize(fd_mode1);
153	populate_files(fd_mode1);
154
155	sprintf(fname_mode2, "tfile_mode2_%d", getpid());
156	fd_mode2 = open(fname_mode2, O_RDWR | O_CREAT, 0700);
157	if (fd_mode2 == -1)
158		tst_brkm(TBROK | TERRNO, cleanup, "open(%s, O_RDWR) failed",
159			 fname_mode2);
160	populate_files(fd_mode2);
161}
162
163/*****************************************************************************
164 * Gets the block size for the file system
165 ******************************************************************************/
166void get_blocksize(int fd)
167{
168	struct stat file_stat;
169
170	if (fstat(fd, &file_stat) < 0)
171		tst_resm(TFAIL | TERRNO,
172			 "fstat failed while getting block_size");
173
174	block_size = file_stat.st_blksize;
175	buf_size = block_size;
176}
177
178/*****************************************************************************
179 * Writes data into the file
180 ******************************************************************************/
181
182void populate_files(int fd)
183{
184	char buf[buf_size + 1];
185	int index;
186	int blocks;
187	int data;
188
189	for (blocks = 0; blocks < BLOCKS_WRITTEN; blocks++) {
190		for (index = 0; index < buf_size; index++)
191			buf[index] = 'A' + (index % 26);
192		buf[buf_size] = '\0';
193		if ((data = write(fd, buf, buf_size)) == -1)
194			tst_brkm(TBROK | TERRNO, cleanup, "write failed");
195	}
196}
197
198int main(int ac, char **av)
199{
200	loff_t expected_size;
201	int lc;
202
203	tst_parse_opts(ac, av, NULL, NULL);
204
205	setup();
206
207	for (lc = 0; TEST_LOOPING(lc); lc++) {
208		tst_count = 0;
209
210		expected_size = BLOCKS_WRITTEN * block_size + block_size;
211		runtest(0, fd_mode1, expected_size);
212
213		expected_size = BLOCKS_WRITTEN * block_size;
214		runtest(FALLOC_FL_KEEP_SIZE, fd_mode2, expected_size);
215	}
216
217	cleanup();
218	tst_exit();
219}
220
221/*****************************************************************************
222 * Calls the system call, with appropriate parameters and writes data
223 ******************************************************************************/
224void runtest(int mode, int fd, loff_t expected_size)
225{
226	loff_t offset;
227	loff_t len = block_size;
228	loff_t write_offset, lseek_offset;
229	offset = lseek(fd, 0, SEEK_END);
230	struct stat file_stat;
231	errno = 0;
232
233	TEST(fallocate(fd, mode, offset, len));
234	/* check return code */
235	if (TEST_RETURN != 0) {
236		if (TEST_ERRNO == EOPNOTSUPP || TEST_ERRNO == ENOSYS) {
237			tst_brkm(TCONF, cleanup,
238				 "fallocate system call is not implemented");
239		}
240		tst_resm(TFAIL | TTERRNO,
241			 "fallocate(%d, %d, %" PRId64 ", %" PRId64 ") failed",
242			 fd, mode, offset, len);
243		return;
244	} else {
245		tst_resm(TPASS,
246			 "fallocate(%d, %d, %" PRId64 ", %" PRId64
247			 ") returned %ld", fd, mode, offset, len,
248			 TEST_RETURN);
249	}
250
251	if (fstat(fd, &file_stat) < 0)
252		tst_resm(TFAIL | TERRNO, "fstat failed after fallocate()");
253
254	if (file_stat.st_size != expected_size)
255		tst_resm(TFAIL | TTERRNO,
256			 "fstat test fails on fallocate (%d, %d, %" PRId64 ", %"
257			 PRId64 ") Failed on mode", fd, mode, offset, len);
258
259	write_offset = random() % len;
260	lseek_offset = lseek(fd, write_offset, SEEK_CUR);
261	if (lseek_offset != offset + write_offset) {
262		tst_resm(TFAIL | TTERRNO,
263			 "lseek fails in fallocate(%d, %d, %" PRId64 ", %"
264			 PRId64 ") failed on mode", fd, mode, offset, len);
265		return;
266	}
267	//Write a character to file at random location
268	TEST(write(fd, "A", 1));
269	/* check return code */
270	if (TEST_RETURN == -1) {
271		tst_resm(TFAIL | TTERRNO,
272			 "write fails in fallocate(%d, %d, %" PRId64 ", %"
273			 PRId64 ") failed", fd, mode, offset, len);
274	} else {
275		tst_resm(TPASS,
276			 "write operation on fallocated(%d, %d, %"
277			 PRId64 ", %" PRId64 ") returned %ld", fd, mode,
278			 offset, len, TEST_RETURN);
279	}
280}
281