| /****************************************************************************** |
| * fallocate01.c |
| * Mon Dec 24 2007 |
| * Copyright (c) International Business Machines Corp., 2007 |
| * Emali : sharyathi@in.ibm.com |
| ******************************************************************************/ |
| |
| /*************************************************************************** |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| ***************************************************************************/ |
| |
| /***************************************************************************** |
| * |
| * OS Test - International Business Machines Corp. 2007. |
| * |
| * TEST IDENTIFIER : fallocate01 |
| * |
| * EXECUTED BY : anyone |
| * |
| * TEST TITLE : Basic test for fallocate() |
| * |
| * TEST CASE TOTAL : 2 |
| * |
| * CPU ARCHITECTURES : PPC,X86, X86_64 |
| * |
| * AUTHOR : Sharyathi Nagesh |
| * |
| * CO-PILOT : |
| * |
| * DATE STARTED : 24/12/2007 |
| * |
| * TEST CASES |
| * (Working of fallocate under 2 modes) |
| * 1) DEFAULT 2)FALLOC_FL_KEEP_SIZE |
| * |
| * INPUT SPECIFICATIONS |
| * No input needs to be specified |
| * fallocate() in puts are generated randomly |
| * |
| * OUTPUT SPECIFICATIONS |
| * Output describing whether test cases passed or failed. |
| * |
| * ENVIRONMENTAL NEEDS |
| * Test Needs to be executed on file system supporting ext4 |
| * LTP {TMP} Needs to be set to such a folder |
| * |
| * SPECIAL PROCEDURAL REQUIREMENTS |
| * None |
| * |
| * DETAILED DESCRIPTION |
| * This is a test case for fallocate() system call. |
| * This test suite tests basic working of fallocate under different modes |
| * It trys to fallocate memory blocks and write into that block |
| * |
| * Total 2 Test Cases :- |
| * (1) Test Case for DEFAULT MODE |
| * (2) Test Case for FALLOC_FL_KEEP_SIZE |
| * |
| * Setup: |
| * Setup file on which fallocate is to be called |
| * Set up 2 files for each mode |
| * |
| * Test: |
| * Loop if the proper options are given. |
| * Execute system call |
| * Check return code, if system call did fail |
| * lseek to some random location with in allocate block |
| * write data into the locattion Report if any error encountered |
| * PASS the test otherwise |
| * |
| * Cleanup: |
| * Cleanup the temporary folder |
| * |
| *************************************************************************/ |
| |
| /* Standard Include Files */ |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <errno.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <fcntl.h> |
| #include <sys/syscall.h> |
| #include <unistd.h> |
| #include <error.h> |
| #include <inttypes.h> |
| #include <sys/utsname.h> |
| |
| /* Harness Specific Include Files. */ |
| #include "test.h" |
| #include "usctest.h" |
| #include "linux_syscall_numbers.h" |
| |
| #define BLOCKS_WRITTEN 12 |
| |
| /* Local Function */ |
| static inline long fallocate(); |
| void get_blocksize(int); |
| void populate_files(int fd); |
| void runtest(int, int, loff_t); |
| |
| /* Extern Global Variables */ |
| extern int Tst_count; /* counter for tst_xxx routines */ |
| /* Global Variables */ |
| char *TCID = "fallocate01"; /* test program identifier */ |
| char fname_mode1[255], fname_mode2[255]; /* Files used for testing */ |
| int fd_mode1, fd_mode2; |
| int TST_TOTAL; |
| int block_size; |
| int buf_size; |
| |
| /****************************************************************************** |
| * Performs all one time clean up for this test on successful |
| * completion, premature exit or failure. Closes all temporary |
| * files, removes all temporary directories exits the test with |
| * appropriate return code by calling tst_exit() function. |
| ******************************************************************************/ |
| extern void cleanup() |
| { |
| /* Close all open file descriptors. */ |
| |
| if (close(fd_mode1) == -1) |
| tst_resm(TWARN|TERRNO, "close(%s) failed", fname_mode1); |
| |
| if (close(fd_mode2) == -1) |
| tst_resm(TWARN|TERRNO, "close(%s) failed", fname_mode2); |
| |
| //remove tem directory and all the files in it |
| tst_rmdir(); |
| //Exit with appropriate return code |
| tst_exit(); |
| } |
| |
| /***************************************************************************** |
| * Performs all one time setup for this test. This function is |
| * used to create temporary dirs and temporary files |
| * that may be used in the course of this test |
| ******************************************************************************/ |
| void setup() |
| { |
| /* Create temporary directories */ |
| TEST_PAUSE; |
| |
| tst_tmpdir(); |
| |
| sprintf(fname_mode1, "tfile_mode1_%d", getpid()); |
| fd_mode1 = open(fname_mode1, O_RDWR | O_CREAT, 0700); |
| if (fd_mode1 == -1) |
| tst_brkm(TBROK|TERRNO, cleanup, "open(%s, O_RDWR) failed", fname_mode1); |
| get_blocksize(fd_mode1); |
| populate_files(fd_mode1); |
| |
| sprintf(fname_mode2, "tfile_mode2_%d", getpid()); |
| fd_mode2 = open(fname_mode2, O_RDWR | O_CREAT, 0700); |
| if (fd_mode2 == -1) |
| tst_brkm(TBROK|TERRNO, cleanup, "open(%s, O_RDWR) failed", fname_mode2); |
| populate_files(fd_mode2); |
| } |
| |
| /***************************************************************************** |
| * Gets the block size for the file system |
| ******************************************************************************/ |
| void get_blocksize(int fd) |
| { |
| struct stat file_stat; |
| |
| if (fstat(fd, &file_stat) < 0) |
| tst_resm(TFAIL|TERRNO, "fstat failed while getting block_size"); |
| |
| block_size = (int)file_stat.st_blksize; |
| buf_size = block_size; |
| } |
| |
| /***************************************************************************** |
| * Writes data into the file |
| ******************************************************************************/ |
| |
| void populate_files(int fd) |
| { |
| char buf[buf_size + 1]; |
| char *fname; |
| int index; |
| int blocks; |
| int data; |
| |
| if (fd == fd_mode1) |
| fname = fname_mode1; |
| else |
| fname = fname_mode2; |
| |
| for (blocks = 0; blocks < BLOCKS_WRITTEN; blocks++) { |
| for (index = 0; index < buf_size; index++) |
| buf[index] = 'A' + (index % 26); |
| buf[buf_size] = '\0'; |
| if ((data = write(fd, buf, buf_size)) < 0) |
| tst_brkm(TBROK|TERRNO, cleanup, |
| "Unable to write to %s", fname); |
| } |
| } |
| |
| /* ac: number of command line parameters */ |
| /* av: pointer to the array of the command line parameters */ |
| int main(int ac, char **av) |
| { |
| int fd; |
| enum { DEFAULT, FALLOC_FL_KEEP_SIZE } mode; |
| loff_t expected_size; |
| int lc; |
| char *msg; |
| |
| TST_TOTAL = 2; |
| |
| /*************************************************************** |
| * parse standard options |
| ***************************************************************/ |
| if ((msg = parse_opts(ac, av, (option_t *) NULL, NULL)) != (char *)NULL) |
| tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg); |
| |
| /* perform global test setup, call setup() function. */ |
| setup(); |
| |
| for (lc = 0; TEST_LOOPING(lc); lc++) { |
| /* reset Tst_count in case we are looping. */ |
| Tst_count = 0; |
| |
| for (mode = DEFAULT; mode <= FALLOC_FL_KEEP_SIZE; mode++) { |
| switch (mode) { |
| case DEFAULT: |
| fd = fd_mode1; |
| expected_size = |
| BLOCKS_WRITTEN * block_size + block_size; |
| break; |
| case FALLOC_FL_KEEP_SIZE: |
| fd = fd_mode2; |
| expected_size = BLOCKS_WRITTEN * block_size; |
| break; |
| } |
| runtest(mode, fd, expected_size); |
| } |
| } |
| |
| cleanup(); |
| return 0; |
| } |
| |
| /***************************************************************************** |
| * Wraper function to call fallocate system call |
| ******************************************************************************/ |
| static inline long fallocate(int fd, int mode, loff_t offset, loff_t len) |
| { |
| #if __WORDSIZE == 32 |
| struct utsname buf; |
| if (uname(&buf) == 0) { |
| if (!strcmp(buf.machine, "ppc64") |
| || !strcmp(buf.machine, "ppc") |
| || !strcmp(buf.machine, "x86_64")) |
| return syscall(__NR_fallocate, fd, mode, |
| (int)(offset >> 32), (int)offset, |
| (int)(len >> 32), (int)len); |
| } else { |
| perror("uname:"); |
| return -1; |
| } |
| #endif |
| return syscall(__NR_fallocate, fd, mode, offset, len); |
| } |
| |
| /***************************************************************************** |
| * Calls the system call, with appropriate parameters and writes data |
| ******************************************************************************/ |
| void runtest(int mode, int fd, loff_t expected_size) |
| { |
| loff_t offset; |
| loff_t len = block_size; |
| loff_t write_offset, lseek_offset; |
| offset = lseek(fd, 0, SEEK_END); |
| struct stat file_stat; |
| errno = 0; |
| |
| TEST(fallocate(fd, mode, offset, len)); |
| /* check return code */ |
| if (TEST_RETURN != 0) { |
| if (TEST_ERRNO == EOPNOTSUPP || TEST_ERRNO == ENOSYS) { |
| tst_brkm(TCONF, cleanup, |
| "fallocate system call is not implemented"); |
| } |
| TEST_ERROR_LOG(TEST_ERRNO); |
| tst_resm(TFAIL|TTERRNO, |
| "fallocate(%d, %d, %"PRId64", %"PRId64") failed", |
| fd, mode, offset, len); |
| return; |
| } else { |
| if (STD_FUNCTIONAL_TEST) { |
| /* No Verification test, yet... */ |
| tst_resm(TPASS, |
| "fallocate(%d, %d, %"PRId64", %"PRId64") returned %ld", |
| fd, mode, offset, len, TEST_RETURN); |
| } |
| } |
| |
| if (fstat(fd, &file_stat) < 0) |
| tst_resm(TFAIL|TERRNO, "fstat failed after fallocate()"); |
| |
| if (file_stat.st_size != expected_size) |
| tst_resm(TFAIL|TTERRNO, |
| "fstat test fails on fallocate (%d, %d, %"PRId64", %"PRId64") Failed on mode", |
| fd, mode, offset, len); |
| |
| write_offset = random() % len; |
| lseek_offset = lseek(fd, write_offset, SEEK_CUR); |
| if (lseek_offset != offset + write_offset) { |
| tst_resm(TFAIL|TTERRNO, |
| "lseek fails in fallocate(%d, %d, %"PRId64", %"PRId64") failed on mode", |
| fd, mode, offset, len); |
| return; |
| } |
| //Write a character to file at random location |
| TEST(write(fd, "A", 1)); |
| /* check return code */ |
| if (TEST_RETURN == -1) { |
| TEST_ERROR_LOG(TEST_ERRNO); |
| tst_resm(TFAIL|TTERRNO, |
| "write fails in fallocate(%d, %d, %"PRId64", %"PRId64") failed", |
| fd, mode, offset, len); |
| } else { |
| if (STD_FUNCTIONAL_TEST) { |
| /* No Verification test, yet... */ |
| tst_resm(TPASS, |
| "write operation on fallocated(%d, %d, %"PRId64", %"PRId64") returned %ld", |
| fd, mode, offset, len, TEST_RETURN); |
| } |
| } |
| } |