mirror of
https://github.com/ceph/ceph
synced 2024-12-26 21:43:10 +00:00
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:
parent
afb2e12078
commit
547c1ed9f1
@ -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,
|
||||
|
@ -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().
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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() {}
|
||||
|
||||
|
@ -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";
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user