1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 51544Seschrock * Common Development and Distribution License (the "License"). 61544Seschrock * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 21789Sahrens /* 228662SJordan.Vaughan@Sun.com * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23789Sahrens * Use is subject to license terms. 24789Sahrens */ 25789Sahrens 26789Sahrens #include <assert.h> 273886Sahl #include <fcntl.h> 28789Sahrens #include <poll.h> 29789Sahrens #include <stdio.h> 30789Sahrens #include <stdlib.h> 313886Sahl #include <string.h> 323886Sahl #include <zlib.h> 33789Sahrens #include <sys/spa.h> 343886Sahl #include <sys/stat.h> 35789Sahrens #include <sys/processor.h> 363886Sahl #include <sys/zfs_context.h> 373886Sahl #include <sys/zmod.h> 383975Sek110237 #include <sys/utsname.h> 398662SJordan.Vaughan@Sun.com #include <sys/systeminfo.h> 402856Snd150628 41789Sahrens /* 42789Sahrens * Emulation of kernel services in userland. 43789Sahrens */ 44789Sahrens 45789Sahrens uint64_t physmem; 46789Sahrens vnode_t *rootdir = (vnode_t *)0xabcd1234; 478662SJordan.Vaughan@Sun.com char hw_serial[HW_HOSTID_LEN]; 483975Sek110237 493975Sek110237 struct utsname utsname = { 503975Sek110237 "userland", "libzpool", "1", "1", "na" 513975Sek110237 }; 52789Sahrens 53789Sahrens /* 54789Sahrens * ========================================================================= 55789Sahrens * threads 56789Sahrens * ========================================================================= 57789Sahrens */ 58789Sahrens /*ARGSUSED*/ 59789Sahrens kthread_t * 60789Sahrens zk_thread_create(void (*func)(), void *arg) 61789Sahrens { 62789Sahrens thread_t tid; 63789Sahrens 64789Sahrens VERIFY(thr_create(0, 0, (void *(*)(void *))func, arg, THR_DETACHED, 65789Sahrens &tid) == 0); 66789Sahrens 67789Sahrens return ((void *)(uintptr_t)tid); 68789Sahrens } 69789Sahrens 70789Sahrens /* 71789Sahrens * ========================================================================= 723403Sbmc * kstats 733403Sbmc * ========================================================================= 743403Sbmc */ 753403Sbmc /*ARGSUSED*/ 763403Sbmc kstat_t * 773403Sbmc kstat_create(char *module, int instance, char *name, char *class, 783403Sbmc uchar_t type, ulong_t ndata, uchar_t ks_flag) 793403Sbmc { 803403Sbmc return (NULL); 813403Sbmc } 823403Sbmc 833403Sbmc /*ARGSUSED*/ 843403Sbmc void 853403Sbmc kstat_install(kstat_t *ksp) 863403Sbmc {} 873403Sbmc 883403Sbmc /*ARGSUSED*/ 893403Sbmc void 903403Sbmc kstat_delete(kstat_t *ksp) 913403Sbmc {} 923403Sbmc 933403Sbmc /* 943403Sbmc * ========================================================================= 95789Sahrens * mutexes 96789Sahrens * ========================================================================= 97789Sahrens */ 98789Sahrens void 99789Sahrens zmutex_init(kmutex_t *mp) 100789Sahrens { 101789Sahrens mp->m_owner = NULL; 1024831Sgw25295 mp->initialized = B_TRUE; 103789Sahrens (void) _mutex_init(&mp->m_lock, USYNC_THREAD, NULL); 104789Sahrens } 105789Sahrens 106789Sahrens void 107789Sahrens zmutex_destroy(kmutex_t *mp) 108789Sahrens { 1094831Sgw25295 ASSERT(mp->initialized == B_TRUE); 110789Sahrens ASSERT(mp->m_owner == NULL); 111789Sahrens (void) _mutex_destroy(&(mp)->m_lock); 112789Sahrens mp->m_owner = (void *)-1UL; 1134831Sgw25295 mp->initialized = B_FALSE; 114789Sahrens } 115789Sahrens 116789Sahrens void 117789Sahrens mutex_enter(kmutex_t *mp) 118789Sahrens { 1194831Sgw25295 ASSERT(mp->initialized == B_TRUE); 120789Sahrens ASSERT(mp->m_owner != (void *)-1UL); 121789Sahrens ASSERT(mp->m_owner != curthread); 1222856Snd150628 VERIFY(mutex_lock(&mp->m_lock) == 0); 123789Sahrens ASSERT(mp->m_owner == NULL); 124789Sahrens mp->m_owner = curthread; 125789Sahrens } 126789Sahrens 127789Sahrens int 128789Sahrens mutex_tryenter(kmutex_t *mp) 129789Sahrens { 1304831Sgw25295 ASSERT(mp->initialized == B_TRUE); 131789Sahrens ASSERT(mp->m_owner != (void *)-1UL); 132789Sahrens if (0 == mutex_trylock(&mp->m_lock)) { 133789Sahrens ASSERT(mp->m_owner == NULL); 134789Sahrens mp->m_owner = curthread; 135789Sahrens return (1); 136789Sahrens } else { 137789Sahrens return (0); 138789Sahrens } 139789Sahrens } 140789Sahrens 141789Sahrens void 142789Sahrens mutex_exit(kmutex_t *mp) 143789Sahrens { 1444831Sgw25295 ASSERT(mp->initialized == B_TRUE); 145789Sahrens ASSERT(mutex_owner(mp) == curthread); 146789Sahrens mp->m_owner = NULL; 1472856Snd150628 VERIFY(mutex_unlock(&mp->m_lock) == 0); 148789Sahrens } 149789Sahrens 150789Sahrens void * 151789Sahrens mutex_owner(kmutex_t *mp) 152789Sahrens { 1534831Sgw25295 ASSERT(mp->initialized == B_TRUE); 154789Sahrens return (mp->m_owner); 155789Sahrens } 156789Sahrens 157789Sahrens /* 158789Sahrens * ========================================================================= 159789Sahrens * rwlocks 160789Sahrens * ========================================================================= 161789Sahrens */ 162789Sahrens /*ARGSUSED*/ 163789Sahrens void 164789Sahrens rw_init(krwlock_t *rwlp, char *name, int type, void *arg) 165789Sahrens { 166789Sahrens rwlock_init(&rwlp->rw_lock, USYNC_THREAD, NULL); 167789Sahrens rwlp->rw_owner = NULL; 1684831Sgw25295 rwlp->initialized = B_TRUE; 169789Sahrens } 170789Sahrens 171789Sahrens void 172789Sahrens rw_destroy(krwlock_t *rwlp) 173789Sahrens { 174789Sahrens rwlock_destroy(&rwlp->rw_lock); 175789Sahrens rwlp->rw_owner = (void *)-1UL; 1764831Sgw25295 rwlp->initialized = B_FALSE; 177789Sahrens } 178789Sahrens 179789Sahrens void 180789Sahrens rw_enter(krwlock_t *rwlp, krw_t rw) 181789Sahrens { 182789Sahrens ASSERT(!RW_LOCK_HELD(rwlp)); 1834831Sgw25295 ASSERT(rwlp->initialized == B_TRUE); 184789Sahrens ASSERT(rwlp->rw_owner != (void *)-1UL); 185789Sahrens ASSERT(rwlp->rw_owner != curthread); 186789Sahrens 187789Sahrens if (rw == RW_READER) 1886689Smaybee VERIFY(rw_rdlock(&rwlp->rw_lock) == 0); 189789Sahrens else 1906689Smaybee VERIFY(rw_wrlock(&rwlp->rw_lock) == 0); 191789Sahrens 192789Sahrens rwlp->rw_owner = curthread; 193789Sahrens } 194789Sahrens 195789Sahrens void 196789Sahrens rw_exit(krwlock_t *rwlp) 197789Sahrens { 1984831Sgw25295 ASSERT(rwlp->initialized == B_TRUE); 199789Sahrens ASSERT(rwlp->rw_owner != (void *)-1UL); 200789Sahrens 201789Sahrens rwlp->rw_owner = NULL; 2026689Smaybee VERIFY(rw_unlock(&rwlp->rw_lock) == 0); 203789Sahrens } 204789Sahrens 205789Sahrens int 206789Sahrens rw_tryenter(krwlock_t *rwlp, krw_t rw) 207789Sahrens { 208789Sahrens int rv; 209789Sahrens 2104831Sgw25295 ASSERT(rwlp->initialized == B_TRUE); 211789Sahrens ASSERT(rwlp->rw_owner != (void *)-1UL); 212789Sahrens 213789Sahrens if (rw == RW_READER) 214789Sahrens rv = rw_tryrdlock(&rwlp->rw_lock); 215789Sahrens else 216789Sahrens rv = rw_trywrlock(&rwlp->rw_lock); 217789Sahrens 218789Sahrens if (rv == 0) { 219789Sahrens rwlp->rw_owner = curthread; 220789Sahrens return (1); 221789Sahrens } 222789Sahrens 223789Sahrens return (0); 224789Sahrens } 225789Sahrens 226789Sahrens /*ARGSUSED*/ 227789Sahrens int 228789Sahrens rw_tryupgrade(krwlock_t *rwlp) 229789Sahrens { 2304831Sgw25295 ASSERT(rwlp->initialized == B_TRUE); 231789Sahrens ASSERT(rwlp->rw_owner != (void *)-1UL); 232789Sahrens 233789Sahrens return (0); 234789Sahrens } 235789Sahrens 236789Sahrens /* 237789Sahrens * ========================================================================= 238789Sahrens * condition variables 239789Sahrens * ========================================================================= 240789Sahrens */ 241789Sahrens /*ARGSUSED*/ 242789Sahrens void 243789Sahrens cv_init(kcondvar_t *cv, char *name, int type, void *arg) 244789Sahrens { 2452856Snd150628 VERIFY(cond_init(cv, type, NULL) == 0); 246789Sahrens } 247789Sahrens 248789Sahrens void 249789Sahrens cv_destroy(kcondvar_t *cv) 250789Sahrens { 2512856Snd150628 VERIFY(cond_destroy(cv) == 0); 252789Sahrens } 253789Sahrens 254789Sahrens void 255789Sahrens cv_wait(kcondvar_t *cv, kmutex_t *mp) 256789Sahrens { 257789Sahrens ASSERT(mutex_owner(mp) == curthread); 258789Sahrens mp->m_owner = NULL; 2592856Snd150628 int ret = cond_wait(cv, &mp->m_lock); 2602856Snd150628 VERIFY(ret == 0 || ret == EINTR); 261789Sahrens mp->m_owner = curthread; 262789Sahrens } 263789Sahrens 264789Sahrens clock_t 265789Sahrens cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime) 266789Sahrens { 267789Sahrens int error; 268789Sahrens timestruc_t ts; 269789Sahrens clock_t delta; 270789Sahrens 271789Sahrens top: 272789Sahrens delta = abstime - lbolt; 273789Sahrens if (delta <= 0) 274789Sahrens return (-1); 275789Sahrens 276789Sahrens ts.tv_sec = delta / hz; 277789Sahrens ts.tv_nsec = (delta % hz) * (NANOSEC / hz); 278789Sahrens 279789Sahrens ASSERT(mutex_owner(mp) == curthread); 280789Sahrens mp->m_owner = NULL; 281789Sahrens error = cond_reltimedwait(cv, &mp->m_lock, &ts); 282789Sahrens mp->m_owner = curthread; 283789Sahrens 284789Sahrens if (error == ETIME) 285789Sahrens return (-1); 286789Sahrens 287789Sahrens if (error == EINTR) 288789Sahrens goto top; 289789Sahrens 290789Sahrens ASSERT(error == 0); 291789Sahrens 292789Sahrens return (1); 293789Sahrens } 294789Sahrens 295789Sahrens void 296789Sahrens cv_signal(kcondvar_t *cv) 297789Sahrens { 2982856Snd150628 VERIFY(cond_signal(cv) == 0); 299789Sahrens } 300789Sahrens 301789Sahrens void 302789Sahrens cv_broadcast(kcondvar_t *cv) 303789Sahrens { 3042856Snd150628 VERIFY(cond_broadcast(cv) == 0); 305789Sahrens } 306789Sahrens 307789Sahrens /* 308789Sahrens * ========================================================================= 309789Sahrens * vnode operations 310789Sahrens * ========================================================================= 311789Sahrens */ 312789Sahrens /* 313789Sahrens * Note: for the xxxat() versions of these functions, we assume that the 314789Sahrens * starting vp is always rootdir (which is true for spa_directory.c, the only 315789Sahrens * ZFS consumer of these interfaces). We assert this is true, and then emulate 316789Sahrens * them by adding '/' in front of the path. 317789Sahrens */ 318789Sahrens 319789Sahrens /*ARGSUSED*/ 320789Sahrens int 321789Sahrens vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3) 322789Sahrens { 323789Sahrens int fd; 324789Sahrens vnode_t *vp; 325789Sahrens int old_umask; 326789Sahrens char realpath[MAXPATHLEN]; 327789Sahrens struct stat64 st; 328789Sahrens 329789Sahrens /* 330789Sahrens * If we're accessing a real disk from userland, we need to use 331789Sahrens * the character interface to avoid caching. This is particularly 332789Sahrens * important if we're trying to look at a real in-kernel storage 333789Sahrens * pool from userland, e.g. via zdb, because otherwise we won't 334789Sahrens * see the changes occurring under the segmap cache. 335789Sahrens * On the other hand, the stupid character device returns zero 336789Sahrens * for its size. So -- gag -- we open the block device to get 337789Sahrens * its size, and remember it for subsequent VOP_GETATTR(). 338789Sahrens */ 339789Sahrens if (strncmp(path, "/dev/", 5) == 0) { 340789Sahrens char *dsk; 341789Sahrens fd = open64(path, O_RDONLY); 342789Sahrens if (fd == -1) 343789Sahrens return (errno); 344789Sahrens if (fstat64(fd, &st) == -1) { 345789Sahrens close(fd); 346789Sahrens return (errno); 347789Sahrens } 348789Sahrens close(fd); 349789Sahrens (void) sprintf(realpath, "%s", path); 350789Sahrens dsk = strstr(path, "/dsk/"); 351789Sahrens if (dsk != NULL) 352789Sahrens (void) sprintf(realpath + (dsk - path) + 1, "r%s", 353789Sahrens dsk + 1); 354789Sahrens } else { 355789Sahrens (void) sprintf(realpath, "%s", path); 356789Sahrens if (!(flags & FCREAT) && stat64(realpath, &st) == -1) 357789Sahrens return (errno); 358789Sahrens } 359789Sahrens 360789Sahrens if (flags & FCREAT) 361789Sahrens old_umask = umask(0); 362789Sahrens 363789Sahrens /* 364789Sahrens * The construct 'flags - FREAD' conveniently maps combinations of 365789Sahrens * FREAD and FWRITE to the corresponding O_RDONLY, O_WRONLY, and O_RDWR. 366789Sahrens */ 367789Sahrens fd = open64(realpath, flags - FREAD, mode); 368789Sahrens 369789Sahrens if (flags & FCREAT) 370789Sahrens (void) umask(old_umask); 371789Sahrens 372789Sahrens if (fd == -1) 373789Sahrens return (errno); 374789Sahrens 375789Sahrens if (fstat64(fd, &st) == -1) { 376789Sahrens close(fd); 377789Sahrens return (errno); 378789Sahrens } 379789Sahrens 380789Sahrens (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 381789Sahrens 382789Sahrens *vpp = vp = umem_zalloc(sizeof (vnode_t), UMEM_NOFAIL); 383789Sahrens 384789Sahrens vp->v_fd = fd; 385789Sahrens vp->v_size = st.st_size; 386789Sahrens vp->v_path = spa_strdup(path); 387789Sahrens 388789Sahrens return (0); 389789Sahrens } 390789Sahrens 3915331Samw /*ARGSUSED*/ 392789Sahrens int 393789Sahrens vn_openat(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, 3945331Samw int x3, vnode_t *startvp, int fd) 395789Sahrens { 396789Sahrens char *realpath = umem_alloc(strlen(path) + 2, UMEM_NOFAIL); 397789Sahrens int ret; 398789Sahrens 399789Sahrens ASSERT(startvp == rootdir); 400789Sahrens (void) sprintf(realpath, "/%s", path); 401789Sahrens 4025331Samw /* fd ignored for now, need if want to simulate nbmand support */ 403789Sahrens ret = vn_open(realpath, x1, flags, mode, vpp, x2, x3); 404789Sahrens 405789Sahrens umem_free(realpath, strlen(path) + 2); 406789Sahrens 407789Sahrens return (ret); 408789Sahrens } 409789Sahrens 410789Sahrens /*ARGSUSED*/ 411789Sahrens int 412789Sahrens vn_rdwr(int uio, vnode_t *vp, void *addr, ssize_t len, offset_t offset, 413789Sahrens int x1, int x2, rlim64_t x3, void *x4, ssize_t *residp) 414789Sahrens { 415789Sahrens ssize_t iolen, split; 416789Sahrens 417789Sahrens if (uio == UIO_READ) { 418789Sahrens iolen = pread64(vp->v_fd, addr, len, offset); 419789Sahrens } else { 420789Sahrens /* 421789Sahrens * To simulate partial disk writes, we split writes into two 422789Sahrens * system calls so that the process can be killed in between. 423789Sahrens */ 424789Sahrens split = (len > 0 ? rand() % len : 0); 425789Sahrens iolen = pwrite64(vp->v_fd, addr, split, offset); 426789Sahrens iolen += pwrite64(vp->v_fd, (char *)addr + split, 427789Sahrens len - split, offset + split); 428789Sahrens } 429789Sahrens 430789Sahrens if (iolen == -1) 431789Sahrens return (errno); 432789Sahrens if (residp) 433789Sahrens *residp = len - iolen; 434789Sahrens else if (iolen != len) 435789Sahrens return (EIO); 436789Sahrens return (0); 437789Sahrens } 438789Sahrens 439789Sahrens void 440789Sahrens vn_close(vnode_t *vp) 441789Sahrens { 442789Sahrens close(vp->v_fd); 443789Sahrens spa_strfree(vp->v_path); 444789Sahrens umem_free(vp, sizeof (vnode_t)); 445789Sahrens } 446789Sahrens 447789Sahrens #ifdef ZFS_DEBUG 448789Sahrens 449789Sahrens /* 450789Sahrens * ========================================================================= 451789Sahrens * Figure out which debugging statements to print 452789Sahrens * ========================================================================= 453789Sahrens */ 454789Sahrens 455789Sahrens static char *dprintf_string; 456789Sahrens static int dprintf_print_all; 457789Sahrens 458789Sahrens int 459789Sahrens dprintf_find_string(const char *string) 460789Sahrens { 461789Sahrens char *tmp_str = dprintf_string; 462789Sahrens int len = strlen(string); 463789Sahrens 464789Sahrens /* 465789Sahrens * Find out if this is a string we want to print. 466789Sahrens * String format: file1.c,function_name1,file2.c,file3.c 467789Sahrens */ 468789Sahrens 469789Sahrens while (tmp_str != NULL) { 470789Sahrens if (strncmp(tmp_str, string, len) == 0 && 471789Sahrens (tmp_str[len] == ',' || tmp_str[len] == '\0')) 472789Sahrens return (1); 473789Sahrens tmp_str = strchr(tmp_str, ','); 474789Sahrens if (tmp_str != NULL) 475789Sahrens tmp_str++; /* Get rid of , */ 476789Sahrens } 477789Sahrens return (0); 478789Sahrens } 479789Sahrens 480789Sahrens void 481789Sahrens dprintf_setup(int *argc, char **argv) 482789Sahrens { 483789Sahrens int i, j; 484789Sahrens 485789Sahrens /* 486789Sahrens * Debugging can be specified two ways: by setting the 487789Sahrens * environment variable ZFS_DEBUG, or by including a 488789Sahrens * "debug=..." argument on the command line. The command 489789Sahrens * line setting overrides the environment variable. 490789Sahrens */ 491789Sahrens 492789Sahrens for (i = 1; i < *argc; i++) { 493789Sahrens int len = strlen("debug="); 494789Sahrens /* First look for a command line argument */ 495789Sahrens if (strncmp("debug=", argv[i], len) == 0) { 496789Sahrens dprintf_string = argv[i] + len; 497789Sahrens /* Remove from args */ 498789Sahrens for (j = i; j < *argc; j++) 499789Sahrens argv[j] = argv[j+1]; 500789Sahrens argv[j] = NULL; 501789Sahrens (*argc)--; 502789Sahrens } 503789Sahrens } 504789Sahrens 505789Sahrens if (dprintf_string == NULL) { 506789Sahrens /* Look for ZFS_DEBUG environment variable */ 507789Sahrens dprintf_string = getenv("ZFS_DEBUG"); 508789Sahrens } 509789Sahrens 510789Sahrens /* 511789Sahrens * Are we just turning on all debugging? 512789Sahrens */ 513789Sahrens if (dprintf_find_string("on")) 514789Sahrens dprintf_print_all = 1; 515789Sahrens } 516789Sahrens 517789Sahrens /* 518789Sahrens * ========================================================================= 519789Sahrens * debug printfs 520789Sahrens * ========================================================================= 521789Sahrens */ 522789Sahrens void 523789Sahrens __dprintf(const char *file, const char *func, int line, const char *fmt, ...) 524789Sahrens { 525789Sahrens const char *newfile; 526789Sahrens va_list adx; 527789Sahrens 528789Sahrens /* 529789Sahrens * Get rid of annoying "../common/" prefix to filename. 530789Sahrens */ 531789Sahrens newfile = strrchr(file, '/'); 532789Sahrens if (newfile != NULL) { 533789Sahrens newfile = newfile + 1; /* Get rid of leading / */ 534789Sahrens } else { 535789Sahrens newfile = file; 536789Sahrens } 537789Sahrens 538789Sahrens if (dprintf_print_all || 539789Sahrens dprintf_find_string(newfile) || 540789Sahrens dprintf_find_string(func)) { 541789Sahrens /* Print out just the function name if requested */ 542789Sahrens flockfile(stdout); 543789Sahrens if (dprintf_find_string("pid")) 544789Sahrens (void) printf("%d ", getpid()); 545789Sahrens if (dprintf_find_string("tid")) 546789Sahrens (void) printf("%u ", thr_self()); 547789Sahrens if (dprintf_find_string("cpu")) 548789Sahrens (void) printf("%u ", getcpuid()); 549789Sahrens if (dprintf_find_string("time")) 550789Sahrens (void) printf("%llu ", gethrtime()); 551789Sahrens if (dprintf_find_string("long")) 552789Sahrens (void) printf("%s, line %d: ", newfile, line); 553789Sahrens (void) printf("%s: ", func); 554789Sahrens va_start(adx, fmt); 555789Sahrens (void) vprintf(fmt, adx); 556789Sahrens va_end(adx); 557789Sahrens funlockfile(stdout); 558789Sahrens } 559789Sahrens } 560789Sahrens 561789Sahrens #endif /* ZFS_DEBUG */ 562789Sahrens 563789Sahrens /* 564789Sahrens * ========================================================================= 565789Sahrens * cmn_err() and panic() 566789Sahrens * ========================================================================= 567789Sahrens */ 568789Sahrens static char ce_prefix[CE_IGNORE][10] = { "", "NOTICE: ", "WARNING: ", "" }; 569789Sahrens static char ce_suffix[CE_IGNORE][2] = { "", "\n", "\n", "" }; 570789Sahrens 571789Sahrens void 572789Sahrens vpanic(const char *fmt, va_list adx) 573789Sahrens { 574789Sahrens (void) fprintf(stderr, "error: "); 575789Sahrens (void) vfprintf(stderr, fmt, adx); 576789Sahrens (void) fprintf(stderr, "\n"); 577789Sahrens 578789Sahrens abort(); /* think of it as a "user-level crash dump" */ 579789Sahrens } 580789Sahrens 581789Sahrens void 582789Sahrens panic(const char *fmt, ...) 583789Sahrens { 584789Sahrens va_list adx; 585789Sahrens 586789Sahrens va_start(adx, fmt); 587789Sahrens vpanic(fmt, adx); 588789Sahrens va_end(adx); 589789Sahrens } 590789Sahrens 5913713Sahrens void 5923713Sahrens vcmn_err(int ce, const char *fmt, va_list adx) 5933713Sahrens { 5943713Sahrens if (ce == CE_PANIC) 5953713Sahrens vpanic(fmt, adx); 5963713Sahrens if (ce != CE_NOTE) { /* suppress noise in userland stress testing */ 5973713Sahrens (void) fprintf(stderr, "%s", ce_prefix[ce]); 5983713Sahrens (void) vfprintf(stderr, fmt, adx); 5993713Sahrens (void) fprintf(stderr, "%s", ce_suffix[ce]); 6003713Sahrens } 6013713Sahrens } 6023713Sahrens 603789Sahrens /*PRINTFLIKE2*/ 604789Sahrens void 605789Sahrens cmn_err(int ce, const char *fmt, ...) 606789Sahrens { 607789Sahrens va_list adx; 608789Sahrens 609789Sahrens va_start(adx, fmt); 6103713Sahrens vcmn_err(ce, fmt, adx); 611789Sahrens va_end(adx); 612789Sahrens } 613789Sahrens 614789Sahrens /* 615789Sahrens * ========================================================================= 6161544Seschrock * kobj interfaces 6171544Seschrock * ========================================================================= 6181544Seschrock */ 6191544Seschrock struct _buf * 6201544Seschrock kobj_open_file(char *name) 6211544Seschrock { 6221544Seschrock struct _buf *file; 6231544Seschrock vnode_t *vp; 6241544Seschrock 6251544Seschrock /* set vp as the _fd field of the file */ 6265331Samw if (vn_openat(name, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0, rootdir, 6275331Samw -1) != 0) 6281544Seschrock return ((void *)-1UL); 6291544Seschrock 6301544Seschrock file = umem_zalloc(sizeof (struct _buf), UMEM_NOFAIL); 6311544Seschrock file->_fd = (intptr_t)vp; 6321544Seschrock return (file); 6331544Seschrock } 6341544Seschrock 6351544Seschrock int 6361544Seschrock kobj_read_file(struct _buf *file, char *buf, unsigned size, unsigned off) 6371544Seschrock { 6381544Seschrock ssize_t resid; 6391544Seschrock 6401544Seschrock vn_rdwr(UIO_READ, (vnode_t *)file->_fd, buf, size, (offset_t)off, 6411544Seschrock UIO_SYSSPACE, 0, 0, 0, &resid); 6421544Seschrock 6433912Slling return (size - resid); 6441544Seschrock } 6451544Seschrock 6461544Seschrock void 6471544Seschrock kobj_close_file(struct _buf *file) 6481544Seschrock { 6491544Seschrock vn_close((vnode_t *)file->_fd); 6501544Seschrock umem_free(file, sizeof (struct _buf)); 6511544Seschrock } 6521544Seschrock 6531544Seschrock int 6543912Slling kobj_get_filesize(struct _buf *file, uint64_t *size) 6551544Seschrock { 6561544Seschrock struct stat64 st; 6573912Slling vnode_t *vp = (vnode_t *)file->_fd; 6583912Slling 6591544Seschrock if (fstat64(vp->v_fd, &st) == -1) { 6601544Seschrock vn_close(vp); 6611544Seschrock return (errno); 6621544Seschrock } 6633912Slling *size = st.st_size; 6641544Seschrock return (0); 6651544Seschrock } 6661544Seschrock 6671544Seschrock /* 6681544Seschrock * ========================================================================= 669789Sahrens * misc routines 670789Sahrens * ========================================================================= 671789Sahrens */ 672789Sahrens 673789Sahrens void 674789Sahrens delay(clock_t ticks) 675789Sahrens { 676789Sahrens poll(0, 0, ticks * (1000 / hz)); 677789Sahrens } 678789Sahrens 679789Sahrens /* 680789Sahrens * Find highest one bit set. 681789Sahrens * Returns bit number + 1 of highest bit that is set, otherwise returns 0. 682789Sahrens * High order bit is 31 (or 63 in _LP64 kernel). 683789Sahrens */ 684789Sahrens int 685789Sahrens highbit(ulong_t i) 686789Sahrens { 687789Sahrens register int h = 1; 688789Sahrens 689789Sahrens if (i == 0) 690789Sahrens return (0); 691789Sahrens #ifdef _LP64 692789Sahrens if (i & 0xffffffff00000000ul) { 693789Sahrens h += 32; i >>= 32; 694789Sahrens } 695789Sahrens #endif 696789Sahrens if (i & 0xffff0000) { 697789Sahrens h += 16; i >>= 16; 698789Sahrens } 699789Sahrens if (i & 0xff00) { 700789Sahrens h += 8; i >>= 8; 701789Sahrens } 702789Sahrens if (i & 0xf0) { 703789Sahrens h += 4; i >>= 4; 704789Sahrens } 705789Sahrens if (i & 0xc) { 706789Sahrens h += 2; i >>= 2; 707789Sahrens } 708789Sahrens if (i & 0x2) { 709789Sahrens h += 1; 710789Sahrens } 711789Sahrens return (h); 712789Sahrens } 713789Sahrens 7145688Sbonwick static int random_fd = -1, urandom_fd = -1; 7155688Sbonwick 716789Sahrens static int 7175688Sbonwick random_get_bytes_common(uint8_t *ptr, size_t len, int fd) 718789Sahrens { 719789Sahrens size_t resid = len; 720789Sahrens ssize_t bytes; 721789Sahrens 722789Sahrens ASSERT(fd != -1); 723789Sahrens 724789Sahrens while (resid != 0) { 725789Sahrens bytes = read(fd, ptr, resid); 7265688Sbonwick ASSERT3S(bytes, >=, 0); 727789Sahrens ptr += bytes; 728789Sahrens resid -= bytes; 729789Sahrens } 730789Sahrens 731789Sahrens return (0); 732789Sahrens } 733789Sahrens 734789Sahrens int 735789Sahrens random_get_bytes(uint8_t *ptr, size_t len) 736789Sahrens { 7375688Sbonwick return (random_get_bytes_common(ptr, len, random_fd)); 738789Sahrens } 739789Sahrens 740789Sahrens int 741789Sahrens random_get_pseudo_bytes(uint8_t *ptr, size_t len) 742789Sahrens { 7435688Sbonwick return (random_get_bytes_common(ptr, len, urandom_fd)); 744789Sahrens } 745789Sahrens 7463975Sek110237 int 7473975Sek110237 ddi_strtoul(const char *hw_serial, char **nptr, int base, unsigned long *result) 7483975Sek110237 { 7493975Sek110237 char *end; 7503975Sek110237 7513975Sek110237 *result = strtoul(hw_serial, &end, base); 7523975Sek110237 if (*result == 0) 7533975Sek110237 return (errno); 7543975Sek110237 return (0); 7553975Sek110237 } 7563975Sek110237 757789Sahrens /* 758789Sahrens * ========================================================================= 759789Sahrens * kernel emulation setup & teardown 760789Sahrens * ========================================================================= 761789Sahrens */ 762789Sahrens static int 763789Sahrens umem_out_of_memory(void) 764789Sahrens { 765789Sahrens char errmsg[] = "out of memory -- generating core dump\n"; 766789Sahrens 767789Sahrens write(fileno(stderr), errmsg, sizeof (errmsg)); 768789Sahrens abort(); 769789Sahrens return (0); 770789Sahrens } 771789Sahrens 772789Sahrens void 773789Sahrens kernel_init(int mode) 774789Sahrens { 775789Sahrens umem_nofail_callback(umem_out_of_memory); 776789Sahrens 777789Sahrens physmem = sysconf(_SC_PHYS_PAGES); 778789Sahrens 779789Sahrens dprintf("physmem = %llu pages (%.2f GB)\n", physmem, 780789Sahrens (double)physmem * sysconf(_SC_PAGE_SIZE) / (1ULL << 30)); 781789Sahrens 7828662SJordan.Vaughan@Sun.com (void) snprintf(hw_serial, sizeof (hw_serial), "%ld", gethostid()); 7833975Sek110237 7845688Sbonwick VERIFY((random_fd = open("/dev/random", O_RDONLY)) != -1); 7855688Sbonwick VERIFY((urandom_fd = open("/dev/urandom", O_RDONLY)) != -1); 7865688Sbonwick 7877837SMatthew.Ahrens@Sun.COM system_taskq_init(); 7887837SMatthew.Ahrens@Sun.COM 789789Sahrens spa_init(mode); 790789Sahrens } 791789Sahrens 792789Sahrens void 793789Sahrens kernel_fini(void) 794789Sahrens { 795789Sahrens spa_fini(); 7965688Sbonwick 797*10612SRicardo.M.Correia@Sun.COM system_taskq_fini(); 798*10612SRicardo.M.Correia@Sun.COM 7995688Sbonwick close(random_fd); 8005688Sbonwick close(urandom_fd); 8015688Sbonwick 8025688Sbonwick random_fd = -1; 8035688Sbonwick urandom_fd = -1; 804789Sahrens } 8053886Sahl 8063886Sahl int 8073886Sahl z_uncompress(void *dst, size_t *dstlen, const void *src, size_t srclen) 8083886Sahl { 8093886Sahl int ret; 8103886Sahl uLongf len = *dstlen; 8113886Sahl 8123886Sahl if ((ret = uncompress(dst, &len, src, srclen)) == Z_OK) 8133886Sahl *dstlen = (size_t)len; 8143886Sahl 8153886Sahl return (ret); 8163886Sahl } 8173886Sahl 8183886Sahl int 8193886Sahl z_compress_level(void *dst, size_t *dstlen, const void *src, size_t srclen, 8203886Sahl int level) 8213886Sahl { 8223886Sahl int ret; 8233886Sahl uLongf len = *dstlen; 8243886Sahl 8253886Sahl if ((ret = compress2(dst, &len, src, srclen, level)) == Z_OK) 8263886Sahl *dstlen = (size_t)len; 8273886Sahl 8283886Sahl return (ret); 8293886Sahl } 8304543Smarks 8314543Smarks uid_t 8324543Smarks crgetuid(cred_t *cr) 8334543Smarks { 8344543Smarks return (0); 8354543Smarks } 8364543Smarks 8374543Smarks gid_t 8384543Smarks crgetgid(cred_t *cr) 8394543Smarks { 8404543Smarks return (0); 8414543Smarks } 8424543Smarks 8434543Smarks int 8444543Smarks crgetngroups(cred_t *cr) 8454543Smarks { 8464543Smarks return (0); 8474543Smarks } 8484543Smarks 8494543Smarks gid_t * 8504543Smarks crgetgroups(cred_t *cr) 8514543Smarks { 8524543Smarks return (NULL); 8534543Smarks } 8544543Smarks 8554543Smarks int 8564543Smarks zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr) 8574543Smarks { 8584543Smarks return (0); 8594543Smarks } 8604543Smarks 8614543Smarks int 8624543Smarks zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr) 8634543Smarks { 8644543Smarks return (0); 8654543Smarks } 8664543Smarks 8674543Smarks int 8684543Smarks zfs_secpolicy_destroy_perms(const char *name, cred_t *cr) 8694543Smarks { 8704543Smarks return (0); 8714543Smarks } 8725959Smarks 8735959Smarks ksiddomain_t * 8745959Smarks ksid_lookupdomain(const char *dom) 8755959Smarks { 8765959Smarks ksiddomain_t *kd; 8775959Smarks 8785959Smarks kd = umem_zalloc(sizeof (ksiddomain_t), UMEM_NOFAIL); 8795959Smarks kd->kd_name = spa_strdup(dom); 8805959Smarks return (kd); 8815959Smarks } 8825959Smarks 8835959Smarks void 8845959Smarks ksiddomain_rele(ksiddomain_t *ksid) 8855959Smarks { 8865959Smarks spa_strfree(ksid->kd_name); 8875959Smarks umem_free(ksid, sizeof (ksiddomain_t)); 8885959Smarks } 88910272SMatthew.Ahrens@Sun.COM 89010272SMatthew.Ahrens@Sun.COM /* 89110272SMatthew.Ahrens@Sun.COM * Do not change the length of the returned string; it must be freed 89210272SMatthew.Ahrens@Sun.COM * with strfree(). 89310272SMatthew.Ahrens@Sun.COM */ 89410272SMatthew.Ahrens@Sun.COM char * 89510272SMatthew.Ahrens@Sun.COM kmem_asprintf(const char *fmt, ...) 89610272SMatthew.Ahrens@Sun.COM { 89710272SMatthew.Ahrens@Sun.COM int size; 89810272SMatthew.Ahrens@Sun.COM va_list adx; 89910272SMatthew.Ahrens@Sun.COM char *buf; 90010272SMatthew.Ahrens@Sun.COM 90110272SMatthew.Ahrens@Sun.COM va_start(adx, fmt); 90210272SMatthew.Ahrens@Sun.COM size = vsnprintf(NULL, 0, fmt, adx) + 1; 90310272SMatthew.Ahrens@Sun.COM va_end(adx); 90410272SMatthew.Ahrens@Sun.COM 90510272SMatthew.Ahrens@Sun.COM buf = kmem_alloc(size, KM_SLEEP); 90610272SMatthew.Ahrens@Sun.COM 90710272SMatthew.Ahrens@Sun.COM va_start(adx, fmt); 90810272SMatthew.Ahrens@Sun.COM size = vsnprintf(buf, size, fmt, adx); 90910272SMatthew.Ahrens@Sun.COM va_end(adx); 91010272SMatthew.Ahrens@Sun.COM 91110272SMatthew.Ahrens@Sun.COM return (buf); 91210272SMatthew.Ahrens@Sun.COM } 913