1/******************************************************************************
2 *				 fallocate03.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	: fallocate03
29 *
30 *	EXECUTED BY		: anyone
31 *
32 *	TEST TITLE		: fallocate
33 *
34 *	TEST CASE TOTAL	: 8
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 on a sparse file)
46 *
47 *
48 *	INPUT SPECIFICATIONS
49 *		No input needs to be specified
50 *		  fallocate() in-puts are specified through test_data
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 working of fallocate on sparse file
65 *		fallocate is tested for different offsets
66 *
67 *		Total 8 Test Cases :-
68 *			Different offsets with in a sparse file is tested
69 *
70 *	Setup:
71 *		Setup file on which fallocate is to be called
72 *		Set up a file with hole, created through lseek
73 *
74 *	Test:
75 *		Loop if the proper options are given
76 *		Execute system call
77 *		Check return code, if system call failed
78 *		TEST fails, PASS the test otherwise
79 *
80 *	Cleanup:
81 *		Cleanup the temporary folder
82 *
83*************************************************************************/
84
85#define _GNU_SOURCE
86
87#include <stdio.h>
88#include <stdlib.h>
89#include <endian.h>
90#include <errno.h>
91#include <sys/stat.h>
92#include <sys/types.h>		//Can be done with out
93#include <fcntl.h>
94#include <unistd.h>
95#include <inttypes.h>
96#include <sys/utsname.h>
97
98#include "test.h"
99#include "safe_macros.h"
100#include "lapi/fallocate.h"
101
102#define BLOCKS_WRITTEN 12
103#define HOLE_SIZE_IN_BLOCKS 12
104#define DEFAULT_MODE 0
105#define TRUE 0
106
107void get_blocksize(int);
108void populate_file();
109void file_seek(off_t);
110
111char *TCID = "fallocate03";
112char fname[255];
113int fd;
114struct test_data_t {
115	int mode;
116	loff_t offset;
117	loff_t len;
118	int error;
119} test_data[] = {
120	{
121	DEFAULT_MODE, 2, 1, TRUE}, {
122	DEFAULT_MODE, BLOCKS_WRITTEN, 1, TRUE}, {
123	DEFAULT_MODE, BLOCKS_WRITTEN + HOLE_SIZE_IN_BLOCKS / 2 - 1, 1, TRUE},
124	{
125	DEFAULT_MODE, BLOCKS_WRITTEN + HOLE_SIZE_IN_BLOCKS + 1, 1, TRUE}, {
126	FALLOC_FL_KEEP_SIZE, 2, 1, TRUE}, {
127	FALLOC_FL_KEEP_SIZE, BLOCKS_WRITTEN, 1, TRUE}, {
128	FALLOC_FL_KEEP_SIZE,
129		    BLOCKS_WRITTEN + HOLE_SIZE_IN_BLOCKS / 2 + 1, 1, TRUE}, {
130	FALLOC_FL_KEEP_SIZE, BLOCKS_WRITTEN + HOLE_SIZE_IN_BLOCKS + 2,
131		    1, TRUE}
132};
133
134int TST_TOTAL = sizeof(test_data) / sizeof(test_data[0]);
135int block_size;
136int buf_size;
137
138/******************************************************************************
139 * Performs all one time clean up for this test on successful
140 * completion,  premature exit or  failure. Closes all temporary
141 * files, removes all temporary directories exits the test with
142 * appropriate return code by calling tst_exit() function.
143******************************************************************************/
144void cleanup(void)
145{
146	/* Close all open file descriptors. */
147	if (close(fd) == -1)
148		tst_resm(TWARN | TERRNO, "close(%s) failed", fname);
149
150	tst_rmdir();
151
152}
153
154/*****************************************************************************
155 * Performs all one time setup for this test. This function is
156 * used to create temporary dirs and temporary files
157 * that may be used in the course of this test
158 ******************************************************************************/
159
160void setup(void)
161{
162	/* Create temporary directories */
163	TEST_PAUSE;
164
165	tst_tmpdir();
166
167	sprintf(fname, "tfile_sparse_%d", getpid());
168	fd = SAFE_OPEN(cleanup, fname, O_RDWR | O_CREAT, 0700);
169	get_blocksize(fd);
170	populate_file();
171	file_seek(BLOCKS_WRITTEN + HOLE_SIZE_IN_BLOCKS);	/* create holes */
172	populate_file();
173	file_seek(0);		/* Rewind */
174}
175
176/*****************************************************************************
177 * Gets the block size for the file system
178 ******************************************************************************/
179void get_blocksize(int fd)
180{
181	struct stat file_stat;
182
183	if (fstat(fd, &file_stat) < 0)
184		tst_resm(TFAIL | TERRNO,
185			 "fstat failed while getting block_size");
186
187	block_size = (int)file_stat.st_blksize;
188	buf_size = block_size;
189}
190
191/*****************************************************************************
192 * Create a Hole in the file
193 ******************************************************************************/
194void file_seek(off_t offset)
195{
196	offset *= block_size;
197	lseek(fd, offset, SEEK_SET);
198}
199
200/*****************************************************************************
201 * Writes data into the file
202 ******************************************************************************/
203void populate_file(void)
204{
205	char buf[buf_size + 1];
206	int index;
207	int blocks;
208	int data;
209	for (blocks = 0; blocks < BLOCKS_WRITTEN; blocks++) {
210		for (index = 0; index < buf_size; index++)
211			buf[index] = 'A' + (index % 26);
212		buf[buf_size] = '\0';
213		if ((data = write(fd, buf, buf_size)) < 0)
214			tst_brkm(TBROK | TERRNO, cleanup,
215				 "Unable to write to %s", fname);
216	}
217}
218
219/*****************************************************************************
220 * Main function that calls the system call with the  appropriate parameters
221 ******************************************************************************/
222/* ac: number of command line parameters */
223/* av: pointer to the array of the command line parameters */
224int main(int ac, char **av)
225{
226	int test_index = 0;
227	int lc;
228
229	/***************************************************************
230	 * parse standard options
231	***************************************************************/
232	tst_parse_opts(ac, av, NULL, NULL);
233
234	/* perform global test setup, call setup() function */
235	setup();
236
237	for (lc = 0; TEST_LOOPING(lc); lc++) {
238		/* reset tst_count in case we are looping */
239		tst_count = 0;
240		for (test_index = 0; test_index < TST_TOTAL; test_index++) {
241			TEST(fallocate
242			     (fd, test_data[test_index].mode,
243			      test_data[test_index].offset * block_size,
244			      test_data[test_index].len * block_size));
245
246			/* check return code */
247			if (TEST_RETURN != test_data[test_index].error) {
248				if (TEST_ERRNO == EOPNOTSUPP
249				    || TEST_ERRNO == ENOSYS) {
250					tst_brkm(TCONF, cleanup,
251						 "fallocate system call is not implemented");
252				}
253				tst_resm(TFAIL | TTERRNO,
254					 "fallocate(%s, %d, %" PRId64 ", %"
255					 PRId64 ") failed", fname,
256					 test_data[test_index].mode,
257					 test_data[test_index].offset *
258					 block_size,
259					 test_data[test_index].len *
260					 block_size);
261			} else {
262				tst_resm(TPASS,
263					 "fallocate(%s, %d, %" PRId64
264					 ", %" PRId64 ") returned %ld",
265					 fname,
266					 test_data[test_index].mode,
267					 test_data[test_index].offset *
268					 block_size,
269					 test_data[test_index].len *
270					 block_size, TEST_RETURN);
271			}
272		}
273	}
274
275	cleanup();
276	tst_exit();
277}
278