Add a few fields to the seg_info structure to store the starting address
and size of the extracopy area. This cleans up the code so we can call
extracopy earlier in the process and not pass around as many pointers.
It also is necessary for the patch to drop pagecache pages. If the
extra_vaddr field is NULL, then the pagecache dropping code assumes this
means there was no extracopy area. This method uses the start address
and size to represent the extracopy area (as opposed to start and end
pointers).

Currently the elf executable header pointer is global in elflink.c, but
passed as a parameter to parse_phdrs(). The only other user of ehdr is
the extracopy code. We run this code at prepare-time, but there is no
reason it couldn't be done at parse-time. Since we store away the
extracopy information anyways, now, this is ok. It does require moving
the parse_phdrs() function (the majority of this patch) to avoid foward
declarations. The only performance implication of this, that I can see,
is that we now will call get_extracopy() unconditionally, whereas before
we would not do prepare (and thus not extracopy) for shared segments.
Since get_extracopy() only does parsing, though, I think this should be
ok (extra work may be done in DEBUG=yes mode, but that's not
performance-critical). parse_phdrs() now does much more than just deal
with the program headers. Rename the function to indicate that it
abstracts all ELF-related parsing. Finally, rename the seg_info member
phdr to index to indicate it indexes into the program header and is not
the program header itself.  With the new extracopy parameter, this helps
clarify some code.

Signed-off-by: Nishanth Aravamudan <[EMAIL PROTECTED]>
---
 elflink.c |  169 ++++++++++++++++++++++++++++++-------------------------------
 1 files changed, 84 insertions(+), 85 deletions(-)

diff --git a/elflink.c b/elflink.c
index 5a57358..3abe8f9 100644
--- a/elflink.c
+++ b/elflink.c
@@ -186,11 +186,11 @@ static char share_path[PATH_MAX+1];
 #define MAX_HTLB_SEGS  2
 
 struct seg_info {
-       void *vaddr;
-       unsigned long filesz, memsz;
+       void *vaddr, *extra_vaddr;
+       unsigned long filesz, memsz, extrasz;
        int prot;
        int fd;
-       int phdr;
+       int index;
 };
 
 static struct seg_info htlb_seg_table[MAX_HTLB_SEGS];
@@ -198,7 +198,6 @@ static int htlb_num_segs;
 static int minimal_copy = 1;
 static int sharing; /* =0 */
 int __debug = 0;
-static Elf_Ehdr *ehdr;
 
 /**
  * assemble_path - handy wrapper around snprintf() for building paths
@@ -232,57 +231,6 @@ static void assemble_path(char *dst, const char *fmt, ...)
        }
 }
 
-/*
- * Parse an ELF header and record segment information for any segments
- * which contain hugetlb information.
- */
-
-static void parse_phdrs(Elf_Ehdr *ehdr)
-{
-       Elf_Phdr *phdr = (Elf_Phdr *)((char *)ehdr + ehdr->e_phoff);
-       int i;
-
-       for (i = 0; i < ehdr->e_phnum; i++) {
-               unsigned long vaddr, filesz, memsz;
-               int prot = 0;
-
-               if (phdr[i].p_type != PT_LOAD)
-                       continue;
-
-               if (! (phdr[i].p_flags & PF_LINUX_HUGETLB))
-                       continue;
-
-               if (htlb_num_segs >= MAX_HTLB_SEGS) {
-                       ERROR("Executable has too many segments marked for "
-                             "hugepage (max %d)\n", MAX_HTLB_SEGS);
-                       htlb_num_segs = 0;
-                       return;
-               }
-
-               vaddr = phdr[i].p_vaddr;
-               filesz = phdr[i].p_filesz;
-               memsz = phdr[i].p_memsz;
-               if (phdr[i].p_flags & PF_R)
-                       prot |= PROT_READ;
-               if (phdr[i].p_flags & PF_W)
-                       prot |= PROT_WRITE;
-               if (phdr[i].p_flags & PF_X)
-                       prot |= PROT_EXEC;
-
-               DEBUG("Hugepage segment %d "
-                       "(phdr %d): %#0lx-%#0lx  (filesz=%#0lx) "
-                       "(prot = %#0x)\n",
-                       htlb_num_segs, i, vaddr, vaddr+memsz, filesz, prot);
-
-               htlb_seg_table[htlb_num_segs].vaddr = (void *)vaddr;
-               htlb_seg_table[htlb_num_segs].filesz = filesz;
-               htlb_seg_table[htlb_num_segs].memsz = memsz;
-               htlb_seg_table[htlb_num_segs].prot = prot;
-               htlb_seg_table[htlb_num_segs].phdr = i;
-               htlb_num_segs++;
-       }
-}
-
 /**
  * find_or_create_share_path - obtain a directory to store the shared
  * hugetlbfs files
@@ -400,19 +348,17 @@ static int get_shared_file_name(struct seg_info 
*htlb_seg_info, char *file_path)
        }
 
        assemble_path(file_path, "%s/%s_%zd_%d", share_path, binary2,
-                     sizeof(unsigned long) * 8, htlb_seg_info->phdr);
+                     sizeof(unsigned long) * 8, htlb_seg_info->index);
 
        return 0;
 }
 
 /* Find the .dynamic program header */
