[Ocfs2-test-devel] [PATCH 2/3] Ocfs2-test: Prepare utility functions for directio test.
Tristan Ye
tristan.ye at oracle.com
Mon Aug 23 03:09:00 PDT 2010
Signed-off-by: Tristan Ye <tristan.ye at oracle.com>
---
programs/directio_test/directio.h | 22 ++
programs/directio_test/directio_test.c | 6 +
programs/directio_test/directio_utils.c | 621 +++++++++++++++++++++++++++++++
3 files changed, 649 insertions(+), 0 deletions(-)
diff --git a/programs/directio_test/directio.h b/programs/directio_test/directio.h
index 92d2bc1..68e50f5 100755
--- a/programs/directio_test/directio.h
+++ b/programs/directio_test/directio.h
@@ -78,4 +78,26 @@ union semun {
struct seminfo *__buf; /* buffer for IPC_INFO */
};
+unsigned long get_rand_ul(unsigned long min, unsigned long max);
+
+int open_file(const char *filename, int flags);
+int get_i_size(char *filename, unsigned long *size);
+int read_at(int fd, void *buf, size_t count, off_t offset);
+int write_at(int fd, const void *buf, size_t count, off_t offset);
+
+void prep_rand_dest_write_unit(struct write_unit *wu, unsigned long chunk_no);
+int do_write_chunk(int fd, struct write_unit wu);
+int do_read_chunk(int fd, unsigned long chunk_no, struct write_unit *wu);
+int prep_orig_file_in_chunks(char *file_name, unsigned long filesize);
+int verify_file(FILE *logfile, char *filename, unsigned long filesize);
+
+int init_sock(char *serv, int port);
+int set_semvalue(int sem_id, int val);
+int semaphore_init(int val);
+int semaphore_close(int sem_id);
+int semaphore_p(int sem_id);
+int semaphore_v(int sem_id);
+
+int open_logfile(FILE **logfile, const char *logname);
+int log_write(struct write_unit *wu, union log_handler log);
#endif
diff --git a/programs/directio_test/directio_test.c b/programs/directio_test/directio_test.c
index 1c38d2a..1e1d923 100755
--- a/programs/directio_test/directio_test.c
+++ b/programs/directio_test/directio_test.c
@@ -26,6 +26,12 @@
#include "directio.h"
+int open_rw_flags = FILE_RW_FLAGS;
+int open_ro_flags = FILE_RO_FLAGS;
+
+int test_flags = 0x00000000;
+int verbose = 0;
+
static void usage(void)
{
printf("Usage: directio_test [-p concurrent_process] "
diff --git a/programs/directio_test/directio_utils.c b/programs/directio_test/directio_utils.c
index 7a37c8d..da4a1a8 100755
--- a/programs/directio_test/directio_utils.c
+++ b/programs/directio_test/directio_utils.c
@@ -16,3 +16,624 @@
*/
#include "directio.h"
+
+static char chunk_pattern[CHUNK_SIZE] __attribute__ ((aligned(DIRECTIO_SLICE)));
+
+extern int open_rw_flags;
+extern int open_ro_flags;
+
+extern int test_flags;
+extern int verbose;
+
+static uint32_t crc32_checksum(uint32_t crc, char *p, size_t len)
+{
+ const uint32_t *b = (uint32_t *)p;
+ const uint32_t *tab = crc32table_le;
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+# define DO_CRC(x) crc = tab[(crc ^ (x)) & 255] ^ (crc >> 8)
+#else
+# define DO_CRC(x) crc = tab[((crc >> 24) ^ (x)) & 255] ^ (crc << 8)
+#endif
+
+ crc = cpu_to_le32(crc);
+ /* Align it */
+ if (((long)b)&3 && len) {
+ do {
+ uint8_t *p = (uint8_t *)b;
+ DO_CRC(*p++);
+ b = (void *)p;
+ } while ((--len) && ((long)b)&3);
+ }
+ if (len >= 4) {
+ /* load data 32 bits wide, xor data 32 bits wide. */
+ size_t save_len = len & 3;
+ len = len >> 2;
+ --b; /* use pre increment below(*++b) for speed */
+ do {
+ crc ^= *++b;
+ DO_CRC(0);
+ DO_CRC(0);
+ DO_CRC(0);
+ DO_CRC(0);
+ } while (--len);
+ b++; /* point to next byte(s) */
+ len = save_len;
+ }
+ /* And the last few bytes */
+ if (len) {
+ do {
+ uint8_t *p = (uint8_t *)b;
+ DO_CRC(*p++);
+ b = (void *)p;
+ } while (--len);
+ }
+
+ return le32_to_cpu(crc);
+#undef DO_CRC
+}
+
+unsigned long get_rand_ul(unsigned long min, unsigned long max)
+{
+ if (min == 0 && max == 0)
+ return 0;
+
+ return min + (rand() % (max - min + 1));
+}
+
+static char rand_char(void)
+{
+ return 'A' + (char) get_rand_ul(0, 25);
+}
+
+int open_file(const char *filename, int flags)
+{
+ int fd, ret = 0;
+
+ fd = open64(filename, flags, FILE_MODE);
+ if (fd < 0) {
+ ret = errno;
+ fprintf(stderr, "open file %s failed:%d:%s\n", filename, ret,
+ strerror(ret));
+ return -1;
+ }
+
+ return fd;
+}
+
+int get_i_size(char *filename, unsigned long *size)
+{
+ struct stat stat;
+ int ret = 0, fd;
+
+ fd = open_file(filename, open_ro_flags);
+ if (fd)
+ return fd;
+
+ ret = fstat(fd, &stat);
+ if (ret == -1) {
+ ret = errno;
+ fprintf(stderr, "stat failure %d: %s\n", ret, strerror(ret));
+ return ret;
+ }
+
+ *size = (unsigned long) stat.st_size;
+ return ret;
+}
+
+int read_at(int fd, void *buf, size_t count, off_t offset)
+{
+ int ret;
+ size_t bytes_read;
+
+ ret = pread(fd, buf, count, offset);
+ if (ret < 0) {
+ ret = errno;
+ fprintf(stderr, "read error %d: \"%s\"\n", ret, strerror(ret));
+ return -1;
+ }
+
+ bytes_read = ret;
+ while (bytes_read < count) {
+
+ ret = pread(fd, buf + bytes_read, count - bytes_read, offset +
+ bytes_read);
+ if (ret < 0) {
+ ret = errno;
+ fprintf(stderr, "read error %d: \"%s\"\n", ret,
+ strerror(ret));
+ return -1;
+ }
+
+ bytes_read += ret;
+ }
+
+ return count;
+}
+
+int write_at(int fd, const void *buf, size_t count, off_t offset)
+{
+ int ret;
+ size_t bytes_write;
+
+ ret = pwrite(fd, buf, count, offset);
+
+ if (ret < 0) {
+ ret = errno;
+ fprintf(stderr, "write error %d: \"%s\"\n", ret, strerror(ret));
+ return -1;
+ }
+
+ bytes_write = ret;
+ while (bytes_write < count) {
+
+ ret = pwrite(fd, buf + bytes_write, count - bytes_write,
+ offset + bytes_write);
+
+ if (ret < 0) {
+ ret = errno;
+ fprintf(stderr, "write error %d: \"%s\"\n", ret,
+ strerror(ret));
+ return -1;
+ }
+
+ bytes_write += ret;
+ }
+
+ return count;
+}
+
+static int fill_chunk_pattern(char *pattern, struct write_unit *wu)
+{
+ unsigned long offset = 0;
+ uint32_t checksum = 0;
+
+ memset(pattern, 0, CHUNK_SIZE);
+ offset = 0;
+
+ memmove(pattern , &wu->wu_chunk_no, sizeof(unsigned long));
+ offset += sizeof(unsigned long);
+ memmove(pattern + offset, &wu->wu_timestamp, sizeof(unsigned long long));
+ offset += sizeof(unsigned long long);
+
+ offset += sizeof(uint32_t);
+
+ memset(pattern + offset, wu->wu_char, CHUNK_SIZE - offset * 2);
+
+ checksum = crc32_checksum(~0, pattern + offset,
+ (size_t)CHUNK_SIZE - offset * 2);
+
+ offset = CHUNK_SIZE - offset;
+
+ memmove(pattern + offset, &checksum, sizeof(uint32_t));
+ offset += sizeof(uint32_t);
+ memmove(pattern + offset, &wu->wu_timestamp,
+ sizeof(unsigned long long));
+ offset += sizeof(unsigned long long);
+ memmove(pattern + offset, &wu->wu_chunk_no, sizeof(unsigned long));
+
+ offset = sizeof(unsigned long) + sizeof(unsigned long long);
+ memmove(pattern + offset, &checksum, sizeof(uint32_t));
+
+ wu->wu_checksum = checksum;
+
+ return 0;
+}
+
+static int dump_pattern(char *pattern, struct write_unit *wu)
+{
+ unsigned long offset = 0;
+
+ memset(wu, 0, sizeof(struct write_unit));
+
+ memmove(&wu->wu_chunk_no, pattern, sizeof(unsigned long));
+ offset += sizeof(unsigned long);
+ memmove(&wu->wu_timestamp, pattern + offset, sizeof(unsigned long long));
+ offset += sizeof(unsigned long long);
+ memmove(&wu->wu_checksum, pattern + offset, sizeof(uint32_t));
+ offset += sizeof(uint32_t);
+
+ memmove(&wu->wu_char, pattern + offset, 1);
+ offset = CHUNK_SIZE - offset;
+
+ memmove(&wu->wu_checksum, pattern + offset, sizeof(uint32_t));
+ offset += sizeof(uint32_t);
+ memmove(&wu->wu_timestamp, pattern + offset, sizeof(unsigned long long));
+ offset += sizeof(unsigned long long);
+ memmove(&wu->wu_chunk_no, pattern + offset, sizeof(unsigned long));
+
+ return 0;
+}
+
+static int verify_chunk_pattern(char *pattern, struct write_unit *wu)
+{
+ char tmp_pattern[CHUNK_SIZE];
+
+ fill_chunk_pattern(tmp_pattern, wu);
+
+ return !memcmp(pattern, tmp_pattern, CHUNK_SIZE);
+}
+
+static unsigned long long get_time_microseconds(void)
+{
+ unsigned long long curtime_ms = 0;
+ struct timeval curtime;
+
+ gettimeofday(&curtime, NULL);
+
+ curtime_ms = (unsigned long long)curtime.tv_sec * 1000000 +
+ curtime.tv_usec;
+ return curtime_ms;
+}
+
+void prep_rand_dest_write_unit(struct write_unit *wu, unsigned long chunk_no)
+{
+ char tmp_pattern[CHUNK_SIZE];
+
+ wu->wu_char = rand_char();
+ wu->wu_chunk_no = chunk_no;
+ wu->wu_timestamp = get_time_microseconds();
+
+ fill_chunk_pattern(tmp_pattern, wu);
+}
+
+int do_write_chunk(int fd, struct write_unit wu)
+{
+ int ret;
+ size_t count = CHUNK_SIZE;
+ off_t offset = CHUNK_SIZE * wu.wu_chunk_no;
+
+ fill_chunk_pattern(chunk_pattern, &wu);
+
+ ret = write_at(fd, chunk_pattern, count, offset);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+int do_read_chunk(int fd, unsigned long chunk_no, struct write_unit *wu)
+{
+ int ret;
+ size_t count = CHUNK_SIZE;
+ off_t offset = CHUNK_SIZE * chunk_no;
+
+ ret = read_at(fd, chunk_pattern, count, offset);
+ if (ret < 0)
+ return ret;
+
+ dump_pattern(chunk_pattern, wu);
+
+ return ret;
+}
+
+int prep_orig_file_in_chunks(char *file_name, unsigned long filesize)
+{
+
+ int fd, ret, flags;
+ unsigned long offset = 0, chunk_no = 0;
+ static struct write_unit wu;
+
+ if ((CHUNK_SIZE % DIRECTIO_SLICE) != 0) {
+
+ fprintf(stderr, "chunk size in destructive tests is expected to "
+ "be %d aligned, your CHUNK_SIZE %d is not allowed.\n",
+ DIRECTIO_SLICE, CHUNK_SIZE);
+ return -EINVAL;
+ }
+
+ flags = FILE_RW_FLAGS;
+
+ fd = open_file(file_name, flags);
+ if (fd < 0)
+ return fd;
+
+ /*
+ * Original file for desctrutive tests, it consists of chunks.
+ * Each chunks consists of following parts:
+ * chunkno + timestamp + checksum + random chars
+ * + checksum + timestamp + chunkno
+ *
+ */
+ while (offset < filesize) {
+
+ prep_rand_dest_write_unit(&wu, chunk_no);
+
+ fill_chunk_pattern(chunk_pattern, &wu);
+
+ ret = do_write_chunk(fd, wu);
+ if (ret < 0)
+ return ret;
+
+ chunk_no++;
+ offset += CHUNK_SIZE;
+ }
+
+ close(fd);
+
+ return 0;
+}
+
+int verify_file(FILE *logfile, char *filename, unsigned long filesize)
+{
+ int fd = 0, ret = 0;
+ struct write_unit *wus, wu, ewu;
+ unsigned long num_chunks = filesize / CHUNK_SIZE;
+ unsigned long i, t_bytes = sizeof(struct write_unit) * num_chunks;
+ char arg1[100], arg2[100], arg3[100], arg4[100];
+
+ memset(&wu, 0, sizeof(struct write_unit));
+ memset(&ewu, 0, sizeof(struct write_unit));
+
+ wus = (struct write_unit *)malloc(t_bytes);
+ memset(wus, 0, t_bytes);
+
+ for (i = 0; i < num_chunks; i++)
+ wus[i].wu_chunk_no = i;
+
+ while (!feof(logfile)) {
+
+ ret = fscanf(logfile, "%s\t%s\t%s\t%s\n", arg1, arg2,
+ arg3, arg4);
+ if (ret != 4) {
+ fprintf(stderr, "input failure from write log, ret "
+ "%d, %d %s\n", ret, errno, strerror(errno));
+ ret = -EINVAL;
+ goto bail;
+ }
+
+ wu.wu_chunk_no = atol(arg1);
+ if (wu.wu_chunk_no > num_chunks) {
+ fprintf(stderr, "Chunkno grabed from write log"
+ "exceeds the filesize, you may probably"
+ " specify a too small filesize.\n");
+ return -EINVAL;
+ }
+
+ wu.wu_timestamp = atoll(arg2);
+ wu.wu_checksum = atoi(arg3);
+ wu.wu_char = arg4[0];
+
+ if (wu.wu_timestamp >= wus[wu.wu_chunk_no].wu_timestamp) {
+
+ memmove(&wus[wu.wu_chunk_no], &wu,
+ sizeof(struct write_unit));
+ }
+ }
+
+ fd = open_file(filename, open_ro_flags);
+ if (fd < 0)
+ return fd;
+
+ for (i = 0; i < num_chunks; i++) {
+ /*
+ * Verification consists of two following parts:
+ *
+ * - verify write records in logfile.
+ * - verify pattern of chunks absent from logfile.
+ */
+
+ ret = do_read_chunk(fd, i, &wu);
+ if (ret < 0)
+ return ret;
+ /*
+ * verify pattern of chunks absent from logfile.
+ */
+ if (!wus[i].wu_timestamp) {
+
+ if (verbose)
+ fprintf(stdout, " verifying #%lu chunk "
+ "out of log\n", i);
+ /*
+ * skip holes
+ */
+ if (!wu.wu_timestamp)
+ continue;
+
+ if (wu.wu_chunk_no != i) {
+ fprintf(stderr, "Chunk no expected: %lu, Found: %lu\n",
+ i, wu.wu_chunk_no);
+ return -EINVAL;
+ }
+
+ /*
+ * recalculate checksum
+ */
+ memcpy(&ewu, &wu, sizeof(wu));
+ fill_chunk_pattern(chunk_pattern, &ewu);
+ if (wu.wu_checksum != ewu.wu_checksum) {
+ fprintf(stderr, "Checksum expected: %u Found: %u\n",
+ ewu.wu_checksum, wu.wu_checksum);
+ return -1;
+ }
+
+ continue;
+ }
+
+ /*
+ * verify write records in logfile.
+ */
+ if (verbose)
+ fprintf(stdout, " verifying #%lu chunk in log\n", i);
+
+ if (ret < CHUNK_SIZE) {
+ fprintf(stderr, "Short read(readed:%d, expected:%d)"
+ "happened, you may probably set too big "
+ "filesize for verfiy_test.\n", ret, CHUNK_SIZE);
+ return -1;
+ }
+
+ fill_chunk_pattern(chunk_pattern, &wu);
+
+ if (!verify_chunk_pattern(chunk_pattern, &wus[i])) {
+
+ dump_pattern(chunk_pattern, &wu);
+ fprintf(stderr, "Inconsistent chunk found in file %s!\n"
+ "Expected:\tchunkno(%ld)\ttimestmp(%llu)\t"
+ "chksum(%d)\tchar(%c)\nFound :\tchunkno"
+ "(%ld)\ttimestmp(%llu)\tchksum(%d)\tchar(%c)\n",
+ filename,
+ wus[i].wu_chunk_no, wus[i].wu_timestamp,
+ wus[i].wu_checksum, wus[i].wu_char,
+ wu.wu_chunk_no, wu.wu_timestamp,
+ wu.wu_checksum, wu.wu_char);
+ ret = -1;
+ goto bail;
+
+ }
+ }
+
+bail:
+ if (wus)
+ free(wus);
+
+ if (fd)
+ close(fd);
+
+ return ret;
+}
+
+int init_sock(char *serv, int port)
+{
+ int sockfd;
+ struct sockaddr_in servaddr;
+
+ sockfd = socket(AF_INET, SOCK_STREAM, 0);
+ bzero(&servaddr, sizeof(struct sockaddr_in));
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_port = htons(port);
+ inet_pton(AF_INET, serv, &servaddr.sin_addr);
+
+ connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
+
+ return sockfd;
+}
+
+int set_semvalue(int sem_id, int val)
+{
+ union semun sem_union;
+
+ sem_union.val = val;
+ if (semctl(sem_id, 0, SETVAL, sem_union) == -1) {
+ perror("semctl");
+ return -1;
+ }
+
+ return 0;
+}
+
+int semaphore_init(int val)
+{
+ int ret, sem_id;
+ key_t sem_key = IPC_PRIVATE;
+
+ /*get and init semaphore*/
+ sem_id = semget(sem_key, 1, 0766 | IPC_CREAT);
+ if (sem_id < 0) {
+ sem_id = errno;
+ fprintf(stderr, "semget failed, %s.\n", strerror(sem_id));
+ return -1;
+ }
+
+ ret = set_semvalue(sem_id, 1);
+ if (ret < 0) {
+ fprintf(stderr, "Set semaphore value failed!\n");
+ return ret;
+ }
+
+ return sem_id;
+}
+
+int semaphore_close(int sem_id)
+{
+ int ret = 0;
+
+ ret = semctl(sem_id, 0, IPC_RMID);
+ if (ret < 0) {
+ ret = errno;
+ fprintf(stderr, "semctl to close sem failed, %s.\n", strerror(ret));
+ return -1;
+ }
+
+ return ret;
+}
+
+int semaphore_p(int sem_id)
+{
+ struct sembuf sem_b;
+
+ sem_b.sem_num = 0;
+ sem_b.sem_op = -1; /* P() */
+ sem_b.sem_flg = SEM_UNDO;
+ if (semop(sem_id, &sem_b, 1) == -1) {
+ fprintf(stderr, "semaphore_p failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int semaphore_v(int sem_id)
+{
+ struct sembuf sem_b;
+
+ sem_b.sem_num = 0;
+ sem_b.sem_op = 1; /* V() */
+ sem_b.sem_flg = SEM_UNDO;
+ if (semop(sem_id, &sem_b, 1) == -1) {
+ fprintf(stderr, "semaphore_v failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int open_logfile(FILE **logfile, const char *logname)
+{
+ if (test_flags & VERI_TEST) {
+ if (!logname)
+ *logfile = stdin;
+ else
+ *logfile = fopen(logname, "r");
+ } else {
+ if (!logname)
+ *logfile = stdout;
+ else *logfile = fopen(logname, "wa");
+
+ }
+
+ if (!(*logfile)) {
+ fprintf(stderr, "Error %d opening logfile: %s\n", errno,
+ strerror(errno));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int log_write(struct write_unit *wu, union log_handler log)
+{
+ int fd, ret = 0;
+ char log_rec[1024];
+
+ if (test_flags & DSCV_TEST) {
+ snprintf(log_rec, sizeof(log_rec), "%lu\t%llu\t%d\t%c\n",
+ wu->wu_chunk_no, wu->wu_timestamp, wu->wu_checksum,
+ wu->wu_char);
+ ret = write(log.socket_log, log_rec, strlen(log_rec) + 1);
+ if (ret < 0) {
+ ret = errno;
+ fprintf(stderr, "write socket error:%d, %s\n",
+ ret , strerror(ret));
+ return -EINVAL;
+ }
+ } else {
+ fprintf(log.stream_log, "%lu\t%llu\t%d\t%c\n", wu->wu_chunk_no,
+ wu->wu_timestamp, wu->wu_checksum, wu->wu_char);
+ fflush(log.stream_log);
+ fd = fileno(log.stream_log);
+ fsync(fd);
+ }
+
+ return ret;
+}
--
1.5.5
More information about the Ocfs2-test-devel
mailing list