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