* - Creation and deletion: rados_create_read_op() rados_release_read_op()
* - Object properties: rados_read_op_stat(), rados_read_op_assert_exists()
* - IO on objects: rados_read_op_read()
+ * - Custom operations: rados_read_op_exec(), rados_read_op_exec_user_buf()
* - Request properties: rados_read_op_set_flags()
* - Performing the operation: rados_read_op_operate(),
* rados_aio_read_op_operate()
int *prval);
/**
+ * Execute an OSD class method on an object
+ * See rados_exec() for general description.
+ *
+ * The output buffer is allocated on the heap; the caller is
+ * expected to release that memory with rados_buffer_free(). The
+ * buffer and length pointers can all be NULL, in which case they are
+ * not filled in.
+ *
+ * @param read_op operation to add this action to
+ * @param cls the name of the class
+ * @param method the name of the method
+ * @param in_buf where to find input
+ * @param in_len length of in_buf in bytes
+ * @param out_buf where to put librados-allocated output buffer
+ * @param out_len length of out_buf in bytes
+ * @param prval where to store the return value from the method
+ */
+void rados_read_op_exec(rados_read_op_t read_op,
+ const char *cls,
+ const char *method,
+ const char *in_buf,
+ size_t in_len,
+ char **out_buf,
+ size_t *out_len,
+ int *prval);
+
+/**
+ * Execute an OSD class method on an object
+ * See rados_exec() for general description.
+ *
+ * If the output buffer is too small, prval will
+ * be set to -ERANGE and used_len will be 0.
+ *
+ * @param read_op operation to add this action to
+ * @param cls the name of the class
+ * @param method the name of the method
+ * @param in_buf where to find input
+ * @param in_len length of in_buf in bytes
+ * @param out_buf user-provided buffer to read into
+ * @param out_len length of out_buf in bytes
+ * @param used_len where to store the number of bytes read into out_buf
+ * @param prval where to store the return value from the method
+ */
+void rados_read_op_exec_user_buf(rados_read_op_t read_op,
+ const char *cls,
+ const char *method,
+ const char *in_buf,
+ size_t in_len,
+ char *out_buf,
+ size_t out_len,
+ size_t *used_len,
+ int *prval);
+
/**
* Perform a write operation synchronously
((::ObjectOperation *)read_op)->read(offset, len, &ctx->out_bl, prval, ctx);
}
+class C_out_buffer : public Context {
+ char **out_buf;
+ size_t *out_len;
+public:
+ bufferlist out_bl;
+ C_out_buffer(char **out_buf, size_t *out_len) : out_buf(out_buf),
+ out_len(out_len) {}
+ void finish(int r) {
+ // ignore r since we don't know the meaning of return values
+ // from custom class methods
+ do_out_buffer(out_bl, out_buf, out_len);
+ }
+};
+
+extern "C" void rados_read_op_exec(rados_read_op_t read_op,
+ const char *cls,
+ const char *method,
+ const char *in_buf,
+ size_t in_len,
+ char **out_buf,
+ size_t *out_len,
+ int *prval)
+{
+ bufferlist inbl;
+ inbl.append(in_buf, in_len);
+ C_out_buffer *ctx = new C_out_buffer(out_buf, out_len);
+ ((::ObjectOperation *)read_op)->call(cls, method, inbl, &ctx->out_bl, ctx,
+ prval);
+}
+
+extern "C" void rados_read_op_exec_user_buf(rados_read_op_t read_op,
+ const char *cls,
+ const char *method,
+ const char *in_buf,
+ size_t in_len,
+ char *out_buf,
+ size_t out_len,
+ size_t *used_len,
+ int *prval)
+{
+ C_bl_to_buf *ctx = new C_bl_to_buf(out_buf, out_len, used_len, prval);
+ bufferlist inbl;
+ inbl.append(in_buf, in_len);
+ ((::ObjectOperation *)read_op)->call(cls, method, inbl, &ctx->out_bl, ctx,
+ prval);
+}
+
extern "C" int rados_read_op_operate(rados_read_op_t read_op,
rados_ioctx_t io,
const char *oid,
remove_object();
}
+TEST_F(CReadOpsTest, Exec) {
+ // create object so we don't get -ENOENT
+ write_object();
+
+ rados_read_op_t op = rados_create_read_op();
+ ASSERT_TRUE(op);
+ size_t bytes_read = 0;
+ char *out = NULL;
+ int rval = 0;
+ rados_read_op_exec(op, "rbd", "get_all_features", NULL, 0, &out,
+ &bytes_read, &rval);
+ ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
+ rados_release_read_op(op);
+ EXPECT_EQ(0, rval);
+ EXPECT_TRUE(out);
+ uint64_t features;
+ EXPECT_EQ(sizeof(features), bytes_read);
+ // make sure buffer is at least as long as it claims
+ ASSERT_TRUE(out[bytes_read-1] == out[bytes_read-1]);
+ rados_buffer_free(out);
+
+ remove_object();
+}
+
+TEST_F(CReadOpsTest, ExecUserBuf) {
+ // create object so we don't get -ENOENT
+ write_object();
+
+ rados_read_op_t op = rados_create_read_op();
+ size_t bytes_read = 0;
+ uint64_t features;
+ char out[sizeof(features)];
+ int rval = 0;
+ rados_read_op_exec_user_buf(op, "rbd", "get_all_features", NULL, 0, out,
+ sizeof(out), &bytes_read, &rval);
+ ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
+ rados_release_read_op(op);
+ EXPECT_EQ(0, rval);
+ EXPECT_EQ(sizeof(features), bytes_read);
+
+ // buffer too short
+ bytes_read = 1024;
+ op = rados_create_read_op();
+ rados_read_op_exec_user_buf(op, "rbd", "get_all_features", NULL, 0, out,
+ sizeof(features) - 1, &bytes_read, &rval);
+ ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
+ EXPECT_EQ(0u, bytes_read);
+ EXPECT_EQ(-ERANGE, rval);
+
+ // input buffer and no rval or bytes_read
+ op = rados_create_read_op();
+ rados_read_op_exec_user_buf(op, "rbd", "get_all_features", out, sizeof(out),
+ out, sizeof(out), NULL, NULL);
+ ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
+ rados_release_read_op(op);
+
+ remove_object();
+}
+
TEST_F(CReadOpsTest, Stat) {
rados_read_op_t op = rados_create_read_op();
uint64_t size = 1;