Skip to main content
RunBook Academy

Proxmox VEXIII · Proxmox Backup ServerPBS architecture

Dirty bitmaps and why incremental backups are fast

Advanced⏱ ~24 minvzdumpjq

What you'll learn

  • Distinguish the dirty-bitmap optimisation from chunk-level deduplication and say what each saves
  • Name what invalidates a dirty bitmap, and why that follows from where the bitmap lives
  • Read the dirty-bitmap and reuse lines in a vzdump task log and say what they mean
  • Answer the recurring "the backup took six hours today, is something broken?" ticket from evidence

Prerequisites

Verified against Proxmox VE 9.2.4 · Proxmox Backup Server 4.2.5 · Ceph Squid / Tentacle · Debian 13 (Trixie) · Linux kernel 7.0 (PVE 9.2 default) · 2026-08-12

Not yet marked complete on this device.

Here is a ticket that arrives in every Proxmox estate that runs PBS, usually on a Monday:

The nightly backup of VM 214 normally finishes in four minutes. Last night it took two hours and forty minutes. Nothing changed. Is the backup server broken?

Nothing is broken. The VM was rebooted on Sunday for a kernel update. This lesson is why that sentence is a complete explanation, and why the operator who cannot give it ends up opening a support case, restarting PBS, or — worst outcome — disabling verification to “make the window fit”.

Two optimisations, not one

Every PBS backup is a full backup: each snapshot is independently restorable and there is no chain of increments to replay. What makes the second one cheap is two distinct mechanisms working at different layers.

Dirty bitmapChunk deduplication
Where it livesIn the running QEMU process on the PVE nodeIn the chunk store on the PBS server
What it savesReading the diskUploading the data
ScopeOne VM, one running QEMU processThe entire datastore, across all guests
Survives a VM restartNoYes
Survives losing the previous snapshotNoYes, if another snapshot references the chunk
Applies to containersNoYes

They are frequently described as one thing — “PBS does incrementals” — and the conflation is precisely what makes the Monday ticket confusing. Losing the bitmap costs you the read; it never costs you the storage.

Deduplication: what the server does

From the technical overview:

For block based backups (like VMs), fixed-sized chunks are used. The content (disk image), is split into chunks of the same length (typically 4 MiB) … Since the image is always split into chunks of the same size, unchanged blocks will result in identical checksums for those chunks, so such chunks do not need to be backed up again.

Fixed-size chunking is what makes this work for disk images. Because every chunk boundary is at a fixed offset, an unchanged region of a disk produces byte-identical chunks with identical checksums every time. The server already has them, so they are not sent.

The client does not even need to guess. The backup protocol describes the negotiation:

If there is a previous Snapshot in the backup group, the client can first download the chunk list of the previous Snapshot. If it detects a chunk that already exists on the server, it can send only the checksum instead of data and checksum.

The dirty bitmap: what the host does

Deduplication saves the upload. It does not save the read. Without a bitmap, backing up a 2 TiB disk means reading 2 TiB from local storage, hashing all of it, and discovering that 99% of it is already on the server. The network is idle and the job still takes hours.

The bitmap removes that work:

As an optimization, VMs in Proxmox VE can make use of “dirty bitmaps”, which can track the changed blocks of an image. Since these bitmaps are also a representation of the image split into chunks, there is a direct relation between the dirty blocks of the image and chunks which need to be uploaded. Thus, only modified chunks of the disk need to be uploaded to a backup.

The alignment in that quote is the elegant part. The bitmap tracks changed blocks; the chunk store addresses fixed 4 MiB chunks; the two granularities map onto each other directly, so a dirty region translates into a specific set of chunks with no ambiguity.

Reading the evidence

The vzdump task log states the bitmap status per disk. This is the single most useful thing in this lesson, because it turns the Monday ticket into a thirty-second answer.

