cls_method_handle_t h_snapshots_list;
cls_method_handle_t h_snapshot_add;
cls_method_handle_t h_snapshot_revert;
+cls_method_handle_t h_assign_bid;
static int snap_read_header(cls_method_context_t hctx, bufferlist& bl)
{
return out->length();
}
+/* assign block id. This method should be called on the rbd_info object */
+int rbd_assign_bid(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
+{
+ struct rbd_info info;
+ int rc;
+ bufferlist bl;
+
+ rc = cls_cxx_read(hctx, 0, sizeof(info), &bl);
+ if (rc < 0 && rc != -EEXIST)
+ return rc;
+
+ if (rc && rc < (int)sizeof(info)) {
+ CLS_LOG("bad rbd_info object, read %d bytes, expected %d", rc, sizeof(info));
+ return -EIO;
+ }
+
+ uint64_t max_id;
+ if (rc) {
+ memcpy(&info, bl.c_str(), sizeof(info));
+ max_id = info.max_id + 1;
+ info.max_id = max_id;
+ } else {
+ memset(&info, 0, sizeof(info));
+ max_id = 0;
+ }
+
+ bufferlist newbl;
+ bufferptr bp(sizeof(info));
+ memcpy(bp.c_str(), &info, sizeof(info));
+ newbl.push_back(bp);
+ rc = cls_cxx_write_full(hctx, &newbl);
+ if (rc < 0) {
+ CLS_LOG("error writing rbd_info, got rc=%d", rc);
+ return rc;
+ }
+
+ ::encode(max_id, *out);
+
+ return out->length();
+}
+
void __cls_init()
{
CLS_LOG("Loaded rbd class!");
cls_register_cxx_method(h_class, "snap_add", CLS_METHOD_RD | CLS_METHOD_WR, snapshot_add, &h_snapshot_add);
cls_register_cxx_method(h_class, "snap_revert", CLS_METHOD_RD | CLS_METHOD_WR, snapshot_revert, &h_snapshot_revert);
+ /* assign a unique block id for rbd blocks */
+ cls_register_cxx_method(h_class, "assign_bid", CLS_METHOD_RD | CLS_METHOD_WR, rbd_assign_bid, &h_assign_bid);
+
return;
}
#define RBD_SUFFIX ".rbd"
#define RBD_DIRECTORY "rbd_directory"
+#define RBD_INFO "rbd_info"
#define RBD_DEFAULT_OBJ_ORDER 22 /* 4MB */
#define RBD_HEADER_TEXT "<<< Rados Block Device Image >>>\n"
#define RBD_HEADER_SIGNATURE "RBD"
-#define RBD_HEADER_VERSION "001.004"
+#define RBD_HEADER_VERSION "001.005"
+
+struct rbd_info {
+ __le64 max_id;
+} __attribute__ ((packed));
struct rbd_obj_snap_ondisk {
__le64 id;
} __attribute__((packed));
struct rbd_obj_header_ondisk {
- char text[64];
+ char text[40];
+ char block_name[24];
char signature[4];
char version[8];
struct {
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
+#include <errno.h>
#include "include/rbd_types.h"
static void init_rbd_header(struct rbd_obj_header_ondisk& ondisk,
- size_t size, int order)
+ size_t size, int order, uint64_t bid)
{
+ uint32_t hi = bid >> 32;
+ uint32_t lo = bid & 0xFFFFFFFF;
memset(&ondisk, 0, sizeof(ondisk));
memcpy(&ondisk.text, RBD_HEADER_TEXT, sizeof(RBD_HEADER_TEXT));
memcpy(&ondisk.signature, RBD_HEADER_SIGNATURE, sizeof(RBD_HEADER_SIGNATURE));
memcpy(&ondisk.version, RBD_HEADER_VERSION, sizeof(RBD_HEADER_VERSION));
+ snprintf(ondisk.block_name, sizeof(ondisk.block_name), "rb.%08x.%08x", hi, lo);
+
ondisk.image_size = size;
if (order)
ondisk.options.order = order;
}
}
+static int init_rbd_info(struct rbd_info *info)
+{
+ memset(info, 0, sizeof(*info));
+ return 0;
+}
+
+int read_rbd_info(pool_t pool, string& info_oid, struct rbd_info *info)
+{
+ int r;
+ bufferlist bl;
+
+ r = rados.read(pool, info_oid, 0, bl, sizeof(*info));
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ return init_rbd_info(info);
+ }
+
+ if (r < (int)sizeof(*info))
+ return -EIO;
+
+ memcpy(info, bl.c_str(), r);
+ return 0;
+}
+
+static int touch_rbd_info(pool_t pool, string& info_oid)
+{
+ bufferlist bl;
+ int r = rados.write(pool, info_oid, 0, bl, 0);
+ if (r < 0)
+ return r;
+ return 0;
+}
+
+static int rbd_assign_bid(pool_t pool, string& info_oid, uint64_t *id)
+{
+ bufferlist bl, out;
+
+ *id = 0;
+
+ int r = touch_rbd_info(pool, info_oid);
+ if (r < 0)
+ return r;
+
+ r = rados.exec(pool, info_oid, "rbd", "assign_bid", bl, out);
+ if (r < 0)
+ return r;
+
+ cerr << "r=" << r << " out.length()=" << out.length() << std::endl;
+
+ bufferlist::iterator iter = out.begin();
+ ::decode(*id, iter);
+
+ return 0;
+}
+
+
static void err_exit(pool_t pool)
{
rados.close_pool(pool);
md_oid += RBD_SUFFIX;
}
string dir_oid = RBD_DIRECTORY;
+ string dir_info_oid= RBD_INFO;
int r = rados.open_pool(poolname, &pool);
if (r < 0) {
err_exit(pool);
}
+ uint64_t bid;
+ r = rbd_assign_bid(pool, dir_info_oid, &bid);
+ if (r < 0) {
+ cerr << "failed assigning block id" << std::endl;
+ err_exit(pool);
+ }
+
struct rbd_obj_header_ondisk header;
- init_rbd_header(header, size, order);
+ init_rbd_header(header, size, order, bid);
bufferlist bl;
bl.append((const char *)&header, sizeof(header));