mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-17 16:47:50 +00:00
test/others: Cover all-raw compression entries
Compression can fall back to raw storage for every block in an entry. The writer then omits compression metadata so restore can use ordinary I/O, but that fast path also depends on a page-aligned payload. Add per-page and region tests with an incompressible mapping. Inspect the pagemap for an aligned 56-page entry without compression metadata, while requiring another genuine LZ4 block to prove compression was active. Restore through direct image I/O, require native AIO when O_DIRECT is available, and verify the workload contents. Run the test in CI when page compression is available. Assisted-by: Codex:GPT-5 Signed-off-by: Radostin Stoyanov <rstoyanov@fedoraproject.org>
This commit is contained in:
parent
f5fc0ddb56
commit
deeb0f8a82
5 changed files with 189 additions and 0 deletions
|
|
@ -367,6 +367,13 @@ run_non_shardable_tests() {
|
|||
echo "Skipping compression/incremental test"
|
||||
fi
|
||||
|
||||
# Raw compression fallback image format.
|
||||
if criu/criu check --feature compress; then
|
||||
make -C test/others/compression/raw run
|
||||
else
|
||||
echo "Skipping compression/raw test"
|
||||
fi
|
||||
|
||||
./test/zdtm.py run -t zdtm/transition/pid_reuse --pre 2 # start time based pid reuse detection
|
||||
./test/zdtm.py run -t zdtm/transition/pidfd_store_sk --rpc --pre 2 # pidfd based pid reuse detection
|
||||
|
||||
|
|
|
|||
1
test/others/compression/raw/.gitignore
vendored
Normal file
1
test/others/compression/raw/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
dump-raw-*/
|
||||
3
test/others/compression/raw/Makefile
Normal file
3
test/others/compression/raw/Makefile
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
run:
|
||||
./run.sh
|
||||
.PHONY: run
|
||||
86
test/others/compression/raw/check_raw_entry.py
Normal file
86
test/others/compression/raw/check_raw_entry.py
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
import pycriu.images
|
||||
|
||||
|
||||
PE_PRESENT = 4
|
||||
PE_PAYLOAD_ALIGNED = 8
|
||||
|
||||
|
||||
def check_raw_entry(directory, pid):
|
||||
path = os.path.join(directory, "pagemap-%s.img" % pid)
|
||||
|
||||
with open(path, "rb") as image:
|
||||
entries = pycriu.images.load(image)["entries"][1:]
|
||||
|
||||
page_size = os.sysconf("SC_PAGE_SIZE")
|
||||
payload_offset = 0
|
||||
found = False
|
||||
found_lz4 = False
|
||||
for entry in entries:
|
||||
flags = int(entry.get("flags", 0))
|
||||
if not flags & PE_PRESENT:
|
||||
continue
|
||||
if flags & PE_PAYLOAD_ALIGNED:
|
||||
payload_offset = (payload_offset + page_size - 1) & -page_size
|
||||
|
||||
is_raw_target = (
|
||||
int(entry.get("nr_pages", 0)) == 56
|
||||
and "compressed_size" not in entry
|
||||
and "total_compressed_size" not in entry
|
||||
and "region_pages" not in entry
|
||||
)
|
||||
if is_raw_target:
|
||||
if not flags & PE_PAYLOAD_ALIGNED:
|
||||
print("FAIL: all-raw entry lacks PE_PAYLOAD_ALIGNED in %s" % path)
|
||||
return 1
|
||||
if payload_offset % page_size:
|
||||
print(
|
||||
"FAIL: all-raw entry starts at unaligned offset %d"
|
||||
% payload_offset
|
||||
)
|
||||
return 1
|
||||
found = True
|
||||
|
||||
compressed_sizes = entry.get("compressed_size")
|
||||
if compressed_sizes:
|
||||
block_pages = int(entry.get("region_pages", 0)) or 1
|
||||
remaining = int(entry.get("nr_pages", 0))
|
||||
for size in compressed_sizes:
|
||||
pages = min(block_pages, remaining)
|
||||
if 0 < int(size) < pages * page_size:
|
||||
found_lz4 = True
|
||||
remaining -= pages
|
||||
payload_offset += sum(int(size) for size in compressed_sizes)
|
||||
else:
|
||||
payload_offset += int(entry.get("nr_pages", 0)) * page_size
|
||||
|
||||
if not found:
|
||||
print(
|
||||
"FAIL: no aligned 56-page all-raw entry without compression metadata "
|
||||
"in %s" % path
|
||||
)
|
||||
return 1
|
||||
if not found_lz4:
|
||||
print("FAIL: compression test produced no LZ4-compressed block in %s" % path)
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Validate raw-fallback pagemap metadata"
|
||||
)
|
||||
parser.add_argument("directory")
|
||||
parser.add_argument("pid")
|
||||
args = parser.parse_args()
|
||||
return check_raw_entry(args.directory, args.pid)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
92
test/others/compression/raw/run.sh
Executable file
92
test/others/compression/raw/run.sh
Executable file
|
|
@ -0,0 +1,92 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Verify that entries made entirely of compression raw fallbacks use the
|
||||
# ordinary uncompressed pagemap representation and still restore correctly.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# shellcheck source=test/others/env.sh
|
||||
source ../../env.sh
|
||||
|
||||
CRIU_CMD=("${CRIU}" --no-default-config)
|
||||
ZDTM_DIR="../../../zdtm/static"
|
||||
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
|
||||
RAW_ENTRY_CHECK="${SCRIPT_DIR}/check_raw_entry.py"
|
||||
PID=""
|
||||
|
||||
function fail {
|
||||
echo "FAIL: $*"
|
||||
exit 1
|
||||
}
|
||||
|
||||
function cleanup {
|
||||
if [ -n "$PID" ] && kill -0 "$PID" 2>/dev/null; then
|
||||
kill -TERM "$PID" 2>/dev/null || true
|
||||
for _ in $(seq 1 50); do
|
||||
kill -0 "$PID" 2>/dev/null || break
|
||||
sleep 0.1
|
||||
done
|
||||
if kill -0 "$PID" 2>/dev/null; then
|
||||
kill -KILL "$PID" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
rm -rf dump-raw-*
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
function start_test {
|
||||
(
|
||||
cd "$ZDTM_DIR" || exit 1
|
||||
make compress_pages00.cleanout
|
||||
make compress_pages00
|
||||
make compress_pages00.pid || exit 1
|
||||
)
|
||||
|
||||
PID=$(cat "$ZDTM_DIR/compress_pages00.pid")
|
||||
kill -0 "$PID" || fail "Test didn't start"
|
||||
}
|
||||
|
||||
function stop_test {
|
||||
(
|
||||
cd "$ZDTM_DIR" || exit 1
|
||||
make compress_pages00.stop
|
||||
grep PASS compress_pages00.out || exit 1
|
||||
) || fail "$1: memory content verification failed"
|
||||
PID=""
|
||||
}
|
||||
|
||||
function assert_raw_entry {
|
||||
local directory="$1"
|
||||
|
||||
PYTHONPATH="${BASE_DIR}/lib${PYTHONPATH:+:${PYTHONPATH}}" \
|
||||
python3 "$RAW_ENTRY_CHECK" "$directory" "$PID"
|
||||
}
|
||||
|
||||
function run_mode {
|
||||
local name="$1"
|
||||
shift
|
||||
local imgdir="dump-raw-$name"
|
||||
|
||||
rm -rf "$imgdir"
|
||||
mkdir "$imgdir"
|
||||
start_test
|
||||
|
||||
"${CRIU_CMD[@]}" dump -D "$imgdir" -o dump.log -t "$PID" -v4 "$@" \
|
||||
|| fail "$name: dump failed"
|
||||
assert_raw_entry "$imgdir" || fail "$name: raw-entry metadata check failed"
|
||||
"${CRIU_CMD[@]}" restore -D "$imgdir" -o restore.log -v4 -d \
|
||||
--image-io-mode direct \
|
||||
|| fail "$name: restore failed"
|
||||
if grep -q "O_DIRECT enabled on pages fd" "$imgdir/restore.log"; then
|
||||
grep -q "Restoring delayed VMA I/O with native AIO" \
|
||||
"$imgdir/restore.log" || \
|
||||
fail "$name: aligned raw ranges did not use direct AIO"
|
||||
fi
|
||||
stop_test "$name"
|
||||
}
|
||||
|
||||
run_mode page --compress
|
||||
run_mode region --compress-region=64K
|
||||
|
||||
echo "Test PASSED"
|
||||
Loading…
Add table
Add a link
Reference in a new issue