From 3fb3892ba4dfdc8d04a739147a6015a057cfcb2f Mon Sep 17 00:00:00 2001
From: Florian Fischer <florian.fischer@muhq.space>
Date: Thu, 2 Sep 2021 13:06:25 +0200
Subject: [PATCH] [IoContext] don't manually invalidate broken chains after
 linux 5.15

---
 emper/Emper.cpp        |  3 +++
 emper/Emper.hpp        | 10 ++++++++++
 emper/io/IoContext.cpp |  9 ++++++++-
 3 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/emper/Emper.cpp b/emper/Emper.cpp
index 2c1c779e..c9f6be84 100644
--- a/emper/Emper.cpp
+++ b/emper/Emper.cpp
@@ -15,6 +15,7 @@
 #include "emper-version.h"
 #include "emper.hpp"
 #include "io/Future.hpp"
+#include "lib/LinuxVersion.hpp"
 
 void async(Fiber* fiber) {
 	assert(fiber != nullptr);
@@ -44,6 +45,8 @@ void async(const Fiber::fiber_fun0_t& function, workeraffinity_t* affinity) {
 
 namespace emper {
 
+bool IO_MUST_INVALIDATE_BROKEN_CHAIN = EMPER_LINUX_LT("5.15.0");
+
 auto getFullVersion() -> std::string { return EMPER_FULL_VERSION; }
 
 static void ensure_no_current_runtime() {
diff --git a/emper/Emper.hpp b/emper/Emper.hpp
index c87e9910..78736f3c 100644
--- a/emper/Emper.hpp
+++ b/emper/Emper.hpp
@@ -130,6 +130,16 @@ static const bool IO_URING_SQPOLL =
 #endif
 		;
 
+// Initialize this bool in Emper.cpp because it needs code evaluation
+// (LinuxVersion::compare) during runtime.
+// Using a static variable here means EACH object file including this header has to
+// evaluate the needed code during library initialization.
+// An extern variable results in a single execution during initialization of the
+// Emper.cpp object.
+// This also has the advantage that the probability we crash because printing
+// warnings during the comparison use not yet initialized components is reduced.
+extern bool IO_MUST_INVALIDATE_BROKEN_CHAIN;
+
 static const bool IO_URING_SHARED_WQ =
 #ifdef EMPER_IO_URING_SHARED_WQ
 		true
diff --git a/emper/io/IoContext.cpp b/emper/io/IoContext.cpp
index bfd680a3..6a867a05 100644
--- a/emper/io/IoContext.cpp
+++ b/emper/io/IoContext.cpp
@@ -197,7 +197,14 @@ void IoContext::submitAndWait(Future &future, unsigned wait_nr) {
 	// broken chains. This means that all sqes in a chain except the broken one will
 	// result in cqes with result -ECANCELD and the invalid one will
 	// generate a cqe with the appropriate error code
-	if (unlikely(static_cast<unsigned>(submitted) < prepared)) {
+
+	// When 5.15 is released with
+	// https://lore.kernel.org/io-uring/180ec124-79b1-2274-4570-9b0d6620d512@linux.alibaba.com/T/#t
+	// the kernel will consume the whole broken chain and we
+	// don't need to manually invalidate not submitted sqes.
+	// This allows SQPOLL to work for invalid chains.
+	if (unlikely(static_cast<unsigned>(submitted) < prepared) &&
+			emper::IO_MUST_INVALIDATE_BROKEN_CHAIN) {
 		cancelUnsubmittedChainParts<callerEnvironment>(future);
 	}
 
-- 
GitLab