int MDCache::path_traverse(const MDRequestRef& mdr, MDSContextFactory& cf,
const filepath& path, int flags,
- vector<CDentry*> *pdnvec, CInode **pin)
+ vector<CDentry*> *pdnvec, CInode **pin, CDir **pdir)
{
bool discover = (flags & MDS_TRAVERSE_DISCOVER);
bool forward = !discover;
pdnvec->clear();
if (pin)
*pin = cur;
+ if (pdir)
+ *pdir = nullptr;
CInode *target_inode = nullptr;
MutationImpl::LockOpVec lov;
// open dir
frag_t fg = cur->pick_dirfrag(path[depth]);
CDir *curdir = cur->get_dirfrag(fg);
+ if (pdir) {
+ *pdir = curdir;
+ }
if (!curdir) {
if (cur->is_auth()) {
// parent dir frozen_dir?
}
}
ceph_assert(curdir);
+ if (pdir) {
+ *pdir = curdir;
+ }
#ifdef MDS_VERIFY_FRAGSTAT
if (curdir->is_complete())
{
dirfrag_t basedirfrag = mdr->more()->fragment_base;
map<dirfrag_t,fragment_info_t>::iterator it = fragments.find(basedirfrag);
- if (it == fragments.end() || it->second.mdr != mdr) {
- dout(7) << "fragment_frozen " << basedirfrag << " must have aborted" << dendl;
+ if (it == fragments.end() || it->second.mdr != mdr || r < 0) {
+ dout(7) << "fragment_frozen " << basedirfrag << " must have aborted; rc=" << r << dendl;
request_finish(mdr);
return;
}
dispatch_fragment_dir(mdr);
}
-void MDCache::dispatch_fragment_dir(const MDRequestRef& mdr)
+void MDCache::dispatch_fragment_dir(const MDRequestRef& mdr, bool abort_if_freezing)
{
dirfrag_t basedirfrag = mdr->more()->fragment_base;
map<dirfrag_t,fragment_info_t>::iterator it = fragments.find(basedirfrag);
if (it == fragments.end() || it->second.mdr != mdr) {
- dout(7) << "dispatch_fragment_dir " << basedirfrag << " must have aborted" << dendl;
+ dout(7) << __func__ << ": " << basedirfrag << " must have aborted" << dendl;
request_finish(mdr);
return;
}
fragment_info_t& info = it->second;
CInode *diri = info.dirs.front()->get_inode();
- dout(10) << "dispatch_fragment_dir " << basedirfrag << " bits " << info.bits
- << " on " << *diri << dendl;
+ dout(10) << __func__ << ": " << basedirfrag << " all_frozen=" << info.all_frozen << " bits: " << info.bits
+ << " on " << *diri << dendl;
if (mdr->more()->peer_error)
mdr->aborted = true;
+ if (abort_if_freezing) {
+ if (info.all_frozen) {
+ dout(20) << __func__ << ": abort_if_freezing: too late, won't abort" << dendl;
+ return;
+ }
+ dout(20) << __func__ << ": abort_if_freezing: will abort" << dendl;
+ mdr->aborted = true;
+ }
+
if (!(mdr->locking_state & MutationImpl::ALL_LOCKED)) {
- /* If quiescelock cannot be wrlocked, we cannot block with tree frozen.
+ /* We cannot afford blocking for quiesce with fragments frozen.
* Otherwise, this can create deadlock where some quiesce_inode requests
- * (on inodes in the dirfrag) are blocked on a frozen tree and the
+ * (on inodes in the dirfrag) are blocked on a frozen cdir and the
* fragment_dir request is blocked on the queiscelock for the directory
* inode's quiescelock.
*/
- if (!mdr->is_wrlocked(&diri->quiescelock) && !diri->quiescelock.can_wrlock()) {
+ if (diri->will_block_for_quiesce(mdr)) {
+ dout(10) << __func__ << ": aborting to avoid a deadlock with quiesce" << dendl;
mdr->aborted = true;
}
}
if (mdr->aborted) {
- dout(10) << " can't auth_pin or acquire quiescelock on "
+ dout(10) << __func__ << " aborted fragmenting of "
<< *diri << ", requeuing dir "
<< info.dirs.front()->dirfrag() << dendl;
if (info.bits > 0)
}
}
+void MDCache::quiesce_overdrive_fragmenting(CDir* dir, bool async) {
+ if (!dir || !dir->state_test(CDir::STATE_FRAGMENTING)) {
+ return;
+ }
+ dout(20) << __func__ << ": will check fragmenting dir " << *dir << dendl;
+
+ auto diri = dir->get_inode();
+ auto mydf = dir->dirfrag();
+ for (auto it = fragments.lower_bound({diri->ino(), {}});
+ it != fragments.end() && it->first.ino == diri->ino();
+ ++it) {
+ if (it->first.frag.contains(mydf.frag)) {
+ dout(20) << __func__ << ": dirfrag " << it->first << " contains my dirfrag " << mydf << dendl;
+ auto const& mdr = it->second.mdr;
+
+ if (async) {
+ dout(10) << __func__ << ": will schedule async abort_if_freezing for " << *mdr << dendl;
+ mds->queue_waiter(new MDSInternalContextWrapper(mds, new LambdaContext( [this, mdr] {
+ if (!mdr->dead) {
+ dispatch_fragment_dir(mdr, true);
+ }
+ })));
+ } else {
+ if (mdr->dead) {
+ dout(20) << __func__ << ": the request is already dead: " << *mdr << dendl;
+ } else {
+ dout(10) << __func__ << ": will call abort_if_freezing for " << *mdr << dendl;
+ dispatch_fragment_dir(mdr, true);
+ }
+ }
+
+ // there can't be (shouldn't be) more than one containing fragment
+ break;
+ }
+ }
+}
+
void MDCache::dispatch_quiesce_inode(const MDRequestRef& mdr)
{
if (mdr->internal_op_finish == nullptr) {
std::vector<MDRequestRef> todispatch;
for (auto& dir : in->get_dirfrags()) {
dout(25) << " iterating " << *dir << dendl;
+ // overdrive syncrhonously since we aren't yet on the waiting list
+ quiesce_overdrive_fragmenting(dir, false);
for (auto& [dnk, dn] : *dir) {
dout(25) << " evaluating (" << dnk << ", " << *dn << ")" << dendl;
auto* in = dn->get_projected_inode();
ceph_assert(mdr->internal_op_finish);
- dout(5) << __func__ << ": dispatching" << dendl;
+ dout(5) << __func__ << ": dispatching " << *mdr << dendl;
C_MDS_QuiescePath* qfinisher = static_cast<C_MDS_QuiescePath*>(mdr->internal_op_finish);
auto& qs = *qfinisher->qs;
| MDS_TRAVERSE_RDLOCK_PATH
| MDS_TRAVERSE_WANT_INODE
;
- int r = path_traverse(mdr, cf, mdr->get_filepath(), ptflags, nullptr, &diri);
- if (r > 0)
+
+ CDir* curdir = nullptr;
+ int r = path_traverse(mdr, cf, mdr->get_filepath(), ptflags, nullptr, &diri, &curdir);
+ if (r > 0) {
+ // we must abort asyncrhonously, since we may be on the unfreeze waiter list,
+ // which whill be flushed syncrhonously with the abort
+ quiesce_overdrive_fragmenting(curdir, true);
return;
- if (r < 0) {
+ } else if (r < 0) {
mds->server->respond_to_request(mdr, r);
return;
}
*/
int path_traverse(const MDRequestRef& mdr, MDSContextFactory& cf,
const filepath& path, int flags,
- std::vector<CDentry*> *pdnvec, CInode **pin=nullptr);
+ std::vector<CDentry*> *pdnvec, CInode **pin=nullptr, CDir **pdir = nullptr);
int maybe_request_forward_to_auth(const MDRequestRef& mdr, MDSContextFactory& cf,
MDSCacheObject *p);
void fragment_unmark_unfreeze_dirs(const std::vector<CDir*>& dirs);
void fragment_drop_locks(fragment_info_t &info);
void fragment_maybe_finish(const fragment_info_iterator& it);
- void dispatch_fragment_dir(const MDRequestRef& mdr);
+ void dispatch_fragment_dir(const MDRequestRef& mdr, bool abort_if_freezing=false);
void _fragment_logged(const MDRequestRef& mdr);
void _fragment_stored(const MDRequestRef& mdr);
void _fragment_committed(dirfrag_t f, const MDRequestRef& mdr);
void finish_uncommitted_fragment(dirfrag_t basedirfrag, int op);
void rollback_uncommitted_fragment(dirfrag_t basedirfrag, frag_vec_t&& old_frags);
+ void quiesce_overdrive_fragmenting(CDir* dir, bool async);
void dispatch_quiesce_path(const MDRequestRef& mdr);
void dispatch_quiesce_inode(const MDRequestRef& mdr);