Consider a scenario like:
- scrub [3:
2525d100:::earlier:head,3:
2525d12f:::foo:200]
- we see 3:
2525d12f:::foo:100 and include it in scrub map
- scrub [3:
2525d12f:::foo:200, 3:
2525dfff:::later:head]
- some op(s) that cause scrub to be preempted
- agent_work wants to evict 3:
2525d12f:::foo:100
- write_blocked_by_scrub sees scrub is preempted, returns false
- 3:
2525d12f:::foo:100 is removed, :head SnapSet is updated
- scrub rescrubs [3:
2525d12f:::foo:200, 3:
2525dfff:::later:head]
- includes (updated) :head SnapSet
- issues error like "3:
2525d12f:::foo:100 is an unexpected clone"
Fix the problem by checking if anything part of the object-to-evict and
its head touch the scrub range; if so, back off. Do not let eviction
preempt scrub; we can come back and do it later.
Fixes: http://tracker.ceph.com/issues/23646
Signed-off-by: Sage Weil <sage@redhat.com>
return true;
}
+bool PG::range_intersects_scrub(const hobject_t &start, const hobject_t& end)
+{
+ // does [start, end] intersect [scrubber.start, scrubber.end)
+ return (start < scrubber.end &&
+ end >= scrubber.start);
+}
+
void PG::scrub_clear_state()
{
assert(is_locked());
// not stop until the scrub range is completed.
bool write_blocked_by_scrub(const hobject_t &soid);
+ /// true if the given range intersects the scrub interval in any way
+ bool range_intersects_scrub(const hobject_t &start, const hobject_t& end);
+
void repair_object(
const hobject_t& soid, list<pair<ScrubMap::object, pg_shard_t> > *ok_peers,
pg_shard_t bad_peer);
osd->logger->inc(l_osd_agent_skip);
continue;
}
- if (write_blocked_by_scrub(obc->obs.oi.soid)) {
+ if (range_intersects_scrub(obc->obs.oi.soid,
+ obc->obs.oi.soid.get_head())) {
dout(20) << __func__ << " skip (scrubbing) " << obc->obs.oi << dendl;
osd->logger->inc(l_osd_agent_skip);
continue;