#include "include/rbd_types.h"
-CLS_VER(1,1)
+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;
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)
{
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 */
<< " snap ls [image-name] dump list of image snapshots\n"
<< " snap create <--snap=name> [image-name] create a snapshot\n"
<< " snap rollback <--snap=name> [image-name] rollback image head to snapshot\n"
+ << " snap rm <--snap=name> [image-name] deletes a snapshot\n"
<< "\n"
<< "Other input options:\n"
<< " -p, --pool <pool> source pool name\n"
return 0;
}
+static int do_rm_snap(pools_t& pp, string& md_oid, const char *snapname)
+{
+ bufferlist bl, bl2;
+
+ ::encode(snapname, bl);
+
+ int r = rados.exec(pp.md, md_oid, "rbd", "snap_remove", bl, bl2);
+ if (r < 0) {
+ cerr << "rbd.snap_remove execution failed failed: " << strerror(-r) << std::endl;
+ return r;
+ }
+
+ return 0;
+}
+
static int do_get_snapc(pools_t& pp, string& md_oid, const char *snapname,
::SnapContext& snapc, vector<snap_t>& snaps, uint64_t& snapid)
{
return 0;
}
+static int do_remove_snap(pools_t& pp, string& md_oid, const char *snapname,
+ uint64_t snapid)
+{
+ int r = do_rm_snap(pp, md_oid, snapname);
+ r = rados.selfmanaged_snap_remove(pp.data, snapid);
+
+ return r;
+}
+
static int do_export(pools_t& pp, string& md_oid, const char *path)
{
struct rbd_obj_header_ondisk header;
OPT_RENAME,
OPT_SNAP_CREATE,
OPT_SNAP_ROLLBACK,
+ OPT_SNAP_REMOVE,
OPT_SNAP_LIST,
};
if (strcmp(cmd, "rollback") == 0||
strcmp(cmd, "revert") == 0)
return OPT_SNAP_ROLLBACK;
+ if (strcmp(cmd, "remove") == 0||
+ strcmp(cmd, "rm") == 0)
+ return OPT_SNAP_REMOVE;
if (strcmp(cmd, "ls") == 0||
strcmp(cmd, "list") == 0)
return OPT_SNAP_LIST;
case OPT_RM:
case OPT_SNAP_CREATE:
case OPT_SNAP_ROLLBACK:
+ case OPT_SNAP_REMOVE:
case OPT_SNAP_LIST:
set_conf_param(CONF_VAL, &imgname, NULL);
break;
set_pool_image_name(poolname, imgname, (char **)&poolname, (char **)&imgname, (char **)&snapname);
set_pool_image_name(dest_poolname, destname, (char **)&dest_poolname, (char **)&destname, NULL);
- if ((opt_cmd == OPT_SNAP_CREATE || opt_cmd == OPT_SNAP_ROLLBACK) && !snapname) {
+ if ((opt_cmd == OPT_SNAP_CREATE || opt_cmd == OPT_SNAP_ROLLBACK ||
+ opt_cmd == OPT_SNAP_REMOVE) && !snapname) {
cerr << "error: snap name was not specified" << std::endl;
usage_exit();
}
usage();
err_exit(pp);
}
+ } else if (opt_cmd == OPT_SNAP_REMOVE) {
+ if (!imgname) {
+ usage();
+ err_exit(pp);
+ }
+ r = do_remove_snap(pp, md_oid, snapname, snapid);
+ if (r < 0) {
+ cerr << "rollback failed: " << strerror(-r) << std::endl;
+ usage();
+ err_exit(pp);
+ }
} else if (opt_cmd == OPT_EXPORT) {
if (!path) {
cerr << "pathname should be specified" << std::endl;