]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
neorados: Fix `Op::cmpext` error and unfound behavior
authorAdam Emerson <aemerson@redhat.com>
Wed, 9 Aug 2023 00:38:24 +0000 (20:38 -0400)
committerAdam Emerson <aemerson@redhat.com>
Thu, 7 Dec 2023 21:23:05 +0000 (16:23 -0500)
A failure will produce the output `osd_errc::cmpext_mismatch`. On
failure, the `unmatch` out parameter, if provided, will be set to the
index of the first nonmatching character; On success, it will be set
to `-1`.

Signed-off-by: Adam Emerson <aemerson@redhat.com>
src/include/neorados/RADOS.hpp
src/librbd/io/ObjectRequest.cc
src/librbd/io/ObjectRequest.h
src/neorados/RADOS.cc
src/osd/error_code.cc
src/osd/error_code.h
src/osdc/Objecter.cc
src/osdc/Objecter.h
src/test/librados_test_stub/NeoradosTestStub.cc

index 67a01b43148e700f3cccb9ed2273eab43c21770a..e890d7a936195e8efaa2b897bdf3976de0c7d97a 100644 (file)
@@ -302,7 +302,8 @@ public:
   void set_fadvise_dontneed();
   void set_fadvise_nocache();
 
-  void cmpext(uint64_t off, ceph::buffer::list&& cmp_bl, std::size_t* s);
+  void cmpext(uint64_t off, ceph::buffer::list&& cmp_bl,
+             uint64_t* unmatch = nullptr);
   void cmpxattr(std::string_view name, cmpxattr_op op,
                const ceph::buffer::list& val);
   void cmpxattr(std::string_view name, cmpxattr_op op, std::uint64_t val);
@@ -536,12 +537,14 @@ public:
     return std::move(*this);
   }
 
