]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mon: Add a new health warning for blaum-roth erasure code profiles with a w+1 that...
authorTom Sollers <tom.sollers@ibm.com>
Thu, 2 Oct 2025 13:36:16 +0000 (14:36 +0100)
committerTom Sollers <tom.sollers@ibm.com>
Tue, 21 Oct 2025 15:53:50 +0000 (16:53 +0100)
This commit adds a new health warning for when a user has an erasure code
profile using the blaum-roth technique which has a w+1 value that is not
prime.

Fixes: http://tracker.ceph.com/issues/64419
Signed-off-by: Tom Sollers <tom.sollers@ibm.com>
doc/rados/operations/health-checks.rst
src/erasure-code/jerasure/ErasureCodeJerasure.cc
src/erasure-code/jerasure/ErasureCodeJerasure.h
src/mon/HealthMonitor.cc
src/mon/HealthMonitor.h
src/mon/Monitor.cc
src/mon/Monitor.h
src/mon/OSDMonitor.cc

index 30a9bd64405fdfb5c590a78ed910eb8eecc63ef7..67dab4a8f1b4ddad713ebcb0c857576924c66623 100644 (file)
@@ -1900,3 +1900,21 @@ To disable the debug mode, run the following command:
 .. prompt:: bash $
 
    ceph dashboard debug disable
+
+BLAUM_ROTH_W_IS_NOT_PRIME
+_________________________
+
+An EC pool is using the ``blaum_roth`` technique and ``w + 1`` is not a prime number. 
+This can result in data corruption.
+
+To check the list of Erasure Code Profiles use the command:
+
+.. prompt:: bash $
+   
+   ceph osd erasure-code-profile ls
+
+Then to check the ``w`` value for a particular profile use the command:
+
+.. prompt:: bash $
+
+   ceph osd erasure-code-profile get <name of profile>
\ No newline at end of file
index 401299d3ca7ac82f3ac9a50f3daaf7cad0510020..aea8d4e7bc031173ba9ddfdd5776795cf21e3bc7 100644 (file)
@@ -707,14 +707,14 @@ void ErasureCodeJerasureLiberation::prepare()
 // ErasureCodeJerasureBlaumRoth
 //
 bool ErasureCodeJerasureBlaumRoth::check_w(ostream *ss) const
