ublk

package module
v0.0.0-...-41989fa Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 28, 2025 License: MIT Imports: 13 Imported by: 0

README

go-ublk

A Go library for building Linux block devices in userspace. Pure Go, dependency-free, no cgo.

ublk is like FUSE, but for block devices instead of filesystems. The kernel forwards block I/O to your userspace program via io_uring - you just implement read/write handlers. go-ublk handles the io_uring setup, kernel communication, and device lifecycle.

As far as I can tell, this is the only pure-Go ublk implementation available.

Usage

Implement the Backend interface (it matches io.ReaderAt/io.WriterAt) and call CreateAndServe:

package main

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

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

// NullBackend discards writes and returns zeros on read
type NullBackend struct{ size int64 }

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

func main() {
    ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT)
    defer stop()

    backend := &NullBackend{size: 1 << 30} // 1GB
    params := ublk.DefaultParams(backend)

    device, _ := ublk.CreateAndServe(ctx, params, nil)
    defer device.Close()

    <-ctx.Done()
}

Try It

The repo includes a RAM-backed block device example:

# Load the kernel module
sudo modprobe ublk_drv

# Build and run
make build
sudo ./bin/ublk-mem --size=1G

# In another terminal: use it like any block device
sudo mkfs.ext4 /dev/ublkb0
sudo mount /dev/ublkb0 /mnt
# ...
sudo umount /mnt

Performance

Local benchmarks on Ubuntu 24.04 VM (2 vCPUs, 8GB RAM, i7-8700K host, 4 queues, depth=64):

Workload go-ublk Loop (RAM) % of Loop
4K Read (1 job) 85k IOPS 220k IOPS 39%
4K Read (4 jobs) 99k IOPS 116k IOPS 85%
4K Write (4 jobs) 90k IOPS 99k IOPS 91%

Multi-queue workloads reach 85-91% of kernel loop device throughput.

Requirements

  • Linux kernel >= 6.8
  • ublk_drv module loaded
  • Root or CAP_SYS_ADMIN

References

License

MIT

Documentation

Overview

Package ublk provides the main API for creating userspace block devices

Index

Constants

View Source
const (
	DefaultQueueDepth         = constants.DefaultQueueDepth
	DefaultLogicalBlockSize   = constants.DefaultLogicalBlockSize
	DefaultMaxIOSize          = constants.DefaultMaxIOSize
	DefaultDiscardAlignment   = constants.DefaultDiscardAlignment
	DefaultDiscardGranularity = constants.DefaultDiscardGranularity
	DefaultMaxDiscardSectors  = constants.DefaultMaxDiscardSectors
	DefaultMaxDiscardSegments = constants.DefaultMaxDiscardSegments
	AutoAssignDeviceID        = constants.AutoAssignDeviceID
	IOBufferSizePerTag        = constants.IOBufferSizePerTag
)

Re-export constants for public API

View Source
const (
	// NoQueue indicates that an error is not associated with a specific queue
	NoQueue = -1
)

Variables

View Source
var (
	ErrNotImplemented     = &Error{Code: ErrCodeNotImplemented, Msg: "not implemented", Queue: NoQueue}
	ErrDeviceNotFound     = &Error{Code: ErrCodeDeviceNotFound, Msg: "device not found", Queue: NoQueue}
	ErrDeviceBusy         = &Error{Code: ErrCodeDeviceBusy, Msg: "device busy", Queue: NoQueue}
	ErrInvalidParameters  = &Error{Code: ErrCodeInvalidParameters, Msg: "invalid parameters", Queue: NoQueue}
	ErrKernelNotSupported = &Error{Code: ErrCodeKernelNotSupported, Msg: "kernel does not support ublk", Queue: NoQueue}
	ErrPermissionDenied   = &Error{Code: ErrCodePermissionDenied, Msg: "permission denied", Queue: NoQueue}
	ErrInsufficientMemory = &Error{Code: ErrCodeInsufficientMemory, Msg: "insufficient memory", Queue: NoQueue}
	ErrIOError            = &Error{Code: ErrCodeIOError, Msg: "I/O error", Queue: NoQueue}
	ErrTimeout            = &Error{Code: ErrCodeTimeout, Msg: "timeout", Queue: NoQueue}
	ErrDeviceOffline      = &Error{Code: ErrCodeDeviceOffline, Msg: "device offline", Queue: NoQueue}
)

Sentinel errors for use with errors.Is()

