PREFIX=${HOME}/local
./autogen.sh
./configure --prefix=${PREFIX}
make -j$(nproc)
make install
OST_ADDR=192.168.0.1:7777
##
# OST Server
#
OST_DATADIR=/var/rawstor
mkdir -p ${OST_DATADIR}
rawstor-ost \
--bind ${OST_ADDR} \
file://${OST_DATADIR}
##
# Client
#
OBJECT_TARGET=$(rawstor create ost://${OST_ADDR} --size=1G)
VHOST_RUNDIR=${PREFIX}/var/run/rawstor
mkdir -p ${VHOST_RUNDIR}
rawstor-vhost \
--socket-path=${VHOST_RUNDIR}/rawstor1.sock \
${OBJECT_TARGET}
qemu-system-x86_64 \
-enable-kvm \
-m 4G \
-machine accel=kvm,memory-backend=mem \
-drive file=image.qcow2,if=none,id=drive1 \
-device virtio-blk-pci,drive=drive1 \
-object memory-backend-memfd,id=mem,size=4G,share=on \
-chardev socket,id=rawstor1,reconnect=1,path=${VHOST_RUNDIR}/rawstor1.sock \
-device vhost-user-blk-pci,chardev=rawstor1,num-queues=1,disable-legacy=on
The following environment variables can be used to tune the behavior of the Rawstor client and server. Default values are shown below.
| Variable | Default | Description |
|---|---|---|
RAWSTOR_LOCATION |
(none) | Fallback LOCATION for rawstor create/list/info when it's omitted from the command line. |
RAWSTOR_OPTS_IO_ATTEMPTS |
3 |
Number of retry attempts for I/O operations that encounter recoverable errors. |
RAWSTOR_OPTS_SESSIONS |
1 |
Number of concurrent sessions that Rawstor client will open for each object. |
RAWSTOR_OPTS_SO_SNDTIMEO |
5000 |
Socket send timeout. Sets SO_SNDTIMEO for network sockets. |
RAWSTOR_OPTS_SO_RCVTIMEO |
5000 |
Socket receive timeout. Sets SO_RCVTIMEO for network sockets. |
RAWSTOR_OPTS_TCP_USER_TIMEOUT |
5000 |
TCP user timeout (Linux TCP_USER_TIMEOUT). Defines how long transmitted data may remain unacknowledged before the connection is closed. |
RAWSTOR_OPTS_LIST_LIMIT |
1000 |
Server-side page size cap for list operations: the maximum number of objects returned in a single call, regardless of the caller-requested limit. Larger listings are paginated across multiple calls. |
Note: All timeout values are expressed in milliseconds unless stated otherwise.
rawstor-ost implements the OST protocol (see Protocol.md), handling network connections and providing access to data stored in locations (as defined in the Locations and Targets documentation).
file://scheme → serves data directly from the local filesystem.ost://scheme → acts as a proxy to an underlying OST backend.- Comma‑separated list → supports mirroring or data locality.
rawstor-ost [-h] -b ADDR LOCATION
| Option | Description |
|---|---|
-h, --help |
Show help message and exit. |
LOCATION |
Comma‑separated list of backend locations (e.g., file:///path, ost://host:port). |
-b, --bind ADDR |
Bind address in <ip>:<port> format (e.g., 127.0.0.1:7777). |
Serve local directory:
rawstor-ost -b 0.0.0.0:7777 file:///var/rawstor/dataProxy to remote OST:
rawstor-ost -b 0.0.0.0:7777 ost://192.168.1.100:7777Data locality (local cache + proxy):
rawstor-ost -b 0.0.0.0:7777 file:///var/rawstor/data,ost://remote:7777Mirroring between two OST backends:
rawstor-ost -b 0.0.0.0:7777 ost://left:7777,ost://right:7777rawstor-vhost is a userspace VirtIO block device backend implementing the
vhost-user protocol
for virtio-blk-pci/vhost-user-blk-pci devices. It gives a guest direct,
zero-copy access to a rawstor object's data: virtqueue descriptors are
resolved straight into the guest's shared memory regions and read from or
written to the backing object via librawstor's native io_uring-based
object I/O, with no host-side kernel block layer or copy in between.
The vhost-user protocol itself (feature/memory-region negotiation,
virtqueue kick/call handling, request dispatch) is implemented natively in
vhost/ — it does not depend on qemu's libvhost-user library. Every I/O
path, including the control socket, is asynchronous and non-blocking, and
multiple in-flight requests on a virtqueue may complete out of order.
rawstor-vhost [-h] -s SOCKET_PATH TARGET [--queue-size SIZE] [-v]
| Option | Description |
|---|---|
-h, --help |
Show help message and exit. |
-s, --socket-path PATH |
Location of the vhost-user Unix domain socket. |
TARGET |
Comma‑separated list of rawstor backend targets (see Locations and Targets). |
--queue-size SIZE |
RawIO queue (io_uring) depth. Default: 256. |
-v, --version |
Print version and exit. |
PREFIX=${HOME}/local
OST_ADDR=192.168.0.1:7777
OBJECT_ID=...
VHOST_RUNDIR=${PREFIX}/var/run/rawstor
rawstor-vhost \
--socket-path=${VHOST_RUNDIR}/rawstor1.sock \
ost://${OST_ADDR}/${OBJECT_ID}
qemu-system-x86_64 \
-enable-kvm \
-m 4G \
-machine accel=kvm,memory-backend=mem \
-drive file=image.qcow2,if=none,id=drive1 \
-device virtio-blk-pci,drive=drive1 \
-object memory-backend-memfd,id=mem,size=4G,share=on \
-chardev socket,id=rawstor1,reconnect=1,path=${VHOST_RUNDIR}/rawstor1.sock \
-device vhost-user-blk-pci,chardev=rawstor1,num-queues=1,disable-legacy=on
rawstor-vhost negotiates VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_SEG_MAX,
VIRTIO_BLK_F_BLK_SIZE, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_MQ,
VIRTIO_RING_F_INDIRECT_DESC and VIRTIO_RING_F_EVENT_IDX, and services
read (VIRTIO_BLK_T_IN), write (VIRTIO_BLK_T_OUT) and identify
(VIRTIO_BLK_T_GET_ID) requests. VIRTIO_BLK_T_FLUSH, _DISCARD and
_WRITE_ZEROES are not implemented and are answered with
VIRTIO_BLK_S_UNSUPP. Although VIRTIO_BLK_F_MQ is negotiated (so a
front-end may query the queue count via VHOST_USER_GET_QUEUE_NUM), only a
single virtqueue is actually serviced per device.
rawstor-vhost serves exactly one front-end connection per process
invocation: it accepts a connection on the socket, serves it until the
front-end disconnects (exiting cleanly), and then exits. A setup or
protocol error (e.g. a mismatched num-queues) is reported and also exits
the process, rather than silently waiting for another connection. Pair it
with reconnect=1 on the QEMU chardev and an external supervisor (e.g.
systemd with Restart=always, or a wrapper loop) if the backend needs to
survive guest-side reconnects. Send SIGINT/SIGTERM to stop it.
rawstor-vhost ships in its own rawstor-vhost deb/rpm package (separate
from librawstor), along with the rawstor-vhost@.service systemd
template unit. The package creates the same system user/group (rawstor)
that rawstor-ost uses, if it doesn't already exist — it does not
depend on libvirt, since rawstor-vhost has no need for it (it talks to
QEMU purely over a vhost-user Unix socket, negotiated when QEMU connects).
Whatever user actually runs QEMU (libvirt-qemu on Debian/Ubuntu, qemu
on Fedora/RHEL, or something else entirely if you invoke QEMU by hand)
needs permission to connect to the socket under RuntimeDirectory=rawstor
(/run/rawstor/*.sock). Add that user to the rawstor group rather than
running rawstor-vhost as it:
sudo usermod -aG rawstor libvirt-qemu # Debian/Ubuntu + libvirt
sudo usermod -aG rawstor qemu # Fedora/RHEL + libvirtThis works because rawstor-vhost chmod()s the socket to 0660 itself
right after creating it, regardless of the caller's umask — on Linux,
connect(2) to a UNIX stream socket requires write permission on the
socket file itself (not just directory access), so leaving it at whatever
bind(2) produced under the process's umask (commonly 0755, i.e.
group gets read+execute but no write) would silently prevent anyone but
the socket's owner from ever connecting. Since the daemon enforces this
itself, it holds regardless of how or by whom rawstor-vhost is invoked —
including if you override User=/Group= below via a drop-in.
If User=/Group=rawstor in the unit doesn't fit your setup (e.g. you'd
rather run rawstor-vhost as the same user QEMU runs as, instead of
sharing access via the group), override it with a drop-in instead of
editing the shipped unit file — systemctl edit rawstor-vhost@.service
(all instances) or systemctl edit rawstor-vhost@<uuid>.service (one
instance) opens an editor and saves the result under
/etc/systemd/system/…/override.conf, which survives package upgrades.
See the comment above User= in systemd/rawstor-vhost@.service and
systemd.unit(5) for details.
make test
We love your contributions and want to make it as easy as possible to work together. Please follow these guidelines when contributing to this project.
For major features or significant changes, please open an issue first to discuss your proposed changes with the maintainers. This helps ensure your work aligns with the project direction and prevents duplicate effort. For small fixes (typos, minor bugs), feel free to open a pull request directly.
-
Fork the repository on GitHub
-
Clone your fork locally:
git clone https://github.com/<your-username>/librawstor.git
cd librawstor- Create a feature branch with a descriptive name:
# For new features:
git checkout -b add/feature-name
# For bug fixes:
git checkout -b fix/bug-description
# For refactoring:
git checkout -b ref/component-name-
Make your changes and commit them with clear, descriptive commit messages
-
Push your branch to your fork:
git push origin <your-branch-name>- Submit a Pull Request from your branch to the
mainbranch of therawstor/librawstorrepository
- Follow the existing code style and patterns in the project
- Write clear, descriptive commit messages
- Include comments for complex logic
- Update documentation when necessary
- Add tests for new functionality
- Provide a clear description of what the PR accomplishes
- Reference any related issues (e.g., "Fixes #123")
- Ensure all tests pass (by running
make test) and code meets quality standards - Keep PRs focused on a single purpose - avoid mixing multiple features
- Check existing issues and discussions
- Ask questions in the project's GitHub Discussions
- Reach out to maintainers by mentioning them in issues
Thank you for contributing!
io_uring_queue_init() failed: Operation not permitted
First check if io_uring is disabled or not in sysctl:
sysctl -a | grep io_uringAccording to the documentation for the sysctl files in /proc/sys/kernel/:
io_uring_disabled:Prevents all processes from creating new
io_uringinstances. Enabling this shrinks the kernel’s attack surface.
0- All processes can createio_uringinstances as normal. This is the default setting.
1-io_uringcreation is disabled (io_uring_setup()will fail with-EPERM) for unprivileged processes not in theio_uring_groupgroup. Existingio_uringinstances can still be used. See the documentation forio_uring_groupfor more information.
2-io_uringcreation is disabled for all processes.io_uring_setup()always fails with-EPERM. Existingio_uringinstances can still be used.
So you need to set it to 0:
sysctl kernel.io_uring_disabled=0