update Intel copyright years to 2014
[dpdk.git] / lib / librte_eal / linuxapp / eal / eal_memory.c
index 7357a12..4bd8987 100644 (file)
@@ -1,35 +1,64 @@
 /*-
  *   BSD LICENSE
  * 
- *   Copyright(c) 2010-2012 Intel Corporation. All rights reserved.
+ *   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 
+ *   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 
+ *     * 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 
+ *     * 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 
+ *     * 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 
+ *   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.
+ */
+/*   BSD LICENSE
+ *
+ *   Copyright(c) 2013 6WIND.
+ *
+ *   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 6WIND S.A. 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 <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/queue.h>
-#include <fcntl.h>
+#include <sys/file.h>
 #include <unistd.h>
 #include <limits.h>
 #include <errno.h>
 #include <sys/ioctl.h>
+#include <sys/time.h>
 
 #include <rte_log.h>
 #include <rte_memory.h>
@@ -56,6 +86,7 @@
 #include <rte_launch.h>
 #include <rte_tailq.h>
 #include <rte_eal.h>
+#include <rte_eal_memconfig.h>
 #include <rte_per_lcore.h>
 #include <rte_lcore.h>
 #include <rte_common.h>
@@ -119,13 +150,13 @@ aslr_enabled(void)
  * which is a multiple of hugepage size.
  */
 static void *
