-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
20be0a0
commit 5a1d5f8
Showing
5 changed files
with
285 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
name: Kernel Panic | ||
|
||
on: | ||
push: | ||
pull_request: | ||
workflow_dispatch: | ||
|
||
env: | ||
CARGO_TERM_COLOR: always | ||
|
||
jobs: | ||
kernel-panic: | ||
name: Kernel Panic | ||
runs-on: ubuntu-latest | ||
strategy: | ||
fail-fast: false | ||
matrix: | ||
fstype: | ||
- btrfs | ||
- ext3 | ||
- ext4 | ||
- xfs | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- uses: actions-rs/toolchain@v1 | ||
with: | ||
toolchain: stable | ||
- name: Install qemu | ||
run: | | ||
sudo apt-get update | ||
sudo apt-get install -y qemu-system-x86 | ||
- name: Install ${{ matrix.fstype }} tools | ||
run: | | ||
sudo apt-get update | ||
case ${{ matrix.fstype }} in | ||
btrfs) sudo apt-get install -y btrfs-progs ;; | ||
ext*) sudo apt-get install -y e2fsprogs ;; | ||
xfs) sudo apt-get install -y xfsprogs ;; | ||
esac | ||
- name: Copy current kernel | ||
run: | | ||
sudo cp "/boot/vmlinuz-$(uname -r)" . | ||
sudo chmod a+r "vmlinuz-$(uname -r)" | ||
- name: Run kernel panic test | ||
run: | | ||
tests/linux-kernel-panic/run-test.sh --kernel "vmlinuz-$(uname -r)" --filesystem-type ${{ matrix.fstype }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
[package] | ||
name = "atomic-write-file-test" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
atomic-write-file = { path = "../.." } | ||
nix = "0.28.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
#!/bin/sh -e | ||
|
||
echo 'Mounting /proc' | ||
mount -t proc none /proc | ||
echo 'Mounting /sys' | ||
mount -t sysfs none /sys | ||
echo 'Mounting /test' | ||
fstype=$(grep -Eo 'test.fs=\w+' /proc/cmdline | cut -d= -f2) | ||
modprobe "$fstype" || true | ||
mount -t "$fstype" /dev/sdb /test | ||
|
||
if grep -q test.verify /proc/cmdline; then | ||
echo 'Verifying test file contents' | ||
echo '-----' | ||
xxd /test/file | ||
echo '-----' | ||
fi | ||
|
||
echo 'Running test binary' | ||
atomic-write-file-test | ||
|
||
echo 'Done' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
#!/bin/bash | ||
|
||
set -o errexit | ||
set -o nounset | ||
set -o pipefail | ||
|
||
status=$'\e[1;32m' | ||
error=$'\e[1;31m' | ||
reset=$'\e[0m' | ||
|
||
qemu=qemu-system-$(uname -m) | ||
kernel=/boot/vmlinuz-$(uname -r) | ||
modules=/usr/lib/modules/$(uname -r) | ||
|
||
busybox=$(which busybox) | ||
init_script=init.sh | ||
test_bin=target/release/atomic-write-file-test | ||
|
||
filesystem_type=ext4 | ||
|
||
build_dir=build | ||
initramfs_build_dir=$build_dir/rootfs | ||
initramfs=$build_dir/rootfs.img | ||
testfs=$build_dir/testfs.img | ||
output=$build_dir/output.txt | ||
|
||
options=$(getopt --name "$0" --options k:m:f: --long kernel:,modules:,filesystem-type: -- "$@") | ||
|
||
eval set -- "$options" | ||
|
||
while true; do | ||
case "$1" in | ||
-k|--kernel) | ||
kernel=$(readlink -f "$2") | ||
shift 2 | ||
;; | ||
-m|--modules) | ||
modules=$(readlink -f "$2") | ||
shift 2 | ||
;; | ||
-f|--filesystem-type) | ||
filesystem_type=$2 | ||
shift 2 | ||
;; | ||
--) | ||
shift | ||
break | ||
;; | ||
esac | ||
done | ||
|
||
if [[ $# -ne 0 ]]; then | ||
echo "$0: extra arguments: $*" >&2 | ||
exit 1 | ||
fi | ||
|
||
cd "$(dirname "$(readlink -f "$0")")" | ||
|
||
# | ||
# Compile the test binary running atomic-write-file | ||
# | ||
# This needs to be a statically-linked binary because the root filesystem won't | ||
# ship with libc | ||
# | ||
|
||
echo "${status}Compiling${reset} static binary at $test_bin" | ||
RUSTFLAGS='-C target-feature=+crt-static' cargo build --release | ||
|
||
# | ||
# Create the root filesystem and put it into an initramfs | ||
# | ||
# The root filesystem contains: | ||
# - busybox (to provide /bin/sh and other basic tools) | ||
# - the test binary | ||
# - an init script | ||
# - kernel modules (to support uncommon filesystems like btrfs) | ||
# | ||
|
||
echo "${status}Building${reset} initramfs at $initramfs" | ||
echo " Using busybox at $busybox" | ||
echo " Using modules at $modules" | ||
echo " Using $init_script as /sbin/init" | ||
|
||
rm -rf "$initramfs" "$initramfs_build_dir" | ||
|
||
echo " ${status}Creating${reset} filesystem" | ||
|
||
mkdir -p \ | ||
"$initramfs_build_dir/bin" \ | ||
"$initramfs_build_dir/dev" \ | ||
"$initramfs_build_dir/lib" \ | ||
"$initramfs_build_dir/proc" \ | ||
"$initramfs_build_dir/sbin" \ | ||
"$initramfs_build_dir/sys" \ | ||
"$initramfs_build_dir/test" \ | ||
"$initramfs_build_dir/usr" | ||
|
||
ln -s ../bin "$initramfs_build_dir/usr/bin" | ||
ln -s ../lib "$initramfs_build_dir/usr/lib" | ||
|
||
cp "$init_script" -T "$initramfs_build_dir/sbin/init" | ||
cp "$test_bin" -t "$initramfs_build_dir/bin" | ||
cp "$busybox" -t "$initramfs_build_dir/bin" | ||
"$busybox" --install -s "$initramfs_build_dir/bin" | ||
|
||
echo " ${status}Adding${reset} uncompressed kernel modules" | ||
|
||
mkdir -p "$initramfs_build_dir/lib/modules" | ||
cp -a "$modules" -t "$initramfs_build_dir/lib/modules" | ||
|
||
include_mods=( "$filesystem_type" ) | ||
|
||
for mod in "${include_mods[@]}"; do | ||
while read -r mod_path; do | ||
if [[ "$mod_path" = *.ko.gz ]]; then | ||
gunzip "$mod_path" -o "$mod_path.uncompressed" | ||
elif [[ "$mod_path" = *.ko.xz ]]; then | ||
unxz "$mod_path" -o "$mod_path.uncompressed" | ||
elif [[ "$mod_path" = *.ko.zst ]]; then | ||
unzstd "$mod_path" -o "$mod_path.uncompressed" | ||
else | ||
continue | ||
fi | ||
mv "$mod_path.uncompressed" "$mod_path" | ||
done < <(modprobe --dirname "$initramfs_build_dir" --show-depends "$mod" | grep ^insmod | cut -d' ' -f2) | ||
done | ||
|
||
echo " ${status}Creating${reset} squashfs file" | ||
|
||
mksquashfs "$initramfs_build_dir" "$initramfs" | ||
|
||
# | ||
# Create the filesystem used for testing | ||
# | ||
|
||
echo "${status}Creating${reset} test $filesystem_type filesystem at $testfs" | ||
|
||
dd if=/dev/zero of="$testfs" bs=1M count=200 | ||
"mkfs.$filesystem_type" "$testfs" | ||
|
||
# | ||
# Run the virtual machine | ||
# | ||
# This will create a file with atomic-write-file and then trigger a kernel | ||
# panic | ||
# | ||
|
||
echo "${status}Running${reset} virtual machine to write test file" | ||
echo " Using qemu at $qemu" | ||
echo " Using kernel at $kernel" | ||
echo " Using initramfs at $initramfs" | ||
|
||
"$qemu" \ | ||
-kernel "$kernel" \ | ||
-append "root=/dev/sda ro panic=-1 console=ttyS0 quiet test.fs=$filesystem_type" \ | ||
-drive "index=0,media=disk,format=raw,file=$initramfs" \ | ||
-drive "index=1,media=disk,format=raw,file=$testfs" \ | ||
-no-reboot \ | ||
-nographic | ||
|
||
# | ||
# Run the virtual machine, again, to verify the file contents | ||
# | ||
|
||
echo "${status}Re-running${reset} virtual machine to verify test file contents" | ||
echo " Using qemu at $qemu" | ||
echo " Using kernel at $kernel" | ||
echo " Using initramfs at $initramfs" | ||
|
||
"$qemu" \ | ||
-kernel "$kernel" \ | ||
-append "root=/dev/sda ro panic=-1 console=ttyS0 quiet test.fs=$filesystem_type test.verify" \ | ||
-drive "index=0,media=disk,format=raw,file=$initramfs" \ | ||
-drive "index=1,media=disk,format=raw,file=$testfs" \ | ||
-no-reboot \ | ||
-nographic \ | ||
| tee "$output" | ||
|
||
if [[ $(sed -n '/-----/, /-----/p' "$output" | xxd -r) = hello ]]; then | ||
echo "${status}Success${reset}" | ||
else | ||
echo "${error}Failure${reset}" | ||
exit 1 | ||
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
use atomic_write_file::AtomicWriteFile; | ||
use nix::fcntl::open; | ||
use nix::fcntl::OFlag; | ||
use nix::sys::stat::Mode; | ||
use nix::unistd::close; | ||
use nix::unistd::fsync; | ||
use std::io::Write; | ||
|
||
fn main() { | ||
let mut file = AtomicWriteFile::open("/test/file").expect("open failed"); | ||
file.write_all(b"hello").expect("write failed"); | ||
file.commit().expect("commit failed"); | ||
|
||
let dir = open( | ||
"/test", | ||
OFlag::O_DIRECTORY | OFlag::O_CLOEXEC, | ||
Mode::empty(), | ||
) | ||
.expect("open directory failed"); | ||
|
||
fsync(dir).expect("directory sync failed"); | ||
close(dir).expect("closing directory failed"); | ||
} |