[PATCH v5 0/3] rust: alloc: add KVVec shrinking method

From: Shivam Kalra via B4 Relay

Date: Sat Feb 14 2026 - 15:35:58 EST


This series adds a shrink_to() method to KVVec to allow explicit
capacity reduction for memory reclamation.

Problem:
When elements are removed from a KVVec, the allocated capacity is not
reduced. The underlying C allocators (krealloc/kvrealloc) don't shrink
memory in-place. This can cause significant memory waste in scenarios
with variable workloads.

Solution:
- Patch 1: Implements shrink_to(min_capacity, flags) method specifically
for KVVec (Vec<T, KVmalloc>). For kmalloc allocations, the method
delegates to realloc(), letting the allocator decide whether shrinking
is worthwhile. For vmalloc allocations (detected via is_vmalloc_addr),
shrinking only occurs if at least one page of memory can be freed,
using an explicit alloc+copy+free (deep copy) since vrealloc does not
yet support in-place shrinking. A TODO comment marks this for future
replacement with a generic implementation using A::realloc() once
allocators properly support shrinking.
- Patch 2: Adds KUnit tests for the new shrink_to method, verifying
page-based shrinking, empty vector handling, no-op behavior, and
min_capacity respect.
- Patch 3: Uses shrink_to() in the Rust binder driver to reclaim memory
when processes are deregistered. Uses a conservative shrinking
strategy (trigger at len < cap / 4, shrink to len * 2) to avoid
shrink-then-regrow oscillation while equalizing capacity more
aggressively when it diverges far from usage.

Testing:
- KUnit tests pass (rust_kvec test suite).
- Kernel boots successfully in QEMU with CONFIG_ANDROID_BINDER_IPC_RUST=y.

Changes since v4:
- Added is_vmalloc_addr() check: kmalloc allocations now delegate to
realloc() directly, keeping semantics as close as possible to the
future generic implementation. Only vmalloc allocations use the
page-threshold + deep copy path. (Danilo Krummrich)
- Updated doc comment to describe kmalloc vs vmalloc behavior
separately: kmalloc delegates to realloc(), vmalloc only shrinks if
at least one page can be freed via deep copy. (Danilo Krummrich)
- Fixed import style to follow kernel coding guidelines (multi-line
block import for page::{AsPageIter, PAGE_SIZE}). (Danilo Krummrich)
- Dropped duplicate TODO comment inside shrink_to() body; the TODO
above the impl block already covers this. (Danilo Krummrich)
- Structured SAFETY comments as lists when justifying multiple
conditions. (Danilo Krummrich)
- Moved semicolons outside unsafe blocks per kernel style.
(Danilo Krummrich)
- Changed binder shrink target from cap / 2 to len * 2, so that
capacity equalizes to usage more aggressively when it has diverged
far from the length. (Alice Ryhl)

Changes since v3:
- Dropped the Shrinkable trait entirely - it was not needed for the
KVVec-specific implementation. (Danilo Krummrich)
- Removed shrink_to_fit() method. Only shrink_to() is implemented.
(Danilo Krummrich)
- Implemented shrink_to() only for KVVec (impl<T> Vec<T, KVmalloc>)
instead of as a generic method, since that covers the actual use
case in binder. (Danilo Krummrich, Alice Ryhl)
- Added TODO comment explaining this is a temporary KVVec-specific
implementation that should be replaced with a generic
Vec<T, A>::shrink_to() calling A::realloc() once the underlying
allocators properly support shrinking via realloc. (Danilo Krummrich)
- Changed binder shrink strategy to be less aggressive to avoid
shrink-then-regrow oscillation: now triggers when len < cap / 4 and
shrinks to cap / 2. (Alice Ryhl)
- Removed the cap > 128 threshold check in binder. (Alice Ryhl)
- Fixed commit prefix from "rust: binder:" to "rust_binder:".
(Alice Ryhl)
- Updated test suite to focus on KVVec-specific behavior.

Changes since v2:
- Introduced new Shrinkable marker trait to distinguish allocators that
benefit from shrinking (Vmalloc) from those that don't (Kmalloc).
- Shrinking now only occurs for vmalloc-backed buffers when at least one
page can be freed, avoiding unnecessary work for kmalloc buffers.
(Suggested by Danilo Krummrich)
- Split into 4 patches: Shrinkable trait introduction is now a
separate patch to improve reviewability.
- Uses explicit alloc+copy+free since vrealloc doesn't yet support
in-place shrinking; TODO added for future optimization when vrealloc
gains that capability. (Discussed with Danilo Krummrich)
- Fixed minor KVVec/KVec terminology (binder uses KVVec not KVec).
- Expanded KUnit tests to cover different allocator backends and
page-boundary shrinking behavior.

Changes since v1:
- Resend with correct threading (no code changes).
- Removed base-commit.
- Added explicit lore link to dependency in cover letter.

[1] https://lore.kernel.org/lkml/20260130205424.261700-1-shivamklr@xxxxxxx/
[2] https://lore.kernel.org/lkml/20260131154016.270385-1-shivamklr@xxxxxxx/
[3] https://lore.kernel.org/lkml/20260207-binder-shrink-vec-v3-v3-0-8ff388563427@xxxxxxx/
[4] https://lore.kernel.org/lkml/20260212-binder-shrink-vec-v3-v4-0-bd02f06bf2cd@xxxxxxxxxxx/

Signed-off-by: Shivam Kalra <shivamkalra98@xxxxxxxxxxx>
---
Shivam Kalra (3):
rust: kvec: implement shrink_to for KVVec
rust: alloc: add KUnit tests for KVVec shrink_to
rust_binder: shrink all_procs when deregistering processes

drivers/android/binder/context.rs | 11 ++
rust/kernel/alloc/kvec.rs | 226 +++++++++++++++++++++++++++++++++++++-
2 files changed, 236 insertions(+), 1 deletion(-)
---
base-commit: 3c4ae63073d84abee5d81ce46d86a94e9dae9c89
change-id: 20260212-binder-shrink-vec-v3-c8c1131efbf7

Best regards,
--
Shivam Kalra <shivamkalra98@xxxxxxxxxxx>