Moving or copying Logical Volumes
LVM is a wonderful feature of Linux which I use all over the place.
It has always struck me as somewhat odd, however, that there is no command to copy or move a Logical Volume from one Volume Group to another.
Therefore I came up with a Bash script to do the job for me, and whilst I was at it, I made it work between servers as well.
- lvmove
#!/bin/bash # Copy or move a Logical Volume from one Volume Group to another # possibly on another machine if [ -z "$4" ] then echo "Usage: $0 LV fromVG [host:]toVG <copy|keep|move> [nocheck]" exit 1 fi # 1. Make sure LV exists on source VG # 2. Parse destination VG - if it contains a colon, it means hostname:VG # 3. Make sure LV does not exist on destination VG # 4. Get size of source LV # 5. Create destination LV # 6. Copy content # 7. Compare source vs. destination if required # 8. If match, delete source and any log files host= LV=$1 fromVG=$2 toVG=$3 task=$4 check=$5 [ "$toVG" = "${toVG/:}" ] || host="${toVG%%:*}" [ -n "$host" ] && toVG="${toVG##*:}" needed="ddrescue lvdisplay diff" for need in $needed do if ! which $need &>/dev/null then echo "Sorry, I need $need installed before this can work." exit 1 fi done if lvdisplay $fromVG/$LV &>/dev/null then if [ -n "$host" ] then if ssh $host "lvdisplay $toVG/$LV 2>/dev/null" | grep -q $LV then echo "Logical Volume $LV already exists in Volume Group $toVG on $host" exit 1 fi else if lvdisplay $toVG/$LV &>/dev/null then echo "Logical Volume $LV already exists in Volume Group $toVG" exit 1 fi fi lvsize=`lvdisplay $fromVG/$LV | grep "Current LE" | tr -s ' ' | cut -d' ' -f4` if [ -n "$host" ] then echo "Creating new LV $LV on destination VG $toVG on $host" ssh $host "lvcreate -y -l $lvsize -n $LV $toVG" echo "Copying content (be patient)..." dd if=/dev/$fromVG/$LV bs=1M | ssh $host dd bs=1M of=/dev/$toVG/$LV else echo "Creating new LV $LV on destination VG $toVG" lvcreate -y -l $lvsize -n $LV $toVG echo "Copying content..." ddrescue -f /dev/$fromVG/$LV /dev/$toVG/$LV /tmp/$LV.log fi OK=no if [ "$check" = "nocheck" ] then OK=yes else if [ -n "$host" ] then echo "Checking the copy..." diff -q <(md5sum /dev/$fromVG/$LV | cut -d' ' -f1) <(ssh $host md5sum /dev/$toVG/$LV | cut -d' ' -f1) && OK=yes else echo "Checking the copy (this will take approximately as long as the copy did)..." diff -q /dev/$fromVG/$LV /dev/$toVG/$LV && OK=yes fi fi if [ "$OK" = "yes" ] then if [ "$task" = "keep" -o "$task" = "copy" ] then rm -f /tmp/$LV.log echo "$LV successfully copied from $fromVG to $toVG" exit 0 elif [ "$task" = "move" ] then lvremove -y $fromVG/$LV rm -f /tmp/$LV.log echo "$LV successfully moved from $fromVG to $toVG" exit 0 else echo "$LV successfully copied from $fromVG to $toVG" echo "but not sure whether you wanted to delete the original, therefore keeping both." exit 0 fi else echo "Something went wrong." exit 1 fi else echo "Logical Volume $LV not found in Volume Group $fromVG" exit 1 fi
The script uses ddrescue if you're working on a single server, but has to use dd (which is just as effective, but produces no progress output) if you're working between two machines.
Between two machines, the script works best if you have passwordless public-key login access between the machines (but will still prompt for a password (several times) if this is not in place).
Go up
Return to main index.