]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - cddl/contrib/opensolaris/lib/libzpool/common/kernel.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / cddl / contrib / opensolaris / lib / libzpool / common / kernel.c
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25
26 #pragma ident   "%Z%%M% %I%     %E% SMI"
27
28 #include <assert.h>
29 #include <fcntl.h>
30 #include <poll.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <zlib.h>
35 #include <sys/spa.h>
36 #include <sys/stat.h>
37 #include <sys/processor.h>
38 #include <sys/zfs_context.h>
39 #include <sys/zmod.h>
40 #include <sys/utsname.h>
41
42 /*
43  * Emulation of kernel services in userland.
44  */
45
46 int hz = 119;   /* frequency when using gethrtime() >> 23 for lbolt */
47 uint64_t physmem;
48 vnode_t *rootdir = (vnode_t *)0xabcd1234;
49 char hw_serial[11];
50
51 struct utsname utsname = {
52         "userland", "libzpool", "1", "1", "na"
53 };
54
55 /*
56  * =========================================================================
57  * threads
58  * =========================================================================
59  */
60 /*ARGSUSED*/
61 kthread_t *
62 zk_thread_create(void (*func)(), void *arg)
63 {
64         thread_t tid;
65
66         VERIFY(thr_create(0, 0, (void *(*)(void *))func, arg, THR_DETACHED,
67             &tid) == 0);
68
69         return ((void *)(uintptr_t)tid);
70 }
71
72 /*
73  * =========================================================================
74  * kstats
75  * =========================================================================
76  */
77 /*ARGSUSED*/
78 kstat_t *
79 kstat_create(char *module, int instance, char *name, char *class,
80     uchar_t type, ulong_t ndata, uchar_t ks_flag)
81 {
82         return (NULL);
83 }
84
85 /*ARGSUSED*/
86 void
87 kstat_install(kstat_t *ksp)
88 {}
89
90 /*ARGSUSED*/
91 void
92 kstat_delete(kstat_t *ksp)
93 {}
94
95 /*
96  * =========================================================================
97  * mutexes
98  * =========================================================================
99  */
100 void
101 zmutex_init(kmutex_t *mp)
102 {
103         mp->m_owner = NULL;
104         (void) _mutex_init(&mp->m_lock, USYNC_THREAD, NULL);
105 }
106
107 void
108 zmutex_destroy(kmutex_t *mp)
109 {
110         ASSERT(mp->m_owner == NULL);
111         (void) _mutex_destroy(&(mp)->m_lock);
112         mp->m_owner = (void *)-1UL;
113 }
114
115 void
116 mutex_enter(kmutex_t *mp)
117 {
118         ASSERT(mp->m_owner != (void *)-1UL);
119         ASSERT(mp->m_owner != curthread);
120         VERIFY(mutex_lock(&mp->m_lock) == 0);
121         ASSERT(mp->m_owner == NULL);
122         mp->m_owner = curthread;
123 }
124
125 int
126 mutex_tryenter(kmutex_t *mp)
127 {
128         ASSERT(mp->m_owner != (void *)-1UL);
129         if (mutex_trylock(&mp->m_lock) == 0) {
130                 ASSERT(mp->m_owner == NULL);
131                 mp->m_owner = curthread;
132                 return (1);
133         } else {
134                 return (0);
135         }
136 }
137
138 void
139 mutex_exit(kmutex_t *mp)
140 {
141         ASSERT(mp->m_owner == curthread);
142         mp->m_owner = NULL;
143         VERIFY(mutex_unlock(&mp->m_lock) == 0);
144 }
145
146 void *
147 mutex_owner(kmutex_t *mp)
148 {
149         return (mp->m_owner);
150 }
151
152 /*
153  * =========================================================================
154  * rwlocks
155  * =========================================================================
156  */
157 /*ARGSUSED*/
158 void
159 rw_init(krwlock_t *rwlp, char *name, int type, void *arg)
160 {
161         rwlock_init(&rwlp->rw_lock, USYNC_THREAD, NULL);
162         rwlp->rw_owner = NULL;
163         rwlp->rw_count = 0;
164 }
165
166 void
167 rw_destroy(krwlock_t *rwlp)
168 {
169         rwlock_destroy(&rwlp->rw_lock);
170         rwlp->rw_owner = (void *)-1UL;
171         rwlp->rw_count = -2;
172 }
173
174 void
175 rw_enter(krwlock_t *rwlp, krw_t rw)
176 {
177         //ASSERT(!RW_LOCK_HELD(rwlp));
178         ASSERT(rwlp->rw_owner != (void *)-1UL);
179         ASSERT(rwlp->rw_owner != curthread);
180
181         if (rw == RW_READER) {
182                 (void) rw_rdlock(&rwlp->rw_lock);
183                 ASSERT(rwlp->rw_count >= 0);
184                 atomic_add_int(&rwlp->rw_count, 1);
185         } else {
186                 (void) rw_wrlock(&rwlp->rw_lock);
187                 ASSERT(rwlp->rw_count == 0);
188                 rwlp->rw_count = -1;
189                 rwlp->rw_owner = curthread;
190         }
191 }
192
193 void
194 rw_exit(krwlock_t *rwlp)
195 {
196         ASSERT(rwlp->rw_owner != (void *)-1UL);
197
198         if (rwlp->rw_owner == curthread) {
199                 /* Write locked. */
200                 ASSERT(rwlp->rw_count == -1);
201                 rwlp->rw_count = 0;
202                 rwlp->rw_owner = NULL;
203         } else {
204                 /* Read locked. */
205                 ASSERT(rwlp->rw_count > 0);
206                 atomic_add_int(&rwlp->rw_count, -1);
207         }
208         (void) rw_unlock(&rwlp->rw_lock);
209 }
210
211 int
212 rw_tryenter(krwlock_t *rwlp, krw_t rw)
213 {
214         int rv;
215
216         ASSERT(rwlp->rw_owner != (void *)-1UL);
217         ASSERT(rwlp->rw_owner != curthread);
218
219         if (rw == RW_READER)
220                 rv = rw_tryrdlock(&rwlp->rw_lock);
221         else
222                 rv = rw_trywrlock(&rwlp->rw_lock);
223
224         if (rv == 0) {
225                 ASSERT(rwlp->rw_owner == NULL);
226                 if (rw == RW_READER) {
227                         ASSERT(rwlp->rw_count >= 0);
228                         atomic_add_int(&rwlp->rw_count, 1);
229                 } else {
230                         ASSERT(rwlp->rw_count == 0);
231                         rwlp->rw_count = -1;
232                         rwlp->rw_owner = curthread;
233                 }
234                 return (1);
235         }
236
237         return (0);
238 }
239
240 /*ARGSUSED*/
241 int
242 rw_tryupgrade(krwlock_t *rwlp)
243 {
244         ASSERT(rwlp->rw_owner != (void *)-1UL);
245
246         return (0);
247 }
248
249 int
250 rw_lock_held(krwlock_t *rwlp)
251 {
252
253         return (rwlp->rw_count != 0);
254 }
255
256 /*
257  * =========================================================================
258  * condition variables
259  * =========================================================================
260  */
261 /*ARGSUSED*/
262 void
263 cv_init(kcondvar_t *cv, char *name, int type, void *arg)
264 {
265         VERIFY(cond_init(cv, name, NULL) == 0);
266 }
267
268 void
269 cv_destroy(kcondvar_t *cv)
270 {
271         VERIFY(cond_destroy(cv) == 0);
272 }
273
274 void
275 cv_wait(kcondvar_t *cv, kmutex_t *mp)
276 {
277         ASSERT(mutex_owner(mp) == curthread);
278         mp->m_owner = NULL;
279         int ret = cond_wait(cv, &mp->m_lock);
280         VERIFY(ret == 0 || ret == EINTR);
281         mp->m_owner = curthread;
282 }
283
284 clock_t
285 cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime)
286 {
287         int error;
288         struct timespec ts;
289         struct timeval tv;
290         clock_t delta;
291
292         ASSERT(abstime > 0);
293 top:
294         delta = abstime;
295         if (delta <= 0)
296                 return (-1);
297
298         if (gettimeofday(&tv, NULL) != 0)
299                 assert(!"gettimeofday() failed");
300
301         ts.tv_sec = tv.tv_sec + delta / hz;
302         ts.tv_nsec = tv.tv_usec * 1000 + (delta % hz) * (NANOSEC / hz);
303         ASSERT(ts.tv_nsec >= 0);
304
305         if(ts.tv_nsec >= NANOSEC) {
306                 ts.tv_sec++;
307                 ts.tv_nsec -= NANOSEC;
308         }
309
310         ASSERT(mutex_owner(mp) == curthread);
311         mp->m_owner = NULL;
312         error = pthread_cond_timedwait(cv, &mp->m_lock, &ts);
313         mp->m_owner = curthread;
314
315         if (error == EINTR)
316                 goto top;
317
318         if (error == ETIMEDOUT)
319                 return (-1);
320
321         ASSERT(error == 0);
322
323         return (1);
324 }
325
326 void
327 cv_signal(kcondvar_t *cv)
328 {
329         VERIFY(cond_signal(cv) == 0);
330 }
331
332 void
333 cv_broadcast(kcondvar_t *cv)
334 {
335         VERIFY(cond_broadcast(cv) == 0);
336 }
337
338 /*
339  * =========================================================================
340  * vnode operations
341  * =========================================================================
342  */
343 /*
344  * Note: for the xxxat() versions of these functions, we assume that the
345  * starting vp is always rootdir (which is true for spa_directory.c, the only
346  * ZFS consumer of these interfaces).  We assert this is true, and then emulate
347  * them by adding '/' in front of the path.
348  */
349
350 /*ARGSUSED*/
351 int
352 vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3)
353 {
354         int fd;
355         vnode_t *vp;
356         int old_umask;
357         char realpath[MAXPATHLEN];
358         struct stat64 st;
359
360         /*
361          * If we're accessing a real disk from userland, we need to use
362          * the character interface to avoid caching.  This is particularly
363          * important if we're trying to look at a real in-kernel storage
364          * pool from userland, e.g. via zdb, because otherwise we won't
365          * see the changes occurring under the segmap cache.
366          * On the other hand, the stupid character device returns zero
367          * for its size.  So -- gag -- we open the block device to get
368          * its size, and remember it for subsequent VOP_GETATTR().
369          */
370         if (strncmp(path, "/dev/", 5) == 0) {
371                 char *dsk;
372                 fd = open64(path, O_RDONLY);
373                 if (fd == -1)
374                         return (errno);
375                 if (fstat64(fd, &st) == -1) {
376                         close(fd);
377                         return (errno);
378                 }
379                 close(fd);
380                 (void) sprintf(realpath, "%s", path);
381                 dsk = strstr(path, "/dsk/");
382                 if (dsk != NULL)
383                         (void) sprintf(realpath + (dsk - path) + 1, "r%s",
384                             dsk + 1);
385         } else {
386                 (void) sprintf(realpath, "%s", path);
387                 if (!(flags & FCREAT) && stat64(realpath, &st) == -1)
388                         return (errno);
389         }
390
391         if (flags & FCREAT)
392                 old_umask = umask(0);
393
394         /*
395          * The construct 'flags - FREAD' conveniently maps combinations of
396          * FREAD and FWRITE to the corresponding O_RDONLY, O_WRONLY, and O_RDWR.
397          */
398         fd = open64(realpath, flags - FREAD, mode);
399
400         if (flags & FCREAT)
401                 (void) umask(old_umask);
402
403         if (fd == -1)
404                 return (errno);
405
406         if (fstat64(fd, &st) == -1) {
407                 close(fd);
408                 return (errno);
409         }
410
411         (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
412
413         *vpp = vp = umem_zalloc(sizeof (vnode_t), UMEM_NOFAIL);
414
415         vp->v_fd = fd;
416         if (S_ISCHR(st.st_mode))
417                 ioctl(fd, DIOCGMEDIASIZE, &vp->v_size);
418         else
419                 vp->v_size = st.st_size;
420         vp->v_path = spa_strdup(path);
421
422         return (0);
423 }
424
425 int
426 vn_openat(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2,
427     int x3, vnode_t *startvp)
428 {
429         char *realpath = umem_alloc(strlen(path) + 2, UMEM_NOFAIL);
430         int ret;
431
432         ASSERT(startvp == rootdir);
433         (void) sprintf(realpath, "/%s", path);
434
435         ret = vn_open(realpath, x1, flags, mode, vpp, x2, x3);
436
437         umem_free(realpath, strlen(path) + 2);
438
439         return (ret);
440 }
441
442 /*ARGSUSED*/
443 int
444 vn_rdwr(int uio, vnode_t *vp, void *addr, ssize_t len, offset_t offset,
445         int x1, int x2, rlim64_t x3, void *x4, ssize_t *residp)
446 {
447         ssize_t iolen, split;
448
449         if (uio == UIO_READ) {
450                 iolen = pread64(vp->v_fd, addr, len, offset);
451         } else {
452                 /*
453                  * To simulate partial disk writes, we split writes into two
454                  * system calls so that the process can be killed in between.
455                  */
456                 split = (len > 0 ? rand() % len : 0);
457                 iolen = pwrite64(vp->v_fd, addr, split, offset);
458                 iolen += pwrite64(vp->v_fd, (char *)addr + split,
459                     len - split, offset + split);
460         }
461
462         if (iolen == -1)
463                 return (errno);
464         if (residp)
465                 *residp = len - iolen;
466         else if (iolen != len)
467                 return (EIO);
468         return (0);
469 }
470
471 void
472 vn_close(vnode_t *vp)
473 {
474         close(vp->v_fd);
475         spa_strfree(vp->v_path);
476         umem_free(vp, sizeof (vnode_t));
477 }
478
479 #ifdef ZFS_DEBUG
480
481 /*
482  * =========================================================================
483  * Figure out which debugging statements to print
484  * =========================================================================
485  */
486
487 static char *dprintf_string;
488 static int dprintf_print_all;
489
490 int
491 dprintf_find_string(const char *string)
492 {
493         char *tmp_str = dprintf_string;
494         int len = strlen(string);
495
496         /*
497          * Find out if this is a string we want to print.
498          * String format: file1.c,function_name1,file2.c,file3.c
499          */
500
501         while (tmp_str != NULL) {
502                 if (strncmp(tmp_str, string, len) == 0 &&
503                     (tmp_str[len] == ',' || tmp_str[len] == '\0'))
504                         return (1);
505                 tmp_str = strchr(tmp_str, ',');
506                 if (tmp_str != NULL)
507                         tmp_str++; /* Get rid of , */
508         }
509         return (0);
510 }
511
512 void
513 dprintf_setup(int *argc, char **argv)
514 {
515         int i, j;
516
517         /*
518          * Debugging can be specified two ways: by setting the
519          * environment variable ZFS_DEBUG, or by including a
520          * "debug=..."  argument on the command line.  The command
521          * line setting overrides the environment variable.
522          */
523
524         for (i = 1; i < *argc; i++) {
525                 int len = strlen("debug=");
526                 /* First look for a command line argument */
527                 if (strncmp("debug=", argv[i], len) == 0) {
528                         dprintf_string = argv[i] + len;
529                         /* Remove from args */
530                         for (j = i; j < *argc; j++)
531                                 argv[j] = argv[j+1];
532                         argv[j] = NULL;
533                         (*argc)--;
534                 }
535         }
536
537         if (dprintf_string == NULL) {
538                 /* Look for ZFS_DEBUG environment variable */
539                 dprintf_string = getenv("ZFS_DEBUG");
540         }
541
542         /*
543          * Are we just turning on all debugging?
544          */
545         if (dprintf_find_string("on"))
546                 dprintf_print_all = 1;
547 }
548
549 /*
550  * =========================================================================
551  * debug printfs
552  * =========================================================================
553  */
554 void
555 __dprintf(const char *file, const char *func, int line, const char *fmt, ...)
556 {
557         const char *newfile;
558         va_list adx;
559
560         /*
561          * Get rid of annoying "../common/" prefix to filename.
562          */
563         newfile = strrchr(file, '/');
564         if (newfile != NULL) {
565                 newfile = newfile + 1; /* Get rid of leading / */
566         } else {
567                 newfile = file;
568         }
569
570         if (dprintf_print_all ||
571             dprintf_find_string(newfile) ||
572             dprintf_find_string(func)) {
573                 /* Print out just the function name if requested */
574                 flockfile(stdout);
575                 if (dprintf_find_string("pid"))
576                         (void) printf("%d ", getpid());
577                 if (dprintf_find_string("tid"))
578                         (void) printf("%u ", thr_self());
579 #if 0
580                 if (dprintf_find_string("cpu"))
581                         (void) printf("%u ", getcpuid());
582 #endif
583                 if (dprintf_find_string("time"))
584                         (void) printf("%llu ", gethrtime());
585                 if (dprintf_find_string("long"))
586                         (void) printf("%s, line %d: ", newfile, line);
587                 (void) printf("%s: ", func);
588                 va_start(adx, fmt);
589                 (void) vprintf(fmt, adx);
590                 va_end(adx);
591                 funlockfile(stdout);
592         }
593 }
594
595 #endif /* ZFS_DEBUG */
596
597 /*
598  * =========================================================================
599  * cmn_err() and panic()
600  * =========================================================================
601  */
602 static char ce_prefix[CE_IGNORE][10] = { "", "NOTICE: ", "WARNING: ", "" };
603 static char ce_suffix[CE_IGNORE][2] = { "", "\n", "\n", "" };
604
605 void
606 vpanic(const char *fmt, va_list adx)
607 {
608         (void) fprintf(stderr, "error: ");
609         (void) vfprintf(stderr, fmt, adx);
610         (void) fprintf(stderr, "\n");
611
612         abort();        /* think of it as a "user-level crash dump" */
613 }
614
615 void
616 panic(const char *fmt, ...)
617 {
618         va_list adx;
619
620         va_start(adx, fmt);
621         vpanic(fmt, adx);
622         va_end(adx);
623 }
624
625 void
626 vcmn_err(int ce, const char *fmt, va_list adx)
627 {
628         if (ce == CE_PANIC)
629                 vpanic(fmt, adx);
630         if (ce != CE_NOTE) {    /* suppress noise in userland stress testing */
631                 (void) fprintf(stderr, "%s", ce_prefix[ce]);
632                 (void) vfprintf(stderr, fmt, adx);
633                 (void) fprintf(stderr, "%s", ce_suffix[ce]);
634         }
635 }
636
637 /*PRINTFLIKE2*/
638 void
639 cmn_err(int ce, const char *fmt, ...)
640 {
641         va_list adx;
642
643         va_start(adx, fmt);
644         vcmn_err(ce, fmt, adx);
645         va_end(adx);
646 }
647
648 /*
649  * =========================================================================
650  * kobj interfaces
651  * =========================================================================
652  */
653 struct _buf *
654 kobj_open_file(char *name)
655 {
656         struct _buf *file;
657         vnode_t *vp;
658
659         /* set vp as the _fd field of the file */
660         if (vn_openat(name, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0, rootdir) != 0)
661                 return ((void *)-1UL);
662
663         file = umem_zalloc(sizeof (struct _buf), UMEM_NOFAIL);
664         file->_fd = (intptr_t)vp;
665         return (file);
666 }
667
668 int
669 kobj_read_file(struct _buf *file, char *buf, unsigned size, unsigned off)
670 {
671         ssize_t resid;
672
673         vn_rdwr(UIO_READ, (vnode_t *)file->_fd, buf, size, (offset_t)off,
674             UIO_SYSSPACE, 0, 0, 0, &resid);
675
676         return (size - resid);
677 }
678
679 void
680 kobj_close_file(struct _buf *file)
681 {
682         vn_close((vnode_t *)file->_fd);
683         umem_free(file, sizeof (struct _buf));
684 }
685
686 int
687 kobj_get_filesize(struct _buf *file, uint64_t *size)
688 {
689         struct stat64 st;
690         vnode_t *vp = (vnode_t *)file->_fd;
691
692         if (fstat64(vp->v_fd, &st) == -1) {
693                 vn_close(vp);
694                 return (errno);
695         }
696         *size = st.st_size;
697         return (0);
698 }
699
700 /*
701  * =========================================================================
702  * misc routines
703  * =========================================================================
704  */
705
706 void
707 delay(clock_t ticks)
708 {
709         poll(0, 0, ticks * (1000 / hz));
710 }
711
712 #if 0
713 /*
714  * Find highest one bit set.
715  *      Returns bit number + 1 of highest bit that is set, otherwise returns 0.
716  * High order bit is 31 (or 63 in _LP64 kernel).
717  */
718 int
719 highbit(ulong_t i)
720 {
721         register int h = 1;
722
723         if (i == 0)
724                 return (0);
725 #ifdef _LP64
726         if (i & 0xffffffff00000000ul) {
727                 h += 32; i >>= 32;
728         }
729 #endif
730         if (i & 0xffff0000) {
731                 h += 16; i >>= 16;
732         }
733         if (i & 0xff00) {
734                 h += 8; i >>= 8;
735         }
736         if (i & 0xf0) {
737                 h += 4; i >>= 4;
738         }
739         if (i & 0xc) {
740                 h += 2; i >>= 2;
741         }
742         if (i & 0x2) {
743                 h += 1;
744         }
745         return (h);
746 }
747 #endif
748
749 static int
750 random_get_bytes_common(uint8_t *ptr, size_t len, char *devname)
751 {
752         int fd = open(devname, O_RDONLY);
753         size_t resid = len;
754         ssize_t bytes;
755
756         ASSERT(fd != -1);
757
758         while (resid != 0) {
759                 bytes = read(fd, ptr, resid);
760                 ASSERT(bytes >= 0);
761                 ptr += bytes;
762                 resid -= bytes;
763         }
764
765         close(fd);
766
767         return (0);
768 }
769
770 int
771 random_get_bytes(uint8_t *ptr, size_t len)
772 {
773         return (random_get_bytes_common(ptr, len, "/dev/random"));
774 }
775
776 int
777 random_get_pseudo_bytes(uint8_t *ptr, size_t len)
778 {
779         return (random_get_bytes_common(ptr, len, "/dev/urandom"));
780 }
781
782 int
783 ddi_strtoul(const char *hw_serial, char **nptr, int base, unsigned long *result)
784 {
785         char *end;
786
787         *result = strtoul(hw_serial, &end, base);
788         if (*result == 0)
789                 return (errno);
790         return (0);
791 }
792
793 /*
794  * =========================================================================
795  * kernel emulation setup & teardown
796  * =========================================================================
797  */
798 static int
799 umem_out_of_memory(void)
800 {
801         char errmsg[] = "out of memory -- generating core dump\n";
802
803         write(fileno(stderr), errmsg, sizeof (errmsg));
804         abort();
805         return (0);
806 }
807
808 void
809 kernel_init(int mode)
810 {
811         umem_nofail_callback(umem_out_of_memory);
812
813         physmem = sysconf(_SC_PHYS_PAGES);
814
815         dprintf("physmem = %llu pages (%.2f GB)\n", physmem,
816             (double)physmem * sysconf(_SC_PAGE_SIZE) / (1ULL << 30));
817
818         snprintf(hw_serial, sizeof (hw_serial), "%ld", gethostid());
819
820         spa_init(mode);
821 }
822
823 void
824 kernel_fini(void)
825 {
826         spa_fini();
827 }
828
829 int
830 z_uncompress(void *dst, size_t *dstlen, const void *src, size_t srclen)
831 {
832         int ret;
833         uLongf len = *dstlen;
834
835         if ((ret = uncompress(dst, &len, src, srclen)) == Z_OK)
836                 *dstlen = (size_t)len;
837
838         return (ret);
839 }
840
841 int
842 z_compress_level(void *dst, size_t *dstlen, const void *src, size_t srclen,
843     int level)
844 {
845         int ret;
846         uLongf len = *dstlen;
847
848         if ((ret = compress2(dst, &len, src, srclen, level)) == Z_OK)
849                 *dstlen = (size_t)len;
850
851         return (ret);
852 }