mds: make both CInode and CDir as entities of scrub

Making CDir as entity of scrub is preparetion for scrubbing across
multiple mds. When subtree bound is encountered, scrub should be
forwarded to subtree's auth mds. The auth mds adds CDir to scrub stack.

Signed-off-by: Simon Gao <simon29rock@gmail.com>
Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
This commit is contained in:
Yan, Zheng 2020-05-02 16:24:17 +08:00
parent afb2e12078
commit 547c1ed9f1
9 changed files with 197 additions and 186 deletions

View File

@ -3480,11 +3480,20 @@ void CDir::scrub_info_create() const
me->scrub_infop.swap(si);
}
void CDir::scrub_initialize(const ScrubHeaderRefConst& header)
void CDir::scrub_initialize(const ScrubHeaderRef& header, MDSContext* f)
{
ceph_assert(header);
// FIXME: weird implicit construction, is someone else meant
// to be calling scrub_info_create first?
scrub_info();
scrub_infop->header = header;
scrub_infop->on_finish = f;
}
void CDir::scrub_initialize_data()
{
dout(20) << __func__ << dendl;
ceph_assert(is_complete());
ceph_assert(header != nullptr);
// FIXME: weird implicit construction, is someone else meant
// to be calling scrub_info_create first?
@ -3519,10 +3528,24 @@ void CDir::scrub_initialize(const ScrubHeaderRefConst& header)
}
}
scrub_infop->directory_scrubbing = true;
scrub_infop->header = header;
}
void CDir::scrub_finished()
void CDir::scrub_aborted(MDSContext **c) {
dout(20) << __func__ << dendl;
ceph_assert(scrub_infop && scrub_infop->directory_scrubbing);
*c = scrub_infop->on_finish;
scrub_infop->on_finish = nullptr;
scrub_infop->directory_scrubbing = false;
scrub_infop->need_scrub_local = false;
scrub_infop->last_scrub_dirty = false;
scrub_infop->pending_scrub_error = false;
scrub_infop->dirty_scrub_stamps.clear();
scrub_infop.reset();
}
void CDir::scrub_finished(MDSContext **c)
{
dout(20) << __func__ << dendl;
ceph_assert(scrub_infop && scrub_infop->directory_scrubbing);
@ -3537,6 +3560,9 @@ void CDir::scrub_finished()
scrub_infop->last_recursive = scrub_infop->recursive_start;
scrub_infop->last_scrub_dirty = true;
*c = scrub_infop->on_finish;
scrub_infop->on_finish = nullptr;
}
int CDir::_next_dentry_on_set(dentry_key_set &dns, bool missing_okay,

View File

@ -108,6 +108,7 @@ public:
/// inodes we contain with dirty scrub stamps
dentry_key_map dirty_scrub_stamps; // TODO: make use of this!
MDSContext *on_finish = nullptr;
scrub_stamps recursive_start; // when we last started a recursive scrub
scrub_stamps last_recursive; // when we last finished a recursive scrub
scrub_stamps last_local; // when we last did a local scrub
@ -125,7 +126,7 @@ public:
dentry_key_set others_scrubbing;
dentry_key_set others_scrubbed;
ScrubHeaderRefConst header;
ScrubHeaderRef header;
};
// -- pins --
@ -320,7 +321,13 @@ public:
* @pre The CDir is marked complete.
* @post It has set up its internal scrubbing state.
*/
void scrub_initialize(const ScrubHeaderRefConst& header);
void scrub_initialize(const ScrubHeaderRef& header,
MDSContext* f);
void scrub_initialize_data();
ScrubHeaderRef get_scrub_header() {
return scrub_infop ? scrub_infop->header : nullptr;
}
/**
* Get the next dentry to scrub. Gives you a CDentry* and its meaning. This
* function will give you all directory-representing dentries before any
@ -353,7 +360,9 @@ public:
* Call this once all CDentries have been scrubbed, according to
* scrub_dentry_next's listing. It finalizes the scrub statistics.
*/
void scrub_finished();
void scrub_finished(MDSContext **c);
void scrub_aborted(MDSContext **c);
/**
* Tell the CDir to do a local scrub of itself.
* @pre The CDir is_complete().

View File

@ -119,7 +119,6 @@ std::string_view CInode::pin_name(int p) const
case PIN_DIRTYRSTAT: return "dirtyrstat";
case PIN_DIRTYPARENT: return "dirtyparent";
case PIN_DIRWAITER: return "dirwaiter";
case PIN_SCRUBQUEUE: return "scrubqueue";
default: return generic_pin_name(p);
}
}

View File

@ -350,7 +350,6 @@ class CInode : public MDSCacheObject, public InodeStoreBase, public Counter<CIno
static const int PIN_EXPORTINGCAPS = 22;
static const int PIN_DIRTYPARENT = 23;
static const int PIN_DIRWAITER = 24;
static const int PIN_SCRUBQUEUE = 25;
// -- dump flags --
static const int DUMP_INODE_STORE_BASE = (1 << 0);
@ -1131,7 +1130,6 @@ class CInode : public MDSCacheObject, public InodeStoreBase, public Counter<CIno
elist<CInode*>::item item_dirty_dirfrag_dir;
elist<CInode*>::item item_dirty_dirfrag_nest;
elist<CInode*>::item item_dirty_dirfrag_dirfragtree;
elist<CInode*>::item item_scrub;
// also update RecoveryQueue::RecoveryQueue() if you change this
elist<CInode*>::item& item_recover_queue = item_dirty_dirfrag_dir;

View File

@ -12833,13 +12833,9 @@ void MDCache::enqueue_scrub_work(MDRequestRef& mdr)
mds->mdlog->wait_for_safe(new MDSInternalContextWrapper(mds, flush_finish));
});
if (!header->get_recursive()) {
mds->scrubstack->enqueue_inode_top(in, header,
new MDSInternalContextWrapper(mds, scrub_finish));
} else {
mds->scrubstack->enqueue_inode_bottom(in, header,
new MDSInternalContextWrapper(mds, scrub_finish));
}
mds->scrubstack->enqueue(in, header,
new MDSInternalContextWrapper(mds, scrub_finish),
!header->get_recursive());
mds->server->respond_to_request(mdr, 0);
return;

View File

@ -18,6 +18,7 @@ std::string_view MDSCacheObject::generic_pin_name(int p) const {
case PIN_TEMPEXPORTING: return "tempexporting";
case PIN_CLIENTLEASE: return "clientlease";
case PIN_DISCOVERBASE: return "discoverbase";
case PIN_SCRUBQUEUE: return "scrubqueue";
default: ceph_abort(); return std::string_view();
}
}

View File

@ -14,6 +14,7 @@
#include "mdstypes.h"
#include "MDSContext.h"
#include "include/elist.h"
#define MDS_REF_SET // define me for improved debug output, sanity checking
//#define MDS_AUTHPIN_SET // define me for debugging auth pin leaks
@ -75,6 +76,7 @@ class MDSCacheObject {
const static int PIN_TEMPEXPORTING = 1008; // temp pin between encode_ and finish_export
static const int PIN_CLIENTLEASE = 1009;
static const int PIN_DISCOVERBASE = 1010;
static const int PIN_SCRUBQUEUE = 1011; // for scrub of inode and dir
// -- state --
const static int STATE_AUTH = (1<<30);
@ -88,6 +90,8 @@ class MDSCacheObject {
const static uint64_t WAIT_SINGLEAUTH = (1ull<<60);
const static uint64_t WAIT_UNFREEZE = (1ull<<59); // pka AUTHPINNABLE
elist<MDSCacheObject*>::item item_scrub; // for scrub inode or dir
MDSCacheObject() {}
virtual ~MDSCacheObject() {}

View File

@ -49,60 +49,57 @@ std::ostream &operator<<(std::ostream &os, const ScrubStack::State &state) {
return os;
}
void ScrubStack::push_inode(CInode *in)
void ScrubStack::dequeue(MDSCacheObject *obj)
{
dout(20) << "pushing " << *in << " on top of ScrubStack" << dendl;
if (!in->item_scrub.is_on_list()) {
in->get(CInode::PIN_SCRUBQUEUE);
stack_size++;
}
inode_stack.push_front(&in->item_scrub);
}
void ScrubStack::push_inode_bottom(CInode *in)
{
dout(20) << "pushing " << *in << " on bottom of ScrubStack" << dendl;
if (!in->item_scrub.is_on_list()) {
in->get(CInode::PIN_SCRUBQUEUE);
stack_size++;
}
inode_stack.push_back(&in->item_scrub);
}
void ScrubStack::pop_inode(CInode *in)
{
dout(20) << "popping " << *in
<< " off of ScrubStack" << dendl;
ceph_assert(in->item_scrub.is_on_list());
in->put(CInode::PIN_SCRUBQUEUE);
in->item_scrub.remove_myself();
dout(20) << "dequeue " << *obj << " from ScrubStack" << dendl;
ceph_assert(obj->item_scrub.is_on_list());
obj->put(MDSCacheObject::PIN_SCRUBQUEUE);
obj->item_scrub.remove_myself();
stack_size--;
}
void ScrubStack::_enqueue_inode(CInode *in, CDentry *parent,
ScrubHeaderRef& header,
MDSContext *on_finish, bool top)
void ScrubStack::_enqueue(MDSCacheObject *obj, CDentry *parent,
ScrubHeaderRef& header,
MDSContext *on_finish, bool top)
{
dout(10) << __func__ << " with {" << *in << "}"
<< ", on_finish=" << on_finish << ", top=" << top << dendl;
ceph_assert(ceph_mutex_is_locked_by_me(mdcache->mds->mds_lock));
in->scrub_initialize(parent, header, on_finish);
if (CInode *in = dynamic_cast<CInode*>(obj)) {
dout(10) << __func__ << " with {" << *in << "}"
<< ", on_finish=" << on_finish << ", top=" << top << dendl;
in->scrub_initialize(parent, header, on_finish);
} else if (CDir *dir = dynamic_cast<CDir*>(obj)) {
dout(10) << __func__ << " with {" << *dir << "}"
<< ", on_finish=" << on_finish << ", top=" << top << dendl;
// The edge directory must be in memory
dir->scrub_initialize(header, on_finish);
} else {
ceph_assert(0 == "queue dentry to scrub stack");
}
dout(20) << "enqueue " << *obj << " to " << (top ? "top" : "bottom") << " of ScrubStack" << dendl;
if (!obj->item_scrub.is_on_list()) {
obj->get(MDSCacheObject::PIN_SCRUBQUEUE);
stack_size++;
}
if (top)
push_inode(in);
scrub_stack.push_front(&obj->item_scrub);
else
push_inode_bottom(in);
scrub_stack.push_back(&obj->item_scrub);
}
void ScrubStack::enqueue_inode(CInode *in, ScrubHeaderRef& header,
MDSContext *on_finish, bool top)
void ScrubStack::enqueue(CInode *in, ScrubHeaderRef& header,
MDSContext *on_finish, bool top)
{
// abort in progress
if (clear_inode_stack) {
if (clear_stack) {
on_finish->complete(-EAGAIN);
return;
}
_enqueue_inode(in, NULL, header, on_finish, top);
scrub_origins.emplace(in);
clog_scrub_summary(in);
_enqueue(in, nullptr, header, on_finish, top);
kick_off_scrubs();
}
@ -111,13 +108,13 @@ void ScrubStack::kick_off_scrubs()
ceph_assert(ceph_mutex_is_locked(mdcache->mds->mds_lock));
dout(20) << __func__ << ": state=" << state << dendl;
if (clear_inode_stack || state == STATE_PAUSING || state == STATE_PAUSED) {
if (clear_stack || state == STATE_PAUSING || state == STATE_PAUSED) {
if (scrubs_in_progress == 0) {
dout(10) << __func__ << ": in progress scrub operations finished, "
<< stack_size << " in the stack" << dendl;
State final_state = state;
if (clear_inode_stack) {
if (clear_stack) {
abort_pending_scrubs();
final_state = STATE_IDLE;
}
@ -135,10 +132,10 @@ void ScrubStack::kick_off_scrubs()
dout(20) << __func__ << " entering with " << scrubs_in_progress << " in "
"progress and " << stack_size << " in the stack" << dendl;
bool can_continue = true;
elist<CInode*>::iterator i = inode_stack.begin();
elist<MDSCacheObject*>::iterator it = scrub_stack.begin();
while (g_conf()->mds_max_scrub_ops_in_progress > scrubs_in_progress &&
can_continue) {
if (i.end()) {
if (it.end()) {
if (scrubs_in_progress == 0) {
set_state(STATE_IDLE);
}
@ -149,51 +146,64 @@ void ScrubStack::kick_off_scrubs()
assert(state == STATE_RUNNING || state == STATE_IDLE);
set_state(STATE_RUNNING);
CInode *curi = *i;
++i; // we have our reference, push iterator forward
if (CInode *in = dynamic_cast<CInode*>(*it)) {
++it; // we have our reference, push iterator forward
dout(20) << __func__ << " examining " << *in << dendl;
dout(20) << __func__ << " examining " << *curi << dendl;
if (!in->is_dir()) {
// it's a regular file, symlink, or hard link
dequeue(in); // we only touch it this once, so remove from stack
if (!curi->is_dir()) {
// it's a regular file, symlink, or hard link
pop_inode(curi); // we only touch it this once, so remove from stack
if (!curi->scrub_info()->on_finish) {
scrubs_in_progress++;
curi->scrub_set_finisher(&scrub_kick);
}
scrub_file_inode(curi);
can_continue = true;
} else {
bool completed; // it's done, so pop it off the stack
bool terminal; // not done, but we can start ops on other directories
bool progress; // it added new dentries to the top of the stack
scrub_dir_inode(curi, &progress, &terminal, &completed);
if (completed) {
dout(20) << __func__ << " dir completed" << dendl;
pop_inode(curi);
} else if (progress) {
dout(20) << __func__ << " dir progressed" << dendl;
// we added new stuff to top of stack, so reset ourselves there
i = inode_stack.begin();
if (!in->scrub_info()->on_finish) {
scrubs_in_progress++;
in->scrub_set_finisher(&scrub_kick);
}
scrub_file_inode(in);
can_continue = true;
} else {
dout(20) << __func__ << " dir no-op" << dendl;
bool done; // it's done, so pop it off the stack
bool added_children; // it added new dentries to the top of the stack
scrub_dir_inode(in, &added_children, &done);
if (done) {
dout(20) << __func__ << " dir inode, done" << dendl;
dequeue(in);
} else if (added_children) {
dout(20) << __func__ << " dir inode, added_children" << dendl;
// we added new stuff to top of stack, so reset ourselves there
it = scrub_stack.begin();
} else {
dout(20) << __func__ << " dir inode, no progress" << dendl;
can_continue = false;
}
}
can_continue = progress || terminal || completed;
} else if (CDir *dir = dynamic_cast<CDir*>(*it)) {
bool done; // it's done, so pop it off the stack
bool added_children; // it added new dentries to the top of the stack
scrub_dirfrag(dir, &added_children, &done);
if (done) {
dout(20) << __func__ << " dirfrag, done" << dendl;
dequeue(dir);
} else if (added_children) {
dout(20) << __func__ << " dirfrag, added_children" << dendl;
// we added new stuff to top of stack, so reset ourselves there
it = scrub_stack.begin();
} else {
dout(20) << __func__ << " dirfrag, no progress" << dendl;
can_continue = false;
}
} else {
ceph_assert(0 == "dentry in scrub stack");
}
}
}
void ScrubStack::scrub_dir_inode(CInode *in,
bool *added_children,
bool *terminal,
bool *done)
{
dout(10) << __func__ << " " << *in << dendl;
*added_children = false;
bool all_frags_terminal = true;
bool all_frags_done = true;
ScrubHeaderRef header = in->get_scrub_header();
@ -232,11 +242,11 @@ void ScrubStack::scrub_dir_inode(CInode *in,
dout(20) << __func__ << " get_next_cdir ready=" << ready << dendl;
if (ready && cur_dir) {
cur_dir->scrub_initialize(header, nullptr);
scrubbing_cdirs.push(cur_dir);
} else if (!ready) {
// We are waiting for load of a frag
all_frags_done = false;
all_frags_terminal = false;
break;
} else {
// Finished with all frags
@ -245,20 +255,17 @@ void ScrubStack::scrub_dir_inode(CInode *in,
}
// scrub that CDir
bool frag_added_children = false;
bool frag_terminal = true;
bool frag_done = false;
scrub_dirfrag(cur_dir, header,
&frag_added_children, &frag_terminal, &frag_done);
scrub_dirfrag(cur_dir,
&frag_added_children, &frag_done);
if (frag_done) {
cur_dir->inode->scrub_dirfrag_finished(cur_dir->frag);
}
*added_children |= frag_added_children;
all_frags_terminal = all_frags_terminal && frag_terminal;
all_frags_done = all_frags_done && frag_done;
}
dout(20) << "finished looping; all_frags_terminal=" << all_frags_terminal
<< ", all_frags_done=" << all_frags_done << dendl;
dout(20) << "finished looping, all_frags_done=" << all_frags_done << dendl;
} else {
dout(20) << "!scrub_recursive" << dendl;
}
@ -272,9 +279,8 @@ void ScrubStack::scrub_dir_inode(CInode *in,
scrub_dir_inode_final(in);
}
*terminal = all_frags_terminal;
*done = all_frags_done;
dout(10) << __func__ << " is exiting " << *terminal << " " << *done << dendl;
dout(10) << __func__ << " is exiting " << *done << dendl;
return;
}
@ -348,18 +354,15 @@ void ScrubStack::scrub_dir_inode_final(CInode *in)
return;
}
void ScrubStack::scrub_dirfrag(CDir *dir,
ScrubHeaderRef& header,
bool *added_children, bool *is_terminal,
bool *done)
void ScrubStack::scrub_dirfrag(CDir *dir, bool *added_children, bool *done)
{
ceph_assert(dir != NULL);
dout(20) << __func__ << " on " << *dir << dendl;
*added_children = false;
*is_terminal = false;
*done = false;
ScrubHeaderRef header = dir->get_scrub_header();
if (!dir->scrub_info()->directory_scrubbing) {
// Get the frag complete before calling
@ -371,7 +374,7 @@ void ScrubStack::scrub_dirfrag(CDir *dir,
return;
}
dir->scrub_initialize(header);
dir->scrub_initialize_data();
}
int r = 0;
@ -393,11 +396,12 @@ void ScrubStack::scrub_dirfrag(CDir *dir,
// Nothing left to scrub, are we done?
auto&& scrubbing = dir->scrub_dentries_scrubbing();
if (scrubbing.empty()) {
dout(20) << __func__ << " dirfrag done: " << *dir << dendl;
// FIXME: greg: What's the diff meant to be between done and terminal
dir->scrub_finished();
*done = true;
*is_terminal = true;
dout(20) << __func__ << " dirfrag done: " << *dir << dendl;
MDSContext *c = nullptr;
dir->scrub_finished(&c);
if (c)
finisher->queue(new MDSIOContextWrapper(mdcache->mds, c), 0);
*done = true;
} else {
dout(20) << __func__ << " " << scrubbing.size() << " dentries still "
"scrubbing in " << *dir << dendl;
@ -409,7 +413,7 @@ void ScrubStack::scrub_dirfrag(CDir *dir,
// never get random IO errors here.
ceph_assert(r == 0);
_enqueue_inode(dn->get_projected_inode(), dn, header, NULL, true);
_enqueue(dn->get_projected_inode(), dn, header, nullptr, true);
*added_children = true;
}
@ -475,8 +479,10 @@ void ScrubStack::_validate_inode_done(CInode *in, int r,
dout(10) << __func__ << " scrub passed on inode " << *in << dendl;
}
MDSContext *c = NULL;
MDSContext *c = nullptr;
in->scrub_finished(&c);
if (c)
finisher->queue(new MDSIOContextWrapper(mdcache->mds, c), 0);
if (in == header->get_origin()) {
scrub_origins.erase(in);
@ -491,9 +497,6 @@ void ScrubStack::_validate_inode_done(CInode *in, int r,
}
}
}
if (c) {
finisher->queue(new MDSIOContextWrapper(mdcache->mds, c), 0);
}
}
ScrubStack::C_KickOffScrubs::C_KickOffScrubs(MDCache *mdcache, ScrubStack *s)
@ -541,7 +544,7 @@ std::string_view ScrubStack::scrub_summary() {
}
if (state == STATE_RUNNING) {
if (clear_inode_stack) {
if (clear_stack) {
*cs << "aborting";
} else {
*cs << "active";
@ -555,7 +558,7 @@ std::string_view ScrubStack::scrub_summary() {
*cs << "paused";
}
if (clear_inode_stack) {
if (clear_stack) {
if (have_more) {
*cs << "+";
}
@ -589,7 +592,7 @@ void ScrubStack::scrub_status(Formatter *f) {
if (state == STATE_IDLE) {
*css << "no active scrubs running";
} else if (state == STATE_RUNNING) {
if (clear_inode_stack) {
if (clear_stack) {
*css << "ABORTING";
} else {
*css << "scrub active";
@ -600,7 +603,7 @@ void ScrubStack::scrub_status(Formatter *f) {
have_more = true;
*css << state;
}
if (clear_inode_stack) {
if (clear_stack) {
if (have_more) {
*css << "+";
}
@ -649,25 +652,33 @@ void ScrubStack::scrub_status(Formatter *f) {
void ScrubStack::abort_pending_scrubs() {
ceph_assert(ceph_mutex_is_locked_by_me(mdcache->mds->mds_lock));
ceph_assert(clear_inode_stack);
ceph_assert(clear_stack);
for (auto inode = inode_stack.begin(); !inode.end(); ++inode) {
CInode *in = *inode;
if (in == in->scrub_info()->header->get_origin()) {
scrub_origins.erase(in);
clog_scrub_summary(in);
}
MDSContext *ctx = nullptr;
in->scrub_aborted(&ctx);
if (ctx != nullptr) {
ctx->complete(-ECANCELED);
for (auto it = scrub_stack.begin(); !it.end(); ++it) {
if (CInode *in = dynamic_cast<CInode*>(*it)) {
if (in == in->scrub_info()->header->get_origin()) {
scrub_origins.erase(in);
clog_scrub_summary(in);
}
MDSContext *ctx = nullptr;
in->scrub_aborted(&ctx);
if (ctx != nullptr) {
ctx->complete(-ECANCELED);
}
} else if (CDir *dir = dynamic_cast<CDir*>(*it)) {
MDSContext *ctx = nullptr;
dir->scrub_aborted(&ctx);
if (ctx != nullptr) {
ctx->complete(-ECANCELED);
}
} else {
ceph_abort(0 == "dentry in scrub stack");
}
}
stack_size = 0;
inode_stack.clear();
clear_inode_stack = false;
scrub_stack.clear();
clear_stack = false;
}
void ScrubStack::scrub_abort(Context *on_finish) {
@ -678,7 +689,7 @@ void ScrubStack::scrub_abort(Context *on_finish) {
<< " scrubs in progress and " << stack_size << " in the"
<< " stack" << dendl;
clear_inode_stack = true;
clear_stack = true;
if (scrub_in_transition_state()) {
control_ctxs.push_back(on_finish);
return;
@ -700,7 +711,7 @@ void ScrubStack::scrub_pause(Context *on_finish) {
<< " stack" << dendl;
// abort is in progress
if (clear_inode_stack) {
if (clear_stack) {
on_finish->complete(-EINVAL);
return;
}
@ -722,7 +733,7 @@ bool ScrubStack::scrub_resume() {
int r = 0;
if (clear_inode_stack) {
if (clear_stack) {
r = -EINVAL;
} else if (state == STATE_PAUSING) {
set_state(STATE_RUNNING);
@ -739,7 +750,7 @@ bool ScrubStack::scrub_resume() {
void ScrubStack::clog_scrub_summary(CInode *in) {
if (in) {
std::string what;
if (clear_inode_stack) {
if (clear_stack) {
what = "aborted";
} else if (scrub_origins.count(in)) {
what = "queued";

View File

@ -33,36 +33,20 @@ public:
mdcache(mdc),
clog(clog),
finisher(finisher_),
inode_stack(member_offset(CInode, item_scrub)),
scrub_stack(member_offset(MDSCacheObject, item_scrub)),
scrub_kick(mdc, this) {}
~ScrubStack() {
ceph_assert(inode_stack.empty());
ceph_assert(scrub_stack.empty());
ceph_assert(!scrubs_in_progress);
}
/**
* Put a inode on the top of the scrub stack, so it is the highest priority.
* If there are other scrubs in progress, they will not continue scrubbing new
* entries until this one is completed.
* @param in The inodey to scrub
* Put the inode at either the top or bottom of the stack, with the
* given scrub params, and kick off more scrubbing.
* @param in The inode to scrub
* @param header The ScrubHeader propagated from wherever this scrub
* was initiated
*/
void enqueue_inode_top(CInode *in, ScrubHeaderRef& header,
MDSContext *on_finish) {
enqueue_inode(in, header, on_finish, true);
scrub_origins.emplace(in);
clog_scrub_summary(in);
}
/** Like enqueue_inode_top, but we wait for all pending scrubs before
* starting this one.
*/
void enqueue_inode_bottom(CInode *in, ScrubHeaderRef& header,
MDSContext *on_finish) {
enqueue_inode(in, header, on_finish, false);
scrub_origins.emplace(in);
clog_scrub_summary(in);
}
void enqueue(CInode *in, ScrubHeaderRef& header,
MDSContext *on_finish, bool top);
/**
* Abort an ongoing scrub operation. The abort operation could be
* delayed if there are in-progress scrub operations on going. The
@ -108,7 +92,7 @@ public:
return state_str == "idle";
}
bool is_scrubbing() const { return !inode_stack.empty(); }
bool is_scrubbing() const { return !scrub_stack.empty(); }
MDCache *mdcache;
@ -137,7 +121,7 @@ protected:
Finisher *finisher;
/// The stack of inodes we want to scrub
elist<CInode*> inode_stack;
elist<MDSCacheObject*> scrub_stack;
/// current number of dentries we're actually scrubbing
int scrubs_in_progress = 0;
int stack_size = 0;
@ -157,32 +141,18 @@ private:
friend class C_InodeValidated;
void _enqueue(MDSCacheObject *obj, CDentry *parent, ScrubHeaderRef& header,
MDSContext *on_finish, bool top);
/**
* Put the inode at either the top or bottom of the stack, with
* the given scrub params, and then try and kick off more scrubbing.
* Remove the inode/dirfrag from the stack.
*/
void enqueue_inode(CInode *in, ScrubHeaderRef& header,
MDSContext *on_finish, bool top);
void _enqueue_inode(CInode *in, CDentry *parent, ScrubHeaderRef& header,
MDSContext *on_finish, bool top);
inline void dequeue(MDSCacheObject *obj);
/**
* Kick off as many scrubs as are appropriate, based on the current
* state of the stack.
*/
void kick_off_scrubs();
/**
* Push a inode on top of the stack.
*/
inline void push_inode(CInode *in);
/**
* Push a inode to the bottom of the stack.
*/
inline void push_inode_bottom(CInode *in);
/**
* Pop the given inode off the stack.
*/
inline void pop_inode(CInode *in);
/**
* Scrub a file inode.
* @param in The inode to scrub
@ -214,12 +184,10 @@ private:
* @param in The CInode to scrub as a directory
* @param added_children set to true if we pushed some of our children
* onto the ScrubStack
* @param is_terminal set to true if there are no descendant dentries
* remaining to start scrubbing.
* @param done set to true if we and all our children have finished scrubbing
*/
void scrub_dir_inode(CInode *in, bool *added_children, bool *is_terminal,
bool *done);
void scrub_dir_inode(CInode *in, bool *added_children, bool *done);
/**
* Make progress on scrubbing a dirfrag. It may return after each of the
* following steps, but will report making progress on each one.
@ -234,8 +202,7 @@ private:
* progress. Try again later.
*
*/
void scrub_dirfrag(CDir *dir, ScrubHeaderRef& header,
bool *added_children, bool *is_terminal, bool *done);
void scrub_dirfrag(CDir *dir, bool *added_children, bool *done);
/**
* Scrub a directory-representing dentry.
*
@ -296,7 +263,7 @@ private:
void clog_scrub_summary(CInode *in=nullptr);
State state = STATE_IDLE;
bool clear_inode_stack = false;
bool clear_stack = false;
// list of pending context completions for asynchronous scrub
// control operations.