| #!/bin/bash | |
| # SPDX-License-Identifier: GPL-2.0 | |
| # Copyright (c) 2015 Red Hat, Inc. All Rights Reserved. | |
| # | |
| # 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-provision-pool" | |
| DMTHIN_POOL_DEV="/dev/mapper/$DMTHIN_POOL_NAME" | |
| # Thin volume | |
| DMTHIN_VOL_NAME="thin-vol" | |
| DMTHIN_VOL_DEV="/dev/mapper/$DMTHIN_VOL_NAME" | |
| _dmthin_cleanup() | |
| { | |
| $UMOUNT_PROG $SCRATCH_MNT > /dev/null 2>&1 | |
| _dmsetup_remove $DMTHIN_VOL_NAME | |
| _dmsetup_remove $DMTHIN_POOL_NAME | |
| _dmsetup_remove $DMTHIN_META_NAME | |
| _dmsetup_remove $DMTHIN_DATA_NAME | |
| } | |
| _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_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_create $DMTHIN_DATA_NAME --table "$DMTHIN_DATA_TABLE" || \ | |
| _fatal "failed to create dm thin data device" | |
| # Zap the pool metadata dev. Explicitly fsync the zeroes to disk | |
| # because a slow-running udev running concurrently with dd can maintain | |
| # an open file descriptor. The block layer only flushes the page cache | |
| # on last close, which means that the thin pool creation below will | |
| # see the (stale) ondisk contents and fail. | |
| dd if=/dev/zero of=$DMTHIN_META_DEV bs=4096 count=1 conv=fsync &>/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_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_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() | |
| { | |
| _scratch_options mount | |
| echo `_common_dev_mount_options $*` $SCRATCH_OPTIONS $DMTHIN_VOL_DEV $SCRATCH_MNT | |
| } | |
| _dmthin_mount() | |
| { | |
| _mount -t $FSTYP `_dmthin_mount_options $*` | |
| } | |
| _dmthin_mkfs() | |
| { | |
| _scratch_options mkfs | |
| _mkfs_dev $SCRATCH_OPTIONS $@ $DMTHIN_VOL_DEV | |
| } |