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