[PATCH for testing] central workspace for zlib, take 3
Jörn Engel
joern at wohnheim.fh-wedel.de
Mon Jun 2 13:38:04 EDT 2003
Hi!
This version picks up a suggestion by Matsunaga and adds a notifier
for added/removed cpus. Completely untested.
Does anyone know the semantics of cpu notifiers? When booting a
machine, how often are the notifier functions called? 0?
num_booting_cpus()? num_booting_cpus() - 1?
Jörn
--
Data expands to fill the space available for storage.
-- Parkinson's Law
--- linux-2.5.70/lib/zlib_deflate/deflate.c~zlibspace 2003-04-07 19:30:42.000000000 +0200
+++ linux-2.5.70/lib/zlib_deflate/deflate.c 2003-05-31 10:44:52.000000000 +0200
@@ -208,6 +208,7 @@
if (level == Z_DEFAULT_COMPRESSION) level = 6;
+ zlib_get_workspace(strm);
mem = (deflate_workspace *) strm->workspace;
if (windowBits < 0) { /* undocumented feature: suppress zlib header */
@@ -558,6 +559,8 @@
strm->state = Z_NULL;
+ zlib_put_workspace(strm);
+
return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
}
--- linux-2.5.70/lib/zlib_inflate/inflate.c~zlibspace 2003-04-07 19:31:23.000000000 +0200
+++ linux-2.5.70/lib/zlib_inflate/inflate.c 2003-05-31 10:44:52.000000000 +0200
@@ -8,6 +8,7 @@
#include "infblock.h"
#include "infutil.h"
+
int ZEXPORT zlib_inflate_workspacesize(void)
{
return sizeof(struct inflate_workspace);
@@ -35,6 +36,7 @@
if (z->state->blocks != Z_NULL)
zlib_inflate_blocks_free(z->state->blocks, z);
z->state = Z_NULL;
+ zlib_put_workspace(z);
return Z_OK;
}
@@ -46,12 +48,13 @@
int stream_size;
{
if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
- stream_size != sizeof(z_stream) || z->workspace == Z_NULL)
+ stream_size != sizeof(z_stream))
return Z_VERSION_ERROR;
/* initialize state */
if (z == Z_NULL)
return Z_STREAM_ERROR;
+ zlib_get_workspace(z);
z->msg = Z_NULL;
z->state = &WS(z)->internal_state;
z->state->blocks = Z_NULL;
--- linux-2.5.70/include/linux/zlib.h~zlibspace 2003-04-07 19:31:43.000000000 +0200
+++ linux-2.5.70/include/linux/zlib.h 2003-05-31 10:44:52.000000000 +0200
@@ -78,6 +78,7 @@
struct internal_state FAR *state; /* not visible by applications */
void *workspace; /* memory allocated for this stream */
+ int ws_num; /* index in the internal workspace array */
int data_type; /* best guess about the data type: ascii or binary */
uLong adler; /* adler32 value of the uncompressed data */
@@ -171,6 +172,18 @@
This check is automatically made by deflateInit and inflateInit.
*/
+ZEXTERN void * __zlib_panic_workspace OF((void));
+/*
+ BIG FAT WARNING:
+ The only valid user of this function is a panic handler. This will
+ break for sure in any other case, as it bypasses the locking.
+
+ Returns the first internal workspace. Use this for a panic handler that
+ needs a workspace during panic, but shouldn't waste the memory for it
+ during normal operation.
+*/
+
+
ZEXTERN int ZEXPORT zlib_deflate_workspacesize OF((void));
/*
Returns the number of bytes that needs to be allocated for a per-
--- /dev/null 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.5.70/lib/zlib_generic.c 2003-06-02 19:27:04.000000000 +0200
@@ -0,0 +1,137 @@
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/zutil.h>
+#include <linux/vmalloc.h>
+#include <linux/smp.h>
+#include <linux/notifier.h>
+
+#include "zlib_inflate/infutil.h" /* for the workspace size */
+#include "zlib_deflate/defutil.h"
+#define MAX(a,b) (a) > (b) ? (a) : (b)
+#define WS_SIZE MAX(sizeof(struct inflate_workspace), \
+ sizeof(struct deflate_workspace))
+
+
+static char zlib_default_workspace[WS_SIZE];
+static void *zlib_workspace[NR_CPUS];
+static unsigned long zlib_workspace_free;
+static struct semaphore zlib_workspace_sem;
+static spinlock_t zlib_workspace_free_lock;
+static int zlib_no_workspaces;
+
+
+void zlib_get_workspace(z_streamp z)
+{
+ if (z->workspace) /* transition period, will remove workspace later */
+ z->ws_num = -1;
+ else {
+ down_interruptible(&zlib_workspace_sem);
+
+ spin_lock(&zlib_workspace_free_lock);
+ z->ws_num = ffs(zlib_workspace_free) - 1;
+ clear_bit(z->ws_num, &zlib_workspace_free);
+ spin_unlock(&zlib_workspace_free_lock);
+
+ z->workspace = zlib_workspace[z->ws_num];
+ }
+}
+
+void zlib_put_workspace(z_streamp z)
+{
+ if (z->ws_num < 0)
+ ;
+ else {
+ z->workspace = NULL;
+
+ spin_lock(&zlib_workspace_free_lock);
+ __set_bit(z->ws_num, &zlib_workspace_free);
+ spin_unlock(&zlib_workspace_free_lock);
+
+ up(&zlib_workspace_sem);
+ }
+}
+
+
+static int zlib_cpu_callback(struct notifier_block *nfb,
+ unsigned long action,
+ void *hcpu)
+{
+ switch (action) {
+ case CPU_ONLINE:
+ if (zlib_no_workspaces > num_online_cpus())
+ break;
+
+ zlib_workspace[zlib_no_workspaces] = vmalloc(WS_SIZE);
+ if (!zlib_workspace[zlib_no_workspaces])
+ break;
+ zlib_no_workspaces++;
+ up(&zlib_workspace_sem);
+ break;
+
+ case CPU_OFFLINE:
+ if (zlib_no_workspaces < num_online_cpus())
+ break;
+
+ down_interruptible(&zlib_workspace_sem);
+ zlib_no_workspaces--;
+ vfree(zlib_workspace[zlib_no_workspaces]);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+
+static struct notifier_block cpu_nfb = {
+ .notifier_call = zlib_cpu_callback,
+};
+
+void __exit zlib_exit(void)
+{
+ int i;
+
+ unregister_cpu_notifier(&cpu_nfb);
+
+ for (i=1; i<zlib_no_workspaces; i++) {
+ vfree(zlib_workspace[i]);
+ }
+}
+
+int __init zlib_init(void)
+{
+ int i;
+
+ zlib_workspace[0] = zlib_default_workspace;
+ zlib_no_workspaces = num_online_cpus();
+
+ for (i=1; i<zlib_no_workspaces; i++) {
+ zlib_workspace[i] = vmalloc(WS_SIZE);
+ if (!zlib_workspace[i]) {
+ zlib_no_workspaces = i-1;
+ }
+ }
+ zlib_workspace_free = 0xffffffff;
+ sema_init(&zlib_workspace_sem, zlib_no_workspaces);
+ spin_lock_init(&zlib_workspace_free_lock);
+
+ register_cpu_notifier(&cpu_nfb);
+
+ return 0;
+}
+
+/**
+ * BIG FAT WARNING:
+ * The only valid user of this function is a panic handler. This will
+ * break for sure in any other case, as it bypasses the locking.
+ */
+void *__zlib_crash_workspace(void)
+{
+ return zlib_workspace[0];
+}
+
+
+EXPORT_SYMBOL(zlib_get_workspace);
+EXPORT_SYMBOL(zlib_put_workspace);
+EXPORT_SYMBOL(__zlib_crash_workspace);
+MODULE_AUTHOR("Jörn Engel <joern at wh.fh-wedel.de>");
+MODULE_LICENSE("GPL");
--- linux-2.5.70/include/linux/zutil.h~zlibspace 2003-04-07 19:31:50.000000000 +0200
+++ linux-2.5.70/include/linux/zutil.h 2003-05-31 10:44:52.000000000 +0200
@@ -123,4 +123,7 @@
return (s2 << 16) | s1;
}
+extern void zlib_get_workspace(z_streamp z);
+extern void zlib_put_workspace(z_streamp z);
+
#endif /* _Z_UTIL_H */
--- linux-2.5.70/lib/Makefile~zlibspace 2003-05-28 21:39:14.000000000 +0200
+++ linux-2.5.70/lib/Makefile 2003-05-31 10:49:36.000000000 +0200
@@ -24,6 +24,7 @@
obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate/
obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/
+obj-$(CONFIG_ZLIB_DEFLATE) += zlib_generic.o
include $(TOPDIR)/drivers/net/Makefile.lib
include $(TOPDIR)/drivers/usb/Makefile.lib
--- linux-2.5.70/lib/Kconfig~zlibspace 2003-04-07 19:31:46.000000000 +0200
+++ linux-2.5.70/lib/Kconfig 2003-05-31 10:48:52.000000000 +0200
@@ -26,5 +26,10 @@
(PPP_DEFLATE=m || JFFS2_FS=m || CRYPTO_DEFLATE=m)
default y if PPP_DEFLATE=y || JFFS2_FS=y || CRYPTO_DEFLATE=y
+config ZLIB_GENERIC
+ tristate
+ default m if ZLIB_DEFLATE=m || ZLIB_INFLATE=m
+ default y if ZLIB_DEFLATE=y || ZLIB_INFLATE=y
+
endmenu
More information about the linux-mtd
mailing list