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