Skip to content

Commit 7e1ac21

Browse files
committed
rgw: add force option to radosgw-admin object rm ...
The `radosgw-admin object rm ...` sub-command will give up if it determines that there's an issue with the head object. This can make it difficult for an admin to clean up a bucket index when there's a damaged or missing head object. When the user adds the "--yes-i-really-mean-it" command-line option, it enables the "force mode". The bucket index entry(ies) will be removed. If the object being removed is the current version in a versioned bucket, the appropriate changes to the OLH will take place. Signed-off-by: J. Eric Ivancich <[email protected]>
1 parent d818d46 commit 7e1ac21

File tree

7 files changed

+110
-36
lines changed

7 files changed

+110
-36
lines changed

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
@@ -197,7 +197,12 @@ auto create_archive_bucket_instance_metadata_handler(rgw::sal::Driver* driver,
197197
-> std::unique_ptr<RGWMetadataHandler>;
198198

199199

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

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

src/rgw/driver/rados/rgw_rados.cc

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6045,9 +6045,13 @@ struct tombstone_entry {
60456045
* Delete an object.
60466046
* bucket: name of the bucket storing the object
60476047
* obj: name of the object to delete
6048+
* force: if b.i. entry exists but head object does not, still remove entry
60486049
* Returns: 0 on success, -ERR# otherwise.
60496050
*/
6050-
int RGWRados::Object::Delete::delete_obj(optional_yield y, const DoutPrefixProvider *dpp, bool log_op)
6051+
int RGWRados::Object::Delete::delete_obj(optional_yield y,
6052+
const DoutPrefixProvider* dpp,
6053+
bool log_op,
6054+
const bool force)
60516055
{
60526056
RGWRados *store = target->get_store();
60536057
const rgw_obj& src_obj = target->get_obj();
@@ -6105,8 +6109,10 @@ int RGWRados::Object::Delete::delete_obj(optional_yield y, const DoutPrefixProvi
61056109
return r;
61066110
}
61076111
result.delete_marker = dirent.is_delete_marker();
6108-
r = store->unlink_obj_instance(dpp, target->get_ctx(), target->get_bucket_info(), obj, params.olh_epoch,
6109-
y, params.bilog_flags, params.null_verid, params.zones_trace, add_log);
6112+
r = store->unlink_obj_instance(
6113+
dpp, target->get_ctx(), target->get_bucket_info(), obj,
6114+
params.olh_epoch, y, params.bilog_flags,
6115+
params.null_verid, params.zones_trace, add_log, force);
61106116
if (r < 0) {
61116117
return r;
61126118
}
@@ -6186,8 +6192,14 @@ int RGWRados::Object::Delete::delete_obj(optional_yield y, const DoutPrefixProvi
61866192
}
61876193

61886194
if (!state->exists) {
6189-
target->invalidate_state();
6190-
return -ENOENT;
6195+
if (!force) {
6196+
target->invalidate_state();
6197+
return -ENOENT;
6198+
} else {
6199+
ldpp_dout(dpp, 5) << "WARNING: head for \"" << src_obj <<
6200+
"\" does not exist; will continue with deleting bucket "
6201+
"index entry(ies)" << dendl;
6202+
}
61916203
}
61926204

61936205
r = target->prepare_atomic_modification(dpp, op, false, NULL, NULL, NULL, true, false, y);
@@ -6272,7 +6284,8 @@ int RGWRados::delete_obj(const DoutPrefixProvider *dpp,
62726284
uint16_t bilog_flags,
62736285
const real_time& expiration_time,
62746286
rgw_zone_set *zones_trace,
6275-
bool log_op)
6287+
bool log_op,
6288+
const bool force) // force removal even if head object is broken
62766289
{
62776290
RGWRados::Object del_target(this, bucket_info, obj_ctx, obj);
62786291
RGWRados::Object::Delete del_op(&del_target);
@@ -6284,7 +6297,7 @@ int RGWRados::delete_obj(const DoutPrefixProvider *dpp,
62846297
del_op.params.zones_trace = zones_trace;
62856298
del_op.params.null_verid = null_verid;
62866299

6287-
return del_op.delete_obj(y, dpp, log_op ? rgw::sal::FLAG_LOG_OP : 0);
6300+
return del_op.delete_obj(y, dpp, log_op, force);
62886301
}
62896302

62906303
int RGWRados::delete_raw_obj(const DoutPrefixProvider *dpp, const rgw_raw_obj& obj, optional_yield y)
@@ -8590,9 +8603,10 @@ int RGWRados::apply_olh_log(const DoutPrefixProvider *dpp,
85908603
std::map<uint64_t, std::vector<rgw_bucket_olh_log_entry> >& log,
85918604
uint64_t *plast_ver,
85928605
optional_yield y,
8593-
bool null_verid,
8594-
rgw_zone_set* zones_trace,
8595-
bool log_op)
8606+
bool null_verid,
8607+
rgw_zone_set* zones_trace,
8608+
bool log_op,
8609+
const bool force)
85968610
{
85978611
if (log.empty()) {
85988612
return 0;
@@ -8705,7 +8719,9 @@ int RGWRados::apply_olh_log(const DoutPrefixProvider *dpp,
87058719
liter != remove_instances.end(); ++liter) {
87068720
cls_rgw_obj_key& key = *liter;
87078721
rgw_obj obj_instance(bucket, key);
8708-
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);
8722+
int ret = delete_obj(dpp, obj_ctx, bucket_info, obj_instance, 0, y,
8723+
null_verid, RGW_BILOG_FLAG_VERSIONED_OP,
8724+
ceph::real_time(), zones_trace, log_op, force);
87098725
if (ret < 0 && ret != -ENOENT) {
87108726
ldpp_dout(dpp, 0) << "ERROR: delete_obj() returned " << ret << " obj_instance=" << obj_instance << dendl;
87118727
return ret;
@@ -8809,7 +8825,15 @@ int RGWRados::clear_olh(const DoutPrefixProvider *dpp,
88098825
/*
88108826
* read olh log and apply it
88118827
*/
8812-
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)
8828+
int RGWRados::update_olh(const DoutPrefixProvider* dpp,
8829+
RGWObjectCtx& obj_ctx,
8830+
RGWObjState* state,
8831+
RGWBucketInfo& bucket_info,
8832+
const rgw_obj& obj, optional_yield y,
8833+
rgw_zone_set* zones_trace,
8834+
bool null_verid,
8835+
bool log_op,
8836+
const bool force)
88138837
{
88148838
map<uint64_t, vector<rgw_bucket_olh_log_entry> > log;
88158839
bool is_truncated;
@@ -8820,7 +8844,9 @@ int RGWRados::update_olh(const DoutPrefixProvider *dpp, RGWObjectCtx& obj_ctx, R
88208844
if (ret < 0) {
88218845
return ret;
88228846
}
8823-
ret = apply_olh_log(dpp, obj_ctx, *state, bucket_info, obj, state->olh_tag, log, &ver_marker, y, null_verid, zones_trace, log_op);
8847+
ret = apply_olh_log(dpp, obj_ctx, *state, bucket_info, obj,
8848+
state->olh_tag, log, &ver_marker, y,
8849+
null_verid, zones_trace, log_op, force);
88248850
if (ret < 0) {
88258851
return ret;
88268852
}
@@ -8921,8 +8947,17 @@ int RGWRados::set_olh(const DoutPrefixProvider *dpp, RGWObjectCtx& obj_ctx,
89218947
return 0;
89228948
}
89238949

8924-
int RGWRados::unlink_obj_instance(const DoutPrefixProvider *dpp, RGWObjectCtx& obj_ctx, RGWBucketInfo& bucket_info, const rgw_obj& target_obj,
8925-
uint64_t olh_epoch, optional_yield y, uint16_t bilog_flags, bool null_verid, rgw_zone_set *zones_trace, bool log_op)
8950+
int RGWRados::unlink_obj_instance(const DoutPrefixProvider* dpp,
8951+
RGWObjectCtx& obj_ctx,
8952+
RGWBucketInfo& bucket_info,
8953+
const rgw_obj& target_obj,
8954+
uint64_t olh_epoch,
8955+
optional_yield y,
8956+
uint16_t bilog_flags,
8957+
bool null_verid,
8958+
rgw_zone_set* zones_trace,
8959+
bool log_op,
8960+
const bool force)
89268961
{
89278962
string op_tag;
89288963

@@ -8977,7 +9012,8 @@ int RGWRados::unlink_obj_instance(const DoutPrefixProvider *dpp, RGWObjectCtx& o
89779012
// it's possible that the pending xattr from this op prevented the olh
89789013
// object from being cleaned by another thread that was deleting the last
89799014
// existing version. We invoke a best-effort update_olh here to handle this case.
8980-
int r = update_olh(dpp, obj_ctx, state, bucket_info, olh_obj, y, zones_trace, null_verid, log_op);
9015+
int r = update_olh(dpp, obj_ctx, state, bucket_info, olh_obj, y,
9016+
zones_trace, null_verid, log_op, force);
89819017
if (r < 0 && r != -ECANCELED) {
89829018
ldpp_dout(dpp, 20) << "update_olh() target_obj=" << olh_obj << " returned " << r << dendl;
89839019
}
@@ -8991,7 +9027,8 @@ int RGWRados::unlink_obj_instance(const DoutPrefixProvider *dpp, RGWObjectCtx& o
89919027
return -EIO;
89929028
}
89939029

8994-
ret = update_olh(dpp, obj_ctx, state, bucket_info, olh_obj, y, zones_trace, null_verid, log_op);
9030+
ret = update_olh(dpp, obj_ctx, state, bucket_info, olh_obj, y,
9031+
zones_trace, null_verid, log_op, force);
89959032
if (ret == -ECANCELED) { /* already did what we needed, no need to retry, raced with another user */
89969033
return 0;
89979034
}

src/rgw/driver/rados/rgw_rados.h

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -872,7 +872,10 @@ class RGWRados
872872

873873
explicit Delete(RGWRados::Object *_target) : target(_target) {}
874874

875-
int delete_obj(optional_yield y, const DoutPrefixProvider *dpp, bool log_op = true);
875+
int delete_obj(optional_yield y,
876+
const DoutPrefixProvider* dpp,
877+
bool log_op,
878+
const bool force); // if head object missing, do a best effort
876879
}; // struct RGWRados::Object::Delete
877880

878881
struct Stat {
@@ -1291,7 +1294,8 @@ int restore_obj_from_cloud(RGWLCCloudTierCtx& tier_ctx,
12911294
uint16_t bilog_flags = 0,
12921295
const ceph::real_time& expiration_time = ceph::real_time(),
12931296
rgw_zone_set *zones_trace = nullptr,
1294-
bool log_op = true);
1297+
bool log_op = true,
1298+
const bool force = false); // if head object missing, do a best effort
12951299

12961300
int delete_raw_obj(const DoutPrefixProvider *dpp, const rgw_raw_obj& obj, optional_yield y);
12971301

@@ -1399,11 +1403,17 @@ int restore_obj_from_cloud(RGWLCCloudTierCtx& tier_ctx,
13991403
std::map<uint64_t, std::vector<rgw_bucket_olh_log_entry> > *log, bool *is_truncated, optional_yield y);
14001404
int bucket_index_trim_olh_log(const DoutPrefixProvider *dpp, RGWBucketInfo& bucket_info, RGWObjState& obj_state, const rgw_obj& obj_instance, uint64_t ver, optional_yield y);
14011405
int bucket_index_clear_olh(const DoutPrefixProvider *dpp, RGWBucketInfo& bucket_info, const std::string& olh_tag, const rgw_obj& obj_instance, optional_yield y);
1402-
int apply_olh_log(const DoutPrefixProvider *dpp, RGWObjectCtx& obj_ctx, RGWObjState& obj_state, RGWBucketInfo& bucket_info, const rgw_obj& obj,
1406+
int apply_olh_log(const DoutPrefixProvider *dpp, RGWObjectCtx& obj_ctx, RGWObjState& obj_state,
1407+
RGWBucketInfo& bucket_info, const rgw_obj& obj,
14031408
bufferlist& obj_tag, std::map<uint64_t, std::vector<rgw_bucket_olh_log_entry> >& log,
1404-
uint64_t *plast_ver, optional_yield y, bool null_verid, rgw_zone_set *zones_trace = nullptr, bool log_op = true);
1405-
int update_olh(const DoutPrefixProvider *dpp, RGWObjectCtx& obj_ctx, RGWObjState *state, RGWBucketInfo& bucket_info, const rgw_obj& obj, optional_yield y,
1406-
rgw_zone_set *zones_trace = nullptr, bool null_verid = false, bool log_op = true);
1409+
uint64_t *plast_ver, optional_yield y, bool null_verid,
1410+
rgw_zone_set *zones_trace = nullptr,
1411+
bool log_op = true,
1412+
const bool force = false);
1413+
int update_olh(const DoutPrefixProvider *dpp, RGWObjectCtx& obj_ctx, RGWObjState *state,
1414+
RGWBucketInfo& bucket_info, const rgw_obj& obj, optional_yield y,
1415+
rgw_zone_set *zones_trace = nullptr, bool null_verid = false,
1416+
bool log_op = true, const bool force = false);
14071417
int clear_olh(const DoutPrefixProvider *dpp,
14081418
RGWObjectCtx& obj_ctx,
14091419
const rgw_obj& obj,
@@ -1426,8 +1436,13 @@ int restore_obj_from_cloud(RGWLCCloudTierCtx& tier_ctx,
14261436
bool skip_olh_obj_update = false); // can skip the OLH object update if, for example, repairing index
14271437
int repair_olh(const DoutPrefixProvider *dpp, RGWObjState* state, const RGWBucketInfo& bucket_info,
14281438
const rgw_obj& obj, optional_yield y);
1429-
int unlink_obj_instance(const DoutPrefixProvider *dpp, RGWObjectCtx& obj_ctx, RGWBucketInfo& bucket_info, const rgw_obj& target_obj,
1430-
uint64_t olh_epoch, optional_yield y, uint16_t bilog_flags, bool null_verid, rgw_zone_set *zones_trace = nullptr, bool log_op = true);
1439+
int unlink_obj_instance(const DoutPrefixProvider *dpp,
1440+
RGWObjectCtx& obj_ctx, RGWBucketInfo& bucket_info,
1441+
const rgw_obj& target_obj,
1442+
uint64_t olh_epoch, optional_yield y,
1443+
uint16_t bilog_flags, bool null_verid,
1444+
rgw_zone_set *zones_trace = nullptr,
1445+
bool log_op = true, const bool force = false);
14311446

14321447
void check_pending_olh_entries(const DoutPrefixProvider *dpp, std::map<std::string, bufferlist>& pending_entries, std::map<std::string, bufferlist> *rm_pending_entries);
14331448
int remove_olh_pending_entries(const DoutPrefixProvider *dpp, const RGWBucketInfo& bucket_info, RGWObjState& state, const rgw_obj& olh_obj, std::map<std::string, bufferlist>& pending_attrs, optional_yield y);

src/rgw/driver/rados/rgw_sal_rados.cc

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3427,6 +3427,7 @@ RadosObject::RadosDeleteOp::RadosDeleteOp(RadosObject *_source) :
34273427
parent_op(&op_target)
34283428
{ }
34293429

3430+
34303431
int RadosObject::RadosDeleteOp::delete_obj(const DoutPrefixProvider* dpp, optional_yield y, uint32_t flags)
34313432
{
34323433
parent_op.params.bucket_owner = params.bucket_owner;
@@ -3448,15 +3449,16 @@ int RadosObject::RadosDeleteOp::delete_obj(const DoutPrefixProvider* dpp, option
34483449
parent_op.params.check_objv = params.objv_tracker->version_for_check();
34493450
}
34503451

3451-
int ret = parent_op.delete_obj(y, dpp, flags & FLAG_LOG_OP);
3452-
if (ret < 0)
3452+
int ret = parent_op.delete_obj(y, dpp, flags & FLAG_LOG_OP, flags & FLAG_FORCE_OP);
3453+
if (ret < 0) {
34533454
return ret;
3455+
}
34543456

34553457
result.delete_marker = parent_op.result.delete_marker;
34563458
result.version_id = parent_op.result.version_id;
34573459

34583460
return ret;
3459-
}
3461+
} // RadosObject::RadosDeleteOp::delete_obj
34603462

34613463
int RadosObject::delete_object(const DoutPrefixProvider* dpp,
34623464
optional_yield y,
@@ -3468,15 +3470,18 @@ int RadosObject::delete_object(const DoutPrefixProvider* dpp,
34683470
RGWRados::Object::Delete del_op(&del_target);
34693471

34703472
del_op.params.bucket_owner = bucket->get_info().owner;
3471-
del_op.params.versioning_status = (flags & FLAG_PREVENT_VERSIONING)
3472-
? 0 : bucket->get_info().versioning_status();
3473+
del_op.params.versioning_status =
3474+
(flags & FLAG_PREVENT_VERSIONING)
3475+
? 0
3476+
: bucket->get_info().versioning_status();
34733477
del_op.params.remove_objs = remove_objs;
34743478
if (objv) {
34753479
del_op.params.check_objv = objv->version_for_check();
34763480
}
34773481

3478-
return del_op.delete_obj(y, dpp, flags & FLAG_LOG_OP);
3479-
}
3482+
// convert flags to bool params
3483+
return del_op.delete_obj(y, dpp, flags & FLAG_LOG_OP, flags & FLAG_FORCE_OP);
3484+
} // RadosObject::delete_object
34803485

34813486
int RadosObject::copy_object(const ACLOwner& owner,
34823487
const rgw_user& remote_user,

src/rgw/radosgw-admin/radosgw-admin.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8312,9 +8312,10 @@ int main(int argc, const char **argv)
83128312
cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
83138313
return -ret;
83148314
}
8315+
83158316
rgw_obj_key key(object, object_version);
8316-
ret = rgw_remove_object(dpp(), driver, bucket.get(), key, null_yield);
83178317

8318+
ret = rgw_remove_object(dpp(), driver, bucket.get(), key, null_yield, yes_i_really_mean_it);
83188319
if (ret < 0) {
83198320
cerr << "ERROR: object remove returned: " << cpp_strerror(-ret) << std::endl;
83208321
return -ret;

src/rgw/rgw_sal.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,10 @@ enum AttrsMod {
155155
static constexpr uint32_t FLAG_LOG_OP = 0x0001;
156156
static constexpr uint32_t FLAG_PREVENT_VERSIONING = 0x0002;
157157

158+
// if cannot do all elements of op, do as much as possible (e.g.,
159+
// delete object where head object is missing)
160+
static constexpr uint32_t FLAG_FORCE_OP = 0x0004;
161+
158162
enum RGWRestoreStatus : uint8_t {
159163
None = 0,
160164
RestoreAlreadyInProgress = 1,

0 commit comments

Comments
 (0)