qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 04/14] linux-user: Reduce lseek+reads while loading


From: Richard Henderson
Subject: [Qemu-devel] [PATCH 04/14] linux-user: Reduce lseek+reads while loading elf files.
Date: Wed, 28 Apr 2010 19:39:50 -0000

Define BPRM_BUF_SIZE to 4k and read that amount initially.  If the
data we want from the binary is in this buffer, use it instead of
reading from the file again.

Signed-off-by: Richard Henderson <address@hidden>
---
 linux-user/elfload.c   |  105 ++++++++++++++++++++---------------------------
 linux-user/linuxload.c |   17 +++-----
 linux-user/qemu.h      |    7 +++-
 3 files changed, 58 insertions(+), 71 deletions(-)

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index ab741fd..962f9ba 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1140,7 +1140,8 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, 
int envc,
 
 static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
                                  int interpreter_fd,
-                                 abi_ulong *interp_load_addr)
+                                 abi_ulong *interp_load_addr,
+                                 char bprm_buf[BPRM_BUF_SIZE])
 {
     struct elf_phdr *elf_phdata  =  NULL;
     struct elf_phdr *eppnt;
@@ -1183,17 +1184,15 @@ static abi_ulong load_elf_interp(struct elfhdr * 
interp_elf_ex,
         return ~((abi_ulong)0UL);
     }
 
-    retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
-    if(retval >= 0) {
-        retval = read(interpreter_fd,
-                      (char *) elf_phdata,
-                      sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
-    }
-    if (retval < 0) {
-        perror("load_elf_interp");
-        exit(-1);
-        free (elf_phdata);
-        return retval;
+    i = interp_elf_ex->e_phnum * sizeof(struct elf_phdr);
+    if (interp_elf_ex->e_phoff + i <= BPRM_BUF_SIZE) {
+        memcpy(elf_phdata, bprm_buf + interp_elf_ex->e_phoff, i);
+    } else {
+        retval = pread(interpreter_fd, elf_phdata, i, interp_elf_ex->e_phoff);
+        if (retval != i) {
+            perror("load_elf_interp");
+            exit(-1);
+        }
     }
 #ifdef BSWAP_NEEDED
     eppnt = elf_phdata;
@@ -1451,17 +1450,15 @@ int load_elf_binary(struct linux_binprm * bprm, struct 
target_pt_regs * regs,
        return -ENOMEM;
     }
 
-    retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
-    if(retval > 0) {
-       retval = read(bprm->fd, (char *) elf_phdata,
-                      elf_ex.e_phentsize * elf_ex.e_phnum);
-    }
-
-    if (retval < 0) {
-       perror("load_elf_binary");
-       exit(-1);
-       free (elf_phdata);
-       return -errno;
+    i = elf_ex.e_phnum * sizeof(struct elf_phdr);
+    if (elf_ex.e_phoff + i <= BPRM_BUF_SIZE) {
+        memcpy(elf_phdata, bprm->buf + elf_ex.e_phoff, i);
+    } else {
+       retval = pread(bprm->fd, (char *) elf_phdata, i, elf_ex.e_phoff);
+        if (retval != i) {
+            perror("load_elf_binary");
+            exit(-1);
+        }
     }
 
 #ifdef BSWAP_NEEDED
@@ -1505,13 +1502,16 @@ int load_elf_binary(struct linux_binprm * bprm, struct 
target_pt_regs * regs,
                return -ENOMEM;
            }
 
-           retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
-           if(retval >= 0) {
-               retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
-           }
-           if(retval < 0) {
-               perror("load_elf_binary2");
-               exit(-1);
+            if (elf_ppnt->p_offset + elf_ppnt->p_filesz <= BPRM_BUF_SIZE) {
+                memcpy(elf_interpreter, bprm->buf + elf_ppnt->p_offset,
+                       elf_ppnt->p_filesz);
+            } else {
+               retval = pread(bprm->fd, elf_interpreter, elf_ppnt->p_filesz,
+                               elf_ppnt->p_offset);
+                if (retval != elf_ppnt->p_filesz) {
+                    perror("load_elf_binary2");
+                    exit(-1);
+                }
            }
 
            /* If the program interpreter is one of these two,
@@ -1525,39 +1525,24 @@ int load_elf_binary(struct linux_binprm * bprm, struct 
target_pt_regs * regs,
                 ibcs2_interpreter = 1;
            }
 
-#if 0
-           printf("Using ELF interpreter %s\n", path(elf_interpreter));
-#endif
-           if (retval >= 0) {
-               retval = open(path(elf_interpreter), O_RDONLY);
-               if(retval >= 0) {
-                   interpreter_fd = retval;
-               }
-               else {
-                   perror(elf_interpreter);
-                   exit(-1);
-                   /* retval = -errno; */
-               }
-           }
+            retval = open(path(elf_interpreter), O_RDONLY);
+            if (retval < 0) {
+                perror(elf_interpreter);
+                exit(-1);
+            }
+            interpreter_fd = retval;
 
-           if (retval >= 0) {
-               retval = lseek(interpreter_fd, 0, SEEK_SET);
-               if(retval >= 0) {
-                   retval = read(interpreter_fd,bprm->buf,128);
-               }
-           }
-           if (retval >= 0) {
-               interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
-               interp_elf_ex = *((struct elfhdr *) bprm->buf); /* elf 
exec-header */
-           }
-           if (retval < 0) {
+            retval = read(interpreter_fd, bprm->buf, BPRM_BUF_SIZE);
+            if (retval < 0) {
                perror("load_elf_binary3");
                exit(-1);
-               free (elf_phdata);
-               free(elf_interpreter);
-               close(bprm->fd);
-               return retval;
            }
+            if (retval < BPRM_BUF_SIZE) {
+                memset(bprm->buf, 0, BPRM_BUF_SIZE - retval);
+            }
+
+            interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
+            interp_elf_ex = *((struct elfhdr *) bprm->buf); /* elf exec-header 
*/
        }
        elf_ppnt++;
     }
@@ -1746,7 +1731,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct 
target_pt_regs * regs,
        }
        else if (interpreter_type & 2) {
            elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
-                                        &interp_load_addr);
+                                        &interp_load_addr, bprm->buf);
        }
         reloc_func_desc = interp_load_addr;
 
diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c
index 13ad9aa..9ee27c3 100644
--- a/linux-user/linuxload.c
+++ b/linux-user/linuxload.c
@@ -96,18 +96,16 @@ static int prepare_binprm(struct linux_binprm *bprm)
        }
     }
 
-    retval = lseek(bprm->fd, 0L, SEEK_SET);
-    if(retval >= 0) {
-        retval = read(bprm->fd, bprm->buf, 128);
-    }
-    if(retval < 0) {
+    retval = read(bprm->fd, bprm->buf, BPRM_BUF_SIZE);
+    if (retval < 0) {
        perror("prepare_binprm");
        exit(-1);
-       /* return(-errno); */
     }
-    else {
-       return(retval);
+    if (retval < BPRM_BUF_SIZE) {
+        /* Make sure the rest of the loader won't read garbage.  */
+        memset(bprm->buf + retval, 0, BPRM_BUF_SIZE - retval);
     }
+    return retval;
 }
 
 /* Construct the envp and argv tables on the target stack.  */
@@ -163,8 +161,7 @@ int loader_exec(const char * filename, char ** argv, char 
** envp,
     int i;
 
     bprm->p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
-    for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
-            bprm->page[i] = NULL;
+    memset(bprm->page, 0, sizeof(bprm->page));
     retval = open(filename, O_RDONLY);
     if (retval < 0)
         return retval;
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index dab3597..f7c8b65 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -31,6 +31,7 @@
  * task_struct fields in the kernel
  */
 struct image_info {
+        abi_ulong       load_bias;
         abi_ulong       load_addr;
         abi_ulong       start_code;
         abi_ulong       end_code;
@@ -143,12 +144,16 @@ extern unsigned long mmap_min_addr;
  */
 #define MAX_ARG_PAGES 33
 
+/* Read a good amount of data initially, to hopefully get all the 
+   program headers loaded.  */
+#define BPRM_BUF_SIZE  4096
+
 /*
  * This structure is used to hold the arguments that are
  * used when loading binaries.
  */
 struct linux_binprm {
-        char buf[128];
+        char buf[BPRM_BUF_SIZE] __attribute__((aligned));
         void *page[MAX_ARG_PAGES];
         abi_ulong p;
        int fd;
-- 
1.6.6.1





reply via email to

[Prev in Thread] Current Thread [Next in Thread]