common/fuzzy: if the fuzz verb is random, keep fuzzing until we get a new value
[xfstests-dev.git] / common / dmthin
1 #!/bin/bash
2 #
3 # Copyright (c) 2015 Red Hat, Inc.  All Rights Reserved.
4 #
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License as
7 # published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it would be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write the Free Software Foundation,
16 # Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17 #
18 #
19 # common functions for setting up and tearing down a dmthin device
20
21 # SOOO many devices!
22 # Create the 2 pool devices on lvs so we can build the whole thing
23 # from a single scratch device
24
25 # Backing data dev
26 DMTHIN_DATA_NAME="thin-data"
27 DMTHIN_DATA_DEV="/dev/mapper/$DMTHIN_DATA_NAME"
28 # Backing metadata dev
29 DMTHIN_META_NAME="thin-meta"
30 DMTHIN_META_DEV="/dev/mapper/$DMTHIN_META_NAME"
31 # Backing pool dev (combination of above)
32 DMTHIN_POOL_NAME="thin-pool"
33 DMTHIN_POOL_DEV="/dev/mapper/$DMTHIN_POOL_NAME"
34 # Thin volume
35 DMTHIN_VOL_NAME="thin-vol"
36 DMTHIN_VOL_DEV="/dev/mapper/$DMTHIN_VOL_NAME"
37
38 _dmthin_cleanup()
39 {
40         $UMOUNT_PROG $SCRATCH_MNT > /dev/null 2>&1
41         # wait for device to be fully settled so that 'dmsetup remove' doesn't
42         # fail due to EBUSY
43         $UDEV_SETTLE_PROG >/dev/null 2>&1
44         $DMSETUP_PROG remove $DMTHIN_VOL_NAME> /dev/null 2>&1
45         $DMSETUP_PROG remove $DMTHIN_POOL_NAME> /dev/null 2>&1
46         $DMSETUP_PROG remove $DMTHIN_META_NAME> /dev/null 2>&1
47         $DMSETUP_PROG remove $DMTHIN_DATA_NAME> /dev/null 2>&1
48 }
49
50 _dmthin_check_fs()
51 {
52         $UMOUNT_PROG $SCRATCH_MNT > /dev/null 2>&1
53         _check_scratch_fs $DMTHIN_VOL_DEV
54 }
55
56 # Set up a dm-thin device on $SCRATCH_DEV
57 #
58 # All arguments are optional, and in this order; defaults follows:
59 # data_dev_size: half of $SCRATCH_DEV
60 # virtual_size: 10x $data_dev_size
61 # cluster_size: 512k
62 # low_water: 100M
63 #
64 # You may specify 0 to 4 of these arguments, but they
65 # must be in the above order.
66 _dmthin_init()
67 {
68         local data_dev_size=$1  # Backing pool data size in sectors
69         local virtual_size=$2   # Virtual size in sectors
70         local cluster_size=$3   # cluster/alloc size, sectors
71         local low_water=$4      # low water mark, sectors
72
73         local dm_backing_dev=$SCRATCH_DEV
74         local blk_dev_size=`blockdev --getsz $dm_backing_dev`
75
76         local pool_id=$RANDOM
77
78         # Default to something small-ish
79         if [ -z "$data_dev_size" ]; then
80                 data_dev_size=$(($blk_dev_size / 2))
81         fi
82
83         # Default to something big-is; 10x backing
84         if [ -z "$virtual_size" ]; then
85                 virtual_size=$(($data_dev_size * 10))
86         fi
87
88         # Default to 512k
89         if [ -z "$cluster_size" ]; then
90                 cluster_size=1024       # 512k in sectors
91         fi
92
93         # Default to 100M
94         if [ -z "$low_water" ]; then
95                 low_water=204800        # 100M, in sectors
96         fi
97         # low_water is expressed in blocks of size $cluster_size
98         low_water=$((low_water / cluster_size))
99
100         # Need to make linear metadata and data devs.  From kernel docs:
101         # As a guide, we suggest you calculate the number of bytes to use in the
102         # metadata device as 48 * $data_dev_size / $data_block_size but round it up
103         # to 2MB (4096 sectors) if the answer is smaller.
104         # So do that:
105
106         local meta_dev_size=$((48 * $data_dev_size / $cluster_size))
107         if [ "$meta_dev_size" -lt "4096" ]; then
108                 meta_dev_size=4096      # 2MB
109         fi
110
111         # scratch dev gets a metadata vol & data vol, start at this offset
112         local meta_dev_offset=10240
113
114         local total_data_dev_size=$(($meta_dev_offset + $meta_dev_size + $data_dev_size))
115         if [ "$total_data_dev_size" -gt "$blk_dev_size" ]; then
116                 _notrun "$SCRATCH_DEV too small"
117         fi
118
119         # Unmount & tear down old stuff
120         _dmthin_cleanup
121
122         # Metadata device
123         DMTHIN_META_TABLE="0 $meta_dev_size linear $dm_backing_dev $meta_dev_offset"
124         $DMSETUP_PROG create $DMTHIN_META_NAME --table "$DMTHIN_META_TABLE" || \
125                 _fatal "failed to create dm thin meta device"
126
127         # Data device
128         local data_dev_offset=$((meta_dev_offset + $meta_dev_size))
129         DMTHIN_DATA_TABLE="0 $data_dev_size linear $dm_backing_dev $data_dev_offset"
130         $DMSETUP_PROG create $DMTHIN_DATA_NAME --table "$DMTHIN_DATA_TABLE" || \
131                 _fatal "failed to create dm thin data device"
132
133         # Zap the pool metadata dev
134         dd if=/dev/zero of=$DMTHIN_META_DEV bs=4096 count=1 &>/dev/null
135
136         # Thin pool
137         # "start length thin-pool metadata_dev data_dev data_block_size low_water_mark"
138         DMTHIN_POOL_TABLE="0 $data_dev_size thin-pool $DMTHIN_META_DEV $DMTHIN_DATA_DEV $cluster_size $low_water"
139         $DMSETUP_PROG create $DMTHIN_POOL_NAME --table "$DMTHIN_POOL_TABLE" || \
140                 _fatal "failed to create dm thin pool device"
141
142         # Thin volume
143         $DMSETUP_PROG message $DMTHIN_POOL_DEV 0 "create_thin $pool_id" || \
144                 _fatal "failed to message pool device"
145
146         # start length thin pool_dev dev_id [external_origin_dev]
147         DMTHIN_VOL_TABLE="0 $virtual_size thin $DMTHIN_POOL_DEV $pool_id"
148         $DMSETUP_PROG create $DMTHIN_VOL_NAME --table "$DMTHIN_VOL_TABLE" || \
149                 _fatal "failed to create dm thin volume device"
150
151 }
152
153 # for internal use
154 _dmthin_reload_table()
155 {
156         local dev_name=$1
157         local table="$2"
158
159         $DMSETUP_PROG suspend $dev_name || \
160                 _fail  "dmsetup suspend of $dev_name failed"
161
162         $DMSETUP_PROG load $dev_name --table "$table" || \
163                 _fail "dmsetup failed to reload $dev_name table"
164
165         $DMSETUP_PROG resume $dev_name || \
166                 _fail  "dmsetup resume of $dev_name failed"
167
168 }
169
170 # Grow the dm-thin device by the given amount
171 # Argument is number of sectors to add, if not specified
172 # defaults to 1/4 of the $SCRATCH_DEV size
173 _dmthin_grow()
174 {
175         local add_sectors=$1    # Number of sectors to add
176
177         local dm_backing_dev=$SCRATCH_DEV
178         local blk_dev_size=`blockdev --getsz $dm_backing_dev`
179
180         # Get current sizes & values
181         local   meta_dev_size=`$DMSETUP_PROG table | grep ^$DMTHIN_META_NAME | awk '{print $3}'`
182         local meta_dev_offset=`$DMSETUP_PROG table | grep ^$DMTHIN_META_NAME | awk '{print $6}'`
183         local   data_dev_size=`$DMSETUP_PROG table | grep ^$DMTHIN_DATA_NAME | awk '{print $3}'`
184         local   pool_dev_size=`$DMSETUP_PROG table | grep ^$DMTHIN_POOL_NAME | awk '{print $3}'`
185         local    cluster_size=`$DMSETUP_PROG table | grep ^$DMTHIN_POOL_NAME | awk '{print $7}'`
186         local       low_water=`$DMSETUP_PROG table | grep ^$DMTHIN_POOL_NAME | awk '{print $8}'`
187
188         # default to 25% growth
189         if [ -z "$add_sectors" ]; then
190                 add_sectors=$(($data_dev_size / 4))
191         fi
192
193         local data_dev_offset=$(($meta_dev_offset + $meta_dev_size))
194
195         # Figure new sizes
196         data_dev_size=$(($data_dev_size + $add_sectors))
197         pool_dev_size=$(($pool_dev_size + $add_sectors))
198
199         # Can we do this?
200         local total_data_dev_size=$(($meta_dev_offset + $meta_dev_size + $data_dev_size))
201         if [ "$total_data_dev_size" -gt "$blk_dev_size" ]; then
202                 _fail "$SCRATCH_DEV too small"
203         fi
204
205         # Grow the data device
206         DMTHIN_DATA_TABLE="0 $data_dev_size linear $dm_backing_dev $data_dev_offset"
207         _dmthin_reload_table $DMTHIN_DATA_NAME "$DMTHIN_DATA_TABLE"
208
209         # Grow the pool
210         DMTHIN_POOL_TABLE="0 $data_dev_size thin-pool $DMTHIN_META_DEV $DMTHIN_DATA_DEV $cluster_size $low_water"
211         _dmthin_reload_table $DMTHIN_POOL_NAME "$DMTHIN_POOL_TABLE"
212 }
213
214 # Queue IOs when full
215 _dmthin_set_queue()
216 {
217         local   data_dev_size=`$DMSETUP_PROG table | grep $DMTHIN_DATA_NAME | awk '{print $3}'`
218         local    cluster_size=`$DMSETUP_PROG table | grep $DMTHIN_POOL_NAME | awk '{print $7}'`
219         local       low_water=`$DMSETUP_PROG table | grep $DMTHIN_POOL_NAME | awk '{print $8}'`
220
221         DMTHIN_POOL_TABLE="0 $data_dev_size thin-pool $DMTHIN_META_DEV $DMTHIN_DATA_DEV $cluster_size $low_water"
222         _dmthin_reload_table $DMTHIN_POOL_NAME "$DMTHIN_POOL_TABLE"
223 }
224
225 # Fail IOs when full
226 _dmthin_set_fail()
227 {
228         local   data_dev_size=`$DMSETUP_PROG table | grep $DMTHIN_DATA_NAME | awk '{print $3}'`
229         local    cluster_size=`$DMSETUP_PROG table | grep $DMTHIN_POOL_NAME | awk '{print $7}'`
230         local       low_water=`$DMSETUP_PROG table | grep $DMTHIN_POOL_NAME | awk '{print $8}'`
231
232         DMTHIN_POOL_TABLE="0 $data_dev_size thin-pool $DMTHIN_META_DEV $DMTHIN_DATA_DEV $cluster_size $low_water 1 error_if_no_space"
233         _dmthin_reload_table $DMTHIN_POOL_NAME "$DMTHIN_POOL_TABLE"
234 }
235
236 _dmthin_mount_options()
237 {
238         echo `_common_dev_mount_options $*` $DMTHIN_VOL_DEV $SCRATCH_MNT
239 }
240
241 _dmthin_mount()
242 {
243         _mount -t $FSTYP `_dmthin_mount_options $*`
244 }