GeminiFS: A Companion File System for GPUs

Shi Qiu, Weinan Liu, Yifan Hu, Jianqin Yan, Zhirong Shen, Xin Yao, Renhai Chen, Gong Zhang, Yiming Zhang | NICE Lab, Xiamen University / Shanghai Jiao Tong University / Huawei Theory Lab | FAST '25 (23rd USENIX Conference on File and Storage Technologies), Feb 25-27 2025, Santa Clara, CA | USENIX, pp. 221-236 | Code: github.com/nicexlab/GeminiFS


Problem

GPU-accelerated ML applications (GNN, LLM) have datasets and weights up to tens of TB that exceed GPU memory, so they offload to NVMe storage. Existing storage access falls into two camps, each deficient. CPU-centric solutions (GPUfs, Dragon, GDS) keep the host CPU on the I/O path to initiate transfers; with hundreds or thousands of GPU threads issuing I/O, the low-parallelism CPU and CPU-GPU synchronization become the bottleneck. GPU-centric BaM lets GPU threads submit NVMe commands directly by placing NVMe queues in GPU memory, but it exposes the device as a raw block device with no file abstraction — losing data/metadata integrity, crash consistency, durability, and cross-process data sharing, and still requiring host-memory bounce copies when reading host file-system files. No prior system gives the GPU a file-system interface while bypassing the CPU on the I/O path.


Core Insight

GPU ML workloads are predictable and mostly read-only / append-only (Table 1), so the dynamic-metadata problem that makes a general GPU file system intractable can be sidestepped: pre-allocate a fixed-size file on the host and embed only the existing private per-file metadata — including a precomputed logical-to-physical block map — directly into the file. The GPU then consumes existing metadata rather than synchronizing mutating metadata with the CPU. Combined with an extended NVMe driver that lets the CPU and GPU establish NVMe I/O queues in parallel, this makes GeminiFS the first GPU-centric file system that unlocks the GPU's view of the host file system for on-demand direct disk access without CPU triggering.


Method

GeminiFS is a lightweight GPU-side file system that coexists with the host file system (the host FS manages file lifecycle and metadata; GeminiFS does the GPU I/O). Four components:

Level 1: GVDK file format (metadata embedding)
  - Embed only private per-file metadata in the file's first block
  - GVDK Helper (host kernel module) precomputes logical->physical block map
  - Two-level mapping (L1 table -> L2 table -> data block); offset m=(m1,m2,m3)
  - ~0.2% capacity overhead (8B NVMe offset per 4KB block)

Level 2: SNVMe (CPU/GPU Shared NVMe Driver)
  - GPU buffer-management module pins GPU I/O-queue pages
    (nvidia_p2p_get_pages_persistent / nvidia_p2p_dma_map_pages)
  - Revises NVMe init steps 1 & 3 so I/O queues live in GPU memory
  - GPU I/O queues use thread polling (reuses BaM's I/O-queue driver)

Level 3: GPU-specific page cache
  - Cross-process sharing via host page-cache module + cuIpcGetMemHandle
  - Warp-level (not thread-level) page acquisition cuts lock contention
    (Ampere: at most 4x108=432 control flows contend at once)
  - Constant-time container (hash table + doubly-linked list) for zero-ref pages
  - Tunable page size / cache size / prefetch count

Level 4: libGemini
  - POSIX-like subset: host G_open/G_close/Geminifs_init; device G_read/G_write/G_sync
  - Not fully POSIX; crash consistency left to apps via G_sync

On read/write the GPU locates metadata via dev_fd, bounds-checks, translates the file offset to an NVMe offset via the cached L1/L2 map, looks up the warp-level page cache, and on a miss the GPU I/O-queue driver builds an NVMe command in a GPU-memory submission queue; the NVMe device DMAs data directly to/from GPU HBM over PCIe while the GPU polls the completion queue. The CPU is entirely off the I/O path.


Experimental Setup

Component Value
CPU 64-core Intel Xeon 5416S, 512 GB RAM
OS Ubuntu 20.04, Linux 5.15.0
GPU 80 GB HBM, peak HBM bandwidth 1,935 GB/s
Interconnect PCIe Gen4 x16 (64 GB/s)
NVMe SSD Intel Optane 5800X, EXT4, ~7 GB/s, up to 135 I/O queue pairs
QP allocation 64 QPs host / 32 QPs GPU
Block size 4K (EXT4 and GeminiFS)
Implementation ~2000 LoC NVMe kernel module + ~3000 LoC libGemini
Baselines GPUfs (4 CPU threads), NVIDIA GDS (cufile), BaM (raw device, no FS)
Workloads 4K read bandwidth/latency vs threads (1-1024); page-cache microbench (20 GB file); GPT2-124M LLM training (batch 64, 3 steps)

Motivation microbenchmarks also used a Zhiti TiPro 7000 SSD (15 µs R/W latency) and an Intel Optane P5800X (4 µs R/W latency). The page-cache microbenchmark substitutes memory replication for NVMe so the disk is not the bottleneck.


Headline Quantitative Results

4K read vs SOTA (Figs. 6-7):

Page cache (Figs. 8-10):

GPT2-124M LLM training (Fig. 11), page cache 2 GB:

Scenario Result
Activations on HBM, runtime -25% / -12% / -10% vs native / DLRover-RM / GDS
Activations on HBM, checkpoint write time -85% / -75% / -59% vs the three
Activations offloaded, runtime -94.5% / -91% vs native / GDS
Offloaded vs all-activations-in-GPU-memory training time rises only ~4x

Storage footprint of one GPT2-124M step (Table 3): model weights 238 MB (read & write), checkpoint 713 MB/step (append-only seq. write), activation 57.96 GB (read & write).


Limitations


Open Problems / Future Work

  1. Full multi-GPU support — parallel reads/writes by logically splitting files.
  2. Aggregating multiple NVMe devices via RAID to meet multi-GPU bandwidth (and, in theory, approach DRAM-only performance for offloaded activations).
  3. File pre-allocation for unpredictable workloads — pre-allocate file slots, then batch-allocate files into them at runtime by actual usage.
  4. Integrating GeminiFS into PyTorch so solutions such as vLLM benefit.