https://github.com/pbs-plus/go-blksnap
Pure Go ioctl-based client for the blksnap Linux kernel module
https://github.com/pbs-plus/go-blksnap
Last synced: about 2 months ago
JSON representation
Pure Go ioctl-based client for the blksnap Linux kernel module
- Host: GitHub
- URL: https://github.com/pbs-plus/go-blksnap
- Owner: pbs-plus
- License: mit
- Created: 2026-05-11T18:39:38.000Z (2 months ago)
- Default Branch: main
- Last Pushed: 2026-05-11T23:58:12.000Z (2 months ago)
- Last Synced: 2026-05-12T01:19:27.233Z (2 months ago)
- Language: Go
- Homepage:
- Size: 81.1 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# go-blksnap — Pure Go Block Device Snapshot Library
[](https://pkg.go.dev/github.com/pbs-plus/go-blksnap)
[](https://go.dev/dl/)
[](LICENSE)
Pure Go [ioctl](https://man7.org/linux/man-pages/man2/ioctl.2.html)-based client for the
[veeamblksnap](https://github.com/veeam/blksnap) standalone kernel module.
Supports both API generations (VAL-6.x and VAL-13.x) with automatic
version detection. No cgo, no C bindings.
> **Important**: This library auto-detects the loaded kernel module version:
> - **v2** (VAL-13.0 / VAL-13.0.1): `/dev/veeamblksnap` + `/dev/bdevfilter`
> - **v1** (VAL-6.0 through VAL-6.3.2): `/dev/veeamblksnap` only
- [Features](#features)
- [Requirements](#requirements)
- [Kernel module installation](#kernel-module-installation)
- [Installation](#installation)
- [Quick start](#quick-start)
- [Architecture](#architecture)
- [Type reference](#type-reference)
- [License](#license)
## Features
- **Multi-version**: Auto-detects v1 (VAL-6.x) or v2 (VAL-13.x) API
- **Snapshot lifecycle**: Create, Take, Destroy, Collect via `/dev/veeamblksnap`
- **Change Block Tracking**: Attach filter, read CBT bitmap, mark dirty blocks
- **Snapshot events**: Wait for corrupted / low-free-space events with timeout
- **Session management**: goroutine-based event monitor, automatic cleanup
- **Zero cgo**: Only depends on `golang.org/x/sys/unix`
## Requirements
- **Linux** (amd64 or arm64)
- **Go 1.26+**
- **veeamblksnap** kernel module loaded (and **bdevfilter** for v2)
- Root privileges (or `CAP_SYS_ADMIN`) for most operations
## Kernel module installation
The veeamblksnap module must be installed and loaded before this library can
be used. There are two ways to obtain it, depending on your distribution.
### Option 1: Pre-built packages (recommended)
Veeam distributes pre-built blksnap packages through the
[Veeam software repository](https://helpcenter.veeam.com/docs/agentforlinux/userguide/installation_val.html)
as part of Veeam Agent for Linux (free community edition available).
#### Add the repository
1. Download the `veeam-release` package from the
[Veeam Agent for Linux download page](https://www.veeam.com/linux-backup-download.html)
(requires a free veeam.com account).
2. Install the repository package:
```bash
# Debian / Ubuntu
sudo dpkg -i ./veeam-release* && sudo apt-get update
# RHEL / Rocky / Alma
sudo rpm -ivh ./veeam-release* && sudo dnf check-update
# SLES / openSUSE
sudo zypper in ./veeam-release* && sudo zypper refresh
```
> **Alternative**: If you can't use the release package, add the key manually:
> ```bash
> # Debian/Ubuntu
> sudo curl -fsSL https://repository.veeam.com/keys/DEB-9BB5AC67.gpg \
> -o /usr/share/keyrings/veeam.gpg
> echo "deb [signed-by=/usr/share/keyrings/veeam.gpg] https://repository.veeam.com/backup/linux/agent/dpkg/debian/public stable veeam" | \
> sudo tee /etc/apt/sources.list.d/veeam.list
> sudo apt-get update
> # RHEL/Rocky/Alma
> sudo rpm --import https://repository.veeam.com/keys/RPM-EFDCEA77
> ```
#### Install the module
```bash
# Debian 11–13 / Ubuntu 22.04 / 24.04
sudo apt-get install blksnap
# RHEL 9 / Rocky 9 / Alma 9 — pre-built kmod
sudo dnf install kmod-blksnap
# RHEL 9 / Rocky 9 / Alma 9 — DKMS (builds from source for your kernel)
sudo dnf install epel-release dkms
sudo dnf install blksnap
# RHEL 8 / Rocky 8 / Alma 8 — pre-built kmod (veeamsnap)
sudo dnf install kmod-veeamsnap
# SLES 15 SP3–SP7 / SLES 16
sudo zypper install blksnap-kmp-default
```
#### Verify
```bash
lsmod | grep -E 'veeamblksnap|bdevfilter'
sudo modprobe veeamblksnap # if not auto-loaded
sudo modprobe bdevfilter # v2 only
ls -la /dev/veeamblksnap /dev/bdevfilter
```
#### Secure Boot
If Secure Boot is enabled, enroll the Veeam key:
```bash
sudo mokutil --import /path/to/blksnap.der
# Reboot and follow the MOK Manager prompt
```
### Option 2: Build from source
For development or if pre-built packages don't support your kernel:
```bash
git clone https://github.com/veeam/blksnap.git -b VAL-13.0.1
cd blksnap/module
make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
sudo mkdir -p /lib/modules/$(uname -r)/extra
sudo install -m 0644 veeamblksnap.ko bdevfilter.ko /lib/modules/$(uname -r)/extra/
sudo depmod -a
sudo modprobe veeamblksnap bdevfilter
```
> **Note**: Ensure `linux-headers-$(uname -r)` is installed. For kernel ≥ 6.17,
> use the VAL-13.0.1 branch.
### Troubleshooting
| Symptom | Cause | Solution |
|---------|-------|----------|
| `modprobe: FATAL: Module veeamblksnap not found` | Not installed | Install package or build from source |
| DKMS build fails (kernel ≥ 6.17) | Package too old | Build from VAL-13.0.1 source |
| `Failed to load module` | Kernel/headers mismatch | `kernel-devel`/`linux-headers` must match `uname -r` |
| Secure Boot blocks module | Unsigned | Enroll key via `mokutil` or disable Secure Boot |
## Installation
```bash
go get github.com/pbs-plus/go-blksnap@latest
```
## Quick start
```go
package main
import (
"log"
"github.com/pbs-plus/go-blksnap"
)
func main() {
session, err := blksnap.CreateSession(
[]string{"/dev/sda1", "/dev/sda2"},
"/var/lib/blksnap/diff_storage",
1024*1024*1024, // 1 GB diff storage limit
)
if err != nil {
log.Fatal(err)
}
defer session.Close()
cbt, _ := session.CBTHandle("/dev/sda1")
info, _ := cbt.Info()
log.Printf("device=%d blocks, block_size=%d", info.BlockCount, info.BlockSize)
data, _ := cbt.Data()
log.Printf("CBT map: %d bytes", len(data))
img, _ := cbt.Image()
log.Printf("snapshot image: %s", img)
if errs, ok := session.Errors(); ok {
for _, e := range errs {
log.Printf("snapshot error: %s", e)
}
}
}
```
## Architecture
The library auto-detects the API version on first use:
```go
v, _ := blksnap.Detect() // returns APIV1 or APIV2
```
Two kernel interfaces are used depending on the version:
| Interface | API | Go types | Purpose |
|-----------|-----|----------|---------|
| `/dev/veeamblksnap` | v1 + v2 | `Service`, `Snapshot` | Snapshot lifecycle |
| `/dev/bdevfilter` | v2 only | `Tracker` | CBT via path-based device IDs |
| `/dev/veeamblksnap` | v1 only | `Tracker` | CBT via major:minor device IDs |
### Low-level API
```go
// Version query (works on both v1 and v2)
svc, _ := blksnap.OpenService()
ver, _ := svc.Version()
fmt.Println(ver) // "7.0.0.0"
// List active snapshots
ids, _ := svc.Collect()
// CBT on v2 (path-based)
t, _ := blksnap.OpenTracker("/dev/sda1")
t.Attach()
info, _ := t.CBTInfo()
buf := make([]byte, info.BlockCount)
t.ReadCBTMap(0, info.BlockCount, buf)
t.Detach()
t.Close()
// Create and take a snapshot (v2)
snap, _ := blksnap.CreateSnapshot("/tmp/diff_storage", 1<<30)
t.SnapshotAdd(snap.ID())
snap.Take()
// Wait for events
for {
ev, ok, _ := snap.WaitEvent(100)
if !ok { continue }
switch ev.Code {
case blksnap.EventCorrupted:
log.Printf("corrupted: dev=%d:%d code=%d",
ev.Corrupted.OrigDevIDMajor,
ev.Corrupted.OrigDevIDMinor,
ev.Corrupted.ErrorCode)
case blksnap.EventLowFreeSpace:
log.Printf("low space: requested=%d sectors",
ev.NoSpace.RequestedSectors)
}
}
snap.Destroy()
snap.Close()
```
### v1-specific API
In v1, devices are identified by major:minor numbers and added at snapshot
creation time:
```go
snap, _, _ := blksnap.CreateSnapshotV1([]blksnap.DevID{
{Major: 8, Minor: 1}, // /dev/sda1
{Major: 8, Minor: 2}, // /dev/sda2
})
// Get image device mappings
images, _ := snap.CollectImages()
for orig, img := range images {
fmt.Printf("%d:%d → %d:%d\n", orig.Major, orig.Minor, img.Major, img.Minor)
}
```
### High-level Session API
```go
session, _ := blksnap.CreateSession(
[]string{"/dev/sda1"},
"/tmp/diff_storage",
1<<30,
blksnap.WithLogger(slog.Default()),
blksnap.WithEventTimeout(50*time.Millisecond),
)
defer session.Close()
```
## Type reference
| C struct (v2) | Go type |
|---------------|---------|
| `struct blksnap_version` | `ModuleVersion` |
| `struct blksnap_uuid` | `UUID` |
| `struct blksnap_cbtinfo` | `CBTInfo` |
| `struct blksnap_sectors` | `SectorRange` |
| `struct blksnap_snapshotinfo` | `SnapshotImageInfo` |
| `struct blksnap_snapshot_event` | `SnapshotEvent` |
| `struct blksnap_event_corrupted` | `SnapshotEventCorrupted` |
| `struct blksnap_event_no_space` | `SnapshotEventLowFreeSpace` |
| `enum blksnap_event_codes` | `SnapshotEventCode` |
| `struct blk_snap_dev_t` (v1) | `DevID` |
| `enum blk_snap_ioctl` (v1) | (internal) |
| `struct bdevfilter_attach/ctl` (v2) | (internal) |
## License
MIT — see [LICENSE](LICENSE).
---
Based on the [blksnap](https://github.com/veeam/blksnap) kernel module UAPI
by Veeam Software Group GmbH. The ioctl protocol derives from kernel UAPI
headers (`veeamblksnap.h`, `bdevfilter.h`, `blk_snap.h`) which are licensed
under GPL-2.0 WITH Linux-syscall-note, permitting independent userspace
implementations under any license.