ソースを参照

Update TemplateVM with running AppVM: part 1

snapshot and origin device type for xen
Marek Marczykowski 13 年 前
コミット
e0b50db2ee
1 ファイル変更189 行追加0 行削除
  1. 189 0
      common/block-snapshot

+ 189 - 0
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: