Skip to content

Commit 565d76c

Browse files
Jim Kenistontorvalds
Jim Keniston
authored andcommitted
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>
1 parent b12d125 commit 565d76c

File tree

9 files changed

+71
-23
lines changed

9 files changed

+71
-23
lines changed

crypto/deflate.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ static int deflate_comp_init(struct deflate_ctx *ctx)
4848
int ret = 0;
4949
struct z_stream_s *stream = &ctx->comp_stream;
5050

51-
stream->workspace = vzalloc(zlib_deflate_workspacesize());
51+
stream->workspace = vzalloc(zlib_deflate_workspacesize(
52+
-DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL));
5253
if (!stream->workspace) {
5354
ret = -ENOMEM;
5455
goto out;

crypto/zlib.c

+11-7
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ static int zlib_compress_setup(struct crypto_pcomp *tfm, void *params,
8585
struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
8686
struct z_stream_s *stream = &ctx->comp_stream;
8787
struct nlattr *tb[ZLIB_COMP_MAX + 1];
88+
int window_bits, mem_level;
8889
size_t workspacesize;
8990
int ret;
9091

@@ -94,7 +95,14 @@ static int zlib_compress_setup(struct crypto_pcomp *tfm, void *params,
9495

9596
zlib_comp_exit(ctx);
9697

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);
98106
stream->workspace = vzalloc(workspacesize);
99107
if (!stream->workspace)
100108
return -ENOMEM;
@@ -106,12 +114,8 @@ static int zlib_compress_setup(struct crypto_pcomp *tfm, void *params,
106114
tb[ZLIB_COMP_METHOD]
107115
? nla_get_u32(tb[ZLIB_COMP_METHOD])
108116
: Z_DEFLATED,
109-
tb[ZLIB_COMP_WINDOWBITS]
110-
? nla_get_u32(tb[ZLIB_COMP_WINDOWBITS])
111-
: MAX_WBITS,
112-
tb[ZLIB_COMP_MEMLEVEL]
113-
? nla_get_u32(tb[ZLIB_COMP_MEMLEVEL])
114-
: DEF_MEM_LEVEL,
117+
window_bits,
118+
mem_level,
115119
tb[ZLIB_COMP_STRATEGY]
116120
? nla_get_u32(tb[ZLIB_COMP_STRATEGY])
117121
: Z_DEFAULT_STRATEGY);

drivers/net/ppp_deflate.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ static void *z_comp_alloc(unsigned char *options, int opt_len)
129129

130130
state->strm.next_in = NULL;
131131
state->w_size = w_size;
132-
state->strm.workspace = vmalloc(zlib_deflate_workspacesize());
132+
state->strm.workspace = vmalloc(zlib_deflate_workspacesize(-w_size, 8));
133133
if (state->strm.workspace == NULL)
134134
goto out_free;
135135

fs/btrfs/zlib.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ static struct list_head *zlib_alloc_workspace(void)
5757
if (!workspace)
5858
return ERR_PTR(-ENOMEM);
5959

60-
workspace->def_strm.workspace = vmalloc(zlib_deflate_workspacesize());
60+
workspace->def_strm.workspace = vmalloc(zlib_deflate_workspacesize(
61+
MAX_WBITS, MAX_MEM_LEVEL));
6162
workspace->inf_strm.workspace = vmalloc(zlib_inflate_workspacesize());
6263
workspace->buf = kmalloc(PAGE_CACHE_SIZE, GFP_NOFS);
6364
if (!workspace->def_strm.workspace ||

fs/jffs2/compr_zlib.c

+4-3
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,13 @@ static z_stream inf_strm, def_strm;
4040

4141
static int __init alloc_workspaces(void)
4242
{
43-
def_strm.workspace = vmalloc(zlib_deflate_workspacesize());
43+
def_strm.workspace = vmalloc(zlib_deflate_workspacesize(MAX_WBITS,
44+
MAX_MEM_LEVEL));
4445
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));
4647
return -ENOMEM;
4748
}
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)));
4950
inf_strm.workspace = vmalloc(zlib_inflate_workspacesize());
5051
if (!inf_strm.workspace) {
5152
printk(KERN_WARNING "Failed to allocate %d bytes for inflate workspace\n", zlib_inflate_workspacesize());

fs/logfs/compr.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ int logfs_uncompress(void *in, void *out, size_t inlen, size_t outlen)
8181

8282
int __init logfs_compr_init(void)
8383
{
84-
size_t size = max(zlib_deflate_workspacesize(),
84+
size_t size = max(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL),
8585
zlib_inflate_workspacesize());
8686
stream.workspace = vmalloc(size);
8787
if (!stream.workspace)

include/linux/zlib.h

+8-3
Original file line numberDiff line numberDiff line change
@@ -179,11 +179,16 @@ typedef z_stream *z_streamp;
179179

180180
/* basic functions */
181181

182-
extern int zlib_deflate_workspacesize (void);
182+
extern int zlib_deflate_workspacesize (int windowBits, int memLevel);
183183
/*
184184
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().
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.
187192
*/
188193

189194
/*

lib/zlib_deflate/deflate.c

+29-2
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ int zlib_deflateInit2(
176176
deflate_state *s;
177177
int noheader = 0;
178178
deflate_workspace *mem;
179+
char *next;
179180

180181
ush *overlay;
181182
/* We overlay pending_buf and d_buf+l_buf. This works since the average
@@ -199,6 +200,21 @@ int zlib_deflateInit2(
199200
strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
200201
return Z_STREAM_ERROR;
201202
}
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+
202218
s = (deflate_state *) &(mem->deflate_memory);
203219
strm->state = (struct internal_state *)s;
204220
s->strm = strm;
@@ -1247,7 +1263,18 @@ static block_state deflate_slow(
12471263
return flush == Z_FINISH ? finish_done : block_done;
12481264
}
12491265

1250-
int zlib_deflate_workspacesize(void)
1266+
int zlib_deflate_workspacesize(int windowBits, int memLevel)
12511267
{
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);
12531280
}

lib/zlib_deflate/defutil.h

+13-4
Original file line numberDiff line numberDiff line change
@@ -241,12 +241,21 @@ typedef struct deflate_state {
241241
typedef struct deflate_workspace {
242242
/* State memory for the deflator */
243243
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)];
244+
Byte *window_memory;
245+
Pos *prev_memory;
246+
Pos *head_memory;
247+
char *overlay_memory;
248248
} deflate_workspace;
249249

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+
250259
/* Output a byte on the stream.
251260
* IN assertion: there is enough room in pending_buf.
252261
*/

0 commit comments

Comments
 (0)