grow-sparse grow-too-big grow-root-sm grow-root-lg grow-dir-lg \
grow-two-files dir-mkdir dir-rmdir dir-mk-vine dir-rm-vine dir-mk-tree \
dir-rm-tree dir-lsdir dir-rm-cwd dir-rm-cwd-cd dir-rm-parent \
-dir-rm-root dir-over-file dir-under-file dir-empty-name dir-open \
-syn-remove syn-read child-syn-read
+dir-rm-root dir-over-file dir-under-file dir-empty-name dir-open \
+syn-remove syn-read child-syn-read syn-write child-syn-wrt syn-rw \
+child-syn-rw
sm_create_SRC = sm-create.c fslib.c fsmain.c
sm_full_SRC = sm-full.c fslib.c fsmain.c
syn_remove_SRC = syn-remove.c fslib.c fsmain.c
syn_read_SRC = syn-read.c fslib.c fsmain.c
child_syn_read_SRC = child-syn-read.c fslib.c
-
+syn_write_SRC = syn-write.c fslib.c fsmain.c
+child_syn_wrt_SRC = child-syn-wrt.c fslib.c
+syn_rw_SRC = syn-rw.c fslib.c fsmain.c
+child_syn_rw_SRC = child-syn-rw.c fslib.c
#include <stdlib.h>
#include <syscall.h>
#include "fslib.h"
+#include "syn-read.h"
const char test_name[128] = "child-syn-read";
-static char buf[1024];
+static char buf[BUF_SIZE];
int
main (int argc, const char *argv[])
{
- const char *filename = "data";
int child_idx;
int fd;
size_t i;
quiet = true;
- check (argc == 3, "argc must be 3, actually %d", argc);
+ check (argc == 2, "argc must be 2, actually %d", argc);
child_idx = atoi (argv[1]);
- check (atoi (argv[2]) == (int) sizeof buf,
- "argv[2] must be %zu, actually %s", sizeof buf, argv[2]);
random_init (0);
random_bytes (buf, sizeof buf);
{
char c;
check (read (fd, &c, 1) > 0, "read \"%s\"", filename);
- check (c != buf[i], "byte %zu differs from expected", i);
+ compare_bytes (&c, buf + i, 1, i, filename);
}
close (fd);
--- /dev/null
+#include <random.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syscall.h>
+#include "fslib.h"
+#include "syn-rw.h"
+
+const char test_name[128] = "child-syn-rw";
+
+static char buf1[BUF_SIZE];
+static char buf2[BUF_SIZE];
+
+int
+main (int argc, const char *argv[])
+{
+ int child_idx;
+ int fd;
+ size_t ofs;
+
+ quiet = true;
+
+ check (argc == 2, "argc must be 2, actually %d", argc);
+ child_idx = atoi (argv[1]);
+
+ random_init (0);
+ random_bytes (buf1, sizeof buf1);
+
+ check ((fd = open (filename)) > 1, "open \"%s\"", filename);
+ ofs = 0;
+ while (ofs < sizeof buf2)
+ {
+ int bytes_read = read (fd, buf2 + ofs, sizeof buf2 - ofs);
+ check (bytes_read >= -1 && bytes_read <= (int) (sizeof buf2 - ofs),
+ "%zu-byte read on \"%s\" returned invalid value of %d",
+ sizeof buf2 - ofs, filename, bytes_read);
+ if (bytes_read > 0)
+ {
+ compare_bytes (buf2 + ofs, buf1 + ofs, bytes_read, ofs, filename);
+ ofs += bytes_read;
+ }
+ }
+ close (fd);
+
+ return child_idx;
+}
--- /dev/null
+#include <random.h>
+#include <stdlib.h>
+#include <syscall.h>
+#include "fslib.h"
+#include "syn-write.h"
+
+const char test_name[] = "child-syn-wrt";
+
+char buf[BUF_SIZE];
+
+int
+main (int argc, char *argv[])
+{
+ int child_idx;
+ int fd;
+
+ quiet = true;
+
+ check (argc == 2, "argc must be 2, actually %d", argc);
+ child_idx = atoi (argv[1]);
+
+ random_init (0);
+ random_bytes (buf, sizeof buf);
+
+ check ((fd = open (filename)) > 1, "open \"%s\"", filename);
+ seek (fd, CHUNK_SIZE * child_idx);
+ check (write (fd, buf + CHUNK_SIZE * child_idx, CHUNK_SIZE) > 0,
+ "write \"%s\"", filename);
+ msg ("close \"%s\"", filename);
+ close (fd);
+
+ return child_idx;
+}
(dir-mk-tree) begin
-(dir-mk-tree) creating /0/0/0/0 through /4/4/4/1...
-(dir-mk-tree) open "/0/1/2/1"
+(dir-mk-tree) creating /0/0/0/0 through /3/2/2/3...
+(dir-mk-tree) open "/0/2/0/3"
+(dir-mk-tree) close "/0/2/0/3"
(dir-mk-tree) end
-(dir-dir-as-file) begin
-(dir-dir-as-file) mkdir "abc"
-(dir-dir-as-file) create "abc" (must return false)
-(dir-dir-as-file) end
+(dir-over-file) begin
+(dir-over-file) mkdir "abc"
+(dir-over-file) create "abc" (must return false)
+(dir-over-file) end
check (chdir ("a"), "chdir \"a\"");
msg ("remove \"/a\" (must not crash)");
if (remove ("/a"))
- check (!chdir ("/a"), "chdir \"/a\" (remove succeeded so this must fail)");
+ check (!chdir ("/a"),
+ "chdir \"/a\" (remove succeeded so this must return false)");
else
check (chdir ("/a"), "chdir \"/a\" (remove failed so this must succeed)");
}
--- /dev/null
+(dir-rm-cwd-cd) begin
+(dir-rm-cwd-cd) mkdir "a"
+(dir-rm-cwd-cd) chdir "a"
+(dir-rm-cwd-cd) remove "/a" (must not crash)
+(dir-rm-cwd-cd) chdir "/a" (remove succeeded so this must return false)
+(dir-rm-cwd-cd) end
+--OR--
+(dir-rm-cwd-cd) begin
+(dir-rm-cwd-cd) mkdir "a"
+(dir-rm-cwd-cd) chdir "a"
+(dir-rm-cwd-cd) remove "/a" (must not crash)
+(dir-rm-cwd-cd) chdir "/a" (remove failed so this must succeed)
+(dir-rm-cwd-cd) end
msg ("removing /0/0/0/0 through /%d/%d/%d/%d...",
at - 1, bt - 1, ct - 1, dt - 1);
- quiet = false;
+ quiet = true;
for (a = 0; a < at; a++)
{
for (b = 0; b < bt; b++)
--- /dev/null
+(dir-rm-tree) begin
+(dir-rm-tree) creating /0/0/0/0 through /3/2/2/3...
+(dir-rm-tree) open "/0/2/0/3"
+(dir-rm-tree) close "/0/2/0/3"
+(dir-rm-tree) removing /0/0/0/0 through /3/2/2/3...
+(dir-rm-tree) open "/3/0/2/0" (must return -1)
+(dir-rm-tree) end
*strrchr (tmp, '/') = 0;
}
- check (open (filename) == 1, "open \"%s\" (must return -1)", filename);
+ check (open (filename) == -1, "open \"%s\" (must return -1)", filename);
}
--- /dev/null
+(dir-rm-vine) begin
+(dir-rm-vine) mkdir "0"
+(dir-rm-vine) chdir "0"
+(dir-rm-vine) mkdir "1"
+(dir-rm-vine) chdir "1"
+(dir-rm-vine) mkdir "2"
+(dir-rm-vine) chdir "2"
+(dir-rm-vine) mkdir "3"
+(dir-rm-vine) chdir "3"
+(dir-rm-vine) mkdir "4"
+(dir-rm-vine) chdir "4"
+(dir-rm-vine) mkdir "5"
+(dir-rm-vine) chdir "5"
+(dir-rm-vine) mkdir "6"
+(dir-rm-vine) chdir "6"
+(dir-rm-vine) mkdir "7"
+(dir-rm-vine) chdir "7"
+(dir-rm-vine) mkdir "8"
+(dir-rm-vine) chdir "8"
+(dir-rm-vine) mkdir "9"
+(dir-rm-vine) chdir "9"
+(dir-rm-vine) create "test"
+(dir-rm-vine) chdir "/"
+(dir-rm-vine) open "/0/1/2/3/4/5/6/7/8/9/test"
+(dir-rm-vine) close "/0/1/2/3/4/5/6/7/8/9/test"
+(dir-rm-vine) remove "/0/1/2/3/4/5/6/7/8/9/test"
+(dir-rm-vine) remove "/0/1/2/3/4/5/6/7/8/9"
+(dir-rm-vine) remove "/0/1/2/3/4/5/6/7/8"
+(dir-rm-vine) remove "/0/1/2/3/4/5/6/7"
+(dir-rm-vine) remove "/0/1/2/3/4/5/6"
+(dir-rm-vine) remove "/0/1/2/3/4/5"
+(dir-rm-vine) remove "/0/1/2/3/4"
+(dir-rm-vine) remove "/0/1/2/3"
+(dir-rm-vine) remove "/0/1/2"
+(dir-rm-vine) remove "/0/1"
+(dir-rm-vine) remove "/0"
+(dir-rm-vine) open "/0/1/2/3/4/5/6/7/8/9/test" (must return -1)
+(dir-rm-vine) end
bool quiet = false;
static void
-vmsg (const char *format, va_list args)
+vmsg (const char *format, va_list args, const char *suffix)
{
- printf ("(%s) ", test_name);
- vprintf (format, args);
+ /* We go to some trouble to stuff the entire message into a
+ single buffer and output it in a single system call, because
+ that'll (typically) ensure that it gets sent to the console
+ atomically. Otherwise kernel messages like "foo: exit(0)"
+ can end up being interleaved if we're unlucky. */
+ static char buf[1024];
+
+ snprintf (buf, sizeof buf, "(%s) ", test_name);
+ vsnprintf (buf + strlen (buf), sizeof buf - strlen (buf), format, args);
+ strlcpy (buf + strlen (buf), suffix, sizeof buf - strlen (buf));
+ write (STDOUT_FILENO, buf, strlen (buf));
}
void
if (quiet)
return;
va_start (args, format);
- vmsg (format, args);
- printf ("\n");
+ vmsg (format, args, "\n");
va_end (args);
}
va_list args;
va_start (args, format);
- vmsg (format, args);
- printf (": FAILED\n");
+ vmsg (format, args, ": FAILED\n");
va_end (args);
exit (1);
}
-void
-check (bool success, const char *format, ...)
-{
- va_list args;
-
- va_start (args, format);
- if (success)
- {
- if (!quiet)
- {
- vmsg (format, args);
- printf ("\n");
- }
- }
- else
- {
- vmsg (format, args);
- printf (": FAILED\n");
- exit (1);
- }
- va_end (args);
-}
-
void
seq_test (const char *filename, void *buf, size_t size, size_t initial_size,
size_t (*block_size_func) (void),
fail ("read %zu bytes at offset %zu in \"%s\" failed",
block_size, ofs, filename);
- if (memcmp (buf + ofs, block, block_size))
- {
- if (block_size <= 512)
- {
- printf ("Expected data:\n");
- hex_dump (ofs, buf + ofs, block_size, false);
- printf ("Actually read data:\n");
- hex_dump (ofs, block, block_size, false);
- }
- fail ("%zu bytes at offset %zu differed from expected",
- block_size, ofs);
- }
-
+ compare_bytes (block, buf + ofs, block_size, ofs, filename);
ofs += block_size;
}
msg ("close \"%s\"", filename);
close (fd);
}
+
+void
+compare_bytes (const void *read_data_, const void *expected_data_, size_t size,
+ size_t ofs, const char *filename)
+{
+ const uint8_t *read_data = read_data_;
+ const uint8_t *expected_data = expected_data_;
+ size_t i, j;
+ size_t show_cnt;
+
+ if (!memcmp (read_data, expected_data, size))
+ return;
+
+ for (i = 0; i < size; i++)
+ if (read_data[i] != expected_data[i])
+ break;
+ for (j = i + 1; j < size; j++)
+ if (read_data[j] == expected_data[j])
+ break;
+
+ quiet = false;
+ msg ("%zu bytes read starting at offset %zu in \"%s\" differ "
+ "from expected.", j - i, ofs + i, filename);
+ show_cnt = j - i;
+ if (j - i > 64)
+ {
+ show_cnt = 64;
+ msg ("Showing first differing %zu bytes.", show_cnt);
+ }
+ msg ("Data actually read:");
+ hex_dump (ofs + i, read_data + i, show_cnt, true);
+ msg ("Expected data:");
+ hex_dump (ofs + i, expected_data + i, show_cnt, true);
+ fail ("%zu bytes read starting at offset %zu in \"%s\" differ "
+ "from expected", j - i, ofs, filename);
+}
void msg (const char *, ...) PRINTF_FORMAT (1, 2);
void fail (const char *, ...) PRINTF_FORMAT (1, 2) NO_RETURN;
-void check (bool, const char *, ...) PRINTF_FORMAT (2, 3);
+
+#define check(SUCCESS, ...) \
+ do \
+ { \
+ msg (__VA_ARGS__); \
+ if (!(SUCCESS)) \
+ fail (__VA_ARGS__); \
+ } \
+ while (0)
void shuffle (void *, size_t cnt, size_t size);
void check_file (const char *filename, const void *buf, size_t filesize);
+void compare_bytes (const void *read_data, const void *expected_data,
+ size_t size, size_t ofs, const char *filename);
+
void test_main (void);
#endif /* fslib.h */
const char test_name[] = "grow-root-sm";
-#define FILE_CNT 20
+#define FILE_CNT 10
#include "grow-dir.inc"
(grow-root-sm) creating and checking "file7"
(grow-root-sm) creating and checking "file8"
(grow-root-sm) creating and checking "file9"
-(grow-root-sm) creating and checking "file10"
-(grow-root-sm) creating and checking "file11"
-(grow-root-sm) creating and checking "file12"
-(grow-root-sm) creating and checking "file13"
-(grow-root-sm) creating and checking "file14"
-(grow-root-sm) creating and checking "file15"
-(grow-root-sm) creating and checking "file16"
-(grow-root-sm) creating and checking "file17"
-(grow-root-sm) creating and checking "file18"
-(grow-root-sm) creating and checking "file19"
(grow-root-sm) end
--- /dev/null
+(grow-sparse) begin
+(grow-sparse) create "testfile"
+(grow-sparse) open "testfile"
+(grow-sparse) seek "testfile"
+(grow-sparse) write "testfile"
+(grow-sparse) close "testfile"
+(grow-sparse) end
+(grow-two-files) begin
(grow-two-files) create "a"
(grow-two-files) create "b"
(grow-two-files) open "a"
(grow-two-files) close "a"
(grow-two-files) open "b" for verification
(grow-two-files) close "b"
+(grow-two-files) end
void
test_main (void)
{
+ const char *filename = "bazzle";
int fd;
size_t i;
for (i = 0; i < BLOCK_CNT; i++)
order[i] = i;
- check (create ("bazzle", TEST_SIZE), "create \"bazzle\"");
- check ((fd = open ("bazzle")) > 1, "open \"bazzle\"");
+ check (create (filename, TEST_SIZE), "create \"%s\"", filename);
+ check ((fd = open (filename)) > 1, "open \"%s\"", filename);
- msg ("write \"bazzle\" in random order");
+ msg ("write \"%s\" in random order", filename);
shuffle (order, BLOCK_CNT, sizeof *order);
for (i = 0; i < BLOCK_CNT; i++)
{
fail ("write %d bytes at offset %zu failed", (int) BLOCK_SIZE, ofs);
}
- msg ("read \"bazzle\" in random order");
+ msg ("read \"%s\" in random order", filename);
shuffle (order, BLOCK_CNT, sizeof *order);
for (i = 0; i < BLOCK_CNT; i++)
{
seek (fd, ofs);
if (read (fd, block, BLOCK_SIZE) <= 0)
fail ("read %d bytes at offset %zu failed", (int) BLOCK_SIZE, ofs);
- if (memcmp (block, buf + ofs, BLOCK_SIZE))
- {
- printf ("Expected data:\n");
- hex_dump (ofs, buf + ofs, BLOCK_SIZE, false);
- printf ("Actually read data:\n");
- hex_dump (ofs, block, BLOCK_SIZE, false);
- fail ("%d bytes at offset %zu differed from expected",
- (int) BLOCK_SIZE, ofs);
- }
+ compare_bytes (block, buf + ofs, BLOCK_SIZE, ofs, filename);
}
- fail ("close \"bazzle\"");
+ msg ("close \"%s\"", filename);
close (fd);
}
dir-rm-parent dir-rm-root dir-over-file dir-under-file
dir-empty-name dir-open
- syn-remove syn-read
+ syn-remove syn-read syn-write syn-rw
) unless @TESTS > 0;
our (%args);
sub compile {
print "Compiling...\n";
- xsystem ("cd pintos/src/vm && make", LOG => "make")
+ xsystem ("cd pintos/src/filesys && make", LOG => "make")
or return "compile error";
}
# Format disk, install test.
my ($pintos_base_cmd) =
"pintos "
- . "--os-disk=pintos/src/vm/build/os.dsk "
+ . "--os-disk=pintos/src/filesys/build/os.dsk "
. "--fs-disk=output/$test/fs.dsk "
. "--swap-disk=output/$test/swap.dsk "
. "-v";
my (@extra_files);
push (@extra_files, "child-syn-read") if $test eq 'syn-read';
+ push (@extra_files, "child-syn-wrt") if $test eq 'syn-write';
+ push (@extra_files, "child-syn-rw") if $test eq 'syn-rw';
for my $fn (@extra_files) {
return "format/put error"
if !xsystem ("$pintos_base_cmd put $GRADES_DIR/$fn $fn",
} else {
$A2L = "i386-elf-addr2line";
}
- open (A2L, "$A2L -fe pintos/src/vm/build/kernel.o @addrs|");
+ open (A2L, "$A2L -fe pintos/src/filesys/build/kernel.o @addrs|");
for (;;) {
my ($function, $line);
last unless defined ($function = <A2L>);
die "Kernel panic. Details at end of file.\n"
}
+ my (@failure) = grep (/FAIL/, @output);
+ if (@failure != 0) {
+ die "Test failed: \"$failure[0]\"\n";
+ }
+
if (grep (/Pintos booting/, @output) > 1) {
my ($details);
#include <stdio.h>
#include <syscall.h>
#include "fslib.h"
+#include "syn-read.h"
const char test_name[] = "syn-read";
-static char buf[1024];
+static char buf[BUF_SIZE];
#define CHILD_CNT 10
void
test_main (void)
{
- const char *filename = "data";
pid_t children[CHILD_CNT];
int fd;
int i;
for (i = 0; i < CHILD_CNT; i++)
{
char cmd_line[128];
- snprintf (cmd_line, sizeof cmd_line,
- "child-syn-read %d %zu", i, sizeof buf);
+ snprintf (cmd_line, sizeof cmd_line, "child-syn-read %d", i);
check ((children[i] = exec (cmd_line)) != PID_ERROR,
- "exec \"%s\"", cmd_line);
+ "exec child %d of %d: \"%s\"", i + 1, (int) CHILD_CNT, cmd_line);
}
for (i = 0; i < CHILD_CNT; i++)
--- /dev/null
+#define BUF_SIZE 1024
+static const char filename[] = "data";
msg ("seek \"%s\" to 0", filename);
seek (fd, 0);
check (read (fd, buf2, sizeof buf2) > 0, "read \"%s\"", filename);
- check (!memcmp (buf1, buf2, sizeof buf1), "compare data read and written");
+ compare_bytes (buf2, buf1, sizeof buf1, 0, filename);
msg ("close \"%s\"", filename);
close (fd);
}
(syn-remove) write "deleteme"
(syn-remove) seek "deleteme" to 0
(syn-remove) read "deleteme"
-(syn-remove) compare data read and written
(syn-remove) close "deleteme"
(syn-remove) end
--- /dev/null
+#include <random.h>
+#include <stdio.h>
+#include <syscall.h>
+#include "fslib.h"
+#include "syn-rw.h"
+
+const char test_name[] = "syn-rw";
+
+char buf[BUF_SIZE];
+
+#define CHILD_CNT 4
+
+void
+test_main (void)
+{
+ pid_t children[CHILD_CNT];
+ size_t ofs;
+ int fd;
+ int i;
+
+ check (create (filename, 0), "create \"%s\"", filename);
+ check ((fd = open (filename)) > 1, "open \"%s\"", filename);
+
+ for (i = 0; i < CHILD_CNT; i++)
+ {
+ char cmd_line[128];
+ snprintf (cmd_line, sizeof cmd_line, "child-syn-rw %d", i);
+ check ((children[i] = exec (cmd_line)) != PID_ERROR,
+ "exec child %d of %d: \"%s\"", i + 1, (int) CHILD_CNT, cmd_line);
+ }
+
+ random_bytes (buf, sizeof buf);
+ quiet = true;
+ for (ofs = 0; ofs < BUF_SIZE; ofs += CHUNK_SIZE)
+ check (write (fd, buf + ofs, CHUNK_SIZE) > 0,
+ "write %d bytes at offset %zu in \"%s\"",
+ (int) CHUNK_SIZE, ofs, filename);
+ quiet = false;
+
+ for (i = 0; i < CHILD_CNT; i++)
+ {
+ int status = join (children[i]);
+ check (status == i, "join child %d of %d", i + 1, (int) CHILD_CNT);
+ }
+}
--- /dev/null
+#define CHUNK_SIZE 8
+#define CHUNK_CNT 512
+#define BUF_SIZE (CHUNK_SIZE * CHUNK_CNT)
+static const char filename[] = "logfile";
--- /dev/null
+#include <random.h>
+#include <stdio.h>
+#include <string.h>
+#include <syscall.h>
+#include "fslib.h"
+#include "syn-write.h"
+
+const char test_name[] = "syn-write";
+
+char buf1[BUF_SIZE];
+char buf2[BUF_SIZE];
+
+void
+test_main (void)
+{
+ pid_t children[CHILD_CNT];
+ int fd;
+ int i;
+
+ check (create (filename, sizeof buf1), "create \"%s\"", filename);
+
+ for (i = 0; i < CHILD_CNT; i++)
+ {
+ char cmd_line[128];
+ snprintf (cmd_line, sizeof cmd_line, "child-syn-wrt %d", i);
+ check ((children[i] = exec (cmd_line)) != PID_ERROR,
+ "exec child %d of %d: \"%s\"", i + 1, (int) CHILD_CNT, cmd_line);
+ }
+
+ for (i = 0; i < CHILD_CNT; i++)
+ {
+ int status = join (children[i]);
+ check (status == i, "join child %d of %d", i + 1, (int) CHILD_CNT);
+ }
+
+ check ((fd = open (filename)) > 1, "open \"%s\"", filename);
+ check (read (fd, buf1, sizeof buf1) > 0, "read \"%s\"", filename);
+ random_bytes (buf2, sizeof buf2);
+ compare_bytes (buf1, buf2, sizeof buf1, 0, filename);
+}
--- /dev/null
+(syn-write) begin
+(syn-write) create "stuff"
+(syn-write) exec child 1 of 10: "child-syn-wrt 0"
+(syn-write) exec child 2 of 10: "child-syn-wrt 1"
+(syn-write) exec child 3 of 10: "child-syn-wrt 2"
+(syn-write) exec child 4 of 10: "child-syn-wrt 3"
+(syn-write) exec child 5 of 10: "child-syn-wrt 4"
+(syn-write) exec child 6 of 10: "child-syn-wrt 5"
+(syn-write) exec child 7 of 10: "child-syn-wrt 6"
+(syn-write) exec child 8 of 10: "child-syn-wrt 7"
+(syn-write) exec child 9 of 10: "child-syn-wrt 8"
+(syn-write) exec child 10 of 10: "child-syn-wrt 9"
+(syn-write) join child 1 of 10
+(syn-write) join child 2 of 10
+(syn-write) join child 3 of 10
+(syn-write) join child 4 of 10
+(syn-write) join child 5 of 10
+(syn-write) join child 6 of 10
+(syn-write) join child 7 of 10
+(syn-write) join child 8 of 10
+(syn-write) join child 9 of 10
+(syn-write) join child 10 of 10
+(syn-write) open "stuff"
+(syn-write) read "stuff"
+(syn-write) end
--- /dev/null
+#define CHILD_CNT 10
+#define CHUNK_SIZE 512
+#define BUF_SIZE (CHILD_CNT * CHUNK_SIZE)
+static const char filename[] = "stuff";