View Source
var LatencyBuckets = []uint64{
	1_000,
	10_000,
	100_000,
	1_000_000,
	10_000_000,
	100_000_000,
	1_000_000_000,
	10_000_000_000,
}

LatencyBuckets defines the latency histogram buckets in nanoseconds. Buckets cover from 1us to 10s with logarithmic spacing.

Functions

func IsCode

func IsCode(err error, code UblkErrorCode) bool

IsCode checks if an error matches a specific error code

func IsErrno

func IsErrno(err error, errno syscall.Errno) bool

IsErrno checks if an error matches a specific errno

Types

type Backend

type Backend interface {
	// ReadAt reads len(p) bytes into p starting at offset off.
	// It returns the number of bytes read (0 <= n <= len(p)) and any error encountered.
	// When ReadAt returns n < len(p), it returns a non-nil error explaining
	// why more bytes were not returned.
	//
	// If the n = len(p) bytes returned by ReadAt are at the end of the input source,
	// ReadAt may return either err == nil or err == io.EOF.
	//
	// Implementations must not retain p.
	ReadAt(p []byte, off int64) (n int, err error)

	// WriteAt writes len(p) bytes from p to the underlying data stream at offset off.
	// It returns the number of bytes written from p (0 <= n <= len(p)) and
	// any error encountered that caused the write to stop early.
	// WriteAt must return a non-nil error if it returns n < len(p).
	//
	// If WriteAt is writing to a destination with a seek offset,
	// WriteAt should not affect nor be affected by the underlying seek offset.
	//
	// Implementations must not retain p.
	WriteAt(p []byte, off int64) (n int, err error)

	// Size returns the size of the backend in bytes.
	// This determines the size of the block device as seen by the kernel.
	Size() int64

	// Close closes the backend and releases any resources.
	// After Close is called, no other methods should be called.
	Close() error

	// Flush flushes any cached writes to stable storage.
	// This is called when the block layer issues a flush/fsync request.
	Flush() error
}

Backend defines the interface that all ublk backends must implement. This interface is intentionally similar to standard Go interfaces like io.ReaderAt and io.WriterAt for familiarity and composability.

type Device

type Device struct {
	// ID is the device ID assigned by the kernel
	ID uint32

	// Path is the path to the block device (e.g., "/dev/ublkb0")
	Path string

	// CharPath is the path to the character device (e.g., "/dev/ublkc0")
	CharPath string

	// Backend is the backend implementation
	Backend Backend
	// contains filtered or unexported fields
}

Device represents a ublk block device

func Create

func Create(params DeviceParams, options *Options) (*Device, error)

Create creates a ublk device without starting I/O processing. Use this when you need more control over the device lifecycle. After Create, call Start() to begin serving I/O, Stop() to pause, and Close() for full cleanup.

Example:

device, err := ublk.Create(params, options)
if err != nil {
    return err
}
defer device.Close()

if err := device.Start(ctx); err != nil {
    return err
}
// Device is now serving I/O

func CreateAndServe

func CreateAndServe(ctx context.Context, params DeviceParams, options *Options) (*Device, error)

CreateAndServe creates a ublk device with the given parameters and starts serving I/O. This is the main entry point for creating ublk devices.

The device will continue serving I/O until: - The context is cancelled - StopAndDelete is called - An unrecoverable error occurs

Example:

backend := mem.New(64 << 20) // 64MB RAM disk
params := ublk.DefaultParams(backend)
device, err := ublk.CreateAndServe(context.Background(), params, nil)

func (*Device) BlockPath

func (d *Device) BlockPath() string

BlockPath returns the path to the block device (e.g., "/dev/ublkb0")

func (*Device) BlockSize

func (d *Device) BlockSize() int

BlockSize returns the logical block size of this device

func (*Device) CharDevicePath

func (d *Device) CharDevicePath() string

CharDevicePath returns the path to the character device (e.g., "/dev/ublkc0")

func (*Device) Close

func (d *Device) Close() error

Close performs full cleanup: stops I/O (if running) and removes the device. After Close(), the device cannot be reused.

func (*Device) DeviceID

func (d *Device) DeviceID() uint32

DeviceID returns the kernel-assigned device ID

func (*Device) Info

func (d *Device) Info() DeviceInfo

Info returns comprehensive information about the device

func (*Device) IsRunning

func (d *Device) IsRunning() bool

IsRunning returns true if the device is currently serving I/O

