From: Josh Durgin Date: Wed, 11 May 2016 00:34:24 +0000 (-0700) Subject: ReplicatedPG: return error codes for dups from the pg log X-Git-Tag: ses5-milestone5~413^2~6 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=4c709e9b6d4c54adbc7581128c12dd7c73c38da9;p=ceph.git ReplicatedPG: return error codes for dups from the pg log This prevents reordering guarded writes or deletes. Without this, the following sequence: delete foo -> -ENOENT write foo -> success (client connection fails) resend delete foo -> success, object deleted resend write foo -> success - dup op, so no write performed results in the object not existing, instead of containing data. After this change, both delete and write are detected as dups and the original ordering is preserved. Fixes: http://tracker.ceph.com/issues/14468 Signed-off-by: Josh Durgin --- diff --git a/src/osd/PGLog.h b/src/osd/PGLog.h index 46b2f3c4f0c..9df9e62f088 100644 --- a/src/osd/PGLog.h +++ b/src/osd/PGLog.h @@ -166,9 +166,11 @@ struct PGLog : DoutPrefixProvider { bool get_request( const osd_reqid_t &r, eversion_t *replay_version, - version_t *user_version) const { + version_t *user_version, + int *return_code) const { assert(replay_version); assert(user_version); + assert(return_code); ceph::unordered_map::const_iterator p; if (!(indexed_data & PGLOG_INDEXED_CALLER_OPS)) { index_caller_ops(); @@ -177,6 +179,7 @@ struct PGLog : DoutPrefixProvider { if (p != caller_ops.end()) { *replay_version = p->second->version; *user_version = p->second->user_version; + *return_code = p->second->return_code; return true; } @@ -194,6 +197,7 @@ struct PGLog : DoutPrefixProvider { if (i->first == r) { *replay_version = p->second->version; *user_version = i->second; + *return_code = p->second->return_code; return true; } } diff --git a/src/osd/ReplicatedPG.cc b/src/osd/ReplicatedPG.cc index 993e59b9e13..5e216f23a1a 100644 --- a/src/osd/ReplicatedPG.cc +++ b/src/osd/ReplicatedPG.cc @@ -1787,13 +1787,14 @@ void ReplicatedPG::do_op(OpRequestRef& op) // purposes here it doesn't matter which one we get. eversion_t replay_version; version_t user_version; + int return_code = 0; bool got = pg_log.get_log().get_request( - m->get_reqid(), &replay_version, &user_version); + m->get_reqid(), &replay_version, &user_version, &return_code); if (got) { dout(3) << __func__ << " dup " << m->get_reqid() << " was " << replay_version << dendl; - if (already_complete(replay_version)) { - osd->reply_op_error(op, 0, replay_version, user_version); + if (return_code < 0 || already_complete(replay_version)) { + osd->reply_op_error(op, return_code, replay_version, user_version); } else { if (m->wants_ack()) { if (already_ack(replay_version)) {