RE: [PATCH] nitro_enclaves: merge contiguous physical memory regions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




> -----Original Message-----
> From: Paraschiv, Andra-Irina [mailto:andraprs@xxxxxxxxxx]
> Sent: Wednesday, September 15, 2021 1:45 AM
> To: Longpeng (Mike, Cloud Infrastructure Service Product Dept.)
> <longpeng2@xxxxxxxxxx>
> Cc: linux-kernel@xxxxxxxxxxxxxxx; Gonglei (Arei) <arei.gonglei@xxxxxxxxxx>; Greg
> KH <gregkh@xxxxxxxxxxxxxxxxxxx>; Kamal Mostafa <kamal@xxxxxxxxxxxxx>;
> Alexandru Vasile <lexnv@xxxxxxxxxx>; Alexandru Ciobotaru
> <alcioa@xxxxxxxxxx>; Paolo Bonzini <pbonzini@xxxxxxxxxx>; Stefano Garzarella
> <sgarzare@xxxxxxxxxx>; Stefan Hajnoczi <stefanha@xxxxxxxxxx>; Vitaly
> Kuznetsov <vkuznets@xxxxxxxxxx>; kvm@xxxxxxxxxxxxxxx;
> ne-devel-upstream@xxxxxxxxxx
> Subject: Re: [PATCH] nitro_enclaves: merge contiguous physical memory regions
> 
> 
> 
> On 14/09/2021 06:14, Longpeng(Mike) wrote:
> >
> 
> Thanks for the patch.
> 
> > There maybe too many physical memory regions if the memory regions
> > backend with 2M hugetlb pages.
> 
> Could update something along these lines:
> 
> There can be cases when there are more memory regions that need to be
> set for an enclave than the maximum supported number of memory regions
> per enclave. One example can be when the memory regions are backed by 2
> MiB hugepages (the minimum supported hugepage size).
> 
> >
> > Let's merge the adjacent regions if they are physical contiguous.
> 
> Let's merge the adjacent regions if they are physical contiguous. This
> way the final number of memory regions is less than before merging and
> could potentially avoid reaching maximum.
> 

Okay, it looks much better, thanks.

> >
> > Signed-off-by: Longpeng(Mike) <longpeng2@xxxxxxxxxx>
> > ---
> >   drivers/virt/nitro_enclaves/ne_misc_dev.c | 64 +++++++++++++++++--------------
> >   1 file changed, 35 insertions(+), 29 deletions(-)
> 
> Let's see the current state of the NE user space tooling and how it
> interacts with the NE kernel driver.
> 
> The Nitro CLI tooling sets one hugepage per memory region [1]. The NE
> sample from the upstream Linux kernel does the same [2].
> 
> We need to have a way to exercise this code path of merging memory
> regions and validate it. Let's have, for example, an update for the NE
> sample, if you can please add as an additional commit in the next revision.
> 
> There could be an option e.g. to have both 2 MiB and 8 MiB memory
> regions, backed by 2 MiB hugepages. For example:
> 
> 
> /**
> - * NE_MIN_MEM_REGION_SIZE - Minimum size of a memory region - 2 MiB.
> + * NE_2MB_MEM_REGION_SIZE - Size of a memory region - 2 MiB.
>    */
> -#define NE_MIN_MEM_REGION_SIZE         (2 * 1024 * 1024)
> +#define NE_2MB_MEM_REGION_SIZE         (2 * 1024 * 1024)
> 
>   /**
> - * NE_DEFAULT_NR_MEM_REGIONS - Default number of memory regions of 2
> MiB set for
> + * NE_8MB_MEM_REGION_SIZE - Size of a memory region - 8 MiB.
> + */
> +#define NE_8MB_MEM_REGION_SIZE         (8 * 1024 * 1024)
> +
> +/**
> + * NE_DEFAULT_NR_2MB_MEM_REGIONS - Default number of memory regions of
> 2 MiB set for
> + *                                an enclave.
> + */
> +#define NE_DEFAULT_NR_2MB_MEM_REGIONS  (128)
> +
> +/**
> + * NE_DEFAULT_NR_8MB_MEM_REGIONS - Default number of memory regions of
> 8 MiB set for
> + *                                an enclave.
> + */
> +#define NE_DEFAULT_NR_8MB_MEM_REGIONS  (32)
> +
> +/**
> + * NE_DEFAULT_NR_MEM_REGIONS - Default number of memory regions of 2
> MiB and 8 MiB set for
>    *                            an enclave.
>    */
> -#define NE_DEFAULT_NR_MEM_REGIONS      (256)
> +#define NE_DEFAULT_NR_MEM_REGIONS
> (NE_DEFAULT_NR_2MB_MEM_REGIONS +
> NE_DEFAULT_NR_8MB_MEM_REGIONS)
> 
> 
> 
> Then the logic from [2] can be updated to allocate the first part, the 2
> MiB memory regions, then the second part, the 8 MiB memory regions.
> 
> Open for other options as well to cover the validation for the regions
> merging case.
> 

Okay, will do in the next version.

By the way, I have another question here.

