Skip to content

Commit 46ba365

Browse files
authored
Merge pull request ceph#62640 from ivancich/wip-admin-robust-rm-obj
rgw: add force option to `radosgw-admin object rm ...` Reviewed-by: Casey Bodley <[email protected]>
2 parents e77cf3b + a84f984 commit 46ba365

File tree

10 files changed

+142
-61
lines changed

10 files changed

+142
-61
lines changed

doc/man/8/radosgw-admin.rst

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,22 +135,23 @@ as follows:
135135
Purge bucket index entries.
136136

137137
:command:`object rm`
138-
Remove an object.
138+
Remove an S3/Swift object. Include "--yes-i-really-mean-it" to remove object's
139+
entry from bucket index, for example if it's damaged.
139140

140141
:command:`object stat`
141-
Stat an object for its metadata.
142+
Stat an S3/Swift object for its metadata.
142143

143144
:command:`object manifest`
144-
Display the manifest of RADOS objects containing the data.
145+
Display the manifest of an S3/Swift object, producing a list of RADOS objects containing the data.
145146

146147
:command:`object unlink`
147-
Unlink object from bucket index.
148+
Unlink S3/Swift object from bucket index.
148149

149150
:command:`object rewrite`
150-
Rewrite the specified object.
151+
Rewrite the specified S3/Swift object.
151152

152153
:command:`object reindex`
153-
Add an object to its bucket's index. Used rarely for emergency repairs.
154+
Add an S3/Swift object to its bucket's index. Used rarely for emergency repairs.
154155

155156
:command:`objects expire`
156157
Run expired objects cleanup.

src/cls/rgw/cls_rgw.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2081,7 +2081,7 @@ static int rgw_bucket_unlink_instance(cls_method_context_t hctx, bufferlist *in,
20812081
olh_key.name.c_str(), olh_key.instance.c_str(), olh_entry.delete_marker);
20822082

20832083
if (olh_key == dest_key) {
2084-
/* this is the current head, need to update! */
2084+
/* this is the current head, need to update the OLH! */
20852085
cls_rgw_obj_key next_key;
20862086
bool found = false;
20872087
ret = obj.find_next_key(&next_key, &found);

src/rgw/driver/rados/rgw_bucket.cc

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,19 @@ bool rgw_bucket_object_check_filter(const std::string& oid)
145145
return rgw_obj_key::oid_to_key_in_ns(oid, &key, empty_ns);
146146
}
147147

148-
int rgw_remove_object(const DoutPrefixProvider *dpp, rgw::sal::Driver* driver, rgw::sal::Bucket* bucket, rgw_obj_key& key, optional_yield y)
148+
int rgw_remove_object(const DoutPrefixProvider *dpp,
149+
rgw::sal::Driver* driver,
150+
rgw::sal::Bucket* bucket,
151+
rgw_obj_key& key,
152+
optional_yield y,
153+
const bool force)
149154
{
150155

151156
std::unique_ptr<rgw::sal::Object> object = bucket->get_object(key);
152157

153-
return object->delete_object(dpp, y, rgw::sal::FLAG_LOG_OP, nullptr, nullptr);
158+
const uint32_t possible_force_flag = force ? rgw::sal::FLAG_FORCE_OP : 0;
159+
160+
return object->delete_object(dpp, y, rgw::sal::FLAG_LOG_OP | possible_force_flag, nullptr, nullptr);
154161
}
155162

156163
static void set_err_msg(std::string *sink, std::string msg)

