Linux PCI subsystem development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Mukesh R" <mrathor@linux.microsoft.com>
Cc: linux-hyperv@vger.kernel.org, linux-pci@vger.kernel.org
Subject: Re: [PATCH v5 7/9] x86/hyperv: Implement Hyper-V virtual IOMMU
Date: Fri, 31 Jul 2026 22:48:46 +0000	[thread overview]
Message-ID: <20260731224846.BD5571F00AC4@smtp.kernel.org> (raw)
In-Reply-To: <20260731223427.2554388-8-mrathor@linux.microsoft.com>

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] Broken partial unmapping logic incorrectly removes entire mapping ranges, leaks mappings, and causes catastrophic error rollback failures.
- [High] Calling dev_iommu_priv_set() in attach_dev callback without holding iommu_probe_device_lock causes a lockdep violation.
- [High] hv_iommu_map_pages ignores the caller's gfp_t argument and calls a potentially sleeping function.
- [Medium] Atomic counter wrap-around in domain ID allocation risks colliding with reserved hypervisor domain IDs.
- [Low] The __setup callback hv_iommu_setup_skip incorrectly returns 0, causing the kernel to treat the command-line argument as an unknown parameter.
--

--- Patch [7]: [PATCH v5 7/9] x86/hyperv: Implement Hyper-V virtual IOMMU ---
commit cdb89379b7cc5351b8dae8a1be7ede22f440c196
Author: Mukesh R <mrathor@linux.microsoft.com>

x86/hyperv: Implement Hyper-V virtual IOMMU

Add a new file to implement a virtual IOMMU that works with Microsoft Hyper-V
hypervisor. The driver communicates with the hypervisor for creating and 
deleting paging domains and mapping pages. The default domain type is 
IDENTITY.

> diff --git a/drivers/iommu/hyperv/hv-iommu-root.c b/drivers/iommu/hyperv/hv-iommu-root.c
> new file mode 100644
> index 0000000000000..97ddd69560318
> --- /dev/null
> +++ b/drivers/iommu/hyperv/hv-iommu-root.c
> @@ -0,0 +1,706 @@
[ ... ]
> +static char *pci_devs_to_skip;
> +static int __init hv_iommu_setup_skip(char *str)
> +{
> +	pci_devs_to_skip = str;
> +
> +	return 0;
> +}

[Severity: Low]
Should this __setup callback return 1? Returning 0 causes the kernel to
treat the command-line argument as an unknown parameter and pass it to
the init process as an environment variable.

