From: Soumya Koduri Date: Mon, 7 Oct 2024 11:24:02 +0000 (+0530) Subject: rgw/lc: Fix issues with non-current objects with instance empty X-Git-Tag: testing/wip-vshankar-testing-20250603.055014-reef-debug~34^2 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=5228a0b05b144da24a26644e0b1d7b1ff1a78a16;p=ceph-ci.git rgw/lc: Fix issues with non-current objects with instance empty When the bucket versioning is enabled, old plain object entry is converted to versioned by updating its instance as "null" in its raw head/old object. However its instance remains empty in the bi list entry. Same is the case for the entries created after versioning is suspended and re-enabled. So to access such objects which are non-current, we need to set rgw_obj_key.instance as 1) "null" to read the actual raw obj and 2) empty while accessing/updating their bi entry. Fixes: https://tracker.ceph.com/issues/71119 Signed-off-by: Soumya Koduri (cherry picked from commit 60149ade9d5193a78fa5fd83e28919f8f36fe05d) --- diff --git a/src/rgw/driver/rados/rgw_lc_tier.cc b/src/rgw/driver/rados/rgw_lc_tier.cc index 1b7de42b375..0509b32bf89 100644 --- a/src/rgw/driver/rados/rgw_lc_tier.cc +++ b/src/rgw/driver/rados/rgw_lc_tier.cc @@ -76,8 +76,9 @@ WRITE_CLASS_ENCODER(rgw_lc_multipart_upload_info) static inline string get_key_instance(const rgw_obj_key& key) { - if (!key.instance.empty() && - !key.have_null_instance()) { + // if non-current entry, add versionID to the + // transitioned object name including "null". + if (!key.instance.empty()) { return "-" + key.instance; } return ""; diff --git a/src/rgw/driver/rados/rgw_rados.cc b/src/rgw/driver/rados/rgw_rados.cc index 31918add52d..9272f9649e8 100644 --- a/src/rgw/driver/rados/rgw_rados.cc +++ b/src/rgw/driver/rados/rgw_rados.cc @@ -4752,7 +4752,7 @@ int RGWRados::copy_obj_data(RGWObjectCtx& obj_ctx, int RGWRados::transition_obj(RGWObjectCtx& obj_ctx, RGWBucketInfo& bucket_info, - const rgw_obj& obj, + rgw_obj obj, const rgw_placement_rule& placement_rule, const real_time& mtime, uint64_t olh_epoch, @@ -4783,6 +4783,11 @@ int RGWRados::transition_obj(RGWObjectCtx& obj_ctx, return -ECANCELED; } + // bi expects empty instance for the entries created when bucket versioning + // is not enabled or suspended. + if (obj.key.instance == "null") { + obj.key.instance.clear(); + } attrs.erase(RGW_ATTR_ID_TAG); attrs.erase(RGW_ATTR_TAIL_TAG); diff --git a/src/rgw/driver/rados/rgw_rados.h b/src/rgw/driver/rados/rgw_rados.h index e0420860427..e89fa1330b4 100644 --- a/src/rgw/driver/rados/rgw_rados.h +++ b/src/rgw/driver/rados/rgw_rados.h @@ -1207,7 +1207,7 @@ public: int transition_obj(RGWObjectCtx& obj_ctx, RGWBucketInfo& bucket_info, - const rgw_obj& obj, + rgw_obj obj, const rgw_placement_rule& placement_rule, const real_time& mtime, uint64_t olh_epoch, diff --git a/src/rgw/driver/rados/rgw_sal_rados.cc b/src/rgw/driver/rados/rgw_sal_rados.cc index 647d311e6ef..2f81a5bca69 100644 --- a/src/rgw/driver/rados/rgw_sal_rados.cc +++ b/src/rgw/driver/rados/rgw_sal_rados.cc @@ -2069,6 +2069,13 @@ int RadosObject::write_cloud_tier(const DoutPrefixProvider* dpp, { rgw::sal::RadosPlacementTier* rtier = static_cast(tier); map attrs = get_attrs(); + rgw_obj_key& obj_key = get_key(); + // bi expects empty instance for the entries created when bucket versioning + // is not enabled or suspended. + if (obj_key.instance == "null") { + obj_key.instance.clear(); + } + RGWRados::Object op_target(store->getRados(), bucket->get_info(), *rados_ctx, get_obj()); RGWRados::Object::Write obj_op(&op_target); diff --git a/src/rgw/rgw_lc.cc b/src/rgw/rgw_lc.cc index cdc17109735..1fa14db3f6d 100644 --- a/src/rgw/rgw_lc.cc +++ b/src/rgw/rgw_lc.cc @@ -499,6 +499,14 @@ struct lc_op_ctx { rctx(env.driver), dpp(dpp), wq(wq) { obj = bucket->get_object(o.key); + /* once bucket versioning is enabled, the non-current entries with + * instance empty should have instance set to "null" to be able + * to correctly read its olh version entry. + */ + if (o.key.instance.empty() && bucket->versioned() && !o.is_current()) { + rgw_obj_key& obj_key = obj->get_key(); + obj_key.instance = "null"; + } } bool next_has_same_name(const std::string& key_name) { @@ -1303,9 +1311,9 @@ public: int delete_tier_obj(lc_op_ctx& oc) { int ret = 0; - /* If bucket is versioned, create delete_marker for current version + /* If bucket has versioning enabled, create delete_marker for current version */ - if (oc.bucket->versioned() && oc.o.is_current() && !oc.o.is_delete_marker()) { + if (oc.bucket->versioning_enabled() && oc.o.is_current() && !oc.o.is_delete_marker()) { ret = remove_expired_obj(oc.dpp, oc, false, rgw::notify::ObjectExpiration); ldpp_dout(oc.dpp, 20) << "delete_tier_obj Object(key:" << oc.o.key << ") current & not delete_marker" << " versioned_epoch: " << oc.o.versioned_epoch << "flags: " << oc.o.flags << dendl; } else { @@ -1316,9 +1324,10 @@ public: } int transition_obj_to_cloud(lc_op_ctx& oc) { - /* If CurrentVersion object, remove it & create delete marker */ + /* If CurrentVersion object & bucket has versioning enabled, remove it & + * create delete marker */ bool delete_object = (!oc.tier->retain_head_object() || - (oc.o.is_current() && oc.bucket->versioned())); + (oc.o.is_current() && oc.bucket->versioning_enabled())); int ret = oc.obj->transition_to_cloud(oc.bucket, oc.tier.get(), oc.o, oc.env.worker->get_cloud_targets(), oc.cct,