hugetlbfs_prefault relies on having a file descriptor associated with
the huge page backed region to prefault the huge pages.  This patch
gives an alternative for prefaulting which will be used when the
kernel supports MAP_HUGETLB.

Signed-off-by: Eric B Munson <[email protected]>
---
 hugeutils.c |   77 +++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 62 insertions(+), 15 deletions(-)

diff --git a/hugeutils.c b/hugeutils.c
index 5616d60..f8c3421 100644
--- a/hugeutils.c
+++ b/hugeutils.c
@@ -52,6 +52,8 @@ struct libhugeopts_t __hugetlb_opts;
 
 static int hugepagesize_errno; /* = 0 */
 
+static int has_segv; /* = 0 */
+
 #define MAX_HPAGE_SIZES 10
 static struct hpage_size hpage_sizes[MAX_HPAGE_SIZES];
 static int nr_hpage_sizes;
@@ -947,30 +949,41 @@ int hugetlbfs_unlinked_fd(void)
                return -1;
 }
 
+static void handle_segv(int signal)
+{
+       has_segv = 1;
+}
+
 #define IOV_LEN 64
 int hugetlbfs_prefault(int fd, void *addr, size_t length)
 {
+       size_t offset;
+       int ret;
+
+       if (!__hugetlbfs_prefault)
+               return 0;
+
        /*
         * The NUMA users of libhugetlbfs' malloc feature are
         * expected to use the numactl program to specify an
         * appropriate policy for hugepage allocation
-        *
-        * Use readv(2) to instantiate the hugepages unless HUGETLB_NO_PREFAULT
-        * is set. If we instead returned a hugepage mapping with insufficient
-        * hugepages, the VM system would kill the process when the
-        * process tried to access the missing memory.
-        *
-        * The value of this environment variable is read during library
-        * initialisation and sets __hugetlbfs_prefault accordingly. If
-        * prefaulting is enabled and we can't get all that were requested,
-        * -ENOMEM is returned. The caller is expected to release the entire
-        * mapping and optionally it may recover by mapping base pages instead.
         */
-       if (__hugetlbfs_prefault) {
-               int i;
-               size_t offset;
+
+       if (fd >= 0) {
+               /*
+                * Use readv(2) to instantiate the hugepages unless 
HUGETLB_NO_PREFAULT
+                * is set. If we instead returned a hugepage mapping with 
insufficient
+                * hugepages, the VM system would kill the process when the
+                * process tried to access the missing memory.
+                *
+                * The value of this environment variable is read during library
+                * initialisation and sets __hugetlbfs_prefault accordingly. If
+                * prefaulting is enabled and we can't get all that were 
requested,
+                * -ENOMEM is returned. The caller is expected to release the 
entire
+                * mapping and optionally it may recover by mapping base pages 
instead.
+                */
                struct iovec iov[IOV_LEN];
-               int ret;
+               int i;
 
                for (offset = 0; offset < length; ) {
                        for (i = 0; i < IOV_LEN && offset < length; i++) {
@@ -988,6 +1001,40 @@ int hugetlbfs_prefault(int fd, void *addr, size_t length)
                                return -ENOMEM;
                        }
                }
+
+       } else {
+               /*
+                * Because the region was mmap'd with MAP_HUGETLB instead of
+                * using hugetlbfs_unlinked_fd we cannot use the readv trick
+                * to prefault each page.  So instead we protect ourselves
+                * from SIGSEGV and try to read from and write to the first
+                * byte of each huge page to fault it.  If we receive a
+                * SIGSEGV then we return -ENOMEM
+                */
+               sighandler_t orig = signal(SIGSEGV, handle_segv);
+               if (orig == SIG_ERR) {
+                       ret = errno;
+                       WARNING("Unable to reserve %ld huge pages "
+                                       "for new region\n",
+                                       length / gethugepagesize());
+                       return ret;
+               }
+
+               for (offset = 0; offset < length && !has_segv;
+                                       offset += gethugepagesize()) {
+                       char *page_start = (char *)(addr + offset);
+                       *page_start = *page_start;
+               }
+
+               signal(SIGSEGV, orig);
+
+               if (has_segv) {
+                       has_segv = 0;
+                       WARNING("Unable to reserve %ld huge pages "
+                                       "for new region\n",
+                                       length / gethugepagesize());
+                       return -ENOMEM;
+               }
        }
 
        return 0;
-- 
1.7.1


------------------------------------------------------------------------------
The Next 800 Companies to Lead America's Growth: New Video Whitepaper
David G. Thomson, author of the best-selling book "Blueprint to a 
Billion" shares his insights and actions to help propel your 
business during the next growth cycle. Listen Now!
http://p.sf.net/sfu/SAP-dev2dev
_______________________________________________
Libhugetlbfs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/libhugetlbfs-devel

Reply via email to