x86: allow extend_brk users to reserve brk space
authorJeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Thu, 12 Mar 2009 23:09:49 +0000 (16:09 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Sun, 15 Mar 2009 00:23:47 +0000 (17:23 -0700)
Impact: new interface; remove hard-coded limit

Add RESERVE_BRK(name, size) macro to reserve space in the brk
area.  This should be a conservative (ie, larger) estimate of
how much space might possibly be required from the brk area.
Any unused space will be freed, so there's no real downside
on making the reservation too large (within limits).

The name should be unique within a given file, and somewhat
descriptive.

The C definition of RESERVE_BRK() ends up being more complex than
one would expect to work around a cluster of gcc infelicities:

  The first attempt was to simply try putting __section(.brk_reservation)
  on a variable.  This doesn't work because it ends up making it a
  @progbits section, which gets actual space allocated in the vmlinux
  executable.

  The second attempt was to emit the space into a section using asm,
  but gcc doesn't allow arguments to be passed to file-level asm()
  statements, making it hard to pass in the size.

  The final attempt is to wrap the asm() in a function to allow
  it to have arguments, and put the function itself into the
  .discard section, which vmlinux*.lds drops entirely from the
  emitted vmlinux.

Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
arch/x86/include/asm/setup.h
arch/x86/kernel/head_32.S
arch/x86/kernel/setup.c
arch/x86/kernel/vmlinux_32.lds.S
arch/x86/kernel/vmlinux_64.lds.S

index 366d366399407328dabe262b441a4b99801b071a..61b126b97885954a3008ede83fa33f11efc50df9 100644 (file)
@@ -104,6 +104,29 @@ extern struct boot_params boot_params;
 extern unsigned long _brk_end;
 void *extend_brk(size_t size, size_t align);
 
+/*
+ * Reserve space in the brk section.  The name must be unique within
+ * the file, and somewhat descriptive.  The size is in bytes.  Must be
+ * used at file scope.
+ *
+ * (This uses a temp function to wrap the asm so we can pass it the
+ * size parameter; otherwise we wouldn't be able to.  We can't use a
+ * "section" attribute on a normal variable because it always ends up
+ * being @progbits, which ends up allocating space in the vmlinux
+ * executable.)
+ */
+#define RESERVE_BRK(name,sz)                                           \
+       static void __section(.discard) __used                  \
+       __brk_reservation_fn_##name##__(void) {                         \
+               asm volatile (                                          \
+                       ".pushsection .brk_reservation,\"aw\",@nobits;" \
+                       "__brk_reservation_" #name "__:"                \
+                       " 1:.skip %c0;"                                 \
+                       " .size __brk_reservation_" #name "__, . - 1b;" \
+                       " .popsection"                                  \
+                       : : "i" (sz));                                  \
+       }
+
 #ifdef __i386__
 
 void __init i386_start_kernel(void);
@@ -115,6 +138,13 @@ void __init x86_64_start_reservations(char *real_mode_data);
 
 #endif /* __i386__ */
 #endif /* _SETUP */
+#else
+#define RESERVE_BRK(name,sz)                           \
+       .pushsection .brk_reservation,"aw",@nobits;     \
+__brk_reservation_##name##__:                          \
+1:     .skip sz;                                       \
+       .size __brk_reservation_##name##__,.-1b;        \
+       .popsection
 #endif /* __ASSEMBLY__ */
 #endif  /*  __KERNEL__  */
 
index 3ce5456dfbe6b091f3ccd2a9ab28cf0cc0ac3fd6..9e89f2a14b90502b98d61a1a9dc0dc0bf4b2f7fe 100644 (file)
@@ -75,6 +75,8 @@ ALLOCATOR_SLOP = 4
 
 INIT_MAP_BEYOND_END = BOOTBITMAP_SIZE + (PAGE_TABLE_SIZE + ALLOCATOR_SLOP)*PAGE_SIZE_asm
 
+RESERVE_BRK(pagetables, PAGE_TABLE_SIZE * PAGE_SIZE)
+
 /*
  * 32-bit kernel entrypoint; only used by the boot CPU.  On entry,
  * %esi points to the real-mode code as a 32-bit pointer.
index e894f36335f21e54151b48e277cc431e1ae57f70..a0d26237d7cf141462a2d20941f8bd99d4195e57 100644 (file)
 #define ARCH_SETUP
 #endif
 
+RESERVE_BRK(dmi_alloc, 65536);
+
 unsigned int boot_cpu_id __read_mostly;
 
 static __initdata unsigned long _brk_start = (unsigned long)__brk_base;
index 1063fbe93c73c1311a25956b69b881c619f3e3c6..a1f28b85fb3415cd44cedcf083397a6883c924f6 100644 (file)
@@ -192,7 +192,8 @@ SECTIONS
 
        . = ALIGN(PAGE_SIZE);
        __brk_base = . ;
-       . += 1024 * 1024 ;
+       . += 64 * 1024 ;        /* 64k slop space */
+       *(.brk_reservation)     /* areas brk users have reserved */
        __brk_limit = . ;
 
        _end = . ;
@@ -201,6 +202,7 @@ SECTIONS
   /* Sections to be discarded */
   /DISCARD/ : {
        *(.exitcall.exit)
+       *(.discard)
        }
 
   STABS_DEBUG
index ff373423138cd6a0ddb32eac33f0bd1b98d8325a..7996687663a2bc53b2a815bb9c098a2c0468c008 100644 (file)
@@ -250,7 +250,8 @@ SECTIONS
 
        . = ALIGN(PAGE_SIZE);
        __brk_base = . ;
-       . += 1024 * 1024 ;
+       . += 64 * 1024;         /* 64k slop space */
+       *(.brk_reservation)     /* areas brk users have reserved */
        __brk_limit = . ;
   }
 
@@ -260,6 +261,7 @@ SECTIONS
   /DISCARD/ : {
        *(.exitcall.exit)
        *(.eh_frame)
+       *(.discard)
        }
 
   STABS_DEBUG