mirror of
https://github.com/vdsm/virtual-dsm.git
synced 2026-08-29 04:07:02 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47af1d07f4 | ||
|
|
4660512f12 | ||
|
|
6d37a0426b | ||
|
|
604cad0207 | ||
|
|
3ad7e78787 | ||
|
|
5f908488ef | ||
|
|
dcdc796e59 | ||
|
|
087d876eaf | ||
|
|
25a7d55cdd | ||
|
|
9683b195f3 | ||
|
|
f810576651 | ||
|
|
5fd954bea4 | ||
|
|
768b8fa51a | ||
|
|
b909555ef3 | ||
|
|
a77026eafb | ||
|
|
e8ef357ed2 | ||
|
|
a16c27ecce | ||
|
|
1917eae0ae | ||
|
|
d5bb90f012 | ||
|
|
d854ae811c | ||
|
|
03993aa773 | ||
|
|
b39ff267f2 | ||
|
|
f7870d1693 | ||
|
|
c648338a18 | ||
|
|
9fe52c874e | ||
|
|
c5eae88dfc | ||
|
|
1d0ac30ae1 | ||
|
|
c355cbe5dc | ||
|
|
6f69eb5c68 | ||
|
|
07595976b2 |
+1
-1
@@ -3,7 +3,7 @@
|
||||
FROM qemux/qemu-host:2.06 AS host
|
||||
FROM scratch
|
||||
|
||||
COPY --from=qemux/qemu:7.45 / /
|
||||
COPY --from=qemux/qemu:7.48 / /
|
||||
|
||||
ARG VERSION_ARG="0.0"
|
||||
ARG VERSION_CSTRUCT="4.7"
|
||||
|
||||
+2
-3
@@ -33,7 +33,7 @@ An empty default means the variable is unset and its value is determined automat
|
||||
|---|---|---|
|
||||
| `DISK_SIZE` | `256G` | Size of the main data disk. |
|
||||
| `DISK_FMT` | `raw` | Disk image format: `raw` or `qcow2`. |
|
||||
| `DISK_TYPE` | `scsi` | Disk device type, such as `sata`, `scsi`, `nvme`, or `blk`. |
|
||||
| `DISK_TYPE` | `scsi` | Disk device type, such as `ide`, `scsi`, or `blk`. |
|
||||
| `DISK_CACHE` | `none` | Disk cache mode, such as `none` or `writeback`. |
|
||||
| `DISK_IO` | `native` | Disk I/O mode, such as `native`, `threads`, or `io_uring`. |
|
||||
| `DISK_DISCARD` | `unmap` | Discard/TRIM mode for the primary disk. |
|
||||
@@ -71,9 +71,8 @@ An empty default means the variable is unset and its value is determined automat
|
||||
| Variable | Default | Description |
|
||||
|---|---|---|
|
||||
| `DISPLAY` | `none` | Display backend, such as `vnc`, `disabled`, or `none`. |
|
||||
| `LOSSY` | `N` | Enables lossy VNC compression to reduce bandwidth usage. |
|
||||
| `VGA` | `none` | QEMU video adapter model. |
|
||||
| `GPU` | `N` | Enables Intel iGPU acceleration. |
|
||||
| `GPU` | `N` | Enables experimental GPU acceleration. |
|
||||
| `RENDERNODE` | `/dev/dri/renderD128` | Render node used for GPU acceleration. |
|
||||
|
||||
## 🎈 Memory Ballooning
|
||||
|
||||
@@ -201,9 +201,9 @@ kubectl apply -f https://raw.githubusercontent.com/vdsm/virtual-dsm/refs/heads/m
|
||||
- 'c *:* rwm'
|
||||
```
|
||||
|
||||
### How do I pass through the GPU?
|
||||
### How do I enable GPU acceleration?
|
||||
|
||||
To pass through your Intel GPU, add the following lines to your compose file:
|
||||
To enable hardware-accelerated graphics, add the following lines to your compose file:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
@@ -212,8 +212,7 @@ kubectl apply -f https://raw.githubusercontent.com/vdsm/virtual-dsm/refs/heads/m
|
||||
- /dev/dri
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> This can be used to enable the facial recognition function in Synology Photos, but does not provide hardware transcoding for video.
|
||||
This can be used to enable the facial recognition function in Synology Photos, but does not provide hardware transcoding for video.
|
||||
|
||||
### How do I enable dynamic memory allocation?
|
||||
|
||||
|
||||
+30
-15
@@ -1,12 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
: "${RNG:=""}"
|
||||
: "${QMP:=""}"
|
||||
: "${UUID:=""}"
|
||||
: "${MONITOR:=""}"
|
||||
|
||||
DEF_OPTS="-nodefaults -boot strict=on"
|
||||
DEV_OPTS=""
|
||||
msg="Configuring QEMU..."
|
||||
enabled "$DEBUG" && echo "$msg"
|
||||
|
||||
# Sanitize variables
|
||||
QMP=$(strip "$QMP")
|
||||
UUID=$(strip "$UUID")
|
||||
MONITOR=$(strip "$MONITOR")
|
||||
|
||||
configureProcessor() {
|
||||
|
||||
@@ -30,11 +36,12 @@ configureMonitor() {
|
||||
MON_OPTS=""
|
||||
[ -n "$QMP" ] && MON_OPTS+=" -qmp $QMP"
|
||||
[ -n "$MONITOR" ] && MON_OPTS+=" -monitor $MONITOR"
|
||||
|
||||
MON_OPTS+=" -name $PROCESS,process=$PROCESS,debug-threads=on"
|
||||
MON_OPTS+=" -pidfile $QEMU_PID"
|
||||
MON_OPTS="${MON_OPTS# }"
|
||||
|
||||
local name="${APP// /-}"
|
||||
ID_OPTS="-name $name,process=$PROCESS,debug-threads=on"
|
||||
PID_OPTS="-pidfile $QEMU_PID"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -48,36 +55,44 @@ configureMachine() {
|
||||
MAC_OPTS="-machine type=$MACHINE,smm=$smm,usb=off"
|
||||
MAC_OPTS+=",vmport=off,dump-guest-core=off,hpet=off${KVM_OPTS}"
|
||||
|
||||
UUID=$(strip "$UUID")
|
||||
[ -n "$UUID" ] && MAC_OPTS+=" -uuid $UUID"
|
||||
[ -n "${SM_BIOS:-}" ] && MAC_OPTS+=" $SM_BIOS"
|
||||
[ -n "$UUID" ] && ID_OPTS+=" -uuid $UUID"
|
||||
[ -n "${SM_BIOS:-}" ] && ID_OPTS+=" $SM_BIOS"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
configureVirtioDevices() {
|
||||
configureDevices() {
|
||||
|
||||
local bus
|
||||
bus=$(getPciBus)
|
||||
|
||||
DEV_OPTS=""
|
||||
|
||||
if ! disabled "$RNG"; then
|
||||
DEV_OPTS+=" -object rng-random,id=objrng0,filename=/dev/urandom"
|
||||
DEV_OPTS+=" -device virtio-rng-pci,rng=objrng0,id=rng0,bus=$bus,addr=0x1c"
|
||||
fi
|
||||
|
||||
# Keep the existing balloon device by default. When dynamic ballooning is
|
||||
# enabled, expose guest statistics and a dedicated QMP control socket.
|
||||
if ! enabled "${BALLOONING:-}"; then
|
||||
DEV_OPTS="-device virtio-balloon-pci,id=balloon0,bus=$bus,addr=0x4"
|
||||
DEV_OPTS+=" -device virtio-balloon-pci,id=balloon0,bus=$bus,addr=0x4"
|
||||
else
|
||||
MON_OPTS+=" -qmp unix:${BALLOONING_SOCKET},server=on,wait=off"
|
||||
DEV_OPTS="-device virtio-balloon-pci,free-page-reporting=on,guest-stats-polling-interval=1,id=balloon0,bus=$bus,addr=0x4"
|
||||
DEV_OPTS+=" -device virtio-balloon-pci,free-page-reporting=on,guest-stats-polling-interval=1,id=balloon0,bus=$bus,addr=0x4"
|
||||
fi
|
||||
|
||||
DEV_OPTS+=" -object rng-random,id=objrng0,filename=/dev/urandom"
|
||||
DEV_OPTS+=" -device virtio-rng-pci,rng=objrng0,id=rng0,bus=$bus,addr=0x1c"
|
||||
DEV_OPTS="${DEV_OPTS# }"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
buildArguments() {
|
||||
|
||||
ARGS="$DEF_OPTS $CPU_OPTS $RAM_OPTS $MAC_OPTS $DISPLAY_OPTS $MON_OPTS $SERIAL_OPTS $NET_OPTS $DISK_OPTS $BOOT_OPTS $DEV_OPTS $ARGUMENTS"
|
||||
local default="-nodefaults"
|
||||
local boot="-boot strict=on"
|
||||
|
||||
ARGS="$default $MAC_OPTS $CPU_OPTS $RAM_OPTS $ID_OPTS $PID_OPTS $DISPLAY_OPTS $MON_OPTS $SERIAL_OPTS $NET_OPTS $DISK_OPTS $boot $BOOT_OPTS $DEV_OPTS $ARGUMENTS"
|
||||
|
||||
# Collapse whitespace after optional argument groups are assembled so empty
|
||||
# features cannot leave malformed spacing in the final QEMU command.
|
||||
@@ -92,7 +107,7 @@ configureMemory
|
||||
configureMonitor
|
||||
configureMachine
|
||||
configureProcessor
|
||||
configureVirtioDevices
|
||||
configureDevices
|
||||
|
||||
buildArguments
|
||||
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
# Docker environment variables
|
||||
|
||||
: "${GPU:="N"}" # GPU passthrough
|
||||
: "${VGA:="virtio"}" # VGA adaptor
|
||||
: "${DISPLAY:="none"}" # Display type
|
||||
: "${LOSSY:="N"}" # Lossy VNC compression
|
||||
: "${RENDERNODE:="/dev/dri/renderD128"}" # Render node
|
||||
|
||||
# Sanitize variables
|
||||
VGA=$(strip "$VGA")
|
||||
LOSSY=$(strip "$LOSSY")
|
||||
DISPLAY=$(strip "$DISPLAY")
|
||||
RENDERNODE=$(strip "$RENDERNODE")
|
||||
|
||||
CPU_VENDOR=$(lscpu | awk '/Vendor ID/{print $3}')
|
||||
|
||||
# The accelerated Intel render-node path is restricted to x86 Intel hosts;
|
||||
# other platforms retain the normal QEMU display backend.
|
||||
if ! enabled "$GPU" || isAmdCpu || [[ "$ARCH" != "amd64" ]]; then
|
||||
|
||||
# A disabled frontend also removes the emulated VGA device to keep the guest
|
||||
# hardware layout headless.
|
||||
[[ "${DISPLAY,,}" == "none" ]] && VGA="none"
|
||||
|
||||
if enabled "$LOSSY" && [[ "${DISPLAY,,}" == vnc=* ]]; then
|
||||
DISPLAY+=",lossy=on"
|
||||
fi
|
||||
|
||||
DISPLAY_OPTS="-display ${DISPLAY} -vga ${VGA}"
|
||||
return 0
|
||||
|
||||
fi
|
||||
|
||||
msg="Configuring display drivers..."
|
||||
html "$msg"
|
||||
enabled "$DEBUG" && echo "$msg"
|
||||
|
||||
DISPLAY_OPTS="-display egl-headless,rendernode=${RENDERNODE}"
|
||||
DISPLAY_OPTS+=" -vga $VGA"
|
||||
|
||||
[ ! -d /dev/dri ] && mkdir -m 755 /dev/dri
|
||||
|
||||
# Extract the card number from the render node
|
||||
# Linux renderD128 corresponds to card0; derive both device minors because
|
||||
# container device bindings may expose only the render node.
|
||||
CARD_NUMBER=$(echo "$RENDERNODE" | grep -oP '(?<=renderD)\d+')
|
||||
CARD_DEVICE="/dev/dri/card$((CARD_NUMBER - 128))"
|
||||
|
||||
if [ ! -c "$CARD_DEVICE" ]; then
|
||||
if mknod "$CARD_DEVICE" c 226 $((CARD_NUMBER - 128)); then
|
||||
chmod 666 "$CARD_DEVICE"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -c "$RENDERNODE" ]; then
|
||||
if mknod "$RENDERNODE" c 226 "$CARD_NUMBER"; then
|
||||
chmod 666 "$RENDERNODE"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -c "$RENDERNODE" ] || [ ! -r "$RENDERNODE" ] || [ ! -w "$RENDERNODE" ]; then
|
||||
warn "render device '${RENDERNODE}' is unavailable or inaccessible."
|
||||
fi
|
||||
|
||||
addDsmPackage() {
|
||||
|
||||
local pkg=$1
|
||||
local desc=$2
|
||||
|
||||
if ! apt-mark showinstall | grep -qx "$pkg"; then
|
||||
[ -z "$COUNTRY" ] && setCountry
|
||||
|
||||
# Use a mainland mirror only for on-demand package installation, avoiding
|
||||
# slow or inaccessible Debian endpoints in that region.
|
||||
if [[ "${COUNTRY^^}" == "CN" ]]; then
|
||||
sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list.d/debian.sources
|
||||
fi
|
||||
fi
|
||||
|
||||
addPackage "$pkg" "$desc"
|
||||
}
|
||||
|
||||
# Install acceleration packages lazily so non-GPU deployments keep the base
|
||||
# image small and do not require OpenGL modules.
|
||||
addDsmPackage "xserver-xorg-video-intel" "Intel GPU drivers"
|
||||
addDsmPackage "qemu-system-modules-opengl" "OpenGL module"
|
||||
|
||||
return 0
|
||||
@@ -23,6 +23,7 @@ cd /run
|
||||
. init.sh # Initialize system
|
||||
. memory.sh # Check memory
|
||||
. server.sh # Start webserver
|
||||
. download.sh # Load functions
|
||||
. install.sh # Run installation
|
||||
. disk.sh # Initialize disks
|
||||
. display.sh # Initialize graphics
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
fKill "progress.sh"
|
||||
|
||||
if [ -s "$QEMU_DIR/qemu.host" ] && [[ "$(<"$QEMU_DIR/qemu.host")" == "172.17."* ]]; then
|
||||
warn "your container IP starts with 172.17.* which will cause conflicts when you install the Container Manager package inside DSM!"
|
||||
fi
|
||||
|
||||
+29
-2
@@ -178,8 +178,35 @@ createSystemImage() {
|
||||
return 67
|
||||
fi
|
||||
|
||||
7z x -y -o"$tmp" "$DSM_BOOT" >/dev/null || return $?
|
||||
DSM_BOOT="${DSM_BOOT%.zip}"
|
||||
local bootTmp="$tmp/boot" bootBase
|
||||
bootBase="$(basename "${DSM_BOOT%.zip}")"
|
||||
|
||||
rm -rf "$bootTmp" || return $?
|
||||
|
||||
if ! makeDir "$bootTmp"; then
|
||||
error "Failed to create directory \"$bootTmp\" !"
|
||||
return 93
|
||||
fi
|
||||
|
||||
if [[ "${fs,,}" == "btrfs" ]]; then
|
||||
{ chattr +C "$bootTmp"; } || :
|
||||
fi
|
||||
|
||||
7z x -y -o"$bootTmp" "$DSM_BOOT" >/dev/null || return $?
|
||||
DSM_BOOT="$bootTmp/$bootBase"
|
||||
|
||||
if [ ! -s "$DSM_BOOT" ]; then
|
||||
error "The PAT boot image could not be extracted."
|
||||
return 67
|
||||
fi
|
||||
|
||||
if [[ "${fs,,}" == "btrfs" ]]; then
|
||||
local attrs
|
||||
attrs=$(lsattr "$DSM_BOOT") || return $?
|
||||
if [[ "$attrs" != *"C"* ]]; then
|
||||
error "Failed to disable COW for boot image $DSM_BOOT on ${fs^^} filesystem."
|
||||
fi
|
||||
fi
|
||||
|
||||
SYSTEM="$STORAGE/$BASE.system.img"
|
||||
rm -f "$SYSTEM" || return $?
|
||||
|
||||
+3
-1
@@ -21,6 +21,7 @@ finish() {
|
||||
|
||||
local reason=$1 failed=0
|
||||
|
||||
# A nonzero exit is unexpected only when QEMU_END is missing.
|
||||
if [ ! -f "$QEMU_END" ] && (( reason != 0 )); then
|
||||
failed=1
|
||||
fi
|
||||
@@ -29,14 +30,15 @@ finish() {
|
||||
|
||||
forceKillQemu "$reason"
|
||||
cleanupHelpers "$HOST_PID"
|
||||
|
||||
fKill "print.sh"
|
||||
|
||||
rm -f -- "$HOST_API_SOCKET" "$HOST_AGENT_SOCKET"
|
||||
|
||||
if ! waitQemuExit 10; then
|
||||
warn "Timed out while waiting for $(app) to exit!"
|
||||
fi
|
||||
|
||||
stopConsole
|
||||
echo
|
||||
|
||||
if (( failed == 0 )); then
|
||||
|
||||
+2
-3
@@ -30,10 +30,9 @@ closeWebserver() {
|
||||
fi
|
||||
|
||||
writeAtomic "$WSD_COMMAND" "portal" || return $?
|
||||
sleep 1.2
|
||||
|
||||
local pids=( "${WEB_PID:-}" "${WSD_PID:-}" )
|
||||
mKill "${pids[@]}"
|
||||
sleep 1.2
|
||||
stopAllServers
|
||||
|
||||
WEB="N"
|
||||
|
||||
|
||||
+7
-1
@@ -23,7 +23,13 @@ server {
|
||||
gzip_disable "msie6";
|
||||
gzip_types text/css text/javascript text/xml text/plain text/x-component application/javascript application/json application/xml application/rss+xml font/truetype font/opentype application/vnd.ms-fontobject image/svg+xml;
|
||||
|
||||
add_header Cache-Control "no-cache";
|
||||
set $cache_control "no-cache";
|
||||
|
||||
if ($uri = /msg.html) {
|
||||
set $cache_control "no-store";
|
||||
}
|
||||
|
||||
add_header Cache-Control $cache_control always;
|
||||
|
||||
location / {
|
||||
|
||||
|
||||
+13
-6
@@ -7,7 +7,6 @@ var portal = false;
|
||||
var portalUrl = "";
|
||||
var interval = 1000;
|
||||
var lastStatus = "";
|
||||
var stopped = "The container has stopped. Check the container logs for details.";
|
||||
|
||||
function abortRequest() {
|
||||
|
||||
@@ -160,6 +159,12 @@ function processMsg(msg) {
|
||||
rememberStatus(msg);
|
||||
setInfo(msg);
|
||||
|
||||
if (msg.toLowerCase().indexOf("href=") !== -1) {
|
||||
var div = document.createElement("div");
|
||||
div.innerHTML = msg;
|
||||
return beginPortal(div.querySelector("a").href);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -297,14 +302,14 @@ function estimateProgress(bytes) {
|
||||
}
|
||||
|
||||
if (previousBoundary === 0) {
|
||||
return Math.min(bytes / boundary * 100, 100);
|
||||
return Math.min(bytes / boundary * 100, 99.9);
|
||||
}
|
||||
|
||||
var rangeProgress =
|
||||
(bytes - previousBoundary) /
|
||||
(boundary - previousBoundary);
|
||||
|
||||
return 30 + Math.pow(rangeProgress, 2) * 70;
|
||||
return Math.min(30 + Math.pow(rangeProgress, 2) * 70, 99.9);
|
||||
}
|
||||
|
||||
function parseProgress(msg) {
|
||||
@@ -512,9 +517,11 @@ function setError(text) {
|
||||
|
||||
function setStopped() {
|
||||
|
||||
var msg = stopped;
|
||||
var msg = "<span style=\"display:block\">The container has stopped.</span>";
|
||||
msg += "<span style=\"display:block; margin-top:1em; font-size:0.85em; font-weight:normal\">Check the container log for more details.</span>";
|
||||
|
||||
if (lastStatus.length > 0) {
|
||||
msg += "<br>(Last status: " + escapeContent(lastStatus) + ")";
|
||||
msg += "<span style=\"display:block; margin-top:1em; font-size:0.75em; font-weight:normal; color:rgba(255,255,255,0.65)\">[ Last status: " + escapeContent(lastStatus) + " ]</span>";
|
||||
}
|
||||
|
||||
return setError(msg);
|
||||
@@ -536,7 +543,7 @@ function reload() {
|
||||
|
||||
navigationTimer = setTimeout(function() {
|
||||
navigationTimer = null;
|
||||
window.location.reload();
|
||||
window.location.replace(window.location.href);
|
||||
}, 3000);
|
||||
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user