From: myoungwon oh Date: Tue, 9 Feb 2021 06:50:22 +0000 (+0900) Subject: osd: fix wrong promotion after writing snapshot X-Git-Tag: v17.1.0~2307^2~34 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=99c7c1621168950473dad5777f97419e2e23018f;p=ceph.git osd: fix wrong promotion after writing snapshot 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 --- diff --git a/src/osd/PrimaryLogPG.cc b/src/osd/PrimaryLogPG.cc index e46072a139c..da83656a514 100644 --- a/src/osd/PrimaryLogPG.cc +++ b/src/osd/PrimaryLogPG.cc @@ -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. diff --git a/src/osd/PrimaryLogPG.h b/src/osd/PrimaryLogPG.h index e9f9cb9c828..78b00416392 100644 --- a/src/osd/PrimaryLogPG.h +++ b/src/osd/PrimaryLogPG.h @@ -1427,6 +1427,7 @@ protected: Context *cb, std::optional 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);