]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: support to list snapshot time stamp
authorPan Liu <pan.liu@istuary.com>
Sat, 28 Jan 2017 16:43:33 +0000 (00:43 +0800)
committerPan Liu <pan.liu@istuary.com>
Mon, 30 Jan 2017 19:18:32 +0000 (03:18 +0800)
Fixes: http://tracker.ceph.com/issues/808
Signed-off-by: Pan Liu <pan.liu@istuary.com>
15 files changed:
src/cls/rbd/cls_rbd.cc
src/cls/rbd/cls_rbd_client.cc
src/cls/rbd/cls_rbd_client.h
src/include/rbd/librbd.h
src/include/rbd/librbd.hpp
src/librbd/SnapInfo.h
src/librbd/image/RefreshRequest.cc
src/librbd/image/RefreshRequest.h
src/librbd/internal.cc
src/librbd/internal.h
src/librbd/librbd.cc
src/pybind/rbd/rbd.pyx
src/test/librbd/image/test_mock_RefreshRequest.cc
src/tools/rbd/action/Snap.cc
src/tracing/librbd.tp

index 8f86ca13f9713e530e0426fb3f55683c3e6a15b2..ae8cf9185d163f510771e331caab9ba3596b7a08 100644 (file)
@@ -1455,6 +1455,35 @@ int get_snapshot_name(cls_method_context_t hctx, bufferlist *in, bufferlist *out
   return 0;
 }
 