func (*Device) Metrics

func (d *Device) Metrics() *Metrics

Metrics returns the current metrics for the device

func (*Device) MetricsSnapshot

func (d *Device) MetricsSnapshot() MetricsSnapshot

MetricsSnapshot returns a point-in-time snapshot of device metrics

func (*Device) NumQueues

func (d *Device) NumQueues() int

NumQueues returns the number of I/O queues configured for this device

func (*Device) QueueDepth

func (d *Device) QueueDepth() int

QueueDepth returns the queue depth configured for this device

func (*Device) Size

func (d *Device) Size() int64

Size returns the size of the device in bytes

func (*Device) Start

func (d *Device) Start(ctx context.Context) error

Start begins serving I/O requests for a device created with Create(). The context controls the lifetime of I/O processing. Returns an error if the device is already started or has been closed.

func (*Device) State

func (d *Device) State() DeviceState

State returns the current state of the device

func (*Device) Stop

func (d *Device) Stop() error

Stop stops I/O processing but keeps the device registered with the kernel. Call Close() for full cleanup, or Start() to resume I/O processing. Returns an error if the device is not started or has been closed.

type DeviceInfo

type DeviceInfo struct {
	ID         uint32      `json:"id"`
	BlockPath  string      `json:"block_path"`
	CharPath   string      `json:"char_path"`
	State      DeviceState `json:"state"`
	NumQueues  int         `json:"num_queues"`
	QueueDepth int         `json:"queue_depth"`
	BlockSize  int         `json:"block_size"`
	Size       int64       `json:"size"`
	Running    bool        `json:"running"`
}

DeviceInfo contains comprehensive information about a ublk device

type DeviceParams

type DeviceParams struct {
	// Backend provides the storage implementation
	Backend Backend

	// Device configuration
	QueueDepth       int // Queue depth per queue (default: 128)
	NumQueues        int // Number of queues (default: number of CPUs)
	LogicalBlockSize int // Logical block size in bytes (default: 512)
	MaxIOSize        int // Maximum I/O size in bytes (default: 1MB)

	// Feature flags
	EnableZeroCopy     bool // Enable zero-copy if supported
	EnableUnprivileged bool // Allow unprivileged operation
	EnableUserCopy     bool // Use user-copy mode
	EnableZoned        bool // Enable zoned storage support
	EnableIoctlEncode  bool // Use ioctl encoding instead of URING_CMD

	// Device attributes
	ReadOnly      bool // Make device read-only
	Rotational    bool // Device is rotational (HDD-like)
	VolatileCache bool // Device has volatile cache
	EnableFUA     bool // Enable Force Unit Access

	// Discard parameters (only used if backend implements DiscardBackend)
	DiscardAlignment   uint32 // Discard alignment
	DiscardGranularity uint32 // Discard granularity
	MaxDiscardSectors  uint32 // Max sectors per discard
	MaxDiscardSegments uint16 // Max segments per discard

	// Advanced options
	DeviceID    int32  // Specific device ID to request (-1 for auto)
	DeviceName  string // Optional device name
	CPUAffinity []int  // CPU affinity mask for queue threads
}

DeviceParams contains parameters for creating a ublk device

func DefaultParams

func DefaultParams(backend Backend) DeviceParams

DefaultParams returns default device parameters

type DeviceState

type DeviceState string

DeviceState represents the current state of a ublk device

const (
	// DeviceStateCreated indicates the device has been created but not started
	DeviceStateCreated DeviceState = "created"
	// DeviceStateRunning indicates the device is actively serving I/O
	DeviceStateRunning DeviceState = "running"
	// DeviceStateStopped indicates the device has been stopped but is still registered
	DeviceStateStopped DeviceState = "stopped"
	// DeviceStateClosed indicates the device has been fully closed and removed
	DeviceStateClosed DeviceState = "closed"
)

type DiscardBackend

type DiscardBackend interface {
	Backend

	// Discard discards the data in the given range, making it available for reuse.
	// The backend may choose to actually deallocate the space or simply mark it as unused.
	// offset and length are in bytes.
	Discard(offset, length int64) error
}

DiscardBackend is an optional interface that backends can implement to support TRIM/DISCARD operations efficiently.

type Error

