DPDK patches and discussions
 help / color / mirror / Atom feed
From: "Li, Ming3" <ming3.li@intel.com>
Cc: "dev@dpdk.org" <dev@dpdk.org>,
	"dmitry.kozliuk@gmail.com" <dmitry.kozliuk@gmail.com>,
	"roretzla@linux.microsoft.com" <roretzla@linux.microsoft.com>
Subject: RE: [PATCH v3] windows/virt2phys: fix block MDL not updated
Date: Mon, 27 Nov 2023 01:31:05 +0000	[thread overview]
Message-ID: <PH7PR11MB5818803C0AB322C6B959D3B9DABDA@PH7PR11MB5818.namprd11.prod.outlook.com> (raw)
In-Reply-To: <20230912111759.1502806-1-ming3.li@intel.com>

Hello,

Any update on the patch review?

Best regards,
Ming

> -----Original Message-----
> From: Li, Ming3 <ming3.li@intel.com>
> Sent: Tuesday, September 12, 2023 7:18 PM
> To: Li, Ming3 <ming3.li@intel.com>
> Cc: dev@dpdk.org; dmitry.kozliuk@gmail.com; roretzla@linux.microsoft.com
> Subject: [PATCH v3] windows/virt2phys: fix block MDL not updated
> 
> The virt2phys_translate function previously scanned existing blocks, returning
> the physical address from the stored MDL info if present.
> This method was problematic when a virtual address pointed to a freed and
> reallocated memory segment, potentially changing the physical address
> mapping. Yet, virt2phys_translate would consistently return the originally
> stored physical address, which could be invalid.
> 
> This issue surfaced when allocating a memory region larger than 2MB using
> rte_malloc. This action would allocate a new memory segment and use virt2phy
> to set the IOVA. The driver would store the MDL and lock the pages initially.
> When this region was freed, the memory segment used as a whole page could
> be freed, invalidating the virtual to physical mapping. Before this fix, the driver
> would only return the initial physical address, leading to illegal IOVA for some
> pages when allocating a new memory region larger than the hugepage size
> (2MB).
> 
> To address this, a function to check block physical address has been added. If a
> block with the same base address is detected in the driver's context, the MDL's
> physical address is compared with the real physical address. If they don't
> match, the block is removed and a new one is created to store the correct
> mapping. To make the removal action clear, the list to store MDL blocks is
> chenged to a double linked list.
> 
> Also fix the printing of PVOID type.
> 
> Bugzilla ID: 1201
> Bugzilla ID: 1213
> 
> Signed-off-by: Ric Li <ming3.li@intel.com>
> ---
> v3:
> * Change refresh action to block removal
> * Change block list to double linked list
> 
> v2:
> * Revert wrong usage of MmGetMdlStartVa
> 
>  windows/virt2phys/virt2phys.c       |  7 +--
>  windows/virt2phys/virt2phys_logic.c | 70 ++++++++++++++++++++++-------
>  2 files changed, 57 insertions(+), 20 deletions(-)
> 
> diff --git a/windows/virt2phys/virt2phys.c b/windows/virt2phys/virt2phys.c
> index f4d5298..b64a13d 100644
> --- a/windows/virt2phys/virt2phys.c
> +++ b/windows/virt2phys/virt2phys.c
> @@ -182,7 +182,7 @@ virt2phys_device_EvtIoInCallerContext(WDFDEVICE
> device, WDFREQUEST request)  {
>  	WDF_REQUEST_PARAMETERS params;
>  	ULONG code;
> -	PVOID *virt;
> +	PVOID *pvirt, virt;
>  	PHYSICAL_ADDRESS *phys;
>  	size_t size;
>  	NTSTATUS status;
> @@ -207,12 +207,13 @@ virt2phys_device_EvtIoInCallerContext(WDFDEVICE
> device, WDFREQUEST request)
>  	}
> 
>  	status = WdfRequestRetrieveInputBuffer(
> -			request, sizeof(*virt), (PVOID *)&virt, &size);
> +			request, sizeof(*pvirt), (PVOID *)&pvirt, &size);
>  	if (!NT_SUCCESS(status)) {
>  		TraceWarning("Retrieving input buffer: %!STATUS!", status);
>  		WdfRequestComplete(request, status);
>  		return;
>  	}
> +	virt = *pvirt;
> 
>  	status = WdfRequestRetrieveOutputBuffer(
>  		request, sizeof(*phys), (PVOID *)&phys, &size); @@ -222,7
> +223,7 @@ virt2phys_device_EvtIoInCallerContext(WDFDEVICE device,
> WDFREQUEST request)
>  		return;
>  	}
> 
> -	status = virt2phys_translate(*virt, phys);
> +	status = virt2phys_translate(virt, phys);
>  	if (NT_SUCCESS(status))
>  		WdfRequestSetInformation(request, sizeof(*phys));
> 
> diff --git a/windows/virt2phys/virt2phys_logic.c
> b/windows/virt2phys/virt2phys_logic.c
> index e3ff293..531f08c 100644
> --- a/windows/virt2phys/virt2phys_logic.c
> +++ b/windows/virt2phys/virt2phys_logic.c
> @@ -12,13 +12,13 @@
>  struct virt2phys_process {
>  	HANDLE id;
>  	LIST_ENTRY next;
> -	SINGLE_LIST_ENTRY blocks;
> +	LIST_ENTRY blocks;
>  	ULONG64 memory;
>  };
> 
>  struct virt2phys_block {
>  	PMDL mdl;
> -	SINGLE_LIST_ENTRY next;
> +	LIST_ENTRY next;
>  };
> 
>  static struct virt2phys_params g_params; @@ -69,24 +69,28 @@
> virt2phys_process_create(HANDLE process_id)
>  	struct virt2phys_process *process;
> 
>  	process = ExAllocatePoolZero(NonPagedPool, sizeof(*process), 'pp2v');
> -	if (process != NULL)
> +	if (process != NULL) {
>  		process->id = process_id;
> +		InitializeListHead(&process->blocks);
> +	}
> +
>  	return process;
>  }
> 
>  static void
>  virt2phys_process_free(struct virt2phys_process *process, BOOLEAN unmap)  {
> -	PSINGLE_LIST_ENTRY node;
> +	PLIST_ENTRY node, next;
>  	struct virt2phys_block *block;
> 
>  	TraceInfo("ID = %p, unmap = %!bool!", process->id, unmap);
> 
> -	node = process->blocks.Next;
> -	while (node != NULL) {
> +	for (node = process->blocks.Flink; node != &process->blocks; node =
> next) {
> +		next = node->Flink;
>  		block = CONTAINING_RECORD(node, struct virt2phys_block,
> next);
> -		node = node->Next;
> -		virt2phys_block_free(block, unmap);
> +		RemoveEntryList(&block->next);
> +
> +		virt2phys_block_free(block, TRUE);
>  	}
> 
>  	ExFreePool(process);
> @@ -109,10 +113,10 @@ virt2phys_process_find(HANDLE process_id)  static
> struct virt2phys_block *  virt2phys_process_find_block(struct virt2phys_process
> *process, PVOID virt)  {
> -	PSINGLE_LIST_ENTRY node;
> +	PLIST_ENTRY node;
>  	struct virt2phys_block *cur;
> 
> -	for (node = process->blocks.Next; node != NULL; node = node->Next) {
> +	for (node = process->blocks.Flink; node != &process->blocks; node =
> +node->Flink) {
>  		cur = CONTAINING_RECORD(node, struct virt2phys_block,
> next);
>  		if (cur->mdl->StartVa == virt)
>  			return cur;
> @@ -182,7 +186,7 @@ virt2phys_process_cleanup(HANDLE process_id)  }
> 
>  static struct virt2phys_block *
> -virt2phys_find_block(HANDLE process_id, void *virt,
> +virt2phys_find_block(HANDLE process_id, PVOID virt,
>  	struct virt2phys_process **process)
>  {
>  	PLIST_ENTRY node;
> @@ -244,13 +248,13 @@ virt2phys_add_block(struct virt2phys_process
> *process,
>  		return STATUS_QUOTA_EXCEEDED;
>  	}
> 
> -	PushEntryList(&process->blocks, &block->next);
> +	InsertHeadList(&process->blocks, &block->next);
>  	process->memory += size;
>  	return STATUS_SUCCESS;
>  }
> 
>  static NTSTATUS
> -virt2phys_query_memory(void *virt, void **base, size_t *size)
> +virt2phys_query_memory(PVOID virt, PVOID *base, size_t *size)
>  {
>  	MEMORY_BASIC_INFORMATION info;
>  	SIZE_T info_size;
> @@ -321,7 +325,7 @@ virt2phys_check_memory(PMDL mdl)  }
> 
>  static NTSTATUS
> -virt2phys_lock_memory(void *virt, size_t size, PMDL *mdl)
> +virt2phys_lock_memory(PVOID virt, size_t size, PMDL *mdl)
>  {
>  	*mdl = IoAllocateMdl(virt, (ULONG)size, FALSE, FALSE, NULL);
>  	if (*mdl == NULL)
> @@ -346,12 +350,35 @@ virt2phys_unlock_memory(PMDL mdl)
>  	IoFreeMdl(mdl);
>  }
> 
> +static BOOLEAN
> +virt2phys_is_valid_block(struct virt2phys_block *block, PVOID base) {
> +	/*
> +	 * Check if MDL in block stores the valid physical address.
> +	 * The virtual to physical memory mapping may be changed when the
> +	 * virtual memory region is freed by the user process and malloc again,
> +	 * then we need to remove the block and create a new one.
> +	 */
> +	PHYSICAL_ADDRESS block_phys, real_phys;
> +
> +	block_phys = virt2phys_block_translate(block, base);
> +	real_phys = MmGetPhysicalAddress(base);
> +
> +	if (block_phys.QuadPart == real_phys.QuadPart)
> +		return TRUE;
> +
> +	TraceWarning("VA = %p, invalid block physical address %llx, valid
> address %llx",
> +		base, block_phys.QuadPart, real_phys.QuadPart);
> +
> +	return FALSE;
> +}
> +
>  NTSTATUS
>  virt2phys_translate(PVOID virt, PHYSICAL_ADDRESS *phys)  {
>  	PMDL mdl;
>  	HANDLE process_id;
> -	void *base;
> +	PVOID base;
>  	size_t size;
>  	struct virt2phys_process *process;
>  	struct virt2phys_block *block;
> @@ -371,8 +398,17 @@ virt2phys_translate(PVOID virt, PHYSICAL_ADDRESS
> *phys)
> 
>  	/* Don't lock the same memory twice. */
>  	if (block != NULL) {
> -		*phys = virt2phys_block_translate(block, virt);
> -		return STATUS_SUCCESS;
> +		if (virt2phys_is_valid_block(block, base)) {
> +			*phys = virt2phys_block_translate(block, virt);
> +			return STATUS_SUCCESS;
> +		}
> +		/* Remove the invalid block. */
> +		KeAcquireSpinLock(g_lock, &irql);
> +		RemoveEntryList(&block->next);
> +		process->memory -= MmGetMdlByteCount(block->mdl);
> +		KeReleaseSpinLock(g_lock, irql);
> +
> +		virt2phys_block_free(block, TRUE);
>  	}
> 
>  	status = virt2phys_lock_memory(base, size, &mdl);
> --
> 2.40.1.windows.1


  reply	other threads:[~2023-11-27  1:31 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-09-11  8:22 [PATCH] " Ric Li
2023-09-11 13:09 ` [PATCH v2] " Ric Li
2023-09-11 21:50   ` Dmitry Kozlyuk
2023-09-12 11:13     ` Li, Ming3
2023-09-12 11:17       ` [PATCH v3] " Ric Li
2023-11-27  1:31         ` Li, Ming3 [this message]
2023-11-30  4:10         ` Dmitry Kozlyuk
2023-12-04 10:22           ` [PATCH v4] " Ric Li
2023-12-04 10:32           ` Ric Li
2023-09-12 12:18       ` [PATCH v2] " Dmitry Kozlyuk

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=PH7PR11MB5818803C0AB322C6B959D3B9DABDA@PH7PR11MB5818.namprd11.prod.outlook.com \
    --to=ming3.li@intel.com \
    --cc=dev@dpdk.org \
    --cc=dmitry.kozliuk@gmail.com \
    --cc=roretzla@linux.microsoft.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).