assert(!in->state_test(CInode::STATE_RECOVERING));
+ bool new_dn = dn->is_new();
+
// unlink
assert(dn->get_projected_linkage()->is_null());
- dn->dir->unlink_inode(dn);
+ dn->dir->unlink_inode(dn, !new_dn);
dn->pop_projected_linkage();
dn->mark_dirty(pdv, ls);
dn->put(CDentry::PIN_PURGING);
// drop dentry?
- if (dn->is_new()) {
+ if (new_dn) {
dout(20) << " dn is new, removing" << dendl;
dn->mark_clean();
dn->dir->remove_dentry(dn);
- } else {
- in->mdcache->touch_dentry_bottom(dn); // drop dn as quickly as possible.
}
// drop inode
assert(!dn->state_test(CDentry::STATE_PURGING));
if (!dn->is_auth()) {
- // has to be mine
- // move to bottom of lru so that we trim quickly!
-
- in->mdcache->touch_dentry_bottom(dn);
return false;
}
return false; // not until some snaps are deleted.
}
- if (in->has_dirfrags()) {
- list<CDir*> ls;
- in->get_nested_dirfrags(ls);
- for (list<CDir*>::iterator p = ls.begin(); p != ls.end(); ++p) {
- (*p)->try_remove_dentries_for_stray();
- }
- }
+ in->mdcache->clear_dirty_bits_for_stray(in);
if (!in->remote_parents.empty()) {
// unlink any stale remote snap dentry.
* if we can do anything with them if we happen to have them in
* cache.
*/
- eval_remote_stray(dn, NULL);
+ _eval_stray_remote(dn, NULL);
return false;
}
}
return ret;
}
-void StrayManager::eval_remote_stray(CDentry *stray_dn, CDentry *remote_dn)
+void StrayManager::eval_remote(CDentry *remote_dn)
{
+ dout(10) << __func__ << " " << *remote_dn << dendl;
+
+ CDentry::linkage_t *dnl = remote_dn->get_projected_linkage();
+ assert(dnl->is_remote());
+ CInode *in = dnl->get_inode();
+
+ if (!in) {
+ dout(20) << __func__ << ": no inode, cannot evaluate" << dendl;
+ return;
+ }
+
+ if (remote_dn->last != CEPH_NOSNAP) {
+ dout(20) << __func__ << ": snap dentry, cannot evaluate" << dendl;
+ return;
+ }
+
+ // refers to stray?
+ CDentry *primary_dn = in->get_projected_parent_dn();
+ assert(primary_dn != NULL);
+ if (primary_dn->get_dir()->get_inode()->is_stray()) {
+ _eval_stray_remote(primary_dn, remote_dn);
+ } else {
+ dout(20) << __func__ << ": inode's primary dn not stray" << dendl;
+ }
+}
+
+class C_RetryEvalRemote : public StrayManagerContext {
+ CDentry *dn;
+ public:
+ C_RetryEvalRemote(StrayManager *sm_, CDentry *dn_) :
+ StrayManagerContext(sm_), dn(dn_) {
+ dn->get(CDentry::PIN_PTRWAITER);
+ }
+ void finish(int r) override {
+ if (dn->get_projected_linkage()->is_remote())
+ sm->eval_remote(dn);
+ dn->put(CDentry::PIN_PTRWAITER);
+ }
+};
+
+void StrayManager::_eval_stray_remote(CDentry *stray_dn, CDentry *remote_dn)
+{
+ dout(20) << __func__ << " " << *stray_dn << dendl;
assert(stray_dn != NULL);
assert(stray_dn->get_dir()->get_inode()->is_stray());
CDentry::linkage_t *stray_dnl = stray_dn->get_projected_linkage();
for (compact_set<CDentry*>::iterator p = stray_in->remote_parents.begin();
p != stray_in->remote_parents.end();
++p)
- if ((*p)->last == CEPH_NOSNAP) {
- remote_dn = *p;
- break;
+ if ((*p)->last == CEPH_NOSNAP && !(*p)->is_projected()) {
+ if ((*p)->is_auth()) {
+ remote_dn = *p;
+ if (remote_dn->dir->can_auth_pin())
+ break;
+ } else if (!remote_dn) {
+ remote_dn = *p;
+ }
}
}
if (!remote_dn) {
assert(remote_dn->last == CEPH_NOSNAP);
// NOTE: we repeat this check in _rename(), since our submission path is racey.
if (!remote_dn->is_projected()) {
- if (remote_dn->is_auth() && remote_dn->dir->can_auth_pin()) {
- reintegrate_stray(stray_dn, remote_dn);
+ if (remote_dn->is_auth()) {
+ if (remote_dn->dir->can_auth_pin()) {
+ reintegrate_stray(stray_dn, remote_dn);
+ } else {
+ remote_dn->dir->add_waiter(CDir::WAIT_UNFREEZE, new C_RetryEvalRemote(this, remote_dn));
+ dout(20) << __func__ << ": not reintegrating (can't authpin remote parent)" << dendl;
+ }
+
} else if (!remote_dn->is_auth() && stray_dn->is_auth()) {
migrate_stray(stray_dn, remote_dn->authority().first);
} else {