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