1 1.9 christos /* $NetBSD: t_union.c,v 1.9 2017/01/13 21:30:40 christos Exp $ */ 2 1.1 pooka 3 1.1 pooka #include <sys/types.h> 4 1.1 pooka #include <sys/mount.h> 5 1.1 pooka 6 1.1 pooka #include <atf-c.h> 7 1.1 pooka #include <err.h> 8 1.1 pooka #include <errno.h> 9 1.1 pooka #include <fcntl.h> 10 1.1 pooka #include <stdio.h> 11 1.1 pooka #include <unistd.h> 12 1.1 pooka #include <string.h> 13 1.1 pooka #include <stdlib.h> 14 1.1 pooka 15 1.1 pooka #include <rump/rump.h> 16 1.1 pooka #include <rump/rump_syscalls.h> 17 1.1 pooka 18 1.1 pooka #include <miscfs/union/union.h> 19 1.1 pooka 20 1.9 christos #include "h_macros.h" 21 1.1 pooka #include "../common/h_fsmacros.h" 22 1.1 pooka 23 1.1 pooka #define MSTR "magic bus" 24 1.1 pooka 25 1.1 pooka static void 26 1.1 pooka xput_tfile(const char *mp, const char *path) 27 1.1 pooka { 28 1.1 pooka char pathb[MAXPATHLEN]; 29 1.1 pooka int fd; 30 1.1 pooka 31 1.1 pooka strcpy(pathb, mp); 32 1.1 pooka strcat(pathb, "/"); 33 1.1 pooka strcat(pathb, path); 34 1.1 pooka 35 1.1 pooka RL(fd = rump_sys_open(pathb, O_CREAT | O_RDWR, 0777)); 36 1.1 pooka if (rump_sys_write(fd, MSTR, sizeof(MSTR)) != sizeof(MSTR)) 37 1.1 pooka atf_tc_fail_errno("write to testfile"); 38 1.1 pooka RL(rump_sys_close(fd)); 39 1.1 pooka } 40 1.1 pooka 41 1.1 pooka static int 42 1.1 pooka xread_tfile(const char *mp, const char *path) 43 1.1 pooka { 44 1.1 pooka char pathb[MAXPATHLEN]; 45 1.1 pooka char buf[128]; 46 1.1 pooka int fd; 47 1.1 pooka 48 1.1 pooka strcpy(pathb, mp); 49 1.1 pooka strcat(pathb, "/"); 50 1.1 pooka strcat(pathb, path); 51 1.1 pooka 52 1.1 pooka fd = rump_sys_open(pathb, O_RDONLY); 53 1.1 pooka if (fd == -1) 54 1.1 pooka return errno; 55 1.1 pooka if (rump_sys_read(fd, buf, sizeof(buf)) == -1) 56 1.1 pooka atf_tc_fail_errno("read tfile"); 57 1.1 pooka RL(rump_sys_close(fd)); 58 1.1 pooka if (strcmp(buf, MSTR) == 0) 59 1.1 pooka return 0; 60 1.1 pooka return EPROGMISMATCH; 61 1.1 pooka } 62 1.1 pooka 63 1.4 pooka /* 64 1.4 pooka * Mount a unionfs for testing. Before calling, "mp" contains 65 1.4 pooka * the upper layer. Lowerpath is constructed so that the directory 66 1.4 pooka * contains rumpfs. 67 1.4 pooka */ 68 1.1 pooka static void 69 1.4 pooka mountunion(const char *mp, char *lowerpath) 70 1.1 pooka { 71 1.1 pooka struct union_args unionargs; 72 1.1 pooka 73 1.4 pooka sprintf(lowerpath, "/lower"); 74 1.4 pooka rump_sys_mkdir(lowerpath, 0777); 75 1.1 pooka 76 1.1 pooka /* mount the union with our testfs as the upper layer */ 77 1.1 pooka memset(&unionargs, 0, sizeof(unionargs)); 78 1.1 pooka unionargs.target = lowerpath; 79 1.1 pooka unionargs.mntflags = UNMNT_BELOW; 80 1.1 pooka 81 1.1 pooka if (rump_sys_mount(MOUNT_UNION, mp, 0, 82 1.2 pooka &unionargs, sizeof(unionargs)) == -1) { 83 1.2 pooka if (errno == EOPNOTSUPP) { 84 1.2 pooka atf_tc_skip("fs does not support VOP_WHITEOUT"); 85 1.2 pooka } else { 86 1.2 pooka atf_tc_fail_errno("union mount"); 87 1.2 pooka } 88 1.2 pooka } 89 1.4 pooka } 90 1.4 pooka 91 1.4 pooka #if 0 92 1.4 pooka static void 93 1.4 pooka toggleroot(void) 94 1.4 pooka { 95 1.4 pooka static int status; 96 1.4 pooka 97 1.4 pooka status ^= MNT_RDONLY; 98 1.4 pooka 99 1.4 pooka printf("0x%x\n", status); 100 1.4 pooka RL(rump_sys_mount(MOUNT_RUMPFS, "/", status | MNT_UPDATE, NULL, 0)); 101 1.4 pooka } 102 1.4 pooka #endif 103 1.4 pooka 104 1.4 pooka #define TFILE "tensti" 105 1.4 pooka #define TDIR "testdir" 106 1.4 pooka #define TDFILE TDIR "/indir" 107 1.4 pooka 108 1.4 pooka static void 109 1.4 pooka basic(const atf_tc_t *tc, const char *mp) 110 1.4 pooka { 111 1.4 pooka char lowerpath[MAXPATHLEN]; 112 1.4 pooka char dbuf[8192]; 113 1.4 pooka struct stat sb; 114 1.4 pooka struct dirent *dp; 115 1.4 pooka int error, fd, dsize; 116 1.4 pooka 117 1.4 pooka mountunion(mp, lowerpath); 118 1.4 pooka 119 1.4 pooka /* create a file in the lower layer */ 120 1.4 pooka xput_tfile(lowerpath, TFILE); 121 1.1 pooka 122 1.1 pooka /* first, test we can read the old file from the new namespace */ 123 1.1 pooka error = xread_tfile(mp, TFILE); 124 1.1 pooka if (error != 0) 125 1.1 pooka atf_tc_fail("union compare failed: %d (%s)", 126 1.1 pooka error, strerror(error)); 127 1.1 pooka 128 1.1 pooka /* then, test upper layer writes don't affect the lower layer */ 129 1.1 pooka xput_tfile(mp, "kiekko"); 130 1.1 pooka if ((error = xread_tfile(lowerpath, "kiekko")) != ENOENT) 131 1.1 pooka atf_tc_fail("invisibility failed: %d (%s)", 132 1.1 pooka error, strerror(error)); 133 1.1 pooka 134 1.1 pooka /* check that we can whiteout stuff in the upper layer */ 135 1.1 pooka FSTEST_ENTER(); 136 1.1 pooka RL(rump_sys_unlink(TFILE)); 137 1.1 pooka ATF_REQUIRE_ERRNO(ENOENT, rump_sys_stat(TFILE, &sb) == -1); 138 1.1 pooka FSTEST_EXIT(); 139 1.1 pooka 140 1.1 pooka /* check that the removed node is not in the directory listing */ 141 1.1 pooka RL(fd = rump_sys_open(mp, O_RDONLY)); 142 1.1 pooka RL(dsize = rump_sys_getdents(fd, dbuf, sizeof(dbuf))); 143 1.1 pooka for (dp = (struct dirent *)dbuf; 144 1.1 pooka (char *)dp < dbuf + dsize; 145 1.1 pooka dp = _DIRENT_NEXT(dp)) { 146 1.1 pooka if (strcmp(dp->d_name, TFILE) == 0 && dp->d_type != DT_WHT) 147 1.1 pooka atf_tc_fail("removed file non-white-outed"); 148 1.1 pooka } 149 1.1 pooka RL(rump_sys_close(fd)); 150 1.1 pooka 151 1.1 pooka RL(rump_sys_unmount(mp, 0)); 152 1.1 pooka } 153 1.1 pooka 154 1.4 pooka static void 155 1.4 pooka whiteout(const atf_tc_t *tc, const char *mp) 156 1.4 pooka { 157 1.4 pooka char lower[MAXPATHLEN]; 158 1.4 pooka struct stat sb; 159 1.4 pooka void *fsarg; 160 1.4 pooka 161 1.4 pooka /* 162 1.4 pooka * XXX: use ffs here to make sure any screwups in rumpfs don't 163 1.4 pooka * affect the test 164 1.4 pooka */ 165 1.4 pooka RL(ffs_fstest_newfs(tc, &fsarg, "daimage", 1024*1024*5, NULL)); 166 1.4 pooka RL(ffs_fstest_mount(tc, fsarg, "/lower", 0)); 167 1.4 pooka 168 1.4 pooka /* create a file in the lower layer */ 169 1.4 pooka RL(rump_sys_chdir("/lower")); 170 1.4 pooka RL(rump_sys_mkdir(TDIR, 0777)); 171 1.4 pooka RL(rump_sys_mkdir(TDFILE, 0777)); 172 1.4 pooka RL(rump_sys_chdir("/")); 173 1.4 pooka 174 1.4 pooka RL(ffs_fstest_unmount(tc, "/lower", 0)); 175 1.4 pooka RL(ffs_fstest_mount(tc, fsarg, "/lower", MNT_RDONLY)); 176 1.4 pooka 177 1.4 pooka mountunion(mp, lower); 178 1.4 pooka 179 1.4 pooka FSTEST_ENTER(); 180 1.8 hannken ATF_REQUIRE_ERRNO(ENOTEMPTY, rump_sys_rmdir(TDIR) == -1); 181 1.8 hannken RL(rump_sys_rmdir(TDFILE)); 182 1.4 pooka RL(rump_sys_rmdir(TDIR)); 183 1.4 pooka ATF_REQUIRE_ERRNO(ENOENT, rump_sys_stat(TDFILE, &sb) == -1); 184 1.4 pooka ATF_REQUIRE_ERRNO(ENOENT, rump_sys_stat(TDIR, &sb) == -1); 185 1.4 pooka 186 1.4 pooka RL(rump_sys_mkdir(TDIR, 0777)); 187 1.4 pooka RL(rump_sys_stat(TDIR, &sb)); 188 1.4 pooka ATF_REQUIRE_ERRNO(ENOENT, rump_sys_stat(TDFILE, &sb) == -1); 189 1.4 pooka FSTEST_EXIT(); 190 1.4 pooka 191 1.4 pooka RL(rump_sys_unmount(mp, 0)); 192 1.4 pooka } 193 1.4 pooka 194 1.1 pooka ATF_TC_FSAPPLY(basic, "check basic union functionality"); 195 1.4 pooka ATF_TC_FSAPPLY(whiteout, "create whiteout in upper layer"); 196 1.1 pooka 197 1.1 pooka ATF_TP_ADD_TCS(tp) 198 1.1 pooka { 199 1.1 pooka 200 1.1 pooka ATF_TP_FSAPPLY(basic); 201 1.4 pooka ATF_TP_FSAPPLY(whiteout); 202 1.4 pooka 203 1.1 pooka return atf_no_error(); 204 1.1 pooka } 205