commit 058717b0fefe84ba18d019763cfddff1a1d2b98a
Author: David Sorber <david.sorber@gmail.com>
Date:   Sat Jul 9 10:08:48 2022 -0400

    read_test: Add helper functions to read and validate the current kernel
    version. Also add validation for the uring read type to ensure that the
    kernel version is >= 5.6.

diff --git a/software/read_test/src/main.cc b/software/read_test/src/main.cc
index f37ca82..19f44bf 100644
--- a/software/read_test/src/main.cc
+++ b/software/read_test/src/main.cc
@@ -1,10 +1,13 @@
 #include <algorithm>
 #include <chrono>
+#include <cstdlib>
 #include <iomanip>
 #include <iostream>
 #include <string>
 #include <vector>
 
+#include <sys/utsname.h>
+
 #include <boost/program_options.hpp>
 
 #include "AIO_ExecDriver.h"
@@ -42,6 +45,55 @@ double printRate(double rawRate, uint32_t& unitIdx)
     return rate;
 }
 
+void getKernelVersion(uint32_t& major, uint32_t& minor, uint32_t& bugfix)
+{
+    // Read "uname" info
+    struct utsname unameBuf;
+    uname(&unameBuf);
+    
+    // Release contains kernel version; e.g. 5.15.0-33-generic
+    char* startPtr = unameBuf.release;
+    char* endPtr = nullptr;
+    major = std::strtoul(startPtr, &endPtr, 10);
+    
+    startPtr = endPtr + 1;
+    minor = std::strtoul(startPtr, &endPtr, 10);
+    
+    startPtr = endPtr + 1;
+    bugfix = std::strtoul(startPtr, &endPtr, 10);
+    
+#if 0
+    std::cout << "MAJOR:  " << major << std::endl;
+    std::cout << "MINOR:  " << minor << std::endl;
+    std::cout << "BUGFIX: " << bugfix << std::endl;
+
+    std::cout << "sysname:  " << unameBuf.sysname << std::endl;
+    std::cout << "nodename: " << unameBuf.nodename << std::endl;
+    std::cout << "release:  " << unameBuf.release << std::endl;
+    std::cout << "version:  " << unameBuf.version << std::endl;
+    std::cout << "machine:  " << unameBuf.machine << std::endl;
+#endif
+}
+
+bool validateKernelVersion(uint32_t major, uint32_t minor, uint32_t bugfix)
+{
+    uint32_t majorVer, minorVer, bugfixVer;
+    getKernelVersion(majorVer, minorVer, bugfixVer);
+
+    if (majorVer >= major)
+    {
+        if (minorVer >= minor)
+        {
+            if (bugfixVer >= bugfix)
+            {
+                return true;
+            }
+        }
+    }
+    
+    return false;
+}
+
 void usage()
 {
     std::cout << BOLD << "Read Test Utility\n\n" << ENDC;
@@ -189,6 +241,19 @@ int main(int argc, char** argv)
     std::cout << "Read type:    " << readType.value << "\n";
     std::cout << "Input file:   " << filename << "\n";
 
+    // Valid kernel version if user selected uring read type
+    if (readType.getValue() == ReadType::URING && 
+        (! validateKernelVersion(5, 6, 0)))
+    {
+        uint32_t majorVer, minorVer, bugfixVer;
+        getKernelVersion(majorVer, minorVer, bugfixVer);
+        std::cerr << BOLD << RED << "\nERROR: " << ENDC << "The uring read type "
+                  << "requires kernel version >= 5.6; the current kernel version"
+                  << " " << majorVer << "." << minorVer << " is too old.\n"
+                  << std::endl;
+        return -1;
+    }
+    
     // Start time measurement
     auto start = std::chrono::system_clock::now();
     
