diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e57b91c65fbc4..da9e3fc01792d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -515,6 +515,7 @@ add_subdirectory(osd) set(ceph_osd_srcs # Link the Object Class API implementation directly as intermediary # static library (like libosd.a) nullifies the effect of `-rdynamic`. + osd/objclass.cc objclass/class_api.cc ceph_osd.cc) add_executable(ceph-osd ${ceph_osd_srcs}) diff --git a/src/cls/cephfs/cls_cephfs.cc b/src/cls/cephfs/cls_cephfs.cc index d05fee1d6ea7f..7207a6b4b849d 100644 --- a/src/cls/cephfs/cls_cephfs.cc +++ b/src/cls/cephfs/cls_cephfs.cc @@ -17,6 +17,7 @@ #include #include "objclass/objclass.h" +#include "osd/osd_types.h" #include "cls_cephfs.h" diff --git a/src/cls/hello/cls_hello.cc b/src/cls/hello/cls_hello.cc index ac3beb3b6871a..c2b71d270846d 100644 --- a/src/cls/hello/cls_hello.cc +++ b/src/cls/hello/cls_hello.cc @@ -35,6 +35,7 @@ #include #include "objclass/objclass.h" +#include "osd/osd_types.h" using ceph::bufferlist; using std::string; diff --git a/src/crimson/os/cyan_store.cc b/src/crimson/os/cyan_store.cc index 796f23544fda6..3bd953dc3562b 100644 --- a/src/crimson/os/cyan_store.cc +++ b/src/crimson/os/cyan_store.cc @@ -126,7 +126,7 @@ seastar::future, ghobject_t> CyanStore::list_objects(CollectionRef c, const ghobject_t& start, const ghobject_t& end, - uint64_t limit) + uint64_t limit) const { logger().debug("{} {} {} {} {}", __func__, c->cid, start, end, limit); @@ -201,7 +201,7 @@ seastar::future CyanStore::read(CollectionRef c, seastar::future CyanStore::get_attr(CollectionRef c, const ghobject_t& oid, - std::string_view name) + std::string_view name) const { logger().debug("{} {} {}", __func__, c->cid, oid); @@ -631,4 +631,10 @@ uuid_d CyanStore::get_fsid() const { return osd_fsid; } + +unsigned CyanStore::get_max_attr_name_length() const +{ + // arbitrary limitation exactly like in the case of MemStore. + return 256; +} } diff --git a/src/crimson/os/cyan_store.h b/src/crimson/os/cyan_store.h index 8eacaa29b8d8e..0ab215fb00f19 100644 --- a/src/crimson/os/cyan_store.h +++ b/src/crimson/os/cyan_store.h @@ -51,7 +51,7 @@ class CyanStore final : public FuturizedStore { uint32_t op_flags = 0) final; seastar::future get_attr(CollectionRef c, const ghobject_t& oid, - std::string_view name) final; + std::string_view name) const final; seastar::future get_attrs(CollectionRef c, const ghobject_t& oid) final; @@ -64,7 +64,7 @@ class CyanStore final : public FuturizedStore { CollectionRef c, const ghobject_t& start, const ghobject_t& end, - uint64_t limit) final; + uint64_t limit) const final; /// Retrieves paged set of values > start (if present) seastar::future omap_get_values( @@ -84,6 +84,7 @@ class CyanStore final : public FuturizedStore { const std::string& value) final; int read_meta(const std::string& key, std::string* value) final; uuid_d get_fsid() const final; + unsigned get_max_attr_name_length() const final; private: int _remove(const coll_t& cid, const ghobject_t& oid); diff --git a/src/crimson/os/futurized_store.h b/src/crimson/os/futurized_store.h index 81f584cf4e0e3..ebbe53a4ceffe 100644 --- a/src/crimson/os/futurized_store.h +++ b/src/crimson/os/futurized_store.h @@ -72,7 +72,7 @@ class FuturizedStore { uint32_t op_flags = 0) = 0; virtual seastar::future get_attr(CollectionRef c, const ghobject_t& oid, - std::string_view name) = 0; + std::string_view name) const = 0; using attrs_t = std::map>; virtual seastar::future get_attrs(CollectionRef c, @@ -87,7 +87,7 @@ class FuturizedStore { CollectionRef c, const ghobject_t& start, const ghobject_t& end, - uint64_t limit) = 0; + uint64_t limit) const = 0; virtual seastar::future omap_get_values( CollectionRef c, ///< [in] collection const ghobject_t &oid, ///< [in] oid @@ -105,6 +105,7 @@ class FuturizedStore { const std::string& value) = 0; virtual int read_meta(const std::string& key, std::string* value) = 0; virtual uuid_d get_fsid() const = 0; + virtual unsigned get_max_attr_name_length() const = 0; }; } diff --git a/src/crimson/osd/CMakeLists.txt b/src/crimson/osd/CMakeLists.txt index 6e92f97661750..e872d5f3f3983 100644 --- a/src/crimson/osd/CMakeLists.txt +++ b/src/crimson/osd/CMakeLists.txt @@ -10,6 +10,7 @@ add_executable(crimson-osd pg_meta.cc replicated_backend.cc shard_services.cc + ops_executer.cc osd_operation.cc osd_operations/client_request.cc osd_operations/compound_peering_request.cc @@ -18,6 +19,9 @@ add_executable(crimson-osd osd_operations/replicated_request.cc osdmap_gate.cc pg_map.cc + objclass.cc + ${PROJECT_SOURCE_DIR}/src/objclass/class_api.cc + ${PROJECT_SOURCE_DIR}/src/osd/ClassHandler.cc ${PROJECT_SOURCE_DIR}/src/osd/PeeringState.cc ${PROJECT_SOURCE_DIR}/src/osd/PGPeeringEvent.cc ${PROJECT_SOURCE_DIR}/src/osd/PGStateUtils.cc diff --git a/src/crimson/osd/exceptions.h b/src/crimson/osd/exceptions.h index 7437ae4b88705..563cc4e3f532e 100644 --- a/src/crimson/osd/exceptions.h +++ b/src/crimson/osd/exceptions.h @@ -4,12 +4,55 @@ #pragma once #include +#include -class object_not_found : public std::exception { +namespace ceph::osd { +class error : private std::system_error { +public: + error(const std::errc ec) + : system_error(std::make_error_code(ec)) { + } + + 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()) { + } }; -class object_corrupted : public std::exception { +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) {} }; -class invalid_argument : public std::exception { +struct object_corrupted : public error { + object_corrupted() : error(std::errc::illegal_byte_sequence) {} }; + +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/objclass.cc b/src/crimson/osd/objclass.cc new file mode 100644 index 0000000000000..8bd8e3a13ac3a --- /dev/null +++ b/src/crimson/osd/objclass.cc @@ -0,0 +1,346 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include +#include +#include "common/ceph_context.h" +#include "common/ceph_releases.h" +#include "common/config.h" +#include "common/debug.h" + +#include "crimson/osd/exceptions.h" +#include "crimson/osd/ops_executer.h" +#include "crimson/osd/pg_backend.h" + +#include "objclass/objclass.h" +#include "osd/ClassHandler.h" + +#include "auth/Crypto.h" +#include "common/armor.h" + +int cls_call(cls_method_context_t hctx, const char *cls, const char *method, + char *indata, int datalen, + char **outdata, int *outdatalen) +{ +// FIXME, HACK: this is for testing only. Let's use dynamic linker to verify +// our depedencies + return 0; +} + +int cls_getxattr(cls_method_context_t hctx, + const char *name, + char **outdata, + int *outdatalen) +{ + return 0; +} + +int cls_setxattr(cls_method_context_t hctx, + const char *name, + const char *value, + int val_len) +{ + return 0; +} + +int cls_read(cls_method_context_t hctx, + int ofs, int len, + char **outdata, + int *outdatalen) +{ + return 0; +} + +int cls_get_request_origin(cls_method_context_t hctx, entity_inst_t *origin) +{ + return 0; +} + +int cls_cxx_create(cls_method_context_t hctx, bool exclusive) +{ + return 0; +} + +int cls_cxx_remove(cls_method_context_t hctx) +{ + return 0; +} + +int cls_cxx_stat(cls_method_context_t hctx, uint64_t *size, time_t *mtime) +{ + OSDOp op;//{CEPH_OSD_OP_STAT}; + op.op.op = CEPH_OSD_OP_STAT; + + // we're blocking here which presumes execution in Seastar's thread. + try { + reinterpret_cast(hctx)->do_osd_op(op).get(); + } catch (ceph::osd::error& e) { + return -e.code().value(); + } + + utime_t ut; + uint64_t s; + try { + auto iter = op.outdata.cbegin(); + decode(s, iter); + decode(ut, iter); + } catch (buffer::error& err) { + return -EIO; + } + if (size) { + *size = s; + } + if (mtime) { + *mtime = ut.sec(); + } + return 0; +} + +int cls_cxx_stat2(cls_method_context_t hctx, + uint64_t *size, + ceph::real_time *mtime) +{ + return 0; +} + +int cls_cxx_read2(cls_method_context_t hctx, + int ofs, + int len, + bufferlist *outbl, + uint32_t op_flags) +{ + OSDOp op; + op.op.op = CEPH_OSD_OP_SYNC_READ; + op.op.extent.offset = ofs; + op.op.extent.length = len; + op.op.flags = op_flags; + try { + reinterpret_cast(hctx)->do_osd_op(op).get(); + } catch (ceph::osd::error& e) { + return -e.code().value(); + } + outbl->claim(op.outdata); + return outbl->length(); +} + +int cls_cxx_write2(cls_method_context_t hctx, + int ofs, + int len, + bufferlist *inbl, + uint32_t op_flags) +{ + return 0; +} + +int cls_cxx_write_full(cls_method_context_t hctx, bufferlist * const inbl) +{ + OSDOp op; + op.op.op = CEPH_OSD_OP_WRITEFULL; + op.op.extent.offset = 0; + op.op.extent.length = inbl->length(); + op.indata = *inbl; + try { + reinterpret_cast(hctx)->do_osd_op(op).get(); + return 0; + } catch (ceph::osd::error& e) { + return -e.code().value(); + } +} + +int cls_cxx_replace(cls_method_context_t hctx, + int ofs, + int len, + bufferlist *inbl) +{ + return 0; +} + +int cls_cxx_truncate(cls_method_context_t hctx, int ofs) +{ + return 0; +} + +int cls_cxx_getxattr(cls_method_context_t hctx, + const char *name, + bufferlist *outbl) +{ + OSDOp op; + op.op.op = CEPH_OSD_OP_GETXATTR; + op.op.xattr.name_len = strlen(name); + op.indata.append(name, op.op.xattr.name_len); + try { + reinterpret_cast(hctx)->do_osd_op(op).get(); + outbl->claim(op.outdata); + return outbl->length(); + } catch (ceph::osd::error& e) { + return -e.code().value(); + } +} + +int cls_cxx_getxattrs(cls_method_context_t hctx, + map *attrset) +{ + return 0; +} + +int cls_cxx_setxattr(cls_method_context_t hctx, + const char *name, + bufferlist *inbl) +{ + OSDOp op; + op.op.op = CEPH_OSD_OP_SETXATTR; + op.op.xattr.name_len = std::strlen(name); + op.op.xattr.value_len = inbl->length(); + op.indata.append(name, op.op.xattr.name_len); + op.indata.append(*inbl); + try { + reinterpret_cast(hctx)->do_osd_op(op).get(); + return 0; + } catch (ceph::osd::error& e) { + return -e.code().value(); + } +} + +int cls_cxx_snap_revert(cls_method_context_t hctx, snapid_t snapid) +{ + return 0; +} + +int cls_cxx_map_get_all_vals(cls_method_context_t hctx, + map* vals, + bool *more) +{ + return 0; +} + +int cls_cxx_map_get_keys(cls_method_context_t hctx, + const string &start_obj, + uint64_t max_to_get, + set *keys, + bool *more) +{ + return 0; +} + +int cls_cxx_map_get_vals(cls_method_context_t hctx, + const string &start_obj, + const string &filter_prefix, + uint64_t max_to_get, + map *vals, + bool *more) +{ + return 0; +} + +int cls_cxx_map_read_header(cls_method_context_t hctx, bufferlist *outbl) +{ + return 0; +} + +int cls_cxx_map_get_val(cls_method_context_t hctx, + const string &key, + bufferlist *outbl) +{ + return 0; +} + +int cls_cxx_map_set_val(cls_method_context_t hctx, + const string &key, + bufferlist *inbl) +{ + return 0; +} + +int cls_cxx_map_set_vals(cls_method_context_t hctx, + const std::map *map) +{ + return 0; +} + +int cls_cxx_map_clear(cls_method_context_t hctx) +{ + return 0; +} + +int cls_cxx_map_write_header(cls_method_context_t hctx, bufferlist *inbl) +{ + return 0; +} + +int cls_cxx_map_remove_range(cls_method_context_t hctx, + const std::string& key_begin, + const std::string& key_end) +{ + return 0; +} + +int cls_cxx_map_remove_key(cls_method_context_t hctx, const string &key) +{ + return 0; +} + +int cls_cxx_list_watchers(cls_method_context_t hctx, + obj_list_watch_response_t *watchers) +{ + return 0; +} + +uint64_t cls_current_version(cls_method_context_t hctx) +{ + return 0; +} + + +int cls_current_subop_num(cls_method_context_t hctx) +{ + return 0; +} + +uint64_t cls_get_features(cls_method_context_t hctx) +{ + return 0; +} + +uint64_t cls_get_client_features(cls_method_context_t hctx) +{ + return 0; +} + +ceph_release_t cls_get_required_osd_release(cls_method_context_t hctx) +{ + // FIXME + return ceph_release_t::nautilus; +} + +ceph_release_t cls_get_min_compatible_client(cls_method_context_t hctx) +{ + // FIXME + return ceph_release_t::nautilus; +} + +int cls_get_snapset_seq(cls_method_context_t hctx, uint64_t *snap_seq) +{ + return 0; +} + +int cls_cxx_chunk_write_and_set(cls_method_context_t hctx, + int ofs, + int len, + bufferlist *write_inbl, + uint32_t op_flags, + bufferlist *set_inbl, + int set_len) +{ + return 0; +} + +bool cls_has_chunk(cls_method_context_t hctx, string fp_oid) +{ + return 0; +} + +uint64_t cls_get_osd_min_alloc_size(cls_method_context_t hctx) { + // FIXME + return 4096; +} diff --git a/src/crimson/osd/ops_executer.cc b/src/crimson/osd/ops_executer.cc new file mode 100644 index 0000000000000..56065d38b1bf4 --- /dev/null +++ b/src/crimson/osd/ops_executer.cc @@ -0,0 +1,411 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "ops_executer.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "crimson/osd/exceptions.h" +#include "osd/ClassHandler.h" + +namespace { + seastar::logger& logger() { + return ceph::get_logger(ceph_subsys_osd); + } +} + +namespace ceph::osd { + +seastar::future<> OpsExecuter::do_op_call(OSDOp& osd_op) +{ + 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&) { + logger().warn("call unable to decode class + method + indata"); + throw ceph::osd::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 (!os->exists && (flags & CLS_METHOD_WR) == 0) { + throw ceph::osd::object_not_found{}; + } + +#if 0 + if (flags & CLS_METHOD_WR) { + ctx->user_modify = true; + } +#endif + + logger().debug("calling method {}.{}", cname, mname); + return seastar::async([this, &osd_op, flags, method, indata=std::move(indata)]() mutable { + ceph::bufferlist outdata; + const auto prev_rd = num_read; + const auto prev_wr = num_write; + const auto ret = method->exec(reinterpret_cast(this), + indata, outdata); + if (num_read > prev_rd && !(flags & CLS_METHOD_RD)) { + logger().error("method tried to read object but is not marked RD"); + throw ceph::osd::input_output_error{}; + } + if (num_write > prev_wr && !(flags & CLS_METHOD_WR)) { + logger().error("method tried to update object but is not marked WR"); + throw ceph::osd::input_output_error{}; + } + + // for write calls we never return data expect errors. For details refer + // to cls/cls_hello.cc. + if (ret < 0 || (flags & CLS_METHOD_WR) == 0) { + logger().debug("method called response length={}", outdata.length()); + osd_op.op.extent.length = outdata.length(); + osd_op.outdata.claim_append(outdata); + } + if (ret < 0) { + throw ceph::osd::make_error(ret); + } + }); +} + +static inline std::unique_ptr get_pgls_filter( + const std::string& type, + bufferlist::const_iterator& iter) +{ + // storing non-const PGLSFilter for the sake of ::init() + std::unique_ptr filter; + if (type.compare("plain") == 0) { + filter = std::make_unique(); + } else { + std::size_t dot = type.find("."); + if (dot == type.npos || dot == 0 || dot == type.size() - 1) { + throw ceph::osd::invalid_argument{}; + } + + const std::string class_name = type.substr(0, dot); + const std::string filter_name = type.substr(dot + 1); + ClassHandler::ClassData *cls = nullptr; + int r = ClassHandler::get_instance().open_class(class_name, &cls); + if (r != 0) { + logger().warn("can't open class {}: {}", class_name, cpp_strerror(r)); + if (r == -EPERM) { + // propogate permission error + throw ceph::osd::permission_denied{}; + } else { + throw ceph::osd::invalid_argument{}; + } + } else { + ceph_assert(cls); + } + + ClassHandler::ClassFilter * const class_filter = cls->get_filter(filter_name); + if (class_filter == nullptr) { + logger().warn("can't find filter {} in class {}", filter_name, class_name); + throw ceph::osd::invalid_argument{}; + } + + filter.reset(class_filter->fn()); + if (!filter) { + // Object classes are obliged to return us something, but let's + // give an error rather than asserting out. + logger().warn("buggy class {} failed to construct filter {}", + class_name, filter_name); + throw ceph::osd::invalid_argument{}; + } + } + + ceph_assert(filter); + int r = filter->init(iter); + if (r < 0) { + logger().warn("error initializing filter {}: {}", type, cpp_strerror(r)); + throw ceph::osd::invalid_argument{}; + } + + // successfully constructed and initialized, return it. + return filter; +} + +static seastar::future pgls_filter( + const PGLSFilter& filter, + const PGBackend& backend, + const hobject_t& sobj) +{ + if (const auto xattr = filter.get_xattr(); !xattr.empty()) { + logger().debug("pgls_filter: filter is interested in xattr={} for obj={}", + xattr, sobj); + return backend.getxattr(sobj, xattr).then_wrapped( + [&filter, sobj] (auto futval) { + logger().debug("pgls_filter: got xvalue for obj={}", sobj); + + ceph::bufferlist val; + if (!futval.failed()) { + val.push_back(std::move(futval).get0()); + } else if (filter.reject_empty_xattr()) { + return seastar::make_ready_future(false, sobj); + } + const bool filtered = filter.filter(sobj, val); + return seastar::make_ready_future(filtered, sobj); + }); + } else { + ceph::bufferlist empty_lvalue_bl; + const bool filtered = filter.filter(sobj, empty_lvalue_bl); + return seastar::make_ready_future(filtered, sobj); + } +} + +static seastar::future do_pgnls_common( + const hobject_t& pg_start, + const hobject_t& pg_end, + const PGBackend& backend, + const hobject_t& lower_bound, + const std::string& nspace, + const uint64_t limit, + const PGLSFilter* const filter) +{ + if (!(lower_bound.is_min() || + lower_bound.is_max() || + (lower_bound >= pg_start && lower_bound < pg_end))) { + // this should only happen with a buggy client. + throw std::invalid_argument("outside of PG bounds"); + } + + return backend.list_objects(lower_bound, limit).then( + [&backend, filter, nspace](auto objects, auto next) { + auto in_my_namespace = [&nspace](const hobject_t& obj) { + using ceph::common::local_conf; + if (obj.get_namespace() == local_conf()->osd_hit_set_namespace) { + return false; + } else if (nspace == librados::all_nspaces) { + return true; + } else { + return obj.get_namespace() == nspace; + } + }; + auto to_pglsed = [&backend, filter] (const hobject_t& obj) { + // this transformation looks costly. However, I don't have any + // reason to think PGLS* operations are critical for, let's say, + // general performance. + // + // from tchaikov: "another way is to use seastar::map_reduce(), + // to 1) save the effort to filter the already filtered objects + // 2) avoid the space to keep the tuple even if + // the object is filtered out". + if (filter) { + return pgls_filter(*filter, backend, obj); + } else { + return seastar::make_ready_future(true, obj); + } + }; + + auto range = objects | boost::adaptors::filtered(in_my_namespace) + | boost::adaptors::transformed(to_pglsed); + logger().debug("do_pgnls_common: finishing the 1st stage of pgls"); + return seastar::when_all_succeed(std::begin(range), + std::end(range)).then( + [next=std::move(next)] (auto items) mutable { + // the sole purpose of this chaining is to pass `next` to 2nd + // stage altogether with items + logger().debug("do_pgnls_common: 1st done"); + return seastar::make_ready_future( + std::move(items), std::move(next)); + }); + }).then( + [pg_end, filter] (const std::vector>& items, auto next) { + auto is_matched = [] (const auto& item) { + return std::get(item); + }; + auto to_entry = [] (const auto& item) { + const auto& obj = std::get(item); + return librados::ListObjectImpl{ + obj.get_namespace(), obj.oid.name, obj.get_key() + }; + }; + + pg_nls_response_t response; + boost::push_back(response.entries, items | boost::adaptors::filtered(is_matched) + | boost::adaptors::transformed(to_entry)); + response.handle = next.is_max() ? pg_end : next; + ceph::bufferlist out; + encode(response, out); + logger().debug("{}: response.entries.size()=", + __func__, response.entries.size()); + return seastar::make_ready_future(std::move(out)); + }); +} + +static seastar::future<> do_pgnls( + const PG& pg, + const std::string& nspace, + OSDOp& osd_op) +{ + hobject_t lower_bound; + try { + ceph::decode(lower_bound, osd_op.indata); + } catch (const buffer::error&) { + throw std::invalid_argument("unable to decode PGNLS handle"); + } + const auto pg_start = pg.get_pgid().pgid.get_hobj_start(); + const auto pg_end = \ + pg.get_pgid().pgid.get_hobj_end(pg.get_pool().info.get_pg_num()); + return do_pgnls_common(pg_start, + pg_end, + pg.get_backend(), + lower_bound, + nspace, + osd_op.op.pgls.count, + nullptr /* no filter */) + .then([&osd_op](bufferlist bl) { + osd_op.outdata = std::move(bl); + return seastar::now(); + }); +} + +static seastar::future<> do_pgnls_filtered( + const PG& pg, + const std::string& nspace, + OSDOp& osd_op) +{ + std::string cname, mname, type; + auto bp = osd_op.indata.cbegin(); + try { + ceph::decode(cname, bp); + ceph::decode(mname, bp); + ceph::decode(type, bp); + } catch (const buffer::error&) { + throw ceph::osd::invalid_argument{}; + } + + auto filter = get_pgls_filter(type, bp); + + hobject_t lower_bound; + try { + lower_bound.decode(bp); + } catch (const buffer::error&) { + throw std::invalid_argument("unable to decode PGNLS_FILTER description"); + } + + logger().debug("{}: cname={}, mname={}, type={}, lower_bound={}, filter={}", + __func__, cname, mname, type, lower_bound, + static_cast(filter.get())); + return seastar::do_with(std::move(filter), + [&, lower_bound=std::move(lower_bound)](auto&& filter) { + const auto pg_start = pg.get_pgid().pgid.get_hobj_start(); + const auto pg_end = pg.get_pgid().pgid.get_hobj_end(pg.get_pool().info.get_pg_num()); + return do_pgnls_common(pg_start, + pg_end, + pg.get_backend(), + lower_bound, + nspace, + osd_op.op.pgls.count, + filter.get()) + .then([&osd_op](bufferlist bl) { + osd_op.outdata = std::move(bl); + return seastar::now(); + }); + }); +} + +seastar::future<> +OpsExecuter::do_osd_op(OSDOp& osd_op) +{ + // TODO: dispatch via call table? + // TODO: we might want to find a way to unify both input and output + // of each op. + logger().debug("handling op {}", ceph_osd_op_name(osd_op.op.op)); + switch (const ceph_osd_op& op = osd_op.op; op.op) { + case CEPH_OSD_OP_SYNC_READ: + [[fallthrough]]; + case CEPH_OSD_OP_READ: + return do_read_op([&osd_op] (auto& backend, const auto& os) { + return backend.read(os.oi, + osd_op.op.extent.offset, + osd_op.op.extent.length, + osd_op.op.extent.truncate_size, + osd_op.op.extent.truncate_seq, + osd_op.op.flags).then( + [&osd_op](bufferlist bl) { + osd_op.rval = bl.length(); + osd_op.outdata = std::move(bl); + return seastar::now(); + }); + }); + case CEPH_OSD_OP_GETXATTR: + return do_read_op([&osd_op] (auto& backend, const auto& os) { + return backend.getxattr(os, osd_op); + }); + case CEPH_OSD_OP_WRITE: + return do_write_op([&osd_op] (auto& backend, auto& os, auto& txn) { + return backend.write(os, osd_op, txn); + }); + case CEPH_OSD_OP_WRITEFULL: + return do_write_op([&osd_op] (auto& backend, auto& os, auto& txn) { + return backend.writefull(os, osd_op, txn); + }); + case CEPH_OSD_OP_SETALLOCHINT: + return seastar::now(); + case CEPH_OSD_OP_SETXATTR: + return do_write_op([&osd_op] (auto& backend, auto& os, auto& txn) { + return backend.setxattr(os, osd_op, txn); + }); + case CEPH_OSD_OP_PGNLS_FILTER: + return do_pg_op([&osd_op] (const auto& pg, const auto& nspace) { + return do_pgnls_filtered(pg, nspace, osd_op); + }); + case CEPH_OSD_OP_PGNLS: + return do_pg_op([&osd_op] (const auto& pg, const auto& nspace) { + return do_pgnls(pg, nspace, osd_op); + }); + case CEPH_OSD_OP_DELETE: + return do_write_op([&osd_op] (auto& backend, auto& os, auto& txn) { + return backend.remove(os, txn); + }); + case CEPH_OSD_OP_CALL: + return this->do_op_call(osd_op); + case CEPH_OSD_OP_STAT: + // note: stat does not require RD + return do_const_op([&osd_op] (/* const */auto& backend, const auto& os) { + return backend.stat(os, osd_op); + }); + default: + logger().warn("unknown op {}", ceph_osd_op_name(op.op)); + throw std::runtime_error( + fmt::format("op '{}' not supported", ceph_osd_op_name(op.op))); + } +} + +} // namespace ceph::osd diff --git a/src/crimson/osd/ops_executer.h b/src/crimson/osd/ops_executer.h new file mode 100644 index 0000000000000..3e8564570dfcb --- /dev/null +++ b/src/crimson/osd/ops_executer.h @@ -0,0 +1,82 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "common/dout.h" +#include "crimson/net/Fwd.h" +#include "os/Transaction.h" +#include "osd/osd_types.h" +#include "osd/osd_internal_types.h" + +#include "crimson/common/type_helpers.h" +#include "crimson/osd/osd_operations/client_request.h" +#include "crimson/osd/osd_operations/peering_event.h" +#include "crimson/osd/shard_services.h" +#include "crimson/osd/osdmap_gate.h" + +#include "crimson/osd/pg.h" +#include "crimson/osd/pg_backend.h" + +class PGLSFilter; +class OSDOp; + +namespace ceph::osd { +class OpsExecuter { + PGBackend::cached_os_t os; + PG& pg; + PGBackend& backend; + ceph::os::Transaction txn; + + size_t num_read = 0; ///< count read ops + size_t num_write = 0; ///< count update ops + + seastar::future<> do_op_call(class OSDOp& osd_op); + + template + auto do_const_op(Func&& f) { + // TODO: pass backend as read-only + return std::forward(f)(backend, std::as_const(*os)); + } + + template + auto do_read_op(Func&& f) { + ++num_read; + // TODO: pass backend as read-only + return do_const_op(std::forward(f)); + } + + template + auto do_write_op(Func&& f) { + ++num_write; + return std::forward(f)(backend, *os, txn); + } + + // PG operations are being provided with pg instead of os. + template + auto do_pg_op(Func&& f) { + return std::forward(f)(std::as_const(pg), + std::as_const(os->oi.soid.get_namespace())); + } + +public: + OpsExecuter(PGBackend::cached_os_t os, PG& pg) + : os(std::move(os)), pg(pg), backend(pg.get_backend()) { + } + + seastar::future<> do_osd_op(class OSDOp& osd_op); + + template seastar::future<> submit_changes(Func&& f) && { + return std::forward(f)(std::move(txn), std::move(os)); + } +}; + +} // namespace ceph::osd diff --git a/src/crimson/osd/osd.cc b/src/crimson/osd/osd.cc index 6cf7e9e04a67a..e38bb9defd4a0 100644 --- a/src/crimson/osd/osd.cc +++ b/src/crimson/osd/osd.cc @@ -20,6 +20,7 @@ #include "messages/MPGStats.h" #include "os/Transaction.h" +#include "osd/ClassHandler.h" #include "osd/PGPeeringEvent.h" #include "osd/PeeringState.h" @@ -78,6 +79,14 @@ OSD::OSD(int id, uint32_t nonce, msgr.get().set_auth_server(monc.get()); msgr.get().set_auth_client(monc.get()); } + + if (local_conf()->osd_open_classes_on_start) { + const int r = ClassHandler::get_instance().open_all_classes(); + if (r) { + logger().warn("{} warning: got an error loading one or more classes: {}", + __func__, cpp_strerror(r)); + } + } } OSD::~OSD() = default; diff --git a/src/crimson/osd/pg.cc b/src/crimson/osd/pg.cc index 4c6116f81bba0..196e8342d1b30 100644 --- a/src/crimson/osd/pg.cc +++ b/src/crimson/osd/pg.cc @@ -37,6 +37,7 @@ #include "crimson/osd/exceptions.h" #include "crimson/osd/pg_meta.h" #include "crimson/osd/pg_backend.h" +#include "crimson/osd/ops_executer.h" #include "crimson/osd/osd_operations/peering_event.h" namespace { @@ -329,92 +330,6 @@ seastar::future<> PG::wait_for_active() } } -// TODO: split the method accordingly to os' constness needs -seastar::future<> -PG::do_osd_op(ObjectState& os, OSDOp& osd_op, ceph::os::Transaction& txn) -{ - // TODO: dispatch via call table? - // TODO: we might want to find a way to unify both input and output - // of each op. - switch (const ceph_osd_op& op = osd_op.op; op.op) { - case CEPH_OSD_OP_SYNC_READ: - [[fallthrough]]; - case CEPH_OSD_OP_READ: - return backend->read(os.oi, - op.extent.offset, - op.extent.length, - op.extent.truncate_size, - op.extent.truncate_seq, - op.flags).then([&osd_op](bufferlist bl) { - osd_op.rval = bl.length(); - osd_op.outdata = std::move(bl); - return seastar::now(); - }); - case CEPH_OSD_OP_WRITE: - return backend->write(os, osd_op, txn); - case CEPH_OSD_OP_WRITEFULL: - // XXX: os = backend->write(std::move(os), ...) instead? - return backend->writefull(os, osd_op, txn); - case CEPH_OSD_OP_SETALLOCHINT: - return seastar::now(); - case CEPH_OSD_OP_PGNLS: - return do_pgnls(osd_op.indata, os.oi.soid.get_namespace(), op.pgls.count) - .then([&osd_op](bufferlist bl) { - osd_op.outdata = std::move(bl); - return seastar::now(); - }); - case CEPH_OSD_OP_DELETE: - return backend->remove(os, txn); - default: - throw std::runtime_error( - fmt::format("op '{}' not supported", ceph_osd_op_name(op.op))); - } -} - -seastar::future PG::do_pgnls(bufferlist& indata, - const std::string& nspace, - uint64_t limit) -{ - hobject_t lower_bound; - try { - ceph::decode(lower_bound, indata); - } catch (const buffer::error& e) { - throw std::invalid_argument("unable to decode PGNLS handle"); - } - const auto pg_start = pgid.pgid.get_hobj_start(); - const auto pg_end = pgid.pgid.get_hobj_end(peering_state.get_pool().info.get_pg_num()); - if (!(lower_bound.is_min() || - lower_bound.is_max() || - (lower_bound >= pg_start && lower_bound < pg_end))) { - // this should only happen with a buggy client. - throw std::invalid_argument("outside of PG bounds"); - } - return backend->list_objects(lower_bound, limit).then( - [lower_bound, pg_end, nspace](auto objects, auto next) { - auto in_my_namespace = [&nspace](const hobject_t& o) { - if (o.get_namespace() == local_conf()->osd_hit_set_namespace) { - return false; - } else if (nspace == librados::all_nspaces) { - return true; - } else { - return o.get_namespace() == nspace; - } - }; - pg_nls_response_t response; - boost::copy(objects | - boost::adaptors::filtered(in_my_namespace) | - boost::adaptors::transformed([](const hobject_t& o) { - return librados::ListObjectImpl{o.get_namespace(), - o.oid.name, - o.get_key()}; }), - std::back_inserter(response.entries)); - response.handle = next.is_max() ? pg_end : next; - bufferlist bl; - encode(response, bl); - return seastar::make_ready_future(std::move(bl)); - }); -} - seastar::future<> PG::submit_transaction(boost::local_shared_ptr&& os, ceph::os::Transaction&& txn, const MOSDOp& req) @@ -438,39 +353,42 @@ seastar::future<> PG::submit_transaction(boost::local_shared_ptr&& seastar::future> PG::do_osd_ops(Ref m) { - return seastar::do_with(std::move(m), ceph::os::Transaction{}, - [this](auto& m, auto& txn) { - const auto oid = m->get_snapid() == CEPH_SNAPDIR ? m->get_hobj().get_head() - : m->get_hobj(); - return backend->get_object_state(oid).then([m,&txn,this](auto os) { - // TODO: issue requests in parallel if they don't write, - // with writes being basically a synchronization barrier - return seastar::do_for_each(std::begin(m->ops), std::end(m->ops), - [m,&txn,this,pos=os.get()](OSDOp& osd_op) { - return do_osd_op(*pos, osd_op, txn); - }).then([&txn,m,this,os=std::move(os)]() mutable { - // XXX: the entire lambda could be scheduled conditionally. ::if_then()? - if (txn.empty()) { - return seastar::now(); - } else { - return submit_transaction(std::move(os), std::move(txn), *m); - } + const auto oid = m->get_snapid() == CEPH_SNAPDIR ? m->get_hobj().get_head() + : m->get_hobj(); + return backend->get_object_state(oid).then([this, m](auto os) mutable { + return seastar::do_with(OpsExecuter{std::move(os), *this/* as const& */}, + [this, m=std::move(m)] (auto& ox) { + return seastar::do_for_each(m->ops, [this, &ox](OSDOp& osd_op) { + logger().debug("will be handling op {}", ceph_osd_op_name(osd_op.op.op)); + return ox.do_osd_op(osd_op); + }).then([this, m, &ox] { + logger().debug("all operations have been executed successfully"); + return std::move(ox).submit_changes([this, m] (auto&& txn, auto&& os) { + // XXX: the entire lambda could be scheduled conditionally. ::if_then()? + if (txn.empty()) { + logger().debug("txn is empty, bypassing mutate"); + return seastar::now(); + } else { + return submit_transaction(std::move(os), std::move(txn), *m); + } + }); }); - }).then([m,this] { - auto reply = make_message(m.get(), 0, get_osdmap_epoch(), - 0, false); - reply->add_flags(CEPH_OSD_FLAG_ACK | CEPH_OSD_FLAG_ONDISK); - return seastar::make_ready_future>(std::move(reply)); - }).handle_exception_type([=](const object_not_found& dne) { - logger().debug("got object_not_found for {}", oid); - - backend->evict_object_state(oid); - auto reply = make_message(m.get(), -ENOENT, get_osdmap_epoch(), - 0, false); - reply->set_enoent_reply_versions(peering_state.get_info().last_update, - peering_state.get_info().last_user_version); - return seastar::make_ready_future>(std::move(reply)); }); + }).then([m,this] { + auto reply = make_message(m.get(), 0, get_osdmap_epoch(), + 0, false); + reply->add_flags(CEPH_OSD_FLAG_ACK | CEPH_OSD_FLAG_ONDISK); + return seastar::make_ready_future>(std::move(reply)); + }).handle_exception_type([=,&oid](const ceph::osd::error& e) { + logger().debug("got ceph::osd::error while handling object {}: {} ({})", + oid, e.code(), e.what()); + + backend->evict_object_state(oid); + auto reply = make_message( + m.get(), -e.code().value(), get_osdmap_epoch(), 0, false); + reply->set_enoent_reply_versions(peering_state.get_info().last_update, + peering_state.get_info().last_user_version); + return seastar::make_ready_future>(std::move(reply)); }); } diff --git a/src/crimson/osd/pg.h b/src/crimson/osd/pg.h index fe6115031ee9e..542cb7912a323 100644 --- a/src/crimson/osd/pg.h +++ b/src/crimson/osd/pg.h @@ -81,6 +81,13 @@ class PG : public boost::intrusive_ref_counter< return pgid; } + PGBackend& get_backend() { + return *backend; + } + const PGBackend& get_backend() const { + return *backend; + } + // EpochSource epoch_t get_osdmap_epoch() const final { return peering_state.get_osdmap_epoch(); @@ -396,6 +403,10 @@ class PG : public boost::intrusive_ref_counter< return peering_state.get_need_up_thru(); } + const auto& get_pool() const { + return peering_state.get_pool(); + } + /// initialize created PG void init( ceph::os::CollectionRef coll_ref, diff --git a/src/crimson/osd/pg_backend.cc b/src/crimson/osd/pg_backend.cc index fe1431d7f5d69..9fe24d4e63c97 100644 --- a/src/crimson/osd/pg_backend.cc +++ b/src/crimson/osd/pg_backend.cc @@ -25,6 +25,8 @@ namespace { } } +using ceph::common::local_conf; + std::unique_ptr PGBackend::create(pg_t pgid, const pg_shard_t pg_shard, const pg_pool_t& pool, @@ -73,7 +75,7 @@ PGBackend::get_object_state(const hobject_t& oid) oid.snap); if (clone == end(ss->clones)) { return seastar::make_exception_future( - object_not_found{}); + ceph::osd::object_not_found{}); } // clone auto soid = oid; @@ -84,7 +86,7 @@ PGBackend::get_object_state(const hobject_t& oid) if (clone_snap->second.empty()) { logger().trace("find_object: {}@[] -- DNE", soid); return seastar::make_exception_future( - object_not_found{}); + ceph::osd::object_not_found{}); } auto first = clone_snap->second.back(); auto last = clone_snap->second.front(); @@ -92,7 +94,7 @@ PGBackend::get_object_state(const hobject_t& oid) logger().trace("find_object: {}@[{},{}] -- DNE", soid, first, last); return seastar::make_exception_future( - object_not_found{}); + ceph::osd::object_not_found{}); } logger().trace("find_object: {}@[{},{}] -- HIT", soid, first, last); @@ -237,13 +239,29 @@ seastar::future PGBackend::read(const object_info_t& oi, logger().error("full-object read crc {} != expected {} on {}", crc, *maybe_crc, soid); // todo: mark soid missing, perform recovery, and retry - throw object_corrupted{}; + throw ceph::osd::object_corrupted{}; } } return seastar::make_ready_future(std::move(bl)); }); } +seastar::future<> PGBackend::stat( + const ObjectState& os, + OSDOp& osd_op) +{ + if (os.exists/* TODO: && !os.is_whiteout() */) { + logger().debug("stat os.oi.size={}, os.oi.mtime={}", os.oi.size, os.oi.mtime); + encode(os.oi.size, osd_op.outdata); + encode(os.oi.mtime, osd_op.outdata); + } else { + logger().debug("stat object does not exist"); + throw ceph::osd::object_not_found{}; + } + return seastar::now(); + // TODO: ctx->delta_stats.num_rd++; +} + bool PGBackend::maybe_create_new_object( ObjectState& os, ceph::os::Transaction& txn) @@ -316,7 +334,7 @@ seastar::future<> PGBackend::writefull( { const ceph_osd_op& op = osd_op.op; if (op.extent.length != osd_op.indata.length()) { - throw ::invalid_argument(); + throw ceph::osd::invalid_argument(); } const bool existing = maybe_create_new_object(os, txn); @@ -347,7 +365,7 @@ seastar::future<> PGBackend::remove(ObjectState& os, } seastar::future, hobject_t> -PGBackend::list_objects(const hobject_t& start, uint64_t limit) +PGBackend::list_objects(const hobject_t& start, uint64_t limit) const { auto gstart = start.is_min() ? ghobject_t{} : ghobject_t{start, 0, shard}; return store->list_objects(coll, @@ -374,3 +392,67 @@ PGBackend::list_objects(const hobject_t& start, uint64_t limit) objects, next.hobj); }); } + +seastar::future<> PGBackend::setxattr( + ObjectState& os, + const OSDOp& osd_op, + ceph::os::Transaction& txn) +{ + if (local_conf()->osd_max_attr_size > 0 && + osd_op.op.xattr.value_len > local_conf()->osd_max_attr_size) { + throw ceph::osd::make_error(-EFBIG); + } + + const auto max_name_len = std::min( + store->get_max_attr_name_length(), local_conf()->osd_max_attr_name_len); + if (osd_op.op.xattr.name_len > max_name_len) { + throw ceph::osd::make_error(-ENAMETOOLONG); + } + + maybe_create_new_object(os, txn); + + std::string name; + ceph::bufferlist val; + { + auto bp = osd_op.indata.cbegin(); + std::string aname; + bp.copy(osd_op.op.xattr.name_len, aname); + name = "_" + aname; + bp.copy(osd_op.op.xattr.value_len, val); + } + + txn.setattr(coll->cid, ghobject_t{os.oi.soid}, name, val); + return seastar::now(); + //ctx->delta_stats.num_wr++; +} + +seastar::future<> PGBackend::getxattr( + const ObjectState& os, + OSDOp& osd_op) const +{ + std::string name; + ceph::bufferlist val; + { + auto bp = osd_op.indata.cbegin(); + std::string aname; + bp.copy(osd_op.op.xattr.name_len, aname); + name = "_" + aname; + } + return getxattr(os.oi.soid, name).then([&osd_op] (ceph::bufferptr val) { + osd_op.outdata.clear(); + osd_op.outdata.push_back(std::move(val)); + osd_op.op.xattr.value_len = osd_op.outdata.length(); + //ctx->delta_stats.num_rd_kb += shift_round_up(osd_op.outdata.length(), 10); + }).handle_exception_type( + [] (ceph::os::FuturizedStore::EnoentException& e) { + return seastar::make_exception_future<>(ceph::osd::object_not_found{}); + }); + //ctx->delta_stats.num_rd++; +} + +seastar::future PGBackend::getxattr( + const hobject_t& soid, + std::string_view key) const +{ + return store->get_attr(coll, ghobject_t{soid}, key); +} diff --git a/src/crimson/osd/pg_backend.h b/src/crimson/osd/pg_backend.h index fbc2653d74c0b..7f3dd4fb3a996 100644 --- a/src/crimson/osd/pg_backend.h +++ b/src/crimson/osd/pg_backend.h @@ -47,6 +47,9 @@ class PGBackend size_t truncate_size, uint32_t truncate_seq, uint32_t flags); + seastar::future<> stat( + const ObjectState& os, + OSDOp& osd_op); seastar::future<> remove( ObjectState& os, ceph::os::Transaction& txn); @@ -68,7 +71,17 @@ class PGBackend eversion_t ver); seastar::future, hobject_t> list_objects( const hobject_t& start, - uint64_t limit); + uint64_t limit) const; + seastar::future<> setxattr( + ObjectState& os, + const OSDOp& osd_op, + ceph::os::Transaction& trans); + seastar::future<> getxattr( + const ObjectState& os, + OSDOp& osd_op) const; + seastar::future getxattr( + const hobject_t& soid, + std::string_view key) const; virtual void got_rep_op_reply(const MOSDRepOpReply&) {} diff --git a/src/objclass/class_api.cc b/src/objclass/class_api.cc index 0e3c889508817..2ff595f08a67f 100644 --- a/src/objclass/class_api.cc +++ b/src/objclass/class_api.cc @@ -1,13 +1,13 @@ // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab +#include +#include "common/ceph_context.h" +#include "common/ceph_releases.h" #include "common/config.h" #include "common/debug.h" #include "objclass/objclass.h" -#include "osd/PrimaryLogPG.h" -#include "osd/osd_types.h" - #include "osd/ClassHandler.h" #include "auth/Crypto.h" @@ -92,565 +92,16 @@ void cls_unregister_filter(cls_filter_handle_t handle) filter->unregister(); } -int cls_call(cls_method_context_t hctx, const char *cls, const char *method, - char *indata, int datalen, - char **outdata, int *outdatalen) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - bufferlist idata; - vector nops(1); - OSDOp& op = nops[0]; - int r; - - op.op.op = CEPH_OSD_OP_CALL; - op.op.cls.class_len = strlen(cls); - op.op.cls.method_len = strlen(method); - op.op.cls.indata_len = datalen; - op.indata.append(cls, op.op.cls.class_len); - op.indata.append(method, op.op.cls.method_len); - op.indata.append(indata, datalen); - r = (*pctx)->pg->do_osd_ops(*pctx, nops); - if (r < 0) - return r; - - *outdata = (char *)malloc(op.outdata.length()); - if (!*outdata) - return -ENOMEM; - memcpy(*outdata, op.outdata.c_str(), op.outdata.length()); - *outdatalen = op.outdata.length(); - - return r; -} - -int cls_getxattr(cls_method_context_t hctx, const char *name, - char **outdata, int *outdatalen) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - bufferlist name_data; - vector nops(1); - OSDOp& op = nops[0]; - int r; - - op.op.op = CEPH_OSD_OP_GETXATTR; - op.op.xattr.name_len = strlen(name); - op.indata.append(name, op.op.xattr.name_len); - r = (*pctx)->pg->do_osd_ops(*pctx, nops); - if (r < 0) - return r; - - *outdata = (char *)malloc(op.outdata.length()); - if (!*outdata) - return -ENOMEM; - memcpy(*outdata, op.outdata.c_str(), op.outdata.length()); - *outdatalen = op.outdata.length(); - - return r; -} - -int cls_setxattr(cls_method_context_t hctx, const char *name, - const char *value, int val_len) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - bufferlist name_data; - vector nops(1); - OSDOp& op = nops[0]; - int r; - - op.op.op = CEPH_OSD_OP_SETXATTR; - op.op.xattr.name_len = strlen(name); - op.op.xattr.value_len = val_len; - op.indata.append(name, op.op.xattr.name_len); - op.indata.append(value, val_len); - r = (*pctx)->pg->do_osd_ops(*pctx, nops); - - return r; -} - -int cls_read(cls_method_context_t hctx, int ofs, int len, - char **outdata, int *outdatalen) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - vector ops(1); - ops[0].op.op = CEPH_OSD_OP_SYNC_READ; - ops[0].op.extent.offset = ofs; - ops[0].op.extent.length = len; - int r = (*pctx)->pg->do_osd_ops(*pctx, ops); - if (r < 0) - return r; - - *outdata = (char *)malloc(ops[0].outdata.length()); - if (!*outdata) - return -ENOMEM; - memcpy(*outdata, ops[0].outdata.c_str(), ops[0].outdata.length()); - *outdatalen = ops[0].outdata.length(); - - return *outdatalen; -} - -int cls_get_request_origin(cls_method_context_t hctx, entity_inst_t *origin) -{ - PrimaryLogPG::OpContext **pctx = static_cast(hctx); - *origin = (*pctx)->op->get_req()->get_orig_source_inst(); - return 0; -} - -int cls_cxx_create(cls_method_context_t hctx, bool exclusive) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - vector ops(1); - ops[0].op.op = CEPH_OSD_OP_CREATE; - ops[0].op.flags = (exclusive ? CEPH_OSD_OP_FLAG_EXCL : 0); - return (*pctx)->pg->do_osd_ops(*pctx, ops); -} - -int cls_cxx_remove(cls_method_context_t hctx) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - vector ops(1); - ops[0].op.op = CEPH_OSD_OP_DELETE; - return (*pctx)->pg->do_osd_ops(*pctx, ops); -} - -int cls_cxx_stat(cls_method_context_t hctx, uint64_t *size, time_t *mtime) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - vector ops(1); - int ret; - ops[0].op.op = CEPH_OSD_OP_STAT; - ret = (*pctx)->pg->do_osd_ops(*pctx, ops); - if (ret < 0) - return ret; - auto iter = ops[0].outdata.cbegin(); - utime_t ut; - uint64_t s; - try { - decode(s, iter); - decode(ut, iter); - } catch (buffer::error& err) { - return -EIO; - } - if (size) - *size = s; - if (mtime) - *mtime = ut.sec(); - return 0; -} - -int cls_cxx_stat2(cls_method_context_t hctx, uint64_t *size, ceph::real_time *mtime) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - vector ops(1); - int ret; - ops[0].op.op = CEPH_OSD_OP_STAT; - ret = (*pctx)->pg->do_osd_ops(*pctx, ops); - if (ret < 0) - return ret; - auto iter = ops[0].outdata.cbegin(); - real_time ut; - uint64_t s; - try { - decode(s, iter); - decode(ut, iter); - } catch (buffer::error& err) { - return -EIO; - } - if (size) - *size = s; - if (mtime) - *mtime = ut; - return 0; -} - int cls_cxx_read(cls_method_context_t hctx, int ofs, int len, bufferlist *outbl) { return cls_cxx_read2(hctx, ofs, len, outbl, 0); } -int cls_cxx_read2(cls_method_context_t hctx, int ofs, int len, - bufferlist *outbl, uint32_t op_flags) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - vector ops(1); - int ret; - ops[0].op.op = CEPH_OSD_OP_SYNC_READ; - ops[0].op.extent.offset = ofs; - ops[0].op.extent.length = len; - ops[0].op.flags = op_flags; - ret = (*pctx)->pg->do_osd_ops(*pctx, ops); - if (ret < 0) - return ret; - outbl->claim(ops[0].outdata); - return outbl->length(); -} - int cls_cxx_write(cls_method_context_t hctx, int ofs, int len, bufferlist *inbl) { return cls_cxx_write2(hctx, ofs, len, inbl, 0); } -int cls_cxx_write2(cls_method_context_t hctx, int ofs, int len, - bufferlist *inbl, uint32_t op_flags) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - vector ops(1); - ops[0].op.op = CEPH_OSD_OP_WRITE; - ops[0].op.extent.offset = ofs; - ops[0].op.extent.length = len; - ops[0].op.flags = op_flags; - ops[0].indata = *inbl; - return (*pctx)->pg->do_osd_ops(*pctx, ops); -} - -int cls_cxx_write_full(cls_method_context_t hctx, bufferlist *inbl) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - vector ops(1); - ops[0].op.op = CEPH_OSD_OP_WRITEFULL; - ops[0].op.extent.offset = 0; - ops[0].op.extent.length = inbl->length(); - ops[0].indata = *inbl; - return (*pctx)->pg->do_osd_ops(*pctx, ops); -} - -int cls_cxx_replace(cls_method_context_t hctx, int ofs, int len, bufferlist *inbl) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - vector ops(2); - ops[0].op.op = CEPH_OSD_OP_TRUNCATE; - ops[0].op.extent.offset = 0; - ops[0].op.extent.length = 0; - ops[1].op.op = CEPH_OSD_OP_WRITE; - ops[1].op.extent.offset = ofs; - ops[1].op.extent.length = len; - ops[1].indata = *inbl; - return (*pctx)->pg->do_osd_ops(*pctx, ops); -} - -int cls_cxx_truncate(cls_method_context_t hctx, int ofs) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - vector ops(1); - ops[0].op.op = CEPH_OSD_OP_TRUNCATE; - ops[0].op.extent.offset = ofs; - ops[0].op.extent.length = 0; - return (*pctx)->pg->do_osd_ops(*pctx, ops); -} - -int cls_cxx_getxattr(cls_method_context_t hctx, const char *name, - bufferlist *outbl) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - bufferlist name_data; - vector nops(1); - OSDOp& op = nops[0]; - int r; - - op.op.op = CEPH_OSD_OP_GETXATTR; - op.op.xattr.name_len = strlen(name); - op.indata.append(name, op.op.xattr.name_len); - r = (*pctx)->pg->do_osd_ops(*pctx, nops); - if (r < 0) - return r; - - outbl->claim(op.outdata); - return outbl->length(); -} - -int cls_cxx_getxattrs(cls_method_context_t hctx, map *attrset) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - vector nops(1); - OSDOp& op = nops[0]; - int r; - - op.op.op = CEPH_OSD_OP_GETXATTRS; - r = (*pctx)->pg->do_osd_ops(*pctx, nops); - if (r < 0) - return r; - - auto iter = op.outdata.cbegin(); - try { - decode(*attrset, iter); - } catch (buffer::error& err) { - return -EIO; - } - return 0; -} - -int cls_cxx_setxattr(cls_method_context_t hctx, const char *name, - bufferlist *inbl) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - bufferlist name_data; - vector nops(1); - OSDOp& op = nops[0]; - int r; - - op.op.op = CEPH_OSD_OP_SETXATTR; - op.op.xattr.name_len = strlen(name); - op.op.xattr.value_len = inbl->length(); - op.indata.append(name, op.op.xattr.name_len); - op.indata.append(*inbl); - r = (*pctx)->pg->do_osd_ops(*pctx, nops); - - return r; -} - -int cls_cxx_snap_revert(cls_method_context_t hctx, snapid_t snapid) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - vector ops(1); - ops[0].op.op = CEPH_OSD_OP_ROLLBACK; - ops[0].op.snap.snapid = snapid; - return (*pctx)->pg->do_osd_ops(*pctx, ops); -} - -int cls_cxx_map_get_all_vals(cls_method_context_t hctx, map* vals, - bool *more) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - vector ops(1); - OSDOp& op = ops[0]; - int ret; - - string start_after; - string filter_prefix; - uint64_t max = (uint64_t)-1; - - encode(start_after, op.indata); - encode(max, op.indata); - encode(filter_prefix, op.indata); - - op.op.op = CEPH_OSD_OP_OMAPGETVALS; - - ret = (*pctx)->pg->do_osd_ops(*pctx, ops); - if (ret < 0) - return ret; - - auto iter = op.outdata.cbegin(); - try { - decode(*vals, iter); - decode(*more, iter); - } catch (buffer::error& err) { - return -EIO; - } - return vals->size(); -} - -int cls_cxx_map_get_keys(cls_method_context_t hctx, const string &start_obj, - uint64_t max_to_get, set *keys, - bool *more) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - vector ops(1); - OSDOp& op = ops[0]; - int ret; - - encode(start_obj, op.indata); - encode(max_to_get, op.indata); - - op.op.op = CEPH_OSD_OP_OMAPGETKEYS; - - ret = (*pctx)->pg->do_osd_ops(*pctx, ops); - if (ret < 0) - return ret; - - auto iter = op.outdata.cbegin(); - try { - decode(*keys, iter); - decode(*more, iter); - } catch (buffer::error& err) { - return -EIO; - } - return keys->size(); -} - -int cls_cxx_map_get_vals(cls_method_context_t hctx, const string &start_obj, - const string &filter_prefix, uint64_t max_to_get, - map *vals, bool *more) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - vector ops(1); - OSDOp& op = ops[0]; - int ret; - - encode(start_obj, op.indata); - encode(max_to_get, op.indata); - encode(filter_prefix, op.indata); - - op.op.op = CEPH_OSD_OP_OMAPGETVALS; - - ret = (*pctx)->pg->do_osd_ops(*pctx, ops); - if (ret < 0) - return ret; - - auto iter = op.outdata.cbegin(); - try { - decode(*vals, iter); - decode(*more, iter); - } catch (buffer::error& err) { - return -EIO; - } - return vals->size(); -} - -int cls_cxx_map_read_header(cls_method_context_t hctx, bufferlist *outbl) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - vector ops(1); - OSDOp& op = ops[0]; - int ret; - op.op.op = CEPH_OSD_OP_OMAPGETHEADER; - ret = (*pctx)->pg->do_osd_ops(*pctx, ops); - if (ret < 0) - return ret; - - outbl->claim(op.outdata); - - return 0; -} - -int cls_cxx_map_get_val(cls_method_context_t hctx, const string &key, - bufferlist *outbl) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - vector ops(1); - OSDOp& op = ops[0]; - int ret; - - set k; - k.insert(key); - encode(k, op.indata); - - op.op.op = CEPH_OSD_OP_OMAPGETVALSBYKEYS; - ret = (*pctx)->pg->do_osd_ops(*pctx, ops); - if (ret < 0) - return ret; - - auto iter = op.outdata.cbegin(); - try { - map m; - - decode(m, iter); - map::iterator iter = m.begin(); - if (iter == m.end()) - return -ENOENT; - - *outbl = iter->second; - } catch (buffer::error& e) { - return -EIO; - } - return 0; -} - -int cls_cxx_map_set_val(cls_method_context_t hctx, const string &key, - bufferlist *inbl) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - vector ops(1); - OSDOp& op = ops[0]; - bufferlist& update_bl = op.indata; - map m; - m[key] = *inbl; - encode(m, update_bl); - - op.op.op = CEPH_OSD_OP_OMAPSETVALS; - - return (*pctx)->pg->do_osd_ops(*pctx, ops); -} - -int cls_cxx_map_set_vals(cls_method_context_t hctx, - const std::map *map) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - vector ops(1); - OSDOp& op = ops[0]; - bufferlist& update_bl = op.indata; - encode(*map, update_bl); - - op.op.op = CEPH_OSD_OP_OMAPSETVALS; - - return (*pctx)->pg->do_osd_ops(*pctx, ops); -} - -int cls_cxx_map_clear(cls_method_context_t hctx) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - vector ops(1); - OSDOp& op = ops[0]; - - op.op.op = CEPH_OSD_OP_OMAPCLEAR; - - return (*pctx)->pg->do_osd_ops(*pctx, ops); -} - -int cls_cxx_map_write_header(cls_method_context_t hctx, bufferlist *inbl) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - vector ops(1); - OSDOp& op = ops[0]; - op.indata.claim(*inbl); - - op.op.op = CEPH_OSD_OP_OMAPSETHEADER; - - return (*pctx)->pg->do_osd_ops(*pctx, ops); -} - -int cls_cxx_map_remove_key(cls_method_context_t hctx, const string &key) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - vector ops(1); - OSDOp& op = ops[0]; - bufferlist& update_bl = op.indata; - set to_rm; - to_rm.insert(key); - - encode(to_rm, update_bl); - - op.op.op = CEPH_OSD_OP_OMAPRMKEYS; - - return (*pctx)->pg->do_osd_ops(*pctx, ops); -} - -int cls_cxx_map_remove_range(cls_method_context_t hctx, - const std::string& key_begin, - const std::string& key_end) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - vector ops(1); - OSDOp& op = ops[0]; - bufferlist& update_bl = op.indata; - - ::encode(key_begin, update_bl); - ::encode(key_end, update_bl); - - op.op.op = CEPH_OSD_OP_OMAPRMKEYRANGE; - - return (*pctx)->pg->do_osd_ops(*pctx, ops); -} - -int cls_cxx_list_watchers(cls_method_context_t hctx, - obj_list_watch_response_t *watchers) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - vector nops(1); - OSDOp& op = nops[0]; - int r; - - op.op.op = CEPH_OSD_OP_LIST_WATCHERS; - r = (*pctx)->pg->do_osd_ops(*pctx, nops); - if (r < 0) - return r; - - auto iter = op.outdata.cbegin(); - try { - decode(*watchers, iter); - } catch (buffer::error& err) { - return -EIO; - } - return 0; -} - int cls_gen_random_bytes(char *buf, int size) { ClassHandler::get_instance().cct->random()->get_bytes(buf, size); @@ -682,45 +133,6 @@ int cls_gen_rand_base64(char *dest, int size) /* size should be the required str return 0; } -uint64_t cls_current_version(cls_method_context_t hctx) -{ - PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx; - - return ctx->pg->get_last_user_version(); -} - - -int cls_current_subop_num(cls_method_context_t hctx) -{ - PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx; - - return ctx->processed_subop_count; -} - -uint64_t cls_get_features(cls_method_context_t hctx) -{ - PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx; - return ctx->pg->get_osdmap()->get_up_osd_features(); -} - -uint64_t cls_get_client_features(cls_method_context_t hctx) -{ - PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx; - return ctx->op->get_req()->get_connection()->get_features(); -} - -ceph_release_t cls_get_required_osd_release(cls_method_context_t hctx) -{ - PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx; - return ctx->pg->get_osdmap()->require_osd_release; -} - -ceph_release_t cls_get_min_compatible_client(cls_method_context_t hctx) -{ - PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx; - return ctx->pg->get_osdmap()->get_require_min_compat_client(); -} - void cls_cxx_subop_version(cls_method_context_t hctx, string *s) { if (!s) @@ -734,16 +146,6 @@ void cls_cxx_subop_version(cls_method_context_t hctx, string *s) *s = buf; } -int cls_get_snapset_seq(cls_method_context_t hctx, uint64_t *snap_seq) { - PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx; - if (!ctx->new_obs.exists || (ctx->new_obs.oi.is_whiteout() && - ctx->obc->ssc->snapset.clones.empty())) { - return -ENOENT; - } - *snap_seq = ctx->obc->ssc->snapset.seq; - return 0; -} - int cls_log(int level, const char *format, ...) { int size = 256; @@ -761,51 +163,3 @@ int cls_log(int level, const char *format, ...) size *= 2; } } - -int cls_cxx_chunk_write_and_set(cls_method_context_t hctx, int ofs, int len, - bufferlist *write_inbl, uint32_t op_flags, bufferlist *set_inbl, - int set_len) -{ - PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; - char cname[] = "cas"; - char method[] = "chunk_set"; - - vector ops(2); - ops[0].op.op = CEPH_OSD_OP_WRITE; - ops[0].op.extent.offset = ofs; - ops[0].op.extent.length = len; - ops[0].op.flags = op_flags; - ops[0].indata = *write_inbl; - - ops[1].op.op = CEPH_OSD_OP_CALL; - ops[1].op.cls.class_len = strlen(cname); - ops[1].op.cls.method_len = strlen(method); - ops[1].op.cls.indata_len = set_len; - ops[1].indata.append(cname, ops[1].op.cls.class_len); - ops[1].indata.append(method, ops[1].op.cls.method_len); - ops[1].indata.append(*set_inbl); - - return (*pctx)->pg->do_osd_ops(*pctx, ops); -} - -bool cls_has_chunk(cls_method_context_t hctx, string fp_oid) -{ - PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx; - if (!ctx->obc->obs.oi.has_manifest()) { - return false; - } - - for (auto &p : ctx->obc->obs.oi.manifest.chunk_map) { - if (p.second.oid.oid.name == fp_oid) { - return true; - } - } - - return false; -} - -uint64_t cls_get_osd_min_alloc_size(cls_method_context_t hctx) { - PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx; - - return ctx->pg->get_min_alloc_size(); -} diff --git a/src/objclass/objclass.h b/src/objclass/objclass.h index ed8d2c5251464..de43905e29fdc 100644 --- a/src/objclass/objclass.h +++ b/src/objclass/objclass.h @@ -14,6 +14,7 @@ #include "include/rados/objclass.h" struct obj_list_watch_response_t; +class PGLSFilter; extern "C" { #endif @@ -74,36 +75,6 @@ extern void class_fini(void); #ifdef __cplusplus } -class PGLSFilter { - CephContext* cct; -protected: - std::string xattr; -public: - PGLSFilter(); - virtual ~PGLSFilter(); - virtual bool filter(const hobject_t &obj, - const ceph::buffer::list& xattr_data) const = 0; - - /** - * Arguments passed from the RADOS client. Implementations must - * handle any encoding errors, and return an appropriate error code, - * or 0 on valid input. - */ - virtual int init(ceph::buffer::list::const_iterator ¶ms) = 0; - - /** - * xattr key, or empty string. If non-empty, this xattr will be fetched - * and the value passed into ::filter - */ - virtual const std::string& get_xattr() const { return xattr; } - - /** - * If true, objects without the named xattr (if xattr name is not empty) - * will be rejected without calling ::filter - */ - virtual bool reject_empty_xattr() const { return true; } -}; - // Classes expose a filter constructor that returns a subclass of PGLSFilter typedef PGLSFilter* (*cls_cxx_filter_factory_t)(); diff --git a/src/osd/ClassHandler.cc b/src/osd/ClassHandler.cc index 4f11e51f1116d..0f9f5111c8b49 100644 --- a/src/osd/ClassHandler.cc +++ b/src/osd/ClassHandler.cc @@ -257,15 +257,17 @@ ClassHandler::ClassFilter *ClassHandler::ClassData::register_cxx_filter( return &filter; } -ClassHandler::ClassMethod *ClassHandler::ClassData::_get_method(const char *mname) +ClassHandler::ClassMethod *ClassHandler::ClassData::_get_method( + const std::string& mname) { - map::iterator iter = methods_map.find(mname); - if (iter == methods_map.end()) - return NULL; - return &(iter->second); + if (auto iter = methods_map.find(mname); iter != methods_map.end()) { + return &(iter->second); + } else { + return nullptr; + } } -int ClassHandler::ClassData::get_method_flags(const char *mname) +int ClassHandler::ClassData::get_method_flags(const std::string& mname) { std::lock_guard l(handler->mutex); ClassMethod *method = _get_method(mname); @@ -329,6 +331,15 @@ int ClassHandler::ClassMethod::exec(cls_method_context_t ctx, bufferlist& indata ClassHandler& ClassHandler::get_instance() { +#ifdef WITH_SEASTAR + // the context is being used solely for: + // 1. random number generation (cls_gen_random_bytes) + // 2. accessing the configuration + // 3. logging + static CephContext cct; + static ClassHandler single(&cct); +#else static ClassHandler single(g_ceph_context); +#endif // WITH_SEASTAR return single; } diff --git a/src/osd/ClassHandler.h b/src/osd/ClassHandler.h index c80c4c0c47bc6..cd992e082979f 100644 --- a/src/osd/ClassHandler.h +++ b/src/osd/ClassHandler.h @@ -43,12 +43,9 @@ class ClassHandler struct ClassFilter { ClassData *cls = nullptr; std::string name; - cls_cxx_filter_factory_t fn; + cls_cxx_filter_factory_t fn = nullptr; void unregister(); - - ClassFilter() : fn(0) - {} }; struct ClassData { @@ -58,11 +55,11 @@ class ClassHandler CLASS_MISSING_DEPS, // missing dependencies CLASS_INITIALIZING, // calling init() right now CLASS_OPEN, // initialized, usable - } status; + } status = CLASS_UNKNOWN; std::string name; - ClassHandler *handler; - void *handle; + ClassHandler *handler = nullptr; + void *handle = nullptr; bool whitelisted = false; @@ -72,34 +69,30 @@ class ClassHandler std::set dependencies; /* our dependencies */ std::set missing_dependencies; /* only missing dependencies */ - ClassMethod *_get_method(const char *mname); - - ClassData() : status(CLASS_UNKNOWN), - handler(NULL), - handle(NULL) {} - ~ClassData() { } + ClassMethod *_get_method(const std::string& mname); - ClassMethod *register_method(const char *mname, int flags, cls_method_call_t func); - ClassMethod *register_cxx_method(const char *mname, int flags, cls_method_cxx_call_t func); + ClassMethod *register_method(const char *mname, + int flags, + cls_method_call_t func); + ClassMethod *register_cxx_method(const char *mname, + int flags, + cls_method_cxx_call_t func); void unregister_method(ClassMethod *method); - ClassFilter *register_cxx_filter( - const std::string &filter_name, - cls_cxx_filter_factory_t fn); + ClassFilter *register_cxx_filter(const std::string &filter_name, + cls_cxx_filter_factory_t fn); void unregister_filter(ClassFilter *method); - ClassMethod *get_method(const char *mname) { + ClassMethod *get_method(const std::string& mname) { std::lock_guard l(handler->mutex); return _get_method(mname); } - int get_method_flags(const char *mname); + int get_method_flags(const std::string& mname); - ClassFilter *get_filter(const std::string &filter_name) - { + ClassFilter *get_filter(const std::string &filter_name) { std::lock_guard l(handler->mutex); - std::map::iterator i = filters_map.find(filter_name); - if (i == filters_map.end()) { - return NULL; + if (auto i = filters_map.find(filter_name); i == filters_map.end()) { + return nullptr; } else { return &(i->second); } @@ -118,7 +111,7 @@ class ClassHandler ceph::mutex mutex = ceph::make_mutex("ClassHandler"); public: - explicit ClassHandler(CephContext *cct_) : cct(cct_) {} + explicit ClassHandler(CephContext *cct) : cct(cct) {} int open_all_classes(); int open_class(const std::string& cname, ClassData **pcls); diff --git a/src/osd/OSD.cc b/src/osd/OSD.cc index b99b670cfad12..40afda69d33ea 100644 --- a/src/osd/OSD.cc +++ b/src/osd/OSD.cc @@ -9961,7 +9961,7 @@ int OSD::init_op_flags(OpRequestRef& op) r = -EIO; return r; } - int flags = cls->get_method_flags(mname.c_str()); + int flags = cls->get_method_flags(mname); if (flags < 0) { if (flags == -ENOENT) r = -EOPNOTSUPP; diff --git a/src/osd/PrimaryLogPG.cc b/src/osd/PrimaryLogPG.cc index 7b01406e48c4e..e5a642c44c954 100644 --- a/src/osd/PrimaryLogPG.cc +++ b/src/osd/PrimaryLogPG.cc @@ -76,14 +76,6 @@ static ostream& _prefix(std::ostream *_dout, T *pg) { MEMPOOL_DEFINE_OBJECT_FACTORY(PrimaryLogPG, replicatedpg, osd); -PGLSFilter::PGLSFilter() : cct(nullptr) -{ -} - -PGLSFilter::~PGLSFilter() -{ -} - /** * The CopyCallback class defines an interface for completions to the * copy_start code. Users of the copy infrastructure must implement @@ -760,27 +752,6 @@ void PrimaryLogPG::maybe_force_recovery() maybe_kick_recovery(soid); } -class PGLSPlainFilter : public PGLSFilter { - string val; -public: - int init(bufferlist::const_iterator ¶ms) override - { - try { - decode(xattr, params); - decode(val, params); - } catch (buffer::error &e) { - return -EINVAL; - } - - return 0; - } - ~PGLSPlainFilter() override {} - bool filter(const hobject_t& obj, - const bufferlist& xattr_data) const override { - return xattr_data.contents_equal(val.c_str(), val.size()); - } -}; - bool PrimaryLogPG::pgls_filter(const PGLSFilter& filter, const hobject_t& sobj) { bufferlist bl; @@ -5685,7 +5656,7 @@ int PrimaryLogPG::do_osd_ops(OpContext *ctx, vector& ops) result = ClassHandler::get_instance().open_class(cname, &cls); ceph_assert(result == 0); // init_op_flags() already verified this works. - ClassHandler::ClassMethod *method = cls->get_method(mname.c_str()); + ClassHandler::ClassMethod *method = cls->get_method(mname); if (!method) { dout(10) << "call method " << cname << "." << mname << " does not exist" << dendl; result = -EOPNOTSUPP; diff --git a/src/osd/objclass.cc b/src/osd/objclass.cc new file mode 100644 index 0000000000000..2ac65fac5e238 --- /dev/null +++ b/src/osd/objclass.cc @@ -0,0 +1,661 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include +#include "common/ceph_context.h" +#include "common/ceph_releases.h" +#include "common/config.h" +#include "common/debug.h" + +#include "objclass/objclass.h" +#include "osd/PrimaryLogPG.h" + +#include "osd/ClassHandler.h" + +#include "auth/Crypto.h" +#include "common/armor.h" + +#define dout_context ClassHandler::get_instance().cct + + +int cls_call(cls_method_context_t hctx, const char *cls, const char *method, + char *indata, int datalen, + char **outdata, int *outdatalen) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + bufferlist idata; + vector nops(1); + OSDOp& op = nops[0]; + int r; + + op.op.op = CEPH_OSD_OP_CALL; + op.op.cls.class_len = strlen(cls); + op.op.cls.method_len = strlen(method); + op.op.cls.indata_len = datalen; + op.indata.append(cls, op.op.cls.class_len); + op.indata.append(method, op.op.cls.method_len); + op.indata.append(indata, datalen); + r = (*pctx)->pg->do_osd_ops(*pctx, nops); + if (r < 0) + return r; + + *outdata = (char *)malloc(op.outdata.length()); + if (!*outdata) + return -ENOMEM; + memcpy(*outdata, op.outdata.c_str(), op.outdata.length()); + *outdatalen = op.outdata.length(); + + return r; +} + +int cls_getxattr(cls_method_context_t hctx, const char *name, + char **outdata, int *outdatalen) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector nops(1); + OSDOp& op = nops[0]; + int r; + + op.op.op = CEPH_OSD_OP_GETXATTR; + op.op.xattr.name_len = strlen(name); + op.indata.append(name, op.op.xattr.name_len); + r = (*pctx)->pg->do_osd_ops(*pctx, nops); + if (r < 0) + return r; + + *outdata = (char *)malloc(op.outdata.length()); + if (!*outdata) + return -ENOMEM; + memcpy(*outdata, op.outdata.c_str(), op.outdata.length()); + *outdatalen = op.outdata.length(); + + return r; +} + +int cls_setxattr(cls_method_context_t hctx, const char *name, + const char *value, int val_len) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector nops(1); + OSDOp& op = nops[0]; + int r; + + op.op.op = CEPH_OSD_OP_SETXATTR; + op.op.xattr.name_len = strlen(name); + op.op.xattr.value_len = val_len; + op.indata.append(name, op.op.xattr.name_len); + op.indata.append(value, val_len); + r = (*pctx)->pg->do_osd_ops(*pctx, nops); + + return r; +} + +int cls_read(cls_method_context_t hctx, int ofs, int len, + char **outdata, int *outdatalen) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector ops(1); + ops[0].op.op = CEPH_OSD_OP_SYNC_READ; + ops[0].op.extent.offset = ofs; + ops[0].op.extent.length = len; + int r = (*pctx)->pg->do_osd_ops(*pctx, ops); + if (r < 0) + return r; + + *outdata = (char *)malloc(ops[0].outdata.length()); + if (!*outdata) + return -ENOMEM; + memcpy(*outdata, ops[0].outdata.c_str(), ops[0].outdata.length()); + *outdatalen = ops[0].outdata.length(); + + return *outdatalen; +} + +int cls_get_request_origin(cls_method_context_t hctx, entity_inst_t *origin) +{ + PrimaryLogPG::OpContext **pctx = static_cast(hctx); + *origin = (*pctx)->op->get_req()->get_orig_source_inst(); + return 0; +} + +int cls_cxx_create(cls_method_context_t hctx, bool exclusive) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector ops(1); + ops[0].op.op = CEPH_OSD_OP_CREATE; + ops[0].op.flags = (exclusive ? CEPH_OSD_OP_FLAG_EXCL : 0); + return (*pctx)->pg->do_osd_ops(*pctx, ops); +} + +int cls_cxx_remove(cls_method_context_t hctx) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector ops(1); + ops[0].op.op = CEPH_OSD_OP_DELETE; + return (*pctx)->pg->do_osd_ops(*pctx, ops); +} + +int cls_cxx_stat(cls_method_context_t hctx, uint64_t *size, time_t *mtime) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector ops(1); + int ret; + ops[0].op.op = CEPH_OSD_OP_STAT; + ret = (*pctx)->pg->do_osd_ops(*pctx, ops); + if (ret < 0) + return ret; + auto iter = ops[0].outdata.cbegin(); + utime_t ut; + uint64_t s; + try { + decode(s, iter); + decode(ut, iter); + } catch (buffer::error& err) { + return -EIO; + } + if (size) + *size = s; + if (mtime) + *mtime = ut.sec(); + return 0; +} + +int cls_cxx_stat2(cls_method_context_t hctx, uint64_t *size, ceph::real_time *mtime) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector ops(1); + int ret; + ops[0].op.op = CEPH_OSD_OP_STAT; + ret = (*pctx)->pg->do_osd_ops(*pctx, ops); + if (ret < 0) + return ret; + auto iter = ops[0].outdata.cbegin(); + real_time ut; + uint64_t s; + try { + decode(s, iter); + decode(ut, iter); + } catch (buffer::error& err) { + return -EIO; + } + if (size) + *size = s; + if (mtime) + *mtime = ut; + return 0; +} + +int cls_cxx_read2(cls_method_context_t hctx, int ofs, int len, + bufferlist *outbl, uint32_t op_flags) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector ops(1); + int ret; + ops[0].op.op = CEPH_OSD_OP_SYNC_READ; + ops[0].op.extent.offset = ofs; + ops[0].op.extent.length = len; + ops[0].op.flags = op_flags; + ret = (*pctx)->pg->do_osd_ops(*pctx, ops); + if (ret < 0) + return ret; + outbl->claim(ops[0].outdata); + return outbl->length(); +} + +int cls_cxx_write2(cls_method_context_t hctx, int ofs, int len, + bufferlist *inbl, uint32_t op_flags) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector ops(1); + ops[0].op.op = CEPH_OSD_OP_WRITE; + ops[0].op.extent.offset = ofs; + ops[0].op.extent.length = len; + ops[0].op.flags = op_flags; + ops[0].indata = *inbl; + return (*pctx)->pg->do_osd_ops(*pctx, ops); +} + +int cls_cxx_write_full(cls_method_context_t hctx, bufferlist *inbl) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector ops(1); + ops[0].op.op = CEPH_OSD_OP_WRITEFULL; + ops[0].op.extent.offset = 0; + ops[0].op.extent.length = inbl->length(); + ops[0].indata = *inbl; + return (*pctx)->pg->do_osd_ops(*pctx, ops); +} + +int cls_cxx_replace(cls_method_context_t hctx, int ofs, int len, bufferlist *inbl) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector ops(2); + ops[0].op.op = CEPH_OSD_OP_TRUNCATE; + ops[0].op.extent.offset = 0; + ops[0].op.extent.length = 0; + ops[1].op.op = CEPH_OSD_OP_WRITE; + ops[1].op.extent.offset = ofs; + ops[1].op.extent.length = len; + ops[1].indata = *inbl; + return (*pctx)->pg->do_osd_ops(*pctx, ops); +} + +int cls_cxx_truncate(cls_method_context_t hctx, int ofs) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector ops(1); + ops[0].op.op = CEPH_OSD_OP_TRUNCATE; + ops[0].op.extent.offset = ofs; + ops[0].op.extent.length = 0; + return (*pctx)->pg->do_osd_ops(*pctx, ops); +} + +int cls_cxx_getxattr(cls_method_context_t hctx, const char *name, + bufferlist *outbl) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector nops(1); + OSDOp& op = nops[0]; + int r; + + op.op.op = CEPH_OSD_OP_GETXATTR; + op.op.xattr.name_len = strlen(name); + op.indata.append(name, op.op.xattr.name_len); + r = (*pctx)->pg->do_osd_ops(*pctx, nops); + if (r < 0) + return r; + + outbl->claim(op.outdata); + return outbl->length(); +} + +int cls_cxx_getxattrs(cls_method_context_t hctx, map *attrset) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector nops(1); + OSDOp& op = nops[0]; + int r; + + op.op.op = CEPH_OSD_OP_GETXATTRS; + r = (*pctx)->pg->do_osd_ops(*pctx, nops); + if (r < 0) + return r; + + auto iter = op.outdata.cbegin(); + try { + decode(*attrset, iter); + } catch (buffer::error& err) { + return -EIO; + } + return 0; +} + +int cls_cxx_setxattr(cls_method_context_t hctx, const char *name, + bufferlist *inbl) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector nops(1); + OSDOp& op = nops[0]; + int r; + + op.op.op = CEPH_OSD_OP_SETXATTR; + op.op.xattr.name_len = strlen(name); + op.op.xattr.value_len = inbl->length(); + op.indata.append(name, op.op.xattr.name_len); + op.indata.append(*inbl); + r = (*pctx)->pg->do_osd_ops(*pctx, nops); + + return r; +} + +int cls_cxx_snap_revert(cls_method_context_t hctx, snapid_t snapid) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector ops(1); + ops[0].op.op = CEPH_OSD_OP_ROLLBACK; + ops[0].op.snap.snapid = snapid; + return (*pctx)->pg->do_osd_ops(*pctx, ops); +} + +int cls_cxx_map_get_all_vals(cls_method_context_t hctx, map* vals, + bool *more) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector ops(1); + OSDOp& op = ops[0]; + int ret; + + string start_after; + string filter_prefix; + uint64_t max = (uint64_t)-1; + + encode(start_after, op.indata); + encode(max, op.indata); + encode(filter_prefix, op.indata); + + op.op.op = CEPH_OSD_OP_OMAPGETVALS; + + ret = (*pctx)->pg->do_osd_ops(*pctx, ops); + if (ret < 0) + return ret; + + auto iter = op.outdata.cbegin(); + try { + decode(*vals, iter); + decode(*more, iter); + } catch (buffer::error& err) { + return -EIO; + } + return vals->size(); +} + +int cls_cxx_map_get_keys(cls_method_context_t hctx, const string &start_obj, + uint64_t max_to_get, set *keys, + bool *more) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector ops(1); + OSDOp& op = ops[0]; + int ret; + + encode(start_obj, op.indata); + encode(max_to_get, op.indata); + + op.op.op = CEPH_OSD_OP_OMAPGETKEYS; + + ret = (*pctx)->pg->do_osd_ops(*pctx, ops); + if (ret < 0) + return ret; + + auto iter = op.outdata.cbegin(); + try { + decode(*keys, iter); + decode(*more, iter); + } catch (buffer::error& err) { + return -EIO; + } + return keys->size(); +} + +int cls_cxx_map_get_vals(cls_method_context_t hctx, const string &start_obj, + const string &filter_prefix, uint64_t max_to_get, + map *vals, bool *more) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector ops(1); + OSDOp& op = ops[0]; + int ret; + + encode(start_obj, op.indata); + encode(max_to_get, op.indata); + encode(filter_prefix, op.indata); + + op.op.op = CEPH_OSD_OP_OMAPGETVALS; + + ret = (*pctx)->pg->do_osd_ops(*pctx, ops); + if (ret < 0) + return ret; + + auto iter = op.outdata.cbegin(); + try { + decode(*vals, iter); + decode(*more, iter); + } catch (buffer::error& err) { + return -EIO; + } + return vals->size(); +} + +int cls_cxx_map_read_header(cls_method_context_t hctx, bufferlist *outbl) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector ops(1); + OSDOp& op = ops[0]; + int ret; + op.op.op = CEPH_OSD_OP_OMAPGETHEADER; + ret = (*pctx)->pg->do_osd_ops(*pctx, ops); + if (ret < 0) + return ret; + + outbl->claim(op.outdata); + + return 0; +} + +int cls_cxx_map_get_val(cls_method_context_t hctx, const string &key, + bufferlist *outbl) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector ops(1); + OSDOp& op = ops[0]; + int ret; + + set k; + k.insert(key); + encode(k, op.indata); + + op.op.op = CEPH_OSD_OP_OMAPGETVALSBYKEYS; + ret = (*pctx)->pg->do_osd_ops(*pctx, ops); + if (ret < 0) + return ret; + + auto iter = op.outdata.cbegin(); + try { + map m; + + decode(m, iter); + map::iterator iter = m.begin(); + if (iter == m.end()) + return -ENOENT; + + *outbl = iter->second; + } catch (buffer::error& e) { + return -EIO; + } + return 0; +} + +int cls_cxx_map_set_val(cls_method_context_t hctx, const string &key, + bufferlist *inbl) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector ops(1); + OSDOp& op = ops[0]; + bufferlist& update_bl = op.indata; + map m; + m[key] = *inbl; + encode(m, update_bl); + + op.op.op = CEPH_OSD_OP_OMAPSETVALS; + + return (*pctx)->pg->do_osd_ops(*pctx, ops); +} + +int cls_cxx_map_set_vals(cls_method_context_t hctx, + const std::map *map) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector ops(1); + OSDOp& op = ops[0]; + bufferlist& update_bl = op.indata; + encode(*map, update_bl); + + op.op.op = CEPH_OSD_OP_OMAPSETVALS; + + return (*pctx)->pg->do_osd_ops(*pctx, ops); +} + +int cls_cxx_map_clear(cls_method_context_t hctx) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector ops(1); + OSDOp& op = ops[0]; + + op.op.op = CEPH_OSD_OP_OMAPCLEAR; + + return (*pctx)->pg->do_osd_ops(*pctx, ops); +} + +int cls_cxx_map_write_header(cls_method_context_t hctx, bufferlist *inbl) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector ops(1); + OSDOp& op = ops[0]; + op.indata.claim(*inbl); + + op.op.op = CEPH_OSD_OP_OMAPSETHEADER; + + return (*pctx)->pg->do_osd_ops(*pctx, ops); +} + +int cls_cxx_map_remove_range(cls_method_context_t hctx, + const std::string& key_begin, + const std::string& key_end) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector ops(1); + OSDOp& op = ops[0]; + bufferlist& update_bl = op.indata; + + ::encode(key_begin, update_bl); + ::encode(key_end, update_bl); + + op.op.op = CEPH_OSD_OP_OMAPRMKEYRANGE; + + return (*pctx)->pg->do_osd_ops(*pctx, ops); +} + +int cls_cxx_map_remove_key(cls_method_context_t hctx, const string &key) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector ops(1); + OSDOp& op = ops[0]; + bufferlist& update_bl = op.indata; + set to_rm; + to_rm.insert(key); + + encode(to_rm, update_bl); + + op.op.op = CEPH_OSD_OP_OMAPRMKEYS; + + return (*pctx)->pg->do_osd_ops(*pctx, ops); +} + +int cls_cxx_list_watchers(cls_method_context_t hctx, + obj_list_watch_response_t *watchers) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + vector nops(1); + OSDOp& op = nops[0]; + int r; + + op.op.op = CEPH_OSD_OP_LIST_WATCHERS; + r = (*pctx)->pg->do_osd_ops(*pctx, nops); + if (r < 0) + return r; + + auto iter = op.outdata.cbegin(); + try { + decode(*watchers, iter); + } catch (buffer::error& err) { + return -EIO; + } + return 0; +} + +uint64_t cls_current_version(cls_method_context_t hctx) +{ + PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx; + + return ctx->pg->get_last_user_version(); +} + + +int cls_current_subop_num(cls_method_context_t hctx) +{ + PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx; + + return ctx->processed_subop_count; +} + +uint64_t cls_get_features(cls_method_context_t hctx) +{ + PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx; + return ctx->pg->get_osdmap()->get_up_osd_features(); +} + +uint64_t cls_get_client_features(cls_method_context_t hctx) +{ + PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx; + return ctx->op->get_req()->get_connection()->get_features(); +} + +ceph_release_t cls_get_required_osd_release(cls_method_context_t hctx) +{ + PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx; + return ctx->pg->get_osdmap()->require_osd_release; +} + +ceph_release_t cls_get_min_compatible_client(cls_method_context_t hctx) +{ + PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx; + return ctx->pg->get_osdmap()->get_require_min_compat_client(); +} + +int cls_get_snapset_seq(cls_method_context_t hctx, uint64_t *snap_seq) { + PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx; + if (!ctx->new_obs.exists || (ctx->new_obs.oi.is_whiteout() && + ctx->obc->ssc->snapset.clones.empty())) { + return -ENOENT; + } + *snap_seq = ctx->obc->ssc->snapset.seq; + return 0; +} + +int cls_cxx_chunk_write_and_set(cls_method_context_t hctx, int ofs, int len, + bufferlist *write_inbl, uint32_t op_flags, bufferlist *set_inbl, + int set_len) +{ + PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx; + char cname[] = "cas"; + char method[] = "chunk_set"; + + vector ops(2); + ops[0].op.op = CEPH_OSD_OP_WRITE; + ops[0].op.extent.offset = ofs; + ops[0].op.extent.length = len; + ops[0].op.flags = op_flags; + ops[0].indata = *write_inbl; + + ops[1].op.op = CEPH_OSD_OP_CALL; + ops[1].op.cls.class_len = strlen(cname); + ops[1].op.cls.method_len = strlen(method); + ops[1].op.cls.indata_len = set_len; + ops[1].indata.append(cname, ops[1].op.cls.class_len); + ops[1].indata.append(method, ops[1].op.cls.method_len); + ops[1].indata.append(*set_inbl); + + return (*pctx)->pg->do_osd_ops(*pctx, ops); +} + +bool cls_has_chunk(cls_method_context_t hctx, string fp_oid) +{ + PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx; + if (!ctx->obc->obs.oi.has_manifest()) { + return false; + } + + for (auto &p : ctx->obc->obs.oi.manifest.chunk_map) { + if (p.second.oid.oid.name == fp_oid) { + return true; + } + } + + return false; +} + +uint64_t cls_get_osd_min_alloc_size(cls_method_context_t hctx) { + PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx; + + return ctx->pg->get_min_alloc_size(); +} diff --git a/src/osd/osd_types.cc b/src/osd/osd_types.cc index 37166a2386e4a..e2bcb31e314f5 100644 --- a/src/osd/osd_types.cc +++ b/src/osd/osd_types.cc @@ -6692,3 +6692,28 @@ void init_pg_ondisk( encode(struct_v, values[string(infover_key)]); t.omap_setkeys(coll, pgmeta_oid, values); } + +PGLSFilter::PGLSFilter() : cct(nullptr) +{ +} + +PGLSFilter::~PGLSFilter() +{ +} + +int PGLSPlainFilter::init(ceph::bufferlist::const_iterator ¶ms) +{ + try { + decode(xattr, params); + decode(val, params); + } catch (buffer::error &e) { + return -EINVAL; + } + return 0; +} + +bool PGLSPlainFilter::filter(const hobject_t& obj, + const ceph::bufferlist& xattr_data) const +{ + return xattr_data.contents_equal(val.c_str(), val.size()); +} diff --git a/src/osd/osd_types.h b/src/osd/osd_types.h index 895f4a32bd1d3..6bee9ad550eb0 100644 --- a/src/osd/osd_types.h +++ b/src/osd/osd_types.h @@ -6104,4 +6104,45 @@ struct omap_stat_t { int64_t omap_keys; }; +// filter for pg listings +class PGLSFilter { + CephContext* cct; +protected: + std::string xattr; +public: + PGLSFilter(); + virtual ~PGLSFilter(); + virtual bool filter(const hobject_t &obj, + const ceph::buffer::list& xattr_data) const = 0; + + /** + * Arguments passed from the RADOS client. Implementations must + * handle any encoding errors, and return an appropriate error code, + * or 0 on valid input. + */ + virtual int init(ceph::buffer::list::const_iterator ¶ms) = 0; + + /** + * xattr key, or empty string. If non-empty, this xattr will be fetched + * and the value passed into ::filter + */ + virtual const std::string& get_xattr() const { return xattr; } + + /** + * If true, objects without the named xattr (if xattr name is not empty) + * will be rejected without calling ::filter + */ + virtual bool reject_empty_xattr() const { return true; } +}; + +class PGLSPlainFilter : public PGLSFilter { + std::string val; +public: + int init(ceph::bufferlist::const_iterator ¶ms) override; + ~PGLSPlainFilter() override {} + bool filter(const hobject_t& obj, + const ceph::bufferlist& xattr_data) const override; +}; + + #endif