xref: /netbsd-src/tests/fs/lfs/t_rfw.c (revision 284084a72cd0118cb341e431179c86206c9c3db9)
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