src/rgw/driver/rados/rgw_bucket.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,12 @@ auto create_archive_bucket_instance_metadata_handler(rgw::sal::Driver* driver,
199199
-> std::unique_ptr<RGWMetadataHandler>;
200200

201201

202-
extern int rgw_remove_object(const DoutPrefixProvider *dpp, rgw::sal::Driver* driver, rgw::sal::Bucket* bucket, rgw_obj_key& key, optional_yield y);
202+
extern int rgw_remove_object(const DoutPrefixProvider* dpp,
203+
rgw::sal::Driver* driver,
204+
rgw::sal::Bucket* bucket,
205+
rgw_obj_key& key,
206+
optional_yield y,
207+
const bool force = false);
203208

204209
extern int rgw_object_get_attr(rgw::sal::Driver* driver, rgw::sal::Object* obj,
205210
const char* attr_name, bufferlist& out_bl,

src/rgw/driver/rados/rgw_rados.cc

Lines changed: 75 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6266,9 +6266,13 @@ struct tombstone_entry {
62666266
* Delete an object.
62676267
* bucket: name of the bucket storing the object
62686268
* obj: name of the object to delete
6269+
* force: if b.i. entry exists but head object does not, still remove entry
62696270
* Returns: 0 on success, -ERR# otherwise.
62706271
*/
6271-
int RGWRados::Object::Delete::delete_obj(optional_yield y, const DoutPrefixProvider *dpp, bool log_op)
6272+
int RGWRados::Object::Delete::delete_obj(optional_yield y,
6273+
const DoutPrefixProvider* dpp,
6274+
bool log_op,
6275+
const bool force)
62726276
{
62736277
RGWRados *store = target->get_store();
62746278
const rgw_obj& src_obj = target->get_obj();
@@ -6297,8 +6301,9 @@ int RGWRados::Object::Delete::delete_obj(optional_yield y, const DoutPrefixProvi
62976301
}
62986302

62996303
result.version_id = marker.key.instance;
6300-
if (result.version_id.empty())
6304+
if (result.version_id.empty()) {
63016305
result.version_id = "null";
6306+
}
63026307
result.delete_marker = true;
63036308

63046309
struct rgw_bucket_dir_entry_meta meta;
@@ -6326,8 +6331,10 @@ int RGWRados::Object::Delete::delete_obj(optional_yield y, const DoutPrefixProvi
63266331
return r;
63276332
}
63286333
result.delete_marker = dirent.is_delete_marker();
6329-
r = store->unlink_obj_instance(dpp, target->get_ctx(), target->get_bucket_info(), obj, params.olh_epoch,
6330-
y, params.bilog_flags, params.null_verid, params.zones_trace, add_log);
6334+
r = store->unlink_obj_instance(
6335+
dpp, target->get_ctx(), target->get_bucket_info(), obj,
6336+
params.olh_epoch, y, params.bilog_flags,
6337+
params.null_verid, params.zones_trace, add_log, force);
63316338
if (r < 0) {
63326339
return r;
63336340
}
@@ -6349,7 +6356,7 @@ int RGWRados::Object::Delete::delete_obj(optional_yield y, const DoutPrefixProvi
63496356
}
63506357

63516358
return 0;
6352-
}
6359+
} // if versioned bucket
63536360

63546361
rgw_rados_ref ref;
63556362
int r = store->get_obj_head_ref(dpp, target->get_bucket_info(), obj, &ref);
@@ -6360,8 +6367,9 @@ int RGWRados::Object::Delete::delete_obj(optional_yield y, const DoutPrefixProvi
63606367
RGWObjState *state;
63616368
RGWObjManifest *manifest = nullptr;
63626369
r = target->get_state(dpp, &state, &manifest, false, y);
6363-
if (r < 0)
6370+
if (r < 0) {
63646371
return r;
6372+
}
63656373

63666374
ObjectWriteOperation op;
63676375

@@ -6383,7 +6391,7 @@ int RGWRados::Object::Delete::delete_obj(optional_yield y, const DoutPrefixProvi
63836391
}
63846392
uint64_t obj_accounted_size = state->accounted_size;
63856393

6386-
if(params.abortmp) {
6394+
if (params.abortmp) {
63876395
obj_accounted_size = params.parts_accounted_size;
63886396
}
63896397

@@ -6409,13 +6417,20 @@ int RGWRados::Object::Delete::delete_obj(optional_yield y, const DoutPrefixProvi
64096417
}
64106418

64116419
if (!state->exists) {
6412-
target->invalidate_state();
6413-
return -ENOENT;
6420+
if (!force) {
6421+
target->invalidate_state();
6422+
return -ENOENT;
6423+
} else {
6424+
ldpp_dout(dpp, 5) << "WARNING: head for \"" << src_obj <<
6425+
"\" does not exist; will continue with deleting bucket "
6426+
"index entry(ies)" << dendl;
6427+
}
64146428
}
64156429

64166430
r = target->prepare_atomic_modification(dpp, op, false, NULL, NULL, NULL, true, false, y);
6417-
if (r < 0)
6431+
if (r < 0) {
64186432
return r;
6433+
}
64196434

64206435
RGWBucketInfo& bucket_info = target->get_bucket_info();
64216436

@@ -6429,10 +6444,10 @@ int RGWRados::Object::Delete::delete_obj(optional_yield y, const DoutPrefixProvi
64296444
index_op.set_bilog_flags(params.bilog_flags | RGW_BILOG_NULL_VERSION);
64306445
}
64316446

6432-
64336447
r = index_op.prepare(dpp, CLS_RGW_OP_DEL, &state->write_tag, y);
6434-
if (r < 0)
6448+
if (r < 0) {
64356449
return r;
6450+
}
64366451

64376452
store->remove_rgw_head_obj(op);
64386453

@@ -6477,8 +6492,9 @@ int RGWRados::Object::Delete::delete_obj(optional_yield y, const DoutPrefixProvi
64776492
target->invalidate_state();
64786493
}
64796494

6480-
if (r < 0)
6495+
if (r < 0) {
64816496
return r;
6497+
}
64826498

64836499
/* update quota cache */
64846500
store->quota_handler->update_stats(params.bucket_owner, obj.bucket, -1, 0, obj_accounted_size);
@@ -6495,7 +6511,8 @@ int RGWRados::delete_obj(const DoutPrefixProvider *dpp,
64956511
uint16_t bilog_flags,
64966512
const real_time& expiration_time,
64976513
rgw_zone_set *zones_trace,
6498-
bool log_op)
6514+
bool log_op,
6515+
const bool force) // force removal even if head object is broken
64996516
{
65006517
RGWRados::Object del_target(this, bucket_info, obj_ctx, obj);
65016518
RGWRados::Object::Delete del_op(&del_target);
@@ -6507,7 +6524,7 @@ int RGWRados::delete_obj(const DoutPrefixProvider *dpp,
65076524
del_op.params.zones_trace = zones_trace;
65086525
del_op.params.null_verid = null_verid;
65096526

6510-
return del_op.delete_obj(y, dpp, log_op ? rgw::sal::FLAG_LOG_OP : 0);
6527+
return del_op.delete_obj(y, dpp, log_op, force);
65116528
}
65126529

65136530
int RGWRados::delete_raw_obj(const DoutPrefixProvider *dpp, const rgw_raw_obj& obj, optional_yield y)
@@ -8618,7 +8635,7 @@ int RGWRados::bucket_index_unlink_instance(const DoutPrefixProvider *dpp,
86188635
}
86198636

86208637
return 0;
8621-
}
8638+
} // bucket_index_unlink_instance
86228639

86238640
int RGWRados::bucket_index_read_olh_log(const DoutPrefixProvider *dpp,
86248641
RGWBucketInfo& bucket_info, RGWObjState& state,
@@ -8813,9 +8830,10 @@ int RGWRados::apply_olh_log(const DoutPrefixProvider *dpp,
88138830
std::map<uint64_t, std::vector<rgw_bucket_olh_log_entry> >& log,
88148831
uint64_t *plast_ver,
88158832
optional_yield y,
8816-
bool null_verid,
8817-
rgw_zone_set* zones_trace,
8818-
bool log_op)
8833+
bool null_verid,
8834+
rgw_zone_set* zones_trace,
8835+
bool log_op,
8836+
const bool force)
88198837
{
88208838
if (log.empty()) {
88218839
return 0;
@@ -8928,7 +8946,9 @@ int RGWRados::apply_olh_log(const DoutPrefixProvider *dpp,
89288946
liter != remove_instances.end(); ++liter) {
89298947
cls_rgw_obj_key& key = *liter;
89308948
rgw_obj obj_instance(bucket, key);
8931-
int ret = delete_obj(dpp, obj_ctx, bucket_info, obj_instance, 0, y, null_verid, RGW_BILOG_FLAG_VERSIONED_OP, ceph::real_time(), zones_trace, log_op);
8949+
int ret = delete_obj(dpp, obj_ctx, bucket_info, obj_instance, 0, y,
8950+
null_verid, RGW_BILOG_FLAG_VERSIONED_OP,
8951+
ceph::real_time(), zones_trace, log_op, force);
89328952
if (ret < 0 && ret != -ENOENT) {
89338953
ldpp_dout(dpp, 0) << "ERROR: delete_obj() returned " << ret << " obj_instance=" << obj_instance << dendl;
89348954
return ret;
@@ -8942,7 +8962,6 @@ int RGWRados::apply_olh_log(const DoutPrefixProvider *dpp,
89428962
return r;
89438963
}
89448964

8945-
89468965
if (need_to_remove) {
89478966
string olh_tag(state.olh_tag.c_str(), state.olh_tag.length());
89488967
r = clear_olh(dpp, obj_ctx, obj, bucket_info, ref, olh_tag, last_ver, y);
@@ -9032,7 +9051,15 @@ int RGWRados::clear_olh(const DoutPrefixProvider *dpp,
90329051
/*
90339052
* read olh log and apply it
90349053
*/
9035-
int RGWRados::update_olh(const DoutPrefixProvider *dpp, RGWObjectCtx& obj_ctx, RGWObjState *state, RGWBucketInfo& bucket_info, const rgw_obj& obj, optional_yield y, rgw_zone_set *zones_trace, bool null_verid, bool log_op)
9054+
int RGWRados::update_olh(const DoutPrefixProvider* dpp,
9055+
RGWObjectCtx& obj_ctx,
9056+
RGWObjState* state,
9057+
RGWBucketInfo& bucket_info,
9058+
const rgw_obj& obj, optional_yield y,
9059+
rgw_zone_set* zones_trace,
9060+
bool null_verid,
9061+
bool log_op,
9062+
const bool force)
90369063
{
90379064
map<uint64_t, vector<rgw_bucket_olh_log_entry> > log;
90389065
bool is_truncated;
@@ -9043,7 +9070,9 @@ int RGWRados::update_olh(const DoutPrefixProvider *dpp, RGWObjectCtx& obj_ctx, R
90439070
if (ret < 0) {
90449071
return ret;
90459072
}
9046-
ret = apply_olh_log(dpp, obj_ctx, *state, bucket_info, obj, state->olh_tag, log, &ver_marker, y, null_verid, zones_trace, log_op);
9073+
ret = apply_olh_log(dpp, obj_ctx, *state, bucket_info, obj,
9074+
state->olh_tag, log, &ver_marker, y,
9075+
null_verid, zones_trace, log_op, force);
90479076
if (ret < 0) {
90489077
return ret;
90499078
}
@@ -9144,8 +9173,17 @@ int RGWRados::set_olh(const DoutPrefixProvider *dpp, RGWObjectCtx& obj_ctx,
91449173
return 0;
91459174
}
91469175

9147-
int RGWRados::unlink_obj_instance(const DoutPrefixProvider *dpp, RGWObjectCtx& obj_ctx, RGWBucketInfo& bucket_info, const rgw_obj& target_obj,
9148-
uint64_t olh_epoch, optional_yield y, uint16_t bilog_flags, bool null_verid, rgw_zone_set *zones_trace, bool log_op)
9176+
int RGWRados::unlink_obj_instance(const DoutPrefixProvider* dpp,
9177+
RGWObjectCtx& obj_ctx,
9178+
RGWBucketInfo& bucket_info,
9179+
const rgw_obj& target_obj,
9180+
uint64_t olh_epoch,
9181+
optional_yield y,
9182+
uint16_t bilog_flags,
9183+
bool null_verid,
9184+
rgw_zone_set* zones_trace,
9185+
bool log_op,
9186+
const bool force)
91499187
{
91509188
string op_tag;
91519189

@@ -9190,31 +9228,36 @@ int RGWRados::unlink_obj_instance(const DoutPrefixProvider *dpp, RGWObjectCtx& o
91909228
bilog_flags = bilog_flags | RGW_BILOG_FLAG_VERSIONED_OP;
91919229
}
91929230

9193-
ret = bucket_index_unlink_instance(dpp, bucket_info, target_obj, op_tag, olh_tag, olh_epoch, y, bilog_flags, zones_trace, log_op);
9231+
ret = bucket_index_unlink_instance(dpp, bucket_info, target_obj,
9232+
op_tag, olh_tag, olh_epoch, y,
9233+
bilog_flags, zones_trace, log_op);
91949234
if (ret < 0) {
91959235
olh_cancel_modification(dpp, bucket_info, *state, olh_obj, op_tag, y);
9196-
ldpp_dout(dpp, 20) << "bucket_index_unlink_instance() target_obj=" << target_obj << " returned " << ret << dendl;
9236+
ldpp_dout(dpp, 20) << "bucket_index_unlink_instance() target_obj=" <<
9237+
target_obj << " returned " << ret << dendl;
91979238
if (ret == -ECANCELED) {
91989239
continue;
91999240
}
92009241
// it's possible that the pending xattr from this op prevented the olh
92019242
// object from being cleaned by another thread that was deleting the last
92029243
// existing version. We invoke a best-effort update_olh here to handle this case.
9203-
int r = update_olh(dpp, obj_ctx, state, bucket_info, olh_obj, y, zones_trace, null_verid, log_op);
9244+
int r = update_olh(dpp, obj_ctx, state, bucket_info, olh_obj, y,
9245+
zones_trace, null_verid, log_op, force);
92049246
if (r < 0 && r != -ECANCELED) {
92059247
ldpp_dout(dpp, 20) << "update_olh() target_obj=" << olh_obj << " returned " << r << dendl;
92069248
}
92079249
return ret;
9208-
}
9250+
} // if error in bucket_index_unlink_instance call
92099251
break;
9210-
}
9252+
} // cancel retry loop
92119253

92129254
if (i == MAX_ECANCELED_RETRY) {
92139255
ldpp_dout(dpp, 0) << "ERROR: exceeded max ECANCELED retries, aborting (EIO)" << dendl;
92149256
return -EIO;
92159257
}
92169258

9217-
ret = update_olh(dpp, obj_ctx, state, bucket_info, olh_obj, y, zones_trace, null_verid, log_op);
9259+
ret = update_olh(dpp, obj_ctx, state, bucket_info, olh_obj, y,
9260+
zones_trace, null_verid, log_op, force);
92189261
if (ret == -ECANCELED) { /* already did what we needed, no need to retry, raced with another user */
92199262
return 0;
92209263
}
@@ -11322,7 +11365,7 @@ int RGWRados::delete_obj_aio(const DoutPrefixProvider *dpp, const rgw_obj& obj,
1132211365
}
1132311366
}
1132411367
return ret;
11325-
}
11368+
} // delete_obj_aio
1132611369

1132711370
void objexp_hint_entry::generate_test_instances(list<objexp_hint_entry*>& o)
1132811371
{

0 commit comments

Comments
 (0)