]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: ignore cache busy errors when shrinking an image 11467/head
authorJason Dillaman <dillaman@redhat.com>
Thu, 8 Sep 2016 15:51:34 +0000 (11:51 -0400)
committerLoic Dachary <ldachary@redhat.com>
Fri, 21 Oct 2016 11:17:02 +0000 (13:17 +0200)
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
(cherry picked from commit 4ce663845679dc35f2f15b893c6f988c4a60b25b)

Conflicts:
     src/test/librbd/operation/test_mock_ResizeRequest.cc:
     when_resize does not have the allow_shrink argument because
     d1f2c557b2c039730baca9efa3f5244bc19dcb1a has not been
     backported

src/librbd/operation/ResizeRequest.cc
src/librbd/operation/ResizeRequest.h
src/test/librbd/mock/MockImageCtx.h
src/test/librbd/operation/test_mock_ResizeRequest.cc

index 79fae3930a155a5bf8cd94338a6fc829b43d32b4..c046e79abb2100df71ffad708ebc3bb85c8cfe01 100644 (file)
@@ -172,6 +172,38 @@ Context *ResizeRequest<I>::handle_trim_image(int *result) {
   return nullptr;
 }
 
+template <typename I>
+void ResizeRequest<I>::send_flush_cache() {
+  I &image_ctx = this->m_image_ctx;
+  if (image_ctx.object_cacher == nullptr) {
+    send_trim_image();
+    return;
+  }
+
+  CephContext *cct = image_ctx.cct;
+  ldout(cct, 5) << this << " " << __func__ << dendl;
+
+  RWLock::RLocker owner_locker(image_ctx.owner_lock);
+  image_ctx.flush_cache(create_async_context_callback(
+    image_ctx, create_context_callback<
+      ResizeRequest<I>, &ResizeRequest<I>::handle_flush_cache>(this)));
+}
+
+template <typename I>
+Context *ResizeRequest<I>::handle_flush_cache(int *result) {
+  I &image_ctx = this->m_image_ctx;
+  CephContext *cct = image_ctx.cct;
+  ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
+
+  if (*result < 0) {
+    lderr(cct) << "failed to flush cache: " << cpp_strerror(*result) << dendl;
+    return this->create_context_finisher(*result);
+  }
+
+  send_invalidate_cache();
+  return nullptr;
+}
+
 template <typename I>
 void ResizeRequest<I>::send_invalidate_cache() {
   I &image_ctx = this->m_image_ctx;
@@ -192,7 +224,10 @@ Context *ResizeRequest<I>::handle_invalidate_cache(int *result) {
   CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
 
-  if (*result < 0) {
+  // ignore busy error -- writeback was successfully flushed so we might be
+  // wasting some cache space for trimmed objects, but they will get purged
+  // eventually. Most likely cause of the issue was a in-flight cache read
+  if (*result < 0 && *result != -EBUSY) {
     lderr(cct) << "failed to invalidate cache: " << cpp_strerror(*result)
                << dendl;
     return this->create_context_finisher(*result);
@@ -215,7 +250,7 @@ Context *ResizeRequest<I>::send_grow_object_map() {
   if (m_original_size == m_new_size) {
     return this->create_context_finisher(0);
   } else if (m_new_size < m_original_size) {
-    send_invalidate_cache();
+    send_flush_cache();
     return nullptr;
   }
 
index 400bde33316ffa71f5902d80685f7f359b371dae..d1c778b9c8c80673a4c5209ad2e3fbff1d3cd354 100644 (file)
@@ -79,7 +79,10 @@ private:
    *    |           STATE_UPDATE_HEADER ----------------------------\
    *    |                                                           |
    *    | (shrink)                                                  |
-   *    |\--------> STATE_INVALIDATE_CACHE                          |
+   *    |\--------> STATE_FLUSH_CACHE                               |
+   *    |                 |                                         |
+   *    |                 v                                         |
+   *    |           STATE_INVALIDATE_CACHE                          |
    *    |                 |                                         |
    *    |                 v                                         |
    *    |           STATE_TRIM_IMAGE                                |
@@ -119,6 +122,9 @@ private:
   Context *send_append_op_event();
   Context *handle_append_op_event(int *result);
 
+  void send_flush_cache();
+  Context *handle_flush_cache(int *result);
+
   void send_invalidate_cache();
   Context *handle_invalidate_cache(int *result);
 
index f7283a72bc6deeed180d17ac6d399cccd569aa6b..2a8b98e28f2286cf429a3a160bf7bcec0fa6c5a2 100644 (file)
@@ -157,6 +157,7 @@ struct MockImageCtx {
   MOCK_METHOD1(flush_async_operations, void(Context *));
   MOCK_METHOD1(flush_copyup, void(Context *));
 
+  MOCK_METHOD1(flush_cache, void(Context *));
   MOCK_METHOD1(invalidate_cache, void(Context *));
   MOCK_METHOD1(shut_down_cache, void(Context *));
 
index c7733cf5565be5a7cd60ec41c060675c2454f43d..e1998ed692a4f673b0d78ec68402125b466a5ed1 100644 (file)
@@ -116,6 +116,11 @@ public:
                   .WillOnce(FinishRequest(&mock_trim_request, r, &mock_image_ctx));
   }
 
+  void expect_flush_cache(MockImageCtx &mock_image_ctx, int r) {
+    EXPECT_CALL(mock_image_ctx, flush_cache(_)).WillOnce(CompleteContext(r, NULL));
+    expect_op_work_queue(mock_image_ctx);
+  }
+
   void expect_invalidate_cache(MockImageCtx &mock_image_ctx, int r) {
     EXPECT_CALL(mock_image_ctx, invalidate_cache(_))
                   .WillOnce(CompleteContext(r, NULL));
@@ -202,6 +207,7 @@ TEST_F(TestMockOperationResizeRequest, ShrinkSuccess) {
   expect_unblock_writes(mock_image_ctx);
 
   MockTrimRequest mock_trim_request;
+  expect_flush_cache(mock_image_ctx, 0);
   expect_invalidate_cache(mock_image_ctx, 0);
   expect_trim(mock_image_ctx, mock_trim_request, 0);
   expect_block_writes(mock_image_ctx, 0);
@@ -263,12 +269,35 @@ TEST_F(TestMockOperationResizeRequest, TrimError) {
   expect_unblock_writes(mock_image_ctx);
 
   MockTrimRequest mock_trim_request;
-  expect_invalidate_cache(mock_image_ctx, 0);
+  expect_flush_cache(mock_image_ctx, 0);
+  expect_invalidate_cache(mock_image_ctx, -EBUSY);
   expect_trim(mock_image_ctx, mock_trim_request, -EINVAL);
   expect_commit_op_event(mock_image_ctx, -EINVAL);
   ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2, 0, false));
 }
 
+TEST_F(TestMockOperationResizeRequest, FlushCacheError) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockImageCtx mock_image_ctx(*ictx);
+  MockExclusiveLock mock_exclusive_lock;
+  MockJournal mock_journal;
+  MockObjectMap mock_object_map;
+  initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
+                      mock_object_map);
+
+  InSequence seq;
+  expect_block_writes(mock_image_ctx, 0);
+  expect_append_op_event(mock_image_ctx, true, 0);
+  expect_unblock_writes(mock_image_ctx);
+
+  MockTrimRequest mock_trim_request;
+  expect_flush_cache(mock_image_ctx, -EINVAL);
+  expect_commit_op_event(mock_image_ctx, -EINVAL);
+  ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2, 0, false));
+}
+
 TEST_F(TestMockOperationResizeRequest, InvalidateCacheError) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
@@ -286,6 +315,7 @@ TEST_F(TestMockOperationResizeRequest, InvalidateCacheError) {
   expect_unblock_writes(mock_image_ctx);
 
   MockTrimRequest mock_trim_request;
+  expect_flush_cache(mock_image_ctx, 0);
   expect_invalidate_cache(mock_image_ctx, -EINVAL);
   expect_commit_op_event(mock_image_ctx, -EINVAL);
   ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2, 0, false));