Add --mount flag for 9p host directory sharing

Add support for sharing host directories into the VM via QEMU 9p
(virtio-9p).  The --mount flag can be repeated; each host directory
appears at the same absolute path inside the VM.

Design:
- QEMU: each --mount gets a short 9p tag (slim0, slim1, …) via
  -virtfs local,path=…,mount_tag=slimN,security_model=mapped-xattr.
  Tags are kept short because 9p mount_tag has a ~31-byte limit.
- Kernel cmdline: the full destination path is passed as
  slim.mount=<tag>:<base64(path)> so the init script knows where to
  mount each tag.  Base64 avoids issues with spaces/special chars.
- slim-init.sh: after networking, parse slim.mount= entries, mkdir -p
  the destination, and mount -t 9p <tag> <dest> -o trans=virtio,version=9p2000.L

Tests verify: 9p share detection via sysfs mount_tag, 9p entry in
mount output, file content accessible at the expected path, and clean
VM exit.
This commit is contained in:
2026-09-10 12:19:59 +02:00
parent 6111bbeb8d
commit 90de50dfed
3 changed files with 165 additions and 4 deletions
+99
View File
@@ -136,6 +136,103 @@ EOF
rm -rf "$work"
}
test_mount() {
echo "=== Testing --mount (9p shares) ==="
work="$(mktemp -d)"
# --- Image 1: no WORKINGDIR, test host:guest and multi-mount ---
img="slim-test-mount"
share_dir="$work/share"
share_dir2="$work/share2"
guest_dir="/mnt/guest"
guest_dir2="/mnt/guest2"
mkdir -p "$share_dir" "$share_dir2"
echo "hello from host" > "$share_dir/testfile.txt"
echo "second share" > "$share_dir2/testfile2.txt"
cat > "$work/Containerfile" <<'EOF'
FROM alpine:latest
CMD ["/bin/sh", "-c", "poweroff -f"]
EOF
echo "-- Building container image (no WORKINGDIR)..."
if ! podman build --network=none -t "$img" -f "$work/Containerfile" >/dev/null 2>&1; then
report fail "--mount (podman build failed)"
rm -rf "$work"
return
fi
echo "-- Building slim VM..."
if ! "$SLIM_BIN" build qcow2 "$img" >/dev/null 2>&1; then
report fail "--mount (slim build failed)"
cleanup "$img" "$img"
rm -rf "$work"
return
fi
share_canon=$(readlink -f "$share_dir")
share_canon2=$(readlink -f "$share_dir2")
echo "-- Test 1: --mount host:guest (absolute guest path, multi-mount)..."
output=$(timeout "$TIMEOUT" "$SLIM_BIN" run "$img" \
--mount "${share_dir}:${guest_dir}" \
--mount "${share_dir2}:${guest_dir2}" \
--cmd "for f in /sys/bus/virtio/drivers/9pnet_virtio/virtio*/mount_tag; do [ -f \"\$f\" ] && echo \"\$f: \$(tr -d '\\0' < \"\$f\")\"; done; mount -v; cat ${guest_dir}/testfile.txt 2>/dev/null || echo NO_FILE; cat ${guest_dir2}/testfile2.txt 2>/dev/null || echo NO_FILE2; echo MOUNT_VERIFY_DONE; poweroff -f" \
2>&1 || true)
check_output "$output" "mount_tag: slim0" "--mount 9p share detected"
check_output "$output" "mount_tag: slim1" "--mount second 9p share detected"
check_output "$output" "type 9p" "--mount 9p filesystem in mount list"
check_output "$output" "hello from host" "--mount file accessible at guest path"
check_output "$output" "second share" "--mount second file accessible at guest path"
check_output "$output" "MOUNT_VERIFY_DONE" "--mount VM ran to completion"
cleanup "$img" "$img"
# --- Image 2: with WORKINGDIR, test relative guest path ---
img="slim-test-mount-wd"
share_dir3="$work/share3"
mkdir -p "$share_dir3"
echo "relative share" > "$share_dir3/relfile.txt"
cat > "$work/Containerfile.wd" <<'EOF'
FROM alpine:latest
WORKDIR /app
CMD ["/bin/sh", "-c", "poweroff -f"]
EOF
echo "-- Building container image (WORKINGDIR /app)..."
if ! podman build --network=none -t "$img" -f "$work/Containerfile.wd" >/dev/null 2>&1; then
report fail "--mount relative (podman build failed)"
rm -rf "$work"
return
fi
echo "-- Building slim VM..."
if ! "$SLIM_BIN" build qcow2 "$img" >/dev/null 2>&1; then
report fail "--mount relative (slim build failed)"
cleanup "$img" "$img"
rm -rf "$work"
return
fi
echo "-- Test 2: --mount host:relative-guest (resolved against WORKINGDIR)..."
output=$(timeout "$TIMEOUT" "$SLIM_BIN" run "$img" \
--mount "${share_dir3}:data" \
--cmd "mount -v; cat /app/data/relfile.txt 2>/dev/null || echo NO_REL_FILE; echo REL_VERIFY_DONE; poweroff -f" \
2>&1 || true)
check_output "$output" "type 9p" "--mount relative 9p filesystem in mount list"
check_output "$output" "relative share" "--mount relative file accessible at WORKINGDIR/data"
check_output "$output" "REL_VERIFY_DONE" "--mount relative VM ran to completion"
cleanup "$img" "$img"
rm -rf "$work"
}
test_service() {
echo "=== Testing nextcloud service ==="
@@ -206,6 +303,8 @@ test_distro "archlinux" "archlinux:latest" "RUN pacman -Sy --noconfirm iproute2
test_user
test_mount
test_service
echo ""