1#!/bin/ksh -p
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 2018 Datto Inc.
16#
17
18. $STF_SUITE/include/libtest.shlib
19
20#
21# DESCRIPTION:
22# Test async unlinked drain to ensure mounting is not held up when there are
23# entries in the unlinked set. We also try to test that the list is able to be
24# filled up and drained at the same time.
25#
26# STRATEGY:
27# 1. Use zfs_unlink_suspend_progress tunable to disable freeing to build up
28#    the unlinked set
29# 2. Make sure mount happens even when there are entries in the unlinked set
30# 3. Drain and build up the unlinked list at the same time to test for races
31#
32
33function cleanup
34{
35	log_must set_tunable32 UNLINK_SUSPEND_PROGRESS $default_unlink_sp
36	for fs in $(seq 1 3); do
37		mounted $TESTDIR.$fs || zfs mount $TESTPOOL/$TESTFS.$fs
38		rm -f $TESTDIR.$fs/file-*
39		zfs set xattr=on $TESTPOOL/$TESTFS.$fs
40	done
41}
42
43function unlinked_size_is
44{
45	MAX_ITERS=5 # iteration to do before we consider reported number stable
46	iters=0
47	last_usize=0
48	while [[ $iters -le $MAX_ITERS ]]; do
49		kstat_file=$(grep -nrwl /proc/spl/kstat/zfs/$2/objset-0x* -e $3)
50		nunlinks=$(awk '/nunlinks/ {print $3}' $kstat_file)
51		nunlinked=$(awk '/nunlinked/ {print $3}' $kstat_file)
52		usize=$(($nunlinks - $nunlinked))
53		if [[ $iters == $MAX_ITERS && $usize == $1 ]]; then
54			return 0
55		fi
56		if [[ $usize == $last_usize ]]; then
57			(( iters++ ))
58		else
59			iters=0
60		fi
61		last_usize=$usize
62	done
63
64	log_note "Unexpected unlinked set size: $last_usize, expected $1"
65	return 1
66}
67
68
69default_unlink_sp=$(get_tunable UNLINK_SUSPEND_PROGRESS)
70
71log_onexit cleanup
72
73log_assert "Unlinked list drain does not hold up mounting of fs"
74
75for fs in 1 2 3; do
76	set -A xattrs on sa off
77	for xa in ${xattrs[@]}; do
78		# setup fs and ensure all deleted files got into unliked set
79		log_must mounted $TESTDIR.$fs
80
81		log_must zfs set xattr=$xa $TESTPOOL/$TESTFS.$fs
82
83		if [[ $xa == off ]]; then
84			for fn in $(seq 1 175); do
85				log_must mkfile 128k $TESTDIR.$fs/file-$fn
86			done
87		else
88			log_must xattrtest -f 175 -x 3 -r -k -p $TESTDIR.$fs
89		fi
90
91		log_must set_tunable32 UNLINK_SUSPEND_PROGRESS 1
92		log_must unlinked_size_is 0 $TESTPOOL $TESTPOOL/$TESTFS.$fs
93
94		# build up unlinked set
95		for fn in $(seq 1 100); do
96			log_must eval "rm $TESTDIR.$fs/file-$fn &"
97		done
98		log_must unlinked_size_is 100 $TESTPOOL $TESTPOOL/$TESTFS.$fs
99
100		# test that we can mount fs without emptying the unlinked list
101		log_must zfs umount $TESTPOOL/$TESTFS.$fs
102		log_must unmounted $TESTDIR.$fs
103		log_must zfs mount $TESTPOOL/$TESTFS.$fs
104		log_must mounted $TESTDIR.$fs
105		log_must unlinked_size_is 100 $TESTPOOL $TESTPOOL/$TESTFS.$fs
106
107		# confirm we can drain and add to unlinked set at the same time
108		log_must set_tunable32 UNLINK_SUSPEND_PROGRESS 0
109		log_must zfs umount $TESTPOOL/$TESTFS.$fs
110		log_must zfs mount $TESTPOOL/$TESTFS.$fs
111		for fn in $(seq 101 175); do
112			log_must eval "rm $TESTDIR.$fs/file-$fn &"
113		done
114		log_must unlinked_size_is 0 $TESTPOOL $TESTPOOL/$TESTFS.$fs
115	done
116done
117
118log_pass "Confirmed unlinked list drain does not hold up mounting of fs"
119