-get_virtual_area(uint64_t *size, uint64_t hugepage_sz)
+get_virtual_area(size_t *size, size_t hugepage_sz)
 {
        void *addr;
        int fd;
        long aligned_addr;
 
-       RTE_LOG(INFO, EAL, "Ask a virtual area of 0x%"PRIx64" bytes\n", *size);
+       RTE_LOG(INFO, EAL, "Ask a virtual area of 0x%zu bytes\n", *size);
 
        fd = open("/dev/zero", O_RDONLY);
        if (fd < 0){
@@ -153,7 +184,7 @@ get_virtual_area(uint64_t *size, uint64_t hugepage_sz)
        aligned_addr &= (~(hugepage_sz - 1));
        addr = (void *)(aligned_addr);
 
-       RTE_LOG(INFO, EAL, "Virtual area found at %p (size = 0x%"PRIx64")\n",
+       RTE_LOG(INFO, EAL, "Virtual area found at %p (size = 0x%zx)\n",
                addr, *size);
 
        return addr;
@@ -174,10 +205,10 @@ map_all_hugepages(struct hugepage *hugepg_tbl,
        unsigned i;
        void *virtaddr;
        void *vma_addr = NULL;
-       uint64_t vma_len = 0;
+       size_t vma_len = 0;
 
        for (i = 0; i < hpi->num_pages[0]; i++) {
-               uint64_t hugepage_sz = hpi->hugepage_sz;
+               size_t hugepage_sz = hpi->hugepage_sz;
 
                if (orig) {
                        hugepg_tbl[i].file_id = i;
@@ -219,6 +250,7 @@ map_all_hugepages(struct hugepage *hugepg_tbl,
                                vma_len = hugepage_sz;
                }
 
+               /* try to create hugepage file */
                fd = open(hugepg_tbl[i].filepath, O_CREAT | O_RDWR, 0755);
                if (fd < 0) {
                        RTE_LOG(ERR, EAL, "%s(): open failed: %s\n", __func__,
@@ -243,9 +275,18 @@ map_all_hugepages(struct hugepage *hugepg_tbl,
                        hugepg_tbl[i].final_va = virtaddr;
                }
 
+               /* set shared flock on the file. */
+               if (flock(fd, LOCK_SH | LOCK_NB) == -1) {
+                       RTE_LOG(ERR, EAL, "%s(): Locking file failed:%s \n",
+                               __func__, strerror(errno));
+                       close(fd);
+                       return -1;
+               }
+
+               close(fd);
+
                vma_addr = (char *)vma_addr + hugepage_sz;
                vma_len -= hugepage_sz;
-               close(fd);
        }
        return 0;
 }
@@ -292,7 +333,7 @@ find_physaddr(struct hugepage *hugepg_tbl, struct hugepage_info *hpi)
                virt_pfn = (unsigned long)hugepg_tbl[i].orig_va /
                        page_size;
                offset = sizeof(uint64_t) * virt_pfn;
-               if (lseek(fd, offset, SEEK_SET) != offset){
+               if (lseek(fd, offset, SEEK_SET) == (off_t) -1) {
                        RTE_LOG(ERR, EAL, "%s(): seek error in /proc/self/pagemap: %s\n",
                                        __func__, strerror(errno));
                        close(fd);
@@ -495,7 +536,6 @@ unmap_unneeded_hugepages(struct hugepage *hugepg_tbl,
 {
        unsigned socket, size;
        int page, nrpages = 0;
-       int fd;
 
        /* get total number of hugepages */
        for (size = 0; size < num_hp_info; size++)
@@ -517,10 +557,16 @@ unmap_unneeded_hugepages(struct hugepage *hugepg_tbl,
                                        if (pages_found == hpi[size].num_pages[socket]) {
                                                munmap(hp->final_va, hp->size);
                                                hp->final_va = NULL;
+                                               if (remove(hp->filepath) == -1) {
+                                                       RTE_LOG(ERR, EAL, "%s(): Removing %s failed: %s\n",
+                                                                       __func__, hp->filepath, strerror(errno));
+                                                       return -1;
+                                               }
                                        }
-                                       else {
+                                       /* lock the page and skip */
+                                       else
                                                pages_found++;
-                                       }
+
                                } /* match page */
                        } /* foreach page */
                } /* foreach socket */
@@ -873,6 +919,18 @@ rte_eal_hugepage_init(void)
                hugepage[i].memseg_id = j;
        }
 
+       if (i < nrpages) {
+               RTE_LOG(ERR, EAL, "Can only reserve %d pages "
+                       "from %d requested\n"
+                       "Current %s=%d is not enough\n"
+                       "Please either increase it or request less amount "
+                       "of memory.\n",
+                       i, nrpages, RTE_STR(CONFIG_RTE_MAX_MEMSEG),
+                       RTE_MAX_MEMSEG);
+               return (-ENOMEM);
+       }
+       
+
        return 0;
 
 
@@ -928,6 +986,40 @@ rte_eal_hugepage_attach(void)
                goto error;
        }
 
+       /* map all segments into memory to make sure we get the addrs */
+       for (s = 0; s < RTE_MAX_MEMSEG; ++s) {
+               void *base_addr;
+
+               /*
+                * the first memory segment with len==0 is the one that
+                * follows the last valid segment.
+                */
+               if (mcfg->memseg[s].len == 0)
+                       break;
+
+               /*
+                * fdzero is mmapped to get a contiguous block of virtual
+                * addresses of the appropriate memseg size.
+                * use mmap to get identical addresses as the primary process.
+                */
+               base_addr = mmap(mcfg->memseg[s].addr, mcfg->memseg[s].len,
+                                PROT_READ, MAP_PRIVATE, fd_zero, 0);
+               if (base_addr == MAP_FAILED ||
+                   base_addr != mcfg->memseg[s].addr) {
+                       RTE_LOG(ERR, EAL, "Could not mmap %llu bytes "
+                               "in /dev/zero to requested address [%p]\n",
+                               (unsigned long long)mcfg->memseg[s].len,
+                               mcfg->memseg[s].addr);
+                       if (aslr_enabled() > 0) {
+                               RTE_LOG(ERR, EAL, "It is recommended to "
+                                       "disable ASLR in the kernel "
+                                       "and retry running both primary "
+                                       "and secondary processes\n");
+                       }
+                       goto error;
+               }
+       }
+
        size = getFileSize(fd_hugepage);
        hp = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd_hugepage, 0);
        if (hp == NULL) {
@@ -938,27 +1030,16 @@ rte_eal_hugepage_attach(void)
        num_hp = size / sizeof(struct hugepage);
        RTE_LOG(DEBUG, EAL, "Analysing %u hugepages\n", num_hp);
 
+       s = 0;
        while (s < RTE_MAX_MEMSEG && mcfg->memseg[s].len > 0){
                void *addr, *base_addr;
                uintptr_t offset = 0;
 
-               /* fdzero is mmapped to get a contiguous block of virtual addresses
-                * get a block of free memory of the appropriate size -
-                * use mmap to attempt to get an identical address as server.
+               /*
+                * free previously mapped memory so we can map the
+                * hugepages into the space
                 */
-               base_addr = mmap(mcfg->memseg[s].addr, mcfg->memseg[s].len,
-                               PROT_READ, MAP_PRIVATE, fd_zero, 0);
-               if (base_addr == MAP_FAILED || base_addr != mcfg->memseg[s].addr) {
-                       RTE_LOG(ERR, EAL, "Could not mmap %llu bytes "
-                               "in /dev/zero to requested address [%p]\n",
-                               (unsigned long long)mcfg->memseg[s].len,
-                               mcfg->memseg[s].addr);
-                       if (aslr_enabled() > 0)
-                               RTE_LOG(ERR, EAL, "It is recommended to disable ASLR in the kernel "
-                                               "and retry running both primary and secondary processes\n");
-                       goto error;
-               }
-               /* free memory so we can map the hugepages into the space */
+               base_addr = mcfg->memseg[s].addr;
                munmap(base_addr, mcfg->memseg[s].len);
 
                /* find the hugepages for this segment and map them
@@ -988,6 +1069,8 @@ rte_eal_hugepage_attach(void)
                                (unsigned long long)mcfg->memseg[s].len);
                s++;
        }
+       /* unmap the hugepage config file, since we are done using it */
+       munmap((void *)(uintptr_t)hp, size);
        close(fd_zero);
        close(fd_hugepage);
        return 0;