Qwen3.8-Flash-Next-Uncensored-ROCmFP4-FAST-GGUF / qwen4exp-qsa-checkpoint-fix.patch
kingjones777's picture
fix: complete MTP patch + QSA checkpoint fix (2026-09-17)
721fc7f verified
Raw History Blame Contribute Delete
4.94 kB
From 85d8f7e83499e434c24993e6e1f3800568b5adfd Mon Sep 17 00:00:00 2001
From: kingjones30 <myron@deploy365.us>
Date: Thu, 3 Sep 2026 12:33:12 +0000
Subject: [PATCH] fix(qwen4exp): serialize QSA indexer cache in context
checkpoints
llama_memory_hybrid_idx inherited state_write/state_read from the hybrid
base and never overrode them, so checkpoints omitted mem_idx. A restore
then left the QSA index pointing at a different position than the KV
caches; the next kernel could wedge the GPU SDMA queue (field report:
kingjones777/Qwen3.8-Flash-Next-ROCmFP4-STRIX-GGUF#6, @liusecret).
Also treat empty seq_rm ranges as no-ops and honor mem_idx->seq_rm.
---
common/common.cpp | 16 ++++++++++++++++
src/llama-memory-hybrid-idx.cpp | 34 ++++++++++++++++++++++++++++++++-
src/llama-memory-hybrid-idx.h | 3 +++
3 files changed, 52 insertions(+), 1 deletion(-)
diff --git a/common/common.cpp b/common/common.cpp
index 1421040..e64a71b 100644
--- a/common/common.cpp
+++ b/common/common.cpp
@@ -1510,6 +1510,22 @@ done:
void common_context_seq_rm(llama_context * ctx, llama_seq_id seq_id, llama_pos p0, llama_pos p1) {
auto * mem = llama_get_memory(ctx);
+ if (mem == nullptr) {
+ return;
+ }
+ // empty range is a no-op, not a fatal. recurrent caches refuse p0 == n_past,
+ // p1 == -1 instead of succeeding, which used to abort the server.
+ const llama_pos p0n = p0 < 0 ? 0 : p0;
+ if (p1 >= 0) {
+ if (p0n >= p1) {
+ return;
+ }
+ } else {
+ const llama_pos p_max = llama_memory_seq_pos_max(mem, seq_id);
+ if (p_max >= 0 && p0n > p_max) {
+ return;
+ }
+ }
if (!llama_memory_seq_rm(mem, seq_id, p0, p1)) {
GGML_ABORT("%s", string_format("failed to remove sequence %d with p0=%d, p1=%d\n", seq_id, p0, p1).c_str());
}
diff --git a/src/llama-memory-hybrid-idx.cpp b/src/llama-memory-hybrid-idx.cpp
index 586b340..b32b1b7 100644
--- a/src/llama-memory-hybrid-idx.cpp
+++ b/src/llama-memory-hybrid-idx.cpp
@@ -142,6 +142,16 @@ void llama_memory_hybrid_idx::clear(bool data) {
}
bool llama_memory_hybrid_idx::seq_rm(llama_seq_id seq_id, llama_pos p0, llama_pos p1) {
+ // empty range is a no-op. the recurrent cache refuses p0 == n_past, p1 == -1
+ // (rollback past n_rs_seq) instead of succeeding, which made common_context_seq_rm abort.
+ {
+ const llama_pos p0n = p0 < 0 ? 0 : p0;
+ const llama_pos p_max = llama_memory_hybrid::seq_pos_max(seq_id);
+ if (p1 >= 0 ? p0n >= p1 : (p_max >= 0 && p0n > p_max)) {
+ return true;
+ }
+ }
+
// same order as llama_memory_hybrid::seq_rm: try the recurrent cache first since it is the
// one that may refuse, and if it does the caches are left untouched
if (!get_mem_recr()->seq_rm(seq_id, p0, p1)) {
@@ -149,7 +159,9 @@ bool llama_memory_hybrid_idx::seq_rm(llama_seq_id seq_id, llama_pos p0, llama_po
}
if (mem_idx) {
- mem_idx->seq_rm(seq_id, p0, p1);
+ if (!mem_idx->seq_rm(seq_id, p0, p1)) {
+ return false;
+ }
}
return get_mem_attn()->seq_rm(seq_id, p0, p1);
@@ -199,6 +211,26 @@ std::map<ggml_backend_buffer_type_t, size_t> llama_memory_hybrid_idx::memory_bre
return mb;
}
+void llama_memory_hybrid_idx::state_write(llama_io_write_i & io, llama_seq_id seq_id, llama_state_seq_flags flags) const {
+ llama_memory_hybrid::state_write(io, seq_id, flags);
+
+ // mem_idx is a KV cache — same PARTIAL_ONLY rule as mem_attn in the base.
+ // without this, context checkpoints restore attn+recr and silently drop the QSA
+ // indexer. after a restore the index describes a different position than the KV
+ // caches, and a later kernel can wedge the GPU SDMA queue.
+ if (mem_idx && (flags & LLAMA_STATE_SEQ_FLAGS_PARTIAL_ONLY) == 0) {
+ mem_idx->state_write(io, seq_id, flags);
+ }
+}
+
+void llama_memory_hybrid_idx::state_read(llama_io_read_i & io, llama_seq_id seq_id, llama_state_seq_flags flags) {
+ llama_memory_hybrid::state_read(io, seq_id, flags);
+
+ if (mem_idx && (flags & LLAMA_STATE_SEQ_FLAGS_PARTIAL_ONLY) == 0) {
+ mem_idx->state_read(io, seq_id, flags);
+ }
+}
+
llama_kv_cache * llama_memory_hybrid_idx::get_mem_idx() const {
return mem_idx.get();
}
diff --git a/src/llama-memory-hybrid-idx.h b/src/llama-memory-hybrid-idx.h
index d5e75ef..18a64c4 100644
--- a/src/llama-memory-hybrid-idx.h
+++ b/src/llama-memory-hybrid-idx.h
@@ -75,6 +75,9 @@ public:
std::map<ggml_backend_buffer_type_t, size_t> memory_breakdown() const override;
+ void state_write(llama_io_write_i & io, llama_seq_id seq_id = -1, llama_state_seq_flags flags = 0) const override;
+ void state_read (llama_io_read_i & io, llama_seq_id seq_id = -1, llama_state_seq_flags flags = 0) override;
+
//
// llama_memory_hybrid_idx specific API
//
--
2.43.0