1 /* $NetBSD: fstest_puffs.c,v 1.11 2013/09/09 19:47:38 pooka Exp $ */
4 * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/types.h>
29 #include <sys/mount.h>
30 #include <sys/socket.h>
31 #include <sys/statvfs.h>
41 #include <puffsdump.h>
48 #include <rump/rump.h>
49 #include <rump/rump_syscalls.h>
51 #include "h_fsmacros.h"
53 #define BUFSIZE (128*1024)
54 #define DTFS_DUMP "-o","dump"
56 static bool mayquit
= false;
59 xread(int fd
, void *vp
, size_t n
)
67 ssz
= read(fd
, vp
, left
);
72 vp
= (char *)vp
+ ssz
;
78 xwrite(int fd
, const void *vp
, size_t n
)
86 ssz
= write(fd
, vp
, left
);
91 vp
= (const char *)vp
+ ssz
;
97 * Threads which shovel data between comfd and /dev/puffs.
98 * (cannot use polling since fd's are in different namespaces)
101 readshovel(void *arg
)
103 struct putter_hdr
*phdr
;
104 struct puffs_req
*preq
;
105 struct puffstestargs
*args
= arg
;
110 comfd
= args
->pta_servfd
;
111 puffsfd
= args
->pta_rumpfd
;
116 rump_pub_lwproc_newlwp(1);
119 n
= rump_sys_read(puffsfd
, buf
, sizeof(*phdr
));
121 fprintf(stderr
, "readshovel r1 %zd / %d\n", n
, errno
);
125 assert(phdr
->pth_framelen
< BUFSIZE
);
126 n
= rump_sys_read(puffsfd
, buf
+sizeof(*phdr
),
127 phdr
->pth_framelen
- sizeof(*phdr
));
129 fprintf(stderr
, "readshovel r2 %zd / %d\n", n
, errno
);
133 /* Analyze request */
134 if (PUFFSOP_OPCLASS(preq
->preq_opclass
) == PUFFSOP_VFS
) {
135 assert(preq
->preq_optype
< PUFFS_VFS_MAX
);
136 args
->pta_vfs_toserv_ops
[preq
->preq_optype
]++;
137 } else if (PUFFSOP_OPCLASS(preq
->preq_opclass
) == PUFFSOP_VN
) {
138 assert(preq
->preq_optype
< PUFFS_VN_MAX
);
139 args
->pta_vn_toserv_ops
[preq
->preq_optype
]++;
142 n
= phdr
->pth_framelen
;
143 if (xwrite(comfd
, buf
, n
) != n
) {
144 fprintf(stderr
, "readshovel write %zd / %d\n", n
, errno
);
149 if (n
!= 0 && mayquit
== false)
155 writeshovel(void *arg
)
157 struct puffstestargs
*args
= arg
;
158 struct putter_hdr
*phdr
;
159 struct puffs_req
*preq
;
165 rump_pub_lwproc_newlwp(1);
167 comfd
= args
->pta_servfd
;
168 puffsfd
= args
->pta_rumpfd
;
170 phdr
= (struct putter_hdr
*)buf
;
177 * Need to write everything to the "kernel" in one chunk,
178 * so make sure we have it here.
181 toread
= sizeof(struct putter_hdr
);
182 assert(toread
< BUFSIZE
);
184 n
= xread(comfd
, buf
+off
, toread
);
186 fprintf(stderr
, "writeshovel read %zd / %d\n",
191 if (off
>= sizeof(struct putter_hdr
))
192 toread
= phdr
->pth_framelen
- off
;
194 toread
= off
- sizeof(struct putter_hdr
);
198 PUFFSOP_OPCLASS(preq
->preq_opclass
) == PUFFSOP_VFS
199 && preq
->preq_optype
== PUFFS_VFS_UNMOUNT
)) {
200 if (preq
->preq_rv
== 0)
204 n
= rump_sys_write(puffsfd
, buf
, phdr
->pth_framelen
);
205 if ((size_t)n
!= phdr
->pth_framelen
) {
206 fprintf(stderr
, "writeshovel wr %zd / %d\n", n
, errno
);
218 rumpshovels(struct puffstestargs
*args
)
223 if ((rv
= rump_init()) == -1)
226 if (pthread_create(&pt
, NULL
, readshovel
, args
) == -1)
227 err(1, "read shovel");
230 if (pthread_create(&pt
, NULL
, writeshovel
, args
) == -1)
231 err(1, "write shovel");
239 atf_tc_fail("child died"); /* almost signal-safe */
242 struct puffstestargs
*theargs
; /* XXX */
244 /* XXX: we don't support size */
246 donewfs(const atf_tc_t
*tc
, void **argp
,
247 const char *image
, off_t size
, void *fspriv
, char **theargv
)
249 struct puffstestargs
*args
;
260 args
= malloc(sizeof(*args
));
263 memset(args
, 0, sizeof(*args
));
265 pflags
= &args
->pta_pflags
;
267 /* Create sucketpair for communication with the real file server */
268 if (socketpair(PF_LOCAL
, SOCK_STREAM
, 0, sv
) == -1)
271 signal(SIGCHLD
, childfail
);
273 switch ((childpid
= fork())) {
276 snprintf(comfd
, sizeof(sv
[0]), "%d", sv
[0]);
277 if (setenv("PUFFS_COMFD", comfd
, 1) == -1)
280 if (execvp(theargv
[0], theargv
) == -1)
290 if ((n
= xread(sv
[1], &len
, sizeof(len
))) != sizeof(len
))
291 err(1, "mp 1 %zd", n
);
292 if (len
> MAXPATHLEN
)
293 err(1, "mntpath > MAXPATHLEN");
294 if ((size_t)xread(sv
[1], args
->pta_dir
, len
) != len
)
296 if (xread(sv
[1], &len
, sizeof(len
)) != sizeof(len
))
298 if (len
> MAXPATHLEN
)
299 err(1, "devpath > MAXPATHLEN");
300 if ((size_t)xread(sv
[1], args
->pta_dev
, len
) != len
)
302 if (xread(sv
[1], &mntflags
, sizeof(mntflags
)) != sizeof(mntflags
))
304 if (xread(sv
[1], &args
->pta_pargslen
, sizeof(args
->pta_pargslen
))
305 != sizeof(args
->pta_pargslen
))
306 err(1, "puffstest_args len");
307 args
->pta_pargs
= malloc(args
->pta_pargslen
);
308 if (args
->pta_pargs
== NULL
)
310 if (xread(sv
[1], args
->pta_pargs
, args
->pta_pargslen
)
311 != (ssize_t
)args
->pta_pargslen
)
312 err(1, "puffstest_args");
313 if (xread(sv
[1], pflags
, sizeof(*pflags
)) != sizeof(*pflags
))
316 args
->pta_childpid
= childpid
;
317 args
->pta_servfd
= sv
[1];
318 strlcpy(args
->pta_dev
, image
, sizeof(args
->pta_dev
));
320 *argp
= theargs
= args
;
326 puffs_fstest_newfs(const atf_tc_t
*tc
, void **argp
,
327 const char *image
, off_t size
, void *fspriv
)
329 char dtfs_path
[MAXPATHLEN
];
333 /* build dtfs exec path from atf test dir */
334 sprintf(dtfs_path
, "%s/../puffs/h_dtfs/h_dtfs",
335 atf_tc_get_config_var(tc
, "srcdir"));
339 theargv
[0] = dtfs_path
;
341 dtfsargv
[0] = dtfs_path
;
342 dtfsargv
[1] = __UNCONST("-i");
343 dtfsargv
[2] = __UNCONST("-s");
344 dtfsargv
[3] = __UNCONST("dtfs");
345 dtfsargv
[4] = __UNCONST("fictional");
351 return donewfs(tc
, argp
, image
, size
, fspriv
, theargv
);
355 p2k_ffs_fstest_newfs(const atf_tc_t
*tc
, void **argp
,
356 const char *image
, off_t size
, void *fspriv
)
358 char *rumpffs_argv
[5];
362 if ((rv
= ffs_fstest_newfs(tc
, argp
, image
, size
, fspriv
)) != 0)
364 if (mkdir("p2kffsfake", 0777) == -1 && errno
!= EEXIST
)
367 setenv("P2K_NODETACH", "1", 1);
368 rumpffs_argv
[0] = __UNCONST("rump_ffs");
369 rumpffs_argv
[1] = __UNCONST(image
);
370 rumpffs_argv
[2] = __UNCONST("p2kffsfake"); /* NOTUSED */
371 rumpffs_argv
[3] = NULL
;
373 if ((rv
= donewfs(tc
, argp
, image
, size
, fspriv
, rumpffs_argv
)) != 0)
374 ffs_fstest_delfs(tc
, argp
);
379 puffs_fstest_mount(const atf_tc_t
*tc
, void *arg
, const char *path
, int flags
)
381 struct puffstestargs
*pargs
= arg
;
385 fd
= rump_sys_open("/dev/puffs", O_RDWR
);
389 if (rump_sys_mkdir(path
, 0777) == -1)
392 if (rump_sys_mount(MOUNT_PUFFS
, path
, flags
,
393 pargs
->pta_pargs
, pargs
->pta_pargslen
) == -1) {
394 /* apply "to kill a child" to avoid atf hang (kludge) */
395 kill(pargs
->pta_childpid
, SIGKILL
);
399 pargs
->pta_rumpfd
= fd
;
404 __strong_alias(p2k_ffs_fstest_mount
,puffs_fstest_mount
);
407 puffs_fstest_delfs(const atf_tc_t
*tc
, void *arg
)
415 p2k_ffs_fstest_delfs(const atf_tc_t
*tc
, void *arg
)
418 return ffs_fstest_delfs(tc
, arg
);
422 puffs_fstest_unmount(const atf_tc_t
*tc
, const char *path
, int flags
)
424 struct puffstestargs
*pargs
= theargs
;
428 /* ok, child might exit here */
429 signal(SIGCHLD
, SIG_IGN
);
431 rv
= rump_sys_unmount(path
, flags
);
435 if ((rv
= rump_sys_rmdir(path
)) != 0)
438 if (waitpid(pargs
->pta_childpid
, &status
, WNOHANG
) > 0)
440 kill(pargs
->pta_childpid
, SIGTERM
);
442 if (waitpid(pargs
->pta_childpid
, &status
, WNOHANG
) > 0)
444 kill(pargs
->pta_childpid
, SIGKILL
);
452 __strong_alias(p2k_ffs_fstest_unmount
,puffs_fstest_unmount
);