1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3 * CDDL HEADER START
4 *
5 * The contents of this file are subject to the terms of the
6 * Common Development and Distribution License (the "License").
7 * You may not use this file except in compliance with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or https://opensource.org/licenses/CDDL-1.0.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2012, 2018 by Delphix. All rights reserved.
25 * Copyright (c) 2016 Actifio, Inc. All rights reserved.
26 * Copyright (c) 2025, Klara, Inc.
27 */
28
29 #include <assert.h>
30 #include <fcntl.h>
31 #include <libgen.h>
32 #include <poll.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <limits.h>
37 #include <libzutil.h>
38 #include <sys/crypto/icp.h>
39 #include <sys/processor.h>
40 #include <sys/rrwlock.h>
41 #include <sys/spa.h>
42 #include <sys/spa_impl.h>
43 #include <sys/sid.h>
44 #include <sys/stat.h>
45 #include <sys/systeminfo.h>
46 #include <sys/time.h>
47 #include <sys/tsd.h>
48
49 #include <libspl.h>
50 #include <libzpool.h>
51 #include <sys/zfs_context.h>
52 #include <sys/zfs_onexit.h>
53 #include <sys/zfs_vfsops.h>
54 #include <sys/zstd/zstd.h>
55 #include <sys/zvol.h>
56 #include <zfs_fletcher.h>
57 #include <zlib.h>
58
59 /*
60 * Emulation of kernel services in userland.
61 */
62
63 uint32_t hostid;
64
65 uint32_t
zone_get_hostid(void * zonep)66 zone_get_hostid(void *zonep)
67 {
68 /*
69 * We're emulating the system's hostid in userland.
70 */
71 (void) zonep;
72 return (hostid);
73 }
74
75 /*
76 * =========================================================================
77 * vnode operations
78 * =========================================================================
79 */
80
81 /*
82 * =========================================================================
83 * Figure out which debugging statements to print
84 * =========================================================================
85 */
86
87 static char *dprintf_string;
88 static int dprintf_print_all;
89
90 int
dprintf_find_string(const char * string)91 dprintf_find_string(const char *string)
92 {
93 char *tmp_str = dprintf_string;
94 int len = strlen(string);
95
96 /*
97 * Find out if this is a string we want to print.
98 * String format: file1.c,function_name1,file2.c,file3.c
99 */
100
101 while (tmp_str != NULL) {
102 if (strncmp(tmp_str, string, len) == 0 &&
103 (tmp_str[len] == ',' || tmp_str[len] == '\0'))
104 return (1);
105 tmp_str = strchr(tmp_str, ',');
106 if (tmp_str != NULL)
107 tmp_str++; /* Get rid of , */
108 }
109 return (0);
110 }
111
112 void
dprintf_setup(int * argc,char ** argv)113 dprintf_setup(int *argc, char **argv)
114 {
115 int i, j;
116
117 /*
118 * Debugging can be specified two ways: by setting the
119 * environment variable ZFS_DEBUG, or by including a
120 * "debug=..." argument on the command line. The command
121 * line setting overrides the environment variable.
122 */
123
124 for (i = 1; i < *argc; i++) {
125 int len = strlen("debug=");
126 /* First look for a command line argument */
127 if (strncmp("debug=", argv[i], len) == 0) {
128 dprintf_string = argv[i] + len;
129 /* Remove from args */
130 for (j = i; j < *argc; j++)
131 argv[j] = argv[j+1];
132 argv[j] = NULL;
133 (*argc)--;
134 }
135 }
136
137 if (dprintf_string == NULL) {
138 /* Look for ZFS_DEBUG environment variable */
139 dprintf_string = getenv("ZFS_DEBUG");
140 }
141
142 /*
143 * Are we just turning on all debugging?
144 */
145 if (dprintf_find_string("on"))
146 dprintf_print_all = 1;
147
148 if (dprintf_string != NULL)
149 zfs_flags |= ZFS_DEBUG_DPRINTF;
150 }
151
152 /*
153 * =========================================================================
154 * debug printfs
155 * =========================================================================
156 */
157 void
__dprintf(boolean_t dprint,const char * file,const char * func,int line,const char * fmt,...)158 __dprintf(boolean_t dprint, const char *file, const char *func,
159 int line, const char *fmt, ...)
160 {
161 /* Get rid of annoying "../common/" prefix to filename. */
162 const char *newfile = zfs_basename(file);
163
164 va_list adx;
165 if (dprint) {
166 /* dprintf messages are printed immediately */
167
168 if (!dprintf_print_all &&
169 !dprintf_find_string(newfile) &&
170 !dprintf_find_string(func))
171 return;
172
173 /* Print out just the function name if requested */
174 flockfile(stdout);
175 if (dprintf_find_string("pid"))
176 (void) printf("%d ", getpid());
177 if (dprintf_find_string("tid"))
178 (void) printf("%ju ",
179 (uintmax_t)(uintptr_t)pthread_self());
180 if (dprintf_find_string("cpu"))
181 (void) printf("%u ", getcpuid());
182 if (dprintf_find_string("time"))
183 (void) printf("%llu ", gethrtime());
184 if (dprintf_find_string("long"))
185 (void) printf("%s, line %d: ", newfile, line);
186 (void) printf("dprintf: %s: ", func);
187 va_start(adx, fmt);
188 (void) vprintf(fmt, adx);
189 va_end(adx);
190 funlockfile(stdout);
191 } else {
192 /* zfs_dbgmsg is logged for dumping later */
193 size_t size;
194 char *buf;
195 int i;
196
197 size = 1024;
198 buf = umem_alloc(size, UMEM_NOFAIL);
199 i = snprintf(buf, size, "%s:%d:%s(): ", newfile, line, func);
200
201 if (i < size) {
202 va_start(adx, fmt);
203 (void) vsnprintf(buf + i, size - i, fmt, adx);
204 va_end(adx);
205 }
206
207 __zfs_dbgmsg(buf);
208
209 umem_free(buf, size);
210 }
211 }
212
213 /*
214 * =========================================================================
215 * cmn_err() and panic()
216 * =========================================================================
217 */
218
219 static __attribute__((noreturn)) void
panic_stop_or_abort(void)220 panic_stop_or_abort(void)
221 {
222 const char *stopenv = getenv("LIBZPOOL_PANIC_STOP");
223 if (stopenv != NULL && atoi(stopenv)) {
224 fputs("libzpool: LIBZPOOL_PANIC_STOP is set, sending "
225 "SIGSTOP to process group\n", stderr);
226 fflush(stderr);
227
228 kill(0, SIGSTOP);
229
230 fputs("libzpool: continued after panic stop, "
231 "aborting\n", stderr);
232 }
233
234 abort(); /* think of it as a "user-level crash dump" */
235 }
236
237 static void
vcmn_msg(int ce,const char * fmt,va_list adx)238 vcmn_msg(int ce, const char *fmt, va_list adx)
239 {
240 switch (ce) {
241 case CE_IGNORE:
242 return;
243 case CE_CONT:
244 break;
245 case CE_NOTE:
246 fputs("libzpool: NOTICE: ", stderr);
247 break;
248 case CE_WARN:
249 fputs("libzpool: WARNING: ", stderr);
250 break;
251 case CE_PANIC:
252 fputs("libzpool: PANIC: ", stderr);
253 break;
254 default:
255 fputs("libzpool: [unknown severity %d]: ", stderr);
256 break;
257 }
258
259 vfprintf(stderr, fmt, adx);
260 if (ce != CE_CONT)
261 fputc('\n', stderr);
262 fflush(stderr);
263 }
264
265 void
vcmn_err(int ce,const char * fmt,va_list adx)266 vcmn_err(int ce, const char *fmt, va_list adx)
267 {
268 vcmn_msg(ce, fmt, adx);
269
270 if (ce == CE_PANIC)
271 panic_stop_or_abort();
272 }
273
274 void
cmn_err(int ce,const char * fmt,...)275 cmn_err(int ce, const char *fmt, ...)
276 {
277 va_list adx;
278
279 va_start(adx, fmt);
280 vcmn_err(ce, fmt, adx);
281 va_end(adx);
282 }
283
284 __attribute__((noreturn)) void
panic(const char * fmt,...)285 panic(const char *fmt, ...)
286 {
287 va_list adx;
288
289 va_start(adx, fmt);
290 vcmn_msg(CE_PANIC, fmt, adx);
291 va_end(adx);
292
293 panic_stop_or_abort();
294 }
295
296 __attribute__((noreturn)) void
vpanic(const char * fmt,va_list adx)297 vpanic(const char *fmt, va_list adx)
298 {
299 vcmn_msg(CE_PANIC, fmt, adx);
300 panic_stop_or_abort();
301 }
302
303 /*
304 * =========================================================================
305 * misc routines
306 * =========================================================================
307 */
308
309 void
delay(clock_t ticks)310 delay(clock_t ticks)
311 {
312 (void) poll(0, 0, ticks * (1000 / hz));
313 }
314
315 int
ddi_strtoull(const char * str,char ** nptr,int base,u_longlong_t * result)316 ddi_strtoull(const char *str, char **nptr, int base, u_longlong_t *result)
317 {
318 errno = 0;
319 *result = strtoull(str, nptr, base);
320 if (*result == 0)
321 return (errno);
322 return (0);
323 }
324
325 /*
326 * =========================================================================
327 * kernel emulation setup & teardown
328 * =========================================================================
329 */
330 static int
umem_out_of_memory(void)331 umem_out_of_memory(void)
332 {
333 char errmsg[] = "out of memory -- generating core dump\n";
334
335 (void) fprintf(stderr, "%s", errmsg);
336 abort();
337 return (0);
338 }
339
340 static void
spa_config_load(void)341 spa_config_load(void)
342 {
343 void *buf = NULL;
344 nvlist_t *nvlist, *child;
345 nvpair_t *nvpair;
346 char *pathname;
347 zfs_file_t *fp;
348 zfs_file_attr_t zfa;
349 uint64_t fsize;
350 int err;
351
352 /*
353 * Open the configuration file.
354 */
355 pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
356
357 (void) snprintf(pathname, MAXPATHLEN, "%s", spa_config_path);
358
359 err = zfs_file_open(pathname, O_RDONLY, 0, &fp);
360 if (err)
361 err = zfs_file_open(ZPOOL_CACHE_BOOT, O_RDONLY, 0, &fp);
362
363 kmem_free(pathname, MAXPATHLEN);
364
365 if (err)
366 return;
367
368 if (zfs_file_getattr(fp, &zfa))
369 goto out;
370
371 fsize = zfa.zfa_size;
372 buf = kmem_alloc(fsize, KM_SLEEP);
373
374 /*
375 * Read the nvlist from the file.
376 */
377 if (zfs_file_read(fp, buf, fsize, NULL) < 0)
378 goto out;
379
380 /*
381 * Unpack the nvlist.
382 */
383 if (nvlist_unpack(buf, fsize, &nvlist, KM_SLEEP) != 0)
384 goto out;
385
386 /*
387 * Iterate over all elements in the nvlist, creating a new spa_t for
388 * each one with the specified configuration.
389 */
390 spa_namespace_enter(FTAG);
391 nvpair = NULL;
392 while ((nvpair = nvlist_next_nvpair(nvlist, nvpair)) != NULL) {
393 if (nvpair_type(nvpair) != DATA_TYPE_NVLIST)
394 continue;
395
396 child = fnvpair_value_nvlist(nvpair);
397
398 if (spa_lookup(nvpair_name(nvpair)) != NULL)
399 continue;
400 (void) spa_add(nvpair_name(nvpair), child, NULL);
401 }
402 spa_namespace_exit(FTAG);
403
404 nvlist_free(nvlist);
405
406 out:
407 if (buf != NULL)
408 kmem_free(buf, fsize);
409
410 zfs_file_close(fp);
411 }
412
413 void
kernel_init(int mode)414 kernel_init(int mode)
415 {
416 extern uint_t rrw_tsd_key;
417
418 libspl_init();
419
420 umem_nofail_callback(umem_out_of_memory);
421
422 dprintf("physmem = %llu pages (%.2f GB)\n", (u_longlong_t)physmem,
423 (double)physmem * sysconf(_SC_PAGE_SIZE) / (1ULL << 30));
424
425 hostid = (mode & SPA_MODE_WRITE) ? get_system_hostid() : 0;
426
427 system_taskq_init();
428 icp_init();
429
430 zstd_init();
431
432 spa_init((spa_mode_t)mode);
433 spa_config_load();
434
435 fletcher_4_init();
436
437 tsd_create(&rrw_tsd_key, rrw_tsd_destroy);
438 }
439
440 void
kernel_fini(void)441 kernel_fini(void)
442 {
443 fletcher_4_fini();
444 spa_fini();
445
446 zstd_fini();
447
448 icp_fini();
449 system_taskq_fini();
450
451 libspl_fini();
452 }
453
454 zfs_file_t *
zfs_onexit_fd_hold(int fd,minor_t * minorp)455 zfs_onexit_fd_hold(int fd, minor_t *minorp)
456 {
457 (void) fd;
458 *minorp = 0;
459 return (NULL);
460 }
461
462 void
zfs_onexit_fd_rele(zfs_file_t * fp)463 zfs_onexit_fd_rele(zfs_file_t *fp)
464 {
465 (void) fp;
466 }
467
468 int
zfs_onexit_add_cb(minor_t minor,void (* func)(void *),void * data,uintptr_t * action_handle)469 zfs_onexit_add_cb(minor_t minor, void (*func)(void *), void *data,
470 uintptr_t *action_handle)
471 {
472 (void) minor, (void) func, (void) data, (void) action_handle;
473 return (0);
474 }
475
476 void
zvol_create_minors(const char * name)477 zvol_create_minors(const char *name)
478 {
479 (void) name;
480 }
481
482 void
zvol_remove_minors(spa_t * spa,const char * name,boolean_t async)483 zvol_remove_minors(spa_t *spa, const char *name, boolean_t async)
484 {
485 (void) spa, (void) name, (void) async;
486 }
487
488 void
zvol_rename_minors(spa_t * spa,const char * oldname,const char * newname,boolean_t async)489 zvol_rename_minors(spa_t *spa, const char *oldname, const char *newname,
490 boolean_t async)
491 {
492 (void) spa, (void) oldname, (void) newname, (void) async;
493 }
494
495 void
zfsvfs_update_fromname(const char * oldname,const char * newname)496 zfsvfs_update_fromname(const char *oldname, const char *newname)
497 {
498 (void) oldname, (void) newname;
499 }
500
501 void
spa_import_os(spa_t * spa)502 spa_import_os(spa_t *spa)
503 {
504 (void) spa;
505 }
506
507 void
spa_export_os(spa_t * spa)508 spa_export_os(spa_t *spa)
509 {
510 (void) spa;
511 }
512
513 void
spa_activate_os(spa_t * spa)514 spa_activate_os(spa_t *spa)
515 {
516 (void) spa;
517 }
518
519 void
spa_deactivate_os(spa_t * spa)520 spa_deactivate_os(spa_t *spa)
521 {
522 (void) spa;
523 }
524