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

Reply via email to