aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlain Knaff <alain@knaff.lu>2009-01-04 16:46:17 -0500
committerH. Peter Anvin <hpa@zytor.com>2009-01-04 18:53:35 -0500
commit30d65dbfe3add7f010a075991dc0bfeaebb7d9e1 (patch)
treec60ce6748eea43d1e74d96ef03990b1e23f33b1d
parentbc22c17e12c130dc929218a95aa347e0f3fd05dc (diff)
bzip2/lzma: config and initramfs support for bzip2/lzma decompression
Impact: New code for initramfs decompression, new features This is the second part of the bzip2/lzma patch The bzip patch is based on an idea by Christian Ludwig, includes support for compressing the kernel with bzip2 or lzma rather than gzip. Both compressors give smaller sizes than gzip. Lzma's decompresses faster than bzip2. It also supports ramdisks and initramfs' compressed using these two compressors. The functionality has been successfully used for a couple of years by the udpcast project This version applies to "tip" kernel 2.6.28 This part contains: - support for new compressions (bzip2 and lzma) in initramfs and old-style ramdisk - config dialog for kernel compression (but new kernel compressions not yet supported) Signed-off-by: Alain Knaff <alain@knaff.lu> Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--drivers/block/Kconfig25
-rw-r--r--init/Kconfig50
-rw-r--r--init/do_mounts_rd.c182
-rw-r--r--init/initramfs.c123
-rw-r--r--lib/Makefile3
5 files changed, 184 insertions, 199 deletions
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 0344a8a8321d..795594442428 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -358,6 +358,31 @@ config BLK_DEV_XIP
358 will prevent RAM block device backing store memory from being 358 will prevent RAM block device backing store memory from being
359 allocated from highmem (only a problem for highmem systems). 359 allocated from highmem (only a problem for highmem systems).
360 360
361config RD_BZIP2
362 bool "Initial ramdisk compressed using bzip2"
363 default n
364 depends on BLK_DEV_INITRD=y
365 help
366 Support loading of a bzip2 encoded initial ramdisk or cpio buffer
367 If unsure, say N.
368
369config RD_LZMA
370 bool "Initial ramdisk compressed using lzma"
371 default n
372 depends on BLK_DEV_INITRD=y
373 help
374 Support loading of a lzma encoded initial ramdisk or cpio buffer
375 If unsure, say N.
376
377config RD_GZIP
378 bool "Initial ramdisk compressed using gzip"
379 default y
380 depends on BLK_DEV_INITRD=y
381 select ZLIB_INFLATE
382 help
383 Support loading of a gzip encoded initial ramdisk or cpio buffer.
384 If unsure, say Y.
385
361config CDROM_PKTCDVD 386config CDROM_PKTCDVD
362 tristate "Packet writing on CD/DVD media" 387 tristate "Packet writing on CD/DVD media"
363 depends on !UML 388 depends on !UML
diff --git a/init/Kconfig b/init/Kconfig
index f6281711166d..df84625b1373 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -101,6 +101,56 @@ config LOCALVERSION_AUTO
101 101
102 which is done within the script "scripts/setlocalversion".) 102 which is done within the script "scripts/setlocalversion".)
103 103
104choice
105 prompt "Kernel compression mode"
106 default KERNEL_GZIP
107 help
108 The linux kernel is a kind of self-extracting executable.
109 Several compression algorithms are available, which differ
110 in efficiency, compression and decompression speed.
111 Compression speed is only relevant when building a kernel.
112 Decompression speed is relevant at each boot.
113
114 If you have any problems with bzip2 or lzma compressed
115 kernels, mail me (Alain Knaff) <alain@knaff.lu>. (An older
116 version of this functionality (bzip2 only), for 2.4, was
117 supplied by Christian Ludwig)
118
119 High compression options are mostly useful for users, who
120 are low on disk space (embedded systems), but for whom ram
121 size matters less.
122
123 If in doubt, select 'gzip'
124
125config KERNEL_GZIP
126 bool "Gzip"
127 help
128 The old and tried gzip compression. Its compression ratio is
129 the poorest among the 3 choices; however its speed (both
130 compression and decompression) is the fastest.
131
132config KERNEL_BZIP2
133 bool "Bzip2"
134 help
135 Its compression ratio and speed is intermediate.
136 Decompression speed is slowest among the 3.
137 The kernel size is about 10 per cent smaller with bzip2,
138 in comparison to gzip.
139 Bzip2 uses a large amount of memory. For modern kernels
140 you will need at least 8MB RAM or more for booting.
141
142config KERNEL_LZMA
143 bool "LZMA"
144 help
145 The most recent compression algorithm.
146 Its ratio is best, decompression speed is between the other
147 2. Compression is slowest.
148 The kernel size is about 33 per cent smaller with lzma,
149 in comparison to gzip.
150
151endchoice
152
153
104config SWAP 154config SWAP
105 bool "Support for paging of anonymous memory (swap)" 155 bool "Support for paging of anonymous memory (swap)"
106 depends on MMU && BLOCK 156 depends on MMU && BLOCK
diff --git a/init/do_mounts_rd.c b/init/do_mounts_rd.c
index a7c748fa977a..dcaeb1f90b32 100644
--- a/init/do_mounts_rd.c
+++ b/init/do_mounts_rd.c
@@ -10,6 +10,12 @@
10 10
11#include "do_mounts.h" 11#include "do_mounts.h"
12 12
13#include <linux/decompress/generic.h>
14
15#include <linux/decompress/bunzip2.h>
16#include <linux/decompress/unlzma.h>
17#include <linux/decompress/inflate.h>
18
13int __initdata rd_prompt = 1;/* 1 = prompt for RAM disk, 0 = don't prompt */ 19int __initdata rd_prompt = 1;/* 1 = prompt for RAM disk, 0 = don't prompt */
14 20
15static int __init prompt_ramdisk(char *str) 21static int __init prompt_ramdisk(char *str)
@@ -28,7 +34,7 @@ static int __init ramdisk_start_setup(char *str)
28} 34}
29__setup("ramdisk_start=", ramdisk_start_setup); 35__setup("ramdisk_start=", ramdisk_start_setup);
30 36
31static int __init crd_load(int in_fd, int out_fd); 37static int __init crd_load(int in_fd, int out_fd, decompress_fn deco);
32 38
33/* 39/*
34 * This routine tries to find a RAM disk image to load, and returns the 40 * This routine tries to find a RAM disk image to load, and returns the
@@ -44,7 +50,7 @@ static int __init crd_load(int in_fd, int out_fd);
44 * gzip 50 * gzip
45 */ 51 */
46static int __init 52static int __init
47identify_ramdisk_image(int fd, int start_block) 53identify_ramdisk_image(int fd, int start_block, decompress_fn *decompressor)
48{ 54{
49 const int size = 512; 55 const int size = 512;
50 struct minix_super_block *minixsb; 56 struct minix_super_block *minixsb;
@@ -70,6 +76,7 @@ identify_ramdisk_image(int fd, int start_block)
70 sys_lseek(fd, start_block * BLOCK_SIZE, 0); 76 sys_lseek(fd, start_block * BLOCK_SIZE, 0);
71 sys_read(fd, buf, size); 77 sys_read(fd, buf, size);
72 78
79#ifdef CONFIG_RD_GZIP
73 /* 80 /*
74 * If it matches the gzip magic numbers, return 0 81 * If it matches the gzip magic numbers, return 0
75 */ 82 */
@@ -77,9 +84,39 @@ identify_ramdisk_image(int fd, int start_block)
77 printk(KERN_NOTICE 84 printk(KERN_NOTICE
78 "RAMDISK: Compressed image found at block %d\n", 85 "RAMDISK: Compressed image found at block %d\n",
79 start_block); 86 start_block);
87 *decompressor = gunzip;
88 nblocks = 0;
89 goto done;
90 }
91#endif
92
93#ifdef CONFIG_RD_BZIP2
94 /*
95 * If it matches the bzip2 magic numbers, return -1
96 */
97 if (buf[0] == 0x42 && (buf[1] == 0x5a)) {
98 printk(KERN_NOTICE
99 "RAMDISK: Bzipped image found at block %d\n",
100 start_block);
101 *decompressor = bunzip2;
102 nblocks = 0;
103 goto done;
104 }
105#endif
106
107#ifdef CONFIG_RD_LZMA
108 /*
109 * If it matches the lzma magic numbers, return -1
110 */
111 if (buf[0] == 0x5d && (buf[1] == 0x00)) {
112 printk(KERN_NOTICE
113 "RAMDISK: Lzma image found at block %d\n",
114 start_block);
115 *decompressor = unlzma;
80 nblocks = 0; 116 nblocks = 0;
81 goto done; 117 goto done;
82 } 118 }
119#endif
83 120
84 /* romfs is at block zero too */ 121 /* romfs is at block zero too */
85 if (romfsb->word0 == ROMSB_WORD0 && 122 if (romfsb->word0 == ROMSB_WORD0 &&
@@ -143,6 +180,7 @@ int __init rd_load_image(char *from)
143 int nblocks, i, disk; 180 int nblocks, i, disk;
144 char *buf = NULL; 181 char *buf = NULL;
145 unsigned short rotate = 0; 182 unsigned short rotate = 0;
183 decompress_fn decompressor = NULL;
146#if !defined(CONFIG_S390) && !defined(CONFIG_PPC_ISERIES) 184#if !defined(CONFIG_S390) && !defined(CONFIG_PPC_ISERIES)
147 char rotator[4] = { '|' , '/' , '-' , '\\' }; 185 char rotator[4] = { '|' , '/' , '-' , '\\' };
148#endif 186#endif
@@ -155,12 +193,12 @@ int __init rd_load_image(char *from)
155 if (in_fd < 0) 193 if (in_fd < 0)
156 goto noclose_input; 194 goto noclose_input;
157 195
158 nblocks = identify_ramdisk_image(in_fd, rd_image_start); 196 nblocks = identify_ramdisk_image(in_fd, rd_image_start, &decompressor);
159 if (nblocks < 0) 197 if (nblocks < 0)
160 goto done; 198 goto done;
161 199
162 if (nblocks == 0) { 200 if (nblocks == 0) {
163 if (crd_load(in_fd, out_fd) == 0) 201 if (crd_load(in_fd, out_fd, decompressor) == 0)
164 goto successful_load; 202 goto successful_load;
165 goto done; 203 goto done;
166 } 204 }
@@ -259,138 +297,48 @@ int __init rd_load_disk(int n)
259 return rd_load_image("/dev/root"); 297 return rd_load_image("/dev/root");
260} 298}
261 299
262/*
263 * gzip declarations
264 */
265
266#define OF(args) args
267
268#ifndef memzero
269#define memzero(s, n) memset ((s), 0, (n))
270#endif
271
272typedef unsigned char uch;
273typedef unsigned short ush;
274typedef unsigned long ulg;
275
276#define INBUFSIZ 4096
277#define WSIZE 0x8000 /* window size--must be a power of two, and */
278 /* at least 32K for zip's deflate method */
279
280static uch *inbuf;
281static uch *window;
282
283static unsigned insize; /* valid bytes in inbuf */
284static unsigned inptr; /* index of next byte to be processed in inbuf */
285static unsigned outcnt; /* bytes in output buffer */
286static int exit_code; 300static int exit_code;
287static int unzip_error; 301static int decompress_error;
288static long bytes_out;
289static int crd_infd, crd_outfd; 302static int crd_infd, crd_outfd;
290 303
291#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) 304static int __init compr_fill(void *buf, unsigned int len)
292
293/* Diagnostic functions (stubbed out) */
294#define Assert(cond,msg)
295#define Trace(x)
296#define Tracev(x)
297#define Tracevv(x)
298#define Tracec(c,x)
299#define Tracecv(c,x)
300
301#define STATIC static
302#define INIT __init
303
304static int __init fill_inbuf(void);
305static void __init flush_window(void);
306static void __init error(char *m);
307
308#define NO_INFLATE_MALLOC
309
310#include "../lib/inflate.c"
311
312/* ===========================================================================
313 * Fill the input buffer. This is called only when the buffer is empty
314 * and at least one byte is really needed.
315 * Returning -1 does not guarantee that gunzip() will ever return.
316 */
317static int __init fill_inbuf(void)
318{ 305{
319 if (exit_code) return -1; 306 int r = sys_read(crd_infd, buf, len);
320 307 if (r < 0)
321 insize = sys_read(crd_infd, inbuf, INBUFSIZ); 308 printk(KERN_ERR "RAMDISK: error while reading compressed data");
322 if (insize == 0) { 309 else if (r == 0)
323 error("RAMDISK: ran out of compressed data"); 310 printk(KERN_ERR "RAMDISK: EOF while reading compressed data");
324 return -1; 311 return r;
325 }
326
327 inptr = 1;
328
329 return inbuf[0];
330} 312}
331 313
332/* =========================================================================== 314static int __init compr_flush(void *window, unsigned int outcnt)
333 * Write the output window window[0..outcnt-1] and update crc and bytes_out.
334 * (Used for the decompressed data only.)
335 */
336static void __init flush_window(void)
337{ 315{
338 ulg c = crc; /* temporary variable */ 316 int written = sys_write(crd_outfd, window, outcnt);
339 unsigned n, written; 317 if (written != outcnt) {
340 uch *in, ch; 318 if (decompress_error == 0)
341 319 printk(KERN_ERR
342 written = sys_write(crd_outfd, window, outcnt); 320 "RAMDISK: incomplete write (%d != %d)\n",
343 if (written != outcnt && unzip_error == 0) { 321 written, outcnt);
344 printk(KERN_ERR "RAMDISK: incomplete write (%d != %d) %ld\n", 322 decompress_error = 1;
345 written, outcnt, bytes_out); 323 return -1;
346 unzip_error = 1; 324 }
347 } 325 return outcnt;
348 in = window;
349 for (n = 0; n < outcnt; n++) {
350 ch = *in++;
351 c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
352 }
353 crc = c;
354 bytes_out += (ulg)outcnt;
355 outcnt = 0;
356} 326}
357 327
358static void __init error(char *x) 328static void __init error(char *x)
359{ 329{
360 printk(KERN_ERR "%s\n", x); 330 printk(KERN_ERR "%s\n", x);
361 exit_code = 1; 331 exit_code = 1;
362 unzip_error = 1; 332 decompress_error = 1;
363} 333}
364 334
365static int __init crd_load(int in_fd, int out_fd) 335static int __init crd_load(int in_fd, int out_fd, decompress_fn deco)
366{ 336{
367 int result; 337 int result;
368
369 insize = 0; /* valid bytes in inbuf */
370 inptr = 0; /* index of next byte to be processed in inbuf */
371 outcnt = 0; /* bytes in output buffer */
372 exit_code = 0;
373 bytes_out = 0;
374 crc = (ulg)0xffffffffL; /* shift register contents */
375
376 crd_infd = in_fd; 338 crd_infd = in_fd;
377 crd_outfd = out_fd; 339 crd_outfd = out_fd;
378 inbuf = kmalloc(INBUFSIZ, GFP_KERNEL); 340 result = deco(NULL, 0, compr_fill, compr_flush, NULL, NULL, error);
379 if (!inbuf) { 341 if (decompress_error)
380 printk(KERN_ERR "RAMDISK: Couldn't allocate gzip buffer\n");
381 return -1;
382 }
383 window = kmalloc(WSIZE, GFP_KERNEL);
384 if (!window) {
385 printk(KERN_ERR "RAMDISK: Couldn't allocate gzip window\n");
386 kfree(inbuf);
387 return -1;
388 }
389 makecrc();
390 result = gunzip();
391 if (unzip_error)
392 result = 1; 342 result = 1;
393 kfree(inbuf);
394 kfree(window);
395 return result; 343 return result;
396} 344}
diff --git a/init/initramfs.c b/init/initramfs.c
index 4f5ba75aaa7c..40bd4fb95788 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -389,11 +389,14 @@ static int __init write_buffer(char *buf, unsigned len)
389 return len - count; 389 return len - count;
390} 390}
391 391
392static void __init flush_buffer(char *buf, unsigned len) 392
393static int __init flush_buffer(void *bufv, unsigned len)
393{ 394{
395 char *buf = (char *) bufv;
394 int written; 396 int written;
397 int origLen = len;
395 if (message) 398 if (message)
396 return; 399 return -1;
397 while ((written = write_buffer(buf, len)) < len && !message) { 400 while ((written = write_buffer(buf, len)) < len && !message) {
398 char c = buf[written]; 401 char c = buf[written];
399 if (c == '0') { 402 if (c == '0') {
@@ -407,73 +410,14 @@ static void __init flush_buffer(char *buf, unsigned len)
407 } else 410 } else
408 error("junk in compressed archive"); 411 error("junk in compressed archive");
409 } 412 }
413 return origLen;
410} 414}
411 415
412/* 416static unsigned my_inptr; /* index of next byte to be processed in inbuf */
413 * gzip declarations
414 */
415
416#define OF(args) args
417
418#ifndef memzero
419#define memzero(s, n) memset ((s), 0, (n))
420#endif
421
422typedef unsigned char uch;
423typedef unsigned short ush;
424typedef unsigned long ulg;
425
426#define WSIZE 0x8000 /* window size--must be a power of two, and */
427 /* at least 32K for zip's deflate method */
428
429static uch *inbuf;
430static uch *window;
431
432static unsigned insize; /* valid bytes in inbuf */
433static unsigned inptr; /* index of next byte to be processed in inbuf */
434static unsigned outcnt; /* bytes in output buffer */
435static long bytes_out;
436
437#define get_byte() (inptr < insize ? inbuf[inptr++] : -1)
438
439/* Diagnostic functions (stubbed out) */
440#define Assert(cond,msg)
441#define Trace(x)
442#define Tracev(x)
443#define Tracevv(x)
444#define Tracec(c,x)
445#define Tracecv(c,x)
446
447#define STATIC static
448#define INIT __init
449
450static void __init flush_window(void);
451static void __init error(char *m);
452
453#define NO_INFLATE_MALLOC
454 417
455#include "../lib/inflate.c" 418#include <linux/decompress/bunzip2.h>
456 419#include <linux/decompress/unlzma.h>
457/* =========================================================================== 420#include <linux/decompress/inflate.h>
458 * Write the output window window[0..outcnt-1] and update crc and bytes_out.
459 * (Used for the decompressed data only.)
460 */
461static void __init flush_window(void)
462{
463 ulg c = crc; /* temporary variable */
464 unsigned n;
465 uch *in, ch;
466
467 flush_buffer(window, outcnt);
468 in = window;
469 for (n = 0; n < outcnt; n++) {
470 ch = *in++;
471 c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
472 }
473 crc = c;
474 bytes_out += (ulg)outcnt;
475 outcnt = 0;
476}
477 421
478static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only) 422static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only)
479{ 423{
@@ -482,9 +426,10 @@ static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only)
482 header_buf = kmalloc(110, GFP_KERNEL); 426 header_buf = kmalloc(110, GFP_KERNEL);
483 symlink_buf = kmalloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1, GFP_KERNEL); 427 symlink_buf = kmalloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1, GFP_KERNEL);
484 name_buf = kmalloc(N_ALIGN(PATH_MAX), GFP_KERNEL); 428 name_buf = kmalloc(N_ALIGN(PATH_MAX), GFP_KERNEL);
485 window = kmalloc(WSIZE, GFP_KERNEL); 429
486 if (!window || !header_buf || !symlink_buf || !name_buf) 430 if (!header_buf || !symlink_buf || !name_buf)
487 panic("can't allocate buffers"); 431 panic("can't allocate buffers");
432
488 state = Start; 433 state = Start;
489 this_header = 0; 434 this_header = 0;
490 message = NULL; 435 message = NULL;
@@ -504,22 +449,38 @@ static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only)
504 continue; 449 continue;
505 } 450 }
506 this_header = 0; 451 this_header = 0;
507 insize = len; 452 if (!gunzip(buf, len, NULL, flush_buffer, NULL,
508 inbuf = buf; 453 &my_inptr, error) &&
509 inptr = 0; 454 message == NULL)
510 outcnt = 0; /* bytes in output buffer */ 455 goto ok;
511 bytes_out = 0; 456
512 crc = (ulg)0xffffffffL; /* shift register contents */ 457#ifdef CONFIG_RD_BZIP2
513 makecrc(); 458 message = NULL; /* Zero out message, or else cpio will
514 gunzip(); 459 think an error has already occured */
460 if (!bunzip2(buf, len, NULL, flush_buffer, NULL,
461 &my_inptr, error) &&
462 message == NULL) {
463 goto ok;
464 }
465#endif
466
467#ifdef CONFIG_RD_LZMA
468 message = NULL; /* Zero out message, or else cpio will
469 think an error has already occured */
470 if (!unlzma(buf, len, NULL, flush_buffer, NULL,
471 &my_inptr, error) &&
472 message == NULL) {
473 goto ok;
474 }
475#endif
476ok:
515 if (state != Reset) 477 if (state != Reset)
516 error("junk in gzipped archive"); 478 error("junk in compressed archive");
517 this_header = saved_offset + inptr; 479 this_header = saved_offset + my_inptr;
518 buf += inptr; 480 buf += my_inptr;
519 len -= inptr; 481 len -= my_inptr;
520 } 482 }
521 dir_utime(); 483 dir_utime();
522 kfree(window);
523 kfree(name_buf); 484 kfree(name_buf);
524 kfree(symlink_buf); 485 kfree(symlink_buf);
525 kfree(header_buf); 486 kfree(header_buf);
diff --git a/lib/Makefile b/lib/Makefile
index 32b0e64ded27..e2a21d5a264f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -11,7 +11,8 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
11 rbtree.o radix-tree.o dump_stack.o \ 11 rbtree.o radix-tree.o dump_stack.o \
12 idr.o int_sqrt.o extable.o prio_tree.o \ 12 idr.o int_sqrt.o extable.o prio_tree.o \
13 sha1.o irq_regs.o reciprocal_div.o argv_split.o \ 13 sha1.o irq_regs.o reciprocal_div.o argv_split.o \
14 proportions.o prio_heap.o ratelimit.o show_mem.o is_single_threaded.o 14 proportions.o prio_heap.o ratelimit.o show_mem.o is_single_threaded.o \
15 decompress_inflate.o decompress_bunzip2.o decompress_unlzma.o
15 16
16lib-$(CONFIG_MMU) += ioremap.o 17lib-$(CONFIG_MMU) += ioremap.o
17lib-$(CONFIG_SMP) += cpumask.o 18lib-$(CONFIG_SMP) += cpumask.o