storage: implement two-layers of dm-snapshot in block-snapshot script
Have dm-snapshot of dm-snapshot. The first layer is to "cache" changes done by base volume holder (TemplateVM in case of root.img), the second layer is to hold changes do by snapshot volume holder (AppVM in case of root.img). In case of Linux VMs the second layer is normally done inside of VM (original volume is exposed read-only). But this does not work for non-Linux VMs, orr even Linux but without qubes-specific startup scripts. This is first part of the change - actual construction of two layers of dm-snapshot, not plugged in to core scripts yet. QubesOS/qubes-issues#2256
This commit is contained in:
parent
48f78dfbc8
commit
b89689e278
@ -53,14 +53,21 @@ get_dev() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get_dm_snapshot_name() {
|
get_dm_snapshot_name() {
|
||||||
|
local base cow cow2
|
||||||
|
|
||||||
base=$1
|
base=$1
|
||||||
cow=$2
|
cow=$2
|
||||||
|
cow2=$3
|
||||||
|
|
||||||
echo snapshot-$(stat -c '%D:%i' "$base")-$(stat -c '%D:%i' "$cow")
|
name="snapshot-$(stat -c '%D:%i' "$base")-$(stat -c '%D:%i' "$cow")"
|
||||||
|
if [ -n "$cow2" ]; then
|
||||||
|
name="$name-$(stat -c '%D:%i' "$cow2")"
|
||||||
|
fi
|
||||||
|
echo "$name"
|
||||||
}
|
}
|
||||||
|
|
||||||
create_dm_snapshot() {
|
create_dm_snapshot() {
|
||||||
local base_dev cow_dev base_sz
|
local base_dev cow_dev base_sz base cow dm_devname
|
||||||
|
|
||||||
dm_devname=$1
|
dm_devname=$1
|
||||||
base=$2
|
base=$2
|
||||||
@ -77,7 +84,7 @@ create_dm_snapshot() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
create_dm_snapshot_origin() {
|
create_dm_snapshot_origin() {
|
||||||
local base_dev base_sz
|
local base_dev base_sz dm_devname base
|
||||||
|
|
||||||
dm_devname=$1
|
dm_devname=$1
|
||||||
base=$2
|
base=$2
|
||||||
@ -103,8 +110,14 @@ case "$command" in
|
|||||||
fi
|
fi
|
||||||
echo $p > "$HOTPLUG_STORE-params"
|
echo $p > "$HOTPLUG_STORE-params"
|
||||||
echo $t > "$HOTPLUG_STORE-type"
|
echo $t > "$HOTPLUG_STORE-type"
|
||||||
base=${p/:*/}
|
base=${p%%:*}
|
||||||
cow=${p/*:/}
|
cow=${p#*:}
|
||||||
|
cow2=${p##*:}
|
||||||
|
if [ "$cow" != "$cow2" ]; then
|
||||||
|
cow=${cow%:*}
|
||||||
|
else
|
||||||
|
cow2=""
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -L "$base" ]; then
|
if [ -L "$base" ]; then
|
||||||
base=$(readlink -f "$base") || fatal "$base link does not exist."
|
base=$(readlink -f "$base") || fatal "$base link does not exist."
|
||||||
@ -114,6 +127,10 @@ case "$command" in
|
|||||||
cow=$(readlink -f "$cow") || fatal "$cow link does not exist."
|
cow=$(readlink -f "$cow") || fatal "$cow link does not exist."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -L "$cow2" ]; then
|
||||||
|
cow2=$(readlink -f "$cow2") || fatal "$cow2 link does not exist."
|
||||||
|
fi
|
||||||
|
|
||||||
# first ensure that snapshot device exists (to write somewhere changes from snapshot-origin)
|
# first ensure that snapshot device exists (to write somewhere changes from snapshot-origin)
|
||||||
dm_devname=$(get_dm_snapshot_name "$base" "$cow")
|
dm_devname=$(get_dm_snapshot_name "$base" "$cow")
|
||||||
|
|
||||||
@ -122,6 +139,12 @@ case "$command" in
|
|||||||
# prepare snapshot device
|
# prepare snapshot device
|
||||||
create_dm_snapshot $dm_devname "$base" "$cow"
|
create_dm_snapshot $dm_devname "$base" "$cow"
|
||||||
|
|
||||||
|
if [ -n "$cow2" ]; then
|
||||||
|
dm_devname_full=$(get_dm_snapshot_name "$base" "$cow" "$cow2")
|
||||||
|
create_dm_snapshot "$dm_devname_full" "/dev/mapper/$dm_devname" "$cow2"
|
||||||
|
dm_devname="$dm_devname_full"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$t" == "snapshot" ]; then
|
if [ "$t" == "snapshot" ]; then
|
||||||
#that's all for snapshot, store name of prepared device
|
#that's all for snapshot, store name of prepared device
|
||||||
xenstore_write "$XENBUS_PATH/node" "/dev/mapper/$dm_devname"
|
xenstore_write "$XENBUS_PATH/node" "/dev/mapper/$dm_devname"
|
||||||
@ -152,8 +175,14 @@ case "$command" in
|
|||||||
case $t in
|
case $t in
|
||||||
snapshot|origin)
|
snapshot|origin)
|
||||||
p=$3
|
p=$3
|
||||||
base=${p/:*/}
|
base=${p%%:*}
|
||||||
cow=${p/*:/}
|
cow=${p#*:}
|
||||||
|
cow2=${p##*:}
|
||||||
|
if [ "$cow" != "$cow2" ]; then
|
||||||
|
cow=${cow%:*}
|
||||||
|
else
|
||||||
|
cow2=""
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -L "$base" ]; then
|
if [ -L "$base" ]; then
|
||||||
base=$(readlink -f "$base") || fatal "$base link does not exist."
|
base=$(readlink -f "$base") || fatal "$base link does not exist."
|
||||||
@ -163,6 +192,10 @@ case "$command" in
|
|||||||
cow=$(readlink -f "$cow") || fatal "$cow link does not exist."
|
cow=$(readlink -f "$cow") || fatal "$cow link does not exist."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -L "$cow2" ]; then
|
||||||
|
cow2=$(readlink -f "$cow2") || fatal "$cow2 link does not exist."
|
||||||
|
fi
|
||||||
|
|
||||||
# first ensure that snapshot device exists (to write somewhere changes from snapshot-origin)
|
# first ensure that snapshot device exists (to write somewhere changes from snapshot-origin)
|
||||||
dm_devname=$(get_dm_snapshot_name "$base" "$cow")
|
dm_devname=$(get_dm_snapshot_name "$base" "$cow")
|
||||||
|
|
||||||
@ -171,6 +204,12 @@ case "$command" in
|
|||||||
# prepare snapshot device
|
# prepare snapshot device
|
||||||
create_dm_snapshot $dm_devname "$base" "$cow"
|
create_dm_snapshot $dm_devname "$base" "$cow"
|
||||||
|
|
||||||
|
if [ -n "$cow2" ]; then
|
||||||
|
dm_devname_full=$(get_dm_snapshot_name "$base" "$cow" "$cow2")
|
||||||
|
create_dm_snapshot "$dm_devname_full" "/dev/mapper/$dm_devname" "$cow2"
|
||||||
|
dm_devname="$dm_devname_full"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$t" == "snapshot" ]; then
|
if [ "$t" == "snapshot" ]; then
|
||||||
#that's all for snapshot, store name of prepared device
|
#that's all for snapshot, store name of prepared device
|
||||||
echo "/dev/mapper/$dm_devname"
|
echo "/dev/mapper/$dm_devname"
|
||||||
@ -232,7 +271,7 @@ case "$command" in
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# get list of used (loop) devices
|
# get list of used (loop) devices
|
||||||
deps="$(dmsetup deps $node | cut -d: -f2 | sed -e 's#(7, \([0-9]\+\))#/dev/loop\1#g')"
|
deps="$(dmsetup deps $node -o blkdevname | cut -d: -f2 | sed -e 's#(\([a-z0-9-]\+\))#/dev/\1#g')"
|
||||||
|
|
||||||
# if this is origin
|
# if this is origin
|
||||||
if [ "${node/origin/}" != "$node" ]; then
|
if [ "${node/origin/}" != "$node" ]; then
|
||||||
@ -241,7 +280,8 @@ case "$command" in
|
|||||||
use_count=$(dmsetup info $snap|grep Open|awk '{print $3}')
|
use_count=$(dmsetup info $snap|grep Open|awk '{print $3}')
|
||||||
if [ "$use_count" -eq 0 ]; then
|
if [ "$use_count" -eq 0 ]; then
|
||||||
# unused snapshot - remove it
|
# unused snapshot - remove it
|
||||||
deps="$deps $(dmsetup deps $snap | cut -d: -f2 | sed -e 's#(7, \([0-9]\+\))#/dev/loop\1#g')"
|
deps="$deps $(dmsetup deps $snap -o blkdevname | cut -d: -f2 |\
|
||||||
|
sed -e 's#(\([a-z0-9-]\+\))#/dev/\1#g')"
|
||||||
log debug "Removing $snap"
|
log debug "Removing $snap"
|
||||||
dmsetup remove $snap
|
dmsetup remove $snap
|
||||||
fi
|
fi
|
||||||
@ -265,11 +305,18 @@ case "$command" in
|
|||||||
dmsetup remove $node
|
dmsetup remove $node
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# try to free loop devices
|
# try to free unused devices
|
||||||
for dev in $deps; do
|
for dev in $deps; do
|
||||||
if [ -b "$dev" ]; then
|
if [ -b "$dev" ]; then
|
||||||
log debug "Removing $dev"
|
log debug "Removing $dev"
|
||||||
losetup -d $dev 2> /dev/null || true
|
case $dev in
|
||||||
|
/dev/loop*)
|
||||||
|
losetup -d $dev 2> /dev/null || true
|
||||||
|
;;
|
||||||
|
/dev/dm-*)
|
||||||
|
dmsetup remove $dev 2> /dev/null || true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user