Files

LMCache Rust Raw Block I/O

This crate provides the low-level raw device I/O layer for LMCache via Rust + PyO3. It is used by both:

  • the legacy non-MP RustRawBlockBackend
  • the MP raw_block L2 adapter (RawBlockL2Adapter) via RawBlockCore

The Rust crate intentionally stays narrow: it owns the raw device handle and exposes blocking pwrite_from_buffer / pread_into primitives. Slotting, checkpointing, recovery, and MP task orchestration all live in Python.

I/O Engines

RawBlockDevice accepts io_engine:

  • posix (default): synchronous Linux pread / pwrite.
  • io_uring: direct Rust io_uring syscall path using the existing worker, batch, and wait_iouring machinery.

use_iouring=True remains accepted for backward compatibility. If io_engine is explicitly set, it wins over the legacy flag.

io_uring_cmd (NVMe Passthrough)

When io_engine="io_uring", you can optionally enable use_uring_cmd=True to use NVMe passthrough via the io_uring command interface for direct device access.

io_uring_cmd notes:

  • Requires NVMe character device node (/dev/ngXnY) instead of the block device node (/dev/nvmeXnY) for direct NVMe passthrough command.
  • Requires io_engine="io_uring" to be set.
  • Supports max_data_transfer_size parameter to split large transfers into smaller chunks that fit within device limits.
  • When use_uring_cmd=True, use_odirect is ignored for NVMe namespace character devices.

MP Mode Integration

In MP mode, the stack looks like this:

StoreController / PrefetchController
                |
                v
        RawBlockL2Adapter
                |
                v
           RawBlockCore
                |
                v
         lmcache_rust_raw_block_io
                |
                v
         raw device / file

This split lets LMCache reuse the same on-device metadata and recovery model in both non-MP and MP mode without duplicating the raw-block implementation.

Zero-Copy Data Path

LMCache LocalCPUBackend (aligned pinned CPU tensor)
                 |
                 |  Python buffer / memoryview (no payload memcpy)
                 v
RustRawBlockBackend (PyO3 boundary)
                 |
                 |  direct pointer path when O_DIRECT constraints are met
                 |  fallback: bounce only for unaligned tail/block
                 v
RawBlockDevice::pwrite_from_buffer / pread_into
                 |
                 v
Block device or file

How To Compare Performance

To compare local_disk vs rust_raw_block on a real NVMe device:

  • Run local_disk on an ext4 mount of the device.
  • Unmount it.
  • Run rust_raw_block directly on the raw block device.

Use the benchmark commands in:

  • benchmarks/storage_backend_io/README.md

No fixed numbers are included here because results are host/device/workload dependent.

Limitations

  • Linux only (pread / pwrite, O_DIRECT semantics).
  • O_DIRECT requires aligned offset, size, and user buffer address.

Build

cd rust/raw_block
pip install maturin
maturin develop --release

Minimal Usage

from lmcache_rust_raw_block_io import RawBlockDevice

dev = RawBlockDevice("/dev/nvme0n1", True, use_odirect=True, alignment=4096)
dev.pwrite_from_buffer(offset=0, data=b"hello", total_len=4096)

buf = bytearray(4096)
dev.pread_into(offset=0, out=buf, payload_len=5, total_len=4096)

io_uring:

dev = RawBlockDevice(
    "/dev/nvme0n1",
    True,
    use_odirect=True,
    alignment=4096,
    io_engine="io_uring",
    iouring_queue_depth=256,
)

io_uring with io_uring_cmd (NVMe passthrough):

dev = RawBlockDevice(
    "/dev/ng0n1",  # Note: NVMe character device node
    True,
    use_odirect=False,
    alignment=4096,
    io_engine="io_uring",
    use_uring_cmd=True,
    iouring_queue_depth=256,
    max_data_transfer_size=131072,  # Optional: split large transfers
)

MP Adapter Example

To use the MP adapter from lmcache server, pass a raw_block L2 adapter config:

lmcache server \
  --l1-size-gb 10 \
  --eviction-policy LRU \
  --l1-align-bytes 4096 \
  --l2-adapter '{
    "type": "raw_block",
    "device_path": "/dev/nvme0n1",
    "slot_bytes": 1048576,
    "block_align": 4096,
    "header_bytes": 4096,
    "meta_total_bytes": 268435456,
    "use_odirect": true,
    "io_engine": "io_uring",
    "num_store_workers": 2,
    "num_lookup_workers": 1,
    "num_load_workers": 4
  }'

Notes:

  • device_path should point to an unmounted raw block device or a dedicated file used only by LMCache.
  • For use_uring_cmd=true, device_path must use the NVMe character device node (e.g., /dev/ng0n1) instead of the block device node.
  • With use_odirect=true, LMCache MP L1 alignment must be at least block_align.
  • Restart recovery uses the metadata checkpoint region on the same device.
  • Raw-block slot reclamation is driven by the shared/global L2 eviction controller or explicit delete() calls.
  • raw_block remains the adapter type for all supported engines.