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 zfs_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=`cat $kstat_file | grep nunlinks | awk '{print $3}'`
51		nunlinked=`cat $kstat_file | grep nunlinked | awk '{print $3}'`
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
69UNLINK_SP_PARAM=/sys/module/zfs/parameters/zfs_unlink_suspend_progress
70default_unlink_sp=$(get_tunable zfs_unlink_suspend_progress)
71
72log_onexit cleanup
73
74log_assert "Unlinked list drain does not hold up mounting of fs"
75
76for fs in 1 2 3; do
77	set -A xattrs on sa off
78	for xa in ${xattrs[@]}; do
79		# setup fs and ensure all deleted files got into unliked set
80		log_must mounted $TESTDIR.$fs
81
82		log_must zfs set xattr=$xa $TESTPOOL/$TESTFS.$fs
83
84		if [[ $xa == off ]]; then
85			for fn in $(seq 1 175); do
86				log_must mkfile 128k $TESTDIR.$fs/file-$fn
87			done
88		else
89			log_must xattrtest -f 175 -x 3 -r -k -p $TESTDIR.$fs
90		fi
91
92		log_must set_tunable32 zfs_unlink_suspend_progress 1
93		log_must unlinked_size_is 0 $TESTPOOL $TESTPOOL/$TESTFS.$fs
94
95		# build up unlinked set
96		for fn in $(seq 1 100); do
97			log_must eval "rm $TESTDIR.$fs/file-$fn &"
98		done
99		log_must unlinked_size_is 100 $TESTPOOL $TESTPOOL/$TESTFS.$fs
100
101		# test that we can mount fs without emptying the unlinked list
102		log_must zfs umount $TESTPOOL/$TESTFS.$fs
103		log_must unmounted $TESTDIR.$fs
104		log_must zfs mount $TESTPOOL/$TESTFS.$fs
105		log_must mounted $TESTDIR.$fs
106		log_must unlinked_size_is 100 $TESTPOOL $TESTPOOL/$TESTFS.$fs
107
108		# confirm we can drain and add to unlinked set at the same time
109		log_must set_tunable32 zfs_unlink_suspend_progress 0
110		log_must zfs umount $TESTPOOL/$TESTFS.$fs
111		log_must zfs mount $TESTPOOL/$TESTFS.$fs
112		for fn in $(seq 101 175); do
113			log_must eval "rm $TESTDIR.$fs/file-$fn &"
114		done
115		log_must unlinked_size_is 0 $TESTPOOL $TESTPOOL/$TESTFS.$fs
116	done
117done
118
119log_pass "Confirmed unlinked list drain does not hold up mounting of fs"
120