From 7324b88975c525a013ae0db747df97924ce80675 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Mon, 28 Aug 2023 10:48:04 +0000 Subject: rust: workqueue: add helper for defining work_struct fields The main challenge with defining `work_struct` fields is making sure that the function pointer stored in the `work_struct` is appropriate for the work item type it is embedded in. It needs to know the offset of the `work_struct` field being used (even if there are several!) so that it can do a `container_of`, and it needs to know the type of the work item so that it can call into the right user-provided code. All of this needs to happen in a way that provides a safe API to the user, so that users of the workqueue cannot mix up the function pointers. There are three important pieces that are relevant when doing this: * The pointer type. * The work item struct. This is what the pointer points at. * The `work_struct` field. This is a field of the work item struct. This patch introduces a separate trait for each piece. The pointer type is given a `WorkItemPointer` trait, which pointer types need to implement to be usable with the workqueue. This trait will be implemented for `Arc` and `Box` in a later patch in this patchset. Implementing this trait is unsafe because this is where the `container_of` operation happens, but user-code will not need to implement it themselves. The work item struct should then implement the `WorkItem` trait. This trait is where user-code specifies what they want to happen when a work item is executed. It also specifies what the correct pointer type is. Finally, to make the work item struct know the offset of its `work_struct` field, we use a trait called `HasWork`. If a type implements this trait, then the type declares that, at the given offset, there is a field of type `Work`. The trait is marked unsafe because the OFFSET constant must be correct, but we provide an `impl_has_work!` macro that can safely implement `HasWork` on a type. The macro expands to something that only compiles if the specified field really has the type `Work`. It is used like this: ``` struct MyWorkItem { work_field: Work, } impl_has_work! { impl HasWork for MyWorkItem { self.work_field } } ``` Note that since the `Work` type is annotated with an id, you can have several `work_struct` fields by using a different id for each one. Co-developed-by: Gary Guo Signed-off-by: Gary Guo Signed-off-by: Alice Ryhl Reviewed-by: Benno Lossin Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Andreas Hindborg Reviewed-by: Boqun Feng Signed-off-by: Tejun Heo --- rust/helpers.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'rust/helpers.c') diff --git a/rust/helpers.c b/rust/helpers.c index 4c86fe4a7e05..70e59efd92bc 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -30,6 +30,7 @@ #include #include #include +#include __noreturn void rust_helper_BUG(void) { @@ -144,6 +145,18 @@ struct kunit *rust_helper_kunit_get_current_test(void) } EXPORT_SYMBOL_GPL(rust_helper_kunit_get_current_test); +void rust_helper_init_work_with_key(struct work_struct *work, work_func_t func, + bool onstack, const char *name, + struct lock_class_key *key) +{ + __init_work(work, onstack); + work->data = (atomic_long_t)WORK_DATA_INIT(); + lockdep_init_map(&work->lockdep_map, name, key, 0); + INIT_LIST_HEAD(&work->entry); + work->func = func; +} +EXPORT_SYMBOL_GPL(rust_helper_init_work_with_key); + /* * `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. -- cgit