From: Andreas Hindborg <a.hindborg@xxxxxxxxxxx> Hi All! This is the second version of the Rust block device driver API and the Rust null block driver. The context and motivation can be seen in cover letter of the RFC v1 [1]. If more context is required, a talk about this effort was recorded at LPC [2]. I hope to be able to discuss this series at LSF this year [3]. The series is still in RFC state, as many dependencies have not yet been merged. Changes from v1: - Improved request lifetime tracking - Changed rust null block driver name to `rnull` - Added timer completion support to `rnull` - Added softirq completion support to `rnull` - Moved to `xarray` for memory backing - Adopted the folio abstraction where applicable - Added `SAFETY` comments to all unsafe blocks - Improved documentation and added examples - Fixed up `vtable` default method behavior - Dropped `unsafe` from vtable builder - Fixed a safety issue in `RawWriter` - Dropped the `TagSetRef` abstraction - Renamed `Bio::iter` -> `Bio::raw_iter` - Updated `core::fmt::Display for Bio` for readability - Simplified `BioIterator::next` - Documented and refactored `bvec_iter` functions - Moved cache alignment out of `Lock` - Added MAINTAINER entry Thanks for all the input on v1! Performance =========== Rather than include an abundance of performance numbers in this letter, I would refer to [4] for a comparison of performance to the C null block driver. In general across all of the benchmark configurations, the mean of the difference is -2.5%, with individual configurations showing [-10%;30%] difference in IO/s. Request lifetime modeling ========================= While implementing timer completion, it became clear that the request lifetime modeling applied in the v1 RFC was not adequate. With that modeling, combined with the timer callback feature, a developer would be able to write safe Rust code that violates the Rust invariants for references, thus leading to undefined behavior. A similar situation would happen in the completion path when developers write code to convert from a completion id to a `&Request`. To make these situations safe, and thus free from undefined behavior, the `Request` type now applies reference counting. The logic piggybacks on the `atomic_t ref` field of the C `struct request`. In order to make this work, the Rust code has to be able to free requests when the refcount reaches zero. Therefore, the series exposes (EXPORT_SYMBOL_GPL) the internal blk-mq symbol `__blk_mq_free_request`. I am curious what the community thinks of this approach and whether it is OK to expose this symbol so that Rust can call it. One consequence of these changes is that requests that are processed by a Rust block device driver, are freed at a different place in the completion path, than requests processed by C drivers. Requests processed by C drivers are typically freed and recycled inline during the call to `blk_mq_complete_request`. The requests processed by a Rust driver will be recycled when the `RequestRef` is dropped, which is usually at some time after the request has been completed. There does not seem to be any statistically significant effect on performance for the rust null block implementation due to this change. Dependencies ============ This series is based on the branch `rnull-deps-v6.8` of [5]. This tree is based on the upstream `v6.8` tag and has been prepared with dependencies for this series: - [17] rust: add `CacheAligned` for easy cache line alignment of values - [16] rust: xarray: add mutable access through `Guard` - [15] rust: hrtimer: introduce hrtimer support - [14] rust: add `Opaque::try_ffi_init` - [13] rust: make `ARef` repr transparent - [12] rust: folio: add `with_slice_into_page()` - [11] rust: page: add `from_raw()` - [10] rust: page: add `with_slice_into_page()` - [ 9] IM: implement `ForeignOwnable` for `Pin` - [ 8] IM: add `module_params` macro - [ 7] rust: xarray: fix example - [ 6] LIST: rust: xarray: Add an abstraction for XArray - [ 5] LIST: rust: types: add FOREIGN_ALIGN to ForeignOwnable - [ 4] LIST: rust: lock: implement `IrqSaveBackend` for `SpinLock` - [ 3] LIST: rust: lock: add support for `Lock::lock_irqsave` - [ 2] LIST: rust: add improved version of `ForeignOwnable::borrow_mut` - [ 1] LIST: rust: folio: introduce basic support for folios - [ 0] LIST: rust: add abstraction for `struct page` Dependencies 0-6 are patches that have appeared on the list but are not yet merged. Dependencies 8-9 are imports from the `rust` branch [6,7] that have not yet been submitted. Dependencies 10-17 I will submit independently in the near future. If the upstream maintainers agree, then when the dependencies are merged, I will eventually start submitting PRs to Jens. I fully commit to maintain this code as indicated in the MAINTAINERS entry. Best regards, Andreas Hindborg [1] https://lore.kernel.org/rust-for-linux/20230503090708.2524310-1-nmi@xxxxxxxxxxxx [2] https://lpc.events/event/17/contributions/1425 [3] https://lore.kernel.org/rust-for-linux/87v87cgsp8.fsf@xxxxxxxxxxxx [4] https://rust-for-linux.com/null-block-driver [5] git https://github.com/metaspace/linux.git rnull-deps-v6.8 [6] git https://github.com/rust-for-Linux/linux.git rust [7] https://rust-for-linux.com/branches#rust Andreas Hindborg (5): rust: block: introduce `kernel::block::mq` module rust: block: introduce `kernel::block::bio` module rust: block: allow `hrtimer::Timer` in `RequestData` rust: block: add rnull, Rust null_blk implementation MAINTAINERS: add entry for Rust block device driver API MAINTAINERS | 14 ++ block/blk-mq.c | 3 +- drivers/block/Kconfig | 4 + drivers/block/Makefile | 3 + drivers/block/rnull.rs | 323 +++++++++++++++++++++++++++ include/linux/blk-mq.h | 1 + rust/bindings/bindings_helper.h | 2 + rust/helpers.c | 46 ++++ rust/kernel/block.rs | 6 + rust/kernel/block/bio.rs | 112 ++++++++++ rust/kernel/block/bio/vec.rs | 279 +++++++++++++++++++++++ rust/kernel/block/mq.rs | 131 +++++++++++ rust/kernel/block/mq/gen_disk.rs | 174 +++++++++++++++ rust/kernel/block/mq/operations.rs | 346 +++++++++++++++++++++++++++++ rust/kernel/block/mq/raw_writer.rs | 60 +++++ rust/kernel/block/mq/request.rs | 269 ++++++++++++++++++++++ rust/kernel/block/mq/tag_set.rs | 117 ++++++++++ rust/kernel/error.rs | 5 + rust/kernel/lib.rs | 1 + scripts/Makefile.build | 2 +- 20 files changed, 1896 insertions(+), 2 deletions(-) create mode 100644 drivers/block/rnull.rs create mode 100644 rust/kernel/block.rs create mode 100644 rust/kernel/block/bio.rs create mode 100644 rust/kernel/block/bio/vec.rs create mode 100644 rust/kernel/block/mq.rs create mode 100644 rust/kernel/block/mq/gen_disk.rs create mode 100644 rust/kernel/block/mq/operations.rs create mode 100644 rust/kernel/block/mq/raw_writer.rs create mode 100644 rust/kernel/block/mq/request.rs create mode 100644 rust/kernel/block/mq/tag_set.rs base-commit: e8f897f4afef0031fe618a8e94127a0934896aba prerequisite-patch-id: 299c2cc48c45c8149e7cb18c6146a0308e5d0a44 prerequisite-patch-id: 5153ee1c410dbdf22a6fd40667712943b4b89a97 prerequisite-patch-id: 4d025bab9bc9741aedecc5327ad18f88f9105271 prerequisite-patch-id: a5e932c86fa6c68234764aa3d7f314e5b534b1d9 prerequisite-patch-id: aef3042976c4c678b7aa96154fc280f9061ebaf7 prerequisite-patch-id: 8bf108ad0af2a3ec89acb8d99ee1b49ca2f51c69 prerequisite-patch-id: a803b221c3232db3258406a4075558e85acefd09 prerequisite-patch-id: 5e9cbcd0dc56a83353f0e4a3b5d4e8d5b51f3160 prerequisite-patch-id: 28bae4a7fe83b36afed9892515a6dde1ea51e98a prerequisite-patch-id: 5b5ea2a21b37afb05fdf655396a6f74d83bb99c4 prerequisite-patch-id: dc53b6ce21f74726d5d13988398c2954da07bcb6 prerequisite-patch-id: b86d2b14f1770c1d4756ca10b93efaada643e560 prerequisite-patch-id: 6a155859eb9a18afcd22a5bda3350d45d92e2fc7 prerequisite-patch-id: c8ca075008f50d3cf1781c1ea1130a8ee735e7d2 prerequisite-patch-id: b000cd190fe80dea3f4dd9172ecf8787f23b72be prerequisite-patch-id: b72f1fc3bd44b60911d9d91ecc5a45812a75eba3 prerequisite-patch-id: 167c7770e124b9afa44bead742f90a57ac73f2d7 prerequisite-patch-id: cc24a3135b4f258f4b1ea83ac91c2be4ffe31772 -- 2.44.0