dn->dir = this;
}
-void CDir::prepare_old_fragment(bool replay)
+void CDir::prepare_old_fragment(map<string_snap_t, std::list<MDSInternalContextBase*> >& dentry_waiters, bool replay)
{
// auth_pin old fragment for duration so that any auth_pinning
// during the dentry migration doesn't trigger side effects
if (!replay && is_auth())
auth_pin(this);
+
+ if (!waiting_on_dentry.empty()) {
+ for (auto p = waiting_on_dentry.begin(); p != waiting_on_dentry.end(); ++p)
+ dentry_waiters[p->first].swap(p->second);
+ waiting_on_dentry.clear();
+ put(PIN_DNWAITER);
+ }
}
void CDir::prepare_new_fragment(bool replay)
fragstatdiff.add_delta(fnode.accounted_fragstat, fnode.fragstat);
dout(10) << " rstatdiff " << rstatdiff << " fragstatdiff " << fragstatdiff << dendl;
- prepare_old_fragment(replay);
+ map<string_snap_t, std::list<MDSInternalContextBase*> > dentry_waiters;
+ prepare_old_fragment(dentry_waiters, replay);
// create subfrag dirs
int n = 0;
f->steal_dentry(dn);
}
+ for (auto& p : dentry_waiters) {
+ frag_t subfrag = inode->pick_dirfrag(p.first.name);
+ int n = (subfrag.value() & (subfrag.mask() ^ frag.mask())) >> subfrag.mask_shift();
+ CDir *f = subfrags[n];
+
+ if (f->waiting_on_dentry.empty())
+ f->get(PIN_DNWAITER);
+ f->waiting_on_dentry[p.first].swap(p.second);
+ }
+
// FIXME: handle dirty old rstat
// fix up new frag fragstats
version_t rstat_version = inode->get_projected_inode()->rstat.version;
version_t dirstat_version = inode->get_projected_inode()->dirstat.version;
+ map<string_snap_t, std::list<MDSInternalContextBase*> > dentry_waiters;
+
for (auto dir : subs) {
dout(10) << " subfrag " << dir->get_frag() << " " << *dir << dendl;
assert(!dir->is_auth() || dir->is_complete() || replay);
fragstatdiff.add_delta(dir->fnode.accounted_fragstat, dir->fnode.fragstat,
&touched_mtime, &touched_chattr);
- dir->prepare_old_fragment(replay);
+ dir->prepare_old_fragment(dentry_waiters, replay);
// steal dentries
while (!dir->items.empty())
inode->close_dirfrag(dir->get_frag());
}
+ if (!dentry_waiters.empty()) {
+ get(PIN_DNWAITER);
+ for (auto& p : dentry_waiters) {
+ waiting_on_dentry[p.first].swap(p.second);
+ }
+ }
+
if (is_auth() && !replay)
mark_complete();
private:
void prepare_new_fragment(bool replay);
- void prepare_old_fragment(bool replay);
+ void prepare_old_fragment(map<string_snap_t, std::list<MDSInternalContextBase*> >& dentry_waiters, bool replay);
void steal_dentry(CDentry *dn); // from another dir. used by merge/split.
void finish_old_fragment(list<MDSInternalContextBase*>& waiters, bool replay);
void init_fragment_pins();
if (who >= 0)
dout(7) << " dir_auth_hint is " << m->get_dir_auth_hint() << dendl;
- frag_t fg = m->get_base_dir_frag();
- CDir *dir = cur->get_dirfrag(fg);
if (m->get_wanted_base_dir()) {
+ frag_t fg = m->get_base_dir_frag();
+ CDir *dir = cur->get_dirfrag(fg);
+
if (cur->is_waiting_for_dir(fg)) {
if (cur->is_auth())
cur->take_waiting(CInode::WAIT_DIR, finished);
// try again?
if (m->get_error_dentry().length()) {
+ frag_t fg = cur->pick_dirfrag(m->get_error_dentry());
+ CDir *dir = cur->get_dirfrag(fg);
// wanted a dentry
if (dir && dir->is_waiting_for_dentry(m->get_error_dentry(), m->get_wanted_snapid())) {
if (dir->is_auth() || dir->lookup(m->get_error_dentry())) {