From: Wedson Almeida Filho <walmeida@xxxxxxxxxxxxx> Introduce the abstractions that will be used by modules to handle buffer heads, which will be used to access cached blocks from block devices. All dead-code annotations are removed in the next commit in the series. Signed-off-by: Wedson Almeida Filho <walmeida@xxxxxxxxxxxxx> --- rust/bindings/bindings_helper.h | 1 + rust/helpers.c | 15 ++++++++ rust/kernel/fs.rs | 3 ++ rust/kernel/fs/buffer.rs | 61 +++++++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 rust/kernel/fs/buffer.rs diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index e2b2ccc835e3..d328375f7cb7 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -7,6 +7,7 @@ */ #include <kunit/test.h> +#include <linux/buffer_head.h> #include <linux/errname.h> #include <linux/fs.h> #include <linux/fs_context.h> diff --git a/rust/helpers.c b/rust/helpers.c index af335d1912e7..a5393c6b93f2 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -21,6 +21,7 @@ */ #include <kunit/test-bug.h> +#include <linux/buffer_head.h> #include <linux/bug.h> #include <linux/build_bug.h> #include <linux/cacheflush.h> @@ -250,6 +251,20 @@ unsigned int rust_helper_MKDEV(unsigned int major, unsigned int minor) } EXPORT_SYMBOL_GPL(rust_helper_MKDEV); +#ifdef CONFIG_BUFFER_HEAD +void rust_helper_get_bh(struct buffer_head *bh) +{ + get_bh(bh); +} +EXPORT_SYMBOL_GPL(rust_helper_get_bh); + +void rust_helper_put_bh(struct buffer_head *bh) +{ + put_bh(bh); +} +EXPORT_SYMBOL_GPL(rust_helper_put_bh); +#endif + /* * `bindgen` binds the C `size_t` type as the Rust `usize` type, so we can * use it in contexts where Rust expects a `usize` like slice (array) indices. diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index e9a9362d2897..4f04cb1d3c6f 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -15,6 +15,9 @@ use core::{marker::PhantomData, marker::PhantomPinned, mem::ManuallyDrop, pin::Pin, ptr}; use macros::{pin_data, pinned_drop}; +#[cfg(CONFIG_BUFFER_HEAD)] +pub mod buffer; + /// Maximum size of an inode. pub const MAX_LFS_FILESIZE: i64 = bindings::MAX_LFS_FILESIZE; diff --git a/rust/kernel/fs/buffer.rs b/rust/kernel/fs/buffer.rs new file mode 100644 index 000000000000..6052af8822b3 --- /dev/null +++ b/rust/kernel/fs/buffer.rs @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! File system buffers. +//! +//! C headers: [`include/linux/buffer_head.h`](../../../include/linux/buffer_head.h) + +use crate::types::{ARef, AlwaysRefCounted, Opaque}; +use core::ptr; + +/// Wraps the kernel's `struct buffer_head`. +/// +/// # Invariants +/// +/// Instances of this type are always ref-counted, that is, a call to `get_bh` ensures that the +/// allocation remains valid at least until the matching call to `put_bh`. +#[repr(transparent)] +pub struct Head(Opaque<bindings::buffer_head>); + +// SAFETY: The type invariants guarantee that `INode` is always ref-counted. +unsafe impl AlwaysRefCounted for Head { + fn inc_ref(&self) { + // SAFETY: The existence of a shared reference means that the refcount is nonzero. + unsafe { bindings::get_bh(self.0.get()) }; + } + + unsafe fn dec_ref(obj: ptr::NonNull<Self>) { + // SAFETY: The safety requirements guarantee that the refcount is nonzero. + unsafe { bindings::put_bh(obj.cast().as_ptr()) } + } +} + +impl Head { + /// Returns the block data associated with the given buffer head. + pub fn data(&self) -> &[u8] { + let h = self.0.get(); + // SAFETY: The existence of a shared reference guarantees that the buffer head is + // available and so we can access its contents. + unsafe { core::slice::from_raw_parts((*h).b_data.cast(), (*h).b_size) } + } +} + +/// A view of a buffer. +/// +/// It may contain just a contiguous subset of the buffer. +pub struct View { + head: ARef<Head>, + offset: usize, + size: usize, +} + +impl View { + #[allow(dead_code)] + pub(crate) fn new(head: ARef<Head>, offset: usize, size: usize) -> Self { + Self { head, size, offset } + } + + /// Returns the view of the buffer head. + pub fn data(&self) -> &[u8] { + &self.head.data()[self.offset..][..self.size] + } +} -- 2.34.1