]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: move object map async ops to standalone classes
authorJason Dillaman <dillaman@redhat.com>
Wed, 12 Aug 2015 14:31:53 +0000 (10:31 -0400)
committerJason Dillaman <dillaman@redhat.com>
Thu, 19 Nov 2015 01:34:33 +0000 (20:34 -0500)
In preparation for creating new async snapshot-related object map
operations, move the existing object map async ops to there own
namespace.

Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/librbd/CopyupRequest.cc
src/librbd/ImageCtx.h
src/librbd/Makefile.am
src/librbd/ObjectMap.cc
src/librbd/ObjectMap.h
src/librbd/object_map/Request.cc [new file with mode: 0644]
src/librbd/object_map/Request.h [new file with mode: 0644]
src/librbd/object_map/ResizeRequest.cc [new file with mode: 0644]
src/librbd/object_map/ResizeRequest.h [new file with mode: 0644]
src/librbd/object_map/UpdateRequest.cc [new file with mode: 0644]
src/librbd/object_map/UpdateRequest.h [new file with mode: 0644]

index 5c3973a2b97f53b2cfb571a9a54f46ed66dbef6a..fdb3d62708003aa02b8585866b59f17e02b196d1 100644 (file)
@@ -57,6 +57,7 @@ public:
       state = OBJECT_EXISTS_CLEAN;
     }
 
+    RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
     RWLock::RLocker object_map_locker(m_image_ctx.object_map_lock);
     m_image_ctx.object_map.aio_update(snap_id, m_object_no, m_object_no + 1,
                                       state, boost::optional<uint8_t>(), this);
index d7010e3b91363ff87781871f1560f098550315fd..28e8f7455afbc0e7a519e16053ef6145c131c258 100644 (file)
@@ -25,6 +25,7 @@
 #include "osdc/ObjectCacher.h"
 
 #include "cls/rbd/cls_rbd_client.h"
+#include "librbd/AsyncRequest.h"
 #include "librbd/LibrbdWriteback.h"
 #include "librbd/ObjectMap.h"
 #include "librbd/SnapInfo.h"