+int get_snapshot_timestamp(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
+{
+  uint64_t snap_id;
+  
+  bufferlist::iterator iter = in->begin();
+  try {
+    ::decode(snap_id, iter);
+  } catch (const buffer::error &err) {
+    return -EINVAL;
+  }
+
+  CLS_LOG(20, "get_snapshot_timestamp snap_id=%llu", (unsigned long long)snap_id);
+
+  if (snap_id == CEPH_NOSNAP) {
+    return -EINVAL;
+  }
+  
+  cls_rbd_snap snap;
+  string snapshot_key;
+  key_from_snap_id(snap_id, &snapshot_key);
+  int r = read_key(hctx, snapshot_key, &snap);
+  if (r < 0) {
+    return r;
+  }
+
+  ::encode(snap.timestamp, *out);
+  return 0;
+}
+
 /**
  * Retrieve namespace of a snapshot.
  *
@@ -4746,6 +4775,7 @@ CLS_INIT(rbd)
   cls_method_handle_t h_get_data_pool;
   cls_method_handle_t h_get_snapshot_name;
   cls_method_handle_t h_get_snapshot_namespace;
+  cls_method_handle_t h_get_snapshot_timestamp;
   cls_method_handle_t h_snapshot_add;
   cls_method_handle_t h_snapshot_remove;
   cls_method_handle_t h_snapshot_rename;
@@ -4836,6 +4866,9 @@ CLS_INIT(rbd)
   cls_register_cxx_method(h_class, "get_snapshot_namespace",
                          CLS_METHOD_RD,
                          get_snapshot_namespace, &h_get_snapshot_namespace);
+  cls_register_cxx_method(h_class, "get_snapshot_timestamp",
+                         CLS_METHOD_RD,
+                         get_snapshot_timestamp, &h_get_snapshot_timestamp);
   cls_register_cxx_method(h_class, "snapshot_add",
                          CLS_METHOD_RD | CLS_METHOD_WR,
                          snapshot_add, &h_snapshot_add);
index c0f3da77858290157314399168fe3323bc88d18e..517bea56809e21accf8c5f12e7d22d0791671aed 100644 (file)
@@ -525,9 +525,7 @@ namespace librbd {
 
     void snapshot_list_start(librados::ObjectReadOperation *op,
                              const std::vector<snapid_t> &ids) {
-      for (vector<snapid_t>::const_iterator it = ids.begin();
-           it != ids.end(); ++it) {
-        snapid_t snap_id = it->val;
+      for (auto snap_id : ids) {
         bufferlist bl1, bl2, bl3, bl4;
         ::encode(snap_id, bl1);
         op->exec("rbd", "get_snapshot_name", bl1);
@@ -594,21 +592,63 @@ namespace librbd {
                                   protection_statuses);
     }
 
-    void snap_namespace_list_start(librados::ObjectReadOperation *op,
-                             const std::vector<snapid_t> &ids)
+    void snapshot_timestamp_list_start(librados::ObjectReadOperation *op,
+                                       const std::vector<snapid_t> &ids)
     {
-      for (vector<snapid_t>::const_iterator it = ids.begin();
-           it != ids.end(); ++it) {
-        snapid_t snap_id = it->val;
+      for (auto snap_id : ids) {
         bufferlist bl;
         ::encode(snap_id, bl);
-       op->exec("rbd", "get_snapshot_namespace", bl);
+        op->exec("rbd", "get_snapshot_timestamp", bl);
       }
     }
 
-    int snap_namespace_list_finish(bufferlist::iterator *it,
-                                  const std::vector<snapid_t> &ids,
-                                  std::vector<cls::rbd::SnapshotNamespace> *namespaces)
+    int snapshot_timestamp_list_finish(bufferlist::iterator *it,
+                                       const std::vector<snapid_t> &ids,
+                                       std::vector<utime_t> *timestamps)
+    {
+      timestamps->resize(ids.size());
+      try {
+        for (size_t i = 0; i < timestamps->size(); ++i) {
+          utime_t t;
+          ::decode(t, *it);
+          (*timestamps)[i] = t;
+        }
+      } catch (const buffer::error &err) {
+        return -EBADMSG;
+      }
+      return 0;
+    }
+
+    int snapshot_timestamp_list(librados::IoCtx *ioctx, const std::string &oid,
+                                const std::vector<snapid_t> &ids,
+                                std::vector<utime_t> *timestamps)
+    {
+      librados::ObjectReadOperation op;
+      snapshot_timestamp_list_start(&op, ids);
+
+      bufferlist out_bl;
+      int r = ioctx->operate(oid, &op, &out_bl);
+      if (r < 0) {
+        return r;
+      }
+
+      bufferlist::iterator it = out_bl.begin();
+      return snapshot_timestamp_list_finish(&it, ids, timestamps);
+    }
+
+    void snapshot_namespace_list_start(librados::ObjectReadOperation *op,
+                                       const std::vector<snapid_t> &ids)
+    {
+      for (auto snap_id : ids) {
+        bufferlist bl;
+        ::encode(snap_id, bl);
+        op->exec("rbd", "get_snapshot_namespace", bl);
+      }
+    }
+
+    int snapshot_namespace_list_finish(bufferlist::iterator *it,
+                                       const std::vector<snapid_t> &ids,
+                                       std::vector<cls::rbd::SnapshotNamespace> *namespaces)
     {
       namespaces->resize(ids.size());
       try {
@@ -623,12 +663,12 @@ namespace librbd {
       return 0;
     }
 
-    int snap_namespace_list(librados::IoCtx *ioctx, const std::string &oid,
-                           const std::vector<snapid_t> &ids,
-                           std::vector<cls::rbd::SnapshotNamespace> *namespaces)
+    int snapshot_namespace_list(librados::IoCtx *ioctx, const std::string &oid,
+                                const std::vector<snapid_t> &ids,
+                                std::vector<cls::rbd::SnapshotNamespace> *namespaces)
     {
       librados::ObjectReadOperation op;
-      snap_namespace_list_start(&op, ids);
+      snapshot_namespace_list_start(&op, ids);
 
       bufferlist out_bl;
       int r = ioctx->operate(oid, &op, &out_bl);
@@ -637,7 +677,7 @@ namespace librbd {
       }
 
       bufferlist::iterator it = out_bl.begin();
-      return snap_namespace_list_finish(&it, ids, namespaces);
+      return snapshot_namespace_list_finish(&it, ids, namespaces);
     }
 
     void old_snapshot_add(librados::ObjectWriteOperation *op,
index 52f259d25c6fea01661d1c3938517b5f37f07a3f..c1d1bd8bdd906afde3a018b66cbd24fcdd3755f3 100644 (file)
@@ -119,6 +119,17 @@ namespace librbd {
                              std::vector<uint64_t> *sizes,
                              std::vector<parent_info> *parents,
                              std::vector<uint8_t> *protection_statuses);
+    void snapshot_timestamp_list_start(librados::ObjectReadOperation *op,
+                                       const std::vector<snapid_t> &ids);
+
+    int snapshot_timestamp_list_finish(bufferlist::iterator *it,
+                                       const std::vector<snapid_t> &ids,
+                                       std::vector<utime_t> *timestamps);
+
+    int snapshot_timestamp_list(librados::IoCtx *ioctx, const std::string &oid,
+                                const std::vector<snapid_t> &ids,
+                                std::vector<utime_t> *timestamps);
+
     int snapshot_list(librados::IoCtx *ioctx, const std::string &oid,
                      const std::vector<snapid_t> &ids,
                      std::vector<string> *names,
@@ -126,14 +137,14 @@ namespace librbd {
                      std::vector<parent_info> *parents,
                      std::vector<uint8_t> *protection_statuses);
 
-    void snap_namespace_list_start(librados::ObjectReadOperation *op,
-                                  const std::vector<snapid_t> &ids);
-    int snap_namespace_list_finish(bufferlist::iterator *it,
-                                  const std::vector<snapid_t> &ids,
-                                  std::vector<cls::rbd::SnapshotNamespace> *namespaces);
-    int snap_namespace_list(librados::IoCtx *ioctx, const std::string &oid,
-                           const std::vector<snapid_t> &ids,
-                           std::vector<cls::rbd::SnapshotNamespace> *namespaces);
+    void snapshot_namespace_list_start(librados::ObjectReadOperation *op,
+                                       const std::vector<snapid_t> &ids);
+    int snapshot_namespace_list_finish(bufferlist::iterator *it,
+                                       const std::vector<snapid_t> &ids,
+                                       std::vector<cls::rbd::SnapshotNamespace> *namespaces);
+    int snapshot_namespace_list(librados::IoCtx *ioctx, const std::string &oid,
+                                const std::vector<snapid_t> &ids,
+                                std::vector<cls::rbd::SnapshotNamespace> *namespaces);
 
     void get_all_features_start(librados::ObjectReadOperation *op);
     int get_all_features_finish(bufferlist::iterator *it,
index 45e9395a5e1b42cf1d987c3e9596ae97b1a07a08..1bdc3551e9fd5d1883d8efa24236952a46ee68f2 100644 (file)
@@ -424,6 +424,15 @@ CEPH_RBD_API int rbd_snap_get_limit(rbd_image_t image, uint64_t *limit);
  */
 CEPH_RBD_API int rbd_snap_set_limit(rbd_image_t image, uint64_t limit);
 
+/**
+ * Get the timestamp of a snapshot for an image. 
+ *
+ * @param snap_id the snap id of a snapshot of input image.
+ * @param timestamp the timestamp of input snapshot.
+ * @returns 0 on success, negative error code on failure
+ */
+CEPH_RBD_API int rbd_snap_get_timestamp(rbd_image_t image, uint64_t snap_id, struct timespec *timestamp);
+
 CEPH_RBD_API int rbd_snap_set(rbd_image_t image, const char *snapname);
 
 CEPH_RBD_API int rbd_flatten(rbd_image_t image);
index 0ac92dea3c77fbce305a63a6896a9093cf24fed9..66b62fd5cb66b9b758a91260a100d31833e0113b 100644 (file)
@@ -296,6 +296,7 @@ public:
   int snap_rename(const char *srcname, const char *dstname);
   int snap_get_limit(uint64_t *limit);
   int snap_set_limit(uint64_t limit);
+  int snap_get_timestamp(uint64_t snap_id, struct timespec *timestamp);
 
   /* I/O */
   ssize_t read(uint64_t ofs, size_t len, ceph::bufferlist& bl);
index 3bd0b98a629cf5399b60e2120d78582ff42763fb..f5de553f49a4acdaa51b1911bf9e7036c80cc2a0 100644 (file)
@@ -17,11 +17,12 @@ namespace librbd {
     parent_info parent;
     uint8_t protection_status;
     uint64_t flags;
+    utime_t timestamp;
     SnapInfo(std::string _name, const cls::rbd::SnapshotNamespace &_snap_namespace,
             uint64_t _size, parent_info _parent,
-             uint8_t _protection_status, uint64_t _flags)
+             uint8_t _protection_status, uint64_t _flags, utime_t _timestamp)
       : name(_name), snap_namespace(_snap_namespace), size(_size), parent(_parent),
-       protection_status(_protection_status), flags(_flags) {}
+       protection_status(_protection_status), flags(_flags), timestamp(_timestamp) {}
   };
 }
 
