How to make a swappable in-memory block device in Linux without tmpfs?

One can make a ramdisk in Linux by modprobe brd rd_nr=1 rd_size=$SizeInKB (creates uncompressed /dev/ram0) or by modprobe zram && echo $SizeInBytes >| /sys/block/zram0/disksize (creates compressed /dev/zram0).
These types of ramdisk are both unable to be paged out to a swap device and thus limited to a fraction of the physical memory.

To make a swappable in-memory block device which can grow larger than physical memory, one can use
mkdir -p /run/ramfs && mount -t tmpfs -o size=0 ramfs /run/ramfs && \
truncate --size $SizeInBytes /run/ramfs/ramfs && losetup -f && losetup -f /run/ramfs/ramfs.
This is uncompressed but can be combined with zswap to make it compressed (at least some in-memory part of it).
But this involves the overhead of the tmpfs filesystem and the loopback device.

Is there a better method to make a pageable/swappable (possibly compressed) in-memory block device that avoids the overhead of a filesystem below the block layer ?


Solution 1:

A way to do it (not sure if it's better than the method you described) is to use this NBD-based RAM disk that I wrote. You would use it like this:

$ nbdkit -U /tmp/sock memory 10G
# nbd-client -unix /tmp/sock /dev/nbd0

This RAM disk is stored as a sparse array so it can be any size up to 8 exabytes. If you add allocator=zstd to the command line then it will be compressed.

There are definitely pros and cons to this. There's going to be a bit more overhead, although performance is pretty good for normal workloads. Having a userspace implementation of the RAM disk does make it easy to tweak and customize. You could even implement deduplication if your workload could benefit from that. (The current implementation does not do deduplication).