1 1.14 christos /* $NetBSD: t_basic.c,v 1.14 2017/01/13 21:30:40 christos Exp $ */ 2 1.1 pooka 3 1.1 pooka #include <sys/types.h> 4 1.1 pooka #include <sys/mount.h> 5 1.1 pooka #include <sys/socket.h> 6 1.1 pooka 7 1.1 pooka #include <assert.h> 8 1.1 pooka #include <atf-c.h> 9 1.1 pooka #include <err.h> 10 1.1 pooka #include <errno.h> 11 1.1 pooka #include <fcntl.h> 12 1.3 pooka #include <pthread.h> 13 1.1 pooka #include <puffs.h> 14 1.4 pooka #include <puffsdump.h> 15 1.1 pooka #include <stdio.h> 16 1.1 pooka #include <unistd.h> 17 1.1 pooka #include <string.h> 18 1.1 pooka #include <stdlib.h> 19 1.1 pooka 20 1.1 pooka #include <rump/rump.h> 21 1.1 pooka #include <rump/rump_syscalls.h> 22 1.1 pooka 23 1.14 christos #include "h_macros.h" 24 1.7 pooka #include "../common/h_fsmacros.h" 25 1.4 pooka 26 1.4 pooka /* 27 1.4 pooka * Do a synchronous operation. When this returns, all FAF operations 28 1.4 pooka * have at least been delivered to the file system. 29 1.4 pooka * 30 1.4 pooka * XXX: is this really good enough considering puffs(9)-issued 31 1.4 pooka * callback operations? 32 1.4 pooka */ 33 1.4 pooka static void 34 1.4 pooka syncbar(const char *fs) 35 1.4 pooka { 36 1.4 pooka struct statvfs svb; 37 1.4 pooka 38 1.7 pooka if (rump_sys_statvfs1(fs, &svb, ST_WAIT) == -1) 39 1.7 pooka atf_tc_fail_errno("statvfs"); 40 1.4 pooka } 41 1.4 pooka 42 1.11 plunky #ifdef PUFFSDUMP 43 1.5 pooka static void __unused 44 1.7 pooka dumpopcount(struct puffstestargs *args) 45 1.4 pooka { 46 1.4 pooka size_t i; 47 1.4 pooka 48 1.4 pooka printf("VFS OPS:\n"); 49 1.4 pooka for (i = 0; i < MIN(puffsdump_vfsop_count, PUFFS_VFS_MAX); i++) { 50 1.4 pooka printf("\t%s: %d\n", 51 1.7 pooka puffsdump_vfsop_revmap[i], args->pta_vfs_toserv_ops[i]); 52 1.4 pooka } 53 1.4 pooka 54 1.4 pooka printf("VN OPS:\n"); 55 1.4 pooka for (i = 0; i < MIN(puffsdump_vnop_count, PUFFS_VN_MAX); i++) { 56 1.4 pooka printf("\t%s: %d\n", 57 1.7 pooka puffsdump_vnop_revmap[i], args->pta_vn_toserv_ops[i]); 58 1.1 pooka } 59 1.3 pooka } 60 1.11 plunky #endif 61 1.3 pooka 62 1.3 pooka ATF_TC(mount); 63 1.3 pooka ATF_TC_HEAD(mount, tc) 64 1.3 pooka { 65 1.3 pooka 66 1.3 pooka atf_tc_set_md_var(tc, "descr", "puffs+dtfs un/mount test"); 67 1.3 pooka } 68 1.3 pooka 69 1.3 pooka ATF_TC_BODY(mount, tc) 70 1.3 pooka { 71 1.7 pooka void *args; 72 1.3 pooka 73 1.7 pooka FSTEST_CONSTRUCTOR(tc, puffs, args); 74 1.7 pooka FSTEST_DESTRUCTOR(tc, puffs, args); 75 1.3 pooka } 76 1.3 pooka 77 1.3 pooka ATF_TC(root_reg); 78 1.3 pooka ATF_TC_HEAD(root_reg, tc) 79 1.3 pooka { 80 1.3 pooka atf_tc_set_md_var(tc, "descr", "root is a regular file"); 81 1.3 pooka } 82 1.3 pooka 83 1.7 pooka #define MAKEOPTS(...) \ 84 1.7 pooka char *theopts[] = {NULL, "-s", __VA_ARGS__, "dtfs", "n/a", NULL} 85 1.7 pooka 86 1.3 pooka ATF_TC_BODY(root_reg, tc) 87 1.3 pooka { 88 1.7 pooka MAKEOPTS("-r", "reg"); 89 1.7 pooka void *args; 90 1.3 pooka int fd, rv; 91 1.3 pooka 92 1.7 pooka FSTEST_CONSTRUCTOR_FSPRIV(tc, puffs, args, theopts); 93 1.3 pooka 94 1.7 pooka fd = rump_sys_open(FSTEST_MNTNAME, O_RDWR); 95 1.3 pooka if (fd == -1) 96 1.3 pooka atf_tc_fail_errno("open root"); 97 1.3 pooka if (rump_sys_write(fd, &fd, sizeof(fd)) != sizeof(fd)) 98 1.3 pooka atf_tc_fail_errno("write to root"); 99 1.7 pooka rv = rump_sys_mkdir(FSTEST_MNTNAME "/test", 0777); 100 1.3 pooka ATF_REQUIRE(errno == ENOTDIR); 101 1.3 pooka ATF_REQUIRE(rv == -1); 102 1.3 pooka rump_sys_close(fd); 103 1.1 pooka 104 1.7 pooka FSTEST_DESTRUCTOR(tc, puffs, args); 105 1.1 pooka } 106 1.1 pooka 107 1.3 pooka ATF_TC(root_lnk); 108 1.3 pooka ATF_TC_HEAD(root_lnk, tc) 109 1.3 pooka { 110 1.3 pooka 111 1.3 pooka atf_tc_set_md_var(tc, "descr", "root is a symbolic link"); 112 1.3 pooka } 113 1.3 pooka 114 1.3 pooka #define LINKSTR "/path/to/nowhere" 115 1.3 pooka ATF_TC_BODY(root_lnk, tc) 116 1.3 pooka { 117 1.7 pooka MAKEOPTS("-r", "lnk " LINKSTR); 118 1.7 pooka void *args; 119 1.3 pooka char buf[PATH_MAX]; 120 1.3 pooka ssize_t len; 121 1.3 pooka 122 1.7 pooka FSTEST_CONSTRUCTOR_FSPRIV(tc, puffs, args, theopts); 123 1.3 pooka 124 1.7 pooka if ((len = rump_sys_readlink(FSTEST_MNTNAME, buf, sizeof(buf)-1)) == -1) 125 1.3 pooka atf_tc_fail_errno("readlink"); 126 1.3 pooka buf[len] = '\0'; 127 1.3 pooka 128 1.3 pooka ATF_REQUIRE_STREQ(buf, LINKSTR); 129 1.3 pooka 130 1.3 pooka #if 0 /* XXX: unmount uses FOLLOW */ 131 1.3 pooka if (rump_sys_unmount("/mp", 0) == -1) 132 1.3 pooka atf_tc_fail_errno("unmount"); 133 1.3 pooka #endif 134 1.3 pooka } 135 1.3 pooka 136 1.3 pooka ATF_TC(root_fifo); 137 1.3 pooka ATF_TC_HEAD(root_fifo, tc) 138 1.3 pooka { 139 1.3 pooka 140 1.3 pooka atf_tc_set_md_var(tc, "descr", "root is a symbolic link"); 141 1.3 pooka } 142 1.3 pooka 143 1.3 pooka #define MAGICSTR "nakit ja muusiperunat maustevoilla" 144 1.3 pooka static void * 145 1.3 pooka dofifow(void *arg) 146 1.3 pooka { 147 1.3 pooka int fd = (int)(uintptr_t)arg; 148 1.3 pooka char buf[512]; 149 1.3 pooka 150 1.3 pooka printf("writing\n"); 151 1.3 pooka strcpy(buf, MAGICSTR); 152 1.3 pooka if (rump_sys_write(fd, buf, strlen(buf)+1) != strlen(buf)+1) 153 1.3 pooka atf_tc_fail_errno("write to fifo"); 154 1.3 pooka 155 1.3 pooka return NULL; 156 1.3 pooka } 157 1.3 pooka 158 1.3 pooka ATF_TC_BODY(root_fifo, tc) 159 1.3 pooka { 160 1.7 pooka MAKEOPTS("-r", "fifo"); 161 1.7 pooka void *args; 162 1.3 pooka pthread_t pt; 163 1.3 pooka char buf[512]; 164 1.3 pooka int fd; 165 1.3 pooka 166 1.7 pooka FSTEST_CONSTRUCTOR_FSPRIV(tc, puffs, args, theopts); 167 1.7 pooka 168 1.7 pooka fd = rump_sys_open(FSTEST_MNTNAME, O_RDWR); 169 1.3 pooka if (fd == -1) 170 1.3 pooka atf_tc_fail_errno("open fifo"); 171 1.3 pooka 172 1.3 pooka pthread_create(&pt, NULL, dofifow, (void *)(uintptr_t)fd); 173 1.3 pooka 174 1.3 pooka memset(buf, 0, sizeof(buf)); 175 1.3 pooka if (rump_sys_read(fd, buf, sizeof(buf)) == -1) 176 1.3 pooka atf_tc_fail_errno("read fifo"); 177 1.3 pooka 178 1.3 pooka ATF_REQUIRE_STREQ(buf, MAGICSTR); 179 1.7 pooka rump_sys_close(fd); 180 1.3 pooka 181 1.7 pooka FSTEST_DESTRUCTOR(tc, puffs, args); 182 1.3 pooka } 183 1.3 pooka 184 1.3 pooka ATF_TC(root_chrdev); 185 1.3 pooka ATF_TC_HEAD(root_chrdev, tc) 186 1.3 pooka { 187 1.3 pooka 188 1.3 pooka atf_tc_set_md_var(tc, "descr", "root is /dev/null"); 189 1.3 pooka } 190 1.3 pooka 191 1.3 pooka ATF_TC_BODY(root_chrdev, tc) 192 1.3 pooka { 193 1.10 pooka MAKEOPTS("-r", "chr 2 2"); 194 1.7 pooka void *args; 195 1.3 pooka ssize_t rv; 196 1.3 pooka char buf[512]; 197 1.3 pooka int fd; 198 1.3 pooka 199 1.7 pooka FSTEST_CONSTRUCTOR_FSPRIV(tc, puffs, args, theopts); 200 1.7 pooka 201 1.7 pooka fd = rump_sys_open(FSTEST_MNTNAME, O_RDWR); 202 1.3 pooka if (fd == -1) 203 1.3 pooka atf_tc_fail_errno("open null"); 204 1.3 pooka 205 1.3 pooka rv = rump_sys_write(fd, buf, sizeof(buf)); 206 1.3 pooka ATF_REQUIRE(rv == sizeof(buf)); 207 1.3 pooka 208 1.3 pooka rv = rump_sys_read(fd, buf, sizeof(buf)); 209 1.3 pooka ATF_REQUIRE(rv == 0); 210 1.3 pooka 211 1.3 pooka rump_sys_close(fd); 212 1.7 pooka 213 1.7 pooka FSTEST_DESTRUCTOR(tc, puffs, args); 214 1.3 pooka } 215 1.3 pooka 216 1.4 pooka /* 217 1.4 pooka * Inactive/reclaim tests 218 1.4 pooka */ 219 1.4 pooka 220 1.4 pooka ATF_TC(inactive_basic); 221 1.4 pooka ATF_TC_HEAD(inactive_basic, tc) 222 1.4 pooka { 223 1.4 pooka 224 1.4 pooka atf_tc_set_md_var(tc, "descr", "inactive gets called"); 225 1.4 pooka } 226 1.4 pooka 227 1.4 pooka ATF_TC_BODY(inactive_basic, tc) 228 1.4 pooka { 229 1.7 pooka struct puffstestargs *pargs; 230 1.7 pooka void *args; 231 1.4 pooka int fd; 232 1.4 pooka 233 1.7 pooka FSTEST_CONSTRUCTOR(tc, puffs, args); 234 1.7 pooka FSTEST_ENTER(); 235 1.7 pooka pargs = args; 236 1.7 pooka 237 1.7 pooka fd = rump_sys_open("file", O_CREAT | O_RDWR, 0777); 238 1.4 pooka if (fd == -1) 239 1.4 pooka atf_tc_fail_errno("create"); 240 1.4 pooka 241 1.7 pooka /* none yet */ 242 1.7 pooka ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE], 0); 243 1.4 pooka 244 1.4 pooka rump_sys_close(fd); 245 1.4 pooka 246 1.7 pooka /* one for file */ 247 1.7 pooka ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE], 1); 248 1.4 pooka 249 1.7 pooka FSTEST_EXIT(); 250 1.7 pooka 251 1.7 pooka /* another for the mountpoint */ 252 1.7 pooka ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE], 2); 253 1.4 pooka 254 1.7 pooka FSTEST_DESTRUCTOR(tc, puffs, args); 255 1.4 pooka } 256 1.4 pooka 257 1.4 pooka ATF_TC(inactive_reclaim); 258 1.4 pooka ATF_TC_HEAD(inactive_reclaim, tc) 259 1.4 pooka { 260 1.4 pooka 261 1.4 pooka atf_tc_set_md_var(tc, "descr", "inactive/reclaim gets called"); 262 1.4 pooka } 263 1.4 pooka 264 1.4 pooka ATF_TC_BODY(inactive_reclaim, tc) 265 1.4 pooka { 266 1.7 pooka struct puffstestargs *pargs; 267 1.7 pooka void *args; 268 1.4 pooka int fd; 269 1.4 pooka 270 1.7 pooka FSTEST_CONSTRUCTOR(tc, puffs, args); 271 1.7 pooka FSTEST_ENTER(); 272 1.7 pooka pargs = args; 273 1.7 pooka 274 1.7 pooka fd = rump_sys_open("file", O_CREAT | O_RDWR, 0777); 275 1.4 pooka if (fd == -1) 276 1.4 pooka atf_tc_fail_errno("create"); 277 1.4 pooka 278 1.7 pooka ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE], 0); 279 1.4 pooka 280 1.7 pooka if (rump_sys_unlink("file") == -1) 281 1.4 pooka atf_tc_fail_errno("remove"); 282 1.4 pooka 283 1.7 pooka ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE], 0); 284 1.7 pooka ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_RECLAIM], 0); 285 1.4 pooka 286 1.4 pooka rump_sys_close(fd); 287 1.7 pooka syncbar(FSTEST_MNTNAME); 288 1.4 pooka 289 1.13 hannken ATF_REQUIRE(pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE] > 0); 290 1.7 pooka ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_RECLAIM], 1); 291 1.4 pooka 292 1.7 pooka FSTEST_EXIT(); 293 1.7 pooka FSTEST_DESTRUCTOR(tc, puffs, args); 294 1.4 pooka } 295 1.4 pooka 296 1.4 pooka ATF_TC(reclaim_hardlink); 297 1.4 pooka ATF_TC_HEAD(reclaim_hardlink, tc) 298 1.4 pooka { 299 1.4 pooka 300 1.4 pooka atf_tc_set_md_var(tc, "descr", "reclaim gets called only after " 301 1.4 pooka "final link is gone"); 302 1.4 pooka } 303 1.4 pooka 304 1.4 pooka ATF_TC_BODY(reclaim_hardlink, tc) 305 1.4 pooka { 306 1.7 pooka struct puffstestargs *pargs; 307 1.7 pooka void *args; 308 1.4 pooka int fd; 309 1.4 pooka int ianow; 310 1.4 pooka 311 1.7 pooka FSTEST_CONSTRUCTOR(tc, puffs, args); 312 1.7 pooka FSTEST_ENTER(); 313 1.7 pooka pargs = args; 314 1.7 pooka 315 1.7 pooka fd = rump_sys_open("file", O_CREAT | O_RDWR, 0777); 316 1.4 pooka if (fd == -1) 317 1.4 pooka atf_tc_fail_errno("create"); 318 1.4 pooka 319 1.7 pooka if (rump_sys_link("file", "anotherfile") == -1) 320 1.4 pooka atf_tc_fail_errno("create link"); 321 1.4 pooka rump_sys_close(fd); 322 1.4 pooka 323 1.7 pooka ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_RECLAIM], 0); 324 1.4 pooka 325 1.4 pooka /* unlink first hardlink */ 326 1.7 pooka if (rump_sys_unlink("file") == -1) 327 1.4 pooka atf_tc_fail_errno("unlink 1"); 328 1.4 pooka 329 1.7 pooka ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_RECLAIM], 0); 330 1.7 pooka ianow = pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE]; 331 1.4 pooka 332 1.4 pooka /* unlink second hardlink */ 333 1.7 pooka if (rump_sys_unlink("anotherfile") == -1) 334 1.4 pooka atf_tc_fail_errno("unlink 2"); 335 1.4 pooka 336 1.7 pooka syncbar(FSTEST_MNTNAME); 337 1.4 pooka 338 1.7 pooka ATF_REQUIRE(ianow < pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE]); 339 1.7 pooka ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_RECLAIM], 1); 340 1.4 pooka 341 1.7 pooka FSTEST_EXIT(); 342 1.7 pooka FSTEST_DESTRUCTOR(tc, puffs, args); 343 1.4 pooka } 344 1.4 pooka 345 1.4 pooka ATF_TC(unlink_accessible); 346 1.4 pooka ATF_TC_HEAD(unlink_accessible, tc) 347 1.4 pooka { 348 1.4 pooka 349 1.4 pooka atf_tc_set_md_var(tc, "descr", "open file is accessible after " 350 1.4 pooka "having been unlinked"); 351 1.4 pooka } 352 1.4 pooka 353 1.4 pooka ATF_TC_BODY(unlink_accessible, tc) 354 1.4 pooka { 355 1.7 pooka MAKEOPTS("-i", "-o", "nopagecache"); 356 1.7 pooka struct puffstestargs *pargs; 357 1.7 pooka void *args; 358 1.4 pooka char buf[512]; 359 1.4 pooka int fd, ianow; 360 1.4 pooka 361 1.4 pooka assert(sizeof(buf) > sizeof(MAGICSTR)); 362 1.4 pooka 363 1.7 pooka FSTEST_CONSTRUCTOR_FSPRIV(tc, puffs, args, theopts); 364 1.7 pooka FSTEST_ENTER(); 365 1.7 pooka pargs = args; 366 1.7 pooka 367 1.7 pooka fd = rump_sys_open("file", O_CREAT | O_RDWR, 0777); 368 1.4 pooka if (fd == -1) 369 1.4 pooka atf_tc_fail_errno("create"); 370 1.4 pooka 371 1.4 pooka if (rump_sys_write(fd, MAGICSTR, sizeof(MAGICSTR)) != sizeof(MAGICSTR)) 372 1.4 pooka atf_tc_fail_errno("write"); 373 1.7 pooka if (rump_sys_unlink("file") == -1) 374 1.4 pooka atf_tc_fail_errno("unlink"); 375 1.4 pooka 376 1.7 pooka ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_RECLAIM], 0); 377 1.7 pooka ianow = pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE]; 378 1.4 pooka 379 1.4 pooka if (rump_sys_pread(fd, buf, sizeof(buf), 0) == -1) 380 1.4 pooka atf_tc_fail_errno("read"); 381 1.4 pooka rump_sys_close(fd); 382 1.4 pooka 383 1.7 pooka syncbar(FSTEST_MNTNAME); 384 1.4 pooka 385 1.7 pooka ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_RECLAIM], 1); 386 1.13 hannken ATF_REQUIRE(pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE] > ianow); 387 1.4 pooka 388 1.4 pooka ATF_REQUIRE_STREQ(buf, MAGICSTR); 389 1.4 pooka 390 1.7 pooka FSTEST_EXIT(); 391 1.7 pooka FSTEST_DESTRUCTOR(tc, puffs, args); 392 1.4 pooka } 393 1.4 pooka 394 1.9 pooka ATF_TC(signals); 395 1.9 pooka ATF_TC_HEAD(signals, tc) 396 1.9 pooka { 397 1.9 pooka 398 1.9 pooka atf_tc_set_md_var(tc, "descr", "Checks that sending a signal can " 399 1.9 pooka "cause an interrupt to puffs wait"); 400 1.9 pooka } 401 1.9 pooka 402 1.9 pooka extern struct proc *rumpns_initproc; 403 1.9 pooka extern void rumpns_psignal(struct proc *, int); 404 1.9 pooka extern void rumpns_sigclearall(struct proc *, void *, void *); 405 1.9 pooka ATF_TC_BODY(signals, tc) 406 1.9 pooka { 407 1.9 pooka struct stat sb; 408 1.9 pooka void *args; 409 1.9 pooka 410 1.9 pooka rump_boot_setsigmodel(RUMP_SIGMODEL_RECORD); 411 1.9 pooka 412 1.9 pooka FSTEST_CONSTRUCTOR(tc, puffs, args); 413 1.9 pooka FSTEST_ENTER(); 414 1.9 pooka RL(rump_sys_stat(".", &sb)); 415 1.9 pooka 416 1.9 pooka /* send SIGUSR1, should not affect puffs ops */ 417 1.9 pooka rump_schedule(); 418 1.9 pooka rumpns_psignal(rumpns_initproc, SIGUSR1); 419 1.9 pooka rump_unschedule(); 420 1.9 pooka RL(rump_sys_stat(".", &sb)); 421 1.9 pooka 422 1.9 pooka /* send SIGTERM, should get EINTR */ 423 1.9 pooka rump_schedule(); 424 1.9 pooka rumpns_psignal(rumpns_initproc, SIGTERM); 425 1.9 pooka rump_unschedule(); 426 1.9 pooka ATF_REQUIRE_ERRNO(EINTR, rump_sys_stat(".", &sb) == -1); 427 1.9 pooka 428 1.9 pooka /* clear sigmask so that we can unmount */ 429 1.9 pooka rump_schedule(); 430 1.9 pooka rumpns_sigclearall(rumpns_initproc, NULL, NULL); 431 1.9 pooka rump_unschedule(); 432 1.9 pooka 433 1.9 pooka FSTEST_EXIT(); 434 1.9 pooka FSTEST_DESTRUCTOR(tc, puffs, args); 435 1.9 pooka } 436 1.9 pooka 437 1.1 pooka ATF_TP_ADD_TCS(tp) 438 1.1 pooka { 439 1.3 pooka 440 1.1 pooka ATF_TP_ADD_TC(tp, mount); 441 1.1 pooka 442 1.3 pooka ATF_TP_ADD_TC(tp, root_fifo); 443 1.3 pooka ATF_TP_ADD_TC(tp, root_lnk); 444 1.3 pooka ATF_TP_ADD_TC(tp, root_reg); 445 1.3 pooka ATF_TP_ADD_TC(tp, root_chrdev); 446 1.3 pooka 447 1.4 pooka ATF_TP_ADD_TC(tp, inactive_basic); 448 1.4 pooka ATF_TP_ADD_TC(tp, inactive_reclaim); 449 1.4 pooka ATF_TP_ADD_TC(tp, reclaim_hardlink); 450 1.4 pooka ATF_TP_ADD_TC(tp, unlink_accessible); 451 1.4 pooka 452 1.9 pooka ATF_TP_ADD_TC(tp, signals); 453 1.9 pooka 454 1.1 pooka return atf_no_error(); 455 1.1 pooka } 456