Compare commits
28
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8124ee9eec | ||
|
|
ccbde3ff91 | ||
|
|
3a0455877a | ||
|
|
6c2c7f9d0f | ||
|
|
11618da189 | ||
|
|
9d2a859760 | ||
|
|
76042d9ea8 | ||
|
|
96473f15f9 | ||
|
|
7207d0fa75 | ||
|
|
0fb58e3c43 | ||
|
|
de7edfd31d | ||
|
|
e6c3f4c6f4 | ||
|
|
b4d172be35 | ||
|
|
a2debfca68 | ||
|
|
4c3c43f8ac | ||
|
|
6638889126 | ||
|
|
7fb5426ae9 | ||
|
|
b4af7409af | ||
|
|
645b1f3081 | ||
|
|
9a21a0ca65 | ||
|
|
28e4610d25 | ||
|
|
2ddefa539f | ||
|
|
3aa307f034 | ||
|
|
3ed7a0bc5e | ||
|
|
ab77f487e3 | ||
|
|
ba9be46acd | ||
|
|
04c7d61ee9 | ||
|
|
d0ae63eb50 |
+127
-109
@@ -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 build_tests test
|
- run: cd /root/vitastor/build && ASAN_OPTIONS=detect_leaks=0 make -j16 test
|
||||||
|
|
||||||
npm_lint:
|
npm_lint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -234,6 +234,60 @@ jobs:
|
|||||||
echo ""
|
echo ""
|
||||||
done
|
done
|
||||||
|
|
||||||
|
test_etcd_fail_https:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
|
container: ${{env.TEST_IMAGE}}:${{github.sha}}
|
||||||
|
steps:
|
||||||
|
- name: Run test
|
||||||
|
id: test
|
||||||
|
timeout-minutes: 10
|
||||||
|
run: ETCD_SCHEME=https /root/vitastor/tests/test_etcd_fail.sh
|
||||||
|
- name: Print logs
|
||||||
|
if: always() && steps.test.outcome == 'failure'
|
||||||
|
run: |
|
||||||
|
for i in /root/vitastor/testdata/*.log /root/vitastor/testdata/*.txt; do
|
||||||
|
echo "-------- $i --------"
|
||||||
|
cat $i
|
||||||
|
echo ""
|
||||||
|
done
|
||||||
|
|
||||||
|
test_etcd_fail_https_antietcd:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
|
container: ${{env.TEST_IMAGE}}:${{github.sha}}
|
||||||
|
steps:
|
||||||
|
- name: Run test
|
||||||
|
id: test
|
||||||
|
timeout-minutes: 10
|
||||||
|
run: ETCD_SCHEME=https ANTIETCD=1 /root/vitastor/tests/test_etcd_fail.sh
|
||||||
|
- name: Print logs
|
||||||
|
if: always() && steps.test.outcome == 'failure'
|
||||||
|
run: |
|
||||||
|
for i in /root/vitastor/testdata/*.log /root/vitastor/testdata/*.txt; do
|
||||||
|
echo "-------- $i --------"
|
||||||
|
cat $i
|
||||||
|
echo ""
|
||||||
|
done
|
||||||
|
|
||||||
|
test_snapshot_https:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
|
container: ${{env.TEST_IMAGE}}:${{github.sha}}
|
||||||
|
steps:
|
||||||
|
- name: Run test
|
||||||
|
id: test
|
||||||
|
timeout-minutes: 3
|
||||||
|
run: ETCD_SCHEME=https /root/vitastor/tests/test_snapshot.sh
|
||||||
|
- name: Print logs
|
||||||
|
if: always() && steps.test.outcome == 'failure'
|
||||||
|
run: |
|
||||||
|
for i in /root/vitastor/testdata/*.log /root/vitastor/testdata/*.txt; do
|
||||||
|
echo "-------- $i --------"
|
||||||
|
cat $i
|
||||||
|
echo ""
|
||||||
|
done
|
||||||
|
|
||||||
test_interrupted_rebalance:
|
test_interrupted_rebalance:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: build
|
needs: build
|
||||||
@@ -306,78 +360,6 @@ jobs:
|
|||||||
echo ""
|
echo ""
|
||||||
done
|
done
|
||||||
|
|
||||||
test_dump_load:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build
|
|
||||||
container: ${{env.TEST_IMAGE}}:${{github.sha}}
|
|
||||||
steps:
|
|
||||||
- name: Run test
|
|
||||||
id: test
|
|
||||||
timeout-minutes: 3
|
|
||||||
run: /root/vitastor/tests/test_dump_load.sh
|
|
||||||
- name: Print logs
|
|
||||||
if: always() && steps.test.outcome == 'failure'
|
|
||||||
run: |
|
|
||||||
for i in /root/vitastor/testdata/*.log /root/vitastor/testdata/*.txt; do
|
|
||||||
echo "-------- $i --------"
|
|
||||||
cat $i
|
|
||||||
echo ""
|
|
||||||
done
|
|
||||||
|
|
||||||
test_dump_load_32k:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build
|
|
||||||
container: ${{env.TEST_IMAGE}}:${{github.sha}}
|
|
||||||
steps:
|
|
||||||
- name: Run test
|
|
||||||
id: test
|
|
||||||
timeout-minutes: 3
|
|
||||||
run: TEST_NAME=32k OSD_ARGS="--data_csum_type crc32c --csum_block_size 32k" OFFSET_ARGS="$OSD_ARGS" /root/vitastor/tests/test_dump_load.sh
|
|
||||||
- name: Print logs
|
|
||||||
if: always() && steps.test.outcome == 'failure'
|
|
||||||
run: |
|
|
||||||
for i in /root/vitastor/testdata/*.log /root/vitastor/testdata/*.txt; do
|
|
||||||
echo "-------- $i --------"
|
|
||||||
cat $i
|
|
||||||
echo ""
|
|
||||||
done
|
|
||||||
|
|
||||||
test_old_dump_load:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build
|
|
||||||
container: ${{env.TEST_IMAGE}}:${{github.sha}}
|
|
||||||
steps:
|
|
||||||
- name: Run test
|
|
||||||
id: test
|
|
||||||
timeout-minutes: 3
|
|
||||||
run: OLD=1 /root/vitastor/tests/test_dump_load.sh
|
|
||||||
- name: Print logs
|
|
||||||
if: always() && steps.test.outcome == 'failure'
|
|
||||||
run: |
|
|
||||||
for i in /root/vitastor/testdata/*.log /root/vitastor/testdata/*.txt; do
|
|
||||||
echo "-------- $i --------"
|
|
||||||
cat $i
|
|
||||||
echo ""
|
|
||||||
done
|
|
||||||
|
|
||||||
test_dump_load_old_32k:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build
|
|
||||||
container: ${{env.TEST_IMAGE}}:${{github.sha}}
|
|
||||||
steps:
|
|
||||||
- name: Run test
|
|
||||||
id: test
|
|
||||||
timeout-minutes: 3
|
|
||||||
run: TEST_NAME=old_32k OLD=1 OSD_ARGS="--data_csum_type crc32c --csum_block_size 32k" OFFSET_ARGS="$OSD_ARGS" /root/vitastor/tests/test_dump_load.sh
|
|
||||||
- name: Print logs
|
|
||||||
if: always() && steps.test.outcome == 'failure'
|
|
||||||
run: |
|
|
||||||
for i in /root/vitastor/testdata/*.log /root/vitastor/testdata/*.txt; do
|
|
||||||
echo "-------- $i --------"
|
|
||||||
cat $i
|
|
||||||
echo ""
|
|
||||||
done
|
|
||||||
|
|
||||||
test_old_interrupted_rebalance:
|
test_old_interrupted_rebalance:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: build
|
needs: build
|
||||||
@@ -720,6 +702,24 @@ jobs:
|
|||||||
echo ""
|
echo ""
|
||||||
done
|
done
|
||||||
|
|
||||||
|
test_snapshot_chain_encrypted:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
|
container: ${{env.TEST_IMAGE}}:${{github.sha}}
|
||||||
|
steps:
|
||||||
|
- name: Run test
|
||||||
|
id: test
|
||||||
|
timeout-minutes: 3
|
||||||
|
run: ENCRYPTED=1 /root/vitastor/tests/test_snapshot_chain.sh
|
||||||
|
- name: Print logs
|
||||||
|
if: always() && steps.test.outcome == 'failure'
|
||||||
|
run: |
|
||||||
|
for i in /root/vitastor/testdata/*.log /root/vitastor/testdata/*.txt; do
|
||||||
|
echo "-------- $i --------"
|
||||||
|
cat $i
|
||||||
|
echo ""
|
||||||
|
done
|
||||||
|
|
||||||
test_old_snapshot_chain:
|
test_old_snapshot_chain:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: build
|
needs: build
|
||||||
@@ -1296,6 +1296,24 @@ jobs:
|
|||||||
echo ""
|
echo ""
|
||||||
done
|
done
|
||||||
|
|
||||||
|
test_checksum_xxhash:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
|
container: ${{env.TEST_IMAGE}}:${{github.sha}}
|
||||||
|
steps:
|
||||||
|
- name: Run test
|
||||||
|
id: test
|
||||||
|
timeout-minutes: 3
|
||||||
|
run: TEST_NAME=xxhash OSD_ARGS="--data_csum_type xxh3_32" /root/vitastor/tests/test_checksum.sh
|
||||||
|
- name: Print logs
|
||||||
|
if: always() && steps.test.outcome == 'failure'
|
||||||
|
run: |
|
||||||
|
for i in /root/vitastor/testdata/*.log /root/vitastor/testdata/*.txt; do
|
||||||
|
echo "-------- $i --------"
|
||||||
|
cat $i
|
||||||
|
echo ""
|
||||||
|
done
|
||||||
|
|
||||||
test_old_checksum:
|
test_old_checksum:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: build
|
needs: build
|
||||||
@@ -1530,24 +1548,6 @@ jobs:
|
|||||||
echo ""
|
echo ""
|
||||||
done
|
done
|
||||||
|
|
||||||
test_resize_last:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build
|
|
||||||
container: ${{env.TEST_IMAGE}}:${{github.sha}}
|
|
||||||
steps:
|
|
||||||
- name: Run test
|
|
||||||
id: test
|
|
||||||
timeout-minutes: 3
|
|
||||||
run: /root/vitastor/tests/test_resize_last.sh
|
|
||||||
- name: Print logs
|
|
||||||
if: always() && steps.test.outcome == 'failure'
|
|
||||||
run: |
|
|
||||||
for i in /root/vitastor/testdata/*.log /root/vitastor/testdata/*.txt; do
|
|
||||||
echo "-------- $i --------"
|
|
||||||
cat $i
|
|
||||||
echo ""
|
|
||||||
done
|
|
||||||
|
|
||||||
test_resize_auto:
|
test_resize_auto:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: build
|
needs: build
|
||||||
@@ -1584,24 +1584,6 @@ jobs:
|
|||||||
echo ""
|
echo ""
|
||||||
done
|
done
|
||||||
|
|
||||||
test_old_resize_last:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build
|
|
||||||
container: ${{env.TEST_IMAGE}}:${{github.sha}}
|
|
||||||
steps:
|
|
||||||
- name: Run test
|
|
||||||
id: test
|
|
||||||
timeout-minutes: 3
|
|
||||||
run: OLD=1 /root/vitastor/tests/test_resize_last.sh
|
|
||||||
- name: Print logs
|
|
||||||
if: always() && steps.test.outcome == 'failure'
|
|
||||||
run: |
|
|
||||||
for i in /root/vitastor/testdata/*.log /root/vitastor/testdata/*.txt; do
|
|
||||||
echo "-------- $i --------"
|
|
||||||
cat $i
|
|
||||||
echo ""
|
|
||||||
done
|
|
||||||
|
|
||||||
test_old_resize_auto:
|
test_old_resize_auto:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: build
|
needs: build
|
||||||
@@ -2160,3 +2142,39 @@ jobs:
|
|||||||
echo ""
|
echo ""
|
||||||
done
|
done
|
||||||
|
|
||||||
|
test_write_encrypted:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
|
container: ${{env.TEST_IMAGE}}:${{github.sha}}
|
||||||
|
steps:
|
||||||
|
- name: Run test
|
||||||
|
id: test
|
||||||
|
timeout-minutes: 3
|
||||||
|
run: /root/vitastor/tests/test_write_encrypted.sh
|
||||||
|
- name: Print logs
|
||||||
|
if: always() && steps.test.outcome == 'failure'
|
||||||
|
run: |
|
||||||
|
for i in /root/vitastor/testdata/*.log /root/vitastor/testdata/*.txt; do
|
||||||
|
echo "-------- $i --------"
|
||||||
|
cat $i
|
||||||
|
echo ""
|
||||||
|
done
|
||||||
|
|
||||||
|
test_write_encrypted_ec:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
|
container: ${{env.TEST_IMAGE}}:${{github.sha}}
|
||||||
|
steps:
|
||||||
|
- name: Run test
|
||||||
|
id: test
|
||||||
|
timeout-minutes: 3
|
||||||
|
run: SCHEME=ec /root/vitastor/tests/test_write_encrypted.sh
|
||||||
|
- name: Print logs
|
||||||
|
if: always() && steps.test.outcome == 'failure'
|
||||||
|
run: |
|
||||||
|
for i in /root/vitastor/testdata/*.log /root/vitastor/testdata/*.txt; do
|
||||||
|
echo "-------- $i --------"
|
||||||
|
cat $i
|
||||||
|
echo ""
|
||||||
|
done
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,14 @@ for my $line (<>)
|
|||||||
{
|
{
|
||||||
$test_name .= '_antietcd';
|
$test_name .= '_antietcd';
|
||||||
}
|
}
|
||||||
|
elsif ($1 eq 'ETCD_SCHEME' && $2 eq 'https')
|
||||||
|
{
|
||||||
|
$test_name .= '_https';
|
||||||
|
}
|
||||||
|
elsif ($1 eq 'ENCRYPTED')
|
||||||
|
{
|
||||||
|
$test_name .= '_encrypted';
|
||||||
|
}
|
||||||
elsif ($1 eq 'OLD')
|
elsif ($1 eq 'OLD')
|
||||||
{
|
{
|
||||||
$test_name =~ s/^test_/test_old_/s;
|
$test_name =~ s/^test_/test_old_/s;
|
||||||
|
|||||||
@@ -3,3 +3,4 @@
|
|||||||
package-lock.json
|
package-lock.json
|
||||||
fio
|
fio
|
||||||
qemu
|
qemu
|
||||||
|
node_modules
|
||||||
|
|||||||
+7
-7
@@ -1,20 +1,20 @@
|
|||||||
cmake_minimum_required(VERSION 2.8...3.30)
|
cmake_minimum_required(VERSION 2.8.12)
|
||||||
|
|
||||||
project(vitastor)
|
project(vitastor)
|
||||||
|
|
||||||
set(VITASTOR_VERSION "3.0.15")
|
set(VITASTOR_VERSION "3.0.5")
|
||||||
|
|
||||||
include(CTest)
|
include(CTest)
|
||||||
|
|
||||||
add_custom_target(build_tests)
|
add_custom_target(build_tests)
|
||||||
set_property(TEST PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_CURRENT_BINARY_DIR}/lsan-suppress.txt)
|
add_custom_target(test
|
||||||
add_test(gen_lsan_suppress
|
COMMAND
|
||||||
${CMAKE_COMMAND} -E echo leak:tcmalloc > "${CMAKE_CURRENT_BINARY_DIR}/lsan-suppress.txt"
|
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)
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ Vitastor поддерживает QEMU-драйвер, протоколы UBLK,
|
|||||||
- [Дисковые параметры OSD](docs/config/layout-osd.ru.md)
|
- [Дисковые параметры OSD](docs/config/layout-osd.ru.md)
|
||||||
- [Прочие параметры OSD](docs/config/osd.ru.md)
|
- [Прочие параметры OSD](docs/config/osd.ru.md)
|
||||||
- [Параметры мониторов](docs/config/monitor.ru.md)
|
- [Параметры мониторов](docs/config/monitor.ru.md)
|
||||||
|
- [Безопасность](docs/config/security.ru.md)
|
||||||
- [Настройки пулов](docs/config/pool.ru.md)
|
- [Настройки пулов](docs/config/pool.ru.md)
|
||||||
- [Метаданные образов в etcd](docs/config/inode.ru.md)
|
- [Метаданные образов в etcd](docs/config/inode.ru.md)
|
||||||
- Использование
|
- Использование
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ Read more details in the documentation. You can start from here: [Quick Start](d
|
|||||||
- [OSD Disk Layout](docs/config/layout-osd.en.md)
|
- [OSD Disk Layout](docs/config/layout-osd.en.md)
|
||||||
- [OSD Runtime Parameters](docs/config/osd.en.md)
|
- [OSD Runtime Parameters](docs/config/osd.en.md)
|
||||||
- [Monitor](docs/config/monitor.en.md)
|
- [Monitor](docs/config/monitor.en.md)
|
||||||
|
- [Security](docs/config/security.en.md)
|
||||||
- [Pool configuration](docs/config/pool.en.md)
|
- [Pool configuration](docs/config/pool.en.md)
|
||||||
- [Image metadata in etcd](docs/config/inode.en.md)
|
- [Image metadata in etcd](docs/config/inode.en.md)
|
||||||
- Usage
|
- Usage
|
||||||
|
|||||||
+1
-1
Submodule cpp-btree updated: 431d2e1d35...8de8b467ac
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
VITASTOR_VERSION ?= v3.0.15
|
VITASTOR_VERSION ?= v3.0.5
|
||||||
|
|
||||||
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.15
|
image: vitalif/vitastor-csi:v3.0.5
|
||||||
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.15
|
image: vitalif/vitastor-csi:v3.0.5
|
||||||
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.15"
|
vitastorCSIDriverVersion = "3.0.5"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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.15-1) unstable; urgency=medium
|
vitastor (3.0.5-1) unstable; urgency=medium
|
||||||
|
|
||||||
* Bugfixes
|
* Bugfixes
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
@@ -3,7 +3,7 @@ Section: admin
|
|||||||
Priority: optional
|
Priority: optional
|
||||||
Maintainer: Vitaliy Filippov <vitalif@yourcmc.ru>
|
Maintainer: Vitaliy Filippov <vitalif@yourcmc.ru>
|
||||||
Build-Depends: debhelper, g++ (>= 8), libstdc++6 (>= 8),
|
Build-Depends: debhelper, g++ (>= 8), libstdc++6 (>= 8),
|
||||||
linux-libc-dev, libgoogle-perftools-dev, libjerasure-dev, libgf-complete-dev,
|
linux-libc-dev, libgoogle-perftools-dev, libjerasure-dev, libgf-complete-dev, libc-ares-dev,
|
||||||
libibverbs-dev, librdmacm-dev, libisal-dev, cmake, pkg-config, libnl-3-dev, libnl-genl-3-dev,
|
libibverbs-dev, librdmacm-dev, libisal-dev, cmake, pkg-config, libnl-3-dev, libnl-genl-3-dev,
|
||||||
node-bindings <!nocheck>, node-gyp, node-nan
|
node-bindings <!nocheck>, node-gyp, node-nan
|
||||||
Standards-Version: 4.5.0
|
Standards-Version: 4.5.0
|
||||||
|
|||||||
Vendored
-1
@@ -11,7 +11,6 @@ override_dh_install:
|
|||||||
cp -v node-binding/package.json node-binding/index.js node-binding/addon.cc node-binding/addon.h node-binding/client.cc node-binding/client.h debian/tmp/usr/lib/x86_64-linux-gnu/nodejs/vitastor
|
cp -v node-binding/package.json node-binding/index.js node-binding/addon.cc node-binding/addon.h node-binding/client.cc node-binding/client.h debian/tmp/usr/lib/x86_64-linux-gnu/nodejs/vitastor
|
||||||
cp -v node-binding/build/Release/addon.node debian/tmp/usr/lib/x86_64-linux-gnu/nodejs/vitastor/build/Release
|
cp -v node-binding/build/Release/addon.node debian/tmp/usr/lib/x86_64-linux-gnu/nodejs/vitastor/build/Release
|
||||||
dh_install
|
dh_install
|
||||||
cd debian/vitastor-mon/usr/lib/vitastor/mon && npm install --production
|
|
||||||
|
|
||||||
override_dh_installdeb:
|
override_dh_installdeb:
|
||||||
cat debian/fio_version >> debian/vitastor-fio.substvars
|
cat debian/fio_version >> debian/vitastor-fio.substvars
|
||||||
|
|||||||
Vendored
+7
-1
@@ -37,8 +37,14 @@ rm -rf a b
|
|||||||
|
|
||||||
echo "dep:fio=$FIO" > debian/fio_version
|
echo "dep:fio=$FIO" > debian/fio_version
|
||||||
|
|
||||||
|
cd /root/vitastor/packages/vitastor-$REL/vitastor-$VER
|
||||||
|
mkdir mon/node_modules
|
||||||
|
cd mon/node_modules
|
||||||
|
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
|
||||||
|
|
||||||
cd /root/vitastor/packages/vitastor-$REL
|
cd /root/vitastor/packages/vitastor-$REL
|
||||||
if [[ ( "$REL" = "trixie" || "$REL" = "resolute" ) && -e ../vitastor-bookworm/vitastor_$VER.orig.tar.xz ]]; then
|
if [[ "$REL" = "trixie" && -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
|
||||||
|
|||||||
Vendored
+1
-1
@@ -25,7 +25,7 @@ RUN set -e -x; \
|
|||||||
echo 'APT::Install-Suggests false;' >> /etc/apt/apt.conf
|
echo 'APT::Install-Suggests false;' >> /etc/apt/apt.conf
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get -y install fio libgoogle-perftools-dev devscripts libjerasure-dev cmake \
|
apt-get -y install fio libgoogle-perftools-dev devscripts libjerasure-dev cmake libc-ares-dev \
|
||||||
libibverbs-dev librdmacm-dev libisal-dev libnl-3-dev libnl-genl-3-dev curl nodejs npm node-nan node-bindings && \
|
libibverbs-dev librdmacm-dev libisal-dev libnl-3-dev libnl-genl-3-dev curl nodejs npm node-nan node-bindings && \
|
||||||
apt-get -y build-dep fio && \
|
apt-get -y build-dep fio && \
|
||||||
apt-get --download-only source fio
|
apt-get --download-only source fio
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
VITASTOR_VERSION ?= v3.0.15
|
VITASTOR_VERSION ?= v3.0.5
|
||||||
|
|
||||||
all: build push
|
all: build push
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
# Desired Vitastor version
|
# Desired Vitastor version
|
||||||
VITASTOR_VERSION=v3.0.15
|
VITASTOR_VERSION=v3.0.5
|
||||||
|
|
||||||
# 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
|
||||||
|
|||||||
@@ -38,3 +38,4 @@ In the future, additional configuration methods may be added:
|
|||||||
- [OSD Disk Layout](config/layout-osd.en.md)
|
- [OSD Disk Layout](config/layout-osd.en.md)
|
||||||
- [OSD Runtime Parameters](config/osd.en.md)
|
- [OSD Runtime Parameters](config/osd.en.md)
|
||||||
- [Monitor](config/monitor.en.md)
|
- [Monitor](config/monitor.en.md)
|
||||||
|
- [Security Parameters](config/security.en.md)
|
||||||
|
|||||||
@@ -41,3 +41,4 @@
|
|||||||
- [Дисковые параметры OSD](config/layout-osd.ru.md)
|
- [Дисковые параметры OSD](config/layout-osd.ru.md)
|
||||||
- [Прочие параметры OSD](config/osd.ru.md)
|
- [Прочие параметры OSD](config/osd.ru.md)
|
||||||
- [Параметры мониторов](config/monitor.ru.md)
|
- [Параметры мониторов](config/monitor.ru.md)
|
||||||
|
- [Параметры безопасности](config/security.ru.md)
|
||||||
|
|||||||
@@ -198,8 +198,14 @@ put a modified value into etcd key /vitastor/config/global.
|
|||||||
- Type: string
|
- Type: string
|
||||||
- Default: none
|
- Default: none
|
||||||
|
|
||||||
Data checksum type to use. May be "crc32c" or "none". Set to "crc32c" to
|
Data and metadata checksum type to use. May be "crc32c", "xxh3_32" or "none".
|
||||||
enable data checksums.
|
Select crc32c or xxh3_32 and set csum_block_size to enable data checksums.
|
||||||
|
|
||||||
|
Both crc32c and xxh3_32 are almost equally fast, xxh3_32 is safer. xxh3_32 is
|
||||||
|
the xxhash3 algorithm truncated from 64 to 32 bits (which is still a good hash).
|
||||||
|
|
||||||
|
Note that enabled data checksums either increase memory usage or reduce
|
||||||
|
performance. Check details in [csum_block_size](#csum_block_size) description.
|
||||||
|
|
||||||
## csum_block_size
|
## csum_block_size
|
||||||
|
|
||||||
|
|||||||
@@ -209,8 +209,12 @@ journal_block_size и meta_block_size. Однако на данный момен
|
|||||||
- Тип: строка
|
- Тип: строка
|
||||||
- Значение по умолчанию: none
|
- Значение по умолчанию: none
|
||||||
|
|
||||||
Тип используемых OSD контрольных сумм данных. Может быть "crc32c" или "none".
|
Тип используемых OSD контрольных сумм данных и метаданных. Может быть "crc32c",
|
||||||
Установите в "crc32c", чтобы включить расчёт и проверку контрольных сумм данных.
|
"xxh3_32" или "none". Выберите crc32c или xxh3_32 и установите csum_block_size,
|
||||||
|
чтобы включить контрольные суммы данных.
|
||||||
|
|
||||||
|
И crc32c, и xxh3_32 примерно одинаково быстры, xxh3_32 надёжней. xxh3_32 - это
|
||||||
|
алгоритм xxhash3, обрезанный с 64 до 32 бит (это всё равно хороший хеш).
|
||||||
|
|
||||||
Следует понимать, что контрольные суммы в зависимости от размера блока их
|
Следует понимать, что контрольные суммы в зависимости от размера блока их
|
||||||
расчёта либо увеличивают потребление памяти, либо снижают производительность.
|
расчёта либо увеличивают потребление памяти, либо снижают производительность.
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ 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
|
||||||
|
|
||||||
@@ -754,9 +753,3 @@ 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,7 +71,6 @@
|
|||||||
- [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
|
||||||
|
|
||||||
@@ -794,9 +793,3 @@ pg_minsize OSD во время переключений, что может по
|
|||||||
- Значение по умолчанию: 100
|
- Значение по умолчанию: 100
|
||||||
|
|
||||||
Данная опция задаёт интервал между обработкой двух порций изменения числа PG пулов.
|
Данная опция задаёт интервал между обработкой двух порций изменения числа PG пулов.
|
||||||
|
|
||||||
## gc_on_start
|
|
||||||
|
|
||||||
- Тип: булево (да/нет)
|
|
||||||
|
|
||||||
Принудительно очищать все мусорные записи в новом хранилище при каждом запуске OSD.
|
|
||||||
|
|||||||
@@ -0,0 +1,150 @@
|
|||||||
|
[Documentation](../../README.md#documentation) → [Configuration](../config.en.md) → Security Parameters
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
[Читать на русском](security.ru.md)
|
||||||
|
|
||||||
|
# Security Parameters
|
||||||
|
|
||||||
|
These parameters affect your Vitastor installation security and apply to OSDs, monitors and clients.
|
||||||
|
|
||||||
|
Most of them can be set in /etc/vitastor/vitastor.conf and in etcd, but don't support online modification.
|
||||||
|
|
||||||
|
- [etcd_client_cert](#etcd_client_cert)
|
||||||
|
- [etcd_client_key](#etcd_client_key)
|
||||||
|
- [etcd_ca](#etcd_ca)
|
||||||
|
- [osd_etcd_client_cert](#osd_etcd_client_cert)
|
||||||
|
- [osd_etcd_client_key](#osd_etcd_client_key)
|
||||||
|
- [mon_etcd_client_cert](#mon_etcd_client_cert)
|
||||||
|
- [mon_etcd_client_key](#mon_etcd_client_key)
|
||||||
|
- [vault_url](#vault_url)
|
||||||
|
- [vault_secret_api_path](#vault_secret_api_path)
|
||||||
|
- [vault_client_cert](#vault_client_cert)
|
||||||
|
- [vault_client_key](#vault_client_key)
|
||||||
|
- [vault_ca](#vault_ca)
|
||||||
|
- [vault_timeout_ms](#vault_timeout_ms)
|
||||||
|
- [vault_error_timeout_sec](#vault_error_timeout_sec)
|
||||||
|
- [vault_refresh_leeway_sec](#vault_refresh_leeway_sec)
|
||||||
|
- [max_aes_xts_pool_size](#max_aes_xts_pool_size)
|
||||||
|
|
||||||
|
## etcd_client_cert
|
||||||
|
|
||||||
|
- Type: string
|
||||||
|
|
||||||
|
Client TLS certificate to use for Vitastor client (not OSD and not monitor)
|
||||||
|
etcd https connections. May be path to a file or just a PEM string with certificate.
|
||||||
|
In the latter case, string must begin with "-----BEGIN CERTIFICATE-----".
|
||||||
|
|
||||||
|
## etcd_client_key
|
||||||
|
|
||||||
|
- Type: string
|
||||||
|
|
||||||
|
Private key for etcd_client_cert (also a file or a PEM string).
|
||||||
|
|
||||||
|
## etcd_ca
|
||||||
|
|
||||||
|
- Type: string
|
||||||
|
|
||||||
|
Trusted TLS CA to verify etcd server certificate. May be path to a file,
|
||||||
|
directory or just a PEM string with certificate.
|
||||||
|
|
||||||
|
## osd_etcd_client_cert
|
||||||
|
|
||||||
|
- Type: string
|
||||||
|
|
||||||
|
Same as [etcd_client_cert](#etcd_client_cert), but only for OSDs.
|
||||||
|
OSDs, clients and monitors should have different permissions, so they should
|
||||||
|
use different certificates.
|
||||||
|
|
||||||
|
## osd_etcd_client_key
|
||||||
|
|
||||||
|
- Type: string
|
||||||
|
|
||||||
|
Same as [etcd_client_key](#etcd_client_key), but only for OSDs.
|
||||||
|
|
||||||
|
## mon_etcd_client_cert
|
||||||
|
|
||||||
|
- Type: string
|
||||||
|
|
||||||
|
Same as [etcd_client_cert](#etcd_client_cert), but only for Vitastor monitors.
|
||||||
|
|
||||||
|
## mon_etcd_client_key
|
||||||
|
|
||||||
|
- Type: string
|
||||||
|
|
||||||
|
Same as [etcd_client_key](#etcd_client_key), but only for Vitastor monitors.
|
||||||
|
|
||||||
|
## vault_url
|
||||||
|
|
||||||
|
- Type: string
|
||||||
|
|
||||||
|
Vault base URL.
|
||||||
|
|
||||||
|
Vitastor clients support AES-256-XTS image data encryption with different per-image keys.
|
||||||
|
Encryption is performed by the client, OSDs don't have access to decrypted data.
|
||||||
|
|
||||||
|
Encryption keys may be stored in etcd or, for the increased security level, in an external
|
||||||
|
[HashiCorp Vault](https://developer.hashicorp.com/vault/) or [OpenBao](https://openbao.org/)
|
||||||
|
instance.
|
||||||
|
|
||||||
|
Vitastor clients use [v1 k/v secrets engine](https://openbao.org/api-docs/secret/kv/kv-v1/)
|
||||||
|
and [TLS authentication engine](https://openbao.org/api-docs/auth/cert/) in Vault.
|
||||||
|
|
||||||
|
In that case, only key IDs are stored in etcd.
|
||||||
|
|
||||||
|
## vault_secret_api_path
|
||||||
|
|
||||||
|
- Type: string
|
||||||
|
- Default: /v1/secret/
|
||||||
|
|
||||||
|
Vault v1 secret API mount path to use.
|
||||||
|
|
||||||
|
## vault_client_cert
|
||||||
|
|
||||||
|
- Type: string
|
||||||
|
|
||||||
|
Client TLS certificate to use for Vault connections. Just like [etcd_client_cert](#etcd_client_cert),
|
||||||
|
may be path to a file or just a certificate in PEM string.
|
||||||
|
|
||||||
|
## vault_client_key
|
||||||
|
|
||||||
|
- Type: string
|
||||||
|
|
||||||
|
Private key for vault_client_cert (also a file or a PEM string).
|
||||||
|
|
||||||
|
## vault_ca
|
||||||
|
|
||||||
|
- Type: string
|
||||||
|
|
||||||
|
Trusted TLS CA to verify Vault server certificate. May be path to a file,
|
||||||
|
directory or just a PEM string with certificate.
|
||||||
|
|
||||||
|
## vault_timeout_ms
|
||||||
|
|
||||||
|
- Type: integer
|
||||||
|
- Default: 5000
|
||||||
|
|
||||||
|
Timeout for Vault requests in milliseconds.
|
||||||
|
|
||||||
|
## vault_error_timeout_sec
|
||||||
|
|
||||||
|
- Type: integer
|
||||||
|
- Default: 60
|
||||||
|
|
||||||
|
Time (in seconds) to wait before retrying after receiving an error from Vault.
|
||||||
|
|
||||||
|
## vault_refresh_leeway_sec
|
||||||
|
|
||||||
|
- Type: integer
|
||||||
|
- Default: 60
|
||||||
|
|
||||||
|
Extra time (in seconds) before real Vault token lease_timeout to refresh it, just
|
||||||
|
in case of system clock drift.
|
||||||
|
|
||||||
|
## max_aes_xts_pool_size
|
||||||
|
|
||||||
|
- Type: integer
|
||||||
|
- Default: 256
|
||||||
|
|
||||||
|
Maximum number of OpenSSL encryption contexts cached in OSD memory. Probably
|
||||||
|
doesn't require modification.
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
[Документация](../../README-ru.md#документация) → [Конфигурация](../config.ru.md) → Параметры безопасности
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
[Read in English](security.en.md)
|
||||||
|
|
||||||
|
# Параметры безопасности
|
||||||
|
|
||||||
|
Данные параметры затрагивают безопасность инсталляций Vitastor и используются
|
||||||
|
OSD, мониторами и клиентами.
|
||||||
|
|
||||||
|
Большая их часть может задаваться в /etc/vitastor/vitastor.conf и в etcd, но не
|
||||||
|
поддерживает онлайн-изменение.
|
||||||
|
|
||||||
|
- [etcd_client_cert](#etcd_client_cert)
|
||||||
|
- [etcd_client_key](#etcd_client_key)
|
||||||
|
- [etcd_ca](#etcd_ca)
|
||||||
|
- [osd_etcd_client_cert](#osd_etcd_client_cert)
|
||||||
|
- [osd_etcd_client_key](#osd_etcd_client_key)
|
||||||
|
- [mon_etcd_client_cert](#mon_etcd_client_cert)
|
||||||
|
- [mon_etcd_client_key](#mon_etcd_client_key)
|
||||||
|
- [vault_url](#vault_url)
|
||||||
|
- [vault_secret_api_path](#vault_secret_api_path)
|
||||||
|
- [vault_client_cert](#vault_client_cert)
|
||||||
|
- [vault_client_key](#vault_client_key)
|
||||||
|
- [vault_ca](#vault_ca)
|
||||||
|
- [vault_timeout_ms](#vault_timeout_ms)
|
||||||
|
- [vault_error_timeout_sec](#vault_error_timeout_sec)
|
||||||
|
- [vault_refresh_leeway_sec](#vault_refresh_leeway_sec)
|
||||||
|
- [max_aes_xts_pool_size](#max_aes_xts_pool_size)
|
||||||
|
|
||||||
|
## etcd_client_cert
|
||||||
|
|
||||||
|
- Тип: строка
|
||||||
|
|
||||||
|
Клиентский TLS сертификат для https-подключений к etcd для клиентов Vitastor
|
||||||
|
(не OSD и не мониторов). Может быть путём к файлу или просто строкой с
|
||||||
|
сертификатом в формате PEM. В последнем случае строка должна начинаться с
|
||||||
|
"-----BEGIN CERTIFICATE-----".
|
||||||
|
|
||||||
|
## etcd_client_key
|
||||||
|
|
||||||
|
- Тип: строка
|
||||||
|
|
||||||
|
Закрытый ключ для сертификата etcd_client_cert (также путь к файлу или PEM строка).
|
||||||
|
|
||||||
|
## etcd_ca
|
||||||
|
|
||||||
|
- Тип: строка
|
||||||
|
|
||||||
|
Доверенный корневой TLS-сертификат для проверки сертификата сервера etcd.
|
||||||
|
Может быть путём к файлу, директории или просто строкой с сертификатом в
|
||||||
|
формате PEM.
|
||||||
|
|
||||||
|
## osd_etcd_client_cert
|
||||||
|
|
||||||
|
- Тип: строка
|
||||||
|
|
||||||
|
Аналогично [etcd_client_cert](#etcd_client_cert), но только для OSD.
|
||||||
|
OSD, клиенты и мониторы должны иметь разные привилегии, поэтому они должны
|
||||||
|
использовать разные сертификаты.
|
||||||
|
|
||||||
|
## osd_etcd_client_key
|
||||||
|
|
||||||
|
- Тип: строка
|
||||||
|
|
||||||
|
Аналогично [etcd_client_key](#etcd_client_key), но только для OSD.
|
||||||
|
|
||||||
|
## mon_etcd_client_cert
|
||||||
|
|
||||||
|
- Тип: строка
|
||||||
|
|
||||||
|
Аналогично [etcd_client_cert](#etcd_client_cert), но только для мониторов Vitastor.
|
||||||
|
|
||||||
|
## mon_etcd_client_key
|
||||||
|
|
||||||
|
- Тип: строка
|
||||||
|
|
||||||
|
Аналогично [etcd_client_key](#etcd_client_key), но только для мониторов Vitastor.
|
||||||
|
|
||||||
|
## vault_url
|
||||||
|
|
||||||
|
- Тип: строка
|
||||||
|
|
||||||
|
Базовый адрес Vault.
|
||||||
|
|
||||||
|
Клиенты Vitastor поддерживают AES-256-XTS шифрование данных образов с отдельными ключами на
|
||||||
|
каждый образ. Данные шифруются клиентами, OSD не имеют доступа к незашифрованным данным.
|
||||||
|
|
||||||
|
Ключи шифрования могут храниться в etcd или, для повышенного уровня безопасности, во внешнем
|
||||||
|
[HashiCorp Vault](https://developer.hashicorp.com/vault/) или [OpenBao](https://openbao.org/).
|
||||||
|
|
||||||
|
Клиенты Vitastor используют [движок секретов v1](https://openbao.org/api-docs/secret/kv/kv-v1/)
|
||||||
|
и [TLS-аутентификацию](https://openbao.org/api-docs/auth/cert/) в Vault.
|
||||||
|
|
||||||
|
В этом случае, только ID ключей хранятся в etcd.
|
||||||
|
|
||||||
|
## vault_secret_api_path
|
||||||
|
|
||||||
|
- Тип: строка
|
||||||
|
- Значение по умолчанию: /v1/secret/
|
||||||
|
|
||||||
|
Путь к API секретов v1 для использования клиентами.
|
||||||
|
|
||||||
|
## vault_client_cert
|
||||||
|
|
||||||
|
- Тип: строка
|
||||||
|
|
||||||
|
Клиентский TLS сертификат для подключений к Vault. Как и [etcd_client_cert](#etcd_client_cert),
|
||||||
|
может быть путём к файлу или просто PEM-строкой с сертификатом.
|
||||||
|
|
||||||
|
## vault_client_key
|
||||||
|
|
||||||
|
- Тип: строка
|
||||||
|
|
||||||
|
Закрытый ключ для сертификата vault_client_cert (также путь к файлу или PEM строка).
|
||||||
|
|
||||||
|
## vault_ca
|
||||||
|
|
||||||
|
- Тип: строка
|
||||||
|
|
||||||
|
Доверенный корневой TLS-сертификат для проверки сертификата сервера Vault.
|
||||||
|
Может быть путём к файлу, директории или просто строкой с сертификатом в
|
||||||
|
формате PEM.
|
||||||
|
|
||||||
|
## vault_timeout_ms
|
||||||
|
|
||||||
|
- Тип: целое число
|
||||||
|
- Значение по умолчанию: 5000
|
||||||
|
|
||||||
|
Максимально время выполнения Vault-запросов в миллисекундах.
|
||||||
|
|
||||||
|
## vault_error_timeout_sec
|
||||||
|
|
||||||
|
- Тип: целое число
|
||||||
|
- Значение по умолчанию: 60
|
||||||
|
|
||||||
|
Время (в секундах) для ожидания перед повторной попыткой при получении ошибки от Vault.
|
||||||
|
|
||||||
|
## vault_refresh_leeway_sec
|
||||||
|
|
||||||
|
- Тип: целое число
|
||||||
|
- Значение по умолчанию: 60
|
||||||
|
|
||||||
|
Зазор времени (в секундах), чтобы обновлять токены Vault чуть раньше их реального
|
||||||
|
lease_timeout, на случай "ухода" системных часов.
|
||||||
|
|
||||||
|
## max_aes_xts_pool_size
|
||||||
|
|
||||||
|
- Тип: целое число
|
||||||
|
- Значение по умолчанию: 256
|
||||||
|
|
||||||
|
Максимальное количество кэшируемых в памяти OSD контекстов шифрования OpenSSL.
|
||||||
|
Вряд ли требует изменения.
|
||||||
@@ -44,6 +44,8 @@
|
|||||||
|
|
||||||
{{../../config/monitor.en.md|indent=2}}
|
{{../../config/monitor.en.md|indent=2}}
|
||||||
|
|
||||||
|
{{../../config/security.en.md|indent=2}}
|
||||||
|
|
||||||
{{../../config/pool.en.md|indent=2}}
|
{{../../config/pool.en.md|indent=2}}
|
||||||
|
|
||||||
{{../../config/inode.en.md|indent=2}}
|
{{../../config/inode.en.md|indent=2}}
|
||||||
|
|||||||
@@ -44,6 +44,8 @@
|
|||||||
|
|
||||||
{{../../config/monitor.ru.md|indent=2}}
|
{{../../config/monitor.ru.md|indent=2}}
|
||||||
|
|
||||||
|
{{../../config/security.ru.md|indent=2}}
|
||||||
|
|
||||||
{{../../config/pool.ru.md|indent=2}}
|
{{../../config/pool.ru.md|indent=2}}
|
||||||
|
|
||||||
{{../../config/inode.ru.md|indent=2}}
|
{{../../config/inode.ru.md|indent=2}}
|
||||||
|
|||||||
@@ -233,11 +233,21 @@
|
|||||||
type: string
|
type: string
|
||||||
default: none
|
default: none
|
||||||
info: |
|
info: |
|
||||||
Data checksum type to use. May be "crc32c" or "none". Set to "crc32c" to
|
Data and metadata checksum type to use. May be "crc32c", "xxh3_32" or "none".
|
||||||
enable data checksums.
|
Select crc32c or xxh3_32 and set csum_block_size to enable data checksums.
|
||||||
|
|
||||||
|
Both crc32c and xxh3_32 are almost equally fast, xxh3_32 is safer. xxh3_32 is
|
||||||
|
the xxhash3 algorithm truncated from 64 to 32 bits (which is still a good hash).
|
||||||
|
|
||||||
|
Note that enabled data checksums either increase memory usage or reduce
|
||||||
|
performance. Check details in [csum_block_size](#csum_block_size) description.
|
||||||
info_ru: |
|
info_ru: |
|
||||||
Тип используемых OSD контрольных сумм данных. Может быть "crc32c" или "none".
|
Тип используемых OSD контрольных сумм данных и метаданных. Может быть "crc32c",
|
||||||
Установите в "crc32c", чтобы включить расчёт и проверку контрольных сумм данных.
|
"xxh3_32" или "none". Выберите crc32c или xxh3_32 и установите csum_block_size,
|
||||||
|
чтобы включить контрольные суммы данных.
|
||||||
|
|
||||||
|
И crc32c, и xxh3_32 примерно одинаково быстры, xxh3_32 надёжней. xxh3_32 - это
|
||||||
|
алгоритм xxhash3, обрезанный с 64 до 32 бит (это всё равно хороший хеш).
|
||||||
|
|
||||||
Следует понимать, что контрольные суммы в зависимости от размера блока их
|
Следует понимать, что контрольные суммы в зависимости от размера блока их
|
||||||
расчёта либо увеличивают потребление памяти, либо снижают производительность.
|
расчёта либо увеличивают потребление памяти, либо снижают производительность.
|
||||||
|
|||||||
@@ -938,7 +938,3 @@
|
|||||||
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.
|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"yaml": "^2.8.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# Security Parameters
|
||||||
|
|
||||||
|
These parameters affect your Vitastor installation security and apply to OSDs, monitors and clients.
|
||||||
|
|
||||||
|
Most of them can be set in /etc/vitastor/vitastor.conf and in etcd, but don't support online modification.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Параметры безопасности
|
||||||
|
|
||||||
|
Данные параметры затрагивают безопасность инсталляций Vitastor и используются
|
||||||
|
OSD, мониторами и клиентами.
|
||||||
|
|
||||||
|
Большая их часть может задаваться в /etc/vitastor/vitastor.conf и в etcd, но не
|
||||||
|
поддерживает онлайн-изменение.
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
- name: etcd_client_cert
|
||||||
|
type: string
|
||||||
|
info: |
|
||||||
|
Client TLS certificate to use for Vitastor client (not OSD and not monitor)
|
||||||
|
etcd https connections. May be path to a file or just a PEM string with certificate.
|
||||||
|
In the latter case, string must begin with "-----BEGIN CERTIFICATE-----".
|
||||||
|
info_ru: |
|
||||||
|
Клиентский TLS сертификат для https-подключений к etcd для клиентов Vitastor
|
||||||
|
(не OSD и не мониторов). Может быть путём к файлу или просто строкой с
|
||||||
|
сертификатом в формате PEM. В последнем случае строка должна начинаться с
|
||||||
|
"-----BEGIN CERTIFICATE-----".
|
||||||
|
- name: etcd_client_key
|
||||||
|
type: string
|
||||||
|
info: Private key for etcd_client_cert (also a file or a PEM string).
|
||||||
|
info_ru: Закрытый ключ для сертификата etcd_client_cert (также путь к файлу или PEM строка).
|
||||||
|
- name: etcd_ca
|
||||||
|
type: string
|
||||||
|
info: |
|
||||||
|
Trusted TLS CA to verify etcd server certificate. May be path to a file,
|
||||||
|
directory or just a PEM string with certificate.
|
||||||
|
info_ru: |
|
||||||
|
Доверенный корневой TLS-сертификат для проверки сертификата сервера etcd.
|
||||||
|
Может быть путём к файлу, директории или просто строкой с сертификатом в
|
||||||
|
формате PEM.
|
||||||
|
- name: osd_etcd_client_cert
|
||||||
|
type: string
|
||||||
|
info: |
|
||||||
|
Same as [etcd_client_cert](#etcd_client_cert), but only for OSDs.
|
||||||
|
OSDs, clients and monitors should have different permissions, so they should
|
||||||
|
use different certificates.
|
||||||
|
info_ru: |
|
||||||
|
Аналогично [etcd_client_cert](#etcd_client_cert), но только для OSD.
|
||||||
|
OSD, клиенты и мониторы должны иметь разные привилегии, поэтому они должны
|
||||||
|
использовать разные сертификаты.
|
||||||
|
- name: osd_etcd_client_key
|
||||||
|
type: string
|
||||||
|
info: Same as [etcd_client_key](#etcd_client_key), but only for OSDs.
|
||||||
|
info_ru: Аналогично [etcd_client_key](#etcd_client_key), но только для OSD.
|
||||||
|
- name: mon_etcd_client_cert
|
||||||
|
type: string
|
||||||
|
info: Same as [etcd_client_cert](#etcd_client_cert), but only for Vitastor monitors.
|
||||||
|
info_ru: Аналогично [etcd_client_cert](#etcd_client_cert), но только для мониторов Vitastor.
|
||||||
|
- name: mon_etcd_client_key
|
||||||
|
type: string
|
||||||
|
info: Same as [etcd_client_key](#etcd_client_key), but only for Vitastor monitors.
|
||||||
|
info_ru: Аналогично [etcd_client_key](#etcd_client_key), но только для мониторов Vitastor.
|
||||||
|
- name: vault_url
|
||||||
|
type: string
|
||||||
|
info: |
|
||||||
|
Vault base URL.
|
||||||
|
|
||||||
|
Vitastor clients support AES-256-XTS image data encryption with different per-image keys.
|
||||||
|
Encryption is performed by the client, OSDs don't have access to decrypted data.
|
||||||
|
|
||||||
|
Encryption keys may be stored in etcd or, for the increased security level, in an external
|
||||||
|
[HashiCorp Vault](https://developer.hashicorp.com/vault/) or [OpenBao](https://openbao.org/)
|
||||||
|
instance.
|
||||||
|
|
||||||
|
Vitastor clients use [v1 k/v secrets engine](https://openbao.org/api-docs/secret/kv/kv-v1/)
|
||||||
|
and [TLS authentication engine](https://openbao.org/api-docs/auth/cert/) in Vault.
|
||||||
|
|
||||||
|
In that case, only key IDs are stored in etcd.
|
||||||
|
info_ru: |
|
||||||
|
Базовый адрес Vault.
|
||||||
|
|
||||||
|
Клиенты Vitastor поддерживают AES-256-XTS шифрование данных образов с отдельными ключами на
|
||||||
|
каждый образ. Данные шифруются клиентами, OSD не имеют доступа к незашифрованным данным.
|
||||||
|
|
||||||
|
Ключи шифрования могут храниться в etcd или, для повышенного уровня безопасности, во внешнем
|
||||||
|
[HashiCorp Vault](https://developer.hashicorp.com/vault/) или [OpenBao](https://openbao.org/).
|
||||||
|
|
||||||
|
Клиенты Vitastor используют [движок секретов v1](https://openbao.org/api-docs/secret/kv/kv-v1/)
|
||||||
|
и [TLS-аутентификацию](https://openbao.org/api-docs/auth/cert/) в Vault.
|
||||||
|
|
||||||
|
В этом случае, только ID ключей хранятся в etcd.
|
||||||
|
- name: vault_secret_api_path
|
||||||
|
type: string
|
||||||
|
default: /v1/secret/
|
||||||
|
info: Vault v1 secret API mount path to use.
|
||||||
|
info_ru: Путь к API секретов v1 для использования клиентами.
|
||||||
|
- name: vault_client_cert
|
||||||
|
type: string
|
||||||
|
info: |
|
||||||
|
Client TLS certificate to use for Vault connections. Just like [etcd_client_cert](#etcd_client_cert),
|
||||||
|
may be path to a file or just a certificate in PEM string.
|
||||||
|
info_ru: |
|
||||||
|
Клиентский TLS сертификат для подключений к Vault. Как и [etcd_client_cert](#etcd_client_cert),
|
||||||
|
может быть путём к файлу или просто PEM-строкой с сертификатом.
|
||||||
|
- name: vault_client_key
|
||||||
|
type: string
|
||||||
|
info: Private key for vault_client_cert (also a file or a PEM string).
|
||||||
|
info_ru: Закрытый ключ для сертификата vault_client_cert (также путь к файлу или PEM строка).
|
||||||
|
- name: vault_ca
|
||||||
|
type: string
|
||||||
|
info: |
|
||||||
|
Trusted TLS CA to verify Vault server certificate. May be path to a file,
|
||||||
|
directory or just a PEM string with certificate.
|
||||||
|
info_ru: |
|
||||||
|
Доверенный корневой TLS-сертификат для проверки сертификата сервера Vault.
|
||||||
|
Может быть путём к файлу, директории или просто строкой с сертификатом в
|
||||||
|
формате PEM.
|
||||||
|
- name: vault_timeout_ms
|
||||||
|
type: int
|
||||||
|
default: 5000
|
||||||
|
info: Timeout for Vault requests in milliseconds.
|
||||||
|
info_ru: Максимально время выполнения Vault-запросов в миллисекундах.
|
||||||
|
- name: vault_error_timeout_sec
|
||||||
|
type: int
|
||||||
|
default: 60
|
||||||
|
info: |
|
||||||
|
Time (in seconds) to wait before retrying after receiving an error from Vault.
|
||||||
|
info_ru: |
|
||||||
|
Время (в секундах) для ожидания перед повторной попыткой при получении ошибки от Vault.
|
||||||
|
- name: vault_refresh_leeway_sec
|
||||||
|
type: int
|
||||||
|
default: 60
|
||||||
|
info: |
|
||||||
|
Extra time (in seconds) before real Vault token lease_timeout to refresh it, just
|
||||||
|
in case of system clock drift.
|
||||||
|
info_ru: |
|
||||||
|
Зазор времени (в секундах), чтобы обновлять токены Vault чуть раньше их реального
|
||||||
|
lease_timeout, на случай "ухода" системных часов.
|
||||||
|
- name: max_aes_xts_pool_size
|
||||||
|
type: int
|
||||||
|
default: 256
|
||||||
|
info: |
|
||||||
|
Maximum number of OpenSSL encryption contexts cached in OSD memory. Probably
|
||||||
|
doesn't require modification.
|
||||||
|
info_ru: |
|
||||||
|
Максимальное количество кэшируемых в памяти OSD контекстов шифрования OpenSSL.
|
||||||
|
Вряд ли требует изменения.
|
||||||
@@ -26,9 +26,9 @@ at Vitastor Kubernetes operator: https://github.com/Antilles7227/vitastor-operat
|
|||||||
The instruction is very simple.
|
The instruction is very simple.
|
||||||
|
|
||||||
1. Download a Docker image of the desired version: \
|
1. Download a Docker image of the desired version: \
|
||||||
`docker pull vitalif/vitastor:v3.0.15`
|
`docker pull vitalif/vitastor:v3.0.5`
|
||||||
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.15 install.sh`
|
`docker run --rm -it -v /etc:/host-etc -v /usr/bin:/host-bin vitalif/vitastor:v3.0.5 install.sh`
|
||||||
3. Reload udev rules: \
|
3. Reload udev rules: \
|
||||||
`udevadm control --reload-rules`
|
`udevadm control --reload-rules`
|
||||||
4. Enable the vitastor-host service: \
|
4. Enable the vitastor-host service: \
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ Vitastor можно установить в Docker/Podman. При этом etcd,
|
|||||||
Инструкция по установке максимально простая.
|
Инструкция по установке максимально простая.
|
||||||
|
|
||||||
1. Скачайте Docker-образ желаемой версии: \
|
1. Скачайте Docker-образ желаемой версии: \
|
||||||
`docker pull vitalif/vitastor:v3.0.15`
|
`docker pull vitalif/vitastor:v3.0.5`
|
||||||
2. Установите скрипты в хост-систему командой: \
|
2. Установите скрипты в хост-систему командой: \
|
||||||
`docker run --rm -it -v /etc:/host-etc -v /usr/bin:/host-bin vitalif/vitastor:v3.0.15 install.sh`
|
`docker run --rm -it -v /etc:/host-etc -v /usr/bin:/host-bin vitalif/vitastor:v3.0.5 install.sh`
|
||||||
3. Перезагрузите правила udev: \
|
3. Перезагрузите правила udev: \
|
||||||
`udevadm control --reload-rules`
|
`udevadm control --reload-rules`
|
||||||
4. Включите сервис vitastor-host: \
|
4. Включите сервис vitastor-host: \
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
- 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,7 +17,6 @@
|
|||||||
- 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`:
|
||||||
|
|||||||
@@ -15,8 +15,9 @@
|
|||||||
- gcc and g++ 8 or newer, clang 10 or newer, or other compiler with C++11 plus
|
- gcc and g++ 8 or newer, clang 10 or newer, or other compiler with C++11 plus
|
||||||
designated initializers support from C++20
|
designated initializers support from C++20
|
||||||
- CMake
|
- CMake
|
||||||
- jerasure headers and libraries
|
- jerasure, c-ares headers and libraries
|
||||||
- ISA-L, libibverbs, librdmacm, libnl3 headers and libraries (optional)
|
- ISA-L, libibverbs, librdmacm, libnl3 headers and libraries (optional)
|
||||||
|
- tcmalloc (google-perftools-dev)
|
||||||
|
|
||||||
## Basic instructions
|
## Basic instructions
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,9 @@
|
|||||||
- gcc и g++ >= 8, либо clang >= 10, либо другой компилятор с поддержкой C++11 плюс
|
- gcc и g++ >= 8, либо clang >= 10, либо другой компилятор с поддержкой C++11 плюс
|
||||||
назначенных инициализаторов (designated initializers) из C++20
|
назначенных инициализаторов (designated initializers) из C++20
|
||||||
- CMake
|
- CMake
|
||||||
- Заголовки и библиотеки jerasure
|
- Заголовки и библиотеки jerasure, c-ares
|
||||||
- Опционально - заголовки и библиотеки ISA-L, libibverbs, librdmacm, libnl3
|
- Опционально - заголовки и библиотеки ISA-L, libibverbs, librdmacm, libnl3
|
||||||
|
- tcmalloc (google-perftools-dev)
|
||||||
|
|
||||||
## Базовая инструкция
|
## Базовая инструкция
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,8 @@
|
|||||||
- [Built-in Prometheus metric exporter](../config/monitor.en.md#enable_prometheus)
|
- [Built-in Prometheus metric exporter](../config/monitor.en.md#enable_prometheus)
|
||||||
- [NFS RDMA support](../usage/nfs.en.md#rdma) (probably also usable for GPUDirect)
|
- [NFS RDMA support](../usage/nfs.en.md#rdma) (probably also usable for GPUDirect)
|
||||||
- [S3](../installation/s3.en.md)
|
- [S3](../installation/s3.en.md)
|
||||||
|
- [TLS support for etcd connections](../config/security.en.md)
|
||||||
|
- [AES-256-XTS image encryption](../usage/cli.en.md#create) and [Vault support](../config/security.en.md#vault_url) for key storage
|
||||||
|
|
||||||
## Plugins and tools
|
## Plugins and tools
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,8 @@
|
|||||||
- [Встроенный Prometheus-экспортер метрик](../config/monitor.ru.md#enable_prometheus)
|
- [Встроенный Prometheus-экспортер метрик](../config/monitor.ru.md#enable_prometheus)
|
||||||
- [Поддержка NFS RDMA](../usage/nfs.ru.md#rdma) (вероятно, также подходящая для GPUDirect)
|
- [Поддержка NFS RDMA](../usage/nfs.ru.md#rdma) (вероятно, также подходящая для GPUDirect)
|
||||||
- [S3](../installation/s3.ru.md)
|
- [S3](../installation/s3.ru.md)
|
||||||
|
- [Поддержка TLS-соединений с etcd](../config/security.ru.md)
|
||||||
|
- [AES-256-XTS шифрование данных](../usage/cli.ru.md#create) и [поддержка Vault](../config/security.ru.md#vault_url) для хранения ключей
|
||||||
|
|
||||||
## Драйверы и инструменты
|
## Драйверы и инструменты
|
||||||
|
|
||||||
|
|||||||
+21
-7
@@ -125,18 +125,31 @@ bench-kaveri kaveri 10 G 10 G 0 B/s 0 0 0 us 0 B/s 0
|
|||||||
|
|
||||||
## create
|
## create
|
||||||
|
|
||||||
`vitastor-cli create -s|--size <size> [-p|--pool <id|name>] [--parent <parent_name>[@<snapshot>]] <name>`
|
`vitastor-cli create -s|--size SIZE [OPTIONS] <name>`
|
||||||
|
|
||||||
Create an image. You may use K/M/G/T suffixes for `<size>`. If `--parent` is specified,
|
Create an image. Options:
|
||||||
a copy-on-write image clone is created. Parent must be a snapshot (readonly image).
|
|
||||||
Pool must be specified if there is more than one pool.
|
* `-s|--size SIZE` - New image size in bytes or with a K/M/G/T unit suffix.
|
||||||
|
* `-p|--pool POOL` - Specify pool for the new image (may be omitted if there is only 1 pool).
|
||||||
|
* `--parent PARENT` - Create a copy-on-write image clone based on PARENT (or PARENT@SNAPSHOT).
|
||||||
|
If parent is not a snapshot, it must be a read-only image.
|
||||||
|
* `--enc-key random` - Generate a new random AES-256-XTS encryption key for the new image.
|
||||||
|
* `--enc-key HEX` - Set a specified AES-256-XTS key (64 bytes in hex) for the new image.
|
||||||
|
* `--enc-key vault:ID` - Use an encryption key from an external Vault secret with specified ID.
|
||||||
|
|
||||||
```
|
```
|
||||||
vitastor-cli create --snapshot <snapshot> [-p|--pool <id|name>] <image>
|
vitastor-cli create --snapshot <snapshot> [OPTIONS] <image>
|
||||||
vitastor-cli snap-create [-p|--pool <id|name>] <image>@<snapshot>
|
vitastor-cli snap-create [OPTIONS] <image>@<snapshot>
|
||||||
```
|
```
|
||||||
|
|
||||||
Create a snapshot of image `<name>` (either form can be used). May be used live if only a single writer is active.
|
Create a snapshot of image `<image>`. May be used live if only a single writer is active.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
|
||||||
|
* `-p|--pool POOL` - Move image to pool POOL, leaving the snapshot in the old pool.
|
||||||
|
* `--enc-key random` - Change image encryption key to a new random AES-256-XTS key.
|
||||||
|
* `--enc-key KEY` - Change image encryption key to a specified key, Vault key or to an empty key.
|
||||||
|
By default, the image retains its old encryption key when taking a snapshot.
|
||||||
|
|
||||||
See also about [how to export snapshots](qemu.en.md#exporting-snapshots).
|
See also about [how to export snapshots](qemu.en.md#exporting-snapshots).
|
||||||
|
|
||||||
@@ -151,6 +164,7 @@ You should resize file system in the image, if present, before shrinking it.
|
|||||||
* `--deleted 1|0` - Set/clear 'deleted image' flag (set automatically during unfinished deletes).
|
* `--deleted 1|0` - Set/clear 'deleted image' flag (set automatically during unfinished deletes).
|
||||||
* `-f|--force` - Proceed with shrinking or setting readwrite flag even if the image has children.
|
* `-f|--force` - Proceed with shrinking or setting readwrite flag even if the image has children.
|
||||||
* `--down-ok` - Proceed with shrinking even if some data will be left on unavailable OSDs.
|
* `--down-ok` - Proceed with shrinking even if some data will be left on unavailable OSDs.
|
||||||
|
* `--enc-key HEX` - Change image encryption key (allowed only with `--force`).
|
||||||
|
|
||||||
## dd
|
## dd
|
||||||
|
|
||||||
|
|||||||
+22
-8
@@ -127,19 +127,32 @@ bench-kaveri kaveri 10 G 10 G 0 B/s 0 0 0 us 0 B/s 0
|
|||||||
|
|
||||||
## create
|
## create
|
||||||
|
|
||||||
`vitastor-cli create -s|--size <size> [-p|--pool <id|name>] [--parent <parent_name>[@<snapshot>]] <name>`
|
`vitastor-cli create -s|--size SIZE [ОПЦИИ] <name>`
|
||||||
|
|
||||||
Создать образ. Для размера `<size>` можно использовать суффиксы K/M/G/T (килобайт-мегабайт-гигабайт-терабайт).
|
Создать образ. Опции:
|
||||||
Если указана опция `--parent`, создаётся клон образа. Родитель `<parent_name>[@<snapshot>]` должен быть
|
|
||||||
снимком (или просто немодифицируемым образом). Пул обязательно указывать, если в кластере больше одного пула.
|
* `-s|--size SIZE` - Размер нового образа в байтах или с суффиксом K/M/G/T (кило/мега/гига/терабайт).
|
||||||
|
* `-p|--pool POOL` - Создать образ в заданном пуле (можно не указывать, если пул всего один).
|
||||||
|
* `--parent PARENT` - Создать легковесный клон на основе образа `PARENT` или снимка `PARENT@SNAP`.
|
||||||
|
Если `PARENT` - не снимок, он должен быть помечен как образ только для чтения.
|
||||||
|
* `--enc-key random` - Сгенерировать случайный ключ шифрования AES-256-XTS для нового образа.
|
||||||
|
* `--enc-key HEX` - Установить заданный ключ AES-256-XTS (64 байта в hex) для нового образа.
|
||||||
|
* `--enc-key vault:ID` - Использовать ключ из внешнего секрета с заданным ID из Vault.
|
||||||
|
|
||||||
```
|
```
|
||||||
vitastor-cli create --snapshot <snapshot> [-p|--pool <id|name>] <image>
|
vitastor-cli create --snapshot <snapshot> [ОПЦИИ] <image>
|
||||||
vitastor-cli snap-create [-p|--pool <id|name>] <image>@<snapshot>
|
vitastor-cli snap-create [ОПЦИИ] <image>@<snapshot>
|
||||||
```
|
```
|
||||||
|
|
||||||
Создать снимок образа `<name>` (можно использовать любую форму команды). Снимок можно создавать без остановки
|
Создать снимок образа `<image>` (можно использовать любую форму команды).
|
||||||
клиентов, если пишущий клиент максимум 1.
|
Снимок можно создавать без остановки клиентов, если пишущих клиентов не больше одного.
|
||||||
|
|
||||||
|
Опции:
|
||||||
|
|
||||||
|
* `-p|--pool POOL` - Переместить образ в пул POOL, оставив снимок в старом пуле.
|
||||||
|
* `--enc-key random` - Изменить ключ шифрования образа на новый случайный ключ AES-256-XTS.
|
||||||
|
* `--enc-key KEY` - Изменить ключ шифрования образа на заданный ключ, ключ из Vault или пустой ключ.
|
||||||
|
По умолчанию шифрованные образы сохраняют старый ключ при снятии снимка.
|
||||||
|
|
||||||
Смотрите также информацию о том, [как экспортировать снимки](qemu.ru.md#экспорт-снимков).
|
Смотрите также информацию о том, [как экспортировать снимки](qemu.ru.md#экспорт-снимков).
|
||||||
|
|
||||||
@@ -156,6 +169,7 @@ vitastor-cli snap-create [-p|--pool <id|name>] <image>@<snapshot>
|
|||||||
* `--deleted 1|0` - Установить/снять флаг "образ удалён" (устанавливается при незавершённом удалении).
|
* `--deleted 1|0` - Установить/снять флаг "образ удалён" (устанавливается при незавершённом удалении).
|
||||||
* `-f|--force` - Разрешить уменьшение или перевод в чтение-запись образа, у которого есть клоны.
|
* `-f|--force` - Разрешить уменьшение или перевод в чтение-запись образа, у которого есть клоны.
|
||||||
* `--down-ok` - Разрешить уменьшение, даже если часть данных останется неудалённой на недоступных OSD.
|
* `--down-ok` - Разрешить уменьшение, даже если часть данных останется неудалённой на недоступных OSD.
|
||||||
|
* `--enc-key HEX` - Изменить ключ шифрования образа (разрешено только с `--force`).
|
||||||
|
|
||||||
## dd
|
## dd
|
||||||
|
|
||||||
|
|||||||
@@ -262,4 +262,3 @@ 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,4 +274,3 @@ VitastorFS из GPUDirect.
|
|||||||
| `--logfile <FILE>` | записывать логи в заданный файл |
|
| `--logfile <FILE>` | записывать логи в заданный файл |
|
||||||
| `--enforce 1` | проверять права доступа на стороне сервера (по умолчанию нет) |
|
| `--enforce 1` | проверять права доступа на стороне сервера (по умолчанию нет) |
|
||||||
| `--foreground 1` | не уходить в фон после запуска |
|
| `--foreground 1` | не уходить в фон после запуска |
|
||||||
| `--trace` | логгировать все запросы NFS |
|
|
||||||
|
|||||||
+1
-1
Submodule json11 updated: edcd85b8bd...fd37016cf8
+8
-16
@@ -27,17 +27,7 @@ class AntiEtcdAdapter
|
|||||||
is_local['::'] = true;
|
is_local['::'] = true;
|
||||||
is_local[''] = true;
|
is_local[''] = true;
|
||||||
// split :, 3 -> <schema>:<//ip>:<port>
|
// split :, 3 -> <schema>:<//ip>:<port>
|
||||||
const selected = [];
|
const selected = cluster.map(s => s.split(':', 3)).filter(ip => is_local[ip[1].substr(2)] && (!cfg_port || ip[2] == cfg_port));
|
||||||
for (let i = 0; i < cluster.length; i++)
|
|
||||||
{
|
|
||||||
const m = /^(https?:\/\/)?(?:\[(.*)\]|([^\[\:]+))(?::(\d+))?$/.exec(cluster[i]);
|
|
||||||
if (!m)
|
|
||||||
continue;
|
|
||||||
const ip = m[3] || m[2];
|
|
||||||
const port = m[4] || 2379;
|
|
||||||
if (is_local[ip] && (!cfg_port || port == cfg_port))
|
|
||||||
selected.push({ idx: i, ip, port });
|
|
||||||
}
|
|
||||||
if (selected.length > 1)
|
if (selected.length > 1)
|
||||||
{
|
{
|
||||||
console.error('More than 1 etcd_address matches local IPs, please specify port');
|
console.error('More than 1 etcd_address matches local IPs, please specify port');
|
||||||
@@ -46,16 +36,18 @@ class AntiEtcdAdapter
|
|||||||
else if (selected.length == 1)
|
else if (selected.length == 1)
|
||||||
{
|
{
|
||||||
const antietcd_config = {
|
const antietcd_config = {
|
||||||
ip: selected[0].ip,
|
ip: selected[0][1].substr(2),
|
||||||
port: selected[0].port,
|
port: selected[0][2],
|
||||||
data: config.antietcd_data_file || ((config.antietcd_data_dir || '/var/lib/vitastor') + '/mon_'+selected[0].port+'.json.gz'),
|
cert: config.antietcd_cert,
|
||||||
|
key: config.antietcd_key,
|
||||||
|
ca: config.etcd_ca,
|
||||||
|
data: config.antietcd_data_file || ((config.antietcd_data_dir || '/var/lib/vitastor') + '/mon_'+selected[0][2]+'.json.gz'),
|
||||||
persist_filter: vitastor_persist_filter({ vitastor_prefix: config.etcd_prefix || '/vitastor' }),
|
persist_filter: vitastor_persist_filter({ vitastor_prefix: config.etcd_prefix || '/vitastor' }),
|
||||||
node_id: cluster[selected[0].idx].replace(/^(https?:\/\/)/, ''), // same as in <cluster> below
|
node_id: selected[0][1].substr(2)+':'+selected[0][2], // node_id = ip:port
|
||||||
cluster: (cluster.length == 1 ? null : cluster.reduce((a, c) => { a[c.replace(/^(https?:\/\/)/, '')] = c; return a; }, {})),
|
cluster: (cluster.length == 1 ? null : cluster.reduce((a, c) => { a[c.replace(/^(https?:\/\/)/, '')] = c; return a; }, {})),
|
||||||
cluster_key: (config.etcd_prefix || '/vitastor'),
|
cluster_key: (config.etcd_prefix || '/vitastor'),
|
||||||
stale_read: 1,
|
stale_read: 1,
|
||||||
log_level: 1,
|
log_level: 1,
|
||||||
logs: { cluster: true },
|
|
||||||
};
|
};
|
||||||
for (const key in config)
|
for (const key in config)
|
||||||
{
|
{
|
||||||
|
|||||||
+27
-6
@@ -1,7 +1,9 @@
|
|||||||
// Copyright (c) Vitaliy Filippov, 2019+
|
// Copyright (c) Vitaliy Filippov, 2019+
|
||||||
// License: VNPL-1.1 (see README.md for details)
|
// License: VNPL-1.1 (see README.md for details)
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
const http = require('http');
|
const http = require('http');
|
||||||
|
const https = require('https');
|
||||||
const WebSocket = require('ws');
|
const WebSocket = require('ws');
|
||||||
const { b64, local_ips } = require('./utils.js');
|
const { b64, local_ips } = require('./utils.js');
|
||||||
|
|
||||||
@@ -15,11 +17,30 @@ class EtcdAdapter
|
|||||||
this.ws = null;
|
this.ws = null;
|
||||||
this.ws_alive = false;
|
this.ws_alive = false;
|
||||||
this.ws_keepalive_timer = null;
|
this.ws_keepalive_timer = null;
|
||||||
|
this.opts = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_config(config)
|
parse_config(config)
|
||||||
{
|
{
|
||||||
this.parse_etcd_addresses(config.etcd_address||config.etcd_url);
|
this.parse_etcd_addresses(config.etcd_address||config.etcd_url);
|
||||||
|
if (config.mon_etcd_client_cert || config.etcd_client_cert)
|
||||||
|
{
|
||||||
|
this.opts.cert = config.mon_etcd_client_cert || config.etcd_client_cert;
|
||||||
|
if (this.opts.cert.substr(0, 5) != '-----')
|
||||||
|
this.opts.cert = fs.readFileSync(this.opts.cert, { encoding: 'utf-8' });
|
||||||
|
}
|
||||||
|
if (config.mon_etcd_client_key || config.etcd_client_key)
|
||||||
|
{
|
||||||
|
this.opts.key = config.mon_etcd_client_key || config.etcd_client_key;
|
||||||
|
if (this.opts.key.substr(0, 5) != '-----')
|
||||||
|
this.opts.key = fs.readFileSync(this.opts.key, { encoding: 'utf-8' });
|
||||||
|
}
|
||||||
|
if (config.etcd_ca)
|
||||||
|
{
|
||||||
|
this.opts.ca = config.etcd_ca;
|
||||||
|
if (this.opts.ca.substr(0, 5) != '-----')
|
||||||
|
this.opts.ca = fs.readFileSync(this.opts.ca, { encoding: 'utf-8' });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_etcd_addresses(addrs)
|
parse_etcd_addresses(addrs)
|
||||||
@@ -39,7 +60,7 @@ class EtcdAdapter
|
|||||||
for (let url of addrs)
|
for (let url of addrs)
|
||||||
{
|
{
|
||||||
let scheme = 'http';
|
let scheme = 'http';
|
||||||
url = url.trim().replace(/^(https?):\/\//, (m, m1) => { scheme = m1; return ''; });
|
url = url.trim().replace(/^(https?):\/\//i, (m, m1) => { scheme = m1.toLowerCase(); return ''; });
|
||||||
const slash = url.indexOf('/');
|
const slash = url.indexOf('/');
|
||||||
const colon = url.indexOf(':');
|
const colon = url.indexOf(':');
|
||||||
const is_local = is_local_ip[colon >= 0 ? url.substr(0, colon) : (slash >= 0 ? url.substr(0, slash) : url)];
|
const is_local = is_local_ip[colon >= 0 ? url.substr(0, colon) : (slash >= 0 ? url.substr(0, slash) : url)];
|
||||||
@@ -130,7 +151,7 @@ class EtcdAdapter
|
|||||||
}
|
}
|
||||||
ok(false);
|
ok(false);
|
||||||
}, this.mon.config.etcd_mon_timeout);
|
}, this.mon.config.etcd_mon_timeout);
|
||||||
this.ws = new WebSocket(base+'/watch');
|
this.ws = new WebSocket(base+'/watch', this.opts);
|
||||||
this.ws_used_url = cur_addr;
|
this.ws_used_url = cur_addr;
|
||||||
const fail = () =>
|
const fail = () =>
|
||||||
{
|
{
|
||||||
@@ -272,7 +293,7 @@ class EtcdAdapter
|
|||||||
{
|
{
|
||||||
throw new Error(MON_STOPPED);
|
throw new Error(MON_STOPPED);
|
||||||
}
|
}
|
||||||
const res = await POST(base+path, body, timeout);
|
const res = await POST(base+path, body, timeout, this.opts);
|
||||||
if (this.mon.stopped)
|
if (this.mon.stopped)
|
||||||
{
|
{
|
||||||
throw new Error(MON_STOPPED);
|
throw new Error(MON_STOPPED);
|
||||||
@@ -298,7 +319,7 @@ class EtcdAdapter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function POST(url, body, timeout)
|
function POST(url, body, timeout, opts)
|
||||||
{
|
{
|
||||||
return new Promise(ok =>
|
return new Promise(ok =>
|
||||||
{
|
{
|
||||||
@@ -310,10 +331,10 @@ function POST(url, body, timeout)
|
|||||||
req = null;
|
req = null;
|
||||||
ok({ error: 'timeout' });
|
ok({ error: 'timeout' });
|
||||||
}, timeout) : null;
|
}, timeout) : null;
|
||||||
let req = http.request(url, { method: 'POST', headers: {
|
let req = (url.substr(0, 5) == 'https' ? https : http).request(url, { method: 'POST', headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Content-Length': body_text.length,
|
'Content-Length': body_text.length,
|
||||||
} }, (res) =>
|
}, ...(opts||{}) }, (res) =>
|
||||||
{
|
{
|
||||||
if (!req)
|
if (!req)
|
||||||
{
|
{
|
||||||
|
|||||||
+11
-1
@@ -45,7 +45,14 @@ const etcd_tree = {
|
|||||||
config_path: "/etc/vitastor/vitastor.conf",
|
config_path: "/etc/vitastor/vitastor.conf",
|
||||||
etcd_prefix: "/vitastor",
|
etcd_prefix: "/vitastor",
|
||||||
// etcd connection - configurable online
|
// etcd connection - configurable online
|
||||||
etcd_address: "10.0.115.10:2379/v3",
|
etcd_address: "http://10.0.115.10:2379/v3",
|
||||||
|
etcd_client_cert: "",
|
||||||
|
etcd_client_key: "",
|
||||||
|
osd_etcd_client_cert: "",
|
||||||
|
osd_etcd_client_key: "",
|
||||||
|
mon_etcd_client_cert: "",
|
||||||
|
mon_etcd_client_key: "",
|
||||||
|
etcd_ca: "",
|
||||||
// mon
|
// mon
|
||||||
etcd_mon_ttl: 5, // min: 1
|
etcd_mon_ttl: 5, // min: 1
|
||||||
etcd_mon_timeout: 1000, // ms. min: 0
|
etcd_mon_timeout: 1000, // ms. min: 0
|
||||||
@@ -217,6 +224,8 @@ const etcd_tree = {
|
|||||||
parent_id?: <inode_t>,
|
parent_id?: <inode_t>,
|
||||||
readonly?: boolean,
|
readonly?: boolean,
|
||||||
deleted?: boolean,
|
deleted?: boolean,
|
||||||
|
enc_key?: string,
|
||||||
|
meta?: any,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, */
|
}, */
|
||||||
@@ -383,6 +392,7 @@ const etcd_tree = {
|
|||||||
/* <name>: {
|
/* <name>: {
|
||||||
id: uint64_t,
|
id: uint64_t,
|
||||||
pool_id: uint64_t,
|
pool_id: uint64_t,
|
||||||
|
// ...plus a copy of everything from config/inode/x/y
|
||||||
}, */
|
}, */
|
||||||
},
|
},
|
||||||
maxid: {
|
maxid: {
|
||||||
|
|||||||
@@ -112,10 +112,9 @@ function make_cyclic(pgs, parity_space)
|
|||||||
{
|
{
|
||||||
if (parity_space > 1)
|
if (parity_space > 1)
|
||||||
{
|
{
|
||||||
for (const id in pgs)
|
for (const pg in pgs)
|
||||||
{
|
{
|
||||||
const pg = pgs[id];
|
for (let i = 1; i < pg.size; i++)
|
||||||
for (let i = 1; i < pg.length; i++)
|
|
||||||
{
|
{
|
||||||
const cyclic = [ ...pg.slice(i), ...pg.slice(0, i) ];
|
const cyclic = [ ...pg.slice(i), ...pg.slice(0, i) ];
|
||||||
pgs['pg_'+cyclic.join('_')] = cyclic;
|
pgs['pg_'+cyclic.join('_')] = cyclic;
|
||||||
|
|||||||
+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] = JSON.parse(JSON.stringify(this.state.pg.history[pool_id][pg]));
|
pg_history[pg-1] = 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();
|
||||||
}, (this.next_recheck_at-now)*1000);
|
}, now-this.next_recheck_at);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vitastor-mon",
|
"name": "vitastor-mon",
|
||||||
"version": "3.0.15",
|
"version": "3.0.5",
|
||||||
"description": "Vitastor SDS monitor service",
|
"description": "Vitastor SDS monitor service",
|
||||||
"main": "mon-main.js",
|
"main": "mon-main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
"author": "Vitaliy Filippov",
|
"author": "Vitaliy Filippov",
|
||||||
"license": "UNLICENSED",
|
"license": "UNLICENSED",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"antietcd": "^1.3.1",
|
"antietcd": "^1.2.4",
|
||||||
"sprintf-js": "^1.1.2",
|
"sprintf-js": "^1.1.2",
|
||||||
"ws": "^7.2.5"
|
"ws": "^7.2.5"
|
||||||
},
|
},
|
||||||
|
|||||||
+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] = JSON.parse(JSON.stringify(merged_history[1]));
|
new_pg_history[i] = { ...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,7 +37,6 @@ 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.15",
|
"version": "3.0.5",
|
||||||
"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": [
|
||||||
|
|||||||
+10
-45
@@ -366,38 +366,15 @@ sub map_volume
|
|||||||
my $prefix = defined $scfg->{vitastor_prefix} ? $scfg->{vitastor_prefix} : 'pve/';
|
my $prefix = defined $scfg->{vitastor_prefix} ? $scfg->{vitastor_prefix} : 'pve/';
|
||||||
|
|
||||||
my ($vtype, $img_name, $vmid) = $class->parse_volname($volname);
|
my ($vtype, $img_name, $vmid) = $class->parse_volname($volname);
|
||||||
my $name = $prefix.$img_name;
|
my $name = $img_name;
|
||||||
$name .= '@'.$snapname if $snapname;
|
$name .= '@'.$snapname if $snapname;
|
||||||
|
|
||||||
my $mapped = run_cli($scfg, [ 'ls' ], binary => '/usr/bin/vitastor-nbd');
|
my $mapped = run_cli($scfg, [ 'ls' ], binary => '/usr/bin/vitastor-nbd');
|
||||||
my ($kerneldev) = grep {
|
my ($kerneldev) = grep { $mapped->{$_}->{image} eq $prefix.$name } keys %$mapped;
|
||||||
$mapped->{$_} && $mapped->{$_}->{image} && $mapped->{$_}->{image} eq $name
|
return $kerneldev if $kerneldev && -b $kerneldev; # already mapped
|
||||||
} keys %$mapped;
|
|
||||||
|
|
||||||
if ($kerneldev && -b $kerneldev)
|
$kerneldev = run_cli($scfg, [ 'map', '--image', $prefix.$name ], binary => '/usr/bin/vitastor-nbd', json => 0);
|
||||||
{
|
return $kerneldev;
|
||||||
my $size = `/usr/sbin/blockdev --getsize64 $kerneldev`;
|
|
||||||
return $kerneldev if $size && $size > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
my $map_out = run_cli($scfg, [ 'map', '--image', $name ], binary => '/usr/bin/vitastor-nbd', json => 0);
|
|
||||||
$map_out =~ s/^\s+|\s+$//gso;
|
|
||||||
|
|
||||||
# Wait until the device is started
|
|
||||||
for (my $i = 0; $i < 100; $i++)
|
|
||||||
{
|
|
||||||
$mapped = run_cli($scfg, [ 'ls' ], binary => '/usr/bin/vitastor-nbd');
|
|
||||||
($kerneldev) = grep { $mapped->{$_} && $mapped->{$_}->{image} && $mapped->{$_}->{image} eq $name } keys %$mapped;
|
|
||||||
if ($kerneldev && -b $kerneldev)
|
|
||||||
{
|
|
||||||
my $size = `/usr/sbin/blockdev --getsize64 $kerneldev`;
|
|
||||||
return $kerneldev if $size && $size > 0;
|
|
||||||
}
|
|
||||||
select(undef, undef, undef, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
die "Failed to map Vitastor image $name via NBD".
|
|
||||||
($map_out ? ", vitastor-nbd map returned '$map_out'" : "")."\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub unmap_volume
|
sub unmap_volume
|
||||||
@@ -406,19 +383,13 @@ sub unmap_volume
|
|||||||
my $prefix = defined $scfg->{vitastor_prefix} ? $scfg->{vitastor_prefix} : 'pve/';
|
my $prefix = defined $scfg->{vitastor_prefix} ? $scfg->{vitastor_prefix} : 'pve/';
|
||||||
|
|
||||||
my ($vtype, $name, $vmid) = $class->parse_volname($volname);
|
my ($vtype, $name, $vmid) = $class->parse_volname($volname);
|
||||||
$name = $prefix.$name;
|
|
||||||
$name .= '@'.$snapname if $snapname;
|
$name .= '@'.$snapname if $snapname;
|
||||||
|
|
||||||
my $mapped = run_cli($scfg, [ 'ls' ], binary => '/usr/bin/vitastor-nbd');
|
my $mapped = run_cli($scfg, [ 'ls' ], binary => '/usr/bin/vitastor-nbd');
|
||||||
|
my ($kerneldev) = grep { $mapped->{$_}->{image} eq $prefix.$name } keys %$mapped;
|
||||||
my @kerneldevs = grep {
|
if ($kerneldev && -b $kerneldev)
|
||||||
$mapped->{$_} && $mapped->{$_}->{image} && $mapped->{$_}->{image} eq $name
|
|
||||||
} keys %$mapped;
|
|
||||||
|
|
||||||
for my $kerneldev (@kerneldevs)
|
|
||||||
{
|
{
|
||||||
next if !$kerneldev || !-b $kerneldev;
|
run_cli($scfg, [ 'unmap', $kerneldev ], binary => '/usr/bin/vitastor-nbd', json => 0);
|
||||||
eval { run_cli($scfg, [ 'unmap', $kerneldev ], binary => '/usr/bin/vitastor-nbd', json => 0); };
|
|
||||||
warn "Failed to unmap Vitastor image $name from $kerneldev: $@" if $@;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -434,13 +405,7 @@ sub activate_volume
|
|||||||
sub deactivate_volume
|
sub deactivate_volume
|
||||||
{
|
{
|
||||||
my ($class, $storeid, $scfg, $volname, $snapname, $cache) = @_;
|
my ($class, $storeid, $scfg, $volname, $snapname, $cache) = @_;
|
||||||
|
$class->unmap_volume($storeid, $scfg, $volname, $snapname) if $scfg->{vitastor_nbd};
|
||||||
# Even with vitastor_nbd=0, Proxmox may call map_volume() for special
|
|
||||||
# volumes like tpmstate0 because swtpm needs a local file/block path.
|
|
||||||
# Therefore, always try to unmap an existing NBD mapping here.
|
|
||||||
# unmap_volume() is a no-op if the volume is not currently mapped.
|
|
||||||
$class->unmap_volume($storeid, $scfg, $volname, $snapname);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.15'
|
VITASTOR_VERSION = '3.0.5'
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|||||||
@@ -1,637 +0,0 @@
|
|||||||
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,172 +1,29 @@
|
|||||||
diff --git a/block/meson.build b/block/meson.build
|
diff --git a/src/client/qemu_driver.c b/src/client/qemu_driver.c
|
||||||
index 34b1b2a306..24ca0f1e52 100644
|
index d8356dab..5f4cd50d 100644
|
||||||
--- a/block/meson.build
|
--- a/src/client/qemu_driver.c
|
||||||
+++ b/block/meson.build
|
+++ b/src/client/qemu_driver.c
|
||||||
@@ -114,6 +114,7 @@ foreach m : [
|
@@ -974,14 +974,21 @@ static void vitastor_co_read_bitmap_cb(void *opaque, long retval, uint8_t *bitma
|
||||||
[libnfs, 'nfs', files('nfs.c')],
|
#endif
|
||||||
[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
|
|
||||||
|
|
||||||
+vitastor = not_found
|
-static int coroutine_fn vitastor_co_block_status(
|
||||||
+if not get_option('vitastor').auto() or have_block
|
- BlockDriverState *bs, bool want_zero, int64_t offset, int64_t bytes,
|
||||||
+ libvitastor_client = cc.find_library('vitastor_client', has_headers: ['vitastor_c.h'],
|
- int64_t *pnum, int64_t *map, BlockDriverState **file)
|
||||||
+ required: get_option('vitastor'))
|
+static int coroutine_fn vitastor_co_block_status(BlockDriverState *bs,
|
||||||
+ if libvitastor_client.found()
|
+#if QEMU_VERSION_MAJOR > 10 || QEMU_VERSION_MAJOR == 10 && QEMU_VERSION_MINOR >= 1
|
||||||
+ if cc.links('''
|
+ unsigned int mode,
|
||||||
+ #include <vitastor_c.h>
|
+#else
|
||||||
+ int main(void) {
|
+ bool want_zero,
|
||||||
+ vitastor_c_create_qemu(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
+#endif
|
||||||
+ return 0;
|
+ int64_t offset, int64_t bytes, int64_t *pnum, int64_t *map, BlockDriverState **file)
|
||||||
+ }''', dependencies: libvitastor_client)
|
{
|
||||||
+ vitastor = declare_dependency(dependencies: libvitastor_client)
|
// Allocated => return BDRV_BLOCK_DATA|BDRV_BLOCK_OFFSET_VALID
|
||||||
+ elif get_option('vitastor').enabled()
|
// Not allocated => return 0
|
||||||
+ error('could not link libvitastor_client')
|
// Error => return -errno
|
||||||
+ else
|
// Set pnum to length of the extent, `*map` = `offset`, `*file` = `bs`
|
||||||
+ warning('could not link libvitastor_client, disabling')
|
+#if QEMU_VERSION_MAJOR > 10 || QEMU_VERSION_MAJOR == 10 && QEMU_VERSION_MINOR >= 1
|
||||||
+ endif
|
+ int want_zero = (mode == BDRV_WANT_PRECISE);
|
||||||
+ endif
|
+#endif
|
||||||
+endif
|
VitastorRPC task;
|
||||||
+
|
VitastorClient *client = bs->opaque;
|
||||||
glusterfs = not_found
|
uint64_t inode = client->watch ? vitastor_c_inode_get_num(client->watch) : client->inode;
|
||||||
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 ;;
|
|
||||||
|
|||||||
@@ -1,172 +0,0 @@
|
|||||||
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 ;;
|
|
||||||
@@ -11,7 +11,7 @@ WORKDIR /root
|
|||||||
RUN sed -i 's/enabled=0/enabled=1/' /etc/yum.repos.d/*.repo
|
RUN sed -i 's/enabled=0/enabled=1/' /etc/yum.repos.d/*.repo
|
||||||
RUN dnf -y install epel-release dnf-plugins-core
|
RUN dnf -y install epel-release dnf-plugins-core
|
||||||
RUN dnf -y install https://vitastor.io/rpms/centos/10/vitastor-release-1.0-1.el10.noarch.rpm
|
RUN dnf -y install https://vitastor.io/rpms/centos/10/vitastor-release-1.0-1.el10.noarch.rpm
|
||||||
RUN dnf -y install gcc-c++ gperftools-devel fio nodejs rpm-build jerasure-devel isa-l-devel gf-complete-devel rdma-core-devel cmake libnl3-devel
|
RUN dnf -y install gcc-c++ gperftools-devel fio nodejs rpm-build jerasure-devel isa-l-devel gf-complete-devel rdma-core-devel cmake libnl3-devel c-ares-devel
|
||||||
RUN dnf download --source fio
|
RUN dnf download --source fio
|
||||||
RUN rpm --nomd5 -i fio*.src.rpm
|
RUN rpm --nomd5 -i fio*.src.rpm
|
||||||
RUN cd ~/rpmbuild/SPECS && dnf builddep -y --spec fio.spec
|
RUN cd ~/rpmbuild/SPECS && dnf builddep -y --spec fio.spec
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
Name: vitastor
|
Name: vitastor
|
||||||
Version: 3.0.15
|
Version: 3.0.5
|
||||||
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.15.el10.tar.gz
|
Source0: vitastor-3.0.5.el10.tar.gz
|
||||||
|
|
||||||
BuildRequires: gperftools-devel
|
BuildRequires: gperftools-devel
|
||||||
BuildRequires: gcc-c++
|
BuildRequires: gcc-c++
|
||||||
@@ -16,6 +16,7 @@ BuildRequires: gf-complete-devel
|
|||||||
BuildRequires: rdma-core-devel
|
BuildRequires: rdma-core-devel
|
||||||
BuildRequires: cmake
|
BuildRequires: cmake
|
||||||
BuildRequires: libnl3-devel
|
BuildRequires: libnl3-devel
|
||||||
|
BuildRequires: c-ares-devel
|
||||||
Requires: vitastor-osd = %{version}-%{release}
|
Requires: vitastor-osd = %{version}-%{release}
|
||||||
Requires: vitastor-mon = %{version}-%{release}
|
Requires: vitastor-mon = %{version}-%{release}
|
||||||
Requires: vitastor-client = %{version}-%{release}
|
Requires: vitastor-client = %{version}-%{release}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ RUN yum -y --enablerepo=extras install centos-release-scl epel-release yum-utils
|
|||||||
RUN perl -i -pe 's!mirrorlist=!#mirrorlist=!s; s!#\s*baseurl=http://mirror.centos.org!baseurl=http://vault.centos.org!' /etc/yum.repos.d/CentOS-SCLo-scl*.repo
|
RUN perl -i -pe 's!mirrorlist=!#mirrorlist=!s; s!#\s*baseurl=http://mirror.centos.org!baseurl=http://vault.centos.org!' /etc/yum.repos.d/CentOS-SCLo-scl*.repo
|
||||||
RUN yum -y install https://vitastor.io/rpms/centos/7/vitastor-release-1.0-1.el7.noarch.rpm
|
RUN yum -y install https://vitastor.io/rpms/centos/7/vitastor-release-1.0-1.el7.noarch.rpm
|
||||||
RUN yum -y install devtoolset-9-gcc-c++ devtoolset-9-libatomic-devel gcc make cmake gperftools-devel \
|
RUN yum -y install devtoolset-9-gcc-c++ devtoolset-9-libatomic-devel gcc make cmake gperftools-devel \
|
||||||
fio rh-nodejs12 jerasure-devel libisa-l-devel gf-complete-devel rdma-core-devel libnl3-devel
|
fio rh-nodejs12 jerasure-devel libisa-l-devel gf-complete-devel rdma-core-devel libnl3-devel c-ares-devel
|
||||||
RUN yumdownloader --disablerepo=centos-sclo-rh --source fio
|
RUN yumdownloader --disablerepo=centos-sclo-rh --source fio
|
||||||
RUN rpm --nomd5 -i fio*.src.rpm
|
RUN rpm --nomd5 -i fio*.src.rpm
|
||||||
RUN rm -f /etc/yum.repos.d/CentOS-Media.repo
|
RUN rm -f /etc/yum.repos.d/CentOS-Media.repo
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
Name: vitastor
|
Name: vitastor
|
||||||
Version: 3.0.15
|
Version: 3.0.5
|
||||||
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.15.el7.tar.gz
|
Source0: vitastor-3.0.5.el7.tar.gz
|
||||||
|
|
||||||
BuildRequires: gperftools-devel
|
BuildRequires: gperftools-devel
|
||||||
BuildRequires: devtoolset-9-gcc-c++
|
BuildRequires: devtoolset-9-gcc-c++
|
||||||
@@ -17,6 +17,7 @@ BuildRequires: gf-complete-devel
|
|||||||
BuildRequires: rdma-core-devel
|
BuildRequires: rdma-core-devel
|
||||||
BuildRequires: cmake3
|
BuildRequires: cmake3
|
||||||
BuildRequires: libnl3-devel
|
BuildRequires: libnl3-devel
|
||||||
|
BuildRequires: c-ares-devel
|
||||||
Requires: vitastor-osd = %{version}-%{release}
|
Requires: vitastor-osd = %{version}-%{release}
|
||||||
Requires: vitastor-mon = %{version}-%{release}
|
Requires: vitastor-mon = %{version}-%{release}
|
||||||
Requires: vitastor-client = %{version}-%{release}
|
Requires: vitastor-client = %{version}-%{release}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ RUN dnf -y install centos-release-advanced-virtualization epel-release dnf-plugi
|
|||||||
RUN sed -i 's/^mirrorlist=/#mirrorlist=/; s!#baseurl=.*!baseurl=http://vault.centos.org/centos/8.4.2105/virt/$basearch/$avdir/!; s!^baseurl=.*Source/.*!baseurl=http://vault.centos.org/centos/8.4.2105/virt/Source/advanced-virtualization/!' /etc/yum.repos.d/CentOS-Advanced-Virtualization.repo
|
RUN sed -i 's/^mirrorlist=/#mirrorlist=/; s!#baseurl=.*!baseurl=http://vault.centos.org/centos/8.4.2105/virt/$basearch/$avdir/!; s!^baseurl=.*Source/.*!baseurl=http://vault.centos.org/centos/8.4.2105/virt/Source/advanced-virtualization/!' /etc/yum.repos.d/CentOS-Advanced-Virtualization.repo
|
||||||
RUN yum -y install https://vitastor.io/rpms/centos/8/vitastor-release-1.0-1.el8.noarch.rpm
|
RUN yum -y install https://vitastor.io/rpms/centos/8/vitastor-release-1.0-1.el8.noarch.rpm
|
||||||
RUN dnf -y install gcc-toolset-9 gcc-toolset-9-gcc-c++ gperftools-devel \
|
RUN dnf -y install gcc-toolset-9 gcc-toolset-9-gcc-c++ gperftools-devel \
|
||||||
fio nodejs rpm-build jerasure-devel libisa-l-devel gf-complete-devel libibverbs-devel libarchive cmake libnl3-devel
|
fio nodejs rpm-build jerasure-devel libisa-l-devel gf-complete-devel libibverbs-devel libarchive cmake libnl3-devel c-ares-devel
|
||||||
RUN dnf download --source fio
|
RUN dnf download --source fio
|
||||||
RUN rpm --nomd5 -i fio*.src.rpm
|
RUN rpm --nomd5 -i fio*.src.rpm
|
||||||
RUN cd ~/rpmbuild/SPECS && dnf builddep -y --enablerepo=powertools --spec fio.spec
|
RUN cd ~/rpmbuild/SPECS && dnf builddep -y --enablerepo=powertools --spec fio.spec
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
Name: vitastor
|
Name: vitastor
|
||||||
Version: 3.0.15
|
Version: 3.0.5
|
||||||
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.15.el8.tar.gz
|
Source0: vitastor-3.0.5.el8.tar.gz
|
||||||
|
|
||||||
BuildRequires: gperftools-devel
|
BuildRequires: gperftools-devel
|
||||||
BuildRequires: gcc-toolset-9-gcc-c++
|
BuildRequires: gcc-toolset-9-gcc-c++
|
||||||
@@ -16,6 +16,7 @@ BuildRequires: gf-complete-devel
|
|||||||
BuildRequires: rdma-core-devel
|
BuildRequires: rdma-core-devel
|
||||||
BuildRequires: cmake
|
BuildRequires: cmake
|
||||||
BuildRequires: libnl3-devel
|
BuildRequires: libnl3-devel
|
||||||
|
BuildRequires: c-ares-devel
|
||||||
Requires: vitastor-osd = %{version}-%{release}
|
Requires: vitastor-osd = %{version}-%{release}
|
||||||
Requires: vitastor-mon = %{version}-%{release}
|
Requires: vitastor-mon = %{version}-%{release}
|
||||||
Requires: vitastor-client = %{version}-%{release}
|
Requires: vitastor-client = %{version}-%{release}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ WORKDIR /root
|
|||||||
RUN sed -i 's/enabled=0/enabled=1/' /etc/yum.repos.d/*.repo
|
RUN sed -i 's/enabled=0/enabled=1/' /etc/yum.repos.d/*.repo
|
||||||
RUN dnf -y install epel-release dnf-plugins-core
|
RUN dnf -y install epel-release dnf-plugins-core
|
||||||
RUN dnf -y install https://vitastor.io/rpms/centos/9/vitastor-release-1.0-1.el9.noarch.rpm
|
RUN dnf -y install https://vitastor.io/rpms/centos/9/vitastor-release-1.0-1.el9.noarch.rpm
|
||||||
RUN dnf -y install gcc-c++ gperftools-devel fio nodejs rpm-build jerasure-devel libisa-l-devel gf-complete-devel rdma-core-devel libarchive cmake libnl3-devel
|
RUN dnf -y install gcc-c++ gperftools-devel fio nodejs rpm-build jerasure-devel libisa-l-devel gf-complete-devel rdma-core-devel libarchive cmake libnl3-devel c-ares-devel
|
||||||
RUN dnf download --source fio
|
RUN dnf download --source fio
|
||||||
RUN rpm --nomd5 -i fio*.src.rpm
|
RUN rpm --nomd5 -i fio*.src.rpm
|
||||||
RUN cd ~/rpmbuild/SPECS && dnf builddep -y --spec fio.spec
|
RUN cd ~/rpmbuild/SPECS && dnf builddep -y --spec fio.spec
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
Name: vitastor
|
Name: vitastor
|
||||||
Version: 3.0.15
|
Version: 3.0.5
|
||||||
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.15.el9.tar.gz
|
Source0: vitastor-3.0.5.el9.tar.gz
|
||||||
|
|
||||||
BuildRequires: gperftools-devel
|
BuildRequires: gperftools-devel
|
||||||
BuildRequires: gcc-c++
|
BuildRequires: gcc-c++
|
||||||
@@ -16,6 +16,7 @@ BuildRequires: gf-complete-devel
|
|||||||
BuildRequires: rdma-core-devel
|
BuildRequires: rdma-core-devel
|
||||||
BuildRequires: cmake
|
BuildRequires: cmake
|
||||||
BuildRequires: libnl3-devel
|
BuildRequires: libnl3-devel
|
||||||
|
BuildRequires: c-ares-devel
|
||||||
Requires: vitastor-osd = %{version}-%{release}
|
Requires: vitastor-osd = %{version}-%{release}
|
||||||
Requires: vitastor-mon = %{version}-%{release}
|
Requires: vitastor-mon = %{version}-%{release}
|
||||||
Requires: vitastor-client = %{version}-%{release}
|
Requires: vitastor-client = %{version}-%{release}
|
||||||
|
|||||||
+11
-2
@@ -1,8 +1,9 @@
|
|||||||
cmake_minimum_required(VERSION 2.8...3.30)
|
cmake_minimum_required(VERSION 2.8.12)
|
||||||
|
|
||||||
project(vitastor)
|
project(vitastor)
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
include(CTest)
|
||||||
include(CheckIncludeFile)
|
include(CheckIncludeFile)
|
||||||
|
|
||||||
find_package(PkgConfig)
|
find_package(PkgConfig)
|
||||||
@@ -20,7 +21,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.15")
|
add_definitions(-DVITASTOR_VERSION="3.0.5")
|
||||||
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})
|
||||||
@@ -74,6 +75,14 @@ if (RDMACM_LIBRARIES)
|
|||||||
add_definitions(-DWITH_RDMACM)
|
add_definitions(-DWITH_RDMACM)
|
||||||
endif (RDMACM_LIBRARIES)
|
endif (RDMACM_LIBRARIES)
|
||||||
|
|
||||||
|
find_package(OpenSSL REQUIRED)
|
||||||
|
if (OPENSSL_FOUND)
|
||||||
|
add_definitions(-DWITH_OPENSSL)
|
||||||
|
endif (OPENSSL_FOUND)
|
||||||
|
|
||||||
|
pkg_check_modules(CARES REQUIRED libcares)
|
||||||
|
include_directories(${CARES_INCLUDE_DIRS})
|
||||||
|
|
||||||
if (${WITH_SYSTEM_LIBURING})
|
if (${WITH_SYSTEM_LIBURING})
|
||||||
pkg_check_modules(LIBURING REQUIRED liburing>=2.10)
|
pkg_check_modules(LIBURING REQUIRED liburing>=2.10)
|
||||||
include_directories(${LIBURING_INCLUDE_DIRS})
|
include_directories(${LIBURING_INCLUDE_DIRS})
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
cmake_minimum_required(VERSION 2.8...3.30)
|
cmake_minimum_required(VERSION 2.8.12)
|
||||||
|
|
||||||
project(vitastor)
|
project(vitastor)
|
||||||
|
|
||||||
# libvitastor_blk.a
|
# libvitastor_blk.a
|
||||||
add_library(vitastor_blk STATIC
|
add_library(vitastor_blk STATIC
|
||||||
../util/allocator.cpp ../util/crc32c.c ../util/ringloop.cpp
|
../util/allocator.cpp ../util/crc32c.c ../util/xxhash.c ../util/ringloop.cpp
|
||||||
multilist.cpp blockstore_heap.cpp blockstore_disk.cpp
|
multilist.cpp blockstore_heap.cpp blockstore_disk.cpp
|
||||||
blockstore.cpp blockstore_impl.cpp blockstore_init.cpp blockstore_open.cpp
|
blockstore.cpp blockstore_impl.cpp blockstore_init.cpp blockstore_open.cpp
|
||||||
blockstore_flush.cpp blockstore_read.cpp blockstore_stable.cpp blockstore_sync.cpp blockstore_write.cpp
|
blockstore_flush.cpp blockstore_read.cpp blockstore_stable.cpp blockstore_sync.cpp blockstore_write.cpp
|
||||||
|
|||||||
@@ -228,9 +228,4 @@ 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;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -83,20 +83,21 @@ void blockstore_disk_t::parse_config(std::map<std::string, std::string> & config
|
|||||||
{
|
{
|
||||||
data_csum_type = BLOCKSTORE_CSUM_CRC32C;
|
data_csum_type = BLOCKSTORE_CSUM_CRC32C;
|
||||||
}
|
}
|
||||||
|
else if (config["data_csum_type"] == "xxh3_32")
|
||||||
|
{
|
||||||
|
data_csum_type = BLOCKSTORE_CSUM_XXH3_32;
|
||||||
|
}
|
||||||
else if (config["data_csum_type"] == "" || config["data_csum_type"] == "none")
|
else if (config["data_csum_type"] == "" || config["data_csum_type"] == "none")
|
||||||
{
|
{
|
||||||
data_csum_type = BLOCKSTORE_CSUM_NONE;
|
data_csum_type = BLOCKSTORE_CSUM_NONE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw std::runtime_error("data_csum_type="+config["data_csum_type"]+" is unsupported, only \"crc32c\" and \"none\" are supported");
|
throw std::runtime_error("data_csum_type="+config["data_csum_type"]+" is unsupported, only \"crc32c\", \"xxh3_32\" and \"none\" are supported");
|
||||||
}
|
}
|
||||||
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;
|
||||||
@@ -517,7 +518,7 @@ void blockstore_disk_t::close_all()
|
|||||||
|
|
||||||
// Sadly DISCARD only works through ioctl(), but it seems to always block the device queue,
|
// Sadly DISCARD only works through ioctl(), but it seems to always block the device queue,
|
||||||
// so it's not a big deal that we can only run it synchronously.
|
// so it's not a big deal that we can only run it synchronously.
|
||||||
int blockstore_disk_t::trim_data(std::function<bool(uint64_t)> is_used)
|
int blockstore_disk_t::trim_data(std::function<bool(uint64_t)> is_free)
|
||||||
{
|
{
|
||||||
if (mock_mode)
|
if (mock_mode)
|
||||||
{
|
{
|
||||||
@@ -528,7 +529,7 @@ int blockstore_disk_t::trim_data(std::function<bool(uint64_t)> is_used)
|
|||||||
uint64_t discarded = 0;
|
uint64_t discarded = 0;
|
||||||
for (; i <= block_count; i++)
|
for (; i <= block_count; i++)
|
||||||
{
|
{
|
||||||
if (i >= block_count || is_used(i))
|
if (i >= block_count || is_free(i))
|
||||||
{
|
{
|
||||||
if (i > j && (i-j)*data_block_size >= min_discard_size)
|
if (i > j && (i-j)*data_block_size >= min_discard_size)
|
||||||
{
|
{
|
||||||
@@ -541,21 +542,17 @@ int blockstore_disk_t::trim_data(std::function<bool(uint64_t)> is_used)
|
|||||||
if (range[0] % discard_granularity)
|
if (range[0] % discard_granularity)
|
||||||
range[0] = range[0] + discard_granularity - (range[0] % discard_granularity);
|
range[0] = range[0] + discard_granularity - (range[0] % discard_granularity);
|
||||||
if (range[0] >= range[1])
|
if (range[0] >= range[1])
|
||||||
range[1] = 0;
|
continue;
|
||||||
else
|
range[1] -= range[0];
|
||||||
range[1] -= range[0];
|
|
||||||
}
|
}
|
||||||
if (range[1] > 0)
|
r = ioctl(data_fd, BLKDISCARD, &range);
|
||||||
|
if (r != 0)
|
||||||
{
|
{
|
||||||
r = ioctl(data_fd, BLKDISCARD, &range);
|
fprintf(stderr, "Failed to execute BLKDISCARD %ju+%ju on %s: %s (code %d)\n",
|
||||||
if (r != 0)
|
range[0], range[1], data_device.c_str(), strerror(-r), r);
|
||||||
{
|
return -errno;
|
||||||
fprintf(stderr, "Failed to execute BLKDISCARD %ju+%ju on %s: %s (code %d)\n",
|
|
||||||
range[0], range[1], data_device.c_str(), strerror(-r), r);
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
discarded += range[1];
|
|
||||||
}
|
}
|
||||||
|
discarded += range[1];
|
||||||
}
|
}
|
||||||
j = i+1;
|
j = i+1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#define BLOCKSTORE_CSUM_NONE 0
|
#define BLOCKSTORE_CSUM_NONE 0
|
||||||
// Lower byte of checksum type is its length
|
// Lower byte of checksum type is its length
|
||||||
#define BLOCKSTORE_CSUM_CRC32C 0x104
|
#define BLOCKSTORE_CSUM_CRC32C 0x104
|
||||||
|
#define BLOCKSTORE_CSUM_XXH3_32 0x204
|
||||||
|
|
||||||
#define MOCK_DATA_FD 1000
|
#define MOCK_DATA_FD 1000
|
||||||
#define MOCK_META_FD 1001
|
#define MOCK_META_FD 1001
|
||||||
@@ -57,10 +58,6 @@ 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;
|
||||||
|
|
||||||
@@ -83,7 +80,7 @@ struct blockstore_disk_t
|
|||||||
void calc_lengths(bool skip_meta_check = false);
|
void calc_lengths(bool skip_meta_check = false);
|
||||||
void check_lengths();
|
void check_lengths();
|
||||||
void close_all();
|
void close_all();
|
||||||
int trim_data(std::function<bool(uint64_t)> is_used);
|
int trim_data(std::function<bool(uint64_t)> is_free);
|
||||||
|
|
||||||
inline uint64_t dirty_dyn_size(uint64_t offset, uint64_t len)
|
inline uint64_t dirty_dyn_size(uint64_t offset, uint64_t len)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -174,18 +174,14 @@ 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:
|
||||||
@@ -200,7 +196,6 @@ 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:
|
||||||
@@ -264,9 +259,11 @@ 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)
|
||||||
{
|
{
|
||||||
bs->prepare_read(read_vec, cur_obj, wr, 0, bs->dsk.data_block_size,
|
auto res = 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)
|
||||||
@@ -276,53 +273,30 @@ resume_1:
|
|||||||
bs->heap->unlock_entry(cur_oid);
|
bs->heap->unlock_entry(cur_oid);
|
||||||
goto resume_0;
|
goto resume_0;
|
||||||
}
|
}
|
||||||
|
mem_or(new_bmp, compact_info.clean_wr->get_int_bitmap(bs->heap), bs->dsk.clean_entry_bitmap_size);
|
||||||
|
if (!bitmap_copied)
|
||||||
|
{
|
||||||
|
memcpy(new_ext_bmp, compact_info.clean_wr->get_ext_bitmap(bs->heap), bs->dsk.clean_entry_bitmap_size);
|
||||||
|
bitmap_copied = true;
|
||||||
|
}
|
||||||
|
if (bs->dsk.csum_block_size && bs->dsk.csum_block_size <= bs->dsk.bitmap_granularity)
|
||||||
|
{
|
||||||
|
memcpy(new_csums, compact_info.clean_wr->get_checksums(bs->heap), bs->dsk.data_block_size/bs->dsk.csum_block_size * (bs->dsk.data_csum_type & 0xFF));
|
||||||
|
for (size_t i = csum_copy.size(); i > 0; i--)
|
||||||
|
{
|
||||||
|
auto wr = csum_copy[i-1];
|
||||||
|
memcpy(new_csums + wr->small().offset/bs->dsk.csum_block_size*(bs->dsk.data_csum_type & 0xFF),
|
||||||
|
wr->get_checksums(bs->heap), wr->small().len/bs->dsk.csum_block_size*(bs->dsk.data_csum_type & 0xFF));
|
||||||
|
}
|
||||||
|
csum_copy.clear();
|
||||||
|
}
|
||||||
|
clean_loc = compact_info.clean_wr->big_location(bs->heap);
|
||||||
flusher->active_flushers++;
|
flusher->active_flushers++;
|
||||||
for (i = 0; i < read_vec.size(); i++)
|
if (bs->log_level > 10)
|
||||||
{
|
{
|
||||||
if ((read_vec[i].copy_flags & COPY_BUF_JOURNAL) &&
|
printf("Compacting %jx:%jx v%ju..v%ju / l%ju..l%ju (%d writes)\n", cur_oid.inode, cur_oid.stripe,
|
||||||
!(read_vec[i].copy_flags & COPY_BUF_COALESCED))
|
compact_info.clean_wr->version, compact_info.compact_version,
|
||||||
{
|
compact_info.clean_wr->lsn, compact_info.compact_lsn, copy_count);
|
||||||
copy_count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (copy_count > 0 && !bs->dsk.disable_data_fsync)
|
|
||||||
{
|
|
||||||
init_fsync_data();
|
|
||||||
}
|
|
||||||
if (compact_info.do_delete)
|
|
||||||
{
|
|
||||||
if (bs->log_level > 10)
|
|
||||||
{
|
|
||||||
printf("Compacting %jx:%jx up to l%ju (delete)\n", cur_oid.inode, cur_oid.stripe, compact_info.compact_lsn);
|
|
||||||
}
|
|
||||||
clean_loc = UINT64_MAX;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
if (!bitmap_copied)
|
|
||||||
{
|
|
||||||
memcpy(new_ext_bmp, compact_info.clean_wr->get_ext_bitmap(bs->heap), bs->dsk.clean_entry_bitmap_size);
|
|
||||||
bitmap_copied = true;
|
|
||||||
}
|
|
||||||
if (bs->dsk.csum_block_size && bs->dsk.csum_block_size <= bs->dsk.bitmap_granularity)
|
|
||||||
{
|
|
||||||
memcpy(new_csums, compact_info.clean_wr->get_checksums(bs->heap), bs->dsk.data_block_size/bs->dsk.csum_block_size * (bs->dsk.data_csum_type & 0xFF));
|
|
||||||
for (size_t i = csum_copy.size(); i > 0; i--)
|
|
||||||
{
|
|
||||||
auto wr = csum_copy[i-1];
|
|
||||||
memcpy(new_csums + wr->small().offset/bs->dsk.csum_block_size*(bs->dsk.data_csum_type & 0xFF),
|
|
||||||
wr->get_checksums(bs->heap), wr->small().len/bs->dsk.csum_block_size*(bs->dsk.data_csum_type & 0xFF));
|
|
||||||
}
|
|
||||||
csum_copy.clear();
|
|
||||||
}
|
|
||||||
clean_loc = compact_info.clean_wr->big_location(bs->heap);
|
|
||||||
}
|
}
|
||||||
overwrite_start = overwrite_end = 0;
|
overwrite_start = overwrite_end = 0;
|
||||||
if (read_vec.size() > 0)
|
if (read_vec.size() > 0)
|
||||||
@@ -362,13 +336,6 @@ 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--;
|
||||||
@@ -382,7 +349,10 @@ resume_4:
|
|||||||
if (res == ENOENT)
|
if (res == ENOENT)
|
||||||
{
|
{
|
||||||
// Abort compaction
|
// Abort compaction
|
||||||
goto abort_compact;
|
flusher->flushing.erase(cur_oid);
|
||||||
|
bs->heap->unlock_entry(cur_oid);
|
||||||
|
flusher->active_flushers--;
|
||||||
|
goto resume_0;
|
||||||
}
|
}
|
||||||
if (res == EAGAIN)
|
if (res == EAGAIN)
|
||||||
{
|
{
|
||||||
@@ -411,14 +381,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++;
|
||||||
}
|
}
|
||||||
@@ -429,17 +399,6 @@ 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
|
||||||
@@ -449,14 +408,12 @@ resume_25:
|
|||||||
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;
|
||||||
}
|
}
|
||||||
@@ -465,7 +422,6 @@ resume_25:
|
|||||||
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;
|
||||||
}
|
}
|
||||||
@@ -630,13 +586,13 @@ 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 punch_holes and then write the block to disk
|
// Modified, we should add_punch_holes and then write the block to disk
|
||||||
return EBUSY;
|
return EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool journal_flusher_co::calc_block_checksums()
|
bool journal_flusher_co::calc_block_checksums()
|
||||||
{
|
{
|
||||||
if (bs->dsk.csum_block_size <= bs->dsk.bitmap_granularity || compact_info.do_delete)
|
if (bs->dsk.csum_block_size <= bs->dsk.bitmap_granularity)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -743,67 +699,6 @@ 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,15 +25,6 @@ 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
|
||||||
@@ -67,7 +58,6 @@ 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;
|
||||||
|
|
||||||
@@ -78,8 +68,6 @@ 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);
|
||||||
@@ -100,7 +88,6 @@ 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;
|
||||||
|
|||||||
+350
-577
File diff suppressed because it is too large
Load Diff
@@ -43,7 +43,7 @@ struct __attribute__((__packed__)) heap_entry_t
|
|||||||
{
|
{
|
||||||
uint16_t size;
|
uint16_t size;
|
||||||
uint16_t entry_type;
|
uint16_t entry_type;
|
||||||
uint32_t crc32c;
|
uint32_t checksum;
|
||||||
uint64_t lsn;
|
uint64_t lsn;
|
||||||
uint64_t inode;
|
uint64_t inode;
|
||||||
uint64_t stripe;
|
uint64_t stripe;
|
||||||
@@ -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() const;
|
bool is_garbage();
|
||||||
void set_garbage();
|
void set_garbage();
|
||||||
bool is_overwrite() const;
|
bool is_overwrite();
|
||||||
bool is_compactable() const;
|
bool is_compactable();
|
||||||
bool is_before(const heap_entry_t *other) const;
|
bool is_before(heap_entry_t *other);
|
||||||
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);
|
||||||
@@ -69,7 +69,8 @@ struct __attribute__((__packed__)) heap_entry_t
|
|||||||
uint32_t *get_checksum(blockstore_heap_t *heap);
|
uint32_t *get_checksum(blockstore_heap_t *heap);
|
||||||
uint64_t big_location(blockstore_heap_t *heap);
|
uint64_t big_location(blockstore_heap_t *heap);
|
||||||
void set_big_location(blockstore_heap_t *heap, uint64_t location);
|
void set_big_location(blockstore_heap_t *heap, uint64_t location);
|
||||||
uint32_t calc_crc32c();
|
uint32_t calc_checksum(blockstore_heap_t *heap);
|
||||||
|
uint32_t calc_checksum(blockstore_disk_t *dsk);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct __attribute__((__packed__)) heap_small_write_t
|
struct __attribute__((__packed__)) heap_small_write_t
|
||||||
@@ -80,7 +81,7 @@ struct __attribute__((__packed__)) heap_small_write_t
|
|||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
|
|
||||||
// Also includes 1 bitmap and 1 crc32c after the bitmap if checksums are disabled
|
// Also includes 1 bitmap and 1 checksum after the bitmap if block checksums are disabled
|
||||||
};
|
};
|
||||||
|
|
||||||
struct __attribute__((__packed__)) heap_big_write_t
|
struct __attribute__((__packed__)) heap_big_write_t
|
||||||
@@ -98,7 +99,7 @@ struct __attribute__((__packed__)) heap_big_intent_t
|
|||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
|
|
||||||
// Also includes 2 bitmaps and 1 crc32c if checksums are disabled
|
// Also includes 2 bitmaps and 1 checksums if block checksums are disabled
|
||||||
};
|
};
|
||||||
|
|
||||||
struct __attribute__((__packed__)) heap_list_item_t
|
struct __attribute__((__packed__)) heap_list_item_t
|
||||||
@@ -117,13 +118,10 @@ struct heap_object_mvcc_t
|
|||||||
|
|
||||||
struct heap_block_info_t
|
struct heap_block_info_t
|
||||||
{
|
{
|
||||||
struct __attribute__((__packed__))
|
uint32_t used_space = 0;
|
||||||
{
|
|
||||||
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 = false;
|
bool is_writing: 1;
|
||||||
|
bool has_garbage: 1;
|
||||||
std::vector<heap_list_item_t*> entries;
|
std::vector<heap_list_item_t*> entries;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -158,16 +156,6 @@ 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,
|
||||||
@@ -197,11 +185,6 @@ 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;
|
||||||
@@ -218,12 +201,9 @@ 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*> postponed_items;
|
std::vector<heap_list_item_t*> loaded_list_items;
|
||||||
std::vector<heap_list_item_t*> init_erase_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;
|
||||||
@@ -232,22 +212,14 @@ 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_items(heap_list_item_t** v, size_t count, bool postpone);
|
void insert_list_item(heap_list_item_t *li);
|
||||||
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);
|
||||||
@@ -362,7 +334,7 @@ public:
|
|||||||
|
|
||||||
// get metadata block data buffer and used space
|
// get metadata block data buffer and used space
|
||||||
void get_meta_block(uint32_t block_num, uint8_t *buffer);
|
void get_meta_block(uint32_t block_num, uint8_t *buffer);
|
||||||
void fill_block_empty_space(uint8_t *buffer, uint64_t pos);
|
void fill_block_empty_space(uint8_t *buffer, uint32_t pos);
|
||||||
uint32_t get_meta_block_used_space(uint32_t block_num);
|
uint32_t get_meta_block_used_space(uint32_t block_num);
|
||||||
|
|
||||||
// get space usage statistics
|
// get space usage statistics
|
||||||
@@ -374,10 +346,6 @@ 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,7 +101,6 @@ 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];
|
||||||
@@ -139,13 +138,7 @@ 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
|
||||||
if (!has_unfinished_sync)
|
wr_st = continue_sync(op);
|
||||||
{
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
@@ -161,7 +154,9 @@ 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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -117,12 +117,9 @@ public:
|
|||||||
|
|
||||||
journal_flusher_t *flusher;
|
journal_flusher_t *flusher;
|
||||||
int write_iodepth = 0;
|
int write_iodepth = 0;
|
||||||
|
int inflight_big = 0;
|
||||||
int intent_write_counter = 0;
|
int intent_write_counter = 0;
|
||||||
uint64_t data_fsync_next = 0;
|
bool fsyncing_data = false;
|
||||||
uint64_t data_fsync_cur = 0;
|
|
||||||
uint64_t data_fsync_sent = 0;
|
|
||||||
uint64_t data_fsync_done = 0;
|
|
||||||
std::deque<bool> data_fsyncs;
|
|
||||||
|
|
||||||
bool live = false, queue_stall = false;
|
bool live = false, queue_stall = false;
|
||||||
ring_loop_i *ringloop = NULL;
|
ring_loop_i *ringloop = NULL;
|
||||||
@@ -232,9 +229,4 @@ 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(); }
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#define INIT_META_EMPTY 0
|
#define INIT_META_EMPTY 0
|
||||||
#define INIT_META_READING 1
|
#define INIT_META_READING 1
|
||||||
#define INIT_META_READ_DONE 2
|
#define INIT_META_READ_DONE 2
|
||||||
|
#define INIT_META_WRITING 3
|
||||||
|
|
||||||
#define GET_SQE() \
|
#define GET_SQE() \
|
||||||
sqe = bs->get_sqe();\
|
sqe = bs->get_sqe();\
|
||||||
@@ -22,15 +23,14 @@ blockstore_init_meta::blockstore_init_meta(blockstore_impl_t *bs)
|
|||||||
this->bs = bs;
|
this->bs = bs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void blockstore_init_meta::handle_event(ring_data_t *data, int buf_num, const char *op)
|
void blockstore_init_meta::handle_event(ring_data_t *data, int buf_num)
|
||||||
{
|
{
|
||||||
if (data->res != data->iov.iov_len)
|
if (data->res < 0)
|
||||||
{
|
{
|
||||||
throw std::runtime_error(strprintf(
|
throw std::runtime_error(
|
||||||
"%s failed at offset %ju: got %s (code %d), but expected %zu",
|
std::string("read metadata failed at offset ") + std::to_string(buf_num >= 0 ? bufs[buf_num].offset : last_read_offset) +
|
||||||
op, (buf_num >= 0 ? bufs[buf_num].offset : last_read_offset), strerror(-data->res),
|
std::string(": ") + strerror(-data->res)
|
||||||
data->res, data->iov.iov_len
|
);
|
||||||
));
|
|
||||||
}
|
}
|
||||||
if (buf_num >= 0)
|
if (buf_num >= 0)
|
||||||
{
|
{
|
||||||
@@ -60,7 +60,7 @@ int blockstore_init_meta::loop()
|
|||||||
GET_SQE();
|
GET_SQE();
|
||||||
last_read_offset = 0;
|
last_read_offset = 0;
|
||||||
data->iov = { bs->meta_superblock, (size_t)bs->dsk.meta_block_size };
|
data->iov = { bs->meta_superblock, (size_t)bs->dsk.meta_block_size };
|
||||||
data->callback = [this](ring_data_t *data) { handle_event(data, -1, "read metadata header"); };
|
data->callback = [this](ring_data_t *data) { handle_event(data, -1); };
|
||||||
io_uring_prep_readv(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset);
|
io_uring_prep_readv(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset);
|
||||||
bs->ringloop->submit();
|
bs->ringloop->submit();
|
||||||
submitted++;
|
submitted++;
|
||||||
@@ -72,19 +72,25 @@ resume_1:
|
|||||||
}
|
}
|
||||||
if (is_zero((uint64_t*)bs->meta_superblock, bs->dsk.meta_block_size))
|
if (is_zero((uint64_t*)bs->meta_superblock, bs->dsk.meta_block_size))
|
||||||
{
|
{
|
||||||
assert(bs->dsk.meta_format == BLOCKSTORE_META_FORMAT_HEAP);
|
{
|
||||||
blockstore_meta_header_v3_t *hdr = (blockstore_meta_header_v3_t *)bs->meta_superblock;
|
blockstore_meta_header_v3_t *hdr = (blockstore_meta_header_v3_t *)bs->meta_superblock;
|
||||||
hdr->zero = 0;
|
hdr->zero = 0;
|
||||||
hdr->magic = BLOCKSTORE_META_MAGIC_V1;
|
hdr->magic = BLOCKSTORE_META_MAGIC_V1;
|
||||||
hdr->version = bs->dsk.meta_format;
|
hdr->version = bs->dsk.meta_format;
|
||||||
hdr->meta_block_size = bs->dsk.meta_block_size;
|
hdr->meta_block_size = bs->dsk.meta_block_size;
|
||||||
hdr->data_block_size = bs->dsk.data_block_size;
|
hdr->data_block_size = bs->dsk.data_block_size;
|
||||||
hdr->bitmap_granularity = bs->dsk.bitmap_granularity;
|
hdr->bitmap_granularity = bs->dsk.bitmap_granularity;
|
||||||
hdr->completed_lsn = 0;
|
if (bs->dsk.meta_format >= BLOCKSTORE_META_FORMAT_V2)
|
||||||
hdr->data_csum_type = bs->dsk.data_csum_type;
|
{
|
||||||
hdr->csum_block_size = bs->dsk.csum_block_size;
|
hdr->data_csum_type = bs->dsk.data_csum_type;
|
||||||
hdr->meta_area_size = bs->dsk.meta_area_size;
|
hdr->csum_block_size = bs->dsk.csum_block_size;
|
||||||
hdr->set_crc32c();
|
}
|
||||||
|
if (bs->dsk.meta_format >= BLOCKSTORE_META_FORMAT_HEAP)
|
||||||
|
{
|
||||||
|
hdr->meta_area_size = bs->dsk.meta_area_size;
|
||||||
|
}
|
||||||
|
hdr->set_crc32c();
|
||||||
|
}
|
||||||
if (bs->readonly)
|
if (bs->readonly)
|
||||||
{
|
{
|
||||||
printf("Skipping metadata initialization because blockstore is readonly\n");
|
printf("Skipping metadata initialization because blockstore is readonly\n");
|
||||||
@@ -92,8 +98,21 @@ resume_1:
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf("Initializing metadata area\n");
|
printf("Initializing metadata area\n");
|
||||||
|
GET_SQE();
|
||||||
|
last_read_offset = 0;
|
||||||
|
data->iov = (struct iovec){ bs->meta_superblock, (size_t)bs->dsk.meta_block_size };
|
||||||
|
data->callback = [this](ring_data_t *data) { handle_event(data, -1); };
|
||||||
|
io_uring_prep_writev(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset);
|
||||||
|
bs->ringloop->submit();
|
||||||
|
submitted++;
|
||||||
|
resume_2:
|
||||||
|
if (submitted > 0)
|
||||||
|
{
|
||||||
|
wait_state = 2;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
zero_on_init = true;
|
||||||
}
|
}
|
||||||
zero_on_init = true;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -134,17 +153,9 @@ 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 && !zero_on_init)
|
if (bs->dsk.inmemory_journal)
|
||||||
{
|
{
|
||||||
// Read buffer area
|
// Read buffer area
|
||||||
printf("Reading buffered data\n");
|
printf("Reading buffered data\n");
|
||||||
@@ -156,7 +167,7 @@ resume_1:
|
|||||||
bs->buffer_area + md_offset,
|
bs->buffer_area + md_offset,
|
||||||
(size_t)(bs->dsk.journal_len - md_offset < bs->metadata_buf_size ? bs->dsk.journal_len - md_offset : bs->metadata_buf_size),
|
(size_t)(bs->dsk.journal_len - md_offset < bs->metadata_buf_size ? bs->dsk.journal_len - md_offset : bs->metadata_buf_size),
|
||||||
};
|
};
|
||||||
data->callback = [this](ring_data_t *data) { handle_event(data, -1, "read buffer area"); };
|
data->callback = [this](ring_data_t *data) { handle_event(data, -1); };
|
||||||
io_uring_prep_readv(sqe, bs->dsk.journal_fd, &data->iov, 1, bs->dsk.journal_offset + md_offset);
|
io_uring_prep_readv(sqe, bs->dsk.journal_fd, &data->iov, 1, bs->dsk.journal_offset + md_offset);
|
||||||
md_offset += data->iov.iov_len;
|
md_offset += data->iov.iov_len;
|
||||||
submitted++;
|
submitted++;
|
||||||
@@ -175,7 +186,7 @@ resume_3:
|
|||||||
next_offset = md_offset;
|
next_offset = md_offset;
|
||||||
// Read the rest of the metadata
|
// Read the rest of the metadata
|
||||||
resume_4:
|
resume_4:
|
||||||
if (next_offset < bs->dsk.meta_area_size && submitted == 0 && (!zero_on_init || !bs->readonly))
|
if (next_offset < bs->dsk.meta_area_size && submitted == 0)
|
||||||
{
|
{
|
||||||
// Submit one read
|
// Submit one read
|
||||||
for (int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++)
|
||||||
@@ -192,15 +203,12 @@ resume_4:
|
|||||||
GET_SQE();
|
GET_SQE();
|
||||||
assert(bufs[i].size <= 0x7fffffff);
|
assert(bufs[i].size <= 0x7fffffff);
|
||||||
data->iov = { bufs[i].buf, (size_t)bufs[i].size };
|
data->iov = { bufs[i].buf, (size_t)bufs[i].size };
|
||||||
|
data->callback = [this, i](ring_data_t *data) { handle_event(data, i); };
|
||||||
if (!zero_on_init)
|
if (!zero_on_init)
|
||||||
{
|
|
||||||
data->callback = [this, i](ring_data_t *data) { handle_event(data, i, "read metadata"); };
|
|
||||||
io_uring_prep_readv(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + bufs[i].offset);
|
io_uring_prep_readv(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + bufs[i].offset);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Fill metadata with empty block pattern
|
// Fill metadata with empty block pattern
|
||||||
data->callback = [this, i](ring_data_t *data) { handle_event(data, i, "clear metadata"); };
|
|
||||||
memset(bufs[i].buf, 0, bufs[i].size);
|
memset(bufs[i].buf, 0, bufs[i].size);
|
||||||
for (uint64_t o = 0; o < bufs[i].size; o += bs->dsk.meta_block_size)
|
for (uint64_t o = 0; o < bufs[i].size; o += bs->dsk.meta_block_size)
|
||||||
bs->heap->fill_block_empty_space(bufs[i].buf + o, 0);
|
bs->heap->fill_block_empty_space(bufs[i].buf + o, 0);
|
||||||
@@ -216,14 +224,11 @@ resume_4:
|
|||||||
if (bufs[i].state == INIT_META_READ_DONE)
|
if (bufs[i].state == INIT_META_READ_DONE)
|
||||||
{
|
{
|
||||||
// Handle result
|
// Handle result
|
||||||
if (!zero_on_init)
|
uint64_t loaded = 0;
|
||||||
{
|
int r = bs->heap->load_blocks(bufs[i].offset-bs->dsk.meta_block_size, bufs[i].size, bufs[i].buf, bs->skip_corrupted_meta_entries, loaded);
|
||||||
uint64_t loaded = 0;
|
if (r != 0)
|
||||||
int r = bs->heap->load_blocks(bufs[i].offset-bs->dsk.meta_block_size, bufs[i].size, bufs[i].buf, bs->skip_corrupted_meta_entries, loaded);
|
exit(1);
|
||||||
if (r != 0)
|
entries_loaded += loaded;
|
||||||
exit(1);
|
|
||||||
entries_loaded += loaded;
|
|
||||||
}
|
|
||||||
bufs[i].state = 0;
|
bufs[i].state = 0;
|
||||||
bs->ringloop->wakeup();
|
bs->ringloop->wakeup();
|
||||||
}
|
}
|
||||||
@@ -233,9 +238,25 @@ resume_4:
|
|||||||
wait_state = 4;
|
wait_state = 4;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
// metadata read/clear finished
|
// metadata read finished
|
||||||
bs->heap->finish_load();
|
bs->heap->finish_load();
|
||||||
printf("Metadata entries loaded: %ju, rechecking unfinished writes and garbage entries\n", entries_loaded);
|
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);
|
||||||
|
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;
|
||||||
@@ -272,11 +293,6 @@ 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++)
|
||||||
{
|
{
|
||||||
@@ -290,7 +306,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*)memalign_or_die(MEM_ALIGNMENT, bs->dsk.meta_block_size);
|
uint8_t *buf = (uint8_t*)malloc_or_die(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)
|
||||||
@@ -316,47 +332,5 @@ resume_9:
|
|||||||
}
|
}
|
||||||
free(metadata_buffer);
|
free(metadata_buffer);
|
||||||
metadata_buffer = NULL;
|
metadata_buffer = NULL;
|
||||||
do_fsync:
|
|
||||||
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, "fsync metadata"); };
|
|
||||||
submitted++;
|
|
||||||
bs->ringloop->submit();
|
|
||||||
resume_5:
|
|
||||||
if (submitted > 0)
|
|
||||||
{
|
|
||||||
wait_state = 5;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (zero_on_init && !header_written && !bs->readonly)
|
|
||||||
{
|
|
||||||
GET_SQE();
|
|
||||||
header_written = true;
|
|
||||||
last_read_offset = 0;
|
|
||||||
data->iov = (struct iovec){ bs->meta_superblock, (size_t)bs->dsk.meta_block_size };
|
|
||||||
data->callback = [this](ring_data_t *data) { handle_event(data, -1, "write metadata header"); };
|
|
||||||
io_uring_prep_writev(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset);
|
|
||||||
bs->ringloop->submit();
|
|
||||||
submitted++;
|
|
||||||
resume_2:
|
|
||||||
if (submitted > 0)
|
|
||||||
{
|
|
||||||
wait_state = 2;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (!bs->dsk.disable_meta_fsync)
|
|
||||||
{
|
|
||||||
goto do_fsync;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ class blockstore_init_meta
|
|||||||
int wait_state = 0;
|
int wait_state = 0;
|
||||||
int wait_count = 0;
|
int wait_count = 0;
|
||||||
bool zero_on_init = false;
|
bool zero_on_init = false;
|
||||||
bool header_written = false;
|
|
||||||
void *metadata_buffer = NULL;
|
void *metadata_buffer = NULL;
|
||||||
blockstore_init_meta_buf bufs[2] = {};
|
blockstore_init_meta_buf bufs[2] = {};
|
||||||
int submitted = 0;
|
int submitted = 0;
|
||||||
@@ -30,7 +29,7 @@ class blockstore_init_meta
|
|||||||
std::vector<uint32_t> recheck_mod;
|
std::vector<uint32_t> recheck_mod;
|
||||||
int i = 0, j = 0;
|
int i = 0, j = 0;
|
||||||
bool handle_meta_block(uint8_t *buf, uint64_t count, uint64_t done_cnt);
|
bool handle_meta_block(uint8_t *buf, uint64_t count, uint64_t done_cnt);
|
||||||
void handle_event(ring_data_t *data, int buf_num, const char *op);
|
void handle_event(ring_data_t *data, int buf_num);
|
||||||
public:
|
public:
|
||||||
blockstore_init_meta(blockstore_impl_t *bs);
|
blockstore_init_meta(blockstore_impl_t *bs);
|
||||||
int loop();
|
int loop();
|
||||||
|
|||||||
@@ -1,113 +0,0 @@
|
|||||||
// Copyright (c) Vitaliy Filippov, 2019+
|
|
||||||
// License: VNPL-1.1 (see README.md for details)
|
|
||||||
|
|
||||||
#include "blockstore_mock.h"
|
|
||||||
|
|
||||||
blockstore_mock_t::blockstore_mock_t(const blockstore_config_t & config)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void blockstore_mock_t::parse_config(blockstore_config_t & config)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void* blockstore_mock_t::reshard_start(pool_id_t pool, uint32_t pg_count, uint32_t pg_stripe_size, uint64_t chunk_limit)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool blockstore_mock_t::reshard_continue(void *reshard_state, uint64_t chunk_limit)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void blockstore_mock_t::loop()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool blockstore_mock_t::is_started()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool blockstore_mock_t::is_stalled()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool blockstore_mock_t::is_safe_to_stop()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void blockstore_mock_t::enqueue_op(blockstore_op_t *op)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int blockstore_mock_t::read_bitmap(object_id oid, uint64_t target_version, void *bitmap, uint64_t *result_version)
|
|
||||||
{
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::map<uint64_t, uint64_t> & blockstore_mock_t::get_inode_space_stats()
|
|
||||||
{
|
|
||||||
return inode_space;
|
|
||||||
}
|
|
||||||
|
|
||||||
void blockstore_mock_t::set_no_inode_stats(const std::vector<uint64_t> & pool_ids)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void blockstore_mock_t::dump_diagnostics()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string blockstore_mock_t::get_op_diag(blockstore_op_t *op)
|
|
||||||
{
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t blockstore_mock_t::get_block_size()
|
|
||||||
{
|
|
||||||
return block_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t blockstore_mock_t::get_block_count()
|
|
||||||
{
|
|
||||||
return block_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t blockstore_mock_t::get_free_block_count()
|
|
||||||
{
|
|
||||||
return block_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t blockstore_mock_t::get_journal_size()
|
|
||||||
{
|
|
||||||
return 32*1024*1024;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t blockstore_mock_t::get_bitmap_granularity()
|
|
||||||
{
|
|
||||||
return bitmap_granularity;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t blockstore_mock_t::get_live_entries()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t blockstore_mock_t::get_live_memory()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t blockstore_mock_t::get_garbage_entries()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t blockstore_mock_t::get_garbage_memory()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
// Copyright (c) Vitaliy Filippov, 2019+
|
|
||||||
// License: VNPL-1.1 (see README.md for details)
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "blockstore.h"
|
|
||||||
|
|
||||||
class blockstore_mock_t: public blockstore_i
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
uint32_t block_size = 128*1024;
|
|
||||||
uint32_t bitmap_granularity = 4096;
|
|
||||||
uint64_t block_count = 100*1024*8;
|
|
||||||
std::map<uint64_t, uint64_t> inode_space;
|
|
||||||
|
|
||||||
blockstore_mock_t(const blockstore_config_t & config);
|
|
||||||
void parse_config(blockstore_config_t & config) override;
|
|
||||||
void* reshard_start(pool_id_t pool, uint32_t pg_count, uint32_t pg_stripe_size, uint64_t chunk_limit) override;
|
|
||||||
bool reshard_continue(void *reshard_state, uint64_t chunk_limit) override;
|
|
||||||
void loop() override;
|
|
||||||
bool is_started() override;
|
|
||||||
bool is_stalled() override;
|
|
||||||
bool is_safe_to_stop() override;
|
|
||||||
void enqueue_op(blockstore_op_t *op) override;
|
|
||||||
int read_bitmap(object_id oid, uint64_t target_version, void *bitmap, uint64_t *result_version = NULL) override;
|
|
||||||
const std::map<uint64_t, uint64_t> & get_inode_space_stats() override;
|
|
||||||
void set_no_inode_stats(const std::vector<uint64_t> & pool_ids) override;
|
|
||||||
void dump_diagnostics() override;
|
|
||||||
std::string get_op_diag(blockstore_op_t *op) override;
|
|
||||||
uint32_t get_block_size() override;
|
|
||||||
uint64_t get_block_count() override;
|
|
||||||
uint64_t get_free_block_count() override;
|
|
||||||
uint64_t get_journal_size() override;
|
|
||||||
uint32_t get_bitmap_granularity() override;
|
|
||||||
uint64_t get_live_entries() override;
|
|
||||||
uint64_t get_live_memory() override;
|
|
||||||
uint64_t get_garbage_entries() override;
|
|
||||||
uint64_t get_garbage_memory() override;
|
|
||||||
};
|
|
||||||
@@ -462,10 +462,6 @@ 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,7 +16,6 @@ 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++)
|
||||||
{
|
{
|
||||||
@@ -28,7 +27,6 @@ int blockstore_impl_t::dequeue_stable(blockstore_op_t *op)
|
|||||||
FINISH_OP(op);
|
FINISH_OP(op);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
priv->modified_block2 = UINT32_MAX;
|
|
||||||
int res = op->opcode == BS_OP_STABLE
|
int res = op->opcode == BS_OP_STABLE
|
||||||
? heap->add_commit(obj, v[priv->stab_pos].version, &priv->modified_block2)
|
? heap->add_commit(obj, v[priv->stab_pos].version, &priv->modified_block2)
|
||||||
: heap->add_rollback(obj, v[priv->stab_pos].version, &priv->modified_block2);
|
: heap->add_rollback(obj, v[priv->stab_pos].version, &priv->modified_block2);
|
||||||
@@ -38,12 +36,6 @@ 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())
|
||||||
@@ -53,6 +45,11 @@ int blockstore_impl_t::dequeue_stable(blockstore_op_t *op)
|
|||||||
FINISH_OP(op);
|
FINISH_OP(op);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
if (priv->modified_block2 != UINT32_MAX)
|
||||||
|
{
|
||||||
|
priv->stab_pos--;
|
||||||
|
goto resume_1;
|
||||||
|
}
|
||||||
priv->wait_for = WAIT_COMPACTION;
|
priv->wait_for = WAIT_COMPACTION;
|
||||||
priv->wait_detail = heap->get_compacted_count();
|
priv->wait_detail = heap->get_compacted_count();
|
||||||
flusher->request_trim();
|
flusher->request_trim();
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ 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)
|
||||||
@@ -29,12 +28,9 @@ bool blockstore_impl_t::has_unsynced()
|
|||||||
|
|
||||||
bool blockstore_impl_t::submit_fsyncs(int & wait_count)
|
bool blockstore_impl_t::submit_fsyncs(int & wait_count)
|
||||||
{
|
{
|
||||||
int n = (unsynced_meta_write_count > 0 && !dsk.disable_meta_fsync ? 1 : 0) +
|
int n = (unsynced_meta_write_count > 0 && !dsk.disable_meta_fsync) +
|
||||||
(unsynced_buffer_write_count > 0 && !dsk.disable_journal_fsync &&
|
(unsynced_buffer_write_count > 0 && !dsk.disable_journal_fsync && dsk.journal_fd != dsk.meta_fd) +
|
||||||
(!unsynced_meta_write_count || dsk.journal_fd != dsk.meta_fd) ? 1 : 0) +
|
(unsynced_data_write_count > 0 && !dsk.disable_data_fsync && dsk.data_fd != dsk.meta_fd && dsk.data_fd != dsk.journal_fd);
|
||||||
(unsynced_data_write_count > 0 && !dsk.disable_data_fsync &&
|
|
||||||
(!unsynced_meta_write_count || dsk.data_fd != dsk.meta_fd) &&
|
|
||||||
(!unsynced_buffer_write_count || dsk.data_fd != dsk.journal_fd) ? 1 : 0);
|
|
||||||
if (ringloop->space_left() < n)
|
if (ringloop->space_left() < n)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -63,8 +59,7 @@ bool blockstore_impl_t::submit_fsyncs(int & wait_count)
|
|||||||
data->callback = cb;
|
data->callback = cb;
|
||||||
wait_count++;
|
wait_count++;
|
||||||
}
|
}
|
||||||
if (unsynced_buffer_write_count > 0 && !dsk.disable_journal_fsync &&
|
if (unsynced_buffer_write_count > 0 && !dsk.disable_journal_fsync && dsk.meta_fd != dsk.journal_fd)
|
||||||
(!unsynced_meta_write_count || dsk.journal_fd != dsk.meta_fd))
|
|
||||||
{
|
{
|
||||||
// fsync buffer
|
// fsync buffer
|
||||||
io_uring_sqe *sqe = get_sqe();
|
io_uring_sqe *sqe = get_sqe();
|
||||||
@@ -75,9 +70,7 @@ bool blockstore_impl_t::submit_fsyncs(int & wait_count)
|
|||||||
data->callback = cb;
|
data->callback = cb;
|
||||||
wait_count++;
|
wait_count++;
|
||||||
}
|
}
|
||||||
if (unsynced_data_write_count > 0 && !dsk.disable_data_fsync &&
|
if (unsynced_data_write_count > 0 && !dsk.disable_data_fsync && dsk.data_fd != dsk.meta_fd && dsk.data_fd != dsk.journal_fd)
|
||||||
(!unsynced_meta_write_count || dsk.data_fd != dsk.meta_fd) &&
|
|
||||||
(!unsynced_buffer_write_count || dsk.data_fd != dsk.journal_fd))
|
|
||||||
{
|
{
|
||||||
// fsync data
|
// fsync data
|
||||||
io_uring_sqe *sqe = get_sqe();
|
io_uring_sqe *sqe = get_sqe();
|
||||||
@@ -111,11 +104,9 @@ 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;
|
||||||
}
|
}
|
||||||
assert(!PRIV(op)->lsn);
|
PRIV(op)->modified_block = heap->get_completed_lsn();
|
||||||
PRIV(op)->lsn = heap->get_completed_lsn();
|
|
||||||
if (!submit_fsyncs(PRIV(op)->pending_ops))
|
if (!submit_fsyncs(PRIV(op)->pending_ops))
|
||||||
{
|
{
|
||||||
PRIV(op)->lsn = 0;
|
|
||||||
PRIV(op)->wait_detail = 1;
|
PRIV(op)->wait_detail = 1;
|
||||||
PRIV(op)->wait_for = WAIT_SQE;
|
PRIV(op)->wait_for = WAIT_SQE;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -127,6 +118,6 @@ resume_1:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
resume_2:
|
resume_2:
|
||||||
heap->mark_lsn_fsynced(PRIV(op)->lsn);
|
heap->mark_lsn_fsynced(PRIV(op)->modified_block);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ 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
|
||||||
);
|
);
|
||||||
@@ -178,18 +177,14 @@ 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);
|
||||||
if (!dsk.disable_data_fsync)
|
|
||||||
{
|
|
||||||
// use PRIV->lsn for fsync_data_id
|
|
||||||
PRIV(op)->lsn = ++data_fsync_next;
|
|
||||||
data_fsyncs.push_back(false);
|
|
||||||
}
|
|
||||||
PRIV(op)->pending_ops++;
|
PRIV(op)->pending_ops++;
|
||||||
write_iodepth++;
|
write_iodepth++;
|
||||||
if (PRIV(op)->write_type == BS_HEAP_BIG_WRITE)
|
if (PRIV(op)->write_type == BS_HEAP_BIG_WRITE)
|
||||||
|
{
|
||||||
PRIV(op)->op_state = 1;
|
PRIV(op)->op_state = 1;
|
||||||
|
inflight_big++;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
PRIV(op)->op_state = 3;
|
PRIV(op)->op_state = 3;
|
||||||
}
|
}
|
||||||
@@ -269,7 +264,6 @@ 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++;
|
||||||
}
|
}
|
||||||
@@ -300,6 +294,8 @@ again:
|
|||||||
goto resume_10;
|
goto resume_10;
|
||||||
else if (op_state == 11)
|
else if (op_state == 11)
|
||||||
goto resume_11;
|
goto resume_11;
|
||||||
|
else if (op_state == 12)
|
||||||
|
goto resume_12;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// In progress
|
// In progress
|
||||||
@@ -318,44 +314,38 @@ again:
|
|||||||
resume_2:
|
resume_2:
|
||||||
// We must fsync all big writes to avoid complex write workflows
|
// We must fsync all big writes to avoid complex write workflows
|
||||||
// It's OK for all HDDs and for server SSDs, but slightly worse for desktop SSDs
|
// It's OK for all HDDs and for server SSDs, but slightly worse for desktop SSDs
|
||||||
|
inflight_big--;
|
||||||
if (!dsk.disable_data_fsync)
|
if (!dsk.disable_data_fsync)
|
||||||
{
|
{
|
||||||
// Mark our data write as completed and advance data_fsync_cur
|
// fsync data in a batch
|
||||||
data_fsyncs[PRIV(op)->lsn - data_fsync_cur - 1] = true;
|
|
||||||
while (data_fsyncs.size() > 0 && data_fsyncs.front())
|
|
||||||
{
|
|
||||||
data_fsyncs.pop_front();
|
|
||||||
data_fsync_cur++;
|
|
||||||
}
|
|
||||||
PRIV(op)->op_state = 11;
|
|
||||||
// Then wait for all other data writes currently in progress to do less fsync calls
|
|
||||||
// I.e. to fsync data in batches
|
|
||||||
PRIV(op)->lsn = data_fsync_cur + data_fsyncs.size();
|
|
||||||
resume_11:
|
resume_11:
|
||||||
if (data_fsync_cur < PRIV(op)->lsn)
|
if (inflight_big > 0)
|
||||||
{
|
{
|
||||||
|
PRIV(op)->op_state = 11;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (PRIV(op)->lsn > data_fsync_sent)
|
if (fsyncing_data)
|
||||||
{
|
{
|
||||||
BS_SUBMIT_GET_SQE(sqe, data);
|
resume_12:
|
||||||
io_uring_prep_fsync(sqe, dsk.data_fd, IORING_FSYNC_DATASYNC);
|
if (fsyncing_data)
|
||||||
data->iov = { 0 };
|
|
||||||
data->callback = [this, op, fs = data_fsync_cur](ring_data_t *data)
|
|
||||||
{
|
{
|
||||||
if (fs > data_fsync_done)
|
PRIV(op)->op_state = 12;
|
||||||
{
|
return 1;
|
||||||
data_fsync_done = fs;
|
}
|
||||||
ringloop->wakeup();
|
goto resume_4;
|
||||||
}
|
|
||||||
};
|
|
||||||
data_fsync_sent = data_fsync_cur;
|
|
||||||
}
|
}
|
||||||
if (PRIV(op)->lsn > data_fsync_done)
|
fsyncing_data = true;
|
||||||
|
BS_SUBMIT_GET_SQE(sqe, data);
|
||||||
|
io_uring_prep_fsync(sqe, dsk.data_fd, IORING_FSYNC_DATASYNC);
|
||||||
|
data->iov = { 0 };
|
||||||
|
data->callback = [this, op](ring_data_t *data)
|
||||||
{
|
{
|
||||||
return 1;
|
fsyncing_data = false;
|
||||||
}
|
handle_write_event(data, op);
|
||||||
PRIV(op)->lsn = 0;
|
};
|
||||||
|
PRIV(op)->pending_ops++;
|
||||||
|
PRIV(op)->op_state = 3;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
resume_4:
|
resume_4:
|
||||||
{
|
{
|
||||||
@@ -463,7 +453,6 @@ 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;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ multilist_alloc_t::multilist_alloc_t(uint32_t count, uint32_t maxn):
|
|||||||
count(count), maxn(maxn)
|
count(count), maxn(maxn)
|
||||||
{
|
{
|
||||||
// not-so-memory-efficient: 16 MB memory per 1 GB buffer space, but buffer spaces are small, so OK
|
// not-so-memory-efficient: 16 MB memory per 1 GB buffer space, but buffer spaces are small, so OK
|
||||||
assert(count > 1 && count < 0x80000000 && count >= maxn);
|
assert(count > 1 && count < 0x80000000);
|
||||||
sizes.resize(count);
|
sizes.resize(count);
|
||||||
nexts.resize(count); // nexts[i] = 0 -> area is used; nexts[i] = 1 -> no next; nexts[i] >= 2 -> next item
|
nexts.resize(count); // nexts[i] = 0 -> area is used; nexts[i] = 1 -> no next; nexts[i] >= 2 -> next item
|
||||||
prevs.resize(count);
|
prevs.resize(count);
|
||||||
@@ -171,7 +171,7 @@ void multilist_alloc_t::print()
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool multilist_alloc_t::use(uint32_t pos, uint32_t size)
|
void multilist_alloc_t::use(uint32_t pos, uint32_t size)
|
||||||
{
|
{
|
||||||
assert(pos+size <= count && size > 0);
|
assert(pos+size <= count && size > 0);
|
||||||
if (sizes[pos] <= 0)
|
if (sizes[pos] <= 0)
|
||||||
@@ -182,8 +182,7 @@ bool multilist_alloc_t::use(uint32_t pos, uint32_t size)
|
|||||||
else
|
else
|
||||||
while (start > 0 && !sizes[start])
|
while (start > 0 && !sizes[start])
|
||||||
start--;
|
start--;
|
||||||
if (sizes[start] < size+(pos-start))
|
assert(sizes[start] >= size);
|
||||||
return false;
|
|
||||||
use_full(start);
|
use_full(start);
|
||||||
uint32_t full = sizes[start];
|
uint32_t full = sizes[start];
|
||||||
sizes[pos-1] = -pos+start;
|
sizes[pos-1] = -pos+start;
|
||||||
@@ -200,8 +199,7 @@ bool multilist_alloc_t::use(uint32_t pos, uint32_t size)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (sizes[pos] < size)
|
assert(sizes[pos] >= size);
|
||||||
return false;
|
|
||||||
use_full(pos);
|
use_full(pos);
|
||||||
if (sizes[pos] > size)
|
if (sizes[pos] > size)
|
||||||
{
|
{
|
||||||
@@ -216,13 +214,12 @@ bool multilist_alloc_t::use(uint32_t pos, uint32_t size)
|
|||||||
#ifdef MULTILIST_TRACE
|
#ifdef MULTILIST_TRACE
|
||||||
print();
|
print();
|
||||||
#endif
|
#endif
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void multilist_alloc_t::use_full(uint32_t pos)
|
void multilist_alloc_t::use_full(uint32_t pos)
|
||||||
{
|
{
|
||||||
uint32_t prevsize = sizes[pos];
|
uint32_t prevsize = sizes[pos];
|
||||||
assert(prevsize > 0);
|
assert(prevsize);
|
||||||
assert(nexts[pos]);
|
assert(nexts[pos]);
|
||||||
uint32_t pi = (prevsize < maxn ? prevsize : maxn)-1;
|
uint32_t pi = (prevsize < maxn ? prevsize : maxn)-1;
|
||||||
if (heads[pi] == pos+1)
|
if (heads[pi] == pos+1)
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ struct multilist_alloc_t
|
|||||||
bool is_free(uint32_t pos);
|
bool is_free(uint32_t pos);
|
||||||
uint32_t find(uint32_t size);
|
uint32_t find(uint32_t size);
|
||||||
void use_full(uint32_t pos);
|
void use_full(uint32_t pos);
|
||||||
bool use(uint32_t pos, uint32_t size);
|
void use(uint32_t pos, uint32_t size);
|
||||||
void do_free(uint32_t pos);
|
void do_free(uint32_t pos);
|
||||||
void free(uint32_t pos);
|
void free(uint32_t pos);
|
||||||
void verify();
|
void verify();
|
||||||
|
|||||||
@@ -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 je->size < 4 ? 0 : crc32c(0x48674bc7, ((uint8_t*)je)+4, je->size-4);
|
return crc32c(0x48674bc7, ((uint8_t*)je)+4, je->size-4);
|
||||||
}
|
}
|
||||||
|
|
||||||
// "VITAstor"
|
// "VITAstor"
|
||||||
|
|||||||
+22
-55
@@ -71,11 +71,6 @@ bool journal_flusher_t::is_active()
|
|||||||
return active_flushers > 0 || dequeuing;
|
return active_flushers > 0 || dequeuing;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t journal_flusher_t::get_queue_size()
|
|
||||||
{
|
|
||||||
return flush_queue.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void journal_flusher_t::loop()
|
void journal_flusher_t::loop()
|
||||||
{
|
{
|
||||||
target_flusher_count = bs->write_iodepth*2;
|
target_flusher_count = bs->write_iodepth*2;
|
||||||
@@ -389,7 +384,6 @@ stop_flusher:
|
|||||||
wait_state = 0;
|
wait_state = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
copy_count = 0;
|
|
||||||
try_trim = true;
|
try_trim = true;
|
||||||
cur.oid = flusher->flush_queue.front();
|
cur.oid = flusher->flush_queue.front();
|
||||||
cur.version = flusher->flush_versions[cur.oid];
|
cur.version = flusher->flush_versions[cur.oid];
|
||||||
@@ -517,31 +511,6 @@ resume_2:
|
|||||||
{
|
{
|
||||||
uo_it->second.was_changed = true;
|
uo_it->second.was_changed = true;
|
||||||
}
|
}
|
||||||
if (!bs->journal.inmemory)
|
|
||||||
{
|
|
||||||
// Verify journaled data checksums (but not COALESCED)
|
|
||||||
for (it = v.begin(); it != v.end(); it++)
|
|
||||||
{
|
|
||||||
if (it->copy_flags == COPY_BUF_JOURNAL)
|
|
||||||
{
|
|
||||||
iovec iov = { .iov_base = it->buf, .iov_len = it->len };
|
|
||||||
bs->verify_journal_checksums(
|
|
||||||
it->csum_buf, it->offset, &iov, 1,
|
|
||||||
[&](uint32_t bad_block, uint32_t calc_csum, uint32_t stored_csum)
|
|
||||||
{
|
|
||||||
printf(
|
|
||||||
"Checksum mismatch in object %jx:%jx v%ju in journal at 0x%jx, checksum block #%u: got %08x, expected %08x\n",
|
|
||||||
cur.oid.inode, cur.oid.stripe, cur.version, it->disk_offset,
|
|
||||||
bad_block / bs->dsk.csum_block_size, calc_csum, stored_csum
|
|
||||||
);
|
|
||||||
bad_block += it->offset;
|
|
||||||
assert(!(bad_block % bs->dsk.csum_block_size) && bad_block < bs->dsk.data_block_size);
|
|
||||||
mangle_csum_blocks.insert(bad_block);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Submit data writes
|
// Submit data writes
|
||||||
for (it = v.begin(); it != v.end(); it++)
|
for (it = v.begin(); it != v.end(); it++)
|
||||||
@@ -551,7 +520,6 @@ 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
|
||||||
);
|
);
|
||||||
@@ -665,7 +633,6 @@ resume_2:
|
|||||||
}
|
}
|
||||||
// All done
|
// All done
|
||||||
flusher->active_flushers--;
|
flusher->active_flushers--;
|
||||||
copy_count = 0; // used by is_mutated()...
|
|
||||||
wait_state = 0;
|
wait_state = 0;
|
||||||
goto resume_0;
|
goto resume_0;
|
||||||
}
|
}
|
||||||
@@ -782,7 +749,6 @@ 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
|
||||||
);
|
);
|
||||||
@@ -847,21 +813,35 @@ bool journal_flusher_co::clear_incomplete_csum_block_bits(int wait_base)
|
|||||||
bs->verify_padded_checksums(new_clean_bitmap, new_clean_bitmap + 2*bs->dsk.clean_entry_bitmap_size,
|
bs->verify_padded_checksums(new_clean_bitmap, new_clean_bitmap + 2*bs->dsk.clean_entry_bitmap_size,
|
||||||
v[i].offset, &iov, 1, [&](uint32_t bad_block, uint32_t calc_csum, uint32_t stored_csum)
|
v[i].offset, &iov, 1, [&](uint32_t bad_block, uint32_t calc_csum, uint32_t stored_csum)
|
||||||
{
|
{
|
||||||
printf("Checksum mismatch in object %jx:%jx v%ju in data area at offset 0x%jx+0x%x during flush: got %08x, expected %08x\n",
|
printf("Checksum mismatch in object %jx:%jx v%ju in data area at offset 0x%jx+0x%x: got %08x, expected %08x\n",
|
||||||
cur.oid.inode, cur.oid.stripe, old_clean_ver, old_clean_loc, bad_block, calc_csum, stored_csum);
|
cur.oid.inode, cur.oid.stripe, old_clean_ver, old_clean_loc, bad_block, calc_csum, stored_csum);
|
||||||
assert(!(bad_block % bs->dsk.csum_block_size) && bad_block < bs->dsk.data_block_size);
|
for (uint32_t j = 0; j < bs->dsk.csum_block_size; j += bs->dsk.bitmap_granularity)
|
||||||
mangle_csum_blocks.insert(bad_block);
|
{
|
||||||
|
// Simplest method of mangling: flip one byte in every sector
|
||||||
|
((uint8_t*)v[i].buf)[j+bad_block-v[i].offset] ^= 0xff;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bs->verify_journal_checksums(v[i].csum_buf, v[i].offset, &iov, 1, [&](uint32_t bad_block, uint32_t calc_csum, uint32_t stored_csum)
|
bs->verify_journal_checksums(v[i].csum_buf, v[i].offset, &iov, 1, [&](uint32_t bad_block, uint32_t calc_csum, uint32_t stored_csum)
|
||||||
{
|
{
|
||||||
printf("Checksum mismatch in object %jx:%jx v%ju in journal at offset 0x%jx+0x%x (block offset 0x%jx) during flush: got %08x, expected %08x\n",
|
printf("Checksum mismatch in object %jx:%jx v%ju in journal at offset 0x%jx+0x%x (block offset 0x%jx): got %08x, expected %08x\n",
|
||||||
cur.oid.inode, cur.oid.stripe, old_clean_ver,
|
cur.oid.inode, cur.oid.stripe, old_clean_ver,
|
||||||
v[i].disk_offset, bad_block, v[i].offset, calc_csum, stored_csum);
|
v[i].disk_offset, bad_block, v[i].offset, calc_csum, stored_csum);
|
||||||
assert(!(bad_block % bs->dsk.csum_block_size) && bad_block < bs->dsk.data_block_size);
|
bad_block += (v[i].offset/bs->dsk.csum_block_size) * bs->dsk.csum_block_size;
|
||||||
mangle_csum_blocks.insert(bad_block);
|
uint32_t bad_block_end = bad_block + bs->dsk.csum_block_size + (v[i].offset/bs->dsk.csum_block_size) * bs->dsk.csum_block_size;
|
||||||
|
if (bad_block < v[i].offset)
|
||||||
|
bad_block = v[i].offset;
|
||||||
|
if (bad_block_end > v[i].offset+v[i].len)
|
||||||
|
bad_block_end = v[i].offset+v[i].len;
|
||||||
|
bad_block -= v[i].offset;
|
||||||
|
bad_block_end -= v[i].offset;
|
||||||
|
for (uint32_t j = bad_block; j < bad_block_end; j += bs->dsk.bitmap_granularity)
|
||||||
|
{
|
||||||
|
// Simplest method of mangling: flip one byte in every sector
|
||||||
|
((uint8_t*)v[i].buf)[j] ^= 0xff;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -970,11 +950,6 @@ void journal_flusher_co::calc_block_checksums(uint32_t *new_data_csums, bool ski
|
|||||||
}
|
}
|
||||||
// `v` should contain aligned items, possibly split into pieces
|
// `v` should contain aligned items, possibly split into pieces
|
||||||
assert(!block_done);
|
assert(!block_done);
|
||||||
for (uint32_t mangle_block: mangle_csum_blocks)
|
|
||||||
{
|
|
||||||
// Flip 1 bit
|
|
||||||
new_data_csums[mangle_block / bs->dsk.csum_block_size] ^= 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void journal_flusher_co::scan_dirty()
|
void journal_flusher_co::scan_dirty()
|
||||||
@@ -1111,8 +1086,7 @@ void journal_flusher_co::scan_dirty()
|
|||||||
last--;
|
last--;
|
||||||
read_to_fill_incomplete = bs->fill_partial_checksum_blocks(
|
read_to_fill_incomplete = bs->fill_partial_checksum_blocks(
|
||||||
v, fulfilled, bmp_ptr, NULL, false, NULL, v[0].offset/bs->dsk.csum_block_size * bs->dsk.csum_block_size,
|
v, fulfilled, bmp_ptr, NULL, false, NULL, v[0].offset/bs->dsk.csum_block_size * bs->dsk.csum_block_size,
|
||||||
((v[last].offset+v[last].len-1) / bs->dsk.csum_block_size + 1) * bs->dsk.csum_block_size,
|
((v[last].offset+v[last].len-1) / bs->dsk.csum_block_size + 1) * bs->dsk.csum_block_size
|
||||||
0, bs->dsk.data_block_size
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if (fill_incomplete && clean_init_bitmap)
|
else if (fill_incomplete && clean_init_bitmap)
|
||||||
@@ -1142,7 +1116,6 @@ bool journal_flusher_co::read_dirty(int wait_base)
|
|||||||
if (wait_state == wait_base) goto resume_0;
|
if (wait_state == wait_base) goto resume_0;
|
||||||
else if (wait_state == wait_base+1) goto resume_1;
|
else if (wait_state == wait_base+1) goto resume_1;
|
||||||
wait_count = wait_journal_count = 0;
|
wait_count = wait_journal_count = 0;
|
||||||
mangle_csum_blocks.clear();
|
|
||||||
if (bs->journal.inmemory && !read_to_fill_incomplete)
|
if (bs->journal.inmemory && !read_to_fill_incomplete)
|
||||||
{
|
{
|
||||||
// Happy path: nothing to read :)
|
// Happy path: nothing to read :)
|
||||||
@@ -1374,7 +1347,7 @@ bool journal_flusher_co::fsync_batch(bool fsync_meta, int wait_base)
|
|||||||
cur_sync->ready_count++;
|
cur_sync->ready_count++;
|
||||||
flusher->syncing_flushers++;
|
flusher->syncing_flushers++;
|
||||||
resume_1:
|
resume_1:
|
||||||
if (cur_sync->state == 0)
|
if (!cur_sync->state)
|
||||||
{
|
{
|
||||||
if (flusher->syncing_flushers >= flusher->active_flushers || !flusher->flush_queue.size())
|
if (flusher->syncing_flushers >= flusher->active_flushers || !flusher->flush_queue.size())
|
||||||
{
|
{
|
||||||
@@ -1402,12 +1375,6 @@ bool journal_flusher_co::fsync_batch(bool fsync_meta, int wait_base)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (cur_sync->state == 1)
|
|
||||||
{
|
|
||||||
// Wait for fsync completion
|
|
||||||
wait_state = wait_base+1;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
flusher->syncing_flushers--;
|
flusher->syncing_flushers--;
|
||||||
cur_sync->ready_count--;
|
cur_sync->ready_count--;
|
||||||
if (cur_sync->ready_count == 0)
|
if (cur_sync->ready_count == 0)
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ class journal_flusher_co
|
|||||||
uint64_t clean_bitmap_offset, clean_bitmap_len;
|
uint64_t clean_bitmap_offset, clean_bitmap_len;
|
||||||
uint8_t *clean_init_dyn_ptr;
|
uint8_t *clean_init_dyn_ptr;
|
||||||
uint8_t *new_clean_bitmap;
|
uint8_t *new_clean_bitmap;
|
||||||
std::unordered_set<uint32_t> mangle_csum_blocks;
|
|
||||||
|
|
||||||
uint64_t new_trim_pos;
|
uint64_t new_trim_pos;
|
||||||
|
|
||||||
@@ -124,7 +123,6 @@ public:
|
|||||||
void loop();
|
void loop();
|
||||||
bool is_trim_wanted() { return trim_wanted; }
|
bool is_trim_wanted() { return trim_wanted; }
|
||||||
bool is_active();
|
bool is_active();
|
||||||
size_t get_queue_size();
|
|
||||||
void mark_trim_possible();
|
void mark_trim_possible();
|
||||||
void request_trim();
|
void request_trim();
|
||||||
void release_trim();
|
void release_trim();
|
||||||
|
|||||||
@@ -6,12 +6,11 @@
|
|||||||
|
|
||||||
namespace v1 {
|
namespace v1 {
|
||||||
|
|
||||||
blockstore_impl_t::blockstore_impl_t(blockstore_config_t & config, ring_loop_i *ringloop, timerfd_manager_t *tfd, bool mock_mode)
|
blockstore_impl_t::blockstore_impl_t(blockstore_config_t & config, ring_loop_i *ringloop, timerfd_manager_t *tfd)
|
||||||
{
|
{
|
||||||
assert(sizeof(blockstore_op_private_t) <= BS_OP_PRIVATE_DATA_SIZE);
|
assert(sizeof(blockstore_op_private_t) <= BS_OP_PRIVATE_DATA_SIZE);
|
||||||
this->tfd = tfd;
|
this->tfd = tfd;
|
||||||
this->ringloop = ringloop;
|
this->ringloop = ringloop;
|
||||||
dsk.mock_mode = mock_mode;
|
|
||||||
ring_consumer.loop = [this]() { loop(); };
|
ring_consumer.loop = [this]() { loop(); };
|
||||||
ringloop->register_consumer(&ring_consumer);
|
ringloop->register_consumer(&ring_consumer);
|
||||||
initialized = 0;
|
initialized = 0;
|
||||||
@@ -36,11 +35,6 @@ blockstore_impl_t::blockstore_impl_t(blockstore_config_t & config, ring_loop_i *
|
|||||||
|
|
||||||
blockstore_impl_t::~blockstore_impl_t()
|
blockstore_impl_t::~blockstore_impl_t()
|
||||||
{
|
{
|
||||||
for (auto& obj: dirty_db)
|
|
||||||
{
|
|
||||||
if (obj.second.dyn_data)
|
|
||||||
free(obj.second.dyn_data);
|
|
||||||
}
|
|
||||||
delete data_alloc;
|
delete data_alloc;
|
||||||
delete flusher;
|
delete flusher;
|
||||||
if (zero_object)
|
if (zero_object)
|
||||||
@@ -861,29 +855,4 @@ 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
|
||||||
|
|||||||
@@ -30,8 +30,6 @@
|
|||||||
|
|
||||||
//#define BLOCKSTORE_DEBUG
|
//#define BLOCKSTORE_DEBUG
|
||||||
|
|
||||||
struct bs_test_t;
|
|
||||||
|
|
||||||
namespace v1 {
|
namespace v1 {
|
||||||
|
|
||||||
#include "journal.h"
|
#include "journal.h"
|
||||||
@@ -98,7 +96,7 @@ struct blockstore_op_private_t
|
|||||||
int op_state;
|
int op_state;
|
||||||
|
|
||||||
// Read
|
// Read
|
||||||
uint64_t clean_loc_used;
|
uint64_t clean_block_used;
|
||||||
std::vector<copy_buffer_t> read_vec;
|
std::vector<copy_buffer_t> read_vec;
|
||||||
|
|
||||||
// Sync, write
|
// Sync, write
|
||||||
@@ -124,7 +122,6 @@ typedef uint64_t pool_pg_id_t;
|
|||||||
|
|
||||||
class blockstore_impl_t: public blockstore_i
|
class blockstore_impl_t: public blockstore_i
|
||||||
{
|
{
|
||||||
friend struct ::bs_test_t;
|
|
||||||
blockstore_disk_t dsk;
|
blockstore_disk_t dsk;
|
||||||
|
|
||||||
/******* OPTIONS *******/
|
/******* OPTIONS *******/
|
||||||
@@ -223,7 +220,6 @@ class blockstore_impl_t: public blockstore_i
|
|||||||
|
|
||||||
// Read
|
// Read
|
||||||
int dequeue_read(blockstore_op_t *read_op);
|
int dequeue_read(blockstore_op_t *read_op);
|
||||||
void release_clean(blockstore_op_t *op);
|
|
||||||
void find_holes(std::vector<copy_buffer_t> & read_vec, uint32_t item_start, uint32_t item_end,
|
void find_holes(std::vector<copy_buffer_t> & read_vec, uint32_t item_start, uint32_t item_end,
|
||||||
std::function<int(int, bool, uint32_t, uint32_t)> callback);
|
std::function<int(int, bool, uint32_t, uint32_t)> callback);
|
||||||
int fulfill_read(blockstore_op_t *read_op,
|
int fulfill_read(blockstore_op_t *read_op,
|
||||||
@@ -234,8 +230,7 @@ class blockstore_impl_t: public blockstore_i
|
|||||||
uint8_t *clean_entry_bitmap, int *dyn_data,
|
uint8_t *clean_entry_bitmap, int *dyn_data,
|
||||||
uint32_t item_start, uint32_t item_end, uint64_t clean_loc, uint64_t clean_ver);
|
uint32_t item_start, uint32_t item_end, uint64_t clean_loc, uint64_t clean_ver);
|
||||||
int fill_partial_checksum_blocks(std::vector<copy_buffer_t> & rv, uint64_t & fulfilled,
|
int fill_partial_checksum_blocks(std::vector<copy_buffer_t> & rv, uint64_t & fulfilled,
|
||||||
uint8_t *clean_entry_bitmap, int *dyn_data, bool from_journal, uint8_t *read_buf,
|
uint8_t *clean_entry_bitmap, int *dyn_data, bool from_journal, uint8_t *read_buf, uint64_t read_offset, uint64_t read_end);
|
||||||
uint32_t read_offset, uint32_t read_end, uint32_t item_start, uint32_t item_end);
|
|
||||||
int pad_journal_read(std::vector<copy_buffer_t> & rv, copy_buffer_t & cp,
|
int pad_journal_read(std::vector<copy_buffer_t> & rv, copy_buffer_t & cp,
|
||||||
uint64_t dirty_offset, uint64_t dirty_end, uint64_t dirty_loc, uint8_t *csum_ptr, int *dyn_data,
|
uint64_t dirty_offset, uint64_t dirty_end, uint64_t dirty_loc, uint8_t *csum_ptr, int *dyn_data,
|
||||||
uint64_t offset, uint64_t submit_len, uint64_t & blk_begin, uint64_t & blk_end, uint8_t* & blk_buf);
|
uint64_t offset, uint64_t submit_len, uint64_t & blk_begin, uint64_t & blk_end, uint8_t* & blk_buf);
|
||||||
@@ -286,7 +281,7 @@ class blockstore_impl_t: public blockstore_i
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
blockstore_impl_t(blockstore_config_t & config, ring_loop_i *ringloop, timerfd_manager_t *tfd, bool mock_mode = false);
|
blockstore_impl_t(blockstore_config_t & config, ring_loop_i *ringloop, timerfd_manager_t *tfd);
|
||||||
~blockstore_impl_t();
|
~blockstore_impl_t();
|
||||||
|
|
||||||
void parse_config(blockstore_config_t & config);
|
void parse_config(blockstore_config_t & config);
|
||||||
@@ -337,10 +332,6 @@ 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
|
||||||
|
|||||||
+68
-83
@@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) Vitaliy Filippov, 2019+
|
// Copyright (c) Vitaliy Filippov, 2019+
|
||||||
// License: VNPL-1.1 (see README.md for details)
|
// License: VNPL-1.1 (see README.md for details)
|
||||||
|
|
||||||
#include "str_util.h"
|
|
||||||
#include "impl.h"
|
#include "impl.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
@@ -31,15 +30,14 @@ blockstore_init_meta::blockstore_init_meta(blockstore_impl_t *bs)
|
|||||||
this->bs = bs;
|
this->bs = bs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void blockstore_init_meta::handle_event(ring_data_t *data, int buf_num, const char *op)
|
void blockstore_init_meta::handle_event(ring_data_t *data, int buf_num)
|
||||||
{
|
{
|
||||||
if (data->res != data->iov.iov_len)
|
if (data->res < 0)
|
||||||
{
|
{
|
||||||
throw std::runtime_error(strprintf(
|
throw std::runtime_error(
|
||||||
"%s failed at offset %ju: got %s (code %d), but expected %zu",
|
std::string("read metadata failed at offset ") + std::to_string(buf_num >= 0 ? bufs[buf_num].offset : last_read_offset) +
|
||||||
op, (buf_num >= 0 ? bufs[buf_num].offset : last_read_offset), strerror(-data->res),
|
std::string(": ") + strerror(-data->res)
|
||||||
data->res, data->iov.iov_len
|
);
|
||||||
));
|
|
||||||
}
|
}
|
||||||
if (buf_num >= 0)
|
if (buf_num >= 0)
|
||||||
{
|
{
|
||||||
@@ -67,11 +65,10 @@ int blockstore_init_meta::loop()
|
|||||||
if (!metadata_buffer)
|
if (!metadata_buffer)
|
||||||
throw std::runtime_error("Failed to allocate metadata read buffer");
|
throw std::runtime_error("Failed to allocate metadata read buffer");
|
||||||
// Read superblock
|
// Read superblock
|
||||||
hdr = (blockstore_meta_header_v2_t *)memalign_or_die(MEM_ALIGNMENT, bs->dsk.meta_block_size);
|
|
||||||
GET_SQE();
|
GET_SQE();
|
||||||
last_read_offset = 0;
|
last_read_offset = 0;
|
||||||
data->iov = { hdr, (size_t)bs->dsk.meta_block_size };
|
data->iov = { metadata_buffer, (size_t)bs->dsk.meta_block_size };
|
||||||
data->callback = [this](ring_data_t *data) { handle_event(data, -1, "read metadata header"); };
|
data->callback = [this](ring_data_t *data) { handle_event(data, -1); };
|
||||||
io_uring_prep_readv(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset);
|
io_uring_prep_readv(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset);
|
||||||
bs->ringloop->submit();
|
bs->ringloop->submit();
|
||||||
submitted++;
|
submitted++;
|
||||||
@@ -81,8 +78,24 @@ resume_1:
|
|||||||
wait_state = 1;
|
wait_state = 1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (iszero((uint64_t*)hdr, bs->dsk.meta_block_size / sizeof(uint64_t)))
|
if (iszero((uint64_t*)metadata_buffer, bs->dsk.meta_block_size / sizeof(uint64_t)))
|
||||||
{
|
{
|
||||||
|
{
|
||||||
|
blockstore_meta_header_v2_t *hdr = (blockstore_meta_header_v2_t *)metadata_buffer;
|
||||||
|
hdr->zero = 0;
|
||||||
|
hdr->magic = BLOCKSTORE_META_MAGIC_V1;
|
||||||
|
hdr->version = bs->dsk.meta_format;
|
||||||
|
hdr->meta_block_size = bs->dsk.meta_block_size;
|
||||||
|
hdr->data_block_size = bs->dsk.data_block_size;
|
||||||
|
hdr->bitmap_granularity = bs->dsk.bitmap_granularity;
|
||||||
|
if (bs->dsk.meta_format >= BLOCKSTORE_META_FORMAT_V2)
|
||||||
|
{
|
||||||
|
hdr->data_csum_type = bs->dsk.data_csum_type;
|
||||||
|
hdr->csum_block_size = bs->dsk.csum_block_size;
|
||||||
|
hdr->header_csum = 0;
|
||||||
|
hdr->header_csum = crc32c(0, hdr, sizeof(*hdr));
|
||||||
|
}
|
||||||
|
}
|
||||||
if (bs->readonly)
|
if (bs->readonly)
|
||||||
{
|
{
|
||||||
printf("Skipping metadata initialization because blockstore is readonly\n");
|
printf("Skipping metadata initialization because blockstore is readonly\n");
|
||||||
@@ -90,11 +103,25 @@ resume_1:
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf("Initializing metadata area\n");
|
printf("Initializing metadata area\n");
|
||||||
|
GET_SQE();
|
||||||
|
last_read_offset = 0;
|
||||||
|
data->iov = (struct iovec){ metadata_buffer, (size_t)bs->dsk.meta_block_size };
|
||||||
|
data->callback = [this](ring_data_t *data) { handle_event(data, -1); };
|
||||||
|
io_uring_prep_writev(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset);
|
||||||
|
bs->ringloop->submit();
|
||||||
|
submitted++;
|
||||||
|
resume_3:
|
||||||
|
if (submitted > 0)
|
||||||
|
{
|
||||||
|
wait_state = 3;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
zero_on_init = true;
|
||||||
}
|
}
|
||||||
zero_on_init = true;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
blockstore_meta_header_v2_t *hdr = (blockstore_meta_header_v2_t *)metadata_buffer;
|
||||||
if (hdr->zero != 0 || hdr->magic != BLOCKSTORE_META_MAGIC_V1 || hdr->version < BLOCKSTORE_META_FORMAT_V1)
|
if (hdr->zero != 0 || hdr->magic != BLOCKSTORE_META_MAGIC_V1 || hdr->version < BLOCKSTORE_META_FORMAT_V1)
|
||||||
{
|
{
|
||||||
printf(
|
printf(
|
||||||
@@ -196,15 +223,12 @@ resume_2:
|
|||||||
GET_SQE();
|
GET_SQE();
|
||||||
assert(bufs[i].size <= 0x7fffffff);
|
assert(bufs[i].size <= 0x7fffffff);
|
||||||
data->iov = { bufs[i].buf, (size_t)bufs[i].size };
|
data->iov = { bufs[i].buf, (size_t)bufs[i].size };
|
||||||
|
data->callback = [this, i](ring_data_t *data) { handle_event(data, i); };
|
||||||
if (!zero_on_init)
|
if (!zero_on_init)
|
||||||
{
|
|
||||||
data->callback = [this, i](ring_data_t *data) { handle_event(data, i, "read metadata"); };
|
|
||||||
io_uring_prep_readv(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + bufs[i].offset);
|
io_uring_prep_readv(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + bufs[i].offset);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Fill metadata with zeroes
|
// Fill metadata with zeroes
|
||||||
data->callback = [this, i](ring_data_t *data) { handle_event(data, i, "clear metadata"); };
|
|
||||||
memset(data->iov.iov_base, 0, data->iov.iov_len);
|
memset(data->iov.iov_base, 0, data->iov.iov_len);
|
||||||
io_uring_prep_writev(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + bufs[i].offset);
|
io_uring_prep_writev(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + bufs[i].offset);
|
||||||
}
|
}
|
||||||
@@ -232,7 +256,7 @@ resume_2:
|
|||||||
GET_SQE();
|
GET_SQE();
|
||||||
assert(bufs[i].size <= 0x7fffffff);
|
assert(bufs[i].size <= 0x7fffffff);
|
||||||
data->iov = { bufs[i].buf, (size_t)bufs[i].size };
|
data->iov = { bufs[i].buf, (size_t)bufs[i].size };
|
||||||
data->callback = [this, i](ring_data_t *data) { handle_event(data, i, "write metadata"); };
|
data->callback = [this, i](ring_data_t *data) { handle_event(data, i); };
|
||||||
io_uring_prep_writev(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + bufs[i].offset);
|
io_uring_prep_writev(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + bufs[i].offset);
|
||||||
bs->ringloop->submit();
|
bs->ringloop->submit();
|
||||||
bufs[i].state = INIT_META_WRITING;
|
bufs[i].state = INIT_META_WRITING;
|
||||||
@@ -261,7 +285,7 @@ resume_2:
|
|||||||
GET_SQE();
|
GET_SQE();
|
||||||
last_read_offset = (1+next_offset)*bs->dsk.meta_block_size;
|
last_read_offset = (1+next_offset)*bs->dsk.meta_block_size;
|
||||||
data->iov = { metadata_buffer, (size_t)bs->dsk.meta_block_size };
|
data->iov = { metadata_buffer, (size_t)bs->dsk.meta_block_size };
|
||||||
data->callback = [this](ring_data_t *data) { handle_event(data, -1, "read metadata"); };
|
data->callback = [this](ring_data_t *data) { handle_event(data, -1); };
|
||||||
io_uring_prep_readv(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + (1+next_offset)*bs->dsk.meta_block_size);
|
io_uring_prep_readv(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + (1+next_offset)*bs->dsk.meta_block_size);
|
||||||
bs->ringloop->submit();
|
bs->ringloop->submit();
|
||||||
submitted++;
|
submitted++;
|
||||||
@@ -278,7 +302,7 @@ resume_5:
|
|||||||
}
|
}
|
||||||
GET_SQE();
|
GET_SQE();
|
||||||
data->iov = { metadata_buffer, (size_t)bs->dsk.meta_block_size };
|
data->iov = { metadata_buffer, (size_t)bs->dsk.meta_block_size };
|
||||||
data->callback = [this](ring_data_t *data) { handle_event(data, -1, "write metadata"); };
|
data->callback = [this](ring_data_t *data) { handle_event(data, -1); };
|
||||||
io_uring_prep_writev(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + (1+next_offset)*bs->dsk.meta_block_size);
|
io_uring_prep_writev(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + (1+next_offset)*bs->dsk.meta_block_size);
|
||||||
bs->ringloop->submit();
|
bs->ringloop->submit();
|
||||||
submitted++;
|
submitted++;
|
||||||
@@ -293,64 +317,27 @@ resume_6:
|
|||||||
}
|
}
|
||||||
// metadata read finished
|
// metadata read finished
|
||||||
printf("Metadata entries loaded: %ju, free blocks: %ju / %ju\n", entries_loaded, bs->data_alloc->get_free_count(), bs->dsk.block_count);
|
printf("Metadata entries loaded: %ju, free blocks: %ju / %ju\n", entries_loaded, bs->data_alloc->get_free_count(), bs->dsk.block_count);
|
||||||
if (zero_on_init && !bs->readonly)
|
|
||||||
{
|
|
||||||
do_fsync:
|
|
||||||
if (!bs->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, "fsync metadata"); };
|
|
||||||
submitted++;
|
|
||||||
bs->ringloop->submit();
|
|
||||||
resume_4:
|
|
||||||
if (submitted > 0)
|
|
||||||
{
|
|
||||||
wait_state = 4;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!header_written)
|
|
||||||
{
|
|
||||||
GET_SQE();
|
|
||||||
hdr->zero = 0;
|
|
||||||
hdr->magic = BLOCKSTORE_META_MAGIC_V1;
|
|
||||||
hdr->version = bs->dsk.meta_format;
|
|
||||||
hdr->meta_block_size = bs->dsk.meta_block_size;
|
|
||||||
hdr->data_block_size = bs->dsk.data_block_size;
|
|
||||||
hdr->bitmap_granularity = bs->dsk.bitmap_granularity;
|
|
||||||
if (bs->dsk.meta_format >= BLOCKSTORE_META_FORMAT_V2)
|
|
||||||
{
|
|
||||||
hdr->data_csum_type = bs->dsk.data_csum_type;
|
|
||||||
hdr->csum_block_size = bs->dsk.csum_block_size;
|
|
||||||
hdr->header_csum = 0;
|
|
||||||
hdr->header_csum = crc32c(0, hdr, sizeof(*hdr));
|
|
||||||
}
|
|
||||||
header_written = true;
|
|
||||||
last_read_offset = 0;
|
|
||||||
data->iov = (struct iovec){ hdr, (size_t)bs->dsk.meta_block_size };
|
|
||||||
data->callback = [this](ring_data_t *data) { handle_event(data, -1, "write metadata header"); };
|
|
||||||
io_uring_prep_writev(sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset);
|
|
||||||
bs->ringloop->submit();
|
|
||||||
submitted++;
|
|
||||||
resume_3:
|
|
||||||
if (submitted > 0)
|
|
||||||
{
|
|
||||||
wait_state = 3;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
goto do_fsync;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!bs->inmemory_meta)
|
if (!bs->inmemory_meta)
|
||||||
{
|
{
|
||||||
free(metadata_buffer);
|
free(metadata_buffer);
|
||||||
metadata_buffer = NULL;
|
metadata_buffer = NULL;
|
||||||
}
|
}
|
||||||
free(hdr);
|
if (zero_on_init && !bs->disable_meta_fsync)
|
||||||
hdr = NULL;
|
{
|
||||||
|
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_4:
|
||||||
|
if (submitted > 0)
|
||||||
|
{
|
||||||
|
wait_state = 4;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,8 +345,6 @@ bool blockstore_init_meta::handle_meta_block(uint8_t *buf, uint64_t entries_per_
|
|||||||
{
|
{
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
uint64_t max_i = entries_per_block;
|
uint64_t max_i = entries_per_block;
|
||||||
if (done_cnt > bs->dsk.block_count)
|
|
||||||
return false;
|
|
||||||
if (max_i > bs->dsk.block_count-done_cnt)
|
if (max_i > bs->dsk.block_count-done_cnt)
|
||||||
max_i = bs->dsk.block_count-done_cnt;
|
max_i = bs->dsk.block_count-done_cnt;
|
||||||
for (uint64_t i = 0; i < max_i; i++)
|
for (uint64_t i = 0; i < max_i; i++)
|
||||||
@@ -470,21 +455,21 @@ blockstore_init_journal::blockstore_init_journal(blockstore_impl_t *bs)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void blockstore_init_journal::handle_event(ring_data_t *data)
|
void blockstore_init_journal::handle_event(ring_data_t *data1)
|
||||||
{
|
{
|
||||||
if (data->res != data->iov.iov_len)
|
if (data1->res <= 0)
|
||||||
{
|
{
|
||||||
throw std::runtime_error(strprintf(
|
throw std::runtime_error(
|
||||||
"read journal failed at offset %ju: got %s (code %d), but expected %zu",
|
std::string("read journal failed at offset ") + std::to_string(journal_pos) +
|
||||||
journal_pos, strerror(-data->res), data->res, data->iov.iov_len
|
std::string(": ") + strerror(-data1->res)
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
done.push_back({
|
done.push_back({
|
||||||
.buf = submitted_buf,
|
.buf = submitted_buf,
|
||||||
.pos = journal_pos,
|
.pos = journal_pos,
|
||||||
.len = (uint64_t)data->res,
|
.len = (uint64_t)data1->res,
|
||||||
});
|
});
|
||||||
journal_pos += data->res;
|
journal_pos += data1->res;
|
||||||
if (journal_pos >= bs->journal.len)
|
if (journal_pos >= bs->journal.len)
|
||||||
{
|
{
|
||||||
// Continue from the beginning
|
// Continue from the beginning
|
||||||
|
|||||||
@@ -16,9 +16,7 @@ class blockstore_init_meta
|
|||||||
blockstore_impl_t *bs;
|
blockstore_impl_t *bs;
|
||||||
int wait_state = 0;
|
int wait_state = 0;
|
||||||
bool zero_on_init = false;
|
bool zero_on_init = false;
|
||||||
bool header_written = false;
|
|
||||||
void *metadata_buffer = NULL;
|
void *metadata_buffer = NULL;
|
||||||
blockstore_meta_header_v2_t *hdr = NULL;
|
|
||||||
blockstore_init_meta_buf bufs[2] = {};
|
blockstore_init_meta_buf bufs[2] = {};
|
||||||
int submitted = 0;
|
int submitted = 0;
|
||||||
struct io_uring_sqe *sqe;
|
struct io_uring_sqe *sqe;
|
||||||
@@ -31,7 +29,7 @@ class blockstore_init_meta
|
|||||||
int i = 0, j = 0;
|
int i = 0, j = 0;
|
||||||
std::vector<uint64_t> entries_to_zero;
|
std::vector<uint64_t> entries_to_zero;
|
||||||
bool handle_meta_block(uint8_t *buf, uint64_t count, uint64_t done_cnt);
|
bool handle_meta_block(uint8_t *buf, uint64_t count, uint64_t done_cnt);
|
||||||
void handle_event(ring_data_t *data, int buf_num, const char *op);
|
void handle_event(ring_data_t *data, int buf_num);
|
||||||
public:
|
public:
|
||||||
blockstore_init_meta(blockstore_impl_t *bs);
|
blockstore_init_meta(blockstore_impl_t *bs);
|
||||||
int loop();
|
int loop();
|
||||||
|
|||||||
@@ -193,7 +193,6 @@ 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
|
||||||
);
|
);
|
||||||
|
|||||||
+54
-145
@@ -101,8 +101,8 @@ int blockstore_impl_t::fulfill_read(blockstore_op_t *read_op,
|
|||||||
.copy_flags = COPY_BUF_JOURNAL|COPY_BUF_CSUM_FILL,
|
.copy_flags = COPY_BUF_JOURNAL|COPY_BUF_CSUM_FILL,
|
||||||
.offset = blk_begin,
|
.offset = blk_begin,
|
||||||
.len = blk_end-blk_begin,
|
.len = blk_end-blk_begin,
|
||||||
.csum_buf = (!csum ? NULL : (csum + (blk_begin/dsk.csum_block_size -
|
.csum_buf = (csum + (blk_begin/dsk.csum_block_size -
|
||||||
item_start/dsk.csum_block_size) * (dsk.data_csum_type & 0xFF))),
|
item_start/dsk.csum_block_size) * (dsk.data_csum_type & 0xFF)),
|
||||||
.dyn_data = dyn_data,
|
.dyn_data = dyn_data,
|
||||||
});
|
});
|
||||||
if (dyn_data)
|
if (dyn_data)
|
||||||
@@ -134,7 +134,7 @@ int blockstore_impl_t::fulfill_read(blockstore_op_t *read_op,
|
|||||||
// If we don't track it then we may IN THEORY read another object's data:
|
// If we don't track it then we may IN THEORY read another object's data:
|
||||||
// submit read -> remove the object -> flush remove -> overwrite with another object -> finish read
|
// submit read -> remove the object -> flush remove -> overwrite with another object -> finish read
|
||||||
// Very improbable, but possible
|
// Very improbable, but possible
|
||||||
PRIV(read_op)->clean_loc_used = UINT64_MAX;
|
PRIV(read_op)->clean_block_used = 1;
|
||||||
}
|
}
|
||||||
rv.insert(rv.begin() + pos, el);
|
rv.insert(rv.begin() + pos, el);
|
||||||
fulfilled += el.len;
|
fulfilled += el.len;
|
||||||
@@ -167,8 +167,7 @@ uint8_t* blockstore_impl_t::get_clean_entry_bitmap(uint64_t block_loc, int offse
|
|||||||
}
|
}
|
||||||
|
|
||||||
int blockstore_impl_t::fill_partial_checksum_blocks(std::vector<copy_buffer_t> & rv, uint64_t & fulfilled,
|
int blockstore_impl_t::fill_partial_checksum_blocks(std::vector<copy_buffer_t> & rv, uint64_t & fulfilled,
|
||||||
uint8_t *clean_entry_bitmap, int *dyn_data, bool from_journal, uint8_t *read_buf,
|
uint8_t *clean_entry_bitmap, int *dyn_data, bool from_journal, uint8_t *read_buf, uint64_t read_offset, uint64_t read_end)
|
||||||
uint32_t read_offset, uint32_t read_end, uint32_t item_start, uint32_t item_end)
|
|
||||||
{
|
{
|
||||||
if (read_end == read_offset)
|
if (read_end == read_offset)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -176,38 +175,10 @@ int blockstore_impl_t::fill_partial_checksum_blocks(std::vector<copy_buffer_t> &
|
|||||||
read_buf -= read_offset;
|
read_buf -= read_offset;
|
||||||
uint32_t last_block = (read_end-1)/dsk.csum_block_size;
|
uint32_t last_block = (read_end-1)/dsk.csum_block_size;
|
||||||
uint32_t start_block = read_offset/dsk.csum_block_size;
|
uint32_t start_block = read_offset/dsk.csum_block_size;
|
||||||
uint32_t item_start_block = item_start/dsk.csum_block_size;
|
|
||||||
uint32_t end_block = 0;
|
uint32_t end_block = 0;
|
||||||
auto zero_range = [&](int pos, bool alloc, uint32_t cur_start, uint32_t cur_end)
|
|
||||||
{
|
|
||||||
if (alloc)
|
|
||||||
return 0;
|
|
||||||
copy_buffer_t el = {
|
|
||||||
.copy_flags = COPY_BUF_ZERO,
|
|
||||||
.offset = cur_start,
|
|
||||||
.len = cur_end-cur_start,
|
|
||||||
};
|
|
||||||
rv.insert(rv.begin() + pos, el);
|
|
||||||
if (read_buf)
|
|
||||||
memset(read_buf + el.offset - read_offset, 0, el.len);
|
|
||||||
fulfilled += el.len;
|
|
||||||
return 1;
|
|
||||||
};
|
|
||||||
if (read_offset < item_start)
|
|
||||||
{
|
|
||||||
// Zero-fill the beginning
|
|
||||||
find_holes(rv, read_offset, item_start, zero_range);
|
|
||||||
read_offset = item_start;
|
|
||||||
}
|
|
||||||
if (read_end > item_end)
|
|
||||||
{
|
|
||||||
// Zero-fill the end
|
|
||||||
find_holes(rv, item_end, read_end, zero_range);
|
|
||||||
read_end = item_end;
|
|
||||||
}
|
|
||||||
while (start_block <= last_block)
|
while (start_block <= last_block)
|
||||||
{
|
{
|
||||||
if (read_range_fulfilled(rv, fulfilled, read_buf, from_journal ? NULL : clean_entry_bitmap,
|
if (read_range_fulfilled(rv, fulfilled, read_buf, clean_entry_bitmap,
|
||||||
start_block*dsk.csum_block_size < read_offset ? read_offset : start_block*dsk.csum_block_size,
|
start_block*dsk.csum_block_size < read_offset ? read_offset : start_block*dsk.csum_block_size,
|
||||||
(start_block+1)*dsk.csum_block_size > read_end ? read_end : (start_block+1)*dsk.csum_block_size))
|
(start_block+1)*dsk.csum_block_size > read_end ? read_end : (start_block+1)*dsk.csum_block_size))
|
||||||
{
|
{
|
||||||
@@ -219,7 +190,7 @@ int blockstore_impl_t::fill_partial_checksum_blocks(std::vector<copy_buffer_t> &
|
|||||||
// Find a sequence of checksum blocks required to be read
|
// Find a sequence of checksum blocks required to be read
|
||||||
end_block = start_block;
|
end_block = start_block;
|
||||||
while ((end_block+1)*dsk.csum_block_size < read_end &&
|
while ((end_block+1)*dsk.csum_block_size < read_end &&
|
||||||
!read_range_fulfilled(rv, fulfilled, read_buf, from_journal ? NULL : clean_entry_bitmap,
|
!read_range_fulfilled(rv, fulfilled, read_buf, clean_entry_bitmap,
|
||||||
(end_block+1)*dsk.csum_block_size < read_offset ? read_offset : (end_block+1)*dsk.csum_block_size,
|
(end_block+1)*dsk.csum_block_size < read_offset ? read_offset : (end_block+1)*dsk.csum_block_size,
|
||||||
(end_block+2)*dsk.csum_block_size > read_end ? read_end : (end_block+2)*dsk.csum_block_size))
|
(end_block+2)*dsk.csum_block_size > read_end ? read_end : (end_block+2)*dsk.csum_block_size))
|
||||||
{
|
{
|
||||||
@@ -231,10 +202,8 @@ int blockstore_impl_t::fill_partial_checksum_blocks(std::vector<copy_buffer_t> &
|
|||||||
.copy_flags = COPY_BUF_CSUM_FILL | (from_journal ? COPY_BUF_JOURNALED_BIG : 0),
|
.copy_flags = COPY_BUF_CSUM_FILL | (from_journal ? COPY_BUF_JOURNALED_BIG : 0),
|
||||||
.offset = start_block*dsk.csum_block_size,
|
.offset = start_block*dsk.csum_block_size,
|
||||||
.len = (end_block-start_block)*dsk.csum_block_size,
|
.len = (end_block-start_block)*dsk.csum_block_size,
|
||||||
// save checksum reference if we're reading clean data from the journal
|
// save clean_entry_bitmap if we're reading clean data from the journal
|
||||||
.csum_buf = from_journal
|
.csum_buf = from_journal ? clean_entry_bitmap : NULL,
|
||||||
? clean_entry_bitmap + dsk.clean_entry_bitmap_size + (start_block-item_start_block)*(dsk.data_csum_type & 0xFF)
|
|
||||||
: NULL,
|
|
||||||
.dyn_data = dyn_data,
|
.dyn_data = dyn_data,
|
||||||
});
|
});
|
||||||
if (dyn_data)
|
if (dyn_data)
|
||||||
@@ -257,11 +226,6 @@ bool blockstore_impl_t::read_range_fulfilled(std::vector<copy_buffer_t> & rv, ui
|
|||||||
{
|
{
|
||||||
if (alloc)
|
if (alloc)
|
||||||
return 0;
|
return 0;
|
||||||
if (!clean_entry_bitmap)
|
|
||||||
{
|
|
||||||
all_done = false;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
int diff = 0;
|
int diff = 0;
|
||||||
uint32_t bmp_start = cur_start/dsk.bitmap_granularity;
|
uint32_t bmp_start = cur_start/dsk.bitmap_granularity;
|
||||||
uint32_t bmp_end = cur_end/dsk.bitmap_granularity;
|
uint32_t bmp_end = cur_end/dsk.bitmap_granularity;
|
||||||
@@ -359,7 +323,7 @@ bool blockstore_impl_t::read_checksum_block(blockstore_op_t *op, int rv_pos, uin
|
|||||||
{
|
{
|
||||||
iov[n_iov++] = (struct iovec){ (uint8_t*)op->buf+cur_start-op->offset, lim_end-cur_start };
|
iov[n_iov++] = (struct iovec){ (uint8_t*)op->buf+cur_start-op->offset, lim_end-cur_start };
|
||||||
rv.insert(rv.begin() + pos, (copy_buffer_t){
|
rv.insert(rv.begin() + pos, (copy_buffer_t){
|
||||||
.copy_flags = COPY_BUF_DATA|COPY_BUF_COALESCED,
|
.copy_flags = COPY_BUF_DATA,
|
||||||
.offset = cur_start,
|
.offset = cur_start,
|
||||||
.len = lim_end-cur_start,
|
.len = lim_end-cur_start,
|
||||||
});
|
});
|
||||||
@@ -397,10 +361,10 @@ bool blockstore_impl_t::read_checksum_block(blockstore_op_t *op, int rv_pos, uin
|
|||||||
PRIV(op)->pending_ops++;
|
PRIV(op)->pending_ops++;
|
||||||
io_uring_prep_readv(sqe, submit_fd, iov + n_pos, n_cur, submit_offset + clean_loc + item_start + d_pos);
|
io_uring_prep_readv(sqe, submit_fd, iov + n_pos, n_cur, submit_offset + clean_loc + item_start + d_pos);
|
||||||
data->callback = [this, op](ring_data_t *data) { handle_read_event(data, op); };
|
data->callback = [this, op](ring_data_t *data) { handle_read_event(data, op); };
|
||||||
if (n_pos > 0 || n_iov > IOV_MAX)
|
if (n_pos > 0 || n_pos + IOV_MAX < n_iov)
|
||||||
{
|
{
|
||||||
uint32_t d_len = 0;
|
uint32_t d_len = 0;
|
||||||
for (int i = 0; i < n_cur; i++)
|
for (int i = 0; i < IOV_MAX; i++)
|
||||||
d_len += iov[n_pos+i].iov_len;
|
d_len += iov[n_pos+i].iov_len;
|
||||||
data->iov.iov_len = d_len;
|
data->iov.iov_len = d_len;
|
||||||
d_pos += d_len;
|
d_pos += d_len;
|
||||||
@@ -412,7 +376,7 @@ bool blockstore_impl_t::read_checksum_block(blockstore_op_t *op, int rv_pos, uin
|
|||||||
{
|
{
|
||||||
// Reads running parallel to flushes of the same clean block may read
|
// Reads running parallel to flushes of the same clean block may read
|
||||||
// a mixture of old and new data. So we don't verify checksums for such blocks.
|
// a mixture of old and new data. So we don't verify checksums for such blocks.
|
||||||
PRIV(op)->clean_loc_used = UINT64_MAX;
|
PRIV(op)->clean_block_used = 1;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -438,7 +402,7 @@ int blockstore_impl_t::dequeue_read(blockstore_op_t *read_op)
|
|||||||
}
|
}
|
||||||
uint64_t fulfilled = 0;
|
uint64_t fulfilled = 0;
|
||||||
PRIV(read_op)->pending_ops = 0;
|
PRIV(read_op)->pending_ops = 0;
|
||||||
PRIV(read_op)->clean_loc_used = 0;
|
PRIV(read_op)->clean_block_used = 0;
|
||||||
auto & rv = PRIV(read_op)->read_vec;
|
auto & rv = PRIV(read_op)->read_vec;
|
||||||
uint64_t result_version = 0;
|
uint64_t result_version = 0;
|
||||||
if (dirty_found)
|
if (dirty_found)
|
||||||
@@ -551,50 +515,26 @@ int blockstore_impl_t::dequeue_read(blockstore_op_t *read_op)
|
|||||||
return 2;
|
return 2;
|
||||||
undo_read:
|
undo_read:
|
||||||
// need to wait. undo added requests, don't dequeue op
|
// need to wait. undo added requests, don't dequeue op
|
||||||
release_clean(read_op);
|
if (dsk.csum_block_size > dsk.bitmap_granularity)
|
||||||
for (auto & vec: rv)
|
|
||||||
{
|
{
|
||||||
if ((vec.copy_flags & COPY_BUF_CSUM_FILL) && vec.buf)
|
for (auto & vec: rv)
|
||||||
{
|
{
|
||||||
free(vec.buf);
|
if ((vec.copy_flags & COPY_BUF_CSUM_FILL) && vec.buf)
|
||||||
vec.buf = NULL;
|
{
|
||||||
}
|
free(vec.buf);
|
||||||
if (vec.dyn_data && --(*vec.dyn_data) == 0) // refcount
|
vec.buf = NULL;
|
||||||
{
|
}
|
||||||
free(vec.dyn_data);
|
if (vec.dyn_data && --(*vec.dyn_data) == 0) // refcount
|
||||||
vec.dyn_data = NULL;
|
{
|
||||||
|
free(vec.dyn_data);
|
||||||
|
vec.dyn_data = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rv.clear();
|
rv.clear();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void blockstore_impl_t::release_clean(blockstore_op_t *op)
|
|
||||||
{
|
|
||||||
if (PRIV(op)->clean_loc_used == UINT64_MAX)
|
|
||||||
{
|
|
||||||
PRIV(op)->clean_loc_used = 0;
|
|
||||||
}
|
|
||||||
if (PRIV(op)->clean_loc_used)
|
|
||||||
{
|
|
||||||
// Release clean data block
|
|
||||||
auto uo_it = used_clean_objects.find(PRIV(op)->clean_loc_used - 1);
|
|
||||||
if (uo_it != used_clean_objects.end())
|
|
||||||
{
|
|
||||||
uo_it->second.refs--;
|
|
||||||
if (uo_it->second.refs <= 0)
|
|
||||||
{
|
|
||||||
if (uo_it->second.was_freed)
|
|
||||||
{
|
|
||||||
data_alloc->set((PRIV(op)->clean_loc_used - 1) / dsk.data_block_size, false);
|
|
||||||
}
|
|
||||||
used_clean_objects.erase(uo_it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PRIV(op)->clean_loc_used = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int blockstore_impl_t::pad_journal_read(std::vector<copy_buffer_t> & rv, copy_buffer_t & cp,
|
int blockstore_impl_t::pad_journal_read(std::vector<copy_buffer_t> & rv, copy_buffer_t & cp,
|
||||||
// FIXME Passing dirty_entry& would be nicer
|
// FIXME Passing dirty_entry& would be nicer
|
||||||
uint64_t dirty_offset, uint64_t dirty_end, uint64_t dirty_loc, uint8_t *csum_ptr, int *dyn_data,
|
uint64_t dirty_offset, uint64_t dirty_end, uint64_t dirty_loc, uint8_t *csum_ptr, int *dyn_data,
|
||||||
@@ -658,15 +598,11 @@ bool blockstore_impl_t::fulfill_clean_read(blockstore_op_t *read_op, uint64_t &
|
|||||||
{
|
{
|
||||||
auto & rv = PRIV(read_op)->read_vec;
|
auto & rv = PRIV(read_op)->read_vec;
|
||||||
int req = fill_partial_checksum_blocks(rv, fulfilled, clean_entry_bitmap, dyn_data, from_journal,
|
int req = fill_partial_checksum_blocks(rv, fulfilled, clean_entry_bitmap, dyn_data, from_journal,
|
||||||
(uint8_t*)read_op->buf, read_op->offset, read_op->offset+read_op->len, item_start, item_end);
|
(uint8_t*)read_op->buf, read_op->offset, read_op->offset+read_op->len);
|
||||||
if (!inmemory_meta && !from_journal && req > 0)
|
if (!inmemory_meta && !from_journal && req > 0)
|
||||||
{
|
{
|
||||||
// Read checksums from disk
|
// Read checksums from disk
|
||||||
uint8_t *csum_buf = read_clean_meta_block(read_op, clean_loc, rv.size()-req);
|
uint8_t *csum_buf = read_clean_meta_block(read_op, clean_loc, rv.size()-req);
|
||||||
if (!csum_buf)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (int i = req; i > 0; i--)
|
for (int i = req; i > 0; i--)
|
||||||
{
|
{
|
||||||
rv[rv.size()-i].csum_buf = csum_buf;
|
rv[rv.size()-i].csum_buf = csum_buf;
|
||||||
@@ -679,7 +615,7 @@ bool blockstore_impl_t::fulfill_clean_read(blockstore_op_t *read_op, uint64_t &
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PRIV(read_op)->clean_loc_used = req > 0 ? UINT64_MAX : 0;
|
PRIV(read_op)->clean_block_used = req > 0;
|
||||||
}
|
}
|
||||||
else if (from_journal)
|
else if (from_journal)
|
||||||
{
|
{
|
||||||
@@ -729,10 +665,6 @@ bool blockstore_impl_t::fulfill_clean_read(blockstore_op_t *read_op, uint64_t &
|
|||||||
{
|
{
|
||||||
// Read checksums from disk
|
// Read checksums from disk
|
||||||
csum_buf = read_clean_meta_block(read_op, clean_loc, PRIV(read_op)->read_vec.size());
|
csum_buf = read_clean_meta_block(read_op, clean_loc, PRIV(read_op)->read_vec.size());
|
||||||
if (!csum_buf)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
csum_done = true;
|
csum_done = true;
|
||||||
}
|
}
|
||||||
uint8_t *csum = !dsk.csum_block_size ? 0 : (csum_buf + 2*dsk.clean_entry_bitmap_size + bmp_start*(dsk.data_csum_type & 0xFF));
|
uint8_t *csum = !dsk.csum_block_size ? 0 : (csum_buf + 2*dsk.clean_entry_bitmap_size + bmp_start*(dsk.data_csum_type & 0xFF));
|
||||||
@@ -747,13 +679,13 @@ bool blockstore_impl_t::fulfill_clean_read(blockstore_op_t *read_op, uint64_t &
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Increment reference counter if clean data is being read from the disk
|
// Increment reference counter if clean data is being read from the disk
|
||||||
if (PRIV(read_op)->clean_loc_used == UINT64_MAX)
|
if (PRIV(read_op)->clean_block_used)
|
||||||
{
|
{
|
||||||
auto & uo = used_clean_objects[clean_loc];
|
auto & uo = used_clean_objects[clean_loc];
|
||||||
uo.refs++;
|
uo.refs++;
|
||||||
if (dsk.csum_block_size && flusher->is_mutated(clean_loc))
|
if (dsk.csum_block_size && flusher->is_mutated(clean_loc))
|
||||||
uo.was_changed = true;
|
uo.was_changed = true;
|
||||||
PRIV(read_op)->clean_loc_used = clean_loc + 1;
|
PRIV(read_op)->clean_block_used = clean_loc;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -793,18 +725,12 @@ bool blockstore_impl_t::verify_padded_checksums(uint8_t *clean_entry_bitmap, uin
|
|||||||
while (pos < iov[i].iov_len)
|
while (pos < iov[i].iov_len)
|
||||||
{
|
{
|
||||||
uint32_t start = pos;
|
uint32_t start = pos;
|
||||||
uint8_t bit = 1;
|
uint8_t bit = (clean_entry_bitmap[bmp_pos >> 3] >> (bmp_pos & 0x7)) & 1;
|
||||||
if (clean_entry_bitmap)
|
while (pos < iov[i].iov_len && ((clean_entry_bitmap[bmp_pos >> 3] >> (bmp_pos & 0x7)) & 1) == bit)
|
||||||
{
|
{
|
||||||
bit = (clean_entry_bitmap[bmp_pos >> 3] >> (bmp_pos & 0x7)) & 1;
|
pos += dsk.bitmap_granularity;
|
||||||
while (pos < iov[i].iov_len && ((clean_entry_bitmap[bmp_pos >> 3] >> (bmp_pos & 0x7)) & 1) == bit)
|
bmp_pos++;
|
||||||
{
|
|
||||||
pos += dsk.bitmap_granularity;
|
|
||||||
bmp_pos++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
pos = iov[i].iov_len;
|
|
||||||
uint32_t len = pos-start;
|
uint32_t len = pos-start;
|
||||||
auto buf = (uint8_t*)iov[i].iov_base+start;
|
auto buf = (uint8_t*)iov[i].iov_base+start;
|
||||||
while (block_done+len >= dsk.csum_block_size)
|
while (block_done+len >= dsk.csum_block_size)
|
||||||
@@ -881,7 +807,7 @@ bool blockstore_impl_t::verify_clean_padded_checksums(blockstore_op_t *op, uint6
|
|||||||
{
|
{
|
||||||
uint32_t offset = clean_loc % dsk.data_block_size;
|
uint32_t offset = clean_loc % dsk.data_block_size;
|
||||||
if (from_journal)
|
if (from_journal)
|
||||||
return verify_padded_checksums(NULL, dyn_data, offset, iov, n_iov, bad_block_cb);
|
return verify_padded_checksums(dyn_data, dyn_data + dsk.clean_entry_bitmap_size, offset, iov, n_iov, bad_block_cb);
|
||||||
clean_loc = (clean_loc / dsk.data_block_size) * dsk.data_block_size;
|
clean_loc = (clean_loc / dsk.data_block_size) * dsk.data_block_size;
|
||||||
if (!dyn_data)
|
if (!dyn_data)
|
||||||
{
|
{
|
||||||
@@ -909,7 +835,7 @@ void blockstore_impl_t::handle_read_event(ring_data_t *data, blockstore_op_t *op
|
|||||||
void *meta_block = NULL;
|
void *meta_block = NULL;
|
||||||
if (dsk.csum_block_size > dsk.bitmap_granularity)
|
if (dsk.csum_block_size > dsk.bitmap_granularity)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < rv.size(); i++)
|
for (int i = rv.size()-1; i >= 0 && (rv[i].copy_flags & COPY_BUF_CSUM_FILL); i--)
|
||||||
{
|
{
|
||||||
if (rv[i].copy_flags & COPY_BUF_META_BLOCK)
|
if (rv[i].copy_flags & COPY_BUF_META_BLOCK)
|
||||||
{
|
{
|
||||||
@@ -919,41 +845,8 @@ void blockstore_impl_t::handle_read_event(ring_data_t *data, blockstore_op_t *op
|
|||||||
rv[i].buf = NULL;
|
rv[i].buf = NULL;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (rv[i].copy_flags & COPY_BUF_ZERO)
|
struct iovec *iov = (struct iovec*)((uint8_t*)rv[i].buf + (rv[i].len & 0xFFFFFFFF));
|
||||||
{
|
int n_iov = rv[i].len >> 32;
|
||||||
// Zero read
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (rv[i].copy_flags & COPY_BUF_COALESCED)
|
|
||||||
{
|
|
||||||
// Sub-block shared with another read. Skip
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ((rv[i].copy_flags & COPY_BUF_JOURNAL) && journal.inmemory)
|
|
||||||
{
|
|
||||||
// Do not check journal checksums in-memory
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
iovec single_iov = {};
|
|
||||||
iovec *iov = NULL;
|
|
||||||
int n_iov = 0;
|
|
||||||
if (rv[i].copy_flags & COPY_BUF_CSUM_FILL)
|
|
||||||
{
|
|
||||||
// Padded, buffer list passed using a 'creepy way'
|
|
||||||
iov = (struct iovec*)((uint8_t*)rv[i].buf + (rv[i].len & 0xFFFFFFFF));
|
|
||||||
n_iov = rv[i].len >> 32;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Not padded, buffer is fully within the input buffer
|
|
||||||
assert(op->buf);
|
|
||||||
assert(rv[i].csum_buf);
|
|
||||||
iov = &single_iov;
|
|
||||||
n_iov = 1;
|
|
||||||
assert(rv[i].offset >= op->offset);
|
|
||||||
assert(rv[i].offset + rv[i].len <= op->offset + op->len);
|
|
||||||
single_iov = { .iov_base = op->buf + rv[i].offset - op->offset, .iov_len = rv[i].len };
|
|
||||||
}
|
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
if (rv[i].copy_flags & COPY_BUF_JOURNAL)
|
if (rv[i].copy_flags & COPY_BUF_JOURNAL)
|
||||||
{
|
{
|
||||||
@@ -1051,7 +944,23 @@ void blockstore_impl_t::handle_read_event(ring_data_t *data, blockstore_op_t *op
|
|||||||
meta_block = NULL;
|
meta_block = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
release_clean(op);
|
if (PRIV(op)->clean_block_used)
|
||||||
|
{
|
||||||
|
// Release clean data block
|
||||||
|
auto uo_it = used_clean_objects.find(PRIV(op)->clean_block_used);
|
||||||
|
if (uo_it != used_clean_objects.end())
|
||||||
|
{
|
||||||
|
uo_it->second.refs--;
|
||||||
|
if (uo_it->second.refs <= 0)
|
||||||
|
{
|
||||||
|
if (uo_it->second.was_freed)
|
||||||
|
{
|
||||||
|
data_alloc->set(PRIV(op)->clean_block_used, false);
|
||||||
|
}
|
||||||
|
used_clean_objects.erase(uo_it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!journal.inmemory)
|
if (!journal.inmemory)
|
||||||
{
|
{
|
||||||
// Release journal sector usage
|
// Release journal sector usage
|
||||||
|
|||||||
@@ -491,7 +491,7 @@ void blockstore_impl_t::mark_stable(obj_ver_id v, bool forget_dirty)
|
|||||||
if (!exists)
|
if (!exists)
|
||||||
{
|
{
|
||||||
uint64_t space_id = dirty_it->first.oid.inode;
|
uint64_t space_id = dirty_it->first.oid.inode;
|
||||||
if (no_inode_stats.find(dirty_it->first.oid.inode >> (64-POOL_ID_BITS)) != no_inode_stats.end())
|
if (no_inode_stats[dirty_it->first.oid.inode >> (64-POOL_ID_BITS)])
|
||||||
space_id = space_id & ~(((uint64_t)1 << (64-POOL_ID_BITS)) - 1);
|
space_id = space_id & ~(((uint64_t)1 << (64-POOL_ID_BITS)) - 1);
|
||||||
inode_space_stats[space_id] += dsk.data_block_size;
|
inode_space_stats[space_id] += dsk.data_block_size;
|
||||||
used_blocks++;
|
used_blocks++;
|
||||||
@@ -501,7 +501,7 @@ void blockstore_impl_t::mark_stable(obj_ver_id v, bool forget_dirty)
|
|||||||
else if (IS_DELETE(dirty_it->second.state))
|
else if (IS_DELETE(dirty_it->second.state))
|
||||||
{
|
{
|
||||||
uint64_t space_id = dirty_it->first.oid.inode;
|
uint64_t space_id = dirty_it->first.oid.inode;
|
||||||
if (no_inode_stats.find(dirty_it->first.oid.inode >> (64-POOL_ID_BITS)) != no_inode_stats.end())
|
if (no_inode_stats[dirty_it->first.oid.inode >> (64-POOL_ID_BITS)])
|
||||||
space_id = space_id & ~(((uint64_t)1 << (64-POOL_ID_BITS)) - 1);
|
space_id = space_id & ~(((uint64_t)1 << (64-POOL_ID_BITS)) - 1);
|
||||||
auto & sp = inode_space_stats[space_id];
|
auto & sp = inode_space_stats[space_id];
|
||||||
if (sp > dsk.data_block_size)
|
if (sp > dsk.data_block_size)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user