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