@@ -37,9 +38,9 @@ class PerfCounters;
 
 namespace librbd {
 
+  struct ImageCtx;
   class AioImageRequestWQ;
   class AsyncOperation;
-  template <typename ImageCtxT> class AsyncRequest;
   class CopyupRequest;
   class LibrbdAdminSocketHook;
   class ImageWatcher;
index 246e94c11a4ce1d9791d0d9f27cfc356a125e5ac..0d8f5b64f85e37bfd61aee152d1d14b53cf4b5d2 100644 (file)
@@ -25,6 +25,9 @@ librbd_internal_la_SOURCES = \
        librbd/LibrbdAdminSocketHook.cc \
        librbd/LibrbdWriteback.cc \
        librbd/ObjectMap.cc \
+       librbd/object_map/Request.cc \
+       librbd/object_map/ResizeRequest.cc \
+       librbd/object_map/UpdateRequest.cc \
        librbd/operation/FlattenRequest.cc \
        librbd/operation/RebuildObjectMapRequest.cc \
        librbd/operation/Request.cc \
@@ -83,6 +86,9 @@ noinst_HEADERS += \
        librbd/SnapInfo.h \
        librbd/TaskFinisher.h \
        librbd/WatchNotifyTypes.h \
+       librbd/object_map/Request.h \
+       librbd/object_map/ResizeRequest.h \
+       librbd/object_map/UpdateRequest.h \
        librbd/operation/FlattenRequest.h \
        librbd/operation/RebuildObjectMapRequest.h \
        librbd/operation/Request.h \
index e1f2e17796ffac22bb8b9f2ff55695762f7e0107..fdfd211b962711a615cd09f3cc334ed4ddf43180 100644 (file)
@@ -4,6 +4,8 @@
 #include "librbd/ImageCtx.h"
 #include "librbd/ImageWatcher.h"
 #include "librbd/internal.h"
+#include "librbd/object_map/ResizeRequest.h"
+#include "librbd/object_map/UpdateRequest.h"
 #include "common/dout.h"
 #include "common/errno.h"
 #include "include/stringify.h"
@@ -200,7 +202,8 @@ void ObjectMap::refresh(uint64_t snap_id)
     r = m_image_ctx.md_ctx.operate(oid, &op);
     if (r == 0) {
       m_object_map.clear();
-      resize(num_objs, OBJECT_NONEXISTENT);
+      object_map::ResizeRequest::resize(&m_object_map, num_objs,
+                                        OBJECT_NONEXISTENT);
     }
   }
   if (r < 0) {
@@ -229,7 +232,8 @@ void ObjectMap::refresh(uint64_t snap_id)
 
     r = m_image_ctx.md_ctx.operate(oid, &op);
     if (r == 0) {
-      resize(num_objs, OBJECT_NONEXISTENT);
+      object_map::ResizeRequest::resize(&m_object_map, num_objs,
+                                        OBJECT_NONEXISTENT);
     }
   } else if (m_object_map.size() > num_objs) {
     // resize op might have been interrupted
@@ -437,8 +441,9 @@ void ObjectMap::aio_resize(uint64_t new_size, uint8_t default_object_state,
   assert(!m_image_ctx.image_watcher->is_lock_supported() ||
          m_image_ctx.image_watcher->is_lock_owner());
 
-  ResizeRequest *req = new ResizeRequest(
-    m_image_ctx, m_snap_id, new_size, default_object_state, on_finish);
+  object_map::ResizeRequest *req = new object_map::ResizeRequest(
+    m_image_ctx, &m_object_map, m_snap_id, new_size, default_object_state,
+    on_finish);
   req->send();
 }
 
@@ -493,10 +498,9 @@ void ObjectMap::aio_update(uint64_t snap_id, uint64_t start_object_no,
                            uint64_t end_object_no, uint8_t new_state,
                            const boost::optional<uint8_t> &current_state,
                            Context *on_finish) {
-  UpdateRequest *req = new UpdateRequest(m_image_ctx, snap_id,
-                                         start_object_no, end_object_no,
-                                         new_state, current_state,
-                                         on_finish);
+  object_map::UpdateRequest *req = new object_map::UpdateRequest(
+    m_image_ctx, &m_object_map, snap_id, start_object_no, end_object_no,
+    new_state, current_state, on_finish);
   req->send();
 }
 
@@ -546,161 +550,4 @@ void ObjectMap::invalidate(uint64_t snap_id, bool force) {
   }
 }
 
