diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 1da54c8..c61ce3c 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -29,15 +29,15 @@ jobs: override: true components: rustfmt, clippy - - name: Build - run: make - - name: Install test deps run: | sudo apt-get update # Virtualization deps sudo apt-get install -y qemu-system-x86-64 qemu-guest-agent qemu-utils ovmf + - name: Build + run: make + - name: Cache test assets uses: actions/cache@v3 with: diff --git a/Cargo.lock b/Cargo.lock index 2e5a64d..3d07ef5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,24 +47,51 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.59.0", + "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.6" +version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", - "windows-sys 0.59.0", + "once_cell", + "windows-sys", ] [[package]] name = "anyhow" -version = "1.0.94" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" + +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + +[[package]] +name = "atty" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] [[package]] name = "autocfg" @@ -78,6 +105,26 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bindgen" +version = "0.71.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" +dependencies = [ + "bitflags 2.8.0", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -86,9 +133,32 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" + +[[package]] +name = "btree-range-map" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1be5c9672446d3800bcbcaabaeba121fe22f1fb25700c4562b22faf76d377c33" +dependencies = [ + "btree-slab", + "cc-traits", + "range-traits", + "slab", +] + +[[package]] +name = "btree-slab" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "7a2b56d3029f075c4fa892428a098425b86cef5c89ae54073137ece416aef13c" +dependencies = [ + "cc-traits", + "slab", + "smallvec", +] [[package]] name = "byteorder" @@ -96,17 +166,57 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "capctl" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a6e71767585f51c2a33fed6d67147ec0343725fc3c03bf4b89fe67fede56aa5" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", +] + +[[package]] +name = "cc-traits" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "060303ef31ef4a522737e1b1ab68c67916f2a787bb2f4f54f383279adba962b5" +dependencies = [ + "slab", +] + +[[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.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" -version = "4.5.23" +version = "4.5.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" +checksum = "8acebd8ad879283633b343856142139f2da2317c96b05b4dd6181c61e2480184" dependencies = [ "clap_builder", "clap_derive", @@ -114,9 +224,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.23" +version = "4.5.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" +checksum = "f6ba32cbda51c7e1dfd49acc1457ba1a7dec5b64fe360e828acb13ca8dc9c2f9" dependencies = [ "anstream", "anstyle", @@ -126,9 +236,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.18" +version = "4.5.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" dependencies = [ "heck", "proc-macro2", @@ -142,6 +252,12 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +[[package]] +name = "cobs" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" + [[package]] name = "colorchoice" version = "1.0.3" @@ -156,15 +272,30 @@ checksum = "55b672471b4e9f9e95499ea597ff64941a309b2cdbffcc46f2cc5e2d971fd335" [[package]] name = "console" -version = "0.15.8" +version = "0.15.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" dependencies = [ "encode_unicode", - "lazy_static", "libc", + "once_cell", "unicode-width", - "windows-sys 0.52.0", + "windows-sys", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", ] [[package]] @@ -173,21 +304,46 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + [[package]] name = "encode_unicode" -version = "0.3.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "env_filter" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" dependencies = [ "log", ] +[[package]] +name = "env_logger" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "env_logger" version = "0.10.2" @@ -203,9 +359,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" dependencies = [ "anstream", "anstyle", @@ -220,7 +376,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys", +] + +[[package]] +name = "error-chain" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" +dependencies = [ + "version_check", ] [[package]] @@ -269,6 +434,7 @@ dependencies = [ "futures-core", "futures-task", "futures-util", + "num_cpus", ] [[package]] @@ -332,14 +498,49 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] -name = "glob" +name = "getrandom" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets", +] + +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + +[[package]] +name = "heapless" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +dependencies = [ + "atomic-polyfill", + "hash32", + "rustc_version", + "serde", + "spin", + "stable_deref_trait", +] [[package]] name = "heck" @@ -347,12 +548,38 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + [[package]] name = "hermit-abi" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + [[package]] name = "humantime" version = "2.1.0" @@ -361,13 +588,13 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "is-terminal" -version = "0.4.13" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +checksum = "e19b23d53f35ce9f56aebc7d1bb4e6ac1e9c0db7ac85c8d1760c04379edced37" dependencies = [ - "hermit-abi", + "hermit-abi 0.4.0", "libc", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -399,21 +626,47 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.168" +version = "0.2.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + +[[package]] +name = "libloading" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +dependencies = [ + "cfg-if", + "windows-targets", +] [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] [[package]] name = "log" -version = "0.4.22" +version = "0.4.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" + +[[package]] +name = "match_cfg" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" [[package]] name = "matchers" @@ -439,6 +692,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "nix" version = "0.25.1" @@ -453,6 +712,16 @@ dependencies = [ "pin-utils", ] +[[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.46.0" @@ -463,11 +732,36 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.9", + "libc", +] + +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + [[package]] name = "once_cell" -version = "1.20.2" +version = "1.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" [[package]] name = "overload" @@ -477,9 +771,9 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "pin-project-lite" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -487,20 +781,49 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "postcard" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170a2601f67cc9dba8edd8c4870b15f71a6a2dc196daec8c83f72b59dff628a8" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "heapless", + "serde", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "zerocopy", + "zerocopy 0.7.35", +] + +[[package]] +name = "prettyplease" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac" +dependencies = [ + "proc-macro2", + "syn", ] [[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -573,9 +896,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -587,8 +910,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.0", + "zerocopy 0.8.17", ] [[package]] @@ -598,7 +932,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.0", ] [[package]] @@ -607,9 +951,25 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", +] + +[[package]] +name = "rand_core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff" +dependencies = [ + "getrandom 0.3.1", + "zerocopy 0.8.17", ] +[[package]] +name = "range-traits" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d20581732dd76fa913c7dff1a2412b714afe3573e94d41c34719de73337cc8ab" + [[package]] name = "regex" version = "1.11.1" @@ -702,6 +1062,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + [[package]] name = "rustc_version" version = "0.4.1" @@ -713,22 +1079,22 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.42" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys", ] [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" [[package]] name = "scopeguard" @@ -738,24 +1104,24 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.23" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" [[package]] name = "serde" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", @@ -764,9 +1130,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.138" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" dependencies = [ "itoa", "memchr", @@ -783,6 +1149,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "slab" version = "0.4.9" @@ -792,6 +1164,27 @@ dependencies = [ "autocfg", ] +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "strsim" version = "0.11.1" @@ -800,26 +1193,40 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.90" +version = "2.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "syslog" +version = "6.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc7e95b5b795122fafe6519e27629b5ab4232c73ebb2428f568e82b1a457ad3" +dependencies = [ + "error-chain", + "hostname", + "libc", + "log", + "time", +] + [[package]] name = "tempfile" -version = "3.14.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" dependencies = [ "cfg-if", "fastrand", + "getrandom 0.3.1", "once_cell", "rustix", - "windows-sys 0.59.0", + "windows-sys", ] [[package]] @@ -833,20 +1240,20 @@ dependencies = [ [[package]] name = "test-log" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dffced63c2b5c7be278154d76b479f9f9920ed34e7574201407f0b14e2bbb93" +checksum = "e7f46083d221181166e5b6f6b1e5f1d499f3a76888826e6cb1d057554157cd0f" dependencies = [ - "env_logger 0.11.5", + "env_logger 0.11.6", "test-log-macros", "tracing-subscriber", ] [[package]] name = "test-log-macros" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" +checksum = "888d0c3c6db53c0fdab160d2ed5e12ba745383d3e85813f2ea0f2b1475ab553f" dependencies = [ "proc-macro2", "quote", @@ -883,6 +1290,39 @@ dependencies = [ "once_cell", ] +[[package]] +name = "time" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +dependencies = [ + "deranged", + "itoa", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tinytemplate" version = "1.2.1" @@ -952,15 +1392,15 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.14" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" [[package]] name = "unicode-width" -version = "0.1.14" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] name = "utf8parse" @@ -968,11 +1408,134 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "uuid" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced87ca4be083373936a67f8de945faa23b6b42384bd5b64434850802c6dccd0" +dependencies = [ + "getrandom 0.3.1", + "rand 0.9.0", + "uuid-macro-internal", +] + +[[package]] +name = "uuid-macro-internal" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d28dd23acb5f2fa7bd2155ab70b960e770596b3bb6395119b40476c3655dfba4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "valuable" -version = "0.1.0" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vhost" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bce0aad4d8776cb64f1ac591e908a561c50ba6adac4416296efee590b155623f" +dependencies = [ + "bitflags 2.8.0", + "libc", + "uuid", + "vm-memory", + "vmm-sys-util", +] + +[[package]] +name = "vhost-user-backend" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daa03d476437d005abd2dec0970c468ed2a692e6a0604b834699680e171de942" +dependencies = [ + "libc", + "log", + "vhost", + "virtio-bindings", + "virtio-queue", + "vm-memory", + "vmm-sys-util", +] + +[[package]] +name = "virtio-bindings" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd2fe65550801ac106389d41f34cb1b32c4f7aaedf1b6cda1da3a211880de7f6" +dependencies = [ + "bindgen", +] + +[[package]] +name = "virtio-queue" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "872e2f3fbd70a7e6f01689720cce3d5c2c5efe52b484dd07b674246ada0e9a8d" +dependencies = [ + "log", + "virtio-bindings", + "vm-memory", + "vmm-sys-util", +] + +[[package]] +name = "virtiofsd" +version = "1.13.1" +source = "git+https://gitlab.com/d-e-s-o/virtiofsd.git?branch=topic/different-caps-backend#6ac68b7399cdf96454b9ba5c60a7589a90a478f2" +dependencies = [ + "bitflags 1.3.2", + "btree-range-map", + "capctl", + "clap", + "env_logger 0.8.4", + "futures", + "libc", + "log", + "postcard", + "serde", + "syslog", + "vhost", + "vhost-user-backend", + "virtio-bindings", + "virtio-queue", + "vm-memory", + "vmm-sys-util", +] + +[[package]] +name = "vm-memory" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1720e7240cdc739f935456eb77f370d7e9b2a3909204da1e2b47bef1137a013" +dependencies = [ + "arc-swap", + "libc", + "thiserror", + "winapi", +] + +[[package]] +name = "vmm-sys-util" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1435039746e20da4f8d507a72ee1b916f7b4b05af7a91c093d2c6561934ede" +dependencies = [ + "bitflags 1.3.2", + "libc", +] [[package]] name = "vmtest" @@ -985,7 +1548,7 @@ dependencies = [ "itertools", "log", "qapi", - "rand", + "rand 0.8.5", "regex", "rexpect", "rstest", @@ -996,6 +1559,9 @@ dependencies = [ "test-log", "tinytemplate", "toml", + "vhost-user-backend", + "virtiofsd", + "vm-memory", ] [[package]] @@ -1004,6 +1570,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "winapi" version = "0.3.9" @@ -1026,7 +1601,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys", ] [[package]] @@ -1035,15 +1610,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - [[package]] name = "windows-sys" version = "0.59.0" @@ -1117,6 +1683,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags 2.8.0", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -1124,7 +1699,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa91407dacce3a68c56de03abe2760159582b846c6a4acd2f456618087f12713" +dependencies = [ + "zerocopy-derive 0.8.17", ] [[package]] @@ -1137,3 +1721,14 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zerocopy-derive" +version = "0.8.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06718a168365cad3d5ff0bb133aad346959a2074bd4a85c121255a11304a8626" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index dac9e99..1bbaceb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,9 @@ serde_derive = "1.0.147" tempfile = "3.5.0" tinytemplate = "1.2.1" toml = "0.5.9" +vhost-user-backend = "0.17.0" +virtiofsd = { version = "1.13.1", default-features = false, git = "https://gitlab.com/d-e-s-o/virtiofsd.git", branch = "topic/different-caps-backend" } +vm-memory = { version = "0.16.1", features = ["backend-mmap", "backend-atomic"] } [dev-dependencies] rexpect = "0.5" diff --git a/README.md b/README.md index b6579f3..8bc9ced 100644 --- a/README.md +++ b/README.md @@ -26,25 +26,24 @@ The following are required dependencies, grouped by location: Host machine: -* [`qemu`](https://pkgs.org/download/qemu) +* [`qemu`](https://pkgs.org/download/qemu) (version 5.9 or higher) * [`qemu-guest-agent`](https://pkgs.org/search/?q=qemu-guest-agent) * [`OVMF`](https://pkgs.org/download/ovmf) Virtual machine image: * `qemu-guest-agent` -* Kernel 9p filesystem support, either compiled in or as modules (see kernel +* Kernel `virtiofs` support, either compiled in or as modules (see kernel dependencies) * Most (if not all) distros already ship support as modules or better -Kernel: +Kernel (version 5.4 or higher): * `CONFIG_VIRTIO=y` * `CONFIG_VIRTIO_PCI=y` * `CONFIG_VIRTIO_CONSOLE=y` -* `CONFIG_NET_9P=y` -* `CONFIG_NET_9P_VIRTIO=y` -* `CONFIG_9P_FS=y` +* `CONFIG_FUSE_FS=y` +* `CONFIG_VIRTIO_FS=y` Note the virtual machine image dependencies are only required if you're using the `image` target parameter. Likewise, the same applies for kernel diff --git a/src/lib.rs b/src/lib.rs index 46b6303..93988c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,3 +16,5 @@ pub use crate::vmtest::*; mod qemu; mod qga; +mod util; +mod virtiofsd; diff --git a/src/output.rs b/src/output.rs index 440e242..e8cd0c2 100644 --- a/src/output.rs +++ b/src/output.rs @@ -10,6 +10,11 @@ use anyhow::Result; /// Receivers should treat failures as terminal and not expect any more /// updates. pub enum Output { + /// On-host initialization starts + InitializeStart, + /// Initialization finished with provided with provided result + InitializeEnd(Result<()>), + /// VM boot begins BootStart, /// Output related to VM boot diff --git a/src/qemu.rs b/src/qemu.rs index 9758110..e4a9ce4 100644 --- a/src/qemu.rs +++ b/src/qemu.rs @@ -20,25 +20,24 @@ use std::time::Duration; use anyhow::{anyhow, bail, Context, Result}; use log::{debug, log_enabled, warn, Level}; use qapi::{qga, qmp, Qmp}; -use rand::Rng; use serde_derive::Serialize; use tempfile::{Builder, NamedTempFile}; use tinytemplate::{format_unescaped, TinyTemplate}; use crate::output::Output; use crate::qga::QgaWrapper; +use crate::util::gen_sock; +use crate::virtiofsd::Virtiofsd; use crate::{Mount, Target, VMConfig}; const INIT_TEMPLATE: &str = include_str!("init/init.sh.template"); const COMMAND_TEMPLATE: &str = include_str!("init/command.template"); -// Needs to be `/dev/root` for kernel to "find" the 9pfs as rootfs -const ROOTFS_9P_FS_MOUNT_TAG: &str = "/dev/root"; -const SHARED_9P_FS_MOUNT_TAG: &str = "vmtest-shared"; +const ROOT_FS_MOUNT_TAG: &str = "rootfs"; +const SHARED_FS_MOUNT_TAG: &str = "vmtest-shared"; const COMMAND_OUTPUT_PORT_NAME: &str = "org.qemu.virtio_serial.0"; const MAGIC_INTERACTIVE_COMMAND: &str = "-"; -const SHARED_9P_FS_MOUNT_PATH: &str = "/mnt/vmtest"; -const MOUNT_OPTS_9P_FS: &str = "trans=virtio,cache=mmap,msize=1048576"; +const SHARED_FS_MOUNT_PATH: &str = "/mnt/vmtest"; const OVMF_PATHS: &[&str] = &[ // Fedora "/usr/share/edk2/ovmf/OVMF_CODE.fd", @@ -57,6 +56,8 @@ type QmpUnixStream = qapi::Stream, UnixStream>; /// Represents a single QEMU instance pub struct Qemu { process: Command, + /// `virtiofsd` instances for each of the mounts in use. + virtiofsds: Vec, qga_sock: PathBuf, qmp_sock: PathBuf, command: String, @@ -120,13 +121,6 @@ fn host_supports_kvm(arch: &str) -> bool { arch == ARCH && Path::new("/dev/kvm").exists() } -// Generate a path to a randomly named socket -fn gen_sock(prefix: &str) -> PathBuf { - let id = rand::thread_rng().gen_range(100_000..1_000_000); - let sock = format!("/tmp/{prefix}-{id}.sock"); - PathBuf::from(sock) -} - // Given a guest temp dir and a host init path, generate the path to the init file // in the guest. // This path is the one that will be passed to the guest via the kernel's `init=` parameter. @@ -250,6 +244,26 @@ fn guest_agent_args(sock: &Path) -> Vec { args } +/// Generate general arguments necessary for working with `virtiofs`. +fn virtiofs_general_args(vm: &VMConfig) -> Vec { + let mut args: Vec = Vec::new(); + + args.push("-object".into()); + // virtiofs requires the VM's memory size as a dedicated argument + // when using shared memory for host file accesses. + args.push( + format!( + "memory-backend-memfd,id=mem,share=on,size={}", + vm.memory.as_str() + ) + .into(), + ); + args.push("-numa".into()); + args.push("node,memdev=mem".into()); + + args +} + /// Generate arguments for full KVM virtualization if host supports it fn kvm_args(arch: &str) -> Vec<&'static str> { let mut args = Vec::new(); @@ -299,30 +313,17 @@ fn machine_protocol_args(sock: &Path) -> Vec { args } -/// Generate arguments for setting up 9p FS server on host +/// Generate per-file-system arguments necessary for working with `virtiofs`. /// -/// `id` is the ID for the FS export (currently unused AFAICT) +/// `id` is the ID for the FS export /// `mount_tag` is used inside guest to find the export -fn plan9_fs_args(host_shared: &Path, id: &str, mount_tag: &str, ro: bool) -> Vec { +fn virtiofs_per_fs_args(virtiofsd: &Virtiofsd, id: &str, mount_tag: &str) -> Vec { let mut args: Vec = Vec::new(); - args.push("-virtfs".into()); - - let mut arg = OsString::new(); - arg.push(format!("local,id={id},path=")); - arg.push(if host_shared.as_os_str().is_empty() { - // This case occurs when the config file path is just "vmtest.toml" - Path::new(".") - } else { - host_shared - }); - arg.push(format!( - ",mount_tag={mount_tag},security_model=none,multidevs=remap" - )); - if ro { - arg.push(",readonly=on") - } - args.push(arg); + args.push("-chardev".into()); + args.push(format!("socket,id={id},path={}", virtiofsd.socket_path().display()).into()); + args.push("-device".into()); + args.push(format!("vhost-user-fs-pci,queue-size=1024,chardev={id},tag={mount_tag}").into()); args } @@ -379,9 +380,9 @@ fn kernel_args( // The guest kernel command line args let mut cmdline: Vec = Vec::new(); - // Tell kernel the rootfs is 9p - cmdline.push("rootfstype=9p".into()); - cmdline.push(format!("rootflags={}", MOUNT_OPTS_9P_FS).into()); + // Tell kernel the rootfs is on a virtiofs and what "tag" it uses. + cmdline.push("rootfstype=virtiofs".into()); + cmdline.push(format!("root={ROOT_FS_MOUNT_TAG}").into()); // Mount rootfs readable/writable to make experience more smooth. // Lots of tools expect to be able to write logs or change global @@ -463,16 +464,6 @@ fn vmconfig_args(vm: &VMConfig) -> Vec { vm.memory.clone().into(), ]; - for mount in vm.mounts.values() { - let name = format!("mount{}", hash(&mount.host_path)); - args.append(&mut plan9_fs_args( - &mount.host_path, - &name, - &name, - !mount.writable, - )); - } - let mut extra_args = vm .extra_args .clone() @@ -662,6 +653,7 @@ impl Qemu { .unwrap_or_else(|| format!("qemu-system-{}", target.arch)); Self::verify_qemu_exists(&program)?; + let mut virtiofsds = Vec::new(); // Start the main QEMU process let mut c = Command::new(program); @@ -673,6 +665,7 @@ impl Qemu { .args(machine_args(&target.arch)) .args(machine_protocol_args(&qmp_sock)) .args(guest_agent_args(&qga_sock)) + .args(virtiofs_general_args(&target.vm)) .args(virtio_serial_args(&command_sock)); // Always ensure the rootfs is first. if let Some(image) = &target.image { @@ -681,28 +674,34 @@ impl Qemu { c.args(uefi_firmware_args(target.vm.bios.as_deref())); } } else if let Some(kernel) = &target.kernel { - c.args(plan9_fs_args( - target.rootfs.as_path(), - "root", - ROOTFS_9P_FS_MOUNT_TAG, - false, - )); + let virtiofsd = Virtiofsd::new(target.rootfs.as_path())?; + c.args(virtiofs_per_fs_args(&virtiofsd, "root", ROOT_FS_MOUNT_TAG)); c.args(kernel_args( kernel, &target.arch, guest_init.as_path(), target.kernel_args.as_ref(), )); + virtiofsds.push(virtiofsd); } else { panic!("Config validation should've enforced XOR"); } + // Now add the shared mount and other extra mounts. - c.args(plan9_fs_args( - host_shared, + let virtiofsd = Virtiofsd::new(host_shared)?; + c.args(virtiofs_per_fs_args( + &virtiofsd, "shared", - SHARED_9P_FS_MOUNT_TAG, - false, + SHARED_FS_MOUNT_TAG, )); + virtiofsds.push(virtiofsd); + + for mount in target.vm.mounts.values() { + let name = format!("mount{}", hash(&mount.host_path)); + let virtiofsd = Virtiofsd::new(&mount.host_path)?; + c.args(virtiofs_per_fs_args(&virtiofsd, &name, &name)); + virtiofsds.push(virtiofsd); + } c.args(vmconfig_args(&target.vm)); if log_enabled!(Level::Error) { @@ -719,6 +718,7 @@ impl Qemu { let mut qemu = Self { process: c, + virtiofsds, qga_sock, qmp_sock, command: target.command, @@ -851,19 +851,12 @@ impl Qemu { // We can race with VM/qemu coming up. So retry a few times with growing backoff. let mut rc = 0; for i in 0..5 { - let mount_opts = if ro { - format!("{},ro", MOUNT_OPTS_9P_FS) - } else { - MOUNT_OPTS_9P_FS.into() - }; - rc = run_in_vm( - qga, - &output_fn, - "mount", - &["-t", "9p", "-o", &mount_opts, mount_tag, guest_path], - false, - None, - )?; + let mut args = vec!["-t", "virtiofs", mount_tag, guest_path]; + if ro { + args.push("-oro") + } + + rc = run_in_vm(qga, &output_fn, "mount", &args, false, None)?; // Exit code 32 from mount(1) indicates mount failure. // We want to retry in this case. @@ -1085,9 +1078,7 @@ impl Qemu { fn setup_vm(&mut self, qga: &QgaWrapper) -> Result<()> { // Mount shared directory inside guest let _ = self.updates.send(Output::SetupStart); - if let Err(e) = - self.mount_in_guest(qga, SHARED_9P_FS_MOUNT_PATH, SHARED_9P_FS_MOUNT_TAG, false) - { + if let Err(e) = self.mount_in_guest(qga, SHARED_FS_MOUNT_PATH, SHARED_FS_MOUNT_TAG, false) { return Err(e).context("Failed to mount shared directory in guest"); } for (guest_path, mount) in &self.mounts { @@ -1109,6 +1100,21 @@ impl Qemu { /// Errors and return status are reported through the `updates` channel passed into the /// constructor. pub fn run(mut self) { + let _ = self.updates.send(Output::InitializeStart); + for phase_fn in [Virtiofsd::launch, Virtiofsd::await_launched] { + for virtiofsd in self.virtiofsds.iter_mut() { + match phase_fn(virtiofsd) { + Ok(()) => (), + Err(e) => { + let _ = self.updates.send(Output::InitializeEnd(Err(e))); + return; + } + } + } + } + + let _ = self.updates.send(Output::InitializeEnd(Ok(()))); + // Start QEMU let (mut child, qga, mut qmp) = match self.boot_vm() { Ok((c, qga, qmp)) => (c, qga, qmp), diff --git a/src/ui.rs b/src/ui.rs index 90b44f2..7c6cbb9 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -200,6 +200,20 @@ impl Ui { }; match &msg { + Output::InitializeStart => { + stage = Stage::new( + term.clone(), + &heading("Initializing host environment", 2), + Some(stage), + ); + stages += 1; + } + Output::InitializeEnd(r) => { + if let Err(e) = r { + error_out_stage(&mut stage, e); + rc = None; + } + } Output::BootStart => { stage = Stage::new(term.clone(), &heading("Booting", 2), Some(stage)); stages += 1; diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..e53f8e4 --- /dev/null +++ b/src/util.rs @@ -0,0 +1,10 @@ +use std::env::temp_dir; +use std::path::PathBuf; + +use rand::Rng as _; + +/// Generate a path to a randomly named socket +pub(crate) fn gen_sock(prefix: &str) -> PathBuf { + let id = rand::thread_rng().gen_range(100_000..1_000_000); + temp_dir().join(format!("{prefix}-{id}.sock")) +} diff --git a/src/virtiofsd.rs b/src/virtiofsd.rs new file mode 100644 index 0000000..b936d44 --- /dev/null +++ b/src/virtiofsd.rs @@ -0,0 +1,124 @@ +use std::path::Path; +use std::path::PathBuf; +use std::sync::Arc; +use std::thread; +use std::thread::JoinHandle; +use std::time::Duration; +use std::time::Instant; + +use anyhow::bail; +use anyhow::Context as _; +use anyhow::Error; +use anyhow::Result; + +use vhost_user_backend::VhostUserDaemon; + +use virtiofsd::passthrough; +use virtiofsd::passthrough::CachePolicy; +use virtiofsd::passthrough::PassthroughFs; +use virtiofsd::vhost_user::VhostUserFsBackend; +use vm_memory::GuestMemoryAtomic; +use vm_memory::GuestMemoryMmap; + +use crate::util::gen_sock; + +enum Either { + A(A), + B(B), +} + +pub(crate) struct Virtiofsd { + #[allow(clippy::type_complexity)] + state: Either< + Option>>>, + JoinHandle>, + >, + /// The path to the Unix domain socket used for communication. + socket_path: PathBuf, +} + +impl Virtiofsd { + /// Create a `Virtiofsd` instance for sharing the given directory. + pub fn new(shared_dir: &Path) -> Result { + let socket = gen_sock("virtiofsd"); + let cache_policy = CachePolicy::Always; + let timeout = match cache_policy { + CachePolicy::Never => Duration::from_secs(0), + CachePolicy::Metadata => Duration::from_secs(86400), + CachePolicy::Auto => Duration::from_secs(1), + CachePolicy::Always => Duration::from_secs(86400), + }; + + let fs_cfg = passthrough::Config { + entry_timeout: timeout, + attr_timeout: timeout, + cache_policy, + root_dir: shared_dir + .to_str() + .context("shared directory is not a valid UTF-8 string")? + .to_string(), + announce_submounts: true, + ..Default::default() + }; + + let fs = PassthroughFs::new(fs_cfg) + .context("failed to create internal filesystem representation")?; + let fs_backend = + Arc::new(VhostUserFsBackend::new(fs).context("error creating vhost-user backend")?); + + let daemon = VhostUserDaemon::new( + String::from("virtiofsd-backend"), + fs_backend, + GuestMemoryAtomic::new(GuestMemoryMmap::new()), + ) + .map_err(|err| Error::msg(err.to_string())) + .context("failed to instantiate vhost user daemon")?; + + let slf = Self { + state: Either::A(Some(daemon)), + socket_path: socket, + }; + Ok(slf) + } + + pub fn launch(&mut self) -> Result<()> { + if let Either::A(ref mut daemon) = &mut self.state { + let mut daemon = daemon.take().unwrap(); + let socket = self.socket_path.clone(); + self.state = Either::B(thread::spawn(move || daemon.serve(socket))); + } + Ok(()) + } + + pub fn await_launched(&mut self) -> Result<()> { + if let Either::A(..) = self.state { + let () = self.launch()?; + } + + match self.state { + Either::A(..) => unreachable!(), + Either::B(..) => { + let now = Instant::now(); + let timeout = Duration::from_secs(5); + + while now.elapsed() < timeout { + if self.socket_path.exists() { + return Ok(()); + } + + thread::sleep(Duration::from_millis(1)); + } + } + }; + + bail!( + "virtiofsd socket `{}` did not appear in time", + self.socket_path.display() + ) + } + + #[inline] + pub fn socket_path(&self) -> &Path { + &self.socket_path + } +} diff --git a/tests/test.rs b/tests/test.rs index 26fc3a6..003ceb9 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -112,7 +112,7 @@ fn test_vmtest_infra_error() { assert_eq!(failed, 69); } -// Expect we can run each target one by one, sucessfully +// Expect we can run each target one by one, successfully #[test] fn test_run_one() { let uefi_image = create_new_image(asset("image-uefi.raw-efi"));