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);
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);
}
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);
}
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});
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) {
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;
};
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)->
return "ORDERSNAP flag set; writer has old snapc";
case osd_errc::blocklisted:
return "Blocklisted";
+ case osd_errc::cmpext_mismatch:
+ return "CmpExt mismatch";
}
if (len) {
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);
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() };
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;
}
#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
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 {
if (*pe) {
**pe = e.code();
}
- if (*pr) {
+ if (*pr && **pr == 0) {
**pr = ceph::from_error_code(e.code());
}
} catch (const std::exception& e) {
if (*pe) {
**pe = osdc_errc::handler_failed;
}
- if (*pr) {
+ if (*pr && **pr == 0) {
**pr = -EIO;
}
}
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());
}
#include "msg/Dispatcher.h"
#include "osd/OSDMap.h"
+#include "osd/error_code.h"
class Context;
class Messenger;
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;
+ }
+ }
}
};
}
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;
}
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) {
&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);