最近在跑 vpp 单元测试时,发现某测试用例报 mmap(): Invalid argument 的错误,经过定位发现是在下面这个函数中调用 mmap() 时报错了:
clib_error_t *
clib_mem_vm_ext_map (clib_mem_vm_map_t * a)
{
int mmap_flags = MAP_SHARED;
void *addr;
if (a->requested_va)
mmap_flags |= MAP_FIXED;
addr = (void *) mmap (uword_to_pointer (a->requested_va, void *), a->size,
PROT_READ | PROT_WRITE, mmap_flags, a->fd, 0);
if (addr == MAP_FAILED)
return clib_error_return_unix (0, "mmap");
a->addr = addr;
return 0;
}
打印了出错现场 mmap() 的入参,如下所示:
a->requested_va = 0x22428a000;
a->size = 2236416;
a->fd = 8;
上面的报错说:参数无效。大眼一看,并没有发现上述参数的取值有什么异常,仔细读了 mmap() 的帮助手册,发现和对齐有关:
MAP_FIXED
Don't interpret addr as a hint: place the mapping at exactly that address. addr must be suitably aligned: for most architectures a multiple of the page size is sufficient; however, some architectures may impose addi-tional restrictions. If the memory region specified by addr and len overlaps pages of any existing mapping(s), then the overlapped part of the existing mapping(s) will be discarded. If the specified address cannot be used, mmap() will fail. Software that aspires to be portable should use this option with care, keeping in mind that the exact layout of a process's memory mappings is allowed to change significantly between kernel versions, C library versions, and operating system releases.
上述测试用例传入 mmap() 的 flag 为 MAP_FIXED | MAP_SHARED,此时需要传入的 addr 是以页大小为对齐的,同时我机器页大小是 16K,而传入的 addr 为 0x22428a000,对 16384 取余为 8192,不是以页大小对齐的,所以报错,解决方法就是让 a->requested_va = (a->requested_va + page_size - 1) & ~(page_size - 1)。