Create a separate routine sev_alloc_pages() for allocating sev pages.
This will be used in the following MMU based pinning.
While at it, validate the number of pages before the RLIMIT check and
use kzalloc instead of kmalloc.
Signed-off-by: Nikunj A Dadhania <[email protected]>
---
arch/x86/kvm/svm/sev.c | 44 ++++++++++++++++++++++++++----------------
1 file changed, 27 insertions(+), 17 deletions(-)
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index d0514975555d..7e39320fc65d 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -397,43 +397,53 @@ static unsigned long get_npages(unsigned long uaddr, unsigned long ulen)
return last - first + 1;
}
-static struct page **sev_pin_memory(struct kvm *kvm, unsigned long uaddr,
- unsigned long ulen, unsigned long *n,
- int write)
+static void *sev_alloc_pages(struct kvm_sev_info *sev, unsigned long uaddr,
+ unsigned long ulen, unsigned long *n)
{
- struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
- struct pinned_region *region;
unsigned long npages, size;
- int npinned;
struct page **pages;
- int ret;
-
- lockdep_assert_held(&kvm->lock);
if (ulen == 0 || uaddr + ulen < uaddr)
return ERR_PTR(-EINVAL);
npages = get_npages(uaddr, ulen);
+ if (WARN_ON_ONCE(npages > INT_MAX))
+ return ERR_PTR(-EINVAL);
if (rlimit_memlock_exceeds(sev->pages_to_lock, npages)) {
pr_err("SEV: %lu locked pages exceed the lock limit of %lu.\n",
- sev->pages_to_lock + npages,
- (rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT));
+ sev->pages_to_lock + npages,
+ (rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT));
return ERR_PTR(-ENOMEM);
}
- if (WARN_ON_ONCE(npages > INT_MAX))
- return ERR_PTR(-EINVAL);
-
/* Avoid using vmalloc for smaller buffers. */
size = npages * sizeof(struct page *);
if (size > PAGE_SIZE)
pages = __vmalloc(size, GFP_KERNEL_ACCOUNT | __GFP_ZERO);
else
- pages = kmalloc(size, GFP_KERNEL_ACCOUNT);
+ pages = kzalloc(size, GFP_KERNEL_ACCOUNT);
- if (!pages)
- return ERR_PTR(-ENOMEM);
+ *n = pages ? npages : 0;
+ return pages;
+}
+
+static struct page **sev_pin_memory(struct kvm *kvm, unsigned long uaddr,
+ unsigned long ulen, unsigned long *n,
+ int write)
+{
+ struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+ struct pinned_region *region;
+ unsigned long npages;
+ struct page **pages;
+ int npinned;
+ int ret;
+
+ lockdep_assert_held(&kvm->lock);
+
+ pages = sev_alloc_pages(sev, uaddr, ulen, &npages);
+ if (IS_ERR(pages))
+ return pages;
/* Pin the user virtual address. */
npinned = pin_user_pages_fast(uaddr, npages, write ? FOLL_WRITE : 0, pages);
--
2.32.0