* The -smb flag in QEMU/KVM is unreliable: it doesn't work without the

-no-kvm-irqchip flag, and on the Hydra machines only works on the
  rather old KVM 76.  So as a workaround, don't use -smb, but use
  QEMU's "guestfwd" feature to forward 10.0.2.4:139 in the guest to a
  Unix domain socket on the host connected to Samba.
* Use "cache=writeback" to improve performance a lot.
* Use "werror=report" to make QEMU crash instead of hang if the host
  filesystem is full.

svn path=/nixpkgs/trunk/; revision=22249
This commit is contained in:
Eelco Dolstra 2010-06-13 23:49:16 +00:00
parent 9bf1c85983
commit 1f8e6d4814

View File

@ -1,4 +1,4 @@
{pkgs}: { pkgs }:
with pkgs; with pkgs;
@ -7,15 +7,18 @@ rec {
inherit (linuxPackages_2_6_32) kernel; inherit (linuxPackages_2_6_32) kernel;
kvm = pkgs.kvm76; kvm = pkgs.qemu_kvm;
modulesClosure = makeModulesClosure { modulesClosure = makeModulesClosure {
inherit kernel; inherit kernel;
rootModules = ["cifs" "virtio_net" "virtio_pci" "virtio_blk" "virtio_balloon" "nls_utf8" "ext2" "ext3" "unix"]; rootModules = [ "cifs" "virtio_net" "virtio_pci" "virtio_blk" "virtio_balloon" "nls_utf8" "ext2" "ext3" "unix" "sd_mod" "ata_piix" ];
}; };
hd = "vda"; # either "sda" or "vda"
initrdUtils = runCommand "initrd-utils" initrdUtils = runCommand "initrd-utils"
{ buildInputs = [ nukeReferences ]; { buildInputs = [ nukeReferences ];
allowedReferences = [ "out" modulesClosure ]; # prevent accidents like glibc being included in the initrd allowedReferences = [ "out" modulesClosure ]; # prevent accidents like glibc being included in the initrd
@ -47,8 +50,8 @@ rec {
# Copy some other tools. # Copy some other tools.
cp ${bash}/bin/bash $out/bin cp ${bash}/bin/bash $out/bin
cp ${module_init_tools}/sbin/insmod $out/bin/insmod cp ${module_init_tools}/sbin/insmod $out/bin/insmod
cp ${pkgs.nettools}/sbin/ifconfig $out/bin cp ${nettools}/sbin/ifconfig $out/bin
cp ${pkgs.sysvinit}/sbin/halt $out/bin cp ${sysvinit}/sbin/halt $out/bin
# Run patchelf to make the programs refer to the copied libraries. # Run patchelf to make the programs refer to the copied libraries.
for i in $out/bin/* $out/lib/*; do if ! test -L $i; then nuke-refs $i; fi; done for i in $out/bin/* $out/lib/*; do if ! test -L $i; then nuke-refs $i; fi; done
@ -65,8 +68,8 @@ rec {
mknod ${dev}/null c 1 3 mknod ${dev}/null c 1 3
mknod ${dev}/zero c 1 5 mknod ${dev}/zero c 1 5
mknod ${dev}/tty c 5 0 mknod ${dev}/tty c 5 0
. /sys/class/block/vda/uevent . /sys/class/block/${hd}/uevent
mknod ${dev}/vda b $MAJOR $MINOR mknod ${dev}/${hd} b $MAJOR $MINOR
''; '';
@ -123,25 +126,17 @@ rec {
if test -z "$mountDisk"; then if test -z "$mountDisk"; then
mount -t tmpfs none /fs mount -t tmpfs none /fs
else else
mount -t ext2 /dev/vda /fs mount -t ext2 /dev/${hd} /fs
fi fi
mkdir -p /fs/hostfs mkdir -p /fs/hostfs
mkdir -p /fs/dev mkdir -p /fs/dev
mount -o bind /dev /fs/dev mount -o bind /dev /fs/dev
n=. for ((n = 0; n < 10; n++)); do
echo "mounting host filesystem..." echo "mounting host filesystem, attempt $n..."
while true; do mount -t cifs //10.0.2.4/qemu /fs/hostfs -o guest,username=nobody && break
if mount -t cifs //10.0.2.4/qemu /fs/hostfs -o guest,username=nobody; then
break
else
n=".$n"
test ''${#n} -le 10 || exit 1
sleep 1
echo "retrying..."
fi
done done
mkdir -p /fs/nix/store mkdir -p /fs/nix/store
@ -215,10 +210,10 @@ rec {
qemuCommandLinux = '' qemuCommandLinux = ''
qemu-system-x86_64 -no-kvm-irqchip \ qemu-system-x86_64 \
-nographic -no-reboot \ -nographic -no-reboot \
-net nic,model=virtio -net user -smb / \ -net nic,model=virtio -chardev socket,id=samba,path=$TMPDIR/samba -net user,guestfwd=tcp:10.0.2.4:139-chardev:samba \
-drive file=$diskImage,if=virtio,boot=on \ -drive file=$diskImage,if=virtio,boot=on,cache=writeback,werror=report \
-kernel ${kernel}/bzImage \ -kernel ${kernel}/bzImage \
-initrd ${initrd}/initrd \ -initrd ${initrd}/initrd \
-append "console=ttyS0 panic=1 command=${stage2Init} tmpDir=$TMPDIR out=$out mountDisk=$mountDisk" \ -append "console=ttyS0 panic=1 command=${stage2Init} tmpDir=$TMPDIR out=$out mountDisk=$mountDisk" \
@ -229,12 +224,28 @@ rec {
vmRunCommand = qemuCommand: writeText "vm-run" '' vmRunCommand = qemuCommand: writeText "vm-run" ''
export > saved-env export > saved-env
PATH=${coreutils}/bin:${kvm}/bin:${samba}/sbin PATH=${coreutils}/bin:${kvm}/bin
diskImage=''${diskImage:-/dev/null} diskImage=''${diskImage:-/dev/null}
eval "$preVM" eval "$preVM"
cat > smb.conf <<EOF
[global]
private dir=$TMPDIR
smb ports=0
socket address=127.0.0.1
pid directory=$TMPDIR
lock directory=$TMPDIR
log file=$TMPDIR/log.smbd
smb passwd file=$TMPDIR/smbpasswd
security = share
[qemu]
path=/
read only=no
guest ok=yes
EOF
# Write the command to start the VM to a file so that the user can # Write the command to start the VM to a file so that the user can
# debug inside the VM if the build fails (when Nix is called with # debug inside the VM if the build fails (when Nix is called with
# the -K option to preserve the temporary build directory). # the -K option to preserve the temporary build directory).
@ -242,6 +253,8 @@ rec {
#! ${bash}/bin/sh #! ${bash}/bin/sh
diskImage=$diskImage diskImage=$diskImage
TMPDIR=$TMPDIR TMPDIR=$TMPDIR
${socat}/bin/socat unix-listen:$TMPDIR/samba exec:'${samba}/sbin/smbd -s $TMPDIR/smb.conf' &
while [ ! -e $TMPDIR/samba ]; do sleep 0.1; done # ugly
${qemuCommand} ${qemuCommand}
EOF EOF
@ -271,8 +284,8 @@ rec {
createRootFS = '' createRootFS = ''
mkdir /mnt mkdir /mnt
${e2fsprogs}/sbin/mke2fs -F /dev/vda ${e2fsprogs}/sbin/mke2fs -F /dev/${hd}
${utillinux}/bin/mount -t ext2 /dev/vda /mnt ${utillinux}/bin/mount -t ext2 /dev/${hd} /mnt
if test -e /mnt/.debug; then if test -e /mnt/.debug; then
exec ${bash}/bin/sh exec ${bash}/bin/sh
@ -429,6 +442,7 @@ rec {
# Make the Nix store available in /mnt, because that's where the RPMs live. # Make the Nix store available in /mnt, because that's where the RPMs live.
mkdir -p /mnt/nix/store mkdir -p /mnt/nix/store
${utillinux}/bin/mount -o bind /nix/store /mnt/nix/store ${utillinux}/bin/mount -o bind /nix/store /mnt/nix/store
${utillinux}/bin/mount -o bind /tmp /mnt/tmp
echo "installing RPMs..." echo "installing RPMs..."
PATH=/usr/bin:/bin:/usr/sbin:/sbin $chroot /mnt \ PATH=/usr/bin:/bin:/usr/sbin:/sbin $chroot /mnt \
@ -440,6 +454,7 @@ rec {
rm /mnt/.debug rm /mnt/.debug
${utillinux}/bin/umount /mnt/nix/store ${utillinux}/bin/umount /mnt/nix/store
${utillinux}/bin/umount /mnt/tmp
${utillinux}/bin/umount /mnt ${utillinux}/bin/umount /mnt
''; '';