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
146i=1
147log_must setup_ds
148
149log_note "Verify zfs clone propery for multiple clones"
150names=$(zfs list -rt all -o name $TESTPOOL)
151log_must verify_clones 3 0
152
153log_note "verfify clone property for clone deletion"
154i=1
155for ds in $datasets; do
156	log_must zfs destroy $ds/$TESTCLONE.$i
157	((i=i+1))
158done
159names=$(zfs list -rt all -o name $TESTPOOL)
160i=1
161log_must verify_clones 2 1
162
163log_must local_cleanup
164log_must setup_ds
165
166log_note "verify zfs deferred destroy on clones property"
167i=1
168names=$(zfs list -rt all -o name $TESTPOOL)
169for ds in $datasets; do
170	log_must zfs destroy -d $ds@snap
171	deferred_snaps=( "${deferred_snaps[@]}" "$ds@snap" )
172	((i=i+1))
173done
174log_must verify_clones 3 0
175
176log_note "verify zfs deferred destroy by destroying clones on clones property"
177d_clones=()
178i=1
179for ds in $datasets; do
180	for fs in $datasets; do
181		log_must zfs destroy $fs/$TESTCLONE.$i
182		d_clones=( "${d_clones[@]}" "$fs/$TESTCLONE.$i" )
183	done
184	((i=i+1))
185done
186names=$(zfs list -rtall -o name $TESTPOOL)
187for snap in ${deferred_snaps[@]}; do
188	status=$(echo "$names" | grep $snap)
189	[[ -z $status ]] || \
190	    log_fail "$snap exist after deferred destroy"
191done
192for dclone in ${d_clones[@]}; do
193	log_note "D CLONE = $dclone"
194	status=$(echo "$names" | grep $dclone)
195	[[ -z $status ]] || \
196	    log_fail "$dclone exist after deferred destroy"
197done
198
199log_must local_cleanup
200log_must setup_ds
201log_note "verify clone property for zfs promote"
202i=1
203for ds in $datasets; do
204	log_must zfs promote $ds/$TESTCLONE.$i
205	((i=i+1))
206done
207names=$(zfs list -rt all -o name,clones $TESTPOOL)
208log_must verify_clones 3 1 $TESTCLONE
209i=1
210for ds in $datasets; do
211	log_must zfs promote $ds
212	((i=i+1))
213done
214log_must local_cleanup
215
216log_note "verify clone list truncated correctly"
217typeset -i j=200
218i=1
219fs=$TESTPOOL/$TESTFS1
220log_must zfs create $fs
221log_must zfs snapshot $fs@snap
222while((i < 7)); do
223	log_must zfs clone $fs@snap $fs/$TESTCLONE$(printf %0.sx {1..200}).$i
224	((i=i+1))
225	((j=j+200))
226done
227clone_list=$(zfs list -o clones $fs@snap)
228char_count=$(echo "$clone_list" | tail -1 | wc | awk '{print $3}')
229[[ $char_count -eq 1024 ]] || \
230    log_fail "Clone list not truncated correctly. Unexpected character count" \
231        "$char_count"
232
233log_pass "'zfs list -o name,origin,clones prints the correct clone information."
234