Presently on PPC64 which uses a 64K page-size, ndtl-check command fails on a BTT device with following error:
$sudo ndctl check-namespace namespace0.0 -vv namespace0.0: namespace_check: checking namespace0.0 namespace0.0: btt_discover_arenas: found 1 BTT arena namespace0.0: btt_create_mappings: mmap arena[0].info [sz = 0x1000, off = 0x1000] failed: Invalid argument error checking namespaces: Invalid argument checked 0 namespaces Error happens when btt_create_mappings() tries to mmap the sections of the BTT device which are usually 4K offset aligned. However the mmap() syscall expects the 'offset' argument to be in multiples of page-size, hence it returns EINVAL causing the btt_create_mappings() to error out. As a fix for the issue this patch proposes addition of two new functions to 'check.c' namely btt_mmap/btt_unmap that can be used to map/unmap parts of BTT device to ndctl process address-space. The functions tweaks the requested 'offset' argument to mmap() ensuring that its page-size aligned and then fix-ups the returned pointer such that it points to the requested offset within m-mapped region. Reported-by: [email protected] Signed-off-by: Vaibhav Jain <[email protected]> --- ndctl/check.c | 71 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 15 deletions(-) diff --git a/ndctl/check.c b/ndctl/check.c index 8a7125053865..18d259048616 100644 --- a/ndctl/check.c +++ b/ndctl/check.c @@ -907,6 +907,47 @@ static int btt_discover_arenas(struct btt_chk *bttc) return ret; } +/* Mmap requested btt region so it works with non 4-K page sizes */ +static void *btt_mmap(struct btt_chk *bttc, void *addr, size_t length, + int prot, int flags, off_t offset) +{ + off_t shift; + + /* Calculate the shift back needed to make offset page aligned */ + shift = offset - rounddown(offset, bttc->sys_page_size); + + /* Update the offset and length with the shift calculated above */ + offset -= shift; + length += shift; + + addr = mmap(addr, length, prot, flags, bttc->fd, offset); + + /* If needed fixup the return pointer to correct offset request */ + if (addr != MAP_FAILED) + addr = (void *) ((uintptr_t)addr + shift); + + dbg(bttc, "mmap: addr=%p length=0x%lx offset=0x%lx shift=0x%lx\n", + addr, length, offset, shift); + + return addr; +} + +static void btt_unmap(struct btt_chk *bttc, void *ptr, size_t length) +{ + uintptr_t addr = ptr; + off_t shift; + + /* Calculate the shift back needed to make offset page aligned */ + shift = addr - rounddown(addr, bttc->sys_page_size); + + addr -= shift; + length += shift; + + munmap((void *)addr, length); + dbg(bttc, "unmap: addr=%p length=0x%lx shift=0x%lx\n", + addr, length, shift); +} + static int btt_create_mappings(struct btt_chk *bttc) { struct arena_info *a; @@ -921,8 +962,8 @@ static int btt_create_mappings(struct btt_chk *bttc) for (i = 0; i < bttc->num_arenas; i++) { a = &bttc->arena[i]; a->map.info_len = BTT_INFO_SIZE; - a->map.info = mmap(NULL, a->map.info_len, mmap_flags, - MAP_SHARED, bttc->fd, a->infooff); + a->map.info = btt_mmap(bttc, NULL, a->map.info_len, mmap_flags, + MAP_SHARED, a->infooff); if (a->map.info == MAP_FAILED) { err(bttc, "mmap arena[%d].info [sz = %#lx, off = %#lx] failed: %s\n", i, a->map.info_len, a->infooff, strerror(errno)); @@ -930,8 +971,8 @@ static int btt_create_mappings(struct btt_chk *bttc) } a->map.data_len = a->mapoff - a->dataoff; - a->map.data = mmap(NULL, a->map.data_len, mmap_flags, - MAP_SHARED, bttc->fd, a->dataoff); + a->map.data = btt_mmap(bttc, NULL, a->map.data_len, mmap_flags, + MAP_SHARED, a->dataoff); if (a->map.data == MAP_FAILED) { err(bttc, "mmap arena[%d].data [sz = %#lx, off = %#lx] failed: %s\n", i, a->map.data_len, a->dataoff, strerror(errno)); @@ -939,8 +980,8 @@ static int btt_create_mappings(struct btt_chk *bttc) } a->map.map_len = a->logoff - a->mapoff; - a->map.map = mmap(NULL, a->map.map_len, mmap_flags, - MAP_SHARED, bttc->fd, a->mapoff); + a->map.map = btt_mmap(bttc, NULL, a->map.map_len, mmap_flags, + MAP_SHARED, a->mapoff); if (a->map.map == MAP_FAILED) { err(bttc, "mmap arena[%d].map [sz = %#lx, off = %#lx] failed: %s\n", i, a->map.map_len, a->mapoff, strerror(errno)); @@ -948,8 +989,8 @@ static int btt_create_mappings(struct btt_chk *bttc) } a->map.log_len = a->info2off - a->logoff; - a->map.log = mmap(NULL, a->map.log_len, mmap_flags, - MAP_SHARED, bttc->fd, a->logoff); + a->map.log = btt_mmap(bttc, NULL, a->map.log_len, mmap_flags, + MAP_SHARED, a->logoff); if (a->map.log == MAP_FAILED) { err(bttc, "mmap arena[%d].log [sz = %#lx, off = %#lx] failed: %s\n", i, a->map.log_len, a->logoff, strerror(errno)); @@ -957,8 +998,8 @@ static int btt_create_mappings(struct btt_chk *bttc) } a->map.info2_len = BTT_INFO_SIZE; - a->map.info2 = mmap(NULL, a->map.info2_len, mmap_flags, - MAP_SHARED, bttc->fd, a->info2off); + a->map.info2 = btt_mmap(bttc, NULL, a->map.info2_len, + mmap_flags, MAP_SHARED, a->info2off); if (a->map.info2 == MAP_FAILED) { err(bttc, "mmap arena[%d].info2 [sz = %#lx, off = %#lx] failed: %s\n", i, a->map.info2_len, a->info2off, strerror(errno)); @@ -977,15 +1018,15 @@ static void btt_remove_mappings(struct btt_chk *bttc) for (i = 0; i < bttc->num_arenas; i++) { a = &bttc->arena[i]; if (a->map.info) - munmap(a->map.info, a->map.info_len); + btt_unmap(bttc, a->map.info, a->map.info_len); if (a->map.data) - munmap(a->map.data, a->map.data_len); + btt_unmap(bttc, a->map.data, a->map.data_len); if (a->map.map) - munmap(a->map.map, a->map.map_len); + btt_unmap(bttc, a->map.map, a->map.map_len); if (a->map.log) - munmap(a->map.log, a->map.log_len); + btt_unmap(bttc, a->map.log, a->map.log_len); if (a->map.info2) - munmap(a->map.info2, a->map.info2_len); + btt_unmap(bttc, a->map.info2, a->map.info2_len); } } -- 2.21.0 _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
