summaryrefslogtreecommitdiff
AgeCommit message (Collapse)Author
2024-08-13nova: start parsing bios headersnovaDave Airlie
Co-authored-by: Danilo Krummrich <dakr@redhat.com> Signed-off-by: Danilo Krummrich <dakr@redhat.com>
2024-08-13nova: fw: copy firmware to vmalloc bufferDanilo Krummrich
Signed-off-by: Danilo Krummrich <dakr@redhat.com>
2024-08-13rust: firmware: implement `copy<A: Allocator>`Danilo Krummrich
Implement `copy<A: Allocator>` to copy firmware to a buffer backed by the given allocator. Signed-off-by: Danilo Krummrich <dakr@redhat.com>
2024-08-13rust: alloc: kvec: implement `truncate` and `resize`topic/nova/allocatorDanilo Krummrich
Signed-off-by: Danilo Krummrich <dakr@redhat.com>
2024-08-13rust: treewide: nova-next: switch to `KBox`Danilo Krummrich
Signed-off-by: Danilo Krummrich <dakr@redhat.com>
2024-08-13MAINTAINERS: add entry for the Rust `alloc` moduleDanilo Krummrich
Add maintainers entry for the Rust `alloc` module. Currently, this includes the `Allocator` API itself, `Allocator` implementations, such as `Kmalloc` or `Vmalloc`, as well as the kernel's implementation of the primary memory allocation data structures, `Box` and `Vec`. Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13kbuild: rust: remove the `alloc` crate and `GlobalAlloc`Danilo Krummrich
Now that we have our own `Allocator`, `Box` and `Vec` types we can remove Rust's `alloc` crate and the `new_uninit` unstable feature. Also remove `Kmalloc`'s `GlobalAlloc` implementation -- we can't remove this in a separate patch, since the `alloc` crate requires a `#[global_allocator]` to set, that implements `GlobalAlloc`. Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13rust: alloc: update module comment of alloc.rsDanilo Krummrich
Before we remove Rust's alloc crate, rewrite the module comment in alloc.rs to avoid a rustdoc warning. Besides that, the module comment in alloc.rs isn't correct anymore, we're no longer extending Rust's alloc crate. Reviewed-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Benno Lossin <benno.lossin@proton.me> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13rust: str: test: replace `alloc::format`Danilo Krummrich
The current implementation of tests in str.rs use `format!` to format strings for comparison, which, internally, creates a new `String`. In order to prepare for getting rid of Rust's alloc crate, we have to cut this dependency. Instead, implement `format!` for `CString`. Note that for userspace tests, `Kmalloc`, which is backing `CString`'s memory, is just a type alias to `Cmalloc`. Reviewed-by: Alice Ryhl <aliceryhl@google.com> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13rust: alloc: implement `Cmalloc` in module allocator_testDanilo Krummrich
So far the kernel's `Box` and `Vec` types can't be used by userspace test cases, since all users of those types (e.g. `CString`) use kernel allocators for instantiation. In order to allow userspace test cases to make use of such types as well, implement the `Cmalloc` allocator within the allocator_test module and type alias all kernel allocators to `Cmalloc`. The `Cmalloc` allocator uses libc's realloc() function as allocator backend. Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13rust: alloc: implement `contains` for `Flags`Danilo Krummrich
Provide a simple helper function to check whether given flags do contain one or multiple other flags. This is used by a subsequent patch implementing the Cmalloc `Allocator` to check for __GFP_ZERO. Reviewed-by: Alice Ryhl <aliceryhl@google.com> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13rust: error: check for config `test` in `Error::name`Danilo Krummrich
Additional to `testlib` also check for `test` in `Error::name`. This is required by a subsequent patch that (indirectly) uses `Error` in test cases. Reviewed-by: Alice Ryhl <aliceryhl@google.com> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13rust: error: use `core::alloc::LayoutError`Danilo Krummrich
Use `core::alloc::LayoutError` instead of `alloc::alloc::LayoutError` in preparation to get rid of Rust's alloc crate. Reviewed-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Benno Lossin <benno.lossin@proton.me> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13rust: alloc: add `Vec` to preludeDanilo Krummrich
Now that we removed `VecExt` and the corresponding includes in prelude.rs, add the new kernel `Vec` type instead. Reviewed-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Benno Lossin <benno.lossin@proton.me> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13rust: alloc: remove `VecExt` extensionDanilo Krummrich
Now that all existing `Vec` users were moved to the kernel `Vec` type, remove the `VecExt` extension. Reviewed-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Benno Lossin <benno.lossin@proton.me> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13rust: treewide: switch to the kernel `Vec` typeDanilo Krummrich
Now that we got the kernel `Vec` in place, convert all existing `Vec` users to make use of it. Reviewed-by: Alice Ryhl <aliceryhl@google.com> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13rust: alloc: implement `collect` for `IntoIter`Danilo Krummrich
Currently, we can't implement `FromIterator`. There are a couple of issues with this trait in the kernel, namely: - Rust's specialization feature is unstable. This prevents us to optimze for the special case where `I::IntoIter` equals `Vec`'s `IntoIter` type. - We also can't use `I::IntoIter`'s type ID either to work around this, since `FromIterator` doesn't require this type to be `'static`. - `FromIterator::from_iter` does return `Self` instead of `Result<Self, AllocError>`, hence we can't properly handle allocation failures. - Neither `Iterator::collect` nor `FromIterator::from_iter` can handle additional allocation flags. Instead, provide `IntoIter::collect`, such that we can at least convert `IntoIter` into a `Vec` again. Reviewed-by: Alice Ryhl <aliceryhl@google.com> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13rust: alloc: implement `IntoIterator` for `Vec`Danilo Krummrich
Implement `IntoIterator` for `Vec`, `Vec`'s `IntoIter` type, as well as `Iterator` for `IntoIter`. `Vec::into_iter` disassembles the `Vec` into its raw parts; additionally, `IntoIter` keeps track of a separate pointer, which is incremented correspondingsly as the iterator advances, while the length, or the count of elements, is decremented. This also means that `IntoIter` takes the ownership of the backing buffer and is responsible to drop the remaining elements and free the backing buffer, if it's dropped. Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13rust: alloc: implement kernel `Vec` typeDanilo Krummrich
`Vec` provides a contiguous growable array type (such as `Vec`) with contents allocated with the kernel's allocators (e.g. `Kmalloc`, `Vmalloc` or `KVmalloc`). In contrast to Rust's `Vec` type, the kernel `Vec` type considers the kernel's GFP flags for all appropriate functions, always reports allocation failures through `Result<_, AllocError>` and remains independent from unstable features. Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13rust: alloc: add `Box` to preludeDanilo Krummrich
Now that we removed `BoxExt` and the corresponding includes in prelude.rs, add the new kernel `Box` type instead. Reviewed-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Benno Lossin <benno.lossin@proton.me> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13rust: alloc: remove `BoxExt` extensionDanilo Krummrich
Now that all existing `Box` users were moved to the kernel `Box` type, remove the `BoxExt` extension and all other related extensions. Reviewed-by: Alice Ryhl <aliceryhl@google.com> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13rust: treewide: switch to our kernel `Box` typeDanilo Krummrich
Now that we got the kernel `Box` type in place, convert all existing `Box` users to make use of it. Reviewed-by: Alice Ryhl <aliceryhl@google.com> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13rust: alloc: implement kernel `Box`Danilo Krummrich
`Box` provides the simplest way to allocate memory for a generic type with one of the kernel's allocators, e.g. `Kmalloc`, `Vmalloc` or `KVmalloc`. In contrast to Rust's `Box` type, the kernel `Box` type considers the kernel's GFP flags for all appropriate functions, always reports allocation failures through `Result<_, AllocError>` and remains independent from unstable features. Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13rust: alloc: add __GFP_NOWARN to `Flags`Danilo Krummrich
Some test cases in subsequent patches provoke allocation failures. Add `__GFP_NOWARN` to enable test cases to silence unpleasant warnings. Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13rust: alloc: implement `KVmalloc` allocatorDanilo Krummrich
Implement `Allocator` for `KVmalloc`, an `Allocator` that tries to allocate memory wth `kmalloc` first and, on failure, falls back to `vmalloc`. All memory allocations made with `KVmalloc` end up in `kvrealloc_noprof()`; all frees in `kvfree()`. Reviewed-by: Alice Ryhl <aliceryhl@google.com> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13rust: alloc: implement `Vmalloc` allocatorDanilo Krummrich
Implement `Allocator` for `Vmalloc`, the kernel's virtually contiguous allocator, typically used for larger objects, (much) larger than page size. All memory allocations made with `Vmalloc` end up in `vrealloc()`. Reviewed-by: Alice Ryhl <aliceryhl@google.com> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13rust: alloc: add module `allocator_test`Danilo Krummrich
`Allocator`s, such as `Kmalloc`, will be used by e.g. `Box` and `Vec` in subsequent patches, and hence this dependency propagates throughout the whole kernel. Add the `allocator_test` module that provides an empty implementation for all `Allocator`s in the kernel, such that we don't break the `rusttest` make target in subsequent patches. Reviewed-by: Alice Ryhl <aliceryhl@google.com> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13rust: alloc: implement `Allocator` for `Kmalloc`Danilo Krummrich
Implement `Allocator` for `Kmalloc`, the kernel's default allocator, typically used for objects smaller than page size. All memory allocations made with `Kmalloc` end up in `krealloc()`. It serves as allocator for the subsequently introduced types `KBox` and `KVec`. Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13rust: alloc: rename `KernelAllocator` to `Kmalloc`Danilo Krummrich
Subsequent patches implement `Vmalloc` and `KVmalloc` allocators, hence align `KernelAllocator` to this naming scheme. Reviewed-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Gary Guo <gary@garyguo.net> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13rust: alloc: separate `aligned_size` from `krealloc_aligned`Danilo Krummrich
Separate `aligned_size` from `krealloc_aligned`. Subsequent patches implement `Allocator` derivates, such as `Kmalloc`, that require `aligned_size` and replace the original `krealloc_aligned`. Reviewed-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Benno Lossin <benno.lossin@proton.me> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13rust: alloc: add `Allocator` traitDanilo Krummrich
Add a kernel specific `Allocator` trait, that in contrast to the one in Rust's core library doesn't require unstable features and supports GFP flags. Subsequent patches add the following trait implementors: `Kmalloc`, `Vmalloc` and `KVmalloc`. Reviewed-by: Alice Ryhl <aliceryhl@google.com> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13mm: krealloc: clarify valid usage of __GFP_ZERODanilo Krummrich
Properly document that if __GFP_ZERO logic is requested, callers must ensure that, starting with the initial memory allocation, every subsequent call to this API for the same memory allocation is flagged with __GFP_ZERO. Otherwise, it is possible that __GFP_ZERO is not fully honored by this API. Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13mm: krealloc: consider spare memory for __GFP_ZERODanilo Krummrich
As long as krealloc() is called with __GFP_ZERO consistently, starting with the initial memory allocation, __GFP_ZERO should be fully honored. However, if for an existing allocation krealloc() is called with a decreased size, it is not ensured that the spare portion the allocation is zeroed. Thus, if krealloc() is subsequently called with a larger size again, __GFP_ZERO can't be fully honored, since we don't know the previous size, but only the bucket size. Example: buf = kzalloc(64, GFP_KERNEL); memset(buf, 0xff, 64); buf = krealloc(buf, 48, GFP_KERNEL | __GFP_ZERO); /* After this call the last 16 bytes are still 0xff. */ buf = krealloc(buf, 64, GFP_KERNEL | __GFP_ZERO); Fix this, by explicitly setting spare memory to zero, when shrinking an allocation with __GFP_ZERO flag set or init_on_alloc enabled. Acked-by: Vlastimil Babka <vbabka@suse.cz> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13mm: kvmalloc: align kvrealloc() with krealloc()Danilo Krummrich
Besides the obvious (and desired) difference between krealloc() and kvrealloc(), there is some inconsistency in their function signatures and behavior: - krealloc() frees the memory when the requested size is zero, whereas kvrealloc() simply returns a pointer to the existing allocation. - krealloc() is self-contained, whereas kvrealloc() relies on the caller to provide the size of the previous allocation. Inconsistent behavior throughout allocation APIs is error prone, hence make kvrealloc() behave like krealloc(), which seems superior in all mentioned aspects. Besides that, implementing kvrealloc() by making use of krealloc() and vrealloc() provides oppertunities to grow (and shrink) allocations more efficiently. For instance, vrealloc() can be optimized to allocate and map additional pages to grow the allocation or unmap and free unused pages to shrink the allocation. Acked-by: Michal Hocko <mhocko@suse.com> Acked-by: Vlastimil Babka <vbabka@suse.cz> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13mm: vmalloc: implement vrealloc()Danilo Krummrich
Implement vrealloc() analogous to krealloc(). Currently, krealloc() requires the caller to pass the size of the previous memory allocation, which, instead, should be self-contained. We attempt to fix this in a subsequent patch which, in order to do so, requires vrealloc(). Besides that, we need realloc() functions for kernel allocators in Rust too. With `Vec` potentially growing (and shrinking) data structures are rather common. Acked-by: Michal Hocko <mhocko@suse.com> Acked-by: Vlastimil Babka <vbabka@suse.cz> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2024-08-13nova: add initial driver stubDanilo Krummrich
Add the initial driver stub of Nova, a Rust-based GSP-only driver for Nvidia GPUs. Nova, in the long term, is intended to serve as the successor of Nouveau for GSP-firmware-based GPUs. [1] As a stub driver Nova's focus is to make use of the most basic device / driver infrastructure required to build a DRM driver on the PCI bus and serve as demonstration example and justification for this infrastructure. In further consequence, the idea is to develop Nova continuously upstream, using those increments to lift further Rust abstractions and infrastructure upstream. Link: https://lore.kernel.org/dri-devel/Zfsj0_tb-0-tNrJy@cassiopeiae/T/#u [1] Signed-off-by: Danilo Krummrich <dakr@redhat.com>
2024-08-13rust: drm: gem: Add GEM object abstractionAsahi Lina
The DRM GEM subsystem is the DRM memory management subsystem used by most modern drivers. Add a Rust abstraction to allow Rust DRM driver implementations to use it. Signed-off-by: Asahi Lina <lina@asahilina.net> Co-developed-by: Danilo Krummrich <dakr@redhat.com> Signed-off-by: Danilo Krummrich <dakr@redhat.com>
2024-08-13rust: drm: file: Add File abstractionAsahi Lina
A DRM File is the DRM counterpart to a kernel file structure, representing an open DRM file descriptor. Add a Rust abstraction to allow drivers to implement their own File types that implement the DriverFile trait. Signed-off-by: Asahi Lina <lina@asahilina.net> Signed-off-by: Danilo Krummrich <dakr@redhat.com>
2024-08-13rust: drm: add DRM driver registrationDanilo Krummrich
Implement the DRM driver `Registration`. The `Registration` structure is responsible to register and unregister a DRM driver. It makes use of the `Devres` container in order to allow the `Registration` to be owned by devres, such that it is automatically dropped (and the DRM driver unregistered) once the parent device is unbound. Co-developed-by: Asahi Lina <lina@asahilina.net> Signed-off-by: Asahi Lina <lina@asahilina.net> Signed-off-by: Danilo Krummrich <dakr@redhat.com>
2024-08-13rust: drm: add device abstractionDanilo Krummrich
Implement the abstraction for a `struct drm_device`. A `drm::device::Device` creates a static const `struct drm_driver` filled with the data from the `drm::drv::Driver` trait implementation of the actual driver creating the `drm::device::Device`. Co-developed-by: Asahi Lina <lina@asahilina.net> Signed-off-by: Asahi Lina <lina@asahilina.net> Signed-off-by: Danilo Krummrich <dakr@redhat.com>
2024-08-13rust: drm: add driver abstractionsDanilo Krummrich
Implement the DRM driver abstractions. The `Driver` trait provides the interface to the actual driver to fill in the driver specific data, such as the `DriverInfo`, driver features and IOCTLs. Co-developed-by: Asahi Lina <lina@asahilina.net> Signed-off-by: Asahi Lina <lina@asahilina.net> Signed-off-by: Danilo Krummrich <dakr@redhat.com>
2024-08-13rust: Add a Sealed traitAsahi Lina
Some traits exposed by the kernel crate may not be intended to be implemented by downstream modules. Add a Sealed trait to allow avoiding this using the sealed trait pattern. Signed-off-by: Asahi Lina <lina@asahilina.net> Signed-off-by: Danilo Krummrich <dakr@redhat.com>
2024-08-13rust: drm: ioctl: Add DRM ioctl abstractionAsahi Lina
DRM drivers need to be able to declare which driver-specific ioctls they support. Add an abstraction implementing the required types and a helper macro to generate the ioctl definition inside the DRM driver. Note that this macro is not usable until further bits of the abstraction are in place (but it will not fail to compile on its own, if not called). Signed-off-by: Asahi Lina <lina@asahilina.net> Signed-off-by: Danilo Krummrich <dakr@redhat.com>
2024-08-13rust: pci: implement I/O mappable `pci::Bar`Danilo Krummrich
Implement `pci::Bar`, `pci::Device::iomap_region` and `pci::Device::iomap_region_sized` to allow for I/O mappings of PCI BARs. To ensure that a `pci::Bar`, and hence the I/O memory mapping, can't out-live the PCI device, the `pci::Bar` type is always embedded into a `Devres` container, such that the `pci::Bar` is revoked once the device is unbound and hence the I/O mapped memory is unmapped. A `pci::Bar` can be requested with (`pci::Device::iomap_region_sized`) or without (`pci::Device::iomap_region`) a const generic representing the minimal requested size of the I/O mapped memory region. In case of the latter only runtime checked I/O reads / writes are possible. Co-developed-by: Philipp Stanner <pstanner@redhat.com> Signed-off-by: Philipp Stanner <pstanner@redhat.com> Signed-off-by: Danilo Krummrich <dakr@redhat.com>
2024-08-13rust: pci: add basic PCI device / driver abstractionsDanilo Krummrich
Implement the basic PCI abstractions required to write a basic PCI driver. This includes the following data structures: The `pci::Driver` trait represents the interface to the driver and provides `pci::Driver::probe` and `pci::Driver::remove` for the driver to implement. The `pci::Device` abstraction represents a `struct pci_dev` and provides abstractions for common functions, such as `pci::Device::set_master`. In order to provide the PCI specific parts to a generic `driver::Registration` the `driver::DriverOps` trait is implemented by the `pci::Adapter`. `pci::DeviceId` implements PCI device IDs based on the generic `driver::RawDevceId` abstraction. This patch is based on previous work from FUJITA Tomonori. Co-developed-by: FUJITA Tomonori <fujita.tomonori@gmail.com> Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com> Co-developed-by: Philipp Stanner <pstanner@redhat.com> Signed-off-by: Philipp Stanner <pstanner@redhat.com> Signed-off-by: Danilo Krummrich <dakr@redhat.com>
2024-08-13rust: add devres abstractionDanilo Krummrich
Add a Rust abstraction for the kernel's devres (device resource management) implementation. The Devres type acts as a container to manage the lifetime and accessibility of device bound resources. Therefore it registers a devres callback and revokes access to the resource on invocation. Users of the Devres abstraction can simply free the corresponding resources in their Drop implementation, which is invoked when either the Devres instance goes out of scope or the devres callback leads to the resource being revoked, which implies a call to drop_in_place(). Signed-off-by: Danilo Krummrich <dakr@redhat.com>
2024-08-13rust: add `io::Io` base typeDanilo Krummrich
I/O memory is typically either mapped through direct calls to ioremap() or subsystem / bus specific ones such as pci_iomap(). Even though subsystem / bus specific functions to map I/O memory are based on ioremap() / iounmap() it is not desirable to re-implement them in Rust. Instead, implement a base type for I/O mapped memory, which generically provides the corresponding accessors, such as `Io::readb` or `Io:try_readb`. `Io` supports an optional const generic, such that a driver can indicate the minimal expected and required size of the mapping at compile time. Correspondingly, calls to the 'non-try' accessors, support compile time checks of the I/O memory offset to read / write, while the 'try' accessors, provide boundary checks on runtime. `Io` is meant to be embedded into a structure (e.g. pci::Bar or io::IoMem) which creates the actual I/O memory mapping and initializes `Io` accordingly. To ensure that I/O mapped memory can't out-live the device it may be bound to, subsystems should embedd the corresponding I/O memory type (e.g. pci::Bar) into a `Devres` container, such that it gets revoked once the device is unbound. Co-developed-by: Philipp Stanner <pstanner@redhat.com> Signed-off-by: Philipp Stanner <pstanner@redhat.com> Signed-off-by: Danilo Krummrich <dakr@redhat.com>
2024-08-13rust: add `dev_*` print macros.Wedson Almeida Filho
Implement `dev_*` print macros for `device::Device`. They behave like the macros with the same names in C, i.e., they print messages to the kernel ring buffer with the given level, prefixing the messages with corresponding device information. Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com> Signed-off-by: Danilo Krummrich <dakr@redhat.com>
2024-08-13rust: add `Revocable` typeWedson Almeida Filho
Revocable allows access to objects to be safely revoked at run time. This is useful, for example, for resources allocated during device probe; when the device is removed, the driver should stop accessing the device resources even if another state is kept in memory due to existing references (i.e., device context data is ref-counted and has a non-zero refcount after removal of the device). Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com> Signed-off-by: Danilo Krummrich <dakr@redhat.com>
2024-08-13rust: add rcu abstractionWedson Almeida Filho
Add a simple abstraction to guard critical code sections with an rcu read lock. Co-developed-by: Andreas Hindborg <a.hindborg@samsung.com> Signed-off-by: Andreas Hindborg <a.hindborg@samsung.com> Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com> Signed-off-by: Danilo Krummrich <dakr@redhat.com>