]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
osd: fix wrong promotion after writing snapshot
authormyoungwon oh <ohmyoungwon@gmail.com>
Tue, 9 Feb 2021 06:50:22 +0000 (15:50 +0900)
committermyoungwon oh <ohmyoungwon@gmail.com>
Mon, 29 Mar 2021 08:12:37 +0000 (17:12 +0900)
Let's assume the following scenario.
snap_create() -> write() -> tier_promote() -> read().
write() trigger to create a snapshot with current chunk_map, but
it does not update chunk_map even if the write() overwrites the region.
So, tier_promote() will overwrite the region by writing old chunk to there.

To avoid this, update_chunk_map_by_dirty is added by splitting
dec_refcount_by_dirty

Signed-off-by: Myoungwon Oh <myoungwon.oh@samsung.com>
src/osd/PrimaryLogPG.cc
src/osd/PrimaryLogPG.h

index e46072a139c704dd890e9ddc5bab9294077a888e..da83656a5146597e49acbb4c01d5e169259122d6 100644 (file)
@@ -3560,11 +3560,7 @@ bool PrimaryLogPG::inc_refcount_by_set(OpContext* ctx, object_manifest_t& set_ch
   return false;
 }
 
-void PrimaryLogPG::dec_refcount_by_dirty(OpContext* ctx)
-{
-  object_ref_delta_t refs;
-  ObjectContextRef cobc = nullptr;
-  ObjectContextRef obc = ctx->obc;
+void PrimaryLogPG::update_chunk_map_by_dirty(OpContext* ctx) {
   for (auto &p : ctx->obs->oi.manifest.chunk_map) {
     if (!ctx->clean_regions.is_clean_region(p.first, p.second.length)) {
       ctx->new_obs.oi.manifest.chunk_map.erase(p.first);
@@ -3575,6 +3571,13 @@ void PrimaryLogPG::dec_refcount_by_dirty(OpContext* ctx)
       }
     }
   }
+}
+
+void PrimaryLogPG::dec_refcount_by_dirty(OpContext* ctx)
+{
+  object_ref_delta_t refs;
+  ObjectContextRef cobc = nullptr;
+  ObjectContextRef obc = ctx->obc;
   // Look over previous snapshot, then figure out whether updated chunk needs to be deleted
   cobc = get_prev_clone_obc(obc);
   obc->obs.oi.manifest.calc_refs_to_drop_on_modify(
@@ -8747,12 +8750,14 @@ void PrimaryLogPG::finish_ctx(OpContext *ctx, int log_op_type, int result)
   // Drop the reference if deduped chunk is modified
   if (ctx->new_obs.oi.is_dirty() &&
     (ctx->obs->oi.has_manifest() && ctx->obs->oi.manifest.is_chunked()) &&
-    // If a clone is creating, ignore dropping the reference for manifest object
-    !ctx->delta_stats.num_object_clones &&
     ctx->new_obs.oi.size != 0 && // missing, redirect and delete
     !ctx->cache_operation &&
     log_op_type != pg_log_entry_t::PROMOTE) {
-    dec_refcount_by_dirty(ctx);
+    update_chunk_map_by_dirty(ctx);
+    // If a clone is creating, ignore dropping the reference for manifest object
+    if (!ctx->delta_stats.num_object_clones) {
+      dec_refcount_by_dirty(ctx);
+    }
   }
 
   // finish and log the op.
index e9f9cb9c828cb2b53b837bc617a7282f9b5a4080..78b00416392e4e026c7cfa2fb828bfb10f85413c 100644 (file)
@@ -1427,6 +1427,7 @@ protected:
                              Context *cb, std::optional<bufferlist> chunk);
   void dec_all_refcount_manifest(const object_info_t& oi, OpContext* ctx);
   void dec_refcount(const hobject_t& soid, const object_ref_delta_t& refs);
+  void update_chunk_map_by_dirty(OpContext* ctx);
   void dec_refcount_by_dirty(OpContext* ctx);
   ObjectContextRef get_prev_clone_obc(ObjectContextRef obc);
   bool recover_adjacent_clones(ObjectContextRef obc, OpRequestRef op);