From ec64fdb93d144ab1884097cfd36e18b62a2db848 Mon Sep 17 00:00:00 2001 From: youzhongyang Date: Wed, 20 Oct 2021 19:07:19 -0400 Subject: [PATCH] Skip snapshot in zfs_iter_mounted() The intention of the zfs_iter_mounted() is to traverse the dataset and its descendants, not the snapshots. The current code can cause a mounted snapshot to be included and thus zfs_open() on the snapshot with ZFS_TYPE_FILESYSTEM would print confusing message such as "cannot open 'rpool/fs@snap': snapshot delimiter '@' is not expected here". Reviewed-by: Brian Behlendorf Signed-off-by: Youzhong Yang Closes #12447 Closes #12448 --- lib/libzfs/libzfs_iter.c | 7 ++- tests/test-runner/include/logapi.shlib | 50 +++++++++++++++++++ .../zfs_unmount/zfs_unmount_nested.ksh | 8 +-- 3 files changed, 59 insertions(+), 6 deletions(-) diff --git a/lib/libzfs/libzfs_iter.c b/lib/libzfs/libzfs_iter.c index 7806e21cd9a9..3c537be79487 100644 --- a/lib/libzfs/libzfs_iter.c +++ b/lib/libzfs/libzfs_iter.c @@ -575,8 +575,11 @@ zfs_iter_mounted(zfs_handle_t *zhp, zfs_iter_f func, void *data) /* Ignore datasets not within the provided dataset */ if (strncmp(entry.mnt_special, zhp->zfs_name, namelen) != 0 || - (entry.mnt_special[namelen] != '/' && - entry.mnt_special[namelen] != '@')) + entry.mnt_special[namelen] != '/') + continue; + + /* Skip snapshot of any child dataset */ + if (strchr(entry.mnt_special, '@') != NULL) continue; if ((mtab_zhp = zfs_open(zhp->zfs_hdl, entry.mnt_special, diff --git a/tests/test-runner/include/logapi.shlib b/tests/test-runner/include/logapi.shlib index 5a7e76c0ddbf..c9c01ab752ea 100644 --- a/tests/test-runner/include/logapi.shlib +++ b/tests/test-runner/include/logapi.shlib @@ -68,6 +68,16 @@ function log_must (( $? != 0 )) && log_fail } +# Execute a positive test (expecting no stderr) and exit $STF_FAIL +# if test fails +# $@ - command to execute + +function log_must_nostderr +{ + log_pos_nostderr "$@" + (( $? != 0 )) && log_fail +} + # Execute a positive test but retry the command on failure if the output # matches an expected pattern. Otherwise behave like log_must and exit # $STF_FAIL is test fails. @@ -292,6 +302,46 @@ function log_pos return $status } +# Execute and print command with status where success equals zero result +# and no stderr output +# +# $@ command to execute +# +# return 0 if command succeeds and no stderr output +# return 1 othersie + +function log_pos_nostderr +{ + typeset out="" + typeset logfile="/tmp/log.$$" + + while [[ -e $logfile ]]; do + logfile="$logfile.$$" + done + + "$@" 2>$logfile + typeset status=$? + out="cat $logfile" + typeset out_msg=$($out) + + if (( $status != 0 )) ; then + print -u2 $out_msg + _printerror "$@" "exited $status" + else + if [[ ! -z "$out_msg" ]]; then + print -u2 $out_msg + _printerror "$@" "message in stderr" \ + " exited $status" + status=1 + else + [[ -n $LOGAPI_DEBUG ]] && cat $logfile + _printsuccess "$@" + fi + fi + _recursive_output $logfile "false" + return $status +} + # Set an exit handler # # $@ - function(s) to perform on exit diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_nested.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_nested.ksh index 987ecca31396..7da8be3d17eb 100755 --- a/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_nested.ksh +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_nested.ksh @@ -83,7 +83,7 @@ for d in ${test_depths[@]}; do log_must zfs snapshot $TESTPOOL/$ds@snap # force snapshot mount in .zfs log_must ls /$TESTPOOL/$ds/.zfs/snapshot/snap - log_must zfs unmount $TESTPOOL/$ds + log_must_nostderr zfs unmount $TESTPOOL/$ds if ! ismounted $TESTPOOL/$ds_pre; then log_fail "$ds_pre is not mounted" @@ -113,7 +113,7 @@ for d in ${test_depths[@]}; do log_must zfs snapshot $TESTPOOL/$ds@snap # force snapshot mount in .zfs log_must ls /$TESTPOOL/$ds/.zfs/snapshot/snap - log_must zfs unmount $TESTPOOL/$ds + log_must_nostderr zfs unmount $TESTPOOL/$ds if ! ismounted $TESTPOOL/$ds_pre; then log_fail "$TESTPOOL/$ds_pre (pre) not mounted" @@ -143,7 +143,7 @@ for d in ${test_depths[@]}; do log_must zfs snapshot $TESTPOOL/$ds@snap # force snapshot mount in .zfs log_must ls /$TESTPOOL/$ds/.zfs/snapshot/snap - log_must zfs unmount $TESTPOOL/$ds + log_must_nostderr zfs unmount $TESTPOOL/$ds if ! ismounted $TESTPOOL/$ds_pre; then log_fail "$TESTPOOL/$ds_pre (pre) not mounted" @@ -173,7 +173,7 @@ for d in ${test_depths[@]}; do log_must zfs snapshot $TESTPOOL/$ds@snap # force snapshot mount in .zfs log_must ls /$TESTPOOL/$ds/.zfs/snapshot/snap - log_must zfs unmount $TESTPOOL/$ds + log_must_nostderr zfs unmount $TESTPOOL/$ds if ! ismounted $TESTPOOL/$ds_pre; then log_fail "$ds_pre is not mounted"