kick_off_scrubs();
}
+void ScrubStack::add_to_waiting(MDSCacheObject *obj)
+{
+ scrubs_in_progress++;
+ obj->item_scrub.remove_myself();
+ scrub_waiting.push_back(&obj->item_scrub);
+}
+
+void ScrubStack::remove_from_waiting(MDSCacheObject *obj)
+{
+ scrubs_in_progress--;
+ if (obj->item_scrub.is_on_list()) {
+ obj->item_scrub.remove_myself();
+ scrub_stack.push_front(&obj->item_scrub);
+ kick_off_scrubs();
+ }
+}
+
+class C_RetryScrub : public MDSInternalContext {
+public:
+ C_RetryScrub(ScrubStack *s, MDSCacheObject *o) :
+ MDSInternalContext(s->mdcache->mds), stack(s), obj(o) {
+ stack->add_to_waiting(obj);
+ }
+ void finish(int r) override {
+ stack->remove_from_waiting(obj);
+ }
+private:
+ ScrubStack *stack;
+ MDSCacheObject *obj;
+};
+
void ScrubStack::kick_off_scrubs()
{
ceph_assert(ceph_mutex_is_locked(mdcache->mds->mds_lock));
assert(state == STATE_RUNNING || state == STATE_IDLE);
set_state(STATE_RUNNING);
+
if (CInode *in = dynamic_cast<CInode*>(*it)) {
dout(20) << __func__ << " examining " << *in << dendl;
++it;
}
}
} else if (CDir *dir = dynamic_cast<CDir*>(*it)) {
+ auto next = it;
+ ++next;
bool done = false; // it's done, so pop it off the stack
scrub_dirfrag(dir, &done);
- ++it;
if (done) {
dout(20) << __func__ << " dirfrag, done" << dendl;
+ ++it; // child inodes were queued at bottom of stack
dequeue(dir);
+ } else {
+ it = next;
}
} else {
ceph_assert(0 == "dentry in scrub stack");
}
}
if (gather.has_subs()) {
- scrubs_in_progress++;
- gather.set_finisher(&scrub_kick);
+ gather.set_finisher(new C_RetryScrub(this, in));
gather.activate();
return;
}
dout(10) << __func__ << " " << *dir << dendl;
if (!dir->is_complete()) {
- scrubs_in_progress++;
- dir->fetch(&scrub_kick, true); // already auth pinned
+ dir->fetch(new C_RetryScrub(this, dir), true); // already auth pinned
dout(10) << __func__ << " incomplete, fetching" << dendl;
return;
}
}
}
-ScrubStack::C_KickOffScrubs::C_KickOffScrubs(MDCache *mdcache, ScrubStack *s)
- : MDSInternalContext(mdcache->mds), stack(s) { }
+ScrubStack::C_KickOffScrubs::C_KickOffScrubs(ScrubStack *s)
+ : MDSInternalContext(s->mdcache->mds), stack(s) { }
void ScrubStack::complete_control_contexts(int r) {
ceph_assert(ceph_mutex_is_locked_by_me(mdcache->mds->mds_lock));
ceph_assert(ceph_mutex_is_locked_by_me(mdcache->mds->mds_lock));
ceph_assert(clear_stack);
- for (auto it = scrub_stack.begin(); !it.end(); ++it) {
- if (CInode *in = dynamic_cast<CInode*>(*it)) {
+ auto abort_one = [this](MDSCacheObject *obj) {
+ if (CInode *in = dynamic_cast<CInode*>(obj)) {
if (in == in->scrub_info()->header->get_origin()) {
scrub_origins.erase(in);
clog_scrub_summary(in);
if (ctx != nullptr) {
ctx->complete(-ECANCELED);
}
- } else if (CDir *dir = dynamic_cast<CDir*>(*it)) {
+ } else if (CDir *dir = dynamic_cast<CDir*>(obj)) {
MDSContext *ctx = nullptr;
dir->scrub_aborted(&ctx);
dir->auth_unpin(this);
} else {
ceph_abort(0 == "dentry in scrub stack");
}
- }
+ };
+ for (auto it = scrub_stack.begin(); !it.end(); ++it)
+ abort_one(*it);
+ for (auto it = scrub_waiting.begin(); !it.end(); ++it)
+ abort_one(*it);
stack_size = 0;
scrub_stack.clear();
+ scrub_waiting.clear();
clear_stack = false;
}
clog(clog),
finisher(finisher_),
scrub_stack(member_offset(MDSCacheObject, item_scrub)),
- scrub_kick(mdc, this) {}
+ scrub_waiting(member_offset(MDSCacheObject, item_scrub)),
+ scrub_kick(this) {}
~ScrubStack() {
ceph_assert(scrub_stack.empty());
ceph_assert(!scrubs_in_progress);
protected:
class C_KickOffScrubs : public MDSInternalContext {
public:
- C_KickOffScrubs(MDCache *mdcache, ScrubStack *s);
+ C_KickOffScrubs(ScrubStack *s);
void finish(int r) override { }
void complete(int r) override {
if (r == -ECANCELED) {
/// The stack of inodes we want to scrub
elist<MDSCacheObject*> scrub_stack;
+ elist<MDSCacheObject*> scrub_waiting;
/// current number of dentries we're actually scrubbing
int scrubs_in_progress = 0;
int stack_size = 0;
C_KickOffScrubs scrub_kick;
+ friend class C_RetryScrub;
private:
// scrub abort is _not_ a state, rather it's an operation that's
// performed after in-progress scrubs are finished.
* state of the stack.
*/
void kick_off_scrubs();
+
+ /**
+ * Move the inode/dirfrag that can't be scrubbed immediately
+ * from scrub queue to waiting list.
+ */
+ void add_to_waiting(MDSCacheObject *obj);
+ /**
+ * Move the inode/dirfrag back to scrub queue.
+ */
+ void remove_from_waiting(MDSCacheObject *obj);
+
/**
* Scrub a file inode.
* @param in The inode to scrub