return true;
// wait!
- dout(7) << "rdlock_try waiting on " << *lock << " on " << *lock->get_parent() << dendl;
- if (con)
+ if (con) {
+ dout(7) << "rdlock_try waiting on " << *lock << " on " << *lock->get_parent() << dendl;
lock->add_waiter(SimpleLock::WAIT_STABLE|SimpleLock::WAIT_RD, con);
+ }
return false;
}
}
+bool Locker::can_rdlock_set(set<SimpleLock*>& locks)
+{
+ dout(10) << "can_rdlock_set " << locks << dendl;
+ for (set<SimpleLock*>::iterator p = locks.begin(); p != locks.end(); ++p)
+ if (!(*p)->can_rdlock(-1)) {
+ dout(10) << "can_rdlock_set can't rdlock " << *p << " on " << *(*p)->get_parent() << dendl;
+ return false;
+ }
+ return true;
+}
+
+bool Locker::rdlock_try_set(set<SimpleLock*>& locks)
+{
+ dout(10) << "rdlock_try_set " << locks << dendl;
+ for (set<SimpleLock*>::iterator p = locks.begin(); p != locks.end(); ++p)
+ if (!rdlock_try(*p, -1, NULL)) {
+ dout(10) << "rdlock_try_set can't rdlock " << *p << " on " << *(*p)->get_parent() << dendl;
+ return false;
+ }
+ return true;
+}
+
+void Locker::rdlock_take_set(set<SimpleLock*>& locks)
+{
+ dout(10) << "rdlock_take_set " << locks << dendl;
+ for (set<SimpleLock*>::iterator p = locks.begin(); p != locks.end(); ++p)
+ (*p)->get_rdlock();
+}
+
+void Locker::rdlock_finish_set(set<SimpleLock*>& locks)
+{
+ dout(10) << "rdlock_finish_set " << locks << dendl;
+ for (set<SimpleLock*>::iterator p = locks.begin(); p != locks.end(); ++p)
+ rdlock_finish(*p, 0);
+}
+
// ------------------
// wrlock
-// dentry specific helpers
-
-/** dentry_can_rdlock_trace
- * see if we can _anonymously_ rdlock an entire trace.
- * if not, and req is specified, wait and retry that message.
- */
-bool Locker::dentry_can_rdlock_trace(vector<CDentry*>& trace)
-{
- // verify dentries are rdlockable.
- // we do this because
- // - we're being less aggressive about locks acquisition, and
- // - we're not acquiring the locks in order!
- for (vector<CDentry*>::iterator it = trace.begin();
- it != trace.end();
- it++) {
- CDentry *dn = *it;
- if (!dn->lock.can_rdlock(-1)) {
- dout(10) << "can_rdlock_trace can't rdlock " << *dn << dendl;
- return false;
- }
- }
- return true;
-}
-
-void Locker::dentry_anon_rdlock_trace_start(vector<CDentry*>& trace)
-{
- // grab dentry rdlocks
- for (vector<CDentry*>::iterator it = trace.begin();
- it != trace.end();
- it++) {
- dout(10) << "dentry_anon_rdlock_trace_start rdlocking " << (*it)->lock << " " << **it << dendl;
- (*it)->lock.get_rdlock();
- }
-}
-
-
-void Locker::dentry_anon_rdlock_trace_finish(vector<CDentry*>& trace)
-{
- for (vector<CDentry*>::iterator it = trace.begin();
- it != trace.end();
- it++)
- rdlock_finish(&(*it)->lock, 0);
-}
-
-
// ==========================================================================
// scatter lock
bool rdlock_try(SimpleLock *lock, client_t client, Context *c);
bool rdlock_start(SimpleLock *lock, MDRequest *mut, bool as_anon=false);
void rdlock_finish(SimpleLock *lock, Mutation *mut);
+ bool can_rdlock_set(set<SimpleLock*>& locks);
+ bool rdlock_try_set(set<SimpleLock*>& locks);
+ void rdlock_take_set(set<SimpleLock*>& locks);
+ void rdlock_finish_set(set<SimpleLock*>& locks);
void wrlock_force(SimpleLock *lock, Mutation *mut);
bool wrlock_start(SimpleLock *lock, MDRequest *mut, bool nowait=false);
void simple_excl(SimpleLock *lock, bool *need_issue=0);
void simple_xlock(SimpleLock *lock);
-public:
- bool dentry_can_rdlock_trace(vector<CDentry*>& trace);
- void dentry_anon_rdlock_trace_start(vector<CDentry*>& trace);
- void dentry_anon_rdlock_trace_finish(vector<CDentry*>& trace);
// scatter
public:
};
+void Migrator::get_export_lock_set(CDir *dir, set<SimpleLock*>& locks)
+{
+ // path
+ vector<CDentry*> trace;
+ cache->make_trace(trace, dir->inode);
+ for (vector<CDentry*>::iterator it = trace.begin();
+ it != trace.end();
+ it++)
+ locks.insert(&(*it)->lock);
+
+ // bound dftlocks:
+ // NOTE: We need to take an rdlock on bounding dirfrags during
+ // migration for a rather irritating reason: when we export the
+ // bound inode, we need to send scatterlock state for the dirfrags
+ // as well, so that the new auth also gets the correct info. If we
+ // race with a refragment, this info is useless, as we can't
+ // redivvy it up. And it's needed for the scatterlocks to work
+ // properly: when the auth is in a sync/lock state it keeps each
+ // dirfrag's portion in the local (auth OR replica) dirfrag.
+ set<CDir*> wouldbe_bounds;
+ cache->get_wouldbe_subtree_bounds(dir, wouldbe_bounds);
+ for (set<CDir*>::iterator p = wouldbe_bounds.begin(); p != wouldbe_bounds.end(); ++p)
+ locks.insert(&(*p)->get_inode()->dirfragtreelock);
+}
+
+
/** export_dir(dir, dest)
* public method to initiate an export.
* will fail if the directory is freezing, frozen, unpinnable, or root.
return;
}
- // pin path?
- vector<CDentry*> trace;
- cache->make_trace(trace, dir->inode);
- if (!mds->locker->dentry_can_rdlock_trace(trace)) {
- dout(7) << "export_dir couldn't pin path, failing." << dendl;
+ // locks?
+ set<SimpleLock*> locks;
+ get_export_lock_set(dir, locks);
+ if (!mds->locker->rdlock_try_set(locks)) {
+ dout(7) << "export_dir can't rdlock needed locks, failing." << dendl;
return;
}
assert(dir->get_cum_auth_pins() == 0);
int dest = export_peer[dir];
-
- // ok, try to grab all my locks.
-
- // pin path?
- vector<CDentry*> trace;
- cache->make_trace(trace, dir->inode);
-
CInode *diri = dir->inode;
- if (!mds->locker->dentry_can_rdlock_trace(trace)) {
- dout(7) << "export_dir couldn't rdlock path or rd|wrlock parent inode file+nest+dftlock, failing. "
+
+ // ok, try to grab all my locks.
+ set<SimpleLock*> locks;
+ get_export_lock_set(dir, locks);
+ if (!mds->locker->can_rdlock_set(locks)) {
+ dout(7) << "export_dir couldn't rdlock all needed locks, failing. "
<< *diri << dendl;
// .. unwind ..
mds->send_message_mds(new MExportDirCancel(dir->dirfrag()), dest);
return;
}
-
- dout(10) << " taking locks on path, parent inode scatterlocks" << dendl;
- // rdlock path
- mds->locker->dentry_anon_rdlock_trace_start(trace);
+ mds->locker->rdlock_take_set(locks);
cache->show_subtrees();
{
dout(10) << "export_unlock " << *dir << dendl;
- // unpin the path
- vector<CDentry*> trace;
- cache->make_trace(trace, dir->inode);
- mds->locker->dentry_anon_rdlock_trace_finish(trace);
+ set<SimpleLock*> locks;
+ get_export_lock_set(dir, locks);
+ mds->locker->rdlock_finish_set(locks);
list<Context*> ls;
mds->queue_waiters(ls);
export_queue.clear();
}
+ void get_export_lock_set(CDir *dir, set<SimpleLock*>& locks);
+
void encode_export_inode(CInode *in, bufferlist& bl,
map<client_t,entity_inst_t>& exported_client_map);
void encode_export_inode_caps(CInode *in, bufferlist& bl,