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 /*
14 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
15 * Copyright (c) 2011, 2020 by Delphix. All rights reserved.
16 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
17 * Copyright (c) 2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
18 * All rights reserved
19 * Copyright (c) 2013 Steven Hartland. All rights reserved.
20 * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
21 * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
22 * Copyright (c) 2018, loli10K <ezomori.nozomu@gmail.com>. All rights reserved.
23 * Copyright (c) 2019 Datto Inc.
24 * Copyright (c) 2024, Klara, Inc.
25 */
26
27 #include <assert.h>
28 #include <err.h>
29 #include <errno.h>
30 #include <pthread.h>
31 #include <stddef.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <sys/abd.h>
35 #include <sys/fs/zfs.h>
36 #include <sys/stdtypes.h>
37 #include <sys/sysmacros.h>
38 #include <sys/zfs_ioctl.h>
39 #include <sys/zio.h>
40 #include <sys/zio_compress.h>
41 #include <unistd.h>
42
43 #include "zstream_util.h"
44
45 void *
safe_malloc(size_t size)46 safe_malloc(size_t size)
47 {
48 void *rv = malloc(size);
49 if (rv == NULL) {
50 errx(1, "failed to allocate %zu bytes, aborting...", size);
51 }
52 return (rv);
53 }
54
55 void *
safe_calloc(size_t size)56 safe_calloc(size_t size)
57 {
58 void *rv = calloc(1, size);
59 if (rv == NULL) {
60 errx(1, "failed to allocate %zu bytes, aborting...", size);
61 }
62 return (rv);
63 }
64
65 void
safe_pthread_sigmask(int how,const sigset_t * set,sigset_t * oldset)66 safe_pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset)
67 {
68 int error = pthread_sigmask(how, set, oldset);
69 if (error != 0) {
70 errno = error;
71 err(1, "pthread_sigmask failed");
72 }
73 }
74
75 pthread_t
safe_create_thread(thread_f * body,void * body_arg,const char * name,boolean_t detach)76 safe_create_thread(thread_f *body, void *body_arg, const char *name,
77 boolean_t detach)
78 {
79 pthread_t tid;
80 int ret;
81 int name_attempts = 3;
82
83 ret = pthread_create(&tid, NULL, body, body_arg);
84 if (ret != 0) {
85 errno = ret;
86 err(1, "pthread_create for %s failed", name);
87 }
88 /*
89 * pthread_setname_np() fails randomly on some Debian systems
90 * because of difficulty reading /proc/self/task. The characteristic
91 * error is "No such file or directory." The name is just a
92 * debugging aid, so we can ignore the error, but we'll make three
93 * attempts to set it. This code previously printed a warning
94 * message, but that interferes with zstream dump output comparisons
95 * in ZTS.
96 */
97 while (name_attempts-- > 0) {
98 ret = pthread_setname_np(tid, name);
99 if (ret == 0)
100 break;
101 usleep(100);
102 }
103 if (detach) {
104 ret = pthread_detach(tid);
105 if (ret != 0) {
106 errno = ret;
107 err(1, "failed to detach %s thread", name);
108 }
109 }
110 return (tid);
111 }
112
113 char *
checksum_str(zio_cksum_t * cksum,char * buff,size_t buff_size)114 checksum_str(zio_cksum_t *cksum, char *buff, size_t buff_size)
115 {
116 snprintf(buff, buff_size, "%.16llx / %.16llx / %.16llx / %.16llx",
117 (long long unsigned int) cksum->zc_word[0],
118 (long long unsigned int) cksum->zc_word[1],
119 (long long unsigned int) cksum->zc_word[2],
120 (long long unsigned int) cksum->zc_word[3]);
121 return (buff);
122 }
123
124 boolean_t
validate_checksum(zio_cksum_t * expected,zio_cksum_t * actual,boolean_t swap,const char * where,off_t stream_offset)125 validate_checksum(zio_cksum_t *expected, zio_cksum_t *actual,
126 boolean_t swap, const char *where, off_t stream_offset)
127 {
128 static char buff[128];
129 zio_cksum_t swapped_actual;
130
131 if (swap) {
132 swapped_actual = *actual;
133 actual = &swapped_actual;
134 ZIO_CHECKSUM_BSWAP(actual);
135 }
136 /* cppcheck-suppress uninitvar */
137 if (ZIO_CHECKSUM_EQUAL(*expected, *actual)) {
138 return (B_TRUE);
139 }
140 fflush(stdout);
141 fprintf(stderr, "Incorrect checksum %s (stream offset %lld)\n", where,
142 (longlong_t)stream_offset);
143 fprintf(stderr, "Expected = %s\n", checksum_str(expected, buff,
144 sizeof (buff)));
145 fprintf(stderr, " Actual = %s\n", checksum_str(actual, buff,
146 sizeof (buff)));
147 return (B_FALSE);
148 }
149
150 boolean_t
write_is_encrypted(struct drr_write * drrw)151 write_is_encrypted(struct drr_write *drrw)
152 {
153 for (int i = 0; i < ZIO_DATA_SALT_LEN; i++) {
154 if (drrw->drr_salt[i] != 0) {
155 return (B_TRUE);
156 }
157 }
158 return (B_FALSE);
159 }
160
161 /*
162 * The specified compress_type must reflect the buffer's actual compression.
163 * Returns an allocated buffer if decompression was successful, NULL
164 * otherwise.
165 */
166 uint8_t *
decompress_buffer(uint8_t * inbuff,size_t inbuff_size,size_t logical_size,enum zio_compress compress_type)167 decompress_buffer(uint8_t *inbuff, size_t inbuff_size, size_t logical_size,
168 enum zio_compress compress_type)
169 {
170 uint8_t *outbuff = safe_malloc(logical_size);
171 abd_t sabd, dabd;
172 int ret;
173
174 VERIFY3B(ctype_is_uncompressed(compress_type), ==, B_FALSE);
175
176 abd_get_from_buf_struct(&sabd, inbuff, inbuff_size);
177 abd_get_from_buf_struct(&dabd, outbuff, logical_size);
178 ret = zio_decompress_data(compress_type, &sabd, &dabd,
179 inbuff_size, abd_get_size(&dabd), NULL);
180
181 abd_free(&dabd);
182 abd_free(&sabd);
183
184 if (ret != 0) {
185 free(outbuff);
186 return (NULL);
187 }
188
189 return (outbuff);
190 }
191
192 /*
193 * Returns an allocated buffer if compression was successful, NULL
194 * otherwise.
195 */
196 uint8_t *
compress_buffer(uint8_t * inbuff,size_t inbuff_size,compression_spec_t compress_type,size_t * compressed_size)197 compress_buffer(uint8_t *inbuff, size_t inbuff_size,
198 compression_spec_t compress_type, size_t *compressed_size)
199 {
200 uint8_t *outbuff = safe_malloc(inbuff_size);
201 abd_t sabd, dabd;
202 size_t csize, rounded;
203
204 VERIFY3B(ctype_is_uncompressed(compress_type.cs_type), ==, B_FALSE);
205
206 abd_t *pabd = abd_get_from_buf_struct(&dabd, outbuff, inbuff_size);
207 abd_get_from_buf_struct(&sabd, inbuff, inbuff_size);
208 csize = zio_compress_data(compress_type.cs_type, &sabd,
209 &pabd, inbuff_size, inbuff_size, compress_type.cs_level);
210
211 rounded = P2ROUNDUP(csize, SPA_MINBLOCKSIZE);
212 if (rounded < inbuff_size) {
213 abd_zero_off(pabd, csize, rounded - csize);
214 *compressed_size = rounded;
215 } else {
216 free(outbuff);
217 outbuff = NULL;
218 }
219
220 abd_free(&sabd);
221 abd_free(&dabd);
222
223 return (outbuff);
224 }
225