Add test case for starving writes bug in as ioscheduler.

Signed-off-by: Divyesh Shah <dpshah@google.com>



git-svn-id: http://test.kernel.org/svn/autotest/trunk@1744 592f7852-d20e-0410-864c-8624ca9c26a4
diff --git a/client/tests/iosched_bugs/control b/client/tests/iosched_bugs/control
new file mode 100644
index 0000000..41615b7
--- /dev/null
+++ b/client/tests/iosched_bugs/control
@@ -0,0 +1,16 @@
+NAME = "iosched bugs"
+AUTHOR = "Divyesh Shah (dpshah@google.com)"
+TEST_TYPE = "client"
+TEST_CLASS = "Kernel"
+TEST_CATEGORY = "Functional"
+TIME = "SHORT"
+DOC = """\
+This is a functional test for the bug in AS io scheduler where
+reads or writes can be starved when switching a batch and a request from the
+previous batch is still in-flight. This test case should see writes being
+starved forever without the bugfix(220.4 and earlier kernels) and with the
+bugfix it should see the writer making forward progress.
+"""
+
+
+job.run_test('iosched_bugs')
diff --git a/client/tests/iosched_bugs/iosched_bugs.py b/client/tests/iosched_bugs/iosched_bugs.py
new file mode 100755
index 0000000..1fe1928
--- /dev/null
+++ b/client/tests/iosched_bugs/iosched_bugs.py
@@ -0,0 +1,40 @@
+import os, time
+import subprocess
+from autotest_lib.client.bin import test
+from autotest_lib.client.common_lib import utils, error
+
+
+class iosched_bugs(test.test):
+    version = 1
+    preserve_srcdir = True
+
+
+    def setup(self):
+        os.chdir(self.srcdir)
+        utils.system('make')
+
+
+    def execute(self):
+        os.chdir(self.tmpdir)
+        (p1, _) = utils.run_bg('dd if=/dev/hda3 of=/dev/null')
+        time.sleep(60)
+        blah = os.path.join(self.tmpdir, 'blah')
+        dirty_bin = os.path.join(self.srcdir, 'dirty')
+        dirty_op = os.path.join(self.tmpdir, 'dirty')
+        utils.system('echo AA > ' + blah)
+        p2 = subprocess.Popen(dirty_bin + ' ' + blah + ' 1 > ' + dirty_op,
+                              shell=True)
+        time.sleep(600)
+        if p2.poll() is None:
+            utils.nuke_subprocess(p1)
+            utils.nuke_subprocess(p2)
+            raise error.TestFail('Writes made no progress')
+# Commenting out use of utils.run as there is a timeout bug
+#
+#       try:
+#           utils.run(dirty_bin + ' ' + blah + '1 > ' + dirty_op, 900, False,
+#                     None, None)
+#       except:
+#           utils.nuke_subprocess(p1)
+#           raise error.TestFail('Writes made no progress')
+        utils.nuke_subprocess(p1)
diff --git a/client/tests/iosched_bugs/src/Makefile b/client/tests/iosched_bugs/src/Makefile
new file mode 100644
index 0000000..da205b0
--- /dev/null
+++ b/client/tests/iosched_bugs/src/Makefile
@@ -0,0 +1,8 @@
+CC=gcc
+
+TESTS=dirty
+
+all: $(TESTS)
+
+dirty: dirty.c
+	$(CC) -o $@ $^
diff --git a/client/tests/iosched_bugs/src/dirty.c b/client/tests/iosched_bugs/src/dirty.c
new file mode 100644
index 0000000..0ed32b6
--- /dev/null
+++ b/client/tests/iosched_bugs/src/dirty.c
@@ -0,0 +1,60 @@
+// Author: Suleiman Souhlal (suleiman@google.com)
+
+#include <stdio.h>
+#include <err.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+
+#define O_NOATIME     01000000 
+
+inline uint64_t
+rdtsc(void)
+{
+	int64_t tsc;
+
+	__asm __volatile("rdtsc" : "=A" (tsc));
+	return (tsc);
+}
+
+int
+main(int argc, char **argv)
+{
+	struct stat st;
+	uint64_t e, s, t;
+	char *p, q;
+	long i;
+	int fd;
+
+	if (argc < 2) {
+		printf("Usage: %s <file>\n", argv[0]);
+		return (1);
+	}
+
+	if ((fd = open(argv[1], O_RDWR | O_NOATIME)) < 0)
+		err(1, "open");
+
+	if (fstat(fd, &st) < 0)
+		err(1, "fstat");
+
+	p = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+
+	t = 0;
+	for (i = 0; i < 1000; i++) {
+		*p = 0;
+		msync(p, 4096, MS_SYNC);
+		s = rdtsc();
+		*p = 0;
+		__asm __volatile(""::: "memory");
+		e = rdtsc();
+		if (argc > 2)
+			printf("%d: %lld cycles %jd %jd\n", i, e - s, (intmax_t)s, (intmax_t)e);
+		t += e - s;
+	}
+
+	printf("average time: %lld cycles\n", t / 1000);
+
+	return (0);
+}