From bf8aa18d4801e9713af6098f9697b5e9e21c0230 Mon Sep 17 00:00:00 2001 From: Yehuda Sadeh Date: Mon, 19 Jul 2010 10:20:01 -0700 Subject: [PATCH] rbd: add removal of snapshots --- man/rbd.8 | 3 ++ src/cls_rbd.cc | 83 +++++++++++++++++++++++++++++++++++++++++++++++++- src/rbd.cc | 44 +++++++++++++++++++++++++- 3 files changed, 128 insertions(+), 2 deletions(-) diff --git a/man/rbd.8 b/man/rbd.8 index 934956134f21b..355ea5407d17f 100644 --- a/man/rbd.8 +++ b/man/rbd.8 @@ -77,6 +77,9 @@ Creates a new snapshot. Requires the snapshot name parameter specified. .TP \fBsnap rollback \fR[ \fIimage-name\fP ] Rollback image content to snapshot. This will iterate through the entire blocks array and update the data head content to the snapshotted version. +.TP +\fBsnap rm \fR[ \fIimage-name\fP ] +Removes the specified snapshot. .SH IMAGE NAME In addition to using the \fB\-\-pool\fR and the \fB\-\-snap\fR options, the image name can include both the pool name and the snapshot name. The image name format is as follows: .IP diff --git a/src/cls_rbd.cc b/src/cls_rbd.cc index d8a90d6449662..406a5c87a5035 100644 --- a/src/cls_rbd.cc +++ b/src/cls_rbd.cc @@ -11,12 +11,13 @@ #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; @@ -238,6 +239,85 @@ int snapshot_revert(cls_method_context_t hctx, bufferlist *in, bufferlist *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) { @@ -286,6 +366,7 @@ void __cls_init() 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 */ diff --git a/src/rbd.cc b/src/rbd.cc index 927405f31354c..81dd4487c9d09 100644 --- a/src/rbd.cc +++ b/src/rbd.cc @@ -61,6 +61,7 @@ void usage() << " 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 source pool name\n" @@ -520,6 +521,21 @@ static int do_add_snap(pools_t& pp, string& md_oid, const char *snapname) 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& snaps, uint64_t& snapid) { @@ -577,6 +593,15 @@ static int do_rollback_snap(pools_t& pp, string& md_oid, ::SnapContext& snapc, u 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; @@ -848,6 +873,7 @@ enum { OPT_RENAME, OPT_SNAP_CREATE, OPT_SNAP_ROLLBACK, + OPT_SNAP_REMOVE, OPT_SNAP_LIST, }; @@ -889,6 +915,9 @@ static int get_cmd(const char *cmd, bool *snapcmd) 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; @@ -968,6 +997,7 @@ int main(int argc, const char **argv) 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; @@ -1010,7 +1040,8 @@ int main(int argc, const char **argv) 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(); } @@ -1163,6 +1194,17 @@ int main(int argc, const char **argv) 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; -- 2.39.5