Read-only / Safea backup that had a usable bitmap
# cat /var/log/pve/tasks/*/UPID:pve1:00001234:vzdump:*
INFO: Starting Backup of VM 214 (qemu)
INFO: Backup started at 2026-08-11 01:00:03
INFO: status = running
INFO: VM Name: db-primary
INFO: include disk 'scsi0' 'ceph-vm:vm-214-disk-0' 512G
INFO: issuing guest-agent 'fs-freeze' command
INFO: issuing guest-agent 'fs-thaw' command
INFO: started backup task
INFO: scsi0: dirty-bitmap status: OK (7.4 GiB of 512.0 GiB dirty)
INFO: using fast incremental mode (dirty-bitmap), 7.4 GiB dirty of 512.0 GiB total
INFO: 100% (7.4 GiB of 7.4 GiB) in 3m 51s, read: 32.8 MiB/s, write: 30.1 MiB/s
INFO: backup is sparse: 1.2 GiB (16%) total zero data
INFO: backup was done incrementally, reused 504.6 GiB (98%)
INFO: Finished Backup of VM 214 (00:03:58)

Illustrative output

Read-only / Safethe same VM after a Sunday reboot
# cat /var/log/pve/tasks/*/UPID:pve1:00005678:vzdump:*
INFO: Starting Backup of VM 214 (qemu)
INFO: include disk 'scsi0' 'ceph-vm:vm-214-disk-0' 512G
INFO: started backup task
INFO: scsi0: dirty-bitmap status: created new
INFO: 100% (512.0 GiB of 512.0 GiB) in 2h 38m 12s, read: 55.2 MiB/s, write: 1.1 MiB/s
INFO: backup was done incrementally, reused 505.9 GiB (98%)
INFO: Finished Backup of VM 214 (02:38:19)

Illustrative output

Compare the two carefully, because the second log contains the answer to the ticket in two places:

dirty-bitmap status: created new — there was no bitmap, so this run read the whole disk and built one for next time.

read: 55.2 MiB/s, write: 1.1 MiB/s — the read rate is fifty times the write rate. The host was reading 512 GiB off local storage and sending almost nothing to PBS, because deduplication was still working perfectly. If the backup server were the problem, the write rate would be the low number and the read rate would be low too, because the reads would be blocked behind it.

reused 505.9 GiB (98%) — no additional storage was consumed on PBS.

Extracting this at fleet scale

Read-only / Safewhich guests lost their bitmap last night
set -euo pipefail

NODE=$(hostname -s)

# List last night's vzdump tasks, newest first.
pvesh get "/nodes/$NODE/tasks" --typefilter vzdump --limit 50 --output-format json \
| jq -r '.[] | [.upid, .status, (.starttime|todate)] | @tsv' \
| while IFS=$'\t' read -r upid status started; do
  log=$(pvesh get "/nodes/$NODE/tasks/$upid/log" --output-format json 2>/dev/null \
        | jq -r '.[].t' 2>/dev/null || true)
  vmid=$(printf '%s' "$log" | sed -n 's/.*Starting Backup of VM \([0-9]*\).*/\1/p' | head -1)
  if printf '%s' "$log" | grep -q 'dirty-bitmap status: created new'; then
    printf '%-8s %-6s %s  BITMAP RECREATED (expect a slow run)\n' "$vmid" "$status" "$started"
  else
    printf '%-8s %-6s %s  ok\n' "$vmid" "$status" "$started"
  fi
done

The container equivalent

Containers get no dirty bitmap — there is no QEMU block layer to hold one. Their equivalent is --pbs-change-detection-mode, which changes how the .pxar archive is produced:

ValueBehaviour
legacyRead and encode all files into a single archive, using pxar format version 1. The default
dataRead and encode all files, but split data and metadata into separate streams, using pxar format version 2
metadataSplit streams and use format version 2 as with data, but use the metadata archive of the previous snapshot to detect unchanged files

metadata is the one that produces the container analogue of a bitmap win: files whose metadata is unchanged are not re-read from disk, so a container with a large static dataset stops paying for it on every run.

Configuration changechange detection for a container with a large static dataset
vzdump 310 --storage pbs-main --pbs-change-detection-mode metadata

Knowledge check

Knowledge check · 4 questions

  1. Q1. A VM backup that normally takes 4 minutes took 2h38m after the guest was restarted, and the task log reports 98% chunk reuse. What happened?

  2. Q2. A reboot issued from inside the guest operating system does not destroy the dirty bitmap, while qm stop followed by qm start does.

  3. Q3. Which statements about fixed-size versus dynamic chunking in PBS are correct? Select all that apply.

  4. Q4. Sixty guests were restarted during a Saturday maintenance window and Saturday night the backup window overran badly. Which response is the sound one?

Passing score: 75%. Answers are checked in this browser.