@@ -2930,7 +2930,8 @@ static int kvm_mmu_remove_some_alloc_mmu
static int shrink_kvm_mmu(struct kvm *kvm, int nr_to_scan)
{
- int idx, freed_pages;
+ int idx;
+ int freed_pages = 0;
idx = srcu_read_lock(&kvm->srcu);
spin_lock(&kvm->mmu_lock);
@@ -2950,23 +2951,50 @@ static int shrink_kvm_mmu(struct kvm *kv
static int mmu_shrink(int nr_to_scan, gfp_t gfp_mask)
{
+ int err;
+ int freed;
struct kvm *kvm;
if (nr_to_scan == 0)
goto out;
+retry:
+ nr_to_scan--;
spin_lock(&kvm_lock);
-
- list_for_each_entry(kvm, &vm_list, vm_list) {
- int freed = shrink_kvm_mmu(kvm, nr_to_scan);
- if (!freed)
- continue;
-
- list_move_tail(&kvm->vm_list, &vm_list);
- break;
+ if (list_empty(&vm_list)) {
+ spin_unlock(&kvm_lock);
+ goto out;
}
-
+ kvm = list_first_entry(&vm_list, struct kvm, vm_list);
+ /*
+ * With a reference to the kvm object, it can not go away
+ * nor get removed from the vm_list.
+ */
+ err = kvm_get_kvm(kvm);
+ /* Did someone race and start destroying the kvm object? */
+ if (err) {
+ spin_unlock(&kvm_lock);
+ goto retry;
+ }
+ /*
+ * Stick this kvm on the end of the list so the next
+ * interation will shrink a different one. Do this here
+ * so that we normally don't have to reacquire the lock.
+ */
+ list_move_tail(&kvm->vm_list, &vm_list);
+ /*
+ * Which lets us release the global lock, holding it for
+ * the minimal amount of time possible, and ensuring that
+ * we don't hold it during the (presumably slow) shrink
+ * operation itself.
+ */
spin_unlock(&kvm_lock);
+ freed = shrink_kvm_mmu(kvm, nr_to_scan);
+
+ kvm_put_kvm(kvm);
+
+ if (!freed && nr_to_scan > 0)
+ goto retry;
out:
return kvm_total_used_mmu_pages;
@@ -314,6 +314,8 @@ void profile_hits(int type, void *__pc,
if (prof_on != type || !prof_buffer)
return;
pc = min((pc - (unsigned long)_stext) >> prof_shift, prof_len - 1);
+ if ((pc == prof_len - 1) && printk_ratelimit())
+ printk("profile_hits(%d, %p, %d)\n", type, __pc, nr_hits);
i = primary = (pc & (NR_PROFILE_GRP - 1)) << PROFILE_GRPSHIFT;
secondary = (~(pc << 1) & (NR_PROFILE_GRP - 1)) << PROFILE_GRPSHIFT;
cpu = get_cpu();