assert(get_num_any() == items.size());
}
+// remove dirty null dentries for deleted directory. the dirfrag will be
+// deleted soon, so it's safe to not commit dirty dentries.
+void CDir::try_remove_dentries_for_stray()
+{
+ dout(10) << __func__ << dendl;
+ assert(inode->inode.nlink == 0);
+
+ CDir::map_t::iterator p = items.begin();
+ while (p != items.end()) {
+ CDentry *dn = p->second;
+ ++p;
+ if (!dn->get_linkage()->is_null() || dn->is_projected())
+ continue; // shouldn't happen
+ if (dn->is_dirty())
+ dn->mark_clean();
+ if (dn->get_num_ref() == 0)
+ remove_dentry(dn);
+ }
+
+ if (is_dirty())
+ mark_clean();
+}
+
void CDir::touch_dentries_bottom() {
dout(12) << "touch_dentries_bottom " << *this << dendl;
{
dout(10) << "mark_clean " << *this << " version " << get_version() << dendl;
if (state_test(STATE_DIRTY)) {
- state_clear(STATE_DIRTY);
- put(PIN_DIRTY);
-
item_dirty.remove_myself();
item_new.remove_myself();
+
+ state_clear(STATE_DIRTY);
+ put(PIN_DIRTY);
}
}
return;
}
+ // unlinked directory inode shouldn't have any entry
+ if (inode->inode.nlink == 0) {
+ dout(7) << "fetch dirfrag for unlinked directory, mark complete" << dendl;
+ mark_complete();
+ if (c)
+ cache->mds->queue_waiter(c);
+ return;
+ }
+
if (c) add_waiter(WAIT_COMPLETE, c);
// already fetching?
assert(is_auth());
assert(ignore_authpinnability || can_auth_pin());
+ if (inode->inode.nlink == 0) {
+ dout(7) << "commit dirfrag for unlinked directory, mark clean" << dendl;
+ try_remove_dentries_for_stray();
+ if (c)
+ cache->mds->queue_waiter(c);
+ return;
+ }
+
// note: queue up a noop if necessary, so that we always
// get an auth_pin.
if (!c)
void purge_stale_snap_data(const std::set<snapid_t>& snaps);
public:
void touch_dentries_bottom();
+ void try_remove_dentries_for_stray();
bool try_trim_snap_dentry(CDentry *dn, const std::set<snapid_t>& snaps);
dout(20) << " caps | leases" << dendl;
return; // wait
}
- if (!in->dirfrags.empty()) {
- dout(20) << " open dirfrags" << dendl;
- return; // wait for dirs to close/trim
- }
if (dn->state_test(CDentry::STATE_PURGING)) {
dout(20) << " already purging" << dendl;
return; // already purging
if (delay) {
if (!dn->item_stray.is_on_list())
delayed_eval_stray.push_back(&dn->item_stray);
- } else
+ } else {
+ if (in->is_dir())
+ in->close_dirfrags();
purge_stray(dn);
+ }
}
else if (in->inode.nlink >= 1) {
// trivial reintegrate?
}
}
+void MDCache::try_remove_dentries_for_stray(CInode* diri) {
+ assert(diri->inode.nlink == 0);
+ if (diri->has_dirfrags()) {
+ list<CDir*> ls;
+ diri->get_nested_dirfrags(ls);
+ for (list<CDir*>::iterator p = ls.begin(); p != ls.end(); ++p)
+ (*p)->try_remove_dentries_for_stray();
+ }
+}
+
void MDCache::eval_remote(CDentry *dn)
{
dout(10) << "eval_remote " << *dn << dendl;
dn->get_dir()->get_inode()->is_stray())
eval_stray(dn, delay);
}
+ void try_remove_dentries_for_stray(CInode* diri);
void fetch_backtrace(inodeno_t ino, int64_t pool, bufferlist& bl, Context *fin);
dn->pop_projected_linkage();
// relink as stray? (i.e. was primary link?)
- CDentry::linkage_t *straydnl = 0;
-
+ CInode *strayin = NULL;
bool snap_is_new = false;
if (straydn) {
dout(20) << " straydn is " << *straydn << dendl;
- straydnl = straydn->pop_projected_linkage();
-
- snap_is_new = straydnl->get_inode()->snaprealm ? true : false;
+ CDentry::linkage_t *straydnl = straydn->pop_projected_linkage();
+ strayin = straydnl->get_inode();
+
+ snap_is_new = strayin->snaprealm ? true : false;
mdcache->touch_dentry_bottom(straydn);
}
dn->mark_dirty(dnpv, mdr->ls);
mdr->apply();
- if (snap_is_new) //only new if straydnl exists
- mdcache->do_realm_invalidate_and_update_notify(straydnl->get_inode(), CEPH_SNAP_OP_SPLIT, true);
+ if (snap_is_new) //only new if strayin exists
+ mdcache->do_realm_invalidate_and_update_notify(strayin, CEPH_SNAP_OP_SPLIT, true);
mds->mdcache->send_dentry_unlink(dn, straydn, mdr);
// update subtree map?
- if (straydn && straydnl->get_inode()->is_dir())
- mdcache->adjust_subtree_after_rename(straydnl->get_inode(), dn->get_dir(), true);
+ if (straydn && strayin->is_dir())
+ mdcache->adjust_subtree_after_rename(strayin, dn->get_dir(), true);
// bump pop
mds->balancer->hit_dir(mdr->get_mds_stamp(), dn->get_dir(), META_POP_IWR);
// reply
respond_to_request(mdr, 0);
- // clean up?
- if (straydn)
- mdcache->eval_stray(straydn);
-
// removing a new dn?
dn->get_dir()->try_remove_unlinked_dn(dn);
+
+ // clean up?
+ if (straydn) {
+ if (strayin->is_dir())
+ mdcache->try_remove_dentries_for_stray(strayin);
+ mdcache->eval_stray(straydn);
+ }
}
bool Server::_rmdir_prepare_witness(MDRequestRef& mdr, mds_rank_t who, CDentry *dn, CDentry *straydn)