From nobody Mon Feb 9 19:25:24 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E8B98EB64DC for ; Sun, 25 Jun 2023 12:18:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232133AbjFYMS0 (ORCPT ); Sun, 25 Jun 2023 08:18:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49734 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232171AbjFYMSF (ORCPT ); Sun, 25 Jun 2023 08:18:05 -0400 Received: from out0-220.mail.aliyun.com (out0-220.mail.aliyun.com [140.205.0.220]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 83493E47; Sun, 25 Jun 2023 05:17:45 -0700 (PDT) X-Alimail-AntiSpam: AC=PASS;BC=-1|-1;BR=01201311R231e4;CH=green;DM=||false|;DS=||;FP=0|-1|-1|-1|0|-1|-1|-1;HT=ay29a033018047190;MF=changxian.cqs@antgroup.com;NM=1;PH=DS;RN=11;SR=0;TI=SMTPD_---.TdIoyYs_1687695461; Received: from localhost(mailfrom:changxian.cqs@antgroup.com fp:SMTPD_---.TdIoyYs_1687695461) by smtp.aliyun-inc.com; Sun, 25 Jun 2023 20:17:42 +0800 From: "Qingsong Chen" To: linux-kernel@vger.kernel.org Cc: "=?UTF-8?B?55Sw5rSq5Lqu?=" , "Qingsong Chen" , "Miguel Ojeda" , "Alex Gaynor" , "Wedson Almeida Filho" , "Boqun Feng" , "Gary Guo" , "=?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?=" , "Benno Lossin" , Subject: [RFC PATCH 8/8] samples: rust: add a device mapper linear target Date: Sun, 25 Jun 2023 20:16:57 +0800 Message-Id: <20230625121657.3631109-9-changxian.cqs@antgroup.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20230625121657.3631109-1-changxian.cqs@antgroup.com> References: <20230625121657.3631109-1-changxian.cqs@antgroup.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Add a device mapper linear target sample, based on the rust device_mapper abstractions. Signed-off-by: Qingsong Chen --- samples/rust/Kconfig | 10 ++ samples/rust/Makefile | 1 + samples/rust/rust_dm_linear.rs | 257 +++++++++++++++++++++++++++++++++ 3 files changed, 268 insertions(+) create mode 100644 samples/rust/rust_dm_linear.rs diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig index b0f74a81c8f9..0d532c995f9a 100644 --- a/samples/rust/Kconfig +++ b/samples/rust/Kconfig @@ -30,6 +30,16 @@ config SAMPLE_RUST_PRINT =20 If unsure, say N. =20 +config SAMPLE_RUST_DM_LINEAR + tristate "Device mapper linear target" + help + This option builds the Rust device mapper linear sample. + + To compile this as a module, choose M here: + the module will be called rust_dm_linear. + + If unsure, say N. + config SAMPLE_RUST_HOSTPROGS bool "Host programs" help diff --git a/samples/rust/Makefile b/samples/rust/Makefile index 03086dabbea4..cf4bf82312d8 100644 --- a/samples/rust/Makefile +++ b/samples/rust/Makefile @@ -2,5 +2,6 @@ =20 obj-$(CONFIG_SAMPLE_RUST_MINIMAL) +=3D rust_minimal.o obj-$(CONFIG_SAMPLE_RUST_PRINT) +=3D rust_print.o +obj-$(CONFIG_SAMPLE_RUST_DM_LINEAR) +=3D rust_dm_linear.o =20 subdir-$(CONFIG_SAMPLE_RUST_HOSTPROGS) +=3D hostprogs diff --git a/samples/rust/rust_dm_linear.rs b/samples/rust/rust_dm_linear.rs new file mode 100644 index 000000000000..1f338e6b227f --- /dev/null +++ b/samples/rust/rust_dm_linear.rs @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Rust device mapper linear target sample. +//! +//! C version: drivers/md/dm-linear.c + +use core::ops::Range; +use core::ptr::NonNull; +use kernel::bindings::PAGE_SECTORS_SHIFT; +use kernel::device_mapper::*; +use kernel::prelude::*; +use kernel::{c_str, fmt, str::CString}; + +module! { + type: RustDmLinear, + name: "rust_dm_linear", + author: "Rust for Linux Contributors", + description: "Rust device mapper linear target sample", + license: "GPL", +} + +struct Linear { + dev: TargetDevice, + start: usize, +} + +impl Linear { + fn new(dev: TargetDevice, start: usize) -> impl Init { + init!(Self { dev, start }) + } + + fn map_sector(&self, sector: usize, base: usize) -> usize { + sector - base + self.start + } +} + +// SAFETY: `Linear` could be used from all threads. +unsafe impl Sync for Linear {} + +#[vtable] +impl TargetOperations for Linear { + type Private =3D Linear; + + fn ctr(t: &mut Target, args: Args) -> Result> { + if args.len() !=3D 2 { + t.set_error(c_str!("Invalid argument count")); + return Err(EINVAL); + } + + let dev =3D match t.get_device(&args[0]) { + Ok(dev) =3D> dev, + Err(e) =3D> { + t.set_error(c_str!("Device lookup failed")); + return Err(e); + } + }; + + let start =3D &args[1].to_str().map_err(|_| EINVAL)?; + let start =3D usize::from_str_radix(start, 10).map_err(|_| { + t.set_error(c_str!("Invalid device sector")); + EINVAL + })?; + + t.set_num_flush_bios(1); + t.set_num_discard_bios(1); + t.set_num_secure_erase_bios(1); + t.set_num_write_zeroes_bios(1); + + Box::init(Linear::new(dev, start)) + } + + fn dtr(_: &mut Target) {} + + fn map(t: &mut Target, mut bio: Pin<&mut Bio>) -> MapState { + let Some(linear) =3D t.private() else { + pr_warn!("Error, found no rust_linear\n"); + return MapState::Kill; + }; + + let offset =3D bio.sector() - linear.dev.target().begin_sector(); + bio.set_dev(&linear.dev); + bio.set_sector(linear.start + offset); + MapState::Remapped + } + + fn status(t: &mut Target, type_: StatusType, _: StatusFlags) -> = Option { + let Some(linear) =3D t.private() else { + pr_warn!("Error, found no rust_linear\n"); + return None; + }; + + match type_ { + StatusType::Info =3D> None, + StatusType::Table =3D> { + CString::try_from_fmt(fmt!("{} {}", linear.dev.device_name= (), linear.start)).ok() + } + StatusType::Ima =3D> { + let version =3D linear.dev.target().version(); + CString::try_from_fmt(fmt!( + "target_name=3D{},target_version=3D{}.{}.{},device_nam= e=3D{},start=3D{};", + linear.dev.target().name(), + version[0], + version[1], + version[2], + linear.dev.device_name(), + linear.start + )) + .ok() + } + _ =3D> { + pr_warn!("Unsupported dm_status_type\n"); + None + } + } + } + + fn prepare_ioctl(t: &mut Target) -> (i32, Option>>) { + let Some(mut linear) =3D t.private() else { + pr_warn!("Error, found no rust_linear\n"); + return (EINVAL.to_errno(), None); + }; + + let mut ret =3D 0; + if linear.start > 0 || linear.dev.target().total_sectors() !=3D li= near.dev.device_sectors() { + ret =3D 1; + } + (ret, Some(linear.dev.as_ptr())) + } + + fn iterate_devices(t: &mut Target) -> Result>>> { + let Some(mut linear) =3D t.private() else { + pr_warn!("Error, found no rust_linear\n"); + return Err(EINVAL); + }; + + Ok(Box::init(IterLinear::new( + linear.dev.as_ptr(), + linear.start, + t.total_sectors(), + ))?) + } + + #[cfg(CONFIG_BLK_DEV_ZONED)] + fn report_zones(t: &mut Target, args: &mut [ReportZonesArgs]) ->= Result { + if args.len() =3D=3D 0 { + pr_warn!("Invalid report_zones_args\n"); + return Err(EINVAL); + } + + let Some(linear) =3D t.private() else { + pr_warn!("Error, found no rust_linear\n"); + return Err(EINVAL); + }; + + let sector =3D linear.map_sector(args[0].next_sector(), linear.dev= .target().begin_sector()); + linear.dev.report_zones(linear.start, sector, args) + } + + #[cfg(CONFIG_FS_DAX)] + fn direct_access( + t: &mut Target, + pgoff: usize, + nr_pages: usize, + mode: DaxMode, + ) -> Result<(usize, Range)> { + let base =3D t.begin_sector(); + let Some(mut linear) =3D t.private() else { + pr_warn!("Error, found no rust_linear\n"); + return Err(EINVAL); + }; + + let sector =3D linear.map_sector(pgoff << PAGE_SECTORS_SHIFT, base= ); + let offset =3D (linear.dev.device_sectors() + sector) >> PAGE_SECT= ORS_SHIFT; + linear.dev.dax_direct_access(offset, nr_pages, mode) + } + + #[cfg(CONFIF_FS_DAX)] + fn dax_zero_page_range(t: &mut Target, pgoff: usize, nr_pages: u= size) -> Result { + let base =3D t.begin_sector(); + let Some(mut linear) =3D t.private() else { + pr_warn!("Error, found no rust_linear\n"); + return Err(EINVAL); + }; + + let sector =3D linear.map_sector(pgoff << PAGE_SECTORS_SHIFT, base= ); + let offset =3D (linear.dev.device_sectors() + sector) >> PAGE_SECT= ORS_SHIFT; + linear.dev.dax_zero_page_range(offset, nr_pages) + } + + #[cfg(CONFIF_FS_DAX)] + fn dax_recovery_write( + t: &mut Target, + iov_iter: Pin<&mut IovIter>, + pgoff: usize, + region: Range, + ) -> usize { + let base =3D t.begin_sector(); + let Some(mut linear) =3D t.private() else { + pr_warn!("Error, found no rust_linear\n"); + return 0; + }; + + let sector =3D linear.map_sector(pgoff << PAGE_SECTORS_SHIFT, base= ); + let offset =3D (linear.dev.device_sectors() + sector) >> PAGE_SECT= ORS_SHIFT; + linear.dev.dax_recovery_write(iov_iter, offset, region) + } +} + +struct IterLinear { + item: Option>, +} + +impl IterLinear { + fn new(dev: NonNull>, start: usize, len: usize) -= > impl Init { + init!(Self { + item: Some((dev, start, len)) + }) + } +} + +impl Iterator for IterLinear { + type Item =3D IterDevice; + + fn next(&mut self) -> Option { + self.item.take() + } +} + +struct RustDmLinear(Pin>); + +impl kernel::Module for RustDmLinear { + fn init(_module: &'static ThisModule) -> Result { + pr_info!("Rust device mapper linear target sample (init)\n"); + + let target =3D Box::pin_init(TargetType::register::( + _module, + c_str!("rust_linear"), + [0, 0, 1], + 0, + )); + + let target =3D match target { + Ok(target) =3D> target, + Err(e) =3D> { + pr_warn!("Target register failed, errno: {}\n", e.to_errno= ()); + return Err(e); + } + }; + Ok(RustDmLinear(target)) + } +} + +impl Drop for RustDmLinear { + fn drop(&mut self) { + pr_info!("Rust device mapper linear target sample (exit)\n"); + } +} --=20 2.40.1