-void ObjectMap::resize(uint64_t num_objs, uint8_t defualt_state) {
-  size_t orig_object_map_size = m_object_map.size();
-  m_object_map.resize(num_objs);
-  for (uint64_t i = orig_object_map_size;
-       i < m_object_map.size(); ++i) {
-    m_object_map[i] = defualt_state;
-  }
-}
-
-bool ObjectMap::Request::should_complete(int r) {
-  CephContext *cct = m_image_ctx.cct;
-  ldout(cct, 20) << &m_image_ctx << " should_complete: r=" << r << dendl;
-
-  switch (m_state)
-  {
-  case STATE_REQUEST:
-    if (r == -EBUSY) {
-      lderr(cct) << "object map lock not owned by client" << dendl;
-      return invalidate();
-    } else if (r < 0) {
-      lderr(cct) << "failed to update object map: " << cpp_strerror(r)
-                << dendl;
-      return invalidate();
-    }
-
-    {
-      RWLock::WLocker l2(m_image_ctx.object_map_lock);
-      finish(&m_image_ctx.object_map);
-    }
-    return true;
-
-  case STATE_INVALIDATE:
-    ldout(cct, 20) << "INVALIDATE" << dendl;
-    if (r < 0) {
-      lderr(cct) << "failed to invalidate object map: " << cpp_strerror(r)
-                << dendl;
-    }
-    return true;
-
-  default:
-    lderr(cct) << "invalid state: " << m_state << dendl;
-    assert(false);
-    break;
-  }
-  return false;
-}
-
-bool ObjectMap::Request::invalidate() {
-  if (m_image_ctx.test_flags(RBD_FLAG_OBJECT_MAP_INVALID)) {
-    return true;
-  }
-
-  CephContext *cct = m_image_ctx.cct;
-  RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
-
-  // requests shouldn't be running while using snapshots
-  assert(m_image_ctx.snap_id == CEPH_NOSNAP);
-
-  uint64_t flags = RBD_FLAG_OBJECT_MAP_INVALID;
-  if ((m_image_ctx.features & RBD_FEATURE_FAST_DIFF) != 0) {
-    flags |= RBD_FLAG_FAST_DIFF_INVALID;
-  }
-
-  lderr(cct) << &m_image_ctx << " invalidating object map" << dendl;
-  m_state = STATE_INVALIDATE;
-  m_image_ctx.flags |= flags;
-
-  librados::ObjectWriteOperation op;
-  cls_client::set_flags(&op, CEPH_NOSNAP, flags, flags);
-
-  librados::AioCompletion *rados_completion = create_callback_completion();
-  int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid,
-                                        rados_completion, &op);
-  assert(r == 0);
-  rados_completion->release();
-  return false;
-}
-
-void ObjectMap::ResizeRequest::send() {
-  CephContext *cct = m_image_ctx.cct;
-
-  RWLock::WLocker l(m_image_ctx.object_map_lock);
-  m_num_objs = Striper::get_num_objects(m_image_ctx.layout, m_new_size);
-
-  ldout(cct, 5) << &m_image_ctx << " resizing on-disk object map: "
-               << m_num_objs << dendl;
-
-  librados::ObjectWriteOperation op;
-  if (m_snap_id == CEPH_NOSNAP) {
-    rados::cls::lock::assert_locked(&op, RBD_LOCK_NAME, LOCK_EXCLUSIVE, "", "");
-  }
-  cls_client::object_map_resize(&op, m_num_objs, m_default_object_state);
-
-  librados::AioCompletion *rados_completion = create_callback_completion();
-  std::string oid(object_map_name(m_image_ctx.id, m_snap_id));
-  int r = m_image_ctx.md_ctx.aio_operate(oid, rados_completion, &op);
-  assert(r == 0);
-  rados_completion->release();
-}
-
-void ObjectMap::ResizeRequest::finish(ObjectMap *object_map) {
-  CephContext *cct = m_image_ctx.cct;
-
-  ldout(cct, 5) << &m_image_ctx << " resizing in-memory object map: "
-               << m_num_objs << dendl;
-  object_map->resize(m_num_objs, m_default_object_state);
-}
-
-void ObjectMap::UpdateRequest::send() {
-  assert(m_image_ctx.object_map_lock.is_locked());
-  CephContext *cct = m_image_ctx.cct;
-
-  // safe to update in-memory state first without handling rollback since any
-  // failures will invalidate the object map
-  ldout(cct, 20) << &m_image_ctx << " updating object map"
-                 << (m_snap_id != CEPH_NOSNAP ?
-                       " snap " + stringify(m_snap_id) : std::string())
-                 << ": ["
-                << m_start_object_no << "," << m_end_object_no << ") = "
-                << (m_current_state ?
-                      stringify(static_cast<uint32_t>(*m_current_state)) : "")
-                << "->" << static_cast<uint32_t>(m_new_state)
-                << dendl;
-
-  ObjectMap& object_map = m_image_ctx.object_map;
-  if (m_snap_id == object_map.m_snap_id) {
-    assert(m_image_ctx.object_map_lock.is_wlocked());
-    for (uint64_t object_no = m_start_object_no;
-         object_no < MIN(m_end_object_no, object_map.m_object_map.size());
-         ++object_no) {
-      uint8_t state = object_map.m_object_map[object_no];
-      if (!m_current_state || state == *m_current_state ||
-          (*m_current_state == OBJECT_EXISTS && state == OBJECT_EXISTS_CLEAN)) {
-        object_map.m_object_map[object_no] = m_new_state;
-      }
-    }
-  }
-
-  librados::ObjectWriteOperation op;
-  if (m_snap_id == CEPH_NOSNAP) {
-    rados::cls::lock::assert_locked(&op, RBD_LOCK_NAME, LOCK_EXCLUSIVE, "", "");
-  }
-  cls_client::object_map_update(&op, m_start_object_no, m_end_object_no,
-                               m_new_state, m_current_state);
-
-  librados::AioCompletion *rados_completion = create_callback_completion();
-  std::string oid(object_map_name(m_image_ctx.id, m_snap_id));
-  int r = m_image_ctx.md_ctx.aio_operate(oid, rados_completion, &op);
-  assert(r == 0);
-  rados_completion->release();
-}
-
-void ObjectMap::UpdateRequest::finish(ObjectMap *object_map) {
-  ldout(m_image_ctx.cct, 20) << &m_image_ctx << " on-disk object map updated"
-                             << dendl;
-}
-
 } // namespace librbd
