From e0b50db2ee6ecfe2b47566acd3f7e28ec8010670 Mon Sep 17 00:00:00 2001 From: Marek Marczykowski Date: Sat, 26 Feb 2011 03:42:55 +0100 Subject: [PATCH] Update TemplateVM with running AppVM: part 1 snapshot and origin device type for xen --- common/block-snapshot | 189 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 common/block-snapshot diff --git a/common/block-snapshot b/common/block-snapshot new file mode 100644 index 0000000..a08a10c --- /dev/null +++ b/common/block-snapshot @@ -0,0 +1,189 @@ +#!/bin/bash + +# Usage: block-snapshot add|remove img-file cow-file +# +# This creates dm-snapshot device on given arguments + +dir=$(dirname "$0") +. "$dir/block-common.sh" + + +get_dev() { + dev=$1 + + if [ -L "$dev" ]; then + dev=$(readlink -f "$dev") || fatal "$dev link does not exist." + fi + + if [ -f "$dev" ]; then + file=$dev + + inode=$(stat -c '%i' "$file") + devnum=$(stat -c '%D' "$file") + if [ -z "$inode" ] || [ -z "$devnum" ] + then + release_lock "block" + fatal "Unable to lookup $file: dev: $devnum inode: $inode" + fi + + dev_list=$(losetup -a | grep ' \[0*'${dev}'\]:'${inode} | cut -d : -f 1) + for dev in $dev_list; do + # found existing loop to this file + echo $dev + return + done + + + # assign new loop device + loopdev=$(losetup -f 2>/dev/null || find_free_loopback_dev) + if [ "$loopdev" = '' ] + then + release_lock "block" + fatal 'Failed to find an unused loop device' + fi + + do_or_die losetup "$loopdev" "$file" + echo $loopdev + else + test -e "$dev" || fatal "$dev does not exist." + test -b "$dev" || fatal "$dev is not a block device nor file." + fi +} + +get_dm_snapshot_name() { + base=$1 + cow=$2 + + echo snapshot-$(stat -c '%D:%i' "$base")-$(stat -c '%D:%i' "$cow") +} + +create_dm_snapshot() { + local base_dev cow_dev base_sz + + dm_devname=$1 + base=$2 + cow=$3 + + if [ ! -e /dev/mapper/$dm_devname ]; then + # prepare new snapshot device + base_dev=$(get_dev $base) + cow_dev=$(get_dev $cow) + base_sz=$(blockdev --getsz $base_dev) + do_or_die dmsetup create $dm_devname --table "0 $base_sz snapshot $base_dev $cow_dev P 256" + fi + +} + +create_dm_snapshot_origin() { + local base_dev base_sz + + dm_devname=$1 + base=$2 + + if [ ! -e /dev/mapper/$dm_devname ]; then + # prepare new snapshot-origin device + base_dev=$(get_dev $base) + base_sz=$(blockdev --getsz $base_dev) + do_or_die dmsetup create $dm_devname --table "0 $base_sz snapshot-origin $base_dev" + fi +} + +t=$(xenstore_read_default "$XENBUS_PATH/type" 'MISSING') + + +case "$command" in + add) + case $t in + snapshot|origin) + p=$(xenstore_read "$XENBUS_PATH/params") + base=${p/:*/} + cow=${p/*:/} + + if [ -L "$base" ]; then + base=$(readlink -f "$base") || fatal "$base link does not exist." + fi + + if [ -L "$cow" ]; then + cow=$(readlink -f "$cow") || fatal "$cow link does not exist." + fi + + # first ensure that snapshot device exists (to write somewhere changes from snapshot-origin) + dm_devname=$(get_dm_snapshot_name "$base" "$cow") + + claim_lock "block" + + # prepare snapshot device + create_dm_snapshot $dm_devname "$base" "$cow" + + if [ "$t" == "snapshot" ]; then + #that's all for snapshot, store name of prepared device + xenstore_write "$XENBUS_PATH/node" "/dev/mapper/$dm_devname" + write_dev /dev/mapper/$dm_devname + elif [ "$t" == "origin" ]; then + # for origin - prepare snapshot-origin device and store its name + dm_devname=origin-$(stat -c '%D:%i' "$base") + create_dm_snapshot_origin $dm_devname "$base" + xenstore_write "$XENBUS_PATH/node" "/dev/mapper/$dm_devname" + write_dev /dev/mapper/$dm_devname + fi + + release_lock "block" + exit 0 + ;; + esac + ;; + remove) + case $t in + snapshot|origin) + node=$(xenstore_read "$XENBUS_PATH/node") + + if [ -z "$node" ]; then + fatal "No device node to remove" + fi + + claim_lock "block" + + use_count=$(dmsetup info $node|grep Open|awk '{print $3}') + + # do not remove snapshot if snapshot origin is still present + if [ "${node/snapshot/}" != "$node" -a + -e "/dev/mapper/origin-$(echo $node|cut -d- -f2)" ]; then + ((use_count++)) + fi + + if [ "$use_count" -gt 0 ]; then + log info "Device $node still in use - not removing" + exit 0 + fi + + # get list of used (loop) devices + deps="$(dmsetup deps $node | cut -d: -f2 | sed -e 's#(7, \([0-9]+\))#/dev/loop\1#g')" + + # remove unused snapshots + for snap in /dev/mapper/snapshot-$(echo $node|cut -d- -f2); do + use_count=$(dmsetup info $snap|grep Open|awk '{print $3}') + if [ $use_count -eq 0 ]; then + # unused snapshot - remove it + deps="$deps $(dmsetup deps $snap | cut -d: -f2 | sed -e 's#(7, \([0-9]+\))#/dev/loop\1#g')" + dmsetup remove $snap + fi + done + + do_or_die dmsetup remove $node + + # try to free loop devices + for dev in $deps; do + if [ -b "$dev" ]; then + losetup -d $dev 2> /dev/null + fi + done + + release_lock "block" + + exit 0 + ;; + esac + ;; +esac + +# vim:sw=2:et: