On Fri, Jul 03, 2026 at 02:10:18PM -0300, Jason Gunthorpe wrote:
> On Fri, Jul 03, 2026 at 12:05:18AM +0800, Yu Zhang wrote:
>
> > @@ -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.
>
Good catch!
> > + 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
>
Indeed. It is much cleaner. Will rewrite using this logic.
B.R.
Yu
> Jason
>