1#!/bin/ksh
2
3#
4# This file and its contents are supplied under the terms of the
5# Common Development and Distribution License ("CDDL"), version 1.0.
6# You may only use this file in accordance with the terms of version
7# 1.0 of the CDDL.
8#
9# A full copy of the text of the CDDL should have accompanied this
10# source.  A copy of the CDDL is also available via the Internet at
11# http://www.illumos.org/license/CDDL.
12#
13
14#
15# Copyright (c) 2019 by Tomohiro Kusumi. All rights reserved.
16#
17
18. $STF_SUITE/include/libtest.shlib
19. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.cfg
20
21#
22# DESCRIPTION:
23# Verify parallel mount ordering is consistent.
24#
25# There was a bug in initial thread dispatching algorithm which put threads
26# under race condition which resulted in undefined mount order.  The purpose
27# of this test is to verify `zfs unmount -a` succeeds (not `zfs mount -a`
28# succeeds, it always does) after `zfs mount -a`, which could fail if threads
29# race.  See github.com/openzfs/zfs/issues/{8450,8833,8878} for details.
30#
31# STRATEGY:
32# 1. Create pools and filesystems.
33# 2. Set same mount point for >1 datasets.
34# 3. Unmount all datasets.
35# 4. Mount all datasets.
36# 5. Unmount all datasets (verify this succeeds).
37#
38
39verify_runnable "both"
40
41TMPDIR=${TMPDIR:-$TEST_BASE_DIR}
42MNTPT=$TMPDIR/zfs_mount_test_race_mntpt
43DISK1="$TMPDIR/zfs_mount_test_race_disk1"
44DISK2="$TMPDIR/zfs_mount_test_race_disk2"
45
46TESTPOOL1=zfs_mount_test_race_tp1
47TESTPOOL2=zfs_mount_test_race_tp2
48
49export __ZFS_POOL_RESTRICT="$TESTPOOL1 $TESTPOOL2"
50log_must zfs $unmountall
51unset __ZFS_POOL_RESTRICT
52
53function cleanup
54{
55	zpool destroy $TESTPOOL1
56	zpool destroy $TESTPOOL2
57	rm -rf $MNTPT
58	rm -rf /$TESTPOOL1
59	rm -rf /$TESTPOOL2
60	rm -f $DISK1
61	rm -f $DISK2
62	export __ZFS_POOL_RESTRICT="$TESTPOOL1 $TESTPOOL2"
63	log_must zfs $mountall
64	unset __ZFS_POOL_RESTRICT
65}
66log_onexit cleanup
67
68log_note "Verify parallel mount ordering is consistent"
69
70log_must truncate -s $MINVDEVSIZE $DISK1
71log_must truncate -s $MINVDEVSIZE $DISK2
72
73log_must zpool create -f $TESTPOOL1 $DISK1
74log_must zpool create -f $TESTPOOL2 $DISK2
75
76log_must zfs create $TESTPOOL1/$TESTFS1
77log_must zfs create $TESTPOOL2/$TESTFS2
78
79log_must zfs set mountpoint=none $TESTPOOL1
80log_must zfs set mountpoint=$MNTPT $TESTPOOL1/$TESTFS1
81
82# Note that unmount can fail (due to race condition on `zfs mount -a`) with or
83# without `canmount=off`.  The race has nothing to do with canmount property,
84# but turn it off for convenience of mount layout used in this test case.
85log_must zfs set canmount=off $TESTPOOL2
86log_must zfs set mountpoint=$MNTPT $TESTPOOL2
87
88# At this point, layout of datasets in two pools will look like below.
89# Previously, on next `zfs mount -a`, pthreads assigned to TESTFS1 and TESTFS2
90# could race, and TESTFS2 usually (actually always) won in OpenZFS.
91# Note that the problem is how two or more threads could initially be assigned
92# to the same top level directory, not this specific layout.
93# This layout is just an example that can reproduce race,
94# and is also the layout reported in #8833.
95#
96# NAME                  MOUNTED  MOUNTPOINT
97# ----------------------------------------------
98# /$TESTPOOL1           no       none
99# /$TESTPOOL1/$TESTFS1  yes      $MNTPT
100# /$TESTPOOL2           no       $MNTPT
101# /$TESTPOOL2/$TESTFS2  yes      $MNTPT/$TESTFS2
102
103# Apparently two datasets must be mounted.
104log_must ismounted $TESTPOOL1/$TESTFS1
105log_must ismounted $TESTPOOL2/$TESTFS2
106# This unmount always succeeds, because potential race hasn't happened yet.
107log_must zfs unmount -a
108# This mount always succeeds, whether threads are under race condition or not.
109log_must zfs mount -a
110
111# Verify datasets are mounted (TESTFS2 fails if the race broke mount order).
112log_must ismounted $TESTPOOL1/$TESTFS1
113log_must ismounted $TESTPOOL2/$TESTFS2
114# Verify unmount succeeds (fails if the race broke mount order).
115log_must zfs unmount -a
116
117log_pass "Verify parallel mount ordering is consistent passed"
118