From c76ed81343f053ba20472e61aec373eaad5603ce Mon Sep 17 00:00:00 2001 From: Radoslaw Zarzynski Date: Wed, 31 Jul 2019 19:52:45 +0200 Subject: [PATCH] crimson/osd: implement CEPH_OSD_OP_CALL. Signed-off-by: Radoslaw Zarzynski --- src/crimson/osd/exceptions.h | 20 ++++++++ src/crimson/osd/pg.cc | 2 + src/crimson/osd/pg_backend.cc | 86 +++++++++++++++++++++++++++++++++++ src/crimson/osd/pg_backend.h | 4 ++ 4 files changed, 112 insertions(+) diff --git a/src/crimson/osd/exceptions.h b/src/crimson/osd/exceptions.h index ab20dd248e5..563cc4e3f53 100644 --- a/src/crimson/osd/exceptions.h +++ b/src/crimson/osd/exceptions.h @@ -16,12 +16,17 @@ public: 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) {} @@ -35,4 +40,19 @@ struct invalid_argument : public error { 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 diff --git a/src/crimson/osd/pg.cc b/src/crimson/osd/pg.cc index 3c1082b07d8..dd0edf70512 100644 --- a/src/crimson/osd/pg.cc +++ b/src/crimson/osd/pg.cc @@ -366,6 +366,8 @@ PG::do_osd_op(ObjectState& os, OSDOp& osd_op, ceph::os::Transaction& txn) }); case CEPH_OSD_OP_DELETE: return backend->remove(os, txn); + case CEPH_OSD_OP_CALL: + return backend->call(os, osd_op, txn); default: logger().warn("unknown op {}", ceph_osd_op_name(op.op)); throw std::runtime_error( diff --git a/src/crimson/osd/pg_backend.cc b/src/crimson/osd/pg_backend.cc index 31d3902f963..4ae3adc760a 100644 --- a/src/crimson/osd/pg_backend.cc +++ b/src/crimson/osd/pg_backend.cc @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "messages/MOSDOp.h" @@ -19,6 +20,8 @@ #include "ec_backend.h" #include "exceptions.h" +#include "osd/ClassHandler.h" + namespace { seastar::logger& logger() { return ceph::get_logger(ceph_subsys_osd); @@ -374,3 +377,86 @@ PGBackend::list_objects(const hobject_t& start, uint64_t limit) 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); + }); + +} diff --git a/src/crimson/osd/pg_backend.h b/src/crimson/osd/pg_backend.h index fbc2653d74c..543c9ec8458 100644 --- a/src/crimson/osd/pg_backend.h +++ b/src/crimson/osd/pg_backend.h @@ -69,6 +69,10 @@ public: seastar::future, hobject_t> list_objects( const hobject_t& start, uint64_t limit); + seastar::future<> call( + ObjectState& os, + OSDOp& osd_op, + ceph::os::Transaction& txn); virtual void got_rep_op_reply(const MOSDRepOpReply&) {} -- 2.47.3