From 30293baaa0f87efeab81f01f9c5d73b26869babf Mon Sep 17 00:00:00 2001 From: Ondrej Kozina <okozina@redhat.com> Date: Fri, 6 Oct 2017 16:28:35 +0200 Subject: [PATCH] fsadm: add support for crypt devices --- WHATS_NEW | 1 + man/fsadm.8_main | 8 ++- scripts/fsadm.sh | 142 +++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 146 insertions(+), 5 deletions(-) diff --git a/WHATS_NEW b/WHATS_NEW index 4314c6900..914085843 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,6 @@ Version 2.02.176 - =================================== + Support for encrypted devices in fsadm. Improve thin pool overprovisioning and repair warning messages. Version 2.02.175 - 6th October 2017 diff --git a/man/fsadm.8_main b/man/fsadm.8_main index c46033ce2..799cb2547 100644 --- a/man/fsadm.8_main +++ b/man/fsadm.8_main @@ -65,6 +65,11 @@ Be more verbose. Answer "yes" at any prompts. . .HP +.BR -c | --cryptresize +.br +Resize dm-crypt mapping together with filesystem detected on the device. The dm-crypt device must be recognizable by cryptsetup(8). +. +.HP .BR \fInew_size [ B | K | M | G | T | P | E ] .br Absolute number of filesystem blocks to be in the filesystem, @@ -111,4 +116,5 @@ Defaults to "\fI/dev\fP" and must be an absolute path. .BR resize_reiserfs (8), .BR xfs_info (8), .BR xfs_growfs (8), -.BR xfs_check (8) +.BR xfs_check (8), +.BR cryptsetup (8) diff --git a/scripts/fsadm.sh b/scripts/fsadm.sh index 753da2b81..da687fd99 100755 --- a/scripts/fsadm.sh +++ b/scripts/fsadm.sh @@ -17,7 +17,7 @@ # Script for resizing devices (usable for LVM resize) # # Needed utilities: -# mount, umount, grep, readlink, blockdev, blkid, fsck, xfs_check +# mount, umount, grep, readlink, blockdev, blkid, fsck, xfs_check, cryptsetup # # ext2/ext3/ext4: resize2fs, tune2fs # reiserfs: resize_reiserfs, reiserfstune @@ -56,6 +56,7 @@ FSCK=fsck XFS_CHECK=xfs_check # XFS_REPAIR -n is used when XFS_CHECK is not found XFS_REPAIR=xfs_repair +CRYPTSETUP=cryptsetup # user may override lvm location by setting LVM_BINARY LVM=${LVM_BINARY:-lvm} @@ -101,6 +102,7 @@ tool_usage() { echo " -f | --force Bypass sanity checks" echo " -n | --dry-run Print commands without running them" echo " -l | --lvresize Resize given device (if it is LVM device)" + echo " -c | --cryptresize Resize given crypt device" echo " -y | --yes Answer \"yes\" at any prompts" echo echo " new_size - Absolute number of filesystem blocks to be in the filesystem," @@ -152,7 +154,7 @@ cleanup() { export _FSADM_YES _FSADM_EXTOFF unset FSADM_RUNNING test -n "$LVM_BINARY" && PATH=$_SAVEPATH - dry exec "$LVM" lvresize $VERB $FORCE -r -L"${NEWSIZE}b" "$VOLUME_ORIG" + dry exec "$LVM" lvresize $VERB $FORCE -r -L"${NEWSIZE_ORIG}b" "$VOLUME_ORIG" fi # error exit status for break @@ -196,7 +198,7 @@ decode_major_minor() { # detect filesystem on the given device # dereference device name if it is symbolic link detect_fs() { - VOLUME_ORIG=$1 + test -n "$VOLUME_ORIG" || VOLUME_ORIG=$1 VOLUME=${1/#"${DM_DEV_DIR}/"/} VOLUME=$("$READLINK" $READLINK_E "$DM_DEV_DIR/$VOLUME") test -n "$VOLUME" || error "Cannot get readlink \"$1\"." @@ -520,6 +522,131 @@ resize_xfs() { fi } +# Find active LUKS device on original volume +# 1) look for LUKS device with well-known UUID format (CRYPT-LUKS[12]-<uuid>-<dmname>) +# 2) the dm-crypt device has to be on top of original device (dont't support detached LUKS headers) +detect_luks_device() { + local _LUKS_VERSION= + local _LUKS_UUID= + + CRYPT_NAME="" + CRYPT_DATA_OFFSET="" + + _LUKS_VERSION=$($CRYPTSETUP luksDump $VOLUME 2> /dev/null | $GREP "Version:") + + if [ -z $_LUKS_VERSION ]; then + verbose "Failed to parse LUKS version on volume \"$VOLUME\"" + return + fi + + _LUKS_VERSION=${_LUKS_VERSION//[Version:[:space:]]/} + + _LUKS_UUID=$($CRYPTSETUP luksDump $VOLUME 2> /dev/null | $GREP "UUID:") + + if [ -z $_LUKS_UUID ]; then + verbose "Failed to parse LUKS UUID on volume \"$VOLUME\"" + return + fi + + _LUKS_UUID="CRYPT-LUKS$_LUKS_VERSION-${_LUKS_UUID//[UID:[:space:]-]/}-*" + + CRYPT_NAME=$(dmsetup info -c --noheadings -S "UUID=~$_LUKS_UUID&&segments=1&&devnos_used='$MAJOR:$MINOR'" -o name) + test -z "$CRYPT_NAME" || CRYPT_DATA_OFFSET=$(dmsetup table $CRYPT_NAME | cut -d ' ' -f 8) +} + +###################################### +# Resize active LUKS device +# - LUKS must be active for fs resize +###################################### +resize_luks() { + local NEWFSIZE= + local NEWCBLOCKCOUNT= + local NAME="" + local SHRINK=0 + + detect_luks_device + + # LUKS device must be active and mapped over volume where detected + if [ -z "$CRYPT_NAME" -o -z "$CRYPT_DATA_OFFSET" ]; then + error "Can not find active LUKS device. Unlock \"$VOLUME\" volume first." + fi + + NAME=$CRYPT_NAME + + verbose "Found active LUKS device \"$NAME\" for volume \"$VOLUME\"" + + decode_size "$1" 512 + + if [ $((NEWSIZE % 512)) -gt 0 ]; then + error "New size is not sector alligned" + fi + + NEWCBLOCKCOUNT=$((NEWBLOCKCOUNT - CRYPT_DATA_OFFSET)) + NEWFSIZE=$(( NEWCBLOCKCOUNT * 512)) + + VOLUME="/dev/mapper/$NAME" + detect_device_size + + test "$DEVSIZE" -le "$NEWSIZE" || SHRINK=1 + + if [ $SHRINK -eq 1 ]; then + # shrink fs on LUKS device first + resize "/dev/mapper/$NAME" "$NEWFSIZE"b + fi + + # resize LUKS device + dry $CRYPTSETUP resize $NAME --size $NEWCBLOCKCOUNT || error "Failed to resize active LUKS device" + + if [ $SHRINK -eq 0 ]; then + # grow fs on top of LUKS device + resize "/dev/mapper/$NAME" "$NEWFSIZE"b + fi +} + +################################# +# Resize active crypt device +# (on direct user request only) +################################# +resize_crypt() { + local CRYPT_TYPE= + local TMP= + local SHRINK=0 + + which $CRYPTSETUP > /dev/null 2>&1 || error "$CRYPTSETUP utility required to resize LUKS volume" + + CRYPT_TYPE=$($CRYPTSETUP status $1 2> /dev/null | $GREP "type:") + + test -n "$CRYPT_TYPE" || error "$CRYPTSETUP failed to detect device type on $1." + + CRYPT_TYPE=${CRYPT_TYPE##*[[:space:]]} + + TMP=$NEWSIZE + + decode_size "$2" 512 + detect_device_size + + if [ "$DEVSIZE" -gt "$NEWSIZE" ]; then + SHRINK=1 + fi + + NEWSIZE=$TMP + + if [ $SHRINK -eq 1 -a -z "$3" ]; then + return + fi + + # going to resize, drop the request flag + unset DO_CRYPTRESIZE + + case "$CRYPT_TYPE" in + LUKS[12]|PLAIN) + dry $CRYPTSETUP resize "$1" --size $NEWBLOCKCOUNT || error "Failed to resize device $1" + ;; + *) + error "Unsupported crypt type \"$CRYPT_TYPE\"" + esac +} + #################### # Resize filesystem #################### @@ -531,14 +658,19 @@ resize() { # if the size parameter is missing use device size #if [ -n "$NEWSIZE" -a $NEWSIZE < test -z "$NEWSIZE" && NEWSIZE=${DEVSIZE}b + test -n "$NEWSIZE_ORIG" || NEWSIZE_ORIG=$NEWSIZE IFS=$NL + test -z "$DO_CRYPTRESIZE" || resize_crypt "$VOLUME_ORIG" "$NEWSIZE_ORIG" case "$FSTYPE" in "ext3"|"ext2"|"ext4") resize_ext $NEWSIZE ;; "reiserfs") resize_reiser $NEWSIZE ;; "xfs") resize_xfs $NEWSIZE ;; + "crypto_LUKS") + which $CRYPTSETUP > /dev/null 2>&1 || error "$CRYPTSETUP utility required to resize LUKS volume" + resize_luks $NEWSIZE ;; *) error "Filesystem \"$FSTYPE\" on device \"$VOLUME\" is not supported by this tool." ;; esac || error "Resize $FSTYPE failed." - cleanup 0 + test -z "$DO_CRYPTRESIZE" || resize_crypt "$VOLUME_ORIG" "$NEWSIZE_ORIG" do_shrink } #################################### @@ -641,6 +773,7 @@ do "-e"|"--ext-offline") EXTOFF=1 ;; "-y"|"--yes") YES="-y" ;; "-l"|"--lvresize") DO_LVRESIZE=1 ;; + "-c"|"--cryptresize") DO_CRYPTRESIZE=1 ;; "check") CHECK=$2 ; shift ;; "resize") RESIZE=$2 ; NEWSIZE=$3 ; shift 2 ;; *) error "Wrong argument \"$1\". (see: $TOOL --help)" @@ -656,6 +789,7 @@ if [ -n "$CHECK" ]; then elif [ -n "$RESIZE" ]; then export FSADM_RUNNING="fsadm" resize "$RESIZE" "$NEWSIZE" + cleanup 0 else error "Missing command. (see: $TOOL --help)" fi