]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rbd: add removal of snapshots
authorYehuda Sadeh <yehuda@hq.newdream.net>
Mon, 19 Jul 2010 17:20:01 +0000 (10:20 -0700)
committerYehuda Sadeh <yehuda@hq.newdream.net>
Mon, 19 Jul 2010 17:20:43 +0000 (10:20 -0700)
man/rbd.8
src/cls_rbd.cc
src/rbd.cc

index 934956134f21bf471f6c43dcfb1aef98db40190e..355ea5407d17f1b2f52fedd79dc75a1963d255b3 100644 (file)
--- 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
index d8a90d6449662a12aa648f89d736d919501ec3af..406a5c87a5035bb6b6cd949a691f92fe10028d54 100644 (file)
 
 #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 */
index 927405f31354cf4ab578f4701ec51dad3aa0e7de..81dd4487c9d09c453013b1f19cd87dca97fbd011 100644 (file)
@@ -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 <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<snap_t>& 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;