[Ocfs2-tools-devel] [PATCH 2/2] Test for the io_cache
tao.ma
tao.ma at oracle.com
Tue Mar 27 18:28:33 PDT 2007
sob.
Joel Becker wrote:
> On Mon, Mar 26, 2007 at 09:25:25PM -0700, Joel Becker wrote:
>
>> This patch introduces a test program for the libocfs2 io_cache. The
>> program takes 12 steps to prove that the caching is functional.
>>
>> Please see the top of the test program for the steps. I'm looking for
>> evaluation of the steps. If there is anything else I can add or
>> re-order, I'm all about suggestions.
>>
>
> This is a new version of the patch that adds tests for
> multiblock reads and writes.
>
> Sunil, Marcos, Tao, I'm looking for signoff.
>
> Index: programs/iocache/iocache.c
> ===================================================================
> --- programs/iocache/iocache.c (.../trunk) (revision 0)
> +++ programs/iocache/iocache.c (.../branches/iocache) (revision 87)
> @@ -0,0 +1,659 @@
> +/* -*- mode: c; c-basic-offset: 8; -*-
> + * vim: noexpandtab sw=8 ts=8 sts=0:
> + *
> + * iocache.c - Test libocfs2 io cache.
> + *
> + * The program is simple.
> + *
> + * 1) Read the original blocks off.
> + * 2) Initialize the cache.
> + * 3) Read the blocks again, compare against the originals.
> + * 4) Read again, expecting the cache to return them. Compare.
> + * 5) Write a pattern to the blocks.
> + * 6) Read them again, expecting the pattern.
> + * 7) Start a child process. It drops and recreates its cache.
> + * 8) The child reads the blocks, expecting the pattern.
> + * 9) The child writes a new pattern to the blocks.
> + * 10) The parent reads the blocks again. Because it has a cache, it
> + * should still see the old pattern.
> + * 11) Drop and recreate the cache. Read the blocks again. It should see
> + * the new pattern.
> + * 12) To test multiblock read and write, write an alternating pattern to
> + * blknos[0].
> + * 13) Read the blocks via a multiblock read. It should see the
> + * alternating pattern.
> + * 14) Drop and recreate the cache. Read the blocks via a multiblock read.
> + * It should see the alternating pattern.
> + * 15) Write the original blocks back.
> + */
> +
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <errno.h>
> +#include <inttypes.h>
> +#include <sys/wait.h>
> +
> +#include <ocfs2/ocfs2.h>
> +
> +#define TRACE 1
> +#ifdef TRACE
> +# define _called() fprintf(stderr, "TRACE: %s called\n", __func__)
> +# define _here() fprintf(stderr, "TRACE: %s line %d\n", __func__, __LINE__)
> +# define _done() fprintf(stderr, "TRACE: %s done\n", __func__)
> +#else
> +# define _called() do { } while (0)
> +# define _here() do { } while (0)
> +# define _done() do { } while (0)
> +#endif
> +
> +#define try_and_fail(_failcount, _call, _label) do { \
> + fprintf(stdout, "Testing %s ... ", #_call); \
> + fflush(stdout); \
> + if (_call()) { \
> + (_failcount)++; \
> + fprintf(stdout, "FAIL\n"); \
> + goto _label; \
> + } else \
> + fprintf(stdout, "PASS\n"); \
> + } while (0)
> +#define try_and_continue(_failcount, _call) do { \
> + fprintf(stdout, "Testing %s ... ", #_call); \
> + fflush(stdout); \
> + if (_call()) { \
> + (_failcount)++; \
> + fprintf(stdout, "FAIL\n"); \
> + } else \
> + fprintf(stdout, "PASS\n"); \
> + } while (0)
> +
> +
> +#define NUM_BLOCKS 10
> +#define BLOCKSIZE 4096
> +#define PATTERN0 'a'
> +#define PATTERN1 'b'
> +#define POISON 'p'
> +
> +char *progname;
> +static int number_of_blocks = NUM_BLOCKS;
> +static uint64_t blknos[NUM_BLOCKS];
> +static int blocksize = BLOCKSIZE;
> +static char *original_blocks[NUM_BLOCKS];
> +static char *pattern_blocks[NUM_BLOCKS];
> +static char *working_blocks[NUM_BLOCKS];
> +static io_channel *channel;
> +static int childp;
> +
> +
> +static void usage(int rc)
> +{
> + fprintf(stderr, "Usage: %s <filename>\n", progname);
> + exit(rc);
> +}
> +
> +static int open_device(const char *dev)
> +{
> + errcode_t ret;
> +
> + ret = io_open(dev, OCFS2_FLAG_RW, &channel);
> + if (ret) {
> + com_err(progname, ret, "while opening file \"%s\"", dev);
> + return -ENXIO;
> + }
> +
> + io_set_blksize(channel, blocksize);
> +
> + return 0;
> +}
> +
> +static void finalize(void);
> +static int initialize(int argc, char *argv[])
> +{
> + int rc, i;
> + errcode_t ret = 0;
> + progname = argv[0];
> + char *original_buffer, *pattern_buffer, *working_buffer;
> +
> + if (argc != 2)
> + usage(-EINVAL);
> + if (!strcmp(argv[1], "-h") ||
> + !strcmp(argv[1], "-?") ||
> + !strcmp(argv[1], "--help"))
> + usage(0);
> + if (argv[1][0] == '-')
> + usage(-EINVAL);
> +
> + rc = open_device(argv[1]);
> + if (rc)
> + goto out;
> +
> + ret = ocfs2_malloc_blocks(channel, number_of_blocks,
> + &original_buffer);
> + if (ret)
> + goto out;
> + ret = ocfs2_malloc_blocks(channel, number_of_blocks,
> + &pattern_buffer);
> + if (ret)
> + goto out;
> + ret = ocfs2_malloc_blocks(channel, number_of_blocks,
> + &working_buffer);
> + if (ret)
> + goto out;
> + /* open_device() set our blocksize */
> + for (i = 0; i < number_of_blocks; i++) {
> + original_blocks[i] = original_buffer;
> + pattern_blocks[i] = pattern_buffer;
> + working_blocks[i] = working_buffer;
> +
> + original_buffer += io_get_blksize(channel);
> + pattern_buffer += io_get_blksize(channel);
> + working_buffer += io_get_blksize(channel);
> + }
> +
> + /*
> + * XXX: Make this smarter :-)
> + * This loop just takes the number_of_blocks blocks starting at
> + * block 20. It really should be randomly picking blocks all
> + * over the disk.
> + */
> + for (i = 0; i < number_of_blocks; i++)
> + blknos[i] = i + 20;
> +
> +out:
> + if (ret) {
> + com_err(progname, ret, "while initializing the test");
> + rc = -ENOMEM;
> +
> + finalize();
> + }
> +
> + return rc;
> +}
> +
> +static void fill_pattern(int even_pat, int odd_pat)
> +{
> + int i, pat;
> +
> + for (i = 0; i < number_of_blocks; i++) {
> + pat = (i % 2) ? even_pat : odd_pat;
> + memset(pattern_blocks[i], pat, io_get_blksize(channel));
> + }
> +}
> +
> +/* Because we're comparing, we want to avoid seeing stale data. */
> +static void poison_working_blocks(void)
> +{
> + int i;
> +
> + for (i = 0; i < number_of_blocks; i++)
> + memset(working_blocks[i], POISON, io_get_blksize(channel));
> +}
> +
> +
> +static int step1(void)
> +{
> + int i, failed = 0;
> + errcode_t ret;
> +
> + for (i = 0; !failed && (i < number_of_blocks); i++) {
> + ret = io_read_block(channel, blknos[i], 1,
> + original_blocks[i]);
> + if (ret) {
> + failed = 1;
> + com_err(progname, ret,
> + "while reading block %"PRIu64, blknos[i]);
> + }
> + }
> +
> + return failed;
> +}
> +
> +static int step2(void)
> +{
> + int failed = 0;
> + errcode_t ret;
> +
> + ret = io_init_cache(channel, number_of_blocks);
> + if (ret) {
> + com_err(progname, ret, "while initializing cache");
> + failed = 1;
> + }
> +
> + return failed;
> +}
> +
> +static int step3(void)
> +{
> + int i, failed = 0;
> + errcode_t ret;
> +
> + poison_working_blocks();
> + for (i = 0; !failed && (i < number_of_blocks); i++) {
> + ret = io_read_block(channel, blknos[i], 1,
> + working_blocks[i]);
> + if (ret) {
> + failed = 1;
> + com_err(progname, ret,
> + "while reading block %"PRIu64, blknos[i]);
> + }
> + }
> +
> + for (i = 0; !failed && (i < number_of_blocks); i++) {
> + if (memcmp(original_blocks[i], working_blocks[i],
> + io_get_blksize(channel))) {
> + failed = 1;
> + fprintf(stderr,
> + "%s: Cache filling read of block %"PRIu64" doesn't match original\n",
> + progname, blknos[i]);
> + }
> + }
> +
> + return failed;
> +}
> +
> +static int step4(void)
> +{
> + int i, failed = 0;
> + errcode_t ret;
> +
> + poison_working_blocks();
> + for (i = 0; !failed && (i < number_of_blocks); i++) {
> + ret = io_read_block(channel, blknos[i], 1,
> + working_blocks[i]);
> + if (ret) {
> + failed = 1;
> + com_err(progname, ret,
> + "while reading cached block %"PRIu64, blknos[i]);
> + }
> + }
> +
> + for (i = 0; !failed && (i < number_of_blocks); i++) {
> + if (memcmp(original_blocks[i], working_blocks[i],
> + io_get_blksize(channel))) {
> + failed = 1;
> + fprintf(stderr,
> + "%s: Cached read of block %"PRIu64" doesn't match original\n",
> + progname, blknos[i]);
> + }
> + }
> +
> + return failed;
> +}
> +
> +static int step5(void)
> +{
> + int i, failed = 0;
> + errcode_t ret;
> +
> + fill_pattern(PATTERN0, PATTERN0);
> +
> + for (i = 0; !failed && (i < number_of_blocks); i++) {
> + ret = io_write_block(channel, blknos[i], 1,
> + pattern_blocks[i]);
> + if (ret) {
> + failed = 1;
> + com_err(progname, ret,
> + "while writing pattern 0 to block %"PRIu64,
> + blknos[i]);
> + }
> + }
> +
> + return failed;
> +}
> +
> +static int step6(void)
> +{
> + int i, failed = 0;
> + errcode_t ret;
> +
> + poison_working_blocks();
> + for (i = 0; !failed && (i < number_of_blocks); i++) {
> + ret = io_read_block(channel, blknos[i], 1,
> + working_blocks[i]);
> + if (ret) {
> + failed = 1;
> + com_err(progname, ret,
> + "while reading cached block %"PRIu64, blknos[i]);
> + }
> + }
> +
> + for (i = 0; !failed && (i < number_of_blocks); i++) {
> + if (memcmp(pattern_blocks[i], working_blocks[i],
> + io_get_blksize(channel))) {
> + failed = 1;
> + fprintf(stderr,
> + "%s: Cached read of block %"PRIu64" doesn't match pattern 0\n",
> + progname, blknos[i]);
> + }
> + }
> +
> + return failed;
> +}
> +
> +
> +static int step7(void)
> +{
> + int tries = 5;
> + pid_t pid, wpid;
> + int status;
> + int failed = 0;
> +
> + do {
> + pid = fork();
> + tries--;
> + } while (tries && (pid < 0));
> +
> + if (pid < 0) {
> + fprintf(stderr, "%s: Unable to create child process: %s\n",
> + progname, strerror(errno));
> + return 1;
> + }
> +
> + if (!pid) {
> + childp = 1;
> +
> + /* Erase the child's cache */
> + io_destroy_cache(channel);
> + io_init_cache(channel, 10);
> + return 0;
> + }
> +
> + while (1) {
> + wpid = waitpid(pid, &status, 0);
> + if (wpid == pid)
> + break;
> + if (errno == EINTR)
> + continue;
> + fprintf(stderr, "%s: Unable to wait on child process: %s\n",
> + progname, strerror(errno));
> + failed = 1;
> + }
> +
> + fprintf(stderr, "Parent step7 ... ");
> + fflush(stdout);
> +
> + return failed;
> +}
> +
> +static int step8(void)
> +{
> + int i, failed = 0;
> + errcode_t ret;
> +
> + poison_working_blocks();
> + for (i = 0; !failed && (i < number_of_blocks); i++) {
> + ret = io_read_block(channel, blknos[i], 1,
> + working_blocks[i]);
> + if (ret) {
> + failed = 1;
> + com_err(progname, ret,
> + "while child reading block %"PRIu64, blknos[i]);
> + }
> + }
> +
> + for (i = 0; !failed && (i < number_of_blocks); i++) {
> + if (memcmp(pattern_blocks[i], working_blocks[i],
> + io_get_blksize(channel))) {
> + failed = 1;
> + fprintf(stderr,
> + "%s: Child's read of block %"PRIu64" doesn't match pattern 0\n",
> + progname, blknos[i]);
> + }
> + }
> +
> + return failed;
> +}
> +
> +static int step9(void)
> +{
> + int i, failed = 0;
> + errcode_t ret;
> +
> + fill_pattern(PATTERN1, PATTERN1);
> +
> + for (i = 0; !failed && (i < number_of_blocks); i++) {
> + ret = io_write_block(channel, blknos[i], 1,
> + pattern_blocks[i]);
> + if (ret) {
> + failed = 1;
> + com_err(progname, ret,
> + "while child writing pattern 1 to block %"PRIu64,
> + blknos[i]);
> + }
> + }
> +
> + return failed;
> +}
> +
> +static int step10(void)
> +{
> + int i, failed = 0;
> + errcode_t ret;
> +
> + poison_working_blocks();
> + for (i = 0; !failed && (i < number_of_blocks); i++) {
> + ret = io_read_block(channel, blknos[i], 1,
> + working_blocks[i]);
> + if (ret) {
> + failed = 1;
> + com_err(progname, ret,
> + "while re-reading cached block %"PRIu64, blknos[i]);
> + }
> + }
> +
> + for (i = 0; !failed && (i < number_of_blocks); i++) {
> + if (memcmp(pattern_blocks[i], working_blocks[i],
> + io_get_blksize(channel))) {
> + failed = 1;
> + fprintf(stderr,
> + "%s: Cached re-read of block %"PRIu64" doesn't match pattern 0\n",
> + progname, blknos[i]);
> + }
> + }
> +
> + return failed;
> +}
> +
> +static int step11(void)
> +{
> + int i, failed = 0;
> + errcode_t ret;
> +
> + io_destroy_cache(channel);
> + io_init_cache(channel, 10);
> +
> + poison_working_blocks();
> + for (i = 0; !failed && (i < number_of_blocks); i++) {
> + ret = io_read_block(channel, blknos[i], 1,
> + working_blocks[i]);
> + if (ret) {
> + failed = 1;
> + com_err(progname, ret,
> + "while re-reading cached block %"PRIu64, blknos[i]);
> + }
> + }
> +
> + for (i = 0; !failed && (i < number_of_blocks); i++) {
> + /* Note, this memcmp is reversed from step 10 */
> + if (!memcmp(pattern_blocks[i], working_blocks[i],
> + io_get_blksize(channel))) {
> + failed = 1;
> + fprintf(stderr,
> + "%s: Re-read of block %"PRIu64" incorrectly matches pattern 0\n",
> + progname, blknos[i]);
> + }
> + }
> +
> + /* Bring the parent's pattern to PATTERN1 */
> + fill_pattern(PATTERN1, PATTERN1);
> +
> + for (i = 0; !failed && (i < number_of_blocks); i++) {
> + if (memcmp(pattern_blocks[i], working_blocks[i],
> + io_get_blksize(channel))) {
> + failed = 1;
> + fprintf(stderr,
> + "%s: Re-read of block %"PRIu64" doesn't match pattern 1\n",
> + progname, blknos[i]);
> + }
> + }
> +
> + return failed;
> +}
> +
> +static int step12(void)
> +{
> + int failed = 0;
> + errcode_t ret;
> +
> + fill_pattern(PATTERN0, PATTERN1);
> +
> + ret = io_write_block(channel, blknos[0], number_of_blocks,
> + pattern_blocks[0]);
> + if (ret) {
> + failed = 1;
> + com_err(progname, ret,
> + "while writing alternating pattern to block %"PRIu64,
> + blknos[0]);
> + }
> +
> + return failed;
> +}
> +
> +static int step13(void)
> +{
> + int i, failed = 0;
> + errcode_t ret;
> +
> + poison_working_blocks();
> + ret = io_read_block(channel, blknos[0], number_of_blocks,
> + working_blocks[0]);
> + if (ret) {
> + failed = 1;
> + com_err(progname, ret,
> + "while doing multiblock read of block %"PRIu64,
> + blknos[0]);
> + }
> +
> + for (i = 0; !failed && (i < number_of_blocks); i++) {
> + if (memcmp(pattern_blocks[i], working_blocks[i],
> + io_get_blksize(channel))) {
> + failed = 1;
> + fprintf(stderr,
> + "%s: Cached re-read of block %"PRIu64" doesn't match alternating pattern\n",
> + progname, blknos[i]);
> + }
> + }
> +
> + return failed;
> +}
> +
> +static int step14(void)
> +{
> + int i, failed = 0;
> + errcode_t ret;
> +
> + io_destroy_cache(channel);
> + io_init_cache(channel, number_of_blocks);
> +
> + poison_working_blocks();
> + ret = io_read_block(channel, blknos[0], number_of_blocks,
> + working_blocks[0]);
> + if (ret) {
> + failed = 1;
> + com_err(progname, ret,
> + "while doing multiblock read of block %"PRIu64,
> + blknos[0]);
> + }
> +
> + for (i = 0; !failed && (i < number_of_blocks); i++) {
> + if (memcmp(pattern_blocks[i], working_blocks[i],
> + io_get_blksize(channel))) {
> + failed = 1;
> + fprintf(stderr,
> + "%s: Cached re-read of block %"PRIu64" doesn't match alternating pattern\n",
> + progname, blknos[i]);
> + }
> + }
> +
> + return failed;
> +}
> +
> +static int step15(void)
> +{
> + int i, failed = 0;
> + errcode_t ret;
> +
> + /* Drop the cache so writeback is through the sync codepaths */
> + io_destroy_cache(channel);
> +
> + for (i = 0; i < number_of_blocks; i++) {
> + ret = io_write_block(channel, blknos[i], 1,
> + original_blocks[i]);
> + if (ret) {
> + failed = 1;
> + com_err(progname, ret,
> + "while writing back original block %"PRIu64,
> + blknos[i]);
> + }
> + }
> +
> + return failed;
> +}
> +
> +static void finalize(void)
> +{
> + /* The blocks are actually allocated in one chunk */
> + ocfs2_free(&original_blocks[0]);
> + ocfs2_free(&pattern_blocks[0]);
> + ocfs2_free(&working_blocks[0]);
> +
> + io_close(channel);
> +}
> +
> +int main(int argc, char *argv[])
> +{
> + int failed = 0;
> + int rc;
> +
> + initialize_ocfs_error_table();
> +
> + rc = initialize(argc, argv);
> + if (rc)
> + goto out;
> +
> + try_and_fail(failed, step1, out);
> + try_and_fail(failed, step2, out);
> + try_and_fail(failed, step3, out);
> + try_and_continue(failed, step4);
> + try_and_fail(failed, step5, out_writeback);
> + try_and_continue(failed, step6);
> + try_and_fail(failed, step7, out_writeback);
> +
> + if (childp) {
> + try_and_fail(failed, step8, out);
> + try_and_fail(failed, step9, out);
> + goto out;
> + }
> +
> + try_and_fail(failed, step10, out_writeback);
> + try_and_fail(failed, step11, out_writeback);
> + try_and_fail(failed, step12, out_writeback);
> + try_and_fail(failed, step13, out_writeback);
> + try_and_fail(failed, step14, out_writeback);
> +
> +out_writeback:
> + try_and_continue(failed, step15);
> +
> +out:
> + finalize();
> +
> + if (!rc && failed)
> + rc = 1;
> +
> + return rc;
> +}
> Index: programs/iocache/Makefile
> ===================================================================
> --- programs/iocache/Makefile (.../trunk) (revision 0)
> +++ programs/iocache/Makefile (.../branches/iocache) (revision 87)
> @@ -0,0 +1,18 @@
> +TOPDIR = ../..
> +
> +include $(TOPDIR)/Preamble.make
> +
> +TESTS = iocache
> +
> +CFLAGS = -O2 -Wall -g $(OCFS2_CFLAGS)
> +
> +SOURCES = iocache.c
> +
> +DIST_FILES = $(SOURCES)
> +
> +BIN_PROGRAMS = iocache
> +
> +iocache: iocache.o
> + $(LINK) $(OCFS2_LIBS)
> +
> +include $(TOPDIR)/Postamble.make
>
> Property changes on: programs/iocache
> ___________________________________________________________________
> Name: svn:ignore
> + .*.sw?
> .*.d
> iocache
>
>
> Index: programs/Makefile
> ===================================================================
> --- programs/Makefile (.../trunk) (revision 87)
> +++ programs/Makefile (.../branches/iocache) (revision 87)
> @@ -23,6 +23,7 @@ SUBDIRS = \
> fill_verify_holes \
> fsck-tests \
> fsx \
> + iocache \
> iozone \
> kernel_build_parallel_find \
> lock_grab \
>
> Property changes on: programs/iozone/iozone3_263/src/current
> ___________________________________________________________________
> Name: svn:ignore
> + .*.d
> .*.sw?
> iozone
> fileop
>
>
>
> Property changes on: programs/extend_files
> ___________________________________________________________________
> Name: svn:ignore
> + .*.d
> .*.sw?
> truncate_direct
>
>
>
> Property changes on: .
> ___________________________________________________________________
> Name: svn:ignore
> - .*.sw?
> configure
> Config.make
> config.log
> config.status
> autom4te.cache
> ocfs2-test*.tar.gz
>
> + .*.sw?
> configure
> Config.make
> config.log
> config.status
> autom4te.cache
> ocfs2-test*.tar.gz
> core
>
>
>
--
* ** Tao Ma
* Member of Techincal Staff *
Oracle Asia Research & Development Center
Open Source Technologies Development
*
Tel: +86 10 8278 6026
Mobile: +86 13701237602
URL: OARDC Intranet <http://cdc.oraclecorp.com/>, Oracle.com/cdc
<http://www.oracle.com/cdc/>
More information about the Ocfs2-tools-devel
mailing list