index f0d1bbe9434b1e058e0656a94accebbb0249783f..b175c3669ff2a432d668673b8175d6ce6977c99b 100644 (file)
@@ -7,7 +7,6 @@
 #include "include/rados/librados.hpp"
 #include "include/rbd/object_map_types.h"
 #include "common/bit_vector.hpp"
-#include "librbd/AsyncRequest.h"
 #include <boost/optional.hpp>
 
 class Context;
@@ -60,89 +59,12 @@ public:
   bool enabled() const;
 
 private:
-
-  class Request : public AsyncRequest<> {
-  public:
-    Request(ImageCtx &image_ctx, uint64_t snap_id, Context *on_finish)
-      : AsyncRequest(image_ctx, on_finish), m_snap_id(snap_id),
-        m_state(STATE_REQUEST)
-    {
-    }
-
-  protected:
-    const uint64_t m_snap_id;
-
-    virtual bool should_complete(int r);
-    virtual int filter_return_code(int r) const {
-      // never propagate an error back to the caller
-      return 0;
-    }
-    virtual void finish(ObjectMap *object_map) = 0;
-  private:
-    /**
-     * <start> ---> STATE_REQUEST ---> <finish>
-     *                   |                ^
-     *                   v                |
-     *            STATE_INVALIDATE -------/
-     */
-    enum State {
-      STATE_REQUEST,
-      STATE_INVALIDATE
-    };
-
-    State m_state;
-
-    bool invalidate();
-  };
-
-  class ResizeRequest : public Request {
-  public:
-    ResizeRequest(ImageCtx &image_ctx, uint64_t snap_id, uint64_t new_size,
-                 uint8_t default_object_state, Context *on_finish)
-      : Request(image_ctx, snap_id, on_finish), m_num_objs(0),
-        m_new_size(new_size), m_default_object_state(default_object_state)
-    {
-    }
-
-    virtual void send();
-  protected:
-    virtual void finish(ObjectMap *object_map);
-  private:
-    uint64_t m_num_objs;
-    uint64_t m_new_size;
-    uint8_t m_default_object_state;
-  };
-
-  class UpdateRequest : public Request {
-  public:
-    UpdateRequest(ImageCtx &image_ctx, uint64_t snap_id,
-                  uint64_t start_object_no, uint64_t end_object_no,
-                  uint8_t new_state,
-                  const boost::optional<uint8_t> &current_state,
-                 Context *on_finish)
-      : Request(image_ctx, snap_id, on_finish),
-        m_start_object_no(start_object_no), m_end_object_no(end_object_no),
-        m_new_state(new_state), m_current_state(current_state)
-    {
-    }
-
-    virtual void send();
-  protected:
-    virtual void finish(ObjectMap *object_map);
-  private:
-    uint64_t m_start_object_no;
-    uint64_t m_end_object_no;
-    uint8_t m_new_state;
-    boost::optional<uint8_t> m_current_state;
-  };
-
   ImageCtx &m_image_ctx;
   ceph::BitVector<2> m_object_map;
   uint64_t m_snap_id;
   bool m_enabled;
 
   void invalidate(uint64_t snap_id, bool force);
-  void resize(uint64_t num_objs, uint8_t default_state);
 };
 
 } // namespace librbd
