#include <asm/bug.h>
+#include <sys/time.h>
+#include <sys/resource.h>
 #include "symbol.h"
 #include "dso.h"
 #include "machine.h"
        return fd;
 }
 
+static void check_data_close(void);
+
 static int open_dso(struct dso *dso, struct machine *machine)
 {
        int fd = __open_dso(dso, machine);
 
-       if (fd > 0)
+       if (fd > 0) {
                dso__list_add(dso);
+               /*
+                * Check if we crossed the allowed number
+                * of opened DSOs and close one if needed.
+                */
+               check_data_close();
+       }
 
        return fd;
 }
        close_data_fd(dso);
 }
 
+static void close_first_dso(void)
+{
+       struct dso *dso;
+
+       dso = list_first_entry(&dso__data_open, struct dso, data.open_entry);
+       close_dso(dso);
+}
+
+static rlim_t get_fd_limit(void)
+{
+       struct rlimit l;
+       rlim_t limit = 0;
+
+       /* Allow half of the current open fd limit. */
+       if (getrlimit(RLIMIT_NOFILE, &l) == 0) {
+               if (l.rlim_cur == RLIM_INFINITY)
+                       limit = l.rlim_cur;
+               else
+                       limit = l.rlim_cur / 2;
+       } else {
+               pr_err("failed to get fd limit\n");
+               limit = 1;
+       }
+
+       return limit;
+}
+
+static bool may_cache_fd(void)
+{
+       static rlim_t limit;
+
+       if (!limit)
+               limit = get_fd_limit();
+
+       if (limit == RLIM_INFINITY)
+               return true;
+
+       return limit > (rlim_t) dso__data_open_cnt;
+}
+
+static void check_data_close(void)
+{
+       bool cache_fd = may_cache_fd();
+
+       if (!cache_fd)
+               close_first_dso();
+}
+
 void dso__data_close(struct dso *dso)
 {
        close_dso(dso);
        if (ret <= 0)
                free(cache);
 
-       dso__data_close(dso);
        return ret;
 }
 
 
 
        /* Check the .eh_frame section for unwinding info */
        offset = elf_section_offset(fd, ".eh_frame_hdr");
-       dso__data_close(dso);
 
        if (offset)
                ret = unwind_spec_ehframe(dso, machine, offset,
 
        /* Check the .debug_frame section for unwinding info */
        *offset = elf_section_offset(fd, ".debug_frame");
-       dso__data_close(dso);
 
        if (*offset)
                return 0;