wok view linux/stuff/linux-freeinitrd-2.6.30.6.u @ rev 5159

linux: fix stacked initrd desallocation
author Pascal Bellard <pascal.bellard@slitaz.org>
date Wed Mar 24 20:46:57 2010 +0100 (2010-03-24)
parents 7589496c772c
children 9b243bbfa976
line source
1 --- linux-2.6.30.4/arch/x86/mm/init.c
2 +++ linux-2.6.30.4/arch/x86/mm/init.c
3 @@ -381,7 +381,7 @@
4 */
5 set_memory_rw(begin, (end - begin) >> PAGE_SHIFT);
7 - printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10);
8 + if (what) printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10);
10 for (; addr < end; addr += PAGE_SIZE) {
11 ClearPageReserved(virt_to_page(addr));
13 --- linux-2.6.30.4/init/initramfs.c
14 +++ linux-2.6.30.4/init/initramfs.c
15 @@ -374,6 +374,52 @@
16 [Reset] = do_reset,
17 };
19 +#include <linux/initrd.h>
20 +#define INITRD_PAGE ((PAGE_SIZE > 64*1024) ? PAGE_SIZE : 64*1024)
21 +#define INITRD_DOT (1024*1024)
22 +
23 +static void free_rootfs_mem(unsigned long start, unsigned long end)
24 +{
25 + free_init_pages(NULL, start, end);
26 +}
27 +
28 +static void _free_initrd(unsigned long initrd_start, unsigned long initrd_end,
29 + void (*free_initrd_mem)(unsigned long, unsigned long));
30 +
31 +static struct {
32 + int offset, last, inptr, freed;
33 + char *max;
34 +} fill;
35 +
36 +static void release_inbuf(void)
37 +{
38 + if (fill.offset >= INITRD_PAGE) {
39 + unsigned rem = fill.offset % INITRD_PAGE;
40 + unsigned end = initrd_start + fill.offset - rem;
41 + _free_initrd(initrd_start, end, free_rootfs_mem);
42 + fill.freed += fill.offset - rem;
43 + if (fill.freed >= INITRD_DOT) {
44 + fill.freed -= INITRD_DOT;
45 + printk(".");
46 + }
47 + initrd_start = end;
48 + fill.offset = rem;
49 + }
50 +}
51 +
52 +static int fill_buffer(void *buffer, unsigned size)
53 +{
54 + int max = fill.max - (char *) initrd_start - fill.offset;
55 + if (max > size) max = size;
56 + if (max > INITRD_PAGE) max = INITRD_PAGE;
57 + memcpy(buffer, (void *)(initrd_start + fill.offset), max);
58 + release_inbuf();
59 + fill.offset += max;
60 + fill.inptr += fill.last;
61 + fill.last = max;
62 + return max;
63 +}
64 +
65 static int __init write_buffer(char *buf, unsigned len)
66 {
67 count = len;
68 @@ -418,6 +464,7 @@
69 decompress_fn decompress;
70 const char *compress_name;
71 static __initdata char msg_buf[64];
72 + int early_free_initrd = (buf == (char *) initrd_start);
74 header_buf = kmalloc(110, GFP_KERNEL);
75 symlink_buf = kmalloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1, GFP_KERNEL);
76 @@ -431,8 +478,31 @@
77 message = NULL;
78 while (!message && len) {
79 loff_t saved_offset = this_header;
80 + fill.offset = buf - (char *) initrd_start;
81 + fill.max = buf + len;
82 + fill.inptr = fill.last = fill.freed = 0;
83 if (*buf == '0' && !(this_header & 3)) {
84 state = Start;
85 + if (early_free_initrd) {
86 + while (len) {
87 + unsigned n = len, tofree;
88 + if (n > INITRD_PAGE)
89 + n = INITRD_PAGE;
90 + flush_buffer(buf, n);
91 + buf += n;
92 + len -= n;
93 + n = buf - (char *) initrd_start;
94 + tofree = n - (n % INITRD_PAGE);
95 + if (!tofree)
96 + continue;
97 + _free_initrd(initrd_start,
98 + initrd_start + tofree,
99 + free_rootfs_mem);
100 + initrd_start += tofree;
101 + printk(".");
102 + }
103 + continue;
104 + }
105 written = write_buffer(buf, len);
106 buf += written;
107 len -= written;
108 @@ -446,9 +516,15 @@
109 }
110 this_header = 0;
111 decompress = decompress_method(buf, len, &compress_name);
112 - if (decompress)
113 - decompress(buf, len, NULL, flush_buffer, NULL,
114 + if (decompress) {
115 + if (early_free_initrd) {
116 + decompress(NULL, 0, fill_buffer, flush_buffer,
117 + NULL, &my_inptr, error);
118 + my_inptr += fill.inptr;
119 + }
120 + else decompress(buf, len, NULL, flush_buffer, NULL,
121 &my_inptr, error);
122 + }
123 else if (compress_name) {
124 if (!message) {
125 snprintf(msg_buf, sizeof msg_buf,
126 @@ -485,7 +561,8 @@
127 #include <linux/initrd.h>
128 #include <linux/kexec.h>
130 -static void __init free_initrd(void)
131 +static void _free_initrd(unsigned long initrd_start, unsigned long initrd_end,
132 + void (*free_initrd_mem)(unsigned long, unsigned long))
133 {
134 #ifdef CONFIG_KEXEC
135 unsigned long crashk_start = (unsigned long)__va(crashk_res.start);
136 @@ -513,6 +590,12 @@
137 #endif
138 free_initrd_mem(initrd_start, initrd_end);
139 skip:
140 + ;
141 +}
142 +
143 +static void __init free_initrd(void)
144 +{
145 + _free_initrd(initrd_start, initrd_end, free_initrd_mem);
146 initrd_start = 0;
147 initrd_end = 0;
148 }