[Ocfs2-test-devel] [PATCH 1/1] Ocfs2-test: Add verification test for truncate.
Tristan Ye
tristan.ye at oracle.com
Tue Feb 2 19:06:13 PST 2010
This patch is used to check whether both memory (page cache) and disk zero
the range between new i_size and the end of it's last allocation(last cluster).
The original file has been generated with a fixed number of clusters, after
truncating, the file content also will be verified from cluster to cluster.
by a given pattern.
Signed-off-by: Tristan Ye <tristan.ye at oracle.com>
---
programs/truncate/Makefile | 16 +-
programs/truncate/verify_truncate.c | 454 +++++++++++++++++++++++++++++++++++
2 files changed, 463 insertions(+), 7 deletions(-)
create mode 100644 programs/truncate/verify_truncate.c
diff --git a/programs/truncate/Makefile b/programs/truncate/Makefile
index 9a22b7f..596fabd 100644
--- a/programs/truncate/Makefile
+++ b/programs/truncate/Makefile
@@ -2,20 +2,22 @@ TOPDIR = ../..
include $(TOPDIR)/Preamble.make
-TESTS = truncate
+TESTS = truncate verify_truncate
-CFLAGS = -O2 -Wall -g
+CFLAGS = -O2 -Wall -g $(OCFS2_CFLAGS)
-SOURCES = truncate.c
-OBJECTS = $(patsubst %.c,%.o,$(SOURCES))
+SOURCES = truncate.c verify_truncate.c
SUBDIRS = ocfs2-tools
DIST_FILES = $(SOURCES)
-BIN_PROGRAMS = truncate
+BIN_PROGRAMS = truncate verify_truncate
-truncate: $(OBJECTS)
- $(LINK)
+truncate: truncate.o
+ $(LINK)
+
+verify_truncate: verify_truncate.o
+ $(LINK) $(OCFS2_LIBS)
include $(TOPDIR)/Postamble.make
diff --git a/programs/truncate/verify_truncate.c b/programs/truncate/verify_truncate.c
new file mode 100644
index 0000000..175305f
--- /dev/null
+++ b/programs/truncate/verify_truncate.c
@@ -0,0 +1,454 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * verify_truncate.c
+ *
+ * verification for truncating.
+ *
+ * Copyright (C) 2010 Oracle. All rights reserved.
+ *
+ * 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
+ * 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 021110-1307, USA.
+ *
+ */
+
+/*
+ * This file is used to check whether both memory (page cache) and disk zero
+ * the range between new i_size and the end of it's allocation(last cluster)
+ *
+ * The original file has been generated with a fixed number of clusters, after
+ * truncating, the file content also will be verified from cluster to cluster.
+ *
+ */
+
+#define _GNU_SOURCE
+#define _XOPEN_SOURCE 500
+#define _LARGEFILE64_SOURCE
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "ocfs2/ocfs2.h"
+
+#define FILE_MODE (S_IRUSR|S_IWUSR|S_IXUSR|S_IROTH|\
+ S_IWOTH|S_IXOTH|S_IRGRP|S_IWGRP|S_IXGRP)
+#define FLAGS_RW (O_CREAT|O_RDWR)
+
+char *pattern;
+char *last_pattern;
+char *device;
+char *filename;
+ocfs2_filesys *fs;
+
+unsigned long clustersize = 32768;
+unsigned long clusters = 100;
+long last_cluster;
+unsigned long iter = 1;
+
+int usage(void)
+{
+ fprintf(stdout, "verify_truncate <-f path> <-i iterations> "
+ "<-c clusters> <-d device>\n");
+ fprintf(stdout, "Example:\n"
+ " ./verify_truncate /storage/testifle "
+ "10 1000 /dev/sda8\n");
+
+ return -1;
+}
+
+unsigned long long get_rand_ull(unsigned long long min,
+ unsigned long long max)
+{
+ unsigned long long rand1, rand2, rand3, big_rand;
+
+ if ((min == 0) && (max == 0))
+ return 0;
+
+ rand1 = (unsigned long long)rand();
+ rand2 = (unsigned long long)rand();
+ rand3 = (unsigned long long)rand();
+
+ big_rand = (rand1 << 32) | (rand2 << 16) | (rand3);
+
+ return min + (big_rand % (max - min + 1));
+}
+
+char rand_char(void)
+{
+ return 'A' + (char) get_rand_ull(0, 25);
+}
+
+int get_rand_buf(char *buf, unsigned long size)
+{
+ unsigned long i;
+
+ for (i = 0; i < size; i++)
+ buf[i] = rand_char();
+
+ return 0;
+}
+
+int open_ocfs2_volume(const char *device)
+{
+ int open_flags = OCFS2_FLAG_HEARTBEAT_DEV_OK | OCFS2_FLAG_RO;
+ int ret;
+ uint64_t superblock = 0, block_size = 0;
+ struct ocfs2_super_block *ocfs2_sb;
+
+ ret = ocfs2_open(device, open_flags, superblock, block_size, &fs);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to open ocfs2 fs on %s\n", device);
+ return ret;
+ }
+
+ ocfs2_sb = OCFS2_RAW_SB(fs->fs_super);
+ clustersize = 1 << ocfs2_sb->s_clustersize_bits;
+
+ ocfs2_close(fs);
+ return 0;
+}
+
+int prep_file_with_pattern(char *file_name, unsigned long long size,
+ unsigned long chunk_size, char *pattern_buf,
+ int once, int flags)
+{
+ int fd, fdt, ret, o_ret;
+ unsigned long long offset = 0, write_size = 0;
+ char tmp_path[PATH_MAX];
+
+ fd = open64(file_name, flags, FILE_MODE);
+ if (fd < 0) {
+ o_ret = fd;
+ fd = errno;
+ fprintf(stderr, "create file %s failed:%d:%s\n", file_name, fd,
+ strerror(fd));
+ fd = o_ret;
+ return fd;
+ }
+
+ if (once) {
+
+ while (offset < size) {
+ if ((offset + chunk_size) > size)
+ write_size = size - offset;
+ else
+ write_size = chunk_size;
+
+ ret = pwrite(fd, pattern_buf, write_size, offset);
+ if (ret < 0)
+ return ret;
+
+ offset += write_size;
+ }
+ } else {
+ snprintf(tmp_path, PATH_MAX, "%s-tmp-file", file_name);
+ fdt = open64(tmp_path, flags, FILE_MODE);
+
+ unlink(tmp_path);
+
+ while (offset < size) {
+
+ if ((offset + chunk_size) > size)
+ write_size = size - offset;
+ else
+ write_size = chunk_size;
+
+ ret = pwrite(fd, pattern_buf, write_size, offset);
+ if (ret < 0)
+ return ret;
+
+ ret = pwrite(fdt, pattern_buf, write_size, offset);
+ if (ret < 0)
+ return ret;
+
+ offset += write_size;
+ }
+
+ close(fdt);
+
+ }
+
+ close(fd);
+ return 0;
+}
+
+int file_truncate(char *file_name, unsigned long long new_i_size)
+{
+ int ret = 0;
+
+ printf("Truncating %s to %lld\n", file_name, new_i_size);
+
+ memcpy(last_pattern, pattern, clustersize);
+
+ ret = truncate(file_name, new_i_size);
+ if (ret) {
+ ret = errno;
+ fprintf(stderr, "Could not truncate %s to %llu bytes: %s\n",
+ file_name, new_i_size, strerror(ret));
+ return -1;
+ }
+
+ if ((new_i_size % clustersize) != 0)
+ memset(last_pattern + new_i_size % clustersize, 0,
+ clustersize - new_i_size % clustersize);
+
+ if ((new_i_size % clustersize) != 0)
+ last_cluster = new_i_size / clustersize;
+ else
+ last_cluster = new_i_size / clustersize - 1;
+
+ return ret;
+}
+
+int verify_truncate(char *file_name)
+{
+
+ int fd, ret = 0, o_ret;
+ int open_ro_flags = O_RDONLY;
+ long i;
+
+ char *buf = NULL;
+
+ buf = malloc(clustersize);
+ memset(buf, 0, clustersize);
+
+ fd = open64(file_name, open_ro_flags, FILE_MODE);
+ if (fd < 0) {
+ fd = errno;
+ fprintf(stderr, "open file %s failed:%d:%s\n", file_name, fd,
+ strerror(fd));
+ ret = -1;
+ goto out;
+ }
+
+ printf("Verifying %s \n", file_name);
+
+ /*
+ * Verify clusters from file start to 2nd last cluster.
+ */
+
+ if (last_cluster < 0)
+ goto out;
+
+ for (i = 0; i < last_cluster - 1; i++) {
+
+ ret = pread(fd, buf, clustersize, i * clustersize);
+ if (ret < 0) {
+ ret = errno;
+ fprintf(stderr, "Pread on %s failed at %d: %s\n",
+ file_name, ret, strerror(ret));
+ ret = -1;
+ goto out;
+ }
+
+ if (memcmp(buf, pattern, clustersize)) {
+ fprintf(stderr, "#%d cluster corrupted on %s.\n",
+ file_name);
+ ret = -1;
+ goto out;
+ }
+ }
+
+ /*
+ * Verify last cluster from page cache.
+ */
+ ret = pread(fd, buf, clustersize, last_cluster * clustersize);
+ if (ret < 0) {
+ ret = errno;
+ fprintf(stderr, "Pread on %s failed at %d: %s\n", file_name,
+ ret, strerror(ret));
+ ret = -1;
+ goto out;
+ }
+
+ if (memcmp(buf, last_pattern, clustersize)) {
+ fprintf(stderr, "pagecache didn't get zero'd on %s\n",
+ file_name);
+ return -1;
+ }
+
+ fsync(fd);
+
+ /*
+ * Verify last cluster from disk.
+ */
+ ret = pread(fd, buf, clustersize, last_cluster * clustersize);
+ if (ret < 0) {
+ ret = errno;
+ fprintf(stderr, "Pread on %s failed at %d: %s\n",
+ file_name, ret, strerror(ret));
+ ret = -1;
+ goto out;
+ }
+
+ if (memcmp(buf, last_pattern, clustersize)) {
+ fprintf(stderr, "data on disk didn't get zero'd on %s\n",
+ file_name);
+ return -1;
+ }
+
+ ret = 0;
+
+out:
+ if (buf)
+ free(buf);
+
+ close(fd);
+
+ return ret;
+}
+
+int parse_opts(int argc, char **argv)
+{
+ char c;
+
+ while (1) {
+ c = getopt(argc, argv, "i:f:c:d:");
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'i':
+ iter = atol(optarg);
+ break;
+ case 'f':
+ filename = optarg;
+ break;
+ case 'c':
+ clusters = atol(optarg);
+ break;
+ case 'd':
+ device = optarg;
+ break;
+ default:
+ return -1;
+ }
+ }
+
+ if (!device) {
+ fprintf(stderr, "device is mandatory option\n");
+ return -1;
+ }
+
+ if (!filename) {
+ fprintf(stderr, "filename is mandatory option\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int setup(int argc, char *argv[])
+{
+
+ int ret = 0;
+
+ pattern = NULL;
+ last_pattern = NULL;
+ device = NULL;
+ filename = NULL;
+ fs = NULL;
+
+ last_cluster = 0;
+
+ ret = parse_opts(argc, argv);
+ if (ret) {
+ usage();
+ return ret;
+ }
+
+ ret = open_ocfs2_volume(device);
+ if (ret)
+ return ret;
+
+ srand(getpid());
+
+ pattern = malloc(clustersize);
+ last_pattern = malloc(clustersize);
+
+ get_rand_buf(pattern, clustersize);
+ memcpy(last_pattern, pattern, clustersize);
+
+ return ret;
+}
+
+void teardown(void)
+{
+ if (pattern)
+ free(pattern);
+
+ if (last_pattern)
+ free(last_pattern);
+}
+
+int run(void)
+{
+ int ret = 0;
+ unsigned long long new_size = get_rand_ull(0, clusters * clustersize);
+
+ ret = prep_file_with_pattern(filename, clusters * clustersize,
+ clustersize, pattern, 0, FLAGS_RW);
+ if (ret)
+ return ret;
+
+ ret = file_truncate(filename, new_size);
+ if (ret)
+ return ret;
+
+ if ((new_size % clustersize) != 0) {
+ printf("Extend %s to %llu\n", filename,
+ (new_size / clustersize + 1) * clustersize);
+ ret = truncate(filename,
+ (new_size / clustersize + 1) * clustersize);
+ if (ret)
+ return ret;
+ }
+
+ ret = verify_truncate(filename);
+ if (ret)
+ return ret;
+
+ ret = unlink(filename);
+
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret = 0;
+ unsigned long i;
+
+ ret = setup(argc, argv);
+ if (ret)
+ goto bail;
+
+ for (i = 0; i < iter; i++) {
+ ret = run();
+ if (ret)
+ goto bail;
+ }
+
+bail:
+ teardown();
+ return ret;
+}
--
1.5.5
More information about the Ocfs2-test-devel
mailing list