1*284084a7Sriastradh /* $NetBSD: t_rfw.c,v 1.3 2020/08/23 22:34:29 riastradh Exp $ */
2c7e481e2Sperseant
3c7e481e2Sperseant #include <sys/types.h>
4c7e481e2Sperseant #include <sys/mount.h>
5c7e481e2Sperseant #include <sys/wait.h>
6c7e481e2Sperseant
7c7e481e2Sperseant #include <atf-c.h>
85e1ae64cSperseant #include <ctype.h>
9c7e481e2Sperseant #include <errno.h>
10c7e481e2Sperseant #include <fcntl.h>
11c7e481e2Sperseant #include <limits.h>
12c7e481e2Sperseant #include <stdio.h>
13c7e481e2Sperseant #include <stdlib.h>
14c7e481e2Sperseant #include <unistd.h>
15c7e481e2Sperseant #include <string.h>
16c7e481e2Sperseant
17c7e481e2Sperseant #include <rump/rump.h>
18c7e481e2Sperseant #include <rump/rump_syscalls.h>
19c7e481e2Sperseant
20c7e481e2Sperseant #include <ufs/ufs/ufsmount.h>
21c7e481e2Sperseant #include <ufs/lfs/lfs.h>
22c7e481e2Sperseant #include <ufs/lfs/lfs_extern.h>
23c7e481e2Sperseant
24c7e481e2Sperseant #include "h_macros.h"
25c7e481e2Sperseant
26c7e481e2Sperseant /* Debugging conditions */
27c7e481e2Sperseant /* #define FORCE_SUCCESS */ /* Don't actually revert, everything worked */
28c7e481e2Sperseant
29c7e481e2Sperseant /* Write a well-known byte pattern into a file, appending if it exists */
30c7e481e2Sperseant int write_file(const char *, int);
31c7e481e2Sperseant
32c7e481e2Sperseant /* Check the byte pattern and size of the file */
33c7e481e2Sperseant int check_file(const char *, int);
34c7e481e2Sperseant
355e1ae64cSperseant /* Check the file system for consistency */
365e1ae64cSperseant int fsck(void);
375e1ae64cSperseant
385e1ae64cSperseant /* Actually run the test, differentiating the orphaned delete problem */
395e1ae64cSperseant void test(int);
405e1ae64cSperseant
41c7e481e2Sperseant ATF_TC(rfw);
ATF_TC_HEAD(rfw,tc)42c7e481e2Sperseant ATF_TC_HEAD(rfw, tc)
43c7e481e2Sperseant {
44c7e481e2Sperseant atf_tc_set_md_var(tc, "descr",
45c7e481e2Sperseant "LFS roll-forward creates an inconsistent filesystem");
46c7e481e2Sperseant atf_tc_set_md_var(tc, "timeout", "20");
47c7e481e2Sperseant }
48c7e481e2Sperseant
495e1ae64cSperseant #define MAXLINE 132
505e1ae64cSperseant #define CHUNKSIZE 300
515e1ae64cSperseant
52c7e481e2Sperseant #define IMGNAME "disk.img"
53c7e481e2Sperseant #define FAKEBLK "/dev/blk"
54c7e481e2Sperseant #define LOGFILE "newfs.log"
55c7e481e2Sperseant #define SBLOCK0_COPY "sb0.dd"
56c7e481e2Sperseant #define SBLOCK1_COPY "sb1.dd"
575e1ae64cSperseant
585e1ae64cSperseant #define MP "/mp"
595e1ae64cSperseant #define UNCHANGED_CONTROL MP "/3-unchanged-control"
605e1ae64cSperseant #define TO_BE_DELETED MP "/4-to-be-deleted"
615e1ae64cSperseant #define TO_BE_APPENDED MP "/5-to-be-appended"
625e1ae64cSperseant #define NEWLY_CREATED MP "/6-newly-created"
635e1ae64cSperseant
645e1ae64cSperseant long long sbaddr[2] = { -1, -1 };
655e1ae64cSperseant const char *sblock[2] = { SBLOCK0_COPY, SBLOCK1_COPY };
665e1ae64cSperseant
ATF_TC_BODY(rfw,tc)67c7e481e2Sperseant ATF_TC_BODY(rfw, tc)
68c7e481e2Sperseant {
69c7e481e2Sperseant struct ufs_args args;
70c7e481e2Sperseant FILE *pipe;
71c7e481e2Sperseant char buf[MAXLINE];
725e1ae64cSperseant int i;
735e1ae64cSperseant
745e1ae64cSperseant setvbuf(stdout, NULL, _IONBF, 0);
75c7e481e2Sperseant
76c7e481e2Sperseant /*
77c7e481e2Sperseant * Initialize.
78c7e481e2Sperseant */
795e1ae64cSperseant atf_tc_expect_fail("roll-forward not yet implemented");
80c7e481e2Sperseant
815e1ae64cSperseant /* Create filesystem, note superblock locations */
82c7e481e2Sperseant fprintf(stderr, "* Create file system\n");
83c7e481e2Sperseant if (system("newfs_lfs -D -F -s 10000 ./" IMGNAME " > " LOGFILE) == -1)
84c7e481e2Sperseant atf_tc_fail_errno("newfs failed");
85c7e481e2Sperseant pipe = fopen(LOGFILE, "r");
86c7e481e2Sperseant if (pipe == NULL)
87c7e481e2Sperseant atf_tc_fail_errno("newfs failed to execute");
88c7e481e2Sperseant while (fgets(buf, MAXLINE, pipe) != NULL) {
895e1ae64cSperseant if (sscanf(buf, "%lld,%lld", sbaddr, sbaddr + 1) == 2)
90c7e481e2Sperseant break;
91c7e481e2Sperseant }
92c7e481e2Sperseant while (fgets(buf, MAXLINE, pipe) != NULL)
93c7e481e2Sperseant ;
94c7e481e2Sperseant fclose(pipe);
955e1ae64cSperseant if (sbaddr[0] < 0 || sbaddr[1] < 0)
96c7e481e2Sperseant atf_tc_fail("superblock not found");
97c7e481e2Sperseant fprintf(stderr, "* Superblocks at %lld and %lld\n",
985e1ae64cSperseant sbaddr[0], sbaddr[1]);
99c7e481e2Sperseant
100c7e481e2Sperseant /* Set up rump */
101c7e481e2Sperseant rump_init();
1025e1ae64cSperseant if (rump_sys_mkdir(MP, 0777) == -1)
103c7e481e2Sperseant atf_tc_fail_errno("cannot create mountpoint");
104c7e481e2Sperseant rump_pub_etfs_register(FAKEBLK, IMGNAME, RUMP_ETFS_BLK);
105c7e481e2Sperseant
106c7e481e2Sperseant /*
107c7e481e2Sperseant * Create initial filesystem state, from which
108c7e481e2Sperseant * we will attempt to roll forward.
109c7e481e2Sperseant */
110c7e481e2Sperseant
111c7e481e2Sperseant /* Mount filesystem */
1125e1ae64cSperseant fprintf(stderr, "* Mount fs [1, initial]\n");
113c7e481e2Sperseant memset(&args, 0, sizeof(args));
114c7e481e2Sperseant args.fspec = __UNCONST(FAKEBLK);
1155e1ae64cSperseant if (rump_sys_mount(MOUNT_LFS, MP, 0, &args, sizeof(args)) == -1)
116c7e481e2Sperseant atf_tc_fail_errno("rump_sys_mount failed");
117c7e481e2Sperseant
118c7e481e2Sperseant /* Payload */
119c7e481e2Sperseant fprintf(stderr, "* Initial payload\n");
1205e1ae64cSperseant write_file(UNCHANGED_CONTROL, CHUNKSIZE);
1215e1ae64cSperseant write_file(TO_BE_DELETED, CHUNKSIZE);
1225e1ae64cSperseant write_file(TO_BE_APPENDED, CHUNKSIZE);
1235e1ae64cSperseant rump_sys_sync();
1245e1ae64cSperseant rump_sys_sync();
1255e1ae64cSperseant sleep(1); /* XXX yuck - but we need the superblocks dirty */
126c7e481e2Sperseant
127c7e481e2Sperseant /* Make copies of superblocks */
1285e1ae64cSperseant for (i = 0; i < 2; i++) {
1295e1ae64cSperseant sprintf(buf, "dd if=%s of=%s bs=512 iseek=%lld"
1305e1ae64cSperseant " count=16 conv=sync", IMGNAME, sblock[i], sbaddr[i]);
131c7e481e2Sperseant system(buf);
1325e1ae64cSperseant }
1335e1ae64cSperseant
1345e1ae64cSperseant /* Unmount */
1355e1ae64cSperseant rump_sys_unmount(MP, 0);
136c7e481e2Sperseant
137c7e481e2Sperseant /*
138c7e481e2Sperseant * Make changes which we will attempt to roll forward.
139c7e481e2Sperseant */
140c7e481e2Sperseant
141c7e481e2Sperseant /* Reconfigure and mount filesystem again */
1425e1ae64cSperseant fprintf(stderr, "* Mount fs [2, after changes]\n");
1435e1ae64cSperseant if (rump_sys_mount(MOUNT_LFS, MP, 0, &args, sizeof(args)) == -1)
144c7e481e2Sperseant atf_tc_fail_errno("rump_sys_mount failed [2]");
145c7e481e2Sperseant
146c7e481e2Sperseant /* Add new file */
1475e1ae64cSperseant write_file(NEWLY_CREATED, CHUNKSIZE);
148c7e481e2Sperseant
149c7e481e2Sperseant /* Append to existing file */
1505e1ae64cSperseant write_file(TO_BE_APPENDED, CHUNKSIZE);
151c7e481e2Sperseant
152c7e481e2Sperseant /* Delete file */
1535e1ae64cSperseant rump_sys_unlink(TO_BE_DELETED);
154c7e481e2Sperseant
155c7e481e2Sperseant /* Done with payload, unmount fs */
1565e1ae64cSperseant rump_sys_unmount(MP, 0);
157c7e481e2Sperseant
158c7e481e2Sperseant #ifndef FORCE_SUCCESS
159c7e481e2Sperseant /*
160c7e481e2Sperseant * Copy back old superblocks, reverting FS to old state
161c7e481e2Sperseant */
1625e1ae64cSperseant for (i = 0; i < 2; i++) {
1635e1ae64cSperseant sprintf(buf, "dd of=%s if=%s bs=512 oseek=%lld count=16"
1645e1ae64cSperseant " conv=sync,notrunc", IMGNAME, sblock[i], sbaddr[i]);
165c7e481e2Sperseant system(buf);
1665e1ae64cSperseant }
167c7e481e2Sperseant
1685e1ae64cSperseant if (fsck())
169c7e481e2Sperseant atf_tc_fail_errno("fsck found errors with old superblocks");
170c7e481e2Sperseant #endif
171c7e481e2Sperseant
172c7e481e2Sperseant /*
173c7e481e2Sperseant * Roll forward.
174c7e481e2Sperseant */
175c7e481e2Sperseant
176c7e481e2Sperseant /* Mount filesystem; this will roll forward. */
1775e1ae64cSperseant fprintf(stderr, "* Mount fs [3, to roll forward]\n");
1785e1ae64cSperseant if (rump_sys_mount(MOUNT_LFS, MP, 0, &args, sizeof(args)) == -1)
179c7e481e2Sperseant atf_tc_fail_errno("rump_sys_mount failed [3]");
180c7e481e2Sperseant
181c7e481e2Sperseant /* Unmount filesystem */
1825e1ae64cSperseant if (rump_sys_unmount(MP, 0) != 0)
1835e1ae64cSperseant atf_tc_fail_errno("rump_sys_umount failed after roll-forward");
184c7e481e2Sperseant
185c7e481e2Sperseant /*
1865e1ae64cSperseant * Use fsck_lfs to look for consistency errors.
187c7e481e2Sperseant */
188c7e481e2Sperseant
1895e1ae64cSperseant if (fsck()) {
1905e1ae64cSperseant fprintf(stderr, "*** FAILED FSCK ***\n");
1915e1ae64cSperseant atf_tc_fail("fsck found errors after roll forward");
1925e1ae64cSperseant }
193c7e481e2Sperseant
194c7e481e2Sperseant /*
195c7e481e2Sperseant * Check file system contents
196c7e481e2Sperseant */
197c7e481e2Sperseant
198c7e481e2Sperseant /* Mount filesystem one last time */
1995e1ae64cSperseant fprintf(stderr, "* Mount fs [4, after roll forward complete]\n");
2005e1ae64cSperseant if (rump_sys_mount(MOUNT_LFS, MP, 0, &args, sizeof(args)) == -1)
201c7e481e2Sperseant atf_tc_fail_errno("rump_sys_mount failed [4]");
202c7e481e2Sperseant
2035e1ae64cSperseant if (check_file(UNCHANGED_CONTROL, CHUNKSIZE) != 0)
2045e1ae64cSperseant atf_tc_fail("Unchanged control file differs(!)");
205c7e481e2Sperseant
2065e1ae64cSperseant if (check_file(TO_BE_APPENDED, 2 * CHUNKSIZE) != 0)
207c7e481e2Sperseant atf_tc_fail("Appended file differs");
208c7e481e2Sperseant
2095e1ae64cSperseant if (rump_sys_access(NEWLY_CREATED, F_OK) != 0)
2105e1ae64cSperseant atf_tc_fail("Newly added file missing");
2115e1ae64cSperseant
2125e1ae64cSperseant if (check_file(NEWLY_CREATED, CHUNKSIZE) != 0)
2135e1ae64cSperseant atf_tc_fail("Newly added file differs");
2145e1ae64cSperseant
2155e1ae64cSperseant if (rump_sys_access(TO_BE_DELETED, F_OK) == 0)
216c7e481e2Sperseant atf_tc_fail("Removed file still present");
217c7e481e2Sperseant
2185e1ae64cSperseant /* Umount filesystem */
2195e1ae64cSperseant rump_sys_unmount(MP, 0);
2205e1ae64cSperseant
2215e1ae64cSperseant /* Final fsck to double check */
2225e1ae64cSperseant if (fsck()) {
2235e1ae64cSperseant fprintf(stderr, "*** FAILED FSCK ***\n");
2245e1ae64cSperseant atf_tc_fail("fsck found errors after final unmount");
2255e1ae64cSperseant }
226c7e481e2Sperseant }
227c7e481e2Sperseant
ATF_TP_ADD_TCS(tp)228c7e481e2Sperseant ATF_TP_ADD_TCS(tp)
229c7e481e2Sperseant {
230c7e481e2Sperseant
231c7e481e2Sperseant ATF_TP_ADD_TC(tp, rfw);
232c7e481e2Sperseant return atf_no_error();
233c7e481e2Sperseant }
234c7e481e2Sperseant
235c7e481e2Sperseant /* Write some data into a file */
write_file(const char * filename,int add)236c7e481e2Sperseant int write_file(const char *filename, int add)
237c7e481e2Sperseant {
238c7e481e2Sperseant int fd, size, i;
239c7e481e2Sperseant struct stat statbuf;
240c7e481e2Sperseant unsigned char b;
241c7e481e2Sperseant int flags = O_CREAT|O_WRONLY;
242c7e481e2Sperseant
243c7e481e2Sperseant if (rump_sys_stat(filename, &statbuf) < 0)
244c7e481e2Sperseant size = 0;
245c7e481e2Sperseant else {
246c7e481e2Sperseant size = statbuf.st_size;
247c7e481e2Sperseant flags |= O_APPEND;
248c7e481e2Sperseant }
249c7e481e2Sperseant
250c7e481e2Sperseant fd = rump_sys_open(filename, flags);
251c7e481e2Sperseant
252c7e481e2Sperseant for (i = 0; i < add; i++) {
2535e1ae64cSperseant b = ((unsigned)(size + i)) & 0xff;
254c7e481e2Sperseant rump_sys_write(fd, &b, 1);
255c7e481e2Sperseant }
256c7e481e2Sperseant rump_sys_close(fd);
257c7e481e2Sperseant
258c7e481e2Sperseant return 0;
259c7e481e2Sperseant }
260c7e481e2Sperseant
261c7e481e2Sperseant /* Check file's existence, size and contents */
check_file(const char * filename,int size)262c7e481e2Sperseant int check_file(const char *filename, int size)
263c7e481e2Sperseant {
264c7e481e2Sperseant int fd, i;
265c7e481e2Sperseant struct stat statbuf;
266c7e481e2Sperseant unsigned char b;
267c7e481e2Sperseant
268c7e481e2Sperseant if (rump_sys_stat(filename, &statbuf) < 0) {
269c7e481e2Sperseant fprintf(stderr, "%s: stat failed\n", filename);
270c7e481e2Sperseant return 1;
271c7e481e2Sperseant }
272c7e481e2Sperseant if (size != statbuf.st_size) {
273c7e481e2Sperseant fprintf(stderr, "%s: expected %d bytes, found %d\n",
274c7e481e2Sperseant filename, size, (int)statbuf.st_size);
275c7e481e2Sperseant return 2;
276c7e481e2Sperseant }
277c7e481e2Sperseant
278c7e481e2Sperseant fd = rump_sys_open(filename, O_RDONLY);
279c7e481e2Sperseant for (i = 0; i < size; i++) {
280c7e481e2Sperseant rump_sys_read(fd, &b, 1);
2815e1ae64cSperseant if (b != (((unsigned)i) & 0xff)) {
282c7e481e2Sperseant fprintf(stderr, "%s: byte %d: expected %x found %x\n",
2835e1ae64cSperseant filename, i, ((unsigned)(i)) & 0xff, b);
2845e1ae64cSperseant rump_sys_close(fd);
285c7e481e2Sperseant return 3;
286c7e481e2Sperseant }
287c7e481e2Sperseant }
288c7e481e2Sperseant rump_sys_close(fd);
2895e1ae64cSperseant fprintf(stderr, "%s: no problem\n", filename);
290c7e481e2Sperseant return 0;
291c7e481e2Sperseant }
2925e1ae64cSperseant
2935e1ae64cSperseant /* Run a file system consistency check */
fsck(void)2945e1ae64cSperseant int fsck(void)
2955e1ae64cSperseant {
2965e1ae64cSperseant char s[MAXLINE];
2975e1ae64cSperseant int i, errors = 0;
2985e1ae64cSperseant FILE *pipe;
2995e1ae64cSperseant char cmd[MAXLINE];
3005e1ae64cSperseant
3015e1ae64cSperseant for (i = 0; i < 2; i++) {
3025e1ae64cSperseant sprintf(cmd, "fsck_lfs -n -b %jd -f " IMGNAME,
3035e1ae64cSperseant (intmax_t)sbaddr[i]);
3045e1ae64cSperseant pipe = popen(cmd, "r");
3055e1ae64cSperseant while (fgets(s, MAXLINE, pipe) != NULL) {
3065e1ae64cSperseant if (isdigit((int)s[0])) /* "5 files ... " */
3075e1ae64cSperseant continue;
3085e1ae64cSperseant if (isspace((int)s[0]) || s[0] == '*')
3095e1ae64cSperseant continue;
3105e1ae64cSperseant if (strncmp(s, "Alternate", 9) == 0)
3115e1ae64cSperseant continue;
3125e1ae64cSperseant if (strncmp(s, "ROLL ", 5) == 0)
3135e1ae64cSperseant continue;
3145e1ae64cSperseant fprintf(stderr, "FSCK[sb@%lld]: %s", sbaddr[i], s);
3155e1ae64cSperseant ++errors;
3165e1ae64cSperseant }
3175e1ae64cSperseant pclose(pipe);
3185e1ae64cSperseant if (errors) {
3195e1ae64cSperseant break;
3205e1ae64cSperseant }
3215e1ae64cSperseant }
3225e1ae64cSperseant
3235e1ae64cSperseant return errors;
3245e1ae64cSperseant }
325