Compare commits

...
35 Commits
Author SHA1 Message Date
Vitaliy Filippov 0c89886374 Release 2.3.0
New features:

- Add a new kernel device mounting method: [ublk](https://vitastor.io/docs/usage/ublk.html).
  It's the fastest method for random IOPS, and it's on par with VDUSE for linear MB/s.
- Disable io_uring waits being reported as iowait on kernels which support it (6.15+)
- Allow to enforce permissions at the VitastorFS NFS server side
- Add qemu_file_mirror_path option to the config to allow to trick Veeam and make it work
- Speed up CRC32C calculation in OSD by fixing a bug and enabling AVX512 version
- Support QEMU 10
- Support Debian 13 Trixie and Proxmox 9.0
- Remove the dependency on system liburing in package builds (build it statically)

Bug fixes:

- Fix checksums NEVER BEING ENABLED in vitastor-disk prepare, even when explicitly requested :-D
- Use default uid and gid from NFS AUTH_SYS when creating files
- Fix object bitmaps supposedly & possibly being corrupted in some rare cases with EC N+2+
- Avoid multiple inflight overwrites to meta blocks - fixes possible data corruption with
  one specific SSD model: Memblaze PBlaze5 910 (github #79)
- Fix a bug in antietcd which was leading to leases sometimes not expiring correctly
- Fix a bug in NFS where ".." entry had its `cookie` equal to 0 instead of 1 (github #78)
- Fix snapshots not being deleted during VM deletion in Proxmox plugin (github #85)
- Fix monitor not filtering OSDs by block size correctly
2025-08-25 21:39:19 +03:00
Vitaliy Filippov e79bef8751 Fix pve-qemu-10.0 patch 2025-08-25 21:38:18 +03:00
Vitaliy Filippov ad76f84e1c Fix compat.h for even older kernel headers 2025-08-25 21:38:04 +03:00
Vitaliy Filippov db827cb34c Add --enforce 1 to docs 2025-08-25 16:05:40 +03:00
Vitaliy Filippov e5c6d85ea1 Add Debian trixie to docs 2025-08-25 00:47:23 +03:00
Vitaliy Filippov 6cc44c1f54 Add qemu_file_mirror_path docs 2025-08-25 00:45:52 +03:00
Vitaliy Filippov c20450c1f1 Add build.sh for Debian Trixie 2025-08-24 22:15:55 +03:00
Vitaliy Filippov db63e58b3d Add UBLK docs 2025-08-24 16:55:58 +03:00
Vitaliy Filippov 31b7021330 Implement Vitastor ublk server 2025-08-24 16:55:58 +03:00
Vitaliy Filippov 2ebe3a468c Mark all symbols hidden by default, export only required ones 2025-08-24 16:55:58 +03:00
Vitaliy Filippov 9892fccfb0 Disable io_uring waits being reported as iowait 2025-08-24 16:55:58 +03:00
Vitaliy Filippov 0be86a306d Remove old liburing version support as it's now included 2025-08-24 16:55:58 +03:00
Vitaliy Filippov d77a775948 Fix liburing include/compat for older kernels 2025-08-24 16:55:58 +03:00
Vitaliy Filippov 8cc82bab39 Include liburing in static build 2025-08-24 16:55:58 +03:00
Vitaliy Filippov f9d5e33ddd Fix filtering OSDs by block size in monitor 2025-08-24 16:46:36 +03:00
f83418d93e Fix snapshots not being deleted during VM deletion in Proxmox plugin (#85)
Co-authored-by: zhu.chengzhen <zhu.chengzhen@jingjiamicro.com>

I accept Vitastor CLA agreement: https://git.yourcmc.ru/vitalif/vitastor/src/branch/master/CLA-en.md
2025-08-24 16:28:12 +03:00
Vitaliy Filippov fbf14fb0cb Allow to enforce permissions at the server side 2025-08-24 16:20:19 +03:00
Vitaliy Filippov fb1c3e00f4 Use default uid and gid from NFS AUTH_SYS when creating files 2025-08-24 16:03:40 +03:00
ston3luandVitaliy Filippov d8332171e9 According to the NFSv3 protocol: Directory traversal should start with cookie '0' - "." entry as the first entry, cookie should be '0' - '.." entry as the second entry, cookie should be '1' 2025-08-24 14:44:48 +03:00
Vitaliy Filippov c24cc9bf0b Bump antietcd version to 1.1.3 2025-08-23 17:45:56 +03:00
Vitaliy Filippov 9f57c75acf unordered_map flush_versions 2025-08-23 17:45:56 +03:00
Vitaliy Filippov 53b12641d1 Fix the fix :) 2025-08-23 17:45:56 +03:00
flynn.yangandVitaliy Filippov 5c5c8825dc Avoid multiple inflight overwrites to meta blocks
https://github.com/vitalif/vitastor/pull/83

By https://github.com/Flynn049

By submitting this pull request, I accept Vitastor CLA
2025-08-23 17:45:03 +03:00
Vitaliy Filippov 3a261ac3fc Support QEMU 10 2025-08-18 10:51:04 +03:00
Vitaliy Filippov 04514435de Fix checking config in qemu driver 2025-08-12 01:16:57 +03:00
Vitaliy Filippov 07303020fc Fix enabling checksums in blockstore-disk O_o 2025-08-10 18:04:52 +03:00
Vitaliy Filippov feaf7a15cf Use CRC32C implementation from ISA-L when available - enables VPCLMULQDQ version with AVX512 which is ~2x faster 2025-08-10 18:03:47 +03:00
Vitaliy Filippov 29dda5066f Stop doing cpuid repeatedly in runtime 2025-08-10 18:03:22 +03:00
Vitaliy Filippov 1de53ef7e6 Move crc32c_pad to util/crc32c.c 2025-08-10 18:03:17 +03:00
Vitaliy Filippov 4793dbe9c3 Use set_immediate() in osd_flush to prevent stack overflows on repeated errors 2025-08-10 17:58:01 +03:00
Vitaliy Filippov 918ea34af2 Remove "Only allow to overwrite part of the bitmap" blockstore API feature 2025-08-10 17:57:04 +03:00
Vitaliy Filippov 2db8184cd8 Fix bitmap calculation for EC N+1 & the new store and EC N+2+ for the old store 2025-08-10 17:57:04 +03:00
Vitaliy Filippov 0e964b3c8c Fix renaming from ddeb 2025-08-09 16:11:22 +03:00
Vitaliy Filippov 1b9296ff6c Add qemu_file_mirror_path option to the config to allow to trick Veeam
When qemu_file_mirror_path is set to "/dir/" in /etc/vitastor/vitastor.conf, QEMU driver
returns "/dir/image_name" as the filename in qemu-img info and in QAPI to trick software
like Veeam which expects file-based access. After that, vitastor-nfs can be mounted to that
directory to make backups work :-)
2025-08-06 01:15:54 +03:00
Vitaliy Filippov 6bf136c199 Add a note about /etc/apt/preferences to docs 2025-08-05 11:25:06 +03:00
152 changed files with 8662 additions and 444 deletions
+1 -1
View File
@@ -20,7 +20,7 @@ RUN echo 'deb http://deb.debian.org/debian bullseye-backports main' >> /etc/apt/
RUN apt-get update RUN apt-get update
RUN apt-get -y install etcd qemu-system-x86 qemu-block-extra qemu-utils fio libasan5 \ RUN apt-get -y install etcd qemu-system-x86 qemu-block-extra qemu-utils fio libasan5 \
liburing1 liburing-dev libgoogle-perftools-dev devscripts libjerasure-dev cmake libibverbs-dev libisal-dev libgoogle-perftools-dev devscripts libjerasure-dev cmake libibverbs-dev libisal-dev
RUN apt-get -y build-dep fio qemu=`dpkg -s qemu-system-x86|grep ^Version:|awk '{print $2}'` RUN apt-get -y build-dep fio qemu=`dpkg -s qemu-system-x86|grep ^Version:|awk '{print $2}'`
RUN apt-get update && apt-get -y install jq lp-solve sudo nfs-common fdisk parted RUN apt-get update && apt-get -y install jq lp-solve sudo nfs-common fdisk parted
RUN apt-get --download-only source fio qemu=`dpkg -s qemu-system-x86|grep ^Version:|awk '{print $2}'` RUN apt-get --download-only source fio qemu=`dpkg -s qemu-system-x86|grep ^Version:|awk '{print $2}'`
+1 -1
View File
@@ -2,6 +2,6 @@ cmake_minimum_required(VERSION 2.8.12)
project(vitastor) project(vitastor)
set(VITASTOR_VERSION "2.2.3") set(VITASTOR_VERSION "2.3.0")
add_subdirectory(src) add_subdirectory(src)
+4 -3
View File
@@ -19,7 +19,7 @@ Vitastor нацелен в первую очередь на SSD и SSD+HDD кл
TCP и RDMA и на хорошем железе может достигать задержки 4 КБ чтения и записи на уровне ~0.1 мс, TCP и RDMA и на хорошем железе может достигать задержки 4 КБ чтения и записи на уровне ~0.1 мс,
что примерно в 10 раз быстрее, чем Ceph и другие популярные программные СХД. что примерно в 10 раз быстрее, чем Ceph и другие популярные программные СХД.
Vitastor поддерживает QEMU-драйвер, протоколы NBD и NFS, драйверы OpenStack, OpenNebula, Proxmox, Kubernetes. Vitastor поддерживает QEMU-драйвер, протоколы UBLK, NBD и NFS, драйверы OpenStack, OpenNebula, Proxmox, Kubernetes.
Другие драйверы могут также быть легко реализованы. Другие драйверы могут также быть легко реализованы.
Подробности смотрите в документации по ссылкам. Можете начать отсюда: [Быстрый старт](docs/intro/quickstart.ru.md). Подробности смотрите в документации по ссылкам. Можете начать отсюда: [Быстрый старт](docs/intro/quickstart.ru.md).
@@ -64,8 +64,9 @@ Vitastor поддерживает QEMU-драйвер, протоколы NBD и
- [vitastor-cli](docs/usage/cli.ru.md) (консольный интерфейс) - [vitastor-cli](docs/usage/cli.ru.md) (консольный интерфейс)
- [vitastor-disk](docs/usage/disk.ru.md) (управление дисками) - [vitastor-disk](docs/usage/disk.ru.md) (управление дисками)
- [fio](docs/usage/fio.ru.md) для тестов производительности - [fio](docs/usage/fio.ru.md) для тестов производительности
- [NBD](docs/usage/nbd.ru.md) для монтирования ядром - [UBLK](docs/usage/ublk.ru.md) для монтирования ядром
- [QEMU и qemu-img](docs/usage/qemu.ru.md) - [NBD](docs/usage/nbd.ru.md) - старый интерфейс для монтирования ядром
- [QEMU, qemu-img и VDUSE](docs/usage/qemu.ru.md)
- [NFS](docs/usage/nfs.ru.md) кластерная файловая система и псевдо-ФС прокси - [NFS](docs/usage/nfs.ru.md) кластерная файловая система и псевдо-ФС прокси
- [Администрирование](docs/usage/admin.ru.md) - [Администрирование](docs/usage/admin.ru.md)
- Производительность - Производительность
+4 -3
View File
@@ -19,7 +19,7 @@ supports TCP and RDMA and may achieve 4 KB read and write latency as low as ~0.1
with proper hardware which is ~10 times faster than other popular SDS's like Ceph with proper hardware which is ~10 times faster than other popular SDS's like Ceph
or internal systems of public clouds. or internal systems of public clouds.
Vitastor supports QEMU, NBD, NFS protocols, OpenStack, OpenNebula, Proxmox, Kubernetes drivers. Vitastor supports QEMU, UBLK, NBD, NFS protocols, OpenStack, OpenNebula, Proxmox, Kubernetes drivers.
More drivers may be created easily. More drivers may be created easily.
Read more details in the documentation. You can start from here: [Quick Start](docs/intro/quickstart.en.md). Read more details in the documentation. You can start from here: [Quick Start](docs/intro/quickstart.en.md).
@@ -64,8 +64,9 @@ Read more details in the documentation. You can start from here: [Quick Start](d
- [vitastor-cli](docs/usage/cli.en.md) (command-line interface) - [vitastor-cli](docs/usage/cli.en.md) (command-line interface)
- [vitastor-disk](docs/usage/disk.en.md) (disk management tool) - [vitastor-disk](docs/usage/disk.en.md) (disk management tool)
- [fio](docs/usage/fio.en.md) for benchmarks - [fio](docs/usage/fio.en.md) for benchmarks
- [NBD](docs/usage/nbd.en.md) for kernel mounts - [UBLK](docs/usage/ublk.en.md) for kernel mounts
- [QEMU and qemu-img](docs/usage/qemu.en.md) - [NBD](docs/usage/nbd.en.md) - old interface for kernel mounts
- [QEMU, qemu-img and VDUSE](docs/usage/qemu.en.md)
- [NFS](docs/usage/nfs.en.md) clustered file system and pseudo-FS proxy - [NFS](docs/usage/nfs.en.md) clustered file system and pseudo-FS proxy
- [Administration](docs/usage/admin.en.md) - [Administration](docs/usage/admin.en.md)
- Performance - Performance
+1 -1
View File
@@ -1,4 +1,4 @@
VITASTOR_VERSION ?= v2.2.3 VITASTOR_VERSION ?= v2.3.0
all: build push all: build push
+1 -1
View File
@@ -49,7 +49,7 @@ spec:
capabilities: capabilities:
add: ["SYS_ADMIN"] add: ["SYS_ADMIN"]
allowPrivilegeEscalation: true allowPrivilegeEscalation: true
image: vitalif/vitastor-csi:v2.2.3 image: vitalif/vitastor-csi:v2.3.0
args: args:
- "--node=$(NODE_ID)" - "--node=$(NODE_ID)"
- "--endpoint=$(CSI_ENDPOINT)" - "--endpoint=$(CSI_ENDPOINT)"
+1 -1
View File
@@ -121,7 +121,7 @@ spec:
privileged: true privileged: true
capabilities: capabilities:
add: ["SYS_ADMIN"] add: ["SYS_ADMIN"]
image: vitalif/vitastor-csi:v2.2.3 image: vitalif/vitastor-csi:v2.3.0
args: args:
- "--node=$(NODE_ID)" - "--node=$(NODE_ID)"
- "--endpoint=$(CSI_ENDPOINT)" - "--endpoint=$(CSI_ENDPOINT)"
+1 -1
View File
@@ -5,7 +5,7 @@ package vitastor
const ( const (
vitastorCSIDriverName = "csi.vitastor.io" vitastorCSIDriverName = "csi.vitastor.io"
vitastorCSIDriverVersion = "2.2.3" vitastorCSIDriverVersion = "2.3.0"
) )
// Config struct fills the parameters of request or user input // Config struct fills the parameters of request or user input
+4
View File
@@ -0,0 +1,4 @@
#!/bin/bash
docker build --build-arg DISTRO=debian --build-arg REL=trixie -t vitastor-buildenv:trixie -f vitastor-buildenv.Dockerfile .
docker run -i --rm -e REL=trixie -v `dirname $0`/../:/root/vitastor vitastor-buildenv:trixie /root/vitastor/debian/vitastor-build.sh
+1 -1
View File
@@ -1,4 +1,4 @@
vitastor (2.2.3-1) unstable; urgency=medium vitastor (2.3.0-1) unstable; urgency=medium
* Bugfixes * Bugfixes
+1 -1
View File
@@ -2,7 +2,7 @@ Source: vitastor
Section: admin Section: admin
Priority: optional Priority: optional
Maintainer: Vitaliy Filippov <vitalif@yourcmc.ru> Maintainer: Vitaliy Filippov <vitalif@yourcmc.ru>
Build-Depends: debhelper, liburing-dev (>= 0.6), g++ (>= 8), libstdc++6 (>= 8), Build-Depends: debhelper, g++ (>= 8), libstdc++6 (>= 8),
linux-libc-dev, libgoogle-perftools-dev, libjerasure-dev, libgf-complete-dev, linux-libc-dev, libgoogle-perftools-dev, libjerasure-dev, libgf-complete-dev,
libibverbs-dev, libisal-dev, cmake, pkg-config, libnl-3-dev, libnl-genl-3-dev, libibverbs-dev, libisal-dev, cmake, pkg-config, libnl-3-dev, libnl-genl-3-dev,
node-bindings <!nocheck>, node-gyp, node-nan node-bindings <!nocheck>, node-gyp, node-nan
+1 -1
View File
@@ -26,7 +26,7 @@ RUN if [ "$REL" = "buster" -o "$REL" = "bullseye" -o "$REL" = "bookworm" ]; then
echo 'APT::Install-Suggests false;' >> /etc/apt/apt.conf echo 'APT::Install-Suggests false;' >> /etc/apt/apt.conf
RUN apt-get update RUN apt-get update
RUN DEBIAN_FRONTEND=noninteractive TZ=Europe/Moscow apt-get -y install fio liburing-dev libgoogle-perftools-dev devscripts RUN DEBIAN_FRONTEND=noninteractive TZ=Europe/Moscow apt-get -y install fio libgoogle-perftools-dev devscripts
RUN DEBIAN_FRONTEND=noninteractive TZ=Europe/Moscow apt-get -y build-dep qemu RUN DEBIAN_FRONTEND=noninteractive TZ=Europe/Moscow apt-get -y build-dep qemu
# To build a custom version # To build a custom version
#RUN cp /root/packages/qemu-orig/* /root #RUN cp /root/packages/qemu-orig/* /root
+1
View File
@@ -51,6 +51,7 @@ DEB_BUILD_OPTIONS=nocheck dpkg-buildpackage --jobs=auto -sa
rm -rf /root/vitastor/packages/vitastor-$REL/vitastor-*/ rm -rf /root/vitastor/packages/vitastor-$REL/vitastor-*/
# Why does ubuntu rename debug packages to *.ddeb? # Why does ubuntu rename debug packages to *.ddeb?
cd /root/vitastor/packages/vitastor-$REL
if ls *.ddeb >/dev/null; then if ls *.ddeb >/dev/null; then
perl -i -pe 's/\.ddeb/.deb/' *.buildinfo *.changes perl -i -pe 's/\.ddeb/.deb/' *.buildinfo *.changes
for i in *.ddeb; do for i in *.ddeb; do
+1 -1
View File
@@ -25,7 +25,7 @@ RUN set -e -x; \
echo 'APT::Install-Suggests false;' >> /etc/apt/apt.conf echo 'APT::Install-Suggests false;' >> /etc/apt/apt.conf
RUN apt-get update && \ RUN apt-get update && \
apt-get -y install fio liburing-dev libgoogle-perftools-dev devscripts libjerasure-dev cmake \ apt-get -y install fio libgoogle-perftools-dev devscripts libjerasure-dev cmake \
libibverbs-dev librdmacm-dev libisal-dev libnl-3-dev libnl-genl-3-dev curl nodejs npm node-nan node-bindings && \ libibverbs-dev librdmacm-dev libisal-dev libnl-3-dev libnl-genl-3-dev curl nodejs npm node-nan node-bindings && \
apt-get -y build-dep fio && \ apt-get -y build-dep fio && \
apt-get --download-only source fio apt-get --download-only source fio
+1
View File
@@ -2,6 +2,7 @@ usr/bin/vita
usr/bin/vitastor-cli usr/bin/vitastor-cli
usr/bin/vitastor-rm usr/bin/vitastor-rm
usr/bin/vitastor-nbd usr/bin/vitastor-nbd
usr/bin/vitastor-ublk
usr/bin/vitastor-nfs usr/bin/vitastor-nfs
usr/bin/vitastor-kv usr/bin/vitastor-kv
usr/bin/vitastor-kv-stress usr/bin/vitastor-kv-stress
+1 -1
View File
@@ -1,4 +1,4 @@
VITASTOR_VERSION ?= v2.2.3 VITASTOR_VERSION ?= v2.3.0
all: build push all: build push
+1 -1
View File
@@ -4,7 +4,7 @@
# #
# Desired Vitastor version # Desired Vitastor version
VITASTOR_VERSION=v2.2.3 VITASTOR_VERSION=v2.3.0
# Additional arguments for all containers # Additional arguments for all containers
# For example, you may want to specify a custom logging driver here # For example, you may want to specify a custom logging driver here
+28
View File
@@ -25,6 +25,9 @@ affect their interaction with the cluster.
- [nbd_max_part](#nbd_max_part) - [nbd_max_part](#nbd_max_part)
- [osd_nearfull_ratio](#osd_nearfull_ratio) - [osd_nearfull_ratio](#osd_nearfull_ratio)
- [hostname](#hostname) - [hostname](#hostname)
- [ublk_queue_depth](#ublk_queue_depth)
- [ublk_max_io_size](#ublk_max_io_size)
- [qemu_file_mirror_path](#qemu_file_mirror_path)
## client_iothread_count ## client_iothread_count
@@ -225,3 +228,28 @@ without destroying and recreating OSDs.
Clients use host name to find their distance to OSDs when [localized reads](pool.en.md#local_reads) Clients use host name to find their distance to OSDs when [localized reads](pool.en.md#local_reads)
are enabled. By default, standard [gethostname](https://man7.org/linux/man-pages/man2/gethostname.2.html) are enabled. By default, standard [gethostname](https://man7.org/linux/man-pages/man2/gethostname.2.html)
function is used to determine host name, but you can also override it with this parameter. function is used to determine host name, but you can also override it with this parameter.
## ublk_queue_depth
- Type: integer
- Default: 256
Default queue depth for [Vitastor ublk servers](../usage/ublk.en.md).
## ublk_max_io_size
- Type: integer
Default maximum I/O size for Vitastor [ublk servers](../usage/ublk.en.md).
The largest of 1 MB and pool block size multiplied by EC data chunk count is used if not specified.
## qemu_file_mirror_path
- Type: string
When set to an FS directory path (for example, `/mnt/vitastor/`), `qemu-img info` and similar
QAPI commands return the name of the image inside this directory instead of normal
`vitastor://?image=abc` URI as `filename`.
This allows to then mount this path using [vitastor-nfs](../usage/nfs.en.md) and trick
third-party systems like Veeam which rely on `filename` in the image info but don't support Vitastor.
+30
View File
@@ -25,6 +25,9 @@
- [nbd_max_part](#nbd_max_part) - [nbd_max_part](#nbd_max_part)
- [osd_nearfull_ratio](#osd_nearfull_ratio) - [osd_nearfull_ratio](#osd_nearfull_ratio)
- [hostname](#hostname) - [hostname](#hostname)
- [ublk_queue_depth](#ublk_queue_depth)
- [ublk_max_io_size](#ublk_max_io_size)
- [qemu_file_mirror_path](#qemu_file_mirror_path)
## client_iothread_count ## client_iothread_count
@@ -230,3 +233,30 @@ RDMA и хотите повысить пиковую производитель
[локальные чтения](pool.ru.md#local_reads). По умолчанию для определения имени [локальные чтения](pool.ru.md#local_reads). По умолчанию для определения имени
хоста используется стандартная функция [gethostname](https://man7.org/linux/man-pages/man2/gethostname.2.html), хоста используется стандартная функция [gethostname](https://man7.org/linux/man-pages/man2/gethostname.2.html),
но вы также можете задать имя хоста вручную данным параметром. но вы также можете задать имя хоста вручную данным параметром.
## ublk_queue_depth
- Тип: целое число
- Значение по умолчанию: 256
Глубина очереди по умолчанию для [ublk-серверов Vitastor](../usage/ublk.ru.md).
## ublk_max_io_size
- Тип: целое число
Максимальный размер запроса ввода-вывода для [ublk-серверов Vitastor](../usage/ublk.ru.md).
Если не задан, используется максимум из 1 МБ и размера блока пула, умноженного на число частей
данных EC-пула.
## qemu_file_mirror_path
- Тип: строка
Если установить эту опцию равной пути к каталогу в ФС, команда `qemu-img info` и подобные
команды QAPI будут возвращать в поле `filename` имя образа внутри заданного каталога вместо
обычного адреса типа `vitastor://?image=abc`.
Это позволяет смонтировать этот путь с помощью [vitastor-nfs](../usage/nfs.ru.md) и обмануть
сторонние системы типа Veeam, которые полагаются на поле `filename` в информации об образе QEMU,
но не поддерживают Vitastor.
+33
View File
@@ -283,3 +283,36 @@
[локальные чтения](pool.ru.md#local_reads). По умолчанию для определения имени [локальные чтения](pool.ru.md#local_reads). По умолчанию для определения имени
хоста используется стандартная функция [gethostname](https://man7.org/linux/man-pages/man2/gethostname.2.html), хоста используется стандартная функция [gethostname](https://man7.org/linux/man-pages/man2/gethostname.2.html),
но вы также можете задать имя хоста вручную данным параметром. но вы также можете задать имя хоста вручную данным параметром.
- name: ublk_queue_depth
type: int
default: 256
online: false
info: Default queue depth for [Vitastor ublk servers](../usage/ublk.en.md).
info_ru: Глубина очереди по умолчанию для [ublk-серверов Vitastor](../usage/ublk.ru.md).
- name: ublk_max_io_size
type: int
online: false
info: |
Default maximum I/O size for Vitastor [ublk servers](../usage/ublk.en.md).
The largest of 1 MB and pool block size multiplied by EC data chunk count is used if not specified.
info_ru: |
Максимальный размер запроса ввода-вывода для [ublk-серверов Vitastor](../usage/ublk.ru.md).
Если не задан, используется максимум из 1 МБ и размера блока пула, умноженного на число частей
данных EC-пула.
- name: qemu_file_mirror_path
type: string
info: |
When set to an FS directory path (for example, `/mnt/vitastor/`), `qemu-img info` and similar
QAPI commands return the name of the image inside this directory instead of normal
`vitastor://?image=abc` URI as `filename`.
This allows to then mount this path using [vitastor-nfs](../usage/nfs.en.md) and trick
third-party systems like Veeam which rely on `filename` in the image info but don't support Vitastor.
info_ru: |
Если установить эту опцию равной пути к каталогу в ФС, команда `qemu-img info` и подобные
команды QAPI будут возвращать в поле `filename` имя образа внутри заданного каталога вместо
обычного адреса типа `vitastor://?image=abc`.
Это позволяет смонтировать этот путь с помощью [vitastor-nfs](../usage/nfs.ru.md) и обмануть
сторонние системы типа Veeam, которые полагаются на поле `filename` в информации об образе QEMU,
но не поддерживают Vitastor.
+4
View File
@@ -24,6 +24,8 @@
{{../../installation/kubernetes.en.md}} {{../../installation/kubernetes.en.md}}
{{../../installation/s3.en.md}}
{{../../installation/source.en.md}} {{../../installation/source.en.md}}
{{../../config.en.md|indent=1}} {{../../config.en.md|indent=1}}
@@ -54,6 +56,8 @@
{{../../usage/fio.en.md}} {{../../usage/fio.en.md}}
{{../../usage/ublk.en.md}}
{{../../usage/nbd.en.md}} {{../../usage/nbd.en.md}}
{{../../usage/qemu.en.md}} {{../../usage/qemu.en.md}}
+4
View File
@@ -26,6 +26,8 @@
{{../../installation/source.ru.md}} {{../../installation/source.ru.md}}
{{../../installation/s3.ru.md}}
{{../../config.ru.md|indent=1}} {{../../config.ru.md|indent=1}}
{{../../config/common.ru.md|indent=2}} {{../../config/common.ru.md|indent=2}}
@@ -54,6 +56,8 @@
{{../../usage/fio.ru.md}} {{../../usage/fio.ru.md}}
{{../../usage/ublk.ru.md}}
{{../../usage/nbd.ru.md}} {{../../usage/nbd.ru.md}}
{{../../usage/qemu.ru.md}} {{../../usage/qemu.ru.md}}
+2 -2
View File
@@ -26,9 +26,9 @@ at Vitastor Kubernetes operator: https://github.com/Antilles7227/vitastor-operat
The instruction is very simple. The instruction is very simple.
1. Download a Docker image of the desired version: \ 1. Download a Docker image of the desired version: \
`docker pull vitalif/vitastor:v2.2.3` `docker pull vitalif/vitastor:v2.3.0`
2. Install scripts to the host system: \ 2. Install scripts to the host system: \
`docker run --rm -it -v /etc:/host-etc -v /usr/bin:/host-bin vitalif/vitastor:v2.2.3 install.sh` `docker run --rm -it -v /etc:/host-etc -v /usr/bin:/host-bin vitalif/vitastor:v2.3.0 install.sh`
3. Reload udev rules: \ 3. Reload udev rules: \
`udevadm control --reload-rules` `udevadm control --reload-rules`
+2 -2
View File
@@ -25,9 +25,9 @@ Vitastor можно установить в Docker/Podman. При этом etcd,
Инструкция по установке максимально простая. Инструкция по установке максимально простая.
1. Скачайте Docker-образ желаемой версии: \ 1. Скачайте Docker-образ желаемой версии: \
`docker pull vitalif/vitastor:v2.2.3` `docker pull vitalif/vitastor:v2.3.0`
2. Установите скрипты в хост-систему командой: \ 2. Установите скрипты в хост-систему командой: \
`docker run --rm -it -v /etc:/host-etc -v /usr/bin:/host-bin vitalif/vitastor:v2.2.3 install.sh` `docker run --rm -it -v /etc:/host-etc -v /usr/bin:/host-bin vitalif/vitastor:v2.3.0 install.sh`
3. Перезагрузите правила udev: \ 3. Перезагрузите правила udev: \
`udevadm control --reload-rules` `udevadm control --reload-rules`
+8 -2
View File
@@ -11,13 +11,20 @@
- Trust Vitastor package signing key: - Trust Vitastor package signing key:
`wget https://vitastor.io/debian/pubkey.gpg -O /etc/apt/trusted.gpg.d/vitastor.gpg` `wget https://vitastor.io/debian/pubkey.gpg -O /etc/apt/trusted.gpg.d/vitastor.gpg`
- Add Vitastor package repository to your /etc/apt/sources.list: - Add Vitastor package repository to your /etc/apt/sources.list:
- Debian 12 (Bookworm/Sid): `deb https://vitastor.io/debian bookworm main` - Debian 13 (Trixie/Sid): `deb https://vitastor.io/debian trixie main`
- Debian 12 (Bookworm): `deb https://vitastor.io/debian bookworm main`
- Debian 11 (Bullseye): `deb https://vitastor.io/debian bullseye main` - Debian 11 (Bullseye): `deb https://vitastor.io/debian bullseye main`
- Debian 10 (Buster): `deb https://vitastor.io/debian buster main` - Debian 10 (Buster): `deb https://vitastor.io/debian buster main`
- Ubuntu 22.04 (Jammy): `deb https://vitastor.io/debian jammy main` - Ubuntu 22.04 (Jammy): `deb https://vitastor.io/debian jammy main`
- Ubuntu 24.04 (Noble): `deb https://vitastor.io/debian noble main` - Ubuntu 24.04 (Noble): `deb https://vitastor.io/debian noble main`
- Add `-oldstable` to bookworm/bullseye/buster in this line to install the last - Add `-oldstable` to bookworm/bullseye/buster in this line to install the last
stable version from 0.9.x branch instead of 1.x stable version from 0.9.x branch instead of 1.x
- To always prefer vitastor-patched QEMU and Libvirt versions, add the following to `/etc/apt/preferences`:
```
Package: *
Pin: origin "vitastor.io"
Pin-Priority: 501
```
- Install packages: `apt update; apt install vitastor lp-solve etcd linux-image-amd64 qemu-system-x86` - Install packages: `apt update; apt install vitastor lp-solve etcd linux-image-amd64 qemu-system-x86`
## CentOS ## CentOS
@@ -43,7 +50,6 @@
recommended because io_uring is a relatively new technology and there is recommended because io_uring is a relatively new technology and there is
at least one bug which reproduces with io_uring and HP SmartArray at least one bug which reproduces with io_uring and HP SmartArray
controllers in 5.4 controllers in 5.4
- liburing 0.4 or newer
- lp_solve - lp_solve
- etcd 3.4.15 or newer. Earlier versions won't work because of various bugs, - etcd 3.4.15 or newer. Earlier versions won't work because of various bugs,
for example [#12402](https://github.com/etcd-io/etcd/pull/12402). for example [#12402](https://github.com/etcd-io/etcd/pull/12402).
+8 -2
View File
@@ -11,13 +11,20 @@
- Добавьте ключ репозитория Vitastor: - Добавьте ключ репозитория Vitastor:
`wget https://vitastor.io/debian/pubkey.gpg -O /etc/apt/trusted.gpg.d/vitastor.gpg` `wget https://vitastor.io/debian/pubkey.gpg -O /etc/apt/trusted.gpg.d/vitastor.gpg`
- Добавьте репозиторий Vitastor в /etc/apt/sources.list: - Добавьте репозиторий Vitastor в /etc/apt/sources.list:
- Debian 12 (Bookworm/Sid): `deb https://vitastor.io/debian bookworm main` - Debian 13 (Trixie/Sid): `deb https://vitastor.io/debian trixie main`
- Debian 12 (Bookworm): `deb https://vitastor.io/debian bookworm main`
- Debian 11 (Bullseye): `deb https://vitastor.io/debian bullseye main` - Debian 11 (Bullseye): `deb https://vitastor.io/debian bullseye main`
- Debian 10 (Buster): `deb https://vitastor.io/debian buster main` - Debian 10 (Buster): `deb https://vitastor.io/debian buster main`
- Ubuntu 22.04 (Jammy): `deb https://vitastor.io/debian jammy main` - Ubuntu 22.04 (Jammy): `deb https://vitastor.io/debian jammy main`
- Ubuntu 24.04 (Noble): `deb https://vitastor.io/debian noble main` - Ubuntu 24.04 (Noble): `deb https://vitastor.io/debian noble main`
- Добавьте `-oldstable` к слову bookworm/bullseye/buster в этой строке, чтобы - Добавьте `-oldstable` к слову bookworm/bullseye/buster в этой строке, чтобы
установить последнюю стабильную версию из ветки 0.9.x вместо 1.x установить последнюю стабильную версию из ветки 0.9.x вместо 1.x
- Чтобы всегда предпочитались версии пакетов QEMU и Libvirt с патчами Vitastor, добавьте в `/etc/apt/preferences`:
```
Package: *
Pin: origin "vitastor.io"
Pin-Priority: 501
```
- Установите пакеты: `apt update; apt install vitastor lp-solve etcd linux-image-amd64 qemu-system-x86` - Установите пакеты: `apt update; apt install vitastor lp-solve etcd linux-image-amd64 qemu-system-x86`
## CentOS ## CentOS
@@ -42,7 +49,6 @@
- Ядро Linux 5.4 или новее, для поддержки io_uring. Рекомендуется даже 5.8, - Ядро Linux 5.4 или новее, для поддержки io_uring. Рекомендуется даже 5.8,
так как io_uring - относительно новый интерфейс и в версиях до 5.8 встречались так как io_uring - относительно новый интерфейс и в версиях до 5.8 встречались
некоторые баги, например, зависание с io_uring и контроллером HP SmartArray некоторые баги, например, зависание с io_uring и контроллером HP SmartArray
- liburing 0.4 или новее
- lp_solve - lp_solve
- etcd 3.4.15 или новее. Более старые версии не будут работать из-за разных багов, - etcd 3.4.15 или новее. Более старые версии не будут работать из-за разных багов,
например, [#12402](https://github.com/etcd-io/etcd/pull/12402). например, [#12402](https://github.com/etcd-io/etcd/pull/12402).
+1 -1
View File
@@ -9,7 +9,7 @@
To enable Vitastor support in Proxmox Virtual Environment (6.4-8.x are supported): To enable Vitastor support in Proxmox Virtual Environment (6.4-8.x are supported):
- Add the corresponding Vitastor Debian repository into sources.list on Proxmox hosts: - Add the corresponding Vitastor Debian repository into sources.list on Proxmox hosts:
bookworm for 8.1+, pve8.0 for 8.0, bullseye for 7.4, pve7.3 for 7.3, pve7.2 for 7.2, pve7.1 for 7.1, buster for 6.4 trixie for 9.0+, bookworm for 8.1+, pve8.0 for 8.0, bullseye for 7.4, pve7.3 for 7.3, pve7.2 for 7.2, pve7.1 for 7.1, buster for 6.4
- Install vitastor-client, pve-qemu-kvm, pve-storage-vitastor (* or see note) packages from Vitastor repository - Install vitastor-client, pve-qemu-kvm, pve-storage-vitastor (* or see note) packages from Vitastor repository
- Define storage in `/etc/pve/storage.cfg` (see below) - Define storage in `/etc/pve/storage.cfg` (see below)
- Block network access from VMs to Vitastor network (to OSDs and etcd), - Block network access from VMs to Vitastor network (to OSDs and etcd),
+1 -1
View File
@@ -9,7 +9,7 @@
Чтобы подключить Vitastor к Proxmox Virtual Environment (поддерживаются версии 6.4-8.x): Чтобы подключить Vitastor к Proxmox Virtual Environment (поддерживаются версии 6.4-8.x):
- Добавьте соответствующий Debian-репозиторий Vitastor в sources.list на хостах Proxmox: - Добавьте соответствующий Debian-репозиторий Vitastor в sources.list на хостах Proxmox:
bookworm для 8.1+, pve8.0 для 8.0, bullseye для 7.4, pve7.3 для 7.3, pve7.2 для 7.2, pve7.1 для 7.1, buster для 6.4 trixie для 9.0+, bookworm для 8.1+, pve8.0 для 8.0, bullseye для 7.4, pve7.3 для 7.3, pve7.2 для 7.2, pve7.1 для 7.1, buster для 6.4
- Установите пакеты vitastor-client, pve-qemu-kvm, pve-storage-vitastor (* или см. сноску) из репозитория Vitastor - Установите пакеты vitastor-client, pve-qemu-kvm, pve-storage-vitastor (* или см. сноску) из репозитория Vitastor
- Определите тип хранилища в `/etc/pve/storage.cfg` (см. ниже) - Определите тип хранилища в `/etc/pve/storage.cfg` (см. ниже)
- Обязательно заблокируйте доступ от виртуальных машин к сети Vitastor (OSD и etcd), т.к. Vitastor (пока) не поддерживает аутентификацию - Обязательно заблокируйте доступ от виртуальных машин к сети Vitastor (OSD и etcd), т.к. Vitastor (пока) не поддерживает аутентификацию
+1 -1
View File
@@ -15,7 +15,7 @@
- gcc and g++ 8 or newer, clang 10 or newer, or other compiler with C++11 plus - gcc and g++ 8 or newer, clang 10 or newer, or other compiler with C++11 plus
designated initializers support from C++20 designated initializers support from C++20
- CMake - CMake
- liburing, jerasure headers and libraries - jerasure headers and libraries
- ISA-L, libibverbs and librdmacm headers and libraries (optional) - ISA-L, libibverbs and librdmacm headers and libraries (optional)
- tcmalloc (google-perftools-dev) - tcmalloc (google-perftools-dev)
+1 -1
View File
@@ -15,7 +15,7 @@
- gcc и g++ >= 8, либо clang >= 10, либо другой компилятор с поддержкой C++11 плюс - gcc и g++ >= 8, либо clang >= 10, либо другой компилятор с поддержкой C++11 плюс
назначенных инициализаторов (designated initializers) из C++20 назначенных инициализаторов (designated initializers) из C++20
- CMake - CMake
- Заголовки и библиотеки liburing, jerasure - Заголовки и библиотеки jerasure
- Опционально - заголовки и библиотеки ISA-L, libibverbs, librdmacm - Опционально - заголовки и библиотеки ISA-L, libibverbs, librdmacm
- tcmalloc (google-perftools-dev) - tcmalloc (google-perftools-dev)
+1 -1
View File
@@ -52,7 +52,7 @@
- Generic user-space client library - Generic user-space client library
- [Native QEMU driver](../usage/qemu.en.md) - [Native QEMU driver](../usage/qemu.en.md)
- [Loadable fio engine for benchmarks](../usage/fio.en.md) - [Loadable fio engine for benchmarks](../usage/fio.en.md)
- [NBD proxy for kernel mounts](../usage/nbd.en.md) - [UBLK](../usage/ublk.en.md) and [NBD](../usage/nbd.en.md) servers for kernel mounts
- [Simplified NFS proxy for file-based image access emulation (suitable for VMWare)](../usage/nfs.en.md#pseudo-fs) - [Simplified NFS proxy for file-based image access emulation (suitable for VMWare)](../usage/nfs.en.md#pseudo-fs)
## Roadmap ## Roadmap
+1 -1
View File
@@ -54,7 +54,7 @@
- Общая пользовательская клиентская библиотека для работы с кластером - Общая пользовательская клиентская библиотека для работы с кластером
- [Драйвер диска для QEMU](../usage/qemu.ru.md) - [Драйвер диска для QEMU](../usage/qemu.ru.md)
- [Драйвер диска для утилиты тестирования производительности fio](../usage/fio.ru.md) - [Драйвер диска для утилиты тестирования производительности fio](../usage/fio.ru.md)
- [NBD-прокси для монтирования образов ядром](../usage/nbd.ru.md) ("блочное устройство в режиме пользователя") - [UBLK](../usage/ublk.ru.md) и [NBD](../usage/nbd.ru.md) серверы для монтирования образов ядром ("блочное устройство в режиме пользователя")
- [Упрощённая NFS-прокси для эмуляции файлового доступа к образам (подходит для VMWare)](../usage/nfs.ru.md#псевдо-фс) - [Упрощённая NFS-прокси для эмуляции файлового доступа к образам (подходит для VMWare)](../usage/nfs.ru.md#псевдо-фс)
## Планы развития ## Планы развития
+3
View File
@@ -89,6 +89,8 @@ POSIX features currently not implemented in VitastorFS:
instead of actually allocated space instead of actually allocated space
- Access times (`atime`) are not tracked (like `-o noatime`) - Access times (`atime`) are not tracked (like `-o noatime`)
- Modification time (`mtime`) is updated lazily every second (like `-o lazytime`) - Modification time (`mtime`) is updated lazily every second (like `-o lazytime`)
- Permission enforcement is disabled by default (and Linux NFS client doesn't
enforce them too). Use `--enforce 1` to enable it.
Other notable missing features which should be addressed in the future: Other notable missing features which should be addressed in the future:
- Inode ID reuse. Currently inode IDs always grow, the limit is 2^48 inodes, so - Inode ID reuse. Currently inode IDs always grow, the limit is 2^48 inodes, so
@@ -258,4 +260,5 @@ Options:
| `--nfspath <PATH>` | set NFS export path to \<PATH> (default is /) | | `--nfspath <PATH>` | set NFS export path to \<PATH> (default is /) |
| `--pidfile <FILE>` | write process ID to the specified file | | `--pidfile <FILE>` | write process ID to the specified file |
| `--logfile <FILE>` | log to the specified file | | `--logfile <FILE>` | log to the specified file |
| `--enforce 1` | enforce permissions at the server side (no by default) |
| `--foreground 1` | stay in foreground, do not daemonize | | `--foreground 1` | stay in foreground, do not daemonize |
+3
View File
@@ -91,6 +91,8 @@ JSON-формате :-). Для инспекции содержимого БД
stat(2), так что `du` всегда показывает сумму размеров файлов, а не фактически занятое место stat(2), так что `du` всегда показывает сумму размеров файлов, а не фактически занятое место
- Времена доступа (`atime`) не отслеживаются (как будто ФС смонтирована с `-o noatime`) - Времена доступа (`atime`) не отслеживаются (как будто ФС смонтирована с `-o noatime`)
- Времена модификации (`mtime`) отслеживаются асинхронно (как будто ФС смонтирована с `-o lazytime`) - Времена модификации (`mtime`) отслеживаются асинхронно (как будто ФС смонтирована с `-o lazytime`)
- Привилегии доступа по умолчанию не проверяются сервером (клиент NFS Linux их также не проверяет).
Чтобы включить проверки, используйте опцию `--enforce 1`.
Другие недостающие функции, которые нужно добавить в будущем: Другие недостающие функции, которые нужно добавить в будущем:
- Переиспользование номеров инодов. В текущей реализации номера инодов всё время - Переиспользование номеров инодов. В текущей реализации номера инодов всё время
@@ -270,4 +272,5 @@ VitastorFS из GPUDirect.
| `--nfspath <PATH>` | установить путь NFS-экспорта в \<PATH> (по умолчанию /) | | `--nfspath <PATH>` | установить путь NFS-экспорта в \<PATH> (по умолчанию /) |
| `--pidfile <FILE>` | записать ID процесса в заданный файл | | `--pidfile <FILE>` | записать ID процесса в заданный файл |
| `--logfile <FILE>` | записывать логи в заданный файл | | `--logfile <FILE>` | записывать логи в заданный файл |
| `--enforce 1` | проверять права доступа на стороне сервера (по умолчанию нет) |
| `--foreground 1` | не уходить в фон после запуска | | `--foreground 1` | не уходить в фон после запуска |
+17 -15
View File
@@ -130,23 +130,16 @@ Linux kernel, starting with version 5.15, supports a new interface for attaching
to the host - VDUSE (vDPA Device in Userspace). QEMU, starting with 7.2, has support for to the host - VDUSE (vDPA Device in Userspace). QEMU, starting with 7.2, has support for
exporting QEMU block devices over this protocol using qemu-storage-daemon. exporting QEMU block devices over this protocol using qemu-storage-daemon.
VDUSE is currently the best interface to attach Vitastor disks as kernel devices because: VDUSE advantages:
- It avoids data copies and thus achieves much better performance than [NBD](nbd.en.md)
- It doesn't have NBD timeout problem - the device doesn't die if an operation executes for too long - VDUSE copies memory 1 time instead of 2, and is thus faster than [NBD](nbd.en.md) for linear read/write.
- It doesn't have NBD timeout problem - the device doesn't die if an operation executes for too long.
- It doesn't have hung device problem - if the userspace process dies it can be restarted (!) - It doesn't have hung device problem - if the userspace process dies it can be restarted (!)
and block device will continue operation and block device will continue operation (UBLK can do it too).
- It doesn't seem to have the device number limit - It doesn't seem to have the device number limit (UBLK also doesn't).
Example performance comparison: At the same time, VDUSE may be slower or faster than [UBLK](ublk.en.md) for linear read/write,
and iops-wise it's sometimes even slower than NBD. See performance comparison examples at the page [UBLK](ublk.en.md).
| | direct fio | NBD | VDUSE |
|----------------------|-------------|-------------|-------------|
| linear write | 3.85 GB/s | 1.12 GB/s | 3.85 GB/s |
| 4k random write Q128 | 240000 iops | 120000 iops | 178000 iops |
| 4k random write Q1 | 9500 iops | 7620 iops | 7640 iops |
| linear read | 4.3 GB/s | 1.8 GB/s | 2.85 GB/s |
| 4k random read Q128 | 287000 iops | 140000 iops | 189000 iops |
| 4k random read Q1 | 9600 iops | 7640 iops | 7780 iops |
To try VDUSE you need at least Linux 5.15, built with VDUSE support To try VDUSE you need at least Linux 5.15, built with VDUSE support
(CONFIG_VDPA=m, CONFIG_VDPA_USER=m, CONFIG_VIRTIO_VDPA=m). (CONFIG_VDPA=m, CONFIG_VDPA_USER=m, CONFIG_VIRTIO_VDPA=m).
@@ -193,3 +186,12 @@ To remove the device:
vdpa dev del test1 vdpa dev del test1
kill <qemu-storage-daemon_process_PID> kill <qemu-storage-daemon_process_PID>
``` ```
## Veeam
Vitastor QEMU driver has a feature that allows to trick third-party systems like Veeam not able to parse qemu-img
vitastor URIs: [qemu_file_mirror_path](../config/client.en.md#qemu_file_mirror_path).
To make such systems work, you should set this option to an FS directory path (for example, `/mnt/vitastor/`) and
mount this directory using [`vitastor-nfs mount --block`](../usage/nfs.en.md). It will make them access
your images using files and, hopefully, succeed in doing their normal job :).
+17 -16
View File
@@ -132,24 +132,16 @@ qemu-system-x86_64 -enable-kvm -m 2048 -M accel=kvm,memory-backend=mem \
к системе - VDUSE (vDPA Device in Userspace), а в QEMU, начиная с версии 7.2, есть поддержка к системе - VDUSE (vDPA Device in Userspace), а в QEMU, начиная с версии 7.2, есть поддержка
экспорта блочных устройств QEMU по этому протоколу через qemu-storage-daemon. экспорта блочных устройств QEMU по этому протоколу через qemu-storage-daemon.
VDUSE - на данный момент лучший интерфейс для подключения дисков Vitastor в виде блочных Преимущества VDUSE:
устройств на уровне ядра, ибо:
- VDUSE не копирует данные и поэтому достигает значительно лучшей производительности, чем [NBD](nbd.ru.md)
- Также оно не имеет проблемы NBD-таймаута - устройство не умирает, если операция выполняется слишком долго
- Также оно не имеет проблемы подвисающих устройств - если процесс-обработчик умирает, его можно
перезапустить (!) и блочное устройство продолжит работать
- По-видимому, у него нет предела числа подключаемых в систему устройств
Пример сравнения производительности: - VDUSE копирует данные 1 раз, а не 2, и поэтому он быстрее, чем [NBD](nbd.ru.md) при линейном доступе.
- VDUSE не имеет проблемы NBD-таймаута - устройство не умирает, если операция выполняется слишком долго.
- VDUSE не имеет проблемы подвисающих устройств - если процесс-обработчик умирает, его можно
перезапустить (!) и блочное устройство продолжит работать (в UBLK это тоже поддерживается).
- По-видимому, у него нет предела числа подключаемых в систему устройств (в UBLK лимита тоже нет).
| | Прямой fio | NBD | VDUSE | Однако, при линейном доступе VDUSE может быть медленнее UBLK (а может быть и быстрее), а по iops
|--------------------------|-------------|-------------|-------------| VDUSE иногда даже медленнее NBD. Пример сравнения производительности смотрите на странице [UBLK](ublk.ru.md).
| линейная запись | 3.85 GB/s | 1.12 GB/s | 3.85 GB/s |
| 4k случайная запись Q128 | 240000 iops | 120000 iops | 178000 iops |
| 4k случайная запись Q1 | 9500 iops | 7620 iops | 7640 iops |
| линейное чтение | 4.3 GB/s | 1.8 GB/s | 2.85 GB/s |
| 4k случайное чтение Q128 | 287000 iops | 140000 iops | 189000 iops |
| 4k случайное чтение Q1 | 9600 iops | 7640 iops | 7780 iops |
Чтобы попробовать VDUSE, вам нужно ядро Linux как минимум версии 5.15, собранное с поддержкой Чтобы попробовать VDUSE, вам нужно ядро Linux как минимум версии 5.15, собранное с поддержкой
VDUSE (CONFIG_VDPA=m, CONFIG_VDPA_USER=m, CONFIG_VIRTIO_VDPA=m). VDUSE (CONFIG_VDPA=m, CONFIG_VDPA_USER=m, CONFIG_VIRTIO_VDPA=m).
@@ -196,3 +188,12 @@ vdpa dev add name test1 mgmtdev vduse
vdpa dev del test1 vdpa dev del test1
kill <PID_процесса_qemu-storage-daemon> kill <PID_процесса_qemu-storage-daemon>
``` ```
## Veeam
Драйвер Vitastor QEMU имеет функцию, которая позволяет обманывать сторонние системы типа Veeam, которые
не могут сами по себе разобрать адреса дисков в vitastor: [qemu_file_mirror_path](../config/client.ru.md#qemu_file_mirror_path).
Чтобы заставить такие системы работать, вам нужно установить эту опцию равной пути к некоторому каталогу
в ФС (например, `/mnt/vitastor/`) и примонтировать этот каталог с помощью [`vitastor-nfs mount --block`](../usage/nfs.ru.md).
Они начнут обращаться к образам как к файлам и, вероятно, смогут заработать корректно :).
+116
View File
@@ -0,0 +1,116 @@
[Documentation](../../README.md#documentation) → Usage → UBLK
-----
[Читать на русском](ublk.ru.md)
# UBLK
[ublk](https://docs.kernel.org/block/ublk.html) is a new io_uring-based Linux interface
for user-space block device drivers, available since Linux 6.0.
It's not zero-copy, but it's still a fast implementation, outperforming both [NBD](nbd.en.md)
and [VDUSE](qemu.en.md#vduse) iops-wise and may or may not outperform VDUSE in linear I/O MB/s.
ublk also allows to recover devices even if the server (vitastor-ublk process) dies.
## Example performance comparison
TCP (100G), 3 hosts each with 6 NVMe OSDs, 3 replicas, single client
| | direct fio | NBD | VDUSE | UBLK |
|----------------------|-------------|-------------|------------|-------------|
| linear write | 3807 MB/s | 1832 MB/s | 3226 MB/s | 3027 MB/s |
| linear read | 3067 MB/s | 1885 MB/s | 1800 MB/s | 2076 MB/s |
| 4k random write Q128 | 128624 iops | 91060 iops | 94621 iops | 149450 iops |
| 4k random read Q128 | 117769 iops | 153408 iops | 93157 iops | 171987 iops |
| 4k random write Q1 | 8090 iops | 6442 iops | 6316 iops | 7272 iops |
| 4k random read Q1 | 9474 iops | 7200 iops | 6840 iops | 8038 iops |
RDMA (100G), 3 hosts each with 6 NVMe OSDs, 3 replicas, single client
| | direct fio | NBD | VDUSE | UBLK |
|----------------------|-------------|-------------|-------------|-------------|
| linear write | 6998 MB/s | 1878 MB/s | 4249 MB/s | 3140 MB/s |
| linear read | 8628 MB/s | 3389 MB/s | 5062 MB/s | 3674 MB/s |
| 4k random write Q128 | 222541 iops | 181589 iops | 138281 iops | 218222 iops |
| 4k random read Q128 | 412647 iops | 239987 iops | 151663 iops | 269583 iops |
| 4k random write Q1 | 11601 iops | 8592 iops | 9111 iops | 10000 iops |
| 4k random read Q1 | 10102 iops | 7788 iops | 8111 iops | 8965 iops |
## Commands
vitastor-ublk supports the following commands:
- [map](#map)
- [unmap](#unmap)
- [ls](#ls)
## map
To create a local block device for a Vitastor image run:
```
vitastor-ublk map [/dev/ublkbN] --image testimg
```
It will output a block device name like /dev/ublkb0 which you can then use as a normal disk.
You can also use `--pool <POOL> --inode <INODE> --size <SIZE>` instead of `--image <IMAGE>` if you want.
vitastor-ublk supports all usual Vitastor configuration options like `--config_path <path_to_config>` plus ublk-specific:
* `--recover` \
Recover a mapped device if the previous ublk server is dead.
* `--queue_depth 256` \
Maximum queue size for the device.
* `--max_io_size 1M` \
Maximum single I/O size for the device. Default: `max(1 MB, pool block size * EC part count)`.
* `--readonly` \
Make the device read-only.
* `--hdd` \
Mark the device as rotational.
* `--logfile /path/to/log/file.txt` \
Write log messages to the specified file instead of dropping them (in background mode)
or printing them to the standard output (in foreground mode).
* `--dev_num N` \
Use the specified device /dev/ublkbN instead of automatic selection (alternative syntax
to /dev/ublkbN positional parameter).
* `--foreground 1` \
Stay in foreground, do not daemonize.
Note that `ublk_queue_depth` and `ublk_max_io_size` may also be specified
in `/etc/vitastor/vitastor.conf` or in other configuration file specified with `--config_path`.
## unmap
To unmap the device run:
```
vitastor-ublk unmap /dev/ublkb0
```
## ls
```
vitastor-ublk ls [--json]
```
List mapped images.
Example output (normal format):
```
/dev/ublkb0
image: bench
pid: 584536
/dev/ublkb1
image: bench1
pid: 584546
```
Example output (JSON format):
```
{"/dev/ublkb0": {"image": "bench", "pid": 584536}, "/dev/ublkb1": {"image": "bench1", "pid": 584546}}
```
+121
View File
@@ -0,0 +1,121 @@
[Документация](../../README-ru.md#документация) → Использование → UBLK
-----
[Read in English](ublk.en.md)
# UBLK
[ublk](https://docs.kernel.org/block/ublk.html) - это новый Linux-интерфейс на основе io_uring
для реализации блочных устройств в пространстве пользователя, доступный, начиная с Linux 6.0.
ublk тоже копирует память (т.е. не является zero-copy), но по IOPS всё равно обгоняет и
[NBD](nbd.ru.md), и [VDUSE](qemu.ru.md#vduse), и иногда может даже обгонять VDUSE по
скорости линейного доступа. Также ublk позволяет оживлять устройства, у которых умер
сервер (процесс-обработчик vitastor-ublk).
## Пример сравнения производительности
TCP (100G), 3 сервера с 6 NVMe OSD каждый, 3 реплики, один клиент
| | Прямой fio | NBD | VDUSE | UBLK |
|--------------------------|-------------|-------------|------------|-------------|
| линейная запись | 3807 MB/s | 1832 MB/s | 3226 MB/s | 3027 MB/s |
| линейное чтение | 3067 MB/s | 1885 MB/s | 1800 MB/s | 2076 MB/s |
| 4k случайная запись Q128 | 128624 iops | 91060 iops | 94621 iops | 149450 iops |
| 4k случайное чтение Q128 | 117769 iops | 153408 iops | 93157 iops | 171987 iops |
| 4k случайная запись Q1 | 8090 iops | 6442 iops | 6316 iops | 7272 iops |
| 4k случайное чтение Q1 | 9474 iops | 7200 iops | 6840 iops | 8038 iops |
RDMA (100G), 3 сервера с 6 NVMe OSD каждый, 3 реплики, один клиент
| | Прямой fio | NBD | VDUSE | UBLK |
|--------------------------|-------------|-------------|-------------|-------------|
| линейная запись | 6998 MB/s | 1878 MB/s | 4249 MB/s | 3140 MB/s |
| линейное чтение | 8628 MB/s | 3389 MB/s | 5062 MB/s | 3674 MB/s |
| 4k случайная запись Q128 | 222541 iops | 181589 iops | 138281 iops | 218222 iops |
| 4k случайное чтение Q128 | 412647 iops | 239987 iops | 151663 iops | 269583 iops |
| 4k случайная запись Q1 | 11601 iops | 8592 iops | 9111 iops | 10000 iops |
| 4k случайное чтение Q1 | 10102 iops | 7788 iops | 8111 iops | 8965 iops |
## Команды
vitastor-ublk поддерживает следующие команды:
- [map](#map)
- [unmap](#unmap)
- [ls](#ls)
## map
Чтобы создать локальное блочное устройство для образа, выполните команду:
```
vitastor-ublk map [/dev/ublkbN] --image testimg
```
Команда напечатает название блочного устройства вида /dev/ublkb0, которое потом можно
будет использовать как обычный диск.
Для обращения по номеру инода, аналогично другим командам, можно использовать опции
`--pool <POOL> --inode <INODE> --size <SIZE>` вместо `--image testimg`.
vitastor-ublk поддерживает все обычные опции Vitastor, например, `--config_path <path_to_config>`,
плюс специфичные для ublk:
* `--recover` \
Восстановить ранее подключённое устройство, у которого умер обработчик.
* `--queue_depth 256` \
Максимальная глубина очереди устройства.
* `--max_io_size 1M` \
Максимальный размер запроса ввода-вывода для устройства. По умолчанию: `max(1 MB, блок данных пула * число частей данных EC)`.
* `--readonly` \
Подключить устройство в режиме только для чтения.
* `--hdd` \
Пометить устройство как вращающийся жёсткий диск (флаг rotational).
* `--logfile /path/to/log/file.txt` \
Писать сообщения о процессе работы в заданный файл, вместо пропуска их
при фоновом режиме запуска или печати на стандартный вывод при запуске
в консоли с `--foreground 1`.
* `--dev_num N` \
Использовать заданное устройство `/dev/ublkbN` вместо автоматического подбора.
* `--foreground 1` \
Не уводить процесс в фоновый режим.
Обратите внимание, что опции `ublk_queue_depth` и `ublk_max_io_size` можно
также задавать в `/etc/vitastor/vitastor.conf` или в другом файле конфигурации,
заданном опцией `--config_path`.
## unmap
Для отключения устройства выполните:
```
vitastor-ublk unmap /dev/ublkb0
```
## ls
```
vitastor-ublk ls [--json]
```
Вывести подключённые устройства.
Пример вывода в обычном формате:
```
/dev/ublkb0
image: bench
pid: 584536
/dev/ublkb1
image: bench1
pid: 584546
```
Пример вывода в JSON-формате:
```
{"/dev/ublkb0": {"image": "bench", "pid": 584536}, "/dev/ublkb1": {"image": "bench1", "pid": 584546}}
```
+1 -1
View File
@@ -179,7 +179,7 @@ function filter_osds_by_block_layout(orig_tree, osd_stats, block_size, bitmap_gr
if (orig_tree[osd].level === 'osd') if (orig_tree[osd].level === 'osd')
{ {
const osd_stat = osd_stats[osd]; const osd_stat = osd_stats[osd];
if (osd_stat && (osd_stat.bs_block_size && osd_stat.bs_block_size != block_size || if (osd_stat && (osd_stat.data_block_size && osd_stat.data_block_size != block_size ||
osd_stat.bitmap_granularity && osd_stat.bitmap_granularity != bitmap_granularity || osd_stat.bitmap_granularity && osd_stat.bitmap_granularity != bitmap_granularity ||
osd_stat.immediate_commit == 'small' && immediate_commit == 'all' || osd_stat.immediate_commit == 'small' && immediate_commit == 'all' ||
osd_stat.immediate_commit == 'none' && immediate_commit != 'none')) osd_stat.immediate_commit == 'none' && immediate_commit != 'none'))
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "vitastor-mon", "name": "vitastor-mon",
"version": "2.2.3", "version": "2.3.0",
"description": "Vitastor SDS monitor service", "description": "Vitastor SDS monitor service",
"main": "mon-main.js", "main": "mon-main.js",
"scripts": { "scripts": {
@@ -9,7 +9,7 @@
"author": "Vitaliy Filippov", "author": "Vitaliy Filippov",
"license": "UNLICENSED", "license": "UNLICENSED",
"dependencies": { "dependencies": {
"antietcd": "^1.1.2", "antietcd": "^1.1.3",
"sprintf-js": "^1.1.2", "sprintf-js": "^1.1.2",
"ws": "^7.2.5" "ws": "^7.2.5"
}, },
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "vitastor", "name": "vitastor",
"version": "2.2.3", "version": "2.3.0",
"description": "Low-level native bindings to Vitastor client library", "description": "Low-level native bindings to Vitastor client library",
"main": "index.js", "main": "index.js",
"keywords": [ "keywords": [
+8 -3
View File
@@ -261,7 +261,7 @@ sub free_image
my ($vtype, $name, $vmid, undef, undef, undef) = $class->parse_volname($volname); my ($vtype, $name, $vmid, undef, undef, undef) = $class->parse_volname($volname);
$class->deactivate_volume($storeid, $scfg, $volname); $class->deactivate_volume($storeid, $scfg, $volname);
my $full_list = run_cli($scfg, [ 'ls', '-l' ]); my $full_list = run_cli($scfg, [ 'ls', '-l' ]);
my $list = _process_list($scfg, $storeid, $full_list); my $list = _process_list($scfg, $storeid, $full_list, 0);
# Remove image and all its snapshots # Remove image and all its snapshots
my $rm_names = { my $rm_names = {
map { ($prefix.$_->{name} => 1) } map { ($prefix.$_->{name} => 1) }
@@ -269,6 +269,10 @@ sub free_image
@$list @$list
}; };
my $children = [ grep { $_->{parent_name} && $rm_names->{$_->{parent_name}} } @$full_list ]; my $children = [ grep { $_->{parent_name} && $rm_names->{$_->{parent_name}} } @$full_list ];
$children = [ grep {
substr($_->{name}, 0, length($prefix.$name)) ne $prefix.$name &&
substr($_->{name}, 0, length($prefix.$name)+1) ne $prefix.$name.'@'
} @$children ];
die "Image has children: ".join(', ', map { die "Image has children: ".join(', ', map {
substr($_->{name}, 0, length $prefix) eq $prefix substr($_->{name}, 0, length $prefix) eq $prefix
? substr($_->name, length $prefix) ? substr($_->name, length $prefix)
@@ -288,14 +292,15 @@ sub free_image
sub _process_list sub _process_list
{ {
my ($scfg, $storeid, $result) = @_; my ($scfg, $storeid, $result, $skip_snapshot) = @_;
$skip_snapshot = 1 if !defined $skip_snapshot;
my $prefix = defined $scfg->{vitastor_prefix} ? $scfg->{vitastor_prefix} : 'pve/'; my $prefix = defined $scfg->{vitastor_prefix} ? $scfg->{vitastor_prefix} : 'pve/';
my $list = []; my $list = [];
foreach my $el (@$result) foreach my $el (@$result)
{ {
next if !$el->{name} || length($prefix) && substr($el->{name}, 0, length $prefix) ne $prefix; next if !$el->{name} || length($prefix) && substr($el->{name}, 0, length $prefix) ne $prefix;
my $name = substr($el->{name}, length $prefix); my $name = substr($el->{name}, length $prefix);
next if $name =~ /@/; next if $skip_snapshot && $name =~ /@/;
my ($owner) = $name =~ /^(?:vm|base)-(\d+)-/s; my ($owner) = $name =~ /^(?:vm|base)-(\d+)-/s;
next if !defined $owner; next if !defined $owner;
my $parent = !defined $el->{parent_name} my $parent = !defined $el->{parent_name}
+1 -1
View File
@@ -50,7 +50,7 @@ from cinder.volume import configuration
from cinder.volume import driver from cinder.volume import driver
from cinder.volume import volume_utils from cinder.volume import volume_utils
VITASTOR_VERSION = '2.2.3' VITASTOR_VERSION = '2.3.0'
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
+172
View File
@@ -0,0 +1,172 @@
Index: pve-qemu-kvm-10.0.2/block/meson.build
===================================================================
--- pve-qemu-kvm-10.0.2.orig/block/meson.build
+++ pve-qemu-kvm-10.0.2/block/meson.build
@@ -126,6 +126,7 @@ foreach m : [
[libnfs, 'nfs', files('nfs.c')],
[libssh, 'ssh', files('ssh.c')],
[rbd, 'rbd', files('rbd.c')],
+ [vitastor, 'vitastor', files('vitastor.c')],
]
if m[0].found()
module_ss = ss.source_set()
Index: pve-qemu-kvm-10.0.2/meson.build
===================================================================
--- pve-qemu-kvm-10.0.2.orig/meson.build
+++ pve-qemu-kvm-10.0.2/meson.build
@@ -1622,6 +1622,26 @@ if not get_option('rbd').auto() or have_
endif
endif
+vitastor = not_found
+if not get_option('vitastor').auto() or have_block
+ libvitastor_client = cc.find_library('vitastor_client', has_headers: ['vitastor_c.h'],
+ required: get_option('vitastor'))
+ if libvitastor_client.found()
+ if cc.links('''
+ #include <vitastor_c.h>
+ int main(void) {
+ vitastor_c_create_qemu(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ return 0;
+ }''', dependencies: libvitastor_client)
+ vitastor = declare_dependency(dependencies: libvitastor_client)
+ elif get_option('vitastor').enabled()
+ error('could not link libvitastor_client')
+ else
+ warning('could not link libvitastor_client, disabling')
+ endif
+ endif
+endif
+
glusterfs = not_found
glusterfs_ftruncate_has_stat = false
glusterfs_iocb_has_stat = false
@@ -2514,6 +2534,7 @@ endif
config_host_data.set('CONFIG_OPENGL', opengl.found())
config_host_data.set('CONFIG_PLUGIN', get_option('plugins'))
config_host_data.set('CONFIG_RBD', rbd.found())
+config_host_data.set('CONFIG_VITASTOR', vitastor.found())
config_host_data.set('CONFIG_RDMA', rdma.found())
config_host_data.set('CONFIG_RELOCATABLE', get_option('relocatable'))
config_host_data.set('CONFIG_SAFESTACK', get_option('safe_stack'))
@@ -4812,6 +4833,7 @@ summary_info += {'fdt support': fd
summary_info += {'libcap-ng support': libcap_ng}
summary_info += {'bpf support': libbpf}
summary_info += {'rbd support': rbd}
+summary_info += {'vitastor support': vitastor}
summary_info += {'smartcard support': cacard}
summary_info += {'U2F support': u2f}
summary_info += {'libusb': libusb}
Index: pve-qemu-kvm-10.0.2/meson_options.txt
===================================================================
--- pve-qemu-kvm-10.0.2.orig/meson_options.txt
+++ pve-qemu-kvm-10.0.2/meson_options.txt
@@ -202,6 +202,8 @@ option('pvg', type: 'feature', value: 'a
description: 'macOS paravirtualized graphics support')
option('rbd', type : 'feature', value : 'auto',
description: 'Ceph block device driver')
+option('vitastor', type : 'feature', value : 'auto',
+ description: 'Vitastor block device driver')
option('opengl', type : 'feature', value : 'auto',
description: 'OpenGL support')
option('rdma', type : 'feature', value : 'auto',
Index: pve-qemu-kvm-10.0.2/qapi/block-core.json
===================================================================
--- pve-qemu-kvm-10.0.2.orig/qapi/block-core.json
+++ pve-qemu-kvm-10.0.2/qapi/block-core.json
@@ -3599,7 +3599,7 @@
'raw', 'rbd',
{ 'name': 'replication', 'if': 'CONFIG_REPLICATION' },
'pbs',
- 'ssh', 'throttle', 'vdi', 'vhdx',
+ 'ssh', 'throttle', 'vdi', 'vhdx', 'vitastor',
{ 'name': 'virtio-blk-vfio-pci', 'if': 'CONFIG_BLKIO' },
{ 'name': 'virtio-blk-vhost-user', 'if': 'CONFIG_BLKIO' },
{ 'name': 'virtio-blk-vhost-vdpa', 'if': 'CONFIG_BLKIO' },
@@ -4725,6 +4725,28 @@
'*server': ['InetSocketAddressBase'] } }
##
+# @BlockdevOptionsVitastor:
+#
+# Driver specific block device options for vitastor
+#
+# @image: Image name
+# @inode: Inode number
+# @pool: Pool ID
+# @size: Desired image size in bytes
+# @config-path: Path to Vitastor configuration
+# @etcd-host: etcd connection address(es)
+# @etcd-prefix: etcd key/value prefix
+##
+{ 'struct': 'BlockdevOptionsVitastor',
+ 'data': { '*inode': 'uint64',
+ '*pool': 'uint64',
+ '*size': 'uint64',
+ '*image': 'str',
+ '*config-path': 'str',
+ '*etcd-host': 'str',
+ '*etcd-prefix': 'str' } }
+
+##
# @ReplicationMode:
#
# An enumeration of replication modes.
@@ -5194,6 +5216,7 @@
'throttle': 'BlockdevOptionsThrottle',
'vdi': 'BlockdevOptionsGenericFormat',
'vhdx': 'BlockdevOptionsGenericFormat',
+ 'vitastor': 'BlockdevOptionsVitastor',
'virtio-blk-vfio-pci':
{ 'type': 'BlockdevOptionsVirtioBlkVfioPci',
'if': 'CONFIG_BLKIO' },
@@ -5674,6 +5697,20 @@
'*encrypt' : 'RbdEncryptionCreateOptions' } }
##
+# @BlockdevCreateOptionsVitastor:
+#
+# Driver specific image creation options for Vitastor.
+#
+# @location: Where to store the new image file. This location cannot
+# point to a snapshot.
+#
+# @size: Size of the virtual disk in bytes
+##
+{ 'struct': 'BlockdevCreateOptionsVitastor',
+ 'data': { 'location': 'BlockdevOptionsVitastor',
+ 'size': 'size' } }
+
+##
# @BlockdevVmdkSubformat:
#
# Subformat options for VMDK images
@@ -5895,6 +5932,7 @@
'ssh': 'BlockdevCreateOptionsSsh',
'vdi': 'BlockdevCreateOptionsVdi',
'vhdx': 'BlockdevCreateOptionsVhdx',
+ 'vitastor': 'BlockdevCreateOptionsVitastor',
'vmdk': 'BlockdevCreateOptionsVmdk',
'vpc': 'BlockdevCreateOptionsVpc'
} }
Index: pve-qemu-kvm-10.0.2/scripts/meson-buildoptions.sh
===================================================================
--- pve-qemu-kvm-10.0.2.orig/scripts/meson-buildoptions.sh
+++ pve-qemu-kvm-10.0.2/scripts/meson-buildoptions.sh
@@ -175,6 +175,7 @@ meson_options_help() {
printf "%s\n" ' qga-vss build QGA VSS support (broken with MinGW)'
printf "%s\n" ' qpl Query Processing Library support'
printf "%s\n" ' rbd Ceph block device driver'
+ printf "%s\n" ' vitastor Vitastor block device driver'
printf "%s\n" ' rdma Enable RDMA-based migration'
printf "%s\n" ' replication replication support'
printf "%s\n" ' rust Rust support'
@@ -458,6 +459,8 @@ _meson_option_parse() {
--disable-qpl) printf "%s" -Dqpl=disabled ;;
--enable-rbd) printf "%s" -Drbd=enabled ;;
--disable-rbd) printf "%s" -Drbd=disabled ;;
+ --enable-vitastor) printf "%s" -Dvitastor=enabled ;;
+ --disable-vitastor) printf "%s" -Dvitastor=disabled ;;
--enable-rdma) printf "%s" -Drdma=enabled ;;
--disable-rdma) printf "%s" -Drdma=disabled ;;
--enable-relocatable) printf "%s" -Drelocatable=true ;;
+172
View File
@@ -0,0 +1,172 @@
diff --git a/block/meson.build b/block/meson.build
index 34b1b2a306..24ca0f1e52 100644
--- a/block/meson.build
+++ b/block/meson.build
@@ -114,6 +114,7 @@ foreach m : [
[libnfs, 'nfs', files('nfs.c')],
[libssh, 'ssh', files('ssh.c')],
[rbd, 'rbd', files('rbd.c')],
+ [vitastor, 'vitastor', files('vitastor.c')],
]
if m[0].found()
module_ss = ss.source_set()
diff --git a/meson.build b/meson.build
index 41f68d3806..29eaed9ba4 100644
--- a/meson.build
+++ b/meson.build
@@ -1622,6 +1622,26 @@ if not get_option('rbd').auto() or have_block
endif
endif
+vitastor = not_found
+if not get_option('vitastor').auto() or have_block
+ libvitastor_client = cc.find_library('vitastor_client', has_headers: ['vitastor_c.h'],
+ required: get_option('vitastor'))
+ if libvitastor_client.found()
+ if cc.links('''
+ #include <vitastor_c.h>
+ int main(void) {
+ vitastor_c_create_qemu(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ return 0;
+ }''', dependencies: libvitastor_client)
+ vitastor = declare_dependency(dependencies: libvitastor_client)
+ elif get_option('vitastor').enabled()
+ error('could not link libvitastor_client')
+ else
+ warning('could not link libvitastor_client, disabling')
+ endif
+ endif
+endif
+
glusterfs = not_found
glusterfs_ftruncate_has_stat = false
glusterfs_iocb_has_stat = false
@@ -2506,6 +2526,7 @@ endif
config_host_data.set('CONFIG_OPENGL', opengl.found())
config_host_data.set('CONFIG_PLUGIN', get_option('plugins'))
config_host_data.set('CONFIG_RBD', rbd.found())
+config_host_data.set('CONFIG_VITASTOR', vitastor.found())
config_host_data.set('CONFIG_RDMA', rdma.found())
config_host_data.set('CONFIG_RELOCATABLE', get_option('relocatable'))
config_host_data.set('CONFIG_SAFESTACK', get_option('safe_stack'))
@@ -4813,6 +4834,7 @@ summary_info += {'fdt support': fdt_opt == 'internal' ? 'internal' : fdt}
summary_info += {'libcap-ng support': libcap_ng}
summary_info += {'bpf support': libbpf}
summary_info += {'rbd support': rbd}
+summary_info += {'vitastor support': vitastor}
summary_info += {'smartcard support': cacard}
summary_info += {'U2F support': u2f}
summary_info += {'libusb': libusb}
diff --git a/meson_options.txt b/meson_options.txt
index 59d973bca0..a3e7123980 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -202,6 +202,8 @@ option('pvg', type: 'feature', value: 'auto',
description: 'macOS paravirtualized graphics support')
option('rbd', type : 'feature', value : 'auto',
description: 'Ceph block device driver')
+option('vitastor', type : 'feature', value : 'auto',
+ description: 'Vitastor block device driver')
option('opengl', type : 'feature', value : 'auto',
description: 'OpenGL support')
option('rdma', type : 'feature', value : 'auto',
diff --git a/qapi/block-core.json b/qapi/block-core.json
index b1937780e1..a511193620 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -3216,7 +3216,7 @@
'parallels', 'preallocate', 'qcow', 'qcow2', 'qed', 'quorum',
'raw', 'rbd',
{ 'name': 'replication', 'if': 'CONFIG_REPLICATION' },
- 'ssh', 'throttle', 'vdi', 'vhdx',
+ 'ssh', 'throttle', 'vdi', 'vhdx', 'vitastor',
{ 'name': 'virtio-blk-vfio-pci', 'if': 'CONFIG_BLKIO' },
{ 'name': 'virtio-blk-vhost-user', 'if': 'CONFIG_BLKIO' },
{ 'name': 'virtio-blk-vhost-vdpa', 'if': 'CONFIG_BLKIO' },
@@ -4299,6 +4299,28 @@
'*key-secret': 'str',
'*server': ['InetSocketAddressBase'] } }
+##
+# @BlockdevOptionsVitastor:
+#
+# Driver specific block device options for vitastor
+#
+# @image: Image name
+# @inode: Inode number
+# @pool: Pool ID
+# @size: Desired image size in bytes
+# @config-path: Path to Vitastor configuration
+# @etcd-host: etcd connection address(es)
+# @etcd-prefix: etcd key/value prefix
+##
+{ 'struct': 'BlockdevOptionsVitastor',
+ 'data': { '*inode': 'uint64',
+ '*pool': 'uint64',
+ '*size': 'uint64',
+ '*image': 'str',
+ '*config-path': 'str',
+ '*etcd-host': 'str',
+ '*etcd-prefix': 'str' } }
+
##
# @ReplicationMode:
#
@@ -4767,6 +4789,7 @@
'throttle': 'BlockdevOptionsThrottle',
'vdi': 'BlockdevOptionsGenericFormat',
'vhdx': 'BlockdevOptionsGenericFormat',
+ 'vitastor': 'BlockdevOptionsVitastor',
'virtio-blk-vfio-pci':
{ 'type': 'BlockdevOptionsVirtioBlkVfioPci',
'if': 'CONFIG_BLKIO' },
@@ -5240,6 +5263,20 @@
'*cluster-size' : 'size',
'*encrypt' : 'RbdEncryptionCreateOptions' } }
+##
+# @BlockdevCreateOptionsVitastor:
+#
+# Driver specific image creation options for Vitastor.
+#
+# @location: Where to store the new image file. This location cannot
+# point to a snapshot.
+#
+# @size: Size of the virtual disk in bytes
+##
+{ 'struct': 'BlockdevCreateOptionsVitastor',
+ 'data': { 'location': 'BlockdevOptionsVitastor',
+ 'size': 'size' } }
+
##
# @BlockdevVmdkSubformat:
#
@@ -5462,6 +5499,7 @@
'ssh': 'BlockdevCreateOptionsSsh',
'vdi': 'BlockdevCreateOptionsVdi',
'vhdx': 'BlockdevCreateOptionsVhdx',
+ 'vitastor': 'BlockdevCreateOptionsVitastor',
'vmdk': 'BlockdevCreateOptionsVmdk',
'vpc': 'BlockdevCreateOptionsVpc'
} }
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 3e8e00852b..45aff3b6a9 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -175,6 +175,7 @@ meson_options_help() {
printf "%s\n" ' qga-vss build QGA VSS support (broken with MinGW)'
printf "%s\n" ' qpl Query Processing Library support'
printf "%s\n" ' rbd Ceph block device driver'
+ printf "%s\n" ' vitastor Vitastor block device driver'
printf "%s\n" ' rdma Enable RDMA-based migration'
printf "%s\n" ' replication replication support'
printf "%s\n" ' rust Rust support'
@@ -458,6 +459,8 @@ _meson_option_parse() {
--disable-qpl) printf "%s" -Dqpl=disabled ;;
--enable-rbd) printf "%s" -Drbd=enabled ;;
--disable-rbd) printf "%s" -Drbd=disabled ;;
+ --enable-vitastor) printf "%s" -Dvitastor=enabled ;;
+ --disable-vitastor) printf "%s" -Dvitastor=disabled ;;
--enable-rdma) printf "%s" -Drdma=enabled ;;
--disable-rdma) printf "%s" -Drdma=disabled ;;
--enable-relocatable) printf "%s" -Drelocatable=true ;;
-14
View File
@@ -21,17 +21,3 @@ RUN rpm --nomd5 -i fio*.src.rpm
RUN rm -f /etc/yum.repos.d/CentOS-Media.repo RUN rm -f /etc/yum.repos.d/CentOS-Media.repo
RUN cd ~/rpmbuild/SPECS && yum-builddep -y fio.spec RUN cd ~/rpmbuild/SPECS && yum-builddep -y fio.spec
RUN yum -y install cmake3 RUN yum -y install cmake3
ADD https://vitastor.io/rpms/liburing-el7/liburing-0.7-2.el7.src.rpm /root
RUN set -e; \
rpm -i liburing*.src.rpm; \
cd ~/rpmbuild/SPECS/; \
. /opt/rh/devtoolset-9/enable; \
rpmbuild -ba liburing.spec; \
mkdir -p /root/packages/liburing-el7; \
rm -rf /root/packages/liburing-el7/*; \
cp ~/rpmbuild/RPMS/*/liburing* /root/packages/liburing-el7/; \
cp ~/rpmbuild/SRPMS/liburing* /root/packages/liburing-el7/
RUN rpm -i `ls /root/packages/liburing-el7/liburing-*.x86_64.rpm | grep -v debug`
+3 -7
View File
@@ -1,13 +1,12 @@
Name: vitastor Name: vitastor
Version: 2.2.3 Version: 2.3.0
Release: 1%{?dist} Release: 1%{?dist}
Summary: Vitastor, a fast software-defined clustered block storage Summary: Vitastor, a fast software-defined clustered block storage
License: Vitastor Network Public License 1.1 License: Vitastor Network Public License 1.1
URL: https://vitastor.io/ URL: https://vitastor.io/
Source0: vitastor-2.2.3.el7.tar.gz Source0: vitastor-2.3.0.el7.tar.gz
BuildRequires: liburing-devel >= 0.6
BuildRequires: gperftools-devel BuildRequires: gperftools-devel
BuildRequires: devtoolset-9-gcc-c++ BuildRequires: devtoolset-9-gcc-c++
BuildRequires: rh-nodejs12 BuildRequires: rh-nodejs12
@@ -35,8 +34,6 @@ size with configurable redundancy (replication or erasure codes/XOR).
Summary: Vitastor - OSD Summary: Vitastor - OSD
Requires: libJerasure2 Requires: libJerasure2
Requires: libisa-l Requires: libisa-l
Requires: liburing >= 0.6
Requires: liburing < 2
Requires: vitastor-client = %{version}-%{release} Requires: vitastor-client = %{version}-%{release}
Requires: util-linux Requires: util-linux
Requires: parted Requires: parted
@@ -60,8 +57,6 @@ scheduling cluster-level operations.
%package -n vitastor-client %package -n vitastor-client
Summary: Vitastor - client Summary: Vitastor - client
Requires: liburing >= 0.6
Requires: liburing < 2
%description -n vitastor-client %description -n vitastor-client
@@ -169,6 +164,7 @@ chown vitastor:vitastor /var/lib/vitastor
%files -n vitastor-client %files -n vitastor-client
%_bindir/vitastor-nbd %_bindir/vitastor-nbd
%_bindir/vitastor-ublk
%_bindir/vitastor-nfs %_bindir/vitastor-nfs
%_bindir/vitastor-cli %_bindir/vitastor-cli
%_bindir/vitastor-rm %_bindir/vitastor-rm
-14
View File
@@ -17,17 +17,3 @@ RUN dnf -y install gcc-toolset-9 gcc-toolset-9-gcc-c++ gperftools-devel \
RUN dnf download --source fio RUN dnf download --source fio
RUN rpm --nomd5 -i fio*.src.rpm RUN rpm --nomd5 -i fio*.src.rpm
RUN cd ~/rpmbuild/SPECS && dnf builddep -y --enablerepo=powertools --spec fio.spec RUN cd ~/rpmbuild/SPECS && dnf builddep -y --enablerepo=powertools --spec fio.spec
ADD https://vitastor.io/rpms/liburing-el7/liburing-0.7-2.el7.src.rpm /root
RUN set -e; \
rpm -i liburing*.src.rpm; \
cd ~/rpmbuild/SPECS/; \
. /opt/rh/gcc-toolset-9/enable; \
rpmbuild -ba liburing.spec; \
mkdir -p /root/packages/liburing-el8; \
rm -rf /root/packages/liburing-el8/*; \
cp ~/rpmbuild/RPMS/*/liburing* /root/packages/liburing-el8/; \
cp ~/rpmbuild/SRPMS/liburing* /root/packages/liburing-el8/
RUN rpm -i `ls /root/packages/liburing-el8/liburing-*.x86_64.rpm | grep -v debug`
+3 -7
View File
@@ -1,13 +1,12 @@
Name: vitastor Name: vitastor
Version: 2.2.3 Version: 2.3.0
Release: 1%{?dist} Release: 1%{?dist}
Summary: Vitastor, a fast software-defined clustered block storage Summary: Vitastor, a fast software-defined clustered block storage
License: Vitastor Network Public License 1.1 License: Vitastor Network Public License 1.1
URL: https://vitastor.io/ URL: https://vitastor.io/
Source0: vitastor-2.2.3.el8.tar.gz Source0: vitastor-2.3.0.el8.tar.gz
BuildRequires: liburing-devel >= 0.6
BuildRequires: gperftools-devel BuildRequires: gperftools-devel
BuildRequires: gcc-toolset-9-gcc-c++ BuildRequires: gcc-toolset-9-gcc-c++
BuildRequires: nodejs >= 10 BuildRequires: nodejs >= 10
@@ -34,8 +33,6 @@ size with configurable redundancy (replication or erasure codes/XOR).
Summary: Vitastor - OSD Summary: Vitastor - OSD
Requires: libJerasure2 Requires: libJerasure2
Requires: libisa-l Requires: libisa-l
Requires: liburing >= 0.6
Requires: liburing < 2
Requires: vitastor-client = %{version}-%{release} Requires: vitastor-client = %{version}-%{release}
Requires: util-linux Requires: util-linux
Requires: parted Requires: parted
@@ -58,8 +55,6 @@ scheduling cluster-level operations.
%package -n vitastor-client %package -n vitastor-client
Summary: Vitastor - client Summary: Vitastor - client
Requires: liburing >= 0.6
Requires: liburing < 2
%description -n vitastor-client %description -n vitastor-client
@@ -166,6 +161,7 @@ chown vitastor:vitastor /var/lib/vitastor
%files -n vitastor-client %files -n vitastor-client
%_bindir/vitastor-nbd %_bindir/vitastor-nbd
%_bindir/vitastor-ublk
%_bindir/vitastor-nfs %_bindir/vitastor-nfs
%_bindir/vitastor-cli %_bindir/vitastor-cli
%_bindir/vitastor-rm %_bindir/vitastor-rm
+1 -1
View File
@@ -10,7 +10,7 @@ WORKDIR /root
RUN sed -i 's/enabled=0/enabled=1/' /etc/yum.repos.d/*.repo RUN sed -i 's/enabled=0/enabled=1/' /etc/yum.repos.d/*.repo
RUN dnf -y install epel-release dnf-plugins-core RUN dnf -y install epel-release dnf-plugins-core
RUN dnf -y install https://vitastor.io/rpms/centos/9/vitastor-release-1.0-1.el9.noarch.rpm RUN dnf -y install https://vitastor.io/rpms/centos/9/vitastor-release-1.0-1.el9.noarch.rpm
RUN dnf -y install gcc-c++ gperftools-devel fio nodejs rpm-build jerasure-devel libisa-l-devel gf-complete-devel rdma-core-devel libarchive liburing-devel cmake libnl3-devel RUN dnf -y install gcc-c++ gperftools-devel fio nodejs rpm-build jerasure-devel libisa-l-devel gf-complete-devel rdma-core-devel libarchive cmake libnl3-devel
RUN dnf download --source fio RUN dnf download --source fio
RUN rpm --nomd5 -i fio*.src.rpm RUN rpm --nomd5 -i fio*.src.rpm
RUN cd ~/rpmbuild/SPECS && dnf builddep -y --spec fio.spec RUN cd ~/rpmbuild/SPECS && dnf builddep -y --spec fio.spec
+3 -3
View File
@@ -1,13 +1,12 @@
Name: vitastor Name: vitastor
Version: 2.2.3 Version: 2.3.0
Release: 1%{?dist} Release: 1%{?dist}
Summary: Vitastor, a fast software-defined clustered block storage Summary: Vitastor, a fast software-defined clustered block storage
License: Vitastor Network Public License 1.1 License: Vitastor Network Public License 1.1
URL: https://vitastor.io/ URL: https://vitastor.io/
Source0: vitastor-2.2.3.el9.tar.gz Source0: vitastor-2.3.0.el9.tar.gz
BuildRequires: liburing-devel >= 0.6
BuildRequires: gperftools-devel BuildRequires: gperftools-devel
BuildRequires: gcc-c++ BuildRequires: gcc-c++
BuildRequires: nodejs >= 10 BuildRequires: nodejs >= 10
@@ -159,6 +158,7 @@ chown vitastor:vitastor /var/lib/vitastor
%files -n vitastor-client %files -n vitastor-client
%_bindir/vitastor-nbd %_bindir/vitastor-nbd
%_bindir/vitastor-ublk
%_bindir/vitastor-nfs %_bindir/vitastor-nfs
%_bindir/vitastor-cli %_bindir/vitastor-cli
%_bindir/vitastor-rm %_bindir/vitastor-rm
+16 -5
View File
@@ -12,6 +12,7 @@ set(WITH_QEMU false CACHE BOOL "Build QEMU driver inside Vitastor source tree")
set(WITH_FIO true CACHE BOOL "Build FIO driver") set(WITH_FIO true CACHE BOOL "Build FIO driver")
set(QEMU_PLUGINDIR qemu CACHE STRING "QEMU plugin directory suffix (qemu-kvm on RHEL)") set(QEMU_PLUGINDIR qemu CACHE STRING "QEMU plugin directory suffix (qemu-kvm on RHEL)")
set(WITH_ASAN false CACHE BOOL "Build with AddressSanitizer") set(WITH_ASAN false CACHE BOOL "Build with AddressSanitizer")
set(WITH_SYSTEM_LIBURING false CACHE BOOL "Use system liburing")
if("${CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/local/?$") if("${CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/local/?$")
if(EXISTS "/etc/debian_version") if(EXISTS "/etc/debian_version")
set(CMAKE_INSTALL_LIBDIR "lib/${CMAKE_LIBRARY_ARCHITECTURE}") set(CMAKE_INSTALL_LIBDIR "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
@@ -19,13 +20,16 @@ if("${CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/local/?$")
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
endif() endif()
add_definitions(-DVITASTOR_VERSION="2.2.3") add_definitions(-DVITASTOR_VERSION="2.3.0")
add_definitions(-D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -Wno-sign-compare -Wno-comment -Wno-parentheses -Wno-pointer-arith -fdiagnostics-color=always -fno-omit-frame-pointer -I ${CMAKE_SOURCE_DIR}/src) add_definitions(-D_GNU_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -Wno-sign-compare -Wno-comment -Wno-parentheses -Wno-pointer-arith -fdiagnostics-color=always -fno-omit-frame-pointer -fvisibility=hidden -I ${CMAKE_SOURCE_DIR}/src)
add_link_options(-fno-omit-frame-pointer) add_link_options(-fno-omit-frame-pointer)
if (${WITH_ASAN}) if (${WITH_ASAN})
add_definitions(-fsanitize=address) add_definitions(-fsanitize=address)
add_link_options(-fsanitize=address -fno-omit-frame-pointer) add_link_options(-fsanitize=address -fno-omit-frame-pointer)
endif (${WITH_ASAN}) endif (${WITH_ASAN})
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fvisibility-inlines-hidden")
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -fvisibility-inlines-hidden")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fvisibility-inlines-hidden")
set(CMAKE_BUILD_TYPE RelWithDebInfo) set(CMAKE_BUILD_TYPE RelWithDebInfo)
string(REGEX REPLACE "([\\/\\-]O)[^ \t\r\n]*" "\\13" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") string(REGEX REPLACE "([\\/\\-]O)[^ \t\r\n]*" "\\13" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
@@ -49,7 +53,6 @@ endmacro(install_symlink)
check_include_file("linux/nbd-netlink.h" HAVE_NBD_NETLINK_H) check_include_file("linux/nbd-netlink.h" HAVE_NBD_NETLINK_H)
find_package(PkgConfig) find_package(PkgConfig)
pkg_check_modules(LIBURING REQUIRED liburing)
if (${WITH_QEMU}) if (${WITH_QEMU})
pkg_check_modules(GLIB REQUIRED glib-2.0) pkg_check_modules(GLIB REQUIRED glib-2.0)
endif (${WITH_QEMU}) endif (${WITH_QEMU})
@@ -66,6 +69,15 @@ if (RDMACM_LIBRARIES)
add_definitions(-DWITH_RDMACM) add_definitions(-DWITH_RDMACM)
endif (RDMACM_LIBRARIES) endif (RDMACM_LIBRARIES)
if (${WITH_SYSTEM_LIBURING})
pkg_check_modules(LIBURING REQUIRED liburing>=2.10)
include_directories(${LIBURING_INCLUDE_DIRS})
else()
include_directories(${CMAKE_SOURCE_DIR}/src/liburing/include)
add_subdirectory(liburing)
set(LIBURING_LIBRARIES uring)
endif (${WITH_SYSTEM_LIBURING})
add_custom_target(build_tests) add_custom_target(build_tests)
add_custom_target(test add_custom_target(test
COMMAND COMMAND
@@ -86,7 +98,6 @@ include_directories(
${CMAKE_SOURCE_DIR}/src/test ${CMAKE_SOURCE_DIR}/src/test
${CMAKE_SOURCE_DIR}/src/util ${CMAKE_SOURCE_DIR}/src/util
/usr/include/jerasure /usr/include/jerasure
${LIBURING_INCLUDE_DIRS}
${IBVERBS_INCLUDE_DIRS} ${IBVERBS_INCLUDE_DIRS}
) )
@@ -101,7 +112,7 @@ add_subdirectory(test)
### Install ### Install
install(TARGETS vitastor-osd vitastor-disk vitastor-nbd vitastor-nfs vitastor-cli vitastor-kv vitastor-kv-stress RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) install(TARGETS vitastor-osd vitastor-disk vitastor-nbd vitastor-ublk vitastor-nfs vitastor-cli vitastor-kv vitastor-kv-stress RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
install_symlink(vitastor-disk ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/vitastor-dump-journal) install_symlink(vitastor-disk ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/vitastor-dump-journal)
install_symlink(vitastor-cli ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/vitastor-rm) install_symlink(vitastor-cli ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/vitastor-rm)
install_symlink(vitastor-cli ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/vita) install_symlink(vitastor-cli ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/vita)
+1
View File
@@ -9,6 +9,7 @@ add_library(vitastor_blk SHARED
) )
target_link_libraries(vitastor_blk target_link_libraries(vitastor_blk
${LIBURING_LIBRARIES} ${LIBURING_LIBRARIES}
${ISAL_LIBRARIES}
tcmalloc_minimal tcmalloc_minimal
# for timerfd_manager # for timerfd_manager
vitastor_common vitastor_common
+2 -2
View File
@@ -135,7 +135,7 @@ Output:
*/ */
struct blockstore_op_t struct __attribute__ ((visibility("default"))) blockstore_op_t
{ {
// operation // operation
uint64_t opcode = 0; uint64_t opcode = 0;
@@ -173,7 +173,7 @@ typedef std::map<std::string, std::string> blockstore_config_t;
class blockstore_impl_t; class blockstore_impl_t;
class blockstore_t class __attribute__((visibility("default"))) blockstore_t
{ {
blockstore_impl_t *impl; blockstore_impl_t *impl;
public: public:
+82 -43
View File
@@ -361,6 +361,10 @@ bool journal_flusher_co::loop()
else if (wait_state == 28) goto resume_28; else if (wait_state == 28) goto resume_28;
else if (wait_state == 29) goto resume_29; else if (wait_state == 29) goto resume_29;
else if (wait_state == 30) goto resume_30; else if (wait_state == 30) goto resume_30;
else if (wait_state == 31) goto resume_31;
else if (wait_state == 32) goto resume_32;
else if (wait_state == 33) goto resume_33;
else if (wait_state == 34) goto resume_34;
resume_0: resume_0:
if (flusher->flush_queue.size() < flusher->min_flusher_count && !flusher->trim_wanted || if (flusher->flush_queue.size() < flusher->min_flusher_count && !flusher->trim_wanted ||
!flusher->flush_queue.size() || !flusher->dequeuing) !flusher->flush_queue.size() || !flusher->dequeuing)
@@ -486,13 +490,14 @@ resume_2:
resume_10: resume_10:
resume_11: resume_11:
resume_12: resume_12:
resume_13:
if (fill_incomplete && !clear_incomplete_csum_block_bits(5)) if (fill_incomplete && !clear_incomplete_csum_block_bits(5))
return false; return false;
// Wait for journal data reads if the journal is not inmemory // Wait for journal data reads if the journal is not inmemory
resume_13: resume_14:
if (wait_journal_count > 0) if (wait_journal_count > 0)
{ {
wait_state = wait_base+13; wait_state = wait_base+14;
return false; return false;
} }
if (bs->dsk.csum_block_size) if (bs->dsk.csum_block_size)
@@ -509,31 +514,26 @@ resume_2:
{ {
if (it->copy_flags == COPY_BUF_JOURNAL || it->copy_flags == (COPY_BUF_JOURNAL|COPY_BUF_COALESCED)) if (it->copy_flags == COPY_BUF_JOURNAL || it->copy_flags == (COPY_BUF_JOURNAL|COPY_BUF_COALESCED))
{ {
await_sqe(14); await_sqe(15);
data->iov = (struct iovec){ it->buf, (size_t)it->len }; data->iov = (struct iovec){ it->buf, (size_t)it->len };
data->callback = simple_callback_w; data->callback = simple_callback_w;
my_uring_prep_writev( io_uring_prep_writev(
sqe, bs->dsk.data_fd, &data->iov, 1, bs->dsk.data_offset + clean_loc + it->offset sqe, bs->dsk.data_fd, &data->iov, 1, bs->dsk.data_offset + clean_loc + it->offset
); );
wait_count++; wait_count++;
} }
} }
// Wait for data writes and metadata reads // Wait for data writes and metadata reads
resume_15:
resume_16: resume_16:
if (!wait_meta_reads(15)) resume_17:
if (!wait_meta_reads(16))
return false; return false;
// Sync data before writing metadata // Sync data before writing metadata
resume_17:
resume_18: resume_18:
resume_19: resume_19:
if (copy_count && !fsync_batch(false, 17)) resume_20:
if (copy_count && !fsync_batch(false, 18))
return false; return false;
// Modify the new metadata entry
update_metadata_entry();
// Update clean_db - it must be equal to the metadata entry
update_clean_db();
// And write metadata entries
if (old_clean_loc != UINT64_MAX && old_clean_loc != clean_loc) if (old_clean_loc != UINT64_MAX && old_clean_loc != clean_loc)
{ {
// zero out old metadata entry // zero out old metadata entry
@@ -548,26 +548,56 @@ resume_2:
} }
} }
memset((uint8_t*)meta_old.buf + meta_old.pos*bs->dsk.clean_entry_size, 0, bs->dsk.clean_entry_size); memset((uint8_t*)meta_old.buf + meta_old.pos*bs->dsk.clean_entry_size, 0, bs->dsk.clean_entry_size);
resume_20: if (meta_old.sector != meta_new.sector)
if (meta_old.sector != meta_new.sector && !write_meta_block(meta_old, 20)) {
return false;
}
resume_21: resume_21:
if (!write_meta_block(meta_new, 21)) if (flusher->inflight_meta_sectors.find(meta_old.sector) != flusher->inflight_meta_sectors.end())
return false; {
wait_state = wait_base+21;
return false;
}
flusher->inflight_meta_sectors.insert(meta_old.sector);
resume_22: resume_22:
if (!write_meta_block(meta_old, 22))
return false;
resume_23:
if (wait_count > 0)
{
wait_state = wait_base+23;
return false;
}
flusher->inflight_meta_sectors.erase(meta_old.sector);
}
}
resume_24:
if (flusher->inflight_meta_sectors.find(meta_new.sector) != flusher->inflight_meta_sectors.end())
{
wait_state = wait_base+24;
return false;
}
flusher->inflight_meta_sectors.insert(meta_new.sector);
// Modify the new metadata entry
update_metadata_entry();
// Update clean_db - it must be equal to the metadata entry
update_clean_db();
// And write metadata entries
resume_25:
if (!write_meta_block(meta_new, 25))
return false;
resume_26:
if (wait_count > 0) if (wait_count > 0)
{ {
wait_state = wait_base+22; wait_state = wait_base+26;
return false; return false;
} }
flusher->inflight_meta_sectors.erase(meta_new.sector);
// Done, free all buffers // Done, free all buffers
free_buffers(); free_buffers();
// And sync metadata (in batches - not per each operation!) // And sync metadata (in batches - not per each operation!)
resume_23: resume_27:
resume_24: resume_28:
resume_25: resume_29:
if (!fsync_batch(true, 23)) if (!fsync_batch(true, 27))
return false; return false;
// Free the data block only when metadata is synced // Free the data block only when metadata is synced
free_data_blocks(); free_data_blocks();
@@ -590,12 +620,12 @@ resume_2:
if (bs->journal_trim_interval && !((++flusher->journal_trim_counter) % bs->journal_trim_interval) || if (bs->journal_trim_interval && !((++flusher->journal_trim_counter) % bs->journal_trim_interval) ||
flusher->trim_wanted > 0) flusher->trim_wanted > 0)
{ {
resume_26:
resume_27:
resume_28:
resume_29:
resume_30: resume_30:
if (!trim_journal(26)) resume_31:
resume_32:
resume_33:
resume_34:
if (!trim_journal(30))
return false; return false;
} }
// All done // All done
@@ -716,7 +746,7 @@ bool journal_flusher_co::write_meta_block(flusher_meta_write_t & meta_block, int
await_sqe(0); await_sqe(0);
data->iov = (struct iovec){ meta_block.buf, (size_t)bs->dsk.meta_block_size }; data->iov = (struct iovec){ meta_block.buf, (size_t)bs->dsk.meta_block_size };
data->callback = simple_callback_w; data->callback = simple_callback_w;
my_uring_prep_writev( io_uring_prep_writev(
sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + bs->dsk.meta_block_size + meta_block.sector sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + bs->dsk.meta_block_size + meta_block.sector
); );
wait_count++; wait_count++;
@@ -734,6 +764,7 @@ bool journal_flusher_co::clear_incomplete_csum_block_bits(int wait_base)
else if (wait_state == wait_base+5) goto resume_5; else if (wait_state == wait_base+5) goto resume_5;
else if (wait_state == wait_base+6) goto resume_6; else if (wait_state == wait_base+6) goto resume_6;
else if (wait_state == wait_base+7) goto resume_7; else if (wait_state == wait_base+7) goto resume_7;
else if (wait_state == wait_base+8) goto resume_8;
cleared_incomplete = false; cleared_incomplete = false;
for (auto it = v.begin(); it != v.end(); it++) for (auto it = v.begin(); it != v.end(); it++)
{ {
@@ -754,11 +785,18 @@ bool journal_flusher_co::clear_incomplete_csum_block_bits(int wait_base)
if (!wait_meta_reads(wait_base+0)) if (!wait_meta_reads(wait_base+0))
return false; return false;
resume_2: resume_2:
if (wait_journal_count > 0) if (flusher->inflight_meta_sectors.find(meta_new.sector) != flusher->inflight_meta_sectors.end())
{ {
wait_state = wait_base+2; wait_state = wait_base+2;
return false; return false;
} }
flusher->inflight_meta_sectors.insert(meta_new.sector);
resume_3:
if (wait_journal_count > 0)
{
wait_state = wait_base+3;
return false;
}
// Verify data checksums // Verify data checksums
for (i = v.size()-1; i >= 0 && (v[i].copy_flags & COPY_BUF_CSUM_FILL); i--) for (i = v.size()-1; i >= 0 && (v[i].copy_flags & COPY_BUF_CSUM_FILL); i--)
{ {
@@ -837,19 +875,20 @@ bool journal_flusher_co::clear_incomplete_csum_block_bits(int wait_base)
} }
} }
// Write and fsync the modified metadata entry // Write and fsync the modified metadata entry
resume_3:
if (!write_meta_block(meta_new, wait_base+3))
return false;
resume_4: resume_4:
if (!write_meta_block(meta_new, wait_base+4))
return false;
resume_5:
if (wait_count > 0) if (wait_count > 0)
{ {
wait_state = wait_base+4; wait_state = wait_base+5;
return false; return false;
} }
resume_5: flusher->inflight_meta_sectors.erase(meta_new.sector);
resume_6: resume_6:
resume_7: resume_7:
if (!fsync_batch(true, wait_base+5)) resume_8:
if (!fsync_batch(true, wait_base+6))
return false; return false;
} }
return true; return true;
@@ -1090,7 +1129,7 @@ bool journal_flusher_co::read_dirty(int wait_base)
vi.buf = memalign_or_die(MEM_ALIGNMENT, vi.len); vi.buf = memalign_or_die(MEM_ALIGNMENT, vi.len);
data->iov = (struct iovec){ vi.buf, (size_t)vi.len }; data->iov = (struct iovec){ vi.buf, (size_t)vi.len };
data->callback = simple_callback_r; data->callback = simple_callback_r;
my_uring_prep_readv( io_uring_prep_readv(
sqe, bs->dsk.data_fd, &data->iov, 1, bs->dsk.data_offset + old_clean_loc + vi.offset sqe, bs->dsk.data_fd, &data->iov, 1, bs->dsk.data_offset + old_clean_loc + vi.offset
); );
wait_count++; wait_count++;
@@ -1122,7 +1161,7 @@ bool journal_flusher_co::read_dirty(int wait_base)
await_sqe(1); await_sqe(1);
data->iov = (struct iovec){ v[i].buf, (size_t)v[i].len }; data->iov = (struct iovec){ v[i].buf, (size_t)v[i].len };
data->callback = simple_callback_rj; data->callback = simple_callback_rj;
my_uring_prep_readv( io_uring_prep_readv(
sqe, bs->dsk.journal_fd, &data->iov, 1, bs->journal.offset + v[i].disk_offset sqe, bs->dsk.journal_fd, &data->iov, 1, bs->journal.offset + v[i].disk_offset
); );
wait_journal_count++; wait_journal_count++;
@@ -1215,7 +1254,7 @@ bool journal_flusher_co::modify_meta_read(uint64_t meta_loc, flusher_meta_write_
data->iov = (struct iovec){ wr.it->second.buf, (size_t)bs->dsk.meta_block_size }; data->iov = (struct iovec){ wr.it->second.buf, (size_t)bs->dsk.meta_block_size };
data->callback = simple_callback_r; data->callback = simple_callback_r;
wr.submitted = true; wr.submitted = true;
my_uring_prep_readv( io_uring_prep_readv(
sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + bs->dsk.meta_block_size + wr.sector sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + bs->dsk.meta_block_size + wr.sector
); );
wait_count++; wait_count++;
@@ -1313,7 +1352,7 @@ bool journal_flusher_co::fsync_batch(bool fsync_meta, int wait_base)
await_sqe(0); await_sqe(0);
data->iov = { 0 }; data->iov = { 0 };
data->callback = simple_callback_w; data->callback = simple_callback_w;
my_uring_prep_fsync(sqe, fsync_meta ? bs->dsk.meta_fd : bs->dsk.data_fd, IORING_FSYNC_DATASYNC); io_uring_prep_fsync(sqe, fsync_meta ? bs->dsk.meta_fd : bs->dsk.data_fd, IORING_FSYNC_DATASYNC);
cur_sync->state = 1; cur_sync->state = 1;
wait_count++; wait_count++;
resume_2: resume_2:
@@ -1383,7 +1422,7 @@ bool journal_flusher_co::trim_journal(int wait_base)
((journal_entry_start*)flusher->journal_superblock)->crc32 = je_crc32((journal_entry*)flusher->journal_superblock); ((journal_entry_start*)flusher->journal_superblock)->crc32 = je_crc32((journal_entry*)flusher->journal_superblock);
data->iov = (struct iovec){ flusher->journal_superblock, (size_t)bs->dsk.journal_block_size }; data->iov = (struct iovec){ flusher->journal_superblock, (size_t)bs->dsk.journal_block_size };
data->callback = simple_callback_w; data->callback = simple_callback_w;
my_uring_prep_writev(sqe, bs->dsk.journal_fd, &data->iov, 1, bs->journal.offset); io_uring_prep_writev(sqe, bs->dsk.journal_fd, &data->iov, 1, bs->journal.offset);
wait_count++; wait_count++;
resume_2: resume_2:
if (wait_count > 0) if (wait_count > 0)
@@ -1394,7 +1433,7 @@ bool journal_flusher_co::trim_journal(int wait_base)
if (!bs->disable_journal_fsync) if (!bs->disable_journal_fsync)
{ {
await_sqe(3); await_sqe(3);
my_uring_prep_fsync(sqe, bs->dsk.journal_fd, IORING_FSYNC_DATASYNC); io_uring_prep_fsync(sqe, bs->dsk.journal_fd, IORING_FSYNC_DATASYNC);
data->iov = { 0 }; data->iov = { 0 };
data->callback = simple_callback_w; data->callback = simple_callback_w;
wait_count++; wait_count++;
+2 -1
View File
@@ -119,7 +119,8 @@ class journal_flusher_t
std::map<uint64_t, meta_sector_t> meta_sectors; std::map<uint64_t, meta_sector_t> meta_sectors;
std::deque<object_id> flush_queue; std::deque<object_id> flush_queue;
std::map<object_id, uint64_t> flush_versions; // FIXME: consider unordered_map? std::unordered_map<object_id, uint64_t> flush_versions;
std::unordered_set<uint64_t> inflight_meta_sectors;
bool try_find_older(std::map<obj_ver_id, dirty_entry>::iterator & dirty_end, obj_ver_id & cur); bool try_find_older(std::map<obj_ver_id, dirty_entry>::iterator & dirty_end, obj_ver_id & cur);
bool try_find_other(std::map<obj_ver_id, dirty_entry>::iterator & dirty_end, obj_ver_id & cur); bool try_find_other(std::map<obj_ver_id, dirty_entry>::iterator & dirty_end, obj_ver_id & cur);
+1
View File
@@ -19,6 +19,7 @@
#include <deque> #include <deque>
#include <new> #include <new>
#include <unordered_map> #include <unordered_map>
#include <unordered_set>
#include "cpp-btree/btree_map.h" #include "cpp-btree/btree_map.h"
+14 -14
View File
@@ -66,7 +66,7 @@ int blockstore_init_meta::loop()
last_read_offset = 0; last_read_offset = 0;
data->iov = { metadata_buffer, (size_t)bs->dsk.meta_block_size }; data->iov = { metadata_buffer, (size_t)bs->dsk.meta_block_size };
data->callback = [this](ring_data_t *data) { handle_event(data, -1); }; data->callback = [this](ring_data_t *data) { handle_event(data, -1); };
my_uring_prep_readv(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset); io_uring_prep_readv(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset);
bs->ringloop->submit(); bs->ringloop->submit();
submitted++; submitted++;
resume_1: resume_1:
@@ -104,7 +104,7 @@ resume_1:
last_read_offset = 0; last_read_offset = 0;
data->iov = (struct iovec){ metadata_buffer, (size_t)bs->dsk.meta_block_size }; data->iov = (struct iovec){ metadata_buffer, (size_t)bs->dsk.meta_block_size };
data->callback = [this](ring_data_t *data) { handle_event(data, -1); }; data->callback = [this](ring_data_t *data) { handle_event(data, -1); };
my_uring_prep_writev(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset); io_uring_prep_writev(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset);
bs->ringloop->submit(); bs->ringloop->submit();
submitted++; submitted++;
resume_3: resume_3:
@@ -213,12 +213,12 @@ resume_2:
data->iov = { bufs[i].buf, (size_t)bufs[i].size }; data->iov = { bufs[i].buf, (size_t)bufs[i].size };
data->callback = [this, i](ring_data_t *data) { handle_event(data, i); }; data->callback = [this, i](ring_data_t *data) { handle_event(data, i); };
if (!zero_on_init) if (!zero_on_init)
my_uring_prep_readv(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + bufs[i].offset); io_uring_prep_readv(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + bufs[i].offset);
else else
{ {
// Fill metadata with zeroes // Fill metadata with zeroes
memset(data->iov.iov_base, 0, data->iov.iov_len); memset(data->iov.iov_base, 0, data->iov.iov_len);
my_uring_prep_writev(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + bufs[i].offset); io_uring_prep_writev(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + bufs[i].offset);
} }
bs->ringloop->submit(); bs->ringloop->submit();
break; break;
@@ -245,7 +245,7 @@ resume_2:
assert(bufs[i].size <= 0x7fffffff); assert(bufs[i].size <= 0x7fffffff);
data->iov = { bufs[i].buf, (size_t)bufs[i].size }; data->iov = { bufs[i].buf, (size_t)bufs[i].size };
data->callback = [this, i](ring_data_t *data) { handle_event(data, i); }; data->callback = [this, i](ring_data_t *data) { handle_event(data, i); };
my_uring_prep_writev(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + bufs[i].offset); io_uring_prep_writev(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + bufs[i].offset);
bs->ringloop->submit(); bs->ringloop->submit();
bufs[i].state = INIT_META_WRITING; bufs[i].state = INIT_META_WRITING;
submitted++; submitted++;
@@ -274,7 +274,7 @@ resume_2:
last_read_offset = (1+next_offset)*bs->dsk.meta_block_size; last_read_offset = (1+next_offset)*bs->dsk.meta_block_size;
data->iov = { metadata_buffer, (size_t)bs->dsk.meta_block_size }; data->iov = { metadata_buffer, (size_t)bs->dsk.meta_block_size };
data->callback = [this](ring_data_t *data) { handle_event(data, -1); }; data->callback = [this](ring_data_t *data) { handle_event(data, -1); };
my_uring_prep_readv(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + (1+next_offset)*bs->dsk.meta_block_size); io_uring_prep_readv(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + (1+next_offset)*bs->dsk.meta_block_size);
bs->ringloop->submit(); bs->ringloop->submit();
submitted++; submitted++;
resume_5: resume_5:
@@ -291,7 +291,7 @@ resume_5:
GET_SQE(); GET_SQE();
data->iov = { metadata_buffer, (size_t)bs->dsk.meta_block_size }; data->iov = { metadata_buffer, (size_t)bs->dsk.meta_block_size };
data->callback = [this](ring_data_t *data) { handle_event(data, -1); }; data->callback = [this](ring_data_t *data) { handle_event(data, -1); };
my_uring_prep_writev(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + (1+next_offset)*bs->dsk.meta_block_size); io_uring_prep_writev(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + (1+next_offset)*bs->dsk.meta_block_size);
bs->ringloop->submit(); bs->ringloop->submit();
submitted++; submitted++;
resume_6: resume_6:
@@ -313,7 +313,7 @@ resume_6:
if (zero_on_init && !bs->disable_meta_fsync) if (zero_on_init && !bs->disable_meta_fsync)
{ {
GET_SQE(); GET_SQE();
my_uring_prep_fsync(sqe, bs->dsk.meta_fd, IORING_FSYNC_DATASYNC); io_uring_prep_fsync(sqe, bs->dsk.meta_fd, IORING_FSYNC_DATASYNC);
last_read_offset = 0; last_read_offset = 0;
data->iov = { 0 }; data->iov = { 0 };
data->callback = [this](ring_data_t *data) { handle_event(data, -1); }; data->callback = [this](ring_data_t *data) { handle_event(data, -1); };
@@ -495,7 +495,7 @@ int blockstore_init_journal::loop()
data = ((ring_data_t*)sqe->user_data); data = ((ring_data_t*)sqe->user_data);
data->iov = { submitted_buf, (size_t)bs->journal.block_size }; data->iov = { submitted_buf, (size_t)bs->journal.block_size };
data->callback = simple_callback; data->callback = simple_callback;
my_uring_prep_readv(sqe, bs->dsk.journal_fd, &data->iov, 1, bs->journal.offset); io_uring_prep_readv(sqe, bs->dsk.journal_fd, &data->iov, 1, bs->journal.offset);
bs->ringloop->submit(); bs->ringloop->submit();
wait_count = 1; wait_count = 1;
resume_1: resume_1:
@@ -536,7 +536,7 @@ resume_1:
GET_SQE(); GET_SQE();
data->iov = (struct iovec){ submitted_buf, (size_t)(2*bs->journal.block_size) }; data->iov = (struct iovec){ submitted_buf, (size_t)(2*bs->journal.block_size) };
data->callback = simple_callback; data->callback = simple_callback;
my_uring_prep_writev(sqe, bs->dsk.journal_fd, &data->iov, 1, bs->journal.offset); io_uring_prep_writev(sqe, bs->dsk.journal_fd, &data->iov, 1, bs->journal.offset);
wait_count++; wait_count++;
bs->ringloop->submit(); bs->ringloop->submit();
resume_6: resume_6:
@@ -548,7 +548,7 @@ resume_1:
if (!bs->disable_journal_fsync) if (!bs->disable_journal_fsync)
{ {
GET_SQE(); GET_SQE();
my_uring_prep_fsync(sqe, bs->dsk.journal_fd, IORING_FSYNC_DATASYNC); io_uring_prep_fsync(sqe, bs->dsk.journal_fd, IORING_FSYNC_DATASYNC);
data->iov = { 0 }; data->iov = { 0 };
data->callback = simple_callback; data->callback = simple_callback;
wait_count++; wait_count++;
@@ -636,7 +636,7 @@ resume_1:
(size_t)(end - journal_pos < JOURNAL_BUFFER_SIZE ? end - journal_pos : JOURNAL_BUFFER_SIZE), (size_t)(end - journal_pos < JOURNAL_BUFFER_SIZE ? end - journal_pos : JOURNAL_BUFFER_SIZE),
}; };
data->callback = [this](ring_data_t *data1) { handle_event(data1); }; data->callback = [this](ring_data_t *data1) { handle_event(data1); };
my_uring_prep_readv(sqe, bs->dsk.journal_fd, &data->iov, 1, bs->journal.offset + journal_pos); io_uring_prep_readv(sqe, bs->dsk.journal_fd, &data->iov, 1, bs->journal.offset + journal_pos);
bs->ringloop->submit(); bs->ringloop->submit();
} }
while (done.size() > 0) while (done.size() > 0)
@@ -651,7 +651,7 @@ resume_1:
GET_SQE(); GET_SQE();
data->iov = { init_write_buf, (size_t)bs->journal.block_size }; data->iov = { init_write_buf, (size_t)bs->journal.block_size };
data->callback = simple_callback; data->callback = simple_callback;
my_uring_prep_writev(sqe, bs->dsk.journal_fd, &data->iov, 1, bs->journal.offset + init_write_sector); io_uring_prep_writev(sqe, bs->dsk.journal_fd, &data->iov, 1, bs->journal.offset + init_write_sector);
wait_count++; wait_count++;
bs->ringloop->submit(); bs->ringloop->submit();
resume_7: resume_7:
@@ -665,7 +665,7 @@ resume_1:
GET_SQE(); GET_SQE();
data->iov = { 0 }; data->iov = { 0 };
data->callback = simple_callback; data->callback = simple_callback;
my_uring_prep_fsync(sqe, bs->dsk.journal_fd, IORING_FSYNC_DATASYNC); io_uring_prep_fsync(sqe, bs->dsk.journal_fd, IORING_FSYNC_DATASYNC);
wait_count++; wait_count++;
bs->ringloop->submit(); bs->ringloop->submit();
} }
+1 -29
View File
@@ -190,7 +190,7 @@ void blockstore_impl_t::prepare_journal_sector_write(int cur_sector, blockstore_
(size_t)journal.block_size (size_t)journal.block_size
}; };
data->callback = [this, flush_id = journal.submit_id](ring_data_t *data) { handle_journal_write(data, flush_id); }; data->callback = [this, flush_id = journal.submit_id](ring_data_t *data) { handle_journal_write(data, flush_id); };
my_uring_prep_writev( io_uring_prep_writev(
sqe, dsk.journal_fd, &data->iov, 1, journal.offset + journal.sector_info[cur_sector].offset sqe, dsk.journal_fd, &data->iov, 1, journal.offset + journal.sector_info[cur_sector].offset
); );
} }
@@ -326,31 +326,3 @@ void journal_t::dump_diagnostics()
journal_used_it == used_sectors.end() ? 0 : journal_used_it->second journal_used_it == used_sectors.end() ? 0 : journal_used_it->second
); );
} }
static uint64_t zero_page[4096];
uint32_t crc32c_pad(uint32_t prev_crc, const void *buf, size_t len, size_t left_pad, size_t right_pad)
{
uint32_t r = prev_crc;
while (left_pad >= 4096)
{
r = crc32c(r, zero_page, 4096);
left_pad -= 4096;
}
if (left_pad > 0)
r = crc32c(r, zero_page, left_pad);
r = crc32c(r, buf, len);
while (right_pad >= 4096)
{
r = crc32c(r, zero_page, 4096);
right_pad -= 4096;
}
if (left_pad > 0)
r = crc32c(r, zero_page, right_pad);
return r;
}
uint32_t crc32c_nopad(uint32_t prev_crc, const void *buf, size_t len, size_t left_pad, size_t right_pad)
{
return crc32c(0, buf, len);
}
-3
View File
@@ -216,6 +216,3 @@ struct blockstore_journal_check_t
}; };
journal_entry* prefill_single_journal_entry(journal_t & journal, uint16_t type, uint32_t size); journal_entry* prefill_single_journal_entry(journal_t & journal, uint16_t type, uint32_t size);
uint32_t crc32c_pad(uint32_t prev_crc, const void *buf, size_t len, size_t left_pad, size_t right_pad);
uint32_t crc32c_nopad(uint32_t prev_crc, const void *buf, size_t len, size_t left_pad, size_t right_pad);
+3 -3
View File
@@ -27,7 +27,7 @@ int blockstore_impl_t::fulfill_read_push(blockstore_op_t *op, void *buf, uint64_
BS_SUBMIT_GET_SQE(sqe, data); BS_SUBMIT_GET_SQE(sqe, data);
data->iov = (struct iovec){ buf, (size_t)len }; data->iov = (struct iovec){ buf, (size_t)len };
PRIV(op)->pending_ops++; PRIV(op)->pending_ops++;
my_uring_prep_readv( io_uring_prep_readv(
sqe, sqe,
IS_JOURNAL(item_state) ? dsk.journal_fd : dsk.data_fd, IS_JOURNAL(item_state) ? dsk.journal_fd : dsk.data_fd,
&data->iov, 1, &data->iov, 1,
@@ -356,7 +356,7 @@ bool blockstore_impl_t::read_checksum_block(blockstore_op_t *op, int rv_pos, uin
int n_cur = n_iov-n_pos < IOV_MAX ? n_iov-n_pos : IOV_MAX; int n_cur = n_iov-n_pos < IOV_MAX ? n_iov-n_pos : IOV_MAX;
BS_SUBMIT_GET_SQE(sqe, data); BS_SUBMIT_GET_SQE(sqe, data);
PRIV(op)->pending_ops++; PRIV(op)->pending_ops++;
my_uring_prep_readv(sqe, submit_fd, iov + n_pos, n_cur, submit_offset + clean_loc + item_start + d_pos); io_uring_prep_readv(sqe, submit_fd, iov + n_pos, n_cur, submit_offset + clean_loc + item_start + d_pos);
data->callback = [this, op](ring_data_t *data) { handle_read_event(data, op); }; data->callback = [this, op](ring_data_t *data) { handle_read_event(data, op); };
if (n_pos > 0 || n_pos + IOV_MAX < n_iov) if (n_pos > 0 || n_pos + IOV_MAX < n_iov)
{ {
@@ -702,7 +702,7 @@ uint8_t* blockstore_impl_t::read_clean_meta_block(blockstore_op_t *op, uint64_t
BS_SUBMIT_GET_SQE(sqe, data); BS_SUBMIT_GET_SQE(sqe, data);
data->iov = (struct iovec){ buf, (size_t)dsk.meta_block_size }; data->iov = (struct iovec){ buf, (size_t)dsk.meta_block_size };
PRIV(op)->pending_ops++; PRIV(op)->pending_ops++;
my_uring_prep_readv(sqe, dsk.meta_fd, &data->iov, 1, dsk.meta_offset + dsk.meta_block_size + sector); io_uring_prep_readv(sqe, dsk.meta_fd, &data->iov, 1, dsk.meta_offset + dsk.meta_block_size + sector);
data->callback = [this, op](ring_data_t *data) { handle_read_event(data, op); }; data->callback = [this, op](ring_data_t *data) { handle_read_event(data, op); };
// return pointer to checksums + bitmap // return pointer to checksums + bitmap
return buf + pos + sizeof(clean_disk_entry); return buf + pos + sizeof(clean_disk_entry);
+1 -1
View File
@@ -101,7 +101,7 @@ resume_2:
if (!disable_journal_fsync) if (!disable_journal_fsync)
{ {
BS_SUBMIT_GET_SQE(sqe, data); BS_SUBMIT_GET_SQE(sqe, data);
my_uring_prep_fsync(sqe, dsk.journal_fd, IORING_FSYNC_DATASYNC); io_uring_prep_fsync(sqe, dsk.journal_fd, IORING_FSYNC_DATASYNC);
data->iov = { 0 }; data->iov = { 0 };
data->callback = [this, op](ring_data_t *data) { handle_write_event(data, op); }; data->callback = [this, op](ring_data_t *data) { handle_write_event(data, op); };
PRIV(op)->min_flushed_journal_sector = PRIV(op)->max_flushed_journal_sector = 0; PRIV(op)->min_flushed_journal_sector = PRIV(op)->max_flushed_journal_sector = 0;
+1 -1
View File
@@ -400,7 +400,7 @@ resume_2:
if (!disable_journal_fsync) if (!disable_journal_fsync)
{ {
BS_SUBMIT_GET_SQE(sqe, data); BS_SUBMIT_GET_SQE(sqe, data);
my_uring_prep_fsync(sqe, dsk.journal_fd, IORING_FSYNC_DATASYNC); io_uring_prep_fsync(sqe, dsk.journal_fd, IORING_FSYNC_DATASYNC);
data->iov = { 0 }; data->iov = { 0 };
data->callback = [this, op](ring_data_t *data) { handle_write_event(data, op); }; data->callback = [this, op](ring_data_t *data) { handle_write_event(data, op); };
PRIV(op)->min_flushed_journal_sector = PRIV(op)->max_flushed_journal_sector = 0; PRIV(op)->min_flushed_journal_sector = PRIV(op)->max_flushed_journal_sector = 0;
+2 -2
View File
@@ -58,7 +58,7 @@ int blockstore_impl_t::continue_sync(blockstore_op_t *op)
if (!disable_data_fsync) if (!disable_data_fsync)
{ {
BS_SUBMIT_GET_SQE(sqe, data); BS_SUBMIT_GET_SQE(sqe, data);
my_uring_prep_fsync(sqe, dsk.data_fd, IORING_FSYNC_DATASYNC); io_uring_prep_fsync(sqe, dsk.data_fd, IORING_FSYNC_DATASYNC);
data->iov = { 0 }; data->iov = { 0 };
data->callback = [this, op](ring_data_t *data) { handle_write_event(data, op); }; data->callback = [this, op](ring_data_t *data) { handle_write_event(data, op); };
PRIV(op)->min_flushed_journal_sector = PRIV(op)->max_flushed_journal_sector = 0; PRIV(op)->min_flushed_journal_sector = PRIV(op)->max_flushed_journal_sector = 0;
@@ -149,7 +149,7 @@ int blockstore_impl_t::continue_sync(blockstore_op_t *op)
if (!disable_journal_fsync) if (!disable_journal_fsync)
{ {
BS_SUBMIT_GET_SQE(sqe, data); BS_SUBMIT_GET_SQE(sqe, data);
my_uring_prep_fsync(sqe, dsk.journal_fd, IORING_FSYNC_DATASYNC); io_uring_prep_fsync(sqe, dsk.journal_fd, IORING_FSYNC_DATASYNC);
data->iov = { 0 }; data->iov = { 0 };
data->callback = [this, op](ring_data_t *data) { handle_write_event(data, op); }; data->callback = [this, op](ring_data_t *data) { handle_write_event(data, op); };
PRIV(op)->min_flushed_journal_sector = PRIV(op)->max_flushed_journal_sector = 0; PRIV(op)->min_flushed_journal_sector = PRIV(op)->max_flushed_journal_sector = 0;
+3 -22
View File
@@ -169,26 +169,7 @@ bool blockstore_impl_t::enqueue_write(blockstore_op_t *op)
if (op->opcode == BS_OP_WRITE_STABLE) if (op->opcode == BS_OP_WRITE_STABLE)
state |= BS_ST_INSTANT; state |= BS_ST_INSTANT;
if (op->bitmap) if (op->bitmap)
{ memcpy(dyn_ptr, op->bitmap, dsk.clean_entry_bitmap_size);
// Only allow to overwrite part of the object bitmap respective to the write's offset/len
uint32_t bit = op->offset/dsk.bitmap_granularity;
uint32_t bits_left = op->len/dsk.bitmap_granularity;
while (!(bit % 8) && bits_left >= 8)
{
// Copy bytes
dyn_ptr[bit/8] = ((uint8_t*)op->bitmap)[bit/8];
bit += 8;
bits_left -= 8;
}
while (bits_left > 0)
{
// Copy bits
dyn_ptr[bit/8] = (dyn_ptr[bit/8] & ~(1 << (bit%8)))
| (((uint8_t*)op->bitmap)[bit/8] & (1 << bit%8));
bit++;
bits_left--;
}
}
} }
// Calculate checksums // Calculate checksums
// FIXME: Allow to receive checksums from outside? // FIXME: Allow to receive checksums from outside?
@@ -384,7 +365,7 @@ int blockstore_impl_t::dequeue_write(blockstore_op_t *op)
} }
data->iov.iov_len = op->len + stripe_offset + stripe_end; // to check it in the callback data->iov.iov_len = op->len + stripe_offset + stripe_end; // to check it in the callback
data->callback = [this, op](ring_data_t *data) { handle_write_event(data, op); }; data->callback = [this, op](ring_data_t *data) { handle_write_event(data, op); };
my_uring_prep_writev( io_uring_prep_writev(
sqe, dsk.data_fd, PRIV(op)->iov_zerofill, vcnt, dsk.data_offset + (loc << dsk.block_order) + op->offset - stripe_offset sqe, dsk.data_fd, PRIV(op)->iov_zerofill, vcnt, dsk.data_offset + (loc << dsk.block_order) + op->offset - stripe_offset
); );
PRIV(op)->pending_ops = 1; PRIV(op)->pending_ops = 1;
@@ -511,7 +492,7 @@ int blockstore_impl_t::dequeue_write(blockstore_op_t *op)
.op = op, .op = op,
}); });
data2->callback = [this, flush_id = journal.submit_id](ring_data_t *data) { handle_journal_write(data, flush_id); }; data2->callback = [this, flush_id = journal.submit_id](ring_data_t *data) { handle_journal_write(data, flush_id); };
my_uring_prep_writev( io_uring_prep_writev(
sqe2, dsk.journal_fd, &data2->iov, 1, journal.offset + journal.next_free sqe2, dsk.journal_fd, &data2->iov, 1, journal.offset + journal.next_free
); );
PRIV(op)->pending_ops++; PRIV(op)->pending_ops++;
+1 -1
View File
@@ -301,7 +301,7 @@ static int bs_invalidate(struct thread_data *td, struct fio_file *f)
return 0; return 0;
} }
struct ioengine_ops ioengine = { struct ioengine_ops __attribute__((visibility("default"))) ioengine = {
.name = "vitastor_blockstore", .name = "vitastor_blockstore",
.version = FIO_IOOPS_VERSION, .version = FIO_IOOPS_VERSION,
.flags = FIO_MEMALIGN | FIO_DISKLESSIO | FIO_NOEXTEND, .flags = FIO_MEMALIGN | FIO_DISKLESSIO | FIO_NOEXTEND,
+6
View File
@@ -68,6 +68,12 @@ if (HAVE_NBD_NETLINK_H AND NL3_LIBRARIES)
target_compile_definitions(vitastor-nbd PUBLIC HAVE_NBD_NETLINK_H) target_compile_definitions(vitastor-nbd PUBLIC HAVE_NBD_NETLINK_H)
endif (HAVE_NBD_NETLINK_H AND NL3_LIBRARIES) endif (HAVE_NBD_NETLINK_H AND NL3_LIBRARIES)
# vitastor-ublk
add_executable(vitastor-ublk
ublk_server.cpp
)
target_link_libraries(vitastor-ublk vitastor_client)
if (${WITH_QEMU}) if (${WITH_QEMU})
# qemu_driver.so # qemu_driver.so
add_library(qemu_vitastor SHARED add_library(qemu_vitastor SHARED
+2 -2
View File
@@ -31,7 +31,7 @@ struct cluster_op_part_t
osd_op_t op; osd_op_t op;
}; };
struct cluster_op_t struct __attribute__((visibility("default"))) cluster_op_t
{ {
uint64_t opcode; // OSD_OP_READ, OSD_OP_WRITE, OSD_OP_SYNC, OSD_OP_DELETE, OSD_OP_READ_BITMAP, OSD_OP_READ_CHAIN_BITMAP uint64_t opcode; // OSD_OP_READ, OSD_OP_WRITE, OSD_OP_SYNC, OSD_OP_DELETE, OSD_OP_READ_BITMAP, OSD_OP_READ_CHAIN_BITMAP
uint64_t inode; uint64_t inode;
@@ -81,7 +81,7 @@ struct inode_list_pg_t;
class writeback_cache_t; class writeback_cache_t;
// FIXME: Split into public and private interfaces // FIXME: Split into public and private interfaces
class cluster_client_t class __attribute__((visibility("default"))) cluster_client_t
{ {
#ifdef __MOCK__ #ifdef __MOCK__
public: public:
+1 -1
View File
@@ -92,7 +92,7 @@ struct inode_watch_t
struct http_co_t; struct http_co_t;
struct etcd_state_client_t struct __attribute__((visibility("default"))) etcd_state_client_t
{ {
protected: protected:
std::vector<std::string> local_ips; std::vector<std::string> local_ips;
+1 -1
View File
@@ -525,7 +525,7 @@ static int sec_invalidate(struct thread_data *td, struct fio_file *f)
return 0; return 0;
} }
struct ioengine_ops ioengine = { struct ioengine_ops __attribute__((visibility("default"))) ioengine = {
.name = "vitastor_cluster", .name = "vitastor_cluster",
.version = FIO_IOOPS_VERSION, .version = FIO_IOOPS_VERSION,
.flags = FIO_MEMALIGN | FIO_DISKLESSIO | FIO_NOEXTEND, .flags = FIO_MEMALIGN | FIO_DISKLESSIO | FIO_NOEXTEND,
+1 -1
View File
@@ -437,7 +437,7 @@ static int sec_invalidate(struct thread_data *td, struct fio_file *f)
return 0; return 0;
} }
struct ioengine_ops ioengine = { struct ioengine_ops __attribute__((visibility("default"))) ioengine = {
.name = "vitastor_secondary_osd", .name = "vitastor_secondary_osd",
.version = FIO_IOOPS_VERSION, .version = FIO_IOOPS_VERSION,
.flags = FIO_MEMALIGN | FIO_DISKLESSIO | FIO_NOEXTEND, .flags = FIO_MEMALIGN | FIO_DISKLESSIO | FIO_NOEXTEND,
+1 -1
View File
@@ -70,7 +70,7 @@ void msgr_iothread_t::add_to_ringloop(ring_loop_t *outer_loop)
assert(sqe != NULL); assert(sqe != NULL);
this->outer_loop = outer_loop; this->outer_loop = outer_loop;
this->outer_loop_data = ((ring_data_t*)sqe->user_data); this->outer_loop_data = ((ring_data_t*)sqe->user_data);
my_uring_prep_poll_add(sqe, eventfd, POLLIN); io_uring_prep_poll_add(sqe, eventfd, POLLIN);
outer_loop_data->callback = [this](ring_data_t *data) outer_loop_data->callback = [this](ring_data_t *data)
{ {
if (data->res < 0) if (data->res < 0)
+1 -1
View File
@@ -174,7 +174,7 @@ struct osd_messenger_t;
struct rdmacm_connecting_t; struct rdmacm_connecting_t;
#endif #endif
struct osd_messenger_t struct __attribute__((visibility("default"))) osd_messenger_t
{ {
protected: protected:
int keepalive_timer_id = -1; int keepalive_timer_id = -1;
+1 -1
View File
@@ -152,7 +152,7 @@ struct blockstore_op_t;
struct osd_primary_op_data_t; struct osd_primary_op_data_t;
struct osd_op_t struct __attribute__((visibility("default"))) osd_op_t
{ {
timespec tv_begin = { 0 }, tv_end = { 0 }; timespec tv_begin = { 0 }, tv_end = { 0 };
uint64_t op_type = OSD_OP_IN; uint64_t op_type = OSD_OP_IN;
+1 -1
View File
@@ -48,7 +48,7 @@ void osd_messenger_t::read_requests()
} }
ring_data_t* data = ((ring_data_t*)sqe->user_data); ring_data_t* data = ((ring_data_t*)sqe->user_data);
data->callback = [this, cl](ring_data_t *data) { handle_read(data->res, cl); }; data->callback = [this, cl](ring_data_t *data) { handle_read(data->res, cl); };
my_uring_prep_recvmsg(sqe, peer_fd, &cl->read_msg, 0); io_uring_prep_recvmsg(sqe, peer_fd, &cl->read_msg, 0);
if (iothread) if (iothread)
{ {
iothread->add_sqe(sqe_local); iothread->add_sqe(sqe_local);
+2 -2
View File
@@ -218,11 +218,11 @@ bool osd_messenger_t::try_send(osd_client_t *cl)
} }
if (use_zc) if (use_zc)
{ {
my_uring_prep_sendmsg_zc(sqe, peer_fd, &cl->write_msg, MSG_WAITALL); io_uring_prep_sendmsg_zc(sqe, peer_fd, &cl->write_msg, MSG_WAITALL);
} }
else else
{ {
my_uring_prep_sendmsg(sqe, peer_fd, &cl->write_msg, MSG_WAITALL); io_uring_prep_sendmsg(sqe, peer_fd, &cl->write_msg, MSG_WAITALL);
} }
if (iothread) if (iothread)
{ {
+2 -2
View File
@@ -1008,7 +1008,7 @@ protected:
data->callback = [this](ring_data_t *data) { handle_send(data->res); }; data->callback = [this](ring_data_t *data) { handle_send(data->res); };
send_msg.msg_iov = send_list.data(); send_msg.msg_iov = send_list.data();
send_msg.msg_iovlen = send_list.size(); send_msg.msg_iovlen = send_list.size();
my_uring_prep_sendmsg(sqe, nbd_fd, &send_msg, MSG_ZEROCOPY); io_uring_prep_sendmsg(sqe, nbd_fd, &send_msg, MSG_ZEROCOPY);
} }
void handle_send(int result) void handle_send(int result)
@@ -1076,7 +1076,7 @@ protected:
} }
read_msg.msg_iov = &read_iov; read_msg.msg_iov = &read_iov;
read_msg.msg_iovlen = 1; read_msg.msg_iovlen = 1;
my_uring_prep_recvmsg(sqe, nbd_fd, &read_msg, 0); io_uring_prep_recvmsg(sqe, nbd_fd, &read_msg, 0);
} }
void handle_read(int result) void handle_read(int result)
+4
View File
@@ -3,6 +3,8 @@
#pragma once #pragma once
#pragma GCC visibility push(default)
// Placement group states // Placement group states
// STARTING -> [acquire lock] -> PEERING -> INCOMPLETE|ACTIVE // STARTING -> [acquire lock] -> PEERING -> INCOMPLETE|ACTIVE
// ACTIVE -> REPEERING -> PEERING // ACTIVE -> REPEERING -> PEERING
@@ -50,3 +52,5 @@ extern const int pg_state_bit_count;
extern const int object_state_bits[]; extern const int object_state_bits[];
extern const char *object_state_names[]; extern const char *object_state_names[];
extern const int object_state_bit_count; extern const int object_state_bit_count;
#pragma GCC visibility pop
+103 -11
View File
@@ -5,7 +5,6 @@
#ifdef VITASTOR_SOURCE_TREE #ifdef VITASTOR_SOURCE_TREE
#define BUILD_DSO #define BUILD_DSO
#define _GNU_SOURCE
#endif #endif
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu/main-loop.h" #include "qemu/main-loop.h"
@@ -14,27 +13,42 @@
#endif #endif
#include "block/block_int.h" #include "block/block_int.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qerror.h" #include "qapi/qmp/qerror.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qemu/module.h" #include "qemu/module.h"
#include "qemu/option.h" #include "qemu/option.h"
#if QEMU_VERSION_MAJOR >= 3 #if QEMU_VERSION_MAJOR >= 10
#include "qemu/units.h" #include "qobject/qstring.h"
#include "block/qdict.h" #include "qobject/qdict.h"
#include "qemu/cutils.h" #include "qobject/qobject.h"
#elif QEMU_VERSION_MAJOR == 2 && QEMU_VERSION_MINOR >= 10 #include "qobject/qjson.h"
#include "qemu/cutils.h" #elif QEMU_VERSION_MAJOR >= 3 || QEMU_VERSION_MAJOR == 2 && QEMU_VERSION_MINOR >= 10
#include "qapi/qmp/qstring.h" #include "qapi/qmp/qstring.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qobject.h"
#include "qapi/qmp/qjson.h" #include "qapi/qmp/qjson.h"
#else #else
#include "qapi/qmp/qstring.h"
#include "qapi/qmp/qint.h" #include "qapi/qmp/qint.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qobject.h"
#include "qapi/qmp/qjson.h"
#define qdict_put_int(options, name, num_val) qdict_put_obj(options, name, QOBJECT(qint_from_int(num_val))) #define qdict_put_int(options, name, num_val) qdict_put_obj(options, name, QOBJECT(qint_from_int(num_val)))
#define qdict_put_str(options, name, value) qdict_put_obj(options, name, QOBJECT(qstring_from_str(value))) #define qdict_put_str(options, name, value) qdict_put_obj(options, name, QOBJECT(qstring_from_str(value)))
#define qobject_unref QDECREF #define qobject_unref QDECREF
#endif #endif
#if QEMU_VERSION_MAJOR == 4 && QEMU_VERSION_MINOR >= 2 || QEMU_VERSION_MAJOR > 4
// parse_uint_full()
#if QEMU_VERSION_MAJOR >= 3 || QEMU_VERSION_MAJOR == 2 && QEMU_VERSION_MINOR >= 6
#include "qemu/cutils.h"
#else
#include "qemu-common.h"
#endif
#if QEMU_VERSION_MAJOR >= 10
#include "system/replay.h"
#elif QEMU_VERSION_MAJOR == 4 && QEMU_VERSION_MINOR >= 2 || QEMU_VERSION_MAJOR > 4
#include "sysemu/replay.h" #include "sysemu/replay.h"
#else #else
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
@@ -43,11 +57,11 @@
#include "vitastor_c.h" #include "vitastor_c.h"
#ifdef VITASTOR_SOURCE_TREE #ifdef VITASTOR_SOURCE_TREE
void qemu_module_dummy(void) void __attribute__((visibility("default"))) qemu_module_dummy(void)
{ {
} }
void DSO_STAMP_FUN(void) void __attribute__((visibility("default"))) DSO_STAMP_FUN(void)
{ {
} }
#endif #endif
@@ -65,6 +79,7 @@ typedef struct VitastorClient
char *etcd_host; char *etcd_host;
char *etcd_prefix; char *etcd_prefix;
char *image; char *image;
char *file_mirror_path;
int skip_parents; int skip_parents;
uint64_t inode; uint64_t inode;
uint64_t pool; uint64_t pool;
@@ -432,6 +447,74 @@ static void strarray_free(str_array *a)
} }
#endif #endif
static void check_config(VitastorClient *client)
{
size_t bufsize = 64*1024, maxsize = 1024*1024, done = 0;
ssize_t r = 0;
char *data = NULL;
QObject *obj = NULL;
QDict *qd = NULL;
int fd = open(client->config_path, O_RDONLY);
if (fd < 0)
{
fprintf(stderr, "vitastor: failed to read %s: %s\n", client->config_path, strerror(errno));
return;
}
data = (char*)malloc(bufsize);
if (!data)
{
fprintf(stderr, "vitastor: memory allocation failed\n");
goto end_free;
}
while (1)
{
if (bufsize <= done)
{
if (bufsize >= maxsize)
{
fprintf(stderr, "vitastor: config file exceeds %zu bytes\n", maxsize);
goto end_free;
}
bufsize *= 2;
data = (char*)realloc(data, bufsize);
if (!data)
{
fprintf(stderr, "vitastor: memory allocation failed\n");
goto end_free;
}
}
r = read(fd, data+done, bufsize-done);
if (r < 0)
{
if (errno == EAGAIN || errno == EINTR)
continue;
fprintf(stderr, "vitastor: failed to read %s: %s\n", client->config_path, strerror(errno));
break;
}
if (!r)
{
break;
}
done += r;
}
obj = qobject_from_json(data
#if QEMU_VERSION_MAJOR == 2 && QEMU_VERSION_MINOR >= 9 || QEMU_VERSION_MAJOR >= 3
, NULL
#endif
);
qd = qobject_to(QDict, obj);
if (qd)
{
client->file_mirror_path = g_strdup(qdict_get_try_str(qd, "qemu_file_mirror_path"));
}
end_free:
if (obj)
qobject_unref(obj);
if (data)
free(data);
close(fd);
}
static int vitastor_file_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) static int vitastor_file_open(BlockDriverState *bs, QDict *options, int flags, Error **errp)
{ {
VitastorRPC task; VitastorRPC task;
@@ -450,6 +533,10 @@ static int vitastor_file_open(BlockDriverState *bs, QDict *options, int flags, E
client->rdma_gid_index = qdict_get_try_int(options, "rdma-gid-index", 0); client->rdma_gid_index = qdict_get_try_int(options, "rdma-gid-index", 0);
client->rdma_mtu = qdict_get_try_int(options, "rdma-mtu", 0); client->rdma_mtu = qdict_get_try_int(options, "rdma-mtu", 0);
client->ctx = bdrv_get_aio_context(bs); client->ctx = bdrv_get_aio_context(bs);
if (client->config_path && strlen(client->config_path))
{
check_config(client);
}
#if defined VITASTOR_C_API_VERSION && VITASTOR_C_API_VERSION >= 2 #if defined VITASTOR_C_API_VERSION && VITASTOR_C_API_VERSION >= 2
str_array opt = {}; str_array opt = {};
char version_buffer[32]; char version_buffer[32];
@@ -624,6 +711,11 @@ static void vitastor_refresh_filename(BlockDriverState *bs)
VitastorClient *client = bs->opaque; VitastorClient *client = bs->opaque;
size_t len = 0; size_t len = 0;
int n = 0; int n = 0;
if (client->image && client->file_mirror_path)
{
len = snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s%s", client->file_mirror_path, client->image);
return;
}
len = snprintf(bs->exact_filename, sizeof(bs->exact_filename), "vitastor://"); len = snprintf(bs->exact_filename, sizeof(bs->exact_filename), "vitastor://");
if (len < sizeof(bs->exact_filename)) if (len < sizeof(bs->exact_filename))
{ {
+900
View File
@@ -0,0 +1,900 @@
// Copyright (c) Vitaliy Filippov, 2019+
// License: VNPL-1.1 (see README.md for details)
// ublk-based Vitastor block device in userspace
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <dirent.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/mman.h>
#include <unistd.h>
#include "../liburing/include/ublk_cmd.h"
#include "cluster_client.h"
#include "epoll_manager.h"
#include "str_util.h"
const char *exe_name = NULL;
const char *help_text =
"Vitastor ublk server " VITASTOR_VERSION "\n"
"(c) Vitaliy Filippov, 2025+ (VNPL-1.1)\n"
"\n"
"COMMANDS:\n"
"\n"
"vitastor-ublk map [OPTIONS] (--image <image> | --pool <pool> --inode <inode> --size <size in bytes>)\n"
" Map a ublk device. Options:\n"
" --recover\n"
" Recover a mapped device if the previous ublk server is dead.\n"
" --queue_depth 256\n"
" Maximum queue size for the device.\n"
" --max_io_size 1M\n"
" Maximum single I/O size for the device. Default: max(1 MB, pool block size * EC part count).\n"
" --readonly\n"
" Make the device read-only.\n"
" --hdd\n"
" Mark the device as rotational.\n"
" --logfile /path/to/log/file.txt\n"
" Write log messages to the specified file instead of dropping them (in background mode)\n"
" or printing them to the standard output (in foreground mode).\n"
" --dev_num N\n"
" Use the specified device /dev/ublkbN instead of automatic selection (alternative syntax\n"
" to /dev/ublkbN positional parameter).\n"
" --foreground 1\n"
" Stay in foreground, do not daemonize.\n"
"\n"
"vitastor-ublk unmap [--force] /dev/ublkb<N>\n"
" Unmap a Vitastor ublk device. Do not check if it's actually mapped if --force is specified.\n"
"\n"
"vitastor-ublk ls [--json]\n"
" List mapped Vitastor ublk devices, optionally in JSON format.\n"
"\n"
"Use vitastor-ublk --help <command> for command details or vitastor-ublk --help --all for all details.\n"
"\n"
"All usual Vitastor config options like --config_path <path_to_config> may also be specified in CLI.\n"
;
class ublk_server
{
protected:
std::string image_name;
uint64_t inode = 0;
uint64_t device_size = 0;
int req_dev_num = -1;
bool readonly = false;
bool hdd = false;
bool recover = false;
uint16_t queue_depth = 256;
uint32_t max_io_size = 0;
ring_loop_t *ringloop = NULL;
epoll_manager_t *epmgr = NULL;
cluster_client_t *cli = NULL;
inode_watch_t *watch = NULL;
std::string logfile = "/dev/null";
public:
ublk_server()
{
ringloop = new ring_loop_t(RINGLOOP_DEFAULT_SIZE, false, true);
}
~ublk_server()
{
if (ctrl_fd >= 0)
{
close(ctrl_fd);
ctrl_fd = -1;
}
if (cdev_fd >= 0)
{
close(cdev_fd);
cdev_fd = -1;
}
for (auto & buf: buffers)
{
free(buf);
}
buffers.clear();
if (ringloop)
{
delete ringloop;
ringloop = NULL;
}
}
static json11::Json::object parse_args(int narg, const char *args[])
{
json11::Json::object cfg;
int pos = 0;
for (int i = 1; i < narg; i++)
{
if (!strcmp(args[i], "-h") || !strcmp(args[i], "--help"))
{
cfg["help"] = 1;
}
else if (args[i][0] == '-' && args[i][1] == '-')
{
const char *opt = args[i]+2;
cfg[opt] = !strcmp(opt, "json") || !strcmp(opt, "all") ||
!strcmp(opt, "readonly") || !strcmp(opt, "hdd") || !strcmp(opt, "recover") ||
!strcmp(opt, "force") || i == narg-1 ? "1" : args[++i];
}
else if (pos == 0)
{
cfg["command"] = args[i];
pos++;
}
else if (pos == 1)
{
char c = 0;
int n = 0;
if (sscanf(args[i], "/dev/ublkb%d%c", &n, &c) == 1)
cfg["dev_num"] = n;
else if (sscanf(args[i], "/dev/ublkc%d%c", &n, &c) == 1)
cfg["dev_num"] = n;
else
cfg["dev_num"] = args[i];
pos++;
}
}
return cfg;
}
void exec(json11::Json cfg)
{
if (cfg["help"].bool_value())
{
goto help;
}
if (cfg["command"] == "map")
{
start(cfg);
}
else if (cfg["command"] == "unmap")
{
if (!cfg["dev_num"].is_number() &&
cfg["dev_num"].string_value() != "0" &&
!cfg["dev_num"].uint64_value())
{
fprintf(stderr, "device name or number is missing\n");
exit(1);
}
open_control();
unmap_device(cfg["dev_num"].uint64_value(), cfg["unpriv"].bool_value(), cfg["wait"].bool_value());
}
else if (cfg["command"] == "ls" || cfg["command"] == "list" || cfg["command"] == "list-mapped")
{
auto mapped = list_mapped();
print_mapped(mapped, !cfg["json"].is_null());
}
else
{
help:
print_help(help_text, "vitastor-ublk", cfg["command"].string_value(), cfg["all"].bool_value());
exit(0);
}
}
void start(json11::Json cfg)
{
// Check options
if (cfg["dev_num"].string_value() != "" || cfg["dev_num"].is_number())
{
req_dev_num = cfg["dev_num"].uint64_value();
}
if (cfg["image"].string_value() != "")
{
// Use image name
image_name = cfg["image"].string_value();
inode = 0;
}
else
{
// Use pool, inode number and size
device_size = cfg["size"].is_string()
? parse_size(cfg["size"].string_value())
: cfg["size"].uint64_value();
if (!device_size)
{
fprintf(stderr, "device size is missing\n");
exit(1);
}
inode = cfg["inode"].uint64_value();
uint64_t pool = cfg["pool"].uint64_value();
if (pool)
{
inode = INODE_WITH_POOL(pool, inode);
}
if (!INODE_POOL(inode))
{
fprintf(stderr, "pool is missing\n");
exit(1);
}
}
if (cfg["client_writeback_allowed"].is_null())
{
// ublk is always aware of fsync, so we allow write-back cache
// by default if it's enabled
auto obj = cfg.object_items();
obj["client_writeback_allowed"] = true;
cfg = obj;
}
readonly = cfg["readonly"].bool_value();
hdd = cfg["hdd"].bool_value();
recover = cfg["recover"].bool_value();
if (recover && req_dev_num < 0)
{
fprintf(stderr, "device is missing\n");
exit(1);
}
// Create client
epmgr = new epoll_manager_t(ringloop);
cli = new cluster_client_t(ringloop, epmgr->tfd, cfg);
// cli->config contains merged config
if (!cfg["queue_depth"].is_null())
{
queue_depth = cfg["queue_depth"].uint64_value();
}
else if (cli->config.find("ublk_queue_depth") != cli->config.end())
{
queue_depth = cli->config["ublk_queue_depth"].uint64_value();
}
if (!cfg["max_io_size"].is_null())
{
max_io_size = parse_size(cfg["max_io_size"].string_value());
}
else if (cli->config.find("ublk_max_io_size") != cli->config.end())
{
max_io_size = cli->config["ublk_max_io_size"].is_string()
? parse_size(cli->config["ublk_max_io_size"].string_value())
: cli->config["ublk_max_io_size"].uint64_value();
}
// Load image metadata
while (!cli->is_ready())
{
ringloop->loop();
if (cli->is_ready())
break;
ringloop->wait();
}
if (!inode)
{
watch = cli->st_cli.watch_inode(image_name);
device_size = watch->cfg.size;
if (!watch->cfg.num || !device_size)
{
// Image does not exist
fprintf(stderr, "Image %s does not exist\n", image_name.c_str());
exit(1);
}
}
const bool writeback = cli->get_immediate_commit(inode);
auto pool_it = cli->st_cli.pool_config.find(INODE_POOL(inode ? inode : watch->cfg.num));
if (pool_it == cli->st_cli.pool_config.end())
{
fprintf(stderr, "Pool %u does not exist\n", INODE_POOL(inode ? inode : watch->cfg.num));
exit(1);
}
auto & pool_cfg = pool_it->second;
uint32_t pg_data_size = pool_cfg.data_block_size * (pool_cfg.scheme == POOL_SCHEME_REPLICATED
? 1 : pool_cfg.pg_size-pool_cfg.parity_chunks);
if (max_io_size & (max_io_size-1))
{
fprintf(stderr, "max_io_size must be a power of 2\n");
exit(1);
}
uint32_t buf_size = max_io_size ? max_io_size : (1024*1024 < pg_data_size ? pg_data_size : 1024*1024);
uint32_t bitmap_granularity = pool_cfg.bitmap_granularity;
load_module();
bool bg = cfg["foreground"].is_null();
if (cfg["logfile"].string_value() != "")
{
logfile = cfg["logfile"].string_value();
}
open_control();
if (recover)
{
recover_device(req_dev_num);
}
else
{
add_device(
req_dev_num,
(writeback ? UBLK_ATTR_VOLATILE_CACHE : 0) |
(readonly ? UBLK_ATTR_READ_ONLY : 0) | (hdd ? UBLK_ATTR_ROTATIONAL : 0),
queue_depth, bitmap_granularity, buf_size, pg_data_size, device_size
);
}
int notifyfd[2] = { -1, -1 };
if (bg)
{
if (socketpair(AF_UNIX, SOCK_STREAM, 0, notifyfd) < 0)
{
perror("socketpair");
exit(1);
}
daemonize_fork(notifyfd);
close(notifyfd[0]);
}
start_device(recover);
if (bg)
{
daemonize_reopen_stdio();
int ok = 0;
write(notifyfd[1], &ok, sizeof(ok));
close(notifyfd[1]);
}
else
printf("/dev/ublkb%d\n", ublk_dev.dev_id);
stop = false;
while (!stop)
{
ringloop->loop();
ringloop->wait();
}
cluster_op_t *close_sync = new cluster_op_t;
close_sync->opcode = OSD_OP_SYNC;
close_sync->callback = [this](cluster_op_t *op)
{
stop = true;
delete op;
};
cli->execute(close_sync);
while (!stop)
{
ringloop->loop();
ringloop->wait();
}
cli->flush();
delete cli;
delete epmgr;
cli = NULL;
epmgr = NULL;
}
void load_module()
{
if (access("/sys/module/ublk_drv", F_OK) == 0)
{
return;
}
int r;
if ((r = system("modprobe ublk_drv")) != 0)
{
if (r < 0)
perror("Failed to load ublk_drv kernel module");
else
fprintf(stderr, "Failed to load ublk_drv kernel module\n");
exit(1);
}
}
void daemonize_fork(int *notifyfd)
{
if (fork())
{
// Parent - check status
close(notifyfd[1]);
int child_errno = 1;
read(notifyfd[0], &child_errno, sizeof(child_errno));
if (!child_errno)
printf("/dev/ublkb%d\n", ublk_dev.dev_id);
exit(child_errno);
}
setsid();
if (fork())
exit(0);
}
void daemonize_reopen_stdio()
{
close(0);
close(1);
close(2);
open("/dev/null", O_RDONLY);
open(logfile.c_str(), O_WRONLY|O_APPEND|O_CREAT, 0666);
open(logfile.c_str(), O_WRONLY|O_APPEND|O_CREAT, 0666);
if (chdir("/") != 0)
fprintf(stderr, "Warning: Failed to chdir into /\n");
}
json11::Json::object list_mapped()
{
int n_in_dev = 0;
DIR *d = opendir("/dev");
if (!d)
{
fprintf(stderr, "Failed to list /dev: %s (code %d)\n", strerror(errno), errno);
exit(1);
}
dirent *ent;
while ((ent = readdir(d)) != NULL)
{
if (!strncmp(ent->d_name, "ublkc", strlen("ublkc")))
n_in_dev++;
}
closedir(d);
json11::Json::object mapped;
const char *self_filename = exe_name;
for (int i = 0; exe_name[i] != 0; i++)
{
if (exe_name[i] == '/')
self_filename = exe_name+i+1;
}
char path[64] = { 0 };
int dev_num = -1, n_in_ctrl = 0;
open_control();
while (true)
{
dev_num++;
int res = get_dev_info(dev_num, false);
if (res == -ENODEV)
{
if (n_in_ctrl >= n_in_dev)
break;
continue;
}
n_in_ctrl++;
sprintf(path, "/proc/%d/cmdline", ublk_dev.ublksrv_pid);
std::string cmdline = read_file(path);
if (cmdline == "")
{
// Process is dead
mapped["/dev/ublkb"+std::to_string(dev_num)] = json11::Json::object{{"dead", true}};
continue;
}
std::vector<const char*> argv;
int last = 0;
for (int i = 0; i < cmdline.size(); i++)
{
if (cmdline[i] == 0)
{
argv.push_back(cmdline.c_str()+last);
last = i+1;
}
}
if (argv.size() > 0)
{
const char *pid_filename = argv[0];
for (int i = 0; argv[0][i] != 0; i++)
{
if (argv[0][i] == '/')
pid_filename = argv[0]+i+1;
}
if (!strcmp(pid_filename, self_filename))
{
json11::Json::object cfg = ublk_server::parse_args(argv.size(), argv.data());
if (cfg["command"] == "map")
{
cfg.erase("command");
cfg["pid"] = ublk_dev.ublksrv_pid;
mapped["/dev/ublkb"+std::to_string(dev_num)] = cfg;
}
}
}
}
return mapped;
}
void print_mapped(json11::Json mapped, bool json)
{
if (json)
{
printf("%s\n", mapped.dump().c_str());
}
else
{
for (auto & dev: mapped.object_items())
{
printf("%s\n", dev.first.c_str());
for (auto & k: dev.second.object_items())
{
printf("%s: %s\n", k.first.c_str(), k.second.as_string().c_str());
}
printf("\n");
}
}
}
std::string read_file(char *path)
{
int fd = open(path, O_RDONLY);
if (fd < 0)
{
if (errno == ENOENT)
return "";
auto err = "open "+std::string(path);
perror(err.c_str());
exit(1);
}
std::string r;
while (true)
{
int l = r.size();
r.resize(l + 1024);
int rd = read(fd, (void*)(r.c_str() + l), 1024);
if (rd <= 0)
{
r.resize(l);
break;
}
r.resize(l + rd);
}
close(fd);
return r;
}
protected:
bool stop = false;
bool new_opcodes = true;
uint64_t ublk_features = 0;
int max_wait_time_ms = 5000;
int ctrl_fd = -1, cdev_fd = -1;
ublksrv_ctrl_dev_info ublk_dev = {};
ublksrv_io_desc *ublk_queue = NULL;
std::vector<uint8_t*> buffers;
void open_control()
{
ctrl_fd = open("/dev/ublk-control", O_RDWR);
if (ctrl_fd < 0)
{
fprintf(stderr, "Failed to open /dev/ublk-control: %s (code %d)\n", strerror(errno), errno);
exit(1);
}
// Check features
int res = sync_ublk_cmd(UBLK_U_CMD_GET_FEATURES, &ublk_features, 8, 0);
if (res == -EOPNOTSUPP)
{
new_opcodes = false;
}
else if (res != 0)
{
fprintf(stderr, "Failed to get ublk features: %s (code %d)\n", strerror(-res), res);
exit(1);
}
}
void add_device(int32_t dev_num, uint32_t attrs, uint16_t queue_depth, uint32_t phys_block_size,
uint32_t max_io_buf_bytes, uint64_t opt_block_size, uint64_t device_size)
{
// Add device
ublk_dev.dev_id = dev_num;
ublk_dev.nr_hw_queues = 1;
ublk_dev.queue_depth = queue_depth;
ublk_dev.max_io_buf_bytes = max_io_buf_bytes;
ublk_dev.flags = UBLK_F_USER_RECOVERY | UBLK_F_USER_RECOVERY_REISSUE;
int res = sync_ublk_cmd(new_opcodes ? UBLK_U_CMD_ADD_DEV : UBLK_CMD_ADD_DEV, &ublk_dev, sizeof(ublk_dev));
if (res != 0)
{
fprintf(stderr, "Failed to add ublk device: %s (code %d)\n", strerror(-res), res);
exit(1);
}
// Wait until the device appears
std::string ublkc_path = "/dev/ublkc"+std::to_string(ublk_dev.dev_id);
int wait_time = 0;
while (wait_time < max_wait_time_ms)
{
cdev_fd = open(ublkc_path.c_str(), O_RDWR);
if (cdev_fd >= 0)
break;
else if (errno != ENOENT)
{
fprintf(stderr, "Failed to open %s: %s (code %d)", ublkc_path.c_str(), strerror(errno), errno);
exit(1);
}
usleep(100);
wait_time += 100;
}
close(cdev_fd);
cdev_fd = -1;
// Set device params
uint8_t io_opt_shift = 0;
while ((opt_block_size >> io_opt_shift) > 1)
{
io_opt_shift++;
}
uint8_t phys_shift = 0;
while ((phys_block_size >> phys_shift) > 1)
{
phys_shift++;
}
ublk_params params = {
.len = sizeof(ublk_params),
.types = UBLK_PARAM_TYPE_BASIC,
.basic = {
.attrs = attrs, // UBLK_ATTR_READ_ONLY | UBLK_ATTR_ROTATIONAL | UBLK_ATTR_VOLATILE_CACHE | UBLK_ATTR_FUA
.logical_bs_shift = 9,
.physical_bs_shift = phys_shift,
.io_opt_shift = io_opt_shift,
.io_min_shift = phys_shift,
.max_sectors = max_io_buf_bytes / phys_block_size,
.chunk_sectors = 0,
.dev_sectors = device_size / phys_block_size,
.virt_boundary_mask = 0,
},
.discard = {
.discard_alignment = 0,
.discard_granularity = 0,
.max_discard_sectors = 0,
.max_write_zeroes_sectors = 0,
.max_discard_segments = 0,
},
};
res = sync_unpriv_cmd(false, new_opcodes ? UBLK_U_CMD_SET_PARAMS : UBLK_CMD_SET_PARAMS, &params, sizeof(params));
if (res != 0)
{
fprintf(stderr, "Failed to set ublk device params: %s (code %d)\n", strerror(-res), res);
exit(1);
}
}
void map_ublk_queue()
{
const unsigned page_sz = getpagesize();
size_t cmd_buf_size = (ublk_dev.queue_depth * sizeof(ublksrv_io_desc) + page_sz-1) / page_sz * page_sz;
//const unsigned queue_offset = (UBLK_MAX_QUEUE_DEPTH * sizeof(ublksrv_io_desc) + page_sz-1) / page_sz * page_sz;
//off = q_id * queue_offset;
ublk_queue = (ublksrv_io_desc*)mmap(0, cmd_buf_size, PROT_READ, MAP_SHARED | MAP_POPULATE, cdev_fd, 0);
if ((void*)ublk_queue == MAP_FAILED)
{
fprintf(stderr, "Failed to mmap() ublk queue buffer\n");
exit(1);
}
}
void recover_device(uint32_t dev_num)
{
ublk_dev.dev_id = dev_num;
int res = sync_ublk_cmd(new_opcodes ? UBLK_U_CMD_GET_DEV_INFO : UBLK_CMD_GET_DEV_INFO, &ublk_dev, sizeof(ublk_dev));
if (res != 0)
{
fprintf(stderr, "Failed to get /dev/ublkb%u device info: %s (code %d)\n", dev_num, strerror(-res), res);
exit(1);
}
if (ublk_dev.nr_hw_queues != 1)
{
fprintf(stderr, "Device /dev/ublkb%u is not supported because it has %d queues\n", dev_num, ublk_dev.nr_hw_queues);
exit(1);
}
if (ublk_dev.ublksrv_pid != 0)
{
res = kill(ublk_dev.ublksrv_pid, 0);
if (res == 0)
{
fprintf(stderr, "Device /dev/ublkb%u is still alive, daemon PID is %u\n", dev_num, ublk_dev.ublksrv_pid);
exit(1);
}
else if (errno != ESRCH)
{
fprintf(stderr, "Device /dev/ublkb%u is still alive, failed to check if the daemon with PID %u is running: %s (code %d)\n",
dev_num, ublk_dev.ublksrv_pid, strerror(errno), errno);
exit(1);
}
}
// Send the "start recovery" command
res = sync_unpriv_cmd(false, new_opcodes ? UBLK_U_CMD_START_USER_RECOVERY : UBLK_CMD_START_USER_RECOVERY, NULL, 0);
if (res != 0)
{
fprintf(stderr, "Failed to start /dev/ublkb%u device recovery: %s (code %d)\n", dev_num, strerror(-res), res);
exit(1);
}
}
void start_device(bool recover)
{
std::string ublkc_path = "/dev/ublkc"+std::to_string(ublk_dev.dev_id);
cdev_fd = open(ublkc_path.c_str(), O_RDWR|O_NONBLOCK);
if (cdev_fd < 0)
{
fprintf(stderr, "Failed to open %s: %s (code %d)", ublkc_path.c_str(), strerror(errno), errno);
exit(1);
}
// FIXME Here we could optionally do ublk_get_queue_affinity
// Map queue command buffer
map_ublk_queue();
// submit initial fetch requests to ublk driver
for (int i = 0; i < ublk_dev.queue_depth; i++)
{
buffers.push_back((uint8_t*)memalign_or_die(MEM_ALIGNMENT, ublk_dev.max_io_buf_bytes));
submit_request(new_opcodes ? UBLK_U_IO_FETCH_REQ : UBLK_IO_FETCH_REQ, i, 0);
}
ringloop->submit();
// start device
ublk_dev.ublksrv_pid = getpid();
int res = sync_unpriv_cmd(false, (recover
? (new_opcodes ? UBLK_U_CMD_END_USER_RECOVERY : UBLK_CMD_END_USER_RECOVERY)
: (new_opcodes ? UBLK_U_CMD_START_DEV : UBLK_CMD_START_DEV)), NULL, 0, ublk_dev.ublksrv_pid);
if (res != 0)
{
fprintf(stderr, "Failed to start ublk device: %s (code %d)\n", strerror(-res), res);
exit(1);
}
close(ctrl_fd);
ctrl_fd = -1;
}
void submit_request(uint64_t ublk_cmd, int i, int res)
{
io_uring_sqe *sqe = ringloop->get_sqe();
ring_data_t* data = ((ring_data_t*)sqe->user_data);
sqe->fd = cdev_fd;
sqe->opcode = IORING_OP_URING_CMD;
//sqe->flags = IOSQE_FIXED_FILE;
sqe->flags = 0;
sqe->rw_flags = 0;
sqe->off = ublk_cmd;
ublksrv_io_cmd *cmd = (ublksrv_io_cmd *)&sqe->addr3; // sqe128 command buffer address
cmd->q_id = 0;
cmd->tag = i;
cmd->addr = (uint64_t)buffers[i];
cmd->result = res;
data->callback = [this, i](ring_data_t *data) { exec_request(data->res, i); };
}
void exec_request(int res, int i)
{
if (res != 0)
{
// Note: res may be also UBLK_IO_RES_NEED_GET_DATA if UBLK_F_NEED_GET_DATA is enabled,
// in this case you should submit_request(UBLK_IO_NEED_GET_DATA, i) again with buffer
if (res == -ENODEV)
{
// ublk device is removed
stop = true;
return;
}
fprintf(stderr, "Fetching ublk request failed: %s (code %d)\n", strerror(-res), res);
exit(1);
}
ublksrv_io_desc *iod = &ublk_queue[i];
uint8_t opcode = ublksrv_get_op(iod);
if (opcode == UBLK_IO_OP_FLUSH)
{
cluster_op_t *op = new cluster_op_t;
op->opcode = OSD_OP_SYNC;
op->callback = [this, i](cluster_op_t *op)
{
submit_request(new_opcodes ? UBLK_U_IO_COMMIT_AND_FETCH_REQ : UBLK_IO_COMMIT_AND_FETCH_REQ, i, op->retval);
delete op;
};
cli->execute(op);
}
else if (opcode == UBLK_IO_OP_WRITE_ZEROES || opcode == UBLK_IO_OP_DISCARD)
{
submit_request(new_opcodes ? UBLK_U_IO_COMMIT_AND_FETCH_REQ : UBLK_IO_COMMIT_AND_FETCH_REQ, i, -EINVAL);
}
else if (opcode == UBLK_IO_OP_READ || opcode == UBLK_IO_OP_WRITE)
{
cluster_op_t *op = new cluster_op_t;
op->opcode = opcode == UBLK_IO_OP_READ ? OSD_OP_READ : OSD_OP_WRITE;
op->inode = inode ? inode : watch->cfg.num;
op->offset = iod->start_sector * 512;
op->len = iod->nr_sectors * 512;
op->iov.push_back(buffers[i], op->len);
op->callback = [this, i](cluster_op_t *op)
{
submit_request(new_opcodes ? UBLK_U_IO_COMMIT_AND_FETCH_REQ : UBLK_IO_COMMIT_AND_FETCH_REQ, i, op->retval);
delete op;
};
cli->execute(op);
}
else
{
submit_request(new_opcodes ? UBLK_U_IO_COMMIT_AND_FETCH_REQ : UBLK_IO_COMMIT_AND_FETCH_REQ, i, -EINVAL);
}
}
int get_dev_info(int dev_num, bool unpriv)
{
// Get device info
ublk_dev.dev_id = dev_num;
int res = unpriv
? sync_unpriv_cmd(true, new_opcodes ? UBLK_U_CMD_GET_DEV_INFO2 : UBLK_CMD_GET_DEV_INFO2, &ublk_dev, sizeof(ublk_dev))
: sync_ublk_cmd(new_opcodes ? UBLK_U_CMD_GET_DEV_INFO : UBLK_CMD_GET_DEV_INFO, &ublk_dev, sizeof(ublk_dev));
if (res != 0 && res != -ENODEV)
{
fprintf(stderr, "Failed to get device info from /dev/ublkc%d: %s (code %d)\n", dev_num, strerror(-res), res);
exit(1);
}
return res;
}
void unmap_device(int dev_num, bool unpriv, bool wait)
{
int res = 0;
// Stop the device
ublk_dev.dev_id = dev_num;
res = sync_unpriv_cmd(unpriv, new_opcodes ? UBLK_U_CMD_STOP_DEV : UBLK_CMD_STOP_DEV, NULL, 0);
if (res != 0)
{
fprintf(stderr, "Failed to stop device /dev/ublkc%d: %s (code %d)\n", dev_num, strerror(-res), res);
exit(1);
}
// Delete the device
res = sync_unpriv_cmd(unpriv, new_opcodes ? (wait ? UBLK_U_CMD_DEL_DEV : UBLK_U_CMD_DEL_DEV_ASYNC) : UBLK_CMD_DEL_DEV, NULL, 0);
if (res != 0)
{
fprintf(stderr, "Failed to delete device /dev/ublkc%d: %s (code %d)\n", dev_num, strerror(-res), res);
exit(1);
}
}
int sync_unpriv_cmd(bool unpriv, uint32_t cmd_op, void *addr, uint32_t len, uint64_t data0 = 0)
{
int res;
if (unpriv)
{
static const int path_max = 64;
char buf[path_max + len];
memset(buf, 0, path_max);
memcpy(buf + path_max, addr, len);
snprintf(buf, path_max, "/dev/ublkc%d", ublk_dev.dev_id);
res = sync_ublk_cmd(cmd_op, buf, sizeof(buf), path_max, data0);
if (!res)
memcpy(addr, buf + path_max, len);
}
else
{
res = sync_ublk_cmd(cmd_op, addr, len, 0, data0);
}
return res;
}
int sync_ublk_cmd(uint32_t cmd_op, void *addr, uint32_t len, uint16_t dev_path_len = 0, uint64_t data0 = 0)
{
io_uring_sqe *sqe = ringloop->get_sqe();
sqe->fd = ctrl_fd;
sqe->opcode = IORING_OP_URING_CMD;
sqe->ioprio = 0;
sqe->off = cmd_op;
ublksrv_ctrl_cmd *cmd = (ublksrv_ctrl_cmd *)&sqe->addr3; // sqe128 command buffer address
cmd->dev_id = ublk_dev.dev_id;
cmd->queue_id = -1;
cmd->addr = (uint64_t)addr;
cmd->len = len;
cmd->data[0] = data0;
cmd->dev_path_len = dev_path_len;
ring_data_t* data = ((ring_data_t*)sqe->user_data);
bool done = false;
int res = 0;
data->callback = [&](ring_data_t *data)
{
res = data->res;
done = true;
};
ringloop->submit();
while (!done)
{
ringloop->loop();
if (!done)
ringloop->wait();
}
return res;
}
};
int main(int narg, const char *args[])
{
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
exe_name = args[0];
ublk_server *p = new ublk_server();
p->exec(ublk_server::parse_args(narg, args));
delete p;
return 0;
}
+1 -1
View File
@@ -6,7 +6,7 @@ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
Name: Vitastor Name: Vitastor
Description: Vitastor client library Description: Vitastor client library
Version: 2.2.3 Version: 2.3.0
Libs: -L${libdir} -lvitastor_client Libs: -L${libdir} -lvitastor_client
Cflags: -I${includedir} Cflags: -I${includedir}
+4
View File
@@ -22,6 +22,8 @@
#include <stdint.h> #include <stdint.h>
#include <sys/uio.h> #include <sys/uio.h>
#pragma GCC visibility push(default)
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@@ -85,4 +87,6 @@ uint32_t vitastor_c_inode_get_immediate_commit(vitastor_c *client, uint64_t inod
} }
#endif #endif
#pragma GCC visibility pop
#endif #endif
+2 -2
View File
@@ -540,7 +540,7 @@ struct cli_dd_t
} }
ring_data_t *data = ((ring_data_t*)sqe->user_data); ring_data_t *data = ((ring_data_t*)sqe->user_data);
data->iov = (iovec){ (uint8_t*)cur_read->buf + cur_read->len, cur_read->max - cur_read->len }; data->iov = (iovec){ (uint8_t*)cur_read->buf + cur_read->len, cur_read->max - cur_read->len };
my_uring_prep_readv(sqe, iinfo.ifd, &data->iov, 1, iinfo.in_seekable ? iseek + cur_read->offset + cur_read->len : -1); io_uring_prep_readv(sqe, iinfo.ifd, &data->iov, 1, iinfo.in_seekable ? iseek + cur_read->offset + cur_read->len : -1);
in_waiting++; in_waiting++;
data->callback = [this, cur_read](ring_data_t *data) data->callback = [this, cur_read](ring_data_t *data)
{ {
@@ -673,7 +673,7 @@ struct cli_dd_t
} }
ring_data_t *data = ((ring_data_t*)sqe->user_data); ring_data_t *data = ((ring_data_t*)sqe->user_data);
data->iov = (iovec){ .iov_base = (uint8_t*)cur_read->buf+cur_read->len, .iov_len = cur_read->max-cur_read->len }; data->iov = (iovec){ .iov_base = (uint8_t*)cur_read->buf+cur_read->len, .iov_len = cur_read->max-cur_read->len };
my_uring_prep_writev(sqe, oinfo.ofd, &data->iov, 1, oinfo.out_seekable ? cur_read->offset+cur_read->len+oseek : -1); io_uring_prep_writev(sqe, oinfo.ofd, &data->iov, 1, oinfo.out_seekable ? cur_read->offset+cur_read->len+oseek : -1);
out_waiting++; out_waiting++;
data->callback = [this, cur_read](ring_data_t *data) data->callback = [this, cur_read](ring_data_t *data)
{ {
+1
View File
@@ -12,4 +12,5 @@ add_executable(vitastor-disk
target_link_libraries(vitastor-disk target_link_libraries(vitastor-disk
tcmalloc_minimal tcmalloc_minimal
${LIBURING_LIBRARIES} ${LIBURING_LIBRARIES}
${ISAL_LIBRARIES}
) )
+2
View File
@@ -9,6 +9,8 @@
int disk_tool_t::prepare_one(std::map<std::string, std::string> options, int is_hdd, json11::Json::object & result) int disk_tool_t::prepare_one(std::map<std::string, std::string> options, int is_hdd, json11::Json::object & result)
{ {
static const char *allow_additional_params[] = { static const char *allow_additional_params[] = {
"data_csum_type",
"csum_block_size",
"autosync_writes", "autosync_writes",
"data_io", "data_io",
"meta_io", "meta_io",
+2 -2
View File
@@ -294,7 +294,7 @@ int disk_tool_t::resize_copy_data()
moving_blocks[i].state = DM_ST_READING; moving_blocks[i].state = DM_ST_READING;
struct ring_data_t *data = ((ring_data_t*)sqe->user_data); struct ring_data_t *data = ((ring_data_t*)sqe->user_data);
data->iov = (struct iovec){ moving_blocks[i].buf, dsk.data_block_size }; data->iov = (struct iovec){ moving_blocks[i].buf, dsk.data_block_size };
my_uring_prep_readv(sqe, dsk.data_fd, &data->iov, 1, dsk.data_offset + moving_blocks[i].old_loc*dsk.data_block_size); io_uring_prep_readv(sqe, dsk.data_fd, &data->iov, 1, dsk.data_offset + moving_blocks[i].old_loc*dsk.data_block_size);
data->callback = [this, i](ring_data_t *data) data->callback = [this, i](ring_data_t *data)
{ {
if (data->res != dsk.data_block_size) if (data->res != dsk.data_block_size)
@@ -319,7 +319,7 @@ int disk_tool_t::resize_copy_data()
moving_blocks[i].state = DM_ST_WRITING; moving_blocks[i].state = DM_ST_WRITING;
struct ring_data_t *data = ((ring_data_t*)sqe->user_data); struct ring_data_t *data = ((ring_data_t*)sqe->user_data);
data->iov = (struct iovec){ moving_blocks[i].buf, dsk.data_block_size }; data->iov = (struct iovec){ moving_blocks[i].buf, dsk.data_block_size };
my_uring_prep_writev(sqe, dsk.data_fd, &data->iov, 1, dsk.data_offset + moving_blocks[i].new_loc*dsk.data_block_size); io_uring_prep_writev(sqe, dsk.data_fd, &data->iov, 1, dsk.data_offset + moving_blocks[i].new_loc*dsk.data_block_size);
data->callback = [this, i](ring_data_t *data) data->callback = [this, i](ring_data_t *data)
{ {
if (data->res != dsk.data_block_size) if (data->res != dsk.data_block_size)
+1 -1
View File
@@ -19,7 +19,7 @@ class cluster_client_t;
struct kv_db_t; struct kv_db_t;
struct vitastorkv_dbw_t struct __attribute__((visibility("default"))) vitastorkv_dbw_t
{ {
// cli = vitastor_c_get_internal_client(client) // cli = vitastor_c_get_internal_client(client)
vitastorkv_dbw_t(cluster_client_t *cli); vitastorkv_dbw_t(cluster_client_t *cli);
+10
View File
@@ -0,0 +1,10 @@
cmake_minimum_required(VERSION 2.8.12)
project(vitastor)
# liburing.a
add_library(uring STATIC
queue.c register.c setup.c syscall.c version.c
)
target_compile_options(uring PUBLIC -fPIC)
target_compile_definitions(uring PUBLIC _GNU_SOURCE _LARGEFILE_SOURCE _FILE_OFFSET_BITS=64)
+20
View File
@@ -0,0 +1,20 @@
Copyright 2020 Jens Axboe
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+27
View File
@@ -0,0 +1,27 @@
liburing
--------
This is a copy if liburing 2.11 from https://github.com/axboe/liburing/
ublk_cmd.h is a copy from https://github.com/ublk-org/ublksrv/blob/master/include/ublk_cmd.h
For more info on io_uring, please see:
https://kernel.dk/io_uring.pdf
Subscribe to io-uring@vger.kernel.org for io_uring related discussions
and development for both kernel and userspace. The list is archived here:
https://lore.kernel.org/io-uring/
License
-------
"This repo" refers to the current directory as it's a copy. :-)
All software contained within this repo is dual licensed LGPL and MIT, see
COPYING and LICENSE, except for a header coming from the kernel which is
dual licensed GPL with a Linux-syscall-note exception and MIT, see
COPYING.GPL and <https://spdx.org/licenses/Linux-syscall-note.html>.
Jens Axboe 2022-05-19
+47
View File
@@ -0,0 +1,47 @@
/* SPDX-License-Identifier: MIT */
#ifndef LIBURING_ARCH_AARCH64_LIB_H
#define LIBURING_ARCH_AARCH64_LIB_H
#include <elf.h>
#include "../../syscall.h"
static inline long __get_page_size(void)
{
Elf64_Off buf[2];
long ret = 4096;
int fd;
fd = __sys_open("/proc/self/auxv", O_RDONLY, 0);
if (fd < 0)
return ret;
while (1) {
ssize_t x;
x = __sys_read(fd, buf, sizeof(buf));
if (x < (long) sizeof(buf))
break;
if (buf[0] == AT_PAGESZ) {
ret = buf[1];
break;
}
}
__sys_close(fd);
return ret;
}
static inline long get_page_size(void)
{
static long cache_val;
if (cache_val)
return cache_val;
cache_val = __get_page_size();
return cache_val;
}
#endif /* #ifndef LIBURING_ARCH_AARCH64_LIB_H */
+91
View File
@@ -0,0 +1,91 @@
/* SPDX-License-Identifier: MIT */
#ifndef LIBURING_ARCH_AARCH64_SYSCALL_H
#define LIBURING_ARCH_AARCH64_SYSCALL_H
#if defined(__aarch64__)
#define __do_syscallN(...) ({ \
__asm__ volatile ( \
"svc 0" \
: "=r"(x0) \
: __VA_ARGS__ \
: "memory", "cc"); \
(long) x0; \
})
#define __do_syscall0(__n) ({ \
register long x8 __asm__("x8") = __n; \
register long x0 __asm__("x0"); \
\
__do_syscallN("r" (x8)); \
})
#define __do_syscall1(__n, __a) ({ \
register long x8 __asm__("x8") = __n; \
register __typeof__(__a) x0 __asm__("x0") = __a; \
\
__do_syscallN("r" (x8), "0" (x0)); \
})
#define __do_syscall2(__n, __a, __b) ({ \
register long x8 __asm__("x8") = __n; \
register __typeof__(__a) x0 __asm__("x0") = __a; \
register __typeof__(__b) x1 __asm__("x1") = __b; \
\
__do_syscallN("r" (x8), "0" (x0), "r" (x1)); \
})
#define __do_syscall3(__n, __a, __b, __c) ({ \
register long x8 __asm__("x8") = __n; \
register __typeof__(__a) x0 __asm__("x0") = __a; \
register __typeof__(__b) x1 __asm__("x1") = __b; \
register __typeof__(__c) x2 __asm__("x2") = __c; \
\
__do_syscallN("r" (x8), "0" (x0), "r" (x1), "r" (x2)); \
})
#define __do_syscall4(__n, __a, __b, __c, __d) ({ \
register long x8 __asm__("x8") = __n; \
register __typeof__(__a) x0 __asm__("x0") = __a; \
register __typeof__(__b) x1 __asm__("x1") = __b; \
register __typeof__(__c) x2 __asm__("x2") = __c; \
register __typeof__(__d) x3 __asm__("x3") = __d; \
\
__do_syscallN("r" (x8), "0" (x0), "r" (x1), "r" (x2), "r" (x3));\
})
#define __do_syscall5(__n, __a, __b, __c, __d, __e) ({ \
register long x8 __asm__("x8") = __n; \
register __typeof__(__a) x0 __asm__("x0") = __a; \
register __typeof__(__b) x1 __asm__("x1") = __b; \
register __typeof__(__c) x2 __asm__("x2") = __c; \
register __typeof__(__d) x3 __asm__("x3") = __d; \
register __typeof__(__e) x4 __asm__("x4") = __e; \
\
__do_syscallN("r" (x8), "0" (x0), "r" (x1), "r" (x2), "r" (x3), \
"r"(x4)); \
})
#define __do_syscall6(__n, __a, __b, __c, __d, __e, __f) ({ \
register long x8 __asm__("x8") = __n; \
register __typeof__(__a) x0 __asm__("x0") = __a; \
register __typeof__(__b) x1 __asm__("x1") = __b; \
register __typeof__(__c) x2 __asm__("x2") = __c; \
register __typeof__(__d) x3 __asm__("x3") = __d; \
register __typeof__(__e) x4 __asm__("x4") = __e; \
register __typeof__(__f) x5 __asm__("x5") = __f; \
\
__do_syscallN("r" (x8), "0" (x0), "r" (x1), "r" (x2), "r" (x3), \
"r" (x4), "r"(x5)); \
})
#include "../syscall-defs.h"
#else /* #if defined(__aarch64__) */
#include "../generic/syscall.h"
#endif /* #if defined(__aarch64__) */
#endif /* #ifndef LIBURING_ARCH_AARCH64_SYSCALL_H */
+17
View File
@@ -0,0 +1,17 @@
/* SPDX-License-Identifier: MIT */
#ifndef LIBURING_ARCH_GENERIC_LIB_H
#define LIBURING_ARCH_GENERIC_LIB_H
static inline long get_page_size(void)
{
long page_size;
page_size = sysconf(_SC_PAGESIZE);
if (page_size < 0)
page_size = 4096;
return page_size;
}
#endif /* #ifndef LIBURING_ARCH_GENERIC_LIB_H */
+100
View File
@@ -0,0 +1,100 @@
/* SPDX-License-Identifier: MIT */
#ifndef LIBURING_ARCH_GENERIC_SYSCALL_H
#define LIBURING_ARCH_GENERIC_SYSCALL_H
#include <fcntl.h>
static inline int __sys_io_uring_register(unsigned int fd, unsigned int opcode,
const void *arg, unsigned int nr_args)
{
int ret;
ret = syscall(__NR_io_uring_register, fd, opcode, arg, nr_args);
return (ret < 0) ? -errno : ret;
}
static inline int __sys_io_uring_setup(unsigned int entries,
struct io_uring_params *p)
{
int ret;
ret = syscall(__NR_io_uring_setup, entries, p);
return (ret < 0) ? -errno : ret;
}
static inline int __sys_io_uring_enter2(unsigned int fd, unsigned int to_submit,
unsigned int min_complete,
unsigned int flags, void *arg,
size_t sz)
{
int ret;
ret = syscall(__NR_io_uring_enter, fd, to_submit, min_complete, flags,
arg, sz);
return (ret < 0) ? -errno : ret;
}
static inline int __sys_io_uring_enter(unsigned int fd, unsigned int to_submit,
unsigned int min_complete,
unsigned int flags, sigset_t *sig)
{
return __sys_io_uring_enter2(fd, to_submit, min_complete, flags, sig,
_NSIG / 8);
}
static inline int __sys_open(const char *pathname, int flags, mode_t mode)
{
int ret;
ret = open(pathname, flags, mode);
return (ret < 0) ? -errno : ret;
}
static inline ssize_t __sys_read(int fd, void *buffer, size_t size)
{
ssize_t ret;
ret = read(fd, buffer, size);
return (ret < 0) ? -errno : ret;
}
static inline void *__sys_mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset)
{
void *ret;
ret = mmap(addr, length, prot, flags, fd, offset);
return (ret == MAP_FAILED) ? ERR_PTR(-errno) : ret;
}
static inline int __sys_munmap(void *addr, size_t length)
{
int ret;
ret = munmap(addr, length);
return (ret < 0) ? -errno : ret;
}
static inline int __sys_madvise(void *addr, size_t length, int advice)
{
int ret;
ret = madvise(addr, length, advice);
return (ret < 0) ? -errno : ret;
}
static inline int __sys_getrlimit(int resource, struct rlimit *rlim)
{
int ret;
ret = getrlimit(resource, rlim);
return (ret < 0) ? -errno : ret;
}
static inline int __sys_setrlimit(int resource, const struct rlimit *rlim)
{
int ret;
ret = setrlimit(resource, rlim);
return (ret < 0) ? -errno : ret;
}
static inline int __sys_close(int fd)
{
int ret;
ret = close(fd);
return (ret < 0) ? -errno : ret;
}
#endif /* #ifndef LIBURING_ARCH_GENERIC_SYSCALL_H */
+48
View File
@@ -0,0 +1,48 @@
/* SPDX-License-Identifier: MIT */
#ifndef LIBURING_ARCH_RISCV64_LIB_H
#define LIBURING_ARCH_RISCV64_LIB_H
#include <elf.h>
#include <sys/auxv.h>
#include "../../syscall.h"
static inline long __get_page_size(void)
{
Elf64_Off buf[2];
long ret = 4096;
int fd;
fd = __sys_open("/proc/self/auxv", O_RDONLY, 0);
if (fd < 0)
return ret;
while (1) {
ssize_t x;
x = __sys_read(fd, buf, sizeof(buf));
if (x < (long) sizeof(buf))
break;
if (buf[0] == AT_PAGESZ) {
ret = buf[1];
break;
}
}
__sys_close(fd);
return ret;
}
static inline long get_page_size(void)
{
static long cache_val;
if (cache_val)
return cache_val;
cache_val = __get_page_size();
return cache_val;
}
#endif /* #ifndef LIBURING_ARCH_RISCV64_LIB_H */
+100
View File
@@ -0,0 +1,100 @@
/* SPDX-License-Identifier: MIT */
#ifndef LIBURING_ARCH_RISCV64_SYSCALL_H
#define LIBURING_ARCH_RISCV64_SYSCALL_H
#if defined(__riscv) && __riscv_xlen == 64
#define __do_syscallM(...) ({ \
__asm__ volatile ( \
"ecall" \
: "=r"(a0) \
: __VA_ARGS__ \
: "memory", "a1"); \
(long) a0; \
})
#define __do_syscallN(...) ({ \
__asm__ volatile ( \
"ecall" \
: "=r"(a0) \
: __VA_ARGS__ \
: "memory"); \
(long) a0; \
})
#define __do_syscall0(__n) ({ \
register long a7 __asm__("a7") = __n; \
register long a0 __asm__("a0"); \
\
__do_syscallM("r" (a7)); \
})
#define __do_syscall1(__n, __a) ({ \
register long a7 __asm__("a7") = __n; \
register __typeof__(__a) a0 __asm__("a0") = __a; \
\
__do_syscallM("r" (a7), "0" (a0)); \
})
#define __do_syscall2(__n, __a, __b) ({ \
register long a7 __asm__("a7") = __n; \
register __typeof__(__a) a0 __asm__("a0") = __a; \
register __typeof__(__b) a1 __asm__("a1") = __b; \
\
__do_syscallN("r" (a7), "0" (a0), "r" (a1)); \
})
#define __do_syscall3(__n, __a, __b, __c) ({ \
register long a7 __asm__("a7") = __n; \
register __typeof__(__a) a0 __asm__("a0") = __a; \
register __typeof__(__b) a1 __asm__("a1") = __b; \
register __typeof__(__c) a2 __asm__("a2") = __c; \
\
__do_syscallN("r" (a7), "0" (a0), "r" (a1), "r" (a2)); \
})
#define __do_syscall4(__n, __a, __b, __c, __d) ({ \
register long a7 __asm__("a7") = __n; \
register __typeof__(__a) a0 __asm__("a0") = __a; \
register __typeof__(__b) a1 __asm__("a1") = __b; \
register __typeof__(__c) a2 __asm__("a2") = __c; \
register __typeof__(__d) a3 __asm__("a3") = __d; \
\
__do_syscallN("r" (a7), "0" (a0), "r" (a1), "r" (a2), "r" (a3));\
})
#define __do_syscall5(__n, __a, __b, __c, __d, __e) ({ \
register long a7 __asm__("a7") = __n; \
register __typeof__(__a) a0 __asm__("a0") = __a; \
register __typeof__(__b) a1 __asm__("a1") = __b; \
register __typeof__(__c) a2 __asm__("a2") = __c; \
register __typeof__(__d) a3 __asm__("a3") = __d; \
register __typeof__(__e) a4 __asm__("a4") = __e; \
\
__do_syscallN("r" (a7), "0" (a0), "r" (a1), "r" (a2), "r" (a3), \
"r"(a4)); \
})
#define __do_syscall6(__n, __a, __b, __c, __d, __e, __f) ({ \
register long a7 __asm__("a7") = __n; \
register __typeof__(__a) a0 __asm__("a0") = __a; \
register __typeof__(__b) a1 __asm__("a1") = __b; \
register __typeof__(__c) a2 __asm__("a2") = __c; \
register __typeof__(__d) a3 __asm__("a3") = __d; \
register __typeof__(__e) a4 __asm__("a4") = __e; \
register __typeof__(__f) a5 __asm__("a5") = __f; \
\
__do_syscallN("r" (a7), "0" (a0), "r" (a1), "r" (a2), "r" (a3), \
"r" (a4), "r"(a5)); \
})
#include "../syscall-defs.h"
#else /* #if defined(__riscv) && __riscv_xlen == 64 */
#include "../generic/syscall.h"
#endif /* #if defined(__riscv) && __riscv_xlen == 64 */
#endif /* #ifndef LIBURING_ARCH_RISCV64_SYSCALL_H */
+94
View File
@@ -0,0 +1,94 @@
/* SPDX-License-Identifier: MIT */
#ifndef LIBURING_ARCH_SYSCALL_DEFS_H
#define LIBURING_ARCH_SYSCALL_DEFS_H
#include <fcntl.h>
static inline int __sys_open(const char *pathname, int flags, mode_t mode)
{
/*
* Some architectures don't have __NR_open, but __NR_openat.
*/
#ifdef __NR_open
return (int) __do_syscall3(__NR_open, pathname, flags, mode);
#else
return (int) __do_syscall4(__NR_openat, AT_FDCWD, pathname, flags, mode);
#endif
}
static inline ssize_t __sys_read(int fd, void *buffer, size_t size)
{
return (ssize_t) __do_syscall3(__NR_read, fd, buffer, size);
}
static inline void *__sys_mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset)
{
int nr;
#if defined(__NR_mmap2)
nr = __NR_mmap2;
offset >>= 12;
#else
nr = __NR_mmap;
#endif
return (void *) __do_syscall6(nr, addr, length, prot, flags, fd, offset);
}
static inline int __sys_munmap(void *addr, size_t length)
{
return (int) __do_syscall2(__NR_munmap, addr, length);
}
static inline int __sys_madvise(void *addr, size_t length, int advice)
{
return (int) __do_syscall3(__NR_madvise, addr, length, advice);
}
static inline int __sys_getrlimit(int resource, struct rlimit *rlim)
{
return (int) __do_syscall2(__NR_getrlimit, resource, rlim);
}
static inline int __sys_setrlimit(int resource, const struct rlimit *rlim)
{
return (int) __do_syscall2(__NR_setrlimit, resource, rlim);
}
static inline int __sys_close(int fd)
{
return (int) __do_syscall1(__NR_close, fd);
}
static inline int __sys_io_uring_register(unsigned int fd, unsigned int opcode,
const void *arg, unsigned int nr_args)
{
return (int) __do_syscall4(__NR_io_uring_register, fd, opcode, arg,
nr_args);
}
static inline int __sys_io_uring_setup(unsigned int entries,
struct io_uring_params *p)
{
return (int) __do_syscall2(__NR_io_uring_setup, entries, p);
}
static inline int __sys_io_uring_enter2(unsigned int fd, unsigned int to_submit,
unsigned int min_complete,
unsigned int flags, void *arg,
size_t sz)
{
return (int) __do_syscall6(__NR_io_uring_enter, fd, to_submit,
min_complete, flags, arg, sz);
}
static inline int __sys_io_uring_enter(unsigned int fd, unsigned int to_submit,
unsigned int min_complete,
unsigned int flags, sigset_t *sig)
{
return __sys_io_uring_enter2(fd, to_submit, min_complete, flags, sig,
_NSIG / 8);
}
#endif
+11
View File
@@ -0,0 +1,11 @@
/* SPDX-License-Identifier: MIT */
#ifndef LIBURING_ARCH_X86_LIB_H
#define LIBURING_ARCH_X86_LIB_H
static inline long get_page_size(void)
{
return 4096;
}
#endif /* #ifndef LIBURING_ARCH_X86_LIB_H */
+296
View File
@@ -0,0 +1,296 @@
/* SPDX-License-Identifier: MIT */
#ifndef LIBURING_ARCH_X86_SYSCALL_H
#define LIBURING_ARCH_X86_SYSCALL_H
#if defined(__x86_64__)
/**
* Note for syscall registers usage (x86-64):
* - %rax is the syscall number.
* - %rax is also the return value.
* - %rdi is the 1st argument.
* - %rsi is the 2nd argument.
* - %rdx is the 3rd argument.
* - %r10 is the 4th argument (**yes it's %r10, not %rcx!**).
* - %r8 is the 5th argument.
* - %r9 is the 6th argument.
*
* `syscall` instruction will clobber %r11 and %rcx.
*
* After the syscall returns to userspace:
* - %r11 will contain %rflags.
* - %rcx will contain the return address.
*
* IOW, after the syscall returns to userspace:
* %r11 == %rflags and %rcx == %rip.
*/
#define __do_syscall0(NUM) ({ \
intptr_t rax; \
\
__asm__ volatile( \
"syscall" \
: "=a"(rax) /* %rax */ \
: "a"(NUM) /* %rax */ \
: "rcx", "r11", "memory" \
); \
rax; \
})
#define __do_syscall1(NUM, ARG1) ({ \
intptr_t rax; \
\
__asm__ volatile( \
"syscall" \
: "=a"(rax) /* %rax */ \
: "a"((NUM)), /* %rax */ \
"D"((ARG1)) /* %rdi */ \
: "rcx", "r11", "memory" \
); \
rax; \
})
#define __do_syscall2(NUM, ARG1, ARG2) ({ \
intptr_t rax; \
\
__asm__ volatile( \
"syscall" \
: "=a"(rax) /* %rax */ \
: "a"((NUM)), /* %rax */ \
"D"((ARG1)), /* %rdi */ \
"S"((ARG2)) /* %rsi */ \
: "rcx", "r11", "memory" \
); \
rax; \
})
#define __do_syscall3(NUM, ARG1, ARG2, ARG3) ({ \
intptr_t rax; \
\
__asm__ volatile( \
"syscall" \
: "=a"(rax) /* %rax */ \
: "a"((NUM)), /* %rax */ \
"D"((ARG1)), /* %rdi */ \
"S"((ARG2)), /* %rsi */ \
"d"((ARG3)) /* %rdx */ \
: "rcx", "r11", "memory" \
); \
rax; \
})
#define __do_syscall4(NUM, ARG1, ARG2, ARG3, ARG4) ({ \
intptr_t rax; \
register __typeof__(ARG4) __r10 __asm__("r10") = (ARG4); \
\
__asm__ volatile( \
"syscall" \
: "=a"(rax) /* %rax */ \
: "a"((NUM)), /* %rax */ \
"D"((ARG1)), /* %rdi */ \
"S"((ARG2)), /* %rsi */ \
"d"((ARG3)), /* %rdx */ \
"r"(__r10) /* %r10 */ \
: "rcx", "r11", "memory" \
); \
rax; \
})
#define __do_syscall5(NUM, ARG1, ARG2, ARG3, ARG4, ARG5) ({ \
intptr_t rax; \
register __typeof__(ARG4) __r10 __asm__("r10") = (ARG4); \
register __typeof__(ARG5) __r8 __asm__("r8") = (ARG5); \
\
__asm__ volatile( \
"syscall" \
: "=a"(rax) /* %rax */ \
: "a"((NUM)), /* %rax */ \
"D"((ARG1)), /* %rdi */ \
"S"((ARG2)), /* %rsi */ \
"d"((ARG3)), /* %rdx */ \
"r"(__r10), /* %r10 */ \
"r"(__r8) /* %r8 */ \
: "rcx", "r11", "memory" \
); \
rax; \
})
#define __do_syscall6(NUM, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) ({ \
intptr_t rax; \
register __typeof__(ARG4) __r10 __asm__("r10") = (ARG4); \
register __typeof__(ARG5) __r8 __asm__("r8") = (ARG5); \
register __typeof__(ARG6) __r9 __asm__("r9") = (ARG6); \
\
__asm__ volatile( \
"syscall" \
: "=a"(rax) /* %rax */ \
: "a"((NUM)), /* %rax */ \
"D"((ARG1)), /* %rdi */ \
"S"((ARG2)), /* %rsi */ \
"d"((ARG3)), /* %rdx */ \
"r"(__r10), /* %r10 */ \
"r"(__r8), /* %r8 */ \
"r"(__r9) /* %r9 */ \
: "rcx", "r11", "memory" \
); \
rax; \
})
#include "../syscall-defs.h"
#else /* #if defined(__x86_64__) */
#ifdef CONFIG_NOLIBC
/**
* Note for syscall registers usage (x86, 32-bit):
* - %eax is the syscall number.
* - %eax is also the return value.
* - %ebx is the 1st argument.
* - %ecx is the 2nd argument.
* - %edx is the 3rd argument.
* - %esi is the 4th argument.
* - %edi is the 5th argument.
* - %ebp is the 6th argument.
*/
#define __do_syscall0(NUM) ({ \
intptr_t eax; \
\
__asm__ volatile( \
"int $0x80" \
: "=a"(eax) /* %eax */ \
: "a"(NUM) /* %eax */ \
: "memory" \
); \
eax; \
})
#define __do_syscall1(NUM, ARG1) ({ \
intptr_t eax; \
\
__asm__ volatile( \
"int $0x80" \
: "=a"(eax) /* %eax */ \
: "a"(NUM), /* %eax */ \
"b"((ARG1)) /* %ebx */ \
: "memory" \
); \
eax; \
})
#define __do_syscall2(NUM, ARG1, ARG2) ({ \
intptr_t eax; \
\
__asm__ volatile( \
"int $0x80" \
: "=a" (eax) /* %eax */ \
: "a"(NUM), /* %eax */ \
"b"((ARG1)), /* %ebx */ \
"c"((ARG2)) /* %ecx */ \
: "memory" \
); \
eax; \
})
#define __do_syscall3(NUM, ARG1, ARG2, ARG3) ({ \
intptr_t eax; \
\
__asm__ volatile( \
"int $0x80" \
: "=a" (eax) /* %eax */ \
: "a"(NUM), /* %eax */ \
"b"((ARG1)), /* %ebx */ \
"c"((ARG2)), /* %ecx */ \
"d"((ARG3)) /* %edx */ \
: "memory" \
); \
eax; \
})
#define __do_syscall4(NUM, ARG1, ARG2, ARG3, ARG4) ({ \
intptr_t eax; \
\
__asm__ volatile( \
"int $0x80" \
: "=a" (eax) /* %eax */ \
: "a"(NUM), /* %eax */ \
"b"((ARG1)), /* %ebx */ \
"c"((ARG2)), /* %ecx */ \
"d"((ARG3)), /* %edx */ \
"S"((ARG4)) /* %esi */ \
: "memory" \
); \
eax; \
})
#define __do_syscall5(NUM, ARG1, ARG2, ARG3, ARG4, ARG5) ({ \
intptr_t eax; \
\
__asm__ volatile( \
"int $0x80" \
: "=a" (eax) /* %eax */ \
: "a"(NUM), /* %eax */ \
"b"((ARG1)), /* %ebx */ \
"c"((ARG2)), /* %ecx */ \
"d"((ARG3)), /* %edx */ \
"S"((ARG4)), /* %esi */ \
"D"((ARG5)) /* %edi */ \
: "memory" \
); \
eax; \
})
/*
* On i386, the 6th argument of syscall goes in %ebp. However, both Clang
* and GCC cannot use %ebp in the clobber list and in the "r" constraint
* without using -fomit-frame-pointer. To make it always available for
* any kind of compilation, the below workaround is implemented:
*
* 1) Push the 6-th argument.
* 2) Push %ebp.
* 3) Load the 6-th argument from 4(%esp) to %ebp.
* 4) Do the syscall (int $0x80).
* 5) Pop %ebp (restore the old value of %ebp).
* 6) Add %esp by 4 (undo the stack pointer).
*
* WARNING:
* Don't use register variables for __do_syscall6(), there is a known
* GCC bug that results in an endless loop.
*
* BugLink: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105032
*
*/
#define __do_syscall6(NUM, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) ({ \
intptr_t eax = (intptr_t)(NUM); \
intptr_t arg6 = (intptr_t)(ARG6); /* Always in memory */ \
__asm__ volatile ( \
"pushl %[_arg6]\n\t" \
"pushl %%ebp\n\t" \
"movl 4(%%esp),%%ebp\n\t" \
"int $0x80\n\t" \
"popl %%ebp\n\t" \
"addl $4,%%esp" \
: "+a"(eax) /* %eax */ \
: "b"(ARG1), /* %ebx */ \
"c"(ARG2), /* %ecx */ \
"d"(ARG3), /* %edx */ \
"S"(ARG4), /* %esi */ \
"D"(ARG5), /* %edi */ \
[_arg6]"m"(arg6) /* memory */ \
: "memory", "cc" \
); \
eax; \
})
#include "../syscall-defs.h"
#else /* #ifdef CONFIG_NOLIBC */
#include "../generic/syscall.h"
#endif /* #ifdef CONFIG_NOLIBC */
#endif /* #if defined(__x86_64__) */
#endif /* #ifndef LIBURING_ARCH_X86_SYSCALL_H */
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More