aboutsummaryrefslogtreecommitdiffstats
path: root/common/dmthin
blob: da0ad28488be5afadfe674ddf1dc62ff10d3fd71 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
#!/bin/bash
#
# Copyright (c) 2015 Red Hat, Inc.  All Rights Reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it would be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write the Free Software Foundation,
# Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
#
#
# common functions for setting up and tearing down a dmthin device

# SOOO many devices!
# Create the 2 pool devices on lvs so we can build the whole thing
# from a single scratch device

# Backing data dev
DMTHIN_DATA_NAME="thin-data"
DMTHIN_DATA_DEV="/dev/mapper/$DMTHIN_DATA_NAME"
# Backing metadata dev
DMTHIN_META_NAME="thin-meta"
DMTHIN_META_DEV="/dev/mapper/$DMTHIN_META_NAME"
# Backing pool dev (combination of above)
DMTHIN_POOL_NAME="thin-pool"
DMTHIN_POOL_DEV="/dev/mapper/$DMTHIN_POOL_NAME"
# Thin volume
DMTHIN_VOL_NAME="thin-vol"
DMTHIN_VOL_DEV="/dev/mapper/$DMTHIN_VOL_NAME"

echo $MOUNT_OPTIONS | grep -q dax
if [ $? -eq 0 ]; then
	_notrun "Cannot run tests with DAX on dmthin devices"
fi

_dmthin_cleanup()
{
	$UMOUNT_PROG $SCRATCH_MNT > /dev/null 2>&1
	# wait for device to be fully settled so that 'dmsetup remove' doesn't
	# fail due to EBUSY
	$UDEV_SETTLE_PROG >/dev/null 2>&1
	$DMSETUP_PROG remove $DMTHIN_VOL_NAME> /dev/null 2>&1
	$DMSETUP_PROG remove $DMTHIN_POOL_NAME> /dev/null 2>&1
	$DMSETUP_PROG remove $DMTHIN_META_NAME> /dev/null 2>&1
	$DMSETUP_PROG remove $DMTHIN_DATA_NAME> /dev/null 2>&1
}

_dmthin_check_fs()
{
	$UMOUNT_PROG $SCRATCH_MNT > /dev/null 2>&1
	_check_scratch_fs $DMTHIN_VOL_DEV
}

# Set up a dm-thin device on $SCRATCH_DEV
#
# All arguments are optional, and in this order; defaults follows:
# data_dev_size: half of $SCRATCH_DEV
# virtual_size: 10x $data_dev_size
# cluster_size: 512k
# low_water: 100M
#
# You may specify 0 to 4 of these arguments, but they
# must be in the above order.
_dmthin_init()
{
	local data_dev_size=$1	# Backing pool data size in sectors
	local virtual_size=$2	# Virtual size in sectors
	local cluster_size=$3   # cluster/alloc size, sectors
	local low_water=$4	# low water mark, sectors

	local dm_backing_dev=$SCRATCH_DEV
	local blk_dev_size=`blockdev --getsz $dm_backing_dev`

	local pool_id=$RANDOM

	# Default to something small-ish
	if [ -z "$data_dev_size" ]; then
		data_dev_size=$(($blk_dev_size / 2))
	fi

	# Default to something big-is; 10x backing
	if [ -z "$virtual_size" ]; then
		virtual_size=$(($data_dev_size * 10))
	fi

	# Default to 512k
	if [ -z "$cluster_size" ]; then
		cluster_size=1024	# 512k in sectors
	fi

	# Default to 100M
	if [ -z "$low_water" ]; then
		low_water=204800	# 100M, in sectors
	fi
	# low_water is expressed in blocks of size $cluster_size
	low_water=$((low_water / cluster_size))

	# Need to make linear metadata and data devs.  From kernel docs:
	# As a guide, we suggest you calculate the number of bytes to use in the
	# metadata device as 48 * $data_dev_size / $data_block_size but round it up
	# to 2MB (4096 sectors) if the answer is smaller.
	# So do that:

	local meta_dev_size=$((48 * $data_dev_size / $cluster_size))
	if [ "$meta_dev_size" -lt "4096" ]; then
		meta_dev_size=4096	# 2MB
	fi

	# scratch dev gets a metadata vol & data vol, start at this offset
	local meta_dev_offset=10240

	local total_data_dev_size=$(($meta_dev_offset + $meta_dev_size + $data_dev_size))
	if [ "$total_data_dev_size" -gt "$blk_dev_size" ]; then
		_notrun "$SCRATCH_DEV too small"
	fi

	# Unmount & tear down old stuff
	_dmthin_cleanup

	# Metadata device
	DMTHIN_META_TABLE="0 $meta_dev_size linear $dm_backing_dev $meta_dev_offset"
	$DMSETUP_PROG create $DMTHIN_META_NAME --table "$DMTHIN_META_TABLE" || \
		_fatal "failed to create dm thin meta device"

	# Data device
	local data_dev_offset=$((meta_dev_offset + $meta_dev_size))
	DMTHIN_DATA_TABLE="0 $data_dev_size linear $dm_backing_dev $data_dev_offset"
	$DMSETUP_PROG create $DMTHIN_DATA_NAME --table "$DMTHIN_DATA_TABLE" || \
		_fatal "failed to create dm thin data device"

	# Zap the pool metadata dev
	dd if=/dev/zero of=$DMTHIN_META_DEV bs=4096 count=1 &>/dev/null

	# Thin pool
	# "start length thin-pool metadata_dev data_dev data_block_size low_water_mark"
	DMTHIN_POOL_TABLE="0 $data_dev_size thin-pool $DMTHIN_META_DEV $DMTHIN_DATA_DEV $cluster_size $low_water"
	$DMSETUP_PROG create $DMTHIN_POOL_NAME --table "$DMTHIN_POOL_TABLE" || \
		_fatal "failed to create dm thin pool device"

	# Thin volume
	$DMSETUP_PROG message $DMTHIN_POOL_DEV 0 "create_thin $pool_id" || \
		_fatal "failed to message pool device"

	# start length thin pool_dev dev_id [external_origin_dev]
	DMTHIN_VOL_TABLE="0 $virtual_size thin $DMTHIN_POOL_DEV $pool_id"
	$DMSETUP_PROG create $DMTHIN_VOL_NAME --table "$DMTHIN_VOL_TABLE" || \
		_fatal "failed to create dm thin volume device"

}

