@@ -1387,7 +1387,8 @@ static void domain_dump_evtchn_info(struct domain *d)
"Polling vCPUs: {%*pbl}\n"
" port [p/m/s]\n", d->domain_id, d->max_vcpus, d->poll_mask);
- spin_lock(&d->event_lock);
+ if ( !keyhandler_spin_lock(&d->event_lock, "could not get event lock") )
+ return;
for ( port = 1; port < d->max_evtchns; ++port )
{
@@ -335,6 +335,11 @@ static inline void grant_read_lock(struct grant_table *gt)
percpu_read_lock(grant_rwlock, >->lock);
}
+static inline int grant_read_trylock(struct grant_table *gt)
+{
+ return percpu_read_trylock(grant_rwlock, >->lock);
+}
+
static inline void grant_read_unlock(struct grant_table *gt)
{
percpu_read_unlock(grant_rwlock, >->lock);
@@ -4040,6 +4045,24 @@ int gnttab_get_status_frame(struct domain *d, unsigned long idx,
return rc;
}
+static int keyhandler_grant_read_lock(struct domain *d)
+{
+ keyhandler_lock_body(int, grant_read_trylock(d->grant_table),
+ "could not get grant lock for %pd\n", d);
+}
+
+static inline struct active_grant_entry *
+keyhandler_active_entry_acquire(struct grant_table *t, grant_ref_t e)
+{
+ struct active_grant_entry *act;
+
+ act = &_active_entry(t, e);
+ if ( !keyhandler_spin_lock(&act->lock, "could not acquire active entry") )
+ return NULL;
+
+ return act;
+}
+
static void gnttab_usage_print(struct domain *rd)
{
int first = 1;
@@ -4047,11 +4070,12 @@ static void gnttab_usage_print(struct domain *rd)
struct grant_table *gt = rd->grant_table;
unsigned int nr_ents;
+ if ( !keyhandler_grant_read_lock(rd) )
+ return;
+
printk(" -------- active -------- -------- shared --------\n");
printk("[ref] localdom mfn pin localdom gmfn flags\n");
- grant_read_lock(gt);
-
printk("grant-table for remote d%d (v%u)\n"
" %u frames (%u max), %u maptrack frames (%u max)\n",
rd->domain_id, gt->gt_version,
@@ -4066,7 +4090,9 @@ static void gnttab_usage_print(struct domain *rd)
uint16_t status;
uint64_t frame;
- act = active_entry_acquire(gt, ref);
+ act = keyhandler_active_entry_acquire(gt, ref);
+ if ( !act )
+ continue;
if ( !act->pin )
{
active_entry_release(act);
@@ -2072,11 +2072,8 @@ static void livepatch_printall(unsigned char key)
if ( !xen_build_id(&binary_id, &len) )
printk("build-id: %*phN\n", len, binary_id);
- if ( !spin_trylock(&payload_lock) )
- {
- printk("Lock held. Try again.\n");
+ if ( !keyhandler_spin_lock(&payload_lock, "could not get payload lock") )
return;
- }
list_for_each_entry ( data, &payload_list, list )
{
@@ -2096,11 +2093,9 @@ static void livepatch_printall(unsigned char key)
{
spin_unlock(&payload_lock);
process_pending_softirqs();
- if ( !spin_trylock(&payload_lock) )
- {
- printk("Couldn't reacquire lock. Try again.\n");
+ if ( !keyhandler_spin_lock(&payload_lock,
+ "could not reacquire payload lock") )
return;
- }
}
}
if ( data->id.len )
@@ -349,17 +349,23 @@ static struct lock_profile_anc lock_profile_ancs[LOCKPROF_TYPE_N];
static struct lock_profile_qhead lock_profile_glb_q;
static spinlock_t lock_profile_lock = SPIN_LOCK_UNLOCKED;
-static void spinlock_profile_iterate(lock_profile_subfunc *sub, void *par)
+static void spinlock_profile_iterate_locked(lock_profile_subfunc *sub,
+ void *par)
{
int i;
struct lock_profile_qhead *hq;
struct lock_profile *eq;
- spin_lock(&lock_profile_lock);
for ( i = 0; i < LOCKPROF_TYPE_N; i++ )
for ( hq = lock_profile_ancs[i].head_q; hq; hq = hq->head_q )
for ( eq = hq->elem_q; eq; eq = eq->next )
sub(eq, i, hq->idx, par);
+}
+
+static void spinlock_profile_iterate(lock_profile_subfunc *sub, void *par)
+{
+ spin_lock(&lock_profile_lock);
+ spinlock_profile_iterate_locked(sub, par);
spin_unlock(&lock_profile_lock);
}
@@ -389,7 +395,13 @@ void spinlock_profile_printall(unsigned char key)
diff = now - lock_profile_start;
printk("Xen lock profile info SHOW (now = %"PRI_stime" total = "
"%"PRI_stime")\n", now, diff);
- spinlock_profile_iterate(spinlock_profile_print_elem, NULL);
+
+ if ( !keyhandler_spin_lock(&lock_profile_lock, "could not get lock") )
+ return;
+
+ spinlock_profile_iterate_locked(spinlock_profile_print_elem, NULL);
+
+ spin_unlock(&lock_profile_lock);
}
static void spinlock_profile_reset_elem(struct lock_profile *data,
@@ -561,12 +561,15 @@ static void dump_timerq(unsigned char key)
ts = &per_cpu(timers, i);
printk("CPU%02d:\n", i);
- spin_lock_irqsave(&ts->lock, flags);
- for ( j = 1; j <= heap_metadata(ts->heap)->size; j++ )
- dump_timer(ts->heap[j], now);
- for ( t = ts->list; t != NULL; t = t->list_next )
- dump_timer(t, now);
- spin_unlock_irqrestore(&ts->lock, flags);
+ if ( keyhandler_spin_lock_irqsave(&ts->lock, &flags,
+ "could not get lock") )
+ {
+ for ( j = 1; j <= heap_metadata(ts->heap)->size; j++ )
+ dump_timer(ts->heap[j], now);
+ for ( t = ts->list; t != NULL; t = t->list_next )
+ dump_timer(t, now);
+ spin_unlock_irqrestore(&ts->lock, flags);
+ }
}
}
@@ -278,6 +278,41 @@ static inline void _percpu_read_lock(percpu_rwlock_t **per_cpudata,
}
}
+static inline int _percpu_read_trylock(percpu_rwlock_t **per_cpudata,
+ percpu_rwlock_t *percpu_rwlock)
+{
+ /* Validate the correct per_cpudata variable has been provided. */
+ _percpu_rwlock_owner_check(per_cpudata, percpu_rwlock);
+
+ /* We cannot support recursion on the same lock. */
+ ASSERT(this_cpu_ptr(per_cpudata) != percpu_rwlock);
+ /*
+ * Detect using a second percpu_rwlock_t simulatenously and fallback
+ * to standard read_trylock.
+ */
+ if ( unlikely(this_cpu_ptr(per_cpudata) != NULL ) )
+ return read_trylock(&percpu_rwlock->rwlock);
+
+ /* Indicate this cpu is reading. */
+ this_cpu_ptr(per_cpudata) = percpu_rwlock;
+ smp_mb();
+ /* Check if a writer is waiting. */
+ if ( unlikely(percpu_rwlock->writer_activating) )
+ {
+ /* Let the waiting writer know we aren't holding the lock. */
+ this_cpu_ptr(per_cpudata) = NULL;
+ /* Try using the read lock to keep the lock fair. */
+ if ( !read_trylock(&percpu_rwlock->rwlock) )
+ return 0;
+ /* Set the per CPU data again and continue. */
+ this_cpu_ptr(per_cpudata) = percpu_rwlock;
+ /* Drop the read lock because we don't need it anymore. */
+ read_unlock(&percpu_rwlock->rwlock);
+ }
+
+ return 1;
+}
+
static inline void _percpu_read_unlock(percpu_rwlock_t **per_cpudata,
percpu_rwlock_t *percpu_rwlock)
{
@@ -318,6 +353,8 @@ static inline void _percpu_write_unlock(percpu_rwlock_t **per_cpudata,
#define percpu_read_lock(percpu, lock) \
_percpu_read_lock(&get_per_cpu_var(percpu), lock)
+#define percpu_read_trylock(percpu, lock) \
+ _percpu_read_trylock(&get_per_cpu_var(percpu), lock)
#define percpu_read_unlock(percpu, lock) \
_percpu_read_unlock(&get_per_cpu_var(percpu), lock)
#define percpu_write_lock(percpu, lock) \
Instead of using the normal locks use the keyhandler provided trylocks with timeouts. This requires adding a percpu read_trylock and a special primitive for the grant lock. Signed-off-by: Juergen Gross <jgross@suse.com> --- xen/common/event_channel.c | 3 ++- xen/common/grant_table.c | 32 +++++++++++++++++++++++++++++--- xen/common/livepatch.c | 11 +++-------- xen/common/spinlock.c | 18 +++++++++++++++--- xen/common/timer.c | 15 +++++++++------ xen/include/xen/rwlock.h | 37 +++++++++++++++++++++++++++++++++++++ 6 files changed, 95 insertions(+), 21 deletions(-)