# HG changeset patch # User Pascal Bellard # Date 1212794125 0 # Node ID 7a8f9456adc28a968f116f6538a49d905e3e1ba9 # Parent 9c22e6598e9f1f86a46fa13881566234768a7820 linux: minimize lzma memory footprint diff -r 9c22e6598e9f -r 7a8f9456adc2 linux/receipt --- a/linux/receipt Sat Jun 07 00:48:02 2008 +0200 +++ b/linux/receipt Fri Jun 06 23:15:25 2008 +0000 @@ -16,7 +16,7 @@ # lzma and boot patch from pascal while read patch_file; do echo "Apply $patch_file" - patch -p1 < ../stuff/$patch_file + patch -p1 < ../stuff/$patch_file || return 1 done < ++#ifdef CONFIG_RD_LZMA ++#define INITRD_PAGE ((PAGE_SIZE > 1024*1024) ? PAGE_SIZE : 1024*1024) ++static int fill_offset, fill_total; ++static int fill_buffer(void *buffer, unsigned size) ++{ ++ int max = initrd_end - initrd_start - fill_offset; ++ if (size < max) max = size; ++ memcpy(buffer, (void *)(initrd_start + fill_offset), max); ++ fill_offset += max; ++ fill_total += max; ++ if (fill_offset >= INITRD_PAGE) { ++ unsigned rem = fill_offset % INITRD_PAGE; ++ unsigned end = initrd_start + fill_offset - rem; ++ free_initrd_mem(initrd_start, end); ++ printk("."); ++ initrd_start = end; ++ fill_offset = rem; ++ } ++ return max; ++} ++#endif ++ + static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only) + { + int written; +@@ -484,6 +507,9 @@ + this_header = 0; + message = NULL; + while (!message && len) { ++#ifdef CONFIG_RD_LZMA ++ int status; ++#endif + loff_t saved_offset = this_header; + if (*buf == '0' && !(this_header & 3)) { + state = Start; +@@ -523,8 +549,20 @@ + #ifdef CONFIG_RD_LZMA + message = NULL; /* Zero out message, or else cpio will + think an error has already occured */ +- if(!unlzma(buf, len, NULL, flush_buffer, &inptr) < 0 && +- message == NULL) { ++ status = -1; ++ if(buf == (char *) initrd_start) { ++ char *work_buffer = malloc(LZMA_IOBUF_SIZE); ++ if (work_buffer) { ++ fill_total = fill_offset = 0; ++ fill_buffer(work_buffer, LZMA_IOBUF_SIZE); ++ status = unlzma(work_buffer, LZMA_IOBUF_SIZE, ++ fill_buffer, flush_buffer, NULL); ++ inptr = fill_total; ++ free(work_buffer); ++ } ++ } ++ else status = unlzma(buf,len, NULL, flush_buffer, &inptr); ++ if (status == 0 && message == NULL) { + goto ok; + } + #endif + +--- linux-2.6.24.2/arch/x86/mm/init_32.c ++++ linux-2.6.24.2/arch/x86/mm/init_32.c +@@ -834,7 +834,8 @@ + free_page(addr); + totalram_pages++; + } +- printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10); ++ if (what) ++ printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10); + } + + void free_initmem(void) +@@ -847,7 +848,7 @@ + #ifdef CONFIG_BLK_DEV_INITRD + void free_initrd_mem(unsigned long start, unsigned long end) + { +- free_init_pages("initrd memory", start, end); ++ free_init_pages(NULL, start, end); + } + #endif + + +--- linux-2.6.24.2/lib/decompress_unlzma.c ++++ linux-2.6.24.2/lib/decompress_unlzma.c +@@ -366,7 +366,8 @@ + header.dict_size = 1; + + bufsize = MIN(header.dst_size, header.dict_size); +- buffer = large_malloc(bufsize); ++ buffer = (uint8_t *) posp; ++ if (writebb) buffer = large_malloc(bufsize); + if(buffer == NULL) + return -1; + +@@ -394,10 +395,12 @@ + int match_byte; + + pos = buffer_pos - rep0; +- while (pos >= header.dict_size) +- pos += header.dict_size; +- if(pos >= bufsize) { +- goto fail; ++ if (writebb) { ++ while (pos >= header.dict_size) ++ pos += header.dict_size; ++ if(pos >= bufsize) { ++ goto fail; ++ } + } + match_byte = buffer[pos]; + do { +@@ -419,20 +422,14 @@ + prob_lit = prob + mi; + rc_get_bit(&rc, prob_lit, &mi); + } ++ previous_byte = (uint8_t) mi; + if (state < 4) + state = 0; + else if (state < 10) + state -= 3; + else + state -= 6; +- previous_byte = (uint8_t) mi; +- one_byte: +- buffer[buffer_pos++] = previous_byte; +- if (buffer_pos == header.dict_size) { +- buffer_pos = 0; +- global_pos += header.dict_size; +- writebb((char*)buffer, header.dict_size); +- } ++ goto store_previous_byte; + } else { + int offset; + uint16_t *prob_len; +@@ -457,14 +454,23 @@ + rc_update_bit_0(&rc, prob); + + state = state < LZMA_NUM_LIT_STATES ? 9 : 11; +- pos = buffer_pos - rep0; +- while (pos >= header.dict_size) +- pos += header.dict_size; +- if(pos >= bufsize) { +- goto fail; ++ pos = buffer_pos - rep0; ++ if (writebb) { ++ while (pos >= header.dict_size) ++ pos += header.dict_size; ++ if(pos >= bufsize) { ++ goto fail; ++ } + } + previous_byte = buffer[pos]; +- goto one_byte; ++ store_previous_byte: ++ buffer[buffer_pos++] = previous_byte; ++ if (writebb && buffer_pos == header.dict_size) { ++ buffer_pos = 0; ++ global_pos += header.dict_size; ++ writebb((char*)buffer, header.dict_size); ++ } ++ continue; + } else { + rc_update_bit_1(&rc, prob); + } +@@ -566,14 +572,16 @@ + + do { + pos = buffer_pos - rep0; +- while (pos >= header.dict_size) +- pos += header.dict_size; +- if(pos >= bufsize) { +- goto fail; ++ if (writebb) { ++ while (pos >= header.dict_size) ++ pos += header.dict_size; ++ if(pos >= bufsize) { ++ goto fail; ++ } + } + previous_byte = buffer[pos]; + buffer[buffer_pos++] = previous_byte; +- if (buffer_pos == header.dict_size) { ++ if (writebb && buffer_pos == header.dict_size) { + buffer_pos = 0; + global_pos += header.dict_size; + writebb((char*)buffer, header.dict_size); +@@ -583,15 +591,17 @@ + } + } + +- writebb((char*)buffer, buffer_pos); +- if(posp) { +- *posp = rc.ptr-rc.buffer; ++ if (writebb) { ++ writebb((char*)buffer, buffer_pos); ++ if(posp) { ++ *posp = rc.ptr-rc.buffer; ++ } ++ large_free(buffer); + } +- large_free(buffer); + large_free(p); + return 0; + fail: +- large_free(buffer); ++ if (writebb) large_free(buffer); + large_free(p); + return -1; + } + +--- linux-2.6.24.2/arch/x86/boot/compressed/misc_32.c ++++ linux-2.6.24.2/arch/x86/boot/compressed/misc_32.c +@@ -444,7 +444,7 @@ + + #ifdef CONFIG_KERNEL_LZMA + putstr("Unlzmaing Linux... "); +- unlzma(input_data, input_len-4, NULL, compr_flush, NULL); ++ unlzma(input_data, input_len-4, NULL, NULL, window); + #endif + + #ifdef CONFIG_KERNEL_GZIP