| #!/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 |
| } |