Pull driver core updates from Danilo Krummrich:
"Arch Topology:
- Move parse_acpi_topology() from arm64 to common code for reuse in
RISC-V
CPU:
- Expose housekeeping CPUs through /sys/devices/system/cpu/housekeeping
- Print a newline (or 0x0A) instead of '(null)' reading
/sys/devices/system/cpu/nohz_full when nohz_full= is not set
debugfs
- Remove (broken) 'no-mount' mode
- Remove redundant access mode checks in debugfs_get_tree() and
debugfs_create_*() functions
Devres:
- Remove unused devm_free_percpu() helper
- Move devm_alloc_percpu() from device.h to devres.h
Firmware Loader:
- Replace simple_strtol() with kstrtoint()
- Do not call cancel_store() when no upload is in progress
kernfs:
- Increase struct super_block::maxbytes to MAX_LFS_FILESIZE
- Fix a missing unwind path in __kernfs_new_node()
Misc:
- Increase the name size in struct auxiliary_device_id to 40
characters
- Replace system_unbound_wq with system_dfl_wq and add WQ_PERCPU to
alloc_workqueue()
Platform:
- Replace ERR_PTR() with IOMEM_ERR_PTR() in platform ioremap
functions
Rust:
- Auxiliary:
- Unregister auxiliary device on parent device unbind
- Move parent() to impl Device; implement device context aware
parent() for Device<Bound>
- Illustrate how to safely obtain a driver's device private data
when calling from an auxiliary driver into the parant device
driver
- DebugFs:
- Implement support for binary large objects
- Device:
- Let probe() return the driver's device private data as pinned
initializer, i.e. impl PinInit<Self, Error>
- Implement safe accessor for a driver's device private data for
Device<Bound> (returned reference can't out-live driver binding
and guarantees the correct private data type)
- Implement AsBusDevice trait, to be used by class device
abstractions to derive the bus device type of the parent device
- DMA:
- Store raw pointer of allocation as NonNull
- Use start_ptr() and start_ptr_mut() to inherit correct
mutability of self
- FS:
- Add file::Offset type alias
- I2C:
- Add abstractions for I2C device / driver infrastructure
- Implement abstractions for manual I2C device registrations
- I/O:
- Use "kernel vertical" style for imports
- Define ResourceSize as resource_size_t
- Move ResourceSize to top-level I/O module
- Add type alias for phys_addr_t
- Implement Rust version of read_poll_timeout_atomic()
- PCI:
- Use "kernel vertical" style for imports
- Move I/O and IRQ infrastructure to separate files
- Add support for PCI interrupt vectors
- Implement TryInto<IrqRequest<'a>> for IrqVector<'a> to convert
an IrqVector bound to specific pci::Device into an IrqRequest
bound to the same pci::Device's parent Device
- Leverage pin_init_scope() to get rid of redundant Result in IRQ
methods
- PinInit:
- Add {pin_}init_scope() to execute code before creating an
initializer
- Platform:
- Leverage pin_init_scope() to get rid of redundant Result in IRQ
methods
- Timekeeping:
- Implement abstraction of udelay()
- Uaccess:
- Implement read_slice_partial() and read_slice_file() for
UserSliceReader
- Implement write_slice_partial() and write_slice_file() for
UserSliceWriter
sysfs:
- Prepare the constification of struct attribute"
* tag 'driver-core-6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core: (75 commits)
rust: pci: fix build failure when CONFIG_PCI_MSI is disabled
debugfs: Fix default access mode config check
debugfs: Remove broken no-mount mode
debugfs: Remove redundant access mode checks
driver core: Check drivers_autoprobe for all added devices
driver core: WQ_PERCPU added to alloc_workqueue users
driver core: replace use of system_unbound_wq with system_dfl_wq
tick/nohz: Expose housekeeping CPUs in sysfs
tick/nohz: avoid showing '(null)' if nohz_full= not set
sysfs/cpu: Use DEVICE_ATTR_RO for nohz_full attribute
kernfs: fix memory leak of kernfs_iattrs in __kernfs_new_node
fs/kernfs: raise sb->maxbytes to MAX_LFS_FILESIZE
mod_devicetable: Bump auxiliary_device_id name size
sysfs: simplify attribute definition macros
samples/kobject: constify 'struct foo_attribute'
samples/kobject: add is_visible() callback to attribute group
sysfs: attribute_group: enable const variants of is_visible()
sysfs: introduce __SYSFS_FUNCTION_ALTERNATIVE()
sysfs: transparently handle const pointers in ATTRIBUTE_GROUPS()
sysfs: attribute_group: allow registration of const attribute
...
pin-init
Note
This crate was originally named
pinned-init, but the migration topin-initis not yet complete. Thelegacybranch contains the current version of thepinned-initcrate & themainbranch already incorporates the rename topin-init.There are still some changes needed on the kernel side before the migration can be completed.
Library to safely and fallibly initialize pinned structs using in-place constructors.
Pinning is Rust's way of ensuring data does not move.
It also allows in-place initialization of big structs that would otherwise produce a stack
overflow.
This library's main use-case is in Rust-for-Linux. Although this version can be used standalone.
There are cases when you want to in-place initialize a struct. For example when it is very big and moving it from the stack is not an option, because it is bigger than the stack itself. Another reason would be that you need the address of the object to initialize it. This stands in direct conflict with Rust's normal process of first initializing an object and then moving it into it's final memory location. For more information, see https://rust-for-linux.com/the-safe-pinned-initialization-problem.
This library allows you to do in-place initialization safely.
Nightly Needed for alloc feature
This library requires the allocator_api unstable feature when the alloc feature is
enabled and thus this feature can only be used with a nightly compiler. When enabling the
alloc feature, the user will be required to activate allocator_api as well.
The feature is enabled by default, thus by default pin-init will require a nightly compiler.
However, using the crate on stable compilers is possible by disabling alloc. In practice this
will require the std feature, because stable compilers have neither Box nor Arc in no-std
mode.
Nightly needed for unsafe-pinned feature
This feature enables the Wrapper implementation on the unstable core::pin::UnsafePinned type.
This requires the unsafe_pinned unstable feature
and therefore a nightly compiler. Note that this feature is not enabled by default.
Overview
To initialize a struct with an in-place constructor you will need two things:
- an in-place constructor,
- a memory location that can hold your
struct(this can be the stack, anArc<T>,Box<T>or any other smart pointer that supports this library).
To get an in-place constructor there are generally three options:
- directly creating an in-place constructor using the [
pin_init!] macro, - a custom function/macro returning an in-place constructor provided by someone else,
- using the unsafe function [
pin_init_from_closure()] to manually create an initializer.
Aside from pinned initialization, this library also supports in-place construction without
pinning, the macros/types/functions are generally named like the pinned variants without the
pin_ prefix.
Examples
Throughout the examples we will often make use of the CMutex type which can be found in
../examples/mutex.rs. It is essentially a userland rebuild of the struct mutex type from
the Linux kernel. It also uses a wait list and a basic spinlock. Importantly the wait list
requires it to be pinned to be locked and thus is a prime candidate for using this library.
Using the [pin_init!] macro
If you want to use [PinInit], then you will have to annotate your struct with
#[[pin_data]]. It is a macro that uses #[pin] as a marker for
structurally pinned fields. After doing this, you can then create an in-place constructor via
[pin_init!]. The syntax is almost the same as normal struct initializers. The difference is
that you need to write <- instead of : for fields that you want to initialize in-place.
use pin_init::{pin_data, pin_init, InPlaceInit};
#[pin_data]
struct Foo {
#[pin]
a: CMutex<usize>,
b: u32,
}
let foo = pin_init!(Foo {
a <- CMutex::new(42),
b: 24,
});
foo now is of the type impl PinInit<Foo>. We can now use any smart pointer that we like
(or just the stack) to actually initialize a Foo:
let foo: Result<Pin<Box<Foo>>, AllocError> = Box::pin_init(foo);
For more information see the [pin_init!] macro.
Using a custom function/macro that returns an initializer
Many types that use this library supply a function/macro that returns an initializer, because the above method only works for types where you can access the fields.
let mtx: Result<Pin<Arc<CMutex<usize>>>, _> = Arc::pin_init(CMutex::new(42));
To declare an init macro/function you just return an impl PinInit<T, E>:
#[pin_data]
struct DriverData {
#[pin]
status: CMutex<i32>,
buffer: Box<[u8; 1_000_000]>,
}
impl DriverData {
fn new() -> impl PinInit<Self, Error> {
try_pin_init!(Self {
status <- CMutex::new(0),
buffer: Box::init(pin_init::init_zeroed())?,
}? Error)
}
}
Manual creation of an initializer
Often when working with primitives the previous approaches are not sufficient. That is where
[pin_init_from_closure()] comes in. This unsafe function allows you to create a
impl PinInit<T, E> directly from a closure. Of course you have to ensure that the closure
actually does the initialization in the correct way. Here are the things to look out for
(we are calling the parameter to the closure slot):
- when the closure returns
Ok(()), then it has completed the initialization successfully, soslotnow contains a valid bit pattern for the typeT, - when the closure returns
Err(e), then the caller may deallocate the memory atslot, so you need to take care to clean up anything if your initialization fails mid-way, - you may assume that
slotwill stay pinned even after the closure returns untildropofslotgets called.
use pin_init::{pin_data, pinned_drop, PinInit, PinnedDrop, pin_init_from_closure};
use core::{
ptr::addr_of_mut,
marker::PhantomPinned,
cell::UnsafeCell,
pin::Pin,
mem::MaybeUninit,
};
mod bindings {
#[repr(C)]
pub struct foo {
/* fields from C ... */
}
extern "C" {
pub fn init_foo(ptr: *mut foo);
pub fn destroy_foo(ptr: *mut foo);
#[must_use = "you must check the error return code"]
pub fn enable_foo(ptr: *mut foo, flags: u32) -> i32;
}
}
/// # Invariants
///
/// `foo` is always initialized
#[pin_data(PinnedDrop)]
pub struct RawFoo {
#[pin]
_p: PhantomPinned,
#[pin]
foo: UnsafeCell<MaybeUninit<bindings::foo>>,
}
impl RawFoo {
pub fn new(flags: u32) -> impl PinInit<Self, i32> {
// SAFETY:
// - when the closure returns `Ok(())`, then it has successfully initialized and
// enabled `foo`,
// - when it returns `Err(e)`, then it has cleaned up before
unsafe {
pin_init_from_closure(move |slot: *mut Self| {
// `slot` contains uninit memory, avoid creating a reference.
let foo = addr_of_mut!((*slot).foo);
let foo = UnsafeCell::raw_get(foo).cast::<bindings::foo>();
// Initialize the `foo`
bindings::init_foo(foo);
// Try to enable it.
let err = bindings::enable_foo(foo, flags);
if err != 0 {
// Enabling has failed, first clean up the foo and then return the error.
bindings::destroy_foo(foo);
Err(err)
} else {
// All fields of `RawFoo` have been initialized, since `_p` is a ZST.
Ok(())
}
})
}
}
}
#[pinned_drop]
impl PinnedDrop for RawFoo {
fn drop(self: Pin<&mut Self>) {
// SAFETY: Since `foo` is initialized, destroying is safe.
unsafe { bindings::destroy_foo(self.foo.get().cast::<bindings::foo>()) };
}
}
For more information on how to use [pin_init_from_closure()], take a look at the uses inside
the kernel crate. The sync module is a good starting point.