[RFC PATCH 6/8] rust: kernel: add DAX related TargetOperations

From: Qingsong Chen
Date: Sun Jun 25 2023 - 08:18:14 EST


- Add `direct_access` to translate `pgoff` to `pfn`.
- Add `dax_zero_page_range` to zero page range.
- Add `dax_recovery_write` to recover a poisoned range.

Signed-off-by: Qingsong Chen <changxian.cqs@xxxxxxxxxxxx>
---
rust/bindings/bindings_helper.h | 1 +
rust/kernel/device_mapper.rs | 139 +++++++++++++++++++++++++++++++-
2 files changed, 139 insertions(+), 1 deletion(-)

diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 807fc9cf41b8..edda3a9173dd 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -12,6 +12,7 @@
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/device-mapper.h>
+#include <linux/dax.h>

/* `bindgen` gets confused at certain things. */
const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL;
diff --git a/rust/kernel/device_mapper.rs b/rust/kernel/device_mapper.rs
index ba13294f2d0b..d2c9d0a5bcd5 100644
--- a/rust/kernel/device_mapper.rs
+++ b/rust/kernel/device_mapper.rs
@@ -5,7 +5,7 @@
//! C header: [`include/linux/device-mapper.h`](../../../../include/linux/device-mapper.h)

use core::marker::PhantomData;
-use core::ops::Index;
+use core::ops::{Index, Range};
use core::ptr::{addr_of, NonNull};

use crate::error::to_result;
@@ -136,6 +136,39 @@ fn iterate_devices(t: &mut Target<Self>) -> Result<Box<dyn Iterator<Item = IterD
fn io_hints(t: &mut Target<Self>, limits: &mut QueueLimits) {
unimplemented!()
}
+
+ /// Translate a device-relative logical-page-offset into an
+ /// absolute physical pfn.
+ ///
+ /// Return the `addr` and the `pages` available for `DAX` at
+ /// that pfn, if success.
+ #[allow(unused)]
+ fn direct_access(
+ t: &mut Target<Self>,
+ pgoff: usize,
+ nr_pages: usize,
+ mode: DaxMode,
+ ) -> Result<(usize, Range<usize>)> {
+ unimplemented!()
+ }
+
+ /// Zero page range.
+ #[allow(unused)]
+ fn dax_zero_page_range(t: &mut Target<Self>, pgoff: usize, nr_pages: usize) -> Result {
+ unimplemented!()
+ }
+
+ /// Recover a poisoned range by DAX device driver capable of
+ /// clearing poison.
+ #[allow(unused)]
+ fn dax_recovery_write(
+ t: &mut Target<Self>,
+ iov_iter: Pin<&mut IovIter>,
+ pgoff: usize,
+ region: Range<usize>,
+ ) -> usize {
+ unimplemented!()
+ }
}

/// Wrap the kernel struct `target_type`.
@@ -214,6 +247,17 @@ pub fn register<T: TargetOperations>(
(HAS_PREPARE_IOCTL, prepare_ioctl, dm_prepare_ioctl_fn),
(HAS_ITERATE_DEVICES, iterate_devices, dm_iterate_devices_fn),
(HAS_IO_HINTS, io_hints, dm_io_hints_fn),
+ (HAS_DIRECT_ACCESS, direct_access, dm_dax_direct_access_fn),
+ (
+ HAS_DAX_ZERO_PAGE_RANGE,
+ dax_zero_page_range,
+ dm_dax_zero_page_range_fn
+ ),
+ (
+ HAS_DAX_RECOVERY_WRITE,
+ dax_recovery_write,
+ dm_dax_recovery_write_fn
+ ),
);

to_result(bindings::dm_register_target(tt))
@@ -494,6 +538,60 @@ impl TargetType {
T::io_hints(t, limits);
}
}
+ unsafe extern "C" fn dm_dax_direct_access_fn<T: TargetOperations>(
+ ti: *mut bindings::dm_target,
+ pgoff: core::ffi::c_ulong,
+ nr_pages: core::ffi::c_long,
+ mode: bindings::dax_access_mode,
+ kaddr: *mut *mut core::ffi::c_void,
+ pfn: *mut bindings::pfn_t,
+ ) -> core::ffi::c_long {
+ // SAFETY: the kernel should pass valid `dm_target`, `kaddr` and
+ // `pfn` pointers.
+ unsafe {
+ let t = Target::borrow_mut(ti);
+ match T::direct_access(t, pgoff as _, nr_pages as _, mode.into()) {
+ Ok((addr, pages)) => {
+ *kaddr = addr as _;
+ (*pfn).val = pages.start as _;
+ pages.len() as _
+ }
+ Err(e) => e.to_errno() as _,
+ }
+ }
+ }
+ unsafe extern "C" fn dm_dax_zero_page_range_fn<T: TargetOperations>(
+ ti: *mut bindings::dm_target,
+ pgoff: core::ffi::c_ulong,
+ nr_pages: usize,
+ ) -> core::ffi::c_int {
+ // SAFETY: the kernel should pass valid `dm_target` pointer.
+ unsafe {
+ let t = Target::borrow_mut(ti);
+ T::dax_zero_page_range(t, pgoff as _, nr_pages as _)
+ .map_or_else(|e| e.to_errno(), |_| 0)
+ }
+ }
+ unsafe extern "C" fn dm_dax_recovery_write_fn<T: TargetOperations>(
+ ti: *mut bindings::dm_target,
+ pgoff: core::ffi::c_ulong,
+ addr: *mut core::ffi::c_void,
+ bytes: usize,
+ i: *mut bindings::iov_iter,
+ ) -> usize {
+ let region = Range {
+ start: addr as usize,
+ end: (addr as usize) + bytes,
+ };
+
+ // SAFETY: the kernel should pass valid `dm_target` and `iov_iter`
+ // pointers.
+ unsafe {
+ let t = Target::borrow_mut(ti);
+ let iov_iter = IovIter::from_raw(i);
+ T::dax_recovery_write(t, iov_iter, pgoff as _, region)
+ }
+ }
}

/// Wrap the kernel struct `dm_target`.
@@ -903,3 +1001,42 @@ unsafe fn borrow_mut<'a>(ptr: *mut bindings::queue_limits) -> &'a mut Self {
unsafe { &mut *(ptr as *mut Self) }
}
}
+
+/// Define dax direct_access mode.
+pub enum DaxMode {
+ /// Normal dax access.
+ Access,
+
+ /// Recovery write.
+ RecoveryWrite,
+
+ /// Undefined.
+ Undefined,
+}
+
+impl From<i32> for DaxMode {
+ fn from(value: i32) -> Self {
+ match value {
+ bindings::dax_access_mode_DAX_ACCESS => Self::Access,
+ bindings::dax_access_mode_DAX_RECOVERY_WRITE => Self::RecoveryWrite,
+ _ => Self::Undefined,
+ }
+ }
+}
+
+/// Wrap the kernel struct `iov_iter`.
+///
+/// Dummy.
+#[allow(dead_code)]
+#[pin_data]
+pub struct IovIter {
+ #[pin]
+ opaque: Opaque<bindings::iov_iter>,
+}
+
+impl IovIter {
+ unsafe fn from_raw<'a>(ptr: *mut bindings::iov_iter) -> Pin<&'a mut Self> {
+ // SAFETY: the caller should pass a valid `ptr`.
+ unsafe { Pin::new_unchecked(&mut *(ptr as *mut Self)) }
+ }
+}
--
2.40.1