-static int find_dynamic(Elf_Dyn **dyntab)
+static int find_dynamic(Elf_Dyn **dyntab, Elf_Phdr *phdr, int phnum)
 {
-       Elf_Phdr *phdr; /* program header table */
        int i = 1;
 
-       phdr = (Elf_Phdr *)((char *)ehdr + ehdr->e_phoff);
-       while ((phdr[i].p_type != PT_DYNAMIC) && (i < ehdr->e_phnum)) {
+       while ((phdr[i].p_type != PT_DYNAMIC) && (i < phnum)) {
                ++i;
        }
        if (phdr[i].p_type == PT_DYNAMIC) {
@@ -497,8 +443,7 @@ static inline int keep_symbol(Elf_Sym *s, void *start, void 
*end)
  * include these initialized variables in our copy.
  */
 
-static void get_extracopy(struct seg_info *seg, void **extra_start,
-                                                       void **extra_end)
+static void get_extracopy(struct seg_info *seg, Elf_Phdr *phdr, int phnum)
 {
        Elf_Dyn *dyntab;        /* dynamic segment table */
        Elf_Sym *symtab = NULL; /* dynamic symbol table */
@@ -511,12 +456,12 @@ static void get_extracopy(struct seg_info *seg, void 
**extra_start,
        end_orig = seg->vaddr + seg->memsz;
        start_orig = seg->vaddr + seg->filesz;
        if (seg->filesz == seg->memsz)
-               goto bail2;
+               return;
        if (!minimal_copy)
                goto bail2;
 
        /* Find dynamic program header */
-       ret = find_dynamic(&dyntab);
+       ret = find_dynamic(&dyntab, phdr, phnum);
        if (ret < 0)
                goto bail;
 
@@ -557,23 +502,72 @@ static void get_extracopy(struct seg_info *seg, void 
**extra_start,
 
        if (found_sym) {
                /* Return the copy window */
-               *extra_start = start;
-               *extra_end = end;
-               return;
-       } else {
-               /* No need to copy anything */
-               *extra_start = start_orig;
-               *extra_end = start_orig;
-               goto bail3;
+               seg->extra_vaddr = start;
+               seg->extrasz = end - start;
        }
+       /*
+        * else no need to copy anything, so leave seg->extra_vaddr as
+        * NULL
+        */
+       return;
 
 bail:
        DEBUG("Unable to perform minimal copy\n");
 bail2:
-       *extra_start = start_orig;
-       *extra_end = end_orig;
-bail3:
-       return;
+       seg->extra_vaddr = start_orig;
+       seg->extrasz = end_orig - start_orig;
+}
+
+/*
+ * Parse an ELF header and record segment information for any segments
+ * which contain hugetlb information.
+ */
+static void parse_elf(Elf_Ehdr *ehdr)
+{
+       Elf_Phdr *phdr = (Elf_Phdr *)((char *)ehdr + ehdr->e_phoff);
+       int i;
+
+       for (i = 0; i < ehdr->e_phnum; i++) {
+               unsigned long vaddr, filesz, memsz;
+               int prot = 0;
+
+               if (phdr[i].p_type != PT_LOAD)
+                       continue;
+
+               if (! (phdr[i].p_flags & PF_LINUX_HUGETLB))
+                       continue;
+
+               if (htlb_num_segs >= MAX_HTLB_SEGS) {
+                       ERROR("Executable has too many segments marked for "
+                             "hugepage (max %d)\n", MAX_HTLB_SEGS);
+                       htlb_num_segs = 0;
+                       return;
+               }
+
+               vaddr = phdr[i].p_vaddr;
+               filesz = phdr[i].p_filesz;
+               memsz = phdr[i].p_memsz;
+               if (phdr[i].p_flags & PF_R)
+                       prot |= PROT_READ;
+               if (phdr[i].p_flags & PF_W)
+                       prot |= PROT_WRITE;
+               if (phdr[i].p_flags & PF_X)
+                       prot |= PROT_EXEC;
+
+               DEBUG("Hugepage segment %d "
+                       "(phdr %d): %#0lx-%#0lx  (filesz=%#0lx) "
+                       "(prot = %#0x)\n",
+                       htlb_num_segs, i, vaddr, vaddr+memsz, filesz, prot);
+
+               htlb_seg_table[htlb_num_segs].vaddr = (void *)vaddr;
+               htlb_seg_table[htlb_num_segs].filesz = filesz;
+               htlb_seg_table[htlb_num_segs].memsz = memsz;
+               htlb_seg_table[htlb_num_segs].prot = prot;
+               htlb_seg_table[htlb_num_segs].index = i;
+               get_extracopy(&htlb_seg_table[htlb_num_segs], phdr,
+                                                       ehdr->e_phnum);
+               htlb_num_segs++;
+       }
 }
 
 /*
@@ -584,7 +578,7 @@ bail3:
 static int prepare_segment(struct seg_info *seg)
 {
        int hpage_size = gethugepagesize();
-       void *p, *extra_start, *extra_end;
+       void *p;
        unsigned long gap;
        unsigned long size;
 
@@ -592,9 +586,13 @@ static int prepare_segment(struct seg_info *seg)
         * Calculate the BSS size that we must copy in order to minimize
         * the size of the shared mapping.
         */
-       get_extracopy(seg, &extra_start, &extra_end);
-       size = ALIGN((unsigned long)extra_end - (unsigned long)seg->vaddr,
+       if (seg->extra_vaddr) {
+               size = ALIGN((unsigned long)seg->extra_vaddr +
+                               seg->extrasz - (unsigned long)seg->vaddr,
                                hpage_size);
+       } else {
+               size = ALIGN(seg->filesz, hpage_size);
+       }
 
        /* Prepare the hugetlbfs file */
 
@@ -617,11 +615,12 @@ static int prepare_segment(struct seg_info *seg)
        memcpy(p, seg->vaddr, seg->filesz);
        DEBUG_CONT("done\n");
 
-       if (extra_end > extra_start) {
+       if (seg->extra_vaddr) {
                DEBUG("Copying extra %#0lx bytes from %p...",
-                       (unsigned long)(extra_end - extra_start), extra_start);
-               gap = extra_start - (seg->vaddr + seg->filesz);
-               memcpy((p + seg->filesz + gap), extra_start, (extra_end - 
extra_start));
+                                       seg->extrasz, seg->extra_vaddr);
+               gap = seg->extra_vaddr - (seg->vaddr + seg->filesz);
+               memcpy((p + seg->filesz + gap), seg->extra_vaddr,
+                                                       seg->extrasz);
                DEBUG_CONT("done\n");
        }
 
@@ -886,7 +885,7 @@ static int check_env(void)
 static void __attribute__ ((constructor)) setup_elflink(void)
 {
        extern Elf_Ehdr __executable_start __attribute__((weak));
-       ehdr = &__executable_start;
+       Elf_Ehdr *ehdr = &__executable_start;
        int ret, i;
 
        if (! ehdr) {
@@ -898,7 +897,7 @@ static void __attribute__ ((constructor)) 
setup_elflink(void)
        if (check_env())
                return;
 
-       parse_phdrs(ehdr);
+       parse_elf(ehdr);
 
        if (htlb_num_segs == 0) {
                DEBUG("Executable is not linked for hugepage segments\n");

-- 
Nishanth Aravamudan <[EMAIL PROTECTED]>
IBM Linux Technology Center

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Libhugetlbfs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/libhugetlbfs-devel

Reply via email to