1 /* $NetBSD: fstest_nfs.c,v 1.9 2011/02/28 21:08:46 pooka Exp $ */
4 * Copyright (c) 2010 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>
42 #include <puffsdump.h>
48 #include <rump/rump.h>
49 #include <rump/rump_syscalls.h>
51 #include "h_fsmacros.h"
52 #include "mount_nfs.h"
53 #include "../../net/config/netconfig.c"
55 #define SERVERADDR "10.3.2.1"
56 #define SERVERROADDR "10.4.2.1"
57 #define CLIENTADDR "10.3.2.2"
58 #define CLIENTROADDR "10.4.2.2"
59 #define NETNETMASK "255.255.255.0"
60 #define EXPORTPATH "/myexport"
66 atf_tc_fail("child died");
69 /* fork rump nfsd, configure interface */
71 donewfs(const atf_tc_t
*tc
, void **argp
,
72 const char *image
, off_t size
, void *fspriv
)
76 char nfsdpath
[MAXPATHLEN
];
77 char imagepath
[MAXPATHLEN
];
78 char ethername
[MAXPATHLEN
], ethername_ro
[MAXPATHLEN
];
79 char ifname
[IFNAMSIZ
], ifname_ro
[IFNAMSIZ
];
81 struct nfstestargs
*args
;
87 * First, we start the nfs service.
89 srcdir
= atf_tc_get_config_var(tc
, "srcdir");
90 sprintf(nfsdpath
, "%s/../nfs/nfsservice/rumpnfsd", srcdir
);
91 sprintf(ethername
, "/%s/%s.etherbus", getcwd(cwd
, sizeof(cwd
)), image
);
92 sprintf(ethername_ro
, "%s_ro", ethername
);
93 sprintf(imagepath
, "/%s/%s", cwd
, image
);
95 nfsdargv
[0] = nfsdpath
;
96 nfsdargv
[1] = ethername
;
97 nfsdargv
[2] = ethername_ro
;
98 nfsdargv
[3] = __UNCONST(SERVERADDR
);
99 nfsdargv
[4] = __UNCONST(SERVERROADDR
);
100 nfsdargv
[5] = __UNCONST(NETNETMASK
);
101 nfsdargv
[6] = __UNCONST(EXPORTPATH
);
102 nfsdargv
[7] = imagepath
;
105 signal(SIGCHLD
, childfail
);
106 if (pipe(pipes
) == -1)
109 switch ((childpid
= fork())) {
111 if (chdir(dirname(nfsdpath
)) == -1)
114 if (dup2(pipes
[1], 3) == -1)
116 if (execvp(nfsdargv
[0], nfsdargv
) == -1)
126 * Ok, nfsd has been run. The following sleep helps with the
127 * theoretical problem that nfsd can't start fast enough to
128 * process our mount request and we end up doing a timeout
129 * before the mount. This would take several seconds. So
130 * try to make sure nfsd is up&running already at this stage.
132 if (read(pipes
[0], &devnull
, 4) == -1)
136 * Configure our networking interface.
139 netcfg_rump_makeshmif(ethername
, ifname
);
140 netcfg_rump_if(ifname
, CLIENTADDR
, NETNETMASK
);
141 netcfg_rump_makeshmif(ethername_ro
, ifname_ro
);
142 netcfg_rump_if(ifname_ro
, CLIENTROADDR
, NETNETMASK
);
145 * That's it. The rest is done in mount, since we don't have
146 * the mountpath available here.
148 args
= malloc(sizeof(*args
));
151 memset(args
, 0, sizeof(*args
));
152 args
->ta_childpid
= childpid
;
153 strcpy(args
->ta_ethername
, ethername
);
161 nfs_fstest_newfs(const atf_tc_t
*tc
, void **argp
,
162 const char *image
, off_t size
, void *fspriv
)
165 return donewfs(tc
, argp
, image
, size
, fspriv
);
169 nfsro_fstest_newfs(const atf_tc_t
*tc
, void **argp
,
170 const char *image
, off_t size
, void *fspriv
)
173 return donewfs(tc
, argp
, image
, size
, fspriv
);
176 /* mount the file system */
178 domount(const atf_tc_t
*tc
, void *arg
, const char *serverpath
,
179 const char *path
, int flags
)
181 char canon_dev
[MAXPATHLEN
], canon_dir
[MAXPATHLEN
];
182 const char *nfscliargs
[] = {
188 struct nfs_args args
;
191 if (rump_sys_mkdir(path
, 0777) == -1)
194 /* XXX: atf does not reset values */
199 * We use nfs parseargs here, since as a side effect it
200 * takes care of the RPC hulabaloo.
202 mount_nfs_parseargs(__arraycount(nfscliargs
)-1, __UNCONST(nfscliargs
),
203 &args
, &mntflags
, canon_dev
, canon_dir
);
205 if (rump_sys_mount(MOUNT_NFS
, path
, flags
, &args
, sizeof(args
)) == -1) {
213 nfs_fstest_mount(const atf_tc_t
*tc
, void *arg
, const char *path
, int flags
)
216 return domount(tc
, arg
, SERVERADDR
":" EXPORTPATH
, path
, flags
);
220 * This is where the magic happens!
222 * If we are mounting r/w, do the normal thing. However, if we are
223 * doing a r/o mount, switch use the r/o server export address
224 * and do a r/w mount. This way we end up testing the r/o export policy
225 * of the server! (yes, slightly questionable semantics, but at least
226 * we notice very quickly if our assumption is broken in the future ;)
229 nfsro_fstest_mount(const atf_tc_t
*tc
, void *arg
, const char *path
, int flags
)
232 if (flags
& MNT_RDONLY
) {
233 flags
&= ~MNT_RDONLY
;
234 return domount(tc
, arg
, SERVERROADDR
":"EXPORTPATH
, path
, flags
);
236 return domount(tc
, arg
, SERVERADDR
":"EXPORTPATH
, path
, flags
);
241 dodelfs(const atf_tc_t
*tc
, void *arg
)
245 * XXX: no access to "args" since we're called from "cleanup".
246 * Trust atf to kill nfsd process and remove etherfile.
250 * It's highly expected that the child will die next, so we
251 * don't need that information anymore thank you very many.
253 signal(SIGCHLD
, SIG_IGN
);
256 * Just KILL it. Sending it SIGTERM first causes it to try
257 * to send some unmount RPCs, leading to sticky situations.
259 kill(args
->ta_childpid
, SIGKILL
);
262 /* remove ethernet bus */
263 if (unlink(args
->ta_ethername
) == -1)
264 atf_tc_fail_errno("unlink ethername");
271 nfs_fstest_delfs(const atf_tc_t
*tc
, void *arg
)
274 return dodelfs(tc
, arg
);
278 nfsro_fstest_delfs(const atf_tc_t
*tc
, void *arg
)
281 return dodelfs(tc
, arg
);
285 dounmount(const atf_tc_t
*tc
, const char *path
, int flags
)
287 int status
, i
, sverrno
;
290 * NFS handles sillyrenames in an workqueue. Some of them might
291 * be still in the queue even if all user activity has ceased.
292 * We try to unmount for 2 seconds to give them a chance
297 for (i
= 0; i
< 20; i
++) {
298 if ((status
= rump_sys_unmount(path
, flags
)) == 0)
301 if (sverrno
!= EBUSY
)
308 if (rump_sys_rmdir(path
) == -1)
315 nfs_fstest_unmount(const atf_tc_t
*tc
, const char *path
, int flags
)
318 return dounmount(tc
, path
, flags
);
322 nfsro_fstest_unmount(const atf_tc_t
*tc
, const char *path
, int flags
)
325 return dounmount(tc
, path
, flags
);