On Wed, Sep 2, 2020 at 1:20 AM Nicolin Chen <nicoleotsuka@xxxxxxxxx> wrote: > > We found that callers of dma_get_seg_boundary mostly do an ALIGN > with page mask and then do a page shift to get number of pages: > ALIGN(boundary + 1, 1 << shift) >> shift > > However, the boundary might be as large as ULONG_MAX, which means > that a device has no specific boundary limit. So either "+ 1" or > passing it to ALIGN() would potentially overflow. > > According to kernel defines: > #define ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) > #define ALIGN(x, a) ALIGN_MASK(x, (typeof(x))(a) - 1) > > We can simplify the logic here into a helper function doing: > ALIGN(boundary + 1, 1 << shift) >> shift > = ALIGN_MASK(b + 1, (1 << s) - 1) >> s > = {[b + 1 + (1 << s) - 1] & ~[(1 << s) - 1]} >> s > = [b + 1 + (1 << s) - 1] >> s > = [b + (1 << s)] >> s > = (b >> s) + 1 > > This patch introduces and applies dma_get_seg_boundary_nr_pages() > as an overflow-free helper for the dma_get_seg_boundary() callers > to get numbers of pages. It also takes care of the NULL dev case > for non-DMA API callers. ... > +static inline unsigned long dma_get_seg_boundary_nr_pages(struct device *dev, > + unsigned int page_shift) > +{ > + if (!dev) > + return (U32_MAX >> page_shift) + 1; > + return (dma_get_seg_boundary(dev) >> page_shift) + 1; Can it be better to do something like unsigned long boundary = dev ? dma_get_seg_boundary(dev) : U32_MAX; return (boundary >> page_shift) + 1; ? > +} -- With Best Regards, Andy Shevchenko