type Error struct {
	Op    string        // Operation that failed (e.g., "CREATE_DEV", "START_DEV")
	DevID uint32        // Device ID (0 if not applicable)
	Queue int           // Queue number (NoQueue if not applicable)
	Code  UblkErrorCode // High-level error category
	Errno syscall.Errno // Kernel errno (0 if not applicable)
	Msg   string        // Human-readable message
	Inner error         // Wrapped error
}

Error represents a structured ublk error with context and errno mapping

func NewError

func NewError(op string, code UblkErrorCode, msg string) *Error

NewError creates a new structured error

func WrapError

func WrapError(op string, inner error) *Error

WrapError wraps an existing error with ublk context

func (*Error) Error

func (e *Error) Error() string

Error implements the error interface

func (*Error) Is

func (e *Error) Is(target error) bool

Is provides errors.Is support by comparing error codes

func (*Error) Unwrap

func (e *Error) Unwrap() error

Unwrap returns the wrapped error for errors.Is/As support

type Logger

type Logger interface {
	Printf(format string, args ...interface{})
	Debugf(format string, args ...interface{})
}

Logger interface for optional logging.

type Metrics

type Metrics struct {
	// I/O operation counters
	ReadOps    atomic.Uint64 // Total read operations
	WriteOps   atomic.Uint64 // Total write operations
	DiscardOps atomic.Uint64 // Total discard operations
	FlushOps   atomic.Uint64 // Total flush operations

	// Byte counters
	ReadBytes    atomic.Uint64 // Total bytes read
	WriteBytes   atomic.Uint64 // Total bytes written
	DiscardBytes atomic.Uint64 // Total bytes discarded

	// Error counters
	ReadErrors    atomic.Uint64 // Read operation errors
	WriteErrors   atomic.Uint64 // Write operation errors
	DiscardErrors atomic.Uint64 // Discard operation errors
	FlushErrors   atomic.Uint64 // Flush operation errors

	// Queue statistics
	QueueDepthTotal atomic.Uint64 // Cumulative queue depth samples
	QueueDepthCount atomic.Uint64 // Number of queue depth measurements
	MaxQueueDepth   atomic.Uint32 // Maximum observed queue depth

	// Performance tracking
	TotalLatencyNs atomic.Uint64 // Cumulative operation latency in nanoseconds
	OpCount        atomic.Uint64 // Total operations (for average latency calculation)

	// Latency histogram buckets (cumulative counts)
	// Each bucket[i] contains the count of operations with latency <= LatencyBuckets[i]
	LatencyBuckets [numLatencyBuckets]atomic.Uint64

	// Device lifecycle
	StartTime atomic.Int64 // Device start timestamp (UnixNano)
	StopTime  atomic.Int64 // Device stop timestamp (UnixNano)
}

Metrics tracks performance and operational statistics for ublk devices

func NewMetrics

func NewMetrics() *Metrics

NewMetrics creates a new metrics instance

func (*Metrics) RecordDiscard

func (m *Metrics) RecordDiscard(bytes uint64, latencyNs uint64, success bool)

RecordDiscard records a discard operation

func (*Metrics) RecordFlush

func (m *Metrics) RecordFlush(latencyNs uint64, success bool)

RecordFlush records a flush operation

func (*Metrics) RecordQueueDepth

func (m *Metrics) RecordQueueDepth(depth uint32)

RecordQueueDepth records current queue depth for statistics

func (*Metrics) RecordRead

func (m *Metrics) RecordRead(bytes uint64, latencyNs uint64, success bool)

RecordRead records a read operation

func (*Metrics) RecordWrite

func (m *Metrics) RecordWrite(bytes uint64, latencyNs uint64, success bool)

RecordWrite records a write operation

func (*Metrics) Reset

func (m *Metrics) Reset()

Reset resets all metrics counters (useful for testing)

func (*Metrics) Snapshot

func (m *Metrics) Snapshot() MetricsSnapshot

Snapshot creates a point-in-time snapshot of metrics

func (*Metrics) Stop

func (m *Metrics) Stop()

Stop marks the device as stopped

type MetricsObserver

type MetricsObserver struct {
	// contains filtered or unexported fields
}

MetricsObserver implements Observer using the built-in Metrics

func NewMetricsObserver

func NewMetricsObserver(m *Metrics) *MetricsObserver

NewMetricsObserver creates an observer that records to the given metrics

func (*MetricsObserver) ObserveDiscard

func (o *MetricsObserver) ObserveDiscard(bytes uint64, latencyNs uint64, success bool)

func (*MetricsObserver) ObserveFlush