index 9884a12bf9ce3219957c4250a4e34db26770b70e..16a76def4e3bb7b42bedfc95ac33fbbdf73b4d35 100644 (file)
@@ -142,11 +142,12 @@ Context *RefreshRequest<I>::handle_v1_get_snapshots(int *result) {
   }
 
   //m_snap_namespaces = {m_snap_names.size(), cls::rbd::UserSnapshotNamespace()};
-  m_snap_namespaces = std::vector
-                             <cls::rbd::SnapshotNamespace>(
+  m_snap_namespaces = std::vector<cls::rbd::SnapshotNamespace>(
                                            m_snap_names.size(),
                                            cls::rbd::UserSnapshotNamespace());
 
+  m_snap_timestamps = std::vector<utime_t>(m_snap_names.size(), utime_t());
+
   send_v1_get_locks();
   return nullptr;
 }
@@ -392,6 +393,7 @@ void RefreshRequest<I>::send_v2_get_snapshots() {
     m_snap_sizes.clear();
     m_snap_parents.clear();
     m_snap_protection.clear();
+    m_snap_timestamps.clear();
     send_v2_refresh_parent();
     return;
   }
@@ -436,6 +438,49 @@ Context *RefreshRequest<I>::handle_v2_get_snapshots(int *result) {
     return m_on_finish;
   }
 
