dirty_dentries(member_offset(CDentry, item_dir_dirty)),
item_dirty(this), item_new(this),
lock_caches_with_auth_pins(member_offset(MDLockCache::DirItem, item_dir)),
+ freezing_inodes(member_offset(CInode, item_freezing_inode)),
dir_rep(REP_NONE),
pop_me(mdcache->decayrate),
pop_nested(mdcache->decayrate),
if (in->auth_pins)
dn->adjust_nested_auth_pins(in->auth_pins, NULL);
+ if (in->is_freezing_inode())
+ freezing_inodes.push_back(&in->item_freezing_inode);
+ else if (in->is_frozen_inode() || in->is_frozen_auth_pin())
+ num_frozen_inodes++;
+
// verify open snaprealm parent
if (in->snaprealm)
in->snaprealm->adjust_parent();
if (in->auth_pins)
dn->adjust_nested_auth_pins(-in->auth_pins, nullptr);
+ if (in->is_freezing_inode())
+ in->item_freezing_inode.remove_myself();
+ else if (in->is_frozen_inode() || in->is_frozen_auth_pin())
+ num_frozen_inodes--;
+
// detach inode
in->remove_primary_parent(dn);
if (in->is_dir())
}
}
+void CDir::enable_frozen_inode()
+{
+ ceph_assert(frozen_inode_suppressed > 0);
+ if (--frozen_inode_suppressed == 0) {
+ for (auto p = freezing_inodes.begin(); !p.end(); ) {
+ CInode *in = *p;
+ ++p;
+ ceph_assert(in->is_freezing_inode());
+ in->maybe_finish_freeze_inode();
+ }
+ }
+}
+
/**
* Slightly less complete than operator<<, because this is intended
* for identifying a directory and its state rather than for dumping
return true;
}
+ bool is_any_freezing_or_frozen_inode() const {
+ return num_frozen_inodes || !freezing_inodes.empty();
+ }
+ void disable_frozen_inode() {
+ ceph_assert(num_frozen_inodes == 0);
+ frozen_inode_suppressed++;
+ }
+ void enable_frozen_inode();
+
ostream& print_db_line_prefix(ostream& out) override;
void print(ostream& out) override;
void dump(Formatter *f, int flags = DUMP_DEFAULT) const;
static int num_frozen_trees;
static int num_freezing_trees;
+ // freezing/frozen inodes in this dirfrag
+ int num_frozen_inodes = 0;
+ int frozen_inode_suppressed = 0;
+ elist<CInode*> freezing_inodes;
+
int dir_auth_pins = 0;
// cache control (defined for authority; hints for replicas)
SimpleLock* CInode::get_lock(int type)
{
switch (type) {
+ case CEPH_LOCK_IVERSION: return &versionlock;
case CEPH_LOCK_IFILE: return &filelock;
case CEPH_LOCK_IAUTH: return &authlock;
case CEPH_LOCK_ILINK: return &linklock;
MDSCacheObject::take_waiting(mask, ls);
}
+void CInode::maybe_finish_freeze_inode()
+{
+ CDir *dir = get_parent_dir();
+ if (auth_pins > auth_pin_freeze_allowance || dir->frozen_inode_suppressed)
+ return;
+
+ dout(10) << "maybe_finish_freeze_inode - frozen" << dendl;
+ ceph_assert(auth_pins == auth_pin_freeze_allowance);
+ get(PIN_FROZEN);
+ put(PIN_FREEZING);
+ state_clear(STATE_FREEZING);
+ state_set(STATE_FROZEN);
+
+ item_freezing_inode.remove_myself();
+ dir->num_frozen_inodes++;
+
+ finish_waiting(WAIT_FROZEN);
+}
+
bool CInode::freeze_inode(int auth_pin_allowance)
{
+ CDir *dir = get_parent_dir();
+ ceph_assert(dir);
+
ceph_assert(auth_pin_allowance > 0); // otherwise we need to adjust parent's nested_auth_pins
ceph_assert(auth_pins >= auth_pin_allowance);
- if (auth_pins > auth_pin_allowance) {
- dout(10) << "freeze_inode - waiting for auth_pins to drop to " << auth_pin_allowance << dendl;
- auth_pin_freeze_allowance = auth_pin_allowance;
- get(PIN_FREEZING);
- state_set(STATE_FREEZING);
- return false;
+ if (auth_pins == auth_pin_allowance && !dir->frozen_inode_suppressed) {
+ dout(10) << "freeze_inode - frozen" << dendl;
+ if (!state_test(STATE_FROZEN)) {
+ get(PIN_FROZEN);
+ state_set(STATE_FROZEN);
+ dir->num_frozen_inodes++;
+ }
+ return true;
}
- dout(10) << "freeze_inode - frozen" << dendl;
- ceph_assert(auth_pins == auth_pin_allowance);
- if (!state_test(STATE_FROZEN)) {
- get(PIN_FROZEN);
- state_set(STATE_FROZEN);
+ dout(10) << "freeze_inode - waiting for auth_pins to drop to " << auth_pin_allowance << dendl;
+ auth_pin_freeze_allowance = auth_pin_allowance;
+ dir->freezing_inodes.push_back(&item_freezing_inode);
+
+ get(PIN_FREEZING);
+ state_set(STATE_FREEZING);
+
+ if (!dir->lock_caches_with_auth_pins.empty())
+ mdcache->mds->locker->invalidate_lock_caches(dir);
+
+ const static int lock_types[] = {
+ CEPH_LOCK_IVERSION, CEPH_LOCK_IFILE, CEPH_LOCK_IAUTH, CEPH_LOCK_ILINK, CEPH_LOCK_IDFT,
+ CEPH_LOCK_IXATTR, CEPH_LOCK_ISNAP, CEPH_LOCK_INEST, CEPH_LOCK_IFLOCK, CEPH_LOCK_IPOLICY, 0
+ };
+ for (int i = 0; lock_types[i]; ++i) {
+ auto lock = get_lock(lock_types[i]);
+ if (lock->is_cached())
+ mdcache->mds->locker->invalidate_lock_caches(lock);
}
- return true;
+ // invalidate_lock_caches() may decrease dir->frozen_inode_suppressed
+ // and finish freezing the inode
+ return state_test(STATE_FROZEN);
}
void CInode::unfreeze_inode(MDSContext::vec& finished)
if (state_test(STATE_FREEZING)) {
state_clear(STATE_FREEZING);
put(PIN_FREEZING);
+ item_freezing_inode.remove_myself();
} else if (state_test(STATE_FROZEN)) {
state_clear(STATE_FROZEN);
put(PIN_FROZEN);
+ get_parent_dir()->num_frozen_inodes--;
} else
ceph_abort();
take_waiting(WAIT_UNFREEZE, finished);
{
ceph_assert(state_test(CInode::STATE_FROZEN));
state_set(CInode::STATE_FROZENAUTHPIN);
+ get_parent_dir()->num_frozen_inodes++;
}
void CInode::unfreeze_auth_pin()
{
ceph_assert(state_test(CInode::STATE_FROZENAUTHPIN));
state_clear(CInode::STATE_FROZENAUTHPIN);
+ get_parent_dir()->num_frozen_inodes--;
if (!state_test(STATE_FREEZING|STATE_FROZEN)) {
MDSContext::vec finished;
take_waiting(WAIT_UNFREEZE, finished);
if (parent)
parent->adjust_nested_auth_pins(-1, by);
- if (is_freezing_inode() &&
- auth_pins == auth_pin_freeze_allowance) {
- dout(10) << "auth_unpin freezing!" << dendl;
- get(PIN_FROZEN);
- put(PIN_FREEZING);
- state_clear(STATE_FREEZING);
- state_set(STATE_FROZEN);
- finish_waiting(WAIT_FROZEN);
- }
+ if (is_freezing_inode())
+ maybe_finish_freeze_inode();
}
// authority
friend class MDCache;
friend class StrayManager;
friend class CDir;
- friend class CInodeExport;
+ friend ostream& operator<<(ostream&, const CInode&);
class scrub_stamp_info_t {
public:
elist<CInode*>::item& item_recover_queue = item_dirty_dirfrag_dir;
elist<CInode*>::item& item_recover_queue_front = item_dirty_dirfrag_nest;
- int auth_pin_freeze_allowance = 0;
-
inode_load_vec_t pop;
elist<CInode*>::item item_pop_lru;
// -- waiting --
mempool::mds_co::compact_map<frag_t, MDSContext::vec > waiting_on_dir;
+
+ // -- freezing inode --
+ int auth_pin_freeze_allowance = 0;
+ elist<CInode*>::item item_freezing_inode;
+ void maybe_finish_freeze_inode();
private:
friend class ValidationContinuation;
if (mdr->lock_cache) {
CDir *dir;
if (CInode *in = dynamic_cast<CInode*>(object)) {
+ ceph_assert(!in->is_frozen_inode() && !in->is_frozen_auth_pin());
dir = in->get_projected_parent_dir();
} else if (CDentry *dn = dynamic_cast<CDentry*>(object)) {
dir = dn->get_dir();
return;
ceph_assert(lock_cache->invalidating);
+
+ CInode *diri = lock_cache->get_dir_inode();
+ for (auto dir : lock_cache->auth_pinned_dirfrags) {
+ if (dir->get_inode() != diri)
+ continue;
+ dir->enable_frozen_inode();
+ }
+
mds->queue_waiter(new C_MDL_DropCache(this, lock_cache));
}
dout(10) << " can't auth_pin(!auth|freezing?) dirfrag " << *dir << ", noop" << dendl;
return;
}
+ if (dir->is_any_freezing_or_frozen_inode()) {
+ dout(10) << " there is freezing/frozen inode in " << *dir << ", noop" << dendl;
+ return;
+ }
}
for (auto& p : mdr->locks) {
auto lock_cache = new MDLockCache(cap, opcode);
- // prevent subtree migration
- for (auto dir : dfv)
+ for (auto dir : dfv) {
+ // prevent subtree migration
lock_cache->auth_pin(dir);
+ // prevent frozen inode
+ dir->disable_frozen_inode();
+ }
for (auto& p : mdr->object_states) {
if (p.first != diri && !ancestors.count(p.first))
return cap;
}
-
void Locker::issue_caps_set(set<CInode*>& inset)
{
for (set<CInode*>::iterator p = inset.begin(); p != inset.end(); ++p)