1#!/bin/ksh
2#
3# CDDL HEADER START
4#
5# This file and its contents are supplied under the terms of the
6# Common Development and Distribution License ("CDDL"), version 1.0.
7# You may only use this file in accordance with the terms of version
8# 1.0 of the CDDL.
9
10# A full copy of the text of the CDDL should have accompanied this
11# source.  A copy of the CDDL is also available via the Internet at
12# http://www.illumos.org/license/CDDL.
13#
14# CDDL HEADER END
15#
16
17#
18# Copyright (c) 2012, 2016 by Delphix. All rights reserved.
19#
20
21. $STF_SUITE/include/libtest.shlib
22
23#
24# DESCRIPTION:
25#	Verify 'zfs list -t all -o name,origin,clones' prints the correct
26#	clone information
27#
28# STRATEGY:
29#	1. Create datasets
30#	2. Create recursive snapshots and their clones
31#	3. Verify zfs clones property displays right information for different
32#	   cases
33#
34
35verify_runnable "both"
36
37function local_cleanup
38{
39	typeset -i i=1
40	for ds in $datasets; do
41                datasetexists $ds/$TESTCLONE.$i && \
42		    log_must zfs destroy -rf $ds/$TESTCLONE.$i
43                datasetexists $ds && log_must zfs destroy -Rf $ds
44		((i=i+1))
45	done
46}
47
48# Set up filesystem with clones
49function setup_ds
50{
51	typeset -i i=1
52	# create nested datasets
53	log_must zfs create -p $TESTPOOL/$TESTFS1/$TESTFS2/$TESTFS3
54
55	# verify dataset creation
56	for ds in $datasets; do
57		datasetexists $ds || log_fail "Create $ds dataset fail."
58	done
59
60	# create recursive nested snapshot
61	log_must zfs snapshot -r $TESTPOOL/$TESTFS1@snap
62	for ds in $datasets; do
63		datasetexists $ds@snap || \
64		    log_fail "Create $ds@snap snapshot fail."
65	done
66	for ds in $datasets; do
67		for fs in $datasets; do
68			log_must zfs clone $ds@snap $fs/$TESTCLONE.$i
69		done
70		((i=i+1))
71	done
72}
73
74# Verify clone list
75function verify_clones
76{
77	typeset -i no_clones=$1
78	typeset unexpected=$2
79	typeset clone_snap=$3
80	typeset -i i=1
81	for ds in $datasets; do
82		if [[ -n $clone_snap ]]; then
83			clone_snap=/$TESTCLONE.$i
84		fi
85		snapshot=$(echo "$names" | grep $ds$clone_snap@snap)
86		actual_clone=$(zfs list -t all -o clones $snapshot | tail -1)
87		save=$IFS
88		IFS=','
89		typeset -a clones=()
90		for token in $actual_clone; do
91			clones=( "${clones[@]}" "$token" )
92		done
93		IFS=$save
94		[[ ${#clones[*]} -ne $no_clones ]] && \
95		    log_fail "$snapshot has unexpected number of clones" \
96		        " ${#clones[*]}"
97		expected_clone=""
98		unexpected_clone=""
99		if [[ $unexpected -eq 1 ]]; then
100			for fs in $datasets; do
101				if [[ $fs == $ds ]]; then
102					if [[ -z $clone_snap ]]; then
103						unexpected_clone=$fs/$TESTCLONE.$i
104						(for match in ${clones[@]};do
105						[[ $match != $unexpected_clone ]] && \
106						    exit 0; done) || log_fail \
107					            "Unexpected clones of the snapshot"
108					else
109						expected_clone=$fs
110						unexpected_clone=$fs/$TESTCLONE.$i
111						(for match in ${clones[@]};do
112						[[ $match == $expected_clone ]] && \
113						    [[ $match != $unexpected_clone ]] \
114						    && exit 0; done) || log_fail \
115						    "Unexpected clones of the snapshot"
116					fi
117				else
118					expected_clone=$fs/$TESTCLONE.$i
119					(for match in ${clones[@]};do
120					[[ $match == $expected_clone ]] && \
121					    exit 0; done) || log_fail \
122					    "Unexpected clones of the snapshot"
123				fi
124			done
125		else
126			for fs in $datasets; do
127				expected_clone=$fs/$TESTCLONE.$i
128				(for match in ${clones[@]};do
129				[[ $match == $expected_clone ]] && exit 0; \
130				    done) || log_fail "Unexpected clones" \
131				    " of the snapshot"
132			done
133		fi
134		((i=i+1))
135	done
136}
137
138
139log_onexit local_cleanup
140datasets="$TESTPOOL/$TESTFS1 $TESTPOOL/$TESTFS1/$TESTFS2
141    $TESTPOOL/$TESTFS1/$TESTFS2/$TESTFS3"
142
143typeset -a d_clones
144typeset -a deferred_snaps
145typeset -i i
146log_must setup_ds
147
148log_note "Verify zfs clone property for multiple clones"
149names=$(zfs list -rt all -o name $TESTPOOL)
150log_must verify_clones 3 0
151
152log_note "verify clone property for clone deletion"
153i=1
154for ds in $datasets; do
155	log_must zfs destroy $ds/$TESTCLONE.$i
156	((i=i+1))
157done
158names=$(zfs list -rt all -o name $TESTPOOL)
159log_must verify_clones 2 1
160
161log_must local_cleanup
162log_must setup_ds
163
164log_note "verify zfs deferred destroy on clones property"
165names=$(zfs list -rt all -o name $TESTPOOL)
166for ds in $datasets; do
167	log_must zfs destroy -d $ds@snap
168	deferred_snaps=( "${deferred_snaps[@]}" "$ds@snap" )
169done
170log_must verify_clones 3 0
171
172log_note "verify zfs deferred destroy by destroying clones on clones property"
173d_clones=()
174i=1
175for ds in $datasets; do
176	for fs in $datasets; do
177		log_must zfs destroy $fs/$TESTCLONE.$i
178		d_clones=( "${d_clones[@]}" "$fs/$TESTCLONE.$i" )
179	done
180	((i=i+1))
181done
182names=$(zfs list -rtall -o name $TESTPOOL)
183for snap in ${deferred_snaps[@]}; do
184	status=$(echo "$names" | grep $snap)
185	[[ -z $status ]] || \
186	    log_fail "$snap exist after deferred destroy"
187done
188for dclone in ${d_clones[@]}; do
189	log_note "D CLONE = $dclone"
190	status=$(echo "$names" | grep $dclone)
191	[[ -z $status ]] || \
192	    log_fail "$dclone exist after deferred destroy"
193done
194
195log_must local_cleanup
196log_must setup_ds
197log_note "verify clone property for zfs promote"
198i=1
199for ds in $datasets; do
200	log_must zfs promote $ds/$TESTCLONE.$i
201	((i=i+1))
202done
203names=$(zfs list -rt all -o name,clones $TESTPOOL)
204log_must verify_clones 3 1 $TESTCLONE
205for ds in $datasets; do
206	log_must zfs promote $ds
207done
208log_must local_cleanup
209
210log_note "verify clone list truncated correctly"
211fs=$TESTPOOL/$TESTFS1
212xs=""; for i in {1..200}; do xs+="x"; done
213if is_linux; then
214	ZFS_MAXPROPLEN=4096
215else
216	ZFS_MAXPROPLEN=1024
217fi
218log_must zfs create $fs
219log_must zfs snapshot $fs@snap
220for (( i = 1; i <= (ZFS_MAXPROPLEN / 200 + 1); i++ )); do
221	log_must zfs clone ${fs}@snap ${fs}/${TESTCLONE}${xs}.${i}
222done
223clone_list=$(zfs list -o clones $fs@snap)
224char_count=$(echo "$clone_list" | tail -1 | wc | awk '{print $3}')
225[[ $char_count -eq $ZFS_MAXPROPLEN ]] || \
226    log_fail "Clone list not truncated correctly. Unexpected character count" \
227        "$char_count"
228
229log_pass "'zfs list -o name,origin,clones prints the correct clone information."
230