Skip to content

Commit fe750c4

Browse files
hoshinolinajannau
authored andcommitted
drm/asahi: alloc: Do not allocate memory to free memory
The existing garbage mechanism could allocate a relatively unbounded vec when freeing garbage, which was hurting memory exhaustion scenarios. The only reason we need that buffer is to move garbage out of the lock so we can drop it without deadlocks. Replace it with a 128-size pre-allocated garbage buffer, and loop around reusing it. Signed-off-by: Asahi Lina <[email protected]>
1 parent de8d510 commit fe750c4

File tree

1 file changed

+33
-21
lines changed

1 file changed

+33
-21
lines changed

drivers/gpu/drm/asahi/alloc.rs

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,7 @@ pub(crate) struct HeapAllocator {
720720
guard_nodes: Vec<mm::Node<HeapAllocatorInner, HeapAllocationInner>>,
721721
mm: mm::Allocator<HeapAllocatorInner, HeapAllocationInner>,
722722
name: CString,
723+
garbage: Option<Vec<mm::Node<HeapAllocatorInner, HeapAllocationInner>>>,
723724
}
724725

725726
impl HeapAllocator {
@@ -773,6 +774,15 @@ impl HeapAllocator {
773774
guard_nodes: Vec::new(),
774775
mm,
775776
name,
777+
garbage: if keep_garbage {
778+
Some({
779+
let mut v = Vec::new();
780+
v.try_reserve(128)?;
781+
v
782+
})
783+
} else {
784+
None
785+
},
776786
})
777787
}
778788

@@ -1038,29 +1048,31 @@ impl Allocator for HeapAllocator {
10381048
})
10391049
}
10401050

1041-
fn collect_garbage(&mut self, count: usize) {
1042-
// Take the garbage out of the inner block, so we can safely drop it without deadlocking
1043-
let mut garbage = Vec::new();
1044-
1045-
if garbage.try_reserve(count).is_err() {
1046-
dev_crit!(
1047-
self.dev,
1048-
"HeapAllocator[{}]:collect_garbage: failed to reserve space\n",
1049-
&*self.name,
1050-
);
1051-
return;
1052-
}
1051+
fn collect_garbage(&mut self, mut count: usize) {
1052+
if let Some(garbage) = self.garbage.as_mut() {
1053+
garbage.clear();
1054+
1055+
while count > 0 {
1056+
let block = count.min(garbage.capacity());
1057+
assert!(block > 0);
1058+
1059+
// Take the garbage out of the inner block, so we can safely drop it without deadlocking
1060+
self.mm.with_inner(|inner| {
1061+
if let Some(g) = inner.garbage.as_mut() {
1062+
for node in g.drain(0..block) {
1063+
inner.total_garbage -= node.size() as usize;
1064+
garbage
1065+
.try_push(node)
1066+
.expect("try_push() failed after reserve()");
1067+
}
1068+
}
1069+
});
10531070

1054-
self.mm.with_inner(|inner| {
1055-
if let Some(g) = inner.garbage.as_mut() {
1056-
for node in g.drain(0..count) {
1057-
inner.total_garbage -= node.size() as usize;
1058-
garbage
1059-
.try_push(node)
1060-
.expect("try_push() failed after reserve()");
1061-
}
1071+
count -= block;
1072+
// Now drop it
1073+
garbage.clear();
10621074
}
1063-
});
1075+
}
10641076
}
10651077
}
10661078

0 commit comments

Comments
 (0)