func (o *MetricsObserver) ObserveFlush(latencyNs uint64, success bool)

func (*MetricsObserver) ObserveQueueDepth

func (o *MetricsObserver) ObserveQueueDepth(depth uint32)

func (*MetricsObserver) ObserveRead

func (o *MetricsObserver) ObserveRead(bytes uint64, latencyNs uint64, success bool)

func (*MetricsObserver) ObserveWrite

func (o *MetricsObserver) ObserveWrite(bytes uint64, latencyNs uint64, success bool)

type MetricsSnapshot

type MetricsSnapshot struct {
	// I/O operations
	ReadOps    uint64
	WriteOps   uint64
	DiscardOps uint64
	FlushOps   uint64

	// Bytes transferred
	ReadBytes    uint64
	WriteBytes   uint64
	DiscardBytes uint64

	// Error counts
	ReadErrors    uint64
	WriteErrors   uint64
	DiscardErrors uint64
	FlushErrors   uint64

	// Queue statistics
	AvgQueueDepth float64
	MaxQueueDepth uint32

	// Performance
	AvgLatencyNs uint64
	UptimeNs     uint64

	// Latency percentiles (in nanoseconds)
	LatencyP50Ns  uint64 // 50th percentile (median)
	LatencyP99Ns  uint64 // 99th percentile
	LatencyP999Ns uint64 // 99.9th percentile

	// Histogram bucket counts (cumulative)
	LatencyHistogram [numLatencyBuckets]uint64

	// Computed statistics
	ReadIOPS       float64 // Operations per second
	WriteIOPS      float64
	ReadBandwidth  float64 // Bytes per second
	WriteBandwidth float64
	TotalOps       uint64
	TotalBytes     uint64
	ErrorRate      float64 // Percentage of failed operations
}

Snapshot returns a point-in-time snapshot of metrics

type MockBackend

type MockBackend struct {
	// contains filtered or unexported fields
}

MockBackend provides a mock implementation of Backend for testing. It implements all optional interfaces and tracks method calls for verification.

func NewMockBackend

func NewMockBackend(size int64) *MockBackend

NewMockBackend creates a new mock backend with the specified size. This is useful for unit testing applications that use ublk backends.

func (*MockBackend) CallCounts

func (m *MockBackend) CallCounts() map[string]int

CallCounts returns the number of times each method has been called

func (*MockBackend) Close

func (m *MockBackend) Close() error

Close implements the Backend interface

func (*MockBackend) Discard

func (m *MockBackend) Discard(offset, length int64) error

Discard implements the DiscardBackend interface

func (*MockBackend) Flush

func (m *MockBackend) Flush() error

Flush implements the Backend interface

func (*MockBackend) IsClosed

func (m *MockBackend) IsClosed() bool

IsClosed returns true if the backend has been closed

func (*MockBackend) IsFlushed

func (m *MockBackend) IsFlushed() bool

IsFlushed returns true if Flush has been called

func (*MockBackend) IsSynced

func (m *MockBackend) IsSynced() bool

IsSynced returns true if Sync or SyncRange has been called

func (*MockBackend) ReadAt

func (m *MockBackend) ReadAt(p []byte, off int64) (int, error)

ReadAt implements the Backend interface

func (*MockBackend) Reset

func (m *MockBackend) Reset()

Reset resets all call counters and state flags

func (*MockBackend) Resize

func (m *MockBackend) Resize(newSize int64) error

Resize implements the ResizeBackend interface

func (*MockBackend) SetCustomStats

func (m *MockBackend) SetCustomStats(stats map[string]interface{})

SetCustomStats allows setting custom statistics for testing

func (*MockBackend) Size

func (m *MockBackend) Size() int64

Size implements the Backend interface

func (*MockBackend) Stats

func (m *MockBackend) Stats() map[string]interface{}

Stats implements the StatBackend interface

func (*MockBackend) Sync

func (m *MockBackend) Sync() error

Sync implements the SyncBackend interface

func (*MockBackend) SyncRange

func (m *MockBackend) SyncRange(offset, length int64) error

SyncRange implements the SyncBackend interface

func (*MockBackend) WriteAt

func (m *MockBackend) WriteAt(p []byte, off int64) (int, error)

WriteAt implements the Backend interface

func (*MockBackend) WriteZeroes

func (m *MockBackend) WriteZeroes(offset, length int64) error

WriteZeroes implements the WriteZeroesBackend interface

