Compare commits
109
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee0bae573f | ||
|
|
27be4ee2fa | ||
|
|
00517e2bac | ||
|
|
e0a2615cbc | ||
|
|
63fe3c323a | ||
|
|
a88465df05 | ||
|
|
ad24be717a | ||
|
|
648e3b12f0 | ||
|
|
a675993c74 | ||
|
|
c9dfd0f67d | ||
|
|
84919a10a9 | ||
|
|
51ae4d6e24 | ||
|
|
572b20fedc | ||
|
|
4e2724b28f | ||
|
|
768b1675f8 | ||
|
|
38fa722725 | ||
|
|
e56d83fb7f | ||
|
|
ff95a85875 | ||
|
|
98203568a8 | ||
|
|
89df98ee08 | ||
|
|
0007a831b6 | ||
|
|
40517c335f | ||
|
|
c9f7308b6a | ||
|
|
85c7e3bde0 | ||
|
|
4fb55b3535 | ||
|
|
912aca11a3 | ||
|
|
7b454bd16c | ||
|
|
a0c8be46a4 | ||
|
|
53b4329fac | ||
|
|
a7f41c4a12 | ||
|
|
5d78057ac3 | ||
|
|
8efc5a353f | ||
|
|
603b26b896 | ||
|
|
a3b0fe0deb | ||
|
|
f504e356d5 | ||
|
|
4ed17b7070 | ||
|
|
1fd2819724 | ||
|
|
dcdabbc1ec | ||
|
|
625d5b7b9e | ||
|
|
9e507fd333 | ||
|
|
c2b5118127 | ||
|
|
4b926e2223 | ||
|
|
a5d9a6996a | ||
|
|
0ee03e7172 | ||
|
|
88b7d9afcd | ||
|
|
f271c8450c | ||
|
|
f78d7d4efc | ||
|
|
fdaf7c88ff | ||
|
|
2fb6eb0c30 | ||
|
|
36d2b56208 | ||
|
|
14b22f2ba9 | ||
|
|
fe8b1fe0cc | ||
|
|
1ec963e468 | ||
|
|
5100f822d8 | ||
|
|
7432494e88 | ||
|
|
d0c0f3ea39 | ||
|
|
f61190f31d | ||
|
|
3dc0ab5c33 | ||
|
|
de96efed2f | ||
|
|
87a5230798 | ||
|
|
0c5e6d4346 | ||
|
|
b278087410 | ||
|
|
a8e821b13b | ||
|
|
caa70317fa | ||
|
|
b8eaaabfe4 | ||
|
|
e4d80c415e | ||
|
|
553191c3ff | ||
|
|
ab385252b5 | ||
|
|
041185c673 | ||
|
|
b03ac80a57 | ||
|
|
2ba56074f9 | ||
|
|
4acfe149cb | ||
|
|
008ed5b269 | ||
|
|
4fffe0f032 | ||
|
|
a76d5ccc0d | ||
|
|
8ed1e180e0 | ||
|
|
8832fc3b14 | ||
|
|
0134934c99 | ||
|
|
2e36f292bd | ||
|
|
bcc6419760 | ||
|
|
dd5941b9a4 | ||
|
|
4005b88865 | ||
|
|
280b5cd675 | ||
|
|
e5c505eaf4 | ||
|
|
c1d244d4f0 | ||
|
|
9b264a212f | ||
|
|
ff7f5cb4f4 | ||
|
|
25ecca7625 | ||
|
|
99c4244004 | ||
|
|
9949b9fb4e | ||
|
|
e6881ad1d5 | ||
|
|
b30635b932 | ||
|
|
0c1154833c | ||
|
|
c227bb05b6 | ||
|
|
dd85315f22 | ||
|
|
47d2f4e0be | ||
|
|
2a5028d17f | ||
|
|
07915c2881 | ||
|
|
79141eb383 | ||
|
|
f7cbb6ed56 | ||
|
|
8f8172db99 | ||
|
|
94be147e80 | ||
|
|
538620b400 | ||
|
|
4c34a47179 | ||
|
|
df16ab627a | ||
|
|
44c895dc30 | ||
|
|
fdea595913 | ||
|
|
ef4c91ecc8 | ||
|
|
5192c6cf50 |
@@ -63,7 +63,7 @@ jobs:
|
|||||||
container: ${{env.TEST_IMAGE}}:${{github.sha}}
|
container: ${{env.TEST_IMAGE}}:${{github.sha}}
|
||||||
steps:
|
steps:
|
||||||
# leak sanitizer sometimes crashes
|
# leak sanitizer sometimes crashes
|
||||||
- run: cd /root/vitastor/build && ASAN_OPTIONS=detect_leaks=0 make -j16 test
|
- run: cd /root/vitastor/build && ASAN_OPTIONS=detect_leaks=0 make -j16 build_tests test
|
||||||
|
|
||||||
npm_lint:
|
npm_lint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
+7
-7
@@ -1,20 +1,20 @@
|
|||||||
cmake_minimum_required(VERSION 2.8.12)
|
cmake_minimum_required(VERSION 2.8...3.30)
|
||||||
|
|
||||||
project(vitastor)
|
project(vitastor)
|
||||||
|
|
||||||
set(VITASTOR_VERSION "3.0.5")
|
set(VITASTOR_VERSION "3.0.12")
|
||||||
|
|
||||||
include(CTest)
|
include(CTest)
|
||||||
|
|
||||||
add_custom_target(build_tests)
|
add_custom_target(build_tests)
|
||||||
add_custom_target(test
|
set_property(TEST PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_CURRENT_BINARY_DIR}/lsan-suppress.txt)
|
||||||
COMMAND
|
add_test(gen_lsan_suppress
|
||||||
echo leak:tcmalloc > ${CMAKE_CURRENT_BINARY_DIR}/lsan-suppress.txt &&
|
${CMAKE_COMMAND} -E echo leak:tcmalloc > "${CMAKE_CURRENT_BINARY_DIR}/lsan-suppress.txt"
|
||||||
env LSAN_OPTIONS=suppressions=${CMAKE_CURRENT_BINARY_DIR}/lsan-suppress.txt ${CMAKE_CTEST_COMMAND}
|
|
||||||
)
|
)
|
||||||
|
set_tests_properties(gen_lsan_suppress PROPERTIES FIXTURES_SETUP f_lsan_suppress)
|
||||||
|
set_property(TEST PROPERTY FIXTURES_REQUIRED f_lsan_suppress)
|
||||||
# make -j16 -C ../../build test_heap && ../../build/src/test/test_heap
|
# make -j16 -C ../../build test_heap && ../../build/src/test/test_heap
|
||||||
# make -j16 -C ../../build test_heap && rm -f $(find ../../build -name '*.gcda') && ctest -V -T test -T coverage -R heap --test-dir ../../build && (cd ../../build; gcovr -f ../src --html --html-nested -o coverage/index.html; cd ../src/test)
|
# make -j16 -C ../../build test_heap && rm -f $(find ../../build -name '*.gcda') && ctest -V -T test -T coverage -R heap --test-dir ../../build && (cd ../../build; gcovr -f ../src --html --html-nested -o coverage/index.html; cd ../src/test)
|
||||||
# make -j16 -C ../../build test_blockstore && rm -f $(find ../../build -name '*.gcda') && ctest -V -T test -T coverage -R blockstore --test-dir ../../build && (cd ../../build; gcovr -f ../src --html --html-nested -o coverage/index.html; cd ../src/test)
|
# make -j16 -C ../../build test_blockstore && rm -f $(find ../../build -name '*.gcda') && ctest -V -T test -T coverage -R blockstore --test-dir ../../build && (cd ../../build; gcovr -f ../src --html --html-nested -o coverage/index.html; cd ../src/test)
|
||||||
# kcov --include-path=../../../src ../../kcov ./test_blockstore
|
# kcov --include-path=../../../src ../../kcov ./test_blockstore
|
||||||
add_dependencies(test build_tests)
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
|||||||
+1
-1
Submodule cpp-btree updated: 8de8b467ac...ebe44c9b66
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
VITASTOR_VERSION ?= v3.0.5
|
VITASTOR_VERSION ?= v3.0.12
|
||||||
|
|
||||||
all: build push
|
all: build push
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ spec:
|
|||||||
capabilities:
|
capabilities:
|
||||||
add: ["SYS_ADMIN"]
|
add: ["SYS_ADMIN"]
|
||||||
allowPrivilegeEscalation: true
|
allowPrivilegeEscalation: true
|
||||||
image: vitalif/vitastor-csi:v3.0.5
|
image: vitalif/vitastor-csi:v3.0.12
|
||||||
args:
|
args:
|
||||||
- "--node=$(NODE_ID)"
|
- "--node=$(NODE_ID)"
|
||||||
- "--endpoint=$(CSI_ENDPOINT)"
|
- "--endpoint=$(CSI_ENDPOINT)"
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ spec:
|
|||||||
privileged: true
|
privileged: true
|
||||||
capabilities:
|
capabilities:
|
||||||
add: ["SYS_ADMIN"]
|
add: ["SYS_ADMIN"]
|
||||||
image: vitalif/vitastor-csi:v3.0.5
|
image: vitalif/vitastor-csi:v3.0.12
|
||||||
args:
|
args:
|
||||||
- "--node=$(NODE_ID)"
|
- "--node=$(NODE_ID)"
|
||||||
- "--endpoint=$(CSI_ENDPOINT)"
|
- "--endpoint=$(CSI_ENDPOINT)"
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ package vitastor
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
vitastorCSIDriverName = "csi.vitastor.io"
|
vitastorCSIDriverName = "csi.vitastor.io"
|
||||||
vitastorCSIDriverVersion = "3.0.5"
|
vitastorCSIDriverVersion = "3.0.12"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config struct fills the parameters of request or user input
|
// Config struct fills the parameters of request or user input
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
vitastor (3.0.5-1) unstable; urgency=medium
|
vitastor (3.0.12-1) unstable; urgency=medium
|
||||||
|
|
||||||
* Bugfixes
|
* Bugfixes
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
@@ -44,7 +44,7 @@ curl -s https://git.yourcmc.ru/vitalif/antietcd/archive/master.tar.gz | tar -zx
|
|||||||
curl -s https://git.yourcmc.ru/vitalif/tinyraft/archive/master.tar.gz | tar -zx
|
curl -s https://git.yourcmc.ru/vitalif/tinyraft/archive/master.tar.gz | tar -zx
|
||||||
|
|
||||||
cd /root/vitastor/packages/vitastor-$REL
|
cd /root/vitastor/packages/vitastor-$REL
|
||||||
if [[ "$REL" = "trixie" && -e ../vitastor-bookworm/vitastor_$VER.orig.tar.xz ]]; then
|
if [[ ( "$REL" = "trixie" || "$REL" = "resolute" ) && -e ../vitastor-bookworm/vitastor_$VER.orig.tar.xz ]]; then
|
||||||
# Fucking shit, archives differ between bookworm (xz 5.4.1) and trixie (xz 5.8.1)
|
# Fucking shit, archives differ between bookworm (xz 5.4.1) and trixie (xz 5.8.1)
|
||||||
cp ../vitastor-bookworm/vitastor_$VER.orig.tar.xz .
|
cp ../vitastor-bookworm/vitastor_$VER.orig.tar.xz .
|
||||||
else
|
else
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
VITASTOR_VERSION ?= v3.0.5
|
VITASTOR_VERSION ?= v3.0.12
|
||||||
|
|
||||||
all: build push
|
all: build push
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ PartOf=vitastor.target
|
|||||||
[Service]
|
[Service]
|
||||||
Restart=always
|
Restart=always
|
||||||
EnvironmentFile=/etc/vitastor/docker.conf
|
EnvironmentFile=/etc/vitastor/docker.conf
|
||||||
ExecStart=bash -c 'docker run --rm -i -v /etc/vitastor:/etc/vitastor -v /dev:/dev -v /run:/run \
|
ExecStart=bash -c 'docker run --rm -i -v /etc/vitastor:/etc/vitastor -v /dev:/dev -v /run:/run -e SYSTEMD_IN_CHROOT=0 \
|
||||||
--security-opt seccomp=unconfined --privileged --pid=host --log-driver none --network host --name vitastor vitastor:$VITASTOR_VERSION \
|
--security-opt seccomp=unconfined --privileged --pid=host --log-driver none --network host --name vitastor vitastor:$VITASTOR_VERSION \
|
||||||
sleep.sh'
|
sleep.sh'
|
||||||
ExecStartPost=udevadm trigger
|
ExecStartPost=udevadm trigger
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
# Desired Vitastor version
|
# Desired Vitastor version
|
||||||
VITASTOR_VERSION=v3.0.5
|
VITASTOR_VERSION=v3.0.12
|
||||||
|
|
||||||
# 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
|
||||||
|
|||||||
+2
-3
@@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
cp -urv /etc/default /host-etc/
|
cp -urv /etc/systemd/system/vitastor* /host-etc/systemd/system/
|
||||||
cp -urv /etc/systemd /host-etc/
|
cp -urv /etc/udev/rules.d /host-etc/udev/
|
||||||
cp -urv /etc/udev /host-etc/
|
|
||||||
cp -urnv /etc/vitastor /host-etc/
|
cp -urnv /etc/vitastor /host-etc/
|
||||||
cp -urnv /opt/scripts/* /host-bin/
|
cp -urnv /opt/scripts/* /host-bin/
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ with an OSD restart or, for some of them, even without restarting by updating co
|
|||||||
- [use_atomic_flag](#use_atomic_flag)
|
- [use_atomic_flag](#use_atomic_flag)
|
||||||
- [pg_reshard_chunk_size](#pg_reshard_chunk_size)
|
- [pg_reshard_chunk_size](#pg_reshard_chunk_size)
|
||||||
- [pg_reshard_chunk_pause_ms](#pg_reshard_chunk_pause_ms)
|
- [pg_reshard_chunk_pause_ms](#pg_reshard_chunk_pause_ms)
|
||||||
|
- [gc_on_start](#gc_on_start)
|
||||||
|
|
||||||
## bind_address
|
## bind_address
|
||||||
|
|
||||||
@@ -753,3 +754,9 @@ This option sets the maximum number of object is a chunk. Moving 100k objects us
|
|||||||
- Default: 100
|
- Default: 100
|
||||||
|
|
||||||
This option sets the interval between handling two PG count change chunks.
|
This option sets the interval between handling two PG count change chunks.
|
||||||
|
|
||||||
|
## gc_on_start
|
||||||
|
|
||||||
|
- Type: boolean
|
||||||
|
|
||||||
|
Forcibly clean all garbage entries in the new store on every OSD restart.
|
||||||
|
|||||||
@@ -71,6 +71,7 @@
|
|||||||
- [use_atomic_flag](#use_atomic_flag)
|
- [use_atomic_flag](#use_atomic_flag)
|
||||||
- [pg_reshard_chunk_size](#pg_reshard_chunk_size)
|
- [pg_reshard_chunk_size](#pg_reshard_chunk_size)
|
||||||
- [pg_reshard_chunk_pause_ms](#pg_reshard_chunk_pause_ms)
|
- [pg_reshard_chunk_pause_ms](#pg_reshard_chunk_pause_ms)
|
||||||
|
- [gc_on_start](#gc_on_start)
|
||||||
|
|
||||||
## bind_address
|
## bind_address
|
||||||
|
|
||||||
@@ -793,3 +794,9 @@ pg_minsize OSD во время переключений, что может по
|
|||||||
- Значение по умолчанию: 100
|
- Значение по умолчанию: 100
|
||||||
|
|
||||||
Данная опция задаёт интервал между обработкой двух порций изменения числа PG пулов.
|
Данная опция задаёт интервал между обработкой двух порций изменения числа PG пулов.
|
||||||
|
|
||||||
|
## gc_on_start
|
||||||
|
|
||||||
|
- Тип: булево (да/нет)
|
||||||
|
|
||||||
|
Принудительно очищать все мусорные записи в новом хранилище при каждом запуске OSD.
|
||||||
|
|||||||
@@ -938,3 +938,7 @@
|
|||||||
This option sets the interval between handling two PG count change chunks.
|
This option sets the interval between handling two PG count change chunks.
|
||||||
info_ru: |
|
info_ru: |
|
||||||
Данная опция задаёт интервал между обработкой двух порций изменения числа PG пулов.
|
Данная опция задаёт интервал между обработкой двух порций изменения числа PG пулов.
|
||||||
|
- name: gc_on_start
|
||||||
|
type: bool
|
||||||
|
info: Forcibly clean all garbage entries in the new store on every OSD restart.
|
||||||
|
info_ru: Принудительно очищать все мусорные записи в новом хранилище при каждом запуске OSD.
|
||||||
|
|||||||
@@ -26,13 +26,37 @@ 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:v3.0.5`
|
`docker pull vitalif/vitastor:v3.0.12`
|
||||||
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:v3.0.5 install.sh`
|
`docker run --rm -it -v /etc:/host-etc -v /usr/bin:/host-bin vitalif/vitastor:v3.0.12 install.sh`
|
||||||
3. Reload udev rules: \
|
3. Reload udev rules: \
|
||||||
`udevadm control --reload-rules`
|
`udevadm control --reload-rules`
|
||||||
|
4. Enable the vitastor-host service: \
|
||||||
|
`systemctl enable --now vitastor-host`
|
||||||
|
|
||||||
And you can return to [Quick Start](../intro/quickstart.en.md).
|
After these steps, you can return to [Quick Start](../intro/quickstart.en.md).
|
||||||
|
|
||||||
|
## Podman
|
||||||
|
|
||||||
|
If you use Podman, run the following commands as root before installing Vitastor containers:
|
||||||
|
|
||||||
|
```
|
||||||
|
ln -s podman /usr/bin/docker
|
||||||
|
|
||||||
|
mkdir -p /etc/systemd/system/systemd-udevd.service.d
|
||||||
|
|
||||||
|
cat >/etc/systemd/system/systemd-udevd.service.d/override.conf <<EOF
|
||||||
|
[Service]
|
||||||
|
CapabilityBoundingSet=~
|
||||||
|
SystemCallFilter=@mount capset
|
||||||
|
EOF
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
|
||||||
|
systemctl restart systemd-udevd
|
||||||
|
```
|
||||||
|
|
||||||
|
Without it, udev fails to do calls into a Podman container and Vitastor disk detection doesn't work.
|
||||||
|
|
||||||
## Upgrading Containers
|
## Upgrading Containers
|
||||||
|
|
||||||
|
|||||||
@@ -25,14 +25,39 @@ Vitastor можно установить в Docker/Podman. При этом etcd,
|
|||||||
Инструкция по установке максимально простая.
|
Инструкция по установке максимально простая.
|
||||||
|
|
||||||
1. Скачайте Docker-образ желаемой версии: \
|
1. Скачайте Docker-образ желаемой версии: \
|
||||||
`docker pull vitalif/vitastor:v3.0.5`
|
`docker pull vitalif/vitastor:v3.0.12`
|
||||||
2. Установите скрипты в хост-систему командой: \
|
2. Установите скрипты в хост-систему командой: \
|
||||||
`docker run --rm -it -v /etc:/host-etc -v /usr/bin:/host-bin vitalif/vitastor:v3.0.5 install.sh`
|
`docker run --rm -it -v /etc:/host-etc -v /usr/bin:/host-bin vitalif/vitastor:v3.0.12 install.sh`
|
||||||
3. Перезагрузите правила udev: \
|
3. Перезагрузите правила udev: \
|
||||||
`udevadm control --reload-rules`
|
`udevadm control --reload-rules`
|
||||||
|
4. Включите сервис vitastor-host: \
|
||||||
|
`systemctl enable --now vitastor-host`
|
||||||
|
|
||||||
После этого вы можете возвращаться к разделу [Быстрый старт](../intro/quickstart.ru.md).
|
После этого вы можете возвращаться к разделу [Быстрый старт](../intro/quickstart.ru.md).
|
||||||
|
|
||||||
|
## Podman
|
||||||
|
|
||||||
|
Если вы используете Podman, перед установкой контейнеров Vitastor выполните следующие
|
||||||
|
команды от имени суперпользователя:
|
||||||
|
|
||||||
|
```
|
||||||
|
ln -s podman /usr/bin/docker
|
||||||
|
|
||||||
|
mkdir -p /etc/systemd/system/systemd-udevd.service.d
|
||||||
|
|
||||||
|
cat >/etc/systemd/system/systemd-udevd.service.d/override.conf <<EOF
|
||||||
|
[Service]
|
||||||
|
CapabilityBoundingSet=~
|
||||||
|
SystemCallFilter=@mount capset
|
||||||
|
EOF
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
|
||||||
|
systemctl restart systemd-udevd
|
||||||
|
```
|
||||||
|
|
||||||
|
Без этих настроек udev не может делать вызовы внутрь Podman-контейнеров и определение дисков Vitastor не работает.
|
||||||
|
|
||||||
## Обновление контейнеров
|
## Обновление контейнеров
|
||||||
|
|
||||||
Сначала обязательно проверьте раздел [Обновление Vitastor](../usage/admin.ru.md#обновление-vitastor),
|
Сначала обязательно проверьте раздел [Обновление Vitastor](../usage/admin.ru.md#обновление-vitastor),
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
- 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`
|
||||||
|
- Ubuntu 26.04 (Resolute): `deb https://vitastor.io/debian resolute 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`:
|
- To always prefer vitastor-patched QEMU and Libvirt versions, add the following to `/etc/apt/preferences`:
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
- 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`
|
||||||
|
- Ubuntu 26.04 (Resolute): `deb https://vitastor.io/debian resolute 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`:
|
- Чтобы всегда предпочитались версии пакетов QEMU и Libvirt с патчами Vitastor, добавьте в `/etc/apt/preferences`:
|
||||||
|
|||||||
@@ -16,8 +16,7 @@
|
|||||||
designated initializers support from C++20
|
designated initializers support from C++20
|
||||||
- CMake
|
- CMake
|
||||||
- jerasure headers and libraries
|
- jerasure headers and libraries
|
||||||
- ISA-L, libibverbs and librdmacm headers and libraries (optional)
|
- ISA-L, libibverbs, librdmacm, libnl3 headers and libraries (optional)
|
||||||
- tcmalloc (google-perftools-dev)
|
|
||||||
|
|
||||||
## Basic instructions
|
## Basic instructions
|
||||||
|
|
||||||
|
|||||||
@@ -16,8 +16,7 @@
|
|||||||
назначенных инициализаторов (designated initializers) из C++20
|
назначенных инициализаторов (designated initializers) из C++20
|
||||||
- CMake
|
- CMake
|
||||||
- Заголовки и библиотеки jerasure
|
- Заголовки и библиотеки jerasure
|
||||||
- Опционально - заголовки и библиотеки ISA-L, libibverbs, librdmacm
|
- Опционально - заголовки и библиотеки ISA-L, libibverbs, librdmacm, libnl3
|
||||||
- tcmalloc (google-perftools-dev)
|
|
||||||
|
|
||||||
## Базовая инструкция
|
## Базовая инструкция
|
||||||
|
|
||||||
|
|||||||
@@ -262,3 +262,4 @@ Options:
|
|||||||
| `--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) |
|
| `--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 |
|
||||||
|
| `--trace` | trace all NFS requests |
|
||||||
|
|||||||
@@ -274,3 +274,4 @@ VitastorFS из GPUDirect.
|
|||||||
| `--logfile <FILE>` | записывать логи в заданный файл |
|
| `--logfile <FILE>` | записывать логи в заданный файл |
|
||||||
| `--enforce 1` | проверять права доступа на стороне сервера (по умолчанию нет) |
|
| `--enforce 1` | проверять права доступа на стороне сервера (по умолчанию нет) |
|
||||||
| `--foreground 1` | не уходить в фон после запуска |
|
| `--foreground 1` | не уходить в фон после запуска |
|
||||||
|
| `--trace` | логгировать все запросы NFS |
|
||||||
|
|||||||
+1
-1
Submodule json11 updated: fd37016cf8...edcd85b8bd
+1
-1
@@ -16,7 +16,7 @@ async function create_http_server(cfg, handler)
|
|||||||
};
|
};
|
||||||
if (cfg.mon_https_ca)
|
if (cfg.mon_https_ca)
|
||||||
{
|
{
|
||||||
tls.mon_https_ca = await fsp.readFile(cfg.mon_https_ca);
|
tls.ca = await fsp.readFile(cfg.mon_https_ca);
|
||||||
}
|
}
|
||||||
if (cfg.mon_https_client_auth)
|
if (cfg.mon_https_client_auth)
|
||||||
{
|
{
|
||||||
|
|||||||
+2
-2
@@ -627,7 +627,7 @@ class Mon
|
|||||||
if (this.state.pg.history[pool_id] &&
|
if (this.state.pg.history[pool_id] &&
|
||||||
this.state.pg.history[pool_id][pg])
|
this.state.pg.history[pool_id][pg])
|
||||||
{
|
{
|
||||||
pg_history[pg-1] = this.state.pg.history[pool_id][pg];
|
pg_history[pg-1] = JSON.parse(JSON.stringify(this.state.pg.history[pool_id][pg]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const real_prev_pgs = [];
|
const real_prev_pgs = [];
|
||||||
@@ -719,7 +719,7 @@ class Mon
|
|||||||
this.next_recheck_timer = null;
|
this.next_recheck_timer = null;
|
||||||
this.next_recheck_at = 0;
|
this.next_recheck_at = 0;
|
||||||
this.schedule_recheck();
|
this.schedule_recheck();
|
||||||
}, now-this.next_recheck_at);
|
}, (this.next_recheck_at-now)*1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vitastor-mon",
|
"name": "vitastor-mon",
|
||||||
"version": "3.0.5",
|
"version": "3.0.12",
|
||||||
"description": "Vitastor SDS monitor service",
|
"description": "Vitastor SDS monitor service",
|
||||||
"main": "mon-main.js",
|
"main": "mon-main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
+2
-2
@@ -84,7 +84,7 @@ function scale_pg_history(prev_pg_history, prev_pgs, new_pgs)
|
|||||||
finish_pg_history(merged_history[1]);
|
finish_pg_history(merged_history[1]);
|
||||||
for (let i = 0; i < new_pg_count; i++)
|
for (let i = 0; i < new_pg_count; i++)
|
||||||
{
|
{
|
||||||
new_pg_history[i] = { ...merged_history[1] };
|
new_pg_history[i] = JSON.parse(JSON.stringify(merged_history[1]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Mark history keys for removed PGs as removed
|
// Mark history keys for removed PGs as removed
|
||||||
@@ -102,7 +102,7 @@ function scale_pg_count(prev_pgs, new_pg_count)
|
|||||||
{
|
{
|
||||||
for (let i = prev_pgs.length; i < new_pg_count; i++)
|
for (let i = prev_pgs.length; i < new_pg_count; i++)
|
||||||
{
|
{
|
||||||
prev_pgs[i] = prev_pgs[i % prev_pgs.length];
|
prev_pgs[i] = [ ...prev_pgs[i % prev_pgs.length] ];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (prev_pgs.length > new_pg_count)
|
else if (prev_pgs.length > new_pg_count)
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ function derive_osd_stats(st, prev, prev_diff)
|
|||||||
const n = c.count - BigInt(pr && pr.count||0);
|
const n = c.count - BigInt(pr && pr.count||0);
|
||||||
diff.recovery_stats[op] = { ...c, bps: n > 0 ? b*1000n/timediff : 0n, iops: n > 0 ? n*1000n/timediff : 0n };
|
diff.recovery_stats[op] = { ...c, bps: n > 0 ? b*1000n/timediff : 0n, iops: n > 0 ? n*1000n/timediff : 0n };
|
||||||
}
|
}
|
||||||
|
diff.inode_stats = {};
|
||||||
for (const pool_id in st.inode_stats||{})
|
for (const pool_id in st.inode_stats||{})
|
||||||
{
|
{
|
||||||
diff.inode_stats[pool_id] = {};
|
diff.inode_stats[pool_id] = {};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vitastor",
|
"name": "vitastor",
|
||||||
"version": "3.0.5",
|
"version": "3.0.12",
|
||||||
"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": [
|
||||||
|
|||||||
+29
-231
@@ -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 = '3.0.5'
|
VITASTOR_VERSION = '3.0.12'
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -291,6 +291,14 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
else:
|
else:
|
||||||
return (1 + resp['kvs'][0]['value'], resp['kvs'][0]['mod_revision'])
|
return (1 + resp['kvs'][0]['value'], resp['kvs'][0]['mod_revision'])
|
||||||
|
|
||||||
|
def _cli(self, descr, *args):
|
||||||
|
args = [ 'vitastor-cli', *args, *(self._vitastor_args()) ]
|
||||||
|
try:
|
||||||
|
self._execute(*args)
|
||||||
|
except processutils.ProcessExecutionError as exc:
|
||||||
|
LOG.error("Failed to "+descr+": "+exc)
|
||||||
|
raise exception.VolumeBackendAPIException(data = exc.stderr)
|
||||||
|
|
||||||
def create_volume(self, volume):
|
def create_volume(self, volume):
|
||||||
"""Creates a logical volume."""
|
"""Creates a logical volume."""
|
||||||
|
|
||||||
@@ -302,7 +310,7 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
|
|
||||||
LOG.debug("creating volume '%s'", vol_name)
|
LOG.debug("creating volume '%s'", vol_name)
|
||||||
|
|
||||||
self._create_image(vol_name, { 'size': size })
|
self._cli('create volume', 'create', vol_name, '--size', size)
|
||||||
|
|
||||||
if volume.encryption_key_id:
|
if volume.encryption_key_id:
|
||||||
self._create_encrypted_volume(volume, volume.obj_context)
|
self._create_encrypted_volume(volume, volume.obj_context)
|
||||||
@@ -346,7 +354,7 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
snap_name = utils.convert_str(snapshot.name)
|
snap_name = utils.convert_str(snapshot.name)
|
||||||
if snap_name.find('@') >= 0 or snap_name.find('/') >= 0:
|
if snap_name.find('@') >= 0 or snap_name.find('/') >= 0:
|
||||||
raise exception.VolumeBackendAPIException(data = '@ and / are forbidden in volume and snapshot names')
|
raise exception.VolumeBackendAPIException(data = '@ and / are forbidden in volume and snapshot names')
|
||||||
self._create_snapshot(vol_name, vol_name+'@'+snap_name)
|
self._cli('create snapshot', 'snap-create', vol_name+'@'+snap_name)
|
||||||
|
|
||||||
def snapshot_revert_use_temp_snapshot(self):
|
def snapshot_revert_use_temp_snapshot(self):
|
||||||
"""Disable the use of a temporary snapshot on revert."""
|
"""Disable the use of a temporary snapshot on revert."""
|
||||||
@@ -359,21 +367,8 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
snap_name = utils.convert_str(snapshot.name)
|
snap_name = utils.convert_str(snapshot.name)
|
||||||
|
|
||||||
# Delete the image and recreate it from the snapshot
|
# Delete the image and recreate it from the snapshot
|
||||||
args = [ 'vitastor-cli', 'rm', vol_name, *(self._vitastor_args()) ]
|
self._cli('delete image', 'rm', vol_name)
|
||||||
try:
|
self._cli('recreate image', 'create', '--parent', vol_name+'@'+snap_name, vol_name)
|
||||||
self._execute(*args)
|
|
||||||
except processutils.ProcessExecutionError as exc:
|
|
||||||
LOG.error("Failed to delete image "+vol_name+": "+exc)
|
|
||||||
raise exception.VolumeBackendAPIException(data = exc.stderr)
|
|
||||||
args = [
|
|
||||||
'vitastor-cli', 'create', '--parent', vol_name+'@'+snap_name,
|
|
||||||
vol_name, *(self._vitastor_args())
|
|
||||||
]
|
|
||||||
try:
|
|
||||||
self._execute(*args)
|
|
||||||
except processutils.ProcessExecutionError as exc:
|
|
||||||
LOG.error("Failed to recreate image "+vol_name+" from "+vol_name+"@"+snap_name+": "+exc)
|
|
||||||
raise exception.VolumeBackendAPIException(data = exc.stderr)
|
|
||||||
|
|
||||||
def delete_snapshot(self, snapshot):
|
def delete_snapshot(self, snapshot):
|
||||||
"""Deletes a snapshot."""
|
"""Deletes a snapshot."""
|
||||||
@@ -381,15 +376,7 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
vol_name = utils.convert_str(snapshot.volume_name)
|
vol_name = utils.convert_str(snapshot.volume_name)
|
||||||
snap_name = utils.convert_str(snapshot.name)
|
snap_name = utils.convert_str(snapshot.name)
|
||||||
|
|
||||||
args = [
|
self._cli('remove snapshot', 'rm', vol_name+'@'+snap_name)
|
||||||
'vitastor-cli', 'rm', vol_name+'@'+snap_name,
|
|
||||||
*(self._vitastor_args())
|
|
||||||
]
|
|
||||||
try:
|
|
||||||
self._execute(*args)
|
|
||||||
except processutils.ProcessExecutionError as exc:
|
|
||||||
LOG.error("Failed to remove snapshot "+vol_name+'@'+snap_name+": "+exc)
|
|
||||||
raise exception.VolumeBackendAPIException(data = exc.stderr)
|
|
||||||
|
|
||||||
def _child_count(self, parents):
|
def _child_count(self, parents):
|
||||||
children = 0
|
children = 0
|
||||||
@@ -427,13 +414,7 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
if src_vref.admin_metadata.get('readonly') == 'True':
|
if src_vref.admin_metadata.get('readonly') == 'True':
|
||||||
# source volume is a volume-image cache entry or other readonly volume
|
# source volume is a volume-image cache entry or other readonly volume
|
||||||
# clone without intermediate snapshot
|
# clone without intermediate snapshot
|
||||||
src = self._get_image(src_name)
|
self._cli('create clone', 'create', '--parent', src_name, '--size', size, dest_name)
|
||||||
LOG.debug("creating image '%s' from '%s'", dest_name, src_name)
|
|
||||||
new_cfg = self._create_image(dest_name, {
|
|
||||||
'size': size,
|
|
||||||
'parent_id': src['idx']['id'],
|
|
||||||
'parent_pool_id': src['idx']['pool_id'],
|
|
||||||
})
|
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
clone_snap = "%s@%s.clone_snap" % (src_name, dest_name)
|
clone_snap = "%s@%s.clone_snap" % (src_name, dest_name)
|
||||||
@@ -446,15 +427,12 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
clone_snap = dest_name
|
clone_snap = dest_name
|
||||||
make_img = False
|
make_img = False
|
||||||
|
|
||||||
LOG.debug("creating layer '%s' under '%s'", clone_snap, src_name)
|
LOG.debug("creating snapshot '%s'", clone_snap)
|
||||||
new_cfg = self._create_snapshot(src_name, clone_snap, True)
|
self._cli('create base snapshot', 'snap-create', '--allow-existing', '1', clone_snap)
|
||||||
|
|
||||||
if make_img:
|
if make_img:
|
||||||
# Then create a clone from it
|
# Then create a clone from it
|
||||||
new_cfg = self._create_image(dest_name, {
|
self._cli('create clone', 'create', '--parent', clone_snap, '--size', size, dest_name)
|
||||||
'size': size,
|
|
||||||
'parent_id': new_cfg['parent_id'],
|
|
||||||
'parent_pool_id': new_cfg['parent_pool_id'],
|
|
||||||
})
|
|
||||||
|
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
@@ -464,7 +442,8 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
vol_name = utils.convert_str(volume.name)
|
vol_name = utils.convert_str(volume.name)
|
||||||
snap_name = utils.convert_str(snapshot.name)
|
snap_name = utils.convert_str(snapshot.name)
|
||||||
|
|
||||||
snap = self._get_image('volume-'+snapshot.volume_id+'@'+snap_name)
|
src_snap = 'volume-'+snapshot.volume_id+'@'+snap_name
|
||||||
|
snap = self._get_image(src_snap)
|
||||||
if not snap:
|
if not snap:
|
||||||
raise exception.SnapshotNotFound(snapshot_id = snap_name)
|
raise exception.SnapshotNotFound(snapshot_id = snap_name)
|
||||||
snap_inode_id = int(resp['responses'][0]['kvs'][0]['value']['id'])
|
snap_inode_id = int(resp['responses'][0]['kvs'][0]['value']['id'])
|
||||||
@@ -473,12 +452,8 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
size = snap['cfg']['size']
|
size = snap['cfg']['size']
|
||||||
if int(volume.size):
|
if int(volume.size):
|
||||||
size = int(volume.size) * units.Gi
|
size = int(volume.size) * units.Gi
|
||||||
new_cfg = self._create_image(vol_name, {
|
|
||||||
'size': size,
|
|
||||||
'parent_id': snap['idx']['id'],
|
|
||||||
'parent_pool_id': snap['idx']['pool_id'],
|
|
||||||
})
|
|
||||||
|
|
||||||
|
self._cli('create clone', 'create', vol_name, '--size', size, '--parent', src_snap)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def _vitastor_args(self):
|
def _vitastor_args(self):
|
||||||
@@ -505,49 +480,7 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
"""Deletes a logical volume."""
|
"""Deletes a logical volume."""
|
||||||
|
|
||||||
vol_name = utils.convert_str(volume.name)
|
vol_name = utils.convert_str(volume.name)
|
||||||
|
self._cli('delete volume', 'rm', '--matching', vol_name, vol_name+'@*', '--progress', '0')
|
||||||
# Find the volume and all its snapshots
|
|
||||||
range_end = b'index/image/' + vol_name.encode('utf-8')
|
|
||||||
range_end = range_end[0 : len(range_end)-1] + six.int2byte(range_end[len(range_end)-1] + 1)
|
|
||||||
resp = self._etcd_txn({ 'success': [
|
|
||||||
{ 'request_range': { 'key': 'index/image/'+vol_name, 'range_end': range_end } },
|
|
||||||
] })
|
|
||||||
if len(resp['responses'][0]['kvs']) == 0:
|
|
||||||
# already deleted
|
|
||||||
LOG.info("volume %s no longer exists in backend", vol_name)
|
|
||||||
return
|
|
||||||
layers = resp['responses'][0]['kvs']
|
|
||||||
layer_ids = {}
|
|
||||||
for kv in layers:
|
|
||||||
inode_id = int(kv['value']['id'])
|
|
||||||
pool_id = int(kv['value']['pool_id'])
|
|
||||||
inode_pool_id = (pool_id << 48) | (inode_id & 0xffffffffffff)
|
|
||||||
layer_ids[inode_pool_id] = True
|
|
||||||
|
|
||||||
# Check if the volume has clones and raise 'busy' if so
|
|
||||||
children = self._child_count(layer_ids)
|
|
||||||
if children > 0:
|
|
||||||
raise exception.VolumeIsBusy(volume_name = vol_name)
|
|
||||||
|
|
||||||
# Clear data
|
|
||||||
for kv in layers:
|
|
||||||
args = [
|
|
||||||
'vitastor-cli', 'rm-data', '--pool', str(kv['value']['pool_id']),
|
|
||||||
'--inode', str(kv['value']['id']), '--progress', '0',
|
|
||||||
*(self._vitastor_args())
|
|
||||||
]
|
|
||||||
try:
|
|
||||||
self._execute(*args)
|
|
||||||
except processutils.ProcessExecutionError as exc:
|
|
||||||
LOG.error("Failed to remove layer "+kv['key']+": "+exc)
|
|
||||||
raise exception.VolumeBackendAPIException(data = exc.stderr)
|
|
||||||
|
|
||||||
# Delete all layers from etcd
|
|
||||||
requests = []
|
|
||||||
for kv in layers:
|
|
||||||
requests.append({ 'request_delete_range': { 'key': kv['key'] } })
|
|
||||||
requests.append({ 'request_delete_range': { 'key': 'config/inode/'+str(kv['value']['pool_id'])+'/'+str(kv['value']['id']) } })
|
|
||||||
self._etcd_txn({ 'success': requests })
|
|
||||||
|
|
||||||
def retype(self, context, volume, new_type, diff, host):
|
def retype(self, context, volume, new_type, diff, host):
|
||||||
"""Change extra type specifications for a volume."""
|
"""Change extra type specifications for a volume."""
|
||||||
@@ -567,98 +500,6 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
"""Removes an export for a logical volume."""
|
"""Removes an export for a logical volume."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _create_image(self, vol_name, cfg):
|
|
||||||
pool_s = str(self.cfg['pool_id'])
|
|
||||||
image_id = 0
|
|
||||||
while image_id == 0:
|
|
||||||
# check if the image already exists and find a free ID
|
|
||||||
resp = self._etcd_txn({ 'success': [
|
|
||||||
{ 'request_range': { 'key': 'index/image/'+vol_name } },
|
|
||||||
{ 'request_range': { 'key': 'index/maxid/'+pool_s } },
|
|
||||||
] })
|
|
||||||
if len(resp['responses'][0]['kvs']) > 0:
|
|
||||||
# already exists
|
|
||||||
raise exception.VolumeBackendAPIException(data = 'Volume '+vol_name+' already exists')
|
|
||||||
image_id, id_mod = self._next_id(resp['responses'][1])
|
|
||||||
# try to create the image
|
|
||||||
resp = self._etcd_txn({ 'compare': [
|
|
||||||
{ 'target': 'MOD', 'mod_revision': id_mod, 'key': 'index/maxid/'+pool_s },
|
|
||||||
{ 'target': 'VERSION', 'version': 0, 'key': 'index/image/'+vol_name },
|
|
||||||
{ 'target': 'VERSION', 'version': 0, 'key': 'config/inode/'+pool_s+'/'+str(image_id) },
|
|
||||||
], 'success': [
|
|
||||||
{ 'request_put': { 'key': 'index/maxid/'+pool_s, 'value': image_id } },
|
|
||||||
{ 'request_put': { 'key': 'index/image/'+vol_name, 'value': json.dumps({
|
|
||||||
'id': image_id, 'pool_id': self.cfg['pool_id']
|
|
||||||
}) } },
|
|
||||||
{ 'request_put': { 'key': 'config/inode/'+pool_s+'/'+str(image_id), 'value': json.dumps({
|
|
||||||
**cfg, 'name': vol_name,
|
|
||||||
}) } },
|
|
||||||
] })
|
|
||||||
if not resp.get('succeeded'):
|
|
||||||
# repeat
|
|
||||||
image_id = 0
|
|
||||||
|
|
||||||
def _create_snapshot(self, vol_name, snap_vol_name, allow_existing = False):
|
|
||||||
while True:
|
|
||||||
# check if the image already exists and snapshot doesn't
|
|
||||||
resp = self._etcd_txn({ 'success': [
|
|
||||||
{ 'request_range': { 'key': 'index/image/'+vol_name } },
|
|
||||||
{ 'request_range': { 'key': 'index/image/'+snap_vol_name } },
|
|
||||||
] })
|
|
||||||
if len(resp['responses'][0]['kvs']) == 0:
|
|
||||||
raise exception.VolumeBackendAPIException(data = 'Volume '+vol_name+' does not exist')
|
|
||||||
if len(resp['responses'][1]['kvs']) > 0:
|
|
||||||
if allow_existing:
|
|
||||||
snap_idx = resp['responses'][1]['kvs'][0]['value']
|
|
||||||
resp = self._etcd_txn({ 'success': [
|
|
||||||
{ 'request_range': { 'key': 'config/inode/'+str(snap_idx['pool_id'])+'/'+str(snap_idx['id']) } },
|
|
||||||
] })
|
|
||||||
if len(resp['responses'][0]['kvs']) == 0:
|
|
||||||
raise exception.VolumeBackendAPIException(data =
|
|
||||||
'Volume '+snap_vol_name+' is already indexed, but does not exist'
|
|
||||||
)
|
|
||||||
return resp['responses'][0]['kvs'][0]['value']
|
|
||||||
raise exception.VolumeBackendAPIException(
|
|
||||||
data = 'Volume '+snap_vol_name+' already exists'
|
|
||||||
)
|
|
||||||
vol_idx = resp['responses'][0]['kvs'][0]['value']
|
|
||||||
vol_idx_mod = resp['responses'][0]['kvs'][0]['mod_revision']
|
|
||||||
# get image inode config and find a new ID
|
|
||||||
resp = self._etcd_txn({ 'success': [
|
|
||||||
{ 'request_range': { 'key': 'config/inode/'+str(vol_idx['pool_id'])+'/'+str(vol_idx['id']) } },
|
|
||||||
{ 'request_range': { 'key': 'index/maxid/'+str(self.cfg['pool_id']) } },
|
|
||||||
] })
|
|
||||||
if len(resp['responses'][0]['kvs']) == 0:
|
|
||||||
raise exception.VolumeBackendAPIException(data = 'Volume '+vol_name+' does not exist')
|
|
||||||
vol_cfg = resp['responses'][0]['kvs'][0]['value']
|
|
||||||
vol_mod = resp['responses'][0]['kvs'][0]['mod_revision']
|
|
||||||
new_id, id_mod = self._next_id(resp['responses'][1])
|
|
||||||
# try to redirect image to the new inode
|
|
||||||
new_cfg = {
|
|
||||||
**vol_cfg, 'name': vol_name, 'parent_id': vol_idx['id'], 'parent_pool_id': vol_idx['pool_id']
|
|
||||||
}
|
|
||||||
resp = self._etcd_txn({ 'compare': [
|
|
||||||
{ 'target': 'MOD', 'mod_revision': vol_idx_mod, 'key': 'index/image/'+vol_name },
|
|
||||||
{ 'target': 'MOD', 'mod_revision': vol_mod, 'key': 'config/inode/'+str(vol_idx['pool_id'])+'/'+str(vol_idx['id']) },
|
|
||||||
{ 'target': 'MOD', 'mod_revision': id_mod, 'key': 'index/maxid/'+str(self.cfg['pool_id']) },
|
|
||||||
{ 'target': 'VERSION', 'version': 0, 'key': 'index/image/'+snap_vol_name },
|
|
||||||
{ 'target': 'VERSION', 'version': 0, 'key': 'config/inode/'+str(self.cfg['pool_id'])+'/'+str(new_id) },
|
|
||||||
], 'success': [
|
|
||||||
{ 'request_put': { 'key': 'index/maxid/'+str(self.cfg['pool_id']), 'value': new_id } },
|
|
||||||
{ 'request_put': { 'key': 'index/image/'+vol_name, 'value': json.dumps({
|
|
||||||
'id': new_id, 'pool_id': self.cfg['pool_id']
|
|
||||||
}) } },
|
|
||||||
{ 'request_put': { 'key': 'config/inode/'+str(self.cfg['pool_id'])+'/'+str(new_id), 'value': json.dumps(new_cfg) } },
|
|
||||||
{ 'request_put': { 'key': 'index/image/'+snap_vol_name, 'value': json.dumps({
|
|
||||||
'id': vol_idx['id'], 'pool_id': vol_idx['pool_id']
|
|
||||||
}) } },
|
|
||||||
{ 'request_put': { 'key': 'config/inode/'+str(vol_idx['pool_id'])+'/'+str(vol_idx['id']), 'value': json.dumps({
|
|
||||||
**vol_cfg, 'name': snap_vol_name, 'readonly': True
|
|
||||||
}) } }
|
|
||||||
] })
|
|
||||||
if resp.get('succeeded'):
|
|
||||||
return new_cfg
|
|
||||||
|
|
||||||
def initialize_connection(self, volume, connector):
|
def initialize_connection(self, volume, connector):
|
||||||
data = {
|
data = {
|
||||||
'driver_volume_type': 'vitastor',
|
'driver_volume_type': 'vitastor',
|
||||||
@@ -697,13 +538,9 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
size = int(volume.size) * units.Gi
|
size = int(volume.size) * units.Gi
|
||||||
dest_name = utils.convert_str(volume.name)
|
dest_name = utils.convert_str(volume.name)
|
||||||
# Find or create the base snapshot
|
# Find or create the base snapshot
|
||||||
snap_cfg = self._create_snapshot(base_vol.name, base_vol.name+'@.clone_snap', True)
|
self._cli('create base snapshot', 'create', '--allow-existing', '1', base_vol.name+'@.clone_snap')
|
||||||
# Then create a clone from it
|
# Then create a clone from it
|
||||||
new_cfg = self._create_image(dest_name, {
|
self._cli('create clone', 'create', dest_name, '--size', size, '--parent', base_vol.name+'@.clone_snap')
|
||||||
'size': size,
|
|
||||||
'parent_id': snap_cfg['parent_id'],
|
|
||||||
'parent_pool_id': snap_cfg['parent_pool_id'],
|
|
||||||
})
|
|
||||||
return ({}, True)
|
return ({}, True)
|
||||||
return ({}, False)
|
return ({}, False)
|
||||||
|
|
||||||
@@ -770,26 +607,8 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
def extend_volume(self, volume, new_size):
|
def extend_volume(self, volume, new_size):
|
||||||
"""Extend an existing volume."""
|
"""Extend an existing volume."""
|
||||||
vol_name = utils.convert_str(volume.name)
|
vol_name = utils.convert_str(volume.name)
|
||||||
while True:
|
size = int(new_size) * units.Gi
|
||||||
vol = self._get_image(vol_name)
|
self._cli('extend volume', 'modify', vol_name, '--resize', new_size)
|
||||||
if not vol:
|
|
||||||
raise exception.VolumeBackendAPIException(data = 'Volume '+vol_name+' does not exist')
|
|
||||||
# change size
|
|
||||||
size = int(new_size) * units.Gi
|
|
||||||
if size == vol['cfg']['size']:
|
|
||||||
break
|
|
||||||
resp = self._etcd_txn({ 'compare': [ {
|
|
||||||
'target': 'MOD',
|
|
||||||
'mod_revision': vol['cfg_mod'],
|
|
||||||
'key': 'config/inode/'+str(vol['idx']['pool_id'])+'/'+str(vol['idx']['id']),
|
|
||||||
} ], 'success': [
|
|
||||||
{ 'request_put': {
|
|
||||||
'key': 'config/inode/'+str(vol['idx']['pool_id'])+'/'+str(vol['idx']['id']),
|
|
||||||
'value': json.dumps({ **vol['cfg'], 'size': size }),
|
|
||||||
} },
|
|
||||||
] })
|
|
||||||
if resp.get('succeeded'):
|
|
||||||
break
|
|
||||||
LOG.debug(
|
LOG.debug(
|
||||||
"Extend volume from %(old_size)s GB to %(new_size)s GB.",
|
"Extend volume from %(old_size)s GB to %(new_size)s GB.",
|
||||||
{'old_size': volume.size, 'new_size': new_size}
|
{'old_size': volume.size, 'new_size': new_size}
|
||||||
@@ -862,28 +681,7 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
"""
|
"""
|
||||||
from_name = self._get_existing_name(existing_ref)
|
from_name = self._get_existing_name(existing_ref)
|
||||||
to_name = utils.convert_str(volume.name)
|
to_name = utils.convert_str(volume.name)
|
||||||
self._rename(from_name, to_name)
|
self._cli('rename', 'modify', from_name, '--rename', to_name)
|
||||||
|
|
||||||
def _rename(self, from_name, to_name):
|
|
||||||
while True:
|
|
||||||
vol = self._get_image(from_name)
|
|
||||||
if not vol:
|
|
||||||
raise exception.VolumeBackendAPIException(data = 'Volume '+from_name+' does not exist')
|
|
||||||
to = self._get_image(to_name)
|
|
||||||
if to:
|
|
||||||
raise exception.VolumeBackendAPIException(data = 'Volume '+to_name+' already exists')
|
|
||||||
resp = self._etcd_txn({ 'compare': [
|
|
||||||
{ 'target': 'MOD', 'mod_revision': vol['idx_mod'], 'key': 'index/image/'+vol['cfg']['name'] },
|
|
||||||
{ 'target': 'MOD', 'mod_revision': vol['cfg_mod'], 'key': 'config/inode/'+str(vol['idx']['pool_id'])+'/'+str(vol['idx']['id']) },
|
|
||||||
{ 'target': 'VERSION', 'version': 0, 'key': 'index/image/'+to_name },
|
|
||||||
], 'success': [
|
|
||||||
{ 'request_delete_range': { 'key': 'index/image/'+vol['cfg']['name'] } },
|
|
||||||
{ 'request_put': { 'key': 'index/image/'+to_name, 'value': json.dumps(vol['idx']) } },
|
|
||||||
{ 'request_put': { 'key': 'config/inode/'+str(vol['idx']['pool_id'])+'/'+str(vol['idx']['id']),
|
|
||||||
'value': json.dumps({ **vol['cfg'], 'name': to_name }) } },
|
|
||||||
] })
|
|
||||||
if resp.get('succeeded'):
|
|
||||||
break
|
|
||||||
|
|
||||||
def unmanage(self, volume):
|
def unmanage(self, volume):
|
||||||
pass
|
pass
|
||||||
@@ -956,7 +754,7 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
snap_name = self._get_existing_name(existing_ref)
|
snap_name = self._get_existing_name(existing_ref)
|
||||||
from_name = vol_name+'@'+snap_name
|
from_name = vol_name+'@'+snap_name
|
||||||
to_name = vol_name+'@'+utils.convert_str(snapshot.name)
|
to_name = vol_name+'@'+utils.convert_str(snapshot.name)
|
||||||
self._rename(from_name, to_name)
|
self._cli('rename', 'modify', from_name, '--rename', to_name)
|
||||||
|
|
||||||
def unmanage_snapshot(self, snapshot):
|
def unmanage_snapshot(self, snapshot):
|
||||||
"""Removes the specified snapshot from Cinder management."""
|
"""Removes the specified snapshot from Cinder management."""
|
||||||
|
|||||||
@@ -0,0 +1,637 @@
|
|||||||
|
diff --git a/include/libvirt/libvirt-storage.h b/include/libvirt/libvirt-storage.h
|
||||||
|
index aaad4a3da1..5f5daa8341 100644
|
||||||
|
--- a/include/libvirt/libvirt-storage.h
|
||||||
|
+++ b/include/libvirt/libvirt-storage.h
|
||||||
|
@@ -326,6 +326,7 @@ typedef enum {
|
||||||
|
VIR_CONNECT_LIST_STORAGE_POOLS_ZFS = 1 << 17, /* (Since: 1.2.8) */
|
||||||
|
VIR_CONNECT_LIST_STORAGE_POOLS_VSTORAGE = 1 << 18, /* (Since: 3.1.0) */
|
||||||
|
VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI_DIRECT = 1 << 19, /* (Since: 5.6.0) */
|
||||||
|
+ VIR_CONNECT_LIST_STORAGE_POOLS_VITASTOR = 1 << 20, /* (Since: 5.0.0) */
|
||||||
|
} virConnectListAllStoragePoolsFlags;
|
||||||
|
|
||||||
|
int virConnectListAllStoragePools(virConnectPtr conn,
|
||||||
|
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
|
||||||
|
index 9ca5c2450c..cc52f00c0c 100644
|
||||||
|
--- a/src/conf/domain_conf.c
|
||||||
|
+++ b/src/conf/domain_conf.c
|
||||||
|
@@ -7453,7 +7453,8 @@ virDomainDiskSourceNetworkParse(xmlNodePtr node,
|
||||||
|
src->configFile = virXPathString("string(./config/@file)", ctxt);
|
||||||
|
|
||||||
|
if (src->protocol == VIR_STORAGE_NET_PROTOCOL_HTTP ||
|
||||||
|
- src->protocol == VIR_STORAGE_NET_PROTOCOL_HTTPS)
|
||||||
|
+ src->protocol == VIR_STORAGE_NET_PROTOCOL_HTTPS ||
|
||||||
|
+ src->protocol == VIR_STORAGE_NET_PROTOCOL_VITASTOR)
|
||||||
|
src->query = virXMLPropString(node, "query");
|
||||||
|
|
||||||
|
if (virDomainStorageNetworkParseHosts(node, ctxt, &src->hosts, &src->nhosts) < 0)
|
||||||
|
@@ -32187,6 +32188,7 @@ virDomainStorageSourceTranslateSourcePool(virStorageSource *src,
|
||||||
|
|
||||||
|
case VIR_STORAGE_POOL_MPATH:
|
||||||
|
case VIR_STORAGE_POOL_RBD:
|
||||||
|
+ case VIR_STORAGE_POOL_VITASTOR:
|
||||||
|
case VIR_STORAGE_POOL_SHEEPDOG:
|
||||||
|
case VIR_STORAGE_POOL_GLUSTER:
|
||||||
|
case VIR_STORAGE_POOL_LAST:
|
||||||
|
diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c
|
||||||
|
index 7346a61731..83e94d762e 100644
|
||||||
|
--- a/src/conf/domain_validate.c
|
||||||
|
+++ b/src/conf/domain_validate.c
|
||||||
|
@@ -520,6 +520,7 @@ virDomainDiskDefValidateSourceChainOne(const virStorageSource *src)
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_RBD:
|
||||||
|
break;
|
||||||
|
|
||||||
|
+ case VIR_STORAGE_NET_PROTOCOL_VITASTOR:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_NBD:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
|
||||||
|
@@ -592,7 +593,7 @@ virDomainDiskDefValidateSourceChainOne(const virStorageSource *src)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- /* internal snapshots and config files are currently supported only with rbd: */
|
||||||
|
+ /* internal snapshots are currently supported only with rbd: */
|
||||||
|
if (virStorageSourceGetActualType(src) != VIR_STORAGE_TYPE_NETWORK &&
|
||||||
|
src->protocol != VIR_STORAGE_NET_PROTOCOL_RBD) {
|
||||||
|
if (src->snapshot) {
|
||||||
|
@@ -600,10 +601,14 @@ virDomainDiskDefValidateSourceChainOne(const virStorageSource *src)
|
||||||
|
_("<snapshot> element is currently supported only with 'rbd' disks"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
-
|
||||||
|
+ }
|
||||||
|
+ /* config files are currently supported only with rbd and vitastor: */
|
||||||
|
+ if (virStorageSourceGetActualType(src) != VIR_STORAGE_TYPE_NETWORK &&
|
||||||
|
+ src->protocol != VIR_STORAGE_NET_PROTOCOL_RBD &&
|
||||||
|
+ src->protocol != VIR_STORAGE_NET_PROTOCOL_VITASTOR) {
|
||||||
|
if (src->configFile) {
|
||||||
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||||
|
- _("<config> element is currently supported only with 'rbd' disks"));
|
||||||
|
+ _("<config> element is currently supported only with 'rbd' and 'vitastor' disks"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng
|
||||||
|
index 114dd3f96f..c71f9a3277 100644
|
||||||
|
--- a/src/conf/schemas/domaincommon.rng
|
||||||
|
+++ b/src/conf/schemas/domaincommon.rng
|
||||||
|
@@ -2093,6 +2093,35 @@
|
||||||
|
</element>
|
||||||
|
</define>
|
||||||
|
|
||||||
|
+ <define name="diskSourceNetworkProtocolVitastor">
|
||||||
|
+ <element name="source">
|
||||||
|
+ <interleave>
|
||||||
|
+ <attribute name="protocol">
|
||||||
|
+ <value>vitastor</value>
|
||||||
|
+ </attribute>
|
||||||
|
+ <ref name="diskSourceCommon"/>
|
||||||
|
+ <optional>
|
||||||
|
+ <attribute name="name"/>
|
||||||
|
+ </optional>
|
||||||
|
+ <optional>
|
||||||
|
+ <attribute name="query"/>
|
||||||
|
+ </optional>
|
||||||
|
+ <zeroOrMore>
|
||||||
|
+ <ref name="diskSourceNetworkHost"/>
|
||||||
|
+ </zeroOrMore>
|
||||||
|
+ <optional>
|
||||||
|
+ <element name="config">
|
||||||
|
+ <attribute name="file">
|
||||||
|
+ <ref name="absFilePath"/>
|
||||||
|
+ </attribute>
|
||||||
|
+ <empty/>
|
||||||
|
+ </element>
|
||||||
|
+ </optional>
|
||||||
|
+ <empty/>
|
||||||
|
+ </interleave>
|
||||||
|
+ </element>
|
||||||
|
+ </define>
|
||||||
|
+
|
||||||
|
<define name="diskSourceNetworkProtocolISCSI">
|
||||||
|
<element name="source">
|
||||||
|
<attribute name="protocol">
|
||||||
|
@@ -2443,6 +2472,7 @@
|
||||||
|
<ref name="diskSourceNetworkProtocolSimple"/>
|
||||||
|
<ref name="diskSourceNetworkProtocolVxHS"/>
|
||||||
|
<ref name="diskSourceNetworkProtocolNFS"/>
|
||||||
|
+ <ref name="diskSourceNetworkProtocolVitastor"/>
|
||||||
|
</choice>
|
||||||
|
</define>
|
||||||
|
|
||||||
|
diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c
|
||||||
|
index 1dc9365bf2..a8a736be81 100644
|
||||||
|
--- a/src/conf/storage_conf.c
|
||||||
|
+++ b/src/conf/storage_conf.c
|
||||||
|
@@ -56,7 +56,7 @@ VIR_ENUM_IMPL(virStoragePool,
|
||||||
|
"logical", "disk", "iscsi",
|
||||||
|
"iscsi-direct", "scsi", "mpath",
|
||||||
|
"rbd", "sheepdog", "gluster",
|
||||||
|
- "zfs", "vstorage",
|
||||||
|
+ "zfs", "vstorage", "vitastor",
|
||||||
|
);
|
||||||
|
|
||||||
|
VIR_ENUM_IMPL(virStoragePoolFormatFileSystem,
|
||||||
|
@@ -242,6 +242,18 @@ static virStoragePoolTypeInfo poolTypeInfo[] = {
|
||||||
|
.formatToString = virStorageFileFormatTypeToString,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
+ {.poolType = VIR_STORAGE_POOL_VITASTOR,
|
||||||
|
+ .poolOptions = {
|
||||||
|
+ .flags = (VIR_STORAGE_POOL_SOURCE_HOST |
|
||||||
|
+ VIR_STORAGE_POOL_SOURCE_NETWORK |
|
||||||
|
+ VIR_STORAGE_POOL_SOURCE_NAME),
|
||||||
|
+ },
|
||||||
|
+ .volOptions = {
|
||||||
|
+ .defaultFormat = VIR_STORAGE_FILE_RAW,
|
||||||
|
+ .formatFromString = virStorageVolumeFormatFromString,
|
||||||
|
+ .formatToString = virStorageFileFormatTypeToString,
|
||||||
|
+ }
|
||||||
|
+ },
|
||||||
|
{.poolType = VIR_STORAGE_POOL_SHEEPDOG,
|
||||||
|
.poolOptions = {
|
||||||
|
.flags = (VIR_STORAGE_POOL_SOURCE_HOST |
|
||||||
|
@@ -538,6 +550,11 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
|
||||||
|
_("element 'name' is mandatory for RBD pool"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
+ if (pool_type == VIR_STORAGE_POOL_VITASTOR && source->name == NULL) {
|
||||||
|
+ virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||||
|
+ _("element 'name' is mandatory for Vitastor pool"));
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
if (options->formatFromString) {
|
||||||
|
g_autofree char *format = NULL;
|
||||||
|
@@ -1127,6 +1144,7 @@ virStoragePoolDefFormatBuf(virBuffer *buf,
|
||||||
|
/* RBD, Sheepdog, Gluster and Iscsi-direct devices are not local block devs nor
|
||||||
|
* files, so they don't have a target */
|
||||||
|
if (def->type != VIR_STORAGE_POOL_RBD &&
|
||||||
|
+ def->type != VIR_STORAGE_POOL_VITASTOR &&
|
||||||
|
def->type != VIR_STORAGE_POOL_SHEEPDOG &&
|
||||||
|
def->type != VIR_STORAGE_POOL_GLUSTER &&
|
||||||
|
def->type != VIR_STORAGE_POOL_ISCSI_DIRECT) {
|
||||||
|
diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h
|
||||||
|
index fc67957cfe..720c07ef74 100644
|
||||||
|
--- a/src/conf/storage_conf.h
|
||||||
|
+++ b/src/conf/storage_conf.h
|
||||||
|
@@ -103,6 +103,7 @@ typedef enum {
|
||||||
|
VIR_STORAGE_POOL_GLUSTER, /* Gluster device */
|
||||||
|
VIR_STORAGE_POOL_ZFS, /* ZFS */
|
||||||
|
VIR_STORAGE_POOL_VSTORAGE, /* Virtuozzo Storage */
|
||||||
|
+ VIR_STORAGE_POOL_VITASTOR, /* Vitastor */
|
||||||
|
|
||||||
|
VIR_STORAGE_POOL_LAST,
|
||||||
|
} virStoragePoolType;
|
||||||
|
@@ -454,6 +455,7 @@ VIR_ENUM_DECL(virStoragePartedFs);
|
||||||
|
VIR_CONNECT_LIST_STORAGE_POOLS_SCSI | \
|
||||||
|
VIR_CONNECT_LIST_STORAGE_POOLS_MPATH | \
|
||||||
|
VIR_CONNECT_LIST_STORAGE_POOLS_RBD | \
|
||||||
|
+ VIR_CONNECT_LIST_STORAGE_POOLS_VITASTOR | \
|
||||||
|
VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG | \
|
||||||
|
VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER | \
|
||||||
|
VIR_CONNECT_LIST_STORAGE_POOLS_ZFS | \
|
||||||
|
diff --git a/src/conf/storage_source_conf.c b/src/conf/storage_source_conf.c
|
||||||
|
index d7b9bdfecb..38aefd0dd4 100644
|
||||||
|
--- a/src/conf/storage_source_conf.c
|
||||||
|
+++ b/src/conf/storage_source_conf.c
|
||||||
|
@@ -90,6 +90,7 @@ VIR_ENUM_IMPL(virStorageNetProtocol,
|
||||||
|
"ssh",
|
||||||
|
"vxhs",
|
||||||
|
"nfs",
|
||||||
|
+ "vitastor",
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1317,6 +1318,7 @@ virStorageSourceNetworkDefaultPort(virStorageNetProtocol protocol)
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
|
||||||
|
return 24007;
|
||||||
|
|
||||||
|
+ case VIR_STORAGE_NET_PROTOCOL_VITASTOR:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_RBD:
|
||||||
|
/* we don't provide a default for RBD */
|
||||||
|
return 0;
|
||||||
|
diff --git a/src/conf/storage_source_conf.h b/src/conf/storage_source_conf.h
|
||||||
|
index 22c35d420d..f1e32ea83d 100644
|
||||||
|
--- a/src/conf/storage_source_conf.h
|
||||||
|
+++ b/src/conf/storage_source_conf.h
|
||||||
|
@@ -131,6 +131,7 @@ typedef enum {
|
||||||
|
VIR_STORAGE_NET_PROTOCOL_SSH,
|
||||||
|
VIR_STORAGE_NET_PROTOCOL_VXHS,
|
||||||
|
VIR_STORAGE_NET_PROTOCOL_NFS,
|
||||||
|
+ VIR_STORAGE_NET_PROTOCOL_VITASTOR,
|
||||||
|
|
||||||
|
VIR_STORAGE_NET_PROTOCOL_LAST
|
||||||
|
} virStorageNetProtocol;
|
||||||
|
diff --git a/src/conf/virstorageobj.c b/src/conf/virstorageobj.c
|
||||||
|
index 59fa5da372..4739167f5f 100644
|
||||||
|
--- a/src/conf/virstorageobj.c
|
||||||
|
+++ b/src/conf/virstorageobj.c
|
||||||
|
@@ -1438,6 +1438,7 @@ virStoragePoolObjSourceFindDuplicateCb(const void *payload,
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
+ case VIR_STORAGE_POOL_VITASTOR:
|
||||||
|
case VIR_STORAGE_POOL_ISCSI_DIRECT:
|
||||||
|
case VIR_STORAGE_POOL_RBD:
|
||||||
|
case VIR_STORAGE_POOL_LAST:
|
||||||
|
@@ -1921,6 +1922,8 @@ virStoragePoolObjMatch(virStoragePoolObj *obj,
|
||||||
|
(obj->def->type == VIR_STORAGE_POOL_MPATH)) ||
|
||||||
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_RBD) &&
|
||||||
|
(obj->def->type == VIR_STORAGE_POOL_RBD)) ||
|
||||||
|
+ (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_VITASTOR) &&
|
||||||
|
+ (obj->def->type == VIR_STORAGE_POOL_VITASTOR)) ||
|
||||||
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG) &&
|
||||||
|
(obj->def->type == VIR_STORAGE_POOL_SHEEPDOG)) ||
|
||||||
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER) &&
|
||||||
|
diff --git a/src/libvirt-storage.c b/src/libvirt-storage.c
|
||||||
|
index db7660aac4..561df34709 100644
|
||||||
|
--- a/src/libvirt-storage.c
|
||||||
|
+++ b/src/libvirt-storage.c
|
||||||
|
@@ -94,6 +94,7 @@ virStoragePoolGetConnect(virStoragePoolPtr pool)
|
||||||
|
* VIR_CONNECT_LIST_STORAGE_POOLS_SCSI
|
||||||
|
* VIR_CONNECT_LIST_STORAGE_POOLS_MPATH
|
||||||
|
* VIR_CONNECT_LIST_STORAGE_POOLS_RBD
|
||||||
|
+ * VIR_CONNECT_LIST_STORAGE_POOLS_VITASTOR
|
||||||
|
* VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG
|
||||||
|
* VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER
|
||||||
|
* VIR_CONNECT_LIST_STORAGE_POOLS_ZFS
|
||||||
|
diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c
|
||||||
|
index 2b988157fa..9d0eb47b25 100644
|
||||||
|
--- a/src/libxl/libxl_conf.c
|
||||||
|
+++ b/src/libxl/libxl_conf.c
|
||||||
|
@@ -1069,6 +1069,7 @@ libxlMakeNetworkDiskSrcStr(virStorageSource *src,
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_SSH:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_VXHS:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_NFS:
|
||||||
|
+ case VIR_STORAGE_NET_PROTOCOL_VITASTOR:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_LAST:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_NONE:
|
||||||
|
virReportError(VIR_ERR_NO_SUPPORT,
|
||||||
|
diff --git a/src/libxl/xen_xl.c b/src/libxl/xen_xl.c
|
||||||
|
index e72e7d7f44..8482c21805 100644
|
||||||
|
--- a/src/libxl/xen_xl.c
|
||||||
|
+++ b/src/libxl/xen_xl.c
|
||||||
|
@@ -1461,6 +1461,7 @@ xenFormatXLDiskSrcNet(virStorageSource *src)
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_SSH:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_VXHS:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_NFS:
|
||||||
|
+ case VIR_STORAGE_NET_PROTOCOL_VITASTOR:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_LAST:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_NONE:
|
||||||
|
virReportError(VIR_ERR_NO_SUPPORT,
|
||||||
|
diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c
|
||||||
|
index 9b43279797..459d8e8a65 100644
|
||||||
|
--- a/src/qemu/qemu_block.c
|
||||||
|
+++ b/src/qemu/qemu_block.c
|
||||||
|
@@ -743,6 +743,38 @@ qemuBlockStorageSourceGetRBDProps(virStorageSource *src,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
+static virJSONValue *
|
||||||
|
+qemuBlockStorageSourceGetVitastorProps(virStorageSource *src)
|
||||||
|
+{
|
||||||
|
+ virJSONValue *ret = NULL;
|
||||||
|
+ virStorageNetHostDef *host;
|
||||||
|
+ size_t i;
|
||||||
|
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
||||||
|
+ g_autofree char *etcd = NULL;
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < src->nhosts; i++) {
|
||||||
|
+ host = src->hosts + i;
|
||||||
|
+ if ((virStorageNetHostTransport)host->transport != VIR_STORAGE_NET_HOST_TRANS_TCP) {
|
||||||
|
+ return NULL;
|
||||||
|
+ }
|
||||||
|
+ virBufferAsprintf(&buf, i > 0 ? ",%s:%u" : "%s:%u", host->name, host->port);
|
||||||
|
+ }
|
||||||
|
+ if (src->nhosts > 0) {
|
||||||
|
+ etcd = virBufferContentAndReset(&buf);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (virJSONValueObjectAdd(&ret,
|
||||||
|
+ "S:etcd-host", etcd,
|
||||||
|
+ "S:etcd-prefix", src->query,
|
||||||
|
+ "S:config-path", src->configFile,
|
||||||
|
+ "s:image", src->path,
|
||||||
|
+ NULL) < 0)
|
||||||
|
+ return NULL;
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+
|
||||||
|
static virJSONValue *
|
||||||
|
qemuBlockStorageSourceGetSshProps(virStorageSource *src)
|
||||||
|
{
|
||||||
|
@@ -1094,6 +1126,12 @@ qemuBlockStorageSourceGetBackendProps(virStorageSource *src,
|
||||||
|
return NULL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
+ case VIR_STORAGE_NET_PROTOCOL_VITASTOR:
|
||||||
|
+ driver = "vitastor";
|
||||||
|
+ if (!(fileprops = qemuBlockStorageSourceGetVitastorProps(src)))
|
||||||
|
+ return NULL;
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_SSH:
|
||||||
|
driver = "ssh";
|
||||||
|
if (!(fileprops = qemuBlockStorageSourceGetSshProps(src)))
|
||||||
|
@@ -1997,6 +2035,7 @@ qemuBlockGetBackingStoreString(virStorageSource *src,
|
||||||
|
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_RBD:
|
||||||
|
+ case VIR_STORAGE_NET_PROTOCOL_VITASTOR:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_VXHS:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_NFS:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_SSH:
|
||||||
|
@@ -2377,6 +2416,12 @@ qemuBlockStorageSourceCreateGetStorageProps(virStorageSource *src,
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
+ case VIR_STORAGE_NET_PROTOCOL_VITASTOR:
|
||||||
|
+ driver = "vitastor";
|
||||||
|
+ if (!(location = qemuBlockStorageSourceGetVitastorProps(src)))
|
||||||
|
+ return -1;
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_SSH:
|
||||||
|
if (srcPriv->nbdkitProcess) {
|
||||||
|
/* disk creation not yet supported with nbdkit, and even if it
|
||||||
|
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
|
||||||
|
index ac56fc7cb4..9e407b4aab 100644
|
||||||
|
--- a/src/qemu/qemu_domain.c
|
||||||
|
+++ b/src/qemu/qemu_domain.c
|
||||||
|
@@ -4677,7 +4677,8 @@ qemuDomainValidateStorageSource(virStorageSource *src,
|
||||||
|
if (src->query &&
|
||||||
|
(actualType != VIR_STORAGE_TYPE_NETWORK ||
|
||||||
|
(src->protocol != VIR_STORAGE_NET_PROTOCOL_HTTPS &&
|
||||||
|
- src->protocol != VIR_STORAGE_NET_PROTOCOL_HTTP))) {
|
||||||
|
+ src->protocol != VIR_STORAGE_NET_PROTOCOL_HTTP &&
|
||||||
|
+ src->protocol != VIR_STORAGE_NET_PROTOCOL_VITASTOR))) {
|
||||||
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||||
|
_("query is supported only with HTTP(S) protocols"));
|
||||||
|
return -1;
|
||||||
|
@@ -9103,6 +9104,7 @@ qemuDomainPrepareStorageSourceTLS(virStorageSource *src,
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_RBD:
|
||||||
|
+ case VIR_STORAGE_NET_PROTOCOL_VITASTOR:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_ISCSI:
|
||||||
|
diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c
|
||||||
|
index e738afffc3..37d64f469b 100644
|
||||||
|
--- a/src/qemu/qemu_snapshot.c
|
||||||
|
+++ b/src/qemu/qemu_snapshot.c
|
||||||
|
@@ -665,6 +665,7 @@ qemuSnapshotPrepareDiskExternalInactive(virDomainSnapshotDiskDef *snapdisk,
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_NONE:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_NBD:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_RBD:
|
||||||
|
+ case VIR_STORAGE_NET_PROTOCOL_VITASTOR:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_ISCSI:
|
||||||
|
@@ -893,6 +894,7 @@ qemuSnapshotPrepareDiskInternal(virDomainDiskDef *disk,
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_NONE:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_NBD:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_RBD:
|
||||||
|
+ case VIR_STORAGE_NET_PROTOCOL_VITASTOR:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_ISCSI:
|
||||||
|
diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c
|
||||||
|
index e19e032427..59f91f4710 100644
|
||||||
|
--- a/src/storage/storage_driver.c
|
||||||
|
+++ b/src/storage/storage_driver.c
|
||||||
|
@@ -1626,6 +1626,7 @@ storageVolLookupByPathCallback(virStoragePoolObj *obj,
|
||||||
|
|
||||||
|
case VIR_STORAGE_POOL_GLUSTER:
|
||||||
|
case VIR_STORAGE_POOL_RBD:
|
||||||
|
+ case VIR_STORAGE_POOL_VITASTOR:
|
||||||
|
case VIR_STORAGE_POOL_SHEEPDOG:
|
||||||
|
case VIR_STORAGE_POOL_ZFS:
|
||||||
|
case VIR_STORAGE_POOL_LAST:
|
||||||
|
diff --git a/src/storage_file/storage_source_backingstore.c b/src/storage_file/storage_source_backingstore.c
|
||||||
|
index 821378883c..2211f6891b 100644
|
||||||
|
--- a/src/storage_file/storage_source_backingstore.c
|
||||||
|
+++ b/src/storage_file/storage_source_backingstore.c
|
||||||
|
@@ -264,6 +264,75 @@ virStorageSourceParseRBDColonString(const char *rbdstr,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
+static int
|
||||||
|
+virStorageSourceParseVitastorColonString(const char *colonstr,
|
||||||
|
+ virStorageSource *src)
|
||||||
|
+{
|
||||||
|
+ char *p, *e, *next;
|
||||||
|
+ g_autofree char *options = NULL;
|
||||||
|
+
|
||||||
|
+ /* optionally skip the "vitastor:" prefix if provided */
|
||||||
|
+ if (STRPREFIX(colonstr, "vitastor:"))
|
||||||
|
+ colonstr += strlen("vitastor:");
|
||||||
|
+
|
||||||
|
+ options = g_strdup(colonstr);
|
||||||
|
+
|
||||||
|
+ p = options;
|
||||||
|
+ while (*p) {
|
||||||
|
+ /* find : delimiter or end of string */
|
||||||
|
+ for (e = p; *e && *e != ':'; ++e) {
|
||||||
|
+ if (*e == '\\') {
|
||||||
|
+ e++;
|
||||||
|
+ if (*e == '\0')
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ if (*e == '\0') {
|
||||||
|
+ next = e; /* last kv pair */
|
||||||
|
+ } else {
|
||||||
|
+ next = e + 1;
|
||||||
|
+ *e = '\0';
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (STRPREFIX(p, "image=")) {
|
||||||
|
+ src->path = g_strdup(p + strlen("image="));
|
||||||
|
+ } else if (STRPREFIX(p, "etcd-prefix=")) {
|
||||||
|
+ src->query = g_strdup(p + strlen("etcd-prefix="));
|
||||||
|
+ } else if (STRPREFIX(p, "config-path=")) {
|
||||||
|
+ src->configFile = g_strdup(p + strlen("config-path="));
|
||||||
|
+ } else if (STRPREFIX(p, "etcd-host=")) {
|
||||||
|
+ char *h, *sep;
|
||||||
|
+
|
||||||
|
+ h = p + strlen("etcd-host=");
|
||||||
|
+ while (h < e) {
|
||||||
|
+ for (sep = h; sep < e; ++sep) {
|
||||||
|
+ if (*sep == '\\' && (sep[1] == ',' ||
|
||||||
|
+ sep[1] == ';' ||
|
||||||
|
+ sep[1] == ' ')) {
|
||||||
|
+ *sep = '\0';
|
||||||
|
+ sep += 2;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (virStorageSourceRBDAddHost(src, h) < 0)
|
||||||
|
+ return -1;
|
||||||
|
+
|
||||||
|
+ h = sep;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ p = next;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (!src->path) {
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+
|
||||||
|
static int
|
||||||
|
virStorageSourceParseNBDColonString(const char *nbdstr,
|
||||||
|
virStorageSource *src)
|
||||||
|
@@ -379,6 +448,11 @@ virStorageSourceParseBackingColon(virStorageSource *src,
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
+ case VIR_STORAGE_NET_PROTOCOL_VITASTOR:
|
||||||
|
+ if (virStorageSourceParseVitastorColonString(path, src) < 0)
|
||||||
|
+ return -1;
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_LAST:
|
||||||
|
case VIR_STORAGE_NET_PROTOCOL_NONE:
|
||||||
|
@@ -953,6 +1027,54 @@ virStorageSourceParseBackingJSONRBD(virStorageSource *src,
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int
|
||||||
|
+virStorageSourceParseBackingJSONVitastor(virStorageSource *src,
|
||||||
|
+ virJSONValue *json,
|
||||||
|
+ const char *jsonstr G_GNUC_UNUSED,
|
||||||
|
+ int opaque G_GNUC_UNUSED)
|
||||||
|
+{
|
||||||
|
+ const char *filename;
|
||||||
|
+ const char *image = virJSONValueObjectGetString(json, "image");
|
||||||
|
+ const char *conf = virJSONValueObjectGetString(json, "config-path");
|
||||||
|
+ const char *etcd_prefix = virJSONValueObjectGetString(json, "etcd-prefix");
|
||||||
|
+ virJSONValue *servers = virJSONValueObjectGetArray(json, "server");
|
||||||
|
+ size_t nservers;
|
||||||
|
+ size_t i;
|
||||||
|
+
|
||||||
|
+ src->type = VIR_STORAGE_TYPE_NETWORK;
|
||||||
|
+ src->protocol = VIR_STORAGE_NET_PROTOCOL_VITASTOR;
|
||||||
|
+
|
||||||
|
+ /* legacy syntax passed via 'filename' option */
|
||||||
|
+ if ((filename = virJSONValueObjectGetString(json, "filename")))
|
||||||
|
+ return virStorageSourceParseVitastorColonString(filename, src);
|
||||||
|
+
|
||||||
|
+ if (!image) {
|
||||||
|
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
|
||||||
|
+ _("missing image name in Vitastor backing volume "
|
||||||
|
+ "JSON specification"));
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ src->path = g_strdup(image);
|
||||||
|
+ src->configFile = g_strdup(conf);
|
||||||
|
+ src->query = g_strdup(etcd_prefix);
|
||||||
|
+
|
||||||
|
+ if (servers) {
|
||||||
|
+ nservers = virJSONValueArraySize(servers);
|
||||||
|
+
|
||||||
|
+ src->hosts = g_new0(virStorageNetHostDef, nservers);
|
||||||
|
+ src->nhosts = nservers;
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < nservers; i++) {
|
||||||
|
+ if (virStorageSourceParseBackingJSONInetSocketAddress(src->hosts + i,
|
||||||
|
+ virJSONValueArrayGet(servers, i)) < 0)
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int
|
||||||
|
virStorageSourceParseBackingJSONRaw(virStorageSource *src,
|
||||||
|
virJSONValue *json,
|
||||||
|
@@ -1130,6 +1252,7 @@ static const struct virStorageSourceJSONDriverParser jsonParsers[] = {
|
||||||
|
{"sheepdog", false, virStorageSourceParseBackingJSONSheepdog, 0},
|
||||||
|
{"ssh", false, virStorageSourceParseBackingJSONSSH, 0},
|
||||||
|
{"rbd", false, virStorageSourceParseBackingJSONRBD, 0},
|
||||||
|
+ {"vitastor", false, virStorageSourceParseBackingJSONVitastor, 0},
|
||||||
|
{"raw", true, virStorageSourceParseBackingJSONRaw, 0},
|
||||||
|
{"nfs", false, virStorageSourceParseBackingJSONNFS, 0},
|
||||||
|
{"vxhs", false, virStorageSourceParseBackingJSONVxHS, 0},
|
||||||
|
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
|
||||||
|
index 1165689de7..bba846351c 100644
|
||||||
|
--- a/src/test/test_driver.c
|
||||||
|
+++ b/src/test/test_driver.c
|
||||||
|
@@ -7345,6 +7345,7 @@ testStorageVolumeTypeForPool(int pooltype)
|
||||||
|
case VIR_STORAGE_POOL_ISCSI_DIRECT:
|
||||||
|
case VIR_STORAGE_POOL_GLUSTER:
|
||||||
|
case VIR_STORAGE_POOL_RBD:
|
||||||
|
+ case VIR_STORAGE_POOL_VITASTOR:
|
||||||
|
return VIR_STORAGE_VOL_NETWORK;
|
||||||
|
case VIR_STORAGE_POOL_LOGICAL:
|
||||||
|
case VIR_STORAGE_POOL_DISK:
|
||||||
|
diff --git a/tests/storagepoolcapsschemadata/poolcaps-fs.xml b/tests/storagepoolcapsschemadata/poolcaps-fs.xml
|
||||||
|
index eee75af746..8bd0a57bdd 100644
|
||||||
|
--- a/tests/storagepoolcapsschemadata/poolcaps-fs.xml
|
||||||
|
+++ b/tests/storagepoolcapsschemadata/poolcaps-fs.xml
|
||||||
|
@@ -204,4 +204,11 @@
|
||||||
|
</enum>
|
||||||
|
</volOptions>
|
||||||
|
</pool>
|
||||||
|
+ <pool type='vitastor' supported='no'>
|
||||||
|
+ <volOptions>
|
||||||
|
+ <defaultFormat type='raw'/>
|
||||||
|
+ <enum name='targetFormatType'>
|
||||||
|
+ </enum>
|
||||||
|
+ </volOptions>
|
||||||
|
+ </pool>
|
||||||
|
</storagepoolCapabilities>
|
||||||
|
diff --git a/tests/storagepoolcapsschemadata/poolcaps-full.xml b/tests/storagepoolcapsschemadata/poolcaps-full.xml
|
||||||
|
index 805950a937..852df0de16 100644
|
||||||
|
--- a/tests/storagepoolcapsschemadata/poolcaps-full.xml
|
||||||
|
+++ b/tests/storagepoolcapsschemadata/poolcaps-full.xml
|
||||||
|
@@ -204,4 +204,11 @@
|
||||||
|
</enum>
|
||||||
|
</volOptions>
|
||||||
|
</pool>
|
||||||
|
+ <pool type='vitastor' supported='yes'>
|
||||||
|
+ <volOptions>
|
||||||
|
+ <defaultFormat type='raw'/>
|
||||||
|
+ <enum name='targetFormatType'>
|
||||||
|
+ </enum>
|
||||||
|
+ </volOptions>
|
||||||
|
+ </pool>
|
||||||
|
</storagepoolCapabilities>
|
||||||
|
diff --git a/tests/storagepoolxml2argvtest.c b/tests/storagepoolxml2argvtest.c
|
||||||
|
index d5c2531ab8..b19308ac38 100644
|
||||||
|
--- a/tests/storagepoolxml2argvtest.c
|
||||||
|
+++ b/tests/storagepoolxml2argvtest.c
|
||||||
|
@@ -57,6 +57,7 @@ testCompareXMLToArgvFiles(bool shouldFail,
|
||||||
|
case VIR_STORAGE_POOL_GLUSTER:
|
||||||
|
case VIR_STORAGE_POOL_ZFS:
|
||||||
|
case VIR_STORAGE_POOL_VSTORAGE:
|
||||||
|
+ case VIR_STORAGE_POOL_VITASTOR:
|
||||||
|
case VIR_STORAGE_POOL_LAST:
|
||||||
|
default:
|
||||||
|
VIR_TEST_DEBUG("pool type '%s' has no xml2argv test", defTypeStr);
|
||||||
|
diff --git a/tools/virsh-pool.c b/tools/virsh-pool.c
|
||||||
|
index 2010ef1356..072e2ff9e8 100644
|
||||||
|
--- a/tools/virsh-pool.c
|
||||||
|
+++ b/tools/virsh-pool.c
|
||||||
|
@@ -1187,6 +1187,9 @@ cmdPoolList(vshControl *ctl, const vshCmd *cmd G_GNUC_UNUSED)
|
||||||
|
case VIR_STORAGE_POOL_VSTORAGE:
|
||||||
|
flags |= VIR_CONNECT_LIST_STORAGE_POOLS_VSTORAGE;
|
||||||
|
break;
|
||||||
|
+ case VIR_STORAGE_POOL_VITASTOR:
|
||||||
|
+ flags |= VIR_CONNECT_LIST_STORAGE_POOLS_VITASTOR;
|
||||||
|
+ break;
|
||||||
|
case VIR_STORAGE_POOL_LAST:
|
||||||
|
break;
|
||||||
|
}
|
||||||
@@ -1,29 +1,172 @@
|
|||||||
diff --git a/src/client/qemu_driver.c b/src/client/qemu_driver.c
|
diff --git a/block/meson.build b/block/meson.build
|
||||||
index d8356dab..5f4cd50d 100644
|
index 34b1b2a306..24ca0f1e52 100644
|
||||||
--- a/src/client/qemu_driver.c
|
--- a/block/meson.build
|
||||||
+++ b/src/client/qemu_driver.c
|
+++ b/block/meson.build
|
||||||
@@ -974,14 +974,21 @@ static void vitastor_co_read_bitmap_cb(void *opaque, long retval, uint8_t *bitma
|
@@ -114,6 +114,7 @@ foreach m : [
|
||||||
#endif
|
[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 50c774a195..e5c7a3a4b1 100644
|
||||||
|
--- a/meson.build
|
||||||
|
+++ b/meson.build
|
||||||
|
@@ -1652,6 +1652,26 @@ if not get_option('rbd').auto() or have_block
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
-static int coroutine_fn vitastor_co_block_status(
|
+vitastor = not_found
|
||||||
- BlockDriverState *bs, bool want_zero, int64_t offset, int64_t bytes,
|
+if not get_option('vitastor').auto() or have_block
|
||||||
- int64_t *pnum, int64_t *map, BlockDriverState **file)
|
+ libvitastor_client = cc.find_library('vitastor_client', has_headers: ['vitastor_c.h'],
|
||||||
+static int coroutine_fn vitastor_co_block_status(BlockDriverState *bs,
|
+ required: get_option('vitastor'))
|
||||||
+#if QEMU_VERSION_MAJOR > 10 || QEMU_VERSION_MAJOR == 10 && QEMU_VERSION_MINOR >= 1
|
+ if libvitastor_client.found()
|
||||||
+ unsigned int mode,
|
+ if cc.links('''
|
||||||
+#else
|
+ #include <vitastor_c.h>
|
||||||
+ bool want_zero,
|
+ int main(void) {
|
||||||
+#endif
|
+ vitastor_c_create_qemu(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||||
+ int64_t offset, int64_t bytes, int64_t *pnum, int64_t *map, BlockDriverState **file)
|
+ return 0;
|
||||||
{
|
+ }''', dependencies: libvitastor_client)
|
||||||
// Allocated => return BDRV_BLOCK_DATA|BDRV_BLOCK_OFFSET_VALID
|
+ vitastor = declare_dependency(dependencies: libvitastor_client)
|
||||||
// Not allocated => return 0
|
+ elif get_option('vitastor').enabled()
|
||||||
// Error => return -errno
|
+ error('could not link libvitastor_client')
|
||||||
// Set pnum to length of the extent, `*map` = `offset`, `*file` = `bs`
|
+ else
|
||||||
+#if QEMU_VERSION_MAJOR > 10 || QEMU_VERSION_MAJOR == 10 && QEMU_VERSION_MINOR >= 1
|
+ warning('could not link libvitastor_client, disabling')
|
||||||
+ int want_zero = (mode == BDRV_WANT_PRECISE);
|
+ endif
|
||||||
+#endif
|
+ endif
|
||||||
VitastorRPC task;
|
+endif
|
||||||
VitastorClient *client = bs->opaque;
|
+
|
||||||
uint64_t inode = client->watch ? vitastor_c_inode_get_num(client->watch) : client->inode;
|
glusterfs = not_found
|
||||||
|
glusterfs_ftruncate_has_stat = false
|
||||||
|
glusterfs_iocb_has_stat = false
|
||||||
|
@@ -2547,6 +2567,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'))
|
||||||
|
@@ -4972,6 +4993,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 fff1521e58..f0844c0e00 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 dc6eb4ae23..d043f4340e 100644
|
||||||
|
--- a/qapi/block-core.json
|
||||||
|
+++ b/qapi/block-core.json
|
||||||
|
@@ -3280,7 +3280,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' },
|
||||||
|
@@ -4363,6 +4363,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:
|
||||||
|
#
|
||||||
|
@@ -4831,6 +4853,7 @@
|
||||||
|
'throttle': 'BlockdevOptionsThrottle',
|
||||||
|
'vdi': 'BlockdevOptionsGenericFormat',
|
||||||
|
'vhdx': 'BlockdevOptionsGenericFormat',
|
||||||
|
+ 'vitastor': 'BlockdevOptionsVitastor',
|
||||||
|
'virtio-blk-vfio-pci':
|
||||||
|
{ 'type': 'BlockdevOptionsVirtioBlkVfioPci',
|
||||||
|
'if': 'CONFIG_BLKIO' },
|
||||||
|
@@ -5304,6 +5327,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:
|
||||||
|
#
|
||||||
|
@@ -5526,6 +5563,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 0ebe6bc52a..2c37ad3892 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'
|
||||||
|
@@ -459,6 +460,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 ;;
|
||||||
|
|||||||
@@ -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 d9293294d8..776a5becc6 100644
|
||||||
|
--- a/meson.build
|
||||||
|
+++ b/meson.build
|
||||||
|
@@ -1665,6 +1665,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
|
||||||
|
@@ -2509,6 +2529,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'))
|
||||||
|
@@ -4948,6 +4969,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 2836156257..148086cc6f 100644
|
||||||
|
--- a/meson_options.txt
|
||||||
|
+++ b/meson_options.txt
|
||||||
|
@@ -206,6 +206,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 b82af74256..f25a6f5ce8 100644
|
||||||
|
--- a/qapi/block-core.json
|
||||||
|
+++ b/qapi/block-core.json
|
||||||
|
@@ -3351,7 +3351,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' },
|
||||||
|
@@ -4434,6 +4434,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:
|
||||||
|
#
|
||||||
|
@@ -4902,6 +4924,7 @@
|
||||||
|
'throttle': 'BlockdevOptionsThrottle',
|
||||||
|
'vdi': 'BlockdevOptionsGenericFormat',
|
||||||
|
'vhdx': 'BlockdevOptionsGenericFormat',
|
||||||
|
+ 'vitastor': 'BlockdevOptionsVitastor',
|
||||||
|
'virtio-blk-vfio-pci':
|
||||||
|
{ 'type': 'BlockdevOptionsVirtioBlkVfioPci',
|
||||||
|
'if': 'CONFIG_BLKIO' },
|
||||||
|
@@ -5376,6 +5399,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:
|
||||||
|
#
|
||||||
|
@@ -5598,6 +5635,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 3d0d132344..65ee8c855e 100644
|
||||||
|
--- a/scripts/meson-buildoptions.sh
|
||||||
|
+++ b/scripts/meson-buildoptions.sh
|
||||||
|
@@ -177,6 +177,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'
|
||||||
|
@@ -464,6 +465,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 ;;
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
Name: vitastor
|
Name: vitastor
|
||||||
Version: 3.0.5
|
Version: 3.0.12
|
||||||
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-3.0.5.el10.tar.gz
|
Source0: vitastor-3.0.12.el10.tar.gz
|
||||||
|
|
||||||
BuildRequires: gperftools-devel
|
BuildRequires: gperftools-devel
|
||||||
BuildRequires: gcc-c++
|
BuildRequires: gcc-c++
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
Name: vitastor
|
Name: vitastor
|
||||||
Version: 3.0.5
|
Version: 3.0.12
|
||||||
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-3.0.5.el7.tar.gz
|
Source0: vitastor-3.0.12.el7.tar.gz
|
||||||
|
|
||||||
BuildRequires: gperftools-devel
|
BuildRequires: gperftools-devel
|
||||||
BuildRequires: devtoolset-9-gcc-c++
|
BuildRequires: devtoolset-9-gcc-c++
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
Name: vitastor
|
Name: vitastor
|
||||||
Version: 3.0.5
|
Version: 3.0.12
|
||||||
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-3.0.5.el8.tar.gz
|
Source0: vitastor-3.0.12.el8.tar.gz
|
||||||
|
|
||||||
BuildRequires: gperftools-devel
|
BuildRequires: gperftools-devel
|
||||||
BuildRequires: gcc-toolset-9-gcc-c++
|
BuildRequires: gcc-toolset-9-gcc-c++
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
Name: vitastor
|
Name: vitastor
|
||||||
Version: 3.0.5
|
Version: 3.0.12
|
||||||
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-3.0.5.el9.tar.gz
|
Source0: vitastor-3.0.12.el9.tar.gz
|
||||||
|
|
||||||
BuildRequires: gperftools-devel
|
BuildRequires: gperftools-devel
|
||||||
BuildRequires: gcc-c++
|
BuildRequires: gcc-c++
|
||||||
|
|||||||
+2
-3
@@ -1,9 +1,8 @@
|
|||||||
cmake_minimum_required(VERSION 2.8.12)
|
cmake_minimum_required(VERSION 2.8...3.30)
|
||||||
|
|
||||||
project(vitastor)
|
project(vitastor)
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
include(CTest)
|
|
||||||
include(CheckIncludeFile)
|
include(CheckIncludeFile)
|
||||||
|
|
||||||
find_package(PkgConfig)
|
find_package(PkgConfig)
|
||||||
@@ -21,7 +20,7 @@ if("${CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/local/?$")
|
|||||||
endif()
|
endif()
|
||||||
set(ENABLE_COVERAGE false CACHE BOOL "Enable code coverage")
|
set(ENABLE_COVERAGE false CACHE BOOL "Enable code coverage")
|
||||||
|
|
||||||
add_definitions(-DVITASTOR_VERSION="3.0.5")
|
add_definitions(-DVITASTOR_VERSION="3.0.12")
|
||||||
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_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})
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 2.8.12)
|
cmake_minimum_required(VERSION 2.8...3.30)
|
||||||
|
|
||||||
project(vitastor)
|
project(vitastor)
|
||||||
|
|
||||||
|
|||||||
@@ -228,4 +228,9 @@ public:
|
|||||||
virtual uint64_t get_journal_size() = 0;
|
virtual uint64_t get_journal_size() = 0;
|
||||||
|
|
||||||
virtual uint32_t get_bitmap_granularity() = 0;
|
virtual uint32_t get_bitmap_granularity() = 0;
|
||||||
|
|
||||||
|
virtual uint64_t get_live_entries() = 0;
|
||||||
|
virtual uint64_t get_live_memory() = 0;
|
||||||
|
virtual uint64_t get_garbage_entries() = 0;
|
||||||
|
virtual uint64_t get_garbage_memory() = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -94,6 +94,9 @@ void blockstore_disk_t::parse_config(std::map<std::string, std::string> & config
|
|||||||
csum_block_size = parse_size(config["csum_block_size"]);
|
csum_block_size = parse_size(config["csum_block_size"]);
|
||||||
discard_on_start = config.find("discard_on_start") != config.end() &&
|
discard_on_start = config.find("discard_on_start") != config.end() &&
|
||||||
(config["discard_on_start"] == "true" || config["discard_on_start"] == "1" || config["discard_on_start"] == "yes");
|
(config["discard_on_start"] == "true" || config["discard_on_start"] == "1" || config["discard_on_start"] == "yes");
|
||||||
|
gc_on_start = config.find("gc_on_start") == config.end() ||
|
||||||
|
(config["gc_on_start"] == "true" || config["gc_on_start"] == "1" || config["gc_on_start"] == "yes");
|
||||||
|
skip_double_claim = (config["skip_double_claim"] == "true" || config["skip_double_claim"] == "1" || config["skip_double_claim"] == "yes");
|
||||||
min_discard_size = parse_size(config["min_discard_size"]);
|
min_discard_size = parse_size(config["min_discard_size"]);
|
||||||
if (!min_discard_size)
|
if (!min_discard_size)
|
||||||
min_discard_size = 1024*1024;
|
min_discard_size = 1024*1024;
|
||||||
|
|||||||
@@ -57,6 +57,10 @@ struct blockstore_disk_t
|
|||||||
bool inmemory_journal = true;
|
bool inmemory_journal = true;
|
||||||
// Data discard granularity and minimum size (for the sake of performance)
|
// Data discard granularity and minimum size (for the sake of performance)
|
||||||
bool discard_on_start = false;
|
bool discard_on_start = false;
|
||||||
|
// GC on start (new store)
|
||||||
|
bool gc_on_start = true;
|
||||||
|
// Skip double claim conflicts on start (new store, temporary until the bug is found)
|
||||||
|
bool skip_double_claim = false;
|
||||||
uint64_t min_discard_size = 1024*1024;
|
uint64_t min_discard_size = 1024*1024;
|
||||||
uint64_t discard_granularity = 0;
|
uint64_t discard_granularity = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -174,14 +174,18 @@ bool journal_flusher_co::loop()
|
|||||||
else if (wait_state == 19) goto resume_19;
|
else if (wait_state == 19) goto resume_19;
|
||||||
else if (wait_state == 20) goto resume_20;
|
else if (wait_state == 20) goto resume_20;
|
||||||
else if (wait_state == 21) goto resume_21;
|
else if (wait_state == 21) goto resume_21;
|
||||||
|
else if (wait_state == 22) goto resume_22;
|
||||||
|
else if (wait_state == 23) goto resume_23;
|
||||||
|
else if (wait_state == 24) goto resume_24;
|
||||||
|
else if (wait_state == 25) goto resume_25;
|
||||||
resume_0:
|
resume_0:
|
||||||
wait_state = 0;
|
wait_state = 0;
|
||||||
wait_count = 0;
|
wait_count = 0;
|
||||||
cur_oid = {};
|
cur_oid = {};
|
||||||
res = bs->heap->get_next_compact(cur_oid);
|
res = bs->heap->get_next_compact(cur_oid);
|
||||||
// Advance fsynced_lsn every <journal_trim_interval> intent writes
|
|
||||||
if ((bs->intent_write_counter >= bs->journal_trim_interval) && co_id == 0)
|
if ((bs->intent_write_counter >= bs->journal_trim_interval) && co_id == 0)
|
||||||
{
|
{
|
||||||
|
// Advance fsynced_lsn every <journal_trim_interval> intent writes
|
||||||
bs->intent_write_counter = 0;
|
bs->intent_write_counter = 0;
|
||||||
resume_17:
|
resume_17:
|
||||||
resume_18:
|
resume_18:
|
||||||
@@ -196,6 +200,7 @@ resume_21:
|
|||||||
if (res == ENOENT && flusher->force_start > 0 && co_id == 0 &&
|
if (res == ENOENT && flusher->force_start > 0 && co_id == 0 &&
|
||||||
(!bs->dsk.disable_journal_fsync || !bs->dsk.disable_meta_fsync || !bs->dsk.disable_data_fsync))
|
(!bs->dsk.disable_journal_fsync || !bs->dsk.disable_meta_fsync || !bs->dsk.disable_data_fsync))
|
||||||
{
|
{
|
||||||
|
// When under pressure, do an additional fsync to force entries to be marked compactable
|
||||||
flusher->active_flushers++;
|
flusher->active_flushers++;
|
||||||
resume_14:
|
resume_14:
|
||||||
resume_15:
|
resume_15:
|
||||||
@@ -259,11 +264,9 @@ resume_1:
|
|||||||
if (wr->type() == BS_HEAP_SMALL_WRITE ||
|
if (wr->type() == BS_HEAP_SMALL_WRITE ||
|
||||||
wr->type() == BS_HEAP_INTENT_WRITE && bs->dsk.csum_block_size > bs->dsk.bitmap_granularity)
|
wr->type() == BS_HEAP_INTENT_WRITE && bs->dsk.csum_block_size > bs->dsk.bitmap_granularity)
|
||||||
{
|
{
|
||||||
auto res = bs->prepare_read(read_vec, cur_obj, wr, 0, bs->dsk.data_block_size,
|
bs->prepare_read(read_vec, cur_obj, wr, 0, bs->dsk.data_block_size,
|
||||||
wr->type() == BS_HEAP_INTENT_WRITE && bs->dsk.csum_block_size > bs->dsk.bitmap_granularity && !bs->perfect_csum_update
|
wr->type() == BS_HEAP_INTENT_WRITE && bs->dsk.csum_block_size > bs->dsk.bitmap_granularity && !bs->perfect_csum_update
|
||||||
? COPY_BUF_SKIP_CSUM : 0);
|
? COPY_BUF_SKIP_CSUM : 0);
|
||||||
if (res > 0)
|
|
||||||
copy_count++;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (!compact_info.compact_lsn)
|
if (!compact_info.compact_lsn)
|
||||||
@@ -273,6 +276,25 @@ resume_1:
|
|||||||
bs->heap->unlock_entry(cur_oid);
|
bs->heap->unlock_entry(cur_oid);
|
||||||
goto resume_0;
|
goto resume_0;
|
||||||
}
|
}
|
||||||
|
flusher->active_flushers++;
|
||||||
|
for (i = 0; i < read_vec.size(); i++)
|
||||||
|
{
|
||||||
|
if ((read_vec[i].copy_flags & COPY_BUF_JOURNAL) &&
|
||||||
|
!(read_vec[i].copy_flags & COPY_BUF_COALESCED))
|
||||||
|
{
|
||||||
|
copy_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (copy_count > 0 && !bs->dsk.disable_data_fsync)
|
||||||
|
{
|
||||||
|
init_fsync_data();
|
||||||
|
}
|
||||||
|
if (bs->log_level > 10)
|
||||||
|
{
|
||||||
|
printf("Compacting %jx:%jx v%ju..v%ju / l%ju..l%ju (%d writes)\n", cur_oid.inode, cur_oid.stripe,
|
||||||
|
compact_info.clean_wr->version, compact_info.compact_version,
|
||||||
|
compact_info.clean_wr->lsn, compact_info.compact_lsn, copy_count);
|
||||||
|
}
|
||||||
mem_or(new_bmp, compact_info.clean_wr->get_int_bitmap(bs->heap), bs->dsk.clean_entry_bitmap_size);
|
mem_or(new_bmp, compact_info.clean_wr->get_int_bitmap(bs->heap), bs->dsk.clean_entry_bitmap_size);
|
||||||
if (!bitmap_copied)
|
if (!bitmap_copied)
|
||||||
{
|
{
|
||||||
@@ -291,13 +313,6 @@ resume_1:
|
|||||||
csum_copy.clear();
|
csum_copy.clear();
|
||||||
}
|
}
|
||||||
clean_loc = compact_info.clean_wr->big_location(bs->heap);
|
clean_loc = compact_info.clean_wr->big_location(bs->heap);
|
||||||
flusher->active_flushers++;
|
|
||||||
if (bs->log_level > 10)
|
|
||||||
{
|
|
||||||
printf("Compacting %jx:%jx v%ju..v%ju / l%ju..l%ju (%d writes)\n", cur_oid.inode, cur_oid.stripe,
|
|
||||||
compact_info.clean_wr->version, compact_info.compact_version,
|
|
||||||
compact_info.clean_wr->lsn, compact_info.compact_lsn, copy_count);
|
|
||||||
}
|
|
||||||
overwrite_start = overwrite_end = 0;
|
overwrite_start = overwrite_end = 0;
|
||||||
if (read_vec.size() > 0)
|
if (read_vec.size() > 0)
|
||||||
{
|
{
|
||||||
@@ -336,6 +351,13 @@ resume_3:
|
|||||||
if (res == ENOENT || res == EDOM)
|
if (res == ENOENT || res == EDOM)
|
||||||
{
|
{
|
||||||
// Abort compaction
|
// Abort compaction
|
||||||
|
abort_compact:
|
||||||
|
if (copy_count > 0 && !bs->dsk.disable_data_fsync)
|
||||||
|
{
|
||||||
|
cur_sync->member_count--;
|
||||||
|
if (cur_sync->member_count > 0)
|
||||||
|
bs->ringloop->wakeup();
|
||||||
|
}
|
||||||
flusher->flushing.erase(cur_oid);
|
flusher->flushing.erase(cur_oid);
|
||||||
bs->heap->unlock_entry(cur_oid);
|
bs->heap->unlock_entry(cur_oid);
|
||||||
flusher->active_flushers--;
|
flusher->active_flushers--;
|
||||||
@@ -349,10 +371,7 @@ resume_4:
|
|||||||
if (res == ENOENT)
|
if (res == ENOENT)
|
||||||
{
|
{
|
||||||
// Abort compaction
|
// Abort compaction
|
||||||
flusher->flushing.erase(cur_oid);
|
goto abort_compact;
|
||||||
bs->heap->unlock_entry(cur_oid);
|
|
||||||
flusher->active_flushers--;
|
|
||||||
goto resume_0;
|
|
||||||
}
|
}
|
||||||
if (res == EAGAIN)
|
if (res == EAGAIN)
|
||||||
{
|
{
|
||||||
@@ -381,14 +400,14 @@ resume_9:
|
|||||||
for (i = 0; i < read_vec.size(); i++)
|
for (i = 0; i < read_vec.size(); i++)
|
||||||
{
|
{
|
||||||
if ((read_vec[i].copy_flags & COPY_BUF_JOURNAL) &&
|
if ((read_vec[i].copy_flags & COPY_BUF_JOURNAL) &&
|
||||||
!(read_vec[i].copy_flags & COPY_BUF_COALESCED) ||
|
!(read_vec[i].copy_flags & COPY_BUF_COALESCED))
|
||||||
(read_vec[i].copy_flags & COPY_BUF_PADDED)) // FIXME Shit, simplify these flags
|
|
||||||
{
|
{
|
||||||
assert(read_vec[i].buf);
|
assert(read_vec[i].buf);
|
||||||
await_sqe(10);
|
await_sqe(10);
|
||||||
data->iov = (struct iovec){ read_vec[i].buf + (read_vec[i].copy_flags & COPY_BUF_PADDED
|
data->iov = (struct iovec){ read_vec[i].buf + (read_vec[i].copy_flags & COPY_BUF_PADDED
|
||||||
? read_vec[i].offset - read_vec[i].disk_offset : 0), (size_t)read_vec[i].len };
|
? read_vec[i].offset - read_vec[i].disk_offset : 0), (size_t)read_vec[i].len };
|
||||||
data->callback = simple_callback_w;
|
data->callback = simple_callback_w;
|
||||||
|
assert(clean_loc + read_vec[i].offset + data->iov.iov_len <= bs->dsk.block_count*bs->dsk.data_block_size);
|
||||||
io_uring_prep_writev(sqe, bs->dsk.data_fd, &data->iov, 1, bs->dsk.data_offset + clean_loc + read_vec[i].offset);
|
io_uring_prep_writev(sqe, bs->dsk.data_fd, &data->iov, 1, bs->dsk.data_offset + clean_loc + read_vec[i].offset);
|
||||||
wait_count++;
|
wait_count++;
|
||||||
}
|
}
|
||||||
@@ -399,6 +418,17 @@ resume_11:
|
|||||||
wait_state = 11;
|
wait_state = 11;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (copy_count > 0 && !bs->dsk.disable_data_fsync)
|
||||||
|
{
|
||||||
|
resume_22:
|
||||||
|
resume_23:
|
||||||
|
resume_24:
|
||||||
|
resume_25:
|
||||||
|
if (!fsync_data(22))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
// Lock is only needed to prevent freeing the big_write because we overwrite it...
|
// Lock is only needed to prevent freeing the big_write because we overwrite it...
|
||||||
bs->heap->unlock_entry(cur_oid);
|
bs->heap->unlock_entry(cur_oid);
|
||||||
// Mark the object compacted, but don't free and remove small_writes
|
// Mark the object compacted, but don't free and remove small_writes
|
||||||
@@ -408,12 +438,14 @@ resume_11:
|
|||||||
if (!cur_obj)
|
if (!cur_obj)
|
||||||
{
|
{
|
||||||
// Abort compaction
|
// Abort compaction
|
||||||
|
flusher->active_flushers--;
|
||||||
flusher->flushing.erase(cur_oid);
|
flusher->flushing.erase(cur_oid);
|
||||||
goto resume_0;
|
goto resume_0;
|
||||||
}
|
}
|
||||||
if (!calc_block_checksums())
|
if (!calc_block_checksums())
|
||||||
{
|
{
|
||||||
// Abort compaction
|
// Abort compaction
|
||||||
|
flusher->active_flushers--;
|
||||||
flusher->flushing.erase(cur_oid);
|
flusher->flushing.erase(cur_oid);
|
||||||
goto resume_0;
|
goto resume_0;
|
||||||
}
|
}
|
||||||
@@ -422,6 +454,7 @@ resume_11:
|
|||||||
if (res == EBUSY)
|
if (res == EBUSY)
|
||||||
{
|
{
|
||||||
// Abort compaction, object is already overwritten by something else
|
// Abort compaction, object is already overwritten by something else
|
||||||
|
flusher->active_flushers--;
|
||||||
flusher->flushing.erase(cur_oid);
|
flusher->flushing.erase(cur_oid);
|
||||||
goto resume_0;
|
goto resume_0;
|
||||||
}
|
}
|
||||||
@@ -586,7 +619,7 @@ int journal_flusher_co::check_and_punch_checksums()
|
|||||||
bs->heap->calc_block_checksums((uint32_t*)(new_csums+csum_off), vec.buf, punch_bmp, vec.offset, vec.offset+vec.len, true, NULL);
|
bs->heap->calc_block_checksums((uint32_t*)(new_csums+csum_off), vec.buf, punch_bmp, vec.offset, vec.offset+vec.len, true, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Modified, we should add_punch_holes and then write the block to disk
|
// Modified, we should punch_holes and then write the block to disk
|
||||||
return EBUSY;
|
return EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -699,6 +732,67 @@ resume_1:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void journal_flusher_co::init_fsync_data()
|
||||||
|
{
|
||||||
|
cur_sync = flusher->data_syncs.begin();
|
||||||
|
if (cur_sync == flusher->data_syncs.end() || cur_sync->ready_count > 0)
|
||||||
|
{
|
||||||
|
cur_sync = flusher->data_syncs.emplace(cur_sync);
|
||||||
|
}
|
||||||
|
cur_sync->member_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool journal_flusher_co::fsync_data(int wait_base)
|
||||||
|
{
|
||||||
|
if (wait_state == wait_base)
|
||||||
|
goto resume_0;
|
||||||
|
else if (wait_state == wait_base+1)
|
||||||
|
goto resume_1;
|
||||||
|
else if (wait_state == wait_base+2)
|
||||||
|
goto resume_2;
|
||||||
|
else if (wait_state == wait_base+3)
|
||||||
|
goto resume_3;
|
||||||
|
cur_sync->ready_count++;
|
||||||
|
resume_0:
|
||||||
|
if (cur_sync->ready_count < cur_sync->member_count)
|
||||||
|
{
|
||||||
|
wait_state = wait_base;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!cur_sync->sent)
|
||||||
|
{
|
||||||
|
// Sync batch is ready. Do it.
|
||||||
|
await_sqe(1);
|
||||||
|
data->iov = { 0 };
|
||||||
|
data->callback = simple_callback_w;
|
||||||
|
io_uring_prep_fsync(sqe, bs->dsk.data_fd, IORING_FSYNC_DATASYNC);
|
||||||
|
cur_sync->sent = true;
|
||||||
|
wait_count++;
|
||||||
|
resume_2:
|
||||||
|
if (wait_count > 0)
|
||||||
|
{
|
||||||
|
wait_state = wait_base+2;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cur_sync->done = true;
|
||||||
|
// Wake up other flushers
|
||||||
|
bs->ringloop->wakeup();
|
||||||
|
}
|
||||||
|
resume_3:
|
||||||
|
if (!cur_sync->done)
|
||||||
|
{
|
||||||
|
wait_state = wait_base+3;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cur_sync->done_count++;
|
||||||
|
if (cur_sync->done_count >= cur_sync->member_count)
|
||||||
|
{
|
||||||
|
flusher->data_syncs.erase(cur_sync);
|
||||||
|
cur_sync = flusher->data_syncs.end();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool journal_flusher_co::fsync_meta(int wait_base)
|
bool journal_flusher_co::fsync_meta(int wait_base)
|
||||||
{
|
{
|
||||||
if (wait_state == wait_base) goto resume_0;
|
if (wait_state == wait_base) goto resume_0;
|
||||||
|
|||||||
@@ -25,6 +25,15 @@ struct flusher_meta_write_t
|
|||||||
std::map<uint64_t, meta_sector_t>::iterator it;
|
std::map<uint64_t, meta_sector_t>::iterator it;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct flusher_data_sync_t
|
||||||
|
{
|
||||||
|
int member_count = 0;
|
||||||
|
int ready_count = 0;
|
||||||
|
int done_count = 0;
|
||||||
|
bool sent = false;
|
||||||
|
bool done = false;
|
||||||
|
};
|
||||||
|
|
||||||
class journal_flusher_t;
|
class journal_flusher_t;
|
||||||
|
|
||||||
// Journal flusher coroutine
|
// Journal flusher coroutine
|
||||||
@@ -58,6 +67,7 @@ class journal_flusher_co
|
|||||||
int i, res;
|
int i, res;
|
||||||
bool read_to_fill_incomplete;
|
bool read_to_fill_incomplete;
|
||||||
int copy_count;
|
int copy_count;
|
||||||
|
std::list<flusher_data_sync_t>::iterator cur_sync;
|
||||||
|
|
||||||
friend class journal_flusher_t;
|
friend class journal_flusher_t;
|
||||||
|
|
||||||
@@ -68,6 +78,8 @@ class journal_flusher_co
|
|||||||
bool calc_block_checksums();
|
bool calc_block_checksums();
|
||||||
bool write_meta_block(int wait_base);
|
bool write_meta_block(int wait_base);
|
||||||
bool read_buffered(int wait_base);
|
bool read_buffered(int wait_base);
|
||||||
|
void init_fsync_data();
|
||||||
|
bool fsync_data(int wait_base);
|
||||||
bool fsync_meta(int wait_base);
|
bool fsync_meta(int wait_base);
|
||||||
bool fsync_buffer(int wait_base);
|
bool fsync_buffer(int wait_base);
|
||||||
bool trim_lsn(int wait_base);
|
bool trim_lsn(int wait_base);
|
||||||
@@ -88,6 +100,7 @@ class journal_flusher_t
|
|||||||
|
|
||||||
robin_hood::unordered_flat_set<object_id> flushing;
|
robin_hood::unordered_flat_set<object_id> flushing;
|
||||||
int active_flushers = 0;
|
int active_flushers = 0;
|
||||||
|
std::list<flusher_data_sync_t> data_syncs;
|
||||||
int wanting_meta_fsync = 0;
|
int wanting_meta_fsync = 0;
|
||||||
bool fsyncing_meta = false;
|
bool fsyncing_meta = false;
|
||||||
int syncing_buffer = 0;
|
int syncing_buffer = 0;
|
||||||
|
|||||||
+501
-231
File diff suppressed because it is too large
Load Diff
@@ -57,11 +57,11 @@ struct __attribute__((__packed__)) heap_entry_t
|
|||||||
inline heap_small_write_t& small() { return *(heap_small_write_t*)this; }
|
inline heap_small_write_t& small() { return *(heap_small_write_t*)this; }
|
||||||
inline heap_big_write_t& big() { return *(heap_big_write_t*)this; }
|
inline heap_big_write_t& big() { return *(heap_big_write_t*)this; }
|
||||||
inline heap_big_intent_t& big_intent() { return *(heap_big_intent_t*)this; }
|
inline heap_big_intent_t& big_intent() { return *(heap_big_intent_t*)this; }
|
||||||
bool is_garbage();
|
bool is_garbage() const;
|
||||||
void set_garbage();
|
void set_garbage();
|
||||||
bool is_overwrite();
|
bool is_overwrite() const;
|
||||||
bool is_compactable();
|
bool is_compactable() const;
|
||||||
bool is_before(heap_entry_t *other);
|
bool is_before(const heap_entry_t *other) const;
|
||||||
uint32_t get_size(blockstore_heap_t *heap);
|
uint32_t get_size(blockstore_heap_t *heap);
|
||||||
uint8_t *get_ext_bitmap(blockstore_heap_t *heap);
|
uint8_t *get_ext_bitmap(blockstore_heap_t *heap);
|
||||||
uint8_t *get_int_bitmap(blockstore_heap_t *heap);
|
uint8_t *get_int_bitmap(blockstore_heap_t *heap);
|
||||||
@@ -117,10 +117,13 @@ struct heap_object_mvcc_t
|
|||||||
|
|
||||||
struct heap_block_info_t
|
struct heap_block_info_t
|
||||||
{
|
{
|
||||||
uint32_t used_space = 0;
|
struct __attribute__((__packed__))
|
||||||
|
{
|
||||||
|
uint32_t used_space = 0;
|
||||||
|
uint32_t garbage_space = 0;
|
||||||
|
};
|
||||||
uint64_t mod_lsn = 0, mod_lsn_to = 0; // only 1 block write of LSN sequence is allowed at a moment
|
uint64_t mod_lsn = 0, mod_lsn_to = 0; // only 1 block write of LSN sequence is allowed at a moment
|
||||||
bool is_writing: 1;
|
bool is_writing = false;
|
||||||
bool has_garbage: 1;
|
|
||||||
std::vector<heap_list_item_t*> entries;
|
std::vector<heap_list_item_t*> entries;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -155,6 +158,16 @@ struct heap_li_equal
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct heap_recheck_state_t
|
||||||
|
{
|
||||||
|
heap_entry_t *obj = NULL;
|
||||||
|
heap_entry_t *next_wr = NULL;
|
||||||
|
size_t total_reads = 0;
|
||||||
|
size_t sent_reads = 0;
|
||||||
|
size_t checked_reads = 0;
|
||||||
|
heap_entry_t *bad_wr = NULL;
|
||||||
|
};
|
||||||
|
|
||||||
using i64hash_t = robin_hood::hash<uint64_t>;
|
using i64hash_t = robin_hood::hash<uint64_t>;
|
||||||
using heap_inode_map_t = robin_hood::unordered_flat_set<heap_list_item_t*, heap_li_hash, heap_li_equal, 88>;
|
using heap_inode_map_t = robin_hood::unordered_flat_set<heap_list_item_t*, heap_li_hash, heap_li_equal, 88>;
|
||||||
using heap_block_index_t = robin_hood::unordered_flat_map<uint64_t,
|
using heap_block_index_t = robin_hood::unordered_flat_map<uint64_t,
|
||||||
@@ -184,6 +197,11 @@ class blockstore_heap_t
|
|||||||
uint64_t buffer_area_used_space = 0;
|
uint64_t buffer_area_used_space = 0;
|
||||||
uint64_t data_used_space = 0;
|
uint64_t data_used_space = 0;
|
||||||
|
|
||||||
|
uint64_t live_entries = 0;
|
||||||
|
uint64_t live_memory = 0;
|
||||||
|
uint64_t garbage_entries = 0;
|
||||||
|
uint64_t garbage_memory = 0;
|
||||||
|
|
||||||
uint64_t next_lsn = 0;
|
uint64_t next_lsn = 0;
|
||||||
uint32_t last_allocated_block = UINT32_MAX;
|
uint32_t last_allocated_block = UINT32_MAX;
|
||||||
heap_mvcc_map_t object_mvcc;
|
heap_mvcc_map_t object_mvcc;
|
||||||
@@ -200,9 +218,11 @@ class blockstore_heap_t
|
|||||||
|
|
||||||
bool marked_used_blocks = false;
|
bool marked_used_blocks = false;
|
||||||
bool recheck_queue_filled = false;
|
bool recheck_queue_filled = false;
|
||||||
std::vector<heap_list_item_t*> loaded_list_items;
|
std::vector<heap_list_item_t*> postponed_items;
|
||||||
std::set<uint32_t> recheck_modified_blocks;
|
std::set<uint32_t> recheck_modified_blocks;
|
||||||
std::deque<heap_entry_t*> recheck_queue;
|
std::deque<heap_entry_t*> recheck_queue;
|
||||||
|
std::map<heap_entry_t*, heap_recheck_state_t> recheck_states;
|
||||||
|
size_t recheck_pending_reads = 0;
|
||||||
int recheck_in_progress = 0;
|
int recheck_in_progress = 0;
|
||||||
bool in_recheck = false;
|
bool in_recheck = false;
|
||||||
std::function<void(bool is_data, uint64_t offset, uint64_t len, uint8_t* buf, std::function<void()>)> recheck_cb;
|
std::function<void(bool is_data, uint64_t offset, uint64_t len, uint8_t* buf, std::function<void()>)> recheck_cb;
|
||||||
@@ -211,14 +231,22 @@ class blockstore_heap_t
|
|||||||
uint64_t get_pg_id(inode_t inode, uint64_t stripe);
|
uint64_t get_pg_id(inode_t inode, uint64_t stripe);
|
||||||
bool validate_object(heap_entry_t *obj);
|
bool validate_object(heap_entry_t *obj);
|
||||||
void fill_recheck_queue();
|
void fill_recheck_queue();
|
||||||
|
void recheck_drop_entries(heap_entry_t *obj, heap_entry_t *bad_wr);
|
||||||
|
void recheck_start_reads(heap_recheck_state_t *st);
|
||||||
int mark_used_blocks();
|
int mark_used_blocks();
|
||||||
|
void init_free_bad_entry(heap_entry_t *wr);
|
||||||
|
void init_erase_bad_entry(heap_list_item_t *li);
|
||||||
|
bool init_erase_double_claim(heap_list_item_t *prev_li, heap_list_item_t *cur_li);
|
||||||
|
void recheck_full_gc();
|
||||||
void recheck_buffer(heap_entry_t *cwr, uint8_t *buf);
|
void recheck_buffer(heap_entry_t *cwr, uint8_t *buf);
|
||||||
void defragment_block(uint32_t block_num);
|
void defragment_block(uint32_t block_num);
|
||||||
void reshard_add(heap_reshard_state_t *st, heap_list_item_t *li);
|
void reshard_add(heap_reshard_state_t *st, heap_list_item_t *li);
|
||||||
|
|
||||||
void gc_block(heap_block_info_t & inf);
|
void gc_block(heap_block_info_t & inf);
|
||||||
int allocate_entry(uint32_t entry_size, uint32_t *block_num, bool allow_last_free);
|
int allocate_entry(uint32_t entry_size, uint32_t *block_num, bool allow_last_free);
|
||||||
void insert_list_item(heap_list_item_t *li);
|
void insert_list_items(heap_list_item_t** v, size_t count, bool postpone);
|
||||||
|
void remove_list_item(heap_list_item_t *li);
|
||||||
|
void unlink_list_item(heap_list_item_t *li);
|
||||||
int add_entry(uint32_t wr_size, uint32_t *modified_block, bool allow_last_free,
|
int add_entry(uint32_t wr_size, uint32_t *modified_block, bool allow_last_free,
|
||||||
bool explicit_complete, std::function<void(heap_entry_t *wr)> fill_entry);
|
bool explicit_complete, std::function<void(heap_entry_t *wr)> fill_entry);
|
||||||
int add_simple(heap_entry_t *obj, uint64_t version, uint32_t *modified_block, uint32_t entry_type);
|
int add_simple(heap_entry_t *obj, uint64_t version, uint32_t *modified_block, uint32_t entry_type);
|
||||||
@@ -345,6 +373,10 @@ public:
|
|||||||
uint32_t get_compact_queue_size();
|
uint32_t get_compact_queue_size();
|
||||||
uint32_t get_to_compact_count();
|
uint32_t get_to_compact_count();
|
||||||
uint64_t get_compacted_count();
|
uint64_t get_compacted_count();
|
||||||
|
uint64_t get_live_entries();
|
||||||
|
uint64_t get_live_memory();
|
||||||
|
uint64_t get_garbage_entries();
|
||||||
|
uint64_t get_garbage_memory();
|
||||||
|
|
||||||
uint64_t entry_pos(uint32_t block_num, uint32_t offset);
|
uint64_t entry_pos(uint32_t block_num, uint32_t offset);
|
||||||
heap_entry_t *entry_from_pos(uint64_t entry_pos, bool allow_unallocated = false);
|
heap_entry_t *entry_from_pos(uint64_t entry_pos, bool allow_unallocated = false);
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ void blockstore_impl_t::loop()
|
|||||||
unsigned initial_ring_space = ringloop->space_left();
|
unsigned initial_ring_space = ringloop->space_left();
|
||||||
int op_idx = 0, new_idx = 0;
|
int op_idx = 0, new_idx = 0;
|
||||||
bool has_unfinished_writes = false;
|
bool has_unfinished_writes = false;
|
||||||
|
bool has_unfinished_sync = false;
|
||||||
for (; op_idx < submit_queue.size(); op_idx++, new_idx++)
|
for (; op_idx < submit_queue.size(); op_idx++, new_idx++)
|
||||||
{
|
{
|
||||||
auto op = submit_queue[op_idx];
|
auto op = submit_queue[op_idx];
|
||||||
@@ -138,7 +139,13 @@ void blockstore_impl_t::loop()
|
|||||||
else if (op->opcode == BS_OP_SYNC)
|
else if (op->opcode == BS_OP_SYNC)
|
||||||
{
|
{
|
||||||
// syncs only completed writes, so doesn't have to be blocked by anything
|
// syncs only completed writes, so doesn't have to be blocked by anything
|
||||||
wr_st = continue_sync(op);
|
if (!has_unfinished_sync)
|
||||||
|
{
|
||||||
|
wr_st = continue_sync(op);
|
||||||
|
has_unfinished_sync = (wr_st != 2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
wr_st = 0;
|
||||||
}
|
}
|
||||||
else if (op->opcode == BS_OP_STABLE || op->opcode == BS_OP_ROLLBACK)
|
else if (op->opcode == BS_OP_STABLE || op->opcode == BS_OP_ROLLBACK)
|
||||||
{
|
{
|
||||||
@@ -154,9 +161,7 @@ void blockstore_impl_t::loop()
|
|||||||
wr_st = 2;
|
wr_st = 2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
wr_st = 0;
|
wr_st = 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (wr_st == 2)
|
if (wr_st == 2)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -229,4 +229,9 @@ public:
|
|||||||
uint64_t get_free_block_count();
|
uint64_t get_free_block_count();
|
||||||
inline uint32_t get_bitmap_granularity() { return dsk.bitmap_granularity; }
|
inline uint32_t get_bitmap_granularity() { return dsk.bitmap_granularity; }
|
||||||
inline uint64_t get_journal_size() { return dsk.journal_len; }
|
inline uint64_t get_journal_size() { return dsk.journal_len; }
|
||||||
|
|
||||||
|
inline uint64_t get_live_entries() { return heap->get_live_entries(); }
|
||||||
|
inline uint64_t get_live_memory() { return heap->get_live_memory(); }
|
||||||
|
inline uint64_t get_garbage_entries() { return heap->get_garbage_entries(); }
|
||||||
|
inline uint64_t get_garbage_memory() { return heap->get_garbage_memory(); }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -153,6 +153,14 @@ resume_1:
|
|||||||
);
|
);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
uint32_t csum = hdr->header_csum;
|
||||||
|
hdr->header_csum = 0;
|
||||||
|
if (crc32c(0, hdr, sizeof(*hdr)) != csum)
|
||||||
|
{
|
||||||
|
printf("Metadata header is corrupt (checksum mismatch).\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
hdr->header_csum = csum;
|
||||||
}
|
}
|
||||||
bs->heap->start_load(((blockstore_meta_header_v3_t *)bs->meta_superblock)->completed_lsn);
|
bs->heap->start_load(((blockstore_meta_header_v3_t *)bs->meta_superblock)->completed_lsn);
|
||||||
if (bs->dsk.inmemory_journal)
|
if (bs->dsk.inmemory_journal)
|
||||||
@@ -240,23 +248,7 @@ resume_4:
|
|||||||
}
|
}
|
||||||
// metadata read finished
|
// metadata read finished
|
||||||
bs->heap->finish_load();
|
bs->heap->finish_load();
|
||||||
printf("Metadata entries loaded: %ju, used blocks: %ju / %ju\n", entries_loaded, bs->heap->get_data_used_space() / bs->dsk.data_block_size, bs->dsk.block_count);
|
printf("Metadata entries loaded: %ju, rechecking unfinished writes and garbage entries\n", entries_loaded);
|
||||||
if (zero_on_init && !bs->dsk.disable_meta_fsync)
|
|
||||||
{
|
|
||||||
GET_SQE();
|
|
||||||
io_uring_prep_fsync(sqe, bs->dsk.meta_fd, IORING_FSYNC_DATASYNC);
|
|
||||||
last_read_offset = 0;
|
|
||||||
data->iov = { 0 };
|
|
||||||
data->callback = [this](ring_data_t *data) { handle_event(data, -1); };
|
|
||||||
submitted++;
|
|
||||||
bs->ringloop->submit();
|
|
||||||
resume_5:
|
|
||||||
if (submitted > 0)
|
|
||||||
{
|
|
||||||
wait_state = 5;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// asynchronous recheck
|
// asynchronous recheck
|
||||||
resume_6:
|
resume_6:
|
||||||
wait_state = 6;
|
wait_state = 6;
|
||||||
@@ -293,6 +285,11 @@ resume_7:
|
|||||||
if (bs->readonly)
|
if (bs->readonly)
|
||||||
{
|
{
|
||||||
recheck_mod.clear();
|
recheck_mod.clear();
|
||||||
|
printf("Actual metadata entries: %ju\n", bs->heap->get_live_entries());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Actual metadata entries: %ju, clearing garbage in %zu metadata blocks\n", bs->heap->get_live_entries(), recheck_mod.size());
|
||||||
}
|
}
|
||||||
for (i = 0; i < recheck_mod.size(); i++)
|
for (i = 0; i < recheck_mod.size(); i++)
|
||||||
{
|
{
|
||||||
@@ -306,7 +303,7 @@ resume_8:
|
|||||||
uint32_t block_num = recheck_mod[i];
|
uint32_t block_num = recheck_mod[i];
|
||||||
uint64_t block_offset = bs->dsk.meta_offset + (uint64_t)(block_num+1) * bs->dsk.meta_block_size;
|
uint64_t block_offset = bs->dsk.meta_offset + (uint64_t)(block_num+1) * bs->dsk.meta_block_size;
|
||||||
data = ((ring_data_t*)sqe->user_data);
|
data = ((ring_data_t*)sqe->user_data);
|
||||||
uint8_t *buf = (uint8_t*)malloc_or_die(bs->dsk.meta_block_size);
|
uint8_t *buf = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, bs->dsk.meta_block_size);
|
||||||
bs->heap->get_meta_block(block_num, buf);
|
bs->heap->get_meta_block(block_num, buf);
|
||||||
data->iov = { buf, bs->dsk.meta_block_size };
|
data->iov = { buf, bs->dsk.meta_block_size };
|
||||||
data->callback = [this, buf, block_offset](ring_data_t *data)
|
data->callback = [this, buf, block_offset](ring_data_t *data)
|
||||||
@@ -332,5 +329,25 @@ resume_9:
|
|||||||
}
|
}
|
||||||
free(metadata_buffer);
|
free(metadata_buffer);
|
||||||
metadata_buffer = NULL;
|
metadata_buffer = NULL;
|
||||||
|
if (!bs->dsk.disable_meta_fsync && !bs->readonly)
|
||||||
|
{
|
||||||
|
GET_SQE();
|
||||||
|
io_uring_prep_fsync(sqe, bs->dsk.meta_fd, IORING_FSYNC_DATASYNC);
|
||||||
|
last_read_offset = 0;
|
||||||
|
data->iov = { 0 };
|
||||||
|
data->callback = [this](ring_data_t *data) { handle_event(data, -1); };
|
||||||
|
submitted++;
|
||||||
|
bs->ringloop->submit();
|
||||||
|
resume_5:
|
||||||
|
if (submitted > 0)
|
||||||
|
{
|
||||||
|
wait_state = 5;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("Loading finished. Data used: %ju / %ju bytes (%s / %s)\n",
|
||||||
|
bs->heap->get_data_used_space(), bs->dsk.block_count * bs->dsk.data_block_size,
|
||||||
|
format_size(bs->heap->get_data_used_space()).c_str(),
|
||||||
|
format_size(bs->dsk.block_count * bs->dsk.data_block_size).c_str());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -462,6 +462,10 @@ int blockstore_impl_t::read_bitmap(object_id oid, uint64_t target_version, void
|
|||||||
{
|
{
|
||||||
if (target_version >= wr->version)
|
if (target_version >= wr->version)
|
||||||
{
|
{
|
||||||
|
if (wr->type() == BS_HEAP_DELETE)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
found = true;
|
found = true;
|
||||||
if (result_version)
|
if (result_version)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ int blockstore_impl_t::dequeue_stable(blockstore_op_t *op)
|
|||||||
else if (priv->op_state == 5) goto resume_5;
|
else if (priv->op_state == 5) goto resume_5;
|
||||||
assert(!priv->op_state);
|
assert(!priv->op_state);
|
||||||
op->retval = 0;
|
op->retval = 0;
|
||||||
|
PRIV(op)->lsn = 0;
|
||||||
priv->modified_block = priv->modified_block2 = UINT32_MAX;
|
priv->modified_block = priv->modified_block2 = UINT32_MAX;
|
||||||
for (priv->stab_pos = 0; priv->stab_pos < op->len; priv->stab_pos++)
|
for (priv->stab_pos = 0; priv->stab_pos < op->len; priv->stab_pos++)
|
||||||
{
|
{
|
||||||
@@ -36,6 +37,12 @@ int blockstore_impl_t::dequeue_stable(blockstore_op_t *op)
|
|||||||
FINISH_OP(op);
|
FINISH_OP(op);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
if (res == ENOENT)
|
||||||
|
{
|
||||||
|
op->retval = -ENOENT;
|
||||||
|
FINISH_OP(op);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
if (res == ENOSPC)
|
if (res == ENOSPC)
|
||||||
{
|
{
|
||||||
if (!heap->get_to_compact_count())
|
if (!heap->get_to_compact_count())
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ int blockstore_impl_t::continue_sync(blockstore_op_t *op)
|
|||||||
if (!PRIV(op)->op_state)
|
if (!PRIV(op)->op_state)
|
||||||
{
|
{
|
||||||
op->retval = 0;
|
op->retval = 0;
|
||||||
|
PRIV(op)->lsn = 0;
|
||||||
}
|
}
|
||||||
int res = do_sync(op, 0);
|
int res = do_sync(op, 0);
|
||||||
if (res == 2)
|
if (res == 2)
|
||||||
@@ -104,7 +105,8 @@ int blockstore_impl_t::do_sync(blockstore_op_t *op, int base_state)
|
|||||||
unsynced_data_write_count = unsynced_buffer_write_count = unsynced_meta_write_count = 0;
|
unsynced_data_write_count = unsynced_buffer_write_count = unsynced_meta_write_count = 0;
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
PRIV(op)->modified_block = heap->get_completed_lsn();
|
assert(!PRIV(op)->lsn);
|
||||||
|
PRIV(op)->lsn = heap->get_completed_lsn();
|
||||||
if (!submit_fsyncs(PRIV(op)->pending_ops))
|
if (!submit_fsyncs(PRIV(op)->pending_ops))
|
||||||
{
|
{
|
||||||
PRIV(op)->wait_detail = 1;
|
PRIV(op)->wait_detail = 1;
|
||||||
@@ -118,6 +120,6 @@ resume_1:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
resume_2:
|
resume_2:
|
||||||
heap->mark_lsn_fsynced(PRIV(op)->modified_block);
|
heap->mark_lsn_fsynced(PRIV(op)->lsn);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ void blockstore_impl_t::prepare_meta_block_write(uint32_t modified_block)
|
|||||||
heap->complete_block_write(modified_block);
|
heap->complete_block_write(modified_block);
|
||||||
ringloop->wakeup();
|
ringloop->wakeup();
|
||||||
};
|
};
|
||||||
|
assert(((uint64_t)modified_block+2)*dsk.meta_block_size <= dsk.meta_area_size);
|
||||||
io_uring_prep_writev(
|
io_uring_prep_writev(
|
||||||
sqe, dsk.meta_fd, &data->iov, 1, dsk.meta_offset + ((uint64_t)modified_block+1)*dsk.meta_block_size
|
sqe, dsk.meta_fd, &data->iov, 1, dsk.meta_offset + ((uint64_t)modified_block+1)*dsk.meta_block_size
|
||||||
);
|
);
|
||||||
@@ -177,6 +178,7 @@ enospc:
|
|||||||
ring_data_t *data = ((ring_data_t*)sqe->user_data);
|
ring_data_t *data = ((ring_data_t*)sqe->user_data);
|
||||||
data->iov = (struct iovec){ op->buf, op->len };
|
data->iov = (struct iovec){ op->buf, op->len };
|
||||||
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); };
|
||||||
|
assert(loc+op->offset+op->len <= dsk.block_count*dsk.data_block_size);
|
||||||
io_uring_prep_writev(sqe, dsk.data_fd, &data->iov, 1, dsk.data_offset + loc + op->offset);
|
io_uring_prep_writev(sqe, dsk.data_fd, &data->iov, 1, dsk.data_offset + loc + op->offset);
|
||||||
PRIV(op)->pending_ops++;
|
PRIV(op)->pending_ops++;
|
||||||
write_iodepth++;
|
write_iodepth++;
|
||||||
@@ -264,6 +266,7 @@ enospc:
|
|||||||
BS_SUBMIT_GET_SQE(sqe2, data2);
|
BS_SUBMIT_GET_SQE(sqe2, data2);
|
||||||
data2->iov = (struct iovec){ op->buf, op->len };
|
data2->iov = (struct iovec){ op->buf, op->len };
|
||||||
data2->callback = [this, op](ring_data_t *data) { handle_write_event(data, op); };
|
data2->callback = [this, op](ring_data_t *data) { handle_write_event(data, op); };
|
||||||
|
assert(loc+op->len <= dsk.journal_len);
|
||||||
io_uring_prep_writev(sqe2, dsk.journal_fd, &data2->iov, 1, dsk.journal_offset + loc);
|
io_uring_prep_writev(sqe2, dsk.journal_fd, &data2->iov, 1, dsk.journal_offset + loc);
|
||||||
PRIV(op)->pending_ops++;
|
PRIV(op)->pending_ops++;
|
||||||
}
|
}
|
||||||
@@ -453,6 +456,7 @@ resume_10:
|
|||||||
BS_SUBMIT_GET_SQE(sqe, data);
|
BS_SUBMIT_GET_SQE(sqe, data);
|
||||||
data->iov = (struct iovec){ op->buf, op->len };
|
data->iov = (struct iovec){ op->buf, op->len };
|
||||||
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); };
|
||||||
|
assert(PRIV(op)->location + op->offset <= dsk.block_count*dsk.data_block_size);
|
||||||
io_uring_prep_writev(sqe, dsk.data_fd, &data->iov, 1, dsk.data_offset + PRIV(op)->location + op->offset);
|
io_uring_prep_writev(sqe, dsk.data_fd, &data->iov, 1, dsk.data_offset + PRIV(op)->location + op->offset);
|
||||||
if (dsk.use_atomic_flag)
|
if (dsk.use_atomic_flag)
|
||||||
sqe->rw_flags = RWF_ATOMIC;
|
sqe->rw_flags = RWF_ATOMIC;
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ struct __attribute__((__packed__)) journal_entry
|
|||||||
inline uint32_t je_crc32(journal_entry *je)
|
inline uint32_t je_crc32(journal_entry *je)
|
||||||
{
|
{
|
||||||
// 0x48674bc7 = crc32(4 zero bytes)
|
// 0x48674bc7 = crc32(4 zero bytes)
|
||||||
return crc32c(0x48674bc7, ((uint8_t*)je)+4, je->size-4);
|
return je->size < 4 ? 0 : crc32c(0x48674bc7, ((uint8_t*)je)+4, je->size-4);
|
||||||
}
|
}
|
||||||
|
|
||||||
// "VITAstor"
|
// "VITAstor"
|
||||||
|
|||||||
@@ -520,6 +520,7 @@ resume_2:
|
|||||||
await_sqe(15);
|
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;
|
||||||
|
assert(clean_loc+it->offset+it->len <= bs->dsk.block_count*bs->dsk.data_block_size);
|
||||||
io_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
|
||||||
);
|
);
|
||||||
@@ -749,6 +750,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;
|
||||||
|
assert(bs->dsk.meta_block_size + meta_block.sector + bs->dsk.meta_block_size <= bs->dsk.meta_area_size);
|
||||||
io_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
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -855,4 +855,29 @@ std::string blockstore_impl_t::get_op_diag(blockstore_op_t *op)
|
|||||||
return std::string(buf);
|
return std::string(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t blockstore_impl_t::get_live_entries()
|
||||||
|
{
|
||||||
|
return used_blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t blockstore_impl_t::get_live_memory()
|
||||||
|
{
|
||||||
|
uint64_t used = 0;
|
||||||
|
for (auto & kv: clean_db_shards)
|
||||||
|
{
|
||||||
|
used += kv.second.size() * sizeof(blockstore_clean_db_t::value_type);
|
||||||
|
}
|
||||||
|
return used;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t blockstore_impl_t::get_garbage_entries()
|
||||||
|
{
|
||||||
|
return dirty_db.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t blockstore_impl_t::get_garbage_memory()
|
||||||
|
{
|
||||||
|
return (sizeof(obj_ver_id) + sizeof(dirty_entry) + 32) * dirty_db.size();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace v1
|
} // namespace v1
|
||||||
|
|||||||
@@ -332,6 +332,10 @@ public:
|
|||||||
inline uint64_t get_free_block_count() { return dsk.block_count - used_blocks; }
|
inline uint64_t get_free_block_count() { return dsk.block_count - used_blocks; }
|
||||||
inline uint32_t get_bitmap_granularity() { return dsk.disk_alignment; }
|
inline uint32_t get_bitmap_granularity() { return dsk.disk_alignment; }
|
||||||
inline uint64_t get_journal_size() { return dsk.journal_len; }
|
inline uint64_t get_journal_size() { return dsk.journal_len; }
|
||||||
|
uint64_t get_live_entries();
|
||||||
|
uint64_t get_live_memory();
|
||||||
|
uint64_t get_garbage_entries();
|
||||||
|
uint64_t get_garbage_memory();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace v1
|
} // namespace v1
|
||||||
|
|||||||
@@ -193,6 +193,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); };
|
||||||
|
assert(journal.sector_info[cur_sector].offset+journal.block_size <= dsk.journal_len);
|
||||||
io_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
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -620,8 +620,7 @@ bool blockstore_impl_t::fulfill_clean_read(blockstore_op_t *read_op, uint64_t &
|
|||||||
else if (from_journal)
|
else if (from_journal)
|
||||||
{
|
{
|
||||||
// Don't scan bitmap - journal writes don't have holes (internal bitmap)!
|
// Don't scan bitmap - journal writes don't have holes (internal bitmap)!
|
||||||
uint8_t *csum = !dsk.csum_block_size ? 0 : (clean_entry_bitmap + dsk.clean_entry_bitmap_size +
|
uint8_t *csum = !dsk.csum_block_size ? 0 : (clean_entry_bitmap + dsk.clean_entry_bitmap_size);
|
||||||
item_start/dsk.csum_block_size*(dsk.data_csum_type & 0xFF));
|
|
||||||
if (!fulfill_read(read_op, fulfilled, item_start, item_end,
|
if (!fulfill_read(read_op, fulfilled, item_start, item_end,
|
||||||
(BS_ST_BIG_WRITE | BS_ST_STABLE), 0, clean_loc + item_start, 0, csum, dyn_data))
|
(BS_ST_BIG_WRITE | BS_ST_STABLE), 0, clean_loc + item_start, 0, csum, dyn_data))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -368,9 +368,9 @@ 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); };
|
||||||
io_uring_prep_writev(
|
const uint64_t write_offset = (loc * dsk.data_block_size) + op->offset - stripe_offset;
|
||||||
sqe, dsk.data_fd, PRIV(op)->iov_zerofill, vcnt, dsk.data_offset + (loc * dsk.data_block_size) + op->offset - stripe_offset
|
assert(write_offset+op->len+stripe_offset+stripe_end <= dsk.block_count*dsk.data_block_size);
|
||||||
);
|
io_uring_prep_writev(sqe, dsk.data_fd, PRIV(op)->iov_zerofill, vcnt, dsk.data_offset + write_offset);
|
||||||
PRIV(op)->pending_ops = 1;
|
PRIV(op)->pending_ops = 1;
|
||||||
if (!(dirty_it->second.state & BS_ST_INSTANT))
|
if (!(dirty_it->second.state & BS_ST_INSTANT))
|
||||||
{
|
{
|
||||||
@@ -495,9 +495,8 @@ 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); };
|
||||||
io_uring_prep_writev(
|
assert(journal.next_free+op->len <= dsk.journal_len);
|
||||||
sqe2, dsk.journal_fd, &data2->iov, 1, journal.offset + journal.next_free
|
io_uring_prep_writev(sqe2, dsk.journal_fd, &data2->iov, 1, journal.offset + journal.next_free);
|
||||||
);
|
|
||||||
PRIV(op)->pending_ops++;
|
PRIV(op)->pending_ops++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 2.8.12)
|
cmake_minimum_required(VERSION 2.8...3.30)
|
||||||
|
|
||||||
project(vitastor)
|
project(vitastor)
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ if (RDMACM_LIBRARIES)
|
|||||||
set(MSGR_RDMACM "msgr_rdmacm.cpp")
|
set(MSGR_RDMACM "msgr_rdmacm.cpp")
|
||||||
endif (RDMACM_LIBRARIES)
|
endif (RDMACM_LIBRARIES)
|
||||||
add_library(vitastor_common STATIC
|
add_library(vitastor_common STATIC
|
||||||
../util/epoll_manager.cpp etcd_state_client.cpp messenger.cpp ../util/addr_util.cpp
|
../util/epoll_manager.cpp etcd_state_client.cpp messenger.cpp msgr_iothread.cpp ../util/addr_util.cpp
|
||||||
msgr_stop.cpp msgr_op.cpp msgr_send.cpp msgr_receive.cpp ../util/ringloop.cpp ../../json11/json11.cpp
|
msgr_stop.cpp msgr_op.cpp msgr_send.cpp msgr_receive.cpp ../util/ringloop.cpp ../../json11/json11.cpp
|
||||||
http_client.cpp osd_ops.cpp pg_states.cpp ../util/timerfd_manager.cpp ../util/str_util.cpp ../util/json_util.cpp ${MSGR_RDMA} ${MSGR_RDMACM}
|
http_client.cpp osd_ops.cpp pg_states.cpp ../util/timerfd_manager.cpp ../util/str_util.cpp ../util/json_util.cpp ${MSGR_RDMA} ${MSGR_RDMACM}
|
||||||
)
|
)
|
||||||
@@ -52,9 +52,6 @@ if (${WITH_FIO})
|
|||||||
../util/rw_blocking.cpp
|
../util/rw_blocking.cpp
|
||||||
../util/addr_util.cpp
|
../util/addr_util.cpp
|
||||||
)
|
)
|
||||||
target_link_libraries(fio_vitastor_sec
|
|
||||||
tcmalloc_minimal
|
|
||||||
)
|
|
||||||
endif (${WITH_FIO})
|
endif (${WITH_FIO})
|
||||||
|
|
||||||
# vitastor-nbd
|
# vitastor-nbd
|
||||||
@@ -101,6 +98,7 @@ add_executable(test_cluster_client
|
|||||||
pg_states.cpp osd_ops.cpp cluster_client.cpp cluster_client_list.cpp cluster_client_wb.cpp msgr_op.cpp ../test/mock/messenger.cpp msgr_stop.cpp
|
pg_states.cpp osd_ops.cpp cluster_client.cpp cluster_client_list.cpp cluster_client_wb.cpp msgr_op.cpp ../test/mock/messenger.cpp msgr_stop.cpp
|
||||||
etcd_state_client.cpp ../util/timerfd_manager.cpp ../util/addr_util.cpp ../util/str_util.cpp ../util/json_util.cpp ../../json11/json11.cpp
|
etcd_state_client.cpp ../util/timerfd_manager.cpp ../util/addr_util.cpp ../util/str_util.cpp ../util/json_util.cpp ../../json11/json11.cpp
|
||||||
)
|
)
|
||||||
|
target_link_libraries(test_cluster_client ${LIBURING_LIBRARIES})
|
||||||
target_compile_definitions(test_cluster_client PUBLIC -D__MOCK__)
|
target_compile_definitions(test_cluster_client PUBLIC -D__MOCK__)
|
||||||
target_include_directories(test_cluster_client BEFORE PUBLIC ${CMAKE_SOURCE_DIR}/src/test/mock)
|
target_include_directories(test_cluster_client BEFORE PUBLIC ${CMAKE_SOURCE_DIR}/src/test/mock)
|
||||||
add_dependencies(build_tests test_cluster_client)
|
add_dependencies(build_tests test_cluster_client)
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ cluster_client_t::cluster_client_t(ring_loop_t *ringloop, timerfd_manager_t *tfd
|
|||||||
msgr.ringloop = ringloop;
|
msgr.ringloop = ringloop;
|
||||||
msgr.repeer_pgs = [this](osd_num_t peer_osd)
|
msgr.repeer_pgs = [this](osd_num_t peer_osd)
|
||||||
{
|
{
|
||||||
if (msgr.osd_peer_fds.find(peer_osd) != msgr.osd_peer_fds.end())
|
if (msgr.osd_peers.find(peer_osd) != msgr.osd_peers.end())
|
||||||
{
|
{
|
||||||
// peer_osd just connected
|
// peer_osd just connected
|
||||||
continue_ops();
|
continue_ops();
|
||||||
@@ -47,8 +47,8 @@ cluster_client_t::cluster_client_t(ring_loop_t *ringloop, timerfd_manager_t *tfd
|
|||||||
msgr.exec_op = [this](osd_op_t *op)
|
msgr.exec_op = [this](osd_op_t *op)
|
||||||
{
|
{
|
||||||
// Garbage in
|
// Garbage in
|
||||||
fprintf(stderr, "Incoming garbage from peer %d\n", op->peer_fd);
|
fprintf(stderr, "Can't handle incoming operation from client %lu\n", op->client_id);
|
||||||
msgr.stop_client(op->peer_fd);
|
msgr.stop_client(op->client_id);
|
||||||
delete op;
|
delete op;
|
||||||
};
|
};
|
||||||
msgr.parse_config(config);
|
msgr.parse_config(config);
|
||||||
@@ -156,7 +156,7 @@ void cluster_client_t::continue_raw_ops(osd_num_t peer_osd)
|
|||||||
{
|
{
|
||||||
auto op = it->second;
|
auto op = it->second;
|
||||||
op->op_type = OSD_OP_OUT;
|
op->op_type = OSD_OP_OUT;
|
||||||
op->peer_fd = msgr.osd_peer_fds.at(peer_osd);
|
op->client_id = msgr.osd_peers.at(peer_osd)->client_id;
|
||||||
msgr.outbox_push(op);
|
msgr.outbox_push(op);
|
||||||
raw_ops.erase(it++);
|
raw_ops.erase(it++);
|
||||||
}
|
}
|
||||||
@@ -590,7 +590,7 @@ void cluster_client_t::on_change_pool_config_hook()
|
|||||||
{
|
{
|
||||||
if (log_level > 2 && pg_counts[pool_item.first])
|
if (log_level > 2 && pg_counts[pool_item.first])
|
||||||
{
|
{
|
||||||
printf("Pool %u (%s) PG count changed from %lu to %lu\n", pool_item.first, pool_item.second.name.c_str(),
|
fprintf(stderr, "Pool %u (%s) PG count changed from %lu to %lu\n", pool_item.first, pool_item.second.name.c_str(),
|
||||||
pg_counts[pool_item.first], pool_item.second.real_pg_count);
|
pg_counts[pool_item.first], pool_item.second.real_pg_count);
|
||||||
}
|
}
|
||||||
// At this point, all pool operations should have been suspended
|
// At this point, all pool operations should have been suspended
|
||||||
@@ -871,13 +871,13 @@ void cluster_client_t::execute_cas(cluster_op_t *op)
|
|||||||
if (op->retval != expected && op->retval >= 0)
|
if (op->retval != expected && op->retval >= 0)
|
||||||
op->retval = -EIO;
|
op->retval = -EIO;
|
||||||
op->retval = op->retval == -EPIPE ? -EINTR : op->retval;
|
op->retval = op->retval == -EPIPE ? -EINTR : op->retval;
|
||||||
auto peer_it = msgr.osd_peer_fds.find(op->parts[0].osd_num);
|
auto peer_it = msgr.osd_peers.find(op->parts[0].osd_num);
|
||||||
if (op->retval != 0 || (op->flags & OP_IMMEDIATE_COMMIT))
|
if (op->retval != 0 || (op->flags & OP_IMMEDIATE_COMMIT))
|
||||||
{
|
{
|
||||||
auto cb = std::move(op->callback);
|
auto cb = std::move(op->callback);
|
||||||
cb(op);
|
cb(op);
|
||||||
}
|
}
|
||||||
else if (peer_it == msgr.osd_peer_fds.end())
|
else if (peer_it == msgr.osd_peers.end())
|
||||||
{
|
{
|
||||||
// Care must be taken to make sure that the client doesn't reconnect to the OSD
|
// Care must be taken to make sure that the client doesn't reconnect to the OSD
|
||||||
// before executing the previously completed operation callback (!)
|
// before executing the previously completed operation callback (!)
|
||||||
@@ -888,10 +888,10 @@ void cluster_client_t::execute_cas(cluster_op_t *op)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// CAS writes have a built-in sync
|
// CAS writes have a built-in sync
|
||||||
auto peer_fd = peer_it->second;
|
osd_client_t *cl = peer_it->second;
|
||||||
*part = (osd_op_t){
|
*part = (osd_op_t){
|
||||||
.op_type = OSD_OP_OUT,
|
.op_type = OSD_OP_OUT,
|
||||||
.peer_fd = peer_fd,
|
.client_id = cl->client_id,
|
||||||
.req = {
|
.req = {
|
||||||
.hdr = {
|
.hdr = {
|
||||||
.magic = SECONDARY_OSD_OP_MAGIC,
|
.magic = SECONDARY_OSD_OP_MAGIC,
|
||||||
@@ -1004,11 +1004,11 @@ bool cluster_client_t::check_rw(cluster_op_t *op)
|
|||||||
|
|
||||||
void cluster_client_t::execute_raw(osd_num_t osd_num, osd_op_t *op)
|
void cluster_client_t::execute_raw(osd_num_t osd_num, osd_op_t *op)
|
||||||
{
|
{
|
||||||
auto fd_it = msgr.osd_peer_fds.find(osd_num);
|
auto peer_it = msgr.osd_peers.find(osd_num);
|
||||||
if (fd_it != msgr.osd_peer_fds.end())
|
if (peer_it != msgr.osd_peers.end())
|
||||||
{
|
{
|
||||||
op->op_type = OSD_OP_OUT;
|
op->op_type = OSD_OP_OUT;
|
||||||
op->peer_fd = fd_it->second;
|
op->client_id = peer_it->second->client_id;
|
||||||
msgr.outbox_push(op);
|
msgr.outbox_push(op);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1119,6 +1119,13 @@ resume_2:
|
|||||||
// Finished successfully
|
// Finished successfully
|
||||||
// Even if the PG count has changed in meanwhile we treat it as success
|
// Even if the PG count has changed in meanwhile we treat it as success
|
||||||
// because if some operations were invalid for the new PG count we'd get errors
|
// because if some operations were invalid for the new PG count we'd get errors
|
||||||
|
if (op->opcode == OSD_OP_READ || op->opcode == OSD_OP_READ_BITMAP || op->opcode == OSD_OP_READ_CHAIN_BITMAP)
|
||||||
|
{
|
||||||
|
// Copy part bitmaps only after finishing all part reads
|
||||||
|
for (auto & part: op->parts)
|
||||||
|
if ((part.flags & (PART_SENT|PART_DONE|PART_VALID)) == (PART_SENT|PART_DONE|PART_VALID))
|
||||||
|
copy_part_bitmap(op, &part);
|
||||||
|
}
|
||||||
if (op->opcode == OSD_OP_READ || op->opcode == OSD_OP_READ_CHAIN_BITMAP)
|
if (op->opcode == OSD_OP_READ || op->opcode == OSD_OP_READ_CHAIN_BITMAP)
|
||||||
{
|
{
|
||||||
// Check parent inode
|
// Check parent inode
|
||||||
@@ -1164,7 +1171,7 @@ resume_2:
|
|||||||
erase_op(op);
|
erase_op(op);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else if (op->retval != 0 && !(op->flags & OP_FLUSH_BUFFER) &&
|
else if (op->retval != 0 && op->opcode != OSD_OP_SYNC && !(op->flags & OP_FLUSH_BUFFER) &&
|
||||||
op->retval != -EPIPE && (op->retval != -EIO || !client_eio_retry_interval) && (op->retval != -ENOSPC || !client_retry_enospc))
|
op->retval != -EPIPE && (op->retval != -EIO || !client_eio_retry_interval) && (op->retval != -ENOSPC || !client_retry_enospc))
|
||||||
{
|
{
|
||||||
// Fatal error (neither -EPIPE, -EIO nor -ENOSPC)
|
// Fatal error (neither -EPIPE, -EIO nor -ENOSPC)
|
||||||
@@ -1401,10 +1408,10 @@ int cluster_client_t::try_send(cluster_op_t *op, int i, std::function<void(osd_o
|
|||||||
primary_osd = nearest_osd;
|
primary_osd = nearest_osd;
|
||||||
}
|
}
|
||||||
part->osd_num = primary_osd;
|
part->osd_num = primary_osd;
|
||||||
auto peer_it = msgr.osd_peer_fds.find(primary_osd);
|
auto peer_it = msgr.osd_peers.find(primary_osd);
|
||||||
if (peer_it != msgr.osd_peer_fds.end())
|
if (peer_it != msgr.osd_peers.end())
|
||||||
{
|
{
|
||||||
int peer_fd = peer_it->second;
|
osd_client_t *cl = peer_it->second;
|
||||||
part->flags |= PART_SENT|PART_VALID;
|
part->flags |= PART_SENT|PART_VALID;
|
||||||
op->inflight_count++;
|
op->inflight_count++;
|
||||||
uint64_t pg_bitmap_size = (pool_cfg.data_block_size / pool_cfg.bitmap_granularity / 8) * (
|
uint64_t pg_bitmap_size = (pool_cfg.data_block_size / pool_cfg.bitmap_granularity / 8) * (
|
||||||
@@ -1419,7 +1426,7 @@ int cluster_client_t::try_send(cluster_op_t *op, int i, std::function<void(osd_o
|
|||||||
}
|
}
|
||||||
part->op = (osd_op_t){
|
part->op = (osd_op_t){
|
||||||
.op_type = OSD_OP_OUT,
|
.op_type = OSD_OP_OUT,
|
||||||
.peer_fd = peer_fd,
|
.client_id = cl->client_id,
|
||||||
.req = { .rw = {
|
.req = { .rw = {
|
||||||
.header = {
|
.header = {
|
||||||
.magic = SECONDARY_OSD_OP_MAGIC,
|
.magic = SECONDARY_OSD_OP_MAGIC,
|
||||||
@@ -1468,8 +1475,8 @@ int cluster_client_t::continue_sync(cluster_op_t *op)
|
|||||||
for (auto do_it = dirty_osds.begin(); do_it != dirty_osds.end(); )
|
for (auto do_it = dirty_osds.begin(); do_it != dirty_osds.end(); )
|
||||||
{
|
{
|
||||||
osd_num_t sync_osd = *do_it;
|
osd_num_t sync_osd = *do_it;
|
||||||
auto peer_it = msgr.osd_peer_fds.find(sync_osd);
|
auto peer_it = msgr.osd_peers.find(sync_osd);
|
||||||
if (peer_it == msgr.osd_peer_fds.end())
|
if (peer_it == msgr.osd_peers.end())
|
||||||
dirty_osds.erase(do_it++);
|
dirty_osds.erase(do_it++);
|
||||||
else
|
else
|
||||||
do_it++;
|
do_it++;
|
||||||
@@ -1522,12 +1529,12 @@ resume_1:
|
|||||||
|
|
||||||
void cluster_client_t::send_sync(cluster_op_t *op, cluster_op_part_t *part)
|
void cluster_client_t::send_sync(cluster_op_t *op, cluster_op_part_t *part)
|
||||||
{
|
{
|
||||||
auto peer_fd = msgr.osd_peer_fds.at(part->osd_num);
|
osd_client_t *cl = msgr.osd_peers.at(part->osd_num);
|
||||||
part->flags |= PART_SENT;
|
part->flags |= PART_SENT;
|
||||||
op->inflight_count++;
|
op->inflight_count++;
|
||||||
part->op = (osd_op_t){
|
part->op = (osd_op_t){
|
||||||
.op_type = OSD_OP_OUT,
|
.op_type = OSD_OP_OUT,
|
||||||
.peer_fd = peer_fd,
|
.client_id = cl->client_id,
|
||||||
.req = {
|
.req = {
|
||||||
.hdr = {
|
.hdr = {
|
||||||
.magic = SECONDARY_OSD_OP_MAGIC,
|
.magic = SECONDARY_OSD_OP_MAGIC,
|
||||||
@@ -1567,10 +1574,10 @@ void cluster_client_t::handle_op_part(cluster_op_part_t *part)
|
|||||||
// Error priority: EIO > ENOSPC > ETIMEDOUT > EPIPE
|
// Error priority: EIO > ENOSPC > ETIMEDOUT > EPIPE
|
||||||
op->retval = part->op.reply.hdr.retval;
|
op->retval = part->op.reply.hdr.retval;
|
||||||
}
|
}
|
||||||
int stop_fd = -1;
|
uint64_t stop_client_id = 0;
|
||||||
if (op->retval != -EINTR && op->retval != -EIO && op->retval != -ENOSPC)
|
if (op->retval != -EINTR && op->retval != -EIO && op->retval != -ENOSPC)
|
||||||
{
|
{
|
||||||
stop_fd = part->op.peer_fd;
|
stop_client_id = part->op.client_id;
|
||||||
if (op->retval != -EPIPE || log_level > 0)
|
if (op->retval != -EPIPE || log_level > 0)
|
||||||
{
|
{
|
||||||
fprintf(
|
fprintf(
|
||||||
@@ -1597,9 +1604,9 @@ void cluster_client_t::handle_op_part(cluster_op_part_t *part)
|
|||||||
op->retry_after = op->retval != -EPIPE ? client_eio_retry_interval : client_retry_interval;
|
op->retry_after = op->retval != -EPIPE ? client_eio_retry_interval : client_retry_interval;
|
||||||
}
|
}
|
||||||
reset_retry_timer(op->retry_after);
|
reset_retry_timer(op->retry_after);
|
||||||
if (stop_fd >= 0)
|
if (stop_client_id)
|
||||||
{
|
{
|
||||||
msgr.stop_client(stop_fd);
|
msgr.stop_client(stop_client_id);
|
||||||
}
|
}
|
||||||
op->inflight_count--;
|
op->inflight_count--;
|
||||||
if (op->inflight_count == 0 && !op->retry_after)
|
if (op->inflight_count == 0 && !op->retry_after)
|
||||||
@@ -1630,13 +1637,6 @@ void cluster_client_t::handle_op_part(cluster_op_part_t *part)
|
|||||||
}
|
}
|
||||||
if (op->inflight_count == 0 && !op->retry_after)
|
if (op->inflight_count == 0 && !op->retry_after)
|
||||||
{
|
{
|
||||||
// Copy part bitmaps only after finishing all part reads
|
|
||||||
if (op->opcode == OSD_OP_READ || op->opcode == OSD_OP_READ_BITMAP || op->opcode == OSD_OP_READ_CHAIN_BITMAP)
|
|
||||||
{
|
|
||||||
for (auto & part: op->parts)
|
|
||||||
if (part.flags == (PART_SENT|PART_VALID|PART_DONE))
|
|
||||||
copy_part_bitmap(op, &part);
|
|
||||||
}
|
|
||||||
if (op->opcode == OSD_OP_SYNC)
|
if (op->opcode == OSD_OP_SYNC)
|
||||||
continue_sync(op);
|
continue_sync(op);
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -83,9 +83,6 @@ class writeback_cache_t;
|
|||||||
// FIXME: Split into public and private interfaces
|
// FIXME: Split into public and private interfaces
|
||||||
class __attribute__((visibility("default"))) cluster_client_t
|
class __attribute__((visibility("default"))) cluster_client_t
|
||||||
{
|
{
|
||||||
#ifdef __MOCK__
|
|
||||||
public:
|
|
||||||
#endif
|
|
||||||
timerfd_manager_t *tfd = NULL;
|
timerfd_manager_t *tfd = NULL;
|
||||||
ring_loop_t *ringloop = NULL;
|
ring_loop_t *ringloop = NULL;
|
||||||
|
|
||||||
@@ -155,15 +152,9 @@ public:
|
|||||||
void list_inode(inode_t inode, uint64_t min_offset, uint64_t max_offset, int max_parallel_pgs, std::function<void(
|
void list_inode(inode_t inode, uint64_t min_offset, uint64_t max_offset, int max_parallel_pgs, std::function<void(
|
||||||
int status, int pgs_left, pg_num_t pg_num, std::set<object_id>&& objects)> pg_callback);
|
int status, int pgs_left, pg_num_t pg_num, std::set<object_id>&& objects)> pg_callback);
|
||||||
|
|
||||||
//inline uint32_t get_bs_bitmap_granularity() { return st_cli.global_bitmap_granularity; }
|
|
||||||
//inline uint64_t get_bs_block_size() { return st_cli.global_block_size; }
|
|
||||||
|
|
||||||
#ifndef __MOCK__
|
|
||||||
protected:
|
protected:
|
||||||
#endif
|
|
||||||
void continue_ops(int time_passed = 0);
|
void continue_ops(int time_passed = 0);
|
||||||
|
|
||||||
protected:
|
|
||||||
bool affects_osd(uint64_t inode, uint64_t offset, uint64_t len, osd_num_t osd);
|
bool affects_osd(uint64_t inode, uint64_t offset, uint64_t len, osd_num_t osd);
|
||||||
bool affects_pg(uint64_t inode, uint64_t offset, uint64_t len, pool_id_t pool_id, pg_num_t pg_num);
|
bool affects_pg(uint64_t inode, uint64_t offset, uint64_t len, pool_id_t pool_id, pg_num_t pg_num);
|
||||||
|
|
||||||
@@ -204,4 +195,5 @@ protected:
|
|||||||
osd_num_t select_nearest_osd(const std::vector<osd_num_t> & osds);
|
osd_num_t select_nearest_osd(const std::vector<osd_num_t> & osds);
|
||||||
|
|
||||||
friend class writeback_cache_t;
|
friend class writeback_cache_t;
|
||||||
|
friend class cluster_client_test_t;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -295,7 +295,7 @@ int cluster_client_t::start_pg_listing(inode_list_pg_t *pg)
|
|||||||
bool conn = true;
|
bool conn = true;
|
||||||
for (osd_num_t peer_osd: all_peers)
|
for (osd_num_t peer_osd: all_peers)
|
||||||
{
|
{
|
||||||
if (msgr.osd_peer_fds.find(peer_osd) == msgr.osd_peer_fds.end())
|
if (msgr.osd_peers.find(peer_osd) == msgr.osd_peers.end())
|
||||||
{
|
{
|
||||||
// Initiate connection
|
// Initiate connection
|
||||||
if (st_cli.peer_states[peer_osd].is_null())
|
if (st_cli.peer_states[peer_osd].is_null())
|
||||||
@@ -340,7 +340,7 @@ void cluster_client_t::send_list(inode_list_osd_t *cur_list)
|
|||||||
osd_op_t *op = new osd_op_t();
|
osd_op_t *op = new osd_op_t();
|
||||||
op->op_type = OSD_OP_OUT;
|
op->op_type = OSD_OP_OUT;
|
||||||
// Already checked that it exists above, but anyway
|
// Already checked that it exists above, but anyway
|
||||||
op->peer_fd = msgr.osd_peer_fds.at(cur_list->osd_num);
|
op->client_id = msgr.osd_peers.at(cur_list->osd_num)->client_id;
|
||||||
op->req = (osd_any_op_t){
|
op->req = (osd_any_op_t){
|
||||||
.sec_list = {
|
.sec_list = {
|
||||||
.header = {
|
.header = {
|
||||||
|
|||||||
@@ -88,6 +88,11 @@ void writeback_cache_t::copy_write(cluster_op_t *op, int state, uint64_t new_flu
|
|||||||
// ...or just save it for writeback if write buffering is enabled
|
// ...or just save it for writeback if write buffering is enabled
|
||||||
if (op->len == 0)
|
if (op->len == 0)
|
||||||
{
|
{
|
||||||
|
// FIXME: OSD_OP_DELETEs are currently only sent by vitastor-cli rm/rm-data and
|
||||||
|
// actually have len=0, because delete is actually a delete of the full object
|
||||||
|
// containing the requested offset, not a "punch hole" operation. But here, writeback
|
||||||
|
// cache assumes it IS a "punch hole" operation. I should select one of these
|
||||||
|
// approaches and fix everything accordingly when I decide to implement TRIM.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto dirty_it = find_dirty(op->inode, op->offset);
|
auto dirty_it = find_dirty(op->inode, op->offset);
|
||||||
@@ -244,12 +249,13 @@ void writeback_cache_t::copy_write(cluster_op_t *op, int state, uint64_t new_flu
|
|||||||
writeback_queue_size--;
|
writeback_queue_size--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!is_del)
|
if (!is_del && op->len > 0)
|
||||||
{
|
{
|
||||||
uint64_t pos = 0, len = op->len, iov_idx = 0;
|
uint64_t pos = 0, len = op->len, iov_idx = 0;
|
||||||
while (len > 0 && iov_idx < op->iov.count)
|
while (iov_idx < op->iov.count)
|
||||||
{
|
{
|
||||||
auto & iov = op->iov.buf[iov_idx];
|
auto & iov = op->iov.buf[iov_idx];
|
||||||
|
assert(pos + iov.iov_len <= len);
|
||||||
memcpy(buf + pos, iov.iov_base, iov.iov_len);
|
memcpy(buf + pos, iov.iov_base, iov.iov_len);
|
||||||
pos += iov.iov_len;
|
pos += iov.iov_len;
|
||||||
iov_idx++;
|
iov_idx++;
|
||||||
@@ -443,7 +449,7 @@ void writeback_cache_t::start_writebacks(cluster_client_t *cli, int count)
|
|||||||
started++;
|
started++;
|
||||||
assert(writeback_queue_size > 0);
|
assert(writeback_queue_size > 0);
|
||||||
writeback_queue_size--;
|
writeback_queue_size--;
|
||||||
writeback_bytes -= off - from_it->first.stripe;
|
writeback_bytes -= (is_del ? 0 : off - from_it->first.stripe);
|
||||||
assert(writeback_queue_size > 0 || !writeback_bytes);
|
assert(writeback_queue_size > 0 || !writeback_bytes);
|
||||||
flush_buffers(cli, from_it, to_it);
|
flush_buffers(cli, from_it, to_it);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1185,7 +1185,6 @@ void etcd_state_client_t::parse_state(const etcd_kv_t & kv)
|
|||||||
if (i >= pg_state_bit_count)
|
if (i >= pg_state_bit_count)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Unexpected pool %u PG %u state keyword in etcd: %s\n", pool_id, pg_num, e.dump().c_str());
|
fprintf(stderr, "Unexpected pool %u PG %u state keyword in etcd: %s\n", pool_id, pg_num, e.dump().c_str());
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!cur_primary || !value["state"].is_array() || !state ||
|
if (!cur_primary || !value["state"].is_array() || !state ||
|
||||||
@@ -1194,7 +1193,6 @@ void etcd_state_client_t::parse_state(const etcd_kv_t & kv)
|
|||||||
(state & PG_INCOMPLETE) && state != PG_INCOMPLETE && state != (PG_INCOMPLETE|PG_HAS_INVALID))
|
(state & PG_INCOMPLETE) && state != PG_INCOMPLETE && state != (PG_INCOMPLETE|PG_HAS_INVALID))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Unexpected pool %u PG %u state in etcd: primary=%ju, state=%s\n", pool_id, pg_num, cur_primary, value["state"].dump().c_str());
|
fprintf(stderr, "Unexpected pool %u PG %u state in etcd: primary=%ju, state=%s\n", pool_id, pg_num, cur_primary, value["state"].dump().c_str());
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
pg_cfg.cur_primary = cur_primary;
|
pg_cfg.cur_primary = cur_primary;
|
||||||
pg_cfg.cur_state = state;
|
pg_cfg.cur_state = state;
|
||||||
|
|||||||
+70
-176
@@ -15,106 +15,6 @@
|
|||||||
#include "msgr_rdma.h"
|
#include "msgr_rdma.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <sys/poll.h>
|
|
||||||
|
|
||||||
msgr_iothread_t::msgr_iothread_t():
|
|
||||||
ring(RINGLOOP_DEFAULT_SIZE, true),
|
|
||||||
thread(&msgr_iothread_t::run, this)
|
|
||||||
{
|
|
||||||
eventfd = ring.register_eventfd();
|
|
||||||
if (eventfd < 0)
|
|
||||||
{
|
|
||||||
throw std::runtime_error(std::string("failed to register eventfd: ") + strerror(-eventfd));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
msgr_iothread_t::~msgr_iothread_t()
|
|
||||||
{
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void msgr_iothread_t::add_sqe(io_uring_sqe & sqe)
|
|
||||||
{
|
|
||||||
mu.lock();
|
|
||||||
queue.push_back((iothread_sqe_t){ .sqe = sqe, .data = std::move(*(ring_data_t*)sqe.user_data) });
|
|
||||||
if (queue.size() == 1)
|
|
||||||
{
|
|
||||||
cond.notify_all();
|
|
||||||
}
|
|
||||||
mu.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void msgr_iothread_t::stop()
|
|
||||||
{
|
|
||||||
mu.lock();
|
|
||||||
if (stopped)
|
|
||||||
{
|
|
||||||
mu.unlock();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
stopped = true;
|
|
||||||
if (outer_loop_data)
|
|
||||||
{
|
|
||||||
outer_loop_data->callback = [](ring_data_t*){};
|
|
||||||
}
|
|
||||||
cond.notify_all();
|
|
||||||
close(eventfd);
|
|
||||||
mu.unlock();
|
|
||||||
thread.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
void msgr_iothread_t::add_to_ringloop(ring_loop_t *outer_loop)
|
|
||||||
{
|
|
||||||
assert(!this->outer_loop || this->outer_loop == outer_loop);
|
|
||||||
io_uring_sqe *sqe = outer_loop->get_sqe();
|
|
||||||
assert(sqe != NULL);
|
|
||||||
this->outer_loop = outer_loop;
|
|
||||||
this->outer_loop_data = ((ring_data_t*)sqe->user_data);
|
|
||||||
io_uring_prep_poll_add(sqe, eventfd, POLLIN);
|
|
||||||
outer_loop_data->callback = [this](ring_data_t *data)
|
|
||||||
{
|
|
||||||
if (data->res < 0)
|
|
||||||
{
|
|
||||||
throw std::runtime_error(std::string("eventfd poll failed: ") + strerror(-data->res));
|
|
||||||
}
|
|
||||||
outer_loop_data = NULL;
|
|
||||||
if (stopped)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
add_to_ringloop(this->outer_loop);
|
|
||||||
ring.loop();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void msgr_iothread_t::run()
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lk(mu);
|
|
||||||
while (!stopped && !queue.size())
|
|
||||||
cond.wait(lk);
|
|
||||||
if (stopped)
|
|
||||||
return;
|
|
||||||
int i = 0;
|
|
||||||
for (; i < queue.size(); i++)
|
|
||||||
{
|
|
||||||
io_uring_sqe *sqe = ring.get_sqe();
|
|
||||||
if (!sqe)
|
|
||||||
break;
|
|
||||||
ring_data_t *data = ((ring_data_t*)sqe->user_data);
|
|
||||||
*data = std::move(queue[i].data);
|
|
||||||
*sqe = queue[i].sqe;
|
|
||||||
sqe->user_data = (uint64_t)data;
|
|
||||||
}
|
|
||||||
queue.erase(queue.begin(), queue.begin()+i);
|
|
||||||
}
|
|
||||||
// We only want to offload sendmsg/recvmsg. Callbacks will be called in main thread
|
|
||||||
ring.submit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void osd_messenger_t::init()
|
void osd_messenger_t::init()
|
||||||
{
|
{
|
||||||
#ifdef WITH_RDMACM
|
#ifdef WITH_RDMACM
|
||||||
@@ -173,21 +73,17 @@ void osd_messenger_t::init()
|
|||||||
}
|
}
|
||||||
if (ringloop && iothread_count > 0)
|
if (ringloop && iothread_count > 0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < iothread_count; i++)
|
init_iothreads();
|
||||||
{
|
|
||||||
auto iot = new msgr_iothread_t();
|
|
||||||
iothreads.push_back(iot);
|
|
||||||
iot->add_to_ringloop(ringloop);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
keepalive_timer_id = tfd->set_timer(1000, true, [this](int)
|
keepalive_timer_id = tfd->set_timer(1000, true, [this](int)
|
||||||
{
|
{
|
||||||
|
std::vector<uint64_t> clients_to_stop;
|
||||||
|
std::vector<osd_op_t*> ops_to_send;
|
||||||
auto cl_it = clients.begin();
|
auto cl_it = clients.begin();
|
||||||
while (cl_it != clients.end())
|
while (cl_it != clients.end())
|
||||||
{
|
{
|
||||||
auto cl = cl_it->second;
|
auto cl = cl_it->second;
|
||||||
cl_it++;
|
cl_it++;
|
||||||
auto peer_fd = cl->peer_fd;
|
|
||||||
if (!cl->osd_num && !cl->in_osd_num || cl->peer_state != PEER_CONNECTED && cl->peer_state != PEER_RDMA)
|
if (!cl->osd_num && !cl->in_osd_num || cl->peer_state != PEER_CONNECTED && cl->peer_state != PEER_RDMA)
|
||||||
{
|
{
|
||||||
// Do not run keepalive on regular clients
|
// Do not run keepalive on regular clients
|
||||||
@@ -199,10 +95,9 @@ void osd_messenger_t::init()
|
|||||||
if (!cl->ping_time_remaining)
|
if (!cl->ping_time_remaining)
|
||||||
{
|
{
|
||||||
// Ping timed out, stop the client
|
// Ping timed out, stop the client
|
||||||
fprintf(stderr, "Ping timed out for OSD %ju (client %d), disconnecting peer\n", cl->in_osd_num ? cl->in_osd_num : cl->osd_num, cl->peer_fd);
|
fprintf(stderr, "Ping timed out for OSD %ju (client %ju), disconnecting peer\n",
|
||||||
stop_client(peer_fd, true);
|
cl->in_osd_num ? cl->in_osd_num : cl->osd_num, cl->client_id);
|
||||||
// Restart iterator because it may be invalidated
|
clients_to_stop.push_back(cl->client_id);
|
||||||
cl_it = clients.upper_bound(peer_fd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (cl->idle_time_remaining > 0)
|
else if (cl->idle_time_remaining > 0)
|
||||||
@@ -213,37 +108,36 @@ void osd_messenger_t::init()
|
|||||||
// Connection is idle for <osd_idle_time>, send ping
|
// Connection is idle for <osd_idle_time>, send ping
|
||||||
osd_op_t *op = new osd_op_t();
|
osd_op_t *op = new osd_op_t();
|
||||||
op->op_type = OSD_OP_OUT;
|
op->op_type = OSD_OP_OUT;
|
||||||
op->peer_fd = cl->peer_fd;
|
op->client_id = cl->client_id;
|
||||||
op->req = (osd_any_op_t){
|
op->req = (osd_any_op_t){
|
||||||
.hdr = {
|
.hdr = {
|
||||||
.magic = SECONDARY_OSD_OP_MAGIC,
|
.magic = SECONDARY_OSD_OP_MAGIC,
|
||||||
.opcode = OSD_OP_PING,
|
.opcode = OSD_OP_PING,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
op->callback = [this, cl](osd_op_t *op)
|
op->callback = [this](osd_op_t *op)
|
||||||
{
|
{
|
||||||
auto cl_it = clients.find(op->peer_fd);
|
auto cl_it = clients.find(op->client_id);
|
||||||
if (cl_it == clients.end() || cl_it->second != cl)
|
if (cl_it == clients.end())
|
||||||
{
|
{
|
||||||
// client is already dropped
|
// client is already dropped
|
||||||
delete op;
|
delete op;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int fail_fd = (op->reply.hdr.retval != 0 ? op->peer_fd : -1);
|
auto cl = cl_it->second;
|
||||||
|
uint64_t fail_client_id = (op->reply.hdr.retval != 0 ? op->client_id : 0);
|
||||||
auto fail_osd_num = cl->in_osd_num ? cl->in_osd_num : cl->osd_num;
|
auto fail_osd_num = cl->in_osd_num ? cl->in_osd_num : cl->osd_num;
|
||||||
cl->ping_time_remaining = 0;
|
cl->ping_time_remaining = 0;
|
||||||
delete op;
|
delete op;
|
||||||
if (fail_fd >= 0)
|
if (fail_client_id)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Ping failed for OSD %ju (client %d), disconnecting peer\n", fail_osd_num, fail_fd);
|
fprintf(stderr, "Ping failed for OSD %ju (client %ju), disconnecting peer\n", fail_osd_num, fail_client_id);
|
||||||
stop_client(fail_fd, true);
|
stop_client(fail_client_id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
cl->ping_time_remaining = osd_ping_timeout;
|
cl->ping_time_remaining = osd_ping_timeout;
|
||||||
cl->idle_time_remaining = osd_idle_timeout;
|
cl->idle_time_remaining = osd_idle_timeout;
|
||||||
outbox_push(op);
|
ops_to_send.push_back(op);
|
||||||
// Restart iterator because it may be invalidated
|
|
||||||
cl_it = clients.upper_bound(peer_fd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -251,6 +145,14 @@ void osd_messenger_t::init()
|
|||||||
cl->idle_time_remaining = osd_idle_timeout;
|
cl->idle_time_remaining = osd_idle_timeout;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (uint64_t client_id: clients_to_stop)
|
||||||
|
{
|
||||||
|
stop_client(client_id);
|
||||||
|
}
|
||||||
|
for (osd_op_t *op: ops_to_send)
|
||||||
|
{
|
||||||
|
outbox_push(op);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,16 +165,9 @@ osd_messenger_t::~osd_messenger_t()
|
|||||||
}
|
}
|
||||||
while (clients.size() > 0)
|
while (clients.size() > 0)
|
||||||
{
|
{
|
||||||
stop_client(clients.begin()->first, true, true);
|
stop_client(clients.begin()->first, true);
|
||||||
}
|
|
||||||
if (iothreads.size())
|
|
||||||
{
|
|
||||||
for (auto iot: iothreads)
|
|
||||||
{
|
|
||||||
delete iot;
|
|
||||||
}
|
|
||||||
iothreads.clear();
|
|
||||||
}
|
}
|
||||||
|
destroy_iothreads();
|
||||||
#ifdef WITH_RDMA
|
#ifdef WITH_RDMA
|
||||||
for (auto rdma_context: rdma_contexts)
|
for (auto rdma_context: rdma_contexts)
|
||||||
{
|
{
|
||||||
@@ -440,7 +335,7 @@ void osd_messenger_t::try_connect_peer(uint64_t peer_osd)
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (osd_peer_fds.find(peer_osd) != osd_peer_fds.end())
|
if (osd_peers.find(peer_osd) != osd_peers.end())
|
||||||
{
|
{
|
||||||
wanted_peers.erase(peer_osd);
|
wanted_peers.erase(peer_osd);
|
||||||
return;
|
return;
|
||||||
@@ -467,20 +362,20 @@ void osd_messenger_t::try_connect_peer_tcp(osd_num_t peer_osd, const char *peer_
|
|||||||
#ifdef WITH_RDMACM
|
#ifdef WITH_RDMACM
|
||||||
if (disable_tcp)
|
if (disable_tcp)
|
||||||
{
|
{
|
||||||
on_connect_peer(peer_osd, -EINVAL);
|
on_connect_peer(peer_osd, -EINVAL, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
struct sockaddr_storage addr;
|
struct sockaddr_storage addr;
|
||||||
if (!string_to_addr(peer_host, 0, peer_port, &addr))
|
if (!string_to_addr(peer_host, 0, peer_port, &addr))
|
||||||
{
|
{
|
||||||
on_connect_peer(peer_osd, -EINVAL);
|
on_connect_peer(peer_osd, -EINVAL, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int peer_fd = socket(addr.ss_family, SOCK_STREAM, 0);
|
int peer_fd = socket(addr.ss_family, SOCK_STREAM, 0);
|
||||||
if (peer_fd < 0)
|
if (peer_fd < 0)
|
||||||
{
|
{
|
||||||
on_connect_peer(peer_osd, -errno);
|
on_connect_peer(peer_osd, -errno, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fcntl(peer_fd, F_SETFL, fcntl(peer_fd, F_GETFL, 0) | O_NONBLOCK);
|
fcntl(peer_fd, F_SETFL, fcntl(peer_fd, F_GETFL, 0) | O_NONBLOCK);
|
||||||
@@ -488,21 +383,25 @@ void osd_messenger_t::try_connect_peer_tcp(osd_num_t peer_osd, const char *peer_
|
|||||||
if (r < 0 && errno != EINPROGRESS)
|
if (r < 0 && errno != EINPROGRESS)
|
||||||
{
|
{
|
||||||
close(peer_fd);
|
close(peer_fd);
|
||||||
on_connect_peer(peer_osd, -errno);
|
on_connect_peer(peer_osd, -errno, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
clients[peer_fd] = new osd_client_t();
|
const uint64_t client_id = next_client_id++;
|
||||||
|
osd_client_t *cl = new osd_client_t();
|
||||||
if (log_level > 0)
|
if (log_level > 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Connecting to OSD %ju at %s:%d (client %d)\n", peer_osd, peer_host, peer_port, peer_fd);
|
fprintf(stderr, "Connecting to OSD %ju at %s:%d (client %ju, FD %d)\n", peer_osd, peer_host, peer_port, client_id, peer_fd);
|
||||||
}
|
}
|
||||||
clients[peer_fd]->peer_addr = addr;
|
cl->client_id = client_id;
|
||||||
clients[peer_fd]->peer_port = peer_port;
|
cl->peer_addr = addr;
|
||||||
clients[peer_fd]->peer_fd = peer_fd;
|
cl->peer_port = peer_port;
|
||||||
clients[peer_fd]->peer_state = PEER_CONNECTING;
|
cl->peer_fd = peer_fd;
|
||||||
clients[peer_fd]->connect_timeout_id = -1;
|
cl->peer_state = PEER_CONNECTING;
|
||||||
clients[peer_fd]->osd_num = peer_osd;
|
cl->connect_timeout_id = -1;
|
||||||
clients[peer_fd]->in_buf = malloc_or_die(receive_buffer_size);
|
cl->osd_num = peer_osd;
|
||||||
|
cl->in_buf = malloc_or_die(receive_buffer_size);
|
||||||
|
clients[client_id] = cl;
|
||||||
|
clients_by_fd[peer_fd] = cl;
|
||||||
tfd->set_fd_handler(peer_fd, true, [this](int peer_fd, int epoll_events)
|
tfd->set_fd_handler(peer_fd, true, [this](int peer_fd, int epoll_events)
|
||||||
{
|
{
|
||||||
// Either OUT (connected) or HUP
|
// Either OUT (connected) or HUP
|
||||||
@@ -510,11 +409,11 @@ void osd_messenger_t::try_connect_peer_tcp(osd_num_t peer_osd, const char *peer_
|
|||||||
});
|
});
|
||||||
if (peer_connect_timeout > 0)
|
if (peer_connect_timeout > 0)
|
||||||
{
|
{
|
||||||
clients[peer_fd]->connect_timeout_id = tfd->set_timer(1000*peer_connect_timeout, false, [this, peer_fd](int timer_id)
|
cl->connect_timeout_id = tfd->set_timer(1000*peer_connect_timeout, false, [this, client_id](int timer_id)
|
||||||
{
|
{
|
||||||
osd_num_t peer_osd = clients.at(peer_fd)->osd_num;
|
osd_num_t peer_osd = clients.at(client_id)->osd_num;
|
||||||
stop_client(peer_fd, true);
|
stop_client(client_id);
|
||||||
on_connect_peer(peer_osd, -EPIPE);
|
on_connect_peer(peer_osd, -EPIPE, 0);
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -522,7 +421,7 @@ void osd_messenger_t::try_connect_peer_tcp(osd_num_t peer_osd, const char *peer_
|
|||||||
|
|
||||||
void osd_messenger_t::handle_connect_epoll(int peer_fd)
|
void osd_messenger_t::handle_connect_epoll(int peer_fd)
|
||||||
{
|
{
|
||||||
auto cl = clients[peer_fd];
|
auto cl = clients_by_fd.at(peer_fd);
|
||||||
if (cl->connect_timeout_id >= 0)
|
if (cl->connect_timeout_id >= 0)
|
||||||
{
|
{
|
||||||
tfd->clear_timer(cl->connect_timeout_id);
|
tfd->clear_timer(cl->connect_timeout_id);
|
||||||
@@ -537,8 +436,8 @@ void osd_messenger_t::handle_connect_epoll(int peer_fd)
|
|||||||
}
|
}
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
{
|
{
|
||||||
stop_client(peer_fd, true);
|
stop_client(cl->client_id);
|
||||||
on_connect_peer(peer_osd, -result);
|
on_connect_peer(peer_osd, -result, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int one = 1;
|
int one = 1;
|
||||||
@@ -555,23 +454,23 @@ void osd_messenger_t::handle_connect_epoll(int peer_fd)
|
|||||||
void osd_messenger_t::handle_peer_epoll(int peer_fd, int epoll_events)
|
void osd_messenger_t::handle_peer_epoll(int peer_fd, int epoll_events)
|
||||||
{
|
{
|
||||||
// Mark client as ready (i.e. some data is available)
|
// Mark client as ready (i.e. some data is available)
|
||||||
|
auto cl = clients_by_fd.at(peer_fd);
|
||||||
if (epoll_events & EPOLLRDHUP)
|
if (epoll_events & EPOLLRDHUP)
|
||||||
{
|
{
|
||||||
// Stop client
|
// Stop client
|
||||||
if (log_level > 0)
|
if (log_level > 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "[OSD %ju] client %d disconnected\n", this->osd_num, peer_fd);
|
fprintf(stderr, "[OSD %ju] client %ju disconnected\n", this->osd_num, cl->client_id);
|
||||||
}
|
}
|
||||||
stop_client(peer_fd, true);
|
stop_client(cl->client_id);
|
||||||
}
|
}
|
||||||
else if (epoll_events & EPOLLIN)
|
else if (epoll_events & EPOLLIN)
|
||||||
{
|
{
|
||||||
// Mark client as ready (i.e. some data is available)
|
// Mark client as ready (i.e. some data is available)
|
||||||
auto cl = clients[peer_fd];
|
|
||||||
cl->read_ready++;
|
cl->read_ready++;
|
||||||
if (cl->read_ready == 1)
|
if (cl->read_ready == 1)
|
||||||
{
|
{
|
||||||
read_ready_clients.push_back(cl->peer_fd);
|
read_ready_clients.push_back(cl->client_id);
|
||||||
if (ringloop)
|
if (ringloop)
|
||||||
ringloop->wakeup();
|
ringloop->wakeup();
|
||||||
else
|
else
|
||||||
@@ -580,13 +479,13 @@ void osd_messenger_t::handle_peer_epoll(int peer_fd, int epoll_events)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void osd_messenger_t::on_connect_peer(osd_num_t peer_osd, int peer_fd)
|
void osd_messenger_t::on_connect_peer(osd_num_t peer_osd, int errcode, uint64_t client_id)
|
||||||
{
|
{
|
||||||
auto & wp = wanted_peers.at(peer_osd);
|
auto & wp = wanted_peers.at(peer_osd);
|
||||||
wp.connecting = false;
|
wp.connecting = false;
|
||||||
if (peer_fd < 0)
|
if (errcode < 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Failed to connect to peer OSD %ju address %s port %d: %s\n", peer_osd, wp.cur_addr.c_str(), wp.cur_port, strerror(-peer_fd));
|
fprintf(stderr, "Failed to connect to peer OSD %ju address %s port %d: %s\n", peer_osd, wp.cur_addr.c_str(), wp.cur_port, strerror(-errcode));
|
||||||
if (wp.address_changed)
|
if (wp.address_changed)
|
||||||
{
|
{
|
||||||
wp.address_changed = false;
|
wp.address_changed = false;
|
||||||
@@ -613,7 +512,7 @@ void osd_messenger_t::on_connect_peer(osd_num_t peer_osd, int peer_fd)
|
|||||||
}
|
}
|
||||||
if (log_level > 0)
|
if (log_level > 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "[OSD %ju] Connected with peer OSD %ju (client %d)\n", osd_num, peer_osd, peer_fd);
|
fprintf(stderr, "[OSD %ju] Connected with peer OSD %ju (client %ju)\n", osd_num, peer_osd, client_id);
|
||||||
}
|
}
|
||||||
wanted_peers.erase(peer_osd);
|
wanted_peers.erase(peer_osd);
|
||||||
repeer_pgs(peer_osd);
|
repeer_pgs(peer_osd);
|
||||||
@@ -623,7 +522,7 @@ void osd_messenger_t::check_peer_config(osd_client_t *cl)
|
|||||||
{
|
{
|
||||||
osd_op_t *op = new osd_op_t();
|
osd_op_t *op = new osd_op_t();
|
||||||
op->op_type = OSD_OP_OUT;
|
op->op_type = OSD_OP_OUT;
|
||||||
op->peer_fd = cl->peer_fd;
|
op->client_id = cl->client_id;
|
||||||
op->req = (osd_any_op_t){
|
op->req = (osd_any_op_t){
|
||||||
.show_conf = {
|
.show_conf = {
|
||||||
.header = {
|
.header = {
|
||||||
@@ -647,7 +546,7 @@ void osd_messenger_t::check_peer_config(osd_client_t *cl)
|
|||||||
if (!selected_ctx)
|
if (!selected_ctx)
|
||||||
{
|
{
|
||||||
if (log_level > 0)
|
if (log_level > 0)
|
||||||
fprintf(stderr, "No RDMA context for OSD %ju connection (peer %d), using only TCP\n", cl->osd_num, cl->peer_fd);
|
fprintf(stderr, "No RDMA context for OSD %ju connection (client %ju), using only TCP\n", cl->osd_num, cl->client_id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -708,8 +607,8 @@ void osd_messenger_t::check_peer_config(osd_client_t *cl)
|
|||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
osd_num_t peer_osd = cl->osd_num;
|
osd_num_t peer_osd = cl->osd_num;
|
||||||
stop_client(op->peer_fd);
|
stop_client(op->client_id);
|
||||||
on_connect_peer(peer_osd, -EINVAL);
|
on_connect_peer(peer_osd, -EINVAL, 0);
|
||||||
delete op;
|
delete op;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -739,21 +638,13 @@ void osd_messenger_t::check_peer_config(osd_client_t *cl)
|
|||||||
fprintf(stderr, "Connected to OSD %ju using RDMA\n", cl->osd_num);
|
fprintf(stderr, "Connected to OSD %ju using RDMA\n", cl->osd_num);
|
||||||
}
|
}
|
||||||
cl->peer_state = PEER_RDMA;
|
cl->peer_state = PEER_RDMA;
|
||||||
tfd->set_fd_handler(cl->peer_fd, false, [this](int peer_fd, int epoll_events)
|
|
||||||
{
|
|
||||||
// Do not miss the disconnection!
|
|
||||||
if (epoll_events & EPOLLRDHUP)
|
|
||||||
{
|
|
||||||
handle_peer_epoll(peer_fd, epoll_events);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Add the initial receive request
|
// Add the initial receive request
|
||||||
init_recv_rdma(cl);
|
init_recv_rdma(cl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
osd_peer_fds[cl->osd_num] = cl->peer_fd;
|
osd_peers[cl->osd_num] = cl;
|
||||||
on_connect_peer(cl->osd_num, cl->peer_fd);
|
on_connect_peer(cl->osd_num, 0, cl->client_id);
|
||||||
delete op;
|
delete op;
|
||||||
};
|
};
|
||||||
outbox_push(op);
|
outbox_push(op);
|
||||||
@@ -768,13 +659,16 @@ void osd_messenger_t::accept_connections(int listen_fd)
|
|||||||
while ((peer_fd = accept(listen_fd, (sockaddr*)&addr, &peer_addr_size)) >= 0)
|
while ((peer_fd = accept(listen_fd, (sockaddr*)&addr, &peer_addr_size)) >= 0)
|
||||||
{
|
{
|
||||||
assert(peer_fd != 0);
|
assert(peer_fd != 0);
|
||||||
fprintf(stderr, "[OSD %ju] new client %d: connection from %s\n", this->osd_num, peer_fd,
|
const uint64_t client_id = next_client_id++;
|
||||||
|
fprintf(stderr, "[OSD %ju] new client %ju (FD %d): connection from %s\n", this->osd_num, client_id, peer_fd,
|
||||||
addr_to_string(addr).c_str());
|
addr_to_string(addr).c_str());
|
||||||
fcntl(peer_fd, F_SETFL, fcntl(peer_fd, F_GETFL, 0) | O_NONBLOCK);
|
fcntl(peer_fd, F_SETFL, fcntl(peer_fd, F_GETFL, 0) | O_NONBLOCK);
|
||||||
int one = 1;
|
int one = 1;
|
||||||
setsockopt(peer_fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one));
|
setsockopt(peer_fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one));
|
||||||
auto cl = new osd_client_t();
|
auto cl = new osd_client_t();
|
||||||
clients[peer_fd] = cl;
|
cl->client_id = client_id;
|
||||||
|
clients[cl->client_id] = cl;
|
||||||
|
clients_by_fd[peer_fd] = cl;
|
||||||
cl->is_incoming = true;
|
cl->is_incoming = true;
|
||||||
cl->peer_addr = addr;
|
cl->peer_addr = addr;
|
||||||
cl->peer_addr = addr;
|
cl->peer_addr = addr;
|
||||||
|
|||||||
+20
-49
@@ -12,6 +12,7 @@
|
|||||||
#include <deque>
|
#include <deque>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "../util/robin_hood.h"
|
||||||
#include "malloc_or_die.h"
|
#include "malloc_or_die.h"
|
||||||
#include "json11/json11.hpp"
|
#include "json11/json11.hpp"
|
||||||
#include "msgr_op.h"
|
#include "msgr_op.h"
|
||||||
@@ -50,6 +51,7 @@ struct msgr_rdma_context_t;
|
|||||||
|
|
||||||
struct osd_client_t
|
struct osd_client_t
|
||||||
{
|
{
|
||||||
|
uint64_t client_id = 0;
|
||||||
int refs = 0;
|
int refs = 0;
|
||||||
|
|
||||||
sockaddr_storage peer_addr = {};
|
sockaddr_storage peer_addr = {};
|
||||||
@@ -85,7 +87,7 @@ struct osd_client_t
|
|||||||
std::vector<osd_op_t*> received_ops;
|
std::vector<osd_op_t*> received_ops;
|
||||||
|
|
||||||
// Outbound operations
|
// Outbound operations
|
||||||
std::map<uint64_t, osd_op_t*> sent_ops;
|
robin_hood::unordered_flat_map<uint64_t, osd_op_t*> sent_ops;
|
||||||
uint64_t send_op_id = 0;
|
uint64_t send_op_id = 0;
|
||||||
|
|
||||||
// PGs dirtied by this client's primary-writes
|
// PGs dirtied by this client's primary-writes
|
||||||
@@ -127,43 +129,7 @@ struct osd_op_stats_t
|
|||||||
uint64_t subop_stat_count[OSD_OP_MAX+1] = { 0 };
|
uint64_t subop_stat_count[OSD_OP_MAX+1] = { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
#include <mutex>
|
|
||||||
#include <condition_variable>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
#ifdef __MOCK__
|
|
||||||
class msgr_iothread_t;
|
class msgr_iothread_t;
|
||||||
#else
|
|
||||||
struct iothread_sqe_t
|
|
||||||
{
|
|
||||||
io_uring_sqe sqe;
|
|
||||||
ring_data_t data;
|
|
||||||
};
|
|
||||||
|
|
||||||
class msgr_iothread_t
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
ring_loop_t ring;
|
|
||||||
ring_loop_t *outer_loop = NULL;
|
|
||||||
ring_data_t *outer_loop_data = NULL;
|
|
||||||
int eventfd = -1;
|
|
||||||
bool stopped = false;
|
|
||||||
std::mutex mu;
|
|
||||||
std::condition_variable cond;
|
|
||||||
std::vector<iothread_sqe_t> queue;
|
|
||||||
std::thread thread;
|
|
||||||
|
|
||||||
void run();
|
|
||||||
public:
|
|
||||||
|
|
||||||
msgr_iothread_t();
|
|
||||||
~msgr_iothread_t();
|
|
||||||
|
|
||||||
void add_sqe(io_uring_sqe & sqe);
|
|
||||||
void stop();
|
|
||||||
void add_to_ringloop(ring_loop_t *outer_loop);
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WITH_RDMA
|
#ifdef WITH_RDMA
|
||||||
struct rdma_event_channel;
|
struct rdma_event_channel;
|
||||||
@@ -201,25 +167,27 @@ protected:
|
|||||||
uint64_t rdma_max_sge = 0, rdma_max_send = 0, rdma_max_recv = 0;
|
uint64_t rdma_max_sge = 0, rdma_max_send = 0, rdma_max_recv = 0;
|
||||||
uint64_t rdma_max_msg = 0;
|
uint64_t rdma_max_msg = 0;
|
||||||
rdma_event_channel *rdmacm_evch = NULL;
|
rdma_event_channel *rdmacm_evch = NULL;
|
||||||
std::map<rdma_cm_id*, osd_client_t*> rdmacm_connections;
|
robin_hood::unordered_flat_map<rdma_cm_id*, osd_client_t*> rdmacm_connections;
|
||||||
std::map<rdma_cm_id*, rdmacm_connecting_t*> rdmacm_connecting;
|
robin_hood::unordered_flat_map<rdma_cm_id*, rdmacm_connecting_t*> rdmacm_connecting;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::vector<msgr_iothread_t*> iothreads;
|
std::vector<msgr_iothread_t*> iothreads;
|
||||||
std::vector<int> read_ready_clients;
|
std::vector<uint64_t> read_ready_clients;
|
||||||
std::vector<int> write_ready_clients;
|
std::vector<uint64_t> write_ready_clients;
|
||||||
// We don't use ringloop->set_immediate here because we may have no ringloop in client :)
|
// We don't use ringloop->set_immediate here because we may have no ringloop in client :)
|
||||||
std::deque<osd_op_t*> set_immediate_ops;
|
std::deque<osd_op_t*> set_immediate_ops;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
timerfd_manager_t *tfd = NULL;
|
timerfd_manager_t *tfd = NULL;
|
||||||
ring_loop_t *ringloop = NULL;
|
ring_loop_i *ringloop = NULL;
|
||||||
bool has_sendmsg_zc = false;
|
bool has_sendmsg_zc = false;
|
||||||
// osd_num_t is only for logging and asserts
|
// osd_num_t is only for logging and asserts
|
||||||
|
uint64_t next_client_id = 1;
|
||||||
osd_num_t osd_num;
|
osd_num_t osd_num;
|
||||||
std::map<int, osd_client_t*> clients;
|
robin_hood::unordered_flat_map<uint64_t, osd_client_t*> clients;
|
||||||
std::map<osd_num_t, osd_wanted_peer_t> wanted_peers;
|
robin_hood::unordered_flat_map<uint64_t, osd_client_t*> osd_peers;
|
||||||
std::map<uint64_t, int> osd_peer_fds;
|
robin_hood::unordered_flat_map<int, osd_client_t*> clients_by_fd;
|
||||||
|
robin_hood::unordered_flat_map<osd_num_t, osd_wanted_peer_t> wanted_peers;
|
||||||
std::vector<std::string> osd_networks;
|
std::vector<std::string> osd_networks;
|
||||||
std::vector<addr_mask_t> osd_network_masks;
|
std::vector<addr_mask_t> osd_network_masks;
|
||||||
std::vector<std::string> osd_cluster_networks;
|
std::vector<std::string> osd_cluster_networks;
|
||||||
@@ -230,9 +198,11 @@ public:
|
|||||||
osd_op_stats_t stats, recovery_stats;
|
osd_op_stats_t stats, recovery_stats;
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
void init_iothreads();
|
||||||
void parse_config(const json11::Json & config);
|
void parse_config(const json11::Json & config);
|
||||||
void connect_peer(uint64_t osd_num, json11::Json peer_state);
|
void connect_peer(uint64_t osd_num, json11::Json peer_state);
|
||||||
void stop_client(int peer_fd, bool force = false, bool force_delete = false);
|
void stop_client(uint64_t client_id, bool force_delete = false);
|
||||||
|
void destroy_client(osd_client_t *cl);
|
||||||
void outbox_push(osd_op_t *cur_op);
|
void outbox_push(osd_op_t *cur_op);
|
||||||
std::function<void(osd_op_t*)> exec_op;
|
std::function<void(osd_op_t*)> exec_op;
|
||||||
std::function<void(osd_num_t)> repeer_pgs;
|
std::function<void(osd_num_t)> repeer_pgs;
|
||||||
@@ -241,6 +211,7 @@ public:
|
|||||||
void read_requests();
|
void read_requests();
|
||||||
void send_replies();
|
void send_replies();
|
||||||
void accept_connections(int listen_fd);
|
void accept_connections(int listen_fd);
|
||||||
|
void destroy_iothreads();
|
||||||
~osd_messenger_t();
|
~osd_messenger_t();
|
||||||
|
|
||||||
static json11::Json::object read_config(const json11::Json & config);
|
static json11::Json::object read_config(const json11::Json & config);
|
||||||
@@ -251,7 +222,7 @@ public:
|
|||||||
|
|
||||||
#ifdef WITH_RDMA
|
#ifdef WITH_RDMA
|
||||||
bool is_rdma_enabled();
|
bool is_rdma_enabled();
|
||||||
bool connect_rdma(int peer_fd, std::string rdma_address, uint64_t client_max_msg);
|
bool connect_rdma(uint64_t client_id, std::string rdma_address, uint64_t client_max_msg);
|
||||||
#endif
|
#endif
|
||||||
#ifdef WITH_RDMACM
|
#ifdef WITH_RDMACM
|
||||||
bool is_use_rdmacm();
|
bool is_use_rdmacm();
|
||||||
@@ -267,7 +238,7 @@ protected:
|
|||||||
void try_connect_peer_tcp(osd_num_t peer_osd, const char *peer_host, int peer_port);
|
void try_connect_peer_tcp(osd_num_t peer_osd, const char *peer_host, int peer_port);
|
||||||
void handle_peer_epoll(int peer_fd, int epoll_events);
|
void handle_peer_epoll(int peer_fd, int epoll_events);
|
||||||
void handle_connect_epoll(int peer_fd);
|
void handle_connect_epoll(int peer_fd);
|
||||||
void on_connect_peer(osd_num_t peer_osd, int peer_fd);
|
void on_connect_peer(osd_num_t peer_osd, int errcode, uint64_t client_id);
|
||||||
void check_peer_config(osd_client_t *cl);
|
void check_peer_config(osd_client_t *cl);
|
||||||
void cancel_osd_ops(osd_client_t *cl);
|
void cancel_osd_ops(osd_client_t *cl);
|
||||||
void cancel_op(osd_op_t *op);
|
void cancel_op(osd_op_t *op);
|
||||||
@@ -282,13 +253,13 @@ protected:
|
|||||||
bool handle_reply_hdr(osd_client_t *cl);
|
bool handle_reply_hdr(osd_client_t *cl);
|
||||||
void handle_reply_ready(osd_op_t *op);
|
void handle_reply_ready(osd_op_t *op);
|
||||||
void handle_immediate_ops();
|
void handle_immediate_ops();
|
||||||
void clear_immediate_ops(int peer_fd);
|
|
||||||
|
|
||||||
#ifdef WITH_RDMA
|
#ifdef WITH_RDMA
|
||||||
void try_send_rdma(osd_client_t *cl);
|
void try_send_rdma(osd_client_t *cl);
|
||||||
bool init_recv_rdma(osd_client_t *cl);
|
bool init_recv_rdma(osd_client_t *cl);
|
||||||
void handle_rdma_events(msgr_rdma_context_t *rdma_context);
|
void handle_rdma_events(msgr_rdma_context_t *rdma_context);
|
||||||
msgr_rdma_context_t* choose_rdma_context(osd_client_t *cl);
|
msgr_rdma_context_t* choose_rdma_context(osd_client_t *cl);
|
||||||
|
void destroy_rdma_conn(msgr_rdma_connection_t *rdma_conn);
|
||||||
#endif
|
#endif
|
||||||
#ifdef WITH_RDMACM
|
#ifdef WITH_RDMACM
|
||||||
void handle_rdmacm_events();
|
void handle_rdmacm_events();
|
||||||
|
|||||||
@@ -0,0 +1,129 @@
|
|||||||
|
// Copyright (c) Vitaliy Filippov, 2019+
|
||||||
|
// License: VNPL-1.1 or GNU GPL-2.0+ (see README.md for details)
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "messenger.h"
|
||||||
|
#include "msgr_iothread.h"
|
||||||
|
|
||||||
|
msgr_iothread_t::msgr_iothread_t():
|
||||||
|
ring(RINGLOOP_DEFAULT_SIZE, true),
|
||||||
|
thread(&msgr_iothread_t::run, this)
|
||||||
|
{
|
||||||
|
eventfd = ring.register_eventfd();
|
||||||
|
if (eventfd < 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::string("failed to register eventfd: ") + strerror(-eventfd));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
msgr_iothread_t::~msgr_iothread_t()
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void msgr_iothread_t::add_sqe(io_uring_sqe & sqe)
|
||||||
|
{
|
||||||
|
mu.lock();
|
||||||
|
queue.push_back((iothread_sqe_t){ .sqe = sqe, .data = std::move(*(ring_data_t*)sqe.user_data) });
|
||||||
|
if (queue.size() == 1)
|
||||||
|
{
|
||||||
|
cond.notify_all();
|
||||||
|
}
|
||||||
|
mu.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void msgr_iothread_t::stop()
|
||||||
|
{
|
||||||
|
mu.lock();
|
||||||
|
if (stopped)
|
||||||
|
{
|
||||||
|
mu.unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stopped = true;
|
||||||
|
if (outer_loop_data)
|
||||||
|
{
|
||||||
|
outer_loop_data->callback = [](ring_data_t*){};
|
||||||
|
}
|
||||||
|
cond.notify_all();
|
||||||
|
close(eventfd);
|
||||||
|
mu.unlock();
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
void msgr_iothread_t::add_to_ringloop(ring_loop_i *outer_loop)
|
||||||
|
{
|
||||||
|
assert(!this->outer_loop || this->outer_loop == outer_loop);
|
||||||
|
io_uring_sqe *sqe = outer_loop->get_sqe();
|
||||||
|
assert(sqe != NULL);
|
||||||
|
this->outer_loop = outer_loop;
|
||||||
|
this->outer_loop_data = ((ring_data_t*)sqe->user_data);
|
||||||
|
io_uring_prep_poll_add(sqe, eventfd, POLLIN);
|
||||||
|
outer_loop_data->callback = [this](ring_data_t *data)
|
||||||
|
{
|
||||||
|
if (data->res < 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::string("eventfd poll failed: ") + strerror(-data->res));
|
||||||
|
}
|
||||||
|
outer_loop_data = NULL;
|
||||||
|
if (stopped)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
add_to_ringloop(this->outer_loop);
|
||||||
|
ring.loop();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void msgr_iothread_t::run()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lk(mu);
|
||||||
|
while (!stopped && !queue.size())
|
||||||
|
cond.wait(lk);
|
||||||
|
if (stopped)
|
||||||
|
return;
|
||||||
|
int i = 0;
|
||||||
|
for (; i < queue.size(); i++)
|
||||||
|
{
|
||||||
|
io_uring_sqe *sqe = ring.get_sqe();
|
||||||
|
if (!sqe)
|
||||||
|
break;
|
||||||
|
ring_data_t *data = ((ring_data_t*)sqe->user_data);
|
||||||
|
*data = std::move(queue[i].data);
|
||||||
|
*sqe = queue[i].sqe;
|
||||||
|
sqe->user_data = (uint64_t)data;
|
||||||
|
}
|
||||||
|
queue.erase(queue.begin(), queue.begin()+i);
|
||||||
|
}
|
||||||
|
// We only want to offload sendmsg/recvmsg. Callbacks will be called in main thread
|
||||||
|
ring.submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void osd_messenger_t::init_iothreads()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < iothread_count; i++)
|
||||||
|
{
|
||||||
|
auto iot = new msgr_iothread_t();
|
||||||
|
iothreads.push_back(iot);
|
||||||
|
iot->add_to_ringloop(ringloop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void osd_messenger_t::destroy_iothreads()
|
||||||
|
{
|
||||||
|
if (iothreads.size())
|
||||||
|
{
|
||||||
|
for (auto iot: iothreads)
|
||||||
|
{
|
||||||
|
delete iot;
|
||||||
|
}
|
||||||
|
iothreads.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright (c) Vitaliy Filippov, 2019+
|
||||||
|
// License: VNPL-1.1 or GNU GPL-2.0+ (see README.md for details)
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include "ringloop.h"
|
||||||
|
|
||||||
|
struct iothread_sqe_t
|
||||||
|
{
|
||||||
|
io_uring_sqe sqe;
|
||||||
|
ring_data_t data;
|
||||||
|
};
|
||||||
|
|
||||||
|
class msgr_iothread_t
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
ring_loop_t ring;
|
||||||
|
ring_loop_i *outer_loop = NULL;
|
||||||
|
ring_data_t *outer_loop_data = NULL;
|
||||||
|
int eventfd = -1;
|
||||||
|
bool stopped = false;
|
||||||
|
std::mutex mu;
|
||||||
|
std::condition_variable cond;
|
||||||
|
std::vector<iothread_sqe_t> queue;
|
||||||
|
std::thread thread;
|
||||||
|
|
||||||
|
void run();
|
||||||
|
public:
|
||||||
|
|
||||||
|
msgr_iothread_t();
|
||||||
|
~msgr_iothread_t();
|
||||||
|
|
||||||
|
void add_sqe(io_uring_sqe & sqe);
|
||||||
|
void stop();
|
||||||
|
void add_to_ringloop(ring_loop_i *outer_loop);
|
||||||
|
};
|
||||||
@@ -156,7 +156,8 @@ 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;
|
||||||
int peer_fd;
|
uint64_t client_id = 0;
|
||||||
|
osd_num_t osd_num = 0;
|
||||||
osd_any_op_t req;
|
osd_any_op_t req;
|
||||||
osd_any_reply_t reply;
|
osd_any_reply_t reply;
|
||||||
blockstore_op_t *bs_op = NULL;
|
blockstore_op_t *bs_op = NULL;
|
||||||
|
|||||||
+45
-16
@@ -187,6 +187,8 @@ std::vector<msgr_rdma_context_t*> msgr_rdma_context_t::create_all(const std::vec
|
|||||||
ibv_device **raw_dev_list = NULL;
|
ibv_device **raw_dev_list = NULL;
|
||||||
ibv_device **dev_list = NULL;
|
ibv_device **dev_list = NULL;
|
||||||
ibv_device *single_list[2] = {};
|
ibv_device *single_list[2] = {};
|
||||||
|
int up_ports = 0;
|
||||||
|
int single_port_num = 0;
|
||||||
|
|
||||||
raw_dev_list = dev_list = ibv_get_device_list(NULL);
|
raw_dev_list = dev_list = ibv_get_device_list(NULL);
|
||||||
if (!dev_list || !*dev_list)
|
if (!dev_list || !*dev_list)
|
||||||
@@ -221,6 +223,7 @@ std::vector<msgr_rdma_context_t*> msgr_rdma_context_t::create_all(const std::vec
|
|||||||
dev_list = single_list;
|
dev_list = single_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retry:
|
||||||
for (int i = 0; dev_list[i]; ++i)
|
for (int i = 0; dev_list[i]; ++i)
|
||||||
{
|
{
|
||||||
auto dev = dev_list[i];
|
auto dev = dev_list[i];
|
||||||
@@ -258,6 +261,9 @@ std::vector<msgr_rdma_context_t*> msgr_rdma_context_t::create_all(const std::vec
|
|||||||
fprintf(stderr, "RDMA device %s port %d GID %d does not exist\n", ibv_get_device_name(dev), port_num, sel_gid_index);
|
fprintf(stderr, "RDMA device %s port %d GID %d does not exist\n", ibv_get_device_name(dev), port_num, sel_gid_index);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
up_ports++;
|
||||||
|
single_port_num = port_num;
|
||||||
|
single_list[0] = dev;
|
||||||
uint32_t port_mtu = sel_mtu ? sel_mtu : ibv_mtu_to_bytes(portinfo.active_mtu);
|
uint32_t port_mtu = sel_mtu ? sel_mtu : ibv_mtu_to_bytes(portinfo.active_mtu);
|
||||||
#ifdef IBV_ADVISE_MR_ADVICE_PREFETCH_NO_FAULT
|
#ifdef IBV_ADVISE_MR_ADVICE_PREFETCH_NO_FAULT
|
||||||
if (sel_gid_index < 0)
|
if (sel_gid_index < 0)
|
||||||
@@ -298,6 +304,14 @@ cleanup_dev:
|
|||||||
ibv_close_device(context);
|
ibv_close_device(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ret.size() && up_ports == 1 && dev_list != single_list)
|
||||||
|
{
|
||||||
|
// Auto-select the only available device/port if there is only one
|
||||||
|
dev_list = single_list;
|
||||||
|
sel_port_num = single_port_num;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
if (raw_dev_list)
|
if (raw_dev_list)
|
||||||
ibv_free_device_list(raw_dev_list);
|
ibv_free_device_list(raw_dev_list);
|
||||||
@@ -493,7 +507,7 @@ int msgr_rdma_connection_t::connect(msgr_rdma_address_t *dest)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool osd_messenger_t::connect_rdma(int peer_fd, std::string rdma_address, uint64_t client_max_msg)
|
bool osd_messenger_t::connect_rdma(uint64_t client_id, std::string rdma_address, uint64_t client_max_msg)
|
||||||
{
|
{
|
||||||
// Try to connect to the peer using RDMA
|
// Try to connect to the peer using RDMA
|
||||||
msgr_rdma_address_t addr;
|
msgr_rdma_address_t addr;
|
||||||
@@ -503,12 +517,12 @@ bool osd_messenger_t::connect_rdma(int peer_fd, std::string rdma_address, uint64
|
|||||||
{
|
{
|
||||||
client_max_msg = rdma_max_msg;
|
client_max_msg = rdma_max_msg;
|
||||||
}
|
}
|
||||||
auto cl = clients.at(peer_fd);
|
auto cl = clients.at(client_id);
|
||||||
msgr_rdma_context_t *selected_ctx = choose_rdma_context(cl);
|
msgr_rdma_context_t *selected_ctx = choose_rdma_context(cl);
|
||||||
if (!selected_ctx)
|
if (!selected_ctx)
|
||||||
{
|
{
|
||||||
if (log_level > 0)
|
if (log_level > 0)
|
||||||
fprintf(stderr, "No RDMA context for peer %d, using only TCP\n", cl->peer_fd);
|
fprintf(stderr, "No RDMA context for peer %ju, using only TCP\n", client_id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
msgr_rdma_connection_t *rdma_conn = msgr_rdma_connection_t::create(selected_ctx, rdma_max_send, rdma_max_recv, rdma_max_sge, client_max_msg);
|
msgr_rdma_connection_t *rdma_conn = msgr_rdma_connection_t::create(selected_ctx, rdma_max_send, rdma_max_recv, rdma_max_sge, client_max_msg);
|
||||||
@@ -519,14 +533,13 @@ bool osd_messenger_t::connect_rdma(int peer_fd, std::string rdma_address, uint64
|
|||||||
{
|
{
|
||||||
delete rdma_conn;
|
delete rdma_conn;
|
||||||
fprintf(
|
fprintf(
|
||||||
stderr, "Failed to connect RDMA queue pair to %s (client %d)\n",
|
stderr, "Failed to connect RDMA queue pair to %s (client %ju)\n",
|
||||||
addr.to_string().c_str(), peer_fd
|
addr.to_string().c_str(), client_id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Remember connection, but switch to RDMA only after sending the configuration response
|
// Remember connection, but switch to RDMA only after sending the configuration response
|
||||||
auto cl = clients.at(peer_fd);
|
|
||||||
cl->rdma_conn = rdma_conn;
|
cl->rdma_conn = rdma_conn;
|
||||||
cl->peer_state = PEER_RDMA_CONNECTING;
|
cl->peer_state = PEER_RDMA_CONNECTING;
|
||||||
return true;
|
return true;
|
||||||
@@ -540,7 +553,7 @@ static void try_send_rdma_wr(osd_client_t *cl, ibv_sge *sge, int op_sge)
|
|||||||
{
|
{
|
||||||
ibv_send_wr *bad_wr = NULL;
|
ibv_send_wr *bad_wr = NULL;
|
||||||
ibv_send_wr wr = {
|
ibv_send_wr wr = {
|
||||||
.wr_id = (uint64_t)(cl->peer_fd*2+1),
|
.wr_id = cl->client_id,
|
||||||
.sg_list = sge,
|
.sg_list = sge,
|
||||||
.num_sge = op_sge,
|
.num_sge = op_sge,
|
||||||
.opcode = IBV_WR_SEND,
|
.opcode = IBV_WR_SEND,
|
||||||
@@ -599,7 +612,9 @@ void osd_messenger_t::try_send_rdma(osd_client_t *cl)
|
|||||||
while (!rc->send_out_full && copied > 0 && rc->cur_send < rc->max_send)
|
while (!rc->send_out_full && copied > 0 && rc->cur_send < rc->max_send)
|
||||||
{
|
{
|
||||||
dst = (uint8_t*)rc->send_out.buf + rc->send_out_pos;
|
dst = (uint8_t*)rc->send_out.buf + rc->send_out_pos;
|
||||||
dst_len = (rc->send_out_pos < rc->send_out_size ? rc->send_out_size-rc->send_out_pos : rc->send_done_pos-rc->send_out_pos);
|
dst_len = (rc->send_out_pos >= rc->send_done_pos
|
||||||
|
? rc->send_out_size-rc->send_out_pos
|
||||||
|
: rc->send_done_pos-rc->send_out_pos);
|
||||||
if (dst_len > rc->max_msg)
|
if (dst_len > rc->max_msg)
|
||||||
dst_len = rc->max_msg;
|
dst_len = rc->max_msg;
|
||||||
copied = try_send_rdma_copy(cl, dst, dst_len);
|
copied = try_send_rdma_copy(cl, dst, dst_len);
|
||||||
@@ -609,7 +624,7 @@ void osd_messenger_t::try_send_rdma(osd_client_t *cl)
|
|||||||
if (rc->send_out_pos == rc->send_out_size)
|
if (rc->send_out_pos == rc->send_out_size)
|
||||||
rc->send_out_pos = 0;
|
rc->send_out_pos = 0;
|
||||||
assert(rc->send_out_pos < rc->send_out_size);
|
assert(rc->send_out_pos < rc->send_out_size);
|
||||||
if (rc->send_out_pos >= rc->send_done_pos)
|
if (rc->send_out_pos == rc->send_done_pos)
|
||||||
rc->send_out_full = true;
|
rc->send_out_full = true;
|
||||||
ibv_sge sge = {
|
ibv_sge sge = {
|
||||||
.addr = (uintptr_t)dst,
|
.addr = (uintptr_t)dst,
|
||||||
@@ -631,7 +646,7 @@ static void try_recv_rdma_wr(osd_client_t *cl, void *buf)
|
|||||||
};
|
};
|
||||||
ibv_recv_wr *bad_wr = NULL;
|
ibv_recv_wr *bad_wr = NULL;
|
||||||
ibv_recv_wr wr = {
|
ibv_recv_wr wr = {
|
||||||
.wr_id = (uint64_t)(cl->peer_fd*2),
|
.wr_id = cl->client_id,
|
||||||
.sg_list = &sge,
|
.sg_list = &sge,
|
||||||
.num_sge = 1,
|
.num_sge = 1,
|
||||||
};
|
};
|
||||||
@@ -688,25 +703,28 @@ void osd_messenger_t::handle_rdma_events(msgr_rdma_context_t *rdma_context)
|
|||||||
event_count = ibv_poll_cq(rdma_context->cq, RDMA_EVENTS_AT_ONCE, wc);
|
event_count = ibv_poll_cq(rdma_context->cq, RDMA_EVENTS_AT_ONCE, wc);
|
||||||
for (int i = 0; i < event_count; i++)
|
for (int i = 0; i < event_count; i++)
|
||||||
{
|
{
|
||||||
int client_id = wc[i].wr_id >> 1;
|
uint64_t client_id = wc[i].wr_id;
|
||||||
bool is_send = wc[i].wr_id & 1;
|
bool is_send = wc[i].opcode == IBV_WC_SEND;
|
||||||
auto cl_it = clients.find(client_id);
|
auto cl_it = clients.find(client_id);
|
||||||
if (cl_it == clients.end())
|
if (cl_it == clients.end())
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
osd_client_t *cl = cl_it->second;
|
osd_client_t *cl = cl_it->second;
|
||||||
|
if (cl->peer_state == PEER_STOPPED)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
auto rc = cl->rdma_conn;
|
auto rc = cl->rdma_conn;
|
||||||
if (wc[i].status != IBV_WC_SUCCESS)
|
if (wc[i].status != IBV_WC_SUCCESS)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "RDMA work request failed for client %d", client_id);
|
fprintf(stderr, "RDMA work request failed for client %ju", client_id);
|
||||||
if (cl->osd_num)
|
if (cl->osd_num)
|
||||||
{
|
{
|
||||||
fprintf(stderr, " (OSD %ju)", cl->osd_num);
|
fprintf(stderr, " (OSD %ju)", cl->osd_num);
|
||||||
}
|
}
|
||||||
fprintf(stderr, " with status: %s, stopping client\n", ibv_wc_status_str(wc[i].status));
|
fprintf(stderr, " with status: %s, stopping client\n", ibv_wc_status_str(wc[i].status));
|
||||||
stop_client(client_id);
|
stop_client(client_id);
|
||||||
clear_immediate_ops(client_id);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!is_send)
|
if (!is_send)
|
||||||
@@ -717,8 +735,6 @@ void osd_messenger_t::handle_rdma_events(msgr_rdma_context_t *rdma_context)
|
|||||||
rc->cur_recv--;
|
rc->cur_recv--;
|
||||||
if (!handle_read_buffer(cl, rc->recv_buffers[rc->next_recv_buf], wc[i].byte_len))
|
if (!handle_read_buffer(cl, rc->recv_buffers[rc->next_recv_buf], wc[i].byte_len))
|
||||||
{
|
{
|
||||||
// handle_read_buffer may stop the client
|
|
||||||
clear_immediate_ops(client_id);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
try_recv_rdma_wr(cl, rc->recv_buffers[rc->next_recv_buf]);
|
try_recv_rdma_wr(cl, rc->recv_buffers[rc->next_recv_buf]);
|
||||||
@@ -778,3 +794,16 @@ void osd_messenger_t::handle_rdma_events(msgr_rdma_context_t *rdma_context)
|
|||||||
} while (event_count > 0);
|
} while (event_count > 0);
|
||||||
handle_immediate_ops();
|
handle_immediate_ops();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void osd_messenger_t::destroy_rdma_conn(msgr_rdma_connection_t *rdma_conn)
|
||||||
|
{
|
||||||
|
if (rdma_conn->cmid)
|
||||||
|
{
|
||||||
|
auto rdma_it = rdmacm_connections.find(rdma_conn->cmid);
|
||||||
|
if (rdma_it != rdmacm_connections.end() && rdma_it->second->rdma_conn == rdma_conn)
|
||||||
|
{
|
||||||
|
rdmacm_connections.erase(rdma_it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete rdma_conn;
|
||||||
|
}
|
||||||
|
|||||||
+12
-32
@@ -11,7 +11,7 @@
|
|||||||
struct rdmacm_connecting_t
|
struct rdmacm_connecting_t
|
||||||
{
|
{
|
||||||
rdma_cm_id *cmid = NULL;
|
rdma_cm_id *cmid = NULL;
|
||||||
int peer_fd = -1;
|
uint64_t client_id = 0;
|
||||||
osd_num_t peer_osd = 0;
|
osd_num_t peer_osd = 0;
|
||||||
std::string addr;
|
std::string addr;
|
||||||
sockaddr_storage parsed_addr = {};
|
sockaddr_storage parsed_addr = {};
|
||||||
@@ -117,9 +117,9 @@ void osd_messenger_t::handle_rdmacm_events()
|
|||||||
auto cli_it = rdmacm_connections.find(ev->id);
|
auto cli_it = rdmacm_connections.find(ev->id);
|
||||||
if (cli_it != rdmacm_connections.end())
|
if (cli_it != rdmacm_connections.end())
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Received %s event for peer %d, closing connection\n",
|
fprintf(stderr, "Received %s event for client %ju, closing connection\n",
|
||||||
event_type_name, cli_it->second->peer_fd);
|
event_type_name, cli_it->second->client_id);
|
||||||
stop_client(cli_it->second->peer_fd);
|
stop_client(cli_it->second->client_id);
|
||||||
}
|
}
|
||||||
else if (rdmacm_connecting.find(ev->id) != rdmacm_connecting.end())
|
else if (rdmacm_connecting.find(ev->id) != rdmacm_connecting.end())
|
||||||
{
|
{
|
||||||
@@ -265,14 +265,6 @@ msgr_rdma_context_t* osd_messenger_t::rdmacm_create_qp(rdma_cm_id *cmid)
|
|||||||
|
|
||||||
void osd_messenger_t::rdmacm_accept(rdma_cm_event *ev)
|
void osd_messenger_t::rdmacm_accept(rdma_cm_event *ev)
|
||||||
{
|
{
|
||||||
// Make a fake FD (FIXME: do not use FDs for identifying clients!)
|
|
||||||
int fake_fd = socket(AF_INET, SOCK_STREAM, 0);
|
|
||||||
if (fake_fd < 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Failed to allocate a fake socket for RDMA-CM client: %s (code %d)\n", strerror(errno), errno);
|
|
||||||
rdma_destroy_id(ev->id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto rdma_context = rdmacm_create_qp(ev->id);
|
auto rdma_context = rdmacm_create_qp(ev->id);
|
||||||
if (!rdma_context)
|
if (!rdma_context)
|
||||||
{
|
{
|
||||||
@@ -297,12 +289,12 @@ void osd_messenger_t::rdmacm_accept(rdma_cm_event *ev)
|
|||||||
// Wait for RDMA_CM_ESTABLISHED, and enable the connection only after it
|
// Wait for RDMA_CM_ESTABLISHED, and enable the connection only after it
|
||||||
auto conn = new rdmacm_connecting_t;
|
auto conn = new rdmacm_connecting_t;
|
||||||
conn->cmid = ev->id;
|
conn->cmid = ev->id;
|
||||||
conn->peer_fd = fake_fd;
|
conn->client_id = next_client_id++;
|
||||||
conn->parsed_addr = *(sockaddr_storage*)rdma_get_peer_addr(ev->id);
|
conn->parsed_addr = *(sockaddr_storage*)rdma_get_peer_addr(ev->id);
|
||||||
conn->rdma_context = rdma_context;
|
conn->rdma_context = rdma_context;
|
||||||
rdmacm_set_conn_timeout(conn);
|
rdmacm_set_conn_timeout(conn);
|
||||||
rdmacm_connecting[ev->id] = conn;
|
rdmacm_connecting[ev->id] = conn;
|
||||||
fprintf(stderr, "[OSD %ju] new client %d: connection from %s via RDMA-CM\n", this->osd_num, conn->peer_fd,
|
fprintf(stderr, "[OSD %ju] new client %ju: connection from %s via RDMA-CM\n", this->osd_num, conn->client_id,
|
||||||
addr_to_string(conn->parsed_addr).c_str());
|
addr_to_string(conn->parsed_addr).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,8 +324,6 @@ void osd_messenger_t::rdmacm_on_connect_peer_error(rdma_cm_id *cmid, int res)
|
|||||||
auto peer_osd = conn->peer_osd;
|
auto peer_osd = conn->peer_osd;
|
||||||
if (conn->timeout_id >= 0)
|
if (conn->timeout_id >= 0)
|
||||||
tfd->clear_timer(conn->timeout_id);
|
tfd->clear_timer(conn->timeout_id);
|
||||||
if (conn->peer_fd >= 0)
|
|
||||||
close(conn->peer_fd);
|
|
||||||
if (conn->rdma_context)
|
if (conn->rdma_context)
|
||||||
conn->rdma_context->reserve_cqe(-rdma_max_send-rdma_max_recv);
|
conn->rdma_context->reserve_cqe(-rdma_max_send-rdma_max_recv);
|
||||||
if (conn->cmid)
|
if (conn->cmid)
|
||||||
@@ -354,7 +344,7 @@ void osd_messenger_t::rdmacm_on_connect_peer_error(rdma_cm_id *cmid, int res)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TCP is disabled
|
// TCP is disabled
|
||||||
on_connect_peer(peer_osd, res == 0 ? -EINVAL : (res > 0 ? -res : res));
|
on_connect_peer(peer_osd, res == 0 ? -EINVAL : (res > 0 ? -res : res), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -365,7 +355,7 @@ void osd_messenger_t::rdmacm_try_connect_peer(uint64_t peer_osd, const std::stri
|
|||||||
if (!string_to_addr(addr, false, rdmacm_port, &sa))
|
if (!string_to_addr(addr, false, rdmacm_port, &sa))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Address %s is invalid\n", addr.c_str());
|
fprintf(stderr, "Address %s is invalid\n", addr.c_str());
|
||||||
on_connect_peer(peer_osd, -EINVAL);
|
on_connect_peer(peer_osd, -EINVAL, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
rdma_cm_id *cmid = NULL;
|
rdma_cm_id *cmid = NULL;
|
||||||
@@ -376,17 +366,7 @@ void osd_messenger_t::rdmacm_try_connect_peer(uint64_t peer_osd, const std::stri
|
|||||||
if (!disable_tcp)
|
if (!disable_tcp)
|
||||||
try_connect_peer_tcp(peer_osd, addr.c_str(), fallback_tcp_port);
|
try_connect_peer_tcp(peer_osd, addr.c_str(), fallback_tcp_port);
|
||||||
else
|
else
|
||||||
on_connect_peer(peer_osd, res);
|
on_connect_peer(peer_osd, res, 0);
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Make a fake FD (FIXME: do not use FDs for identifying clients!)
|
|
||||||
int fake_fd = socket(AF_INET, SOCK_STREAM, 0);
|
|
||||||
if (fake_fd < 0)
|
|
||||||
{
|
|
||||||
int res = -errno;
|
|
||||||
rdma_destroy_id(cmid);
|
|
||||||
// Can't create socket, pointless to try TCP
|
|
||||||
on_connect_peer(peer_osd, res);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (log_level > 0)
|
if (log_level > 0)
|
||||||
@@ -394,7 +374,7 @@ void osd_messenger_t::rdmacm_try_connect_peer(uint64_t peer_osd, const std::stri
|
|||||||
auto conn = new rdmacm_connecting_t;
|
auto conn = new rdmacm_connecting_t;
|
||||||
rdmacm_connecting[cmid] = conn;
|
rdmacm_connecting[cmid] = conn;
|
||||||
conn->cmid = cmid;
|
conn->cmid = cmid;
|
||||||
conn->peer_fd = fake_fd;
|
conn->client_id = next_client_id++;
|
||||||
conn->peer_osd = peer_osd;
|
conn->peer_osd = peer_osd;
|
||||||
conn->addr = addr;
|
conn->addr = addr;
|
||||||
conn->parsed_addr = sa;
|
conn->parsed_addr = sa;
|
||||||
@@ -511,13 +491,13 @@ void osd_messenger_t::rdmacm_established(rdma_cm_event *ev)
|
|||||||
auto cl = new osd_client_t();
|
auto cl = new osd_client_t();
|
||||||
cl->peer_addr = conn->parsed_addr;
|
cl->peer_addr = conn->parsed_addr;
|
||||||
cl->peer_port = conn->rdmacm_port;
|
cl->peer_port = conn->rdmacm_port;
|
||||||
cl->peer_fd = conn->peer_fd;
|
cl->client_id = conn->client_id;
|
||||||
cl->peer_state = PEER_RDMA;
|
cl->peer_state = PEER_RDMA;
|
||||||
cl->connect_timeout_id = -1;
|
cl->connect_timeout_id = -1;
|
||||||
cl->osd_num = peer_osd;
|
cl->osd_num = peer_osd;
|
||||||
cl->in_buf = malloc_or_die(receive_buffer_size);
|
cl->in_buf = malloc_or_die(receive_buffer_size);
|
||||||
cl->rdma_conn = rc;
|
cl->rdma_conn = rc;
|
||||||
clients[conn->peer_fd] = cl;
|
clients[conn->client_id] = cl;
|
||||||
if (conn->timeout_id >= 0)
|
if (conn->timeout_id >= 0)
|
||||||
{
|
{
|
||||||
tfd->clear_timer(conn->timeout_id);
|
tfd->clear_timer(conn->timeout_id);
|
||||||
|
|||||||
+34
-47
@@ -2,14 +2,16 @@
|
|||||||
// License: VNPL-1.1 or GNU GPL-2.0+ (see README.md for details)
|
// License: VNPL-1.1 or GNU GPL-2.0+ (see README.md for details)
|
||||||
|
|
||||||
#include "messenger.h"
|
#include "messenger.h"
|
||||||
|
#include "msgr_iothread.h"
|
||||||
|
|
||||||
void osd_messenger_t::read_requests()
|
void osd_messenger_t::read_requests()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < read_ready_clients.size(); i++)
|
for (int i = 0; i < read_ready_clients.size(); i++)
|
||||||
{
|
{
|
||||||
int peer_fd = read_ready_clients[i];
|
uint64_t client_id = read_ready_clients[i];
|
||||||
auto cl_it = clients.find(peer_fd);
|
auto cl_it = clients.find(client_id);
|
||||||
if (cl_it == clients.end() || !cl_it->second || cl_it->second->read_msg.msg_iovlen)
|
if (cl_it == clients.end() || !cl_it->second || cl_it->second->read_msg.msg_iovlen ||
|
||||||
|
cl_it->second->peer_state != PEER_CONNECTED)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -31,7 +33,7 @@ void osd_messenger_t::read_requests()
|
|||||||
cl->refs++;
|
cl->refs++;
|
||||||
if (ringloop && !use_sync_send_recv)
|
if (ringloop && !use_sync_send_recv)
|
||||||
{
|
{
|
||||||
auto iothread = iothreads.size() ? iothreads[peer_fd % iothreads.size()] : NULL;
|
auto iothread = iothreads.size() ? iothreads[cl->peer_fd % iothreads.size()] : NULL;
|
||||||
io_uring_sqe sqe_local;
|
io_uring_sqe sqe_local;
|
||||||
ring_data_t data_local;
|
ring_data_t data_local;
|
||||||
io_uring_sqe* sqe = (iothread ? &sqe_local : ringloop->get_sqe());
|
io_uring_sqe* sqe = (iothread ? &sqe_local : ringloop->get_sqe());
|
||||||
@@ -49,7 +51,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); };
|
||||||
io_uring_prep_recvmsg(sqe, peer_fd, &cl->read_msg, 0);
|
io_uring_prep_recvmsg(sqe, cl->peer_fd, &cl->read_msg, 0);
|
||||||
if (iothread)
|
if (iothread)
|
||||||
{
|
{
|
||||||
iothread->add_sqe(sqe_local);
|
iothread->add_sqe(sqe_local);
|
||||||
@@ -57,7 +59,7 @@ void osd_messenger_t::read_requests()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int result = recvmsg(peer_fd, &cl->read_msg, 0);
|
int result = recvmsg(cl->peer_fd, &cl->read_msg, 0);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
{
|
{
|
||||||
result = -errno;
|
result = -errno;
|
||||||
@@ -72,14 +74,17 @@ void osd_messenger_t::read_requests()
|
|||||||
bool osd_messenger_t::handle_read(int result, osd_client_t *cl)
|
bool osd_messenger_t::handle_read(int result, osd_client_t *cl)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
int peer_fd = cl->peer_fd;
|
|
||||||
cl->read_msg.msg_iovlen = 0;
|
cl->read_msg.msg_iovlen = 0;
|
||||||
cl->refs--;
|
cl->refs--;
|
||||||
|
if (cl->peer_state == PEER_RDMA)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (cl->peer_state == PEER_STOPPED)
|
if (cl->peer_state == PEER_STOPPED)
|
||||||
{
|
{
|
||||||
if (cl->refs <= 0)
|
if (cl->refs <= 0)
|
||||||
{
|
{
|
||||||
delete cl;
|
destroy_client(cl);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -88,20 +93,20 @@ bool osd_messenger_t::handle_read(int result, osd_client_t *cl)
|
|||||||
// this is a client socket, so don't panic on error. just disconnect it
|
// this is a client socket, so don't panic on error. just disconnect it
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Client %d socket read error: %d (%s). Disconnecting client\n", cl->peer_fd, -result, strerror(-result));
|
fprintf(stderr, "Client %ju socket read error: %d (%s). Disconnecting client\n", cl->client_id, -result, strerror(-result));
|
||||||
}
|
}
|
||||||
stop_client(cl->peer_fd);
|
stop_client(cl->client_id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (result == -EAGAIN || result == -EINTR || result < cl->read_iov.iov_len)
|
if (result == -EAGAIN || result == -EINTR || result < cl->read_iov.iov_len)
|
||||||
{
|
{
|
||||||
cl->read_ready--;
|
cl->read_ready--;
|
||||||
if (cl->read_ready > 0)
|
if (cl->read_ready > 0)
|
||||||
read_ready_clients.push_back(cl->peer_fd);
|
read_ready_clients.push_back(cl->client_id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
read_ready_clients.push_back(cl->peer_fd);
|
read_ready_clients.push_back(cl->client_id);
|
||||||
}
|
}
|
||||||
if (result > 0)
|
if (result > 0)
|
||||||
{
|
{
|
||||||
@@ -109,7 +114,6 @@ bool osd_messenger_t::handle_read(int result, osd_client_t *cl)
|
|||||||
{
|
{
|
||||||
if (!handle_read_buffer(cl, cl->in_buf, result))
|
if (!handle_read_buffer(cl, cl->in_buf, result))
|
||||||
{
|
{
|
||||||
clear_immediate_ops(peer_fd);
|
|
||||||
handle_immediate_ops();
|
handle_immediate_ops();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -123,7 +127,6 @@ bool osd_messenger_t::handle_read(int result, osd_client_t *cl)
|
|||||||
{
|
{
|
||||||
if (!handle_finished_read(cl))
|
if (!handle_finished_read(cl))
|
||||||
{
|
{
|
||||||
clear_immediate_ops(peer_fd);
|
|
||||||
handle_immediate_ops();
|
handle_immediate_ops();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -138,26 +141,6 @@ bool osd_messenger_t::handle_read(int result, osd_client_t *cl)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void osd_messenger_t::clear_immediate_ops(int peer_fd)
|
|
||||||
{
|
|
||||||
size_t i = 0, j = 0;
|
|
||||||
while (i < set_immediate_ops.size())
|
|
||||||
{
|
|
||||||
if (set_immediate_ops[i]->peer_fd == peer_fd && set_immediate_ops[i]->op_type == OSD_OP_IN)
|
|
||||||
{
|
|
||||||
delete set_immediate_ops[i];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (i != j)
|
|
||||||
set_immediate_ops[j] = set_immediate_ops[i];
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
set_immediate_ops.resize(j);
|
|
||||||
}
|
|
||||||
|
|
||||||
void osd_messenger_t::handle_immediate_ops()
|
void osd_messenger_t::handle_immediate_ops()
|
||||||
{
|
{
|
||||||
while (set_immediate_ops.size())
|
while (set_immediate_ops.size())
|
||||||
@@ -166,7 +149,11 @@ void osd_messenger_t::handle_immediate_ops()
|
|||||||
set_immediate_ops.pop_front();
|
set_immediate_ops.pop_front();
|
||||||
if (op->op_type == OSD_OP_IN)
|
if (op->op_type == OSD_OP_IN)
|
||||||
{
|
{
|
||||||
exec_op(op);
|
auto cl_it = clients.find(op->client_id);
|
||||||
|
if (cl_it != clients.end() && cl_it->second->peer_state != PEER_STOPPED)
|
||||||
|
exec_op(op);
|
||||||
|
else
|
||||||
|
delete op;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -184,7 +171,7 @@ bool osd_messenger_t::handle_read_buffer(osd_client_t *cl, void *curbuf, int rem
|
|||||||
if (!cl->read_op)
|
if (!cl->read_op)
|
||||||
{
|
{
|
||||||
cl->read_op = new osd_op_t;
|
cl->read_op = new osd_op_t;
|
||||||
cl->read_op->peer_fd = cl->peer_fd;
|
cl->read_op->client_id = cl->client_id;
|
||||||
cl->read_op->op_type = OSD_OP_IN;
|
cl->read_op->op_type = OSD_OP_IN;
|
||||||
cl->recv_list.push_back(cl->read_op->req.buf, OSD_PACKET_SIZE);
|
cl->recv_list.push_back(cl->read_op->req.buf, OSD_PACKET_SIZE);
|
||||||
cl->read_remaining = OSD_PACKET_SIZE;
|
cl->read_remaining = OSD_PACKET_SIZE;
|
||||||
@@ -238,8 +225,8 @@ bool osd_messenger_t::handle_finished_read(osd_client_t *cl)
|
|||||||
{
|
{
|
||||||
if (cl->read_op->req.hdr.id != cl->read_op_id)
|
if (cl->read_op->req.hdr.id != cl->read_op_id)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Warning: operation sequencing is broken on client %d: expected num %ju, got %ju, stopping client\n", cl->peer_fd, cl->read_op_id, cl->read_op->req.hdr.id);
|
fprintf(stderr, "Warning: operation sequencing is broken on client %ju: expected num %ju, got %ju, stopping client\n", cl->client_id, cl->read_op_id, cl->read_op->req.hdr.id);
|
||||||
stop_client(cl->peer_fd);
|
stop_client(cl->client_id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
cl->read_op_id++;
|
cl->read_op_id++;
|
||||||
@@ -248,8 +235,8 @@ bool osd_messenger_t::handle_finished_read(osd_client_t *cl)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Received garbage: magic=%jx id=%ju opcode=%jx from %d\n", cl->read_op->req.hdr.magic, cl->read_op->req.hdr.id, cl->read_op->req.hdr.opcode, cl->peer_fd);
|
fprintf(stderr, "Received garbage: magic=%jx id=%ju opcode=%jx from client %ju\n", cl->read_op->req.hdr.magic, cl->read_op->req.hdr.id, cl->read_op->req.hdr.opcode, cl->client_id);
|
||||||
stop_client(cl->peer_fd);
|
stop_client(cl->client_id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -362,11 +349,11 @@ void osd_messenger_t::handle_op_hdr(osd_client_t *cl)
|
|||||||
bool osd_messenger_t::handle_reply_hdr(osd_client_t *cl)
|
bool osd_messenger_t::handle_reply_hdr(osd_client_t *cl)
|
||||||
{
|
{
|
||||||
auto req_it = cl->sent_ops.find(cl->read_op->req.hdr.id);
|
auto req_it = cl->sent_ops.find(cl->read_op->req.hdr.id);
|
||||||
if (req_it == cl->sent_ops.end())
|
if (req_it == cl->sent_ops.end() || req_it->second->req.hdr.opcode != cl->read_op->req.hdr.opcode)
|
||||||
{
|
{
|
||||||
// Command out of sync. Drop connection
|
// Command out of sync. Drop connection
|
||||||
fprintf(stderr, "Client %d command out of sync: id %ju\n", cl->peer_fd, cl->read_op->req.hdr.id);
|
fprintf(stderr, "Client %ju command out of sync: id %ju\n", cl->client_id, cl->read_op->req.hdr.id);
|
||||||
stop_client(cl->peer_fd);
|
stop_client(cl->client_id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
osd_op_t *op = req_it->second;
|
osd_op_t *op = req_it->second;
|
||||||
@@ -380,13 +367,13 @@ bool osd_messenger_t::handle_reply_hdr(osd_client_t *cl)
|
|||||||
if (op->reply.hdr.retval >= 0 && (op->reply.hdr.retval != expected_size || bmp_len > op->bitmap_len))
|
if (op->reply.hdr.retval >= 0 && (op->reply.hdr.retval != expected_size || bmp_len > op->bitmap_len))
|
||||||
{
|
{
|
||||||
// Check reply length to not overflow the buffer
|
// Check reply length to not overflow the buffer
|
||||||
fprintf(stderr, "Client %d read reply of different length: expected %u+%u, got %jd+%u\n",
|
fprintf(stderr, "Client %ju read reply of different length: expected %u+%u, got %jd+%u\n",
|
||||||
cl->peer_fd, expected_size, op->bitmap_len, op->reply.hdr.retval, bmp_len);
|
cl->client_id, expected_size, op->bitmap_len, op->reply.hdr.retval, bmp_len);
|
||||||
cl->sent_ops[op->req.hdr.id] = op;
|
cl->sent_ops[op->req.hdr.id] = op;
|
||||||
stop_client(cl->peer_fd);
|
stop_client(cl->client_id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (bmp_len > 0)
|
if (op->reply.hdr.retval >= 0 && bmp_len > 0)
|
||||||
{
|
{
|
||||||
assert(op->bitmap);
|
assert(op->bitmap);
|
||||||
cl->recv_list.push_back(op->bitmap, bmp_len);
|
cl->recv_list.push_back(op->bitmap, bmp_len);
|
||||||
|
|||||||
+35
-37
@@ -6,11 +6,18 @@
|
|||||||
#include <sys/epoll.h>
|
#include <sys/epoll.h>
|
||||||
|
|
||||||
#include "messenger.h"
|
#include "messenger.h"
|
||||||
|
#include "msgr_iothread.h"
|
||||||
|
|
||||||
void osd_messenger_t::outbox_push(osd_op_t *cur_op)
|
void osd_messenger_t::outbox_push(osd_op_t *cur_op)
|
||||||
{
|
{
|
||||||
assert(cur_op->peer_fd);
|
assert(cur_op->client_id);
|
||||||
osd_client_t *cl = clients.at(cur_op->peer_fd);
|
auto cl_it = clients.find(cur_op->client_id);
|
||||||
|
if (cl_it == clients.end() || cl_it->second->peer_state == PEER_STOPPED)
|
||||||
|
{
|
||||||
|
delete cur_op;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
osd_client_t *cl = cl_it->second;
|
||||||
if (cur_op->op_type == OSD_OP_OUT)
|
if (cur_op->op_type == OSD_OP_OUT)
|
||||||
{
|
{
|
||||||
clock_gettime(CLOCK_REALTIME, &cur_op->tv_begin);
|
clock_gettime(CLOCK_REALTIME, &cur_op->tv_begin);
|
||||||
@@ -18,8 +25,7 @@ void osd_messenger_t::outbox_push(osd_op_t *cur_op)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Check that operation actually belongs to this client
|
// Remove the operation from received op list
|
||||||
// FIXME: Review if this is still needed
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (auto it = cl->received_ops.begin(); it != cl->received_ops.end(); it++)
|
for (auto it = cl->received_ops.begin(); it != cl->received_ops.end(); it++)
|
||||||
{
|
{
|
||||||
@@ -30,11 +36,8 @@ void osd_messenger_t::outbox_push(osd_op_t *cur_op)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found)
|
// Can't be not found because client IDs are unique
|
||||||
{
|
assert(found);
|
||||||
delete cur_op;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
auto & to_send_list = cl->write_msg.msg_iovlen ? cl->next_send_list : cl->send_list;
|
auto & to_send_list = cl->write_msg.msg_iovlen ? cl->next_send_list : cl->send_list;
|
||||||
auto & to_outbox = cl->write_msg.msg_iovlen ? cl->next_outbox : cl->outbox;
|
auto & to_outbox = cl->write_msg.msg_iovlen ? cl->next_outbox : cl->outbox;
|
||||||
@@ -97,10 +100,15 @@ void osd_messenger_t::outbox_push(osd_op_t *cur_op)
|
|||||||
if (cur_op->req.hdr.opcode == OSD_OP_SEC_READ_BMP)
|
if (cur_op->req.hdr.opcode == OSD_OP_SEC_READ_BMP)
|
||||||
{
|
{
|
||||||
if (cur_op->op_type == OSD_OP_IN && cur_op->reply.hdr.retval > 0)
|
if (cur_op->op_type == OSD_OP_IN && cur_op->reply.hdr.retval > 0)
|
||||||
|
{
|
||||||
to_send_list.push_back((iovec){ .iov_base = cur_op->buf, .iov_len = (size_t)cur_op->reply.hdr.retval });
|
to_send_list.push_back((iovec){ .iov_base = cur_op->buf, .iov_len = (size_t)cur_op->reply.hdr.retval });
|
||||||
|
to_outbox.push_back((msgr_sendp_t){ .op = cur_op, .flags = 0 });
|
||||||
|
}
|
||||||
else if (cur_op->op_type == OSD_OP_OUT && cur_op->req.sec_read_bmp.len > 0)
|
else if (cur_op->op_type == OSD_OP_OUT && cur_op->req.sec_read_bmp.len > 0)
|
||||||
|
{
|
||||||
to_send_list.push_back((iovec){ .iov_base = cur_op->buf, .iov_len = (size_t)cur_op->req.sec_read_bmp.len });
|
to_send_list.push_back((iovec){ .iov_base = cur_op->buf, .iov_len = (size_t)cur_op->req.sec_read_bmp.len });
|
||||||
to_outbox.push_back((msgr_sendp_t){ .op = cur_op, .flags = 0 });
|
to_outbox.push_back((msgr_sendp_t){ .op = cur_op, .flags = 0 });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (cur_op->op_type == OSD_OP_IN)
|
if (cur_op->op_type == OSD_OP_IN)
|
||||||
{
|
{
|
||||||
@@ -126,7 +134,7 @@ void osd_messenger_t::outbox_push(osd_op_t *cur_op)
|
|||||||
if ((cl->write_msg.msg_iovlen > 0 || !try_send(cl)) && (cl->write_state == 0))
|
if ((cl->write_msg.msg_iovlen > 0 || !try_send(cl)) && (cl->write_state == 0))
|
||||||
{
|
{
|
||||||
cl->write_state = CL_WRITE_READY;
|
cl->write_state = CL_WRITE_READY;
|
||||||
write_ready_clients.push_back(cur_op->peer_fd);
|
write_ready_clients.push_back(cur_op->client_id);
|
||||||
}
|
}
|
||||||
ringloop->wakeup();
|
ringloop->wakeup();
|
||||||
}
|
}
|
||||||
@@ -183,15 +191,14 @@ void osd_messenger_t::measure_exec(osd_op_t *cur_op)
|
|||||||
|
|
||||||
bool osd_messenger_t::try_send(osd_client_t *cl)
|
bool osd_messenger_t::try_send(osd_client_t *cl)
|
||||||
{
|
{
|
||||||
int peer_fd = cl->peer_fd;
|
if (!cl->send_list.size() || cl->write_msg.msg_iovlen > 0 || cl->peer_state == PEER_STOPPED || cl->peer_fd < 0)
|
||||||
if (!cl->send_list.size() || cl->write_msg.msg_iovlen > 0)
|
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
assert(cl->peer_state != PEER_RDMA);
|
assert(cl->peer_state != PEER_RDMA);
|
||||||
if (ringloop && !use_sync_send_recv)
|
if (ringloop && !use_sync_send_recv)
|
||||||
{
|
{
|
||||||
auto iothread = iothreads.size() ? iothreads[peer_fd % iothreads.size()] : NULL;
|
auto iothread = iothreads.size() ? iothreads[cl->peer_fd % iothreads.size()] : NULL;
|
||||||
io_uring_sqe sqe_local;
|
io_uring_sqe sqe_local;
|
||||||
ring_data_t data_local;
|
ring_data_t data_local;
|
||||||
io_uring_sqe* sqe = (iothread ? &sqe_local : ringloop->get_sqe());
|
io_uring_sqe* sqe = (iothread ? &sqe_local : ringloop->get_sqe());
|
||||||
@@ -218,11 +225,11 @@ bool osd_messenger_t::try_send(osd_client_t *cl)
|
|||||||
}
|
}
|
||||||
if (use_zc)
|
if (use_zc)
|
||||||
{
|
{
|
||||||
io_uring_prep_sendmsg_zc(sqe, peer_fd, &cl->write_msg, MSG_WAITALL);
|
io_uring_prep_sendmsg_zc(sqe, cl->peer_fd, &cl->write_msg, MSG_WAITALL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
io_uring_prep_sendmsg(sqe, peer_fd, &cl->write_msg, MSG_WAITALL);
|
io_uring_prep_sendmsg(sqe, cl->peer_fd, &cl->write_msg, MSG_WAITALL);
|
||||||
}
|
}
|
||||||
if (iothread)
|
if (iothread)
|
||||||
{
|
{
|
||||||
@@ -234,7 +241,7 @@ bool osd_messenger_t::try_send(osd_client_t *cl)
|
|||||||
cl->write_msg.msg_iov = cl->send_list.data();
|
cl->write_msg.msg_iov = cl->send_list.data();
|
||||||
cl->write_msg.msg_iovlen = cl->send_list.size() < IOV_MAX ? cl->send_list.size() : IOV_MAX;
|
cl->write_msg.msg_iovlen = cl->send_list.size() < IOV_MAX ? cl->send_list.size() : IOV_MAX;
|
||||||
cl->refs++;
|
cl->refs++;
|
||||||
int result = sendmsg(peer_fd, &cl->write_msg, MSG_NOSIGNAL);
|
int result = sendmsg(cl->peer_fd, &cl->write_msg, MSG_NOSIGNAL);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
{
|
{
|
||||||
result = -errno;
|
result = -errno;
|
||||||
@@ -249,9 +256,9 @@ void osd_messenger_t::send_replies()
|
|||||||
{
|
{
|
||||||
for (int i = 0; i < write_ready_clients.size(); i++)
|
for (int i = 0; i < write_ready_clients.size(); i++)
|
||||||
{
|
{
|
||||||
int peer_fd = write_ready_clients[i];
|
uint64_t client_id = write_ready_clients[i];
|
||||||
auto cl_it = clients.find(peer_fd);
|
auto cl_it = clients.find(client_id);
|
||||||
if (cl_it != clients.end() && !try_send(cl_it->second))
|
if (cl_it != clients.end() && cl_it->second->peer_state != PEER_RDMA && !try_send(cl_it->second))
|
||||||
{
|
{
|
||||||
write_ready_clients.erase(write_ready_clients.begin(), write_ready_clients.begin() + i);
|
write_ready_clients.erase(write_ready_clients.begin(), write_ready_clients.begin() + i);
|
||||||
return;
|
return;
|
||||||
@@ -274,15 +281,15 @@ void osd_messenger_t::handle_send(int result, bool prev, bool more, osd_client_t
|
|||||||
{
|
{
|
||||||
if (cl->refs <= 0)
|
if (cl->refs <= 0)
|
||||||
{
|
{
|
||||||
delete cl;
|
destroy_client(cl);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (result < 0 && result != -EAGAIN && result != -EINTR)
|
if (result < 0 && result != -EAGAIN && result != -EINTR)
|
||||||
{
|
{
|
||||||
// this is a client socket, so don't panic. just disconnect it
|
// this is a client socket, so don't panic. just disconnect it
|
||||||
fprintf(stderr, "Client %d socket write error: %d (%s). Disconnecting client\n", cl->peer_fd, -result, strerror(-result));
|
fprintf(stderr, "Client %ju socket write error: %d (%s). Disconnecting client\n", cl->client_id, -result, strerror(-result));
|
||||||
stop_client(cl->peer_fd);
|
stop_client(cl->client_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (result >= 0)
|
if (result >= 0)
|
||||||
@@ -326,9 +333,9 @@ void osd_messenger_t::handle_send(int result, bool prev, bool more, osd_client_t
|
|||||||
int expected = cl->send_list.size() < IOV_MAX ? cl->send_list.size() : IOV_MAX;
|
int expected = cl->send_list.size() < IOV_MAX ? cl->send_list.size() : IOV_MAX;
|
||||||
if (done != expected)
|
if (done != expected)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Client %d socket write error: expected to send "
|
fprintf(stderr, "Client %ju socket write error: expected to send "
|
||||||
"%d iovecs with MSG_WAITALL but sent %d. Disconnecting client\n", cl->peer_fd, expected, done);
|
"%d iovecs with MSG_WAITALL but sent %d. Disconnecting client\n", cl->client_id, expected, done);
|
||||||
stop_client(cl->peer_fd);
|
stop_client(cl->client_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cl->zc_free_list.push_back(NULL); // end marker
|
cl->zc_free_list.push_back(NULL); // end marker
|
||||||
@@ -349,21 +356,12 @@ void osd_messenger_t::handle_send(int result, bool prev, bool more, osd_client_t
|
|||||||
#ifdef WITH_RDMA
|
#ifdef WITH_RDMA
|
||||||
if (cl->rdma_conn && !cl->outbox.size() && cl->peer_state == PEER_RDMA_CONNECTING)
|
if (cl->rdma_conn && !cl->outbox.size() && cl->peer_state == PEER_RDMA_CONNECTING)
|
||||||
{
|
{
|
||||||
// FIXME: Do something better than just forgetting the FD
|
|
||||||
// FIXME: Ignore pings during RDMA state transition
|
// FIXME: Ignore pings during RDMA state transition
|
||||||
if (log_level > 0)
|
if (log_level > 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Successfully connected with client %d using RDMA\n", cl->peer_fd);
|
fprintf(stderr, "Successfully connected with client %ju using RDMA\n", cl->client_id);
|
||||||
}
|
}
|
||||||
cl->peer_state = PEER_RDMA;
|
cl->peer_state = PEER_RDMA;
|
||||||
tfd->set_fd_handler(cl->peer_fd, false, [this](int peer_fd, int epoll_events)
|
|
||||||
{
|
|
||||||
// Do not miss the disconnection!
|
|
||||||
if (epoll_events & EPOLLRDHUP)
|
|
||||||
{
|
|
||||||
handle_peer_epoll(peer_fd, epoll_events);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Add the initial receive request
|
// Add the initial receive request
|
||||||
init_recv_rdma(cl);
|
init_recv_rdma(cl);
|
||||||
}
|
}
|
||||||
@@ -371,6 +369,6 @@ void osd_messenger_t::handle_send(int result, bool prev, bool more, osd_client_t
|
|||||||
}
|
}
|
||||||
if (cl->write_state != 0)
|
if (cl->write_state != 0)
|
||||||
{
|
{
|
||||||
write_ready_clients.push_back(cl->peer_fd);
|
write_ready_clients.push_back(cl->client_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+61
-60
@@ -5,9 +5,6 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include "messenger.h"
|
#include "messenger.h"
|
||||||
#ifdef WITH_RDMA
|
|
||||||
#include "msgr_rdma.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void osd_client_t::cancel_ops()
|
void osd_client_t::cancel_ops()
|
||||||
{
|
{
|
||||||
@@ -43,34 +40,40 @@ void osd_op_t::cancel()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void osd_messenger_t::stop_client(int peer_fd, bool force, bool force_delete)
|
// force_delete means stop the client anyway, even if there are refs to it in the event loop.
|
||||||
|
// the flag should be used in the destructor.
|
||||||
|
// why? - because yes, we could close the FD first and let it fail all requests in the event loop,
|
||||||
|
// but in that case it can be quickly reopened and we can get old failed responses for the new FD.
|
||||||
|
void osd_messenger_t::stop_client(uint64_t client_id, bool force_delete)
|
||||||
{
|
{
|
||||||
assert(peer_fd != 0);
|
auto it = clients.find(client_id);
|
||||||
auto it = clients.find(peer_fd);
|
if (!client_id || it == clients.end())
|
||||||
if (it == clients.end())
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
osd_client_t *cl = it->second;
|
osd_client_t *cl = it->second;
|
||||||
// FIXME: This 'force' flag is probably an ugly reenterability hack - check its logic and maybe remove it
|
if (cl->peer_state == PEER_STOPPED)
|
||||||
if (cl->peer_state == PEER_CONNECTING && !force || cl->peer_state == PEER_STOPPED)
|
|
||||||
{
|
{
|
||||||
|
if (force_delete)
|
||||||
|
{
|
||||||
|
destroy_client(cl);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
clear_immediate_ops(peer_fd);
|
cl->received_ops.clear();
|
||||||
if (log_level > 0)
|
if (log_level > 0)
|
||||||
{
|
{
|
||||||
if (cl->osd_num)
|
if (cl->osd_num)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "[OSD %ju] Stopping client %d (OSD peer %ju)\n", osd_num, peer_fd, cl->osd_num);
|
fprintf(stderr, "[OSD %ju] Stopping client %ju (OSD peer %ju)\n", osd_num, client_id, cl->osd_num);
|
||||||
}
|
}
|
||||||
else if (cl->in_osd_num)
|
else if (cl->in_osd_num)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "[OSD %ju] Stopping client %d (incoming OSD peer %ju)\n", osd_num, peer_fd, cl->in_osd_num);
|
fprintf(stderr, "[OSD %ju] Stopping client %ju (incoming OSD peer %ju)\n", osd_num, client_id, cl->in_osd_num);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf(stderr, "[OSD %ju] Stopping client %d (regular client)\n", osd_num, peer_fd);
|
fprintf(stderr, "[OSD %ju] Stopping client %ju (regular client)\n", osd_num, client_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// First set state to STOPPED so another stop_client() call doesn't try to free it again
|
// First set state to STOPPED so another stop_client() call doesn't try to free it again
|
||||||
@@ -79,48 +82,18 @@ void osd_messenger_t::stop_client(int peer_fd, bool force, bool force_delete)
|
|||||||
cl->peer_state = PEER_STOPPED;
|
cl->peer_state = PEER_STOPPED;
|
||||||
if (cl->osd_num)
|
if (cl->osd_num)
|
||||||
{
|
{
|
||||||
auto osd_it = osd_peer_fds.find(cl->osd_num);
|
auto osd_it = osd_peers.find(cl->osd_num);
|
||||||
if (osd_it != osd_peer_fds.end() && osd_it->second == cl->peer_fd)
|
if (osd_it != osd_peers.end() && osd_it->second == cl)
|
||||||
{
|
{
|
||||||
// ...and forget OSD peer
|
// ...and forget OSD peer
|
||||||
osd_peer_fds.erase(osd_it);
|
osd_peers.erase(osd_it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef WITH_RDMA
|
|
||||||
if (cl->rdma_conn && cl->rdma_conn->cmid)
|
|
||||||
{
|
|
||||||
auto rdma_it = rdmacm_connections.find(cl->rdma_conn->cmid);
|
|
||||||
if (rdma_it != rdmacm_connections.end() && rdma_it->second == cl)
|
|
||||||
{
|
|
||||||
rdmacm_connections.erase(rdma_it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifndef __MOCK__
|
|
||||||
// Then remove FD from the eventloop so we don't accidentally read something
|
|
||||||
tfd->set_fd_handler(peer_fd, false, NULL);
|
|
||||||
if (cl->connect_timeout_id >= 0)
|
if (cl->connect_timeout_id >= 0)
|
||||||
{
|
{
|
||||||
tfd->clear_timer(cl->connect_timeout_id);
|
tfd->clear_timer(cl->connect_timeout_id);
|
||||||
cl->connect_timeout_id = -1;
|
cl->connect_timeout_id = -1;
|
||||||
}
|
}
|
||||||
for (auto rit = read_ready_clients.begin(); rit != read_ready_clients.end(); rit++)
|
|
||||||
{
|
|
||||||
if (*rit == peer_fd)
|
|
||||||
{
|
|
||||||
read_ready_clients.erase(rit);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (auto wit = write_ready_clients.begin(); wit != write_ready_clients.end(); wit++)
|
|
||||||
{
|
|
||||||
if (*wit == peer_fd)
|
|
||||||
{
|
|
||||||
write_ready_clients.erase(wit);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (cl->in_osd_num && break_pg_locks)
|
if (cl->in_osd_num && break_pg_locks)
|
||||||
{
|
{
|
||||||
// Break PG locks
|
// Break PG locks
|
||||||
@@ -134,19 +107,56 @@ void osd_messenger_t::stop_client(int peer_fd, bool force, bool force_delete)
|
|||||||
// so do not repeer on it.
|
// so do not repeer on it.
|
||||||
repeer_pgs(cl->osd_num);
|
repeer_pgs(cl->osd_num);
|
||||||
}
|
}
|
||||||
// Find the item again because it can be invalidated at this point
|
if (cl->peer_fd >= 0)
|
||||||
it = clients.find(peer_fd);
|
|
||||||
if (it != clients.end())
|
|
||||||
{
|
{
|
||||||
clients.erase(it);
|
int r = shutdown(cl->peer_fd, SHUT_RDWR);
|
||||||
|
if (r != 0 && errno != ENOTCONN)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "[OSD %ju] failed to shutdown a socket: %s (code %d)\n", osd_num, strerror(errno), errno);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cl->refs--;
|
cl->refs--;
|
||||||
if (cl->refs <= 0 || force_delete)
|
if (cl->refs <= 0 || force_delete)
|
||||||
{
|
{
|
||||||
delete cl;
|
destroy_client(cl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void osd_messenger_t::destroy_client(osd_client_t *cl)
|
||||||
|
{
|
||||||
|
// Find the item again because it can be invalidated at this point
|
||||||
|
clients.erase(cl->client_id);
|
||||||
|
if (cl->peer_fd >= 0)
|
||||||
|
{
|
||||||
|
tfd->set_fd_handler(cl->peer_fd, false, NULL);
|
||||||
|
for (auto rit = read_ready_clients.begin(); rit != read_ready_clients.end(); rit++)
|
||||||
|
{
|
||||||
|
if (*rit == cl->client_id)
|
||||||
|
{
|
||||||
|
read_ready_clients.erase(rit);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto wit = write_ready_clients.begin(); wit != write_ready_clients.end(); wit++)
|
||||||
|
{
|
||||||
|
if (*wit == cl->client_id)
|
||||||
|
{
|
||||||
|
write_ready_clients.erase(wit);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clients_by_fd.erase(cl->peer_fd);
|
||||||
|
}
|
||||||
|
#ifdef WITH_RDMA
|
||||||
|
if (cl->rdma_conn)
|
||||||
|
{
|
||||||
|
destroy_rdma_conn(cl->rdma_conn);
|
||||||
|
cl->rdma_conn = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
delete cl;
|
||||||
|
}
|
||||||
|
|
||||||
osd_client_t::~osd_client_t()
|
osd_client_t::~osd_client_t()
|
||||||
{
|
{
|
||||||
free(in_buf);
|
free(in_buf);
|
||||||
@@ -176,13 +186,4 @@ osd_client_t::~osd_client_t()
|
|||||||
delete op;
|
delete op;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifndef __MOCK__
|
|
||||||
#ifdef WITH_RDMA
|
|
||||||
if (rdma_conn)
|
|
||||||
{
|
|
||||||
delete rdma_conn;
|
|
||||||
rdma_conn = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1049,7 +1049,7 @@ static int coroutine_fn vitastor_co_block_status(BlockDriverState *bs,
|
|||||||
{
|
{
|
||||||
// Get larger allocated extents, possibly with false positives
|
// Get larger allocated extents, possibly with false positives
|
||||||
uint64_t bmp_pos = (offset-task.offset) / task.bitmap_granularity;
|
uint64_t bmp_pos = (offset-task.offset) / task.bitmap_granularity;
|
||||||
uint64_t bmp_end = (offset+bytes-task.offset) / task.bitmap_granularity - bmp_pos;
|
uint64_t bmp_end = (offset+bytes-task.offset) / task.bitmap_granularity;
|
||||||
while (bmp_pos < bmp_end)
|
while (bmp_pos < bmp_end)
|
||||||
{
|
{
|
||||||
if (!(bmp_pos & 7) && bmp_end >= bmp_pos+8)
|
if (!(bmp_pos & 7) && bmp_end >= bmp_pos+8)
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ help:
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const bool writeback = cli->get_immediate_commit(inode);
|
const bool writeback = !cli->get_immediate_commit(inode);
|
||||||
auto pool_it = cli->st_cli.pool_config.find(INODE_POOL(inode ? inode : watch->cfg.num));
|
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())
|
if (pool_it == cli->st_cli.pool_config.end())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
|
|||||||
|
|
||||||
Name: Vitastor
|
Name: Vitastor
|
||||||
Description: Vitastor client library
|
Description: Vitastor client library
|
||||||
Version: 3.0.5
|
Version: 3.0.12
|
||||||
Libs: -L${libdir} -lvitastor_client
|
Libs: -L${libdir} -lvitastor_client
|
||||||
Cflags: -I${includedir}
|
Cflags: -I${includedir}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 2.8.12)
|
cmake_minimum_required(VERSION 2.8...3.30)
|
||||||
|
|
||||||
project(vitastor)
|
project(vitastor)
|
||||||
|
|
||||||
@@ -27,6 +27,7 @@ add_library(vitastor_cli STATIC
|
|||||||
cli_pool_ls.cpp
|
cli_pool_ls.cpp
|
||||||
cli_pool_modify.cpp
|
cli_pool_modify.cpp
|
||||||
cli_pool_rm.cpp
|
cli_pool_rm.cpp
|
||||||
|
cli_raw_ls.cpp
|
||||||
)
|
)
|
||||||
target_compile_options(vitastor_cli PUBLIC -fPIC)
|
target_compile_options(vitastor_cli PUBLIC -fPIC)
|
||||||
|
|
||||||
|
|||||||
@@ -126,6 +126,11 @@ static const char* help_text =
|
|||||||
" --min-offset, --max-offset\n"
|
" --min-offset, --max-offset\n"
|
||||||
" Restrict listing to specific offsets inside inodes.\n"
|
" Restrict listing to specific offsets inside inodes.\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
"vitastor-cli raw-ls [OPTIONS]\n"
|
||||||
|
" Find object(s) in the cluster using raw secondary listing operations. Options:\n"
|
||||||
|
" [--min_inode NUM] [--max_inode NUM] [--offset NUM] [--pg_num NUM] [--pg_count COUNT]\n"
|
||||||
|
" [--pg_stripe_size NUM] [--osds 1,2,3,...]\n"
|
||||||
|
"\n"
|
||||||
"vitastor-cli fix [--objects <objects>] [--bad-osds <osds>] [--part <part>] [--check no]\n"
|
"vitastor-cli fix [--objects <objects>] [--bad-osds <osds>] [--part <part>] [--check no]\n"
|
||||||
" Fix inconsistent objects in the cluster by deleting some copies.\n"
|
" Fix inconsistent objects in the cluster by deleting some copies.\n"
|
||||||
" --objects <objects>\n"
|
" --objects <objects>\n"
|
||||||
@@ -459,6 +464,11 @@ static int run(cli_tool_t *p, json11::Json::object cfg)
|
|||||||
// Describe unclean objects
|
// Describe unclean objects
|
||||||
action_cb = p->start_describe(cfg);
|
action_cb = p->start_describe(cfg);
|
||||||
}
|
}
|
||||||
|
else if (cmd[0] == "raw-ls")
|
||||||
|
{
|
||||||
|
// Run raw listings
|
||||||
|
action_cb = p->start_raw_ls(cfg);
|
||||||
|
}
|
||||||
else if (cmd[0] == "fix")
|
else if (cmd[0] == "fix")
|
||||||
{
|
{
|
||||||
// Fix inconsistent objects (by deleting some copies)
|
// Fix inconsistent objects (by deleting some copies)
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ public:
|
|||||||
std::function<bool(cli_result_t &)> start_fix(json11::Json);
|
std::function<bool(cli_result_t &)> start_fix(json11::Json);
|
||||||
std::function<bool(cli_result_t &)> start_flatten(json11::Json);
|
std::function<bool(cli_result_t &)> start_flatten(json11::Json);
|
||||||
std::function<bool(cli_result_t &)> start_ls(json11::Json);
|
std::function<bool(cli_result_t &)> start_ls(json11::Json);
|
||||||
|
std::function<bool(cli_result_t &)> start_raw_ls(json11::Json cfg);
|
||||||
std::function<bool(cli_result_t &)> start_merge(json11::Json);
|
std::function<bool(cli_result_t &)> start_merge(json11::Json);
|
||||||
std::function<bool(cli_result_t &)> start_modify(json11::Json);
|
std::function<bool(cli_result_t &)> start_modify(json11::Json);
|
||||||
std::function<bool(cli_result_t &)> start_modify_osd(json11::Json);
|
std::function<bool(cli_result_t &)> start_modify_osd(json11::Json);
|
||||||
|
|||||||
@@ -0,0 +1,212 @@
|
|||||||
|
// Copyright (c) Vitaliy Filippov, 2019+
|
||||||
|
// License: VNPL-1.1 (see README.md for details)
|
||||||
|
|
||||||
|
#include "cli_fix.h"
|
||||||
|
#include "cluster_client.h"
|
||||||
|
#include "pg_states.h"
|
||||||
|
#include "str_util.h"
|
||||||
|
#include "json_util.h"
|
||||||
|
|
||||||
|
std::vector<uint64_t> parse_uint64_list(json11::Json val);
|
||||||
|
|
||||||
|
// Find object(s) in the cluster using raw secondary listing operations.
|
||||||
|
// Only for troubleshooting.
|
||||||
|
struct cli_raw_ls_t
|
||||||
|
{
|
||||||
|
json11::Json cfg;
|
||||||
|
pool_id_t pool_id = 0;
|
||||||
|
pg_num_t pg_num = 0;
|
||||||
|
pg_num_t pg_count = 0;
|
||||||
|
uint32_t pg_stripe_size = 0;
|
||||||
|
std::set<uint64_t> osds;
|
||||||
|
std::vector<osd_num_t> osd_list;
|
||||||
|
uint64_t min_inode = 0, max_inode = 0, min_offset = 0, max_offset = 0;
|
||||||
|
bool offset_set = false;
|
||||||
|
|
||||||
|
cli_tool_t *parent = NULL;
|
||||||
|
int state = 0;
|
||||||
|
cli_result_t result;
|
||||||
|
bool first = true;
|
||||||
|
size_t osd_pos = 0;
|
||||||
|
|
||||||
|
bool is_done()
|
||||||
|
{
|
||||||
|
return state == 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
if (state == 1)
|
||||||
|
goto resume_1;
|
||||||
|
if (state == 100)
|
||||||
|
return;
|
||||||
|
pool_id = cfg["pool_id"].uint64_value();
|
||||||
|
pg_num = (pg_num_t)cfg["pg_num"].uint64_value();
|
||||||
|
pg_count = (pg_num_t)cfg["pg_count"].uint64_value();
|
||||||
|
pg_stripe_size = cfg["pg_stripe_size"].uint64_value();
|
||||||
|
if (!pool_id)
|
||||||
|
{
|
||||||
|
result = (cli_result_t){ .err = EINVAL, .text = "Pool ID is required" };
|
||||||
|
state = 100;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cfg["min_inode"].is_null() && cfg["max_inode"].is_null())
|
||||||
|
{
|
||||||
|
min_inode = INODE_WITH_POOL(cfg["pool_id"].uint64_value(), 0);
|
||||||
|
max_inode = INODE_WITH_POOL(cfg["pool_id"].uint64_value(), UINT64_MAX);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
min_inode = INODE_WITH_POOL(cfg["pool_id"].uint64_value(), stoull_full(cfg["min_inode"].as_string()));
|
||||||
|
max_inode = INODE_WITH_POOL(cfg["pool_id"].uint64_value(), stoull_full(cfg["max_inode"].as_string()));
|
||||||
|
}
|
||||||
|
if (cfg["offset"].is_null())
|
||||||
|
{
|
||||||
|
if (!pg_num)
|
||||||
|
{
|
||||||
|
result = (cli_result_t){ .err = EINVAL, .text = "PG number is required if offset is not specified" };
|
||||||
|
state = 100;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
min_offset = 0;
|
||||||
|
max_offset = UINT64_MAX;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
min_offset = max_offset = stoull_full(cfg["offset"].as_string());
|
||||||
|
offset_set = true;
|
||||||
|
}
|
||||||
|
for (auto osd_num: parse_uint64_list(cfg["osds"]))
|
||||||
|
{
|
||||||
|
osds.insert(osd_num);
|
||||||
|
}
|
||||||
|
if (!pg_count || !pg_stripe_size || !osds.size())
|
||||||
|
{
|
||||||
|
auto pool_it = parent->cli->st_cli.pool_config.find(pool_id);
|
||||||
|
if (pool_it == parent->cli->st_cli.pool_config.end())
|
||||||
|
{
|
||||||
|
result = (cli_result_t){ .err = EINVAL, .text = "pg_count, pg_stripe_size and osds are required if the pool does not exist" };
|
||||||
|
state = 100;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!pg_count)
|
||||||
|
{
|
||||||
|
pg_count = pool_it->second.real_pg_count;
|
||||||
|
}
|
||||||
|
if (!pg_stripe_size)
|
||||||
|
{
|
||||||
|
pg_stripe_size = pool_it->second.pg_stripe_size;
|
||||||
|
}
|
||||||
|
if (!osds.size())
|
||||||
|
{
|
||||||
|
for (auto & pgp: pool_it->second.pg_config)
|
||||||
|
{
|
||||||
|
for (osd_num_t pg_osd: pgp.second.target_set)
|
||||||
|
osds.insert(pg_osd);
|
||||||
|
for (osd_num_t pg_osd: pgp.second.all_peers)
|
||||||
|
osds.insert(pg_osd);
|
||||||
|
for (auto & hist_item: pgp.second.target_history)
|
||||||
|
for (auto pg_osd: hist_item)
|
||||||
|
osds.insert(pg_osd);
|
||||||
|
}
|
||||||
|
osds.erase(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (offset_set)
|
||||||
|
{
|
||||||
|
min_offset = (min_offset / pg_stripe_size) * pg_stripe_size;
|
||||||
|
max_offset = ((max_offset / pg_stripe_size) * pg_stripe_size) | STRIPE_MASK;
|
||||||
|
pg_num = (min_offset/pg_stripe_size) % pg_count + 1; // like map_to_pg()
|
||||||
|
fprintf(stderr, "Selected PG %u\n", pg_num);
|
||||||
|
}
|
||||||
|
parent->cli->init_msgr();
|
||||||
|
osd_list = std::vector<osd_num_t>(osds.begin(), osds.end());
|
||||||
|
osd_pos = 0;
|
||||||
|
state = 1;
|
||||||
|
resume_1:
|
||||||
|
for (; osd_pos < osd_list.size() && parent->waiting < parent->parallel_osds; osd_pos++)
|
||||||
|
{
|
||||||
|
uint64_t osd_num = osd_list[osd_pos];
|
||||||
|
if (parent->cli->st_cli.peer_states[osd_num].is_null())
|
||||||
|
{
|
||||||
|
fprintf(stderr, "OSD %ju is unavailable, skipping\n", osd_num);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
osd_op_t *op = new osd_op_t;
|
||||||
|
op->req = (osd_any_op_t){
|
||||||
|
.sec_list = {
|
||||||
|
.header = {
|
||||||
|
.magic = SECONDARY_OSD_OP_MAGIC,
|
||||||
|
.opcode = OSD_OP_SEC_LIST,
|
||||||
|
},
|
||||||
|
.list_pg = pg_num,
|
||||||
|
.pg_count = pg_count,
|
||||||
|
.pg_stripe_size = pg_stripe_size,
|
||||||
|
.min_inode = min_inode,
|
||||||
|
.max_inode = max_inode,
|
||||||
|
.min_stripe = min_offset,
|
||||||
|
.max_stripe = max_offset,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
op->callback = [this, osd_num](osd_op_t *op)
|
||||||
|
{
|
||||||
|
if (op->reply.hdr.retval < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "OSD %ju listing failed: retval=%jd\n", osd_num, op->reply.hdr.retval);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (uint64_t i = 0; i < op->reply.hdr.retval; i++)
|
||||||
|
{
|
||||||
|
auto & ov = ((obj_ver_id*)op->buf)[i];
|
||||||
|
if (parent->json_output)
|
||||||
|
{
|
||||||
|
printf("%s{\"osd\":%ju,\"inode\":\"0x%jx\",\"stripe\":\"0x%jx\",\"version\":%ju,\"stable\":%s}",
|
||||||
|
first ? "" : ",\n", osd_num, ov.oid.inode, ov.oid.stripe, ov.version,
|
||||||
|
i < op->reply.sec_list.stable_count ? "true" : "false");
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("OSD %ju - %jx:%jx v%ju%s\n",
|
||||||
|
osd_num, ov.oid.inode, ov.oid.stripe, ov.version,
|
||||||
|
i < op->reply.sec_list.stable_count ? " stable" : "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parent->waiting--;
|
||||||
|
loop();
|
||||||
|
delete op;
|
||||||
|
};
|
||||||
|
parent->waiting++;
|
||||||
|
parent->cli->execute_raw(osd_num, op);
|
||||||
|
}
|
||||||
|
if (parent->waiting > 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!first)
|
||||||
|
{
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
state = 100;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::function<bool(cli_result_t &)> cli_tool_t::start_raw_ls(json11::Json cfg)
|
||||||
|
{
|
||||||
|
auto raw_ls = new cli_raw_ls_t();
|
||||||
|
raw_ls->parent = this;
|
||||||
|
raw_ls->cfg = cfg;
|
||||||
|
return [raw_ls](cli_result_t & result)
|
||||||
|
{
|
||||||
|
raw_ls->loop();
|
||||||
|
if (raw_ls->is_done())
|
||||||
|
{
|
||||||
|
result = raw_ls->result;
|
||||||
|
delete raw_ls;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -286,6 +286,8 @@ struct rm_inode_t
|
|||||||
.data = data,
|
.data = data,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// Wakeup callers (otherwise they wake up only on next loop())
|
||||||
|
parent->ringloop->wakeup();
|
||||||
}
|
}
|
||||||
in_continue = false;
|
in_continue = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 2.8.12)
|
cmake_minimum_required(VERSION 2.8...3.30)
|
||||||
|
|
||||||
project(vitastor)
|
project(vitastor)
|
||||||
|
|
||||||
@@ -11,7 +11,6 @@ add_executable(vitastor-disk
|
|||||||
../blockstore/blockstore_disk.cpp ../blockstore/blockstore_heap.cpp ../blockstore/multilist.cpp
|
../blockstore/blockstore_disk.cpp ../blockstore/blockstore_heap.cpp ../blockstore/multilist.cpp
|
||||||
)
|
)
|
||||||
target_link_libraries(vitastor-disk
|
target_link_libraries(vitastor-disk
|
||||||
tcmalloc_minimal
|
|
||||||
${LIBURING_LIBRARIES}
|
${LIBURING_LIBRARIES}
|
||||||
${ISAL_LIBRARIES}
|
${ISAL_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -427,6 +427,9 @@ int main(int argc, char *argv[])
|
|||||||
self.dsk.open_journal();
|
self.dsk.open_journal();
|
||||||
self.dsk.calc_lengths();
|
self.dsk.calc_lengths();
|
||||||
self.dsk.close_all();
|
self.dsk.close_all();
|
||||||
|
self.new_meta_device = self.dsk.meta_device;
|
||||||
|
self.new_meta_offset = self.dsk.meta_offset;
|
||||||
|
self.new_meta_len = self.dsk.meta_area_size;
|
||||||
}
|
}
|
||||||
std::string json_err;
|
std::string json_err;
|
||||||
json11::Json meta = json11::Json::parse(read_all_fd(0), json_err);
|
json11::Json meta = json11::Json::parse(read_all_fd(0), json_err);
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ struct disk_tool_t
|
|||||||
bool all = false, json = false, now = false;
|
bool all = false, json = false, now = false;
|
||||||
bool dump_with_blocks = false, dump_with_data = false;
|
bool dump_with_blocks = false, dump_with_data = false;
|
||||||
bool dump_as_old = false;
|
bool dump_as_old = false;
|
||||||
bool skip_obsolete = false;
|
|
||||||
int log_level = 1;
|
int log_level = 1;
|
||||||
double meta_reserve_multiple = 2;
|
double meta_reserve_multiple = 2;
|
||||||
uint64_t meta_reserve_min_size = (uint64_t)1024*1024*1024;
|
uint64_t meta_reserve_min_size = (uint64_t)1024*1024*1024;
|
||||||
@@ -138,8 +137,6 @@ struct disk_tool_t
|
|||||||
int resize_write_new_journal();
|
int resize_write_new_journal();
|
||||||
void remap_big_write(heap_entry_t *wr);
|
void remap_big_write(heap_entry_t *wr);
|
||||||
void remap_small_write(heap_entry_t *wr);
|
void remap_small_write(heap_entry_t *wr);
|
||||||
void fill_old_clean_entry(blockstore_heap_t *heap, heap_entry_t *big_wr);
|
|
||||||
void fill_old_journal_entry(blockstore_heap_t *heap, heap_entry_t *wr);
|
|
||||||
int resize_rebuild_meta();
|
int resize_rebuild_meta();
|
||||||
int resize_write_new_meta();
|
int resize_write_new_meta();
|
||||||
void free_new_meta();
|
void free_new_meta();
|
||||||
|
|||||||
@@ -589,6 +589,7 @@ int disk_tool_t::write_json_meta(json11::Json meta)
|
|||||||
|
|
||||||
int disk_tool_t::write_json_heap(json11::Json meta, json11::Json journal)
|
int disk_tool_t::write_json_heap(json11::Json meta, json11::Json journal)
|
||||||
{
|
{
|
||||||
|
assert(new_meta_len >= sizeof(blockstore_meta_header_v3_t));
|
||||||
new_meta_buf = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, new_meta_len);
|
new_meta_buf = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, new_meta_len);
|
||||||
memset(new_meta_buf, 0, new_meta_len);
|
memset(new_meta_buf, 0, new_meta_len);
|
||||||
new_meta_hdr = (blockstore_meta_header_v3_t *)new_meta_buf;
|
new_meta_hdr = (blockstore_meta_header_v3_t *)new_meta_buf;
|
||||||
@@ -606,9 +607,9 @@ int disk_tool_t::write_json_heap(json11::Json meta, json11::Json journal)
|
|||||||
: (meta["data_csum_type"].string_value() == "crc32c"
|
: (meta["data_csum_type"].string_value() == "crc32c"
|
||||||
? BLOCKSTORE_CSUM_CRC32C
|
? BLOCKSTORE_CSUM_CRC32C
|
||||||
: BLOCKSTORE_CSUM_NONE);
|
: BLOCKSTORE_CSUM_NONE);
|
||||||
|
new_meta_hdr->meta_area_size = new_meta_len;
|
||||||
new_meta_hdr->csum_block_size = meta["csum_block_size"].uint64_value();
|
new_meta_hdr->csum_block_size = meta["csum_block_size"].uint64_value();
|
||||||
new_meta_hdr->header_csum = crc32c(0, new_meta_hdr, sizeof(blockstore_meta_header_v3_t));
|
new_meta_hdr->header_csum = crc32c(0, new_meta_hdr, sizeof(blockstore_meta_header_v3_t));
|
||||||
new_meta_hdr->meta_area_size = new_meta_len;
|
|
||||||
new_clean_entry_bitmap_size = (new_meta_hdr->data_block_size / new_meta_hdr->bitmap_granularity + 7) / 8;
|
new_clean_entry_bitmap_size = (new_meta_hdr->data_block_size / new_meta_hdr->bitmap_granularity + 7) / 8;
|
||||||
new_clean_entry_size = 0;
|
new_clean_entry_size = 0;
|
||||||
new_entries_per_block = 0;
|
new_entries_per_block = 0;
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ int disk_tool_t::raw_resize()
|
|||||||
fprintf(stderr, "Done\n");
|
fprintf(stderr, "Done\n");
|
||||||
ret:
|
ret:
|
||||||
free_new_meta();
|
free_new_meta();
|
||||||
return 0;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int disk_tool_t::resize_parse_params()
|
int disk_tool_t::resize_parse_params()
|
||||||
@@ -154,9 +154,6 @@ int disk_tool_t::resize_parse_params()
|
|||||||
? parse_size(options["new_journal_offset"]) : dsk.journal_offset;
|
? parse_size(options["new_journal_offset"]) : dsk.journal_offset;
|
||||||
new_journal_len = options.find("new_journal_len") != options.end()
|
new_journal_len = options.find("new_journal_len") != options.end()
|
||||||
? parse_size(options["new_journal_len"]) : dsk.journal_len;
|
? parse_size(options["new_journal_len"]) : dsk.journal_len;
|
||||||
new_meta_format = options.find("new_meta_format") != options.end()
|
|
||||||
? stoull_full(options["new_meta_format"]) : 0;
|
|
||||||
skip_obsolete = options.find("skip_obsolete") != options.end();
|
|
||||||
if (new_data_len+new_data_offset > dsk.data_device_size)
|
if (new_data_len+new_data_offset > dsk.data_device_size)
|
||||||
new_data_len = dsk.data_device_size-new_data_offset;
|
new_data_len = dsk.data_device_size-new_data_offset;
|
||||||
if (new_meta_device == dsk.data_device && new_data_offset < new_meta_offset &&
|
if (new_meta_device == dsk.data_device && new_data_offset < new_meta_offset &&
|
||||||
@@ -205,10 +202,7 @@ void disk_tool_t::resize_init(blockstore_meta_header_v3_t *hdr)
|
|||||||
{
|
{
|
||||||
dsk.meta_format = hdr->version;
|
dsk.meta_format = hdr->version;
|
||||||
}
|
}
|
||||||
if (new_meta_format == 0)
|
new_meta_format = hdr && hdr->version == BLOCKSTORE_META_FORMAT_HEAP ? BLOCKSTORE_META_FORMAT_HEAP : BLOCKSTORE_META_FORMAT_V2;
|
||||||
{
|
|
||||||
new_meta_format = hdr && hdr->version == BLOCKSTORE_META_FORMAT_HEAP ? BLOCKSTORE_META_FORMAT_HEAP : BLOCKSTORE_META_FORMAT_V2;
|
|
||||||
}
|
|
||||||
dsk.calc_lengths();
|
dsk.calc_lengths();
|
||||||
if (((new_data_offset-dsk.data_offset) % dsk.data_block_size))
|
if (((new_data_offset-dsk.data_offset) % dsk.data_block_size))
|
||||||
{
|
{
|
||||||
@@ -563,66 +557,6 @@ void disk_tool_t::remap_small_write(heap_entry_t *wr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void disk_tool_t::fill_old_clean_entry(blockstore_heap_t *heap, heap_entry_t *big_wr)
|
|
||||||
{
|
|
||||||
uint64_t block_num = big_wr->big().block_num;
|
|
||||||
clean_disk_entry *new_entry = (clean_disk_entry*)(new_meta_buf + dsk.meta_block_size +
|
|
||||||
dsk.meta_block_size*(block_num / new_entries_per_block) +
|
|
||||||
new_clean_entry_size*(block_num % new_entries_per_block));
|
|
||||||
new_entry->oid = (object_id){ .inode = big_wr->inode, .stripe = big_wr->stripe };
|
|
||||||
new_entry->version = big_wr->version;
|
|
||||||
memcpy(new_entry->bitmap, big_wr->get_ext_bitmap(heap), new_clean_entry_bitmap_size);
|
|
||||||
memcpy(new_entry->bitmap + new_clean_entry_bitmap_size, big_wr->get_int_bitmap(heap), new_clean_entry_bitmap_size);
|
|
||||||
memcpy(new_entry->bitmap + 2*new_clean_entry_bitmap_size, big_wr->get_checksums(heap), new_data_csum_size);
|
|
||||||
uint32_t *new_entry_csum = (uint32_t*)(((uint8_t*)new_entry) + new_clean_entry_size - 4);
|
|
||||||
*new_entry_csum = crc32c(0, new_entry, new_clean_entry_size - 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
void disk_tool_t::fill_old_journal_entry(blockstore_heap_t *heap, heap_entry_t *wr)
|
|
||||||
{
|
|
||||||
assert(wr->type() == BS_HEAP_SMALL_WRITE ||
|
|
||||||
wr->type() == BS_HEAP_BIG_WRITE ||
|
|
||||||
wr->type() == BS_HEAP_BIG_INTENT);
|
|
||||||
uint32_t je_size = ((wr->entry_type & BS_HEAP_TYPE) == BS_HEAP_SMALL_WRITE
|
|
||||||
? sizeof(journal_entry_small_write) + dsk.dirty_dyn_size(wr->small().offset, wr->small().len)
|
|
||||||
: sizeof(journal_entry_big_write) + dsk.dirty_dyn_size(0, dsk.data_block_size));
|
|
||||||
choose_journal_block(je_size);
|
|
||||||
journal_entry *je = (journal_entry*)(new_journal_ptr + new_journal_in_pos);
|
|
||||||
je->magic = JOURNAL_MAGIC;
|
|
||||||
je->type = (wr->entry_type & BS_HEAP_STABLE) ? JE_SMALL_WRITE_INSTANT : JE_SMALL_WRITE;
|
|
||||||
je->size = je_size;
|
|
||||||
je->crc32_prev = new_crc32_prev;
|
|
||||||
je->small_write.oid = (object_id){ .inode = wr->inode, .stripe = wr->stripe };
|
|
||||||
je->small_write.version = wr->version;
|
|
||||||
if (wr->type() == BS_HEAP_SMALL_WRITE)
|
|
||||||
{
|
|
||||||
je->small_write.offset = wr->small().offset;
|
|
||||||
je->small_write.len = wr->small().len;
|
|
||||||
je->small_write.data_offset = new_journal_data-new_journal_buf;
|
|
||||||
if (je->small_write.data_offset + je->small_write.len > new_journal_len)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Error: live entries don't fit to the new journal\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
memcpy(new_journal_data, buffer_area+wr->small().location, je->small_write.len);
|
|
||||||
new_journal_data += je->small_write.len;
|
|
||||||
if (dsk.data_csum_type == 0 && wr->get_checksum(heap))
|
|
||||||
je->small_write.crc32_data = *wr->get_checksum(heap);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
je->big_write.location = wr->big_location(heap);
|
|
||||||
}
|
|
||||||
memcpy((uint8_t*)je + je->size, wr->get_ext_bitmap(heap), new_clean_entry_bitmap_size);
|
|
||||||
if (dsk.data_csum_type != 0 && wr->get_checksums(heap))
|
|
||||||
{
|
|
||||||
memcpy((uint8_t*)je + je->size + new_clean_entry_bitmap_size, wr->get_checksums(heap), heap->get_csum_size(wr));
|
|
||||||
}
|
|
||||||
je->crc32 = je_crc32(je);
|
|
||||||
new_journal_in_pos += je->size;
|
|
||||||
new_crc32_prev = je->crc32;
|
|
||||||
}
|
|
||||||
|
|
||||||
int disk_tool_t::resize_rebuild_meta()
|
int disk_tool_t::resize_rebuild_meta()
|
||||||
{
|
{
|
||||||
new_meta_buf = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, new_meta_len);
|
new_meta_buf = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, new_meta_len);
|
||||||
@@ -630,13 +564,12 @@ int disk_tool_t::resize_rebuild_meta()
|
|||||||
new_meta_hdr = (blockstore_meta_header_v3_t *)new_meta_buf;
|
new_meta_hdr = (blockstore_meta_header_v3_t *)new_meta_buf;
|
||||||
uint64_t new_meta_pos = dsk.meta_block_size;
|
uint64_t new_meta_pos = dsk.meta_block_size;
|
||||||
uint64_t next_lsn = 0;
|
uint64_t next_lsn = 0;
|
||||||
std::vector<heap_entry_t*> writes;
|
|
||||||
int r = process_meta(
|
int r = process_meta(
|
||||||
[&](blockstore_meta_header_v3_t *hdr)
|
[&](blockstore_meta_header_v3_t *hdr)
|
||||||
{
|
{
|
||||||
new_meta_hdr->zero = 0;
|
new_meta_hdr->zero = 0;
|
||||||
new_meta_hdr->magic = BLOCKSTORE_META_MAGIC_V1;
|
new_meta_hdr->magic = BLOCKSTORE_META_MAGIC_V1;
|
||||||
new_meta_hdr->version = new_meta_format == 0 ? BLOCKSTORE_META_FORMAT_HEAP : new_meta_format;
|
new_meta_hdr->version = new_meta_format;
|
||||||
new_meta_hdr->meta_block_size = dsk.meta_block_size;
|
new_meta_hdr->meta_block_size = dsk.meta_block_size;
|
||||||
new_meta_hdr->data_block_size = dsk.data_block_size;
|
new_meta_hdr->data_block_size = dsk.data_block_size;
|
||||||
new_meta_hdr->bitmap_granularity = dsk.bitmap_granularity ? dsk.bitmap_granularity : 4096;
|
new_meta_hdr->bitmap_granularity = dsk.bitmap_granularity ? dsk.bitmap_granularity : 4096;
|
||||||
@@ -654,18 +587,16 @@ int disk_tool_t::resize_rebuild_meta()
|
|||||||
},
|
},
|
||||||
[&](blockstore_heap_t *heap, heap_entry_t *obj, uint32_t meta_block_num)
|
[&](blockstore_heap_t *heap, heap_entry_t *obj, uint32_t meta_block_num)
|
||||||
{
|
{
|
||||||
|
assert(new_meta_format == BLOCKSTORE_META_FORMAT_HEAP);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
{
|
{
|
||||||
// Finish
|
// Finish
|
||||||
if (new_meta_format == BLOCKSTORE_META_FORMAT_HEAP)
|
heap->fill_block_empty_space(new_meta_buf, new_meta_pos);
|
||||||
|
new_meta_pos = (new_meta_pos/dsk.meta_block_size + 1) * dsk.meta_block_size;
|
||||||
|
while (new_meta_pos < new_meta_len)
|
||||||
{
|
{
|
||||||
heap->fill_block_empty_space(new_meta_buf, new_meta_pos);
|
heap->fill_block_empty_space(new_meta_buf, new_meta_pos);
|
||||||
new_meta_pos = (new_meta_pos/dsk.meta_block_size + 1) * dsk.meta_block_size;
|
new_meta_pos += dsk.meta_block_size;
|
||||||
while (new_meta_pos < new_meta_len)
|
|
||||||
{
|
|
||||||
heap->fill_block_empty_space(new_meta_buf, new_meta_pos);
|
|
||||||
new_meta_pos += dsk.meta_block_size;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -679,72 +610,24 @@ int disk_tool_t::resize_rebuild_meta()
|
|||||||
{
|
{
|
||||||
remap_small_write(wr);
|
remap_small_write(wr);
|
||||||
}
|
}
|
||||||
else if (wr->type() != BS_HEAP_DELETE && new_meta_format != BLOCKSTORE_META_FORMAT_HEAP)
|
// New -> New
|
||||||
|
if ((new_meta_pos % dsk.meta_block_size) + wr->size > dsk.meta_block_size)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Object %jx:%jx can't be converted to the old format because it contains an entry of type 0x%x%s\n",
|
heap->fill_block_empty_space(new_meta_buf, new_meta_pos);
|
||||||
wr->inode, wr->stripe, wr->entry_type,
|
new_meta_pos = (new_meta_pos/dsk.meta_block_size + 1) * dsk.meta_block_size;
|
||||||
(wr->type() == BS_HEAP_INTENT_WRITE ? " (intent_write)" : ""));
|
if (new_meta_pos >= new_meta_len)
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if (new_meta_format == BLOCKSTORE_META_FORMAT_HEAP)
|
|
||||||
{
|
|
||||||
// New -> New
|
|
||||||
if ((new_meta_pos % dsk.meta_block_size) + wr->size > dsk.meta_block_size)
|
|
||||||
{
|
{
|
||||||
heap->fill_block_empty_space(new_meta_buf, new_meta_pos);
|
fprintf(stderr, "New metadata doesn't fit into the provided area\n");
|
||||||
new_meta_pos = (new_meta_pos/dsk.meta_block_size + 1) * dsk.meta_block_size;
|
exit(1);
|
||||||
if (new_meta_pos >= new_meta_len)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "New metadata doesn't fit into the provided area\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
memcpy(new_meta_buf + new_meta_pos, wr, wr->size);
|
|
||||||
new_meta_pos += wr->size;
|
|
||||||
if (skip_obsolete && wr->type() == BS_HEAP_BIG_WRITE && stable)
|
|
||||||
{
|
|
||||||
// Skip older writes
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// New -> Old
|
|
||||||
if (wr->type() == BS_HEAP_DELETE && stable)
|
|
||||||
{
|
|
||||||
// Object is deleted, skip it
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (wr->type() == BS_HEAP_BIG_WRITE && stable)
|
|
||||||
{
|
|
||||||
fill_old_clean_entry(heap, wr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
writes.push_back(wr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
memcpy(new_meta_buf + new_meta_pos, wr, wr->size);
|
||||||
|
new_meta_pos += wr->size;
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
if (new_meta_format != BLOCKSTORE_META_FORMAT_HEAP || skip_obsolete)
|
for (auto wr = obj; wr; wr = heap->prev(wr))
|
||||||
{
|
{
|
||||||
heap->iterate_with_stable(obj, obj->lsn, handle_write);
|
handle_write(wr, false);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (auto wr = obj; wr; wr = heap->prev(wr))
|
|
||||||
{
|
|
||||||
handle_write(wr, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (writes.size())
|
|
||||||
{
|
|
||||||
for (size_t i = writes.size(); i > 0; i--)
|
|
||||||
{
|
|
||||||
fill_old_journal_entry(heap, writes[i-1]);
|
|
||||||
}
|
|
||||||
writes.clear();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[&](uint64_t block_num, clean_disk_entry *entry, uint8_t *bitmap)
|
[&](uint64_t block_num, clean_disk_entry *entry, uint8_t *bitmap)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 2.8.12)
|
cmake_minimum_required(VERSION 2.8...3.30)
|
||||||
|
|
||||||
project(vitastor)
|
project(vitastor)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 2.8.12)
|
cmake_minimum_required(VERSION 2.8...3.30)
|
||||||
|
|
||||||
project(vitastor)
|
project(vitastor)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 2.8.12)
|
cmake_minimum_required(VERSION 2.8...3.30)
|
||||||
|
|
||||||
project(vitastor)
|
project(vitastor)
|
||||||
|
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ static const char* help_text =
|
|||||||
" --logfile <FILE> log to the specified file\n"
|
" --logfile <FILE> log to the specified file\n"
|
||||||
" --enforce 1 enforce permissions at the server side (default is disabled)\n"
|
" --enforce 1 enforce permissions at the server side (default is disabled)\n"
|
||||||
" --foreground 1 stay in foreground, do not daemonize\n"
|
" --foreground 1 stay in foreground, do not daemonize\n"
|
||||||
|
" --trace trace all NFS requests\n"
|
||||||
"\n"
|
"\n"
|
||||||
"NFS proxy is stateless if you use immediate_commit=all in your cluster and if\n"
|
"NFS proxy is stateless if you use immediate_commit=all in your cluster and if\n"
|
||||||
"you do not use client_enable_writeback=true, so you can freely use multiple\n"
|
"you do not use client_enable_writeback=true, so you can freely use multiple\n"
|
||||||
@@ -158,7 +159,7 @@ json11::Json::object nfs_proxy_t::parse_args(int narg, const char *args[])
|
|||||||
{
|
{
|
||||||
const char *opt = args[i]+2;
|
const char *opt = args[i]+2;
|
||||||
cfg[str_replace(opt, "-", "_")] = !strcmp(opt, "json") || !strcmp(opt, "block") ||
|
cfg[str_replace(opt, "-", "_")] = !strcmp(opt, "json") || !strcmp(opt, "block") ||
|
||||||
!strcmp(opt, "dry-run") || !strcmp(opt, "recalc-stats") ||
|
!strcmp(opt, "dry-run") || !strcmp(opt, "recalc-stats") || !strcmp(opt, "trace") ||
|
||||||
!strcmp(opt, "include-empty") || !strcmp(opt, "no-rm") || i == narg-1 ? "1" : args[++i];
|
!strcmp(opt, "include-empty") || !strcmp(opt, "no-rm") || i == narg-1 ? "1" : args[++i];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -586,8 +586,8 @@ send_again:
|
|||||||
}
|
}
|
||||||
// Estimate reply WR count, create WR and SGE arrays
|
// Estimate reply WR count, create WR and SGE arrays
|
||||||
xdr_write_chunk *reply_chunk = rop->in_rdma_msg.rdma_body.rdma_msg.rdma_reply;
|
xdr_write_chunk *reply_chunk = rop->in_rdma_msg.rdma_body.rdma_msg.rdma_reply;
|
||||||
int reply_chunk_wr_count = (reply_chunk ? reply_chunk->target.target_len : 0);
|
uint32_t reply_chunk_wr_count = (reply_chunk ? reply_chunk->target.target_len : 0);
|
||||||
uint32_t wr_count = 1 + (chunk_iov ? 1 : 0) + (reply_chunk ? reply_chunk_wr_count : 0);
|
uint32_t wr_count = 1 + (chunk_iov ? 1 : 0) + reply_chunk_wr_count;
|
||||||
if (wr_count > ctx->max_send_wr)
|
if (wr_count > ctx->max_send_wr)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Reply fragmentation (%u) exceeds max_send_wr (%u), sending ERR_CHUNK\n", wr_count, ctx->max_send_wr);
|
fprintf(stderr, "Reply fragmentation (%u) exceeds max_send_wr (%u), sending ERR_CHUNK\n", wr_count, ctx->max_send_wr);
|
||||||
@@ -622,7 +622,7 @@ chunk_error:
|
|||||||
{
|
{
|
||||||
size_t reply_chunk_len = 0;
|
size_t reply_chunk_len = 0;
|
||||||
size_t left = msg_size;
|
size_t left = msg_size;
|
||||||
for (uint32_t i = 0; i < reply_chunk->target.target_len; i++)
|
for (uint32_t i = 0; i < reply_chunk_wr_count; i++)
|
||||||
{
|
{
|
||||||
reply_chunk_len += reply_chunk->target.target_val[i].length;
|
reply_chunk_len += reply_chunk->target.target_val[i].length;
|
||||||
if (reply_chunk->target.target_val[i].length > left)
|
if (reply_chunk->target.target_val[i].length > left)
|
||||||
@@ -653,7 +653,7 @@ chunk_error:
|
|||||||
}
|
}
|
||||||
ibv_sge sges[wr_count];
|
ibv_sge sges[wr_count];
|
||||||
ibv_send_wr wrs[wr_count];
|
ibv_send_wr wrs[wr_count];
|
||||||
int wr_pos = 0;
|
uint32_t wr_pos = 0;
|
||||||
// Use a buffer from rdma_malloc for the reply
|
// Use a buffer from rdma_malloc for the reply
|
||||||
assert(!rop->buffer);
|
assert(!rop->buffer);
|
||||||
rop->buffer = rdma_malloc_alloc(conn_dev->alloc, hdr_size+msg_size);
|
rop->buffer = rdma_malloc_alloc(conn_dev->alloc, hdr_size+msg_size);
|
||||||
@@ -685,7 +685,7 @@ chunk_error:
|
|||||||
if (reply_chunk)
|
if (reply_chunk)
|
||||||
{
|
{
|
||||||
size_t pos = hdr_size;
|
size_t pos = hdr_size;
|
||||||
for (uint32_t i = 0; i < reply_chunk->target.target_len && pos < msg_size; i++)
|
for (uint32_t i = 0; i < reply_chunk_wr_count && pos < msg_size; i++)
|
||||||
{
|
{
|
||||||
uint32_t len = (reply_chunk->target.target_val[i].length < msg_size-pos
|
uint32_t len = (reply_chunk->target.target_val[i].length < msg_size-pos
|
||||||
? reply_chunk->target.target_val[i].length : msg_size-pos);
|
? reply_chunk->target.target_val[i].length : msg_size-pos);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 2.8.12)
|
cmake_minimum_required(VERSION 2.8...3.30)
|
||||||
|
|
||||||
project(vitastor)
|
project(vitastor)
|
||||||
|
|
||||||
@@ -19,20 +19,19 @@ target_link_libraries(vitastor-osd
|
|||||||
|
|
||||||
# osd_rmw_test
|
# osd_rmw_test
|
||||||
add_executable(osd_rmw_test EXCLUDE_FROM_ALL osd_rmw_test.cpp ../util/allocator.cpp)
|
add_executable(osd_rmw_test EXCLUDE_FROM_ALL osd_rmw_test.cpp ../util/allocator.cpp)
|
||||||
target_link_libraries(osd_rmw_test Jerasure ${ISAL_LIBRARIES} tcmalloc_minimal)
|
target_link_libraries(osd_rmw_test Jerasure ${ISAL_LIBRARIES})
|
||||||
add_dependencies(build_tests osd_rmw_test)
|
add_dependencies(build_tests osd_rmw_test)
|
||||||
add_test(NAME osd_rmw_test COMMAND osd_rmw_test)
|
add_test(NAME osd_rmw_test COMMAND osd_rmw_test)
|
||||||
|
|
||||||
if (ISAL_LIBRARIES)
|
if (ISAL_LIBRARIES)
|
||||||
add_executable(osd_rmw_test_je EXCLUDE_FROM_ALL osd_rmw_test.cpp ../util/allocator.cpp)
|
add_executable(osd_rmw_test_je EXCLUDE_FROM_ALL osd_rmw_test.cpp ../util/allocator.cpp)
|
||||||
target_compile_definitions(osd_rmw_test_je PUBLIC -DNO_ISAL)
|
target_compile_definitions(osd_rmw_test_je PUBLIC -DNO_ISAL)
|
||||||
target_link_libraries(osd_rmw_test_je Jerasure tcmalloc_minimal)
|
target_link_libraries(osd_rmw_test_je Jerasure)
|
||||||
add_dependencies(build_tests osd_rmw_test_je)
|
add_dependencies(build_tests osd_rmw_test_je)
|
||||||
add_test(NAME osd_rmw_test_jerasure COMMAND osd_rmw_test_je)
|
add_test(NAME osd_rmw_test_jerasure COMMAND osd_rmw_test_je)
|
||||||
endif (ISAL_LIBRARIES)
|
endif (ISAL_LIBRARIES)
|
||||||
|
|
||||||
# osd_peering_pg_test
|
# osd_peering_pg_test
|
||||||
add_executable(osd_peering_pg_test EXCLUDE_FROM_ALL osd_peering_pg_test.cpp osd_peering_pg.cpp)
|
add_executable(osd_peering_pg_test EXCLUDE_FROM_ALL osd_peering_pg_test.cpp osd_peering_pg.cpp)
|
||||||
target_link_libraries(osd_peering_pg_test tcmalloc_minimal)
|
|
||||||
add_dependencies(build_tests osd_peering_pg_test)
|
add_dependencies(build_tests osd_peering_pg_test)
|
||||||
add_test(NAME osd_peering_pg_test COMMAND osd_peering_pg_test)
|
add_test(NAME osd_peering_pg_test COMMAND osd_peering_pg_test)
|
||||||
|
|||||||
+10
-9
@@ -15,22 +15,19 @@
|
|||||||
#include "str_util.h"
|
#include "str_util.h"
|
||||||
#include "json_util.h"
|
#include "json_util.h"
|
||||||
|
|
||||||
osd_t::osd_t(const json11::Json & config, ring_loop_t *ringloop)
|
osd_t::osd_t(const json11::Json & config, ring_loop_i *ringloop, timerfd_manager_t *tfd)
|
||||||
{
|
{
|
||||||
zero_buffer_size = 1<<20;
|
zero_buffer_size = 1<<20;
|
||||||
zero_buffer = malloc_or_die(zero_buffer_size);
|
zero_buffer = malloc_or_die(zero_buffer_size);
|
||||||
memset(zero_buffer, 0, zero_buffer_size);
|
memset(zero_buffer, 0, zero_buffer_size);
|
||||||
|
|
||||||
this->ringloop = ringloop;
|
this->ringloop = ringloop;
|
||||||
|
this->tfd = tfd;
|
||||||
|
|
||||||
this->cli_config = config.object_items();
|
this->cli_config = config.object_items();
|
||||||
this->file_config = msgr.read_config(this->cli_config);
|
this->file_config = msgr.read_config(this->cli_config);
|
||||||
parse_config(true);
|
parse_config(true);
|
||||||
|
|
||||||
epmgr = new epoll_manager_t(ringloop);
|
|
||||||
// FIXME: Use timerfd_interval based directly on io_uring
|
|
||||||
this->tfd = epmgr->tfd;
|
|
||||||
|
|
||||||
if (json_is_true(this->config["osd_memlock"]))
|
if (json_is_true(this->config["osd_memlock"]))
|
||||||
{
|
{
|
||||||
// Lock all OSD memory if requested
|
// Lock all OSD memory if requested
|
||||||
@@ -99,7 +96,6 @@ osd_t::~osd_t()
|
|||||||
}
|
}
|
||||||
ringloop->unregister_consumer(&consumer);
|
ringloop->unregister_consumer(&consumer);
|
||||||
ringloop->unregister_consumer(&init_consumer);
|
ringloop->unregister_consumer(&init_consumer);
|
||||||
delete epmgr;
|
|
||||||
if (bs)
|
if (bs)
|
||||||
delete bs;
|
delete bs;
|
||||||
#ifdef WITH_RDMACM
|
#ifdef WITH_RDMACM
|
||||||
@@ -398,7 +394,7 @@ void osd_t::bind_socket()
|
|||||||
{
|
{
|
||||||
int listen_fd = create_and_bind_socket(bind_address, listening_port ? listening_port : bind_port, listen_backlog, &listening_port);
|
int listen_fd = create_and_bind_socket(bind_address, listening_port ? listening_port : bind_port, listen_backlog, &listening_port);
|
||||||
fcntl(listen_fd, F_SETFL, fcntl(listen_fd, F_GETFL, 0) | O_NONBLOCK);
|
fcntl(listen_fd, F_SETFL, fcntl(listen_fd, F_GETFL, 0) | O_NONBLOCK);
|
||||||
epmgr->set_fd_handler(listen_fd, false, [this](int fd, int events)
|
tfd->set_fd_handler(listen_fd, false, [this](int fd, int events)
|
||||||
{
|
{
|
||||||
msgr.accept_connections(fd);
|
msgr.accept_connections(fd);
|
||||||
});
|
});
|
||||||
@@ -529,6 +525,11 @@ void osd_t::exec_op(osd_op_t *cur_op)
|
|||||||
|
|
||||||
void osd_t::print_stats()
|
void osd_t::print_stats()
|
||||||
{
|
{
|
||||||
|
if (bs && log_level > 1)
|
||||||
|
{
|
||||||
|
printf("[OSD %ju] Live entries: %ju (%ju bytes), garbage entries: %ju (%ju bytes)\n", osd_num,
|
||||||
|
bs->get_live_entries(), bs->get_live_memory(), bs->get_garbage_entries(), bs->get_garbage_memory());
|
||||||
|
}
|
||||||
for (int i = OSD_OP_MIN; i <= OSD_OP_MAX; i++)
|
for (int i = OSD_OP_MIN; i <= OSD_OP_MAX; i++)
|
||||||
{
|
{
|
||||||
if (msgr.stats.op_stat_count[i] != prev_stats.op_stat_count[i] && i != OSD_OP_PING)
|
if (msgr.stats.op_stat_count[i] != prev_stats.op_stat_count[i] && i != OSD_OP_PING)
|
||||||
@@ -616,11 +617,11 @@ void osd_t::print_slow()
|
|||||||
bufprintf("[OSD %ju] Slow op %jx", osd_num, (uint64_t)op);
|
bufprintf("[OSD %ju] Slow op %jx", osd_num, (uint64_t)op);
|
||||||
if (kv.second->osd_num)
|
if (kv.second->osd_num)
|
||||||
{
|
{
|
||||||
bufprintf(" from peer OSD %ju (client %d)", kv.second->osd_num, kv.second->peer_fd);
|
bufprintf(" from peer OSD %ju (client %ju)", kv.second->osd_num, kv.second->client_id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bufprintf(" from client %d", kv.second->peer_fd);
|
bufprintf(" from client %ju", kv.second->client_id);
|
||||||
}
|
}
|
||||||
bufprintf(": %s id=%ju", osd_op_names[op->req.hdr.opcode], op->req.hdr.id);
|
bufprintf(": %s id=%ju", osd_op_names[op->req.hdr.opcode], op->req.hdr.id);
|
||||||
if (op->req.hdr.opcode == OSD_OP_SEC_READ || op->req.hdr.opcode == OSD_OP_SEC_WRITE ||
|
if (op->req.hdr.opcode == OSD_OP_SEC_READ || op->req.hdr.opcode == OSD_OP_SEC_WRITE ||
|
||||||
|
|||||||
+6
-8
@@ -19,7 +19,6 @@
|
|||||||
#include "blockstore.h"
|
#include "blockstore.h"
|
||||||
#include "ringloop.h"
|
#include "ringloop.h"
|
||||||
#include "timerfd_manager.h"
|
#include "timerfd_manager.h"
|
||||||
#include "epoll_manager.h"
|
|
||||||
#include "osd_peering_pg.h"
|
#include "osd_peering_pg.h"
|
||||||
#include "messenger.h"
|
#include "messenger.h"
|
||||||
#include "etcd_state_client.h"
|
#include "etcd_state_client.h"
|
||||||
@@ -210,9 +209,8 @@ class osd_t
|
|||||||
void *zero_buffer = NULL;
|
void *zero_buffer = NULL;
|
||||||
uint64_t zero_buffer_size = 0;
|
uint64_t zero_buffer_size = 0;
|
||||||
uint32_t bs_block_size, bs_bitmap_granularity, clean_entry_bitmap_size;
|
uint32_t bs_block_size, bs_bitmap_granularity, clean_entry_bitmap_size;
|
||||||
ring_loop_t *ringloop = NULL;
|
ring_loop_i *ringloop = NULL;
|
||||||
timerfd_manager_t *tfd = NULL;
|
timerfd_manager_t *tfd = NULL;
|
||||||
epoll_manager_t *epmgr = NULL;
|
|
||||||
|
|
||||||
int listening_port = 0;
|
int listening_port = 0;
|
||||||
std::vector<std::string> bind_addresses;
|
std::vector<std::string> bind_addresses;
|
||||||
@@ -347,13 +345,12 @@ class osd_t
|
|||||||
bool check_write_queue(osd_op_t *cur_op, pg_t & pg);
|
bool check_write_queue(osd_op_t *cur_op, pg_t & pg);
|
||||||
pg_osd_set_state_t* add_object_to_set(pg_t & pg, const object_id oid, const pg_osd_set_t & osd_set,
|
pg_osd_set_state_t* add_object_to_set(pg_t & pg, const object_id oid, const pg_osd_set_t & osd_set,
|
||||||
uint64_t old_pg_state, int log_at_level);
|
uint64_t old_pg_state, int log_at_level);
|
||||||
void remove_object_from_state(object_id & oid, pg_osd_set_state_t **object_state, pg_t &pg, bool report = true);
|
bool remove_object_from_state(object_id & oid, pg_osd_set_state_t **object_state, pg_t &pg, bool report = true);
|
||||||
pg_osd_set_state_t *mark_object(pg_t & pg, object_id oid, pg_osd_set_state_t *prev_object_state, bool ref,
|
pg_osd_set_state_t *mark_object(pg_t & pg, object_id oid, pg_osd_set_state_t *prev_object_state, bool ref,
|
||||||
std::function<int(pg_osd_set_t & new_set)> calc_set);
|
std::function<int(pg_osd_set_t & new_set)> calc_set);
|
||||||
pg_osd_set_state_t *mark_object_corrupted(pg_t & pg, object_id oid, pg_osd_set_state_t *prev_object_state,
|
pg_osd_set_state_t *mark_object_corrupted(pg_t & pg, object_id oid, pg_osd_set_state_t *prev_object_state,
|
||||||
osd_rmw_stripe_t *stripes, bool ref);
|
osd_rmw_stripe_t *stripes, bool ref);
|
||||||
pg_osd_set_state_t *mark_partial_write(pg_t & pg, object_id oid, pg_osd_set_state_t *prev_object_state,
|
pg_osd_set_state_t *mark_partial_write(pg_t & pg, osd_op_t *cur_op);
|
||||||
osd_rmw_stripe_t *stripes, bool ref);
|
|
||||||
void deref_object_state(pg_t & pg, pg_osd_set_state_t **object_state, bool deref);
|
void deref_object_state(pg_t & pg, pg_osd_set_state_t **object_state, bool deref);
|
||||||
bool remember_unstable_write(osd_op_t *cur_op, pg_t & pg, pg_osd_set_t & loc_set, int base_state);
|
bool remember_unstable_write(osd_op_t *cur_op, pg_t & pg, pg_osd_set_t & loc_set, int base_state);
|
||||||
void handle_primary_subop(osd_op_t *subop, osd_op_t *cur_op);
|
void handle_primary_subop(osd_op_t *subop, osd_op_t *cur_op);
|
||||||
@@ -366,9 +363,10 @@ class osd_t
|
|||||||
osd_rmw_stripe_t *stripes, const uint64_t* osd_set, osd_op_t *cur_op, int subop_idx, int zero_read);
|
osd_rmw_stripe_t *stripes, const uint64_t* osd_set, osd_op_t *cur_op, int subop_idx, int zero_read);
|
||||||
void submit_primary_subop(osd_op_t *cur_op, osd_op_t *subop,
|
void submit_primary_subop(osd_op_t *cur_op, osd_op_t *subop,
|
||||||
osd_rmw_stripe_t *si, bool wr, inode_t inode, uint64_t op_version);
|
osd_rmw_stripe_t *si, bool wr, inode_t inode, uint64_t op_version);
|
||||||
|
bool submit_to_osd(osd_op_t *subop, osd_num_t osd_num);
|
||||||
void submit_primary_del_subops(osd_op_t *cur_op, uint64_t *cur_set, uint64_t set_size, pg_osd_set_t & loc_set);
|
void submit_primary_del_subops(osd_op_t *cur_op, uint64_t *cur_set, uint64_t set_size, pg_osd_set_t & loc_set);
|
||||||
void submit_primary_del_batch(osd_op_t *cur_op, obj_ver_osd_t *chunks_to_delete, int chunks_to_delete_count);
|
void submit_primary_del_batch(osd_op_t *cur_op, obj_ver_osd_t *chunks_to_delete, int chunks_to_delete_count);
|
||||||
int submit_primary_sync_subops(osd_op_t *cur_op);
|
void submit_primary_sync_subops(osd_op_t *cur_op);
|
||||||
void submit_primary_stab_subops(osd_op_t *cur_op);
|
void submit_primary_stab_subops(osd_op_t *cur_op);
|
||||||
void submit_primary_rollback_subops(osd_op_t *cur_op, const uint64_t* osd_set);
|
void submit_primary_rollback_subops(osd_op_t *cur_op, const uint64_t* osd_set);
|
||||||
|
|
||||||
@@ -392,7 +390,7 @@ class osd_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
osd_t(const json11::Json & config, ring_loop_t *ringloop);
|
osd_t(const json11::Json & config, ring_loop_i *ringloop, timerfd_manager_t *tfd);
|
||||||
~osd_t();
|
~osd_t();
|
||||||
void force_stop(int exitcode);
|
void force_stop(int exitcode);
|
||||||
bool shutdown();
|
bool shutdown();
|
||||||
|
|||||||
@@ -991,7 +991,7 @@ void osd_t::apply_pg_config()
|
|||||||
// Add peers
|
// Add peers
|
||||||
for (auto pg_osd: all_peers)
|
for (auto pg_osd: all_peers)
|
||||||
{
|
{
|
||||||
if (pg_osd != this->osd_num && msgr.osd_peer_fds.find(pg_osd) == msgr.osd_peer_fds.end())
|
if (pg_osd != this->osd_num && msgr.osd_peers.find(pg_osd) == msgr.osd_peers.end())
|
||||||
{
|
{
|
||||||
msgr.connect_peer(pg_osd, st_cli.peer_states[pg_osd]);
|
msgr.connect_peer(pg_osd, st_cli.peer_states[pg_osd]);
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user