summaryrefslogtreecommitdiffstats
path: root/src/cls/cas
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/cls/cas/cls_cas.cc265
-rw-r--r--src/cls/cas/cls_cas_client.cc62
-rw-r--r--src/cls/cas/cls_cas_client.h13
-rw-r--r--src/cls/cas/cls_cas_ops.h142
4 files changed, 482 insertions, 0 deletions
diff --git a/src/cls/cas/cls_cas.cc b/src/cls/cas/cls_cas.cc
new file mode 100644
index 00000000..c6a7b9b5
--- /dev/null
+++ b/src/cls/cas/cls_cas.cc
@@ -0,0 +1,265 @@
+// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include <errno.h>
+
+#include "objclass/objclass.h"
+#include "cls_cas_ops.h"
+
+#include "include/compat.h"
+#include "osd/osd_types.h"
+
+CLS_VER(1,0)
+CLS_NAME(cas)
+
+struct chunk_obj_refcount;
+
+static int chunk_read_refcount(cls_method_context_t hctx, chunk_obj_refcount *objr)
+{
+ bufferlist bl;
+ objr->refs.clear();
+ int ret = cls_cxx_getxattr(hctx, CHUNK_REFCOUNT_ATTR, &bl);
+ if (ret == -ENODATA) {
+ return 0;
+ }
+ if (ret < 0)
+ return ret;
+
+ try {
+ auto iter = bl.cbegin();
+ decode(*objr, iter);
+ } catch (buffer::error& err) {
+ CLS_LOG(0, "ERROR: chunk_read_refcount(): failed to decode refcount entry\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int chunk_set_refcount(cls_method_context_t hctx, const struct chunk_obj_refcount& objr)
+{
+ bufferlist bl;
+
+ encode(objr, bl);
+
+ int ret = cls_cxx_setxattr(hctx, CHUNK_REFCOUNT_ATTR, &bl);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int cls_rc_chunk_refcount_get(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
+{
+ auto in_iter = in->cbegin();
+
+ cls_chunk_refcount_get_op op;
+ try {
+ decode(op, in_iter);
+ } catch (buffer::error& err) {
+ CLS_LOG(1, "ERROR: cls_rc_refcount_get(): failed to decode entry\n");
+ return -EINVAL;
+ }
+
+ chunk_obj_refcount objr;
+ int ret = chunk_read_refcount(hctx, &objr);
+ if (ret < 0)
+ return ret;
+
+ CLS_LOG(10, "cls_rc_chunk_refcount_get() oid=%s\n", op.source.oid.name.c_str());
+
+ objr.refs.insert(op.source);
+
+ ret = chunk_set_refcount(hctx, objr);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int cls_rc_chunk_refcount_put(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
+{
+ auto in_iter = in->cbegin();
+
+ cls_chunk_refcount_put_op op;
+ try {
+ decode(op, in_iter);
+ } catch (buffer::error& err) {
+ CLS_LOG(1, "ERROR: cls_rc_chunk_refcount_put(): failed to decode entry\n");
+ return -EINVAL;
+ }
+
+ chunk_obj_refcount objr;
+ int ret = chunk_read_refcount(hctx, &objr);
+ if (ret < 0)
+ return ret;
+
+ if (objr.refs.empty()) {// shouldn't happen!
+ CLS_LOG(0, "ERROR: cls_rc_chunk_refcount_put() was called without any references!\n");
+ return -EINVAL;
+ }
+
+ CLS_LOG(10, "cls_rc_chunk_refcount_put() oid=%s\n", op.source.oid.name.c_str());
+
+ bool found = false;
+ for (auto &p : objr.refs) {
+ if (p == op.source) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ return 0;
+ }
+
+ auto p = objr.refs.find(op.source);
+ objr.refs.erase(p);
+
+ if (objr.refs.empty()) {
+ return cls_cxx_remove(hctx);
+ }
+
+ ret = chunk_set_refcount(hctx, objr);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int cls_rc_chunk_refcount_set(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
+{
+ auto in_iter = in->cbegin();
+
+ cls_chunk_refcount_set_op op;
+ try {
+ decode(op, in_iter);
+ } catch (buffer::error& err) {
+ CLS_LOG(1, "ERROR: cls_chunk_refcount_set(): failed to decode entry\n");
+ return -EINVAL;
+ }
+
+ if (!op.refs.size()) {
+ return cls_cxx_remove(hctx);
+ }
+
+ chunk_obj_refcount objr;
+ objr.refs = op.refs;
+
+ int ret = chunk_set_refcount(hctx, objr);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int cls_rc_chunk_refcount_read(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
+{
+ chunk_obj_refcount objr;
+
+ cls_chunk_refcount_read_ret read_ret;
+ int ret = chunk_read_refcount(hctx, &objr);
+ if (ret < 0)
+ return ret;
+
+ for (auto &p : objr.refs) {
+ read_ret.refs.insert(p);
+ }
+
+ encode(read_ret, *out);
+
+ return 0;
+}
+
+static int cls_rc_write_or_get(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
+{
+ auto in_iter = in->cbegin();
+ hobject_t src_obj;
+ bufferlist indata, outdata;
+ ceph_osd_op op;
+ try {
+ decode (op, in_iter);
+ decode(src_obj, in_iter);
+ in_iter.copy(op.extent.length, indata);
+ }
+ catch (buffer::error& e) {
+ return -EINVAL;
+ }
+
+ CLS_LOG(10, " offset: %llu length: %llu \n",
+ static_cast<long long unsigned>(op.extent.offset),
+ static_cast<long long unsigned>(op.extent.length));
+ chunk_obj_refcount objr;
+ int ret = chunk_read_refcount(hctx, &objr);
+ if (ret == -ENOENT) {
+ objr.refs.insert(src_obj);
+ bufferlist set_bl;
+ encode(objr, set_bl);
+ ret = cls_cxx_chunk_write_and_set(hctx, op.extent.offset, op.extent.length, &indata, op.flags,
+ &set_bl, set_bl.length());
+ if (ret < 0)
+ return ret;
+
+ return 0;
+ }
+
+ objr.refs.insert(src_obj);
+ ret = chunk_set_refcount(hctx, objr);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+
+static int cls_rc_has_chunk(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
+{
+ auto in_iter = in->cbegin();
+ string fp_oid;
+ bufferlist indata, outdata;
+ try {
+ decode (fp_oid, in_iter);
+ }
+ catch (buffer::error& e) {
+ return -EINVAL;
+ }
+ CLS_LOG(10, " fp_oid: %s \n", fp_oid.c_str());
+
+ bool ret = cls_has_chunk(hctx, fp_oid);
+ if (ret) {
+ return 0;
+ }
+ return -ENOENT;
+}
+
+CLS_INIT(cas)
+{
+ CLS_LOG(1, "Loaded cas class!");
+
+ cls_handle_t h_class;
+ cls_method_handle_t h_cas_write_or_get;
+ cls_method_handle_t h_chunk_refcount_get;
+ cls_method_handle_t h_chunk_refcount_put;
+ cls_method_handle_t h_chunk_refcount_set;
+ cls_method_handle_t h_chunk_refcount_read;
+ cls_method_handle_t h_chunk_has_chunk;
+
+ cls_register("cas", &h_class);
+
+ /* chunk refcount */
+ cls_register_cxx_method(h_class, "chunk_get", CLS_METHOD_RD | CLS_METHOD_WR, cls_rc_chunk_refcount_get,
+ &h_chunk_refcount_get);
+ cls_register_cxx_method(h_class, "chunk_put", CLS_METHOD_RD | CLS_METHOD_WR, cls_rc_chunk_refcount_put,
+ &h_chunk_refcount_put);
+ cls_register_cxx_method(h_class, "chunk_set", CLS_METHOD_RD | CLS_METHOD_WR, cls_rc_chunk_refcount_set,
+ &h_chunk_refcount_set);
+ cls_register_cxx_method(h_class, "chunk_read", CLS_METHOD_RD, cls_rc_chunk_refcount_read,
+ &h_chunk_refcount_read);
+ cls_register_cxx_method(h_class, "cas_write_or_get", CLS_METHOD_RD | CLS_METHOD_WR, cls_rc_write_or_get,
+ &h_cas_write_or_get);
+ cls_register_cxx_method(h_class, "has_chunk", CLS_METHOD_RD, cls_rc_has_chunk,
+ &h_chunk_has_chunk);
+
+ return;
+}
+
diff --git a/src/cls/cas/cls_cas_client.cc b/src/cls/cas/cls_cas_client.cc
new file mode 100644
index 00000000..b041641f
--- /dev/null
+++ b/src/cls/cas/cls_cas_client.cc
@@ -0,0 +1,62 @@
+#include <errno.h>
+
+#include "cls/cas/cls_cas_client.h"
+#include "cls/cas/cls_cas_ops.h"
+#include "include/rados/librados.hpp"
+
+using namespace librados;
+
+void cls_chunk_refcount_get(librados::ObjectWriteOperation& op, const hobject_t& soid)
+{
+ bufferlist in;
+ cls_chunk_refcount_get_op call;
+ call.source = soid;
+ encode(call, in);
+ op.exec("cas", "chunk_get", in);
+}
+
+void cls_chunk_refcount_put(librados::ObjectWriteOperation& op, const hobject_t& soid)
+{
+ bufferlist in;
+ cls_chunk_refcount_put_op call;
+ call.source = soid;
+ encode(call, in);
+ op.exec("cas", "chunk_put", in);
+}
+
+void cls_chunk_refcount_set(librados::ObjectWriteOperation& op, set<hobject_t>& refs)
+{
+ bufferlist in;
+ cls_chunk_refcount_set_op call;
+ call.refs = refs;
+ encode(call, in);
+ op.exec("cas", "chunk_set", in);
+}
+
+int cls_chunk_refcount_read(librados::IoCtx& io_ctx, string& oid, set<hobject_t> *refs)
+{
+ bufferlist in, out;
+ int r = io_ctx.exec(oid, "cas", "chunk_read", in, out);
+ if (r < 0)
+ return r;
+
+ cls_chunk_refcount_read_ret ret;
+ try {
+ auto iter = out.cbegin();
+ decode(ret, iter);
+ } catch (buffer::error& err) {
+ return -EIO;
+ }
+
+ *refs = ret.refs;
+
+ return r;
+}
+
+int cls_chunk_has_chunk(librados::IoCtx& io_ctx, string& oid, string& fp_oid)
+{
+ bufferlist in, out;
+ encode(fp_oid, in);
+ int r = io_ctx.exec(oid, "cas", "has_chunk", in, out);
+ return r;
+}
diff --git a/src/cls/cas/cls_cas_client.h b/src/cls/cas/cls_cas_client.h
new file mode 100644
index 00000000..323be9eb
--- /dev/null
+++ b/src/cls/cas/cls_cas_client.h
@@ -0,0 +1,13 @@
+#ifndef CEPH_CLS_CAS_CLIENT_H
+#define CEPH_CLS_CAS_CLIENT_H
+
+#include "include/types.h"
+#include "include/rados/librados_fwd.hpp"
+#include "common/hobject.h"
+
+void cls_chunk_refcount_get(librados::ObjectWriteOperation& op, const hobject_t& soid);
+void cls_chunk_refcount_put(librados::ObjectWriteOperation& op, const hobject_t& soid);
+void cls_chunk_refcount_set(librados::ObjectWriteOperation& op, set<hobject_t>& refs);
+int cls_chunk_refcount_read(librados::IoCtx& io_ctx, string& oid, set<hobject_t> *refs);
+int cls_chunk_has_chunk(librados::IoCtx& io_ctx, string& oid, string& fp_oid);
+#endif
diff --git a/src/cls/cas/cls_cas_ops.h b/src/cls/cas/cls_cas_ops.h
new file mode 100644
index 00000000..35bc90df
--- /dev/null
+++ b/src/cls/cas/cls_cas_ops.h
@@ -0,0 +1,142 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_CLS_CAS_OPS_H
+#define CEPH_CLS_CAS_OPS_H
+
+#include "include/types.h"
+#include "common/hobject.h"
+
+#define CHUNK_REFCOUNT_ATTR "chunk_refcount"
+
+struct cls_chunk_refcount_get_op {
+ hobject_t source;
+
+ cls_chunk_refcount_get_op() {}
+
+ void encode(bufferlist& bl) const {
+ ENCODE_START(1, 1, bl);
+ encode(source, bl);
+ ENCODE_FINISH(bl);
+ }
+
+ void decode(bufferlist::const_iterator& bl) {
+ DECODE_START(1, bl);
+ decode(source, bl);
+ DECODE_FINISH(bl);
+ }
+ void dump(ceph::Formatter *f) const;
+ static void generate_test_instances(list<cls_chunk_refcount_get_op*>& ls);
+};
+WRITE_CLASS_ENCODER(cls_chunk_refcount_get_op)
+
+struct cls_chunk_refcount_put_op {
+ hobject_t source;
+
+ cls_chunk_refcount_put_op() {}
+
+ void encode(bufferlist& bl) const {
+ ENCODE_START(1, 1, bl);
+ encode(source, bl);
+ ENCODE_FINISH(bl);
+ }
+
+ void decode(bufferlist::const_iterator& bl) {
+ DECODE_START(1, bl);
+ decode(source, bl);
+ DECODE_FINISH(bl);
+ }
+
+ void dump(ceph::Formatter *f) const;
+ static void generate_test_instances(list<cls_chunk_refcount_put_op*>& ls);
+};
+WRITE_CLASS_ENCODER(cls_chunk_refcount_put_op)
+
+struct cls_chunk_refcount_set_op {
+ set<hobject_t> refs;
+
+ cls_chunk_refcount_set_op() {}
+
+ void encode(bufferlist& bl) const {
+ ENCODE_START(1, 1, bl);
+ encode(refs, bl);
+ ENCODE_FINISH(bl);
+ }
+
+ void decode(bufferlist::const_iterator& bl) {
+ DECODE_START(1, bl);
+ decode(refs, bl);
+ DECODE_FINISH(bl);
+ }
+
+ void dump(ceph::Formatter *f) const;
+ static void generate_test_instances(list<cls_chunk_refcount_set_op*>& ls);
+};
+WRITE_CLASS_ENCODER(cls_chunk_refcount_set_op)
+
+struct cls_chunk_refcount_read_ret {
+ set<hobject_t> refs;
+
+ cls_chunk_refcount_read_ret() {}
+
+ void encode(bufferlist& bl) const {
+ ENCODE_START(1, 1, bl);
+ encode(refs, bl);
+ ENCODE_FINISH(bl);
+ }
+
+ void decode(bufferlist::const_iterator& bl) {
+ DECODE_START(1, bl);
+ decode(refs, bl);
+ DECODE_FINISH(bl);
+ }
+
+ void dump(ceph::Formatter *f) const;
+ static void generate_test_instances(list<cls_chunk_refcount_read_ret*>& ls);
+};
+WRITE_CLASS_ENCODER(cls_chunk_refcount_read_ret)
+
+struct chunk_obj_refcount {
+ set<hobject_t> refs;
+
+ chunk_obj_refcount() {}
+
+ void encode(bufferlist& bl) const {
+ ENCODE_START(1, 1, bl);
+ encode(refs, bl);
+ ENCODE_FINISH(bl);
+ }
+
+ void decode(bufferlist::const_iterator& bl) {
+ DECODE_START(1, bl);
+ decode(refs, bl);
+ DECODE_FINISH(bl);
+ }
+};
+WRITE_CLASS_ENCODER(chunk_obj_refcount)
+
+struct obj_refcount {
+ map<string, bool> refs;
+ set<string> retired_refs;
+
+ obj_refcount() {}
+
+ void encode(bufferlist& bl) const {
+ ENCODE_START(2, 1, bl);
+ encode(refs, bl);
+ encode(retired_refs, bl);
+ ENCODE_FINISH(bl);
+ }
+
+ void decode(bufferlist::const_iterator& bl) {
+ DECODE_START(2, bl);
+ decode(refs, bl);
+ if (struct_v >= 2) {
+ decode(retired_refs, bl);
+ }
+ DECODE_FINISH(bl);
+ }
+};
+WRITE_CLASS_ENCODER(obj_refcount)
+
+#endif