diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 6869aa67c..26f9207e4 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -7,6 +7,7 @@ dist_pkgdata_SCRIPTS = \ $(top_builddir)/scripts/common.sh \ $(top_srcdir)/scripts/zconfig.sh \ $(top_srcdir)/scripts/zfault.sh \ + $(top_srcdir)/scripts/ziltest.sh \ $(top_srcdir)/scripts/zimport.sh \ $(top_srcdir)/scripts/zfs.sh \ $(top_srcdir)/scripts/zpool-create.sh \ diff --git a/scripts/ziltest.sh b/scripts/ziltest.sh new file mode 100755 index 000000000..dafeb5751 --- /dev/null +++ b/scripts/ziltest.sh @@ -0,0 +1,301 @@ +#!/bin/bash +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# Linux version +# +# To run just type ziltest.sh +# +# - creates a 200MB pool in /var/tmp/ +# - prints information on: +# working set files +# ZIL records written +# ZIL block usage +# verification results +# - returns status of 0 on success +# +########################################################################## +# +# Here's how it all works: +# +# The general idea is to build up +# an intent log from a bunch of diverse user commands +# without actually committing them to the file system. +# Then copy the file system, replay the intent +# log and compare the file system and the copy. +# +# To enable this automated testing of the intent log +# requires some but minimal support from the file system. +# In particular, a "freeze" command is required to flush +# the in-flight transactions; to stop the actual +# committing of transactions; and to ensure no deltas are +# discarded. All deltas past a freeze point are kept for +# replay and comparison later. Here is the flow: +# +# create an empty file system (FS) +# freeze FS +# run various user commands that create files, directories and ACLs +# copy FS to temporary location (COPY) +# unmount filesystem +# +# remount FS +# compare FS against the COPY +# + +PATH=/usr/bin +PATH=$PATH:/usr/sbin +PATH=$PATH:/bin +PATH=$PATH:/sbin +export PATH + +# ==================================================================== +# SETUP +# ==================================================================== +CMD=$(basename "$0") +POOL=ziltestpool.$$ +DEVSIZE=${DEVSIZE-200m} +POOLDIR=/var/tmp +POOLFILE=$POOLDIR/ziltest_poolfile.$$ +SLOGFILE=$POOLDIR/ziltest_slog.$$ +FS=$POOL/fs +ROOT=/$FS +COPY=/var/tmp/${POOL} +KEEP=no + +cleanup() +{ + zfs destroy -rf $FS + echo "$CMD: pool I/O summary & status:" + echo "----------------------------------------------------" + zpool iostat $POOL + echo + zpool status $POOL + echo "----------------------------------------------------" + echo + zpool destroy -f $POOL + rm -rf $COPY + rm $POOLFILE $SLOGFILE +} + +bail() +{ + test $KEEP = no && cleanup + echo "$1" + exit 1 +} + +test $# -eq 0 || bail "usage: $CMD" + +# ==================================================================== +# PREP +# +# Create a pool using a file based vdev +# Create a destination for runtime copy of FS +# Freeze transaction syncing in the pool +# ==================================================================== +fallocate -l "$DEVSIZE" $POOLFILE || bail "can't make $POOLFILE" +fallocate -l "$DEVSIZE" $SLOGFILE || bail "can't make $SLOGFILE" +zpool create $POOL $POOLFILE log $SLOGFILE || bail "can't create pool +$POOL" +zpool list $POOL + +zfs set compression=on $POOL || bail "can't enable compression on $POOL" +zfs create $FS || bail "can't create $FS" +mkdir -p $COPY || bail "can't create $COPY" + +# +# This dd command works around an issue where ZIL records aren't created +# after freezing the pool unless a ZIL header already exists. Create a file +# synchronously to force ZFS to write one out. +# +dd if=/dev/zero of=$ROOT/sync conv=fdatasync,fsync bs=1 count=1 2> /dev/null + +zpool freeze $POOL || bail "can't freeze $POOL" + +# ==================================================================== +# TESTS +# +# Add operations here that will add commit records to the ZIL +# +# Use $ROOT for all file name prefixes +# ==================================================================== + +# +# TX_CREATE +# +touch $ROOT/a + +# +# TX_RENAME +# +mv $ROOT/a $ROOT/b + +# +# TX_SYMLINK +# +touch $ROOT/c +ln -s $ROOT/c $ROOT/d + +# +# TX_LINK +# +touch $ROOT/e +ln $ROOT/e $ROOT/f + +# +# TX_MKDIR +# +mkdir $ROOT/dir_to_delete + +# +# TX_RMDIR +# +rmdir $ROOT/dir_to_delete + +# +# Create a simple validation payload +# +PAYLOAD=$(modinfo -F filename zfs) +cp "$PAYLOAD" "$ROOT/payload" +CHECKSUM_BEFORE=$(sha256sum -b "$PAYLOAD") + +# +# TX_WRITE (small file with ordering) +# +cp /etc/mtab $ROOT/small_file +cp /etc/profile $ROOT/small_file + +# +# TX_CREATE, TX_MKDIR, TX_REMOVE, TX_RMDIR +# +cp -R /usr/share/dict $ROOT +rm -rf $ROOT/dict + +# +# TX_SETATTR +# +touch $ROOT/setattr +chmod 567 $ROOT/setattr +chgrp root $ROOT/setattr +touch -cm -t 201311271200 $ROOT/setattr + +# +# TX_TRUNCATE (to zero) +# +cp /etc/services $ROOT/truncated_file +> $ROOT/truncated_file + +# +# Write to an open but removed file +# +(sleep 2; date) > $ROOT/date & sleep 1; rm $ROOT/date; wait + +# +# TX_WRITE (large file) +# +dd if=/usr/share/lib/termcap of=$ROOT/large bs=128k oflag=sync 2> /dev/null + +# +# Write zeroes, which compresss to holes, in the middle of a file +# +dd if=$POOLFILE of=$ROOT/holes.1 bs=128k count=8 2> /dev/null +dd if=/dev/zero of=$ROOT/holes.1 bs=128k count=2 2> /dev/null + +dd if=$POOLFILE of=$ROOT/holes.2 bs=128k count=8 2> /dev/null +dd if=/dev/zero of=$ROOT/holes.2 bs=128k count=2 oseek=2 2> /dev/null + +dd if=$POOLFILE of=$ROOT/holes.3 bs=128k count=8 2> /dev/null +dd if=/dev/zero of=$ROOT/holes.3 bs=128k count=2 oseek=2 conv=notrunc 2> /dev/null + +# +# TX_MKXATTR +# +mkdir $ROOT/xattr.dir +attr -qs fileattr -V HelloWorld $ROOT/xattr.dir +attr -qs tmpattr -V HelloWorld $ROOT/xattr.dir +attr -qr tmpattr $ROOT/xattr.dir + +touch $ROOT/xattr.file +attr -qs fileattr -V HelloWorld $ROOT/xattr.file +attr -qs tmpattr -V HelloWorld $ROOT/xattr.file +attr -qr tmpattr $ROOT/xattr.file +rm $ROOT/xattr.file + + +# ==================================================================== +# REPLAY +# ==================================================================== + +KEEP=yes # keep stuff around if we fail, so we can look at it + +cd $ROOT +find . | cpio -pdmu --quiet $COPY +echo +cd / + +zfs unmount $FS || bail "can't unmount $FS" + +echo "$CMD: transactions to replay:" +echo "----------------------------------------------------" +zdb -ivv $FS || bail "can't run zdb on $POOL" +echo "----------------------------------------------------" +echo + +# +# Export and reimport the pool to unfreeze it and claim log blocks. +# It has to be import -f because we can't write a frozen pool's labels! +# +zpool export $POOL || bail "can't export $POOL" +zpool import -f -d $POOLDIR $POOL || bail "can't import $POOL" + +# ==================================================================== +# VERIFY +# ==================================================================== + +echo "$CMD: current block usage:" +echo "----------------------------------------------------" +zdb -bcv $POOL || bail "blocks were leaked!" +echo "----------------------------------------------------" +echo + +echo "$CMD: Copy of xattrs:" +echo "----------------------------------------------------" +attr -l $ROOT/xattr.dir || bail "can't list xattrs" +echo "----------------------------------------------------" +echo + +echo "$CMD: Results of workingset diff:" +echo "----------------------------------------------------" +diff -r $ROOT $COPY > /dev/null || diff -r $ROOT $COPY || bail "replay diffs!" + +echo "$CHECKSUM_BEFORE" | sha256sum -c || bail "payload checksums don't match" +echo "payload checksum matched" +echo "----------------------------------------------------" +echo + +cleanup + +exit 0