aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJim Keniston <jkenisto@linux.vnet.ibm.com>2011-03-22 19:35:12 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-22 20:44:17 -0400
commit565d76cb7d5fd7cb010fd690602280a69ab116ef (patch)
treebeff4279da00976e10145820c22e699192056973
parentb12d12596992f608f5506a8dabe4d1299594bd1e (diff)
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>
-rw-r--r--crypto/deflate.c3
-rw-r--r--crypto/zlib.c18
-rw-r--r--drivers/net/ppp_deflate.c2
-rw-r--r--fs/btrfs/zlib.c3
-rw-r--r--fs/jffs2/compr_zlib.c7
-rw-r--r--fs/logfs/compr.c2
-rw-r--r--include/linux/zlib.h11
-rw-r--r--lib/zlib_deflate/deflate.c31
-rw-r--r--lib/zlib_deflate/defutil.h17
9 files changed, 71 insertions, 23 deletions
diff --git a/crypto/deflate.c b/crypto/deflate.c
index cbc7a33a9600..b5ccae29be74 100644
--- a/crypto/deflate.c
+++ b/crypto/deflate.c
@@ -48,7 +48,8 @@ static int deflate_comp_init(struct deflate_ctx *ctx)
48 int ret = 0; 48 int ret = 0;
49 struct z_stream_s *stream = &ctx->comp_stream; 49 struct z_stream_s *stream = &ctx->comp_stream;
50 50
51 stream->workspace = vzalloc(zlib_deflate_workspacesize()); 51 stream->workspace = vzalloc(zlib_deflate_workspacesize(
52 -DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL));
52 if (!stream->workspace) { 53 if (!stream->workspace) {
53 ret = -ENOMEM; 54 ret = -ENOMEM;
54 goto out; 55 goto out;
diff --git a/crypto/zlib.c b/crypto/zlib.c
index 739b8fca4cea..d11d761a5e41 100644
--- a/crypto/zlib.c
+++ b/crypto/zlib.c
@@ -85,6 +85,7 @@ static int zlib_compress_setup(struct crypto_pcomp *tfm, void *params,
85 struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm)); 85 struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
86 struct z_stream_s *stream = &ctx->comp_stream; 86 struct z_stream_s *stream = &ctx->comp_stream;
87 struct nlattr *tb[ZLIB_COMP_MAX + 1]; 87 struct nlattr *tb[ZLIB_COMP_MAX + 1];
88 int window_bits, mem_level;
88 size_t workspacesize; 89 size_t workspacesize;
89 int ret; 90 int ret;
90 91
@@ -94,7 +95,14 @@ static int zlib_compress_setup(struct crypto_pcomp *tfm, void *params,
94 95
95 zlib_comp_exit(ctx); 96 zlib_comp_exit(ctx);
96 97
97 workspacesize = zlib_deflate_workspacesize(); 98 window_bits = tb[ZLIB_COMP_WINDOWBITS]
99 ? nla_get_u32(tb[ZLIB_COMP_WINDOWBITS])
100 : MAX_WBITS;
101 mem_level = tb[ZLIB_COMP_MEMLEVEL]
102 ? nla_get_u32(tb[ZLIB_COMP_MEMLEVEL])
103 : DEF_MEM_LEVEL;
104
105 workspacesize = zlib_deflate_workspacesize(window_bits, mem_level);
98 stream->workspace = vzalloc(workspacesize); 106 stream->workspace = vzalloc(workspacesize);
99 if (!stream->workspace) 107 if (!stream->workspace)
100 return -ENOMEM; 108 return -ENOMEM;
@@ -106,12 +114,8 @@ static int zlib_compress_setup(struct crypto_pcomp *tfm, void *params,
106 tb[ZLIB_COMP_METHOD] 114 tb[ZLIB_COMP_METHOD]
107 ? nla_get_u32(tb[ZLIB_COMP_METHOD]) 115 ? nla_get_u32(tb[ZLIB_COMP_METHOD])
108 : Z_DEFLATED, 116 : Z_DEFLATED,
109 tb[ZLIB_COMP_WINDOWBITS] 117 window_bits,
110 ? nla_get_u32(tb[ZLIB_COMP_WINDOWBITS]) 118 mem_level,
111 : MAX_WBITS,
112 tb[ZLIB_COMP_MEMLEVEL]
113 ? nla_get_u32(tb[ZLIB_COMP_MEMLEVEL])
114 : DEF_MEM_LEVEL,
115 tb[ZLIB_COMP_STRATEGY] 119 tb[ZLIB_COMP_STRATEGY]
116 ? nla_get_u32(tb[ZLIB_COMP_STRATEGY]) 120 ? nla_get_u32(tb[ZLIB_COMP_STRATEGY])
117 : Z_DEFAULT_STRATEGY); 121 : Z_DEFAULT_STRATEGY);
diff --git a/drivers/net/ppp_deflate.c b/drivers/net/ppp_deflate.c
index 43583309a65d..31e9407a0739 100644
--- a/drivers/net/ppp_deflate.c
+++ b/drivers/net/ppp_deflate.c
@@ -129,7 +129,7 @@ static void *z_comp_alloc(unsigned char *options, int opt_len)
129 129
130 state->strm.next_in = NULL; 130 state->strm.next_in = NULL;
131 state->w_size = w_size; 131 state->w_size = w_size;
132 state->strm.workspace = vmalloc(zlib_deflate_workspacesize()); 132 state->strm.workspace = vmalloc(zlib_deflate_workspacesize(-w_size, 8));
133 if (state->strm.workspace == NULL) 133 if (state->strm.workspace == NULL)
134 goto out_free; 134 goto out_free;
135 135
diff --git a/fs/btrfs/zlib.c b/fs/btrfs/zlib.c
index f5ec2d44150d..faccd47c6c46 100644
--- a/fs/btrfs/zlib.c
+++ b/fs/btrfs/zlib.c
@@ -57,7 +57,8 @@ static struct list_head *zlib_alloc_workspace(void)
57 if (!workspace) 57 if (!workspace)
58 return ERR_PTR(-ENOMEM); 58 return ERR_PTR(-ENOMEM);
59 59
60 workspace->def_strm.workspace = vmalloc(zlib_deflate_workspacesize()); 60 workspace->def_strm.workspace = vmalloc(zlib_deflate_workspacesize(
61 MAX_WBITS, MAX_MEM_LEVEL));
61 workspace->inf_strm.workspace = vmalloc(zlib_inflate_workspacesize()); 62 workspace->inf_strm.workspace = vmalloc(zlib_inflate_workspacesize());
62 workspace->buf = kmalloc(PAGE_CACHE_SIZE, GFP_NOFS); 63 workspace->buf = kmalloc(PAGE_CACHE_SIZE, GFP_NOFS);
63 if (!workspace->def_strm.workspace || 64 if (!workspace->def_strm.workspace ||
diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c
index fd05a0b9431d..5a001020c542 100644
--- a/fs/jffs2/compr_zlib.c
+++ b/fs/jffs2/compr_zlib.c
@@ -40,12 +40,13 @@ static z_stream inf_strm, def_strm;
40 40
41static int __init alloc_workspaces(void) 41static int __init alloc_workspaces(void)
42{ 42{
43 def_strm.workspace = vmalloc(zlib_deflate_workspacesize()); 43 def_strm.workspace = vmalloc(zlib_deflate_workspacesize(MAX_WBITS,
44 MAX_MEM_LEVEL));
44 if (!def_strm.workspace) { 45 if (!def_strm.workspace) {
45 printk(KERN_WARNING "Failed to allocate %d bytes for deflate workspace\n", zlib_deflate_workspacesize()); 46 printk(KERN_WARNING "Failed to allocate %d bytes for deflate workspace\n", zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL));
46 return -ENOMEM; 47 return -ENOMEM;
47 } 48 }
48 D1(printk(KERN_DEBUG "Allocated %d bytes for deflate workspace\n", zlib_deflate_workspacesize())); 49 D1(printk(KERN_DEBUG "Allocated %d bytes for deflate workspace\n", zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL)));
49 inf_strm.workspace = vmalloc(zlib_inflate_workspacesize()); 50 inf_strm.workspace = vmalloc(zlib_inflate_workspacesize());
50 if (!inf_strm.workspace) { 51 if (!inf_strm.workspace) {
51 printk(KERN_WARNING "Failed to allocate %d bytes for inflate workspace\n", zlib_inflate_workspacesize()); 52 printk(KERN_WARNING "Failed to allocate %d bytes for inflate workspace\n", zlib_inflate_workspacesize());
diff --git a/fs/logfs/compr.c b/fs/logfs/compr.c
index 44bbfd249abc..961f02b86d97 100644
--- a/fs/logfs/compr.c
+++ b/fs/logfs/compr.c
@@ -81,7 +81,7 @@ error:
81 81
82int __init logfs_compr_init(void) 82int __init logfs_compr_init(void)
83{ 83{
84 size_t size = max(zlib_deflate_workspacesize(), 84 size_t size = max(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL),
85 zlib_inflate_workspacesize()); 85 zlib_inflate_workspacesize());
86 stream.workspace = vmalloc(size); 86 stream.workspace = vmalloc(size);
87 if (!stream.workspace) 87 if (!stream.workspace)
diff --git a/include/linux/zlib.h b/include/linux/zlib.h
index 40c49cb3eb51..9c5a6b4de0a3 100644
--- a/include/linux/zlib.h
+++ b/include/linux/zlib.h
@@ -179,11 +179,16 @@ typedef z_stream *z_streamp;
179 179
180 /* basic functions */ 180 /* basic functions */
181 181
182extern int zlib_deflate_workspacesize (void); 182extern int zlib_deflate_workspacesize (int windowBits, int memLevel);
183/* 183/*
184 Returns the number of bytes that needs to be allocated for a per- 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 185 stream workspace with the specified parameters. A pointer to this
186 returned in stream->workspace before calling zlib_deflateInit(). 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.
187*/ 192*/
188 193
189/* 194/*
diff --git a/lib/zlib_deflate/deflate.c b/lib/zlib_deflate/deflate.c
index 46a31e5f49c3..d63381e8e333 100644
--- a/lib/zlib_deflate/deflate.c
+++ b/lib/zlib_deflate/deflate.c
@@ -176,6 +176,7 @@ int zlib_deflateInit2(
176 deflate_state *s; 176 deflate_state *s;
177 int noheader = 0; 177 int noheader = 0;
178 deflate_workspace *mem; 178 deflate_workspace *mem;
179 char *next;
179 180
180 ush *overlay; 181 ush *overlay;
181 /* We overlay pending_buf and d_buf+l_buf. This works since the average 182 /* We overlay pending_buf and d_buf+l_buf. This works since the average
@@ -199,6 +200,21 @@ int zlib_deflateInit2(
199 strategy < 0 || strategy > Z_HUFFMAN_ONLY) { 200 strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
200 return Z_STREAM_ERROR; 201 return Z_STREAM_ERROR;
201 } 202 }
203
204 /*
205 * Direct the workspace's pointers to the chunks that were allocated
206 * along with the deflate_workspace struct.
207 */
208 next = (char *) mem;
209 next += sizeof(*mem);
210 mem->window_memory = (Byte *) next;
211 next += zlib_deflate_window_memsize(windowBits);
212 mem->prev_memory = (Pos *) next;
213 next += zlib_deflate_prev_memsize(windowBits);
214 mem->head_memory = (Pos *) next;
215 next += zlib_deflate_head_memsize(memLevel);
216 mem->overlay_memory = next;
217
202 s = (deflate_state *) &(mem->deflate_memory); 218 s = (deflate_state *) &(mem->deflate_memory);
203 strm->state = (struct internal_state *)s; 219 strm->state = (struct internal_state *)s;
204 s->strm = strm; 220 s->strm = strm;
@@ -1247,7 +1263,18 @@ static block_state deflate_slow(
1247 return flush == Z_FINISH ? finish_done : block_done; 1263 return flush == Z_FINISH ? finish_done : block_done;
1248} 1264}
1249 1265
1250int zlib_deflate_workspacesize(void) 1266int zlib_deflate_workspacesize(int windowBits, int memLevel)
1251{ 1267{
1252 return sizeof(deflate_workspace); 1268 if (windowBits < 0) /* undocumented feature: suppress zlib header */
1269 windowBits = -windowBits;
1270
1271 /* Since the return value is typically passed to vmalloc() unchecked... */
1272 BUG_ON(memLevel < 1 || memLevel > MAX_MEM_LEVEL || windowBits < 9 ||
1273 windowBits > 15);
1274
1275 return sizeof(deflate_workspace)
1276 + zlib_deflate_window_memsize(windowBits)
1277 + zlib_deflate_prev_memsize(windowBits)
1278 + zlib_deflate_head_memsize(memLevel)
1279 + zlib_deflate_overlay_memsize(memLevel);
1253} 1280}
diff --git a/lib/zlib_deflate/defutil.h b/lib/zlib_deflate/defutil.h
index 6b15a909ca3f..b640b6402e99 100644
--- a/lib/zlib_deflate/defutil.h
+++ b/lib/zlib_deflate/defutil.h
@@ -241,12 +241,21 @@ typedef struct deflate_state {
241typedef struct deflate_workspace { 241typedef struct deflate_workspace {
242 /* State memory for the deflator */ 242 /* State memory for the deflator */
243 deflate_state deflate_memory; 243 deflate_state deflate_memory;
244 Byte window_memory[2 * (1 << MAX_WBITS)]; 244 Byte *window_memory;
245 Pos prev_memory[1 << MAX_WBITS]; 245 Pos *prev_memory;
246 Pos head_memory[1 << (MAX_MEM_LEVEL + 7)]; 246 Pos *head_memory;
247 char overlay_memory[(1 << (MAX_MEM_LEVEL + 6)) * (sizeof(ush)+2)]; 247 char *overlay_memory;
248} deflate_workspace; 248} deflate_workspace;
249 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
250/* Output a byte on the stream. 259/* Output a byte on the stream.
251 * IN assertion: there is enough room in pending_buf. 260 * IN assertion: there is enough room in pending_buf.
252 */ 261 */