diff --git a/share/man/man5/core.5 b/share/man/man5/core.5
index 5a827e2993f4..3f54f890ef9d 100644
--- a/share/man/man5/core.5
+++ b/share/man/man5/core.5
@@ -28,7 +28,7 @@
 .\"     @(#)core.5	8.3 (Berkeley) 12/11/93
 .\" $FreeBSD$
 .\"
-.Dd November 22, 2012
+.Dd March 8, 2015
 .Dt CORE 5
 .Os
 .Sh NAME
@@ -101,25 +101,23 @@ variable
 .Va kern.sugid_coredump
 to 1.
 .Pp
-Corefiles can be compressed by the kernel if the following items
-are included in the kernel configuration file:
+Corefiles can be compressed by the kernel if the following item
+is included in the kernel configuration file:
 .Bl -tag -width "1234567890" -compact -offset "12345"
 .It options
-COMPRESS_USER_CORES
-.It devices
-gzio
+GZIO
 .El
 .Pp
-When COMPRESS_USER_CORES is included the following sysctls can control
-if core files will be compressed:
+When the GZIO option is included, the following sysctls control whether core
+files will be compressed:
 .Bl -tag -width "kern.compress_user_cores_gzlevel" -compact -offset "12345"
 .It Em kern.compress_user_cores_gzlevel
 Gzip compression level.
-Defaults to -1.
+Defaults to 6.
 .It Em kern.compress_user_cores
 Actually compress user cores.
-Core files will have the suffix
-.Em .gz
+Compressed core files will have a suffix of
+.Ql .gz
 appended to them.
 .El
 .Sh EXAMPLES
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index 8b6a4c8b3c60..c0d587911825 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -2889,11 +2889,6 @@ options 	SHMMNI=33
 # a single process at one time.
 options 	SHMSEG=9
 
-# Compress user core dumps.
-options		COMPRESS_USER_CORES
-# required to compress file output from kernel for COMPRESS_USER_CORES.
-device		gzio	    
-
 # Set the amount of time (in seconds) the system will wait before
 # rebooting automatically when a kernel panic occurs.  If set to (-1),
 # the system will wait indefinitely until a key is pressed on the
@@ -2983,3 +2978,7 @@ options 	RANDOM_DEBUG	# Debugging messages
 
 # Module to enable execution of application via emulators like QEMU
 options         IMAGACT_BINMISC
+
+# zlib I/O stream support
+# This enables support for compressed core dumps.
+options 	GZIO
diff --git a/sys/conf/options b/sys/conf/options
index 2d6d54b2e24e..28d7950d6757 100644
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -87,13 +87,13 @@ COMPAT_FREEBSD9	opt_compat.h
 COMPAT_FREEBSD10	opt_compat.h
 COMPAT_LINUXAPI	opt_compat.h
 COMPILING_LINT	opt_global.h
-COMPRESS_USER_CORES opt_core.h
 CY_PCI_FASTINTR
 DEADLKRES	opt_watchdog.h
 DIRECTIO
 FILEMON		opt_dontuse.h
 FFCLOCK
 FULL_PREEMPTION	opt_sched.h
+GZIO		opt_gzio.h
 IMAGACT_BINMISC		opt_dontuse.h
 IPI_PREEMPTION	opt_sched.h
 GEOM_AES	opt_geom.h
diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c
index 075139b922c9..0a8b79a4a927 100644
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
@@ -33,12 +33,13 @@ __FBSDID("$FreeBSD$");
 
 #include "opt_capsicum.h"
 #include "opt_compat.h"
-#include "opt_core.h"
+#include "opt_gzio.h"
 
 #include <sys/param.h>
 #include <sys/capsicum.h>
 #include <sys/exec.h>
 #include <sys/fcntl.h>
+#include <sys/gzio.h>
 #include <sys/imgact.h>
 #include <sys/imgact_elf.h>
 #include <sys/jail.h>
@@ -69,8 +70,6 @@ __FBSDID("$FreeBSD$");
 #include <sys/eventhandler.h>
 #include <sys/user.h>
 
-#include <net/zlib.h>
-
 #include <vm/vm.h>
 #include <vm/vm_kern.h>
 #include <vm/vm_param.h>
@@ -105,11 +104,7 @@ static Elf_Word __elfN(untrans_prot)(vm_prot_t);
 SYSCTL_NODE(_kern, OID_AUTO, __CONCAT(elf, __ELF_WORD_SIZE), CTLFLAG_RW, 0,
     "");
 
