Add some basic tests for inactive/reclaim. To make this possible,

adjust the read/write shovel threads so, that we can tap into the
operations between puffs(9) and the file server.
This commit is contained in:
pooka 2010-07-11 12:26:19 +00:00
parent 52a4f7ac75
commit a436045559
2 changed files with 247 additions and 16 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.5 2010/07/07 10:49:51 pooka Exp $
# $NetBSD: Makefile,v 1.6 2010/07/11 12:26:19 pooka Exp $
#
.include <bsd.own.mk>
@ -14,6 +14,7 @@ LDADD+= -lrumpfs_syspuffs -lrumpvfs_fifofs
LDADD+= -lrumpnet_local -lrumpnet_net -lrumpnet
LDADD+= -lrumpvfs
LDADD+= -lrump -lrumpuser -lpthread
LDADD+= -lpuffs -lutil
.include <bsd.test.mk>
.include <bsd.subdir.mk>

View File

@ -1,4 +1,4 @@
/* $NetBSD: t_basic.c,v 1.3 2010/07/07 10:49:51 pooka Exp $ */
/* $NetBSD: t_basic.c,v 1.4 2010/07/11 12:26:19 pooka Exp $ */
#include <sys/types.h>
#include <sys/mount.h>
@ -11,6 +11,7 @@
#include <fcntl.h>
#include <pthread.h>
#include <puffs.h>
#include <puffsdump.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
@ -31,12 +32,49 @@ struct puffs_args {
};
#define BUFSIZE (64*1024)
#define DTFS_DUMP "-o","dump"
struct thefds {
int rumpfd;
int servfd;
};
int vfs_toserv_ops[PUFFS_VFS_MAX];
int vn_toserv_ops[PUFFS_VN_MAX];
/*
* Do a synchronous operation. When this returns, all FAF operations
* have at least been delivered to the file system.
*
* XXX: is this really good enough considering puffs(9)-issued
* callback operations?
*/
static void
syncbar(const char *fs)
{
struct statvfs svb;
rump_sys_statvfs1(fs, &svb, ST_WAIT);
}
static void
dumpopcount(void)
{
size_t i;
printf("VFS OPS:\n");
for (i = 0; i < MIN(puffsdump_vfsop_count, PUFFS_VFS_MAX); i++) {
printf("\t%s: %d\n",
puffsdump_vfsop_revmap[i], vfs_toserv_ops[i]);
}
printf("VN OPS:\n");
for (i = 0; i < MIN(puffsdump_vnop_count, PUFFS_VN_MAX); i++) {
printf("\t%s: %d\n",
puffsdump_vnop_revmap[i], vn_toserv_ops[i]);
}
}
/*
* Threads which shovel data between comfd and /dev/puffs.
* (cannot use polling since fd's are in different namespaces)
@ -44,6 +82,8 @@ struct thefds {
static void *
readshovel(void *arg)
{
struct putter_hdr *phdr;
struct puffs_req *preq;
struct thefds *fds = arg;
char buf[BUFSIZE];
ssize_t n;
@ -52,25 +92,37 @@ readshovel(void *arg)
comfd = fds->servfd;
puffsfd = fds->rumpfd;
phdr = (void *)buf;
preq = (void *)buf;
/* use static thread id */
rump_pub_lwp_alloc_and_switch(0, 0);
rump_pub_lwp_alloc_and_switch(0, 10);
for (;;) {
ssize_t n, n2;
n = rump_sys_read(puffsfd, buf, BUFSIZE);
if (n <= 0) {
n = rump_sys_read(puffsfd, buf, sizeof(*phdr));
if (n <= 0)
break;
assert(phdr->pth_framelen < BUFSIZE);
n = rump_sys_read(puffsfd, buf+sizeof(*phdr),
phdr->pth_framelen - sizeof(*phdr));
if (n <= 0)
break;
/* Analyze request */
if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) {
assert(preq->preq_optype < PUFFS_VFS_MAX);
vfs_toserv_ops[preq->preq_optype]++;
} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
assert(preq->preq_optype < PUFFS_VN_MAX);
vn_toserv_ops[preq->preq_optype]++;
}
while (n) {
n2 = write(comfd, buf, n);
if (n2 == -1)
err(1, "readshovel failed write: %d");
if (n2 == 0)
n = phdr->pth_framelen;
if (write(comfd, buf, n) != n)
break;
n -= n2;
}
}
return NULL;
@ -86,7 +138,7 @@ writeshovel(void *arg)
int error, comfd, puffsfd;
/* use static thread id */
rump_pub_lwp_alloc_and_switch(0, 0);
rump_pub_lwp_alloc_and_switch(0, 11);
comfd = fds->servfd;
puffsfd = fds->rumpfd;
@ -103,6 +155,7 @@ writeshovel(void *arg)
*/
off = 0;
toread = sizeof(struct putter_hdr);
assert(toread < BUFSIZE);
do {
n = read(comfd, buf+off, toread);
if (n <= 0) {
@ -117,10 +170,9 @@ writeshovel(void *arg)
n = rump_sys_write(puffsfd, buf, phdr->pth_framelen);
if (n != phdr->pth_framelen)
goto out;
break;
}
out:
return NULL;
}
@ -438,6 +490,179 @@ ATF_TC_BODY(root_chrdev, tc)
atf_tc_fail_errno("unmount");
}
/*
* Inactive/reclaim tests
*/
ATF_TC(inactive_basic);
ATF_TC_HEAD(inactive_basic, tc)
{
atf_tc_set_md_var(tc, "descr", "inactive gets called");
}
ATF_TC_BODY(inactive_basic, tc)
{
char *myopts[] = {
"-i",
"dtfs",
};
int fd;
dtfsmountv("/mp", myopts);
fd = rump_sys_open("/mp/file", O_CREAT | O_RDWR, 0777);
if (fd == -1)
atf_tc_fail_errno("create");
/* one for /mp */
ATF_REQUIRE_EQ(vn_toserv_ops[PUFFS_VN_INACTIVE], 1);
rump_sys_close(fd);
/* one for /mp/file */
ATF_REQUIRE_EQ(vn_toserv_ops[PUFFS_VN_INACTIVE], 2);
if (rump_sys_unmount("/mp", 0) == -1)
atf_tc_fail_errno("unmount");
/* one for /mp again */
ATF_REQUIRE_EQ(vn_toserv_ops[PUFFS_VN_INACTIVE], 3);
}
ATF_TC(inactive_reclaim);
ATF_TC_HEAD(inactive_reclaim, tc)
{
atf_tc_set_md_var(tc, "descr", "inactive/reclaim gets called");
}
ATF_TC_BODY(inactive_reclaim, tc)
{
char *myopts[] = {
"-i",
"dtfs",
};
int fd;
dtfsmountv("/mp", myopts);
fd = rump_sys_open("/mp/file", O_CREAT | O_RDWR, 0777);
if (fd == -1)
atf_tc_fail_errno("create");
ATF_REQUIRE_EQ(vn_toserv_ops[PUFFS_VN_INACTIVE], 1);
if (rump_sys_unlink("/mp/file") == -1)
atf_tc_fail_errno("remove");
ATF_REQUIRE_EQ(vn_toserv_ops[PUFFS_VN_INACTIVE], 2);
ATF_REQUIRE_EQ(vn_toserv_ops[PUFFS_VN_RECLAIM], 0);
rump_sys_close(fd);
syncbar("/mp");
ATF_REQUIRE_EQ(vn_toserv_ops[PUFFS_VN_INACTIVE], 4);
ATF_REQUIRE_EQ(vn_toserv_ops[PUFFS_VN_RECLAIM], 1);
if (rump_sys_unmount("/mp", 0) == -1)
atf_tc_fail_errno("unmount");
}
ATF_TC(reclaim_hardlink);
ATF_TC_HEAD(reclaim_hardlink, tc)
{
atf_tc_set_md_var(tc, "descr", "reclaim gets called only after "
"final link is gone");
}
ATF_TC_BODY(reclaim_hardlink, tc)
{
char *myopts[] = {
"-i",
"dtfs",
};
int fd;
int ianow;
dtfsmountv("/mp", myopts);
fd = rump_sys_open("/mp/file", O_CREAT | O_RDWR, 0777);
if (fd == -1)
atf_tc_fail_errno("create");
if (rump_sys_link("/mp/file", "/mp/anotherfile") == -1)
atf_tc_fail_errno("create link");
rump_sys_close(fd);
ATF_REQUIRE_EQ(vn_toserv_ops[PUFFS_VN_RECLAIM], 0);
/* unlink first hardlink */
if (rump_sys_unlink("/mp/file") == -1)
atf_tc_fail_errno("unlink 1");
ATF_REQUIRE_EQ(vn_toserv_ops[PUFFS_VN_RECLAIM], 0);
ianow = vn_toserv_ops[PUFFS_VN_INACTIVE];
/* unlink second hardlink */
if (rump_sys_unlink("/mp/anotherfile") == -1)
atf_tc_fail_errno("unlink 2");
syncbar("/mp");
ATF_REQUIRE(ianow < vn_toserv_ops[PUFFS_VN_INACTIVE]);
ATF_REQUIRE_EQ(vn_toserv_ops[PUFFS_VN_RECLAIM], 1);
if (rump_sys_unmount("/mp", 0) == -1)
atf_tc_fail_errno("unmount");
}
ATF_TC(unlink_accessible);
ATF_TC_HEAD(unlink_accessible, tc)
{
atf_tc_set_md_var(tc, "descr", "open file is accessible after "
"having been unlinked");
}
ATF_TC_BODY(unlink_accessible, tc)
{
char *myopts[] = {
"-i",
"-o","nopagecache",
"dtfs",
};
char buf[512];
int fd, ianow;
assert(sizeof(buf) > sizeof(MAGICSTR));
dtfsmountv("/mp", myopts);
fd = rump_sys_open("/mp/file", O_CREAT | O_RDWR, 0777);
if (fd == -1)
atf_tc_fail_errno("create");
if (rump_sys_write(fd, MAGICSTR, sizeof(MAGICSTR)) != sizeof(MAGICSTR))
atf_tc_fail_errno("write");
if (rump_sys_unlink("/mp/file") == -1)
atf_tc_fail_errno("unlink");
ATF_REQUIRE_EQ(vn_toserv_ops[PUFFS_VN_RECLAIM], 0);
ianow = vn_toserv_ops[PUFFS_VN_INACTIVE];
if (rump_sys_pread(fd, buf, sizeof(buf), 0) == -1)
atf_tc_fail_errno("read");
rump_sys_close(fd);
syncbar("/mp");
ATF_REQUIRE_EQ(vn_toserv_ops[PUFFS_VN_RECLAIM], 1);
ATF_REQUIRE_EQ(vn_toserv_ops[PUFFS_VN_INACTIVE], ianow+2);
ATF_REQUIRE_STREQ(buf, MAGICSTR);
if (rump_sys_unmount("/mp", 0) == -1)
atf_tc_fail_errno("unmount");
}
ATF_TP_ADD_TCS(tp)
{
@ -448,5 +673,10 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, root_reg);
ATF_TP_ADD_TC(tp, root_chrdev);
ATF_TP_ADD_TC(tp, inactive_basic);
ATF_TP_ADD_TC(tp, inactive_reclaim);
ATF_TP_ADD_TC(tp, reclaim_hardlink);
ATF_TP_ADD_TC(tp, unlink_accessible);
return atf_no_error();
}