type NoOpObserver

type NoOpObserver struct{}

NoOpObserver is a no-op implementation of Observer

func (NoOpObserver) ObserveDiscard

func (NoOpObserver) ObserveDiscard(uint64, uint64, bool)

func (NoOpObserver) ObserveFlush

func (NoOpObserver) ObserveFlush(uint64, bool)

func (NoOpObserver) ObserveQueueDepth

func (NoOpObserver) ObserveQueueDepth(uint32)

func (NoOpObserver) ObserveRead

func (NoOpObserver) ObserveRead(uint64, uint64, bool)

func (NoOpObserver) ObserveWrite

func (NoOpObserver) ObserveWrite(uint64, uint64, bool)

type Observer

type Observer interface {
	// ObserveRead is called for each read operation
	ObserveRead(bytes uint64, latencyNs uint64, success bool)

	// ObserveWrite is called for each write operation
	ObserveWrite(bytes uint64, latencyNs uint64, success bool)

	// ObserveDiscard is called for each discard operation
	ObserveDiscard(bytes uint64, latencyNs uint64, success bool)

	// ObserveFlush is called for each flush operation
	ObserveFlush(latencyNs uint64, success bool)

	// ObserveQueueDepth is called periodically with current queue depth
	ObserveQueueDepth(depth uint32)
}

Observer interface allows pluggable metrics collection

type Options

type Options struct {
	// Context for cancellation (if nil, uses context.Background())
	Context context.Context

	// Logger for debug/info messages (if nil, no logging)
	Logger Logger

	// Observer for metrics collection (if nil, uses no-op observer)
	Observer Observer
}

Options contains additional options for device creation

type ResizeBackend

type ResizeBackend interface {
	Backend

	// Resize changes the size of the backend.
	// The new size must be greater than or equal to 0.
	// If the new size is smaller, data may be truncated.
	// If the new size is larger, the new space should read as zeros.
	Resize(newSize int64) error
}

ResizeBackend is an optional interface for backends that support resizing.

type StatBackend

type StatBackend interface {
	Backend

	// Stats returns backend-specific statistics.
	// The returned map contains string keys with numeric values.
	Stats() map[string]interface{}
}

StatBackend is an optional interface that provides device statistics.

type SyncBackend

type SyncBackend interface {
	Backend

	// Sync synchronizes the backend state to stable storage.
	// This is different from Flush in that it may also sync metadata.
	Sync() error

	// SyncRange synchronizes only the specified range to stable storage.
	// This can be more efficient than syncing the entire backend.
	SyncRange(offset, length int64) error
}

SyncBackend is an optional interface for fine-grained sync control.

type UblkErrorCode

type UblkErrorCode string

UblkErrorCode represents high-level error categories

const (
	ErrCodeNotImplemented     UblkErrorCode = "not implemented"
	ErrCodeDeviceNotFound     UblkErrorCode = "device not found"
	ErrCodeDeviceBusy         UblkErrorCode = "device busy"
	ErrCodeInvalidParameters  UblkErrorCode = "invalid parameters"
	ErrCodeKernelNotSupported UblkErrorCode = "kernel does not support ublk"
	ErrCodePermissionDenied   UblkErrorCode = "permission denied"
	ErrCodeInsufficientMemory UblkErrorCode = "insufficient memory"
	ErrCodeIOError            UblkErrorCode = "I/O error"
	ErrCodeTimeout            UblkErrorCode = "timeout"
	ErrCodeDeviceOffline      UblkErrorCode = "device offline"
)

type WriteZeroesBackend

type WriteZeroesBackend interface {
	Backend

	// WriteZeroes efficiently writes zeros to the given range.
	// This is more efficient than WriteAt with a zero-filled buffer.
	// offset and length are in bytes.
	WriteZeroes(offset, length int64) error
}

WriteZeroesBackend is an optional interface for efficient zero-writing.

Directories

Path Synopsis
examples
ublk-mem command
internal
interfaces
Package interfaces provides internal interface definitions for go-ublk.
Package interfaces provides internal interface definitions for go-ublk.
logging
Package logging provides simple logging for the go-ublk project
Package logging provides simple logging for the go-ublk project
uapi
Package uapi provides Linux kernel UAPI definitions for ublk
Package uapi provides Linux kernel UAPI definitions for ublk
uring
Package uring provides interfaces for io_uring operations
Package uring provides interfaces for io_uring operations

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL