Commit ecf72cc2 authored by David Woodhouse's avatar David Woodhouse

drivers/net/ppp_deflate.c

    Use vmalloc for ppp_deflate workspace. It's 400KiB, and kmalloc strangely
    doesn't seem to work very well for that :)
    
    Use schedule_task to do a delayed cleanup, because the z_comp_free routine
    is called with spinlocks held, hence we can't just call vfree().
    
    Fix double MOD_DEC_USE_COUNT when allocation fails, for both compression
    and decompression workspaces.
    
    Change licence text to one that insmod likes.
parent c39e9205
...@@ -35,12 +35,16 @@ ...@@ -35,12 +35,16 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/smp_lock.h>
#include <linux/ppp_defs.h> #include <linux/ppp_defs.h>
#include <linux/ppp-comp.h> #include <linux/ppp-comp.h>
#include <linux/zlib.h> #include <linux/zlib.h>
static spinlock_t comp_free_list_lock = SPIN_LOCK_UNLOCKED;
static LIST_HEAD(comp_free_list);
/* /*
* State for a Deflate (de)compressor. * State for a Deflate (de)compressor.
*/ */
...@@ -52,6 +56,7 @@ struct ppp_deflate_state { ...@@ -52,6 +56,7 @@ struct ppp_deflate_state {
int debug; int debug;
z_stream strm; z_stream strm;
struct compstat stats; struct compstat stats;
struct list_head list;
}; };
#define DEFLATE_OVHD 2 /* Deflate overhead/packet */ #define DEFLATE_OVHD 2 /* Deflate overhead/packet */
...@@ -76,6 +81,27 @@ static void z_comp_reset __P((void *state)); ...@@ -76,6 +81,27 @@ static void z_comp_reset __P((void *state));
static void z_decomp_reset __P((void *state)); static void z_decomp_reset __P((void *state));
static void z_comp_stats __P((void *state, struct compstat *stats)); static void z_comp_stats __P((void *state, struct compstat *stats));
static void z_comp_delayedfree(void *arg)
{
struct ppp_deflate_state *state;
spin_lock_bh(&comp_free_list_lock);
while(!list_empty(&comp_free_list)) {
state = list_entry(comp_free_list.next, struct ppp_deflate_state, list);
list_del(&state->list);
spin_unlock_bh(&comp_free_list_lock);
if (state->strm.workspace)
vfree(state->strm.workspace);
kfree(state);
spin_lock_bh(&comp_free_list_lock);
}
spin_unlock_bh(&comp_free_list_lock);
}
static struct tq_struct z_comp_task = {
routine: z_comp_delayedfree
};
static void static void
z_comp_free(arg) z_comp_free(arg)
void *arg; void *arg;
...@@ -84,9 +110,12 @@ z_comp_free(arg) ...@@ -84,9 +110,12 @@ z_comp_free(arg)
if (state) { if (state) {
zlib_deflateEnd(&state->strm); zlib_deflateEnd(&state->strm);
if (state->strm.workspace)
kfree(state->strm.workspace); spin_lock_bh(&comp_free_list_lock);
kfree(state); list_add(&state->list, &comp_free_list);
spin_unlock_bh(&comp_free_list_lock);
schedule_task(&z_comp_task);
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
} }
} }
...@@ -121,8 +150,7 @@ z_comp_alloc(options, opt_len) ...@@ -121,8 +150,7 @@ z_comp_alloc(options, opt_len)
memset (state, 0, sizeof (struct ppp_deflate_state)); memset (state, 0, sizeof (struct ppp_deflate_state));
state->strm.next_in = NULL; state->strm.next_in = NULL;
state->w_size = w_size; state->w_size = w_size;
state->strm.workspace = kmalloc(zlib_deflate_workspacesize(), state->strm.workspace = vmalloc(zlib_deflate_workspacesize());
GFP_KERNEL);
if (state->strm.workspace == NULL) if (state->strm.workspace == NULL)
goto out_free; goto out_free;
...@@ -134,7 +162,6 @@ z_comp_alloc(options, opt_len) ...@@ -134,7 +162,6 @@ z_comp_alloc(options, opt_len)
out_free: out_free:
z_comp_free(state); z_comp_free(state);
MOD_DEC_USE_COUNT;
return NULL; return NULL;
} }
...@@ -319,7 +346,6 @@ z_decomp_alloc(options, opt_len) ...@@ -319,7 +346,6 @@ z_decomp_alloc(options, opt_len)
out_free: out_free:
z_decomp_free(state); z_decomp_free(state);
MOD_DEC_USE_COUNT;
return NULL; return NULL;
} }
...@@ -590,8 +616,10 @@ void __exit deflate_cleanup(void) ...@@ -590,8 +616,10 @@ void __exit deflate_cleanup(void)
{ {
ppp_unregister_compressor(&ppp_deflate); ppp_unregister_compressor(&ppp_deflate);
ppp_unregister_compressor(&ppp_deflate_draft); ppp_unregister_compressor(&ppp_deflate_draft);
/* Ensure that any deflate state pending free is actually freed */
flush_scheduled_tasks();
} }
module_init(deflate_init); module_init(deflate_init);
module_exit(deflate_cleanup); module_exit(deflate_cleanup);
MODULE_LICENSE("BSD without advertisement clause"); MODULE_LICENSE("Dual BSD/GPL");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment