diff --git a/emper/Emper.cpp b/emper/Emper.cpp
index 2c1c779e9f25216a3ad37e98a8abe16650d71159..c9f6be84169409faf91499385fb6cc53c1d8fabd 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 c87e99100b7ddcd950f8920f4140285fb8b3dfbc..78736f3c93835e51010025719b5c885a48f6ba6b 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 bfd680a340fed2d5e50be02da4583970dd66910c..6a867a05893fed7fecd757acee78caf17a7b2c18 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);
 	}
 
diff --git a/emper/lib/LinuxVersion.cpp b/emper/lib/LinuxVersion.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f37e5f362e0b865f429c6b317bd49e7b1748d0af
--- /dev/null
+++ b/emper/lib/LinuxVersion.cpp
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: LGPL-3.0-or-later
+// Copyright © 2021 Florian Fischer
+#include "lib/LinuxVersion.hpp"
+
+#include <cassert>
+#include <cerrno>
+#include <cstdlib>
+
+#include "Common.hpp"
+#include "Debug.hpp"
+
+static auto checked_strtol(const std::string& s) -> long {
+	static const int DECIMAL = 10;
+	char* endptr;
+	const char* startptr = s.c_str();
+	errno = 0;
+
+	long res = strtol(startptr, &endptr, DECIMAL);
+	if (errno != 0) {
+		DIE_MSG_ERRNO("strtol failed");
+	}
+
+	if (endptr == startptr) {
+		DIE_MSG("strtol found no digits in " << s);
+	}
+
+	if (endptr != startptr + s.size()) {
+		LOGW("LinuxVersion compare ignored non digits in " << s)
+	}
+
+	return res;
+}
+
+namespace emper::lib {
+
+LinuxVersion LinuxVersion::linuxVersion;
+
+// Returns 1 if s is smaller, -1 if this is smaller, 0 if equal
+auto LinuxVersion::compare(const std::string& s) -> int {
+	size_t last_dot_pos = 0, last_dot_pos2 = 0;
+
+	for (;;) {
+		size_t dot_pos = this->version.find('.', last_dot_pos);
+		// We run out of parts to compare the versions must be equal
+		if (dot_pos == std::string::npos) return 0;
+
+		size_t dot_pos2 = s.find('.', last_dot_pos2);
+		assert(dot_pos2 != std::string::npos);
+
+		long n1 = checked_strtol(this->version.substr(last_dot_pos, dot_pos - last_dot_pos));
+		long n2 = checked_strtol(s.substr(last_dot_pos2, dot_pos2 - last_dot_pos2));
+
+		if (n1 > n2) return 1;
+
+		if (n1 < n2) return -1;
+
+		last_dot_pos = dot_pos + 1;
+		last_dot_pos2 = dot_pos2 + 1;
+	}
+}
+
+}	 // namespace emper::lib
diff --git a/emper/lib/LinuxVersion.hpp b/emper/lib/LinuxVersion.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..6256cc40210261e7f413bb0f34cec92e03f02ead
--- /dev/null
+++ b/emper/lib/LinuxVersion.hpp
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: LGPL-3.0-or-later
+// Copyright © 2021 Florian Fischer
+#pragma once
+
+#include <sys/utsname.h>
+
+#include <string>
+
+namespace emper::lib {
+class LinuxVersion {
+	std::string version;
+
+	auto compare(const std::string& s) -> int;
+
+ public:
+	static LinuxVersion linuxVersion;
+
+	LinuxVersion() {
+		struct utsname buf;
+		uname(&buf);
+		this->version = std::string(buf.release);
+	}
+
+	auto operator>(const std::string& s) -> bool { return compare(s) > 0; }
+
+	auto operator<(const std::string& s) -> bool { return compare(s) < 0; }
+
+	auto operator==(const std::string& s) -> bool { return compare(s) == 0; }
+
+	auto operator>=(const std::string& s) -> bool { return *this > s || *this == s; }
+
+	auto operator<=(const std::string& s) -> bool { return *this < s || *this == s; }
+};
+}	 // namespace emper::lib
+
+#define EMPER_LINUX_EQ(version) \
+	([]() -> bool { return empere::lib::LinuxVersion::linuxVersion == version; }())
+#define EMPER_LINUX_GT(version) \
+	([]() -> bool { return emper::lib::LinuxVersion::linuxVersion > version; }())
+#define EMPER_LINUX_GE(version) \
+	([]() -> bool { return emper::lib::LinuxVersion::linuxVersion >= version; }())
+#define EMPER_LINUX_LT(version) \
+	([]() -> bool { return emper::lib::LinuxVersion::linuxVersion < version; }())
+#define EMPER_LINUX_LE(version) \
+	([]() -> bool { return emper::lib::LinuxVersion::linuxVersion <= version; }())
diff --git a/emper/lib/meson.build b/emper/lib/meson.build
index 126bdd278cc7cb27c107f35b8c4f230a59f51dc8..88b68f898aa5ccb9a4a790bae234b640e48306c8 100644
--- a/emper/lib/meson.build
+++ b/emper/lib/meson.build
@@ -1,3 +1,4 @@
 emper_cpp_sources += files(
   'DebugUtil.cpp',
+  'LinuxVersion.cpp',
 )