Home | History | Annotate | Line # | Download | only in common
fstest_nfs.c revision 1.9.44.1
      1  1.9.44.1  christos /*	$NetBSD: fstest_nfs.c,v 1.9.44.1 2019/06/10 22:10:00 christos Exp $	*/
      2       1.1     pooka 
      3       1.1     pooka /*
      4       1.1     pooka  * Copyright (c) 2010 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 <libgen.h>
     40       1.1     pooka #include <pthread.h>
     41       1.1     pooka #include <puffs.h>
     42       1.1     pooka #include <puffsdump.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.1     pooka #include <rump/rump_syscalls.h>
     50       1.1     pooka 
     51       1.1     pooka #include "h_fsmacros.h"
     52       1.1     pooka #include "mount_nfs.h"
     53       1.1     pooka #include "../../net/config/netconfig.c"
     54       1.1     pooka 
     55       1.1     pooka #define SERVERADDR "10.3.2.1"
     56       1.5     pooka #define SERVERROADDR "10.4.2.1"
     57       1.1     pooka #define CLIENTADDR "10.3.2.2"
     58       1.5     pooka #define CLIENTROADDR "10.4.2.2"
     59       1.1     pooka #define NETNETMASK "255.255.255.0"
     60       1.1     pooka #define EXPORTPATH "/myexport"
     61       1.1     pooka 
     62       1.1     pooka static void
     63       1.1     pooka childfail(int status)
     64       1.1     pooka {
     65       1.1     pooka 
     66       1.1     pooka 	atf_tc_fail("child died");
     67       1.1     pooka }
     68       1.1     pooka 
     69       1.1     pooka /* fork rump nfsd, configure interface */
     70       1.5     pooka static int
     71       1.5     pooka donewfs(const atf_tc_t *tc, void **argp,
     72       1.3     pooka 	const char *image, off_t size, void *fspriv)
     73       1.1     pooka {
     74       1.1     pooka 	const char *srcdir;
     75       1.7     pooka 	char *nfsdargv[16];
     76       1.1     pooka 	char nfsdpath[MAXPATHLEN];
     77       1.1     pooka 	char imagepath[MAXPATHLEN];
     78       1.5     pooka 	char ethername[MAXPATHLEN], ethername_ro[MAXPATHLEN];
     79       1.5     pooka 	char ifname[IFNAMSIZ], ifname_ro[IFNAMSIZ];
     80       1.1     pooka 	char cwd[MAXPATHLEN];
     81       1.1     pooka 	struct nfstestargs *args;
     82       1.1     pooka 	pid_t childpid;
     83       1.1     pooka 	int pipes[2];
     84       1.1     pooka 	int devnull;
     85       1.1     pooka 
     86       1.1     pooka 	/*
     87       1.1     pooka 	 * First, we start the nfs service.
     88       1.1     pooka 	 */
     89       1.1     pooka 	srcdir = atf_tc_get_config_var(tc, "srcdir");
     90       1.1     pooka 	sprintf(nfsdpath, "%s/../nfs/nfsservice/rumpnfsd", srcdir);
     91       1.1     pooka 	sprintf(ethername, "/%s/%s.etherbus", getcwd(cwd, sizeof(cwd)), image);
     92       1.5     pooka 	sprintf(ethername_ro, "%s_ro", ethername);
     93       1.1     pooka 	sprintf(imagepath, "/%s/%s", cwd, image);
     94       1.1     pooka 
     95       1.1     pooka 	nfsdargv[0] = nfsdpath;
     96       1.1     pooka 	nfsdargv[1] = ethername;
     97       1.5     pooka 	nfsdargv[2] = ethername_ro;
     98       1.5     pooka 	nfsdargv[3] = __UNCONST(SERVERADDR);
     99       1.5     pooka 	nfsdargv[4] = __UNCONST(SERVERROADDR);
    100       1.5     pooka 	nfsdargv[5] = __UNCONST(NETNETMASK);
    101       1.5     pooka 	nfsdargv[6] = __UNCONST(EXPORTPATH);
    102       1.5     pooka 	nfsdargv[7] = imagepath;
    103       1.5     pooka 	nfsdargv[8] = NULL;
    104       1.1     pooka 
    105       1.1     pooka 	signal(SIGCHLD, childfail);
    106       1.1     pooka 	if (pipe(pipes) == -1)
    107       1.1     pooka 		return errno;
    108       1.1     pooka 
    109       1.1     pooka 	switch ((childpid = fork())) {
    110       1.1     pooka 	case 0:
    111       1.1     pooka 		if (chdir(dirname(nfsdpath)) == -1)
    112       1.1     pooka 			err(1, "chdir");
    113       1.1     pooka 		close(pipes[0]);
    114       1.1     pooka 		if (dup2(pipes[1], 3) == -1)
    115       1.1     pooka 			err(1, "dup2");
    116  1.9.44.1  christos 		execvp(nfsdargv[0], nfsdargv);
    117  1.9.44.1  christos 		err(1, "execvp");
    118       1.1     pooka 	case -1:
    119       1.1     pooka 		return errno;
    120       1.1     pooka 	default:
    121       1.1     pooka 		close(pipes[1]);
    122       1.1     pooka 		break;
    123       1.1     pooka 	}
    124       1.1     pooka 
    125       1.1     pooka 	/*
    126       1.1     pooka 	 * Ok, nfsd has been run.  The following sleep helps with the
    127       1.1     pooka 	 * theoretical problem that nfsd can't start fast enough to
    128       1.1     pooka 	 * process our mount request and we end up doing a timeout
    129       1.1     pooka 	 * before the mount.  This would take several seconds.  So
    130       1.1     pooka 	 * try to make sure nfsd is up&running already at this stage.
    131       1.1     pooka 	 */
    132       1.1     pooka 	if (read(pipes[0], &devnull, 4) == -1)
    133       1.1     pooka 		return errno;
    134       1.1     pooka 
    135       1.1     pooka 	/*
    136       1.1     pooka 	 * Configure our networking interface.
    137       1.1     pooka 	 */
    138       1.1     pooka 	rump_init();
    139       1.1     pooka 	netcfg_rump_makeshmif(ethername, ifname);
    140       1.1     pooka 	netcfg_rump_if(ifname, CLIENTADDR, NETNETMASK);
    141       1.5     pooka 	netcfg_rump_makeshmif(ethername_ro, ifname_ro);
    142       1.5     pooka 	netcfg_rump_if(ifname_ro, CLIENTROADDR, NETNETMASK);
    143       1.1     pooka 
    144       1.1     pooka 	/*
    145       1.1     pooka 	 * That's it.  The rest is done in mount, since we don't have
    146       1.1     pooka 	 * the mountpath available here.
    147       1.1     pooka 	 */
    148       1.1     pooka 	args = malloc(sizeof(*args));
    149       1.6     njoly 	if (args == NULL)
    150       1.6     njoly 		return errno;
    151       1.6     njoly 	memset(args, 0, sizeof(*args));
    152       1.1     pooka 	args->ta_childpid = childpid;
    153       1.1     pooka 	strcpy(args->ta_ethername, ethername);
    154       1.1     pooka 
    155       1.1     pooka 	*argp = args;
    156       1.1     pooka 
    157       1.1     pooka 	return 0;
    158       1.1     pooka }
    159       1.1     pooka 
    160       1.5     pooka int
    161       1.5     pooka nfs_fstest_newfs(const atf_tc_t *tc, void **argp,
    162       1.5     pooka 	const char *image, off_t size, void *fspriv)
    163       1.5     pooka {
    164       1.5     pooka 
    165       1.5     pooka 	return donewfs(tc, argp, image, size, fspriv);
    166       1.5     pooka }
    167       1.5     pooka 
    168       1.5     pooka int
    169       1.5     pooka nfsro_fstest_newfs(const atf_tc_t *tc, void **argp,
    170       1.5     pooka 	const char *image, off_t size, void *fspriv)
    171       1.5     pooka {
    172       1.5     pooka 
    173       1.5     pooka 	return donewfs(tc, argp, image, size, fspriv);
    174       1.5     pooka }
    175       1.5     pooka 
    176       1.1     pooka /* mount the file system */
    177       1.5     pooka static int
    178       1.5     pooka domount(const atf_tc_t *tc, void *arg, const char *serverpath,
    179       1.5     pooka 	const char *path, int flags)
    180       1.1     pooka {
    181       1.1     pooka 	char canon_dev[MAXPATHLEN], canon_dir[MAXPATHLEN];
    182       1.1     pooka 	const char *nfscliargs[] = {
    183       1.1     pooka 		"nfsclient",
    184       1.5     pooka 		serverpath,
    185       1.1     pooka 		path,
    186       1.1     pooka 		NULL,
    187       1.1     pooka 	};
    188       1.1     pooka 	struct nfs_args args;
    189       1.1     pooka 	int mntflags;
    190       1.1     pooka 
    191       1.1     pooka 	if (rump_sys_mkdir(path, 0777) == -1)
    192       1.1     pooka 		return errno;
    193       1.1     pooka 
    194       1.1     pooka 	/* XXX: atf does not reset values */
    195       1.1     pooka 	optind = 1;
    196       1.1     pooka 	opterr = 1;
    197       1.1     pooka 
    198       1.5     pooka 	/*
    199       1.5     pooka 	 * We use nfs parseargs here, since as a side effect it
    200       1.5     pooka 	 * takes care of the RPC hulabaloo.
    201       1.5     pooka 	 */
    202       1.1     pooka 	mount_nfs_parseargs(__arraycount(nfscliargs)-1, __UNCONST(nfscliargs),
    203       1.1     pooka 	    &args, &mntflags, canon_dev, canon_dir);
    204       1.1     pooka 
    205       1.1     pooka 	if (rump_sys_mount(MOUNT_NFS, path, flags, &args, sizeof(args)) == -1) {
    206       1.1     pooka 		return errno;
    207       1.1     pooka 	}
    208       1.1     pooka 
    209       1.1     pooka 	return 0;
    210       1.1     pooka }
    211       1.1     pooka 
    212       1.1     pooka int
    213       1.5     pooka nfs_fstest_mount(const atf_tc_t *tc, void *arg, const char *path, int flags)
    214       1.5     pooka {
    215       1.5     pooka 
    216       1.5     pooka 	return domount(tc, arg, SERVERADDR ":" EXPORTPATH, path, flags);
    217       1.5     pooka }
    218       1.5     pooka 
    219       1.5     pooka /*
    220       1.5     pooka  * This is where the magic happens!
    221       1.5     pooka  *
    222       1.5     pooka  * If we are mounting r/w, do the normal thing.  However, if we are
    223       1.5     pooka  * doing a r/o mount, switch use the r/o server export address
    224       1.5     pooka  * and do a r/w mount.  This way we end up testing the r/o export policy
    225       1.5     pooka  * of the server! (yes, slightly questionable semantics, but at least
    226       1.5     pooka  * we notice very quickly if our assumption is broken in the future ;)
    227       1.5     pooka  */
    228       1.5     pooka int
    229       1.5     pooka nfsro_fstest_mount(const atf_tc_t *tc, void *arg, const char *path, int flags)
    230       1.5     pooka {
    231       1.5     pooka 
    232       1.5     pooka 	if (flags & MNT_RDONLY) {
    233       1.5     pooka 		flags &= ~MNT_RDONLY;
    234       1.5     pooka 		return domount(tc, arg, SERVERROADDR":"EXPORTPATH, path, flags);
    235       1.5     pooka 	} else {
    236       1.5     pooka 		return domount(tc, arg, SERVERADDR":"EXPORTPATH, path, flags);
    237       1.5     pooka 	}
    238       1.5     pooka }
    239       1.5     pooka 
    240       1.5     pooka static int
    241       1.5     pooka dodelfs(const atf_tc_t *tc, void *arg)
    242       1.5     pooka {
    243       1.5     pooka 
    244       1.5     pooka 	/*
    245       1.5     pooka 	 * XXX: no access to "args" since we're called from "cleanup".
    246       1.5     pooka 	 * Trust atf to kill nfsd process and remove etherfile.
    247       1.5     pooka 	 */
    248       1.5     pooka #if 0
    249       1.5     pooka 	/*
    250       1.5     pooka 	 * It's highly expected that the child will die next, so we
    251       1.5     pooka 	 * don't need that information anymore thank you very many.
    252       1.5     pooka 	 */
    253       1.5     pooka 	signal(SIGCHLD, SIG_IGN);
    254       1.5     pooka 
    255       1.5     pooka 	/*
    256       1.5     pooka 	 * Just KILL it.  Sending it SIGTERM first causes it to try
    257       1.5     pooka 	 * to send some unmount RPCs, leading to sticky situations.
    258       1.5     pooka 	 */
    259       1.5     pooka 	kill(args->ta_childpid, SIGKILL);
    260       1.5     pooka 	wait(&status);
    261       1.5     pooka 
    262       1.5     pooka 	/* remove ethernet bus */
    263       1.5     pooka 	if (unlink(args->ta_ethername) == -1)
    264       1.5     pooka 		atf_tc_fail_errno("unlink ethername");
    265       1.5     pooka #endif
    266       1.5     pooka 
    267       1.5     pooka 	return 0;
    268       1.5     pooka }
    269       1.5     pooka 
    270       1.5     pooka int
    271       1.1     pooka nfs_fstest_delfs(const atf_tc_t *tc, void *arg)
    272       1.1     pooka {
    273       1.1     pooka 
    274       1.5     pooka 	return dodelfs(tc, arg);
    275       1.1     pooka }
    276       1.1     pooka 
    277       1.1     pooka int
    278       1.5     pooka nfsro_fstest_delfs(const atf_tc_t *tc, void *arg)
    279       1.5     pooka {
    280       1.5     pooka 
    281       1.5     pooka 	return dodelfs(tc, arg);
    282       1.5     pooka }
    283       1.5     pooka 
    284       1.5     pooka static int
    285       1.5     pooka dounmount(const atf_tc_t *tc, const char *path, int flags)
    286       1.1     pooka {
    287       1.4     pooka 	int status, i, sverrno;
    288       1.1     pooka 
    289       1.4     pooka 	/*
    290       1.4     pooka 	 * NFS handles sillyrenames in an workqueue.  Some of them might
    291       1.4     pooka 	 * be still in the queue even if all user activity has ceased.
    292       1.4     pooka 	 * We try to unmount for 2 seconds to give them a chance
    293       1.4     pooka 	 * to flush out.
    294       1.4     pooka 	 *
    295       1.4     pooka 	 * PR kern/43799
    296       1.4     pooka 	 */
    297       1.4     pooka 	for (i = 0; i < 20; i++) {
    298       1.4     pooka 		if ((status = rump_sys_unmount(path, flags)) == 0)
    299       1.4     pooka 			break;
    300       1.4     pooka 		sverrno = errno;
    301       1.4     pooka 		if (sverrno != EBUSY)
    302       1.4     pooka 			break;
    303       1.4     pooka 		usleep(100000);
    304       1.1     pooka 	}
    305       1.4     pooka 	if (status == -1)
    306       1.4     pooka 		return sverrno;
    307       1.1     pooka 
    308       1.5     pooka 	if (rump_sys_rmdir(path) == -1)
    309       1.5     pooka 		return errno;
    310       1.5     pooka 
    311       1.5     pooka 	return 0;
    312       1.5     pooka }
    313       1.5     pooka 
    314       1.5     pooka int
    315       1.5     pooka nfs_fstest_unmount(const atf_tc_t *tc, const char *path, int flags)
    316       1.5     pooka {
    317       1.1     pooka 
    318       1.5     pooka 	return dounmount(tc, path, flags);
    319       1.5     pooka }
    320       1.1     pooka 
    321       1.5     pooka int
    322       1.5     pooka nfsro_fstest_unmount(const atf_tc_t *tc, const char *path, int flags)
    323       1.5     pooka {
    324       1.1     pooka 
    325       1.5     pooka 	return dounmount(tc, path, flags);
    326       1.1     pooka }
    327