From: John Spray Date: Wed, 25 Oct 2017 10:30:57 +0000 (-0400) Subject: mds: flush after scrub repairs X-Git-Tag: v13.0.1~293^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=7e52729699e87dd75022433153450fd4ba71b40e;p=ceph.git mds: flush after scrub repairs Otherwise, if we restart the MDS right after the scrub, then scrub again, it will see the same inconsistency when it looks at the on-disk state. This involves adapting the use of ScrubHeader to be something writeable during scrub to record whether repair happened. Signed-off-by: John Spray --- diff --git a/src/mds/CInode.cc b/src/mds/CInode.cc index f1974c54ce842..f12600b8afc98 100644 --- a/src/mds/CInode.cc +++ b/src/mds/CInode.cc @@ -3955,7 +3955,12 @@ next: << "(" << 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 @@ -4320,7 +4325,7 @@ void CInode::scrub_maybe_delete_info() } void CInode::scrub_initialize(CDentry *scrub_parent, - const ScrubHeaderRefConst& header, + ScrubHeaderRef& header, MDSInternalContextBase *f) { dout(20) << __func__ << " with scrub_version " << get_version() << dendl; diff --git a/src/mds/CInode.h b/src/mds/CInode.h index 2ced5b22b3571..364f42a516c05 100644 --- a/src/mds/CInode.h +++ b/src/mds/CInode.h @@ -273,7 +273,7 @@ class CInode : public MDSCacheObject, public InodeStoreBase, public Counter dirfrag_stamps; - ScrubHeaderRefConst header; + ScrubHeaderRef header; scrub_info_t() : scrub_stamp_info_t(), scrub_parent(NULL), on_finish(NULL), @@ -287,6 +287,14 @@ class CInode : public MDSCacheObject, public InodeStoreBase, public Counterheader; + } + } + bool scrub_is_in_progress() const { return (scrub_infop && scrub_infop->scrub_in_progress); } @@ -299,7 +307,7 @@ class CInode : public MDSCacheObject, public InodeStoreBase, public Counterset_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 &expiring_segments = mds->mdlog->get_expiring_segments(); + for (std::set::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; diff --git a/src/mds/ScrubHeader.h b/src/mds/ScrubHeader.h index 18c68ae8f9d47..c22683d028081 100644 --- a/src/mds/ScrubHeader.h +++ b/src/mds/ScrubHeader.h @@ -43,6 +43,9 @@ public: 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; @@ -50,6 +53,8 @@ protected: const bool repair; Formatter * const formatter; CInode *origin; + + bool repaired = false; // May be set during scrub if repairs happened }; typedef ceph::shared_ptr ScrubHeaderRef; diff --git a/src/mds/ScrubStack.cc b/src/mds/ScrubStack.cc index 7626b4e61a12f..83ae53abe3336 100644 --- a/src/mds/ScrubStack.cc +++ b/src/mds/ScrubStack.cc @@ -59,7 +59,7 @@ void ScrubStack::pop_inode(CInode *in) } void ScrubStack::_enqueue_inode(CInode *in, CDentry *parent, - const ScrubHeaderRefConst& header, + ScrubHeaderRef& header, MDSInternalContextBase *on_finish, bool top) { dout(10) << __func__ << " with {" << *in << "}" @@ -72,7 +72,7 @@ void ScrubStack::_enqueue_inode(CInode *in, CDentry *parent, 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); @@ -134,7 +134,8 @@ void ScrubStack::scrub_dir_inode(CInode *in, 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 scrubbing_frags; @@ -289,7 +290,7 @@ void ScrubStack::scrub_dir_inode_final(CInode *in) } void ScrubStack::scrub_dirfrag(CDir *dir, - const ScrubHeaderRefConst& header, + ScrubHeaderRef& header, bool *added_children, bool *is_terminal, bool *done) { diff --git a/src/mds/ScrubStack.h b/src/mds/ScrubStack.h index c35b1aa9c4632..848efdc841f7e 100644 --- a/src/mds/ScrubStack.h +++ b/src/mds/ScrubStack.h @@ -73,14 +73,14 @@ public: * @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); } @@ -90,9 +90,9 @@ private: * 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 @@ -164,7 +164,7 @@ private: * 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.