+  send_v2_get_snap_timestamps();
+  return nullptr;
+}
+
+template <typename I>
+void RefreshRequest<I>::send_v2_get_snap_timestamps() {
+  CephContext *cct = m_image_ctx.cct;
+  ldout(cct, 10) << this << " " << __func__ << dendl;
+
+  librados::ObjectReadOperation op;
+  cls_client::snapshot_timestamp_list_start(&op, m_snapc.snaps);
+
+  using klass = RefreshRequest<I>;
+  librados::AioCompletion *comp = create_rados_ack_callback<
+                 klass, &klass::handle_v2_get_snap_timestamps>(this);
+  m_out_bl.clear();
+  int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, comp, &op,
+                                 &m_out_bl);
+  assert(r == 0);
+  comp->release();
+}
+
+template <typename I>
+Context *RefreshRequest<I>::handle_v2_get_snap_timestamps(int *result) {
+  CephContext *cct = m_image_ctx.cct;
+  ldout(cct, 10) << this << " " << __func__ << ": " << "r=" << *result << dendl;
+
+  if (*result == 0) {
+    bufferlist::iterator it = m_out_bl.begin();
+    *result = cls_client::snapshot_timestamp_list_finish(&it, m_snapc.snaps, &m_snap_timestamps);
+  }
+  if (*result == -ENOENT) {
+    ldout(cct, 10) << "out-of-sync snapshot state detected" << dendl;
+    send_v2_get_mutable_metadata();
+    return nullptr;
+  } else if (*result == -EOPNOTSUPP) {
+    // Ignore it means no snap timestamps are available
+  } else if (*result < 0) {
+    lderr(cct) << "failed to retrieve snapshots: " << cpp_strerror(*result)
+               << dendl;
+    return m_on_finish;
+  }
+
   send_v2_get_snap_namespaces();
   return nullptr;
 }
