Re: [PATCH RFC v8 48/56] KVM: SVM: Add SNP-specific handling for memory attribute updates

From: Dave Hansen
Date: Wed Mar 01 2023 - 18:37:31 EST


On 2/20/23 10:38, Michael Roth wrote:
> + /*
> + * TODO: The RMP entry's hugepage bit is ignored for
> + * shared/unassigned pages. Either handle looping through each
> + * sub-page as part of snp_make_page_shared(), or remove the
> + * level argument.
> + */
> + if (op == SNP_PAGE_STATE_PRIVATE && order &&
> + IS_ALIGNED(gfn, 1 << order) && (gfn + (1 << order)) <= end) {
> + level = order_to_level(order);
> + npages = 1 << order;
> + }

That's a wee bit obtuse.

First of all, I assume that the 'RFC' is because of these TODOs and they
won't survive to the point when you ask for this to be merged.

BTW, what keeps the restrictedmem_get_page() offset and the gfn aligned?

Let's start with this:

> +static inline u8 order_to_level(int order)
> +{
> + BUILD_BUG_ON(KVM_MAX_HUGEPAGE_LEVEL > PG_LEVEL_1G);
> +
> + if (order >= KVM_HPAGE_GFN_SHIFT(PG_LEVEL_1G))
> + return PG_LEVEL_1G;
> +
> + if (order >= KVM_HPAGE_GFN_SHIFT(PG_LEVEL_2M))
> + return PG_LEVEL_2M;
> +
> + return PG_LEVEL_4K;
> +}

Right now, 'order' comes only from restrictedmem_get_page(), which I dug
out of:

> https://github.com/mdroth/linux/commit/c6792672cd11737fd255dff10b2d5b6bccc626a8

That order is *only* filled in by THPs. That makes the PG_LEVEL_1G
stuff here kinda silly. I guess it might be seen as thorough, but it's
dead code. I'd probably just make this work on order==9 || order==0 and
warn on anything else.

I'd also highly recommend some comments about how racy this all is. I
guess it probably works, but it would be good to add some comments about
page splits and collapsing.

It's also not obvious why this only cares about private pages.

Anyway, this is the exact kind of thing where I really like a
well-commented helper:

bool can_install_large_rmp_entry(gfn, order)
{
// small pages, blah blah
if (!order)
return false;

// The region being updated must be aligned
if (!IS_ALIGNED(gfn, 1 << order))
return false;
// ... and fit
if (gfn + (1 << order)) > end)
return false;

return true;
}

Which gets used like this:

if (op == SNP_PAGE_STATE_PRIVATE &&
can_install_large_rmp_entry(gfn, order)) {
level = ...
}