DAX#
An L2 adapter that maps Device-DAX paths, such as /dev/daxX.X and
/dev/daxY.Y, and stores KV cache objects in fixed-size slots. This adapter
is intended for byte-addressable memory devices such as persistent memory or
CXL memory.
The MP dax adapter is volatile in this release. It keeps the key index in
server memory and rebuilds an empty index on restart. Old bytes may remain on
the DAX device, but they are unreachable after the LMCache server restarts.
Required fields for the legacy single-device form:
device_path: Path to the mmap-able DAX device or test file.max_dax_size_gb: Number of GiB to map fromdevice_path.slot_bytes: Fixed slot size in bytes. This must be large enough for one full LMCache chunk because MP memory descriptors do not expose the non-MP full-chunk size.
Required fields for the multi-device form:
devices: List of objects withdevice_pathandmax_dax_size_gb. The list may be empty only whenhotplug_enabledistrue.slot_bytes: Fixed slot size in bytes shared by every DAX device in the adapter facade.
Optional fields:
hotplug_enabled(bool, defaultfalse): Enables runtime/reconfigure/dax/status,/reconfigure/dax/add,/reconfigure/dax/remove, and/reconfigure/dax/resize.num_store_workers(int, default1): Store worker threads.num_lookup_workers(int, default1): Lookup worker threads.num_load_workers(int, defaultmin(4, os.cpu_count())): Load worker threads.persist_enabled(bool): Accepted by common L2 config parsing but has no effect fordaxbecause restart recovery is not implemented.
Configuration examples:
# Backward-compatible single-device form.
--l2-adapter '{
"type": "dax",
"device_path": "/dev/dax1.0",
"max_dax_size_gb": 100,
"slot_bytes": 268435456,
"num_store_workers": 1,
"num_lookup_workers": 1,
"num_load_workers": 4,
"eviction": {
"eviction_policy": "LRU",
"trigger_watermark": 0.9,
"eviction_ratio": 0.1
}
}'
# Multi-device hotplug-ready form.
--l2-adapter '{
"type": "dax",
"devices": [
{"device_path": "/dev/daxX.X", "max_dax_size_gb": 100},
{"device_path": "/dev/daxY.Y", "max_dax_size_gb": 100}
],
"slot_bytes": 268435456,
"hotplug_enabled": true,
"num_store_workers": 1,
"num_lookup_workers": 1,
"num_load_workers": 4
}'
Runtime management uses JSON bodies because DAX paths contain slashes. See the Device-DAX backend guide for complete examples. These routes use StorageManager’s generic L2 adapter reconfiguration API; the HTTP path selects the backend and operation, the DAX adapter interprets the operation payload, and the same interface can be reused by future adapters such as P2P.
curl http://127.0.0.1:9000/reconfigure/dax/status
curl -X POST http://127.0.0.1:9000/reconfigure/dax/add \
-H 'Content-Type: application/json' \
-d '{"device_path": "/dev/daxX.X", "size": "100GiB"}'
Current limits:
Runtime hotplug changes only LMCache mappings and metadata. It does not create, destroy, or reconfigure kernel CXL or DAX devices.
Per-TP partitions and on-device restart metadata are not implemented.
Only single-buffer objects are supported. Multi-tensor objects are rejected.
Capacity is slot-based, not payload-byte-based. L2 eviction and usage metrics count occupied slots.
Lookups acquire DAX-side external locks.
submit_unlockreleases those locks after load/retrieve completes, making entries evictable again.Remove
mode="evict"is destructive for the DAX tier. Removemode="migrate"requires enough capacity on another active DAX device.