1*57718be8SEnji Cooper /* $NetBSD: fstest_nfs.c,v 1.9 2011/02/28 21:08:46 pooka Exp $ */ 2*57718be8SEnji Cooper 3*57718be8SEnji Cooper /* 4*57718be8SEnji Cooper * Copyright (c) 2010 The NetBSD Foundation, Inc. 5*57718be8SEnji Cooper * 6*57718be8SEnji Cooper * Redistribution and use in source and binary forms, with or without 7*57718be8SEnji Cooper * modification, are permitted provided that the following conditions 8*57718be8SEnji Cooper * are met: 9*57718be8SEnji Cooper * 1. Redistributions of source code must retain the above copyright 10*57718be8SEnji Cooper * notice, this list of conditions and the following disclaimer. 11*57718be8SEnji Cooper * 2. Redistributions in binary form must reproduce the above copyright 12*57718be8SEnji Cooper * notice, this list of conditions and the following disclaimer in the 13*57718be8SEnji Cooper * documentation and/or other materials provided with the distribution. 14*57718be8SEnji Cooper * 15*57718be8SEnji Cooper * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16*57718be8SEnji Cooper * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17*57718be8SEnji Cooper * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18*57718be8SEnji Cooper * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*57718be8SEnji Cooper * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*57718be8SEnji Cooper * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21*57718be8SEnji Cooper * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*57718be8SEnji Cooper * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*57718be8SEnji Cooper * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*57718be8SEnji Cooper * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*57718be8SEnji Cooper * SUCH DAMAGE. 26*57718be8SEnji Cooper */ 27*57718be8SEnji Cooper 28*57718be8SEnji Cooper #include <sys/types.h> 29*57718be8SEnji Cooper #include <sys/mount.h> 30*57718be8SEnji Cooper #include <sys/socket.h> 31*57718be8SEnji Cooper #include <sys/statvfs.h> 32*57718be8SEnji Cooper #include <sys/wait.h> 33*57718be8SEnji Cooper 34*57718be8SEnji Cooper #include <assert.h> 35*57718be8SEnji Cooper #include <atf-c.h> 36*57718be8SEnji Cooper #include <err.h> 37*57718be8SEnji Cooper #include <errno.h> 38*57718be8SEnji Cooper #include <fcntl.h> 39*57718be8SEnji Cooper #include <libgen.h> 40*57718be8SEnji Cooper #include <pthread.h> 41*57718be8SEnji Cooper #include <puffs.h> 42*57718be8SEnji Cooper #include <puffsdump.h> 43*57718be8SEnji Cooper #include <stdio.h> 44*57718be8SEnji Cooper #include <unistd.h> 45*57718be8SEnji Cooper #include <string.h> 46*57718be8SEnji Cooper #include <stdlib.h> 47*57718be8SEnji Cooper 48*57718be8SEnji Cooper #include <rump/rump.h> 49*57718be8SEnji Cooper #include <rump/rump_syscalls.h> 50*57718be8SEnji Cooper 51*57718be8SEnji Cooper #include "h_fsmacros.h" 52*57718be8SEnji Cooper #include "mount_nfs.h" 53*57718be8SEnji Cooper #include "../../net/config/netconfig.c" 54*57718be8SEnji Cooper 55*57718be8SEnji Cooper #define SERVERADDR "10.3.2.1" 56*57718be8SEnji Cooper #define SERVERROADDR "10.4.2.1" 57*57718be8SEnji Cooper #define CLIENTADDR "10.3.2.2" 58*57718be8SEnji Cooper #define CLIENTROADDR "10.4.2.2" 59*57718be8SEnji Cooper #define NETNETMASK "255.255.255.0" 60*57718be8SEnji Cooper #define EXPORTPATH "/myexport" 61*57718be8SEnji Cooper 62*57718be8SEnji Cooper static void 63*57718be8SEnji Cooper childfail(int status) 64*57718be8SEnji Cooper { 65*57718be8SEnji Cooper 66*57718be8SEnji Cooper atf_tc_fail("child died"); 67*57718be8SEnji Cooper } 68*57718be8SEnji Cooper 69*57718be8SEnji Cooper /* fork rump nfsd, configure interface */ 70*57718be8SEnji Cooper static int 71*57718be8SEnji Cooper donewfs(const atf_tc_t *tc, void **argp, 72*57718be8SEnji Cooper const char *image, off_t size, void *fspriv) 73*57718be8SEnji Cooper { 74*57718be8SEnji Cooper const char *srcdir; 75*57718be8SEnji Cooper char *nfsdargv[16]; 76*57718be8SEnji Cooper char nfsdpath[MAXPATHLEN]; 77*57718be8SEnji Cooper char imagepath[MAXPATHLEN]; 78*57718be8SEnji Cooper char ethername[MAXPATHLEN], ethername_ro[MAXPATHLEN]; 79*57718be8SEnji Cooper char ifname[IFNAMSIZ], ifname_ro[IFNAMSIZ]; 80*57718be8SEnji Cooper char cwd[MAXPATHLEN]; 81*57718be8SEnji Cooper struct nfstestargs *args; 82*57718be8SEnji Cooper pid_t childpid; 83*57718be8SEnji Cooper int pipes[2]; 84*57718be8SEnji Cooper int devnull; 85*57718be8SEnji Cooper 86*57718be8SEnji Cooper /* 87*57718be8SEnji Cooper * First, we start the nfs service. 88*57718be8SEnji Cooper */ 89*57718be8SEnji Cooper srcdir = atf_tc_get_config_var(tc, "srcdir"); 90*57718be8SEnji Cooper sprintf(nfsdpath, "%s/../nfs/nfsservice/rumpnfsd", srcdir); 91*57718be8SEnji Cooper sprintf(ethername, "/%s/%s.etherbus", getcwd(cwd, sizeof(cwd)), image); 92*57718be8SEnji Cooper sprintf(ethername_ro, "%s_ro", ethername); 93*57718be8SEnji Cooper sprintf(imagepath, "/%s/%s", cwd, image); 94*57718be8SEnji Cooper 95*57718be8SEnji Cooper nfsdargv[0] = nfsdpath; 96*57718be8SEnji Cooper nfsdargv[1] = ethername; 97*57718be8SEnji Cooper nfsdargv[2] = ethername_ro; 98*57718be8SEnji Cooper nfsdargv[3] = __UNCONST(SERVERADDR); 99*57718be8SEnji Cooper nfsdargv[4] = __UNCONST(SERVERROADDR); 100*57718be8SEnji Cooper nfsdargv[5] = __UNCONST(NETNETMASK); 101*57718be8SEnji Cooper nfsdargv[6] = __UNCONST(EXPORTPATH); 102*57718be8SEnji Cooper nfsdargv[7] = imagepath; 103*57718be8SEnji Cooper nfsdargv[8] = NULL; 104*57718be8SEnji Cooper 105*57718be8SEnji Cooper signal(SIGCHLD, childfail); 106*57718be8SEnji Cooper if (pipe(pipes) == -1) 107*57718be8SEnji Cooper return errno; 108*57718be8SEnji Cooper 109*57718be8SEnji Cooper switch ((childpid = fork())) { 110*57718be8SEnji Cooper case 0: 111*57718be8SEnji Cooper if (chdir(dirname(nfsdpath)) == -1) 112*57718be8SEnji Cooper err(1, "chdir"); 113*57718be8SEnji Cooper close(pipes[0]); 114*57718be8SEnji Cooper if (dup2(pipes[1], 3) == -1) 115*57718be8SEnji Cooper err(1, "dup2"); 116*57718be8SEnji Cooper if (execvp(nfsdargv[0], nfsdargv) == -1) 117*57718be8SEnji Cooper err(1, "execvp"); 118*57718be8SEnji Cooper case -1: 119*57718be8SEnji Cooper return errno; 120*57718be8SEnji Cooper default: 121*57718be8SEnji Cooper close(pipes[1]); 122*57718be8SEnji Cooper break; 123*57718be8SEnji Cooper } 124*57718be8SEnji Cooper 125*57718be8SEnji Cooper /* 126*57718be8SEnji Cooper * Ok, nfsd has been run. The following sleep helps with the 127*57718be8SEnji Cooper * theoretical problem that nfsd can't start fast enough to 128*57718be8SEnji Cooper * process our mount request and we end up doing a timeout 129*57718be8SEnji Cooper * before the mount. This would take several seconds. So 130*57718be8SEnji Cooper * try to make sure nfsd is up&running already at this stage. 131*57718be8SEnji Cooper */ 132*57718be8SEnji Cooper if (read(pipes[0], &devnull, 4) == -1) 133*57718be8SEnji Cooper return errno; 134*57718be8SEnji Cooper 135*57718be8SEnji Cooper /* 136*57718be8SEnji Cooper * Configure our networking interface. 137*57718be8SEnji Cooper */ 138*57718be8SEnji Cooper rump_init(); 139*57718be8SEnji Cooper netcfg_rump_makeshmif(ethername, ifname); 140*57718be8SEnji Cooper netcfg_rump_if(ifname, CLIENTADDR, NETNETMASK); 141*57718be8SEnji Cooper netcfg_rump_makeshmif(ethername_ro, ifname_ro); 142*57718be8SEnji Cooper netcfg_rump_if(ifname_ro, CLIENTROADDR, NETNETMASK); 143*57718be8SEnji Cooper 144*57718be8SEnji Cooper /* 145*57718be8SEnji Cooper * That's it. The rest is done in mount, since we don't have 146*57718be8SEnji Cooper * the mountpath available here. 147*57718be8SEnji Cooper */ 148*57718be8SEnji Cooper args = malloc(sizeof(*args)); 149*57718be8SEnji Cooper if (args == NULL) 150*57718be8SEnji Cooper return errno; 151*57718be8SEnji Cooper memset(args, 0, sizeof(*args)); 152*57718be8SEnji Cooper args->ta_childpid = childpid; 153*57718be8SEnji Cooper strcpy(args->ta_ethername, ethername); 154*57718be8SEnji Cooper 155*57718be8SEnji Cooper *argp = args; 156*57718be8SEnji Cooper 157*57718be8SEnji Cooper return 0; 158*57718be8SEnji Cooper } 159*57718be8SEnji Cooper 160*57718be8SEnji Cooper int 161*57718be8SEnji Cooper nfs_fstest_newfs(const atf_tc_t *tc, void **argp, 162*57718be8SEnji Cooper const char *image, off_t size, void *fspriv) 163*57718be8SEnji Cooper { 164*57718be8SEnji Cooper 165*57718be8SEnji Cooper return donewfs(tc, argp, image, size, fspriv); 166*57718be8SEnji Cooper } 167*57718be8SEnji Cooper 168*57718be8SEnji Cooper int 169*57718be8SEnji Cooper nfsro_fstest_newfs(const atf_tc_t *tc, void **argp, 170*57718be8SEnji Cooper const char *image, off_t size, void *fspriv) 171*57718be8SEnji Cooper { 172*57718be8SEnji Cooper 173*57718be8SEnji Cooper return donewfs(tc, argp, image, size, fspriv); 174*57718be8SEnji Cooper } 175*57718be8SEnji Cooper 176*57718be8SEnji Cooper /* mount the file system */ 177*57718be8SEnji Cooper static int 178*57718be8SEnji Cooper domount(const atf_tc_t *tc, void *arg, const char *serverpath, 179*57718be8SEnji Cooper const char *path, int flags) 180*57718be8SEnji Cooper { 181*57718be8SEnji Cooper char canon_dev[MAXPATHLEN], canon_dir[MAXPATHLEN]; 182*57718be8SEnji Cooper const char *nfscliargs[] = { 183*57718be8SEnji Cooper "nfsclient", 184*57718be8SEnji Cooper serverpath, 185*57718be8SEnji Cooper path, 186*57718be8SEnji Cooper NULL, 187*57718be8SEnji Cooper }; 188*57718be8SEnji Cooper struct nfs_args args; 189*57718be8SEnji Cooper int mntflags; 190*57718be8SEnji Cooper 191*57718be8SEnji Cooper if (rump_sys_mkdir(path, 0777) == -1) 192*57718be8SEnji Cooper return errno; 193*57718be8SEnji Cooper 194*57718be8SEnji Cooper /* XXX: atf does not reset values */ 195*57718be8SEnji Cooper optind = 1; 196*57718be8SEnji Cooper opterr = 1; 197*57718be8SEnji Cooper 198*57718be8SEnji Cooper /* 199*57718be8SEnji Cooper * We use nfs parseargs here, since as a side effect it 200*57718be8SEnji Cooper * takes care of the RPC hulabaloo. 201*57718be8SEnji Cooper */ 202*57718be8SEnji Cooper mount_nfs_parseargs(__arraycount(nfscliargs)-1, __UNCONST(nfscliargs), 203*57718be8SEnji Cooper &args, &mntflags, canon_dev, canon_dir); 204*57718be8SEnji Cooper 205*57718be8SEnji Cooper if (rump_sys_mount(MOUNT_NFS, path, flags, &args, sizeof(args)) == -1) { 206*57718be8SEnji Cooper return errno; 207*57718be8SEnji Cooper } 208*57718be8SEnji Cooper 209*57718be8SEnji Cooper return 0; 210*57718be8SEnji Cooper } 211*57718be8SEnji Cooper 212*57718be8SEnji Cooper int 213*57718be8SEnji Cooper nfs_fstest_mount(const atf_tc_t *tc, void *arg, const char *path, int flags) 214*57718be8SEnji Cooper { 215*57718be8SEnji Cooper 216*57718be8SEnji Cooper return domount(tc, arg, SERVERADDR ":" EXPORTPATH, path, flags); 217*57718be8SEnji Cooper } 218*57718be8SEnji Cooper 219*57718be8SEnji Cooper /* 220*57718be8SEnji Cooper * This is where the magic happens! 221*57718be8SEnji Cooper * 222*57718be8SEnji Cooper * If we are mounting r/w, do the normal thing. However, if we are 223*57718be8SEnji Cooper * doing a r/o mount, switch use the r/o server export address 224*57718be8SEnji Cooper * and do a r/w mount. This way we end up testing the r/o export policy 225*57718be8SEnji Cooper * of the server! (yes, slightly questionable semantics, but at least 226*57718be8SEnji Cooper * we notice very quickly if our assumption is broken in the future ;) 227*57718be8SEnji Cooper */ 228*57718be8SEnji Cooper int 229*57718be8SEnji Cooper nfsro_fstest_mount(const atf_tc_t *tc, void *arg, const char *path, int flags) 230*57718be8SEnji Cooper { 231*57718be8SEnji Cooper 232*57718be8SEnji Cooper if (flags & MNT_RDONLY) { 233*57718be8SEnji Cooper flags &= ~MNT_RDONLY; 234*57718be8SEnji Cooper return domount(tc, arg, SERVERROADDR":"EXPORTPATH, path, flags); 235*57718be8SEnji Cooper } else { 236*57718be8SEnji Cooper return domount(tc, arg, SERVERADDR":"EXPORTPATH, path, flags); 237*57718be8SEnji Cooper } 238*57718be8SEnji Cooper } 239*57718be8SEnji Cooper 240*57718be8SEnji Cooper static int 241*57718be8SEnji Cooper dodelfs(const atf_tc_t *tc, void *arg) 242*57718be8SEnji Cooper { 243*57718be8SEnji Cooper 244*57718be8SEnji Cooper /* 245*57718be8SEnji Cooper * XXX: no access to "args" since we're called from "cleanup". 246*57718be8SEnji Cooper * Trust atf to kill nfsd process and remove etherfile. 247*57718be8SEnji Cooper */ 248*57718be8SEnji Cooper #if 0 249*57718be8SEnji Cooper /* 250*57718be8SEnji Cooper * It's highly expected that the child will die next, so we 251*57718be8SEnji Cooper * don't need that information anymore thank you very many. 252*57718be8SEnji Cooper */ 253*57718be8SEnji Cooper signal(SIGCHLD, SIG_IGN); 254*57718be8SEnji Cooper 255*57718be8SEnji Cooper /* 256*57718be8SEnji Cooper * Just KILL it. Sending it SIGTERM first causes it to try 257*57718be8SEnji Cooper * to send some unmount RPCs, leading to sticky situations. 258*57718be8SEnji Cooper */ 259*57718be8SEnji Cooper kill(args->ta_childpid, SIGKILL); 260*57718be8SEnji Cooper wait(&status); 261*57718be8SEnji Cooper 262*57718be8SEnji Cooper /* remove ethernet bus */ 263*57718be8SEnji Cooper if (unlink(args->ta_ethername) == -1) 264*57718be8SEnji Cooper atf_tc_fail_errno("unlink ethername"); 265*57718be8SEnji Cooper #endif 266*57718be8SEnji Cooper 267*57718be8SEnji Cooper return 0; 268*57718be8SEnji Cooper } 269*57718be8SEnji Cooper 270*57718be8SEnji Cooper int 271*57718be8SEnji Cooper nfs_fstest_delfs(const atf_tc_t *tc, void *arg) 272*57718be8SEnji Cooper { 273*57718be8SEnji Cooper 274*57718be8SEnji Cooper return dodelfs(tc, arg); 275*57718be8SEnji Cooper } 276*57718be8SEnji Cooper 277*57718be8SEnji Cooper int 278*57718be8SEnji Cooper nfsro_fstest_delfs(const atf_tc_t *tc, void *arg) 279*57718be8SEnji Cooper { 280*57718be8SEnji Cooper 281*57718be8SEnji Cooper return dodelfs(tc, arg); 282*57718be8SEnji Cooper } 283*57718be8SEnji Cooper 284*57718be8SEnji Cooper static int 285*57718be8SEnji Cooper dounmount(const atf_tc_t *tc, const char *path, int flags) 286*57718be8SEnji Cooper { 287*57718be8SEnji Cooper int status, i, sverrno; 288*57718be8SEnji Cooper 289*57718be8SEnji Cooper /* 290*57718be8SEnji Cooper * NFS handles sillyrenames in an workqueue. Some of them might 291*57718be8SEnji Cooper * be still in the queue even if all user activity has ceased. 292*57718be8SEnji Cooper * We try to unmount for 2 seconds to give them a chance 293*57718be8SEnji Cooper * to flush out. 294*57718be8SEnji Cooper * 295*57718be8SEnji Cooper * PR kern/43799 296*57718be8SEnji Cooper */ 297*57718be8SEnji Cooper for (i = 0; i < 20; i++) { 298*57718be8SEnji Cooper if ((status = rump_sys_unmount(path, flags)) == 0) 299*57718be8SEnji Cooper break; 300*57718be8SEnji Cooper sverrno = errno; 301*57718be8SEnji Cooper if (sverrno != EBUSY) 302*57718be8SEnji Cooper break; 303*57718be8SEnji Cooper usleep(100000); 304*57718be8SEnji Cooper } 305*57718be8SEnji Cooper if (status == -1) 306*57718be8SEnji Cooper return sverrno; 307*57718be8SEnji Cooper 308*57718be8SEnji Cooper if (rump_sys_rmdir(path) == -1) 309*57718be8SEnji Cooper return errno; 310*57718be8SEnji Cooper 311*57718be8SEnji Cooper return 0; 312*57718be8SEnji Cooper } 313*57718be8SEnji Cooper 314*57718be8SEnji Cooper int 315*57718be8SEnji Cooper nfs_fstest_unmount(const atf_tc_t *tc, const char *path, int flags) 316*57718be8SEnji Cooper { 317*57718be8SEnji Cooper 318*57718be8SEnji Cooper return dounmount(tc, path, flags); 319*57718be8SEnji Cooper } 320*57718be8SEnji Cooper 321*57718be8SEnji Cooper int 322*57718be8SEnji Cooper nfsro_fstest_unmount(const atf_tc_t *tc, const char *path, int flags) 323*57718be8SEnji Cooper { 324*57718be8SEnji Cooper 325*57718be8SEnji Cooper return dounmount(tc, path, flags); 326*57718be8SEnji Cooper } 327