-#ifdef COMPRESS_USER_CORES
-static int compress_core(gzFile, char *, char *, unsigned int,
-    struct thread * td);
-#endif
-#define CORE_BUF_SIZE	(16 * 1024)
+#define	CORE_BUF_SIZE	(16 * 1024)
 
 int __elfN(fallback_brand) = -1;
 SYSCTL_INT(__CONCAT(_kern_elf, __ELF_WORD_SIZE), OID_AUTO,
@@ -1067,11 +1062,23 @@ struct note_info {
 
 TAILQ_HEAD(note_info_list, note_info);
 
+/* Coredump output parameters. */
+struct coredump_params {
+	off_t		offset;
+	struct ucred	*active_cred;
+	struct ucred	*file_cred;
+	struct thread	*td;
+	struct vnode	*vp;
+	struct gzio_stream *gzs;
+};
+
 static void cb_put_phdr(vm_map_entry_t, void *);
 static void cb_size_segment(vm_map_entry_t, void *);
+static int core_write(struct coredump_params *, void *, size_t, off_t,
+    enum uio_seg);
 static void each_writable_segment(struct thread *, segment_callback, void *);
-static int __elfN(corehdr)(struct thread *, struct vnode *, struct ucred *,
-    int, void *, size_t, struct note_info_list *, size_t, gzFile);
+static int __elfN(corehdr)(struct coredump_params *, int, void *, size_t,
+    struct note_info_list *, size_t);
 static void __elfN(prepare_notes)(struct thread *, struct note_info_list *,
     size_t *);
 static void __elfN(puthdr)(struct thread *, void *, size_t, int, size_t);
@@ -1095,42 +1102,60 @@ static void note_procstat_rlimit(void *, struct sbuf *, size_t *);
 static void note_procstat_umask(void *, struct sbuf *, size_t *);
 static void note_procstat_vmmap(void *, struct sbuf *, size_t *);
 
-#ifdef COMPRESS_USER_CORES
-extern int compress_user_cores;
+#ifdef GZIO
 extern int compress_user_cores_gzlevel;
-#endif
 
+/*
+ * Write out a core segment to the compression stream.
+ */
 static int
-core_output(struct vnode *vp, void *base, size_t len, off_t offset,
-    struct ucred *active_cred, struct ucred *file_cred,
-    struct thread *td, char *core_buf, gzFile gzfile) {
-
+compress_chunk(struct coredump_params *p, char *base, char *buf, u_int len)
+{
+	u_int chunk_len;
 	int error;
-	if (gzfile) {
-#ifdef COMPRESS_USER_CORES
-		error = compress_core(gzfile, base, core_buf, len, td);
-#else
-		panic("shouldn't be here");
-#endif
-	} else {
-		error = vn_rdwr_inchunks(UIO_WRITE, vp, base, len, offset,
-		    UIO_USERSPACE, IO_UNIT | IO_DIRECT | IO_RANGELOCKED,
-		    active_cred, file_cred, NULL, td);
+
+	while (len > 0) {
+		chunk_len = MIN(len, CORE_BUF_SIZE);
+		copyin(base, buf, chunk_len);
+		error = gzio_write(p->gzs, buf, chunk_len);
+		if (error != 0)
+			break;
+		base += chunk_len;
+		len -= chunk_len;
 	}
 	return (error);
 }
 
-/* Coredump output parameters for sbuf drain routine. */
-struct sbuf_drain_core_params {
-	off_t		offset;
-	struct ucred	*active_cred;
-	struct ucred	*file_cred;
-	struct thread	*td;
-	struct vnode	*vp;
-#ifdef COMPRESS_USER_CORES
-	gzFile		gzfile;
+static int
+core_gz_write(void *base, size_t len, off_t offset, void *arg)
+{
+
+	return (core_write((struct coredump_params *)arg, base, len, offset,
+	    UIO_SYSSPACE));
+}
+#endif /* GZIO */
+
+static int
+core_write(struct coredump_params *p, void *base, size_t len, off_t offset,
+    enum uio_seg seg)
+{
+
+	return (vn_rdwr_inchunks(UIO_WRITE, p->vp, base, len, offset,
+	    seg, IO_UNIT | IO_DIRECT | IO_RANGELOCKED,
+	    p->active_cred, p->file_cred, NULL, p->td));
+}
+
+static int
+core_output(void *base, size_t len, off_t offset, struct coredump_params *p,
+    void *tmpbuf)
+{
+
+#ifdef GZIO
+	if (p->gzs != NULL)
+		return (compress_chunk(p, base, tmpbuf, len));
 #endif
-};
+	return (core_write(p, base, len, offset, UIO_USERSPACE));
+}
 
 /*
  * Drain into a core file.
@@ -1138,10 +1163,10 @@ struct sbuf_drain_core_params {
 static int
 sbuf_drain_core_output(void *arg, const char *data, int len)
 {
-	struct sbuf_drain_core_params *p;
+	struct coredump_params *p;
 	int error, locked;
 
-	p = (struct sbuf_drain_core_params *)arg;
+	p = (struct coredump_params *)arg;
 
 	/*
 	 * Some kern_proc out routines that print to this sbuf may
@@ -1154,16 +1179,13 @@ sbuf_drain_core_output(void *arg, const char *data, int len)
 	locked = PROC_LOCKED(p->td->td_proc);
 	if (locked)
 		PROC_UNLOCK(p->td->td_proc);
-#ifdef COMPRESS_USER_CORES
-	if (p->gzfile != Z_NULL)
-		error = compress_core(p->gzfile, NULL, __DECONST(char *, data),
-		    len, p->td);
+#ifdef GZIO
+	if (p->gzs != NULL)
+		error = gzio_write(p->gzs, __DECONST(char *, data), len);
 	else
 #endif
-		error = vn_rdwr_inchunks(UIO_WRITE, p->vp,
-		    __DECONST(void *, data), len, p->offset, UIO_SYSSPACE,
-		    IO_UNIT | IO_DIRECT | IO_RANGELOCKED, p->active_cred,
-		    p->file_cred, NULL, p->td);
+		error = core_write(p, __DECONST(void *, data), len, p->offset,
+		    UIO_SYSSPACE);
 	if (locked)
 		PROC_LOCK(p->td->td_proc);
 	if (error != 0)
@@ -1192,42 +1214,16 @@ __elfN(coredump)(struct thread *td, struct vnode *vp, off_t limit, int flags)
 	int error = 0;
 	struct sseg_closure seginfo;
 	struct note_info_list notelst;
+	struct coredump_params params;
 	struct note_info *ninfo;
-	void *hdr;
+	void *hdr, *tmpbuf;
 	size_t hdrsize, notesz, coresize;
+	boolean_t compress;
 
-	gzFile gzfile = Z_NULL;
-	char *core_buf = NULL;
-#ifdef COMPRESS_USER_CORES
-	char gzopen_flags[8];
-	char *p;
-	int doing_compress = flags & IMGACT_CORE_COMPRESS;
-#endif
-
+	compress = (flags & IMGACT_CORE_COMPRESS) != 0;
 	hdr = NULL;
 	TAILQ_INIT(&notelst);
 
-#ifdef COMPRESS_USER_CORES
-        if (doing_compress) {
-                p = gzopen_flags;
-                *p++ = 'w';
-                if (compress_user_cores_gzlevel >= 0 &&
-                    compress_user_cores_gzlevel <= 9)
-                        *p++ = '0' + compress_user_cores_gzlevel;
-                *p = 0;
-                gzfile = gz_open("", gzopen_flags, vp);
-                if (gzfile == Z_NULL) {
-                        error = EFAULT;
-                        goto done;
-                }
-                core_buf = malloc(CORE_BUF_SIZE, M_TEMP, M_WAITOK | M_ZERO);
-                if (!core_buf) {
-                        error = ENOMEM;
-                        goto done;
-                }
-        }
-#endif
-
 	/* Size the program segments. */
 	seginfo.count = 0;
 	seginfo.size = 0;
@@ -1254,6 +1250,28 @@ __elfN(coredump)(struct thread *td, struct vnode *vp, off_t limit, int flags)
 		goto done;
 	}
 
+	/* Set up core dump parameters. */
+	params.offset = 0;
+	params.active_cred = cred;
+	params.file_cred = NOCRED;
+	params.td = td;
+	params.vp = vp;
+	params.gzs = NULL;
+
+	tmpbuf = NULL;
+#ifdef GZIO
+	/* Create a compression stream if necessary. */
+	if (compress) {
+		params.gzs = gzio_init(core_gz_write, GZIO_DEFLATE,
+		    CORE_BUF_SIZE, compress_user_cores_gzlevel, &params);
+		if (params.gzs == NULL) {
+			error = EFAULT;
+			goto done;
+		}
+		tmpbuf = malloc(CORE_BUF_SIZE, M_TEMP, M_WAITOK | M_ZERO);
+        }
+#endif
+
 	/*
 	 * Allocate memory for building the header, fill it up,
 	 * and write it out following the notes.
@@ -1263,8 +1281,8 @@ __elfN(coredump)(struct thread *td, struct vnode *vp, off_t limit, int flags)
 		error = EINVAL;
 		goto done;
 	}
-	error = __elfN(corehdr)(td, vp, cred, seginfo.count, hdr, hdrsize,
-	    &notelst, notesz, gzfile);
+	error = __elfN(corehdr)(&params, seginfo.count, hdr, hdrsize, &notelst,
+	    notesz);
 
 	/* Write the contents of all of the writable segments. */
 	if (error == 0) {
@@ -1275,13 +1293,17 @@ __elfN(coredump)(struct thread *td, struct vnode *vp, off_t limit, int flags)
 		php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1;
 		offset = round_page(hdrsize + notesz);
 		for (i = 0; i < seginfo.count; i++) {
-			error = core_output(vp, (caddr_t)(uintptr_t)php->p_vaddr,
-			    php->p_filesz, offset, cred, NOCRED, curthread, core_buf, gzfile);
+			error = core_output((caddr_t)(uintptr_t)php->p_vaddr,
+			    php->p_filesz, offset, &params, tmpbuf);
 			if (error != 0)
 				break;
 			offset += php->p_filesz;
 			php++;
 		}
+#ifdef GZIO
+		if (error == 0 && compress)
+			error = gzio_flush(params.gzs);
+#endif
 	}
 	if (error) {
 		log(LOG_WARNING,
@@ -1290,11 +1312,11 @@ __elfN(coredump)(struct thread *td, struct vnode *vp, off_t limit, int flags)
 	}
 
 done:
-#ifdef COMPRESS_USER_CORES
-	if (core_buf)
-		free(core_buf, M_TEMP);
-	if (gzfile)
-		gzclose(gzfile);
+#ifdef GZIO
+	if (compress) {
+		free(tmpbuf, M_TEMP);
+		gzio_fini(params.gzs);
+	}
 #endif
 	while ((ninfo = TAILQ_FIRST(&notelst)) != NULL) {
 		TAILQ_REMOVE(&notelst, ninfo, link);
@@ -1419,29 +1441,19 @@ each_writable_segment(td, func, closure)
  * the page boundary.
  */
 static int
-__elfN(corehdr)(struct thread *td, struct vnode *vp, struct ucred *cred,
-    int numsegs, void *hdr, size_t hdrsize, struct note_info_list *notelst,
-    size_t notesz, gzFile gzfile)
+__elfN(corehdr)(struct coredump_params *p, int numsegs, void *hdr,
+    size_t hdrsize, struct note_info_list *notelst, size_t notesz)
 {
-	struct sbuf_drain_core_params params;
 	struct note_info *ninfo;
 	struct sbuf *sb;
 	int error;
 
 	/* Fill in the header. */
 	bzero(hdr, hdrsize);
-	__elfN(puthdr)(td, hdr, hdrsize, numsegs, notesz);
+	__elfN(puthdr)(p->td, hdr, hdrsize, numsegs, notesz);
 
-	params.offset = 0;
-	params.active_cred = cred;
-	params.file_cred = NOCRED;
-	params.td = td;
-	params.vp = vp;
-#ifdef COMPRESS_USER_CORES
-	params.gzfile = gzfile;
-#endif
 	sb = sbuf_new(NULL, NULL, CORE_BUF_SIZE, SBUF_FIXEDLEN);
-	sbuf_set_drain(sb, sbuf_drain_core_output, &params);
+	sbuf_set_drain(sb, sbuf_drain_core_output, p);
 	sbuf_start_section(sb, NULL);
 	sbuf_bcat(sb, hdr, hdrsize);
 	TAILQ_FOREACH(ninfo, notelst, link)
@@ -2108,58 +2120,6 @@ static struct execsw __elfN(execsw) = {
 };
 EXEC_SET(__CONCAT(elf, __ELF_WORD_SIZE), __elfN(execsw));
 
-#ifdef COMPRESS_USER_CORES
-/*
- * Compress and write out a core segment for a user process.
- *
- * 'inbuf' is the starting address of a VM segment in the process' address
- * space that is to be compressed and written out to the core file.  'dest_buf'
- * is a buffer in the kernel's address space.  The segment is copied from 
- * 'inbuf' to 'dest_buf' first before being processed by the compression
- * routine gzwrite().  This copying is necessary because the content of the VM
- * segment may change between the compression pass and the crc-computation pass
- * in gzwrite().  This is because realtime threads may preempt the UNIX kernel.
- *
- * If inbuf is NULL it is assumed that data is already copied to 'dest_buf'.
- */
-static int
-compress_core (gzFile file, char *inbuf, char *dest_buf, unsigned int len,
-    struct thread *td)
-{
-	int len_compressed;
-	int error = 0;
-	unsigned int chunk_len;
-
-	while (len) {
-		if (inbuf != NULL) {
-			chunk_len = (len > CORE_BUF_SIZE) ? CORE_BUF_SIZE : len;
-			copyin(inbuf, dest_buf, chunk_len);
-			inbuf += chunk_len;
-		} else {
-			chunk_len = len;
-		}
-		len_compressed = gzwrite(file, dest_buf, chunk_len);
-
-		EVENTHANDLER_INVOKE(app_coredump_progress, td, len_compressed);
-
-		if ((unsigned int)len_compressed != chunk_len) {
-			log(LOG_WARNING,
-			    "compress_core: length mismatch (0x%x returned, "
-			    "0x%x expected)\n", len_compressed, chunk_len);
-			EVENTHANDLER_INVOKE(app_coredump_error, td,
-			    "compress_core: length mismatch %x -> %x",
-			    chunk_len, len_compressed);
-			error = EFAULT;
-			break;
-		}
-		len -= chunk_len;
-		maybe_yield();
-	}
-
-	return (error);
-}
-#endif /* COMPRESS_USER_CORES */
-
 static vm_prot_t
 __elfN(trans_prot)(Elf_Word flags)
 {
diff --git a/sys/kern/kern_gzio.c b/sys/kern/kern_gzio.c
index 15dc3015ca25..a4974a729c3f 100644
--- a/sys/kern/kern_gzio.c
+++ b/sys/kern/kern_gzio.c
@@ -1,400 +1,223 @@
-/*
- * $Id: kern_gzio.c,v 1.6 2008-10-18 22:54:45 lbazinet Exp $
+/*-
+ * Copyright (c) 2014 Mark Johnston <markj@FreeBSD.org>
  *
- * core_gzip.c -- gzip routines used in compressing user process cores
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
  *
- * This file is derived from src/lib/libz/gzio.c in FreeBSD.
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
-/* gzio.c -- IO on .gz files
- * Copyright (C) 1995-1998 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h
- *
- */
-
-/* @(#) $FreeBSD$ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
-#include <sys/proc.h>
+
+#include <sys/gzio.h>
+#include <sys/kernel.h>
 #include <sys/malloc.h>
-#include <sys/vnode.h>
-#include <sys/syslog.h>
-#include <sys/endian.h>
+
 #include <net/zutil.h>
-#include <sys/libkern.h>
 
-#include <sys/vnode.h>
-#include <sys/mount.h>
+#define	KERN_GZ_HDRLEN		10	/* gzip header length */
+#define	KERN_GZ_TRAILERLEN	8	/* gzip trailer length */
+#define	KERN_GZ_MAGIC1		0x1f	/* first magic byte */
+#define	KERN_GZ_MAGIC2		0x8b	/* second magic byte */
 
-#define GZ_HEADER_LEN	10
+MALLOC_DEFINE(M_GZIO, "gzio", "zlib state");
 
-#ifndef Z_BUFSIZE
-#  ifdef MAXSEG_64K
-#    define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
-#  else
-#    define Z_BUFSIZE 16384
-#  endif
-#endif
-#ifndef Z_PRINTF_BUFSIZE
-#  define Z_PRINTF_BUFSIZE 4096
-#endif
+struct gzio_stream {
+	uint8_t *	gz_buffer;	/* output buffer */
+	size_t		gz_bufsz;	/* total buffer size */
+	off_t		gz_off;		/* offset into the output stream */
+	enum gzio_mode	gz_mode;	/* stream mode */
+	uint32_t	gz_crc;		/* stream CRC32 */
+	gzio_cb		gz_cb;		/* output callback */
+	void *		gz_arg;		/* private callback arg */
+	z_stream	gz_stream;	/* zlib state */
+};
 
-#define ALLOC(size) malloc(size, M_TEMP, M_WAITOK | M_ZERO)
-#define TRYFREE(p) {if (p) free(p, M_TEMP);}
+static void *	gz_alloc(void *, u_int, u_int);
+static void	gz_free(void *, void *);
+static int	gz_write(struct gzio_stream *, void *, u_int, int);
 
-static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
-
-/* gzip flag byte */
-#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
-#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
-#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
-#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
-#define COMMENT      0x10 /* bit 4 set: file comment present */
-#define RESERVED     0xE0 /* bits 5..7: reserved */
-
-typedef struct gz_stream {
-    z_stream stream;
-    int      z_err;   /* error code for last stream operation */
-    int      z_eof;   /* set if end of input file */
-    struct vnode *file; /* vnode pointer of .gz file */
-    Byte     *inbuf;  /* input buffer */
-    Byte     *outbuf; /* output buffer */
-    uLong    crc;     /* crc32 of uncompressed data */
-    char     *msg;    /* error message */
-    char     *path;   /* path name for debugging only */
-    int      transparent; /* 1 if input file is not a .gz file */
-    char     mode;    /* 'w' or 'r' */
-    long     startpos; /* start of compressed data in file (header skipped) */
-    off_t    outoff;  /* current offset in output file */
-    int	     flags;
-} gz_stream;
-
-
-local int do_flush        OF((gzFile file, int flush));
-local int    destroy      OF((gz_stream *s));
-local void   putU32      OF((gz_stream *file, uint32_t x));
-local void *gz_alloc      OF((void *notused, u_int items, u_int size));
-local void gz_free        OF((void *notused, void *ptr));
-
-/* ===========================================================================
-     Opens a gzip (.gz) file for reading or writing. The mode parameter
-   is as in fopen ("rb" or "wb"). The file is given either by file descriptor
-   or path name (if fd == -1).
-     gz_open return NULL if the file could not be opened or if there was
-   insufficient memory to allocate the (de)compression state; errno
-   can be checked to distinguish the two cases (if errno is zero, the
-   zlib error is Z_MEM_ERROR).
-*/
-gzFile gz_open (path, mode, vp)
-    const char *path;
-    const char *mode;
-    struct vnode *vp;
+struct gzio_stream *
+gzio_init(gzio_cb cb, enum gzio_mode mode, size_t bufsz, int level, void *arg)
 {
-    int err;
-    int level = Z_DEFAULT_COMPRESSION; /* compression level */
-    int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
-    const char *p = mode;
-    gz_stream *s;
-    char fmode[80]; /* copy of mode, without the compression level */
-    char *m = fmode;
-    ssize_t resid;
-    int error;
-    char buf[GZ_HEADER_LEN + 1];
+	struct gzio_stream *s;
+	uint8_t *hdr;
+	int error;
 
-    if (!path || !mode) return Z_NULL;
+	if (bufsz < KERN_GZ_HDRLEN)
+		return (NULL);
+	if (mode != GZIO_DEFLATE)
+		return (NULL);
 
-    s = (gz_stream *)ALLOC(sizeof(gz_stream));
-    if (!s) return Z_NULL;
+	s = gz_alloc(NULL, 1, sizeof(*s));
+	s->gz_bufsz = bufsz;
+	s->gz_buffer = gz_alloc(NULL, 1, s->gz_bufsz);
+	s->gz_mode = mode;
+	s->gz_crc = ~0U;
+	s->gz_cb = cb;
+	s->gz_arg = arg;
 
-    s->stream.zalloc = (alloc_func)gz_alloc;
-    s->stream.zfree = (free_func)gz_free;
-    s->stream.opaque = (voidpf)0;
-    s->stream.next_in = s->inbuf = Z_NULL;
-    s->stream.next_out = s->outbuf = Z_NULL;
-    s->stream.avail_in = s->stream.avail_out = 0;
-    s->file = NULL;
-    s->z_err = Z_OK;
-    s->z_eof = 0;
-    s->crc = 0;
-    s->msg = NULL;
-    s->transparent = 0;
-    s->outoff = 0;
-    s->flags = 0;
+	s->gz_stream.zalloc = gz_alloc;
+	s->gz_stream.zfree = gz_free;
+	s->gz_stream.opaque = NULL;
+	s->gz_stream.next_in = Z_NULL;
+	s->gz_stream.avail_in = 0;
 
-    s->path = (char*)ALLOC(strlen(path)+1);
-    if (s->path == NULL) {
-        return destroy(s), (gzFile)Z_NULL;
-    }
-    strcpy(s->path, path); /* do this early for debugging */
+	error = deflateInit2(&s->gz_stream, level, Z_DEFLATED, -MAX_WBITS,
+	    DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+	if (error != 0)
+		goto fail;
 
-    s->mode = '\0';
-    do {
-        if (*p == 'r') s->mode = 'r';
-        if (*p == 'w' || *p == 'a') s->mode = 'w';
-        if (*p >= '0' && *p <= '9') {
-	    level = *p - '0';
-	} else if (*p == 'f') {
-	  strategy = Z_FILTERED;
-	} else if (*p == 'h') {
-	  strategy = Z_HUFFMAN_ONLY;
-	} else {
-	    *m++ = *p; /* copy the mode */
-	}
-    } while (*p++ && m != fmode + sizeof(fmode));
+	s->gz_stream.avail_out = s->gz_bufsz;
+	s->gz_stream.next_out = s->gz_buffer;
 
-    if (s->mode != 'w') {
-        log(LOG_ERR, "gz_open: mode is not w (%c)\n", s->mode);
-        return destroy(s), (gzFile)Z_NULL;
-    }
-    
-    err = deflateInit2(&(s->stream), level,
-                       Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
-    /* windowBits is passed < 0 to suppress zlib header */
+	/* Write the gzip header to the output buffer. */
+	hdr = s->gz_buffer;
+	memset(hdr, 0, KERN_GZ_HDRLEN);
+	hdr[0] = KERN_GZ_MAGIC1;
+	hdr[1] = KERN_GZ_MAGIC2;
+	hdr[2] = Z_DEFLATED;
+	hdr[9] = OS_CODE;
+	s->gz_stream.next_out += KERN_GZ_HDRLEN;
+	s->gz_stream.avail_out -= KERN_GZ_HDRLEN;
 
-    s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
-    if (err != Z_OK || s->outbuf == Z_NULL) {
-        return destroy(s), (gzFile)Z_NULL;
-    }
+	return (s);
 
-    s->stream.avail_out = Z_BUFSIZE;
-    s->file = vp;
-
-    /* Write a very simple .gz header:
-     */
-    snprintf(buf, sizeof(buf), "%c%c%c%c%c%c%c%c%c%c", gz_magic[0],
-             gz_magic[1], Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/,
-             0 /*xflags*/, OS_CODE);
-
-    if ((error = vn_rdwr(UIO_WRITE, s->file, buf, GZ_HEADER_LEN, s->outoff,
-                         UIO_SYSSPACE, IO_UNIT, curproc->p_ucred,
-                         NOCRED, &resid, curthread))) {
-        s->outoff += GZ_HEADER_LEN - resid;
-        return destroy(s), (gzFile)Z_NULL;
-    }
-    s->outoff += GZ_HEADER_LEN;
-    s->startpos = 10L;
-    
-    return (gzFile)s;
+fail:
+	gz_free(NULL, s->gz_buffer);
+	gz_free(NULL, s);
+	return (NULL);
 }
 
-
- /* ===========================================================================
- * Cleanup then free the given gz_stream. Return a zlib error code.
-   Try freeing in the reverse order of allocations.
- */
-local int destroy (s)
-    gz_stream *s;
+int
+gzio_write(struct gzio_stream *s, void *data, u_int len)
 {
-    int err = Z_OK;
 
-    if (!s) return Z_STREAM_ERROR;
-
-    TRYFREE(s->msg);
-
-    if (s->stream.state != NULL) {
-	if (s->mode == 'w') {
-	    err = deflateEnd(&(s->stream));
-	}
-    }
-    if (s->z_err < 0) err = s->z_err;
-
-    TRYFREE(s->inbuf);
-    TRYFREE(s->outbuf);
-    TRYFREE(s->path);
-    TRYFREE(s);
-    return err;
+	return (gz_write(s, data, len, Z_NO_FLUSH));
 }
 
-
-/* ===========================================================================
-     Writes the given number of uncompressed bytes into the compressed file.
-   gzwrite returns the number of bytes actually written (0 in case of error).
-*/
-int ZEXPORT gzwrite (file, buf, len)
-    gzFile file;
-    const voidp buf;
-    unsigned len;
+int
+gzio_flush(struct gzio_stream *s)
 {
-    gz_stream *s = (gz_stream*)file;
-    off_t curoff;
-    size_t resid;
-    int error;
 
-    if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
-
-    s->stream.next_in = (Bytef*)buf;
-    s->stream.avail_in = len;
-
-    curoff = s->outoff;
-    while (s->stream.avail_in != 0) {
-
-        if (s->stream.avail_out == 0) {
-
-            s->stream.next_out = s->outbuf;
-            error = vn_rdwr_inchunks(UIO_WRITE, s->file, s->outbuf, Z_BUFSIZE,
-                        curoff, UIO_SYSSPACE, IO_UNIT,
-                        curproc->p_ucred, NOCRED, &resid, curthread);
-            if (error) {
-                log(LOG_ERR, "gzwrite: vn_rdwr return %d\n", error);
-                curoff += Z_BUFSIZE - resid;
-                s->z_err = Z_ERRNO;
-                break;
-            }
-            curoff += Z_BUFSIZE;
-            s->stream.avail_out = Z_BUFSIZE;
-        }
-        s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
-        if (s->z_err != Z_OK) {
-            log(LOG_ERR,
-                "gzwrite: deflate returned error %d\n", s->z_err);
-            break;
-        }
-    }
-
-    s->crc = ~crc32_raw(buf, len, ~s->crc);
-    s->outoff = curoff;
-
-    return (int)(len - s->stream.avail_in);
+	return (gz_write(s, NULL, 0, Z_FINISH));
 }
 
-
-/* ===========================================================================
-     Flushes all pending output into the compressed file. The parameter
-   flush is as in the deflate() function.
-*/
-local int do_flush (file, flush)
-    gzFile file;
-    int flush;
+void
+gzio_fini(struct gzio_stream *s)
 {
-    uInt len;
-    int done = 0;
-    gz_stream *s = (gz_stream*)file;
-    off_t curoff = s->outoff;
-    size_t resid;
-    int error;
 
-    if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
-
-    if (s->stream.avail_in) {
-        log(LOG_WARNING, "do_flush: avail_in non-zero on entry\n");
-    } 
-
-    s->stream.avail_in = 0; /* should be zero already anyway */
-
-    for (;;) {
-        len = Z_BUFSIZE - s->stream.avail_out;
-
-        if (len != 0) {
-            error = vn_rdwr_inchunks(UIO_WRITE, s->file, s->outbuf, len, curoff,
-                        UIO_SYSSPACE, IO_UNIT, curproc->p_ucred,
-                        NOCRED, &resid, curthread);
-	    if (error) {
-                s->z_err = Z_ERRNO;
-                s->outoff = curoff + len - resid;
-                return Z_ERRNO;
-            }
-            s->stream.next_out = s->outbuf;
-            s->stream.avail_out = Z_BUFSIZE;
-            curoff += len;
-        }
-        if (done) break;
-        s->z_err = deflate(&(s->stream), flush);
-
-	/* Ignore the second of two consecutive flushes: */
-	if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
-
-        /* deflate has finished flushing only when it hasn't used up
-         * all the available space in the output buffer: 
-         */
-        done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
- 
-        if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
-    }
-    s->outoff = curoff;
-
-    return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+	(void)deflateEnd(&s->gz_stream);
+	gz_free(NULL, s->gz_buffer);
+	gz_free(NULL, s);
 }
 
-int ZEXPORT gzflush (file, flush)
-     gzFile file;
-     int flush;
-{
-    gz_stream *s = (gz_stream*)file;
-    int err = do_flush (file, flush);
-
-    if (err) return err;
-    return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
-}
-
-
-/* ===========================================================================
-   Outputs a long in LSB order to the given file
-*/
-local void putU32 (s, x)
-    gz_stream *s;
-    uint32_t x;
-{
-    uint32_t xx;
-    off_t curoff = s->outoff;
-    ssize_t resid;
-
-#if BYTE_ORDER == BIG_ENDIAN
-    xx = bswap32(x);
-#else
-    xx = x;
-#endif
-    vn_rdwr(UIO_WRITE, s->file, (caddr_t)&xx, sizeof(xx), curoff,
-            UIO_SYSSPACE, IO_UNIT, curproc->p_ucred,
-            NOCRED, &resid, curthread);
-    s->outoff += sizeof(xx) - resid;
-}
-
-
-/* ===========================================================================
-     Flushes all pending output if necessary, closes the compressed file
-   and deallocates all the (de)compression state.
-*/
-int ZEXPORT gzclose (file)
-    gzFile file;
-{
-    int err;
-    gz_stream *s = (gz_stream*)file;
-
-    if (s == NULL) return Z_STREAM_ERROR;
-
-    if (s->mode == 'w') {
-        err = do_flush (file, Z_FINISH);
-        if (err != Z_OK) {
-            log(LOG_ERR, "gzclose: do_flush failed (err %d)\n", err);
-            return destroy((gz_stream*)file);
-        }
-#if 0
-	printf("gzclose: putting crc: %lld total: %lld\n",
-	    (long long)s->crc, (long long)s->stream.total_in);
-	printf("sizeof uLong = %d\n", (int)sizeof(uLong));
-#endif
-        putU32 (s, s->crc);
-        putU32 (s, (uint32_t) s->stream.total_in);
-    }
-    return destroy((gz_stream*)file);
-}
-
-/*
- * Space allocation and freeing routines for use by zlib routines when called
- * from gzip modules.
- */
 static void *
-gz_alloc(void *notused __unused, u_int items, u_int size)
+gz_alloc(void *arg __unused, u_int n, u_int sz)
 {
-    void *ptr;
 
-    MALLOC(ptr, void *, items * size, M_TEMP, M_NOWAIT | M_ZERO);
-    return ptr;
+	/*
+	 * Memory for zlib state is allocated using M_NODUMP since it may be
+	 * used to compress a kernel dump, and we don't want zlib to attempt to
+	 * compress its own state.
+	 */
+	return (malloc(n * sz, M_GZIO, M_WAITOK | M_ZERO | M_NODUMP));
 }
-                                     
+
 static void
-gz_free(void *opaque __unused, void *ptr)
+gz_free(void *arg __unused, void *ptr)
 {
-    FREE(ptr, M_TEMP);
+
+	free(ptr, M_GZIO);
 }
 
+static int
+gz_write(struct gzio_stream *s, void *buf, u_int len, int zflag)
+{
+	uint8_t trailer[KERN_GZ_TRAILERLEN];
+	size_t room;
+	int error, zerror;
+
+	KASSERT(zflag == Z_FINISH || zflag == Z_NO_FLUSH,
+	    ("unexpected flag %d", zflag));
+	KASSERT(s->gz_mode == GZIO_DEFLATE,
+	    ("invalid stream mode %d", s->gz_mode));
+
+	if (len > 0) {
+		s->gz_stream.avail_in = len;
+		s->gz_stream.next_in = buf;
+		s->gz_crc = crc32_raw(buf, len, s->gz_crc);
+	} else
+		s->gz_crc ^= ~0U;
+
+	error = 0;
+	do {
+		zerror = deflate(&s->gz_stream, zflag);
+		if (zerror != Z_OK && zerror != Z_STREAM_END) {
+			error = EIO;
+			break;
+		}
+
+		if (s->gz_stream.avail_out == 0 || zerror == Z_STREAM_END) {
+			/*
+			 * Our output buffer is full or there's nothing left
+			 * to produce, so we're flushing the buffer.
+			 */
+			len = s->gz_bufsz - s->gz_stream.avail_out;
+			if (zerror == Z_STREAM_END) {
+				/*
+				 * Try to pack as much of the trailer into the
+				 * output buffer as we can.
+				 */
+				((uint32_t *)trailer)[0] = s->gz_crc;
+				((uint32_t *)trailer)[1] =
+				    s->gz_stream.total_in;
+				room = MIN(KERN_GZ_TRAILERLEN,
+				    s->gz_bufsz - len);
+				memcpy(s->gz_buffer + len, trailer, room);
+				len += room;
+			}
+
+			error = s->gz_cb(s->gz_buffer, len, s->gz_off,
+			    s->gz_arg);
+			if (error != 0)
+				break;
+
+			s->gz_off += len;
+			s->gz_stream.next_out = s->gz_buffer;
+			s->gz_stream.avail_out = s->gz_bufsz;
+
+			/*
+			 * If we couldn't pack the trailer into the output
+			 * buffer, write it out now.
+			 */
+			if (zerror == Z_STREAM_END && room < KERN_GZ_TRAILERLEN)
+				error = s->gz_cb(trailer + room,
+				    KERN_GZ_TRAILERLEN - room, s->gz_off,
+				    s->gz_arg);
+		}
+	} while (zerror != Z_STREAM_END &&
+	    (zflag == Z_FINISH || s->gz_stream.avail_in > 0));
+
+	return (error);
+}
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index 57f66b02632d..58d9707029c7 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -38,8 +38,8 @@
 __FBSDID("$FreeBSD$");
 
 #include "opt_compat.h"
+#include "opt_gzio.h"
 #include "opt_ktrace.h"
-#include "opt_core.h"
 
 #include <sys/param.h>
 #include <sys/ctype.h>
@@ -3075,17 +3075,18 @@ sysctl_debug_num_cores_check (SYSCTL_HANDLER_ARGS)
 SYSCTL_PROC(_debug, OID_AUTO, ncores, CTLTYPE_INT|CTLFLAG_RW,
 	    0, sizeof(int), sysctl_debug_num_cores_check, "I", "");
 
-#if defined(COMPRESS_USER_CORES)
-int compress_user_cores = 1;
-SYSCTL_INT(_kern, OID_AUTO, compress_user_cores, CTLFLAG_RW,
+#define	GZ_SUFFIX	".gz"
+
+#ifdef GZIO
+static int compress_user_cores = 1;
+SYSCTL_INT(_kern, OID_AUTO, compress_user_cores, CTLFLAG_RWTUN,
     &compress_user_cores, 0, "Compression of user corefiles");
 
-int compress_user_cores_gzlevel = -1; /* default level */
-SYSCTL_INT(_kern, OID_AUTO, compress_user_cores_gzlevel, CTLFLAG_RW,
-    &compress_user_cores_gzlevel, -1, "Corefile gzip compression level");
-
-#define GZ_SUFFIX	".gz"
-#define GZ_SUFFIX_LEN	3
+int compress_user_cores_gzlevel = 6;
+SYSCTL_INT(_kern, OID_AUTO, compress_user_cores_gzlevel, CTLFLAG_RWTUN,
+    &compress_user_cores_gzlevel, 0, "Corefile gzip compression level");
+#else
+static int compress_user_cores = 0;
 #endif
 
 static char corefilename[MAXPATHLEN] = {"%N.core"};
@@ -3162,10 +3163,8 @@ corefile_open(const char *comm, uid_t uid, pid_t pid, struct thread *td,
 		}
 	}
 	free(hostname, M_TEMP);
-#ifdef COMPRESS_USER_CORES
 	if (compress)
 		sbuf_printf(&sb, GZ_SUFFIX);
-#endif
 	if (sbuf_error(&sb) != 0) {
 		log(LOG_ERR, "pid %ld (%s), uid (%lu): corename is too "
 		    "long\n", (long)pid, comm, (u_long)uid);
@@ -3260,18 +3259,12 @@ coredump(struct thread *td)
 	char *name;			/* name of corefile */
 	void *rl_cookie;
 	off_t limit;
-	int compress;
 	char *data = NULL;
 	char *fullpath, *freepath = NULL;
 	size_t len;
 	static const char comm_name[] = "comm=";
 	static const char core_name[] = "core=";
 
-#ifdef COMPRESS_USER_CORES
-	compress = compress_user_cores;
-#else
-	compress = 0;
-#endif
 	PROC_LOCK_ASSERT(p, MA_OWNED);
 	MPASS((p->p_flag & P_HADTHREADS) == 0 || p->p_singlethread == td);
 	_STOPEVENT(p, S_CORE, 0);
@@ -3297,8 +3290,8 @@ coredump(struct thread *td)
 	}
 	PROC_UNLOCK(p);
 
-	error = corefile_open(p->p_comm, cred->cr_uid, p->p_pid, td, compress,
-	    &vp, &name);
+	error = corefile_open(p->p_comm, cred->cr_uid, p->p_pid, td,
+	    compress_user_cores, &vp, &name);
 	if (error != 0)
 		return (error);
 
@@ -3337,7 +3330,7 @@ coredump(struct thread *td)
 
 	if (p->p_sysent->sv_coredump != NULL) {
 		error = p->p_sysent->sv_coredump(td, vp, limit,
-		    compress ? IMGACT_CORE_COMPRESS : 0);
+		    compress_user_cores ? IMGACT_CORE_COMPRESS : 0);
 	} else {
 		error = ENOSYS;
 	}
diff --git a/sys/net/zlib.h b/sys/net/zlib.h
index 04941df360b5..16edae12b6f6 100644
--- a/sys/net/zlib.h
+++ b/sys/net/zlib.h
@@ -1010,13 +1010,6 @@ extern int EXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
 
 uLongf *get_crc_table OF((void)); /* can be used by asm versions of crc32() */
 
-#ifdef _KERNEL
-struct vnode;
-extern gzFile gz_open     OF((const char *path, const char *mode,
-	                              struct vnode *vp));
-#endif
-
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/sys/sys/gzio.h b/sys/sys/gzio.h
new file mode 100644
index 000000000000..c61c2818f2e9
--- /dev/null
+++ b/sys/sys/gzio.h
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2014 Mark Johnston <markj@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SYS__GZIO_H_
+#define _SYS__GZIO_H_
+
+#ifdef _KERNEL
+
+enum gzio_mode {
+	GZIO_DEFLATE,
+};
+
+typedef int (*gzio_cb)(void *, size_t, off_t, void *);
+
+struct gzio_stream;
+
+struct gzio_stream *gzio_init(gzio_cb cb, enum gzio_mode, size_t, int, void *);
+int		gzio_write(struct gzio_stream *, void *, u_int);
+int		gzio_flush(struct gzio_stream *);
+void		gzio_fini(struct gzio_stream *);
+
+#endif /* _KERNEL */
+
+#endif /* _SYS__GZIO_H_ */