From 55ea7048d0ebf0b9c8ed06ca6b9025a90ae15b16 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 20 Jul 2007 11:31:18 +0300 Subject: Add test program orph.c Signed-off-by: Adrian Hunter Signed-off-by: Artem Bityutskiy --- tests/fs-tests/lib/tests.c | 48 ++++++++++- tests/fs-tests/lib/tests.h | 14 ++++ tests/fs-tests/simple/Makefile | 4 +- tests/fs-tests/simple/orph.c | 184 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 247 insertions(+), 3 deletions(-) create mode 100644 tests/fs-tests/simple/orph.c (limited to 'tests/fs-tests') diff --git a/tests/fs-tests/lib/tests.c b/tests/fs-tests/lib/tests.c index 8c34b00..e2a6d5b 100644 --- a/tests/fs-tests/lib/tests.c +++ b/tests/fs-tests/lib/tests.c @@ -506,9 +506,9 @@ void tests_check_filled_file_fd(int fd) char buf[WRITE_BUFFER_SIZE]; do { - sz = read(fd,buf,WRITE_BUFFER_SIZE); + sz = read(fd, buf, WRITE_BUFFER_SIZE); CHECK(sz >= 0); - CHECK(memcmp(buf,write_buffer,sz) == 0); + CHECK(memcmp(buf, write_buffer, sz) == 0); } while (sz); } @@ -585,6 +585,26 @@ uint64_t tests_get_big_file_size(unsigned numerator, unsigned denominator) return numerator * (tests_get_free_space() / denominator); } +/* Create file "fragment_n" where n is the file_number, and unlink it */ +int tests_create_orphan(unsigned file_number) +{ + int fd; + int flags; + mode_t mode; + char file_name[256]; + + sprintf(file_name, "fragment_%u", file_number); + flags = O_CREAT | O_TRUNC | O_RDWR | tests_maybe_sync_flag(); + mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; + fd = open(file_name, flags, mode); + if (fd == -1 && (errno == ENOSPC || errno == EMFILE)) + return fd; /* File system full or too many open files */ + CHECK(fd != -1); + tests_sync_directory(file_name); + CHECK(unlink(file_name) != -1); + return fd; +} + /* Write size bytes at offset to the file "fragment_n" where n is the file_number and file_number also determines the random data written i.e. seed for random numbers */ @@ -709,6 +729,30 @@ void tests_delete_fragment_file(unsigned file_number) tests_delete_file(file_name); } +/* Check the random data in file "fragment_n" is what is expected */ +void tests_check_fragment_file_fd(unsigned file_number, int fd) +{ + ssize_t sz, i; + int d; + uint64_t u; + char buf[8192]; + + CHECK(lseek(fd, 0, SEEK_SET) == 0); + srand(file_number); + u = RAND_MAX; + u += 1; + u /= 256; + d = (int) u; + for (;;) { + sz = read(fd, buf, 8192); + if (sz == 0) + break; + CHECK(sz >= 0); + for (i = 0; i < sz; ++i) + CHECK(buf[i] == (char) (rand() / d)); + } +} + /* Check the random data in file "fragment_n" is what is expected */ void tests_check_fragment_file(unsigned file_number) { diff --git a/tests/fs-tests/lib/tests.h b/tests/fs-tests/lib/tests.h index 36ca310..db08628 100644 --- a/tests/fs-tests/lib/tests.h +++ b/tests/fs-tests/lib/tests.h @@ -85,6 +85,17 @@ uint64_t tests_create_file(const char *file_name, uint64_t file_size); /* Calculate: free_space * numerator / denominator */ uint64_t tests_get_big_file_size(unsigned numerator, unsigned denominator); +/* Create file "fragment_n" where n is the file_number, and unlink it */ +int tests_create_orphan(unsigned file_number); + +/* Write size bytes at offset to the file "fragment_n" where n is the + file_number and file_number also determines the random data written + i.e. seed for random numbers */ +unsigned tests_write_fragment_file(unsigned file_number, + int fd, + off_t offset, + unsigned size); + /* Write size bytes to the end of file descriptor fd using file_number to determine the random data written i.e. seed for random numbers */ unsigned tests_fill_fragment_file(unsigned file_number, @@ -108,6 +119,9 @@ unsigned tests_overwite_fragment_file( unsigned file_number, /* Delete file "fragment_n" where n is the file_number */ void tests_delete_fragment_file(unsigned file_number); +/* Check the random data in file "fragment_n" is what is expected */ +void tests_check_fragment_file_fd(unsigned file_number, int fd); + /* Check the random data in file "fragment_n" is what is expected */ void tests_check_fragment_file(unsigned file_number); diff --git a/tests/fs-tests/simple/Makefile b/tests/fs-tests/simple/Makefile index 07ddf65..8190993 100644 --- a/tests/fs-tests/simple/Makefile +++ b/tests/fs-tests/simple/Makefile @@ -9,7 +9,8 @@ LDFLAGS := $(LDFLAGS) TARGETS = test_1 \ test_2 \ - ftrunc + ftrunc \ + orph all: $(TARGETS) @@ -24,3 +25,4 @@ tests: all ./test_1 --sync ./test_2 --sync ./ftrunc + ./orph --sync diff --git a/tests/fs-tests/simple/orph.c b/tests/fs-tests/simple/orph.c new file mode 100644 index 0000000..f6d8956 --- /dev/null +++ b/tests/fs-tests/simple/orph.c @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2007 Nokia Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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 + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * Author: Adrian Hunter + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tests.h" + +#define MAX_ORPHANS 1000000 + +void orph(void) +{ + pid_t pid; + unsigned i, j, k, n; + int fd, done, full; + int64_t repeat; + ssize_t sz; + char dir_name[256]; + int fds[MAX_ORPHANS]; + + /* Create a directory to test in */ + pid = getpid(); + tests_cat_pid(dir_name, "orph_test_dir_", pid); + if (chdir(dir_name) == -1) + CHECK(mkdir(dir_name, 0777) != -1); + CHECK(chdir(dir_name) != -1); + + repeat = tests_repeat_parameter; + for (;;) { + full = 0; + done = 0; + n = 0; + while (n + 100 < MAX_ORPHANS && !done) { + /* Make 100 more orphans */ + for (i = 0; i < 100; i++) { + fd = tests_create_orphan(n + i); + if (fd < 0) { + done = 1; + if (errno == ENOSPC) + full = 1; + else if (errno != EMFILE) + CHECK(0); + errno = 0; + break; + } + fds[n + i] = fd; + } + if (!full) { + /* Write to orphans just created */ + k = i; + for (i = 0; i < k; i++) { + if (tests_write_fragment_file(n + i, + fds[n+i], + 0, 1000) + != 1000) { + /* + * Out of space, so close + * remaining files + */ + for (j = i; j < k; j++) + CHECK(close(fds[n + j]) + != -1); + done = 1; + break; + } + } + } + if (!done) + CHECK(tests_count_files_in_dir(".") == 0); + n += i; + } + /* Check the data in the files */ + for (i = 0; i < n; i++) + tests_check_fragment_file_fd(i, fds[i]); + if (!full && n) { + /* Ensure the file system is full */ + n -= 1; + do { + sz = write(fds[n], fds, 4096); + if (sz == -1 && errno == ENOSPC) { + errno = 0; + break; + } + CHECK(sz >= 0); + } while (sz == 4096); + CHECK(close(fds[n]) != -1); + } + /* Check the data in the files */ + for (i = 0; i < n; i++) + tests_check_fragment_file_fd(i, fds[i]); + /* Sleep */ + if (tests_sleep_parameter > 0) { + unsigned us = tests_sleep_parameter * 1000; + unsigned rand_divisor = RAND_MAX / us; + unsigned s = (us / 2) + (rand() / rand_divisor); + usleep(s); + } + /* Close orphans */ + for (i = 0; i < n; i++) + CHECK(close(fds[i]) != -1); + /* Break if repeat count exceeded */ + if (tests_repeat_parameter > 0 && --repeat <= 0) + break; + } + CHECK(tests_count_files_in_dir(".") == 0); + CHECK(chdir("..") != -1); + CHECK(rmdir(dir_name) != -1); +} + +/* Title of this test */ + +const char *orph_get_title(void) +{ + return "Create many open unlinked files"; +} + +/* Description of this test */ + +const char *orph_get_description(void) +{ + return + "Create a directory named orph_test_dir_pid, where " \ + "pid is the process id. Within that directory, " \ + "create files and keep them open and unlink them. " \ + "Create as many files as possible until the file system is " \ + "full or the maximum allowed open files is reached. " \ + "If a sleep value is specified, the process sleeps. " \ + "The sleep value is given by the -p or --sleep option, " \ + "otherwise it defaults to 0. " \ + "Sleep is specified in milliseconds. " \ + "Then close the files. " \ + "If a repeat count is specified, then the task repeats " \ + "that number of times. " \ + "The repeat count is given by the -n or --repeat option, " \ + "otherwise it defaults to 1. " \ + "A repeat count of zero repeats forever. " \ + "Finally remove the directory."; +} + +int main(int argc, char *argv[]) +{ + int run_test; + + /* Set default test repetition */ + tests_repeat_parameter = 1; + + /* Set default test sleep */ + tests_sleep_parameter = 0; + + /* Handle common arguments */ + run_test = tests_get_args(argc, argv, orph_get_title(), + orph_get_description(), "nps"); + if (!run_test) + return 1; + /* Change directory to the file system and check it is ok for testing */ + tests_check_test_file_system(); + /* Do the actual test */ + orph(); + return 0; +} -- cgit v1.2.3