Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/vm.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ layouts are understood and the algorithm follows from the hash length.

| Function | Contract |
| --- | --- |
| `vm_import_disk <vmid> <image> <storage> [format]` | `qm disk import` (or `qm importdisk` on older hosts) with `DISK_IMPORT_FORMAT`; sets `VM_IMPORTED_DISK` to the volume Proxmox reported or the `unusedN` entry the import added. Never guesses a name. |
| `vm_import_disk <vmid> <image> <storage> [format]` | Flushes the image to disk (`sync -f`, best effort), then `qm disk import` (or `qm importdisk` on older hosts) with `DISK_IMPORT_FORMAT`; sets `VM_IMPORTED_DISK` to the volume Proxmox reported or the `unusedN` entry the import added. Never guesses a name. |
| `kvm_check` | Part of `vm_preflight`, as on Incus: exit 236 when `/dev/kvm` is missing, before any question or download. `qm start` refuses a KVM guest without it. |
| `vm_fit_cores` | Cuts `CORE_COUNT` to the host's CPU threads, with a warning. `vm_start_script` calls it after `default_settings`; `vm_prompt_cpu_cores` refuses a larger answer. |
| `vm_claim_vmid` | Call right before `qm create`: re-checks `VMID`, which was picked before the download. An auto-picked ID another run took moves to the next free one and the disk names follow; an ID chosen in advanced settings stops with exit 205. |
Expand Down
10 changes: 10 additions & 0 deletions pve/vm-core.func
Original file line number Diff line number Diff line change
Expand Up @@ -2630,6 +2630,12 @@ vm_resize_disk() {
# entry the import added. Scripts used to guess the name or take the last
# `pvesm list` line, which sorts disk-10 before disk-9. The format defaults to
# DISK_IMPORT_FORMAT from vm_select_storage.
#
# The image is flushed to disk first. Images are often just extracted or
# converted (xz, gzip, qemu-img, virt-customize), leaving gigabytes of dirty
# pages. When they live on the same ZFS pool as the target (rpool/var-lib-vz
# and rpool/data on a default install), the zvol create inside the import runs
# into Proxmox's zfs command timeout ("got timeout") while ZFS writes them back.
vm_import_disk() {
local vmid="${1:?vmid}" file="${2:?image}" storage="${3:?storage}" format="${4:-${DISK_IMPORT_FORMAT:-}}"
local out before volume
Expand All @@ -2640,6 +2646,10 @@ vm_import_disk() {
[[ -n "$format" ]] && opts=(--format "$format")
before="$(qm config "$vmid" 2>/dev/null | sed -n 's/^unused[0-9]*: //p')" || before=""

msg_info "Flushing $(basename "$file") to disk"
# Best effort: a failed flush is no reason to skip the import.
sync -f "$file" 2>/dev/null || sync 2>/dev/null || true

msg_info "Importing $(basename "$file") to ${storage}"
if ! out="$("${cmd[@]}" "$vmid" "$file" "$storage" "${opts[@]}" 2>&1)"; then
msg_error "Importing $(basename "$file") into VM ${vmid} failed"
Expand Down
16 changes: 16 additions & 0 deletions tests/vm-helpers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ qm() {
*) return 0 ;;
esac
}
sync() { printf 'sync %s\n' "$*" >>"$LOG"; return "${SYNC_RC:-0}"; }
pct() { return 1; }
lvs() { :; }
pvesh() { printf '%s\n' "${NEXTID:-105}"; }
Expand All @@ -256,6 +257,21 @@ assert_eq "$VM_IMPORTED_DISK" "local-lvm:vm-100-disk-1" "volume from qm's report
assert_contains "$LOG" "qm disk import 100 $IMAGE local-lvm --format raw"
ok "vm_import_disk uses qm disk import and the reported volume"

# Dirty pages from extraction stall the zvol create on the same ZFS pool (#18580).
sync_line="$(grep -n "^sync -f $IMAGE\$" "$LOG" | cut -d: -f1)"
import_line="$(grep -n "^qm disk import 100 " "$LOG" | cut -d: -f1)"
[[ -n "$sync_line" && -n "$import_line" && "$sync_line" -lt "$import_line" ]] ||
fail "the image must be flushed before qm disk import"
ok "vm_import_disk flushes the image before importing it"

import_case
SYNC_RC=1
vm_import_disk 100 "$IMAGE" local-lvm || fail "a failed flush must not stop the import"
assert_eq "$VM_IMPORTED_DISK" "local-lvm:vm-100-disk-1" "imported despite the failed flush"
assert_contains "$LOG" "qm disk import 100 $IMAGE local-lvm"
SYNC_RC=0
ok "vm_import_disk imports even when the flush fails"

import_case
QM_MODERN=no
vm_import_disk 100 "$IMAGE" local-lvm qcow2 || fail "legacy import"
Expand Down
Loading