using system_error::code;
using system_error::what;
+ friend error make_error(int ret);
+
private:
error(const int ret) noexcept
: system_error(ret, std::system_category()) {
}
};
+inline error make_error(const int ret) {
+ return error{-ret};
+}
struct object_not_found : public error {
object_not_found() : error(std::errc::no_such_file_or_directory) {}
invalid_argument() : error(std::errc::invalid_argument) {}
};
+// FIXME: error handling
+struct operation_not_supported : public error {
+ operation_not_supported()
+ : error(std::errc::operation_not_supported) {
+ }
+};
+
+struct permission_denied : public error {
+ permission_denied() : error(std::errc::operation_not_permitted) {}
+};
+
+struct input_output_error : public error {
+ input_output_error() : error(std::errc::io_error) {}
+};
+
} // namespace ceph::osd
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <fmt/ostream.h>
+#include <seastar/core/thread.hh>
#include <seastar/core/print.hh>
#include "messages/MOSDOp.h"
#include "ec_backend.h"
#include "exceptions.h"
+#include "osd/ClassHandler.h"
+
namespace {
seastar::logger& logger() {
return ceph::get_logger(ceph_subsys_osd);
objects, next.hobj);
});
}
+
+seastar::future<> PGBackend::call(
+ ObjectState& os,
+ OSDOp& osd_op,
+ ceph::os::Transaction& txn)
+{
+ if (!os.exists) {
+ throw ::object_not_found();
+ }
+
+ std::string cname, mname;
+ ceph::bufferlist indata;
+ try {
+ auto bp = std::begin(osd_op.indata);
+ bp.copy(osd_op.op.cls.class_len, cname);
+ bp.copy(osd_op.op.cls.method_len, mname);
+ bp.copy(osd_op.op.cls.indata_len, indata);
+ } catch (buffer::error& e) {
+ logger().warn("call unable to decode class + method + indata");
+ throw ::invalid_argument{};
+ }
+
+ // NOTE: opening a class can actually result in dlopen(), and thus
+ // blocking the entire reactor. Thankfully to ClassHandler's cache
+ // this is supposed to be extremely infrequent.
+ ClassHandler::ClassData* cls;
+ int r = ClassHandler::get_instance().open_class(cname, &cls);
+ if (r) {
+ logger().warn("class {} open got {}", cname, cpp_strerror(r));
+ if (r == -ENOENT) {
+ throw ceph::osd::operation_not_supported{};
+ } else if (r == -EPERM) {
+ // propagate permission errors
+ throw ceph::osd::permission_denied{};
+ }
+ throw ceph::osd::input_output_error{};
+ }
+
+ ClassHandler::ClassMethod* method = cls->get_method(mname);
+ if (!method) {
+ logger().warn("call method {}.{} does not exist", cname, mname);
+ throw ceph::osd::operation_not_supported{};
+ }
+
+ const auto flags = method->get_flags();
+#if 0
+ if (flags & CLS_METHOD_WR) {
+ ctx->user_modify = true;
+ }
+#endif
+
+ logger().debug("calling method {}.{}", cname, mname);
+#if 0
+ int prev_rd = ctx->num_read;
+ int prev_wr = ctx->num_write;
+#endif
+
+
+ return seastar::async([&osd_op, method, indata=std::move(indata)]() mutable {
+ ceph::bufferlist outdata;
+ const auto ret = method->exec((cls_method_context_t)&osd_op, indata, outdata);
+ if (ret < 0) {
+ throw ceph::osd::make_error(ret);
+ }
+#if 0
+ if (ctx->num_read > prev_rd && !(flags & CLS_METHOD_RD)) {
+ derr << "method " << cname << "." << mname << " tried to read object but is not marked RD" << dendl;
+ result = -EIO;
+ break;
+ }
+ if (ctx->num_write > prev_wr && !(flags & CLS_METHOD_WR)) {
+ derr << "method " << cname << "." << mname << " tried to update object but is not marked WR" << dendl;
+ result = -EIO;
+ break;
+ }
+#endif
+
+ logger().debug("method called response length={}", outdata.length());
+ osd_op.op.extent.length = outdata.length();
+ osd_op.outdata.claim_append(outdata);
+ });
+
+}