xref: /freebsd/tools/test/stress2/misc/mapwrite.sh (revision 81b7ebe32edd4be705fe2d50c8d061191ba41573)
1#!/bin/sh
2
3# File corruption scenario
4
5# Test program by Rob Norris <rob norris klarasystems com>
6# Test program obtained from: https://gist.github.com/robn/9804c60cd0275086d26893d73e7af35c
7# https://github.com/openzfs/zfs/issues/15654
8
9[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
10
11. ../default.cfg
12
13set -u
14prog=$(basename "$0" .sh)
15cat > /tmp/$prog.c <<EOF
16/*
17 * Some kind of clone-related crasher. Not sure if legit or just outdated
18 * assertion.
19 *
20 * Creates clone, maps it, writes from map back into itself.
21 *
22 * Compile a recent (2.2+) ZFS with --enable-debug.
23 *
24 * cc -o mapwrite mapwrite.c
25 *
26 * echo 1 > /sys/modules/zfs/parameters/zfs_bclone_enabled
27 * zpool create tank ...
28 * cd /tank
29 * mapwrite
30 *
31 * [    7.666305] VERIFY(arc_released(db->db_buf)) failed
32 * [    7.666443] PANIC at dbuf.c:2150:dbuf_redirty()
33 * [    7.666489] Showing stack for process 608
34 * [    7.666534] CPU: 1 PID: 608 Comm: mapwrite Tainted: P           O      5.10.170 #3
35 * [    7.666610] Call Trace:
36 * [    7.666646]  dump_stack+0x57/0x6e
37 * [    7.666717]  spl_panic+0xd3/0xfb [spl]
38 * [    7.667113]  ? zfs_btree_find+0x16a/0x300 [zfs]
39 * [    7.667278]  ? range_tree_find_impl+0x55/0xa0 [zfs]
40 * [    7.667333]  ? _cond_resched+0x1a/0x50
41 * [    7.667371]  ? __kmalloc_node+0x14a/0x2b0
42 * [    7.667415]  ? spl_kmem_alloc_impl+0xb0/0xd0 [spl]
43 * [    7.667555]  ? __list_add+0x12/0x30 [zfs]
44 * [    7.667681]  spl_assert+0x17/0x20 [zfs]
45 * [    7.667807]  dbuf_redirty+0xad/0xb0 [zfs]
46 * [    7.667963]  dbuf_dirty+0xe76/0x1310 [zfs]
47 * [    7.668011]  ? mutex_lock+0xe/0x30
48 * [    7.668133]  ? dbuf_noread+0x112/0x240 [zfs]
49 * [    7.668271]  dmu_write_uio_dnode+0x101/0x1b0 [zfs]
50 * [    7.668411]  dmu_write_uio_dbuf+0x4a/0x70 [zfs]
51 * [    7.668555]  zfs_write+0x500/0xc80 [zfs]
52 * [    7.668610]  ? page_add_file_rmap+0xe/0xb0
53 * [    7.668740]  zpl_iter_write+0xe4/0x130 [zfs]
54 * [    7.668803]  new_sync_write+0x119/0x1b0
55 * [    7.668843]  vfs_write+0x1ce/0x260
56 * [    7.668880]  __x64_sys_pwrite64+0x91/0xc0
57 * [    7.668918]  do_syscall_64+0x30/0x40
58 * [    7.668957]  entry_SYSCALL_64_after_hwframe+0x61/0xc6
59 */
60
61#define	_GNU_SOURCE
62
63#include <fcntl.h>
64#include <string.h>
65#include <stdio.h>
66#include <stdlib.h>
67#include <unistd.h>
68#include <errno.h>
69#include <sys/stat.h>
70#include <sys/mman.h>
71
72#define	DATASIZE	(1024*1024)
73char data[DATASIZE];
74
75#define NDATA		(512)
76
77#define FILE_NAME	"file"
78#define CLONE_NAME	"clone"
79
80static int
81_create_file(void)
82{
83	memset(data, 0x5a, DATASIZE);
84
85	int fd;
86	if ((fd = open(FILE_NAME, O_RDWR | O_CREAT | O_APPEND,
87	    S_IRUSR | S_IWUSR)) < 0) {
88		perror("open '" FILE_NAME "'");
89		abort();
90	}
91
92	for (int i = 0; i < NDATA; i++) {
93		int nwr = write(fd, data, DATASIZE);
94		if (nwr < 0) {
95			perror("write");
96			abort();
97		}
98		if (nwr < DATASIZE) {
99			fprintf(stderr, "short write\n");
100			abort();
101		}
102	}
103
104	if (lseek(fd, 0, SEEK_SET) < 0) {
105		perror("lseek");
106		abort();
107	}
108
109	sync();
110
111	return (fd);
112}
113
114static int
115_clone_file(int sfd)
116{
117	int dfd;
118	if ((dfd = open(CLONE_NAME, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
119		perror("open '" CLONE_NAME "'");
120		abort();
121	}
122
123	if (copy_file_range(sfd, 0, dfd, 0, DATASIZE * NDATA, 0) < 0) {
124		perror("copy_file_range");
125		abort();
126	}
127
128	return (dfd);
129}
130
131static void *
132_map_file(int fd)
133{
134	void *p = mmap(NULL, DATASIZE*NDATA, PROT_READ, MAP_SHARED, fd, 0);
135	if (p == MAP_FAILED) {
136		perror("mmap");
137		abort();
138	}
139
140	return (p);
141}
142
143static void
144_map_write(void *p, int fd)
145{
146	if (pwrite(fd, p, DATASIZE, 0) < 0) {
147		perror("pwrite");
148		abort();
149	}
150}
151
152int
153main(void)
154{
155	int sfd = _create_file();
156	int dfd = _clone_file(sfd);
157	void *p = _map_file(dfd);
158	_map_write(p, dfd);
159	return (0);
160}
161EOF
162mycc -o /tmp/$prog -Wall -Wextra -O2 /tmp/$prog.c || exit 1
163
164mount | grep -q "on $mntpoint " && umount -f $mntpoint
165mdconfig -l | grep -q md$mdstart && mdconfig -d -u $mdstart
166mdconfig -s 5g -u $mdstart
167
168newfs -n $newfs_flags /dev/md$mdstart > /dev/null
169mount /dev/md$mdstart $mntpoint
170
171mycc -o /tmp/swap -Wall -Wextra -O0 ../tools/swap.c || exit 1
172timeout -k 90 60 /tmp/swap -d 100 &
173for i in `jot 10`; do
174	capacity=`swapinfo | tail -1 | sed 's/.* //; s/%//'`
175	[ $capacity -gt 1 ] && break
176	sleep 2	# Wait for swapping
177done
178
179cd $mntpoint
180/tmp/$prog; s=$?
181pkill swap
182wait
183cmp $mntpoint/file $mntpoint/clone || { echo Fail; s=1; }
184cd -
185
186umount $mntpoint
187mdconfig -d -u $mdstart
188rm /tmp/$prog /tmp/$prog.c
189exit $s
190