]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rbd: add snapshot creation via rbd class
authorYehuda Sadeh <yehuda@hq.newdream.net>
Tue, 18 May 2010 18:01:56 +0000 (11:01 -0700)
committerYehuda Sadeh <yehuda@hq.newdream.net>
Thu, 10 Jun 2010 21:45:39 +0000 (14:45 -0700)
src/Makefile.am
src/cls_rbd.cc
src/rbdtool.cc
src/testradospp.cc

index a706bea9389fc153fe69ab7af61a6a7cce41ac9a..ba4589c29cf9e77e22d4dafcc112a22ef3168824 100644 (file)
@@ -210,6 +210,10 @@ libcls_acl.so: cls_acl.cc
        ${CXX} -I. -fPIC -shared -g -o libcls_acl.so cls_acl.cc
 BUILT_SOURCES += libcls_acl.so
 
+libcls_rbd.so: cls_rbd.cc
+       ${CXX} -I. -fPIC -shared -g -o libcls_rbd.so cls_rbd.cc
+BUILT_SOURCES += libcls_rbd.so
+
 
 ## hadoop client
 if WITH_HADOOPCLIENT
index 129569b66ad0fd08205ff8284d3d9266d432c81c..da070fb4ef91bcb24a28f86af47acbf80cf79b79 100644 (file)
@@ -19,14 +19,14 @@ CLS_NAME(rbd)
 
 cls_handle_t h_class;
 cls_method_handle_t h_snapshots_list;
+cls_method_handle_t h_snapshot_add;
 
-int snapshots_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
+static int snap_read_header(cls_method_context_t hctx, bufferlist& bl)
 {
   int snap_count = 0;
   uint64_t snap_names_len = 0;
   int rc;
   struct rbd_obj_header_ondisk *header;
-  bufferlist bl;
 
   cls_log("snapshots_list");
 
@@ -51,23 +51,127 @@ int snapshots_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
     break;
   }
 
-  bufferptr p(snap_names_len);
+  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(),
-         bl.c_str() + sizeof(*header) + snap_count * sizeof(struct rbd_obj_snap_ondisk),
-         snap_names_len);
+         buf + sizeof(*header) + header->snap_count * sizeof(struct rbd_obj_snap_ondisk),
+         header->snap_names_len);
+
+  ::encode(header->snap_count, *out);
+
+  for (int 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 = header->snap_seq + 1;
+
+  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);
 
-  out->push_back(p);
+  rc = cls_cxx_write(hctx, 0, len, &newbl);
+  if (rc < 0)
+    return rc;
 
-  return snap_count;
+  return 0;
 }
 
 void class_init()
 {
-   cls_log("Loaded rbd class!");
+  CLS_LOG("Loaded rbd class!");
 
-   cls_register("rbd", &h_class);
-   cls_register_cxx_method(h_class, "snap_list", CLS_METHOD_RD, snapshots_list, &h_snapshots_list);
+  cls_register("rbd", &h_class);
+  cls_register_cxx_method(h_class, "snap_list", CLS_METHOD_RD, snapshots_list, &h_snapshots_list);
+  cls_register_cxx_method(h_class, "snap_add", CLS_METHOD_RD | CLS_METHOD_WR, snapshot_add, &h_snapshot_add);
 
-   return;
+  return;
 }
 
index bd7eb3eecc393c8c2e2b3834b2d553f762e3c6f0..2769308fb154dcc5d0516c9cf7a0fb632ef8c771 100644 (file)
@@ -33,7 +33,7 @@ pool_t pool;
 
 void usage()
 {
-  cout << "usage: rbdtool [-n <auth user>] [-p|--pool <name>] <cmd>\n"
+  cout << "usage: rbdtool [-n <auth user>] [-p|--pool <name>] [-n|--object <imagename>] <cmd>\n"
        << "where 'pool' is a rados pool name (default is 'rbd') and 'cmd' is one of:\n"
        << "\t--list    list rbd images\n"
        << "\t--info    show information about image size, striping, etc.\n"
@@ -42,8 +42,11 @@ void usage()
        << "\t--resize <image name> --size <new size in MB>\n"
        << "\t          resize (expand or contract) image\n"
        << "\t--delete <image name>\n"
-       << "\t          delete an image" << std::endl;
-  exit(1);
+       << "\t          delete an image\n"
+       << "\t--list-snaps <image name>\n"
+       << "\t          dump list of specific image snapshots"
+       << "\t--add-snap <snap name>\n"
+       << "\t          create a snapshot for the spacified image" << std::endl;
 }
 
 
