diff options
Diffstat (limited to 'src/crimson/osd/objclass.cc')
-rw-r--r-- | src/crimson/osd/objclass.cc | 584 |
1 files changed, 584 insertions, 0 deletions
diff --git a/src/crimson/osd/objclass.cc b/src/crimson/osd/objclass.cc new file mode 100644 index 000000000..4cc9d7336 --- /dev/null +++ b/src/crimson/osd/objclass.cc @@ -0,0 +1,584 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include <cstdarg> +#include <cstring> +#include <boost/container/small_vector.hpp> +#include "common/ceph_context.h" +#include "common/ceph_releases.h" +#include "common/config.h" +#include "crimson/common/config_proxy.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" + +using std::map; +using std::string; + +#define dout_context ClassHandler::get_instance().cct + +static constexpr int dout_subsys = ceph_subsys_objclass; + +static inline int execute_osd_op(cls_method_context_t hctx, OSDOp& op) +{ + // we can expect the memory under `ret` will be still fine after + // executing the osd op as we're running inside `seastar::thread` + // created for us by `seastar::async` in `::do_op_call()`. + int ret = 0; + using osd_op_errorator = crimson::osd::OpsExecuter::osd_op_errorator; + reinterpret_cast<crimson::osd::OpsExecuter*>(hctx)->execute_op(op) + .handle_error_interruptible( + osd_op_errorator::all_same_way([&ret] (const std::error_code& err) { + assert(err.value() > 0); + ret = -err.value(); + return seastar::now(); + })).get(); // we're blocking here which requires `seastar::thread`. + return ret; +} + +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) +{ + assert(origin); + + try { + const auto& message = \ + reinterpret_cast<crimson::osd::OpsExecuter*>(hctx)->get_message(); + *origin = message.get_orig_source_inst(); + return 0; + } catch (crimson::osd::error& e) { + return -e.code().value(); + } +} + +int cls_cxx_create(cls_method_context_t hctx, const bool exclusive) +{ + OSDOp op{CEPH_OSD_OP_CREATE}; + op.op.flags = (exclusive ? CEPH_OSD_OP_FLAG_EXCL : 0); + return execute_osd_op(hctx, op); +} + +int cls_cxx_remove(cls_method_context_t hctx) +{ + OSDOp op{CEPH_OSD_OP_DELETE}; + return execute_osd_op(hctx, op); +} + +int cls_cxx_stat(cls_method_context_t hctx, uint64_t *size, time_t *mtime) +{ + OSDOp op{CEPH_OSD_OP_STAT}; + if (const auto ret = execute_osd_op(hctx, op); ret < 0) { + return ret; + } + 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) +{ + OSDOp op{CEPH_OSD_OP_STAT}; + if (const int ret = execute_osd_op(hctx, op); ret < 0) { + return ret; + } + uint64_t dummy_size; + real_time dummy_mtime; + uint64_t& out_size = size ? *size : dummy_size; + real_time& out_mtime = mtime ? *mtime : dummy_mtime; + try { + auto iter = op.outdata.cbegin(); + decode(out_size, iter); + decode(out_mtime, iter); + return 0; + } catch (buffer::error& err) { + return -EIO; + } +} + +int cls_cxx_read2(cls_method_context_t hctx, + int ofs, + int len, + bufferlist *outbl, + uint32_t op_flags) +{ + OSDOp op{CEPH_OSD_OP_SYNC_READ}; + op.op.extent.offset = ofs; + op.op.extent.length = len; + op.op.flags = op_flags; + if (const auto ret = execute_osd_op(hctx, op); ret < 0) { + return ret; + } + *outbl = std::move(op.outdata); + return outbl->length(); +} + +int cls_cxx_write2(cls_method_context_t hctx, + int ofs, + int len, + bufferlist *inbl, + uint32_t op_flags) +{ + OSDOp op{CEPH_OSD_OP_WRITE}; + op.op.extent.offset = ofs; + op.op.extent.length = len; + op.op.flags = op_flags; + op.indata = *inbl; + return execute_osd_op(hctx, op); +} + +int cls_cxx_write_full(cls_method_context_t hctx, bufferlist * const inbl) +{ + OSDOp op{CEPH_OSD_OP_WRITEFULL}; + op.op.extent.offset = 0; + op.op.extent.length = inbl->length(); + op.indata = *inbl; + return execute_osd_op(hctx, op); +} + +int cls_cxx_replace(cls_method_context_t hctx, + int ofs, + int len, + bufferlist *inbl) +{ + { + OSDOp top{CEPH_OSD_OP_TRUNCATE}; + top.op.extent.offset = 0; + top.op.extent.length = 0; + if (const auto ret = execute_osd_op(hctx, top); ret < 0) { + return ret; + } + } + + { + OSDOp wop{CEPH_OSD_OP_WRITE}; + wop.op.extent.offset = ofs; + wop.op.extent.length = len; + wop.indata = *inbl; + if (const auto ret = execute_osd_op(hctx, wop); ret < 0) { + return ret; + } + } + return 0; +} + +int cls_cxx_truncate(cls_method_context_t hctx, int ofs) +{ + OSDOp op{CEPH_OSD_OP_TRUNCATE}; + op.op.extent.offset = ofs; + op.op.extent.length = 0; + return execute_osd_op(hctx, op); +} + +int cls_cxx_write_zero(cls_method_context_t hctx, int offset, int len) +{ + OSDOp op{CEPH_OSD_OP_ZERO}; + op.op.extent.offset = offset; + op.op.extent.length = len; + return execute_osd_op(hctx, op); +} + +int cls_cxx_getxattr(cls_method_context_t hctx, + const char *name, + bufferlist *outbl) +{ + OSDOp op{CEPH_OSD_OP_GETXATTR}; + op.op.xattr.name_len = strlen(name); + op.indata.append(name, op.op.xattr.name_len); + if (const auto ret = execute_osd_op(hctx, op); ret < 0) { + return ret; + } + *outbl = std::move(op.outdata); + return outbl->length(); +} + +int cls_cxx_getxattrs(cls_method_context_t hctx, + map<string, bufferlist> *attrset) +{ + OSDOp op{CEPH_OSD_OP_GETXATTRS}; + if (const int ret = execute_osd_op(hctx, op); ret < 0) { + return ret; + } + try { + auto iter = op.outdata.cbegin(); + 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) +{ + OSDOp 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); + return execute_osd_op(hctx, op); +} + +int cls_cxx_snap_revert(cls_method_context_t hctx, snapid_t snapid) +{ + OSDOp op{CEPH_OSD_OP_ROLLBACK}; + op.op.snap.snapid = snapid; + return execute_osd_op(hctx, op); +} + +int cls_cxx_map_get_all_vals(cls_method_context_t hctx, + map<string, bufferlist>* vals, + bool *more) +{ + return 0; +} + +int cls_cxx_map_get_keys(cls_method_context_t hctx, + const std::string& start_obj, + const uint64_t max_to_get, + std::set<std::string>* const keys, + bool* const more) +{ + OSDOp op{CEPH_OSD_OP_OMAPGETKEYS}; + encode(start_obj, op.indata); + encode(max_to_get, op.indata); + if (const auto ret = execute_osd_op(hctx, op); ret < 0) { + return ret; + } + try { + auto iter = op.outdata.cbegin(); + decode(*keys, iter); + decode(*more, iter); + } catch (buffer::error&) { + return -EIO; + } + return keys->size(); +} + +int cls_cxx_map_get_vals(cls_method_context_t hctx, + const std::string& start_obj, + const std::string& filter_prefix, + const uint64_t max_to_get, + std::map<std::string, ceph::bufferlist> *vals, + bool* const more) +{ + OSDOp op{CEPH_OSD_OP_OMAPGETVALS}; + encode(start_obj, op.indata); + encode(max_to_get, op.indata); + encode(filter_prefix, op.indata); + if (const auto ret = execute_osd_op(hctx, op); ret < 0) { + return ret; + } + try { + auto iter = op.outdata.cbegin(); + decode(*vals, iter); + decode(*more, iter); + } catch (buffer::error&) { + return -EIO; + } + return vals->size(); +} + +int cls_cxx_map_get_vals_by_keys(cls_method_context_t hctx, + const std::set<std::string> &keys, + std::map<std::string, ceph::bufferlist> *vals) +{ + OSDOp op{CEPH_OSD_OP_OMAPGETVALSBYKEYS}; + encode(keys, op.indata); + if (const auto ret = execute_osd_op(hctx, op); ret < 0) { + return ret; + } + try { + auto iter = op.outdata.cbegin(); + decode(*vals, iter); + } catch (buffer::error&) { + return -EIO; + } + return 0; +} + +int cls_cxx_map_read_header(cls_method_context_t hctx, bufferlist *outbl) +{ + OSDOp op{CEPH_OSD_OP_OMAPGETHEADER}; + if (const auto ret = execute_osd_op(hctx, op); ret < 0) { + return ret; + } + *outbl = std::move(op.outdata); + return 0; +} + +int cls_cxx_map_get_val(cls_method_context_t hctx, + const string &key, + bufferlist *outbl) +{ + OSDOp op{CEPH_OSD_OP_OMAPGETVALSBYKEYS}; + { + std::set<std::string> k{key}; + encode(k, op.indata); + } + if (const auto ret = execute_osd_op(hctx, op); ret < 0) { + return ret; + } + std::map<std::string, ceph::bufferlist> m; + try { + auto iter = op.outdata.cbegin(); + decode(m, iter); + } catch (buffer::error&) { + return -EIO; + } + if (auto iter = std::begin(m); iter != std::end(m)) { + *outbl = std::move(iter->second); + return 0; + } else { + return -ENOENT; + } +} + +int cls_cxx_map_set_val(cls_method_context_t hctx, + const string &key, + bufferlist *inbl) +{ + OSDOp op{CEPH_OSD_OP_OMAPSETVALS}; + { + std::map<std::string, ceph::bufferlist> m; + m[key] = *inbl; + encode(m, op.indata); + } + return execute_osd_op(hctx, op); +} + +int cls_cxx_map_set_vals(cls_method_context_t hctx, + const std::map<string, ceph::bufferlist> *map) +{ + OSDOp op{CEPH_OSD_OP_OMAPSETVALS}; + encode(*map, op.indata); + return execute_osd_op(hctx, op); +} + +int cls_cxx_map_clear(cls_method_context_t hctx) +{ + OSDOp op{CEPH_OSD_OP_OMAPCLEAR}; + return execute_osd_op(hctx, op); +} + +int cls_cxx_map_write_header(cls_method_context_t hctx, bufferlist *inbl) +{ + OSDOp op{CEPH_OSD_OP_OMAPSETHEADER}; + op.indata = std::move(*inbl); + return execute_osd_op(hctx, op); +} + +int cls_cxx_map_remove_range(cls_method_context_t hctx, + const std::string& key_begin, + const std::string& key_end) +{ + OSDOp op{CEPH_OSD_OP_OMAPRMKEYRANGE}; + encode(key_begin, op.indata); + encode(key_end, op.indata); + return execute_osd_op(hctx, op); +} + +int cls_cxx_map_remove_key(cls_method_context_t hctx, const string &key) +{ + OSDOp op{CEPH_OSD_OP_OMAPRMKEYS}; + std::vector<string> to_rm{key}; + encode(to_rm, op.indata); + return execute_osd_op(hctx, op); +} + +int cls_cxx_list_watchers(cls_method_context_t hctx, + obj_list_watch_response_t *watchers) +{ + OSDOp op{CEPH_OSD_OP_LIST_WATCHERS}; + if (const auto ret = execute_osd_op(hctx, op); ret < 0) { + return ret; + } + + try { + auto iter = op.outdata.cbegin(); + decode(*watchers, iter); + } catch (buffer::error&) { + return -EIO; + } + return 0; +} + +uint64_t cls_current_version(cls_method_context_t hctx) +{ + auto* ox = reinterpret_cast<crimson::osd::OpsExecuter*>(hctx); + return ox->get_last_user_version(); +} + + +int cls_current_subop_num(cls_method_context_t hctx) +{ + auto* ox = reinterpret_cast<crimson::osd::OpsExecuter*>(hctx); + // in contrast to classical OSD, crimson doesn't count OP_CALL and + // OP_STAT which seems fine regarding how the plugins we take care + // about use this part of API. + return ox->get_processed_rw_ops_num(); +} + +uint64_t cls_get_features(cls_method_context_t hctx) +{ + return 0; +} + +uint64_t cls_get_client_features(cls_method_context_t hctx) +{ + try { + const auto& message = \ + reinterpret_cast<crimson::osd::OpsExecuter*>(hctx)->get_message(); + return message.get_features(); + } catch (crimson::osd::error& e) { + return -e.code().value(); + } +} + +uint64_t cls_get_pool_stripe_width(cls_method_context_t hctx) +{ + auto* ox = reinterpret_cast<crimson::osd::OpsExecuter*>(hctx); + return ox->get_pool_stripe_width(); +} + +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; +} + +const ConfigProxy& cls_get_config(cls_method_context_t hctx) +{ + return crimson::common::local_conf(); +} + +const object_info_t& cls_get_object_info(cls_method_context_t hctx) +{ + return reinterpret_cast<crimson::osd::OpsExecuter*>(hctx)->get_object_info(); +} + +int cls_get_snapset_seq(cls_method_context_t hctx, uint64_t *snap_seq) +{ + auto* ox = reinterpret_cast<crimson::osd::OpsExecuter*>(hctx); + auto obc = ox->get_obc(); + if (!obc->obs.exists || + (obc->obs.oi.is_whiteout() && + obc->ssc->snapset.clones.empty())) { + return -ENOENT; + } + *snap_seq = 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) +{ + return 0; +} + +int cls_get_manifest_ref_count(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; +} + +int cls_cxx_gather(cls_method_context_t hctx, const std::set<std::string> &src_objs, const std::string& pool, + const char *cls, const char *method, bufferlist& inbl) +{ + return 0; +} + +int cls_cxx_get_gathered_data(cls_method_context_t hctx, std::map<std::string, bufferlist> *results) +{ + return 0; +} + +// although at first glance the implementation looks the same as in +// the classical OSD, it's different b/c of how the dout macro expands. +int cls_log(int level, const char *format, ...) +{ + size_t size = 256; + va_list ap; + while (1) { + boost::container::small_vector<char, 256> buf(size); + va_start(ap, format); + int n = vsnprintf(buf.data(), size, format, ap); + va_end(ap); +#define MAX_SIZE 8196UL + if ((n > -1 && static_cast<size_t>(n) < size) || size > MAX_SIZE) { + dout(ceph::dout::need_dynamic(level)) << buf.data() << dendl; + return n; + } + size *= 2; + } +} |