<< "(" << path << "), rewriting it";
in->_mark_dirty_parent(in->mdcache->mds->mdlog->get_current_segment(),
false);
+ // Flag that we repaired this BT so that it won't go into damagetable
results->backtrace.repaired = true;
+
+ // Flag that we did some repair work so that our repair operation
+ // can be flushed at end of scrub
+ in->scrub_infop->header->set_repaired();
}
// If the inode's number was free in the InoTable, fix that
}
void CInode::scrub_initialize(CDentry *scrub_parent,
- const ScrubHeaderRefConst& header,
+ ScrubHeaderRef& header,
MDSInternalContextBase *f)
{
dout(20) << __func__ << " with scrub_version " << get_version() << dendl;
/// my own (temporary) stamps and versions for each dirfrag we have
std::map<frag_t, scrub_stamp_info_t> dirfrag_stamps;
- ScrubHeaderRefConst header;
+ ScrubHeaderRef header;
scrub_info_t() : scrub_stamp_info_t(),
scrub_parent(NULL), on_finish(NULL),
return scrub_infop;
}
+ ScrubHeaderRef get_scrub_header() {
+ if (scrub_infop == nullptr) {
+ return nullptr;
+ } else {
+ return scrub_infop->header;
+ }
+ }
+
bool scrub_is_in_progress() const {
return (scrub_infop && scrub_infop->scrub_in_progress);
}
* directory's get_projected_version())
*/
void scrub_initialize(CDentry *scrub_parent,
- const ScrubHeaderRefConst& header,
+ ScrubHeaderRef& header,
MDSInternalContextBase *f);
/**
* Get the next dirfrag to scrub. Gives you a frag_t in output param which
header->set_origin(in);
- // only set completion context for non-recursive scrub, because we don't
- // want to block asok caller on long running scrub
+ Context *fin = nullptr;
+ if (!header->get_recursive()) {
+ cs->take_finisher();
+ }
+
+ // If the scrub did some repair, then flush the journal at the end of
+ // the scrub. Otherwise in the case of e.g. rewriting a backtrace
+ // the on disk state will still look damaged.
+ auto expiry_fin = new FunctionContext([this, header, fin](int r){
+ if (header->get_repaired()) {
+ dout(4) << "Flushing journal because scrub did some repairs" << dendl;
+ mds->mdlog->start_new_segment();
+ mds->mdlog->trim_all();
+ if (fin) {
+ MDSGatherBuilder expiry_gather(g_ceph_context);
+ const std::set<LogSegment*> &expiring_segments = mds->mdlog->get_expiring_segments();
+ for (std::set<LogSegment*>::const_iterator i = expiring_segments.begin();
+ i != expiring_segments.end(); ++i) {
+ (*i)->wait_for_expiry(expiry_gather.new_sub());
+ }
+ expiry_gather.set_finisher(new MDSInternalContextWrapper(mds, fin));
+ expiry_gather.activate();
+ }
+ } else {
+ if (fin) {
+ fin->complete(r);
+ }
+ }
+ });
+
if (!header->get_recursive()) {
- Context *fin = cs->take_finisher();
mds->scrubstack->enqueue_inode_top(in, header,
- new MDSInternalContextWrapper(mds, fin));
- } else
- mds->scrubstack->enqueue_inode_bottom(in, header, NULL);
+ new MDSInternalContextWrapper(mds,
+ expiry_fin));
+ } else {
+ mds->scrubstack->enqueue_inode_bottom(in, header,
+ new MDSInternalContextWrapper(mds,
+ expiry_fin));
+ }
mds->server->respond_to_request(mdr, 0);
return;
const std::string &get_tag() const { return tag; }
Formatter &get_formatter() const { return *formatter; }
+ bool get_repaired() const { return repaired; }
+ void set_repaired() { repaired = true; }
+
protected:
const std::string tag;
const bool force;
const bool repair;
Formatter * const formatter;
CInode *origin;
+
+ bool repaired = false; // May be set during scrub if repairs happened
};
typedef ceph::shared_ptr<ScrubHeader> ScrubHeaderRef;
}
void ScrubStack::_enqueue_inode(CInode *in, CDentry *parent,
- const ScrubHeaderRefConst& header,
+ ScrubHeaderRef& header,
MDSInternalContextBase *on_finish, bool top)
{
dout(10) << __func__ << " with {" << *in << "}"
push_inode_bottom(in);
}
-void ScrubStack::enqueue_inode(CInode *in, const ScrubHeaderRefConst& header,
+void ScrubStack::enqueue_inode(CInode *in, ScrubHeaderRef& header,
MDSInternalContextBase *on_finish, bool top)
{
_enqueue_inode(in, NULL, header, on_finish, top);
bool all_frags_terminal = true;
bool all_frags_done = true;
- const ScrubHeaderRefConst& header = in->scrub_info()->header;
+ ScrubHeaderRef header = in->get_scrub_header();
+ assert(header != nullptr);
if (header->get_recursive()) {
list<frag_t> scrubbing_frags;
}
void ScrubStack::scrub_dirfrag(CDir *dir,
- const ScrubHeaderRefConst& header,
+ ScrubHeaderRef& header,
bool *added_children, bool *is_terminal,
bool *done)
{
* @param header The ScrubHeader propagated from whereever this scrub
* was initiated
*/
- void enqueue_inode_top(CInode *in, const ScrubHeaderRefConst& header,
+ void enqueue_inode_top(CInode *in, ScrubHeaderRef& header,
MDSInternalContextBase *on_finish) {
enqueue_inode(in, header, on_finish, true);
}
/** Like enqueue_inode_top, but we wait for all pending scrubs before
* starting this one.
*/
- void enqueue_inode_bottom(CInode *in, const ScrubHeaderRefConst& header,
+ void enqueue_inode_bottom(CInode *in, ScrubHeaderRef& header,
MDSInternalContextBase *on_finish) {
enqueue_inode(in, header, on_finish, false);
}
* 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.
*/
- void enqueue_inode(CInode *in, const ScrubHeaderRefConst& header,
+ void enqueue_inode(CInode *in, ScrubHeaderRef& header,
MDSInternalContextBase *on_finish, bool top);
- void _enqueue_inode(CInode *in, CDentry *parent, const ScrubHeaderRefConst& header,
+ void _enqueue_inode(CInode *in, CDentry *parent, ScrubHeaderRef& header,
MDSInternalContextBase *on_finish, bool top);
/**
* Kick off as many scrubs as are appropriate, based on the current
* progress. Try again later.
*
*/
- void scrub_dirfrag(CDir *dir, const ScrubHeaderRefConst& header,
+ void scrub_dirfrag(CDir *dir, ScrubHeaderRef& header,
bool *added_children, bool *is_terminal, bool *done);
/**
* Scrub a directory-representing dentry.