-  ReadOp& cmpext(uint64_t off, ceph::buffer::list&& cmp_bl, std::size_t* s) & {
-    Op::cmpext(off, std::move(cmp_bl), s);
+  ReadOp& cmpext(uint64_t off, ceph::buffer::list&& cmp_bl,
+                uint64_t* unmatch = nullptr) & {
+    Op::cmpext(off, std::move(cmp_bl), unmatch);
     return *this;
   }
-  ReadOp&& cmpext(uint64_t off, ceph::buffer::list&& cmp_bl, std::size_t* s) && {
-    Op::cmpext(off, std::move(cmp_bl), s);
+  ReadOp&& cmpext(uint64_t off, ceph::buffer::list&& cmp_bl,
+                 uint64_t* unmatch = nullptr) && {
+    Op::cmpext(off, std::move(cmp_bl), unmatch);
     return std::move(*this);
   }
 
@@ -918,12 +921,14 @@ public:
     return std::move(*this);
   }
 
-  WriteOp& cmpext(uint64_t off, ceph::buffer::list&& cmp_bl, std::size_t* s) & {
-    Op::cmpext(off, std::move(cmp_bl), s);
+  WriteOp& cmpext(uint64_t off, ceph::buffer::list&& cmp_bl,
+                 uint64_t* unmatch = nullptr) & {
+    Op::cmpext(off, std::move(cmp_bl), unmatch);
     return *this;
   }
-  WriteOp&& cmpext(uint64_t off, ceph::buffer::list&& cmp_bl, std::size_t* s) && {
-    Op::cmpext(off, std::move(cmp_bl), s);
+  WriteOp&& cmpext(uint64_t off, ceph::buffer::list&& cmp_bl,
+                  uint64_t* unmatch = nullptr) && {
+    Op::cmpext(off, std::move(cmp_bl), unmatch);
     return std::move(*this);
   }
 
index 86650869616dc3ef569e70bae4cc82992b8db3ca..428f0fbdf5844a5cdf74c323fa75389fc876c31e 100644 (file)
@@ -698,7 +698,7 @@ void ObjectWriteSameRequest<I>::add_write_ops(neorados::WriteOp* wr) {
 
 template <typename I>
 void ObjectCompareAndWriteRequest<I>::add_write_ops(neorados::WriteOp* wr) {
-  wr->cmpext(this->m_object_off, bufferlist{m_cmp_bl}, nullptr);
+  wr->cmpext(this->m_object_off, bufferlist{m_cmp_bl}, &m_mismatch_object_offset);
 
   if (this->m_full_object) {
     wr->write_full(bufferlist{m_write_bl});
@@ -710,13 +710,14 @@ void ObjectCompareAndWriteRequest<I>::add_write_ops(neorados::WriteOp* wr) {
 
 template <typename I>
 int ObjectCompareAndWriteRequest<I>::filter_write_result(int r) const {
-  if (r <= -MAX_ERRNO) {
+  // Error code value for cmpext mismatch. Works for both neorados and
+  // mock image, which seems to be short-circuiting on nonexistence.
+  if (r == -MAX_ERRNO) {
     I *image_ctx = this->m_ictx;
 
     // object extent compare mismatch
-    uint64_t offset = -MAX_ERRNO - r;
     auto [image_extents, _] = io::util::object_to_area_extents(
-        image_ctx, this->m_object_no, {{offset, this->m_object_len}});
+        image_ctx, this->m_object_no, {{m_mismatch_object_offset, this->m_object_len}});
     ceph_assert(image_extents.size() == 1);
 
     if (m_mismatch_offset) {
index caf644023be7dde450423a1db2ff6e925e1a8da8..d9815860f78f444ab766bb4a7e46e440817e368a 100644 (file)
@@ -440,6 +440,7 @@ private:
   ceph::bufferlist m_cmp_bl;
   ceph::bufferlist m_write_bl;
   uint64_t *m_mismatch_offset;
+  uint64_t m_mismatch_object_offset;
   int m_op_flags;
 };
 
index 026f77043dc97b77474fb76b950a8450143a5d9b..47b1c0d48824d88fde26246a7a587017d94546e2 100644 (file)
@@ -420,9 +420,9 @@ void Op::set_fadvise_nocache() {
     CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
 }
 
-void Op::cmpext(uint64_t off, bufferlist&& cmp_bl, std::size_t* s) {
+void Op::cmpext(uint64_t off, bufferlist&& cmp_bl, uint64_t* unmatch) {
   reinterpret_cast<OpImpl*>(&impl)->op.cmpext(off, std::move(cmp_bl), nullptr,
-                                             s);
+                                             unmatch);
 }
 void Op::cmpxattr(std::string_view name, cmpxattr_op op, const bufferlist& val) {
   reinterpret_cast<OpImpl*>(&impl)->
index 97f0012fdba1e4f9018991a1b08a7d6047f5cde3..927e4592b123191da15e026a84416b1b82b4901c 100644 (file)
@@ -53,6 +53,8 @@ const char* osd_error_category::message(int ev, char* buf,
     return "ORDERSNAP flag set; writer has old snapc";
   case osd_errc::blocklisted:
     return "Blocklisted";
+  case osd_errc::cmpext_mismatch:
+    return "CmpExt mismatch";
   }
 
   if (len) {
@@ -72,6 +74,8 @@ std::string osd_error_category::message(int ev) const {
     return "ORDERSNAP flag set; writer has old snapc";
   case osd_errc::blocklisted:
     return "Blocklisted";
+  case osd_errc::cmpext_mismatch:
+    return "CmpExt mismatch";
   }
 
   return cpp_strerror(ev);
@@ -79,7 +83,8 @@ std::string osd_error_category::message(int ev) const {
 
 boost::system::error_condition osd_error_category::default_error_condition(int ev) const noexcept {
   if (ev == static_cast<int>(osd_errc::old_snapc) ||
-      ev == static_cast<int>(osd_errc::blocklisted))
+      ev == static_cast<int>(osd_errc::blocklisted) ||
+      ev == static_cast<int>(osd_errc::cmpext_mismatch))
     return { ev, *this };
   else
     return { ev, boost::system::generic_category() };
@@ -91,6 +96,8 @@ bool osd_error_category::equivalent(int ev, const boost::system::error_condition
       return c == boost::system::errc::invalid_argument;
   case osd_errc::blocklisted:
       return c == boost::system::errc::operation_not_permitted;
+  case osd_errc::cmpext_mismatch:
+      return c == boost::system::errc::operation_canceled;
   }
   return default_error_condition(ev) == c;
 }
index d36e79db4a8b62ea6b87a45eef7226116e58214d..762e03a4643b81e8727f914778d43b8e6eedc1b5 100644 (file)
@@ -19,6 +19,8 @@
 
 #include "include/rados.h"
 
+#include "include/err.h"
+
 const boost::system::error_category& osd_category() noexcept;
 
 // Since the OSD mostly uses POSIX error codes plus a couple
@@ -27,7 +29,8 @@ const boost::system::error_category& osd_category() noexcept;
 
 enum class osd_errc {
   old_snapc = 85,  /* ORDERSNAP flag set; writer has old snapc*/
-  blocklisted = 108 /* blocklisted */
+  blocklisted = 108, /* blocklisted */
+  cmpext_mismatch = MAX_ERRNO /* cmpext failed */
 };
 
 namespace boost::system {
index a74d21b0f15f8bbd03c0dc44e129cd15e8753217..9c2daed3ba6ecd946c5f31db24ac59fa6a360d5e 100644 (file)
@@ -3586,7 +3586,7 @@ void Objecter::handle_osd_op_reply(MOSDOpReply *m)
        if (*pe) {
          **pe = e.code();
        }
-       if (*pr) {
+       if (*pr && **pr == 0) {
          **pr = ceph::from_error_code(e.code());
        }
       } catch (const std::exception& e) {
@@ -3596,7 +3596,7 @@ void Objecter::handle_osd_op_reply(MOSDOpReply *m)
        if (*pe) {
          **pe = osdc_errc::handler_failed;
        }
-       if (*pr) {
+       if (*pr && **pr == 0) {
          **pr = -EIO;
        }
       }
@@ -3633,6 +3633,8 @@ void Objecter::handle_osd_op_reply(MOSDOpReply *m)
   if (Op::has_completion(onfinish)) {
     if (rc == 0 && handler_error) {
       Op::complete(std::move(onfinish), handler_error, -EIO, service.get_executor());
+    } else if (handler_error) {
+      Op::complete(std::move(onfinish), handler_error, rc, service.get_executor());
     } else {
       Op::complete(std::move(onfinish), osdcode(rc), rc, service.get_executor());
     }
index 870083a29b6c3deb793ea06b5bbe868566e0c056..512a4435eccb126e35470122bf2a17b471fe3645 100644 (file)
@@ -64,6 +64,7 @@
 #include "msg/Dispatcher.h"
 
 #include "osd/OSDMap.h"
+#include "osd/error_code.h"
 
 class Context;
 class Messenger;
@@ -434,19 +435,41 @@ struct ObjectOperation {
   struct CB_ObjectOperation_cmpext {
     int* prval = nullptr;
     boost::system::error_code* ec = nullptr;
-    std::size_t* s = nullptr;
+    uint64_t* mismatch_offset = nullptr;
     explicit CB_ObjectOperation_cmpext(int *prval)
       : prval(prval) {}
-    CB_ObjectOperation_cmpext(boost::system::error_code* ec, std::size_t* s)
-      : ec(ec), s(s) {}
+    CB_ObjectOperation_cmpext(boost::system::error_code* ec,
+                             uint64_t* mismatch_offset)
+      : ec(ec), mismatch_offset(mismatch_offset) {}
 
-    void operator()(boost::system::error_code ec, int r, const ceph::buffer::list&) {
+    void operator()(boost::system::error_code ec, int r,
+                   const ceph::buffer::list&) {
       if (prval)
         *prval = r;
-      if (this->ec)
-       *this->ec = ec;
-      if (s)
-       *s = static_cast<std::size_t>(-(MAX_ERRNO - r));
+
+      if (r <= -MAX_ERRNO) {
+       if (this->ec) {
+         *this->ec = make_error_code(osd_errc::cmpext_mismatch);
+       }
+       if (mismatch_offset) {
+         *mismatch_offset = -MAX_ERRNO - r;
+       }
+       throw boost::system::system_error(osd_errc::cmpext_mismatch);
+      } else if (r < 0) {
+       if (this->ec) {
+         *this->ec = ec;
+       }
+       if (mismatch_offset) {
+         *mismatch_offset = -1;
+       }
+      } else {
+       if (this->ec) {
+         this->ec->clear();
+       }
+       if (mismatch_offset) {
+         *mismatch_offset = -1;
+       }
+      }
     }
   };
 
@@ -457,9 +480,9 @@ struct ObjectOperation {
   }
 
   void cmpext(uint64_t off, ceph::buffer::list&& cmp_bl, boost::system::error_code* ec,
-             std::size_t* s) {
+             uint64_t* mismatch_offset) {
     add_data(CEPH_OSD_OP_CMPEXT, off, cmp_bl.length(), cmp_bl);
-    set_handler(CB_ObjectOperation_cmpext(ec, s));
+    set_handler(CB_ObjectOperation_cmpext(ec, mismatch_offset));
     out_ec.back() = ec;
   }
 
index 8e2a864f9b892523b9bd3502bbc1abe60c16c560..1eb0d627ebeea5b5497eb8974db391cfbb762fb2 100644 (file)
@@ -113,11 +113,19 @@ librados::AioCompletionImpl* create_aio_completion(
   return impl;
 }
 
-int save_operation_size(int result, size_t* pval) {
-  if (pval != NULL) {
-    *pval = result;
+int save_operation_size(int result, uint64_t* pval) {
+  int our_r = result;
+  if (result <= -MAX_ERRNO) {
+    if (pval != NULL) {
+      *pval = -MAX_ERRNO - result;
+    }
+    our_r = -MAX_ERRNO;
+  } else {
+    if (pval != NULL) {
+      *pval = -1;
+    }
   }
-  return result;
+  return our_r;
 }
 
 int save_operation_ec(int result, boost::system::error_code* ec) {
@@ -323,7 +331,7 @@ void Op::assert_version(uint64_t ver) {
           &librados::TestIoCtxImpl::assert_version, _1, _2, ver));
 }
 
-void Op::cmpext(uint64_t off, ceph::buffer::list&& cmp_bl, std::size_t* s) {
+void Op::cmpext(uint64_t off, ceph::buffer::list&& cmp_bl, uint64_t* s) {
   auto o = *reinterpret_cast<librados::TestObjectOperationImpl**>(&impl);
   librados::ObjectOperationTestImpl op = std::bind(
     &librados::TestIoCtxImpl::cmpext, _1, _2, off, cmp_bl, _4);