Add a test case for PR kern/36681 demonstrating how easy it is to

get tmpfs rename to "tstile".

Note1: triggering this on any non-SMP system is not as easy (because
one system call tends to run from start to finish in one go) and
therefore I've limited it to i386 and amd64.  Incidentally, I'm
still waiting for the eternally elusive MI CPU_INFO_FOREACH (or at
least something else than a stupid macro) ...

Note2: this is a "race condition" test.  I tested it on my development
host and in qemu and it triggers pretty instantly.  But YMMV.
This commit is contained in:
pooka 2010-07-04 12:43:23 +00:00
parent 76cbf63f87
commit d2c2528c3b
1 changed files with 99 additions and 3 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: t_renamerace.c,v 1.6 2009/04/26 15:15:38 pooka Exp $ */
/* $NetBSD: t_renamerace.c,v 1.7 2010/07/04 12:43:23 pooka Exp $ */
/*
* Modified for rump and atf from a program supplied
@ -7,14 +7,16 @@
#include <sys/types.h>
#include <sys/mount.h>
#include <sys/utsname.h>
#include <atf-c.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <rump/rump.h>
#include <rump/rump_syscalls.h>
@ -73,8 +75,102 @@ ATF_TC_BODY(renamerace, tc)
sleep(10);
}
ATF_TC(renamerace2);
ATF_TC_HEAD(renamerace2, tc)
{
atf_tc_set_md_var(tc, "descr", "rename(2) lock order inversion");
atf_tc_set_md_var(tc, "timeout", "6");
}
static volatile int quittingtime = 0;
static void *
r2w1(void *arg)
{
int fd;
rump_pub_lwp_alloc_and_switch(0, 0);
fd = rump_sys_open("/file", O_CREAT | O_RDWR, 0777);
if (fd == -1)
atf_tc_fail_errno("creat");
rump_sys_close(fd);
while (!quittingtime) {
if (rump_sys_rename("/file", "/dir/file") == -1)
atf_tc_fail_errno("rename 1");
if (rump_sys_rename("/dir/file", "/file") == -1)
atf_tc_fail_errno("rename 2");
}
return NULL;
}
static void *
r2w2(void *arg)
{
int fd;
rump_pub_lwp_alloc_and_switch(0, 0);
while (!quittingtime) {
fd = rump_sys_open("/dir/file1", O_RDWR);
if (fd != -1)
rump_sys_close(fd);
}
return NULL;
}
ATF_TC_BODY(renamerace2, tc)
{
struct tmpfs_args args;
struct utsname un;
pthread_t pt[2];
/*
* Check that we are running on an SMP-capable arch. It should
* be a rump capability, but after the CPU_INFO_FOREACH is
* fixed, it will be every arch (for rump), so don't bother.
*/
if (uname(&un) == -1)
atf_tc_fail_errno("uname");
if (strcmp(un.machine, "i386") != 0 && strcmp(un.machine, "amd64") != 0)
atf_tc_skip("i386 or amd64 required (have %s)", un.machine);
/*
* Force SMP regardless of how many host CPUs there are.
* Deadlock is highly unlikely to trigger otherwise.
*/
setenv("RUMP_NCPU", "2", 1);
rump_init();
memset(&args, 0, sizeof(args));
args.ta_version = TMPFS_ARGS_VERSION;
args.ta_root_mode = 0777;
if (rump_sys_mount(MOUNT_TMPFS, "/", 0, &args, sizeof(args)) == -1)
atf_tc_fail_errno("could not mount tmpfs");
if (rump_sys_mkdir("/dir", 0777) == -1)
atf_tc_fail_errno("cannot create directory");
pthread_create(&pt[0], NULL, r2w1, NULL);
pthread_create(&pt[1], NULL, r2w2, NULL);
/* usually triggers in <<1s for me */
sleep(4);
quittingtime = 1;
atf_tc_expect_timeout("PR kern/36681");
pthread_join(pt[0], NULL);
pthread_join(pt[1], NULL);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, renamerace);
return 0; /*XXX?*/
ATF_TP_ADD_TC(tp, renamerace2);
return atf_no_error();
}