-{
+{ 
   // back in Firefly, w = 7 was the default and produced usable
   // chunks. Tolerate this value for backward compatibility.
   if (w == 7)
     return true;
   if (w <= 2 || !is_prime(w+1)) {
     *ss <<  "w=" << w << " must be greater than two and "
-       << "w+1 must be prime" << std::endl;
+         << "w+1 must be prime" << std::endl;
     return false;
   } else {
     return true;
index 14ea1d99d5805adb1b4399bd7b4345fbf1a1c9fe..fe084c0537c0146c14a29ed221366b07341fbb6e 100644 (file)
@@ -305,6 +305,7 @@ public:
   ErasureCodeJerasureBlaumRoth() :
     ErasureCodeJerasureLiberation("blaum_roth")
   {
+    DEFAULT_W = "6";
   }
 
   bool check_w(std::ostream *ss) const override;
index b78f900330ea891d3349e8b57fb88a760e636bdf..1a2f8639dc1d6a7b731b3a8493d4cc5fc39ff370 100644 (file)
@@ -27,6 +27,8 @@
 #include "mon/Monitor.h"
 #include "mon/HealthMonitor.h"
 #include "mon/OSDMonitor.h"
+#include "osd/OSDMap.h"
+
 
 #include "messages/MMonCommand.h"
 #include "messages/MMonHealthChecks.h"
@@ -749,6 +751,9 @@ bool HealthMonitor::check_leader_health()
   // STRETCH MODE
   check_mon_crush_loc_stretch_mode(&next);
 
+  //CHECK_ERASURE_CODE_PROFILE
+  check_erasure_code_profiles(&next);
+
   if (next != leader_checks) {
     changed = true;
     leader_checks = next;
@@ -1169,3 +1174,34 @@ void HealthMonitor::check_netsplit(health_check_map_t *checks, std::set<std::str
     d.detail.swap(details);
   }
 }
+
+void HealthMonitor::check_erasure_code_profiles(health_check_map_t *checks)
+{
+  list<string> details;
+  
+  //This is a loop that will go through all the erasure code profiles 
+  for (auto& erasure_code_profile : mon.osdmon()->osdmap.get_erasure_code_profiles()) {
+    dout(20) << "check_erasure_code_profiles" << "checking" << erasure_code_profile << dendl;
+
+    //This will look at the erasure code profiles technique is blaum_roth and will check that the w key exists 
+      if (erasure_code_profile.second.at("technique") == "blaum_roth" && 
+      erasure_code_profile.second.count("w") == 1) {
+        //Read the w value from the profile and convert it to an int 
+        int w = std::stoi(erasure_code_profile.second.at("w"));
+
+        if (!mon.is_prime(w + 1)) {
+          ostringstream ds;
+          ds << "w+1="<< w+1 << " for the EC profile " << erasure_code_profile.first 
+            << " is not prime and could lead to data corruption";
+          details.push_back(ds.str());
+      }
+    }
+  }
+  if (!details.empty()) {
+            ostringstream ss;
+            ss << "1 or more EC profiles have a w value such that w+1 is not prime."
+              << " This can result in data corruption";
+            auto &d = checks->add("BLAUM_ROTH_W_IS_NOT_PRIME", HEALTH_WARN, ss.str(), details.size());
+            d.detail.swap(details);
+        }
+}
index 52dc82f359468af2205af13e3ddd148c19416177..52393c599b7fe53c1d052d414fd316ba12d5bd3f 100644 (file)
@@ -73,6 +73,7 @@ private:
   void check_for_clock_skew(health_check_map_t *checks);
   void check_mon_crush_loc_stretch_mode(health_check_map_t *checks);
   void check_if_msgr2_enabled(health_check_map_t *checks);
+  void check_erasure_code_profiles(health_check_map_t *checks);
   void check_netsplit(health_check_map_t *checks, std::set<std::string> &mons_down);
   bool check_leader_health();
   bool check_member_health();
index 1d8245c98f04fa22ade0e5d0edd8e5ba0974f719..810e8500e187538b0fd2bd8afbecb45fac2d5eda 100644 (file)
@@ -7083,3 +7083,19 @@ void Monitor::disconnect_disallowed_stretch_sessions()
     session_stretch_allowed(*j, blank);
   }
 }
+
+// A utility function that will check to see if the given value is prime using a set of the first 55 prime numbers
+bool Monitor::is_prime(int value) {
+  int prime55[] = {
+    2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,
+    73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,
+    151,157,163,167,173,179,
+    181,191,193,197,199,211,223,227,229,233,239,241,251,257
+  };
+
+  for (int i: prime55)
+    if (value == i) 
+      return true;
+  
+  return false;
+}
index 93c758dc5019a59bd6fdaaaf4087e86ccb2f3cec..8e202dbb5e5a74c96d84266c50696cf6c71cd4d9 100644 (file)
@@ -283,6 +283,8 @@ public:
   bool is_degraded_stretch_mode() { return degraded_stretch_mode; }
   bool is_recovering_stretch_mode() { return recovering_stretch_mode; }
 
+  bool is_prime(int value); // A utility funtion that returns true if value is prime 
+
   /**
    * This set of functions maintains the in-memory stretch state
    * and sets up transitions of the map states by calling in to
index 29ceebe21061cdf3d446dac4927e7a8004c3791d..b06515eb7e2f7c5ce1ed3ff75c98e6127f550afa 100644 (file)
@@ -11668,6 +11668,43 @@ bool OSDMonitor::prepare_command_impl(MonOpRequestRef op,
       err = -EINVAL;
       goto reply_no_propose;
     }
+
+    bool force_no_fake = false;
+         cmd_getval(cmdmap, "yes_i_really_mean_it", force_no_fake);
+
+
+
+    //This is the start of the validation for the w value in a blaum_roth profile
+    //this will search the Profile map, which contains the values for the parameters given in the command, for the technique parameter
+    if (auto found = profile_map.find("technique"); found != profile_map.end()) {
+
+      //if the technique parameter is found then save the value of it
+      string technique = found->second;
+
+      
+      //then search the profile map again for the w value, which doesnt have to be specified, and if it is found and the technique used is blaum-roth then check that the w value is correct.
+      if (found = profile_map.find("w"); technique == "blaum_roth" && found != profile_map.end()) {
+        int w = std::stoi(found->second);
+        
+        //checks if w+1 is not prime
+        if (w <= 2 || !mon.is_prime(w + 1)) {
+
+          if (force ^ force_no_fake) {
+            err = -EPERM;
+            ss << "Creating a blaum-roth erasure code profile with a w+1 value that is not prime is dangerious,"
+              << " as it can cause data corruption."
+              << " You need to use both --yes-i-really-mean-it and --force flags." << std::endl;
+            goto reply_no_propose;
+          } else if (!force && !force_no_fake) {
+            ss << "erasure-code-profile: " << profile_map 
+              << " must use a w value such that w+1 is prime and w is greater than 2." << std::endl;
+            err = -EINVAL;
+            goto reply_no_propose;
+          }
+        }
+      }
+    }
+
     string plugin = profile_map["plugin"];
 
     if (pending_inc.has_erasure_code_profile(name)) {
@@ -11689,8 +11726,7 @@ bool OSDMonitor::prepare_command_impl(MonOpRequestRef op,
          err = 0;
          goto reply_no_propose;
        }
-       bool force_no_fake = false;
-       cmd_getval(cmdmap, "yes_i_really_mean_it", force_no_fake);
+
        if (!force) {
          err = -EPERM;
          ss << "will not override erasure code profile " << name