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);
+}