On Fri, Jul 03, 2026 at 12:05:18AM +0800, Yu Zhang wrote:
quoted hunk ↗ jump to hunk
@@ -401,10 +402,74 @@ static void hv_iommu_flush_iotlb_all(struct iommu_domain *domain)
hv_flush_device_domain(to_hv_iommu_domain(domain));
}
+/*
+ * Calculate the minimal power-of-two aligned range that covers [start, end]
+ * (end is inclusive). Returns a single (page_number, page_mask_shift)
+ * descriptor that may over-flush when the range is not naturally aligned.
+ */
+static void hv_iommu_calc_flush_range(unsigned long start, unsigned long end,
+ union hv_iommu_flush_va *va)
+{
+ unsigned long start_pfn = HVPFN_DOWN(start);
+ unsigned long last_pfn = HVPFN_UP(end + 1) - 1;
Pedantically end can be ULONG_MAX, you shouldn't be adding to it since
it will overflow.
+ unsigned long mask_shift, aligned_pfn;
+
+ if (start_pfn == last_pfn) {
+ mask_shift = 0;
+ } else {
+ /*
+ * Find the highest bit position where start_pfn and last_pfn
+ * differ. A range aligned to one above that bit is the
+ * smallest power-of-two region that covers both endpoints.
+ */
+ mask_shift = __fls(start_pfn ^ last_pfn) + 1;
+ }
+
+ aligned_pfn = ALIGN_DOWN(start_pfn, 1UL << mask_shift);
I think the whole thing is simpler if it stays using bytes until the end:
sz_lg2 = __fls(gather->start ^ gather->end);
if (sz_lg2 < HV_PAGE_SHIFT)
cmd.sz_lg2 = HV_PAGE_SHIFT;
page_number = (gather->start & ~(1UL << sz_lg2)) >> HV_PAGE_SHIFT;
page_mask_shift = sz_lg2 - HV_PAGE_SIFT;
No overflows that way either
Jason