cubelinux: the release starts with a digit, because module tooling demands it

The store's sort no longer lives on the kernel stack (heapsort, see the parent
commit's gate), and the release is now 6.19.3-cubelinux0.6 instead of
CUBELinux.0.6 — depmod/mkinitramfs reject a version whose first character is
not numeric, so the literal name cannot be uname -r. The box's own kernel uses
the same shape (6.19.3-cube+); this is the same concession.
This commit is contained in:
surface-camera-build
2026-09-19 06:07:47 -04:00
parent e202f960d5
commit ed5ff764ba
3 changed files with 83 additions and 2 deletions
+53 -1
View File
@@ -598,8 +598,37 @@ impl Merged {
/// Put the entries in the order a checkpoint would write them: by space, then by key,
/// with the later write of a coordinate last — so a group's final entry decides it.
///
/// This is a heapsort, and the reason is a panic rather than a preference.
/// `slice::sort_unstable` allocates about 3.5 KiB of *kernel stack* per recursion level in
/// this kernel's Rust, so a store with a couple of hundred records overflowed the 16 KiB
/// kernel stack and took the machine down — `BUG: TASK stack guard page was hit`, with the
/// instruction pointer inside
/// `core::slice::sort::unstable::quicksort::<cubelinux_store::Entry>` and `sub rsp, 0xdd8` in
/// the function's first bytes. A heapsort has a constant frame and allocates nothing, so the
/// size of a store cannot decide whether reading it is safe, and the sort cannot fail for want
/// of memory in the middle of a read.
///
/// It is not stable, which costs nothing here: `seq` is part of the ordering key, so the order
/// is total and two entries never compare equal.
fn sort_entries(&mut self) {
self.entries.as_mut_slice().sort_unstable();
let entries = self.entries.as_mut_slice();
let len = entries.len();
if len < 2 {
return;
}
// Build a max-heap, then repeatedly move the maximum to the end.
let mut start = len / 2;
while start > 0 {
start -= 1;
sift_down(entries, start, len);
}
let mut end = len;
while end > 1 {
end -= 1;
entries.swap(0, end);
sift_down(entries, 0, end);
}
}
fn value(&self, e: &Entry) -> &[u8] {
@@ -608,6 +637,29 @@ impl Merged {
}
}
/// Restore the heap property below `root` over `entries[..end]`.
///
/// Iterative on purpose: the whole point of the heapsort above is that nothing here grows with the
/// size of the store.
fn sift_down(entries: &mut [Entry], mut root: usize, end: usize) {
loop {
let left = 2 * root + 1;
if left >= end {
return;
}
let mut largest = left;
if left + 1 < end && entries[left] < entries[left + 1] {
largest = left + 1;
}
if entries[root] < entries[largest] {
entries.swap(root, largest);
root = largest;
} else {
return;
}
}
}
/// Read the log that follows the image, if there is one, and apply its entries.
///
/// The log is a delta on the image, so its entries override image records for the same