zlib: slim down zlib_deflate() workspace when possible

Instead of always creating a huge (268K) deflate_workspace with the
maximum compression parameters (windowBits=15, memLevel=8), allow the
caller to obtain a smaller workspace by specifying smaller parameter
values.

For example, when capturing oops and panic reports to a medium with
limited capacity, such as NVRAM, compression may be the only way to
capture the whole report. In this case, a small workspace (24K works
fine) is a win, whether you allocate the workspace when you need it (i.e.,
during an oops or panic) or at boot time.

I've verified that this patch works with all accepted values of windowBits
(positive and negative), memLevel, and compression level.

Signed-off-by: Jim Keniston <jkenisto@us.ibm.com>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: David Miller <davem@davemloft.net>
Cc: Chris Mason <chris.mason@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by Jim Keniston and committed by Linus Torvalds 565d76cb b12d1259

+71 -23
+2 -1
crypto/deflate.c
··· 48 int ret = 0; 49 struct z_stream_s *stream = &ctx->comp_stream; 50 51 - stream->workspace = vzalloc(zlib_deflate_workspacesize()); 52 if (!stream->workspace) { 53 ret = -ENOMEM; 54 goto out;
··· 48 int ret = 0; 49 struct z_stream_s *stream = &ctx->comp_stream; 50 51 + stream->workspace = vzalloc(zlib_deflate_workspacesize( 52 + -DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL)); 53 if (!stream->workspace) { 54 ret = -ENOMEM; 55 goto out;
+11 -7
crypto/zlib.c
··· 85 struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm)); 86 struct z_stream_s *stream = &ctx->comp_stream; 87 struct nlattr *tb[ZLIB_COMP_MAX + 1]; 88 size_t workspacesize; 89 int ret; 90 ··· 95 96 zlib_comp_exit(ctx); 97 98 - workspacesize = zlib_deflate_workspacesize(); 99 stream->workspace = vzalloc(workspacesize); 100 if (!stream->workspace) 101 return -ENOMEM; ··· 114 tb[ZLIB_COMP_METHOD] 115 ? nla_get_u32(tb[ZLIB_COMP_METHOD]) 116 : Z_DEFLATED, 117 - tb[ZLIB_COMP_WINDOWBITS] 118 - ? nla_get_u32(tb[ZLIB_COMP_WINDOWBITS]) 119 - : MAX_WBITS, 120 - tb[ZLIB_COMP_MEMLEVEL] 121 - ? nla_get_u32(tb[ZLIB_COMP_MEMLEVEL]) 122 - : DEF_MEM_LEVEL, 123 tb[ZLIB_COMP_STRATEGY] 124 ? nla_get_u32(tb[ZLIB_COMP_STRATEGY]) 125 : Z_DEFAULT_STRATEGY);
··· 85 struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm)); 86 struct z_stream_s *stream = &ctx->comp_stream; 87 struct nlattr *tb[ZLIB_COMP_MAX + 1]; 88 + int window_bits, mem_level; 89 size_t workspacesize; 90 int ret; 91 ··· 94 95 zlib_comp_exit(ctx); 96 97 + window_bits = tb[ZLIB_COMP_WINDOWBITS] 98 + ? nla_get_u32(tb[ZLIB_COMP_WINDOWBITS]) 99 + : MAX_WBITS; 100 + mem_level = tb[ZLIB_COMP_MEMLEVEL] 101 + ? nla_get_u32(tb[ZLIB_COMP_MEMLEVEL]) 102 + : DEF_MEM_LEVEL; 103 + 104 + workspacesize = zlib_deflate_workspacesize(window_bits, mem_level); 105 stream->workspace = vzalloc(workspacesize); 106 if (!stream->workspace) 107 return -ENOMEM; ··· 106 tb[ZLIB_COMP_METHOD] 107 ? nla_get_u32(tb[ZLIB_COMP_METHOD]) 108 : Z_DEFLATED, 109 + window_bits, 110 + mem_level, 111 tb[ZLIB_COMP_STRATEGY] 112 ? nla_get_u32(tb[ZLIB_COMP_STRATEGY]) 113 : Z_DEFAULT_STRATEGY);
+1 -1
drivers/net/ppp_deflate.c
··· 129 130 state->strm.next_in = NULL; 131 state->w_size = w_size; 132 - state->strm.workspace = vmalloc(zlib_deflate_workspacesize()); 133 if (state->strm.workspace == NULL) 134 goto out_free; 135
··· 129 130 state->strm.next_in = NULL; 131 state->w_size = w_size; 132 + state->strm.workspace = vmalloc(zlib_deflate_workspacesize(-w_size, 8)); 133 if (state->strm.workspace == NULL) 134 goto out_free; 135
+2 -1
fs/btrfs/zlib.c
··· 57 if (!workspace) 58 return ERR_PTR(-ENOMEM); 59 60 - workspace->def_strm.workspace = vmalloc(zlib_deflate_workspacesize()); 61 workspace->inf_strm.workspace = vmalloc(zlib_inflate_workspacesize()); 62 workspace->buf = kmalloc(PAGE_CACHE_SIZE, GFP_NOFS); 63 if (!workspace->def_strm.workspace ||
··· 57 if (!workspace) 58 return ERR_PTR(-ENOMEM); 59 60 + workspace->def_strm.workspace = vmalloc(zlib_deflate_workspacesize( 61 + MAX_WBITS, MAX_MEM_LEVEL)); 62 workspace->inf_strm.workspace = vmalloc(zlib_inflate_workspacesize()); 63 workspace->buf = kmalloc(PAGE_CACHE_SIZE, GFP_NOFS); 64 if (!workspace->def_strm.workspace ||
+4 -3
fs/jffs2/compr_zlib.c
··· 40 41 static int __init alloc_workspaces(void) 42 { 43 - def_strm.workspace = vmalloc(zlib_deflate_workspacesize()); 44 if (!def_strm.workspace) { 45 - printk(KERN_WARNING "Failed to allocate %d bytes for deflate workspace\n", zlib_deflate_workspacesize()); 46 return -ENOMEM; 47 } 48 - D1(printk(KERN_DEBUG "Allocated %d bytes for deflate workspace\n", zlib_deflate_workspacesize())); 49 inf_strm.workspace = vmalloc(zlib_inflate_workspacesize()); 50 if (!inf_strm.workspace) { 51 printk(KERN_WARNING "Failed to allocate %d bytes for inflate workspace\n", zlib_inflate_workspacesize());
··· 40 41 static int __init alloc_workspaces(void) 42 { 43 + def_strm.workspace = vmalloc(zlib_deflate_workspacesize(MAX_WBITS, 44 + MAX_MEM_LEVEL)); 45 if (!def_strm.workspace) { 46 + printk(KERN_WARNING "Failed to allocate %d bytes for deflate workspace\n", zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL)); 47 return -ENOMEM; 48 } 49 + D1(printk(KERN_DEBUG "Allocated %d bytes for deflate workspace\n", zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL))); 50 inf_strm.workspace = vmalloc(zlib_inflate_workspacesize()); 51 if (!inf_strm.workspace) { 52 printk(KERN_WARNING "Failed to allocate %d bytes for inflate workspace\n", zlib_inflate_workspacesize());
+1 -1
fs/logfs/compr.c
··· 81 82 int __init logfs_compr_init(void) 83 { 84 - size_t size = max(zlib_deflate_workspacesize(), 85 zlib_inflate_workspacesize()); 86 stream.workspace = vmalloc(size); 87 if (!stream.workspace)
··· 81 82 int __init logfs_compr_init(void) 83 { 84 + size_t size = max(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL), 85 zlib_inflate_workspacesize()); 86 stream.workspace = vmalloc(size); 87 if (!stream.workspace)
+8 -3
include/linux/zlib.h
··· 179 180 /* basic functions */ 181 182 - extern int zlib_deflate_workspacesize (void); 183 /* 184 Returns the number of bytes that needs to be allocated for a per- 185 - stream workspace. A pointer to this number of bytes should be 186 - returned in stream->workspace before calling zlib_deflateInit(). 187 */ 188 189 /*
··· 179 180 /* basic functions */ 181 182 + extern int zlib_deflate_workspacesize (int windowBits, int memLevel); 183 /* 184 Returns the number of bytes that needs to be allocated for a per- 185 + stream workspace with the specified parameters. A pointer to this 186 + number of bytes should be returned in stream->workspace before 187 + you call zlib_deflateInit() or zlib_deflateInit2(). If you call 188 + zlib_deflateInit(), specify windowBits = MAX_WBITS and memLevel = 189 + MAX_MEM_LEVEL here. If you call zlib_deflateInit2(), the windowBits 190 + and memLevel parameters passed to zlib_deflateInit2() must not 191 + exceed those passed here. 192 */ 193 194 /*
+29 -2
lib/zlib_deflate/deflate.c
··· 176 deflate_state *s; 177 int noheader = 0; 178 deflate_workspace *mem; 179 180 ush *overlay; 181 /* We overlay pending_buf and d_buf+l_buf. This works since the average ··· 200 strategy < 0 || strategy > Z_HUFFMAN_ONLY) { 201 return Z_STREAM_ERROR; 202 } 203 s = (deflate_state *) &(mem->deflate_memory); 204 strm->state = (struct internal_state *)s; 205 s->strm = strm; ··· 1263 return flush == Z_FINISH ? finish_done : block_done; 1264 } 1265 1266 - int zlib_deflate_workspacesize(void) 1267 { 1268 - return sizeof(deflate_workspace); 1269 }
··· 176 deflate_state *s; 177 int noheader = 0; 178 deflate_workspace *mem; 179 + char *next; 180 181 ush *overlay; 182 /* We overlay pending_buf and d_buf+l_buf. This works since the average ··· 199 strategy < 0 || strategy > Z_HUFFMAN_ONLY) { 200 return Z_STREAM_ERROR; 201 } 202 + 203 + /* 204 + * Direct the workspace's pointers to the chunks that were allocated 205 + * along with the deflate_workspace struct. 206 + */ 207 + next = (char *) mem; 208 + next += sizeof(*mem); 209 + mem->window_memory = (Byte *) next; 210 + next += zlib_deflate_window_memsize(windowBits); 211 + mem->prev_memory = (Pos *) next; 212 + next += zlib_deflate_prev_memsize(windowBits); 213 + mem->head_memory = (Pos *) next; 214 + next += zlib_deflate_head_memsize(memLevel); 215 + mem->overlay_memory = next; 216 + 217 s = (deflate_state *) &(mem->deflate_memory); 218 strm->state = (struct internal_state *)s; 219 s->strm = strm; ··· 1247 return flush == Z_FINISH ? finish_done : block_done; 1248 } 1249 1250 + int zlib_deflate_workspacesize(int windowBits, int memLevel) 1251 { 1252 + if (windowBits < 0) /* undocumented feature: suppress zlib header */ 1253 + windowBits = -windowBits; 1254 + 1255 + /* Since the return value is typically passed to vmalloc() unchecked... */ 1256 + BUG_ON(memLevel < 1 || memLevel > MAX_MEM_LEVEL || windowBits < 9 || 1257 + windowBits > 15); 1258 + 1259 + return sizeof(deflate_workspace) 1260 + + zlib_deflate_window_memsize(windowBits) 1261 + + zlib_deflate_prev_memsize(windowBits) 1262 + + zlib_deflate_head_memsize(memLevel) 1263 + + zlib_deflate_overlay_memsize(memLevel); 1264 }
+13 -4
lib/zlib_deflate/defutil.h
··· 241 typedef struct deflate_workspace { 242 /* State memory for the deflator */ 243 deflate_state deflate_memory; 244 - Byte window_memory[2 * (1 << MAX_WBITS)]; 245 - Pos prev_memory[1 << MAX_WBITS]; 246 - Pos head_memory[1 << (MAX_MEM_LEVEL + 7)]; 247 - char overlay_memory[(1 << (MAX_MEM_LEVEL + 6)) * (sizeof(ush)+2)]; 248 } deflate_workspace; 249 250 /* Output a byte on the stream. 251 * IN assertion: there is enough room in pending_buf.
··· 241 typedef struct deflate_workspace { 242 /* State memory for the deflator */ 243 deflate_state deflate_memory; 244 + Byte *window_memory; 245 + Pos *prev_memory; 246 + Pos *head_memory; 247 + char *overlay_memory; 248 } deflate_workspace; 249 + 250 + #define zlib_deflate_window_memsize(windowBits) \ 251 + (2 * (1 << (windowBits)) * sizeof(Byte)) 252 + #define zlib_deflate_prev_memsize(windowBits) \ 253 + ((1 << (windowBits)) * sizeof(Pos)) 254 + #define zlib_deflate_head_memsize(memLevel) \ 255 + ((1 << ((memLevel)+7)) * sizeof(Pos)) 256 + #define zlib_deflate_overlay_memsize(memLevel) \ 257 + ((1 << ((memLevel)+6)) * (sizeof(ush)+2)) 258 259 /* Output a byte on the stream. 260 * IN assertion: there is enough room in pending_buf.