@@ -1848,7 +1848,7 @@ static int __mmu_unsync_walk(struct kvm_mmu_page *sp,
child = page_header(ent & PT64_BASE_ADDR_MASK);
if (child->unsync_children) {
- if (mmu_pages_add(pvec, child, i))
+ if (mmu_pages_add(pvec, sp, i))
return -ENOSPC;
ret = __mmu_unsync_walk(child, pvec);
@@ -1861,7 +1861,14 @@ static int __mmu_unsync_walk(struct kvm_mmu_page *sp,
return ret;
} else if (child->unsync) {
nr_unsync_leaf++;
- if (mmu_pages_add(pvec, child, i))
+ if (mmu_pages_add(pvec, sp, i))
+ return -ENOSPC;
+
+ /*
+ * the unsync is on the last level so its 'idx' is
+ * useless, we set it to 0 to catch potential bugs.
+ */
+ if (mmu_pages_add(pvec, child, 0))
return -ENOSPC;
} else
clear_unsync_child_bit(sp, i);
@@ -1876,7 +1883,6 @@ static int mmu_unsync_walk(struct kvm_mmu_page *sp,
if (!sp->unsync_children)
return 0;
- mmu_pages_add(pvec, sp, 0);
return __mmu_unsync_walk(sp, pvec);
}
@@ -2002,16 +2008,18 @@ static int mmu_pages_next(struct kvm_mmu_pages *pvec,
{
int n;
- for (n = i+1; n < pvec->nr; n++) {
+ for (n = i + 1; n < pvec->nr; n++) {
struct kvm_mmu_page *sp = pvec->page[n].sp;
+ unsigned int idx = pvec->page[n].idx;
if (sp->role.level == PT_PAGE_TABLE_LEVEL) {
- parents->idx[0] = pvec->page[n].idx;
+ /* we always set the idex as 0 for the unsync page. */
+ WARN_ON(idx != 0);
return n;
}
- parents->parent[sp->role.level-2] = sp;
- parents->idx[sp->role.level-1] = pvec->page[n].idx;
+ parents->parent[sp->role.level - 2] = sp;
+ parents->idx[sp->role.level - 2] = idx;
}
return n;
@@ -2031,14 +2039,18 @@ static void mmu_pages_clear_parents(struct mmu_page_path *parents)
clear_unsync_child_bit(sp, idx);
level++;
- } while (level < PT64_ROOT_LEVEL-1 && !sp->unsync_children);
+ } while (level < PT64_ROOT_LEVEL - 1 && !sp->unsync_children);
}
static void kvm_mmu_pages_init(struct kvm_mmu_page *parent,
struct mmu_page_path *parents,
struct kvm_mmu_pages *pvec)
{
- parents->parent[parent->role.level-1] = NULL;
+ /*
+ * set the highest level to NULL to stop mmu_pages_clear_parents()
+ * handing it on 32 bit guest.
+ */
+ parents->parent[parent->role.level - 2] = NULL;
pvec->nr = 0;
}