symlink_recovery = g_conf().get_val<bool>("mds_symlink_recovery");
+ kill_shutdown_at = g_conf().get_val<uint64_t>("mds_kill_shutdown_at");
+
lru.lru_set_midpoint(g_conf().get_val<double>("mds_cache_mid"));
bottom_lru.lru_set_midpoint(0);
symlink_recovery = g_conf().get_val<bool>("mds_symlink_recovery");
dout(10) << "Storing symlink targets on file object's head " << symlink_recovery << dendl;
}
+ if (changed.count("mds_kill_shutdown_at")) {
+ kill_shutdown_at = g_conf().get_val<uint64_t>("mds_kill_shutdown_at");
+ }
migrator->handle_conf_change(changed, mdsmap);
mds->balancer->handle_conf_change(changed, mdsmap);
bool MDCache::shutdown_pass()
{
dout(7) << "shutdown_pass" << dendl;
+ ceph_assert(kill_shutdown_at != KILL_SHUTDOWN_AT::SHUTDOWN_START);
if (mds->is_stopped()) {
dout(7) << " already shut down" << dendl;
// trim cache
trim(UINT64_MAX);
dout(5) << "lru size now " << lru.lru_get_size() << "/" << bottom_lru.lru_get_size() << dendl;
+ ceph_assert(kill_shutdown_at != KILL_SHUTDOWN_AT::SHUTDOWN_POSTTRIM);
// Export all subtrees to another active (usually rank 0) if not rank 0
int num_auth_subtree = 0;
dest = 0;
dout(7) << "sending " << *dir << " back to mds." << dest << dendl;
migrator->export_dir_nicely(dir, dest);
+ ceph_assert(kill_shutdown_at != KILL_SHUTDOWN_AT::SHUTDOWN_POSTONEEXPORT);
}
}
+ ceph_assert(kill_shutdown_at != KILL_SHUTDOWN_AT::SHUTDOWN_POSTALLEXPORTS);
+
if (!strays_all_exported) {
dout(7) << "waiting for strays to migrate" << dendl;
return false;
mds->server->terminate_sessions();
return false;
}
+ ceph_assert(kill_shutdown_at != KILL_SHUTDOWN_AT::SHUTDOWN_SESSIONTERMINATE);
// Fully trim the log so that all objects in cache are clean and may be
// trimmed by a future MDCache::trim. Note that MDSRank::tick does not
auto sle = create_subtree_map();
mds->mdlog->submit_entry(sle);
mds->mdlog->flush();
+ ceph_assert(kill_shutdown_at != KILL_SHUTDOWN_AT::SHUTDOWN_SUBTREEMAP);
}
}
mds->mdlog->trim_all();
dout(7) << "still >1 segments, waiting for log to trim" << dendl;
return false;
}
+ ceph_assert(kill_shutdown_at != KILL_SHUTDOWN_AT::SHUTDOWN_TRIMALL);
// drop our reference to our stray dir inode
for (int i = 0; i < NUM_STRAY; ++i) {
strays[i]->put_stickydirs();
}
}
+ ceph_assert(kill_shutdown_at != KILL_SHUTDOWN_AT::SHUTDOWN_STRAYPUT);
CDir *mydir = myin ? myin->get_dirfrag(frag_t()) : NULL;
if (mydir && !mydir->is_subtree_root())
dout(7) << "capping the mdlog" << dendl;
mds->mdlog->cap();
}
+ ceph_assert(kill_shutdown_at != KILL_SHUTDOWN_AT::SHUTDOWN_LOGCAP);
if (!mds->mdlog->empty())
mds->mdlog->trim(0);
myin->close_dirfrag(mydir->get_frag());
}
ceph_assert(subtrees.empty());
+ ceph_assert(kill_shutdown_at != KILL_SHUTDOWN_AT::SHUTDOWN_EMPTYSUBTREES);
if (myin) {
remove_inode(myin);
ceph_assert(!myin);
}
+ ceph_assert(kill_shutdown_at != KILL_SHUTDOWN_AT::SHUTDOWN_MYINREMOVAL);
if (global_snaprealm) {
remove_inode(global_snaprealm->inode);
global_snaprealm = nullptr;
}
+ ceph_assert(kill_shutdown_at != KILL_SHUTDOWN_AT::SHUTDOWN_GLOBALSNAPREALMREMOVAL);
// done!
dout(5) << "shutdown done." << dendl;
int num_remote_waiters = 0; // number of remote authpin waiters
};
+ enum KILL_SHUTDOWN_AT {
+ SHUTDOWN_NULL,
+ SHUTDOWN_START,
+ SHUTDOWN_POSTTRIM,
+ SHUTDOWN_POSTONEEXPORT,
+ SHUTDOWN_POSTALLEXPORTS,
+ SHUTDOWN_SESSIONTERMINATE,
+ SHUTDOWN_SUBTREEMAP,
+ SHUTDOWN_TRIMALL,
+ SHUTDOWN_STRAYPUT,
+ SHUTDOWN_LOGCAP,
+ SHUTDOWN_EMPTYSUBTREES,
+ SHUTDOWN_MYINREMOVAL,
+ SHUTDOWN_GLOBALSNAPREALMREMOVAL,
+ SHUTDOWN_UNUSED
+ };
+
typedef std::map<dirfrag_t,fragment_info_t>::iterator fragment_info_iterator;
friend class EFragment;
time upkeep_last_trim = time::min();
time upkeep_last_release = time::min();
std::atomic<bool> upkeep_trim_shutdown{false};
+
+ uint64_t kill_shutdown_at = 0;
};
class C_MDS_RetryRequest : public MDSInternalContext {