[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [RFC 3/6] linux-stubdomain: Build a disk image.



This patch build a disk image intend to be mounted as rootfs by the
stub-domain. It is build using the 'debugfs' tool and make a ext2 fs.

Signed-off-by: Anthony PERARD <anthony.perard@xxxxxxxxxx>
---
 stubdom-linux/.gitignore        |   2 +
 stubdom-linux/Makefile          |  16 +++-
 stubdom-linux/extra/initscript  |  40 +++++++++
 stubdom-linux/extra/qemu-ifup   |   7 ++
 stubdom-linux/mk-ramdisk-common | 178 ++++++++++++++++++++++++++++++++++++++++
 stubdom-linux/mk-ramdisk-ioemu  | 124 ++++++++++++++++++++++++++++
 6 files changed, 366 insertions(+), 1 deletion(-)
 create mode 100644 stubdom-linux/extra/initscript
 create mode 100644 stubdom-linux/extra/qemu-ifup
 create mode 100755 stubdom-linux/mk-ramdisk-common
 create mode 100755 stubdom-linux/mk-ramdisk-ioemu

diff --git a/stubdom-linux/.gitignore b/stubdom-linux/.gitignore
index 170e0c7..2cb91da 100644
--- a/stubdom-linux/.gitignore
+++ b/stubdom-linux/.gitignore
@@ -1,3 +1,5 @@
 /linux-*.tar.xz
 /linux-*/
 /vmlinuz-stubdom
+/initramfs
+/stubdom-disk.img
diff --git a/stubdom-linux/Makefile b/stubdom-linux/Makefile
index 0844046..93f8f48 100644
--- a/stubdom-linux/Makefile
+++ b/stubdom-linux/Makefile
@@ -9,7 +9,13 @@ LINUX_V=linux-3.4.13
 QEMU_TREE=git://xenbits.xen.org/people/aperard/qemu-dm.git
 QEMU_BRANCH=origin/stubdom-preview1
 
-all: vmlinuz-stubdom
+# Stubdom disk content
+STUBDOM_DISK_FILE= \
+  qemu-build/i386-softmmu/qemu-system-i386 \
+  extra/initscript \
+  extra/qemu-ifup
+
+all: stubdom-disk.img vmlinuz-stubdom
 
 qemu-remote:
        export GIT=$(GIT); \
@@ -67,3 +73,11 @@ $(LINUX_V)/arch/x86/boot/bzImage: $(LINUX_V)/.config
 
 vmlinuz-stubdom: $(LINUX_V)/arch/x86/boot/bzImage
        cp -f $^ $@
+
+stubdom-disk.img: mk-ramdisk-common mk-ramdisk-ioemu $(STUBDOM_DISK_FILE)
+       env -u MAKELEVEL -u MAKEFLAGS -u MFLAGS ./mk-ramdisk-ioemu
+       chmod a-w $@
+
+install: stubdom-disk.img vmlinuz-stubdom
+       cp -f vmlinuz-stubdom $(DESTDIR)/usr/lib/xen/boot/
+       cp -f stubdom-disk.img $(DESTDIR)/usr/lib/xen/boot/
diff --git a/stubdom-linux/extra/initscript b/stubdom-linux/extra/initscript
new file mode 100644
index 0000000..122892f
--- /dev/null
+++ b/stubdom-linux/extra/initscript
@@ -0,0 +1,40 @@
+#!/bin/busybox sh
+
+_initscript_panic() {
+  sleep 10
+}
+
+trap _initscript_panic 0
+
+set -e
+set -x
+mount -t sysfs /sys /sys
+mount -t proc /proc /proc
+mount -t xenfs -o nodev /proc/xen /proc/xen
+
+# TODO: Check if there is network for the vm before doing this
+if test -e /sys/class/net/eth0; then
+  ip link set eth0 address fe:ff:ff:ff:ff:fe
+  ip addr flush eth0
+  ip link set eth0 up
+  brctl addbr br0
+  brctl addif br0 eth0
+  ip link set br0 up
+else
+  echo "No network interface named eth0."
+  ls -l /sys/class/net/
+fi
+
+# TODO Could probably to xenstore-read `xenstore-read vm`/image/dmargs
+# because /local/domain/$domid is probably the root for relative path
+domid=$(xenstore-read target)
+dom_path="/local/domain/$domid"
+vm_path=$(xenstore-read "$dom_path/vm")
+dm_args=$(xenstore-read "$vm_path/image/dmargs")
+
+( sleep 30; free ) &
+( sleep 60; free ) &
+#( sleep 120; ip addr ) &
+( sleep 120; free ) &
+free
+/bin/qemu $dm_args
diff --git a/stubdom-linux/extra/qemu-ifup b/stubdom-linux/extra/qemu-ifup
new file mode 100644
index 0000000..d71672b
--- /dev/null
+++ b/stubdom-linux/extra/qemu-ifup
@@ -0,0 +1,7 @@
+#! /bin/busybox sh
+
+ip link set "$1" down
+ip link set "$1" address fe:ff:ff:ff:ff:fd
+ip addr flush "$1"
+brctl addif br0 "$1"
+ip link set "$1" up
diff --git a/stubdom-linux/mk-ramdisk-common b/stubdom-linux/mk-ramdisk-common
new file mode 100755
index 0000000..9a4a810
--- /dev/null
+++ b/stubdom-linux/mk-ramdisk-common
@@ -0,0 +1,178 @@
+#!/bin/bash
+#
+# This a simple implementaton of mkinitrd
+
+
+# Set the umask. For iscsi, the initrd can contain platintext
+# password (chap secret), so only allow read by owner.
+umask 022
+
+TMPDIR="/tmp"
+PROBE="yes"
+MNTIMAGE="`pwd`/initramfs/"
+IMAGE="./initramfs.cpio"
+verbose=""
+: ${debug:=false}
+case $debug in
+  true|false) ;;
+  *)
+    echo '$debug need to be true or false.'
+    exit 1
+    ;;
+esac
+$debug && verbose='-v'
+
+DSO_DEPS=""
+LDSO=""
+get_dso_deps() {
+    bin="$1" ; shift
+    DSO_DEPS=""
+
+    declare -a FILES
+    declare -a NAMES
+
+    # this is a hack, but the only better way requires binutils or elfutils
+    # be installed.  i.e., we need readelf to find the interpretter.
+    if [ -z "$LDSO" ]; then
+        for ldso in /lib*/ld*.so* ; do
+            [ -L $ldso ] && continue
+            [ -x $ldso ] || continue
+            $ldso --verify $bin >/dev/null 2>&1 || continue
+            LDSO="$ldso"
+        done
+    fi
+
+    # I still hate shell.
+    declare -i n=0
+    while read NAME I0 FILE ADDR I1 ; do
+      # ignore libfakeroot lib
+      [ "$NAME" == "libfakeroot-sysv.so" ] && continue
+      [ "$NAME" == "libfakeroot.so" ] && continue
+      [ "$NAME" == "libfakeroot-0.so" ] && continue
+      [ "$FILE" == "not" ] && FILE="$FILE $ADDR"
+      NAMES[$n]="$NAME"
+      FILES[$n]="$FILE"
+      n=$((n+1))
+    done << EOF
+        $(LD_TRACE_PRELINKING=1 LD_WARN= LD_TRACE_LOADED_OBJECTS=1 \
+            $LDSO $bin 2>/dev/null)
+EOF
+
+    [ ${#FILES[*]} -eq 0 ] && return
+
+    # we don't want the name of the binary in the list
+    if [ "${FILES[0]}" == "$bin" ]; then
+        FILES[0]=""
+        NAMES[0]=""
+        [ ${#FILES[*]} -eq 1 ] && return
+    fi
+
+    declare -i n=0
+    while [ $n -lt ${#FILES[*]} ]; do
+        FILE="${FILES[$n]}"
+        if [ "$FILE" == "not found" ]; then
+            cat 1>&2 <<EOF
+There are missing files on your system.  The dynamic object $bin
+requires ${NAMES[$n]} n order to properly function.  mkinitrd cannot continue.
+EOF
+            exit 1
+        fi
+        case "$FILE" in
+            /lib*)
+                TLIBDIR=`echo "$FILE" | sed 's,\(/lib[^/]*\)/.*$,\1,'`
+                BASE=`basename "$FILE"`
+                # Prefer nosegneg libs over direct segment accesses on i686.
+                if [ -f "$TLIBDIR/i686/nosegneg/$BASE" ]; then
+                    FILE="$TLIBDIR/i686/nosegneg/$BASE"
+                # Otherwise, prefer base libraries rather than their optimized
+                # variants.
+                elif [ -f "$TLIBDIR/$BASE" ]; then
+                    FILE="$TLIBDIR/$BASE"
+                fi
+                FILES[$n]="$FILE"
+                ;;
+        esac
+        dynamic="yes"
+        n=$((n+1))
+    done
+
+    DSO_DEPS="${FILES[@]}"
+}
+
+readlink_() {
+  l=$(readlink "$1")
+  if ! test -e "$l"; then
+    echo "$(dirname "$1")/$l"
+  else
+    echo "$l"
+  fi
+}
+
+indent_chars="_"
+inst() {
+    if [ "$#" != "2" -a "$#" != "3" ];then
+        echo "usage: inst <file> <root> [<destination file>]"
+        return 1
+    fi
+    local file="$1" ; shift
+    local root="${1%%/}/"; shift
+    local dest="${1##/}"; shift || true
+    [ -z "$dest" ] && dest="${file##/}"
+
+    local old_indent_chars=${indent_chars}
+    indent_chars="${indent_chars}  "
+    indent=${indent_chars:2}
+
+    mkdir -p "$root/$(dirname $dest)"
+
+    local RET=0
+    local target=""
+    [ -L "$file" ] && target=$(readlink_ "$file")
+    if [ -n "$target" -a "$dest" != "$target" ]; then
+        if [ -e "$root$dest" ]; then
+            $debug && echo "${indent}$dest already exists"
+            RET=0
+        else
+            $debug && echo "l${indent:1}$file -> $dest"
+            ln -sf "$(readlink "$file")" "$root$dest"
+
+            inst "$target" "$root" "/lib/$(basename $target)"
+            l=`echo "$x" | sed -n 's,\(/lib[^/]*\)/.*$,\1,p'`
+            if [ -n "$l" ]; then
+                inst "$x" "$root" "$l"/`basename "$x"`
+            else
+                inst "$x" "$root"
+            fi
+            RET=$?
+            indent_chars=${old_indent_chars}
+            return $RET
+        fi
+    fi
+
+    if [ -e "$root$dest" ]; then
+   #     echo "${indent}$root$dest already exists"
+        RET=0
+    else
+        if [ -n "$target" -a -L "$target" ]; then
+            inst "$target" "$root"
+            RET=$?
+        else
+            $debug && echo "${indent}$file -> $dest"
+            cp -aL "$file" "$root$dest"
+
+            get_dso_deps "$file"
+            local DEPS="$DSO_DEPS"
+            for x in $DEPS ; do
+                $debug && echo "_${indent:1}$x (deb of $(basename $file)"
+                #TLIBDIR=`echo "${x#$XEN_LIB}" | sed -r 
's,.*(/lib[^/]*)/.*$,\1,'`
+                #[ "$TLIBDIR" == "$(basename "$x")" ] &&
+                TLIBDIR="/lib"
+                BASE=`basename "$x"`
+                inst "$x" "$root" "$TLIBDIR/$BASE"
+            done
+            RET=$?
+        fi
+    fi
+    indent_chars=${old_indent_chars}
+    return $RET
+}
diff --git a/stubdom-linux/mk-ramdisk-ioemu b/stubdom-linux/mk-ramdisk-ioemu
new file mode 100755
index 0000000..9b222d1
--- /dev/null
+++ b/stubdom-linux/mk-ramdisk-ioemu
@@ -0,0 +1,124 @@
+#!/bin/bash
+
+XEN_ROOT="`pwd`/.."
+
+script_qemu_ifup="extra/qemu-ifup"
+script_init="extra/initscript"
+
+debug=false
+verbose=
+
+set -e
+export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$XEN_ROOT/tools/xenstore"
+export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$XEN_ROOT/tools/libxc"
+
+source ./mk-ramdisk-common
+
+cp(){
+  command cp $verbose "$@"
+}
+
+rm -fr "$MNTIMAGE" "$IMAGE"
+
+mkdir -p "$MNTIMAGE"/{bin,etc,proc/xen,sys,lib,usr,dev,tmp}
+ln -s ../lib "$MNTIMAGE"/usr/lib
+ln -s lib "$MNTIMAGE"/lib64
+
+echo "Building initrd in $MNTIMAGE"
+#inst /bin/busybox "$MNTIMAGE" /bin/busybox
+cp -L /bin/busybox "$MNTIMAGE/bin/busybox"
+# Will use make install from qemu
+make DESTDIR="$MNTIMAGE" -C qemu-build install
+# this gather libs install on the system
+inst "$MNTIMAGE/bin/qemu-system-i386" "$MNTIMAGE" /bin/qemu
+
+# this cp keep the link to ld-2.11.x.so
+if test "`uname -m`" = x86_64; then
+  cp --no-dereference "/lib/ld-linux-x86-64.so.2" 
"$MNTIMAGE/lib/ld-linux-x86-64.so.2"
+else
+  cp --no-dereference "/lib/ld-linux.so.2" "$MNTIMAGE/lib/ld-linux.so.2"
+fi
+
+inst "$XEN_ROOT/tools/xenstore/xenstore-read" "$MNTIMAGE" "/bin/xenstore-read"
+
+cp "$script_qemu_ifup" "$MNTIMAGE/etc/"
+chmod +x "$MNTIMAGE/etc/qemu-ifup"
+cp "$script_init" "$MNTIMAGE/init"
+chmod 755 "$MNTIMAGE/init"
+
+mkdir -p $MNTIMAGE/etc/udev
+touch $MNTIMAGE/etc/udev/udev.conf
+
+findall() {
+    find "$@"
+}
+
+ln -s busybox "$MNTIMAGE/bin/sleep"
+ln -s busybox "$MNTIMAGE/bin/mount"
+
+try_make_disk=true
+if $try_make_disk; then
+  stubdom_disk=stubdom-disk.img
+  rm -f $stubdom_disk
+  dd if=/dev/null of=$stubdom_disk bs=1M seek=40
+  mkfs.ext2 -q -F -m0 $stubdom_disk
+
+  cd "$MNTIMAGE"
+  stubdom_disk="../$stubdom_disk"
+    new_link(){
+      image=$1
+      link=$2
+      target=`readlink $link`
+      dir=`dirname $link`
+      dir=${dir#./}
+      name_link=$(basename $link)
+      dir_inode=$(debugfs -R "stat /$dir" $image 2>/dev/null |
+        sed -nr 's/^Inode: ([[:digit:]]+)[[:space:]].*/\1/p')
+      test "$dir_inode" || echo 'no dir inode found'
+      test "$dir_inode"
+      while true; do
+        free_inode=$(debugfs -R "find_free_inode $dir_inode 0777" -w $image 
2>/dev/null |
+        sed -nr 's/^Free inode found: ([[:digit:]]+)$/\1/p')
+        undel_output="$(debugfs -R "undel <$free_inode> /$dir/$name_link" -w 
$image 2>&1)"
+        if grep -q "make_link: No free space in the directory" 
<<<"$undel_output"; then
+          debugfs -R "expand_dir /$dir" -w $image 2>/dev/null
+        else
+          break
+        fi
+      done
+      debugfs -f <(
+        echo "cd /$dir"
+        echo "set_inode_field $name_link mode 0120777"
+        echo "set_inode_field $name_link size ${#target}"
+        # TODO still need to write the link into blocks
+        if test ${#target} -lt $((12*4)); then
+          # write into direct block
+          blockn=0
+          while test "$target"; do
+            t="${target:0:4}"
+            target="${target:4}"
+            #convert a four charactere string into hexa
+            val=$(printf '0x%02x%02x%02x%02x\n' \'${t:3:1} \'${t:2:1} 
\'${t:1:1} \'${t:0:1})
+            echo "set_inode_field $name_link block[$blockn] $val"
+            blockn=$((blockn+1))
+          done
+        else
+          # write into a block
+          echo >&2 ".... write into block not implemented"
+        fi
+      ) -w $image >/dev/null 2>/dev/null
+    }
+  # TODO Should check for "copy_file: Could not allocate block in ext2 
filesystem"
+  debugfs -f <(find . \
+    \( -type d \! -name . -printf 'cd /\nmkdir %h/%f\n' \) \
+    -o \( -type f -printf 'cd /%h\nwrite %h/%f %f\n' \) \
+    | sed -re 's%^((mkdir|cd) )./%\1/%' ) -w $stubdom_disk >/dev/null
+  find . -type l | while read line; do
+    new_link $stubdom_disk "$line"
+  done
+  fsck.ext2 -fy $stubdom_disk || true
+  cd - >/dev/null
+else
+  (cd "$MNTIMAGE"; findall . | cpio -H newc --quiet -o) >| "$IMAGE" || exit 1
+  gzip -f "$IMAGE"
+fi
-- 
Anthony PERARD


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.