out << " need_snapflush=" << in.client_need_snapflush;
+ if (in.scatter_pins > 0)
+ out << " scatter_pins=" << in.scatter_pins;
+
// locks
if (!in.authlock.is_sync_and_unlocked())
out << " " << in.authlock;
}
}
+void CInode::put_scatter_pin(list<Context*>& ls)
+{
+ assert(scatter_pins > 0);
+ scatter_pins--;
+ if (scatter_pins == 0) {
+ dirfragtreelock.take_waiting(SimpleLock::WAIT_ALL, ls);
+ filelock.take_waiting(SimpleLock::WAIT_ALL, ls);
+ nestlock.take_waiting(SimpleLock::WAIT_ALL, ls);
+ ls.push_back(new Locker::C_EvalScatterGathers(mdcache->mds->locker, this));
+ }
+}
+
+
+
// waiting
bool CInode::is_frozen()
snaplock(this, &snaplock_type),
nestlock(this, &nestlock_type),
flocklock(this, &flocklock_type),
+ scatter_pins(0),
loner_cap(-1), want_loner_cap(-1)
{
g_num_ino++;
ScatterLock nestlock;
SimpleLock flocklock;
+ int scatter_pins;
+
SimpleLock* get_lock(int type) {
switch (type) {
case CEPH_LOCK_IFILE: return &filelock;
void finish_scatter_gather_update(int type);
void finish_scatter_gather_update_accounted(int type, Mutation *mut, EMetaBlob *metablob);
+ // scatter pins prevent either a scatter or unscatter on _any_
+ // scatterlock for this inode.
+ bool is_scatter_pinned() {
+ return scatter_pins > 0;
+ }
+ bool can_scatter_pin() {
+ return
+ dirfragtreelock.can_scatter_pin(get_loner()) &&
+ filelock.can_scatter_pin(get_loner()) &&
+ nestlock.can_scatter_pin(get_loner());
+ }
+ void get_scatter_pin() {
+ scatter_pins++;
+ }
+ void put_scatter_pin(list<Context*>& ls);
// -- snap --
void open_snaprealm(bool no_split=false);
(IS_TRUE_AND_LT_AUTH(lock->get_sm()->states[next].can_wrlock, auth) || !lock->is_wrlocked()) &&
(IS_TRUE_AND_LT_AUTH(lock->get_sm()->states[next].can_xlock, auth) || !lock->is_xlocked()) &&
(IS_TRUE_AND_LT_AUTH(lock->get_sm()->states[next].can_lease, auth) || !lock->is_leased()) &&
+ (!in || !in->is_scatter_pinned() || !lock->is_scatterlock()) &&
(!caps || ((~lock->gcaps_allowed(CAP_ANY, next) & other_issued) == 0 &&
(~lock->gcaps_allowed(CAP_LONER, next) & loner_issued) == 0 &&
(~lock->gcaps_allowed(CAP_XLOCKER, next) & xlocker_issued) == 0)) &&
finish_contexts(finishers);
}
+void Locker::eval_scatter_gathers(CInode *in)
+{
+ bool need_issue = false;
+ list<Context*> finishers;
+
+ dout(10) << "eval_scatter_gathers " << *in << dendl;
+
+ // kick locks now
+ if (!in->filelock.is_stable())
+ eval_gather(&in->filelock, false, &need_issue, &finishers);
+ if (!in->nestlock.is_stable())
+ eval_gather(&in->nestlock, false, &need_issue, &finishers);
+ if (!in->dirfragtreelock.is_stable())
+ eval_gather(&in->dirfragtreelock, false, &need_issue, &finishers);
+
+ if (need_issue && in->is_head())
+ issue_caps(in);
+
+ finish_contexts(finishers);
+}
+
void Locker::eval(SimpleLock *lock, bool *need_issue)
{
switch (lock->get_type()) {
CInode *in = (CInode*)lock->get_parent();
dout(10) << "scatter_writebehind " << in->inode.mtime << " on " << *lock << " on " << *in << dendl;
+ assert(!in->is_scatter_pinned());
+
// journal
Mutation *mut = new Mutation;
mut->ls = mds->mdlog->get_current_segment();
{
CInode *p = (CInode *)lock->get_parent();
+ if (p->is_scatter_pinned()) {
+ dout(10) << "scatter_nudge waiting for scatter pin release on " << *p << dendl;
+ if (c)
+ p->filelock.add_waiter(SimpleLock::WAIT_RD, c);
+ else
+ // just requeue. not ideal.. starvation prone..
+ updated_scatterlocks.push_back(lock->get_updated_item());
+ return;
+ }
if (p->is_frozen() || p->is_freezing()) {
dout(10) << "scatter_nudge waiting for unfreeze on " << *p << dendl;
if (c)
eval(lock, need_issue);
}
+ class C_EvalScatterGathers : public Context {
+ Locker *locker;
+ CInode *in;
+ public:
+ C_EvalScatterGathers(Locker *l, CInode *i) : locker(l), in(i) {
+ in->get(CInode::PIN_PTRWAITER);
+ }
+ void finish(int r) {
+ in->put(CInode::PIN_PTRWAITER);
+ locker->eval_scatter_gathers(in);
+ }
+ };
+ void eval_scatter_gathers(CInode *in);
+
void eval_cap_gather(CInode *in);
bool eval(CInode *in, int mask);
}
}
+ bool is_scatterlock() const {
+ return true;
+ }
+
bool is_sync_and_unlocked() const {
return
SimpleLock::is_sync_and_unlocked() &&
!is_flushing();
}
+ bool can_scatter_pin(client_t loner) {
+ return can_rdlock(-1) || can_wrlock(loner);
+ }
xlist<ScatterLock*>::item *get_updated_item() { return &more()->item_updated; }
utime_t get_update_stamp() { return more()->update_stamp; }
delete _unstable;
}
+ virtual bool is_scatterlock() const {
+ return false;
+ }
+
// parent
MDSCacheObject *get_parent() { return parent; }
int get_type() { return type->type; }