Linux userspace block devices

Userspace block devices, with Go and Zig libraries

ublk serves Linux block devices from a userspace process through io_uring. This site explains the kernel protocol and documents go-ublk, a pure-Go library, and lib-ublk, a Zig core with a C ABI and language bindings. The benchmarks report measured RAM workloads with their evidence. lib-ublk’s source release is pending.

Learn how ublk works Get started with go-ublk Explore lib-ublk Read the benchmarks

How it fits together#

An application reads and writes /dev/ublkbN like any disk. The kernel’s ublk_drv turns each block request into a descriptor and completes an io_uring command that your server left waiting. The server handles the request against its backend, then commits the result and re-arms the slot. The architecture chapter walks a request through the path. The UAPI reference lists the kernel commands and features.

Quick start with go-ublk#

A complete block device that discards writes and reads zeros. Implement five methods and hand the backend to CreateAndServe:

package main

import (
	"context"
	"os/signal"
	"syscall"

	"github.com/ehrlich-b/go-ublk"
)

type null struct{ size int64 }

func (n null) ReadAt(p []byte, off int64) (int, error)  { clear(p); return len(p), nil }
func (n null) WriteAt(p []byte, off int64) (int, error) { return len(p), nil }
func (n null) Size() int64                              { return n.size }
func (n null) Flush() error                             { return nil }
func (n null) Close() error                             { return nil }

func main() {
	// Serve until a signal; cancelling the context stops the device gracefully.
	ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
	defer stop()
	dev, err := ublk.CreateAndServe(ctx, ublk.DefaultParams(null{1 << 30}), nil)
	if err != nil {
		panic(err)
	}
	<-dev.Done()
	dev.Close() // delete the device
}
sudo modprobe ublk_drv
go build -o nulldisk . && sudo ./nulldisk &
sudo mkfs.ext4 /dev/ublkb0 && sudo mount /dev/ublkb0 /mnt

Getting started covers requirements, the two example servers, and how to clean up a device left behind by a killed process.

Library status and testing#

go-ublk v0.2.0 implements the kernel interface through Linux 7.3-rc5, including recovery and zero copy. Its API can change between minor releases. Releases and testing describe its current scope.

lib-ublk’s RAM and multi-queue device stages passed on six kernels. Its bindings passed RAM data-integrity stages on Linux 6.12, and the property campaign passed 200,000 cases per property. Its source release is pending, and a license hasn’t been selected.

The compatibility matrix keeps the libraries’ test scopes separate. Known kernel bugs includes the zero-copy UBSAN finding and the source analysis behind it.