xref: /linux/rust/kernel/list/impl_list_item_mod.rs (revision 40c53294596b4a7fe2ae126d7aab986752496c31)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 // Copyright (C) 2024 Google LLC.
4 
5 //! Helpers for implementing list traits safely.
6 
7 use crate::list::ListLinks;
8 
9 /// Declares that this type has a `ListLinks<ID>` field at a fixed offset.
10 ///
11 /// This trait is only used to help implement `ListItem` safely. If `ListItem` is implemented
12 /// manually, then this trait is not needed. Use the [`impl_has_list_links!`] macro to implement
13 /// this trait.
14 ///
15 /// # Safety
16 ///
17 /// All values of this type must have a `ListLinks<ID>` field at the given offset.
18 ///
19 /// The behavior of `raw_get_list_links` must not be changed.
20 pub unsafe trait HasListLinks<const ID: u64 = 0> {
21     /// The offset of the `ListLinks` field.
22     const OFFSET: usize;
23 
24     /// Returns a pointer to the [`ListLinks<T, ID>`] field.
25     ///
26     /// # Safety
27     ///
28     /// The provided pointer must point at a valid struct of type `Self`.
29     ///
30     /// [`ListLinks<T, ID>`]: ListLinks
31     // We don't really need this method, but it's necessary for the implementation of
32     // `impl_has_list_links!` to be correct.
33     #[inline]
34     unsafe fn raw_get_list_links(ptr: *mut Self) -> *mut ListLinks<ID> {
35         // SAFETY: The caller promises that the pointer is valid. The implementer promises that the
36         // `OFFSET` constant is correct.
37         unsafe { (ptr as *mut u8).add(Self::OFFSET) as *mut ListLinks<ID> }
38     }
39 }
40 
41 /// Implements the [`HasListLinks`] trait for the given type.
42 #[macro_export]
43 macro_rules! impl_has_list_links {
44     ($(impl$(<$($implarg:ident),*>)?
45        HasListLinks$(<$id:tt>)?
46        for $self:ident $(<$($selfarg:ty),*>)?
47        { self$(.$field:ident)* }
48     )*) => {$(
49         // SAFETY: The implementation of `raw_get_list_links` only compiles if the field has the
50         // right type.
51         //
52         // The behavior of `raw_get_list_links` is not changed since the `addr_of_mut!` macro is
53         // equivalent to the pointer offset operation in the trait definition.
54         unsafe impl$(<$($implarg),*>)? $crate::list::HasListLinks$(<$id>)? for
55             $self $(<$($selfarg),*>)?
56         {
57             const OFFSET: usize = ::core::mem::offset_of!(Self, $($field).*) as usize;
58 
59             #[inline]
60             unsafe fn raw_get_list_links(ptr: *mut Self) -> *mut $crate::list::ListLinks$(<$id>)? {
61                 // SAFETY: The caller promises that the pointer is not dangling. We know that this
62                 // expression doesn't follow any pointers, as the `offset_of!` invocation above
63                 // would otherwise not compile.
64                 unsafe { ::core::ptr::addr_of_mut!((*ptr)$(.$field)*) }
65             }
66         }
67     )*};
68 }
69 pub use impl_has_list_links;
70 
71 /// Implements the [`ListItem`] trait for the given type.
72 ///
73 /// Requires that the type implements [`HasListLinks`]. Use the [`impl_has_list_links!`] macro to
74 /// implement that trait.
75 ///
76 /// [`ListItem`]: crate::list::ListItem
77 #[macro_export]
78 macro_rules! impl_list_item {
79     (
80         $(impl$({$($generics:tt)*})? ListItem<$num:tt> for $t:ty {
81             using ListLinks;
82         })*
83     ) => {$(
84         // SAFETY: See GUARANTEES comment on each method.
85         unsafe impl$(<$($generics)*>)? $crate::list::ListItem<$num> for $t {
86             // GUARANTEES:
87             // * This returns the same pointer as `prepare_to_insert` because `prepare_to_insert`
88             //   is implemented in terms of `view_links`.
89             // * By the type invariants of `ListLinks`, the `ListLinks` has two null pointers when
90             //   this value is not in a list.
91             unsafe fn view_links(me: *const Self) -> *mut $crate::list::ListLinks<$num> {
92                 // SAFETY: The caller guarantees that `me` points at a valid value of type `Self`.
93                 unsafe {
94                     <Self as $crate::list::HasListLinks<$num>>::raw_get_list_links(me.cast_mut())
95                 }
96             }
97 
98             // GUARANTEES:
99             // * `me` originates from the most recent call to `prepare_to_insert`, which just added
100             //   `offset` to the pointer passed to `prepare_to_insert`. This method subtracts
101             //   `offset` from `me` so it returns the pointer originally passed to
102             //   `prepare_to_insert`.
103             // * The pointer remains valid until the next call to `post_remove` because the caller
104             //   of the most recent call to `prepare_to_insert` promised to retain ownership of the
105             //   `ListArc` containing `Self` until the next call to `post_remove`. The value cannot
106             //   be destroyed while a `ListArc` reference exists.
107             unsafe fn view_value(me: *mut $crate::list::ListLinks<$num>) -> *const Self {
108                 let offset = <Self as $crate::list::HasListLinks<$num>>::OFFSET;
109                 // SAFETY: `me` originates from the most recent call to `prepare_to_insert`, so it
110                 // points at the field at offset `offset` in a value of type `Self`. Thus,
111                 // subtracting `offset` from `me` is still in-bounds of the allocation.
112                 unsafe { (me as *const u8).sub(offset) as *const Self }
113             }
114 
115             // GUARANTEES:
116             // This implementation of `ListItem` will not give out exclusive access to the same
117             // `ListLinks` several times because calls to `prepare_to_insert` and `post_remove`
118             // must alternate and exclusive access is given up when `post_remove` is called.
119             //
120             // Other invocations of `impl_list_item!` also cannot give out exclusive access to the
121             // same `ListLinks` because you can only implement `ListItem` once for each value of
122             // `ID`, and the `ListLinks` fields only work with the specified `ID`.
123             unsafe fn prepare_to_insert(me: *const Self) -> *mut $crate::list::ListLinks<$num> {
124                 // SAFETY: The caller promises that `me` points at a valid value.
125                 unsafe { <Self as $crate::list::ListItem<$num>>::view_links(me) }
126             }
127 
128             // GUARANTEES:
129             // * `me` originates from the most recent call to `prepare_to_insert`, which just added
130             //   `offset` to the pointer passed to `prepare_to_insert`. This method subtracts
131             //   `offset` from `me` so it returns the pointer originally passed to
132             //   `prepare_to_insert`.
133             unsafe fn post_remove(me: *mut $crate::list::ListLinks<$num>) -> *const Self {
134                 let offset = <Self as $crate::list::HasListLinks<$num>>::OFFSET;
135                 // SAFETY: `me` originates from the most recent call to `prepare_to_insert`, so it
136                 // points at the field at offset `offset` in a value of type `Self`. Thus,
137                 // subtracting `offset` from `me` is still in-bounds of the allocation.
138                 unsafe { (me as *const u8).sub(offset) as *const Self }
139             }
140         }
141     )*};
142 }
143 pub use impl_list_item;
144