/*- * BSD LICENSE * * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rte_ivshmem.h" #define IVSHMEM_CONFIG_FILE_FMT "/var/run/.dpdk_ivshmem_metadata_%s" #define IVSHMEM_QEMU_CMD_LINE_HEADER_FMT "-device ivshmem,size=%" PRIu64 "M,shm=fd%s" #define IVSHMEM_QEMU_CMD_FD_FMT ":%s:0x%" PRIx64 ":0x%" PRIx64 #define IVSHMEM_QEMU_CMDLINE_BUFSIZE 1024 #define IVSHMEM_MAX_PAGES (1 << 12) #define adjacent(x,y) (((x).phys_addr+(x).len)==(y).phys_addr) #define METADATA_SIZE_ALIGNED \ (RTE_ALIGN_CEIL(sizeof(struct rte_ivshmem_metadata),pagesz)) #define GET_PAGEMAP_ADDR(in,addr,dlm,err) \ { \ char *end; \ errno = 0; \ addr = strtoull((in), &end, 16); \ if (errno != 0 || *end != (dlm)) { \ RTE_LOG(ERR, EAL, err); \ goto error; \ } \ (in) = end + 1; \ } static int pagesz; struct memseg_cache_entry { char filepath[PATH_MAX]; uint64_t offset; uint64_t len; }; struct ivshmem_config { struct rte_ivshmem_metadata * metadata; struct memseg_cache_entry memseg_cache[IVSHMEM_MAX_PAGES]; /**< account for multiple files per segment case */ struct flock lock; rte_spinlock_t sl; }; static struct ivshmem_config ivshmem_global_config[RTE_LIBRTE_IVSHMEM_MAX_METADATA_FILES]; static rte_spinlock_t global_cfg_sl; static struct ivshmem_config * get_config_by_name(const char * name) { struct rte_ivshmem_metadata * config; unsigned i; for (i = 0; i < RTE_DIM(ivshmem_global_config); i++) { config = ivshmem_global_config[i].metadata; if (config == NULL) return NULL; if (strncmp(name, config->name, IVSHMEM_NAME_LEN) == 0) return &ivshmem_global_config[i]; } return NULL; } static int overlap(const struct rte_memzone * s1, const struct rte_memzone * s2) { uint64_t start1, end1, start2, end2; start1 = s1->addr_64; end1 = s1->addr_64 + s1->len; start2 = s2->addr_64; end2 = s2->addr_64 + s2->len; if (start1 >= start2 && start1 < end2) return 1; if (start2 >= start1 && start2 < end1) return 1; return 0; } static struct rte_memzone * get_memzone_by_addr(const void * addr) { struct rte_memzone * tmp, * mz; struct rte_mem_config * mcfg; int i; mcfg = rte_eal_get_configuration()->mem_config; mz = NULL; /* find memzone for the ring */ for (i = 0; i < RTE_MAX_MEMZONE; i++) { tmp = &mcfg->memzone[i]; if (tmp->addr_64 == (uint64_t) addr) { mz = tmp; break; } } return mz; } static int entry_compare(const void * a, const void * b) { const struct rte_ivshmem_metadata_entry * e1 = (const struct rte_ivshmem_metadata_entry*) a; const struct rte_ivshmem_metadata_entry * e2 = (const struct rte_ivshmem_metadata_entry*) b; /* move unallocated zones to the end */ if (e1->mz.addr == NULL && e2->mz.addr == NULL) return 0; if (e1->mz.addr == 0) return 1; if (e2->mz.addr == 0) return -1; return e1->mz.phys_addr > e2->mz.phys_addr; } /* fills hugepage cache entry for a given start virt_addr */ static int get_hugefile_by_virt_addr(uint64_t virt_addr, struct memseg_cache_entry * e) { uint64_t start_addr, end_addr; char *start,*path_end; char buf[PATH_MAX*2]; FILE *f; start = NULL; path_end = NULL; start_addr = 0; memset(e->filepath, 0, sizeof(e->filepath)); /* open /proc/self/maps */ f = fopen("/proc/self/maps", "r"); if (f == NULL) { RTE_LOG(ERR, EAL, "cannot open /proc/self/maps!\n"); return -1; } /* parse maps */ while (fgets(buf, sizeof(buf), f) != NULL) { /* get endptr to end of start addr */ start = buf; GET_PAGEMAP_ADDR(start,start_addr,'-', "Cannot find start address in maps!\n"); /* if start address is bigger than our address, skip */ if (start_addr > virt_addr) continue; GET_PAGEMAP_ADDR(start,end_addr,' ', "Cannot find end address in maps!\n"); /* if end address is less than our address, skip */ if (end_addr <= virt_addr) continue; /* find where the path starts */ start = strstr(start, "/"); if (start == NULL) continue; /* at this point, we know that this is our map. * now let's find the file */ path_end = strstr(start, "\n"); break; } if (path_end == NULL) { RTE_LOG(ERR, EAL, "Hugefile path not found!\n"); goto error; } /* calculate offset and copy the file path */ snprintf(e->filepath, RTE_PTR_DIFF(path_end, start) + 1, "%s", start); e->offset = virt_addr - start_addr; fclose(f); return 0; error: fclose(f); return -1; } /* * This is a complex function. What it does is the following: * 1. Goes through metadata and gets list of hugepages involved * 2. Sorts the hugepages by size (1G first) * 3. Goes through metadata again and writes correct offsets * 4. Goes through pages and finds out their filenames, offsets etc. */ static int build_config(struct rte_ivshmem_metadata * metadata) { struct rte_ivshmem_metadata_entry * e_local; struct memseg_cache_entry * ms_local; struct rte_memseg pages[IVSHMEM_MAX_PAGES]; struct rte_ivshmem_metadata_entry *entry; struct memseg_cache_entry * c_entry, * prev_entry; struct ivshmem_config * config; unsigned i, j, mz_iter, ms_iter; uint64_t biggest_len; int biggest_idx; /* return error if we try to use an unknown config file */ config = get_config_by_name(metadata->name); if (config == NULL) { RTE_LOG(ERR, EAL, "Cannot find IVSHMEM config %s!\n", metadata->name); goto fail_e; } memset(pages, 0, sizeof(pages)); e_local = malloc(sizeof(config->metadata->entry)); if (e_local == NULL) goto fail_e; ms_local = malloc(sizeof(config->memseg_cache)); if (ms_local == NULL) goto fail_ms; /* make local copies before doing anything */ memcpy(e_local, config->metadata->entry, sizeof(config->metadata->entry)); memcpy(ms_local, config->memseg_cache, sizeof(config->memseg_cache)); qsort(e_local, RTE_DIM(config->metadata->entry), sizeof(struct rte_ivshmem_metadata_entry), entry_compare); /* first pass - collect all huge pages */ for (mz_iter = 0; mz_iter < RTE_DIM(config->metadata->entry); mz_iter++) { entry = &e_local[mz_iter]; uint64_t start_addr = RTE_ALIGN_FLOOR(entry->mz.addr_64, entry->mz.hugepage_sz); uint64_t offset = entry->mz.addr_64 - start_addr; uint64_t len = RTE_ALIGN_CEIL(entry->mz.len + offset, entry->mz.hugepage_sz); if (entry->mz.addr_64 == 0 || start_addr == 0 || len == 0) continue; int start_page; /* find first unused page - mz are phys_addr sorted so we don't have to * look out for holes */ for (i = 0; i < RTE_DIM(pages); i++) { /* skip if we already have this page */ if (pages[i].addr_64 == start_addr) { start_addr += entry->mz.hugepage_sz; len -= entry->mz.hugepage_sz; continue; } /* we found a new page */ else if (pages[i].addr_64 == 0) { start_page = i; break; } } if (i == RTE_DIM(pages)) { RTE_LOG(ERR, EAL, "Cannot find unused page!\n"); goto fail; } /* populate however many pages the memzone has */ for (i = start_page; i < RTE_DIM(pages) && len != 0; i++) { pages[i].addr_64 = start_addr; pages[i].len = entry->mz.hugepage_sz; start_addr += entry->mz.hugepage_sz; len -= entry->mz.hugepage_sz; } /* if there's still length left */ if (len != 0) { RTE_LOG(ERR, EAL, "Not enough space for pages!\n"); goto fail; } } /* second pass - sort pages by size */ for (i = 0; i < RTE_DIM(pages); i++) { if (pages[i].addr == NULL) break; biggest_len = 0; biggest_idx = -1; /* * browse all entries starting at 'i', and find the * entry with the smallest addr */ for (j=i; j< RTE_DIM(pages); j++) { if (pages[j].addr == NULL) break; if (biggest_len == 0 || pages[j].len > biggest_len) { biggest_len = pages[j].len; biggest_idx = j; } } /* should not happen */ if (biggest_idx == -1) { RTE_LOG(ERR, EAL, "Error sorting by size!\n"); goto fail; } if (i != (unsigned) biggest_idx) { struct rte_memseg tmp; memcpy(&tmp, &pages[biggest_idx], sizeof(struct rte_memseg)); /* we don't want to break contiguousness, so instead of just * swapping segments, we move all the preceding segments to the * right and then put the old segment @ biggest_idx in place of * segment @ i */ for (j = biggest_idx - 1; j >= i; j--) { memcpy(&pages[j+1], &pages[j], sizeof(struct rte_memseg)); memset(&pages[j], 0, sizeof(struct rte_memseg)); if (j == 0) break; } /* put old biggest segment to its new place */ memcpy(&pages[i], &tmp, sizeof(struct rte_memseg)); } } /* third pass - write correct offsets */ for (mz_iter = 0; mz_iter < RTE_DIM(config->metadata->entry); mz_iter++) { uint64_t offset = 0; entry = &e_local[mz_iter]; if (entry->mz.addr_64 == 0) break; /* find page for current memzone */ for (i = 0; i < RTE_DIM(pages); i++) { /* we found our page */ if (entry->mz.addr_64 >= pages[i].addr_64 && entry->mz.addr_64 < pages[i].addr_64 + pages[i].len) { entry->offset = (entry->mz.addr_64 - pages[i].addr_64) + offset; break; } offset += pages[i].len; } if (i == RTE_DIM(pages)) { RTE_LOG(ERR, EAL, "Page not found!\n"); goto fail; } } ms_iter = 0; prev_entry = NULL; /* fourth pass - create proper memseg cache */ for (i = 0; i < RTE_DIM(pages) && ms_iter <= RTE_DIM(config->memseg_cache); i++) { if (pages[i].addr_64 == 0) break; if (ms_iter == RTE_DIM(pages)) { RTE_LOG(ERR, EAL, "The universe has collapsed!\n"); goto fail; } c_entry = &ms_local[ms_iter]; c_entry->len = pages[i].len; if (get_hugefile_by_virt_addr(pages[i].addr_64, c_entry) < 0) goto fail; /* if previous entry has the same filename and is contiguous, * clear current entry and increase previous entry's length */ if (prev_entry != NULL && strncmp(c_entry->filepath, prev_entry->filepath, sizeof(c_entry->filepath)) == 0 && prev_entry->offset + prev_entry->len == c_entry->offset) { prev_entry->len += pages[i].len; memset(c_entry, 0, sizeof(struct memseg_cache_entry)); } else { prev_entry = c_entry; ms_iter++; } } /* update current configuration with new valid data */ memcpy(config->metadata->entry, e_local, sizeof(config->metadata->entry)); memcpy(config->memseg_cache, ms_local, sizeof(config->memseg_cache)); free(ms_local); free(e_local); return 0; fail: free(ms_local); fail_ms: free(e_local); fail_e: return -1; } static int add_memzone_to_metadata(const struct rte_memzone * mz, struct ivshmem_config * config) { struct rte_ivshmem_metadata_entry * entry; unsigned i, idx; struct rte_mem_config *mcfg; if (mz->len == 0) { RTE_LOG(ERR, EAL, "Trying to add an empty memzone\n"); return -1; } rte_spinlock_lock(&config->sl); mcfg = rte_eal_get_configuration()->mem_config; /* it prevents the memzone being freed while we add it to the metadata */ rte_rwlock_write_lock(&mcfg->mlock); /* find free slot in this config */ for (i = 0; i < RTE_DIM(config->metadata->entry); i++) { entry = &config->metadata->entry[i]; if (&entry->mz.addr_64 != 0 && overlap(mz, &entry->mz)) { RTE_LOG(ERR, EAL, "Overlapping memzones!\n"); goto fail; } /* if addr is zero, the memzone is probably free */ if (entry->mz.addr_64 == 0) { RTE_LOG(DEBUG, EAL, "Adding memzone '%s' at %p to metadata %s\n", mz->name, mz->addr, config->metadata->name); memcpy(&entry->mz, mz, sizeof(struct rte_memzone)); /* run config file parser */ if (build_config(config->metadata) < 0) goto fail; break; } } /* if we reached the maximum, that means we have no place in config */ if (i == RTE_DIM(config->metadata->entry)) { RTE_LOG(ERR, EAL, "No space left in IVSHMEM metadata %s!\n", config->metadata->name); goto fail; } idx = ((uintptr_t)mz - (uintptr_t)mcfg->memzone); idx = idx / sizeof(struct rte_memzone); /* mark the memzone not freeable */ mcfg->memzone[idx].ioremap_addr = mz->phys_addr; rte_rwlock_write_unlock(&mcfg->mlock); rte_spinlock_unlock(&config->sl); return 0; fail: rte_rwlock_write_unlock(&mcfg->mlock); rte_spinlock_unlock(&config->sl); return -1; } static int add_ring_to_metadata(const struct rte_ring * r, struct ivshmem_config * config) { struct rte_memzone * mz; mz = get_memzone_by_addr(r); if (!mz) { RTE_LOG(ERR, EAL, "Cannot find memzone for ring!\n"); return -1; } return add_memzone_to_metadata(mz, config); } static int add_mempool_memzone_to_metadata(const void *addr, struct ivshmem_config *config) { struct rte_memzone *mz; mz = get_memzone_by_addr(addr); if (!mz) { RTE_LOG(ERR, EAL, "Cannot find memzone for mempool!\n"); return -1; } return add_memzone_to_metadata(mz, config); } static int add_mempool_to_metadata(const struct rte_mempool *mp, struct ivshmem_config *config) { struct rte_mempool_memhdr *memhdr; int ret; ret = add_mempool_memzone_to_metadata(mp, config); if (ret < 0) return -1; STAILQ_FOREACH(memhdr, &mp->mem_list, next) { ret = add_mempool_memzone_to_metadata(memhdr->addr, config); if (ret < 0) return -1; } /* mempool consists of memzone and ring */ return add_ring_to_metadata(mp->pool_data, config); } int rte_ivshmem_metadata_add_ring(const struct rte_ring * r, const char * name) { struct ivshmem_config * config; if (name == NULL || r == NULL) return -1; config = get_config_by_name(name); if (config == NULL) { RTE_LOG(ERR, EAL, "Cannot find IVSHMEM config %s!\n", name); return -1; } return add_ring_to_metadata(r, config); } int rte_ivshmem_metadata_add_memzone(const struct rte_memzone * mz, const char * name) { struct ivshmem_config * config; if (name == NULL || mz == NULL) return -1; config = get_config_by_name(name); if (config == NULL) { RTE_LOG(ERR, EAL, "Cannot find IVSHMEM config %s!\n", name); return -1; } return add_memzone_to_metadata(mz, config); } int rte_ivshmem_metadata_add_mempool(const struct rte_mempool * mp, const char * name) { struct ivshmem_config * config; if (name == NULL || mp == NULL) return -1; config = get_config_by_name(name); if (config == NULL) { RTE_LOG(ERR, EAL, "Cannot find IVSHMEM config %s!\n", name); return -1; } return add_mempool_to_metadata(mp, config); } static inline void ivshmem_config_path(char *buffer, size_t bufflen, const char *name) { snprintf(buffer, bufflen, IVSHMEM_CONFIG_FILE_FMT, name); } static inline void *ivshmem_metadata_create(const char *name, size_t size, struct flock *lock) { int retval, fd; void *metadata_addr; char pathname[PATH_MAX]; ivshmem_config_path(pathname, sizeof(pathname), name); fd = open(pathname, O_RDWR | O_CREAT, 0660); if (fd < 0) { RTE_LOG(ERR, EAL, "Cannot open '%s'\n", pathname); return NULL; } size = METADATA_SIZE_ALIGNED; retval = fcntl(fd, F_SETLK, lock); if (retval < 0){ close(fd); RTE_LOG(ERR, EAL, "Cannot create lock on '%s'. Is another " "process using it?\n", pathname); return NULL; } retval = ftruncate(fd, size); if (retval < 0){ close(fd); RTE_LOG(ERR, EAL, "Cannot resize '%s'\n", pathname); return NULL; } metadata_addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (metadata_addr == MAP_FAILED){ RTE_LOG(ERR, EAL, "Cannot mmap memory for '%s'\n", pathname); /* we don't care if we can't unlock */ fcntl(fd, F_UNLCK, lock); close(fd); return NULL; } return metadata_addr; } int rte_ivshmem_metadata_create(const char *name) { struct ivshmem_config * ivshmem_config; unsigned index; if (pagesz == 0) pagesz = getpagesize(); if (name == NULL) return -1; rte_spinlock_lock(&global_cfg_sl); for (index = 0; index < RTE_DIM(ivshmem_global_config); index++) { if (ivshmem_global_config[index].metadata == NULL) { ivshmem_config = &ivshmem_global_config[index]; break; } } if (index == RTE_DIM(ivshmem_global_config)) { RTE_LOG(ERR, EAL, "Cannot create more ivshmem config files. " "Maximum has been reached\n"); rte_spinlock_unlock(&global_cfg_sl); return -1; } ivshmem_config->lock.l_type = F_WRLCK; ivshmem_config->lock.l_whence = SEEK_SET; ivshmem_config->lock.l_start = 0; ivshmem_config->lock.l_len = METADATA_SIZE_ALIGNED; ivshmem_global_config[index].metadata = ((struct rte_ivshmem_metadata *) ivshmem_metadata_create( name, sizeof(struct rte_ivshmem_metadata), &ivshmem_config->lock)); if (ivshmem_global_config[index].metadata == NULL) { rte_spinlock_unlock(&global_cfg_sl); return -1; } /* Metadata setup */ memset(ivshmem_config->metadata, 0, sizeof(struct rte_ivshmem_metadata)); ivshmem_config->metadata->magic_number = IVSHMEM_MAGIC; snprintf(ivshmem_config->metadata->name, sizeof(ivshmem_config->metadata->name), "%s", name); rte_spinlock_unlock(&global_cfg_sl); return 0; } int rte_ivshmem_metadata_cmdline_generate(char *buffer, unsigned size, const char *name) { const struct memseg_cache_entry * ms_cache, *entry; struct ivshmem_config * config; char cmdline[IVSHMEM_QEMU_CMDLINE_BUFSIZE], *cmdline_ptr; char cfg_file_path[PATH_MAX]; unsigned remaining_len, tmplen, iter; uint64_t shared_mem_size, zero_size, total_size; if (buffer == NULL || name == NULL) return -1; config = get_config_by_name(name); if (config == NULL) { RTE_LOG(ERR, EAL, "Config %s not found!\n", name); return -1; } rte_spinlock_lock(&config->sl); /* prepare metadata file path */ snprintf(cfg_file_path, sizeof(cfg_file_path), IVSHMEM_CONFIG_FILE_FMT, config->metadata->name); ms_cache = config->memseg_cache; cmdline_ptr = cmdline; remaining_len = sizeof(cmdline); shared_mem_size = 0; iter = 0; while ((ms_cache[iter].len != 0) && (iter < RTE_DIM(config->metadata->entry))) { entry = &ms_cache[iter]; /* Offset and sizes within the current pathname */ tmplen = snprintf(cmdline_ptr, remaining_len, IVSHMEM_QEMU_CMD_FD_FMT, entry->filepath, entry->offset, entry->len); shared_mem_size += entry->len; cmdline_ptr = RTE_PTR_ADD(cmdline_ptr, tmplen); remaining_len -= tmplen; if (remaining_len == 0) { RTE_LOG(ERR, EAL, "Command line too long!\n"); rte_spinlock_unlock(&config->sl); return -1; } iter++; } total_size = rte_align64pow2(shared_mem_size + METADATA_SIZE_ALIGNED); zero_size = total_size - shared_mem_size - METADATA_SIZE_ALIGNED; /* add /dev/zero to command-line to fill the space */ tmplen = snprintf(cmdline_ptr, remaining_len, IVSHMEM_QEMU_CMD_FD_FMT, "/dev/zero", (uint64_t)0x0, zero_size); cmdline_ptr = RTE_PTR_ADD(cmdline_ptr, tmplen); remaining_len -= tmplen; if (remaining_len == 0) { RTE_LOG(ERR, EAL, "Command line too long!\n"); rte_spinlock_unlock(&config->sl); return -1; } /* add metadata file to the end of command-line */ tmplen = snprintf(cmdline_ptr, remaining_len, IVSHMEM_QEMU_CMD_FD_FMT, cfg_file_path, (uint64_t)0x0, METADATA_SIZE_ALIGNED); cmdline_ptr = RTE_PTR_ADD(cmdline_ptr, tmplen); remaining_len -= tmplen; if (remaining_len == 0) { RTE_LOG(ERR, EAL, "Command line too long!\n"); rte_spinlock_unlock(&config->sl); return -1; } /* if current length of the command line is bigger than the buffer supplied * by the user, or if command-line is bigger than what IVSHMEM accepts */ if ((sizeof(cmdline) - remaining_len) > size) { RTE_LOG(ERR, EAL, "Buffer is too short!\n"); rte_spinlock_unlock(&config->sl); return -1; } /* complete the command-line */ snprintf(buffer, size, IVSHMEM_QEMU_CMD_LINE_HEADER_FMT, total_size >> 20, cmdline); rte_spinlock_unlock(&config->sl); return 0; } void rte_ivshmem_metadata_dump(FILE *f, const char *name) { unsigned i = 0; struct ivshmem_config * config; struct rte_ivshmem_metadata_entry *entry; #ifdef RTE_LIBRTE_IVSHMEM_DEBUG uint64_t addr; uint64_t end, hugepage_sz; struct memseg_cache_entry e; #endif if (name == NULL) return; /* return error if we try to use an unknown config file */ config = get_config_by_name(name); if (config == NULL) { RTE_LOG(ERR, EAL, "Cannot find IVSHMEM config %s!\n", name); return; } rte_spinlock_lock(&config->sl); entry = &config->metadata->entry[0]; while (entry->mz.addr != NULL && i < RTE_DIM(config->metadata->entry)) { fprintf(f, "Entry %u: name:<%-20s>, phys:0x%-15lx, len:0x%-15lx, " "virt:%-15p, off:0x%-15lx\n", i, entry->mz.name, entry->mz.phys_addr, entry->mz.len, entry->mz.addr, entry->offset); i++; #ifdef RTE_LIBRTE_IVSHMEM_DEBUG fprintf(f, "\tHugepage files:\n"); hugepage_sz = entry->mz.hugepage_sz; addr = RTE_ALIGN_FLOOR(entry->mz.addr_64, hugepage_sz); end = addr + RTE_ALIGN_CEIL(entry->mz.len + (entry->mz.addr_64 - addr), hugepage_sz); for (; addr < end; addr += hugepage_sz) { memset(&e, 0, sizeof(e)); get_hugefile_by_virt_addr(addr, &e); fprintf(f, "\t0x%"PRIx64 "-0x%" PRIx64 " offset: 0x%" PRIx64 " %s\n", addr, addr + hugepage_sz, e.offset, e.filepath); } #endif entry++; } rte_spinlock_unlock(&config->sl); }