xref: /src/sys/contrib/openzfs/lib/libzpool/kernel.c (revision 80aae8a3f8aa70712930664572be9e6885dc0be7)
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