When uploading a multipart part to a non-default storage class,
original logic writes the object data to the correct pool
for its storage class.
But when completing the upload, there's another write op
(with a bunch of setxattrs) to the head object targeting
the standard pool (because non-multipart uploads
write their head objects to the default pool).
As a result of this setxattrs op, a redundant zero-sized object is
created in a wrong pool. Multipart complete, multipart abort and
GC would never try to it clean up.
The fix is to make RGWRados::Object::Write::_do_write_meta() learn the
difference between multipart and non-multipart head objects and pick the
correct placement rule for RGWRados::get_obj_head_ref().
Fixes: http://tracker.ceph.com/issues/49128
Signed-off-by: Jeegn Chen <jeegnchen@tencent.com>
(cherry picked from commit
7647823bd42ce8228c3622a91e87680ee22df710)
Conflicts:
src/rgw/rgw_sal.h
Cherry-pick notes:
- RGWAttrs renamed to Attrs after pacific
obj_op->params.zones_trace = zones_trace;
obj_op->params.modify_tail = true;
obj_op->params.attrs = &attrs;
+ obj_op->params.pmeta_placement_rule = &tail_placement_rule;
r = obj_op->prepare(y);
if (r < 0) {
return r;
return 0;
}
-int RGWRados::get_obj_head_ref(const DoutPrefixProvider *dpp, const RGWBucketInfo& bucket_info, const rgw_obj& obj, rgw_rados_ref *ref)
+int RGWRados::get_obj_head_ref(const DoutPrefixProvider *dpp,
+ const rgw_placement_rule& target_placement_rule,
+ const rgw_obj& obj,
+ rgw_rados_ref *ref)
{
get_obj_bucket_and_oid_loc(obj, ref->obj.oid, ref->obj.loc);
rgw_pool pool;
- if (!get_obj_data_pool(bucket_info.placement_rule, obj, &pool)) {
+ if (!get_obj_data_pool(target_placement_rule, obj, &pool)) {
ldpp_dout(dpp, 0) << "ERROR: cannot get data pool for obj=" << obj << ", probably misconfiguration" << dendl;
return -EIO;
}
return 0;
}
+int RGWRados::get_obj_head_ref(const DoutPrefixProvider *dpp,
+ const RGWBucketInfo& bucket_info,
+ const rgw_obj& obj,
+ rgw_rados_ref *ref)
+{
+ return get_obj_head_ref(dpp, bucket_info.placement_rule, obj, ref);
+}
+
int RGWRados::get_raw_obj_ref(const DoutPrefixProvider *dpp, const rgw_raw_obj& obj, rgw_rados_ref *ref)
{
ref->obj = obj;
}
rgw_rados_ref ref;
- r = store->get_obj_head_ref(dpp, target->get_bucket_info(), obj, &ref);
+ r = store->get_obj_head_ref(dpp, target->get_meta_placement_rule(), obj, &ref);
if (r < 0)
return r;
// This field represents the number of bucket index object shards
uint32_t bucket_index_max_shards;
+ int get_obj_head_ref(const DoutPrefixProvider *dpp, const rgw_placement_rule& target_placement_rule, const rgw_obj& obj, rgw_rados_ref *ref);
int get_obj_head_ref(const DoutPrefixProvider *dpp, const RGWBucketInfo& bucket_info, const rgw_obj& obj, rgw_rados_ref *ref);
int get_system_obj_ref(const DoutPrefixProvider *dpp, const rgw_raw_obj& obj, rgw_rados_ref *ref);
uint64_t max_bucket_id;
bool bs_initialized;
+ const rgw_placement_rule *pmeta_placement_rule;
+
protected:
int get_state(const DoutPrefixProvider *dpp, RGWObjState **pstate, bool follow_olh, optional_yield y, bool assume_noent = false);
void invalidate_state();
Object(RGWRados *_store, const RGWBucketInfo& _bucket_info, RGWObjectCtx& _ctx, const rgw_obj& _obj) : store(_store), bucket_info(_bucket_info),
ctx(_ctx), obj(_obj), bs(store),
state(NULL), versioning_disabled(false),
- bs_initialized(false) {}
+ bs_initialized(false),
+ pmeta_placement_rule(nullptr) {}
RGWRados *get_store() { return store; }
rgw_obj& get_obj() { return obj; }
return (!versioning_disabled && bucket_info.versioning_enabled());
}
+ void set_meta_placement_rule(const rgw_placement_rule *p) {
+ pmeta_placement_rule = p;
+ }
+
+ const rgw_placement_rule& get_meta_placement_rule() {
+ return pmeta_placement_rule ? *pmeta_placement_rule : bucket_info.placement_rule;
+ }
+
struct Read {
RGWRados::Object *source;
bool completeMultipart{false};
bool appendable{false};
RGWAttrs* attrs{nullptr};
+ // In MultipartObjectProcessor::complete, we need this parameter
+ // to tell the exact placement rule since it may be different from
+ // bucket.placement_rule when Storage Class is specified explicitly
+ const rgw_placement_rule *pmeta_placement_rule{nullptr};
} params;
virtual ~WriteOp() = default;
int RGWRadosObject::RadosWriteOp::prepare(optional_yield y)
{
op_target.set_versioning_disabled(params.versioning_disabled);
+ op_target.set_meta_placement_rule(params.pmeta_placement_rule);
parent_op.meta.mtime = params.mtime;
parent_op.meta.rmattrs = params.rmattrs;
parent_op.meta.data = params.data;