Added testsync to help test sync.

Testsync works in conjunction with platform_SyncCrash to
test fsync and msync. The test writes data to a file,
calls a flavor of sync and then the crashes the system.
After the system comes back up, testsync verifies that
the data was saved correctly.

BUG=chromium:239536
TEST=platform_SyncCrash

Change-Id: Ieceba236a00b344ca96fdc5f44c52985e1c51492
Reviewed-on: https://gerrit.chromium.org/gerrit/56412
Tested-by: Paul Taysom <taysom@chromium.org>
Reviewed-by: Luigi Semenzato <semenzato@chromium.org>
Commit-Queue: Paul Taysom <taysom@chromium.org>
diff --git a/file.m/testsync.c b/file.m/testsync.c
new file mode 100644
index 0000000..30e5bc2
--- /dev/null
+++ b/file.m/testsync.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ * These tests verify that sync works correctly.
+ *
+ * Each test is written in two phases. The first sets up the test,
+ * writes the data, calls sync and then crashes the system.
+ *
+ * After the system reboots, the second phase of the test verifies
+ * the results and cleans up.
+ *
+ * Current phases:
+ * writer - writes to the given file, calls fsync, then crashes.
+ * mapper - uses memory mapped file to write data, calls msync,
+ *          then crashes.
+ * verifier - verifies that all the data that was synced is there.
+ *
+ * Uses a 64 bit counter for the data.
+ */
+
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <debug.h>
+#include <eprintf.h>
+#include <esys.h>
+#include <puny.h>
+#include <style.h>
+#include <util.h>
+
+enum {
+	CHUNK_SIZE = (1<<13),
+	NUM_U64_PER_CHUNK = CHUNK_SIZE / sizeof(u64)
+};
+
+static char *PhaseName;
+typedef void (*phasefn_t)(void);
+
+struct phase {
+	char *name;
+	phasefn_t fn;
+};
+
+u64 Buf[NUM_U64_PER_CHUNK];
+u64 Value;
+
+static void fill(void)
+{
+	int i;
+
+	for (i = 0; i < NUM_U64_PER_CHUNK; i++)
+		Buf[i] = Value++;
+}
+
+static void verify(void)
+{
+	int i;
+
+	for (i = 0; i < NUM_U64_PER_CHUNK; i++) {
+		if (Buf[i] != Value)
+			fatal("Expected %lld is %lld", Value, Buf[i]);
+		Value++;
+	}
+}
+
+static void writer(void)
+{
+	u64 size = Option.file_size;
+	u64 chunks = size / sizeof(Buf);
+	u64 i;
+	int fd = eopen(Option.file, O_WRONLY | O_CREAT | O_TRUNC);
+
+	Value = 0;
+	for (i = 0; i < chunks; i++) {
+		fill();
+		ewrite(fd, Buf, sizeof(Buf));
+	}
+	efsync(fd);
+	crash();
+}
+
+static void mapper(void)
+{
+	u64 size = Option.file_size;
+	u64 chunks = size / sizeof(Buf);
+	u64 i;
+	u8 *map;
+	u8 *m;
+	int fd = eopen(Option.file, O_RDWR | O_CREAT | O_TRUNC);
+
+	Value = 0;
+	epwrite(fd, "", 1, size - 1);
+	map = emmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+	for (m = map, i = 0; i < chunks; i++, m += sizeof(Buf)) {
+		fill();
+		memcpy(m, Buf, sizeof(Buf));
+	}
+	emsync(map, size, MS_SYNC);
+	crash();
+}
+
+static void verifier(void)
+{
+	u64 size = Option.file_size;
+	u64 blocks = size / sizeof(Buf);
+	u64 i;
+	int fd = eopen(Option.file, O_RDONLY);
+
+	Value = 0;
+	for (i = 0; i < blocks; i++) {
+		eread(fd, Buf, sizeof(Buf));
+		verify();
+	}
+	eclose(fd);
+}
+
+static struct phase Phase[] = {
+	{ "writer", writer },
+	{ "mapper", mapper },
+	{ "verifier", verifier }
+};
+
+static phasefn_t find_phase(char *name)
+{
+	int n = sizeof(Phase) / sizeof(struct phase);
+	int i;
+
+	for (i = 0; i < n; i++)
+		if (strcmp(name, Phase[i].name) == 0)
+			return Phase[i].fn;
+	fatal("Phase %s: not found", name);
+	return NULL;
+}
+
+static bool myopt(int c)
+{
+	switch (c) {
+	case 'p':
+		PhaseName = strdup(optarg);
+		break;
+	default:
+		return FALSE;
+	}
+	return TRUE;
+}
+
+void usage (void)
+{
+	pr_usage("-f <file> -p <test phase name>\n"
+		"\tf - file to write");
+}
+
+int main(int argc, char *argv[])
+{
+	phasefn_t fn;
+
+	punyopt(argc, argv, myopt, "p:");
+	fn = find_phase(PhaseName);
+	if (fn)
+		fn();
+	return 0;
+}
diff --git a/include/esys.h b/include/esys.h
new file mode 100644
index 0000000..c655e66
--- /dev/null
+++ b/include/esys.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ * esys wraps all the system calls and calls fatal on errors.
+ */
+
+void eclose(int fd);
+int ecreat(const char *pathname);
+void efsync(int fd);
+void efdatasync(int fd);
+int eopen(const char *pathname, int flags);
+int eread(int fd, void *buf, size_t nbyte);
+int epread(int fd, void *buf, size_t nbyte, off_t offset);
+void esync(void);
+void esyncfs(int fd);
+void eunlink(const char *pathname);
+int ewrite(int fd, const void *buf, size_t nbyte);
+int epwrite(int fd, void *buf, size_t nbyte, off_t offset);
+void *emmap(void *addr, size_t length, int prot, int flags,
+	int fd, off_t offset);
+void emunmap(void *addr, size_t length);
+void emsync(void *addr, size_t length, int flags);
diff --git a/include/twister.h b/include/twister.h
index e2a5d93..21c99c9 100644
--- a/include/twister.h
+++ b/include/twister.h
@@ -57,6 +57,7 @@
 #define _TWISTER_H_ 1
 
 #include <style.h>
