1 1.14 andvar /* $NetBSD: fstest_puffs.c,v 1.14 2023/08/03 20:45:50 andvar Exp $ */ 2 1.1 pooka 3 1.1 pooka /* 4 1.8 pooka * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc. 5 1.1 pooka * 6 1.1 pooka * Redistribution and use in source and binary forms, with or without 7 1.1 pooka * modification, are permitted provided that the following conditions 8 1.1 pooka * are met: 9 1.1 pooka * 1. Redistributions of source code must retain the above copyright 10 1.1 pooka * notice, this list of conditions and the following disclaimer. 11 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 pooka * notice, this list of conditions and the following disclaimer in the 13 1.1 pooka * documentation and/or other materials provided with the distribution. 14 1.1 pooka * 15 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16 1.1 pooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 1.1 pooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 1.1 pooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 1.1 pooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 1.1 pooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 1.1 pooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 1.1 pooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 1.1 pooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 1.1 pooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 1.1 pooka * SUCH DAMAGE. 26 1.1 pooka */ 27 1.1 pooka 28 1.1 pooka #include <sys/types.h> 29 1.1 pooka #include <sys/mount.h> 30 1.1 pooka #include <sys/socket.h> 31 1.1 pooka #include <sys/statvfs.h> 32 1.1 pooka #include <sys/wait.h> 33 1.1 pooka 34 1.1 pooka #include <assert.h> 35 1.1 pooka #include <atf-c.h> 36 1.1 pooka #include <err.h> 37 1.1 pooka #include <errno.h> 38 1.1 pooka #include <fcntl.h> 39 1.1 pooka #include <pthread.h> 40 1.1 pooka #include <puffs.h> 41 1.1 pooka #include <puffsdump.h> 42 1.1 pooka #include <signal.h> 43 1.1 pooka #include <stdio.h> 44 1.1 pooka #include <unistd.h> 45 1.1 pooka #include <string.h> 46 1.1 pooka #include <stdlib.h> 47 1.1 pooka 48 1.1 pooka #include <rump/rump.h> 49 1.13 kamil #include <rump/rump_syscallshotgun.h> 50 1.1 pooka #include <rump/rump_syscalls.h> 51 1.1 pooka 52 1.1 pooka #include "h_fsmacros.h" 53 1.1 pooka 54 1.1 pooka #define BUFSIZE (128*1024) 55 1.1 pooka #define DTFS_DUMP "-o","dump" 56 1.1 pooka 57 1.6 pooka static bool mayquit = false; 58 1.6 pooka 59 1.7 yamt static ssize_t 60 1.7 yamt xread(int fd, void *vp, size_t n) 61 1.7 yamt { 62 1.7 yamt size_t left; 63 1.7 yamt 64 1.7 yamt left = n; 65 1.7 yamt do { 66 1.7 yamt ssize_t ssz; 67 1.7 yamt 68 1.7 yamt ssz = read(fd, vp, left); 69 1.7 yamt if (ssz == -1) { 70 1.7 yamt return ssz; 71 1.7 yamt } 72 1.7 yamt left -= ssz; 73 1.7 yamt vp = (char *)vp + ssz; 74 1.7 yamt } while (left > 0); 75 1.7 yamt return n; 76 1.7 yamt } 77 1.7 yamt 78 1.7 yamt static ssize_t 79 1.7 yamt xwrite(int fd, const void *vp, size_t n) 80 1.7 yamt { 81 1.7 yamt size_t left; 82 1.7 yamt 83 1.7 yamt left = n; 84 1.7 yamt do { 85 1.7 yamt ssize_t ssz; 86 1.7 yamt 87 1.7 yamt ssz = write(fd, vp, left); 88 1.7 yamt if (ssz == -1) { 89 1.7 yamt return ssz; 90 1.7 yamt } 91 1.7 yamt left -= ssz; 92 1.7 yamt vp = (const char *)vp + ssz; 93 1.7 yamt } while (left > 0); 94 1.7 yamt return n; 95 1.7 yamt } 96 1.7 yamt 97 1.1 pooka /* 98 1.1 pooka * Threads which shovel data between comfd and /dev/puffs. 99 1.1 pooka * (cannot use polling since fd's are in different namespaces) 100 1.1 pooka */ 101 1.1 pooka static void * 102 1.1 pooka readshovel(void *arg) 103 1.1 pooka { 104 1.1 pooka struct putter_hdr *phdr; 105 1.1 pooka struct puffs_req *preq; 106 1.2 pooka struct puffstestargs *args = arg; 107 1.1 pooka char buf[BUFSIZE]; 108 1.6 pooka ssize_t n; 109 1.1 pooka int comfd, puffsfd; 110 1.1 pooka 111 1.2 pooka comfd = args->pta_servfd; 112 1.2 pooka puffsfd = args->pta_rumpfd; 113 1.1 pooka 114 1.1 pooka phdr = (void *)buf; 115 1.1 pooka preq = (void *)buf; 116 1.1 pooka 117 1.4 pooka rump_pub_lwproc_newlwp(1); 118 1.1 pooka 119 1.1 pooka for (;;) { 120 1.1 pooka n = rump_sys_read(puffsfd, buf, sizeof(*phdr)); 121 1.4 pooka if (n <= 0) { 122 1.5 pgoyette fprintf(stderr, "readshovel r1 %zd / %d\n", n, errno); 123 1.1 pooka break; 124 1.4 pooka } 125 1.1 pooka 126 1.1 pooka assert(phdr->pth_framelen < BUFSIZE); 127 1.1 pooka n = rump_sys_read(puffsfd, buf+sizeof(*phdr), 128 1.1 pooka phdr->pth_framelen - sizeof(*phdr)); 129 1.4 pooka if (n <= 0) { 130 1.5 pgoyette fprintf(stderr, "readshovel r2 %zd / %d\n", n, errno); 131 1.1 pooka break; 132 1.4 pooka } 133 1.1 pooka 134 1.1 pooka /* Analyze request */ 135 1.1 pooka if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) { 136 1.1 pooka assert(preq->preq_optype < PUFFS_VFS_MAX); 137 1.2 pooka args->pta_vfs_toserv_ops[preq->preq_optype]++; 138 1.1 pooka } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) { 139 1.1 pooka assert(preq->preq_optype < PUFFS_VN_MAX); 140 1.2 pooka args->pta_vn_toserv_ops[preq->preq_optype]++; 141 1.1 pooka } 142 1.1 pooka 143 1.1 pooka n = phdr->pth_framelen; 144 1.7 yamt if (xwrite(comfd, buf, n) != n) { 145 1.5 pgoyette fprintf(stderr, "readshovel write %zd / %d\n", n, errno); 146 1.1 pooka break; 147 1.4 pooka } 148 1.1 pooka } 149 1.1 pooka 150 1.6 pooka if (n != 0 && mayquit == false) 151 1.6 pooka abort(); 152 1.6 pooka return NULL; 153 1.1 pooka } 154 1.1 pooka 155 1.1 pooka static void * 156 1.1 pooka writeshovel(void *arg) 157 1.1 pooka { 158 1.2 pooka struct puffstestargs *args = arg; 159 1.1 pooka struct putter_hdr *phdr; 160 1.6 pooka struct puffs_req *preq; 161 1.1 pooka char buf[BUFSIZE]; 162 1.1 pooka size_t toread; 163 1.6 pooka ssize_t n; 164 1.1 pooka int comfd, puffsfd; 165 1.1 pooka 166 1.4 pooka rump_pub_lwproc_newlwp(1); 167 1.1 pooka 168 1.2 pooka comfd = args->pta_servfd; 169 1.2 pooka puffsfd = args->pta_rumpfd; 170 1.1 pooka 171 1.1 pooka phdr = (struct putter_hdr *)buf; 172 1.6 pooka preq = (void *)buf; 173 1.1 pooka 174 1.1 pooka for (;;) { 175 1.1 pooka uint64_t off; 176 1.1 pooka 177 1.1 pooka /* 178 1.1 pooka * Need to write everything to the "kernel" in one chunk, 179 1.1 pooka * so make sure we have it here. 180 1.1 pooka */ 181 1.1 pooka off = 0; 182 1.1 pooka toread = sizeof(struct putter_hdr); 183 1.1 pooka assert(toread < BUFSIZE); 184 1.1 pooka do { 185 1.7 yamt n = xread(comfd, buf+off, toread); 186 1.1 pooka if (n <= 0) { 187 1.5 pgoyette fprintf(stderr, "writeshovel read %zd / %d\n", 188 1.4 pooka n, errno); 189 1.6 pooka goto out; 190 1.1 pooka } 191 1.1 pooka off += n; 192 1.1 pooka if (off >= sizeof(struct putter_hdr)) 193 1.1 pooka toread = phdr->pth_framelen - off; 194 1.1 pooka else 195 1.1 pooka toread = off - sizeof(struct putter_hdr); 196 1.1 pooka } while (toread); 197 1.1 pooka 198 1.6 pooka if (__predict_false( 199 1.6 pooka PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS 200 1.6 pooka && preq->preq_optype == PUFFS_VFS_UNMOUNT)) { 201 1.6 pooka if (preq->preq_rv == 0) 202 1.6 pooka mayquit = true; 203 1.6 pooka } 204 1.6 pooka 205 1.1 pooka n = rump_sys_write(puffsfd, buf, phdr->pth_framelen); 206 1.4 pooka if ((size_t)n != phdr->pth_framelen) { 207 1.5 pgoyette fprintf(stderr, "writeshovel wr %zd / %d\n", n, errno); 208 1.1 pooka break; 209 1.4 pooka } 210 1.1 pooka } 211 1.1 pooka 212 1.6 pooka out: 213 1.6 pooka if (n != 0) 214 1.6 pooka abort(); 215 1.6 pooka return NULL; 216 1.1 pooka } 217 1.1 pooka 218 1.1 pooka static void 219 1.2 pooka rumpshovels(struct puffstestargs *args) 220 1.1 pooka { 221 1.1 pooka pthread_t pt; 222 1.1 pooka int rv; 223 1.1 pooka 224 1.1 pooka if ((rv = rump_init()) == -1) 225 1.1 pooka err(1, "rump_init"); 226 1.1 pooka 227 1.2 pooka if (pthread_create(&pt, NULL, readshovel, args) == -1) 228 1.1 pooka err(1, "read shovel"); 229 1.1 pooka pthread_detach(pt); 230 1.2 pooka 231 1.2 pooka if (pthread_create(&pt, NULL, writeshovel, args) == -1) 232 1.1 pooka err(1, "write shovel"); 233 1.1 pooka pthread_detach(pt); 234 1.1 pooka } 235 1.1 pooka 236 1.1 pooka static void 237 1.1 pooka childfail(int sign) 238 1.1 pooka { 239 1.1 pooka 240 1.1 pooka atf_tc_fail("child died"); /* almost signal-safe */ 241 1.1 pooka } 242 1.1 pooka 243 1.2 pooka struct puffstestargs *theargs; /* XXX */ 244 1.2 pooka 245 1.1 pooka /* XXX: we don't support size */ 246 1.8 pooka static int 247 1.8 pooka donewfs(const atf_tc_t *tc, void **argp, 248 1.8 pooka const char *image, off_t size, void *fspriv, char **theargv) 249 1.1 pooka { 250 1.1 pooka struct puffstestargs *args; 251 1.1 pooka pid_t childpid; 252 1.1 pooka int *pflags; 253 1.1 pooka char comfd[16]; 254 1.1 pooka int sv[2]; 255 1.1 pooka int mntflags; 256 1.1 pooka size_t len; 257 1.1 pooka ssize_t n; 258 1.1 pooka 259 1.1 pooka *argp = NULL; 260 1.1 pooka 261 1.1 pooka args = malloc(sizeof(*args)); 262 1.1 pooka if (args == NULL) 263 1.1 pooka return errno; 264 1.10 njoly memset(args, 0, sizeof(*args)); 265 1.1 pooka 266 1.1 pooka pflags = &args->pta_pflags; 267 1.1 pooka 268 1.14 andvar /* Create socketpair for communication with the real file server */ 269 1.1 pooka if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sv) == -1) 270 1.1 pooka return errno; 271 1.1 pooka 272 1.1 pooka signal(SIGCHLD, childfail); 273 1.1 pooka 274 1.1 pooka switch ((childpid = fork())) { 275 1.1 pooka case 0: 276 1.1 pooka close(sv[1]); 277 1.1 pooka snprintf(comfd, sizeof(sv[0]), "%d", sv[0]); 278 1.1 pooka if (setenv("PUFFS_COMFD", comfd, 1) == -1) 279 1.1 pooka return errno; 280 1.1 pooka 281 1.12 mrg execvp(theargv[0], theargv); 282 1.12 mrg return errno; 283 1.1 pooka case -1: 284 1.1 pooka return errno; 285 1.1 pooka default: 286 1.1 pooka close(sv[0]); 287 1.1 pooka break; 288 1.1 pooka } 289 1.1 pooka 290 1.1 pooka /* read args */ 291 1.7 yamt if ((n = xread(sv[1], &len, sizeof(len))) != sizeof(len)) 292 1.1 pooka err(1, "mp 1 %zd", n); 293 1.1 pooka if (len > MAXPATHLEN) 294 1.1 pooka err(1, "mntpath > MAXPATHLEN"); 295 1.7 yamt if ((size_t)xread(sv[1], args->pta_dir, len) != len) 296 1.1 pooka err(1, "mp 2"); 297 1.7 yamt if (xread(sv[1], &len, sizeof(len)) != sizeof(len)) 298 1.1 pooka err(1, "fn 1"); 299 1.1 pooka if (len > MAXPATHLEN) 300 1.1 pooka err(1, "devpath > MAXPATHLEN"); 301 1.7 yamt if ((size_t)xread(sv[1], args->pta_dev, len) != len) 302 1.1 pooka err(1, "fn 2"); 303 1.7 yamt if (xread(sv[1], &mntflags, sizeof(mntflags)) != sizeof(mntflags)) 304 1.1 pooka err(1, "mntflags"); 305 1.7 yamt if (xread(sv[1], &args->pta_pargslen, sizeof(args->pta_pargslen)) 306 1.2 pooka != sizeof(args->pta_pargslen)) 307 1.1 pooka err(1, "puffstest_args len"); 308 1.1 pooka args->pta_pargs = malloc(args->pta_pargslen); 309 1.1 pooka if (args->pta_pargs == NULL) 310 1.1 pooka err(1, "malloc"); 311 1.7 yamt if (xread(sv[1], args->pta_pargs, args->pta_pargslen) 312 1.2 pooka != (ssize_t)args->pta_pargslen) 313 1.1 pooka err(1, "puffstest_args"); 314 1.7 yamt if (xread(sv[1], pflags, sizeof(*pflags)) != sizeof(*pflags)) 315 1.1 pooka err(1, "pflags"); 316 1.1 pooka 317 1.1 pooka args->pta_childpid = childpid; 318 1.1 pooka args->pta_servfd = sv[1]; 319 1.1 pooka strlcpy(args->pta_dev, image, sizeof(args->pta_dev)); 320 1.1 pooka 321 1.2 pooka *argp = theargs = args; 322 1.1 pooka 323 1.1 pooka return 0; 324 1.1 pooka } 325 1.1 pooka 326 1.1 pooka int 327 1.8 pooka puffs_fstest_newfs(const atf_tc_t *tc, void **argp, 328 1.8 pooka const char *image, off_t size, void *fspriv) 329 1.8 pooka { 330 1.8 pooka char dtfs_path[MAXPATHLEN]; 331 1.8 pooka char *dtfsargv[6]; 332 1.8 pooka char **theargv; 333 1.8 pooka 334 1.8 pooka /* build dtfs exec path from atf test dir */ 335 1.8 pooka sprintf(dtfs_path, "%s/../puffs/h_dtfs/h_dtfs", 336 1.8 pooka atf_tc_get_config_var(tc, "srcdir")); 337 1.8 pooka 338 1.8 pooka if (fspriv) { 339 1.8 pooka theargv = fspriv; 340 1.8 pooka theargv[0] = dtfs_path; 341 1.8 pooka } else { 342 1.8 pooka dtfsargv[0] = dtfs_path; 343 1.8 pooka dtfsargv[1] = __UNCONST("-i"); 344 1.8 pooka dtfsargv[2] = __UNCONST("-s"); 345 1.8 pooka dtfsargv[3] = __UNCONST("dtfs"); 346 1.8 pooka dtfsargv[4] = __UNCONST("fictional"); 347 1.8 pooka dtfsargv[5] = NULL; 348 1.8 pooka 349 1.8 pooka theargv = dtfsargv; 350 1.8 pooka } 351 1.8 pooka 352 1.8 pooka return donewfs(tc, argp, image, size, fspriv, theargv); 353 1.8 pooka } 354 1.8 pooka 355 1.8 pooka int 356 1.8 pooka p2k_ffs_fstest_newfs(const atf_tc_t *tc, void **argp, 357 1.8 pooka const char *image, off_t size, void *fspriv) 358 1.8 pooka { 359 1.8 pooka char *rumpffs_argv[5]; 360 1.8 pooka int rv; 361 1.8 pooka 362 1.8 pooka rump_init(); 363 1.8 pooka if ((rv = ffs_fstest_newfs(tc, argp, image, size, fspriv)) != 0) 364 1.8 pooka return rv; 365 1.9 pooka if (mkdir("p2kffsfake", 0777) == -1 && errno != EEXIST) 366 1.8 pooka return errno; 367 1.8 pooka 368 1.8 pooka setenv("P2K_NODETACH", "1", 1); 369 1.8 pooka rumpffs_argv[0] = __UNCONST("rump_ffs"); 370 1.8 pooka rumpffs_argv[1] = __UNCONST(image); 371 1.8 pooka rumpffs_argv[2] = __UNCONST("p2kffsfake"); /* NOTUSED */ 372 1.8 pooka rumpffs_argv[3] = NULL; 373 1.8 pooka 374 1.8 pooka if ((rv = donewfs(tc, argp, image, size, fspriv, rumpffs_argv)) != 0) 375 1.8 pooka ffs_fstest_delfs(tc, argp); 376 1.8 pooka return rv; 377 1.8 pooka } 378 1.8 pooka 379 1.8 pooka int 380 1.1 pooka puffs_fstest_mount(const atf_tc_t *tc, void *arg, const char *path, int flags) 381 1.1 pooka { 382 1.1 pooka struct puffstestargs *pargs = arg; 383 1.1 pooka int fd; 384 1.1 pooka 385 1.1 pooka rump_init(); 386 1.1 pooka fd = rump_sys_open("/dev/puffs", O_RDWR); 387 1.1 pooka if (fd == -1) 388 1.1 pooka return fd; 389 1.1 pooka 390 1.1 pooka if (rump_sys_mkdir(path, 0777) == -1) 391 1.1 pooka return -1; 392 1.1 pooka 393 1.1 pooka if (rump_sys_mount(MOUNT_PUFFS, path, flags, 394 1.1 pooka pargs->pta_pargs, pargs->pta_pargslen) == -1) { 395 1.1 pooka /* apply "to kill a child" to avoid atf hang (kludge) */ 396 1.1 pooka kill(pargs->pta_childpid, SIGKILL); 397 1.1 pooka return -1; 398 1.1 pooka } 399 1.1 pooka 400 1.2 pooka pargs->pta_rumpfd = fd; 401 1.2 pooka rumpshovels(pargs); 402 1.1 pooka 403 1.1 pooka return 0; 404 1.1 pooka } 405 1.8 pooka __strong_alias(p2k_ffs_fstest_mount,puffs_fstest_mount); 406 1.1 pooka 407 1.1 pooka int 408 1.1 pooka puffs_fstest_delfs(const atf_tc_t *tc, void *arg) 409 1.1 pooka { 410 1.1 pooka 411 1.2 pooka /* useless ... */ 412 1.1 pooka return 0; 413 1.1 pooka } 414 1.1 pooka 415 1.1 pooka int 416 1.8 pooka p2k_ffs_fstest_delfs(const atf_tc_t *tc, void *arg) 417 1.8 pooka { 418 1.8 pooka 419 1.8 pooka return ffs_fstest_delfs(tc, arg); 420 1.8 pooka } 421 1.8 pooka 422 1.8 pooka int 423 1.1 pooka puffs_fstest_unmount(const atf_tc_t *tc, const char *path, int flags) 424 1.1 pooka { 425 1.2 pooka struct puffstestargs *pargs = theargs; 426 1.2 pooka int status; 427 1.1 pooka int rv; 428 1.1 pooka 429 1.1 pooka /* ok, child might exit here */ 430 1.1 pooka signal(SIGCHLD, SIG_IGN); 431 1.1 pooka 432 1.1 pooka rv = rump_sys_unmount(path, flags); 433 1.1 pooka if (rv) 434 1.1 pooka return rv; 435 1.1 pooka 436 1.2 pooka if ((rv = rump_sys_rmdir(path)) != 0) 437 1.2 pooka return rv; 438 1.2 pooka 439 1.2 pooka if (waitpid(pargs->pta_childpid, &status, WNOHANG) > 0) 440 1.2 pooka return 0; 441 1.2 pooka kill(pargs->pta_childpid, SIGTERM); 442 1.2 pooka usleep(10); 443 1.2 pooka if (waitpid(pargs->pta_childpid, &status, WNOHANG) > 0) 444 1.2 pooka return 0; 445 1.2 pooka kill(pargs->pta_childpid, SIGKILL); 446 1.2 pooka usleep(500); 447 1.2 pooka wait(&status); 448 1.2 pooka 449 1.8 pooka rmdir("p2kffsfake"); 450 1.8 pooka 451 1.2 pooka return 0; 452 1.1 pooka } 453 1.8 pooka __strong_alias(p2k_ffs_fstest_unmount,puffs_fstest_unmount); 454