aboutsummaryrefslogtreecommitdiff
path: root/rust/kernel/block
diff options
context:
space:
mode:
Diffstat (limited to 'rust/kernel/block')
-rw-r--r--rust/kernel/block/mq/gen_disk.rs72
-rw-r--r--rust/kernel/block/mq/operations.rs16
-rw-r--r--rust/kernel/block/mq/request.rs16
-rw-r--r--rust/kernel/block/mq/tag_set.rs35
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> {}