The nitro_enclaves.ko consists of two parts: the misc part and the pci_dev part. 
The main logic is in the misc part, the pci_dev part is responsible for the 
device management and command routing.

So how about to decouple these two parts, e.g. split the nitro_enclaves.ko into 
ne_ioctl.ko and ne_pdev.ko ?  In this way, we can allow other modules to connect 
with ne_ioctl.ko:

                  ne_ioctl.ko
              ---/     |     --\ 
          ---/         |        -----\
      ---/             |              ----\
 ne_pdev.ko        test_pdev.ko          others...


With test_pdev.ko, we can validate the core logic of the ne_ioctl.ko in local.
What's more, other vendor's device could also support software enclave feature 
if they follow the specification.

> >
> > diff --git a/drivers/virt/nitro_enclaves/ne_misc_dev.c
> b/drivers/virt/nitro_enclaves/ne_misc_dev.c
> > index e21e1e8..2920f26 100644
> > --- a/drivers/virt/nitro_enclaves/ne_misc_dev.c
> > +++ b/drivers/virt/nitro_enclaves/ne_misc_dev.c
> > @@ -824,6 +824,11 @@ static int
> ne_sanity_check_user_mem_region_page(struct ne_enclave *ne_enclave,
> >          return 0;
> >   }
> >
> > +struct phys_contig_mem_region {
> > +       u64 paddr;
> > +       u64 size;
> > +};
> > +
> >   /**
> >    * ne_set_user_memory_region_ioctl() - Add user space memory region to
> the slot
> >    *                                    associated with the current
> enclave.
> > @@ -843,9 +848,10 @@ static int ne_set_user_memory_region_ioctl(struct
> ne_enclave *ne_enclave,
> >          unsigned long max_nr_pages = 0;
> >          unsigned long memory_size = 0;
> >          struct ne_mem_region *ne_mem_region = NULL;
> > -       unsigned long nr_phys_contig_mem_regions = 0;
> >          struct pci_dev *pdev = ne_devs.ne_pci_dev->pdev;
> > -       struct page **phys_contig_mem_regions = NULL;
> > +       struct phys_contig_mem_region *phys_regions = NULL;
> > +       unsigned long nr_phys_regions = 0;
> > +       u64 prev_phys_region_end;
> 
> It's indeed initialized later on and it's not used till then, but let's
> just have an init to 0 here as well.
> 

Okay.

> >          int rc = -EINVAL;
> >
> >          rc = ne_sanity_check_user_mem_region(ne_enclave, mem_region);
> > @@ -866,9 +872,8 @@ static int ne_set_user_memory_region_ioctl(struct
> ne_enclave *ne_enclave,
> >                  goto free_mem_region;
> >          }
> >
> > -       phys_contig_mem_regions = kcalloc(max_nr_pages,
> sizeof(*phys_contig_mem_regions),
> > -                                         GFP_KERNEL);
> > -       if (!phys_contig_mem_regions) {
> > +       phys_regions = kcalloc(max_nr_pages, sizeof(*phys_regions),
> GFP_KERNEL);
> > +       if (!phys_regions) {
> >                  rc = -ENOMEM;
> >
> >                  goto free_mem_region;
> > @@ -903,25 +908,29 @@ static int ne_set_user_memory_region_ioctl(struct
> ne_enclave *ne_enclave,
> >
> >                  /*
> >                   * TODO: Update once handled non-contiguous memory
> regions
> > -                * received from user space or contiguous physical memory
> regions
> > -                * larger than 2 MiB e.g. 8 MiB.
> > +                * received from user space.
> >                   */
> 
> Can remove this TODO completely, similar as below.
> 

Okay.