[ ... ]
> +static size_t hv_iommu_del_tree_mappings(struct hv_domain *hvdom,
> +					 unsigned long iova, size_t size)
> +{
> +	unsigned long flags;
> +	size_t unmapped = 0;
> +	unsigned long last = iova + size - 1;
> +	struct hv_iommu_mapping *mapping = NULL;
> +	struct interval_tree_node *node, *next;
> +
> +	spin_lock_irqsave(&hvdom->mappings_lock, flags);
> +	next = interval_tree_iter_first(&hvdom->mappings_tree, iova, last);
> +	while (next) {
> +		node = next;
> +		mapping = container_of(node, struct hv_iommu_mapping, iova);
> +		next = interval_tree_iter_next(node, iova, last);
> +
> +		/* Splitting of a mapping is not supported at present */
> +		if (mapping->iova.start < iova)
> +			break;

[Severity: High]
How does this code handle partial unmaps? If an unmap request starts in the
middle of a mapping, doesn't the break statement here leave the memory
mapped? Furthermore, if the request starts at the beginning but is smaller
than the full mapping, this removes the entire node and returns its full size,
prompting the caller to erroneously unmap the full region from hardware.

[ ... ]
> +static struct iommu_domain *hv_iommu_domain_alloc_paging(struct device *dev)
> +{
> +	struct hv_domain *hvdom;
> +	int rc;
> +	u32 unique_id;
> +	u64 ptid = hv_get_current_partid();
> +
> +	if (ptid == HV_PARTITION_ID_INVALID)
> +		return NULL;
> +
> +	hvdom = kzalloc_obj(struct hv_domain);
> +	if (hvdom == NULL)
> +		return NULL;
> +
> +	spin_lock_init(&hvdom->mappings_lock);
> +	hvdom->mappings_tree = RB_ROOT_CACHED;
> +
> +	unique_id = (u32)atomic_inc_return(&hv_unique_id);
> +	if (unique_id == HV_DEVICE_DOMAIN_ID_S2_NULL)	/* ie, UINTMAX */
> +		goto out_err;

[Severity: Medium]
What happens when this 32-bit atomic counter wraps around? Since it will wrap
to 0 (which is HV_DEVICE_DOMAIN_ID_S2_DEFAULT), could this new domain
improperly map to the hypervisor's default domain and cause hypercall
failures? Should an IDA allocator be used instead?

[ ... ]
> +static int hv_iommu_attach_dev(struct iommu_domain *immdom, struct device *dev,
> +			       struct iommu_domain *old)
> +{
> +	struct pci_dev *pdev;
> +	int rc;
> +	struct hv_domain *hvdom_new = to_hv_domain(immdom);
> +	struct hv_domain *hvdom_prev = to_hv_domain(old);
[ ... ]
> +	rc = hv_iommu_att_dev2dom(hvdom_new, pdev);
> +
> +	if (rc == 0)
> +		dev_iommu_priv_set(dev, hvdom_new);  /* sets "private" field */

[Severity: High]
Can this trigger a lockdep splat? The core function dev_iommu_priv_set()
requires iommu_probe_device_lock to be held, but this attach_dev callback
executes with group->mutex held. Is it safe to use this private field for
dynamic domain state?

> +	else {
> +		if (hvdom_prev && !hv_special_domain(hvdom_prev))
> +			WARN(1, "Failed to attach dev:%s\n", pci_name(pdev));
> +		dev_iommu_priv_set(dev, NULL);
> +	}
> +
> +	return rc;
> +}
[ ... ]
> +static int hv_iommu_map_pages(struct iommu_domain *immdom, ulong iova,
> +			      phys_addr_t paddr, size_t pgsize, size_t pgcount,
> +			      int prot, gfp_t gfp, size_t *mapped)
> +{
[ ... ]
> +		if (hv_result(status) == HV_STATUS_INSUFFICIENT_MEMORY) {
> +			ret = hv_call_deposit_pages(NUMA_NO_NODE,
> +						    hv_current_partition_id,
> +						    256);

[Severity: High]
Does this sequence sleep in atomic context? The IOMMU map_pages callback can
be invoked in atomic contexts (such as inside interrupt handlers) and is
passed a gfp_t argument. However, this ignores the gfp argument and calls
hv_call_deposit_pages(), which allocates pages using GFP_KERNEL.

[ ... ]
> +	if (!hv_result_success(status)) {
> +		size_t done_size = done << HV_HYP_PAGE_SHIFT;
> +
> +		hv_status_err(status, "pgs:%lx/%lx iova:%lx\n",
> +			      done, npages, iova);
> +		/*
> +		 * lookup tree has all mappings [0 - size-1]. Below unmap will
> +		 * only remove from [0 - done], we need to remove second chunk
> +		 * [done+1 - size-1].
> +		 */
> +		hv_iommu_del_tree_mappings(hvdom, iova, size - done_size);

[Severity: High]
Is the error cleanup path unmapping memory that was never mapped? If a
multi-page map fails halfway, it tries to unmap the unmapped portion, which
hits the break condition in hv_iommu_del_tree_mappings() discussed earlier.
This fails to remove the node and then erroneously issues a hypercall to
unmap the entire size.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260731223427.2554388-1-mrathor@linux.microsoft.com?part=7

  reply	other threads:[~2026-07-31 22:48 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-31 22:34 [PATCH v5 0/9] PCI passthru on Hyper-V Mukesh R
2026-07-31 22:34 ` [PATCH v5 1/9] mshv: Provide a way to get partition ID if running in a VMM process Mukesh R
2026-07-31 22:47   ` sashiko-bot
2026-07-31 22:34 ` [PATCH v5 2/9] mshv: Add declarations and definitions for VFIO-MSHV bridge device Mukesh R
2026-07-31 22:42   ` sashiko-bot
2026-07-31 22:34 ` [PATCH v5 3/9] mshv: Introduce basic mshv bridge device for VFIO to build upon Mukesh R
2026-07-31 22:49   ` sashiko-bot
2026-07-31 22:34 ` [PATCH v5 4/9] mshv: Add ioctl support for MSHV-VFIO bridge device Mukesh R
2026-07-31 22:49   ` sashiko-bot
2026-07-31 22:34 ` [PATCH v5 5/9] mshv: Import data structs around device passthru from hyperv headers Mukesh R
2026-07-31 22:45   ` sashiko-bot
2026-07-31 22:34 ` [PATCH v5 6/9] PCI: hv: Export hv_build_devid_type_pci() and change return type Mukesh R
2026-07-31 22:47   ` sashiko-bot
2026-07-31 22:34 ` [PATCH v5 7/9] x86/hyperv: Implement Hyper-V virtual IOMMU Mukesh R
2026-07-31 22:48   ` sashiko-bot [this message]
2026-07-31 22:34 ` [PATCH v5 8/9] mshv: Populate mmio mappings for PCI passthru Mukesh R
2026-07-31 22:54   ` sashiko-bot
2026-07-31 22:34 ` [PATCH v5 9/9] mshv: Disable movable regions upfront if device passthru Mukesh R
2026-07-31 22:57   ` sashiko-bot

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=20260731224846.BD5571F00AC4@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-hyperv@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=mrathor@linux.microsoft.com \
    --cc=sashiko-reviews@lists.linux.dev \
    /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