X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lib%2Fext2fs%2Ftest_io.c;h=480e68fccab0d0a22c89b27563faecce297d8a20;hb=b9cbd54b4a9c1bef0362b9b84b3ab61da0025998;hp=4cf33bd783ad00ef7a5c7d0d76e7f8f03edc66a5;hpb=c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4e;p=tools%2Fe2fsprogs.git diff --git a/lib/ext2fs/test_io.c b/lib/ext2fs/test_io.c index 4cf33bd..480e68f 100644 --- a/lib/ext2fs/test_io.c +++ b/lib/ext2fs/test_io.c @@ -4,11 +4,12 @@ * Copyright (C) 1996 Theodore Ts'o. * * %Begin-Header% - * This file may be redistributed under the terms of the GNU Public - * License. + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. * %End-Header% */ +#include "config.h" #include #include #if HAVE_UNISTD_H @@ -22,6 +23,14 @@ #if HAVE_SYS_TYPES_H #include #endif +#ifdef HAVE_SYS_PRCTL_H +#include +#else +#define PR_GET_DUMPABLE 3 +#endif +#if (!defined(HAVE_PRCTL) && defined(linux)) +#include +#endif #include "ext2_fs.h" #include "ext2fs.h" @@ -32,45 +41,22 @@ #define EXT2_CHECK_MAGIC(struct, code) \ if ((struct)->magic != (code)) return (code) - + struct test_private_data { int magic; io_channel real; int flags; FILE *outfile; unsigned long block; + int read_abort_count, write_abort_count; void (*read_blk)(unsigned long block, int count, errcode_t err); void (*write_blk)(unsigned long block, int count, errcode_t err); void (*set_blksize)(int blksize, errcode_t err); void (*write_byte)(unsigned long block, int count, errcode_t err); + void (*read_blk64)(unsigned long long block, int count, errcode_t err); + void (*write_blk64)(unsigned long long block, int count, errcode_t err); }; -static errcode_t test_open(const char *name, int flags, io_channel *channel); -static errcode_t test_close(io_channel channel); -static errcode_t test_set_blksize(io_channel channel, int blksize); -static errcode_t test_read_blk(io_channel channel, unsigned long block, - int count, void *data); -static errcode_t test_write_blk(io_channel channel, unsigned long block, - int count, const void *data); -static errcode_t test_flush(io_channel channel); -static errcode_t test_write_byte(io_channel channel, unsigned long offset, - int count, const void *buf); - -static struct struct_io_manager struct_test_manager = { - EXT2_ET_MAGIC_IO_MANAGER, - "Test I/O Manager", - test_open, - test_close, - test_set_blksize, - test_read_blk, - test_write_blk, - test_flush, - test_write_byte - -}; - -io_manager test_io_manager = &struct_test_manager; - /* * These global variable can be set by the test program as * necessary *before* calling test_open @@ -80,6 +66,10 @@ void (*test_io_cb_read_blk) (unsigned long block, int count, errcode_t err) = 0; void (*test_io_cb_write_blk) (unsigned long block, int count, errcode_t err) = 0; +void (*test_io_cb_read_blk64) + (unsigned long long block, int count, errcode_t err) = 0; +void (*test_io_cb_write_blk64) + (unsigned long long block, int count, errcode_t err) = 0; void (*test_io_cb_set_blksize) (int blksize, errcode_t err) = 0; void (*test_io_cb_write_byte) @@ -92,6 +82,11 @@ void (*test_io_cb_write_byte) #define TEST_FLAG_WRITE 0x02 #define TEST_FLAG_SET_BLKSIZE 0x04 #define TEST_FLAG_FLUSH 0x08 +#define TEST_FLAG_DUMP 0x10 +#define TEST_FLAG_SET_OPTION 0x20 +#define TEST_FLAG_DISCARD 0x40 +#define TEST_FLAG_READAHEAD 0x80 +#define TEST_FLAG_ZEROOUT 0x100 static void test_dump_block(io_channel channel, struct test_private_data *data, @@ -113,24 +108,84 @@ static void test_dump_block(io_channel channel, } } +/* + * Flush data buffers to disk. + */ +static errcode_t test_flush(io_channel channel) +{ + struct test_private_data *data; + errcode_t retval = 0; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct test_private_data *)channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL); + + if (data->real) + retval = io_channel_flush(data->real); + + if (data->flags & TEST_FLAG_FLUSH) + fprintf(data->outfile, "Test_io: flush() returned %s\n", + retval ? error_message(retval) : "OK"); + + return retval; +} + +static void test_abort(io_channel channel, unsigned long block) +{ + struct test_private_data *data; + FILE *f; + + data = (struct test_private_data *) channel->private_data; + f = data->outfile; + test_flush(channel); + + fprintf(f, "Aborting due to I/O to block %lu\n", block); + fflush(f); + abort(); +} + +static char *safe_getenv(const char *arg) +{ +#if !defined(_WIN32) + if ((getuid() != geteuid()) || (getgid() != getegid())) + return NULL; +#endif +#if HAVE_PRCTL + if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) + return NULL; +#else +#if (defined(linux) && defined(SYS_prctl)) + if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) + return NULL; +#endif +#endif + +#if defined(HAVE_SECURE_GETENV) + return secure_getenv(arg); +#elif defined(HAVE___SECURE_GETENV) + return __secure_getenv(arg); +#else + return getenv(arg); +#endif +} + static errcode_t test_open(const char *name, int flags, io_channel *channel) { io_channel io = NULL; struct test_private_data *data = NULL; errcode_t retval; + char *value; if (name == 0) return EXT2_ET_BAD_DEVICE_NAME; retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io); if (retval) - return retval; + goto cleanup; memset(io, 0, sizeof(struct struct_io_channel)); io->magic = EXT2_ET_MAGIC_IO_CHANNEL; retval = ext2fs_get_mem(sizeof(struct test_private_data), &data); - if (retval) { - retval = EXT2_ET_NO_MEMORY; + if (retval) goto cleanup; - } io->manager = test_io_manager; retval = ext2fs_get_mem(strlen(name)+1, &io->name); if (retval) @@ -142,6 +197,7 @@ static errcode_t test_open(const char *name, int flags, io_channel *channel) io->read_error = 0; io->write_error = 0; io->refcount = 1; + io->flags = 0; memset(data, 0, sizeof(struct test_private_data)); data->magic = EXT2_ET_MAGIC_TEST_IO_CHANNEL; @@ -150,27 +206,44 @@ static errcode_t test_open(const char *name, int flags, io_channel *channel) &data->real); if (retval) goto cleanup; - } else + } else { data->real = 0; - data->read_blk = test_io_cb_read_blk; - data->write_blk = test_io_cb_write_blk; - data->set_blksize = test_io_cb_set_blksize; - data->write_byte = test_io_cb_write_byte; + } + data->read_blk = test_io_cb_read_blk; + data->write_blk = test_io_cb_write_blk; + data->set_blksize = test_io_cb_set_blksize; + data->write_byte = test_io_cb_write_byte; + data->read_blk64 = test_io_cb_read_blk64; + data->write_blk64 = test_io_cb_write_blk64; data->outfile = NULL; - if (getenv("TEST_IO_LOGFILE")) - data->outfile = fopen(getenv("TEST_IO_LOGFILE"), "w"); + if ((value = safe_getenv("TEST_IO_LOGFILE")) != NULL) + data->outfile = fopen(value, "w"); if (!data->outfile) data->outfile = stderr; data->flags = 0; - if (getenv("TEST_IO_FLAGS")) - data->flags = strtoul(getenv("TEST_IO_FLAGS"), NULL, 0); - + if ((value = safe_getenv("TEST_IO_FLAGS")) != NULL) + data->flags = strtoul(value, NULL, 0); + data->block = 0; - if (getenv("TEST_IO_BLOCK")) - data->block = strtoul(getenv("TEST_IO_BLOCK"), NULL, 0); - + if ((value = safe_getenv("TEST_IO_BLOCK")) != NULL) + data->block = strtoul(value, NULL, 0); + + data->read_abort_count = 0; + if ((value = safe_getenv("TEST_IO_READ_ABORT")) != NULL) + data->read_abort_count = strtoul(value, NULL, 0); + + data->write_abort_count = 0; + if ((value = safe_getenv("TEST_IO_WRITE_ABORT")) != NULL) + data->write_abort_count = strtoul(value, NULL, 0); + + if (data->real) { + io->align = data->real->align; + if (data->real->flags & CHANNEL_FLAGS_THREADS) + io->flags |= CHANNEL_FLAGS_THREADS; + } + *channel = io; return 0; @@ -193,13 +266,13 @@ static errcode_t test_close(io_channel channel) if (--channel->refcount > 0) return 0; - + if (data->real) retval = io_channel_close(data->real); if (data->outfile && data->outfile != stderr) fclose(data->outfile); - + ext2fs_free_mem(&channel->private_data); if (channel->name) ext2fs_free_mem(&channel->name); @@ -216,8 +289,10 @@ static errcode_t test_set_blksize(io_channel channel, int blksize) data = (struct test_private_data *) channel->private_data; EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL); - if (data->real) + if (data->real) { retval = io_channel_set_blksize(data->real, blksize); + channel->align = data->real->align; + } if (data->set_blksize) data->set_blksize(blksize, retval); if (data->flags & TEST_FLAG_SET_BLKSIZE) @@ -247,8 +322,12 @@ static errcode_t test_read_blk(io_channel channel, unsigned long block, fprintf(data->outfile, "Test_io: read_blk(%lu, %d) returned %s\n", block, count, retval ? error_message(retval) : "OK"); - if (data->block && data->block == block) - test_dump_block(channel, data, block, buf); + if (data->block && data->block == block) { + if (data->flags & TEST_FLAG_DUMP) + test_dump_block(channel, data, block, buf); + if (--data->read_abort_count == 0) + test_abort(channel, block); + } return retval; } @@ -270,8 +349,66 @@ static errcode_t test_write_blk(io_channel channel, unsigned long block, fprintf(data->outfile, "Test_io: write_blk(%lu, %d) returned %s\n", block, count, retval ? error_message(retval) : "OK"); - if (data->block && data->block == block) - test_dump_block(channel, data, block, buf); + if (data->block && data->block == block) { + if (data->flags & TEST_FLAG_DUMP) + test_dump_block(channel, data, block, buf); + if (--data->write_abort_count == 0) + test_abort(channel, block); + } + return retval; +} + +static errcode_t test_read_blk64(io_channel channel, unsigned long long block, + int count, void *buf) +{ + struct test_private_data *data; + errcode_t retval = 0; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct test_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL); + + if (data->real) + retval = io_channel_read_blk64(data->real, block, count, buf); + if (data->read_blk64) + data->read_blk64(block, count, retval); + if (data->flags & TEST_FLAG_READ) + fprintf(data->outfile, + "Test_io: read_blk64(%llu, %d) returned %s\n", + block, count, retval ? error_message(retval) : "OK"); + if (data->block && data->block == block) { + if (data->flags & TEST_FLAG_DUMP) + test_dump_block(channel, data, block, buf); + if (--data->read_abort_count == 0) + test_abort(channel, block); + } + return retval; +} + +static errcode_t test_write_blk64(io_channel channel, unsigned long long block, + int count, const void *buf) +{ + struct test_private_data *data; + errcode_t retval = 0; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct test_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL); + + if (data->real) + retval = io_channel_write_blk64(data->real, block, count, buf); + if (data->write_blk64) + data->write_blk64(block, count, retval); + if (data->flags & TEST_FLAG_WRITE) + fprintf(data->outfile, + "Test_io: write_blk64(%llu, %d) returned %s\n", + block, count, retval ? error_message(retval) : "OK"); + if (data->block && data->block == block) { + if (data->flags & TEST_FLAG_DUMP) + test_dump_block(channel, data, block, buf); + if (--data->write_abort_count == 0) + test_abort(channel, block); + } return retval; } @@ -296,25 +433,123 @@ static errcode_t test_write_byte(io_channel channel, unsigned long offset, return retval; } -/* - * Flush data buffers to disk. - */ -static errcode_t test_flush(io_channel channel) +static errcode_t test_set_option(io_channel channel, const char *option, + const char *arg) +{ + struct test_private_data *data; + errcode_t retval = 0; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct test_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL); + + + if (data->flags & TEST_FLAG_SET_OPTION) + fprintf(data->outfile, "Test_io: set_option(%s, %s) ", + option, arg); + if (data->real && data->real->manager->set_option) { + retval = (data->real->manager->set_option)(data->real, + option, arg); + if (data->flags & TEST_FLAG_SET_OPTION) + fprintf(data->outfile, "returned %s\n", + retval ? error_message(retval) : "OK"); + } else { + if (data->flags & TEST_FLAG_SET_OPTION) + fprintf(data->outfile, "not implemented\n"); + } + return retval; +} + +static errcode_t test_get_stats(io_channel channel, io_stats *stats) +{ + struct test_private_data *data; + errcode_t retval = 0; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct test_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL); + + if (data->real && data->real->manager->get_stats) { + retval = (data->real->manager->get_stats)(data->real, stats); + } + return retval; +} + +static errcode_t test_discard(io_channel channel, unsigned long long block, + unsigned long long count) { struct test_private_data *data; errcode_t retval = 0; - + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); data = (struct test_private_data *) channel->private_data; EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL); if (data->real) - retval = io_channel_flush(data->real); - - if (data->flags & TEST_FLAG_FLUSH) - fprintf(data->outfile, "Test_io: flush() returned %s\n", - retval ? error_message(retval) : "OK"); - + retval = io_channel_discard(data->real, block, count); + if (data->flags & TEST_FLAG_DISCARD) + fprintf(data->outfile, + "Test_io: discard(%llu, %llu) returned %s\n", + block, count, retval ? error_message(retval) : "OK"); return retval; } +static errcode_t test_cache_readahead(io_channel channel, + unsigned long long block, + unsigned long long count) +{ + struct test_private_data *data; + errcode_t retval = 0; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct test_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL); + + if (data->real) + retval = io_channel_cache_readahead(data->real, block, count); + if (data->flags & TEST_FLAG_READAHEAD) + fprintf(data->outfile, + "Test_io: readahead(%llu, %llu) returned %s\n", + block, count, retval ? error_message(retval) : "OK"); + return retval; +} + +static errcode_t test_zeroout(io_channel channel, unsigned long long block, + unsigned long long count) +{ + struct test_private_data *data; + errcode_t retval = 0; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct test_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL); + + if (data->real) + retval = io_channel_zeroout(data->real, block, count); + if (data->flags & TEST_FLAG_ZEROOUT) + fprintf(data->outfile, + "Test_io: zeroout(%llu, %llu) returned %s\n", + block, count, retval ? error_message(retval) : "OK"); + return retval; +} + +static struct struct_io_manager struct_test_manager = { + .magic = EXT2_ET_MAGIC_IO_MANAGER, + .name = "Test I/O Manager", + .open = test_open, + .close = test_close, + .set_blksize = test_set_blksize, + .read_blk = test_read_blk, + .write_blk = test_write_blk, + .flush = test_flush, + .write_byte = test_write_byte, + .set_option = test_set_option, + .get_stats = test_get_stats, + .read_blk64 = test_read_blk64, + .write_blk64 = test_write_blk64, + .discard = test_discard, + .cache_readahead = test_cache_readahead, + .zeroout = test_zeroout, +}; + +io_manager test_io_manager = &struct_test_manager;