diff options
Diffstat (limited to 'rust/kernel/block')
| -rw-r--r-- | rust/kernel/block/mq/gen_disk.rs | 72 | ||||
| -rw-r--r-- | rust/kernel/block/mq/operations.rs | 16 | ||||
| -rw-r--r-- | rust/kernel/block/mq/request.rs | 16 | ||||
| -rw-r--r-- | rust/kernel/block/mq/tag_set.rs | 35 |
4 files changed, 81 insertions, 58 deletions
diff --git a/rust/kernel/block/mq/gen_disk.rs b/rust/kernel/block/mq/gen_disk.rs index fc97dd873974..0fe640f3aec6 100644 --- a/rust/kernel/block/mq/gen_disk.rs +++ b/rust/kernel/block/mq/gen_disk.rs @@ -7,14 +7,26 @@ use crate::{ bindings, - block::mq::{Operations, TagSet}, - error::{self, from_err_ptr, Result}, - fmt::{self, Write}, + block::mq::{ + Operations, + TagSet, // + }, + error::{ + from_err_ptr, + to_result, // + }, + fmt::{ + self, + Write, // + }, prelude::*, static_lock_class, str::NullTerminatedFormatter, sync::Arc, - types::{ForeignOwnable, ScopeGuard}, + types::{ + ForeignOwnable, + ScopeGuard, // + }, // }; /// A builder for [`GenDisk`]. @@ -54,7 +66,7 @@ impl GenDiskBuilder { /// and that it is a power of two. pub fn validate_block_size(size: u32) -> Result { if !(512..=bindings::PAGE_SIZE as u32).contains(&size) || !size.is_power_of_two() { - Err(error::code::EINVAL) + Err(EINVAL) } else { Ok(()) } @@ -63,7 +75,7 @@ impl GenDiskBuilder { /// Set the logical block size of the device to be built. /// /// This method will check that block size is a power of two and between 512 - /// and 4096. If not, an error is returned and the block size is not set. + /// and `PAGE_SIZE`. If not, an error is returned and the block size is not set. /// /// This is the smallest unit the storage device can address. It is /// typically 4096 bytes. @@ -76,7 +88,7 @@ impl GenDiskBuilder { /// Set the physical block size of the device to be built. /// /// This method will check that block size is a power of two and between 512 - /// and 4096. If not, an error is returned and the block size is not set. + /// and `PAGE_SIZE`. If not, an error is returned and the block size is not set. /// /// This is the smallest unit a physical storage device can write /// atomically. It is usually the same as the logical block size but may be @@ -125,30 +137,9 @@ impl GenDiskBuilder { ) })?; - const TABLE: bindings::block_device_operations = bindings::block_device_operations { - submit_bio: None, - open: None, - release: None, - ioctl: None, - compat_ioctl: None, - check_events: None, - unlock_native_capacity: None, - getgeo: None, - set_read_only: None, - swap_slot_free_notify: None, - report_zones: None, - devnode: None, - alternative_gpt_sector: None, - get_unique_id: None, - // TODO: Set to `THIS_MODULE`. - owner: core::ptr::null_mut(), - pr_ops: core::ptr::null_mut(), - free_disk: None, - poll_bio: None, - }; - - // SAFETY: `gendisk` is a valid pointer as we initialized it above - unsafe { (*gendisk).fops = &TABLE }; + // SAFETY: `gendisk` is a valid pointer. We have exclusive access, + // since the disk is not added to the VFS yet. + unsafe { (*gendisk).fops = &GenDisk::<T>::VTABLE }; let cleanup_failure = ScopeGuard::new_with_data((gendisk, data), |(gendisk, data)| { // SAFETY: `gendisk` came from `__blk_mq_alloc_disk()` above and @@ -177,7 +168,7 @@ impl GenDiskBuilder { // operation, so we will not race. unsafe { bindings::set_capacity(gendisk, self.capacity_sectors) }; - crate::error::to_result( + to_result( // SAFETY: `gendisk` points to a valid and initialized instance of // `struct gendisk`. unsafe { @@ -211,9 +202,22 @@ pub struct GenDisk<T: Operations> { gendisk: *mut bindings::gendisk, } +impl<T: Operations> GenDisk<T> { + const VTABLE: bindings::block_device_operations = bindings::block_device_operations { + owner: crate::module::this_module::<T::OwnerModule>().as_ptr(), + ..pin_init::zeroed() + }; +} + // SAFETY: `GenDisk` is an owned pointer to a `struct gendisk` and an `Arc` to a -// `TagSet` It is safe to send this to other threads as long as T is Send. -unsafe impl<T: Operations + Send> Send for GenDisk<T> {} +// `TagSet`. It is safe to send this to other threads as long as these two are `Send`. +unsafe impl<T> Send for GenDisk<T> +where + T: Operations, + T::QueueData: Send, + Arc<TagSet<T>>: Send, +{ +} impl<T: Operations> Drop for GenDisk<T> { fn drop(&mut self) { diff --git a/rust/kernel/block/mq/operations.rs b/rust/kernel/block/mq/operations.rs index 861903e18fbf..08111d8368eb 100644 --- a/rust/kernel/block/mq/operations.rs +++ b/rust/kernel/block/mq/operations.rs @@ -6,11 +6,17 @@ use crate::{ bindings, - block::mq::{request::RequestDataWrapper, Request}, - error::{from_result, Result}, + block::mq::{ + request::RequestDataWrapper, + Request, // + }, + error::from_result, prelude::*, - sync::{aref::ARef, Refcount}, - types::ForeignOwnable, + sync::{ + aref::ARef, + Refcount, // + }, + types::ForeignOwnable, // }; use core::marker::PhantomData; @@ -30,7 +36,7 @@ type ForeignBorrowed<'a, T> = <T as ForeignOwnable>::Borrowed<'a>; pub trait Operations: Sized { /// Data associated with the `struct request_queue` that is allocated for /// the `GenDisk` associated with this `Operations` implementation. - type QueueData: ForeignOwnable; + type QueueData: ForeignOwnable + Sync; /// Called by the kernel to queue a request with the driver. If `is_last` is /// `false`, the driver is allowed to defer committing the request. diff --git a/rust/kernel/block/mq/request.rs b/rust/kernel/block/mq/request.rs index ce3e30c81cb5..6115f9aec228 100644 --- a/rust/kernel/block/mq/request.rs +++ b/rust/kernel/block/mq/request.rs @@ -7,15 +7,21 @@ use crate::{ bindings, block::mq::Operations, - error::Result, + prelude::*, sync::{ - aref::{ARef, AlwaysRefCounted}, + aref::{ + ARef, + AlwaysRefCounted, // + }, atomic::Relaxed, - Refcount, + Refcount, // }, - types::Opaque, + types::Opaque, // +}; +use core::{ + marker::PhantomData, + ptr::NonNull, // }; -use core::{marker::PhantomData, ptr::NonNull}; /// A wrapper around a blk-mq [`struct request`]. This represents an IO request. /// diff --git a/rust/kernel/block/mq/tag_set.rs b/rust/kernel/block/mq/tag_set.rs index dae9df408a86..5f04008820b7 100644 --- a/rust/kernel/block/mq/tag_set.rs +++ b/rust/kernel/block/mq/tag_set.rs @@ -4,17 +4,21 @@ //! //! C header: [`include/linux/blk-mq.h`](srctree/include/linux/blk-mq.h) -use core::pin::Pin; - use crate::{ bindings, - block::mq::{operations::OperationsVTable, request::RequestDataWrapper, Operations}, - error::{self, Result}, - prelude::try_pin_init, - types::Opaque, + block::mq::{ + operations::OperationsVTable, + request::RequestDataWrapper, + Operations, // + }, + error::to_result, + prelude::*, + types::Opaque, // +}; +use core::{ + convert::TryInto, + marker::PhantomData, // }; -use core::{convert::TryInto, marker::PhantomData}; -use pin_init::{pin_data, pinned_drop, PinInit}; /// A wrapper for the C `struct blk_mq_tag_set`. /// @@ -33,11 +37,7 @@ pub struct TagSet<T: Operations> { impl<T: Operations> TagSet<T> { /// Try to create a new tag set - pub fn new( - nr_hw_queues: u32, - num_tags: u32, - num_maps: u32, - ) -> impl PinInit<Self, error::Error> { + pub fn new(nr_hw_queues: u32, num_tags: u32, num_maps: u32) -> impl PinInit<Self, Error> { let tag_set: bindings::blk_mq_tag_set = pin_init::zeroed(); let tag_set: Result<_> = core::mem::size_of::<RequestDataWrapper>() .try_into() @@ -63,7 +63,7 @@ impl<T: Operations> TagSet<T> { // SAFETY: we do not move out of `tag_set`. let tag_set: &mut Opaque<_> = unsafe { Pin::get_unchecked_mut(tag_set) }; // SAFETY: `tag_set` is a reference to an initialized `blk_mq_tag_set`. - error::to_result( unsafe { bindings::blk_mq_alloc_tag_set(tag_set.get())}) + to_result( unsafe { bindings::blk_mq_alloc_tag_set(tag_set.get())}) }), _p: PhantomData, }) @@ -83,3 +83,10 @@ impl<T: Operations> PinnedDrop for TagSet<T> { unsafe { bindings::blk_mq_free_tag_set(self.inner.get()) }; } } + +// SAFETY: It is safe to transfer ownership of `TagSet` between threads. +unsafe impl<T: Operations> Send for TagSet<T> {} + +// SAFETY: It is safe to share `&TagSet` across threads. `TagSet` exposes no +// `&self` methods that mutate the contained `blk_mq_tag_set`. +unsafe impl<T: Operations> Sync for TagSet<T> {} |