diff --git a/src/librbd/object_map/Request.cc b/src/librbd/object_map/Request.cc
new file mode 100644 (file)
index 0000000..706c87c
--- /dev/null
@@ -0,0 +1,90 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "librbd/object_map/Request.h"
+#include "include/rados/librados.hpp"
+#include "include/rbd/librbd.hpp"
+#include "common/dout.h"
+#include "common/errno.h"
+#include "common/RWLock.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/ImageWatcher.h"
+
+#define dout_subsys ceph_subsys_rbd
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::object_map::Request: "
+
+namespace librbd {
+namespace object_map {
+
+bool Request::should_complete(int r) {
+  CephContext *cct = m_image_ctx.cct;
+  ldout(cct, 20) << &m_image_ctx << " should_complete: r=" << r << dendl;
+
+  switch (m_state)
+  {
+  case STATE_REQUEST:
+    if (r == -EBUSY) {
+      lderr(cct) << "object map lock not owned by client" << dendl;
+      return invalidate();
+    } else if (r < 0) {
+      lderr(cct) << "failed to update object map: " << cpp_strerror(r)
+                << dendl;
+      return invalidate();
+    }
+
+    {
+      RWLock::WLocker l2(m_image_ctx.object_map_lock);
+      finish();
+    }
+    return true;
+
+  case STATE_INVALIDATE:
+    ldout(cct, 20) << "INVALIDATE" << dendl;
+    if (r < 0) {
+      lderr(cct) << "failed to invalidate object map: " << cpp_strerror(r)
+                << dendl;
+    }
+    return true;
+
+  default:
+    lderr(cct) << "invalid state: " << m_state << dendl;
+    assert(false);
+    break;
+  }
+  return false;
+}
+
+bool Request::invalidate() {
+  if (m_image_ctx.test_flags(RBD_FLAG_OBJECT_MAP_INVALID)) {
+    return true;
+  }
+
+  CephContext *cct = m_image_ctx.cct;
+  RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
+
+  // requests shouldn't be running while using snapshots
+  assert(m_image_ctx.snap_id == CEPH_NOSNAP);
+
+  uint64_t flags = RBD_FLAG_OBJECT_MAP_INVALID;
+  if ((m_image_ctx.features & RBD_FEATURE_FAST_DIFF) != 0) {
+    flags |= RBD_FLAG_FAST_DIFF_INVALID;
+  }
+
+  lderr(cct) << &m_image_ctx << " invalidating object map" << dendl;
+  m_state = STATE_INVALIDATE;
+  m_image_ctx.flags |= flags;
+
+  librados::ObjectWriteOperation op;
+  cls_client::set_flags(&op, CEPH_NOSNAP, flags, flags);
+
+  librados::AioCompletion *rados_completion = create_callback_completion();
+  int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid,
+                                        rados_completion, &op);
+  assert(r == 0);
+  rados_completion->release();
+  return false;
+}
+
+} // namespace object_map
+} // namespace librbd
diff --git a/src/librbd/object_map/Request.h b/src/librbd/object_map/Request.h
new file mode 100644 (file)
index 0000000..fdc22de
--- /dev/null
@@ -0,0 +1,58 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_OBJECT_MAP_REQUEST_H
+#define CEPH_LIBRBD_OBJECT_MAP_REQUEST_H
+
+#include "include/int_types.h"
+#include "librbd/AsyncRequest.h"
+
+class Context;
+
+namespace librbd {
+
+class ImageCtx;
+
+namespace object_map {
+
+class Request : public AsyncRequest<> {
+public:
+  Request(ImageCtx &image_ctx, uint64_t snap_id, Context *on_finish)
+    : AsyncRequest(image_ctx, on_finish), m_snap_id(snap_id),
+      m_state(STATE_REQUEST)
+  {
+  }
+
+  virtual void send() = 0;
+
+protected:
+  const uint64_t m_snap_id;
+
+  virtual bool should_complete(int r);
+  virtual int filter_return_code(int r) const {
+    // never propagate an error back to the caller
+    return 0;
+  }
+  virtual void finish() = 0;
+
+private:
+  /**
+   * <start> ---> STATE_REQUEST ---> <finish>
+   *                   |                ^
+   *                   v                |
+   *            STATE_INVALIDATE -------/
+   */
+  enum State {
+    STATE_REQUEST,
+    STATE_INVALIDATE
+  };
+
+  State m_state;
+
+  bool invalidate();
+};
+
+} // namespace object_map
+} // namespace librbd
+
+#endif // CEPH_LIBRBD_OBJECT_MAP_REQUEST_H
diff --git a/src/librbd/object_map/ResizeRequest.cc b/src/librbd/object_map/ResizeRequest.cc
new file mode 100644 (file)
index 0000000..8bdb64c
--- /dev/null
@@ -0,0 +1,58 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "librbd/object_map/ResizeRequest.h"
+#include "common/dout.h"
+#include "common/errno.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/ObjectMap.h"
+#include "cls/lock/cls_lock_client.h"
+
+#define dout_subsys ceph_subsys_rbd
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::object_map::ResizeRequest: "
+
+namespace librbd {
+namespace object_map {
+
+void ResizeRequest::resize(ceph::BitVector<2> *object_map, uint64_t num_objs,
+                           uint8_t default_state) {
+  size_t orig_object_map_size = object_map->size();
+  object_map->resize(num_objs);
+  for (uint64_t i = orig_object_map_size; i < object_map->size(); ++i) {
+    (*object_map)[i] = default_state;
+  }
+}
+
+void ResizeRequest::send() {
+  CephContext *cct = m_image_ctx.cct;
+
+  RWLock::WLocker l(m_image_ctx.object_map_lock);
+  m_num_objs = Striper::get_num_objects(m_image_ctx.layout, m_new_size);
+
+  ldout(cct, 5) << &m_image_ctx << " resizing on-disk object map: "
+               << m_num_objs << dendl;
+
+  librados::ObjectWriteOperation op;
+  if (m_snap_id == CEPH_NOSNAP) {
+    rados::cls::lock::assert_locked(&op, RBD_LOCK_NAME, LOCK_EXCLUSIVE, "", "");
+  }
+  cls_client::object_map_resize(&op, m_num_objs, m_default_object_state);
+
+  librados::AioCompletion *rados_completion = create_callback_completion();
+  std::string oid(ObjectMap::object_map_name(m_image_ctx.id, m_snap_id));
+  int r = m_image_ctx.md_ctx.aio_operate(oid, rados_completion, &op);
+  assert(r == 0);
+  rados_completion->release();
+}
+
+void ResizeRequest::finish() {
+  CephContext *cct = m_image_ctx.cct;
+
+  ldout(cct, 5) << &m_image_ctx << " resizing in-memory object map: "
+               << m_num_objs << dendl;
+  resize(m_object_map, m_num_objs, m_default_object_state);
+}
+
+} // namespace object_map
+} // namespace librbd
diff --git a/src/librbd/object_map/ResizeRequest.h b/src/librbd/object_map/ResizeRequest.h
new file mode 100644 (file)
index 0000000..ca95393
--- /dev/null
@@ -0,0 +1,48 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_OBJECT_MAP_RESIZE_REQUEST_H
+#define CEPH_LIBRBD_OBJECT_MAP_RESIZE_REQUEST_H
+
+#include "include/int_types.h"
+#include "librbd/object_map/Request.h"
+#include "common/bit_vector.hpp"
+
+class Context;
+
+namespace librbd {
+
+class ImageCtx;
+
+namespace object_map {
+
+class ResizeRequest : public Request {
+public:
+  ResizeRequest(ImageCtx &image_ctx, ceph::BitVector<2> *object_map,
+                uint64_t snap_id, uint64_t new_size,
+         uint8_t default_object_state, Context *on_finish)
+    : Request(image_ctx, snap_id, on_finish), m_object_map(object_map),
+      m_num_objs(0), m_new_size(new_size),
+      m_default_object_state(default_object_state)
+  {
+  }
+
+  static void resize(ceph::BitVector<2> *object_map, uint64_t num_objs,
+                     uint8_t default_state);
+
+  virtual void send();
+
+protected:
+  virtual void finish();
+
+private:
+  ceph::BitVector<2> *m_object_map;
+  uint64_t m_num_objs;
+  uint64_t m_new_size;
+  uint8_t m_default_object_state;
+};
+
+} // namespace object_map
+} // namespace librbd
+
+#endif // CEPH_LIBRBD_OBJECT_MAP_RESIZE_REQUEST_H
diff --git a/src/librbd/object_map/UpdateRequest.cc b/src/librbd/object_map/UpdateRequest.cc
new file mode 100644 (file)
index 0000000..eef5488
--- /dev/null
@@ -0,0 +1,72 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "librbd/object_map/UpdateRequest.h"
+#include "include/rbd/object_map_types.h"
+#include "include/stringify.h"
+#include "common/dout.h"
+#include "common/errno.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/ObjectMap.h"
+#include "cls/lock/cls_lock_client.h"
+#include <string>
+
+#define dout_subsys ceph_subsys_rbd
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::object_map::UpdateRequest: "
+
+namespace librbd {
+namespace object_map {
+
+void UpdateRequest::send() {
+  assert(m_image_ctx.snap_lock.is_locked());
+  assert(m_image_ctx.object_map_lock.is_locked());
+  CephContext *cct = m_image_ctx.cct;
+
+  // safe to update in-memory state first without handling rollback since any
+  // failures will invalidate the object map
+  ldout(cct, 20) << &m_image_ctx << " updating object map"
+                 << (m_snap_id != CEPH_NOSNAP ?
+                       " snap " + stringify(m_snap_id) : std::string())
+                 << ": ["
+                << m_start_object_no << "," << m_end_object_no << ") = "
+                << (m_current_state ?
+                      stringify(static_cast<uint32_t>(*m_current_state)) : "")
+                << "->" << static_cast<uint32_t>(m_new_state)
+                << dendl;
+
+  // rebuilding the object map might update on-disk only
+  if (m_snap_id == m_image_ctx.snap_id) {
+    assert(m_image_ctx.object_map_lock.is_wlocked());
+    for (uint64_t object_no = m_start_object_no;
+         object_no < MIN(m_end_object_no, m_object_map.size());
+         ++object_no) {
+      uint8_t state = m_object_map[object_no];
+      if (!m_current_state || state == *m_current_state ||
+          (*m_current_state == OBJECT_EXISTS && state == OBJECT_EXISTS_CLEAN)) {
+        m_object_map[object_no] = m_new_state;
+      }
+    }
+  }
+
+  librados::ObjectWriteOperation op;
+  if (m_snap_id == CEPH_NOSNAP) {
+    rados::cls::lock::assert_locked(&op, RBD_LOCK_NAME, LOCK_EXCLUSIVE, "", "");
+  }
+  cls_client::object_map_update(&op, m_start_object_no, m_end_object_no,
+                               m_new_state, m_current_state);
+
+  librados::AioCompletion *rados_completion = create_callback_completion();
+  std::string oid(ObjectMap::object_map_name(m_image_ctx.id, m_snap_id));
+  int r = m_image_ctx.md_ctx.aio_operate(oid, rados_completion, &op);
+  assert(r == 0);
+  rados_completion->release();
+}
+
+void UpdateRequest::finish() {
+  ldout(m_image_ctx.cct, 20) << &m_image_ctx << " on-disk object map updated"
+                             << dendl;
+}
+
+} // namespace object_map
+} // namespace librbd
diff --git a/src/librbd/object_map/UpdateRequest.h b/src/librbd/object_map/UpdateRequest.h
new file mode 100644 (file)
index 0000000..6c277b0
--- /dev/null
@@ -0,0 +1,49 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_OBJECT_MAP_UPDATE_REQUEST_H
+#define CEPH_LIBRBD_OBJECT_MAP_UPDATE_REQUEST_H
+
+#include "include/int_types.h"
+#include "librbd/object_map/Request.h"
+#include "common/bit_vector.hpp"
+#include <boost/optional.hpp>
+
+class Context;
+
+namespace librbd {
+
+class ImageCtx;
+
+namespace object_map {
+
+class UpdateRequest : public Request {
+public:
+  UpdateRequest(ImageCtx &image_ctx, ceph::BitVector<2> *object_map,
+                uint64_t snap_id, uint64_t start_object_no,
+                uint64_t end_object_no, uint8_t new_state,
+                const boost::optional<uint8_t> &current_state,
+         Context *on_finish)
+    : Request(image_ctx, snap_id, on_finish), m_object_map(*object_map),
+      m_start_object_no(start_object_no), m_end_object_no(end_object_no),
+      m_new_state(new_state), m_current_state(current_state)
+  {
+  }
+
+  virtual void send();
+
+protected:
+  virtual void finish();
+
+private:
+  ceph::BitVector<2> &m_object_map;
+  uint64_t m_start_object_no;
+  uint64_t m_end_object_no;
+  uint8_t m_new_state;
+  boost::optional<uint8_t> m_current_state;
+};
+
+} // namespace object_map
+} // namespace librbd
+
+#endif // CEPH_LIBRBD_OBJECT_MAP_UPDATE_REQUEST_H