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