# for internal use
_dmthin_reload_table()
{
	local dev_name=$1
	local table="$2"

	$DMSETUP_PROG suspend $dev_name || \
		_fail  "dmsetup suspend of $dev_name failed"

	$DMSETUP_PROG load $dev_name --table "$table" || \
		_fail "dmsetup failed to reload $dev_name table"

	$DMSETUP_PROG resume $dev_name || \
		_fail  "dmsetup resume of $dev_name failed"

}

# Grow the dm-thin device by the given amount
# Argument is number of sectors to add, if not specified
# defaults to 1/4 of the $SCRATCH_DEV size
_dmthin_grow()
{
	local add_sectors=$1	# Number of sectors to add

	local dm_backing_dev=$SCRATCH_DEV
	local blk_dev_size=`blockdev --getsz $dm_backing_dev`

	# Get current sizes & values
	local   meta_dev_size=`$DMSETUP_PROG table | grep ^$DMTHIN_META_NAME | awk '{print $3}'`
	local meta_dev_offset=`$DMSETUP_PROG table | grep ^$DMTHIN_META_NAME | awk '{print $6}'`
	local   data_dev_size=`$DMSETUP_PROG table | grep ^$DMTHIN_DATA_NAME | awk '{print $3}'`
	local   pool_dev_size=`$DMSETUP_PROG table | grep ^$DMTHIN_POOL_NAME | awk '{print $3}'`
	local    cluster_size=`$DMSETUP_PROG table | grep ^$DMTHIN_POOL_NAME | awk '{print $7}'`
	local       low_water=`$DMSETUP_PROG table | grep ^$DMTHIN_POOL_NAME | awk '{print $8}'`

	# default to 25% growth
	if [ -z "$add_sectors" ]; then
		add_sectors=$(($data_dev_size / 4))
	fi

	local data_dev_offset=$(($meta_dev_offset + $meta_dev_size))

	# Figure new sizes
	data_dev_size=$(($data_dev_size + $add_sectors))
	pool_dev_size=$(($pool_dev_size + $add_sectors))

	# Can we do this?
	local total_data_dev_size=$(($meta_dev_offset + $meta_dev_size + $data_dev_size))
	if [ "$total_data_dev_size" -gt "$blk_dev_size" ]; then
		_fail "$SCRATCH_DEV too small"
	fi

	# Grow the data device
	DMTHIN_DATA_TABLE="0 $data_dev_size linear $dm_backing_dev $data_dev_offset"
	_dmthin_reload_table $DMTHIN_DATA_NAME "$DMTHIN_DATA_TABLE"

	# Grow the pool
	DMTHIN_POOL_TABLE="0 $data_dev_size thin-pool $DMTHIN_META_DEV $DMTHIN_DATA_DEV $cluster_size $low_water"
	_dmthin_reload_table $DMTHIN_POOL_NAME "$DMTHIN_POOL_TABLE"
}

# Queue IOs when full
_dmthin_set_queue()
{
	local   data_dev_size=`$DMSETUP_PROG table | grep $DMTHIN_DATA_NAME | awk '{print $3}'`
	local    cluster_size=`$DMSETUP_PROG table | grep $DMTHIN_POOL_NAME | awk '{print $7}'`
	local       low_water=`$DMSETUP_PROG table | grep $DMTHIN_POOL_NAME | awk '{print $8}'`

	DMTHIN_POOL_TABLE="0 $data_dev_size thin-pool $DMTHIN_META_DEV $DMTHIN_DATA_DEV $cluster_size $low_water"
	_dmthin_reload_table $DMTHIN_POOL_NAME "$DMTHIN_POOL_TABLE"
}

# Fail IOs when full
_dmthin_set_fail()
{
	local   data_dev_size=`$DMSETUP_PROG table | grep $DMTHIN_DATA_NAME | awk '{print $3}'`
	local    cluster_size=`$DMSETUP_PROG table | grep $DMTHIN_POOL_NAME | awk '{print $7}'`
	local       low_water=`$DMSETUP_PROG table | grep $DMTHIN_POOL_NAME | awk '{print $8}'`

	DMTHIN_POOL_TABLE="0 $data_dev_size thin-pool $DMTHIN_META_DEV $DMTHIN_DATA_DEV $cluster_size $low_water 1 error_if_no_space"
	_dmthin_reload_table $DMTHIN_POOL_NAME "$DMTHIN_POOL_TABLE"
}

_dmthin_mount_options()
{
	echo `_common_dev_mount_options $*` $DMTHIN_VOL_DEV $SCRATCH_MNT
}

_dmthin_mount()
{
	_mount -t $FSTYP `_dmthin_mount_options $*`
}