// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #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" #include "common/armor.h" static constexpr int dout_subsys = ceph_subsys_objclass; static ClassHandler *ch; void cls_initialize(ClassHandler *h) { ch = h; } void cls_finalize() { ch = NULL; } void *cls_alloc(size_t size) { return malloc(size); } void cls_free(void *p) { free(p); } int cls_register(const char *name, cls_handle_t *handle) { ClassHandler::ClassData *cls = ch->register_class(name); *handle = (cls_handle_t)cls; return (cls != NULL); } int cls_unregister(cls_handle_t handle) { ClassHandler::ClassData *cls = (ClassHandler::ClassData *)handle; ch->unregister_class(cls); return 1; } int cls_register_method(cls_handle_t hclass, const char *method, int flags, cls_method_call_t class_call, cls_method_handle_t *handle) { if (!(flags & (CLS_METHOD_RD | CLS_METHOD_WR))) return -EINVAL; ClassHandler::ClassData *cls = (ClassHandler::ClassData *)hclass; cls_method_handle_t hmethod =(cls_method_handle_t)cls->register_method(method, flags, class_call); if (handle) *handle = hmethod; return (hmethod != NULL); } int cls_register_cxx_method(cls_handle_t hclass, const char *method, int flags, cls_method_cxx_call_t class_call, cls_method_handle_t *handle) { ClassHandler::ClassData *cls = (ClassHandler::ClassData *)hclass; cls_method_handle_t hmethod = (cls_method_handle_t)cls->register_cxx_method(method, flags, class_call); if (handle) *handle = hmethod; return (hmethod != NULL); } int cls_unregister_method(cls_method_handle_t handle) { ClassHandler::ClassMethod *method = (ClassHandler::ClassMethod *)handle; method->unregister(); return 1; } int cls_register_cxx_filter(cls_handle_t hclass, const std::string &filter_name, cls_cxx_filter_factory_t fn, cls_filter_handle_t *handle) { ClassHandler::ClassData *cls = (ClassHandler::ClassData *)hclass; cls_filter_handle_t hfilter = (cls_filter_handle_t)cls->register_cxx_filter(filter_name, fn); if (handle) { *handle = hfilter; } return (hfilter != NULL); } void cls_unregister_filter(cls_filter_handle_t handle) { ClassHandler::ClassFilter *filter = (ClassHandler::ClassFilter *)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.indata.append(name); op.op.xattr.name_len = strlen(name); 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.indata.append(name); op.indata.append(value); op.op.xattr.name_len = strlen(name); op.op.xattr.value_len = 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; bufferlist::iterator iter = ops[0].outdata.begin(); 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; bufferlist::iterator iter = ops[0].outdata.begin(); 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_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.indata.append(name); op.op.xattr.name_len = strlen(name); 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; bufferlist::iterator iter = op.outdata.begin(); 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.indata.append(name); op.indata.append(*inbl); op.op.xattr.name_len = strlen(name); op.op.xattr.value_len = inbl->length(); 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; bufferlist::iterator iter = op.outdata.begin(); 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; bufferlist::iterator iter = op.outdata.begin(); 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; bufferlist::iterator iter = op.outdata.begin(); 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; bufferlist::iterator iter = op.outdata.begin(); 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_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; bufferlist::iterator iter = op.outdata.begin(); try { ::decode(*watchers, iter); } catch (buffer::error& err) { return -EIO; } return 0; } int cls_gen_random_bytes(char *buf, int size) { return get_random_bytes(buf, size); } int cls_gen_rand_base64(char *dest, int size) /* size should be the required string size + 1 */ { char buf[size]; char tmp_dest[size + 4]; /* so that there's space for the extra '=' characters, and some */ int ret; ret = cls_gen_random_bytes(buf, sizeof(buf)); if (ret < 0) { lgeneric_derr(ch->cct) << "cannot get random bytes: " << ret << dendl; return -1; } ret = ceph_armor(tmp_dest, &tmp_dest[sizeof(tmp_dest)], (const char *)buf, ((const char *)buf) + ((size - 1) * 3 + 4 - 1) / 4); if (ret < 0) { lgeneric_derr(ch->cct) << "ceph_armor failed" << dendl; return -1; } tmp_dest[ret] = '\0'; memcpy(dest, tmp_dest, size); dest[size-1] = '\0'; return 0; } uint64_t cls_current_version(cls_method_context_t hctx) { PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx; return ctx->pg->info.last_user_version; } int cls_current_subop_num(cls_method_context_t hctx) { PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx; return ctx->current_osd_subop_num; } 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(); } void cls_cxx_subop_version(cls_method_context_t hctx, string *s) { if (!s) return; char buf[32]; uint64_t ver = cls_current_version(hctx); int subop_num = cls_current_subop_num(hctx); snprintf(buf, sizeof(buf), "%lld.%d", (long long)ver, subop_num); *s = buf; } int cls_log(int level, const char *format, ...) { int size = 256; va_list ap; while (1) { char buf[size]; va_start(ap, format); int n = vsnprintf(buf, size, format, ap); va_end(ap); #define MAX_SIZE 8196 if ((n > -1 && n < size) || size > MAX_SIZE) { ldout(ch->cct, level) << buf << dendl; return n; } size *= 2; } }