> > -               phys_contig_mem_regions[i] = ne_mem_region->pages[i];
> > +               if (nr_phys_regions &&
> > +                   prev_phys_region_end ==
> page_to_phys(ne_mem_region->pages[i]))
> > +                       phys_regions[nr_phys_regions - 1].size +=
> > +
> page_size(ne_mem_region->pages[i]);
> 
> Please add parantheses here as well.
> 
> if ... {
> 
> 
> } else {
> 
> }
> 
> > +               else {
> > +                       phys_regions[nr_phys_regions].paddr =
> > +
> page_to_phys(ne_mem_region->pages[i]);
> > +                       phys_regions[nr_phys_regions].size =
> > +
> page_size(ne_mem_region->pages[i]);
> > +                       nr_phys_regions++;
> > +               }
> > +
> > +               prev_phys_region_end = phys_regions[nr_phys_regions -
> 1].paddr +
> > +                                       phys_regions[nr_phys_regions -
> 1].size;
> >
> >                  memory_size += page_size(ne_mem_region->pages[i]);
> >
> >                  ne_mem_region->nr_pages++;
> >          } while (memory_size < mem_region.memory_size);
> >
> > -       /*
> > -        * TODO: Update once handled non-contiguous memory regions
> received
> > -        * from user space or contiguous physical memory regions larger than
> > -        * 2 MiB e.g. 8 MiB.
> > -        */
> > -       nr_phys_contig_mem_regions = ne_mem_region->nr_pages;
> > -
> > -       if ((ne_enclave->nr_mem_regions + nr_phys_contig_mem_regions) >
> > -           ne_enclave->max_mem_regions) {
> > +       if ((ne_enclave->nr_mem_regions + nr_phys_regions) >
> ne_enclave->max_mem_regions) {
> >                  dev_err_ratelimited(ne_misc_dev.this_device,
> >                                      "Reached max memory
> regions %lld\n",
> >                                      ne_enclave->max_mem_regions);
> > @@ -931,11 +940,8 @@ static int ne_set_user_memory_region_ioctl(struct
> ne_enclave *ne_enclave,
> >                  goto put_pages;
> >          }
> >
> > -       for (i = 0; i < nr_phys_contig_mem_regions; i++) {
> > -               u64 phys_region_addr =
> page_to_phys(phys_contig_mem_regions[i]);
> > -               u64 phys_region_size =
> page_size(phys_contig_mem_regions[i]);
> > -
> > -               if (phys_region_size & (NE_MIN_MEM_REGION_SIZE - 1)) {
> > +       for (i = 0; i < nr_phys_regions; i++) {
> > +               if (phys_regions[i].size & (NE_MIN_MEM_REGION_SIZE - 1)) {
> >                          dev_err_ratelimited(ne_misc_dev.this_device,
> >                                              "Physical mem region
> size is not multiple of 2 MiB\n");
> >
> > @@ -944,7 +950,7 @@ static int ne_set_user_memory_region_ioctl(struct
> ne_enclave *ne_enclave,
> >                          goto put_pages;
> >                  }
> >
> > -               if (!IS_ALIGNED(phys_region_addr,
> NE_MIN_MEM_REGION_SIZE)) {
> > +               if (!IS_ALIGNED(phys_regions[i].paddr,
> NE_MIN_MEM_REGION_SIZE)) {
> >                          dev_err_ratelimited(ne_misc_dev.this_device,
> >                                              "Physical mem region
> address is not 2 MiB aligned\n");
> >
> > @@ -959,13 +965,13 @@ static int ne_set_user_memory_region_ioctl(struct
> ne_enclave *ne_enclave,
> >
> >          list_add(&ne_mem_region->mem_region_list_entry,
> &ne_enclave->mem_regions_list);
> >
> > -       for (i = 0; i < nr_phys_contig_mem_regions; i++) {
> > +       for (i = 0; i < nr_phys_regions; i++) {
> >                  struct ne_pci_dev_cmd_reply cmd_reply = {};
> >                  struct slot_add_mem_req slot_add_mem_req = {};
> >
> >                  slot_add_mem_req.slot_uid = ne_enclave->slot_uid;
> > -               slot_add_mem_req.paddr =
> page_to_phys(phys_contig_mem_regions[i]);
> > -               slot_add_mem_req.size =
> page_size(phys_contig_mem_regions[i]);
> > +               slot_add_mem_req.paddr = phys_regions[i].paddr;
> > +               slot_add_mem_req.size = phys_regions[i].size;
> >
> >                  rc = ne_do_request(pdev, SLOT_ADD_MEM,
> >                                     &slot_add_mem_req,
> sizeof(slot_add_mem_req),
> > @@ -974,7 +980,7 @@ static int ne_set_user_memory_region_ioctl(struct
> ne_enclave *ne_enclave,
> >                          dev_err_ratelimited(ne_misc_dev.this_device,
> >                                              "Error in slot add mem
> [rc=%d]\n", rc);
> >
> > -                       kfree(phys_contig_mem_regions);
> > +                       kfree(phys_regions);
> >
> >                          /*
> >                           * Exit here without put pages as memory regions
> may
> > @@ -987,7 +993,7 @@ static int ne_set_user_memory_region_ioctl(struct
> ne_enclave *ne_enclave,
> >                  ne_enclave->nr_mem_regions++;
> >          }
> >
> > -       kfree(phys_contig_mem_regions);
> > +       kfree(phys_regions);
> >
> >          return 0;
> >
> > @@ -995,7 +1001,7 @@ static int ne_set_user_memory_region_ioctl(struct
> ne_enclave *ne_enclave,
> >          for (i = 0; i < ne_mem_region->nr_pages; i++)
> >                  put_page(ne_mem_region->pages[i]);
> >   free_mem_region:
> > -       kfree(phys_contig_mem_regions);
> > +       kfree(phys_regions);
> >          kfree(ne_mem_region->pages);
> >          kfree(ne_mem_region);
> >
> > --
> > 1.8.3.1
> >
> 
> Please also add the changelog after the "---" line in the patches so
> that we can track changes between revisions.
> 

Got it, thanks.

> Thanks,
> Andra
> 
> [1]
> https://github.com/aws/aws-nitro-enclaves-cli/blob/main/src/enclave_proc/resour
> ce_manager.rs#L211
> [2]
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/samples/nitr
> o_enclaves/ne_ioctl_sample.c#n817
> 
> 
> 
> Amazon Development Center (Romania) S.R.L. registered office: 27A Sf. Lazar
> Street, UBC5, floor 2, Iasi, Iasi County, 700045, Romania. Registered in Romania.
> Registration number J22/2621/2005.




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux