From d12614521a307c709778e5f7f91ae6085f63f9e0 Mon Sep 17 00:00:00 2001 From: John Gallagher Date: Wed, 26 Sep 2018 11:08:12 -0700 Subject: Fixes for procfs files backed by linked lists There are some issues with the way the seq_file interface is implemented for kstats backed by linked lists (zfs_dbgmsgs and certain per-pool debugging info): * We don't account for the fact that seq_file sometimes visits a node multiple times, which results in missing messages when read through procfs. * We don't keep separate state for each reader of a file, so concurrent readers will receive incorrect results. * We don't account for the fact that entries may have been removed from the list between read syscalls, so reading from these files in procfs can cause the system to crash. This change fixes these issues and adds procfs_list, a wrapper around a linked list which abstracts away the details of implementing the seq_file interface for a list and exposing the contents of the list through procfs. Reviewed by: Don Brady Reviewed-by: Serapheim Dimitropoulos Reviewed by: Brad Lewis Reviewed-by: Brian Behlendorf Signed-off-by: John Gallagher External-issue: LX-1211 Closes #7819 --- tests/runfiles/linux.run | 9 +- tests/zfs-tests/tests/functional/Makefile.am | 2 +- tests/zfs-tests/tests/functional/kstat/Makefile.am | 5 - tests/zfs-tests/tests/functional/kstat/cleanup.ksh | 28 ---- tests/zfs-tests/tests/functional/kstat/setup.ksh | 34 ----- tests/zfs-tests/tests/functional/kstat/state.ksh | 144 --------------------- .../zfs-tests/tests/functional/procfs/Makefile.am | 8 ++ .../zfs-tests/tests/functional/procfs/cleanup.ksh | 29 +++++ .../tests/functional/procfs/pool_state.ksh | 144 +++++++++++++++++++++ .../tests/functional/procfs/procfs_list_basic.ksh | 95 ++++++++++++++ .../procfs/procfs_list_concurrent_readers.ksh | 82 ++++++++++++ .../functional/procfs/procfs_list_stale_read.ksh | 98 ++++++++++++++ tests/zfs-tests/tests/functional/procfs/setup.ksh | 34 +++++ 13 files changed, 496 insertions(+), 216 deletions(-) delete mode 100644 tests/zfs-tests/tests/functional/kstat/Makefile.am delete mode 100755 tests/zfs-tests/tests/functional/kstat/cleanup.ksh delete mode 100755 tests/zfs-tests/tests/functional/kstat/setup.ksh delete mode 100755 tests/zfs-tests/tests/functional/kstat/state.ksh create mode 100644 tests/zfs-tests/tests/functional/procfs/Makefile.am create mode 100755 tests/zfs-tests/tests/functional/procfs/cleanup.ksh create mode 100755 tests/zfs-tests/tests/functional/procfs/pool_state.ksh create mode 100755 tests/zfs-tests/tests/functional/procfs/procfs_list_basic.ksh create mode 100755 tests/zfs-tests/tests/functional/procfs/procfs_list_concurrent_readers.ksh create mode 100755 tests/zfs-tests/tests/functional/procfs/procfs_list_stale_read.ksh create mode 100755 tests/zfs-tests/tests/functional/procfs/setup.ksh (limited to 'tests') diff --git a/tests/runfiles/linux.run b/tests/runfiles/linux.run index 4b41c3f74..95e70f043 100644 --- a/tests/runfiles/linux.run +++ b/tests/runfiles/linux.run @@ -584,10 +584,6 @@ tests = ['inuse_001_pos', 'inuse_003_pos', 'inuse_004_pos', post = tags = ['functional', 'inuse'] -[tests/functional/kstat] -tests = ['state'] -tags = ['functional', 'kstat'] - [tests/functional/large_files] tests = ['large_files_001_pos', 'large_files_002_pos'] tags = ['functional', 'large_files'] @@ -672,6 +668,11 @@ tags = ['functional', 'poolversion'] tests = ['privilege_001_pos', 'privilege_002_pos'] tags = ['functional', 'privilege'] +[tests/functional/procfs] +tests = ['procfs_list_basic', 'procfs_list_concurrent_readers', + 'procfs_list_stale_read', 'pool_state'] +tags = ['functional', 'procfs'] + [tests/functional/projectquota] tests = ['projectid_001_pos', 'projectid_002_pos', 'projectid_003_pos', 'projectquota_001_pos', 'projectquota_002_pos', 'projectquota_003_pos', diff --git a/tests/zfs-tests/tests/functional/Makefile.am b/tests/zfs-tests/tests/functional/Makefile.am index e0a4aca99..961a34027 100644 --- a/tests/zfs-tests/tests/functional/Makefile.am +++ b/tests/zfs-tests/tests/functional/Makefile.am @@ -29,7 +29,6 @@ SUBDIRS = \ inheritance \ inuse \ io \ - kstat \ large_files \ largest_pool \ libzfs \ @@ -48,6 +47,7 @@ SUBDIRS = \ pool_names \ poolversion \ privilege \ + procfs \ projectquota \ quota \ raidz \ diff --git a/tests/zfs-tests/tests/functional/kstat/Makefile.am b/tests/zfs-tests/tests/functional/kstat/Makefile.am deleted file mode 100644 index 8ad83ec3e..000000000 --- a/tests/zfs-tests/tests/functional/kstat/Makefile.am +++ /dev/null @@ -1,5 +0,0 @@ -pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/kstat -dist_pkgdata_SCRIPTS = \ - setup.ksh \ - cleanup.ksh \ - state.ksh diff --git a/tests/zfs-tests/tests/functional/kstat/cleanup.ksh b/tests/zfs-tests/tests/functional/kstat/cleanup.ksh deleted file mode 100755 index 8a212ce37..000000000 --- a/tests/zfs-tests/tests/functional/kstat/cleanup.ksh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/ksh -p -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (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 (c) 2018 by Lawrence Livermore National Security, LLC. -# - -. $STF_SUITE/include/libtest.shlib - -default_cleanup diff --git a/tests/zfs-tests/tests/functional/kstat/setup.ksh b/tests/zfs-tests/tests/functional/kstat/setup.ksh deleted file mode 100755 index 57717a096..000000000 --- a/tests/zfs-tests/tests/functional/kstat/setup.ksh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/ksh -p -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (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 (c) 2018 by Lawrence Livermore National Security, LLC. -# - -. $STF_SUITE/include/libtest.shlib - -if ! is_linux ; then - log_unsupported "/proc/spl/kstat//health only supported on Linux" -fi - -default_mirror_setup $DISKS - -log_pass diff --git a/tests/zfs-tests/tests/functional/kstat/state.ksh b/tests/zfs-tests/tests/functional/kstat/state.ksh deleted file mode 100755 index 3c29266e5..000000000 --- a/tests/zfs-tests/tests/functional/kstat/state.ksh +++ /dev/null @@ -1,144 +0,0 @@ -#!/bin/ksh -p -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (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 (c) 2018 by Lawrence Livermore National Security, LLC. -# - -# -# DESCRIPTION: -# Test /proc/spl/kstat/zfs//state kstat -# -# STRATEGY: -# 1. Create a mirrored pool -# 2. Check that pool is ONLINE -# 3. Fault one disk -# 4. Check that pool is DEGRADED -# 5. Create a new pool with a single scsi_debug disk -# 6. Remove the disk -# 7. Check that pool is SUSPENDED -# 8. Add the disk back in -# 9. Clear errors and destroy the pools - -. $STF_SUITE/include/libtest.shlib - -verify_runnable "both" - -function cleanup -{ - # Destroy the scsi_debug pool - if [ -n "$TESTPOOL2" ] ; then - if [ -n "$host" ] ; then - # Re-enable the disk - scan_scsi_hosts $host - - # Device may have changed names after being inserted - SDISK=$(get_debug_device) - log_must ln $DEV_RDSKDIR/$SDISK $REALDISK - fi - - # Restore our working pool image - if [ -n "$BACKUP" ] ; then - gunzip -c $BACKUP > $REALDISK - log_must rm -f $BACKUP - fi - - # Our disk is back. Now we can clear errors and destroy the - # pool cleanly. - log_must zpool clear $TESTPOOL2 - - # Now that the disk is back and errors cleared, wait for our - # hung 'zpool scrub' to finish. - wait - - destroy_pool $TESTPOOL2 - log_must rm $REALDISK - unload_scsi_debug - fi -} - -# Check that our pool state values match what's expected -# -# $1: pool name -# $2: expected state ("ONLINE", "DEGRADED", "SUSPENDED", etc) -function check_all -{ - pool=$1 - expected=$2 - - state1=$(zpool status $pool | awk '/state: /{print $2}'); - state2=$(zpool list -H -o health $pool) - state3=$(cat /proc/spl/kstat/zfs/$pool/state) - log_note "Checking $expected = $state1 = $state2 = $state3" - if [[ "$expected" == "$state1" && "$expected" == "$state2" && \ - "$expected" == "$state3" ]] ; then - true - else - false - fi -} - -log_onexit cleanup - -log_assert "Testing /proc/spl/kstat/zfs//state kstat" - -# Test that the initial pool is healthy -check_all $TESTPOOL "ONLINE" - -# Fault one of the disks, and check that pool is degraded -DISK1=$(echo "$DISKS" | awk '{print $2}') -zpool offline -tf $TESTPOOL $DISK1 -check_all $TESTPOOL "DEGRADED" - -# Create a new pool out of a scsi_debug disk -TESTPOOL2=testpool2 -MINVDEVSIZE_MB=$((MINVDEVSIZE / 1048576)) -load_scsi_debug $MINVDEVSIZE_MB 1 1 1 '512b' - -SDISK=$(get_debug_device) -host=$(get_scsi_host $SDISK) - -# Use $REALDISK instead of $SDISK in our pool because $SDISK can change names -# as we remove/add the disk (i.e. /dev/sdf -> /dev/sdg). -REALDISK=/dev/kstat-state-realdisk -log_must [ ! -e $REALDISK ] -ln $DEV_RDSKDIR/$SDISK $REALDISK - -log_must zpool create $TESTPOOL2 $REALDISK - -# Backup the contents of the disk image -BACKUP=$TEST_BASE_DIR/kstat-state-realdisk.gz -log_must [ ! -e $BACKUP ] -gzip -c $REALDISK > $BACKUP - -# Yank out the disk from under the pool -log_must rm $REALDISK -remove_disk $SDISK - -# Run a 'zpool scrub' in the background to suspend the pool. We run it in the -# background since the command will hang when the pool gets suspended. The -# command will resume and exit after we restore the missing disk later on. -zpool scrub $TESTPOOL2 & -sleep 1 # Give the scrub some time to run before we check if it fails - -log_must check_all $TESTPOOL2 "SUSPENDED" - -log_pass "/proc/spl/kstat/zfs//state test successful" diff --git a/tests/zfs-tests/tests/functional/procfs/Makefile.am b/tests/zfs-tests/tests/functional/procfs/Makefile.am new file mode 100644 index 000000000..a7f022d9f --- /dev/null +++ b/tests/zfs-tests/tests/functional/procfs/Makefile.am @@ -0,0 +1,8 @@ +pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/procfs +dist_pkgdata_SCRIPTS = \ + setup.ksh \ + cleanup.ksh \ + procfs_list_basic.ksh \ + procfs_list_concurrent_readers.ksh \ + procfs_list_stale_read.ksh \ + pool_state.ksh diff --git a/tests/zfs-tests/tests/functional/procfs/cleanup.ksh b/tests/zfs-tests/tests/functional/procfs/cleanup.ksh new file mode 100755 index 000000000..8fe46577e --- /dev/null +++ b/tests/zfs-tests/tests/functional/procfs/cleanup.ksh @@ -0,0 +1,29 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 (c) 2018 by Delphix. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib + +default_cleanup diff --git a/tests/zfs-tests/tests/functional/procfs/pool_state.ksh b/tests/zfs-tests/tests/functional/procfs/pool_state.ksh new file mode 100755 index 000000000..3c29266e5 --- /dev/null +++ b/tests/zfs-tests/tests/functional/procfs/pool_state.ksh @@ -0,0 +1,144 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 (c) 2018 by Lawrence Livermore National Security, LLC. +# + +# +# DESCRIPTION: +# Test /proc/spl/kstat/zfs//state kstat +# +# STRATEGY: +# 1. Create a mirrored pool +# 2. Check that pool is ONLINE +# 3. Fault one disk +# 4. Check that pool is DEGRADED +# 5. Create a new pool with a single scsi_debug disk +# 6. Remove the disk +# 7. Check that pool is SUSPENDED +# 8. Add the disk back in +# 9. Clear errors and destroy the pools + +. $STF_SUITE/include/libtest.shlib + +verify_runnable "both" + +function cleanup +{ + # Destroy the scsi_debug pool + if [ -n "$TESTPOOL2" ] ; then + if [ -n "$host" ] ; then + # Re-enable the disk + scan_scsi_hosts $host + + # Device may have changed names after being inserted + SDISK=$(get_debug_device) + log_must ln $DEV_RDSKDIR/$SDISK $REALDISK + fi + + # Restore our working pool image + if [ -n "$BACKUP" ] ; then + gunzip -c $BACKUP > $REALDISK + log_must rm -f $BACKUP + fi + + # Our disk is back. Now we can clear errors and destroy the + # pool cleanly. + log_must zpool clear $TESTPOOL2 + + # Now that the disk is back and errors cleared, wait for our + # hung 'zpool scrub' to finish. + wait + + destroy_pool $TESTPOOL2 + log_must rm $REALDISK + unload_scsi_debug + fi +} + +# Check that our pool state values match what's expected +# +# $1: pool name +# $2: expected state ("ONLINE", "DEGRADED", "SUSPENDED", etc) +function check_all +{ + pool=$1 + expected=$2 + + state1=$(zpool status $pool | awk '/state: /{print $2}'); + state2=$(zpool list -H -o health $pool) + state3=$(cat /proc/spl/kstat/zfs/$pool/state) + log_note "Checking $expected = $state1 = $state2 = $state3" + if [[ "$expected" == "$state1" && "$expected" == "$state2" && \ + "$expected" == "$state3" ]] ; then + true + else + false + fi +} + +log_onexit cleanup + +log_assert "Testing /proc/spl/kstat/zfs//state kstat" + +# Test that the initial pool is healthy +check_all $TESTPOOL "ONLINE" + +# Fault one of the disks, and check that pool is degraded +DISK1=$(echo "$DISKS" | awk '{print $2}') +zpool offline -tf $TESTPOOL $DISK1 +check_all $TESTPOOL "DEGRADED" + +# Create a new pool out of a scsi_debug disk +TESTPOOL2=testpool2 +MINVDEVSIZE_MB=$((MINVDEVSIZE / 1048576)) +load_scsi_debug $MINVDEVSIZE_MB 1 1 1 '512b' + +SDISK=$(get_debug_device) +host=$(get_scsi_host $SDISK) + +# Use $REALDISK instead of $SDISK in our pool because $SDISK can change names +# as we remove/add the disk (i.e. /dev/sdf -> /dev/sdg). +REALDISK=/dev/kstat-state-realdisk +log_must [ ! -e $REALDISK ] +ln $DEV_RDSKDIR/$SDISK $REALDISK + +log_must zpool create $TESTPOOL2 $REALDISK + +# Backup the contents of the disk image +BACKUP=$TEST_BASE_DIR/kstat-state-realdisk.gz +log_must [ ! -e $BACKUP ] +gzip -c $REALDISK > $BACKUP + +# Yank out the disk from under the pool +log_must rm $REALDISK +remove_disk $SDISK + +# Run a 'zpool scrub' in the background to suspend the pool. We run it in the +# background since the command will hang when the pool gets suspended. The +# command will resume and exit after we restore the missing disk later on. +zpool scrub $TESTPOOL2 & +sleep 1 # Give the scrub some time to run before we check if it fails + +log_must check_all $TESTPOOL2 "SUSPENDED" + +log_pass "/proc/spl/kstat/zfs//state test successful" diff --git a/tests/zfs-tests/tests/functional/procfs/procfs_list_basic.ksh b/tests/zfs-tests/tests/functional/procfs/procfs_list_basic.ksh new file mode 100755 index 000000000..c9eff3649 --- /dev/null +++ b/tests/zfs-tests/tests/functional/procfs/procfs_list_basic.ksh @@ -0,0 +1,95 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 (c) 2018 by Delphix. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION: +# Test that we can read from and write to a file in procfs whose contents is +# backed by a linked list. +# +# STRATEGY: +# 1. Take some snapshots of a filesystem, which will cause some messages to be +# written to the zfs dbgmsgs. +# 2. Read the dbgmsgs via procfs and verify that the expected messages are +# present. +# 3. Write to the dbgmsgs file to clear the messages. +# 4. Read the dbgmsgs again, and make sure the messages are no longer present. +# + +function cleanup +{ + datasetexists $FS && log_must zfs destroy -r $FS +} + +function count_snap_cmds +{ + typeset expected_count=$1 + count=$(grep "command: zfs snapshot $FS@testsnapshot" | wc -l) + log_must eval "[[ $count -eq $expected_count ]]" +} + +typeset -r ZFS_DBGMSG=/proc/spl/kstat/zfs/dbgmsg +typeset -r FS=$TESTPOOL/fs +typeset snap_msgs + +log_onexit cleanup + +# Clear out old messages +echo 0 >$ZFS_DBGMSG || log_fail "failed to write to $ZFS_DBGMSG" + +log_must zfs create $FS +for i in {1..20}; do + log_must zfs snapshot "$FS@testsnapshot$i" +done +log_must zpool sync $TESTPOOL + +# +# Read the debug message file in small chunks to make sure that the read is +# split up into multiple syscalls. This tests that when a syscall begins we +# correctly pick up in the list of messages where the previous syscall left +# off. The size of the read can affect how many bytes the seq_file code has +# left in its internal buffer, which in turn can affect the relative pos that +# the seq_file code picks up at when the next read starts. Try a few +# different size reads to make sure we can handle each case. +# +# Check that the file has the right contents by grepping for some of the +# messages that we expect to be present. +# +for chunk_sz in {1,64,256,1024,4096}; do + dd if=$ZFS_DBGMSG bs=$chunk_sz | count_snap_cmds 20 +done + +# Clear out old messages and check that they really are gone +echo 0 >$ZFS_DBGMSG || log_fail "failed to write to $ZFS_DBGMSG" +cat $ZFS_DBGMSG | count_snap_cmds 0 +# +# Even though we don't expect any messages in the file, reading should still +# succeed. +# +log_must cat $ZFS_DBGMSG + +log_pass "Basic reading/writing of procfs file backed by linked list successful" diff --git a/tests/zfs-tests/tests/functional/procfs/procfs_list_concurrent_readers.ksh b/tests/zfs-tests/tests/functional/procfs/procfs_list_concurrent_readers.ksh new file mode 100755 index 000000000..473de5c84 --- /dev/null +++ b/tests/zfs-tests/tests/functional/procfs/procfs_list_concurrent_readers.ksh @@ -0,0 +1,82 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 (c) 2018 by Delphix. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION: +# Make sure that interleaving reads from different readers does not affect the +# results that are returned. +# +# STRATEGY: +# 1. Make sure a few debug messages have been logged. +# 2. Open the procfs file and start reading from it. +# 3. Open the file again, and read its entire contents. +# 4. Resume reading from the first instance. +# 5. Check that the contents read by the two instances are identical. +# + +function cleanup +{ + [[ -z $msgs1 ]] || log_must rm $msgs1 + [[ -z $msgs2 ]] || log_must rm $msgs2 + datasetexists $FS && log_must zfs destroy -r $FS +} + +typeset -r ZFS_DBGMSG=/proc/spl/kstat/zfs/dbgmsg +typeset -r FS=$TESTPOOL/fs +typeset msgs1 msgs2 + +log_onexit cleanup + +# Clear out old messages +echo 0 >$ZFS_DBGMSG || log_fail "failed to write to $ZFS_DBGMSG" + +# Add some new messages +log_must zfs create $FS +for i in {1..20}; do + log_must zfs snapshot "$FS@testsnapshot$i" +done +log_must zpool sync $TESTPOOL + +msgs1=$(mktemp) || log_fail +msgs2=$(mktemp) || log_fail + +# +# Start reading file, pause and read it from another process, and then finish +# reading. +# +{ dd bs=512 count=4; cat $ZFS_DBGMSG >$msgs1; cat; } <$ZFS_DBGMSG >$msgs2 + +# +# Truncate the result of the read that completed second in case it picked up an +# extra message that was logged after the first read completed. +# +log_must truncate -s $(stat -c "%s" $msgs1) $msgs2 + +log_must diff $msgs1 $msgs2 + +log_pass "Concurrent readers receive identical results" diff --git a/tests/zfs-tests/tests/functional/procfs/procfs_list_stale_read.ksh b/tests/zfs-tests/tests/functional/procfs/procfs_list_stale_read.ksh new file mode 100755 index 000000000..c363e7f8b --- /dev/null +++ b/tests/zfs-tests/tests/functional/procfs/procfs_list_stale_read.ksh @@ -0,0 +1,98 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 (c) 2018 by Delphix. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION: +# Make sure errors caused by messages being dropped from the list backing the +# procfs file are handled gracefully. +# +# STRATEGY: +# 1. Make sure a few entries have been logged. +# 2. Open the procfs file and start reading from it. +# 3. Write to the file to cause its contents to be dropped. +# 4. Resume reading from the first instance, and check that the expected +# error is received. +# 5. Repeat steps 1-4, except instead of dropping all the messages by writing +# to the file, cause enough new messages to be written that the old messages +# are dropped. +# + +function cleanup +{ + echo $default_max_entries >$MAX_ENTRIES_PARAM || log_fail +} + +function sync_n +{ + for i in {1..$1}; do + log_must zpool sync $TESTPOOL + done + return 0 +} + +function do_test +{ + typeset cmd=$1 + + # Clear out old entries + echo 0 >$TXG_HIST || log_fail + + # Add some new entries + sync_n 20 + + # Confirm that there actually is something in the file. + [[ $(wc -l <$TXG_HIST) -ge 20 ]] || log_fail "expected more entries" + + # + # Start reading file, pause and run a command that will cause the + # current offset into the file to become invalid, and then try to + # finish reading. + # + { + log_must dd bs=512 count=4 >/dev/null + log_must eval "$cmd" + cat 2>&1 >/dev/null | log_must grep "Input/output error" + } <$TXG_HIST +} + +typeset -r TXG_HIST=/proc/spl/kstat/zfs/$TESTPOOL/txgs +typeset MAX_ENTRIES_PARAM=/sys/module/zfs/parameters/zfs_txg_history +typeset default_max_entries + +log_onexit cleanup + +default_max_entries=$(cat $MAX_ENTRIES_PARAM) || log_fail +echo 50 >$MAX_ENTRIES_PARAM || log_fail + +# Clear all of the existing entries. +do_test "echo 0 >$TXG_HIST" + +# Add enough new entries to the list that all of the old ones are dropped. +do_test "sync_n 60" + +log_pass "Attempting to read dropped message returns expected error" diff --git a/tests/zfs-tests/tests/functional/procfs/setup.ksh b/tests/zfs-tests/tests/functional/procfs/setup.ksh new file mode 100755 index 000000000..b3812dbdc --- /dev/null +++ b/tests/zfs-tests/tests/functional/procfs/setup.ksh @@ -0,0 +1,34 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 (c) 2018 by Delphix. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib + +if ! is_linux ; then + log_unsupported "procfs is only used on Linux" +fi + +default_mirror_setup $DISKS +log_pass -- cgit v1.2.3