+#include <stdlib.h>
 
 /*
  * Interfaces to Mersenne Twister pseudorandom number generator.
diff --git a/include/util.h b/include/util.h
new file mode 100644
index 0000000..4a4e530
--- /dev/null
+++ b/include/util.h
@@ -0,0 +1,11 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ * Miscellaneous utilities for writing tests.
+ */
+
+void gen_name(char *name, int len);
+void crash(void);
diff --git a/libpuny.b/esys.c b/libpuny.b/esys.c
new file mode 100644
index 0000000..d61558a
--- /dev/null
+++ b/libpuny.b/esys.c
@@ -0,0 +1,132 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ * esys wraps all the system calls and generates fatal errors.
+ * Some arguments are hard coded.
+ */
+
+#define _GNU_SOURCE
+
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <eprintf.h>
+#include <esys.h>
+
+void eclose(int fd)
+{
+	int rc = close(fd);
+	if (rc == -1)
+		fatal("close:");
+}
+
+int ecreat(const char *pathname)
+{
+	int fd = creat(pathname, 0666);
+	if (fd == -1)
+		fatal("creat %s:", pathname);
+	return fd;
+}
+
+void efsync(int fd)
+{
+	int rc = fsync(fd);
+	if (rc == -1)
+		fatal("fsync:");
+}
+
+void efdatasync(int fd)
+{
+	int rc = fdatasync(fd);
+	if (rc == -1)
+		fatal("fdatasync:");
+}
+
+int eopen(const char *pathname, int flags)
+{
+	int fd = open(pathname, flags, 0666);
+	if (fd == -1)
+		fatal("open %s:", pathname);
+	return fd;
+}
+
+int eread(int fd, void *buf, size_t nbyte)
+{
+	ssize_t	rc = read(fd, buf, nbyte);
+	if (rc == -1)
+		fatal("read:");
+	return rc;
+}
+
+int epread(int fd, void *buf, size_t nbyte, off_t offset)
+{
+	ssize_t	rc = pread(fd, buf, nbyte, offset);
+	if (rc == -1)
+		fatal("pread:");
+	return rc;
+}
+
+void esync(void)
+{
+	sync();
+}
+
+void esyncfs(int fd)
+{
+	syncfs(fd);
+}
+
+void eunlink(const char *pathname)
+{
+	int rc = unlink(pathname);
+	if (rc == -1)
+		fatal("unlink %s:", pathname);
+}
+
+int ewrite(int fildes, const void *buf, size_t nbyte)
+{
+	ssize_t	rc = write(fildes, buf, nbyte);
+	if (rc == -1)
+		fatal("write:");
+	return rc;
+}
+
+int epwrite(int fd, void *buf, size_t nbyte, off_t offset)
+{
+	ssize_t	rc;
+
+	rc = pwrite(fd, buf, nbyte, offset);
+	if (rc == -1)
+		fatal("pwrite:");
+	return rc;
+}
+
+void *emmap(void *addr, size_t length, int prot, int flags,
+	int fd, off_t offset)
+{
+	void *map = mmap(addr, length, prot, flags, fd, offset);
+	if (map == MAP_FAILED)
+		fatal("mmap:");
+	return map;
+}
+
+void emunmap(void *addr, size_t length)
+{
+	int rc = munmap(addr, length);
+	if (rc == -1)
+		fatal("munmap:");
+}
+
+void emsync(void *addr, size_t length, int flags)
+{
+	int rc = msync(addr, length, flags);
+	if (rc == -1)
+		fatal("msync;");
+}
+
diff --git a/libpuny.b/util.c b/libpuny.b/util.c
new file mode 100644
index 0000000..f80fbe4
--- /dev/null
+++ b/libpuny.b/util.c
@@ -0,0 +1,44 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ * Miscellaneous utilities for writing tests.
+ */
+
+
+#include <fcntl.h>
+
+#include <esys.h>
+#include <twister.h>
+#include <util.h>
+
+/*
+ * gen_name: generate a random file name of the given length.
+ * The len include the null at the end.
+ */
+void gen_name(char *name, int len)
+{
+	static char file_name_char[] =	"abcdefghijklmnopqrstuvwxyz"
+					"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+					"_0123456789";
+	char *c = name;
+
+	for (--len; len > 0; len--)
+		*c++ = file_name_char[twister_urand(sizeof(file_name_char) - 1)];
+	*c = '\0';
+}
+
+
+/*
+ * crash crashes the system by causing a panic:
+ * echo panic >/proc/breakme
+ */
+
+void crash(void)
+{
+	static char panic[] = "panic";
+	int fd = eopen("/proc/breakme", O_WRONLY);
+	ewrite(fd, panic, sizeof(panic));
+}