diff --git a/.cargo/config.toml b/.cargo/config.toml index fe0b7da..22790b2 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -3,6 +3,7 @@ rustflags = ["--cfg=web_sys_unstable_apis"] [alias] gadget-musl-aarch64 = ["build", "-p", "smoo-gadget-cli", "--release", "--target", "aarch64-unknown-linux-musl"] +gadget-musl-armv7 = ["build", "-p", "smoo-gadget-cli", "--release", "--target", "armv7-unknown-linux-musleabihf"] gadget-musl-x86_64 = ["build", "-p", "smoo-gadget-cli", "--release", "--target", "x86_64-unknown-linux-musl"] xtask = ["run", "--quiet", "--package", "xtask", "--"] @@ -10,6 +11,10 @@ xtask = ["run", "--quiet", "--package", "xtask", "--"] linker = "rust-lld" rustflags = ["-C", "target-feature=+crt-static"] +[target.armv7-unknown-linux-musleabihf] +linker = "rust-lld" +rustflags = ["-C", "target-feature=+crt-static", "--cfg=io_uring_skip_arch_check"] + [target.x86_64-unknown-linux-musl] linker = "rust-lld" rustflags = ["-C", "target-feature=+crt-static"] diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ab3f7db..67f9f96 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -53,9 +53,24 @@ jobs: - name: x86_64 runner: ubuntu-24.04 target: x86_64-unknown-linux-musl + build_args: "--bins" + extra_packages: "" + rustflags: "" + upload_host: true - name: aarch64 runner: ubuntu-24.04-arm target: aarch64-unknown-linux-musl + build_args: "--bins" + extra_packages: "" + rustflags: "" + upload_host: true + - name: armv7 + runner: ubuntu-24.04 + target: armv7-unknown-linux-musleabihf + build_args: "-p smoo-gadget-cli" + extra_packages: "" + rustflags: "--cfg=io_uring_skip_arch_check" + upload_host: false steps: - uses: actions/checkout@v4 @@ -68,7 +83,7 @@ jobs: - name: Install musl toolchain run: | sudo apt-get update - sudo apt-get install -y musl-tools linux-libc-dev + sudo apt-get install -y musl-tools linux-libc-dev ${{ matrix.extra_packages }} - name: Set up musl kernel headers run: | @@ -80,12 +95,18 @@ jobs: sudo ln -sf /usr/include/$(uname -m)-linux-gnu/asm /usr/include/$(uname -m)-linux-musl/asm elif [ -d /usr/include/asm ]; then sudo ln -sf /usr/include/asm /usr/include/$(uname -m)-linux-musl/asm + else + sudo ln -sf /usr/include/asm-generic /usr/include/$(uname -m)-linux-musl/asm + sudo ln -sf /usr/include/asm-generic /usr/include/asm fi - name: Build (static musl) + env: + RUSTFLAGS: "-D warnings ${{ matrix.rustflags }}" run: | cargo build \ - --bins \ + ${{ matrix.build_args }} \ + --locked \ --release \ --target ${{ matrix.target }} @@ -96,22 +117,34 @@ jobs: path: target/${{ matrix.target }}/release/smoo-gadget - name: Upload smoo-host artifact + if: matrix.upload_host uses: actions/upload-artifact@v4 with: name: smoo-host-${{ matrix.name }} path: target/${{ matrix.target }}/release/smoo-host - - name: Prepare release binaries + - name: Prepare smoo-gadget release binary if: github.event_name == 'release' run: | cp target/${{ matrix.target }}/release/smoo-gadget smoo-gadget-${{ matrix.name }} + + - name: Prepare smoo-host release binary + if: github.event_name == 'release' && matrix.upload_host + run: | cp target/${{ matrix.target }}/release/smoo-host smoo-host-${{ matrix.name }} - - name: Upload binaries to release + - name: Upload smoo-gadget binary to release if: github.event_name == 'release' uses: softprops/action-gh-release@v2 with: name: ${{ github.event.release.name }} files: | smoo-gadget-${{ matrix.name }} + + - name: Upload smoo-host binary to release + if: github.event_name == 'release' && matrix.upload_host + uses: softprops/action-gh-release@v2 + with: + name: ${{ github.event.release.name }} + files: | smoo-host-${{ matrix.name }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 717f388..08af67a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -172,6 +172,11 @@ jobs: name: smoo-gadget-aarch64 path: release-artifacts/smoo-gadget-aarch64 + - uses: actions/download-artifact@v4 + with: + name: smoo-gadget-armv7 + path: release-artifacts/smoo-gadget-armv7 + - uses: actions/download-artifact@v4 with: name: smoo-host-aarch64 @@ -195,11 +200,13 @@ jobs: cp release-artifacts/smoo-gadget-x86_64/smoo-gadget release-assets/smoo-gadget-x86_64 cp release-artifacts/smoo-host-x86_64/smoo-host release-assets/smoo-host-x86_64 cp release-artifacts/smoo-gadget-aarch64/smoo-gadget release-assets/smoo-gadget-aarch64 + cp release-artifacts/smoo-gadget-armv7/smoo-gadget release-assets/smoo-gadget-armv7 cp release-artifacts/smoo-host-aarch64/smoo-host release-assets/smoo-host-aarch64 tar -C release-artifacts/smoo-gadget-x86_64 -czf release-assets/smoo-gadget-cli-x86_64-unknown-linux-musl.tar.gz smoo-gadget tar -C release-artifacts/smoo-host-x86_64 -czf release-assets/smoo-host-cli-x86_64-unknown-linux-musl.tar.gz smoo-host tar -C release-artifacts/smoo-gadget-aarch64 -czf release-assets/smoo-gadget-cli-aarch64-unknown-linux-musl.tar.gz smoo-gadget + tar -C release-artifacts/smoo-gadget-armv7 -czf release-assets/smoo-gadget-cli-armv7-unknown-linux-musleabihf.tar.gz smoo-gadget tar -C release-artifacts/smoo-host-aarch64 -czf release-assets/smoo-host-cli-aarch64-unknown-linux-musl.tar.gz smoo-host cp release-artifacts/APKBUILD/APKBUILD release-assets/APKBUILD @@ -212,10 +219,12 @@ jobs: test -f release-assets/smoo-gadget-x86_64 test -f release-assets/smoo-host-x86_64 test -f release-assets/smoo-gadget-aarch64 + test -f release-assets/smoo-gadget-armv7 test -f release-assets/smoo-host-aarch64 test -f release-assets/smoo-gadget-cli-x86_64-unknown-linux-musl.tar.gz test -f release-assets/smoo-host-cli-x86_64-unknown-linux-musl.tar.gz test -f release-assets/smoo-gadget-cli-aarch64-unknown-linux-musl.tar.gz + test -f release-assets/smoo-gadget-cli-armv7-unknown-linux-musleabihf.tar.gz test -f release-assets/smoo-host-cli-aarch64-unknown-linux-musl.tar.gz test -f release-assets/APKBUILD compgen -G 'release-assets/*.apk' >/dev/null @@ -230,10 +239,12 @@ jobs: release-assets/smoo-gadget-x86_64 release-assets/smoo-host-x86_64 release-assets/smoo-gadget-aarch64 + release-assets/smoo-gadget-armv7 release-assets/smoo-host-aarch64 release-assets/smoo-gadget-cli-x86_64-unknown-linux-musl.tar.gz release-assets/smoo-host-cli-x86_64-unknown-linux-musl.tar.gz release-assets/smoo-gadget-cli-aarch64-unknown-linux-musl.tar.gz + release-assets/smoo-gadget-cli-armv7-unknown-linux-musleabihf.tar.gz release-assets/smoo-host-cli-aarch64-unknown-linux-musl.tar.gz release-assets/APKBUILD release-assets/*.apk diff --git a/Cargo.lock b/Cargo.lock index 4e87c09..28b19e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -104,7 +104,7 @@ dependencies = [ "futures-lite", "parking", "polling", - "rustix 1.1.4", + "rustix", "slab", "windows-sys 0.61.2", ] @@ -155,49 +155,6 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "bindgen" -version = "0.69.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools 0.12.1", - "lazy_static", - "lazycell", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash 1.1.0", - "shlex", - "syn", - "which", -] - -[[package]] -name = "bindgen" -version = "0.72.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools 0.13.0", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash 2.1.2", - "shlex", - "syn", -] - [[package]] name = "bitflags" version = "2.11.1" @@ -260,15 +217,6 @@ dependencies = [ "shlex", ] -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - [[package]] name = "cfg-if" version = "1.0.4" @@ -281,17 +229,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc 0.2.185", - "libloading", -] - [[package]] name = "clap" version = "4.6.1" @@ -438,15 +375,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f75635036496136320802f8f1756f51bf3e7100f28d71e6d8342aeac48e539f7" dependencies = [ "log", - "rustix 1.1.4", + "rustix", ] -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - [[package]] name = "equivalent" version = "1.0.2" @@ -623,9 +554,9 @@ dependencies = [ [[package]] name = "gadgetry-most-foul" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aca37cf2a3b6ae2ad764a6c689a8fca79d1d325b085b6629977a3c0d663d04a0" +checksum = "706c81a929c7009eaa6427d32b3af28ce5dd2133abafe63ff79f9c8fd79e849d" dependencies = [ "async-io", "bitflags", @@ -636,7 +567,7 @@ dependencies = [ "log", "macaddr", "proc-mounts", - "rustix 1.1.4", + "rustix", "slab", "strum", "uuid", @@ -710,12 +641,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "glob" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" - [[package]] name = "gloo-timers" version = "0.3.0" @@ -803,15 +728,6 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" -[[package]] -name = "home" -version = "0.5.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" -dependencies = [ - "windows-sys 0.61.2", -] - [[package]] name = "http" version = "0.2.12" @@ -1099,7 +1015,6 @@ version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d09b98f7eace8982db770e4408e7470b028ce513ac28fecdc6bf4c30fe92b62" dependencies = [ - "bindgen 0.69.5", "bitflags", "cfg-if", "libc 0.2.185", @@ -1127,24 +1042,6 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.18" @@ -1169,12 +1066,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "leb128fmt" version = "0.1.0" @@ -1193,16 +1084,6 @@ version = "0.2.185" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" -[[package]] -name = "libloading" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" -dependencies = [ - "cfg-if", - "windows-link", -] - [[package]] name = "libusb1-sys" version = "0.7.0" @@ -1215,12 +1096,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - [[package]] name = "linux-raw-sys" version = "0.12.1" @@ -1317,12 +1192,6 @@ dependencies = [ "sketches-ddsketch", ] -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "mio" version = "1.2.0" @@ -1368,16 +1237,6 @@ dependencies = [ "libc 0.2.185", ] -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - [[package]] name = "nu-ansi-term" version = "0.50.3" @@ -1407,10 +1266,10 @@ dependencies = [ "core-foundation-sys", "futures-core", "io-kit-sys", - "linux-raw-sys 0.12.1", + "linux-raw-sys", "log", "once_cell", - "rustix 1.1.4", + "rustix", "slab", "tokio", "windows-sys 0.61.2", @@ -1486,7 +1345,7 @@ dependencies = [ "concurrent-queue", "hermit-abi", "pin-project-lite", - "rustix 1.1.4", + "rustix", "windows-sys 0.61.2", ] @@ -1568,7 +1427,7 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 2.1.2", + "rustc-hash", "rustls", "socket2 0.6.3", "thiserror 2.0.18", @@ -1588,7 +1447,7 @@ dependencies = [ "lru-slab", "rand 0.9.4", "ring", - "rustc-hash 2.1.2", + "rustc-hash", "rustls", "rustls-pki-types", "slab", @@ -1842,31 +1701,12 @@ dependencies = [ "libusb1-sys", ] -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustc-hash" version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags", - "errno", - "libc 0.2.185", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - [[package]] name = "rustix" version = "1.1.4" @@ -1876,8 +1716,8 @@ dependencies = [ "bitflags", "errno", "libc 0.2.185", - "linux-raw-sys 0.12.1", - "windows-sys 0.52.0", + "linux-raw-sys", + "windows-sys 0.61.2", ] [[package]] @@ -2089,11 +1929,8 @@ version = "0.0.2-rc.6" dependencies = [ "anyhow", "async-channel", - "bindgen 0.72.1", "io-uring", "libc 0.2.185", - "regex", - "serde", "tokio", "tracing", "tracing-subscriber", @@ -2376,7 +2213,7 @@ dependencies = [ "fastrand", "getrandom 0.4.2", "once_cell", - "rustix 1.1.4", + "rustix", "windows-sys 0.61.2", ] @@ -2880,18 +2717,6 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix 0.38.44", -] - [[package]] name = "winapi" version = "0.3.9" @@ -2929,15 +2754,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.60.2" diff --git a/Cargo.toml b/Cargo.toml index d3e00f2..23fa051 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ libc = "0.2.177" hyper = "0.14" metrics-exporter-prometheus = { version = "0.13", default-features = false } serde = "1.0.228" -gadgetry-most-foul = "0.1.0" +gadgetry-most-foul = "0.1.1" js-sys = "0.3.82" wasm-bindgen = "0.2.105" wasm-bindgen-futures = "0.4.55" diff --git a/crates/smoo-gadget-ublk/Cargo.toml b/crates/smoo-gadget-ublk/Cargo.toml index e793421..f3be6ec 100644 --- a/crates/smoo-gadget-ublk/Cargo.toml +++ b/crates/smoo-gadget-ublk/Cargo.toml @@ -9,21 +9,15 @@ description = { workspace = true } [features] default = [] -apkbuild = ["io-uring/bindgen"] +apkbuild = [] [dependencies] anyhow = { workspace = true } async-channel = "2.5.0" io-uring = "0.7.11" libc = { workspace = true } -serde = { workspace = true, features = ["derive"] } tracing = "0.1.41" tracing-subscriber = { version = "0.3.20", features = ["env-filter"] } -[build-dependencies] -regex = "1.12.2" -bindgen = "0.72.1" -anyhow = { workspace = true } - [dev-dependencies] tokio = { workspace = true, features = ["rt-multi-thread"] } diff --git a/crates/smoo-gadget-ublk/build.rs b/crates/smoo-gadget-ublk/build.rs deleted file mode 100644 index 39fd554..0000000 --- a/crates/smoo-gadget-ublk/build.rs +++ /dev/null @@ -1,102 +0,0 @@ -use bindgen::callbacks::ItemInfo; - -#[derive(Debug)] -pub struct Fix753 {} -impl bindgen::callbacks::ParseCallbacks for Fix753 { - fn item_name(&self, item_info: ItemInfo) -> Option { - Some(item_info.name.trim_start_matches("Fix753_").to_owned()) - } -} - -fn add_serialize(outdir: &std::path::Path) -> anyhow::Result { - use std::fs::File; - use std::io::Write; - - let res = std::fs::read_to_string(outdir.join("ublk_cmd.rs"))?; - let data = format!( - "use serde::{{Serialize, Deserialize}};\n{}", - regex::Regex::new(r"#\s*\[\s*derive\s*\((?P[^)]+)\)\s*\]\s*pub\s*(?Pstruct|enum)")? - .replace_all(&res, "#[derive($d, Serialize, Deserialize)] pub $s") - ) - .replace( - "#[derive(Copy, Clone, Serialize, Deserialize)] pub struct ublksrv_io_desc", - "#[derive(Copy, Clone)] pub struct ublksrv_io_desc", - ) - .replace( - "#[derive(Copy, Clone, Serialize, Deserialize)] pub struct ublksrv_io_cmd", - "#[derive(Copy, Clone)] pub struct ublksrv_io_cmd", - ); - let mut fd = File::create(outdir.join("ublk_cmd.rs"))?; - fd.write_all(data.as_bytes())?; - - Ok(0) -} - -fn main() { - use std::env; - use std::path::PathBuf; - - const INCLUDE: &str = r#" -#include -#include -#include -#include "ublk_cmd.h" - -#ifdef UBLK_F_CMD_IOCTL_ENCODE -// Bindgen does not emit constants for Linux _IO*() function-like macros. -// Force them through C consts, then strip this prefix in ParseCallbacks. -#define MARK_FIX_753(req_name) const unsigned int Fix753_##req_name = req_name; -#else -#define MARK_FIX_753(req_name) -#endif -MARK_FIX_753(UBLK_U_CMD_GET_QUEUE_AFFINITY); -MARK_FIX_753(UBLK_U_CMD_GET_DEV_INFO); -MARK_FIX_753(UBLK_U_CMD_ADD_DEV); -MARK_FIX_753(UBLK_U_CMD_DEL_DEV); -MARK_FIX_753(UBLK_U_CMD_START_DEV); -MARK_FIX_753(UBLK_U_CMD_STOP_DEV); -MARK_FIX_753(UBLK_U_CMD_SET_PARAMS); -MARK_FIX_753(UBLK_U_CMD_GET_PARAMS); -MARK_FIX_753(UBLK_U_CMD_START_USER_RECOVERY); -MARK_FIX_753(UBLK_U_CMD_END_USER_RECOVERY); -MARK_FIX_753(UBLK_U_CMD_GET_DEV_INFO2); -MARK_FIX_753(UBLK_U_CMD_GET_FEATURES); -MARK_FIX_753(UBLK_U_IO_FETCH_REQ); -MARK_FIX_753(UBLK_U_IO_COMMIT_AND_FETCH_REQ); -MARK_FIX_753(UBLK_U_IO_NEED_GET_DATA); -MARK_FIX_753(UBLK_U_CMD_DEL_DEV_ASYNC); -#ifdef UBLK_U_CMD_QUIESCE_DEV -MARK_FIX_753(UBLK_U_CMD_QUIESCE_DEV); -#endif -MARK_FIX_753(UBLK_U_IO_REGISTER_IO_BUF); -MARK_FIX_753(UBLK_U_IO_UNREGISTER_IO_BUF); -const int Fix753_UBLK_IO_RES_ABORT = UBLK_IO_RES_ABORT; - "#; - - let outdir = PathBuf::from(env::var("OUT_DIR").unwrap()); - let mut builder = bindgen::Builder::default(); - builder = builder.header_contents("include-file.h", INCLUDE); - - builder - .ctypes_prefix("libc") - .prepend_enum_name(false) - .derive_default(true) - .generate_comments(true) - .use_core() - .generate_inline_functions(true) - .allowlist_var("UBLKSRV_.*|UBLK_.*|UBLK_U_.*|Fix753_.*") - .allowlist_function("ublk_sqe_addr_to_auto_buf_reg") - .allowlist_function("ublk_auto_buf_reg_to_sqe_addr") - .allowlist_type("ublksrv_.*|ublk_.*") - .allowlist_var("BLK_ZONE_.*") - .allowlist_type("blk_zone_.*") - .parse_callbacks(Box::new(Fix753 {})) - .generate() - .unwrap() - .write_to_file(outdir.join("ublk_cmd.rs")) - .unwrap(); - - if let Err(error) = add_serialize(&outdir) { - eprintln!("Error: {error}") - } -} diff --git a/crates/smoo-gadget-ublk/src/lib.rs b/crates/smoo-gadget-ublk/src/lib.rs index 55576acf..f942821 100644 --- a/crates/smoo-gadget-ublk/src/lib.rs +++ b/crates/smoo-gadget-ublk/src/lib.rs @@ -610,8 +610,7 @@ impl SmooUblk { ublksrv_pid: unsafe { libc::getpid() } as i32, ..Default::default() }; - info.flags |= - (UBLK_F_USER_RECOVERY | UBLK_F_USER_RECOVERY_REISSUE | UBLK_F_QUIESCE) as u64; + info.flags |= UBLK_F_USER_RECOVERY | UBLK_F_USER_RECOVERY_REISSUE | UBLK_F_QUIESCE; // ublk_params is passed in ublksrv_ctrl_dev_info during UBLK_CMD_SET_PARAMS let mut params = ublk_params { @@ -654,7 +653,7 @@ impl SmooUblk { cmd.addr = &raw mut params as _; submit_ctrl_command_blocking(&sender, UBLK_CMD_SET_PARAMS, cmd, "set params", None)?; - let ioctl_encode = (info.flags & (sys::UBLK_F_CMD_IOCTL_ENCODE as u64)) != 0; + let ioctl_encode = (info.flags & sys::UBLK_F_CMD_IOCTL_ENCODE) != 0; let max_io_bytes = usize::try_from(info.max_io_buf_bytes).context("max_io_buf_bytes overflow")?; let cdev_path = format!("/dev/ublkc{dev_id}"); @@ -782,7 +781,7 @@ impl SmooUblk { .context("query ublk device params")?; let queue_count = info.nr_hw_queues; let queue_depth = info.queue_depth; - let ioctl_encode = (info.flags & (sys::UBLK_F_CMD_IOCTL_ENCODE as u64)) != 0; + let ioctl_encode = (info.flags & sys::UBLK_F_CMD_IOCTL_ENCODE) != 0; let block_size_shift = params.basic.logical_bs_shift; ensure!(block_size_shift >= 9, "invalid logical block size shift"); let block_size = 1usize << block_size_shift; @@ -1805,17 +1804,15 @@ fn queue_cmd_buf_size(depth: u32) -> usize { } fn io_desc_nr_sectors(desc: &ublksrv_io_desc) -> u32 { - // Linux exposes nr_sectors/nr_zones as an anonymous C union. - unsafe { desc.__bindgen_anon_1.nr_sectors } + desc.nr_sectors } fn io_cmd_with_addr(q_id: u16, tag: u16, result: i32, addr: u64) -> ublksrv_io_cmd { - // Linux exposes addr/zone_append_lba as an anonymous C union. ublksrv_io_cmd { q_id, tag, result, - __bindgen_anon_1: sys::ublksrv_io_cmd__bindgen_ty_1 { addr }, + addr, } } diff --git a/crates/smoo-gadget-ublk/src/sys.rs b/crates/smoo-gadget-ublk/src/sys.rs index a3e74bc..b2e6ae7 100644 --- a/crates/smoo-gadget-ublk/src/sys.rs +++ b/crates/smoo-gadget-ublk/src/sys.rs @@ -1,6 +1,284 @@ -#![allow(non_upper_case_globals)] #![allow(non_camel_case_types)] -#![allow(non_snake_case)] -#![allow(dead_code)] -#![allow(unsafe_op_in_unsafe_fn)] -include!(concat!(env!("OUT_DIR"), "/ublk_cmd.rs")); + +use std::mem::{align_of, offset_of, size_of}; + +pub const UBLK_CMD_GET_DEV_INFO: u32 = 0x02; +pub const UBLK_CMD_ADD_DEV: u32 = 0x04; +pub const UBLK_CMD_DEL_DEV: u32 = 0x05; +pub const UBLK_CMD_START_DEV: u32 = 0x06; +pub const UBLK_CMD_STOP_DEV: u32 = 0x07; +pub const UBLK_CMD_SET_PARAMS: u32 = 0x08; +pub const UBLK_CMD_GET_PARAMS: u32 = 0x09; +pub const UBLK_CMD_START_USER_RECOVERY: u32 = 0x10; +pub const UBLK_CMD_END_USER_RECOVERY: u32 = 0x11; +pub const UBLK_CMD_GET_DEV_INFO2: u32 = 0x12; +pub const UBLK_CMD_QUIESCE_DEV: u32 = 0x16; + +const UBLK_IO_FETCH_REQ: u32 = 0x20; +const UBLK_IO_COMMIT_AND_FETCH_REQ: u32 = 0x21; + +pub const UBLK_IO_RES_ABORT: i32 = -libc::ENODEV; + +pub const UBLKSRV_CMD_BUF_OFFSET: u32 = 0; +pub const UBLK_MAX_QUEUE_DEPTH: u32 = 4096; + +pub const UBLK_F_USER_RECOVERY: u64 = 1 << 3; +pub const UBLK_F_USER_RECOVERY_REISSUE: u64 = 1 << 4; +pub const UBLK_F_CMD_IOCTL_ENCODE: u64 = 1 << 6; +pub const UBLK_F_QUIESCE: u64 = 1 << 12; + +pub const UBLK_IO_OP_READ: u32 = 0; +pub const UBLK_IO_OP_WRITE: u32 = 1; +pub const UBLK_IO_OP_FLUSH: u32 = 2; +pub const UBLK_IO_OP_DISCARD: u32 = 3; + +pub const UBLK_PARAM_TYPE_BASIC: u32 = 1 << 0; + +pub const UBLK_U_CMD_QUIESCE_DEV: u32 = iowr::(UBLK_CMD_QUIESCE_DEV); +pub const UBLK_U_IO_FETCH_REQ: u32 = iowr::(UBLK_IO_FETCH_REQ); +pub const UBLK_U_IO_COMMIT_AND_FETCH_REQ: u32 = + iowr::(UBLK_IO_COMMIT_AND_FETCH_REQ); + +const IOC_NRBITS: u32 = 8; +const IOC_TYPEBITS: u32 = 8; +const IOC_SIZEBITS: u32 = 14; + +const IOC_NRSHIFT: u32 = 0; +const IOC_TYPESHIFT: u32 = IOC_NRSHIFT + IOC_NRBITS; +const IOC_SIZESHIFT: u32 = IOC_TYPESHIFT + IOC_TYPEBITS; +const IOC_DIRSHIFT: u32 = IOC_SIZESHIFT + IOC_SIZEBITS; + +const IOC_WRITE: u32 = 1; +const IOC_READ: u32 = 2; + +const fn ioc(dir: u32, ty: u32, nr: u32, size: u32) -> u32 { + (dir << IOC_DIRSHIFT) | (ty << IOC_TYPESHIFT) | (nr << IOC_NRSHIFT) | (size << IOC_SIZESHIFT) +} + +const fn iowr(nr: u32) -> u32 { + ioc(IOC_READ | IOC_WRITE, b'u' as u32, nr, size_of::() as u32) +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default)] +pub struct ublksrv_ctrl_cmd { + pub dev_id: u32, + pub queue_id: u16, + pub len: u16, + pub addr: u64, + pub data: [u64; 1], + pub dev_path_len: u16, + pub pad: u16, + pub reserved: u32, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default)] +pub struct ublksrv_ctrl_dev_info { + pub nr_hw_queues: u16, + pub queue_depth: u16, + pub state: u16, + pub pad0: u16, + pub max_io_buf_bytes: u32, + pub dev_id: u32, + pub ublksrv_pid: i32, + pub pad1: u32, + pub flags: u64, + pub ublksrv_flags: u64, + pub owner_uid: u32, + pub owner_gid: u32, + pub reserved1: u64, + pub reserved2: u64, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default)] +pub struct ublksrv_io_desc { + pub op_flags: u32, + pub nr_sectors: u32, + pub start_sector: u64, + pub addr: u64, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default)] +pub struct ublksrv_io_cmd { + pub q_id: u16, + pub tag: u16, + pub result: i32, + pub addr: u64, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default)] +pub struct ublk_param_basic { + pub attrs: u32, + pub logical_bs_shift: u8, + pub physical_bs_shift: u8, + pub io_opt_shift: u8, + pub io_min_shift: u8, + pub max_sectors: u32, + pub chunk_sectors: u32, + pub dev_sectors: u64, + pub virt_boundary_mask: u64, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default)] +pub struct ublk_param_discard { + pub discard_alignment: u32, + pub discard_granularity: u32, + pub max_discard_sectors: u32, + pub max_write_zeroes_sectors: u32, + pub max_discard_segments: u16, + pub reserved0: u16, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default)] +pub struct ublk_param_devt { + pub char_major: u32, + pub char_minor: u32, + pub disk_major: u32, + pub disk_minor: u32, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default)] +pub struct ublk_param_zoned { + pub max_open_zones: u32, + pub max_active_zones: u32, + pub max_zone_append_sectors: u32, + pub reserved: [u8; 20], +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default)] +pub struct ublk_param_dma_align { + pub alignment: u32, + pub pad: [u8; 4], +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default)] +pub struct ublk_param_segment { + pub seg_boundary_mask: u64, + pub max_segment_size: u32, + pub max_segments: u16, + pub pad: [u8; 2], +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default)] +pub struct ublk_params { + pub len: u32, + pub types: u32, + pub basic: ublk_param_basic, + pub discard: ublk_param_discard, + pub devt: ublk_param_devt, + pub zoned: ublk_param_zoned, + pub dma: ublk_param_dma_align, + pub seg: ublk_param_segment, +} + +const _: () = { + assert!(size_of::() == 32); + assert!(align_of::() == 8); + assert!(offset_of!(ublksrv_ctrl_cmd, dev_id) == 0); + assert!(offset_of!(ublksrv_ctrl_cmd, queue_id) == 4); + assert!(offset_of!(ublksrv_ctrl_cmd, len) == 6); + assert!(offset_of!(ublksrv_ctrl_cmd, addr) == 8); + assert!(offset_of!(ublksrv_ctrl_cmd, data) == 16); + assert!(offset_of!(ublksrv_ctrl_cmd, dev_path_len) == 24); + assert!(offset_of!(ublksrv_ctrl_cmd, pad) == 26); + assert!(offset_of!(ublksrv_ctrl_cmd, reserved) == 28); + + assert!(size_of::() == 64); + assert!(align_of::() == 8); + assert!(offset_of!(ublksrv_ctrl_dev_info, nr_hw_queues) == 0); + assert!(offset_of!(ublksrv_ctrl_dev_info, queue_depth) == 2); + assert!(offset_of!(ublksrv_ctrl_dev_info, state) == 4); + assert!(offset_of!(ublksrv_ctrl_dev_info, pad0) == 6); + assert!(offset_of!(ublksrv_ctrl_dev_info, max_io_buf_bytes) == 8); + assert!(offset_of!(ublksrv_ctrl_dev_info, dev_id) == 12); + assert!(offset_of!(ublksrv_ctrl_dev_info, ublksrv_pid) == 16); + assert!(offset_of!(ublksrv_ctrl_dev_info, pad1) == 20); + assert!(offset_of!(ublksrv_ctrl_dev_info, flags) == 24); + assert!(offset_of!(ublksrv_ctrl_dev_info, ublksrv_flags) == 32); + assert!(offset_of!(ublksrv_ctrl_dev_info, owner_uid) == 40); + assert!(offset_of!(ublksrv_ctrl_dev_info, owner_gid) == 44); + assert!(offset_of!(ublksrv_ctrl_dev_info, reserved1) == 48); + assert!(offset_of!(ublksrv_ctrl_dev_info, reserved2) == 56); + + assert!(size_of::() == 24); + assert!(align_of::() == 8); + assert!(offset_of!(ublksrv_io_desc, op_flags) == 0); + assert!(offset_of!(ublksrv_io_desc, nr_sectors) == 4); + assert!(offset_of!(ublksrv_io_desc, start_sector) == 8); + assert!(offset_of!(ublksrv_io_desc, addr) == 16); + + assert!(size_of::() == 16); + assert!(align_of::() == 8); + assert!(offset_of!(ublksrv_io_cmd, q_id) == 0); + assert!(offset_of!(ublksrv_io_cmd, tag) == 2); + assert!(offset_of!(ublksrv_io_cmd, result) == 4); + assert!(offset_of!(ublksrv_io_cmd, addr) == 8); + + assert!(size_of::() == 32); + assert!(align_of::() == 8); + assert!(offset_of!(ublk_param_basic, attrs) == 0); + assert!(offset_of!(ublk_param_basic, logical_bs_shift) == 4); + assert!(offset_of!(ublk_param_basic, physical_bs_shift) == 5); + assert!(offset_of!(ublk_param_basic, io_opt_shift) == 6); + assert!(offset_of!(ublk_param_basic, io_min_shift) == 7); + assert!(offset_of!(ublk_param_basic, max_sectors) == 8); + assert!(offset_of!(ublk_param_basic, chunk_sectors) == 12); + assert!(offset_of!(ublk_param_basic, dev_sectors) == 16); + assert!(offset_of!(ublk_param_basic, virt_boundary_mask) == 24); + + assert!(size_of::() == 20); + assert!(align_of::() == 4); + assert!(offset_of!(ublk_param_discard, discard_alignment) == 0); + assert!(offset_of!(ublk_param_discard, discard_granularity) == 4); + assert!(offset_of!(ublk_param_discard, max_discard_sectors) == 8); + assert!(offset_of!(ublk_param_discard, max_write_zeroes_sectors) == 12); + assert!(offset_of!(ublk_param_discard, max_discard_segments) == 16); + assert!(offset_of!(ublk_param_discard, reserved0) == 18); + + assert!(size_of::() == 16); + assert!(align_of::() == 4); + assert!(offset_of!(ublk_param_devt, char_major) == 0); + assert!(offset_of!(ublk_param_devt, char_minor) == 4); + assert!(offset_of!(ublk_param_devt, disk_major) == 8); + assert!(offset_of!(ublk_param_devt, disk_minor) == 12); + + assert!(size_of::() == 32); + assert!(align_of::() == 4); + assert!(offset_of!(ublk_param_zoned, max_open_zones) == 0); + assert!(offset_of!(ublk_param_zoned, max_active_zones) == 4); + assert!(offset_of!(ublk_param_zoned, max_zone_append_sectors) == 8); + assert!(offset_of!(ublk_param_zoned, reserved) == 12); + + assert!(size_of::() == 8); + assert!(align_of::() == 4); + assert!(offset_of!(ublk_param_dma_align, alignment) == 0); + assert!(offset_of!(ublk_param_dma_align, pad) == 4); + + assert!(size_of::() == 16); + assert!(align_of::() == 8); + assert!(offset_of!(ublk_param_segment, seg_boundary_mask) == 0); + assert!(offset_of!(ublk_param_segment, max_segment_size) == 8); + assert!(offset_of!(ublk_param_segment, max_segments) == 12); + assert!(offset_of!(ublk_param_segment, pad) == 14); + + assert!(size_of::() == 136); + assert!(align_of::() == 8); + assert!(offset_of!(ublk_params, len) == 0); + assert!(offset_of!(ublk_params, types) == 4); + assert!(offset_of!(ublk_params, basic) == 8); + assert!(offset_of!(ublk_params, discard) == 40); + assert!(offset_of!(ublk_params, devt) == 60); + assert!(offset_of!(ublk_params, zoned) == 76); + assert!(offset_of!(ublk_params, dma) == 108); + assert!(offset_of!(ublk_params, seg) == 120); +}; diff --git a/crates/smoo-gadget-ublk/ublk_cmd.h b/crates/smoo-gadget-ublk/ublk_cmd.h deleted file mode 100644 index c9751bd..0000000 --- a/crates/smoo-gadget-ublk/ublk_cmd.h +++ /dev/null @@ -1,617 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#ifndef USER_BLK_DRV_CMD_INC_H -#define USER_BLK_DRV_CMD_INC_H - -#include - -/* ublk server command definition */ - -/* - * Admin commands, issued by ublk server, and handled by ublk driver. - * - * Legacy command definition, don't use in new application, and don't - * add new such definition any more - */ -#define UBLK_CMD_GET_QUEUE_AFFINITY 0x01 -#define UBLK_CMD_GET_DEV_INFO 0x02 -#define UBLK_CMD_ADD_DEV 0x04 -#define UBLK_CMD_DEL_DEV 0x05 -#define UBLK_CMD_START_DEV 0x06 -#define UBLK_CMD_STOP_DEV 0x07 -#define UBLK_CMD_SET_PARAMS 0x08 -#define UBLK_CMD_GET_PARAMS 0x09 -#define UBLK_CMD_START_USER_RECOVERY 0x10 -#define UBLK_CMD_END_USER_RECOVERY 0x11 -#define UBLK_CMD_GET_DEV_INFO2 0x12 - -/* Any new ctrl command should encode by __IO*() */ -#define UBLK_U_CMD_GET_QUEUE_AFFINITY \ - _IOR('u', UBLK_CMD_GET_QUEUE_AFFINITY, struct ublksrv_ctrl_cmd) -#define UBLK_U_CMD_GET_DEV_INFO \ - _IOR('u', UBLK_CMD_GET_DEV_INFO, struct ublksrv_ctrl_cmd) -#define UBLK_U_CMD_ADD_DEV \ - _IOWR('u', UBLK_CMD_ADD_DEV, struct ublksrv_ctrl_cmd) -#define UBLK_U_CMD_DEL_DEV \ - _IOWR('u', UBLK_CMD_DEL_DEV, struct ublksrv_ctrl_cmd) -#define UBLK_U_CMD_START_DEV \ - _IOWR('u', UBLK_CMD_START_DEV, struct ublksrv_ctrl_cmd) -#define UBLK_U_CMD_STOP_DEV \ - _IOWR('u', UBLK_CMD_STOP_DEV, struct ublksrv_ctrl_cmd) -#define UBLK_U_CMD_SET_PARAMS \ - _IOWR('u', UBLK_CMD_SET_PARAMS, struct ublksrv_ctrl_cmd) -#define UBLK_U_CMD_GET_PARAMS \ - _IOR('u', UBLK_CMD_GET_PARAMS, struct ublksrv_ctrl_cmd) -#define UBLK_U_CMD_START_USER_RECOVERY \ - _IOWR('u', UBLK_CMD_START_USER_RECOVERY, struct ublksrv_ctrl_cmd) -#define UBLK_U_CMD_END_USER_RECOVERY \ - _IOWR('u', UBLK_CMD_END_USER_RECOVERY, struct ublksrv_ctrl_cmd) -#define UBLK_U_CMD_GET_DEV_INFO2 \ - _IOR('u', UBLK_CMD_GET_DEV_INFO2, struct ublksrv_ctrl_cmd) -#define UBLK_U_CMD_GET_FEATURES \ - _IOR('u', 0x13, struct ublksrv_ctrl_cmd) -#define UBLK_U_CMD_DEL_DEV_ASYNC \ - _IOR('u', 0x14, struct ublksrv_ctrl_cmd) -#define UBLK_U_CMD_UPDATE_SIZE \ - _IOWR('u', 0x15, struct ublksrv_ctrl_cmd) -#define UBLK_U_CMD_QUIESCE_DEV \ - _IOWR('u', 0x16, struct ublksrv_ctrl_cmd) - -/* - * 64bits are enough now, and it should be easy to extend in case of - * running out of feature flags - */ -#define UBLK_FEATURES_LEN 8 - -/* - * IO commands, issued by ublk server, and handled by ublk driver. - * - * FETCH_REQ: issued via sqe(URING_CMD) beforehand for fetching IO request - * from ublk driver, should be issued only when starting device. After - * the associated cqe is returned, request's tag can be retrieved via - * cqe->userdata. - * - * COMMIT_AND_FETCH_REQ: issued via sqe(URING_CMD) after ublkserver handled - * this IO request, request's handling result is committed to ublk - * driver, meantime FETCH_REQ is piggyback, and FETCH_REQ has to be - * handled before completing io request. - * - * NEED_GET_DATA: only used for write requests to set io addr and copy data - * When NEED_GET_DATA is set, ublksrv has to issue UBLK_IO_NEED_GET_DATA - * command after ublk driver returns UBLK_IO_RES_NEED_GET_DATA. - * - * It is only used if ublksrv set UBLK_F_NEED_GET_DATA flag - * while starting a ublk device. - */ - -/* - * Legacy IO command definition, don't use in new application, and don't - * add new such definition any more - */ -#define UBLK_IO_FETCH_REQ 0x20 -#define UBLK_IO_COMMIT_AND_FETCH_REQ 0x21 -#define UBLK_IO_NEED_GET_DATA 0x22 - -/* Any new IO command should encode by __IOWR() */ -#define UBLK_U_IO_FETCH_REQ \ - _IOWR('u', UBLK_IO_FETCH_REQ, struct ublksrv_io_cmd) -#define UBLK_U_IO_COMMIT_AND_FETCH_REQ \ - _IOWR('u', UBLK_IO_COMMIT_AND_FETCH_REQ, struct ublksrv_io_cmd) -#define UBLK_U_IO_NEED_GET_DATA \ - _IOWR('u', UBLK_IO_NEED_GET_DATA, struct ublksrv_io_cmd) -#define UBLK_U_IO_REGISTER_IO_BUF \ - _IOWR('u', 0x23, struct ublksrv_io_cmd) -#define UBLK_U_IO_UNREGISTER_IO_BUF \ - _IOWR('u', 0x24, struct ublksrv_io_cmd) - -/* only ABORT means that no re-fetch */ -#define UBLK_IO_RES_OK 0 -#define UBLK_IO_RES_NEED_GET_DATA 1 -#define UBLK_IO_RES_ABORT (-ENODEV) - -#define UBLKSRV_CMD_BUF_OFFSET 0 -#define UBLKSRV_IO_BUF_OFFSET 0x80000000 - -/* tag bit is 16bit, so far limit at most 4096 IOs for each queue */ -#define UBLK_MAX_QUEUE_DEPTH 4096 - -/* single IO buffer max size is 32MB */ -#define UBLK_IO_BUF_OFF 0 -#define UBLK_IO_BUF_BITS 25 -#define UBLK_IO_BUF_BITS_MASK ((1ULL << UBLK_IO_BUF_BITS) - 1) - -/* so at most 64K IOs for each queue */ -#define UBLK_TAG_OFF UBLK_IO_BUF_BITS -#define UBLK_TAG_BITS 16 -#define UBLK_TAG_BITS_MASK ((1ULL << UBLK_TAG_BITS) - 1) - -/* max 4096 queues */ -#define UBLK_QID_OFF (UBLK_TAG_OFF + UBLK_TAG_BITS) -#define UBLK_QID_BITS 12 -#define UBLK_QID_BITS_MASK ((1ULL << UBLK_QID_BITS) - 1) - -#define UBLK_MAX_NR_QUEUES (1U << UBLK_QID_BITS) - -#define UBLKSRV_IO_BUF_TOTAL_BITS (UBLK_QID_OFF + UBLK_QID_BITS) -#define UBLKSRV_IO_BUF_TOTAL_SIZE (1ULL << UBLKSRV_IO_BUF_TOTAL_BITS) - -/* - * ublk server can register data buffers for incoming I/O requests with a sparse - * io_uring buffer table. The request buffer can then be used as the data buffer - * for io_uring operations via the fixed buffer index. - * Note that the ublk server can never directly access the request data memory. - * - * To use this feature, the ublk server must first register a sparse buffer - * table on an io_uring instance. - * When an incoming ublk request is received, the ublk server submits a - * UBLK_U_IO_REGISTER_IO_BUF command to that io_uring instance. The - * ublksrv_io_cmd's q_id and tag specify the request whose buffer to register - * and addr is the index in the io_uring's buffer table to install the buffer. - * SQEs can now be submitted to the io_uring to read/write the request's buffer - * by enabling fixed buffers (e.g. using IORING_OP_{READ,WRITE}_FIXED or - * IORING_URING_CMD_FIXED) and passing the registered buffer index in buf_index. - * Once the last io_uring operation using the request's buffer has completed, - * the ublk server submits a UBLK_U_IO_UNREGISTER_IO_BUF command with q_id, tag, - * and addr again specifying the request buffer to unregister. - * The ublk request is completed when its buffer is unregistered from all - * io_uring instances and the ublk server issues UBLK_U_IO_COMMIT_AND_FETCH_REQ. - * - * Not available for UBLK_F_UNPRIVILEGED_DEV, as a ublk server can leak - * uninitialized kernel memory by not reading into the full request buffer. - */ -#define UBLK_F_SUPPORT_ZERO_COPY (1ULL << 0) - -/* - * Force to complete io cmd via io_uring_cmd_complete_in_task so that - * performance comparison is done easily with using task_work_add - */ -#define UBLK_F_URING_CMD_COMP_IN_TASK (1ULL << 1) - -/* - * User should issue io cmd again for write requests to - * set io buffer address and copy data from bio vectors - * to the userspace io buffer. - * - * In this mode, task_work is not used. - */ -#define UBLK_F_NEED_GET_DATA (1UL << 2) - -/* - * - Block devices are recoverable if ublk server exits and restarts - * - Outstanding I/O when ublk server exits is met with errors - * - I/O issued while there is no ublk server queues - */ -#define UBLK_F_USER_RECOVERY (1UL << 3) - -/* - * - Block devices are recoverable if ublk server exits and restarts - * - Outstanding I/O when ublk server exits is reissued - * - I/O issued while there is no ublk server queues - */ -#define UBLK_F_USER_RECOVERY_REISSUE (1UL << 4) - -/* - * Unprivileged user can create /dev/ublkcN and /dev/ublkbN. - * - * /dev/ublk-control needs to be available for unprivileged user, and it - * can be done via udev rule to make all control commands available to - * unprivileged user. Except for the command of UBLK_CMD_ADD_DEV, all - * other commands are only allowed for the owner of the specified device. - * - * When userspace sends UBLK_CMD_ADD_DEV, the device pair's owner_uid and - * owner_gid are stored to ublksrv_ctrl_dev_info by kernel, so far only - * the current user's uid/gid is stored, that said owner of the created - * device is always the current user. - * - * We still need udev rule to apply OWNER/GROUP with the stored owner_uid - * and owner_gid. - * - * Then ublk server can be run as unprivileged user, and /dev/ublkbN can - * be accessed and managed by its owner represented by owner_uid/owner_gid. - */ -#define UBLK_F_UNPRIVILEGED_DEV (1UL << 5) - -/* use ioctl encoding for uring command */ -#define UBLK_F_CMD_IOCTL_ENCODE (1UL << 6) - -/* - * Copy between request and user buffer by pread()/pwrite() - * - * Not available for UBLK_F_UNPRIVILEGED_DEV, otherwise userspace may - * deceive us by not filling request buffer, then kernel uninitialized - * data may be leaked. - */ -#define UBLK_F_USER_COPY (1UL << 7) - -/* - * User space sets this flag when setting up the device to request zoned storage support. Kernel may - * deny the request by returning an error. - */ -#define UBLK_F_ZONED (1ULL << 8) - -/* - * - Block devices are recoverable if ublk server exits and restarts - * - Outstanding I/O when ublk server exits is met with errors - * - I/O issued while there is no ublk server is met with errors - */ -#define UBLK_F_USER_RECOVERY_FAIL_IO (1ULL << 9) - -/* - * Resizing a block device is possible with UBLK_U_CMD_UPDATE_SIZE - * New size is passed in cmd->data[0] and is in units of sectors - */ -#define UBLK_F_UPDATE_SIZE (1ULL << 10) - -/* - * request buffer is registered automatically to uring_cmd's io_uring - * context before delivering this io command to ublk server, meantime - * it is un-registered automatically when completing this io command. - * - * For using this feature: - * - * - ublk server has to create sparse buffer table on the same `io_ring_ctx` - * for issuing `UBLK_IO_FETCH_REQ` and `UBLK_IO_COMMIT_AND_FETCH_REQ`. - * If uring_cmd isn't issued on same `io_ring_ctx`, it is ublk server's - * responsibility to unregister the buffer by issuing `IO_UNREGISTER_IO_BUF` - * manually, otherwise this ublk request won't complete. - * - * - ublk server passes auto buf register data via uring_cmd's sqe->addr, - * `struct ublk_auto_buf_reg` is populated from sqe->addr, please see - * the definition of ublk_sqe_addr_to_auto_buf_reg() - * - * - pass buffer index from `ublk_auto_buf_reg.index` - * - * - all reserved fields in `ublk_auto_buf_reg` need to be zeroed - * - * - pass flags from `ublk_auto_buf_reg.flags` if needed - * - * This way avoids extra cost from two uring_cmd, but also simplifies backend - * implementation, such as, the dependency on IO_REGISTER_IO_BUF and - * IO_UNREGISTER_IO_BUF becomes not necessary. - * - * If wrong data or flags are provided, both IO_FETCH_REQ and - * IO_COMMIT_AND_FETCH_REQ are failed, for the latter, the ublk IO request - * won't be completed until new IO_COMMIT_AND_FETCH_REQ command is issued - * successfully - */ -#define UBLK_F_AUTO_BUF_REG (1ULL << 11) - -/* - * Control command `UBLK_U_CMD_QUIESCE_DEV` is added for quiescing device, - * which state can be transitioned to `UBLK_S_DEV_QUIESCED` or - * `UBLK_S_DEV_FAIL_IO` finally, and it needs ublk server cooperation for - * handling `UBLK_IO_RES_ABORT` correctly. - * - * Typical use case is for supporting to upgrade ublk server application, - * meantime keep ublk block device persistent during the period. - * - * This feature is only available when UBLK_F_USER_RECOVERY is enabled. - * - * Note, this command returns -EBUSY in case that all IO commands are being - * handled by ublk server and not completed in specified time period which - * is passed from the control command parameter. - */ -#define UBLK_F_QUIESCE (1ULL << 12) - -/* - * If this feature is set, ublk_drv supports each (qid,tag) pair having - * its own independent daemon task that is responsible for handling it. - * If it is not set, daemons are per-queue instead, so for two pairs - * (qid1,tag1) and (qid2,tag2), if qid1 == qid2, then the same task must - * be responsible for handling (qid1,tag1) and (qid2,tag2). - */ -#define UBLK_F_PER_IO_DAEMON (1ULL << 13) - -/* device state */ -#define UBLK_S_DEV_DEAD 0 -#define UBLK_S_DEV_LIVE 1 -#define UBLK_S_DEV_QUIESCED 2 -#define UBLK_S_DEV_FAIL_IO 3 - -/* shipped via sqe->cmd of io_uring command */ -struct ublksrv_ctrl_cmd { - /* sent to which device, must be valid */ - __u32 dev_id; - - /* sent to which queue, must be -1 if the cmd isn't for queue */ - __u16 queue_id; - /* - * cmd specific buffer, can be IN or OUT. - */ - __u16 len; - __u64 addr; - - /* inline data */ - __u64 data[1]; - - /* - * Used for UBLK_F_UNPRIVILEGED_DEV and UBLK_CMD_GET_DEV_INFO2 - * only, include null char - */ - __u16 dev_path_len; - __u16 pad; - __u32 reserved; -}; - -struct ublksrv_ctrl_dev_info { - __u16 nr_hw_queues; - __u16 queue_depth; - __u16 state; - __u16 pad0; - - __u32 max_io_buf_bytes; - __u32 dev_id; - - __s32 ublksrv_pid; - __u32 pad1; - - __u64 flags; - - /* For ublksrv internal use, invisible to ublk driver */ - __u64 ublksrv_flags; - - __u32 owner_uid; /* store by kernel */ - __u32 owner_gid; /* store by kernel */ - __u64 reserved1; - __u64 reserved2; -}; - -#define UBLK_IO_OP_READ 0 -#define UBLK_IO_OP_WRITE 1 -#define UBLK_IO_OP_FLUSH 2 -#define UBLK_IO_OP_DISCARD 3 -#define UBLK_IO_OP_WRITE_SAME 4 -#define UBLK_IO_OP_WRITE_ZEROES 5 -#define UBLK_IO_OP_ZONE_OPEN 10 -#define UBLK_IO_OP_ZONE_CLOSE 11 -#define UBLK_IO_OP_ZONE_FINISH 12 -#define UBLK_IO_OP_ZONE_APPEND 13 -#define UBLK_IO_OP_ZONE_RESET_ALL 14 -#define UBLK_IO_OP_ZONE_RESET 15 -/* - * Construct a zone report. The report request is carried in `struct - * ublksrv_io_desc`. The `start_sector` field must be the first sector of a zone - * and shall indicate the first zone of the report. The `nr_zones` shall - * indicate how many zones should be reported at most. The report shall be - * delivered as a `struct blk_zone` array. To report fewer zones than requested, - * zero the last entry of the returned array. - * - * Related definitions(blk_zone, blk_zone_cond, blk_zone_type, ...) in - * include/uapi/linux/blkzoned.h are part of ublk UAPI. - */ -#define UBLK_IO_OP_REPORT_ZONES 18 - -#define UBLK_IO_F_FAILFAST_DEV (1U << 8) -#define UBLK_IO_F_FAILFAST_TRANSPORT (1U << 9) -#define UBLK_IO_F_FAILFAST_DRIVER (1U << 10) -#define UBLK_IO_F_META (1U << 11) -#define UBLK_IO_F_FUA (1U << 13) -#define UBLK_IO_F_NOUNMAP (1U << 15) -#define UBLK_IO_F_SWAP (1U << 16) -/* - * For UBLK_F_AUTO_BUF_REG & UBLK_AUTO_BUF_REG_FALLBACK only. - * - * This flag is set if auto buffer register is failed & ublk server passes - * UBLK_AUTO_BUF_REG_FALLBACK, and ublk server need to register buffer - * manually for handling the delivered IO command if this flag is observed - * - * ublk server has to check this flag if UBLK_AUTO_BUF_REG_FALLBACK is - * passed in. - */ -#define UBLK_IO_F_NEED_REG_BUF (1U << 17) - -/* - * io cmd is described by this structure, and stored in share memory, indexed - * by request tag. - * - * The data is stored by ublk driver, and read by ublksrv after one fetch command - * returns. - */ -struct ublksrv_io_desc { - /* op: bit 0-7, flags: bit 8-31 */ - __u32 op_flags; - - union { - __u32 nr_sectors; - __u32 nr_zones; /* for UBLK_IO_OP_REPORT_ZONES */ - }; - - /* start sector for this io */ - __u64 start_sector; - - /* buffer address in ublksrv daemon vm space, from ublk driver */ - __u64 addr; -}; - -static inline __u8 ublksrv_get_op(const struct ublksrv_io_desc *iod) -{ - return iod->op_flags & 0xff; -} - -static inline __u32 ublksrv_get_flags(const struct ublksrv_io_desc *iod) -{ - return iod->op_flags >> 8; -} - -/* - * If this flag is set, fallback by completing the uring_cmd and setting - * `UBLK_IO_F_NEED_REG_BUF` in case of auto-buf-register failure; - * otherwise the client ublk request is failed silently - * - * If ublk server passes this flag, it has to check if UBLK_IO_F_NEED_REG_BUF - * is set in `ublksrv_io_desc.op_flags`. If UBLK_IO_F_NEED_REG_BUF is set, - * ublk server needs to register io buffer manually for handling IO command. - */ -#define UBLK_AUTO_BUF_REG_FALLBACK (1 << 0) -#define UBLK_AUTO_BUF_REG_F_MASK UBLK_AUTO_BUF_REG_FALLBACK - -struct ublk_auto_buf_reg { - /* index for registering the delivered request buffer */ - __u16 index; - __u8 flags; - __u8 reserved0; - - /* - * io_ring FD can be passed via the reserve field in future for - * supporting to register io buffer to external io_uring - */ - __u32 reserved1; -}; - -/* - * For UBLK_F_AUTO_BUF_REG, auto buffer register data is carried via - * uring_cmd's sqe->addr: - * - * - bit0 ~ bit15: buffer index - * - bit16 ~ bit23: flags - * - bit24 ~ bit31: reserved0 - * - bit32 ~ bit63: reserved1 - */ -static inline struct ublk_auto_buf_reg ublk_sqe_addr_to_auto_buf_reg( - __u64 sqe_addr) -{ - struct ublk_auto_buf_reg reg = { - .index = (__u16)sqe_addr, - .flags = (__u8)(sqe_addr >> 16), - .reserved0 = (__u8)(sqe_addr >> 24), - .reserved1 = (__u32)(sqe_addr >> 32), - }; - - return reg; -} - -static inline __u64 -ublk_auto_buf_reg_to_sqe_addr(const struct ublk_auto_buf_reg *buf) -{ - __u64 addr = buf->index | (__u64)buf->flags << 16 | (__u64)buf->reserved0 << 24 | - (__u64)buf->reserved1 << 32; - - return addr; -} - -/* issued to ublk driver via /dev/ublkcN */ -struct ublksrv_io_cmd { - __u16 q_id; - - /* for fetch/commit which result */ - __u16 tag; - - /* io result, it is valid for COMMIT* command only */ - __s32 result; - - union { - /* - * userspace buffer address in ublksrv daemon process, valid for - * FETCH* command only - * - * `addr` should not be used when UBLK_F_USER_COPY is enabled, - * because userspace handles data copy by pread()/pwrite() over - * /dev/ublkcN. But in case of UBLK_F_ZONED, this union is - * re-used to pass back the allocated LBA for - * UBLK_IO_OP_ZONE_APPEND which actually depends on - * UBLK_F_USER_COPY - */ - __u64 addr; - __u64 zone_append_lba; - }; -}; - -struct ublk_param_basic { -#define UBLK_ATTR_READ_ONLY (1 << 0) -#define UBLK_ATTR_ROTATIONAL (1 << 1) -#define UBLK_ATTR_VOLATILE_CACHE (1 << 2) -#define UBLK_ATTR_FUA (1 << 3) - __u32 attrs; - __u8 logical_bs_shift; - __u8 physical_bs_shift; - __u8 io_opt_shift; - __u8 io_min_shift; - - __u32 max_sectors; - __u32 chunk_sectors; - - __u64 dev_sectors; - __u64 virt_boundary_mask; -}; - -struct ublk_param_discard { - __u32 discard_alignment; - - __u32 discard_granularity; - __u32 max_discard_sectors; - - __u32 max_write_zeroes_sectors; - __u16 max_discard_segments; - __u16 reserved0; -}; - -/* - * read-only, can't set via UBLK_CMD_SET_PARAMS, disk_devt is available - * after device is started - */ -struct ublk_param_devt { - __u32 char_major; - __u32 char_minor; - __u32 disk_major; - __u32 disk_minor; -}; - -struct ublk_param_zoned { - __u32 max_open_zones; - __u32 max_active_zones; - __u32 max_zone_append_sectors; - __u8 reserved[20]; -}; - -struct ublk_param_dma_align { - __u32 alignment; - __u8 pad[4]; -}; - -#define UBLK_MIN_SEGMENT_SIZE 4096 -/* - * If any one of the three segment parameter is set as 0, the behavior is - * undefined. - */ -struct ublk_param_segment { - /* - * seg_boundary_mask + 1 needs to be power_of_2(), and the sum has - * to be >= UBLK_MIN_SEGMENT_SIZE(4096) - */ - __u64 seg_boundary_mask; - - /* - * max_segment_size could be override by virt_boundary_mask, so be - * careful when setting both. - * - * max_segment_size has to be >= UBLK_MIN_SEGMENT_SIZE(4096) - */ - __u32 max_segment_size; - __u16 max_segments; - __u8 pad[2]; -}; - -struct ublk_params { - /* - * Total length of parameters, userspace has to set 'len' for both - * SET_PARAMS and GET_PARAMS command, and driver may update len - * if two sides use different version of 'ublk_params', same with - * 'types' fields. - */ - __u32 len; -#define UBLK_PARAM_TYPE_BASIC (1 << 0) -#define UBLK_PARAM_TYPE_DISCARD (1 << 1) -#define UBLK_PARAM_TYPE_DEVT (1 << 2) -#define UBLK_PARAM_TYPE_ZONED (1 << 3) -#define UBLK_PARAM_TYPE_DMA_ALIGN (1 << 4) -#define UBLK_PARAM_TYPE_SEGMENT (1 << 5) - __u32 types; /* types of parameter included */ - - struct ublk_param_basic basic; - struct ublk_param_discard discard; - struct ublk_param_devt devt; - struct ublk_param_zoned zoned; - struct ublk_param_dma_align dma; - struct ublk_param_segment seg; -}; - -#endif