]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: guard object map against incompatible image sizes 9039/head
authorJason Dillaman <dillaman@redhat.com>
Wed, 4 May 2016 21:00:59 +0000 (17:00 -0400)
committerJason Dillaman <dillaman@redhat.com>
Tue, 10 May 2016 17:31:47 +0000 (13:31 -0400)
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
(cherry picked from commit 42d3d3ac2d33360aae071330cfa34b87c87eadc5)

src/librbd/ObjectMap.cc
src/librbd/ObjectMap.h
src/librbd/Operations.cc
src/librbd/internal.cc

index 59d3a363585f47e4650f05d437c58dc8268aa0a2..9f7d1d4a45cf3fc22cefb59d8febc67e2240c1b9 100644 (file)
 #include "common/dout.h"
 #include "common/errno.h"
 #include "common/WorkQueue.h"
-#include "include/stringify.h"
 #include "cls/lock/cls_lock_client.h"
+#include "cls/rbd/cls_rbd_types.h"
+#include "include/stringify.h"
+#include "osdc/Striper.h"
 #include <sstream>
 
 #define dout_subsys ceph_subsys_rbd
@@ -48,6 +50,11 @@ std::string ObjectMap::object_map_name(const std::string &image_id,
   return oid;
 }
 
+bool ObjectMap::is_compatible(const file_layout_t& layout, uint64_t size) {
+  uint64_t object_count = Striper::get_num_objects(layout, size);
+  return (object_count <= cls::rbd::MAX_OBJECT_MAP_OBJECT_COUNT);
+}
+
 ceph::BitVector<2u>::Reference ObjectMap::operator[](uint64_t object_no)
 {
   assert(m_image_ctx.object_map_lock.is_wlocked());
index a2868aa6ef64f0fdb6be284931da4539da4a4e9f..f2852961aa38edc819596e0cd1e08b8de9bc6eaf 100644 (file)
@@ -4,6 +4,7 @@
 #define CEPH_LIBRBD_OBJECT_MAP_H
 
 #include "include/int_types.h"
+#include "include/fs_types.h"
 #include "include/rados/librados.hpp"
 #include "include/rbd/object_map_types.h"
 #include "common/bit_vector.hpp"
@@ -24,6 +25,8 @@ public:
   static std::string object_map_name(const std::string &image_id,
                                     uint64_t snap_id);
 
+  static bool is_compatible(const file_layout_t& layout, uint64_t size);
+
   ceph::BitVector<2u>::Reference operator[](uint64_t object_no);
   uint8_t operator[](uint64_t object_no) const;
   inline uint64_t size() const {
index 5c8b3d222ba4ec67112f11f1d66026f76a4ab5a2..620b0bf6cee105b47fc5b7cb1cbe81fa15ef1546 100644 (file)
@@ -9,6 +9,7 @@
 #include "librbd/ImageCtx.h"
 #include "librbd/ImageState.h"
 #include "librbd/ImageWatcher.h"
+#include "librbd/ObjectMap.h"
 #include "librbd/Utils.h"
 #include "librbd/operation/FlattenRequest.h"
 #include "librbd/operation/RebuildObjectMapRequest.h"
@@ -499,6 +500,12 @@ int Operations<I>::resize(uint64_t size, ProgressContext& prog_ctx) {
     return r;
   }
 
+  if (m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP) &&
+      !ObjectMap::is_compatible(m_image_ctx.layout, size)) {
+    lderr(cct) << "New size not compatible with object map" << dendl;
+    return -EINVAL;
+  }
+
   uint64_t request_id = ++m_async_request_seq;
   r = invoke_async_request("resize", false,
                            boost::bind(&Operations<I>::execute_resize, this,
@@ -525,13 +532,17 @@ void Operations<I>::execute_resize(uint64_t size, ProgressContext &prog_ctx,
   ldout(cct, 5) << this << " " << __func__ << ": "
                 << "size=" << m_image_ctx.size << ", "
                 << "new_size=" << size << dendl;
-  m_image_ctx.snap_lock.put_read();
 
-  m_image_ctx.snap_lock.get_read();
   if (m_image_ctx.snap_id != CEPH_NOSNAP || m_image_ctx.read_only) {
     m_image_ctx.snap_lock.put_read();
     on_finish->complete(-EROFS);
     return;
+  } else if (m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP,
+                                       m_image_ctx.snap_lock) &&
+             !ObjectMap::is_compatible(m_image_ctx.layout, size)) {
+    m_image_ctx.snap_lock.put_read();
+    on_finish->complete(-EINVAL);
+    return;
   }
   m_image_ctx.snap_lock.put_read();
 
index f8e23aba35e5ea498db72a02082043f4bed92a26..92fab7f4cf12b9d3e27cae6851ed3423f96466a1 100644 (file)
@@ -95,18 +95,26 @@ int remove_object_map(ImageCtx *ictx) {
   }
   return 0;
 }
+
 int create_object_map(ImageCtx *ictx) {
   assert(ictx->snap_lock.is_locked());
   CephContext *cct = ictx->cct;
 
   int r;
+  uint64_t max_size = ictx->size;
   std::vector<uint64_t> snap_ids;
   snap_ids.push_back(CEPH_NOSNAP);
   for (std::map<snap_t, SnapInfo>::iterator it = ictx->snap_info.begin();
        it != ictx->snap_info.end(); ++it) {
+    max_size = MAX(max_size, it->second.size);
     snap_ids.push_back(it->first);
   }
 
+  if (!ObjectMap::is_compatible(ictx->layout, max_size)) {
+    lderr(cct) << "image size not compatible with object map" << dendl;
+    return -EINVAL;
+  }
+
   for (std::vector<uint64_t>::iterator it = snap_ids.begin();
     it != snap_ids.end(); ++it) {
     librados::ObjectWriteOperation op;
@@ -1098,6 +1106,11 @@ remove_mirroring_image:
         layout.stripe_count = stripe_count;
       }
 
+      if (!ObjectMap::is_compatible(layout, size)) {
+        lderr(cct) << "image size not compatible with object map" << dendl;
+        goto err_remove_header;
+      }
+
       librados::ObjectWriteOperation op;
       cls_client::object_map_resize(&op, Striper::get_num_objects(layout, size),
                                     OBJECT_NONEXISTENT);