1c5832a5Alek Pinchuk#!/bin/ksh -p
2c5832a5Alek Pinchuk
3c5832a5Alek Pinchuk#
4c5832a5Alek Pinchuk# This file and its contents are supplied under the terms of the
5c5832a5Alek Pinchuk# Common Development and Distribution License ("CDDL"), version 1.0.
6c5832a5Alek Pinchuk# You may only use this file in accordance with the terms of version
7c5832a5Alek Pinchuk# 1.0 of the CDDL.
8c5832a5Alek Pinchuk#
9c5832a5Alek Pinchuk# A full copy of the text of the CDDL should have accompanied this
10c5832a5Alek Pinchuk# source.  A copy of the CDDL is also available via the Internet at
11c5832a5Alek Pinchuk# http://www.illumos.org/license/CDDL.
12c5832a5Alek Pinchuk#
13c5832a5Alek Pinchuk
14c5832a5Alek Pinchuk#
15c5832a5Alek Pinchuk# Copyright 2018 Datto Inc.
16c5832a5Alek Pinchuk#
17c5832a5Alek Pinchuk
18c5832a5Alek Pinchuk. $STF_SUITE/include/libtest.shlib
19c5832a5Alek Pinchuk
20c5832a5Alek Pinchuk#
21c5832a5Alek Pinchuk# DESCRIPTION:
22c5832a5Alek Pinchuk# Test async unlinked drain to ensure mounting is not held up when there are
23c5832a5Alek Pinchuk# entries in the unlinked set. We also try to test that the list is able to be
24c5832a5Alek Pinchuk# filled up and drained at the same time.
25c5832a5Alek Pinchuk#
26c5832a5Alek Pinchuk# STRATEGY:
27c5832a5Alek Pinchuk# 1. Use zfs_unlink_suspend_progress tunable to disable freeing to build up
28c5832a5Alek Pinchuk#    the unlinked set
29c5832a5Alek Pinchuk# 2. Make sure mount happens even when there are entries in the unlinked set
30c5832a5Alek Pinchuk# 3. Drain and build up the unlinked list at the same time to test for races
31c5832a5Alek Pinchuk#
32c5832a5Alek Pinchuk
33c5832a5Alek Pinchukfunction cleanup
34c5832a5Alek Pinchuk{
35c5832a5Alek Pinchuk	log_must set_tunable32 zfs_unlink_suspend_progress $default_unlink_sp
36c5832a5Alek Pinchuk	for fs in $(seq 1 3); do
37c5832a5Alek Pinchuk		mounted $TESTDIR.$fs || zfs mount $TESTPOOL/$TESTFS.$fs
38c5832a5Alek Pinchuk		rm -f $TESTDIR.$fs/file-*
39c5832a5Alek Pinchuk		zfs set xattr=on $TESTPOOL/$TESTFS.$fs
40c5832a5Alek Pinchuk	done
41c5832a5Alek Pinchuk}
42c5832a5Alek Pinchuk
43c5832a5Alek Pinchukfunction unlinked_size_is
44c5832a5Alek Pinchuk{
45c5832a5Alek Pinchuk	MAX_ITERS=5 # iteration to do before we consider reported number stable
46c5832a5Alek Pinchuk	iters=0
47c5832a5Alek Pinchuk	last_usize=0
48c5832a5Alek Pinchuk	while [[ $iters -le $MAX_ITERS ]]; do
49c5832a5Alek Pinchuk		kstat_file=$(grep -nrwl /proc/spl/kstat/zfs/$2/objset-0x* -e $3)
50c5832a5Alek Pinchuk		nunlinks=`cat $kstat_file | grep nunlinks | awk '{print $3}'`
51c5832a5Alek Pinchuk		nunlinked=`cat $kstat_file | grep nunlinked | awk '{print $3}'`
52c5832a5Alek Pinchuk		usize=$(($nunlinks - $nunlinked))
53c5832a5Alek Pinchuk		if [[ $iters == $MAX_ITERS && $usize == $1 ]]; then
54c5832a5Alek Pinchuk			return 0
55c5832a5Alek Pinchuk		fi
56c5832a5Alek Pinchuk		if [[ $usize == $last_usize ]]; then
57c5832a5Alek Pinchuk			(( iters++ ))
58c5832a5Alek Pinchuk		else
59c5832a5Alek Pinchuk			iters=0
60c5832a5Alek Pinchuk		fi
61c5832a5Alek Pinchuk		last_usize=$usize
62c5832a5Alek Pinchuk	done
63c5832a5Alek Pinchuk
64c5832a5Alek Pinchuk	log_note "Unexpected unlinked set size: $last_usize, expected $1"
65c5832a5Alek Pinchuk	return 1
66c5832a5Alek Pinchuk}
67c5832a5Alek Pinchuk
68c5832a5Alek Pinchuk
69c5832a5Alek PinchukUNLINK_SP_PARAM=/sys/module/zfs/parameters/zfs_unlink_suspend_progress
70c5832a5Alek Pinchukdefault_unlink_sp=$(get_tunable zfs_unlink_suspend_progress)
71c5832a5Alek Pinchuk
72c5832a5Alek Pinchuklog_onexit cleanup
73c5832a5Alek Pinchuk
74c5832a5Alek Pinchuklog_assert "Unlinked list drain does not hold up mounting of fs"
75c5832a5Alek Pinchuk
76c5832a5Alek Pinchukfor fs in 1 2 3; do
77c5832a5Alek Pinchuk	set -A xattrs on sa off
78c5832a5Alek Pinchuk	for xa in ${xattrs[@]}; do
79c5832a5Alek Pinchuk		# setup fs and ensure all deleted files got into unliked set
80c5832a5Alek Pinchuk		log_must mounted $TESTDIR.$fs
81c5832a5Alek Pinchuk
82c5832a5Alek Pinchuk		log_must zfs set xattr=$xa $TESTPOOL/$TESTFS.$fs
83c5832a5Alek Pinchuk
84c5832a5Alek Pinchuk		if [[ $xa == off ]]; then
85c5832a5Alek Pinchuk			for fn in $(seq 1 175); do
86c5832a5Alek Pinchuk				log_must mkfile 128k $TESTDIR.$fs/file-$fn
87c5832a5Alek Pinchuk			done
88c5832a5Alek Pinchuk		else
89c5832a5Alek Pinchuk			log_must xattrtest -f 175 -x 3 -r -k -p $TESTDIR.$fs
90c5832a5Alek Pinchuk		fi
91c5832a5Alek Pinchuk
92c5832a5Alek Pinchuk		log_must set_tunable32 zfs_unlink_suspend_progress 1
93c5832a5Alek Pinchuk		log_must unlinked_size_is 0 $TESTPOOL $TESTPOOL/$TESTFS.$fs
94c5832a5Alek Pinchuk
95c5832a5Alek Pinchuk		# build up unlinked set
96c5832a5Alek Pinchuk		for fn in $(seq 1 100); do
97c5832a5Alek Pinchuk			log_must eval "rm $TESTDIR.$fs/file-$fn &"
98c5832a5Alek Pinchuk		done
99c5832a5Alek Pinchuk		log_must unlinked_size_is 100 $TESTPOOL $TESTPOOL/$TESTFS.$fs
100c5832a5Alek Pinchuk
101c5832a5Alek Pinchuk		# test that we can mount fs without emptying the unlinked list
102c5832a5Alek Pinchuk		log_must zfs umount $TESTPOOL/$TESTFS.$fs
103c5832a5Alek Pinchuk		log_must unmounted $TESTDIR.$fs
104c5832a5Alek Pinchuk		log_must zfs mount $TESTPOOL/$TESTFS.$fs
105c5832a5Alek Pinchuk		log_must mounted $TESTDIR.$fs
106c5832a5Alek Pinchuk		log_must unlinked_size_is 100 $TESTPOOL $TESTPOOL/$TESTFS.$fs
107c5832a5Alek Pinchuk
108c5832a5Alek Pinchuk		# confirm we can drain and add to unlinked set at the same time
109c5832a5Alek Pinchuk		log_must set_tunable32 zfs_unlink_suspend_progress 0
110c5832a5Alek Pinchuk		log_must zfs umount $TESTPOOL/$TESTFS.$fs
111c5832a5Alek Pinchuk		log_must zfs mount $TESTPOOL/$TESTFS.$fs
112c5832a5Alek Pinchuk		for fn in $(seq 101 175); do
113c5832a5Alek Pinchuk			log_must eval "rm $TESTDIR.$fs/file-$fn &"
114c5832a5Alek Pinchuk		done
115c5832a5Alek Pinchuk		log_must unlinked_size_is 0 $TESTPOOL $TESTPOOL/$TESTFS.$fs
116c5832a5Alek Pinchuk	done
117c5832a5Alek Pinchukdone
118c5832a5Alek Pinchuk
119c5832a5Alek Pinchuklog_pass "Confirmed unlinked list drain does not hold up mounting of fs"