1 /* $NetBSD: t_rfw.c,v 1.1 2020/08/18 03:02:50 perseant Exp $ */ 2 3 #include <sys/types.h> 4 #include <sys/mount.h> 5 #include <sys/sysctl.h> 6 #include <sys/wait.h> 7 8 #include <atf-c.h> 9 #include <errno.h> 10 #include <fcntl.h> 11 #include <limits.h> 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <unistd.h> 15 #include <string.h> 16 17 #include <rump/rump.h> 18 #include <rump/rump_syscalls.h> 19 20 #include <ufs/ufs/ufsmount.h> 21 #include <ufs/lfs/lfs.h> 22 #include <ufs/lfs/lfs_extern.h> 23 24 #include "h_macros.h" 25 26 /* Debugging conditions */ 27 /* #define FORCE_SUCCESS */ /* Don't actually revert, everything worked */ 28 /* #define FORCE_SYSCTL */ /* Don't check - necessary for FORCE_SUCCESS */ 29 30 /* Write a well-known byte pattern into a file, appending if it exists */ 31 int write_file(const char *, int); 32 33 /* Check the byte pattern and size of the file */ 34 int check_file(const char *, int); 35 36 ATF_TC(rfw); 37 ATF_TC_HEAD(rfw, tc) 38 { 39 atf_tc_set_md_var(tc, "descr", 40 "LFS roll-forward creates an inconsistent filesystem"); 41 atf_tc_set_md_var(tc, "timeout", "20"); 42 } 43 44 #define IMGNAME "disk.img" 45 #define FAKEBLK "/dev/blk" 46 #define LOGFILE "newfs.log" 47 #define SBLOCK0_COPY "sb0.dd" 48 #define SBLOCK1_COPY "sb1.dd" 49 #define MAXLINE 132 50 #define CHUNKSIZE 300 51 ATF_TC_BODY(rfw, tc) 52 { 53 struct ufs_args args; 54 FILE *pipe; 55 #if (!defined FORCE_SUCCESS && !defined FORCE_SYSCTL) 56 int o_sysctl_rfw; 57 int n_sysctl_rfw; 58 int mib[3]; 59 size_t len; 60 #endif 61 char buf[MAXLINE]; 62 long long sb0addr = -1, sb1addr = -1; 63 64 /* 65 * Initialize. 66 */ 67 #if (!defined FORCE_SUCCESS && !defined FORCE_SYSCTL) 68 /* Set sysctl to allow roll-forward */ 69 fprintf(stderr, "* Set sysctl\n"); 70 mib[0] = CTL_VFS; 71 mib[1] = 5; /* LFS */ 72 mib[2] = LFS_DO_RFW; 73 len = sizeof(o_sysctl_rfw); 74 if (sysctl(mib, 3, &o_sysctl_rfw, &len, 75 &n_sysctl_rfw, sizeof(n_sysctl_rfw)) < 0) 76 atf_tc_skip("roll-forward not enabled in kernel"); 77 #endif /* !FORCE_SUCCESS && !FORCE_SYSCTL */ 78 79 /* Create filesystem */ 80 fprintf(stderr, "* Create file system\n"); 81 if (system("newfs_lfs -D -F -s 10000 ./" IMGNAME " > " LOGFILE) == -1) 82 atf_tc_fail_errno("newfs failed"); 83 pipe = fopen(LOGFILE, "r"); 84 if (pipe == NULL) 85 atf_tc_fail_errno("newfs failed to execute"); 86 while (fgets(buf, MAXLINE, pipe) != NULL) { 87 if (sscanf(buf, "%lld,%lld", &sb0addr, &sb1addr) == 2) 88 break; 89 } 90 while (fgets(buf, MAXLINE, pipe) != NULL) 91 ; 92 fclose(pipe); 93 if (sb0addr < 0 || sb1addr < 0) 94 atf_tc_fail("superblock not found"); 95 fprintf(stderr, "* Superblocks at %lld and %lld\n", 96 sb0addr, sb1addr); 97 98 /* Set up rump */ 99 rump_init(); 100 if (rump_sys_mkdir("/mp", 0777) == -1) 101 atf_tc_fail_errno("cannot create mountpoint"); 102 rump_pub_etfs_register(FAKEBLK, IMGNAME, RUMP_ETFS_BLK); 103 104 /* 105 * Create initial filesystem state, from which 106 * we will attempt to roll forward. 107 */ 108 109 /* Mount filesystem */ 110 fprintf(stderr, "* Mount fs [1]\n"); 111 memset(&args, 0, sizeof(args)); 112 args.fspec = __UNCONST(FAKEBLK); 113 if (rump_sys_mount(MOUNT_LFS, "/mp", 0, &args, sizeof(args)) == -1) 114 atf_tc_fail_errno("rump_sys_mount failed"); 115 116 /* Payload */ 117 fprintf(stderr, "* Initial payload\n"); 118 write_file("/mp/to_be_deleted", CHUNKSIZE); 119 write_file("/mp/to_be_appended", CHUNKSIZE); 120 121 /* Unmount */ 122 rump_sys_unmount("/mp", 0); 123 124 /* Make copies of superblocks */ 125 sprintf(buf, "dd if=%s of=%s bs=512 iseek=%lld count=16 conv=sync", 126 IMGNAME, SBLOCK0_COPY, sb0addr); 127 system(buf); 128 sprintf(buf, "dd if=%s of=%s bs=512 iseek=%lld count=16 conv=sync", 129 IMGNAME, SBLOCK1_COPY, sb1addr); 130 system(buf); 131 132 /* 133 * Make changes which we will attempt to roll forward. 134 */ 135 136 /* Reconfigure and mount filesystem again */ 137 fprintf(stderr, "* Mount fs [2]\n"); 138 if (rump_sys_mount(MOUNT_LFS, "/mp", 0, &args, sizeof(args)) == -1) 139 atf_tc_fail_errno("rump_sys_mount failed [2]"); 140 141 /* Add new file */ 142 write_file("/mp/newly_created", CHUNKSIZE); 143 144 /* Append to existing file */ 145 write_file("/mp/to_be_appended", CHUNKSIZE); 146 147 /* Delete file */ 148 rump_sys_unlink("/mp/to_be_deleted"); 149 150 /* Done with payload, unmount fs */ 151 rump_sys_unmount("/mp", 0); 152 153 #ifndef FORCE_SUCCESS 154 /* 155 * Copy back old superblocks, reverting FS to old state 156 */ 157 sprintf(buf, "dd of=%s if=%s bs=512 oseek=%lld count=16 conv=sync,notrunc", 158 IMGNAME, SBLOCK0_COPY, sb0addr); 159 system(buf); 160 sprintf(buf, "dd of=%s if=%s bs=512 oseek=%lld count=16 conv=sync,notrunc", 161 IMGNAME, SBLOCK1_COPY, sb1addr); 162 system(buf); 163 164 if (system("fsck_lfs -n -f " IMGNAME)) 165 atf_tc_fail_errno("fsck found errors with old superblocks"); 166 #endif 167 168 /* 169 * Roll forward. 170 */ 171 172 /* Mount filesystem; this will roll forward. */ 173 fprintf(stderr, "* Mount fs [3]\n"); 174 if (rump_sys_mount(MOUNT_LFS, "/mp", 0, &args, sizeof(args)) == -1) 175 atf_tc_fail_errno("rump_sys_mount failed [3]"); 176 177 /* Unmount filesystem */ 178 rump_sys_unmount("/mp", 0); 179 180 /* 181 * Use fsck_lfs to look for consistency errors 182 */ 183 184 if (system("fsck_lfs -n -f " IMGNAME)) 185 atf_tc_fail_errno("fsck found errors"); 186 187 /* 188 * Check file system contents 189 */ 190 191 /* Mount filesystem one last time */ 192 fprintf(stderr, "* Mount fs [4]\n"); 193 if (rump_sys_mount(MOUNT_LFS, "/mp", 0, &args, sizeof(args)) == -1) 194 atf_tc_fail_errno("rump_sys_mount failed [4]"); 195 196 if (check_file("/mp/newly_created", CHUNKSIZE) != 0) 197 atf_tc_fail("Newly added file differs"); 198 199 if (check_file("/mp/to_be_appended", 2 * CHUNKSIZE) != 0) 200 atf_tc_fail("Appended file differs"); 201 202 if (rump_sys_access("/mp/to_be_deleted", F_OK) == 0) 203 atf_tc_fail("Removed file still present"); 204 205 /* Umount filesystem, test completed */ 206 rump_sys_unmount("/mp", 0); 207 } 208 209 ATF_TP_ADD_TCS(tp) 210 { 211 212 ATF_TP_ADD_TC(tp, rfw); 213 return atf_no_error(); 214 } 215 216 /* Write some data into a file */ 217 int write_file(const char *filename, int add) 218 { 219 int fd, size, i; 220 struct stat statbuf; 221 unsigned char b; 222 int flags = O_CREAT|O_WRONLY; 223 224 if (rump_sys_stat(filename, &statbuf) < 0) 225 size = 0; 226 else { 227 size = statbuf.st_size; 228 flags |= O_APPEND; 229 } 230 231 fd = rump_sys_open(filename, flags); 232 233 for (i = 0; i < add; i++) { 234 b = (size + i) & 0xff; 235 rump_sys_write(fd, &b, 1); 236 } 237 rump_sys_close(fd); 238 239 return 0; 240 } 241 242 /* Check file's existence, size and contents */ 243 int check_file(const char *filename, int size) 244 { 245 int fd, i; 246 struct stat statbuf; 247 unsigned char b; 248 249 if (rump_sys_stat(filename, &statbuf) < 0) { 250 fprintf(stderr, "%s: stat failed\n", filename); 251 return 1; 252 } 253 if (size != statbuf.st_size) { 254 fprintf(stderr, "%s: expected %d bytes, found %d\n", 255 filename, size, (int)statbuf.st_size); 256 return 2; 257 } 258 259 fd = rump_sys_open(filename, O_RDONLY); 260 261 for (i = 0; i < size; i++) { 262 rump_sys_read(fd, &b, 1); 263 if (b != (i & 0xff)) { 264 fprintf(stderr, "%s: byte %d: expected %x found %x\n", 265 filename, i, (unsigned)(i & 0xff), b); 266 return 3; 267 } 268 } 269 rump_sys_close(fd); 270 271 return 0; 272 } 273