1314817Sngie/* $NetBSD: t_basic.c,v 1.14 2017/01/13 21:30:40 christos Exp $ */ 2272343Sngie 3272343Sngie#include <sys/types.h> 4272343Sngie#include <sys/mount.h> 5272343Sngie#include <sys/socket.h> 6272343Sngie 7272343Sngie#include <assert.h> 8272343Sngie#include <atf-c.h> 9272343Sngie#include <err.h> 10272343Sngie#include <errno.h> 11272343Sngie#include <fcntl.h> 12272343Sngie#include <pthread.h> 13272343Sngie#include <puffs.h> 14272343Sngie#include <puffsdump.h> 15272343Sngie#include <stdio.h> 16272343Sngie#include <unistd.h> 17272343Sngie#include <string.h> 18272343Sngie#include <stdlib.h> 19272343Sngie 20272343Sngie#include <rump/rump.h> 21272343Sngie#include <rump/rump_syscalls.h> 22272343Sngie 23314817Sngie#include "h_macros.h" 24272343Sngie#include "../common/h_fsmacros.h" 25272343Sngie 26272343Sngie/* 27272343Sngie * Do a synchronous operation. When this returns, all FAF operations 28272343Sngie * have at least been delivered to the file system. 29272343Sngie * 30272343Sngie * XXX: is this really good enough considering puffs(9)-issued 31272343Sngie * callback operations? 32272343Sngie */ 33272343Sngiestatic void 34272343Sngiesyncbar(const char *fs) 35272343Sngie{ 36272343Sngie struct statvfs svb; 37272343Sngie 38272343Sngie if (rump_sys_statvfs1(fs, &svb, ST_WAIT) == -1) 39272343Sngie atf_tc_fail_errno("statvfs"); 40272343Sngie} 41272343Sngie 42272343Sngie#ifdef PUFFSDUMP 43272343Sngiestatic void __unused 44272343Sngiedumpopcount(struct puffstestargs *args) 45272343Sngie{ 46272343Sngie size_t i; 47272343Sngie 48272343Sngie printf("VFS OPS:\n"); 49272343Sngie for (i = 0; i < MIN(puffsdump_vfsop_count, PUFFS_VFS_MAX); i++) { 50272343Sngie printf("\t%s: %d\n", 51272343Sngie puffsdump_vfsop_revmap[i], args->pta_vfs_toserv_ops[i]); 52272343Sngie } 53272343Sngie 54272343Sngie printf("VN OPS:\n"); 55272343Sngie for (i = 0; i < MIN(puffsdump_vnop_count, PUFFS_VN_MAX); i++) { 56272343Sngie printf("\t%s: %d\n", 57272343Sngie puffsdump_vnop_revmap[i], args->pta_vn_toserv_ops[i]); 58272343Sngie } 59272343Sngie} 60272343Sngie#endif 61272343Sngie 62272343SngieATF_TC(mount); 63272343SngieATF_TC_HEAD(mount, tc) 64272343Sngie{ 65272343Sngie 66272343Sngie atf_tc_set_md_var(tc, "descr", "puffs+dtfs un/mount test"); 67272343Sngie} 68272343Sngie 69272343SngieATF_TC_BODY(mount, tc) 70272343Sngie{ 71272343Sngie void *args; 72272343Sngie 73272343Sngie FSTEST_CONSTRUCTOR(tc, puffs, args); 74272343Sngie FSTEST_DESTRUCTOR(tc, puffs, args); 75272343Sngie} 76272343Sngie 77272343SngieATF_TC(root_reg); 78272343SngieATF_TC_HEAD(root_reg, tc) 79272343Sngie{ 80272343Sngie atf_tc_set_md_var(tc, "descr", "root is a regular file"); 81272343Sngie} 82272343Sngie 83272343Sngie#define MAKEOPTS(...) \ 84272343Sngie char *theopts[] = {NULL, "-s", __VA_ARGS__, "dtfs", "n/a", NULL} 85272343Sngie 86272343SngieATF_TC_BODY(root_reg, tc) 87272343Sngie{ 88272343Sngie MAKEOPTS("-r", "reg"); 89272343Sngie void *args; 90272343Sngie int fd, rv; 91272343Sngie 92272343Sngie FSTEST_CONSTRUCTOR_FSPRIV(tc, puffs, args, theopts); 93272343Sngie 94272343Sngie fd = rump_sys_open(FSTEST_MNTNAME, O_RDWR); 95272343Sngie if (fd == -1) 96272343Sngie atf_tc_fail_errno("open root"); 97272343Sngie if (rump_sys_write(fd, &fd, sizeof(fd)) != sizeof(fd)) 98272343Sngie atf_tc_fail_errno("write to root"); 99272343Sngie rv = rump_sys_mkdir(FSTEST_MNTNAME "/test", 0777); 100272343Sngie ATF_REQUIRE(errno == ENOTDIR); 101272343Sngie ATF_REQUIRE(rv == -1); 102272343Sngie rump_sys_close(fd); 103272343Sngie 104272343Sngie FSTEST_DESTRUCTOR(tc, puffs, args); 105272343Sngie} 106272343Sngie 107272343SngieATF_TC(root_lnk); 108272343SngieATF_TC_HEAD(root_lnk, tc) 109272343Sngie{ 110272343Sngie 111272343Sngie atf_tc_set_md_var(tc, "descr", "root is a symbolic link"); 112272343Sngie} 113272343Sngie 114272343Sngie#define LINKSTR "/path/to/nowhere" 115272343SngieATF_TC_BODY(root_lnk, tc) 116272343Sngie{ 117272343Sngie MAKEOPTS("-r", "lnk " LINKSTR); 118272343Sngie void *args; 119272343Sngie char buf[PATH_MAX]; 120272343Sngie ssize_t len; 121272343Sngie 122272343Sngie FSTEST_CONSTRUCTOR_FSPRIV(tc, puffs, args, theopts); 123272343Sngie 124272343Sngie if ((len = rump_sys_readlink(FSTEST_MNTNAME, buf, sizeof(buf)-1)) == -1) 125272343Sngie atf_tc_fail_errno("readlink"); 126272343Sngie buf[len] = '\0'; 127272343Sngie 128272343Sngie ATF_REQUIRE_STREQ(buf, LINKSTR); 129272343Sngie 130272343Sngie#if 0 /* XXX: unmount uses FOLLOW */ 131272343Sngie if (rump_sys_unmount("/mp", 0) == -1) 132272343Sngie atf_tc_fail_errno("unmount"); 133272343Sngie#endif 134272343Sngie} 135272343Sngie 136272343SngieATF_TC(root_fifo); 137272343SngieATF_TC_HEAD(root_fifo, tc) 138272343Sngie{ 139272343Sngie 140272343Sngie atf_tc_set_md_var(tc, "descr", "root is a symbolic link"); 141272343Sngie} 142272343Sngie 143272343Sngie#define MAGICSTR "nakit ja muusiperunat maustevoilla" 144272343Sngiestatic void * 145272343Sngiedofifow(void *arg) 146272343Sngie{ 147272343Sngie int fd = (int)(uintptr_t)arg; 148272343Sngie char buf[512]; 149272343Sngie 150272343Sngie printf("writing\n"); 151272343Sngie strcpy(buf, MAGICSTR); 152272343Sngie if (rump_sys_write(fd, buf, strlen(buf)+1) != strlen(buf)+1) 153272343Sngie atf_tc_fail_errno("write to fifo"); 154272343Sngie 155272343Sngie return NULL; 156272343Sngie} 157272343Sngie 158272343SngieATF_TC_BODY(root_fifo, tc) 159272343Sngie{ 160272343Sngie MAKEOPTS("-r", "fifo"); 161272343Sngie void *args; 162272343Sngie pthread_t pt; 163272343Sngie char buf[512]; 164272343Sngie int fd; 165272343Sngie 166272343Sngie FSTEST_CONSTRUCTOR_FSPRIV(tc, puffs, args, theopts); 167272343Sngie 168272343Sngie fd = rump_sys_open(FSTEST_MNTNAME, O_RDWR); 169272343Sngie if (fd == -1) 170272343Sngie atf_tc_fail_errno("open fifo"); 171272343Sngie 172272343Sngie pthread_create(&pt, NULL, dofifow, (void *)(uintptr_t)fd); 173272343Sngie 174272343Sngie memset(buf, 0, sizeof(buf)); 175272343Sngie if (rump_sys_read(fd, buf, sizeof(buf)) == -1) 176272343Sngie atf_tc_fail_errno("read fifo"); 177272343Sngie 178272343Sngie ATF_REQUIRE_STREQ(buf, MAGICSTR); 179272343Sngie rump_sys_close(fd); 180272343Sngie 181272343Sngie FSTEST_DESTRUCTOR(tc, puffs, args); 182272343Sngie} 183272343Sngie 184272343SngieATF_TC(root_chrdev); 185272343SngieATF_TC_HEAD(root_chrdev, tc) 186272343Sngie{ 187272343Sngie 188272343Sngie atf_tc_set_md_var(tc, "descr", "root is /dev/null"); 189272343Sngie} 190272343Sngie 191272343SngieATF_TC_BODY(root_chrdev, tc) 192272343Sngie{ 193272343Sngie MAKEOPTS("-r", "chr 2 2"); 194272343Sngie void *args; 195272343Sngie ssize_t rv; 196272343Sngie char buf[512]; 197272343Sngie int fd; 198272343Sngie 199272343Sngie FSTEST_CONSTRUCTOR_FSPRIV(tc, puffs, args, theopts); 200272343Sngie 201272343Sngie fd = rump_sys_open(FSTEST_MNTNAME, O_RDWR); 202272343Sngie if (fd == -1) 203272343Sngie atf_tc_fail_errno("open null"); 204272343Sngie 205272343Sngie rv = rump_sys_write(fd, buf, sizeof(buf)); 206272343Sngie ATF_REQUIRE(rv == sizeof(buf)); 207272343Sngie 208272343Sngie rv = rump_sys_read(fd, buf, sizeof(buf)); 209272343Sngie ATF_REQUIRE(rv == 0); 210272343Sngie 211272343Sngie rump_sys_close(fd); 212272343Sngie 213272343Sngie FSTEST_DESTRUCTOR(tc, puffs, args); 214272343Sngie} 215272343Sngie 216272343Sngie/* 217272343Sngie * Inactive/reclaim tests 218272343Sngie */ 219272343Sngie 220272343SngieATF_TC(inactive_basic); 221272343SngieATF_TC_HEAD(inactive_basic, tc) 222272343Sngie{ 223272343Sngie 224272343Sngie atf_tc_set_md_var(tc, "descr", "inactive gets called"); 225272343Sngie} 226272343Sngie 227272343SngieATF_TC_BODY(inactive_basic, tc) 228272343Sngie{ 229272343Sngie struct puffstestargs *pargs; 230272343Sngie void *args; 231272343Sngie int fd; 232272343Sngie 233272343Sngie FSTEST_CONSTRUCTOR(tc, puffs, args); 234272343Sngie FSTEST_ENTER(); 235272343Sngie pargs = args; 236272343Sngie 237272343Sngie fd = rump_sys_open("file", O_CREAT | O_RDWR, 0777); 238272343Sngie if (fd == -1) 239272343Sngie atf_tc_fail_errno("create"); 240272343Sngie 241272343Sngie /* none yet */ 242272343Sngie ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE], 0); 243272343Sngie 244272343Sngie rump_sys_close(fd); 245272343Sngie 246272343Sngie /* one for file */ 247272343Sngie ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE], 1); 248272343Sngie 249272343Sngie FSTEST_EXIT(); 250272343Sngie 251272343Sngie /* another for the mountpoint */ 252272343Sngie ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE], 2); 253272343Sngie 254272343Sngie FSTEST_DESTRUCTOR(tc, puffs, args); 255272343Sngie} 256272343Sngie 257272343SngieATF_TC(inactive_reclaim); 258272343SngieATF_TC_HEAD(inactive_reclaim, tc) 259272343Sngie{ 260272343Sngie 261272343Sngie atf_tc_set_md_var(tc, "descr", "inactive/reclaim gets called"); 262272343Sngie} 263272343Sngie 264272343SngieATF_TC_BODY(inactive_reclaim, tc) 265272343Sngie{ 266272343Sngie struct puffstestargs *pargs; 267272343Sngie void *args; 268272343Sngie int fd; 269272343Sngie 270272343Sngie FSTEST_CONSTRUCTOR(tc, puffs, args); 271272343Sngie FSTEST_ENTER(); 272272343Sngie pargs = args; 273272343Sngie 274272343Sngie fd = rump_sys_open("file", O_CREAT | O_RDWR, 0777); 275272343Sngie if (fd == -1) 276272343Sngie atf_tc_fail_errno("create"); 277272343Sngie 278272343Sngie ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE], 0); 279272343Sngie 280272343Sngie if (rump_sys_unlink("file") == -1) 281272343Sngie atf_tc_fail_errno("remove"); 282272343Sngie 283272343Sngie ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE], 0); 284272343Sngie ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_RECLAIM], 0); 285272343Sngie 286272343Sngie rump_sys_close(fd); 287272343Sngie syncbar(FSTEST_MNTNAME); 288272343Sngie 289313535Sngie ATF_REQUIRE(pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE] > 0); 290272343Sngie ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_RECLAIM], 1); 291272343Sngie 292272343Sngie FSTEST_EXIT(); 293272343Sngie FSTEST_DESTRUCTOR(tc, puffs, args); 294272343Sngie} 295272343Sngie 296272343SngieATF_TC(reclaim_hardlink); 297272343SngieATF_TC_HEAD(reclaim_hardlink, tc) 298272343Sngie{ 299272343Sngie 300272343Sngie atf_tc_set_md_var(tc, "descr", "reclaim gets called only after " 301272343Sngie "final link is gone"); 302272343Sngie} 303272343Sngie 304272343SngieATF_TC_BODY(reclaim_hardlink, tc) 305272343Sngie{ 306272343Sngie struct puffstestargs *pargs; 307272343Sngie void *args; 308272343Sngie int fd; 309272343Sngie int ianow; 310272343Sngie 311272343Sngie FSTEST_CONSTRUCTOR(tc, puffs, args); 312272343Sngie FSTEST_ENTER(); 313272343Sngie pargs = args; 314272343Sngie 315272343Sngie fd = rump_sys_open("file", O_CREAT | O_RDWR, 0777); 316272343Sngie if (fd == -1) 317272343Sngie atf_tc_fail_errno("create"); 318272343Sngie 319272343Sngie if (rump_sys_link("file", "anotherfile") == -1) 320272343Sngie atf_tc_fail_errno("create link"); 321272343Sngie rump_sys_close(fd); 322272343Sngie 323272343Sngie ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_RECLAIM], 0); 324272343Sngie 325272343Sngie /* unlink first hardlink */ 326272343Sngie if (rump_sys_unlink("file") == -1) 327272343Sngie atf_tc_fail_errno("unlink 1"); 328272343Sngie 329272343Sngie ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_RECLAIM], 0); 330272343Sngie ianow = pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE]; 331272343Sngie 332272343Sngie /* unlink second hardlink */ 333272343Sngie if (rump_sys_unlink("anotherfile") == -1) 334272343Sngie atf_tc_fail_errno("unlink 2"); 335272343Sngie 336272343Sngie syncbar(FSTEST_MNTNAME); 337272343Sngie 338272343Sngie ATF_REQUIRE(ianow < pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE]); 339272343Sngie ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_RECLAIM], 1); 340272343Sngie 341272343Sngie FSTEST_EXIT(); 342272343Sngie FSTEST_DESTRUCTOR(tc, puffs, args); 343272343Sngie} 344272343Sngie 345272343SngieATF_TC(unlink_accessible); 346272343SngieATF_TC_HEAD(unlink_accessible, tc) 347272343Sngie{ 348272343Sngie 349272343Sngie atf_tc_set_md_var(tc, "descr", "open file is accessible after " 350272343Sngie "having been unlinked"); 351272343Sngie} 352272343Sngie 353272343SngieATF_TC_BODY(unlink_accessible, tc) 354272343Sngie{ 355272343Sngie MAKEOPTS("-i", "-o", "nopagecache"); 356272343Sngie struct puffstestargs *pargs; 357272343Sngie void *args; 358272343Sngie char buf[512]; 359272343Sngie int fd, ianow; 360272343Sngie 361272343Sngie assert(sizeof(buf) > sizeof(MAGICSTR)); 362272343Sngie 363272343Sngie FSTEST_CONSTRUCTOR_FSPRIV(tc, puffs, args, theopts); 364272343Sngie FSTEST_ENTER(); 365272343Sngie pargs = args; 366272343Sngie 367272343Sngie fd = rump_sys_open("file", O_CREAT | O_RDWR, 0777); 368272343Sngie if (fd == -1) 369272343Sngie atf_tc_fail_errno("create"); 370272343Sngie 371272343Sngie if (rump_sys_write(fd, MAGICSTR, sizeof(MAGICSTR)) != sizeof(MAGICSTR)) 372272343Sngie atf_tc_fail_errno("write"); 373272343Sngie if (rump_sys_unlink("file") == -1) 374272343Sngie atf_tc_fail_errno("unlink"); 375272343Sngie 376272343Sngie ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_RECLAIM], 0); 377272343Sngie ianow = pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE]; 378272343Sngie 379272343Sngie if (rump_sys_pread(fd, buf, sizeof(buf), 0) == -1) 380272343Sngie atf_tc_fail_errno("read"); 381272343Sngie rump_sys_close(fd); 382272343Sngie 383272343Sngie syncbar(FSTEST_MNTNAME); 384272343Sngie 385272343Sngie ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_RECLAIM], 1); 386313535Sngie ATF_REQUIRE(pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE] > ianow); 387272343Sngie 388272343Sngie ATF_REQUIRE_STREQ(buf, MAGICSTR); 389272343Sngie 390272343Sngie FSTEST_EXIT(); 391272343Sngie FSTEST_DESTRUCTOR(tc, puffs, args); 392272343Sngie} 393272343Sngie 394272343SngieATF_TC(signals); 395272343SngieATF_TC_HEAD(signals, tc) 396272343Sngie{ 397272343Sngie 398272343Sngie atf_tc_set_md_var(tc, "descr", "Checks that sending a signal can " 399272343Sngie "cause an interrupt to puffs wait"); 400272343Sngie} 401272343Sngie 402272343Sngieextern struct proc *rumpns_initproc; 403272343Sngieextern void rumpns_psignal(struct proc *, int); 404272343Sngieextern void rumpns_sigclearall(struct proc *, void *, void *); 405272343SngieATF_TC_BODY(signals, tc) 406272343Sngie{ 407272343Sngie struct stat sb; 408272343Sngie void *args; 409272343Sngie 410272343Sngie rump_boot_setsigmodel(RUMP_SIGMODEL_RECORD); 411272343Sngie 412272343Sngie FSTEST_CONSTRUCTOR(tc, puffs, args); 413272343Sngie FSTEST_ENTER(); 414272343Sngie RL(rump_sys_stat(".", &sb)); 415272343Sngie 416272343Sngie /* send SIGUSR1, should not affect puffs ops */ 417272343Sngie rump_schedule(); 418272343Sngie rumpns_psignal(rumpns_initproc, SIGUSR1); 419272343Sngie rump_unschedule(); 420272343Sngie RL(rump_sys_stat(".", &sb)); 421272343Sngie 422272343Sngie /* send SIGTERM, should get EINTR */ 423272343Sngie rump_schedule(); 424272343Sngie rumpns_psignal(rumpns_initproc, SIGTERM); 425272343Sngie rump_unschedule(); 426272343Sngie ATF_REQUIRE_ERRNO(EINTR, rump_sys_stat(".", &sb) == -1); 427272343Sngie 428272343Sngie /* clear sigmask so that we can unmount */ 429272343Sngie rump_schedule(); 430272343Sngie rumpns_sigclearall(rumpns_initproc, NULL, NULL); 431272343Sngie rump_unschedule(); 432272343Sngie 433272343Sngie FSTEST_EXIT(); 434272343Sngie FSTEST_DESTRUCTOR(tc, puffs, args); 435272343Sngie} 436272343Sngie 437272343SngieATF_TP_ADD_TCS(tp) 438272343Sngie{ 439272343Sngie 440272343Sngie ATF_TP_ADD_TC(tp, mount); 441272343Sngie 442272343Sngie ATF_TP_ADD_TC(tp, root_fifo); 443272343Sngie ATF_TP_ADD_TC(tp, root_lnk); 444272343Sngie ATF_TP_ADD_TC(tp, root_reg); 445272343Sngie ATF_TP_ADD_TC(tp, root_chrdev); 446272343Sngie 447272343Sngie ATF_TP_ADD_TC(tp, inactive_basic); 448272343Sngie ATF_TP_ADD_TC(tp, inactive_reclaim); 449272343Sngie ATF_TP_ADD_TC(tp, reclaim_hardlink); 450272343Sngie ATF_TP_ADD_TC(tp, unlink_accessible); 451272343Sngie 452272343Sngie ATF_TP_ADD_TC(tp, signals); 453272343Sngie 454272343Sngie return atf_no_error(); 455272343Sngie} 456