On Thu, Dec 1, 2016 at 2:29 PM, Dan Williams <dan.j.williams@xxxxxxxxx> wrote: > devm_memremap_pages() records mapped ranges in pgmap_radix with a entry > per section's worth of memory (128MB). The key for each of those entries is > a section number. > > This leads to false positives when devm_memremap_pages() is passed a > section-unaligned range as lookups in the misalignment fail to return > NULL. We can close this hole by using the unmodified physical address as > the key for entries in the tree. The number of entries required to > describe a remapped range is reduced by leveraging multi-order entries. > > In practice this approach usually yields just one entry in the tree if > the size and starting address is power-of-2 aligned. Previously we > needed mapping_size / 128MB entries. > > Link: https://lists.01.org/pipermail/linux-nvdimm/2016-August/006666.html > Reported-by: Toshi Kani <toshi.kani@xxxxxxx> > Cc: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> > Signed-off-by: Dan Williams <dan.j.williams@xxxxxxxxx> > --- > kernel/memremap.c | 53 +++++++++++++++++++++++++++++++++++++++-------------- > mm/Kconfig | 1 + > 2 files changed, 40 insertions(+), 14 deletions(-) > > diff --git a/kernel/memremap.c b/kernel/memremap.c > index b501e390bb34..10becd7855ca 100644 > --- a/kernel/memremap.c > +++ b/kernel/memremap.c > @@ -194,18 +194,39 @@ void put_zone_device_page(struct page *page) > } > EXPORT_SYMBOL(put_zone_device_page); > > -static void pgmap_radix_release(struct resource *res) > +static unsigned order_at(struct resource *res, unsigned long offset) > { > - resource_size_t key, align_start, align_size, align_end; > + unsigned long phys_offset = res->start + offset; > + resource_size_t size = resource_size(res); > + unsigned order_max, order_offset; > > - align_start = res->start & ~(SECTION_SIZE - 1); > - align_size = ALIGN(resource_size(res), SECTION_SIZE); > - align_end = align_start + align_size - 1; > + if (size == offset) > + return UINT_MAX; > + > + /* > + * What is the largest power-of-2 range available from this > + * resource offset to the end of the resource range, considering > + * the alignment of the current offset? > + */ > + order_offset = ilog2(size | phys_offset); > + order_max = ilog2(size - offset); > + return min(order_max, order_offset); > +} > + > +#define foreach_order_offset(res, order, offset) \ > + for (offset = 0, order = order_at((res), offset); order < UINT_MAX; \ > + offset += 1UL << order, order = order_at((res), offset)) The radix tree expects 'order' to be in PAGE_SIZE units, so I need to respin this patch to account for PAGE_SHIFT. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@xxxxxxxxx. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@xxxxxxxxx"> email@xxxxxxxxx </a>