mirror of
https://github.com/ceph/ceph
synced 2024-12-22 03:22:00 +00:00
378 lines
9.9 KiB
C++
378 lines
9.9 KiB
C++
|
|
|
|
|
|
#include <iostream>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
|
|
#include "include/types.h"
|
|
#include "objclass/objclass.h"
|
|
|
|
#include "include/rbd_types.h"
|
|
|
|
CLS_VER(1,2)
|
|
CLS_NAME(rbd)
|
|
|
|
cls_handle_t h_class;
|
|
cls_method_handle_t h_snapshots_list;
|
|
cls_method_handle_t h_snapshot_add;
|
|
cls_method_handle_t h_snapshot_remove;
|
|
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)
|
|
{
|
|
unsigned snap_count = 0;
|
|
uint64_t snap_names_len = 0;
|
|
int rc;
|
|
struct rbd_obj_header_ondisk *header;
|
|
|
|
cls_log("snapshots_list");
|
|
|
|
while (1) {
|
|
int len = sizeof(*header) +
|
|
snap_count * sizeof(struct rbd_obj_snap_ondisk) +
|
|
snap_names_len;
|
|
|
|
rc = cls_cxx_read(hctx, 0, len, &bl);
|
|
if (rc < 0)
|
|
return rc;
|
|
|
|
header = (struct rbd_obj_header_ondisk *)bl.c_str();
|
|
|
|
if ((snap_count != header->snap_count) ||
|
|
(snap_names_len != header->snap_names_len)) {
|
|
snap_count = header->snap_count;
|
|
snap_names_len = header->snap_names_len;
|
|
bl.clear();
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int snapshots_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
|
|
{
|
|
bufferlist bl;
|
|
struct rbd_obj_header_ondisk *header;
|
|
int rc = snap_read_header(hctx, bl);
|
|
if (rc < 0)
|
|
return rc;
|
|
|
|
header = (struct rbd_obj_header_ondisk *)bl.c_str();
|
|
bufferptr p(header->snap_names_len);
|
|
char *buf = (char *)header;
|
|
char *name = buf + sizeof(*header) + header->snap_count * sizeof(struct rbd_obj_snap_ondisk);
|
|
char *end = name + header->snap_names_len;
|
|
memcpy(p.c_str(),
|
|
buf + sizeof(*header) + header->snap_count * sizeof(struct rbd_obj_snap_ondisk),
|
|
header->snap_names_len);
|
|
|
|
::encode(header->snap_seq, *out);
|
|
::encode(header->snap_count, *out);
|
|
|
|
for (unsigned i = 0; i < header->snap_count; i++) {
|
|
string s = name;
|
|
::encode(header->snaps[i].id, *out);
|
|
::encode(header->snaps[i].image_size, *out);
|
|
::encode(s, *out);
|
|
|
|
name += strlen(name) + 1;
|
|
if (name > end)
|
|
return -EIO;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int snapshot_add(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
|
|
{
|
|
bufferlist bl;
|
|
struct rbd_obj_header_ondisk *header;
|
|
bufferlist newbl;
|
|
bufferptr header_bp(sizeof(*header));
|
|
struct rbd_obj_snap_ondisk *new_snaps;
|
|
|
|
int rc = snap_read_header(hctx, bl);
|
|
if (rc < 0)
|
|
return rc;
|
|
|
|
header = (struct rbd_obj_header_ondisk *)bl.c_str();
|
|
|
|
int snaps_id_ofs = sizeof(*header);
|
|
int len = snaps_id_ofs;
|
|
int names_ofs = snaps_id_ofs + sizeof(*new_snaps) * header->snap_count;
|
|
const char *snap_name;
|
|
const char *snap_names = ((char *)header) + names_ofs;
|
|
const char *end = snap_names + header->snap_names_len;
|
|
bufferlist::iterator iter = in->begin();
|
|
string s;
|
|
uint64_t snap_id;
|
|
|
|
try {
|
|
::decode(s, iter);
|
|
::decode(snap_id, iter);
|
|
} catch (buffer::error *err) {
|
|
return -EINVAL;
|
|
}
|
|
snap_name = s.c_str();
|
|
|
|
|
|
const char *cur_snap_name;
|
|
for (cur_snap_name = snap_names; cur_snap_name < end; cur_snap_name += strlen(cur_snap_name) + 1) {
|
|
if (strncmp(cur_snap_name, snap_name, end - cur_snap_name) == 0)
|
|
return -EEXIST;
|
|
}
|
|
if (cur_snap_name > end)
|
|
return -EIO;
|
|
|
|
int snap_name_len = strlen(snap_name);
|
|
|
|
bufferptr new_names_bp(header->snap_names_len + snap_name_len + 1);
|
|
bufferptr new_snaps_bp(sizeof(*new_snaps) * (header->snap_count + 1));
|
|
|
|
/* copy snap names and append to new snap name */
|
|
char *new_snap_names = new_names_bp.c_str();
|
|
strcpy(new_snap_names, snap_name);
|
|
memcpy(new_snap_names + snap_name_len + 1, snap_names, header->snap_names_len);
|
|
|
|
/* append new snap id */
|
|
new_snaps = (struct rbd_obj_snap_ondisk *)new_snaps_bp.c_str();
|
|
memcpy(new_snaps + 1, header->snaps, sizeof(*new_snaps) * header->snap_count);
|
|
|
|
header->snap_count = header->snap_count + 1;
|
|
header->snap_names_len = header->snap_names_len + snap_name_len + 1;
|
|
header->snap_seq = snap_id;
|
|
|
|
new_snaps[0].id = snap_id;
|
|
new_snaps[0].image_size = header->image_size;
|
|
|
|
len += sizeof(*new_snaps) * header->snap_count + header->snap_names_len;
|
|
|
|
memcpy(header_bp.c_str(), header, sizeof(*header));
|
|
|
|
newbl.push_back(header_bp);
|
|
newbl.push_back(new_snaps_bp);
|
|
newbl.push_back(new_names_bp);
|
|
|
|
rc = cls_cxx_write_full(hctx, &newbl);
|
|
if (rc < 0)
|
|
return rc;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int snapshot_revert(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
|
|
{
|
|
bufferlist bl;
|
|
struct rbd_obj_header_ondisk *header;
|
|
bufferlist newbl;
|
|
bufferptr header_bp(sizeof(*header));
|
|
struct rbd_obj_snap_ondisk *new_snaps;
|
|
|
|
int rc = snap_read_header(hctx, bl);
|
|
if (rc < 0)
|
|
return rc;
|
|
|
|
header = (struct rbd_obj_header_ondisk *)bl.c_str();
|
|
|
|
int snaps_id_ofs = sizeof(*header);
|
|
int names_ofs = snaps_id_ofs + sizeof(*new_snaps) * header->snap_count;
|
|
const char *snap_name;
|
|
const char *snap_names = ((char *)header) + names_ofs;
|
|
const char *end = snap_names + header->snap_names_len;
|
|
bufferlist::iterator iter = in->begin();
|
|
string s;
|
|
int i;
|
|
bool found = false;
|
|
struct rbd_obj_snap_ondisk snap;
|
|
|
|
try {
|
|
::decode(s, iter);
|
|
} catch (buffer::error *err) {
|
|
return -EINVAL;
|
|
}
|
|
snap_name = s.c_str();
|
|
|
|
for (i = 0; snap_names < end; i++) {
|
|
if (strcmp(snap_names, snap_name) == 0) {
|
|
snap = header->snaps[i];
|
|
found = true;
|
|
break;
|
|
}
|
|
snap_names += strlen(snap_names) + 1;
|
|
}
|
|
if (!found) {
|
|
CLS_LOG("couldn't find snap %s\n",snap_name);
|
|
return -ENOENT;
|
|
}
|
|
|
|
header->image_size = snap.image_size;
|
|
header->snap_seq = header->snap_seq + 1;
|
|
|
|
snap_names += strlen(snap_names) + 1;
|
|
i++;
|
|
|
|
header->snap_count = header->snap_count - i;
|
|
bufferptr new_names_bp(end - snap_names);
|
|
bufferptr new_snaps_bp(sizeof(header->snaps[0]) * header->snap_count);
|
|
|
|
memcpy(header_bp.c_str(), header, sizeof(*header));
|
|
newbl.push_back(header_bp);
|
|
|
|
if (header->snap_count) {
|
|
memcpy(new_snaps_bp.c_str(), header->snaps + i, sizeof(header->snaps[0]) * header->snap_count);
|
|
memcpy(new_names_bp.c_str(), snap_names, end - snap_names);
|
|
newbl.push_back(new_snaps_bp);
|
|
newbl.push_back(new_names_bp);
|
|
}
|
|
|
|
rc = cls_cxx_write_full(hctx, &newbl);
|
|
if (rc < 0)
|
|
return rc;
|
|
|
|
::encode(snap.id, *out);
|
|
|
|
return out->length();
|
|
}
|
|
|
|
int snapshot_remove(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
|
|
{
|
|
bufferlist bl;
|
|
struct rbd_obj_header_ondisk *header;
|
|
bufferlist newbl;
|
|
bufferptr header_bp(sizeof(*header));
|
|
struct rbd_obj_snap_ondisk *new_snaps;
|
|
|
|
int rc = snap_read_header(hctx, bl);
|
|
if (rc < 0)
|
|
return rc;
|
|
|
|
header = (struct rbd_obj_header_ondisk *)bl.c_str();
|
|
|
|
int snaps_id_ofs = sizeof(*header);
|
|
int names_ofs = snaps_id_ofs + sizeof(*new_snaps) * header->snap_count;
|
|
const char *snap_name;
|
|
const char *snap_names = ((char *)header) + names_ofs;
|
|
const char *orig_names = snap_names;
|
|
const char *end = snap_names + header->snap_names_len;
|
|
bufferlist::iterator iter = in->begin();
|
|
string s;
|
|
unsigned i;
|
|
bool found = false;
|
|
struct rbd_obj_snap_ondisk snap;
|
|
|
|
try {
|
|
::decode(s, iter);
|
|
} catch (buffer::error *err) {
|
|
return -EINVAL;
|
|
}
|
|
snap_name = s.c_str();
|
|
|
|
for (i = 0; snap_names < end; i++) {
|
|
if (strcmp(snap_names, snap_name) == 0) {
|
|
snap = header->snaps[i];
|
|
found = true;
|
|
break;
|
|
}
|
|
snap_names += strlen(snap_names) + 1;
|
|
}
|
|
if (!found) {
|
|
CLS_LOG("couldn't find snap %s\n",snap_name);
|
|
return -ENOENT;
|
|
}
|
|
|
|
snap_names += s.length() + 1;
|
|
|
|
header->snap_names_len = header->snap_names_len - (s.length() + 1);
|
|
header->snap_count = header->snap_count - 1;
|
|
|
|
bufferptr new_names_bp(header->snap_names_len);
|
|
bufferptr new_snaps_bp(sizeof(header->snaps[0]) * header->snap_count);
|
|
|
|
memcpy(header_bp.c_str(), header, sizeof(*header));
|
|
newbl.push_back(header_bp);
|
|
|
|
if (header->snap_count) {
|
|
if (i > 0) {
|
|
memcpy(new_snaps_bp.c_str(), header->snaps, sizeof(header->snaps[0]) * i);
|
|
memcpy(new_names_bp.c_str(), header->snaps, snap_names - orig_names);
|
|
}
|
|
snap_names += s.length() + 1;
|
|
|
|
if (i < header->snap_count) {
|
|
memcpy(new_snaps_bp.c_str(), header->snaps, sizeof(header->snaps[0]) * i);
|
|
memcpy(new_names_bp.c_str(), snap_names , end - snap_names);
|
|
}
|
|
}
|
|
|
|
rc = cls_cxx_write_full(hctx, &newbl);
|
|
if (rc < 0)
|
|
return rc;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
/* 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("rbd", &h_class);
|
|
cls_register_cxx_method(h_class, "snap_list", CLS_METHOD_RD | CLS_METHOD_PUBLIC, snapshots_list, &h_snapshots_list);
|
|
cls_register_cxx_method(h_class, "snap_add", CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PUBLIC, snapshot_add, &h_snapshot_add);
|
|
cls_register_cxx_method(h_class, "snap_remove", CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PUBLIC, snapshot_remove, &h_snapshot_remove);
|
|
cls_register_cxx_method(h_class, "snap_revert", CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PUBLIC, 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 | CLS_METHOD_PUBLIC, rbd_assign_bid, &h_assign_bid);
|
|
|
|
return;
|
|
}
|
|
|