@@ -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>
@@ -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.
@@ -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;
new file mode 100644
@@ -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]
+ }
+}