update copyright date to 2013
[dpdk.git] / lib / librte_eal / linuxapp / eal / eal_memory.c
index 7357a12..fcc7db3 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  * 
- *   Copyright(c) 2010-2012 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2013 Intel Corporation. All rights reserved.
  *   All rights reserved.
  * 
  *   Redistribution and use in source and binary forms, with or without 
  *   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 <stdarg.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 <sys/resource.h>
 
 #include <rte_log.h>
 #include <rte_memory.h>
@@ -56,6 +88,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>
@@ -111,6 +144,44 @@ aslr_enabled(void)
        }
 }
 
+/*
+ * Increase limit for open files for current process
+ */
+static int
+increase_open_file_limit(void)
+{
+       struct rlimit limit;
+
+       /* read current limits */
+       if (getrlimit(RLIMIT_NOFILE, &limit) != 0) {
+               RTE_LOG(ERR, EAL, "Error reading resource limit: %s\n",
+                               strerror(errno));
+               return -1;
+       }
+
+       /* check if current soft limit matches the hard limit */
+       if (limit.rlim_cur < limit.rlim_max) {
+               /* set soft limit to match hard limit */
+               limit.rlim_cur = limit.rlim_max;
+       }
+       else {
+               /* we can't increase the soft limit so now we try to increase
+                * soft and hard limit. this might fail when run as non-root.
+                */
+               limit.rlim_cur *= 2;
+               limit.rlim_max *= 2;
+       }
+
+       /* set current resource limit */
+       if (setrlimit(RLIMIT_NOFILE, &limit) != 0) {
+               RTE_LOG(ERR, EAL, "Error increasing open files limit: %s\n",
+                               strerror(errno));
+               return -1;
+       }
+
+       return 0;
+}
+
 /*
  * Try to mmap *size bytes in /dev/zero. If it is succesful, return the
  * pointer to the mmap'd area and keep *size unmodified. Else, retry
@@ -219,6 +290,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 +315,11 @@ map_all_hugepages(struct hugepage *hugepg_tbl,
                        hugepg_tbl[i].final_va = virtaddr;
                }
 
+               /* close the file descriptor, files will be locked later */
+               close(fd);
+
                vma_addr = (char *)vma_addr + hugepage_sz;
                vma_len -= hugepage_sz;
-               close(fd);
        }
        return 0;
 }
@@ -292,7 +366,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);
@@ -518,7 +592,30 @@ unmap_unneeded_hugepages(struct hugepage *hugepg_tbl,
                                                munmap(hp->final_va, hp->size);
                                                hp->final_va = NULL;
                                        }
+                                       /* lock the page and skip */
                                        else {
+                                               /* try and open the hugepage file */
+                                               while ((fd = open(hp->filepath, O_CREAT | O_RDWR, 0755)) < 0) {
+                                                       /* if we can't open due to resource limits */
+                                                       if (errno == EMFILE) {
+                                                               RTE_LOG(INFO, EAL, "Increasing open file limit\n");
+
+                                                               /* if we manage to increase resource limit, try again */
+                                                               if (increase_open_file_limit() == 0)
+                                                                       continue;
+                                                       }
+                                                       else
+                                                               RTE_LOG(ERR, EAL, "%s(): open failed: %s\n", __func__,
+                                                                               strerror(errno));
+                                                       return -1;
+                                               }
+                                               /* try and lock the hugepage */
+                                               if (flock(fd, LOCK_SH | LOCK_NB) == -1) {
+                                                       RTE_LOG(ERR, EAL, "Locking hugepage file failed!\n");
+                                                       close(fd);
+                                                       return -1;
+                                               }
+                                               hp->page_lock = fd;
                                                pages_found++;
                                        }
                                } /* match page */
@@ -873,6 +970,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;