@@ -116,11 +119,11 @@ int main(int argc, const char **argv)
   common_init(args, "rbdtool", false, true);
 
   bool opt_create = false, opt_delete = false, opt_list = false, opt_info = false, opt_resize = false,
-       opt_list_snaps = false;
+       opt_list_snaps = false, opt_add_snap = false;
   char *poolname = (char *)"rbd";
   uint64_t size = 0;
   int order = 0;
-  char *imgname;
+  char *imgname = NULL, *snapname = NULL;
 
   FOR_EACH_ARG(args) {
     if (CONF_ARG_EQ("list", '\0')) {
@@ -140,6 +143,9 @@ int main(int argc, const char **argv)
     } else if (CONF_ARG_EQ("list-snaps", '\0')) {
       CONF_SAFE_SET_ARG_VAL(&imgname, OPT_STR);
       opt_list_snaps = true;
+    } else if (CONF_ARG_EQ("add-snap", '\0')) {
+      CONF_SAFE_SET_ARG_VAL(&snapname, OPT_STR);
+      opt_add_snap = true;
     } else if (CONF_ARG_EQ("pool", 'p')) {
       CONF_SAFE_SET_ARG_VAL(&poolname, OPT_STR);
     } else if (CONF_ARG_EQ("object", 'n')) {
@@ -154,9 +160,15 @@ int main(int argc, const char **argv)
   }
 
   if (!opt_create && !opt_delete && !opt_list && !opt_info && !opt_resize &&
-      !opt_list_snaps)
+      !opt_list_snaps && !opt_add_snap) {
     usage();
+    exit(1);
+  }
 
+  if (!imgname) {
+    usage();
+    exit(1);
+  }
 
   if (rados.initialize(argc, argv) < 0) {
      cerr << "couldn't initialize rados!" << std::endl;
@@ -302,17 +314,49 @@ int main(int argc, const char **argv)
     cout << "done." << std::endl;
   } else if (opt_list_snaps) {
     bufferlist bl, bl2;
-    char *s;
-    r = rados.exec(pool, md_oid, "rbd", "snap_list", bl, bl2);
+    if (!imgname) {
+      usage();
+      err_exit(pool);
+    }
 
+    r = rados.exec(pool, md_oid, "rbd", "snap_list", bl, bl2);
     if (r < 0) {
       cerr << "list_snaps failed: " << strerror(-r) << std::endl;
       err_exit(pool);
     }
 
-    s = bl2.c_str();
-    for (int i=0; i<r; i++, s += strlen(s) + 1)
-      cout << s << std::endl;
+    uint32_t num_snaps;
+    bufferlist::iterator iter = bl2.begin();
+    ::decode(num_snaps, iter);
+    for (uint32_t i=0; i < num_snaps; i++) {
+      uint64_t id, image_size;
+      string s;
+      ::decode(id, iter);
+      ::decode(image_size, iter);
+      ::decode(s, iter);
+      cout << id << "\t" << s << "\t" << image_size << std::endl;
+    }
+  } else if (opt_add_snap) {
+    bufferlist bl, bl2;
+    uint64_t snap_id;
+    if (!imgname || !snapname) {
+      usage();
+      err_exit(pool);
+    }
+    r = rados.selfmanaged_snap_create(pool, &snap_id);
+    if (r < 0) {
+      cerr << "failed to create snap id: " << strerror(-r) << std::endl;
+      err_exit(pool);
+    }
+
+    ::encode(snapname, bl);
+    ::encode(snap_id, bl);
+
+    r = rados.exec(pool, md_oid, "rbd", "snap_add", bl, bl2);
+    if (r < 0) {
+      cerr << "list_snaps failed: " << strerror(-r) << std::endl;
+      err_exit(pool);
+    }
   }
 
   rados.close_pool(pool);
index a933590ac76ee7b8d45fe8a32bce4b6cea565cbb..9361ed4b00e980d8e447ed6729b312db8b7b9e96 100644 (file)
@@ -102,6 +102,8 @@ int main(int argc, const char **argv)
   const char *oid2 = "jjj10.rbd";
   r = rados.exec(pool, oid2, "rbd", "snap_list", bl, bl2);
   cout << "snap_list result=" << r << std::endl;
+  r = rados.exec(pool, oid2, "rbd", "snap_add", bl, bl2);
+  cout << "snap_add result=" << r << std::endl;
 
   if (r > 0) {
     char *s = bl2.c_str();