@@ -446,7 +491,7 @@ void RefreshRequest<I>::send_v2_get_snap_namespaces() {
   ldout(cct, 10) << this << " " << __func__ << dendl;
 
   librados::ObjectReadOperation op;
-  cls_client::snap_namespace_list_start(&op, m_snapc.snaps);
+  cls_client::snapshot_namespace_list_start(&op, m_snapc.snaps);
 
   using klass = RefreshRequest<I>;
   librados::AioCompletion *comp = create_rados_ack_callback<
@@ -466,8 +511,8 @@ Context *RefreshRequest<I>::handle_v2_get_snap_namespaces(int *result) {
 
   if (*result == 0) {
     bufferlist::iterator it = m_out_bl.begin();
-    *result = cls_client::snap_namespace_list_finish(&it, m_snapc.snaps,
-                                                    &m_snap_namespaces);
+    *result = cls_client::snapshot_namespace_list_finish(&it, m_snapc.snaps,
+                                                         &m_snap_namespaces);
   }
   if (*result == -ENOENT) {
     ldout(cct, 10) << "out-of-sync snapshot state detected" << dendl;
@@ -1004,7 +1049,7 @@ void RefreshRequest<I>::apply() {
       }
 
       m_image_ctx.add_snap(m_snap_names[i], m_snap_namespaces[i], m_snapc.snaps[i].val,
-                           m_snap_sizes[i], parent, protection_status, flags);
+                           m_snap_sizes[i], parent, protection_status, flags, m_snap_timestamps[i]);
     }
     m_image_ctx.snapc = m_snapc;
 
index 315dd7938b37bf9ff02ccbe4ef9c67714a0353dc..8bc57ae10d7b6174e109aca45826b63b28b63e8b 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "include/int_types.h"
 #include "include/buffer.h"
+#include "include/utime.h"
 #include "common/snap_types.h"
 #include "cls/lock/cls_lock_types.h"
 #include "librbd/ImageCtx.h"
@@ -60,6 +61,9 @@ private:
    *            V2_GET_SNAPSHOTS (skip if no snaps)           |
    *                |                                         |
    *                v                                         |
+   *            V2_GET_SNAP_TIMESTAMPS                        |
+   *                |                                         |
+   *                v                                         |
    *            V2_GET_SNAP_NAMESPACES                        |
    *                |                                         |
    *                v                                         |
@@ -134,6 +138,7 @@ private:
   std::vector<parent_info> m_snap_parents;
   std::vector<uint8_t> m_snap_protection;
   std::vector<uint64_t> m_snap_flags;
+  std::vector<utime_t> m_snap_timestamps;
 
   std::map<rados::cls::lock::locker_id_t,
            rados::cls::lock::locker_info_t> m_lockers;
@@ -170,6 +175,9 @@ private:
   void send_v2_get_snap_namespaces();
   Context *handle_v2_get_snap_namespaces(int *result);
 
+  void send_v2_get_snap_timestamps();
+  Context *handle_v2_get_snap_timestamps(int *result);
+
   void send_v2_refresh_parent();
   Context *handle_v2_refresh_parent(int *result);
 
index f946f2fa51ed54c25ae8d9c0e60903e6b502ac3d..2ac4f4329d4003c4948b14cc6f5c09ed0287e3be 100644 (file)
@@ -1956,6 +1956,15 @@ void filter_out_mirror_watchers(ImageCtx *ictx,
     return r;
   }
 
+  int snap_get_timestamp(ImageCtx *ictx, uint64_t snap_id, struct timespec *timestamp)
+  {
+    std::map<librados::snap_t, SnapInfo>::iterator snap_it = ictx->snap_info.find(snap_id);
+    assert(snap_it != ictx->snap_info.end());
+    utime_t time = snap_it->second.timestamp;
+    time.to_timespec(timestamp);
+    return 0;
+  }
+
   int snap_get_limit(ImageCtx *ictx, uint64_t *limit)
   {
     int r = cls_client::snapshot_get_limit(&ictx->md_ctx, ictx->header_oid,
index 550eecf9ac5c74ce98365f7a7339e3a3d4f9c601..428c99ccd0871657a0ea58b7e53a848c534c89c5 100644 (file)
@@ -144,6 +144,7 @@ namespace librbd {
   int snap_exists(ImageCtx *ictx, const char *snap_name, bool *exists);
   int snap_get_limit(ImageCtx *ictx, uint64_t *limit);
   int snap_set_limit(ImageCtx *ictx, uint64_t limit);
+  int snap_get_timestamp(ImageCtx *ictx, uint64_t snap_id, struct timespec *timestamp);
   int snap_remove(ImageCtx *ictx, const char *snap_name, uint32_t flags, ProgressContext& pctx);
   int get_snap_namespace(ImageCtx *ictx,
                         const char *snap_name,
index 97c2ca589dc3f743f62e6c119d79f17dc7c4c13b..5cac1226d308f96258fede16bd8cb6788e7ee60b 100644 (file)
@@ -1174,6 +1174,15 @@ namespace librbd {
     return r;
   }
 
+  int Image::snap_get_timestamp(uint64_t snap_id, struct timespec *timestamp)
+  {
+    ImageCtx *ictx = (ImageCtx *)ctx;
+    tracepoint(librbd, snap_get_timestamp_enter, ictx, ictx->name.c_str());
+    int r = librbd::snap_get_timestamp(ictx, snap_id, timestamp);
+    tracepoint(librbd, snap_get_timestamp_exit, r);
+    return r;
+  }
+
   int Image::snap_get_limit(uint64_t *limit)
   {
     ImageCtx *ictx = (ImageCtx *)ctx;
@@ -2582,6 +2591,15 @@ extern "C" int rbd_snap_get_limit(rbd_image_t image, uint64_t *limit)
   return r;
 }
 
+extern "C" int rbd_snap_get_timestamp(rbd_image_t image, uint64_t snap_id, struct timespec *timestamp)
+{
+  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
+  tracepoint(librbd, snap_get_timestamp_enter, ictx, ictx->name.c_str());
+  int r = librbd::snap_get_timestamp(ictx, snap_id, timestamp);
+  tracepoint(librbd, snap_get_timestamp_exit, r);
+  return r;
+}
+
 extern "C" int rbd_snap_set_limit(rbd_image_t image, uint64_t limit)
 {
   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
index 2e1fa940c3c09bf83fc754a3974b44d0d51748d7..b4a1cd07f9f4b8bb992989ba1d4cf34ec6c64001 100644 (file)
@@ -40,6 +40,9 @@ cdef extern from "Python.h":
 
 cdef extern from "time.h":
     ctypedef long int time_t
+    cdef struct timespec:
+        time_t tv_sec
+        long tv_nsec
 
 cdef extern from "limits.h":
     cdef uint64_t INT64_MAX
@@ -235,6 +238,7 @@ cdef extern from "rbd/librbd.h" nogil:
                               int *is_protected)
     int rbd_snap_get_limit(rbd_image_t image, uint64_t *limit)
     int rbd_snap_set_limit(rbd_image_t image, uint64_t limit)
+    int rbd_snap_get_timestamp(rbd_image_t image, uint64_t snap_id, timespec *timestamp)
     int rbd_snap_set(rbd_image_t image, const char *snapname)
     int rbd_flatten(rbd_image_t image)
     int rbd_rebuild_object_map(rbd_image_t image, librbd_progress_fn_t cb,
@@ -1744,6 +1748,20 @@ cdef class Image(object):
             raise make_ex(ret, 'error setting snapshot limit for %s' % self.name)
         return ret
 
+    def get_snap_timestamp(self, snap_id):
+        """
+        Get the snapshot timestamp for an image.
+        :param snap_id: the snapshot id of a snap shot
+        """
+        cdef:
+            timespec timestamp
+            uint64_t _snap_id = snap_id
+        with nogil:
+            ret = rbd_snap_get_timestamp(self.image, _snap_id, &timestamp)
+        if ret != 0:
+            raise make_ex(ret, 'error getting snapshot timestamp for image: %s, snap_id: %d' % (self.name, snap_id))
+        return datetime.fromtimestamp(timestamp.tv_sec)
+
     def remove_snap_limit(self):
         """
         Remove the snapshot limit for an image, essentially setting
index 5f96ddb90e9ccf7a1a56c449f862c38753138fcf..e9c20434def3686546c931b7ca59499f0c730d27 100644 (file)
@@ -198,6 +198,16 @@ public:
     }
   }
 
+  void expect_snap_timestamp_list(MockRefreshImageCtx &mock_image_ctx, int r) {
+    auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
+                               exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("get_snapshot_timestamp"), _, _, _));
+       if (r < 0) {
+      expect.WillOnce(Return(r));
+    } else {
+      expect.WillOnce(DoDefault());
+    }
+  }
+
   void expect_snap_namespace_list(MockRefreshImageCtx &mock_image_ctx, int r) {
     auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
                                exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("get_snapshot_namespace"), _, _, _));
@@ -421,6 +431,7 @@ TEST_F(TestMockImageRefreshRequest, SuccessSnapshotV2) {
   expect_get_flags(mock_image_ctx, 0);
   expect_get_group(mock_image_ctx, 0);
   expect_get_snapshots(mock_image_ctx, 0);
+  expect_snap_timestamp_list(mock_image_ctx, 0);
   expect_snap_namespace_list(mock_image_ctx, 0);
   expect_refresh_parent_is_required(mock_refresh_parent_request, false);
   if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
@@ -455,6 +466,7 @@ TEST_F(TestMockImageRefreshRequest, SuccessSetSnapshotV2) {
   expect_get_flags(mock_image_ctx, 0);
   expect_get_group(mock_image_ctx, 0);
   expect_get_snapshots(mock_image_ctx, 0);
+  expect_snap_timestamp_list(mock_image_ctx, 0);
   expect_snap_namespace_list(mock_image_ctx, 0);
   expect_refresh_parent_is_required(mock_refresh_parent_request, false);
   if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
index 209ae1dbc1f2275e829b4bd5769a04d4f5251717..15b975aabf4763c04315ee4b04672ba7261b46e9 100644 (file)
@@ -35,18 +35,29 @@ int do_list_snaps(librbd::Image& image, Formatter *f)
     t.define_column("SNAPID", TextTable::RIGHT, TextTable::RIGHT);
     t.define_column("NAME", TextTable::LEFT, TextTable::LEFT);
     t.define_column("SIZE", TextTable::RIGHT, TextTable::RIGHT);
+    t.define_column("TIMESTAMP", TextTable::LEFT, TextTable::LEFT);
   }
 
   for (std::vector<librbd::snap_info_t>::iterator s = snaps.begin();
        s != snaps.end(); ++s) {
+    struct timespec timestamp;
+    image.snap_get_timestamp(s->id, &timestamp);
+    string tt_str = "";
+    if(timestamp.tv_sec != 0) {
+      time_t tt = timestamp.tv_sec;
+      tt_str = ctime(&tt);
+      tt_str = tt_str.substr(0, tt_str.length() - 1);  
+    }
+
     if (f) {
       f->open_object_section("snapshot");
       f->dump_unsigned("id", s->id);
       f->dump_string("name", s->name);
       f->dump_unsigned("size", s->size);
+      f->dump_string("timestamp", tt_str);
       f->close_section();
     } else {
-      t << s->id << s->name << stringify(prettybyte_t(s->size))
+      t << s->id << s->name << stringify(prettybyte_t(s->size)) << tt_str
         << TextTable::endrow;
     }
   }
index 70074ca843e60011c4102bdd9204b358c92aba32..0652210076eb064cdb328167f276c42f267775fa 100644 (file)
@@ -1316,6 +1316,24 @@ TRACEPOINT_EVENT(librbd, snap_exists_exit,
     )
 )
 
+TRACEPOINT_EVENT(librbd, snap_get_timestamp_enter,
+    TP_ARGS(
+        void*, imagectx,
+        const char*, name),
+    TP_FIELDS(
+        ctf_integer_hex(void*, imagectx, imagectx)
+        ctf_string(name, name)
+    )    
+)
+
+TRACEPOINT_EVENT(librbd, snap_get_timestamp_exit,
+    TP_ARGS(
+        int, retval),
+       TP_FIELDS(
+        ctf_integer(int, retval, retval)
+    )
+)
+
 TRACEPOINT_EVENT(librbd, snap_get_limit_enter,
     TP_ARGS(
         void*, imagectx,