author | timh |
Sun, 27 Apr 2008 10:20:38 -0700 | |
changeset 6492 | 903545192033 |
parent 5994 | bedab011a2e5 |
child 6643 | 3a34b0dbb107 |
permissions | -rw-r--r-- |
789 | 1 |
/* |
2 |
* CDDL HEADER START |
|
3 |
* |
|
4 |
* The contents of this file are subject to the terms of the |
|
1485 | 5 |
* Common Development and Distribution License (the "License"). |
6 |
* You may not use this file except in compliance with the License. |
|
789 | 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 |
/* |
|
5994
bedab011a2e5
6580270 'zdb [-C|-L] <pool'> can't open alternate root pools
ck153898
parents:
5530
diff
changeset
|
22 |
* Copyright 2008 Sun Microsystems, Inc. All rights reserved. |
789 | 23 |
* Use is subject to license terms. |
24 |
*/ |
|
25 |
||
26 |
#pragma ident "%Z%%M% %I% %E% SMI" |
|
27 |
||
28 |
/* |
|
29 |
* The objective of this program is to provide a DMU/ZAP/SPA stress test |
|
30 |
* that runs entirely in userland, is easy to use, and easy to extend. |
|
31 |
* |
|
32 |
* The overall design of the ztest program is as follows: |
|
33 |
* |
|
34 |
* (1) For each major functional area (e.g. adding vdevs to a pool, |
|
35 |
* creating and destroying datasets, reading and writing objects, etc) |
|
36 |
* we have a simple routine to test that functionality. These |
|
37 |
* individual routines do not have to do anything "stressful". |
|
38 |
* |
|
39 |
* (2) We turn these simple functionality tests into a stress test by |
|
40 |
* running them all in parallel, with as many threads as desired, |
|
41 |
* and spread across as many datasets, objects, and vdevs as desired. |
|
42 |
* |
|
43 |
* (3) While all this is happening, we inject faults into the pool to |
|
44 |
* verify that self-healing data really works. |
|
45 |
* |
|
46 |
* (4) Every time we open a dataset, we change its checksum and compression |
|
47 |
* functions. Thus even individual objects vary from block to block |
|
48 |
* in which checksum they use and whether they're compressed. |
|
49 |
* |
|
50 |
* (5) To verify that we never lose on-disk consistency after a crash, |
|
51 |
* we run the entire test in a child of the main process. |
|
52 |
* At random times, the child self-immolates with a SIGKILL. |
|
53 |
* This is the software equivalent of pulling the power cord. |
|
54 |
* The parent then runs the test again, using the existing |
|
55 |
* storage pool, as many times as desired. |
|
56 |
* |
|
57 |
* (6) To verify that we don't have future leaks or temporal incursions, |
|
58 |
* many of the functional tests record the transaction group number |
|
59 |
* as part of their data. When reading old data, they verify that |
|
60 |
* the transaction group number is less than the current, open txg. |
|
61 |
* If you add a new test, please do this if applicable. |
|
62 |
* |
|
63 |
* When run with no arguments, ztest runs for about five minutes and |
|
64 |
* produces no output if successful. To get a little bit of information, |
|
65 |
* specify -V. To get more information, specify -VV, and so on. |
|
66 |
* |
|
67 |
* To turn this into an overnight stress test, use -T to specify run time. |
|
68 |
* |
|
69 |
* You can ask more more vdevs [-v], datasets [-d], or threads [-t] |
|
70 |
* to increase the pool capacity, fanout, and overall stress level. |
|
71 |
* |
|
72 |
* The -N(okill) option will suppress kills, so each child runs to completion. |
|
73 |
* This can be useful when you're trying to distinguish temporal incursions |
|
74 |
* from plain old race conditions. |
|
75 |
*/ |
|
76 |
||
77 |
#include <sys/zfs_context.h> |
|
78 |
#include <sys/spa.h> |
|
79 |
#include <sys/dmu.h> |
|
80 |
#include <sys/txg.h> |
|
81 |
#include <sys/zap.h> |
|
82 |
#include <sys/dmu_traverse.h> |
|
83 |
#include <sys/dmu_objset.h> |
|
84 |
#include <sys/poll.h> |
|
85 |
#include <sys/stat.h> |
|
86 |
#include <sys/time.h> |
|
87 |
#include <sys/wait.h> |
|
88 |
#include <sys/mman.h> |
|
89 |
#include <sys/resource.h> |
|
90 |
#include <sys/zio.h> |
|
91 |
#include <sys/zio_checksum.h> |
|
92 |
#include <sys/zio_compress.h> |
|
93 |
#include <sys/zil.h> |
|
94 |
#include <sys/vdev_impl.h> |
|
95 |
#include <sys/spa_impl.h> |
|
96 |
#include <sys/dsl_prop.h> |
|
97 |
#include <sys/refcount.h> |
|
98 |
#include <stdio.h> |
|
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
1807
diff
changeset
|
99 |
#include <stdio_ext.h> |
789 | 100 |
#include <stdlib.h> |
101 |
#include <unistd.h> |
|
102 |
#include <signal.h> |
|
103 |
#include <umem.h> |
|
104 |
#include <dlfcn.h> |
|
105 |
#include <ctype.h> |
|
106 |
#include <math.h> |
|
107 |
#include <sys/fs/zfs.h> |
|
108 |
||
109 |
static char cmdname[] = "ztest"; |
|
110 |
static char *zopt_pool = cmdname; |
|
111 |
||
112 |
static uint64_t zopt_vdevs = 5; |
|
113 |
static uint64_t zopt_vdevtime; |
|
1732 | 114 |
static int zopt_ashift = SPA_MINBLOCKSHIFT; |
789 | 115 |
static int zopt_mirrors = 2; |
116 |
static int zopt_raidz = 4; |
|
2082 | 117 |
static int zopt_raidz_parity = 1; |
789 | 118 |
static size_t zopt_vdev_size = SPA_MINDEVSIZE; |
1732 | 119 |
static int zopt_datasets = 7; |
789 | 120 |
static int zopt_threads = 23; |
121 |
static uint64_t zopt_passtime = 60; /* 60 seconds */ |
|
122 |
static uint64_t zopt_killrate = 70; /* 70% kill rate */ |
|
123 |
static int zopt_verbose = 0; |
|
124 |
static int zopt_init = 1; |
|
125 |
static char *zopt_dir = "/tmp"; |
|
126 |
static uint64_t zopt_time = 300; /* 5 minutes */ |
|
127 |
static int zopt_maxfaults; |
|
5329 | 128 |
static uint16_t zopt_write_fail_shift = 5; |
789 | 129 |
|
5530 | 130 |
typedef struct ztest_block_tag { |
131 |
uint64_t bt_objset; |
|
132 |
uint64_t bt_object; |
|
133 |
uint64_t bt_offset; |
|
134 |
uint64_t bt_txg; |
|
135 |
uint64_t bt_thread; |
|
136 |
uint64_t bt_seq; |
|
137 |
} ztest_block_tag_t; |
|
138 |
||
789 | 139 |
typedef struct ztest_args { |
5530 | 140 |
char za_pool[MAXNAMELEN]; |
141 |
spa_t *za_spa; |
|
789 | 142 |
objset_t *za_os; |
143 |
zilog_t *za_zilog; |
|
144 |
thread_t za_thread; |
|
145 |
uint64_t za_instance; |
|
146 |
uint64_t za_random; |
|
147 |
uint64_t za_diroff; |
|
148 |
uint64_t za_diroff_shared; |
|
1544 | 149 |
uint64_t za_zil_seq; |
789 | 150 |
hrtime_t za_start; |
151 |
hrtime_t za_stop; |
|
152 |
hrtime_t za_kill; |
|
153 |
traverse_handle_t *za_th; |
|
5530 | 154 |
/* |
155 |
* Thread-local variables can go here to aid debugging. |
|
156 |
*/ |
|
157 |
ztest_block_tag_t za_rbt; |
|
158 |
ztest_block_tag_t za_wbt; |
|
159 |
dmu_object_info_t za_doi; |
|
160 |
dmu_buf_t *za_dbuf; |
|
789 | 161 |
} ztest_args_t; |
162 |
||
163 |
typedef void ztest_func_t(ztest_args_t *); |
|
164 |
||
165 |
/* |
|
166 |
* Note: these aren't static because we want dladdr() to work. |
|
167 |
*/ |
|
168 |
ztest_func_t ztest_dmu_read_write; |
|
169 |
ztest_func_t ztest_dmu_write_parallel; |
|
170 |
ztest_func_t ztest_dmu_object_alloc_free; |
|
171 |
ztest_func_t ztest_zap; |
|
172 |
ztest_func_t ztest_zap_parallel; |
|
173 |
ztest_func_t ztest_traverse; |
|
174 |
ztest_func_t ztest_dsl_prop_get_set; |
|
175 |
ztest_func_t ztest_dmu_objset_create_destroy; |
|
176 |
ztest_func_t ztest_dmu_snapshot_create_destroy; |
|
177 |
ztest_func_t ztest_spa_create_destroy; |
|
178 |
ztest_func_t ztest_fault_inject; |
|
179 |
ztest_func_t ztest_vdev_attach_detach; |
|
180 |
ztest_func_t ztest_vdev_LUN_growth; |
|
181 |
ztest_func_t ztest_vdev_add_remove; |
|
182 |
ztest_func_t ztest_scrub; |
|
183 |
ztest_func_t ztest_spa_rename; |
|
184 |
||
185 |
typedef struct ztest_info { |
|
186 |
ztest_func_t *zi_func; /* test function */ |
|
5530 | 187 |
uint64_t zi_iters; /* iterations per execution */ |
789 | 188 |
uint64_t *zi_interval; /* execute every <interval> seconds */ |
189 |
uint64_t zi_calls; /* per-pass count */ |
|
190 |
uint64_t zi_call_time; /* per-pass time */ |
|
191 |
uint64_t zi_call_total; /* cumulative total */ |
|
192 |
uint64_t zi_call_target; /* target cumulative total */ |
|
193 |
} ztest_info_t; |
|
194 |
||
195 |
uint64_t zopt_always = 0; /* all the time */ |
|
196 |
uint64_t zopt_often = 1; /* every second */ |
|
197 |
uint64_t zopt_sometimes = 10; /* every 10 seconds */ |
|
198 |
uint64_t zopt_rarely = 60; /* every 60 seconds */ |
|
199 |
||
200 |
ztest_info_t ztest_info[] = { |
|
5530 | 201 |
{ ztest_dmu_read_write, 1, &zopt_always }, |
202 |
{ ztest_dmu_write_parallel, 30, &zopt_always }, |
|
203 |
{ ztest_dmu_object_alloc_free, 1, &zopt_always }, |
|
204 |
{ ztest_zap, 30, &zopt_always }, |
|
205 |
{ ztest_zap_parallel, 100, &zopt_always }, |
|
206 |
{ ztest_traverse, 1, &zopt_often }, |
|
207 |
{ ztest_dsl_prop_get_set, 1, &zopt_sometimes }, |
|
208 |
{ ztest_dmu_objset_create_destroy, 1, &zopt_sometimes }, |
|
209 |
{ ztest_dmu_snapshot_create_destroy, 1, &zopt_rarely }, |
|
210 |
{ ztest_spa_create_destroy, 1, &zopt_sometimes }, |
|
211 |
{ ztest_fault_inject, 1, &zopt_sometimes }, |
|
212 |
{ ztest_spa_rename, 1, &zopt_rarely }, |
|
213 |
{ ztest_vdev_attach_detach, 1, &zopt_rarely }, |
|
214 |
{ ztest_vdev_LUN_growth, 1, &zopt_rarely }, |
|
215 |
{ ztest_vdev_add_remove, 1, &zopt_vdevtime }, |
|
216 |
{ ztest_scrub, 1, &zopt_vdevtime }, |
|
789 | 217 |
}; |
218 |
||
219 |
#define ZTEST_FUNCS (sizeof (ztest_info) / sizeof (ztest_info_t)) |
|
220 |
||
221 |
#define ZTEST_SYNC_LOCKS 16 |
|
222 |
||
223 |
/* |
|
224 |
* Stuff we need to share writably between parent and child. |
|
225 |
*/ |
|
226 |
typedef struct ztest_shared { |
|
227 |
mutex_t zs_vdev_lock; |
|
228 |
rwlock_t zs_name_lock; |
|
229 |
uint64_t zs_vdev_primaries; |
|
230 |
uint64_t zs_enospc_count; |
|
231 |
hrtime_t zs_start_time; |
|
232 |
hrtime_t zs_stop_time; |
|
233 |
uint64_t zs_alloc; |
|
234 |
uint64_t zs_space; |
|
235 |
ztest_info_t zs_info[ZTEST_FUNCS]; |
|
236 |
mutex_t zs_sync_lock[ZTEST_SYNC_LOCKS]; |
|
237 |
uint64_t zs_seq[ZTEST_SYNC_LOCKS]; |
|
238 |
} ztest_shared_t; |
|
239 |
||
240 |
static char ztest_dev_template[] = "%s/%s.%llua"; |
|
241 |
static ztest_shared_t *ztest_shared; |
|
242 |
||
243 |
static int ztest_random_fd; |
|
244 |
static int ztest_dump_core = 1; |
|
245 |
||
5329 | 246 |
static boolean_t ztest_exiting = B_FALSE; |
247 |
||
5530 | 248 |
extern uint64_t metaslab_gang_bang; |
3668 | 249 |
extern uint16_t zio_zil_fail_shift; |
5329 | 250 |
extern uint16_t zio_io_fail_shift; |
789 | 251 |
|
252 |
#define ZTEST_DIROBJ 1 |
|
253 |
#define ZTEST_MICROZAP_OBJ 2 |
|
254 |
#define ZTEST_FATZAP_OBJ 3 |
|
255 |
||
256 |
#define ZTEST_DIROBJ_BLOCKSIZE (1 << 10) |
|
257 |
#define ZTEST_DIRSIZE 256 |
|
258 |
||
4008
a95c00c4179a
6543732 fix for 6524407 broke the nightly build with gcc
raf
parents:
3972
diff
changeset
|
259 |
static void usage(boolean_t) __NORETURN; |
3972 | 260 |
|
789 | 261 |
/* |
262 |
* These libumem hooks provide a reasonable set of defaults for the allocator's |
|
263 |
* debugging facilities. |
|
264 |
*/ |
|
265 |
const char * |
|
266 |
_umem_debug_init() |
|
267 |
{ |
|
268 |
return ("default,verbose"); /* $UMEM_DEBUG setting */ |
|
269 |
} |
|
270 |
||
271 |
const char * |
|
272 |
_umem_logging_init(void) |
|
273 |
{ |
|
274 |
return ("fail,contents"); /* $UMEM_LOGGING setting */ |
|
275 |
} |
|
276 |
||
277 |
#define FATAL_MSG_SZ 1024 |
|
278 |
||
279 |
char *fatal_msg; |
|
280 |
||
281 |
static void |
|
282 |
fatal(int do_perror, char *message, ...) |
|
283 |
{ |
|
284 |
va_list args; |
|
285 |
int save_errno = errno; |
|
286 |
char buf[FATAL_MSG_SZ]; |
|
287 |
||
288 |
(void) fflush(stdout); |
|
289 |
||
290 |
va_start(args, message); |
|
291 |
(void) sprintf(buf, "ztest: "); |
|
292 |
/* LINTED */ |
|
293 |
(void) vsprintf(buf + strlen(buf), message, args); |
|
294 |
va_end(args); |
|
295 |
if (do_perror) { |
|
296 |
(void) snprintf(buf + strlen(buf), FATAL_MSG_SZ - strlen(buf), |
|
297 |
": %s", strerror(save_errno)); |
|
298 |
} |
|
299 |
(void) fprintf(stderr, "%s\n", buf); |
|
300 |
fatal_msg = buf; /* to ease debugging */ |
|
301 |
if (ztest_dump_core) |
|
302 |
abort(); |
|
303 |
exit(3); |
|
304 |
} |
|
305 |
||
306 |
static int |
|
307 |
str2shift(const char *buf) |
|
308 |
{ |
|
309 |
const char *ends = "BKMGTPEZ"; |
|
310 |
int i; |
|
311 |
||
312 |
if (buf[0] == '\0') |
|
313 |
return (0); |
|
314 |
for (i = 0; i < strlen(ends); i++) { |
|
315 |
if (toupper(buf[0]) == ends[i]) |
|
316 |
break; |
|
317 |
} |
|
3972 | 318 |
if (i == strlen(ends)) { |
319 |
(void) fprintf(stderr, "ztest: invalid bytes suffix: %s\n", |
|
320 |
buf); |
|
321 |
usage(B_FALSE); |
|
322 |
} |
|
789 | 323 |
if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0')) { |
324 |
return (10*i); |
|
325 |
} |
|
3972 | 326 |
(void) fprintf(stderr, "ztest: invalid bytes suffix: %s\n", buf); |
327 |
usage(B_FALSE); |
|
328 |
/* NOTREACHED */ |
|
789 | 329 |
} |
330 |
||
331 |
static uint64_t |
|
332 |
nicenumtoull(const char *buf) |
|
333 |
{ |
|
334 |
char *end; |
|
335 |
uint64_t val; |
|
336 |
||
337 |
val = strtoull(buf, &end, 0); |
|
338 |
if (end == buf) { |
|
3972 | 339 |
(void) fprintf(stderr, "ztest: bad numeric value: %s\n", buf); |
340 |
usage(B_FALSE); |
|
789 | 341 |
} else if (end[0] == '.') { |
342 |
double fval = strtod(buf, &end); |
|
343 |
fval *= pow(2, str2shift(end)); |
|
3972 | 344 |
if (fval > UINT64_MAX) { |
345 |
(void) fprintf(stderr, "ztest: value too large: %s\n", |
|
346 |
buf); |
|
347 |
usage(B_FALSE); |
|
348 |
} |
|
789 | 349 |
val = (uint64_t)fval; |
350 |
} else { |
|
351 |
int shift = str2shift(end); |
|
3972 | 352 |
if (shift >= 64 || (val << shift) >> shift != val) { |
353 |
(void) fprintf(stderr, "ztest: value too large: %s\n", |
|
354 |
buf); |
|
355 |
usage(B_FALSE); |
|
356 |
} |
|
789 | 357 |
val <<= shift; |
358 |
} |
|
359 |
return (val); |
|
360 |
} |
|
361 |
||
362 |
static void |
|
3972 | 363 |
usage(boolean_t requested) |
789 | 364 |
{ |
365 |
char nice_vdev_size[10]; |
|
366 |
char nice_gang_bang[10]; |
|
3972 | 367 |
FILE *fp = requested ? stdout : stderr; |
789 | 368 |
|
369 |
nicenum(zopt_vdev_size, nice_vdev_size); |
|
5530 | 370 |
nicenum(metaslab_gang_bang, nice_gang_bang); |
789 | 371 |
|
3972 | 372 |
(void) fprintf(fp, "Usage: %s\n" |
789 | 373 |
"\t[-v vdevs (default: %llu)]\n" |
374 |
"\t[-s size_of_each_vdev (default: %s)]\n" |
|
1732 | 375 |
"\t[-a alignment_shift (default: %d) (use 0 for random)]\n" |
789 | 376 |
"\t[-m mirror_copies (default: %d)]\n" |
377 |
"\t[-r raidz_disks (default: %d)]\n" |
|
2082 | 378 |
"\t[-R raidz_parity (default: %d)]\n" |
789 | 379 |
"\t[-d datasets (default: %d)]\n" |
380 |
"\t[-t threads (default: %d)]\n" |
|
381 |
"\t[-g gang_block_threshold (default: %s)]\n" |
|
382 |
"\t[-i initialize pool i times (default: %d)]\n" |
|
383 |
"\t[-k kill percentage (default: %llu%%)]\n" |
|
384 |
"\t[-p pool_name (default: %s)]\n" |
|
385 |
"\t[-f file directory for vdev files (default: %s)]\n" |
|
386 |
"\t[-V(erbose)] (use multiple times for ever more blather)\n" |
|
1732 | 387 |
"\t[-E(xisting)] (use existing pool instead of creating new one)\n" |
789 | 388 |
"\t[-T time] total run time (default: %llu sec)\n" |
389 |
"\t[-P passtime] time per pass (default: %llu sec)\n" |
|
3668 | 390 |
"\t[-z zil failure rate (default: fail every 2^%llu allocs)]\n" |
5329 | 391 |
"\t[-w write failure rate (default: fail every 2^%llu allocs)]\n" |
3972 | 392 |
"\t[-h] (print help)\n" |
789 | 393 |
"", |
394 |
cmdname, |
|
5329 | 395 |
(u_longlong_t)zopt_vdevs, /* -v */ |
396 |
nice_vdev_size, /* -s */ |
|
397 |
zopt_ashift, /* -a */ |
|
398 |
zopt_mirrors, /* -m */ |
|
399 |
zopt_raidz, /* -r */ |
|
400 |
zopt_raidz_parity, /* -R */ |
|
401 |
zopt_datasets, /* -d */ |
|
402 |
zopt_threads, /* -t */ |
|
403 |
nice_gang_bang, /* -g */ |
|
404 |
zopt_init, /* -i */ |
|
405 |
(u_longlong_t)zopt_killrate, /* -k */ |
|
406 |
zopt_pool, /* -p */ |
|
407 |
zopt_dir, /* -f */ |
|
408 |
(u_longlong_t)zopt_time, /* -T */ |
|
409 |
(u_longlong_t)zopt_passtime, /* -P */ |
|
410 |
(u_longlong_t)zio_zil_fail_shift, /* -z */ |
|
411 |
(u_longlong_t)zopt_write_fail_shift); /* -w */ |
|
3972 | 412 |
exit(requested ? 0 : 1); |
789 | 413 |
} |
414 |
||
415 |
static uint64_t |
|
416 |
ztest_random(uint64_t range) |
|
417 |
{ |
|
418 |
uint64_t r; |
|
419 |
||
420 |
if (range == 0) |
|
421 |
return (0); |
|
422 |
||
423 |
if (read(ztest_random_fd, &r, sizeof (r)) != sizeof (r)) |
|
424 |
fatal(1, "short read from /dev/urandom"); |
|
425 |
||
426 |
return (r % range); |
|
427 |
} |
|
428 |
||
429 |
static void |
|
430 |
ztest_record_enospc(char *s) |
|
431 |
{ |
|
432 |
dprintf("ENOSPC doing: %s\n", s ? s : "<unknown>"); |
|
433 |
ztest_shared->zs_enospc_count++; |
|
434 |
} |
|
435 |
||
436 |
static void |
|
437 |
process_options(int argc, char **argv) |
|
438 |
{ |
|
439 |
int opt; |
|
440 |
uint64_t value; |
|
441 |
||
442 |
/* By default, test gang blocks for blocks 32K and greater */ |
|
5530 | 443 |
metaslab_gang_bang = 32 << 10; |
789 | 444 |
|
3668 | 445 |
/* Default value, fail every 32nd allocation */ |
446 |
zio_zil_fail_shift = 5; |
|
447 |
||
789 | 448 |
while ((opt = getopt(argc, argv, |
5329 | 449 |
"v:s:a:m:r:R:d:t:g:i:k:p:f:VET:P:z:w:h")) != EOF) { |
789 | 450 |
value = 0; |
451 |
switch (opt) { |
|
4451 | 452 |
case 'v': |
453 |
case 's': |
|
454 |
case 'a': |
|
455 |
case 'm': |
|
456 |
case 'r': |
|
457 |
case 'R': |
|
458 |
case 'd': |
|
459 |
case 't': |
|
460 |
case 'g': |
|
461 |
case 'i': |
|
462 |
case 'k': |
|
463 |
case 'T': |
|
464 |
case 'P': |
|
465 |
case 'z': |
|
5329 | 466 |
case 'w': |
789 | 467 |
value = nicenumtoull(optarg); |
468 |
} |
|
469 |
switch (opt) { |
|
4451 | 470 |
case 'v': |
789 | 471 |
zopt_vdevs = value; |
472 |
break; |
|
4451 | 473 |
case 's': |
789 | 474 |
zopt_vdev_size = MAX(SPA_MINDEVSIZE, value); |
475 |
break; |
|
4451 | 476 |
case 'a': |
1732 | 477 |
zopt_ashift = value; |
478 |
break; |
|
4451 | 479 |
case 'm': |
789 | 480 |
zopt_mirrors = value; |
481 |
break; |
|
4451 | 482 |
case 'r': |
789 | 483 |
zopt_raidz = MAX(1, value); |
484 |
break; |
|
4451 | 485 |
case 'R': |
2082 | 486 |
zopt_raidz_parity = MIN(MAX(value, 1), 2); |
487 |
break; |
|
4451 | 488 |
case 'd': |
1732 | 489 |
zopt_datasets = MAX(1, value); |
789 | 490 |
break; |
4451 | 491 |
case 't': |
789 | 492 |
zopt_threads = MAX(1, value); |
493 |
break; |
|
4451 | 494 |
case 'g': |
5530 | 495 |
metaslab_gang_bang = MAX(SPA_MINBLOCKSIZE << 1, value); |
789 | 496 |
break; |
4451 | 497 |
case 'i': |
789 | 498 |
zopt_init = value; |
499 |
break; |
|
4451 | 500 |
case 'k': |
789 | 501 |
zopt_killrate = value; |
502 |
break; |
|
4451 | 503 |
case 'p': |
789 | 504 |
zopt_pool = strdup(optarg); |
505 |
break; |
|
4451 | 506 |
case 'f': |
789 | 507 |
zopt_dir = strdup(optarg); |
508 |
break; |
|
4451 | 509 |
case 'V': |
789 | 510 |
zopt_verbose++; |
511 |
break; |
|
4451 | 512 |
case 'E': |
789 | 513 |
zopt_init = 0; |
514 |
break; |
|
4451 | 515 |
case 'T': |
789 | 516 |
zopt_time = value; |
517 |
break; |
|
4451 | 518 |
case 'P': |
789 | 519 |
zopt_passtime = MAX(1, value); |
520 |
break; |
|
4451 | 521 |
case 'z': |
3668 | 522 |
zio_zil_fail_shift = MIN(value, 16); |
523 |
break; |
|
5329 | 524 |
case 'w': |
525 |
zopt_write_fail_shift = MIN(value, 16); |
|
526 |
break; |
|
4451 | 527 |
case 'h': |
3972 | 528 |
usage(B_TRUE); |
529 |
break; |
|
4451 | 530 |
case '?': |
531 |
default: |
|
3972 | 532 |
usage(B_FALSE); |
789 | 533 |
break; |
534 |
} |
|
535 |
} |
|
536 |
||
2082 | 537 |
zopt_raidz_parity = MIN(zopt_raidz_parity, zopt_raidz - 1); |
538 |
||
789 | 539 |
zopt_vdevtime = (zopt_vdevs > 0 ? zopt_time / zopt_vdevs : UINT64_MAX); |
2082 | 540 |
zopt_maxfaults = MAX(zopt_mirrors, 1) * (zopt_raidz_parity + 1) - 1; |
789 | 541 |
} |
542 |
||
1732 | 543 |
static uint64_t |
544 |
ztest_get_ashift(void) |
|
545 |
{ |
|
546 |
if (zopt_ashift == 0) |
|
547 |
return (SPA_MINBLOCKSHIFT + ztest_random(3)); |
|
548 |
return (zopt_ashift); |
|
549 |
} |
|
550 |
||
789 | 551 |
static nvlist_t * |
552 |
make_vdev_file(size_t size) |
|
553 |
{ |
|
554 |
char dev_name[MAXPATHLEN]; |
|
555 |
uint64_t vdev; |
|
1732 | 556 |
uint64_t ashift = ztest_get_ashift(); |
789 | 557 |
int fd; |
558 |
nvlist_t *file; |
|
559 |
||
560 |
if (size == 0) { |
|
561 |
(void) snprintf(dev_name, sizeof (dev_name), "%s", |
|
562 |
"/dev/bogus"); |
|
563 |
} else { |
|
564 |
vdev = ztest_shared->zs_vdev_primaries++; |
|
565 |
(void) sprintf(dev_name, ztest_dev_template, |
|
566 |
zopt_dir, zopt_pool, vdev); |
|
567 |
||
568 |
fd = open(dev_name, O_RDWR | O_CREAT | O_TRUNC, 0666); |
|
569 |
if (fd == -1) |
|
570 |
fatal(1, "can't open %s", dev_name); |
|
571 |
if (ftruncate(fd, size) != 0) |
|
572 |
fatal(1, "can't ftruncate %s", dev_name); |
|
573 |
(void) close(fd); |
|
574 |
} |
|
575 |
||
576 |
VERIFY(nvlist_alloc(&file, NV_UNIQUE_NAME, 0) == 0); |
|
577 |
VERIFY(nvlist_add_string(file, ZPOOL_CONFIG_TYPE, VDEV_TYPE_FILE) == 0); |
|
578 |
VERIFY(nvlist_add_string(file, ZPOOL_CONFIG_PATH, dev_name) == 0); |
|
1732 | 579 |
VERIFY(nvlist_add_uint64(file, ZPOOL_CONFIG_ASHIFT, ashift) == 0); |
789 | 580 |
|
581 |
return (file); |
|
582 |
} |
|
583 |
||
584 |
static nvlist_t * |
|
585 |
make_vdev_raidz(size_t size, int r) |
|
586 |
{ |
|
587 |
nvlist_t *raidz, **child; |
|
588 |
int c; |
|
589 |
||
590 |
if (r < 2) |
|
591 |
return (make_vdev_file(size)); |
|
592 |
||
593 |
child = umem_alloc(r * sizeof (nvlist_t *), UMEM_NOFAIL); |
|
594 |
||
595 |
for (c = 0; c < r; c++) |
|
596 |
child[c] = make_vdev_file(size); |
|
597 |
||
598 |
VERIFY(nvlist_alloc(&raidz, NV_UNIQUE_NAME, 0) == 0); |
|
599 |
VERIFY(nvlist_add_string(raidz, ZPOOL_CONFIG_TYPE, |
|
600 |
VDEV_TYPE_RAIDZ) == 0); |
|
2082 | 601 |
VERIFY(nvlist_add_uint64(raidz, ZPOOL_CONFIG_NPARITY, |
602 |
zopt_raidz_parity) == 0); |
|
789 | 603 |
VERIFY(nvlist_add_nvlist_array(raidz, ZPOOL_CONFIG_CHILDREN, |
604 |
child, r) == 0); |
|
605 |
||
606 |
for (c = 0; c < r; c++) |
|
607 |
nvlist_free(child[c]); |
|
608 |
||
609 |
umem_free(child, r * sizeof (nvlist_t *)); |
|
610 |
||
611 |
return (raidz); |
|
612 |
} |
|
613 |
||
614 |
static nvlist_t * |
|
4527 | 615 |
make_vdev_mirror(size_t size, int log, int r, int m) |
789 | 616 |
{ |
617 |
nvlist_t *mirror, **child; |
|
618 |
int c; |
|
619 |
||
620 |
if (m < 1) |
|
621 |
return (make_vdev_raidz(size, r)); |
|
622 |
||
623 |
child = umem_alloc(m * sizeof (nvlist_t *), UMEM_NOFAIL); |
|
624 |
||
625 |
for (c = 0; c < m; c++) |
|
626 |
child[c] = make_vdev_raidz(size, r); |
|
627 |
||
628 |
VERIFY(nvlist_alloc(&mirror, NV_UNIQUE_NAME, 0) == 0); |
|
629 |
VERIFY(nvlist_add_string(mirror, ZPOOL_CONFIG_TYPE, |
|
630 |
VDEV_TYPE_MIRROR) == 0); |
|
631 |
VERIFY(nvlist_add_nvlist_array(mirror, ZPOOL_CONFIG_CHILDREN, |
|
632 |
child, m) == 0); |
|
4527 | 633 |
VERIFY(nvlist_add_uint64(mirror, ZPOOL_CONFIG_IS_LOG, log) == 0); |
789 | 634 |
|
635 |
for (c = 0; c < m; c++) |
|
636 |
nvlist_free(child[c]); |
|
637 |
||
638 |
umem_free(child, m * sizeof (nvlist_t *)); |
|
639 |
||
640 |
return (mirror); |
|
641 |
} |
|
642 |
||
643 |
static nvlist_t * |
|
4527 | 644 |
make_vdev_root(size_t size, int log, int r, int m, int t) |
789 | 645 |
{ |
646 |
nvlist_t *root, **child; |
|
647 |
int c; |
|
648 |
||
649 |
ASSERT(t > 0); |
|
650 |
||
651 |
child = umem_alloc(t * sizeof (nvlist_t *), UMEM_NOFAIL); |
|
652 |
||
653 |
for (c = 0; c < t; c++) |
|
4527 | 654 |
child[c] = make_vdev_mirror(size, log, r, m); |
789 | 655 |
|
656 |
VERIFY(nvlist_alloc(&root, NV_UNIQUE_NAME, 0) == 0); |
|
657 |
VERIFY(nvlist_add_string(root, ZPOOL_CONFIG_TYPE, VDEV_TYPE_ROOT) == 0); |
|
658 |
VERIFY(nvlist_add_nvlist_array(root, ZPOOL_CONFIG_CHILDREN, |
|
659 |
child, t) == 0); |
|
660 |
||
661 |
for (c = 0; c < t; c++) |
|
662 |
nvlist_free(child[c]); |
|
663 |
||
664 |
umem_free(child, t * sizeof (nvlist_t *)); |
|
665 |
||
666 |
return (root); |
|
667 |
} |
|
668 |
||
669 |
static void |
|
670 |
ztest_set_random_blocksize(objset_t *os, uint64_t object, dmu_tx_t *tx) |
|
671 |
{ |
|
672 |
int bs = SPA_MINBLOCKSHIFT + |
|
673 |
ztest_random(SPA_MAXBLOCKSHIFT - SPA_MINBLOCKSHIFT + 1); |
|
674 |
int ibs = DN_MIN_INDBLKSHIFT + |
|
675 |
ztest_random(DN_MAX_INDBLKSHIFT - DN_MIN_INDBLKSHIFT + 1); |
|
676 |
int error; |
|
677 |
||
678 |
error = dmu_object_set_blocksize(os, object, 1ULL << bs, ibs, tx); |
|
679 |
if (error) { |
|
680 |
char osname[300]; |
|
681 |
dmu_objset_name(os, osname); |
|
682 |
fatal(0, "dmu_object_set_blocksize('%s', %llu, %d, %d) = %d", |
|
683 |
osname, object, 1 << bs, ibs, error); |
|
684 |
} |
|
685 |
} |
|
686 |
||
687 |
static uint8_t |
|
688 |
ztest_random_checksum(void) |
|
689 |
{ |
|
690 |
uint8_t checksum; |
|
691 |
||
692 |
do { |
|
693 |
checksum = ztest_random(ZIO_CHECKSUM_FUNCTIONS); |
|
694 |
} while (zio_checksum_table[checksum].ci_zbt); |
|
695 |
||
696 |
if (checksum == ZIO_CHECKSUM_OFF) |
|
697 |
checksum = ZIO_CHECKSUM_ON; |
|
698 |
||
699 |
return (checksum); |
|
700 |
} |
|
701 |
||
702 |
static uint8_t |
|
703 |
ztest_random_compress(void) |
|
704 |
{ |
|
705 |
return ((uint8_t)ztest_random(ZIO_COMPRESS_FUNCTIONS)); |
|
706 |
} |
|
707 |
||
708 |
typedef struct ztest_replay { |
|
709 |
objset_t *zr_os; |
|
710 |
uint64_t zr_assign; |
|
711 |
} ztest_replay_t; |
|
712 |
||
713 |
static int |
|
714 |
ztest_replay_create(ztest_replay_t *zr, lr_create_t *lr, boolean_t byteswap) |
|
715 |
{ |
|
716 |
objset_t *os = zr->zr_os; |
|
717 |
dmu_tx_t *tx; |
|
718 |
int error; |
|
719 |
||
720 |
if (byteswap) |
|
721 |
byteswap_uint64_array(lr, sizeof (*lr)); |
|
722 |
||
723 |
tx = dmu_tx_create(os); |
|
724 |
dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); |
|
725 |
error = dmu_tx_assign(tx, zr->zr_assign); |
|
726 |
if (error) { |
|
727 |
dmu_tx_abort(tx); |
|
728 |
return (error); |
|
729 |
} |
|
730 |
||
731 |
error = dmu_object_claim(os, lr->lr_doid, lr->lr_mode, 0, |
|
732 |
DMU_OT_NONE, 0, tx); |
|
2082 | 733 |
ASSERT3U(error, ==, 0); |
789 | 734 |
dmu_tx_commit(tx); |
735 |
||
736 |
if (zopt_verbose >= 5) { |
|
737 |
char osname[MAXNAMELEN]; |
|
738 |
dmu_objset_name(os, osname); |
|
739 |
(void) printf("replay create of %s object %llu" |
|
740 |
" in txg %llu = %d\n", |
|
741 |
osname, (u_longlong_t)lr->lr_doid, |
|
742 |
(u_longlong_t)zr->zr_assign, error); |
|
743 |
} |
|
744 |
||
745 |
return (error); |
|
746 |
} |
|
747 |
||
748 |
static int |
|
749 |
ztest_replay_remove(ztest_replay_t *zr, lr_remove_t *lr, boolean_t byteswap) |
|
750 |
{ |
|
751 |
objset_t *os = zr->zr_os; |
|
752 |
dmu_tx_t *tx; |
|
753 |
int error; |
|
754 |
||
755 |
if (byteswap) |
|
756 |
byteswap_uint64_array(lr, sizeof (*lr)); |
|
757 |
||
758 |
tx = dmu_tx_create(os); |
|
759 |
dmu_tx_hold_free(tx, lr->lr_doid, 0, DMU_OBJECT_END); |
|
760 |
error = dmu_tx_assign(tx, zr->zr_assign); |
|
761 |
if (error) { |
|
762 |
dmu_tx_abort(tx); |
|
763 |
return (error); |
|
764 |
} |
|
765 |
||
766 |
error = dmu_object_free(os, lr->lr_doid, tx); |
|
767 |
dmu_tx_commit(tx); |
|
768 |
||
769 |
return (error); |
|
770 |
} |
|
771 |
||
772 |
zil_replay_func_t *ztest_replay_vector[TX_MAX_TYPE] = { |
|
773 |
NULL, /* 0 no such transaction type */ |
|
774 |
ztest_replay_create, /* TX_CREATE */ |
|
775 |
NULL, /* TX_MKDIR */ |
|
776 |
NULL, /* TX_MKXATTR */ |
|
777 |
NULL, /* TX_SYMLINK */ |
|
778 |
ztest_replay_remove, /* TX_REMOVE */ |
|
779 |
NULL, /* TX_RMDIR */ |
|
780 |
NULL, /* TX_LINK */ |
|
781 |
NULL, /* TX_RENAME */ |
|
782 |
NULL, /* TX_WRITE */ |
|
783 |
NULL, /* TX_TRUNCATE */ |
|
784 |
NULL, /* TX_SETATTR */ |
|
785 |
NULL, /* TX_ACL */ |
|
786 |
}; |
|
787 |
||
788 |
/* |
|
789 |
* Verify that we can't destroy an active pool, create an existing pool, |
|
790 |
* or create a pool with a bad vdev spec. |
|
791 |
*/ |
|
792 |
void |
|
793 |
ztest_spa_create_destroy(ztest_args_t *za) |
|
794 |
{ |
|
795 |
int error; |
|
796 |
spa_t *spa; |
|
797 |
nvlist_t *nvroot; |
|
798 |
||
799 |
/* |
|
800 |
* Attempt to create using a bad file. |
|
801 |
*/ |
|
4527 | 802 |
nvroot = make_vdev_root(0, 0, 0, 0, 1); |
4715
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4543
diff
changeset
|
803 |
error = spa_create("ztest_bad_file", nvroot, NULL, NULL); |
789 | 804 |
nvlist_free(nvroot); |
805 |
if (error != ENOENT) |
|
806 |
fatal(0, "spa_create(bad_file) = %d", error); |
|
807 |
||
808 |
/* |
|
809 |
* Attempt to create using a bad mirror. |
|
810 |
*/ |
|
4527 | 811 |
nvroot = make_vdev_root(0, 0, 0, 2, 1); |
4715
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4543
diff
changeset
|
812 |
error = spa_create("ztest_bad_mirror", nvroot, NULL, NULL); |
789 | 813 |
nvlist_free(nvroot); |
814 |
if (error != ENOENT) |
|
815 |
fatal(0, "spa_create(bad_mirror) = %d", error); |
|
816 |
||
817 |
/* |
|
818 |
* Attempt to create an existing pool. It shouldn't matter |
|
819 |
* what's in the nvroot; we should fail with EEXIST. |
|
820 |
*/ |
|
821 |
(void) rw_rdlock(&ztest_shared->zs_name_lock); |
|
4527 | 822 |
nvroot = make_vdev_root(0, 0, 0, 0, 1); |
4715
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4543
diff
changeset
|
823 |
error = spa_create(za->za_pool, nvroot, NULL, NULL); |
789 | 824 |
nvlist_free(nvroot); |
825 |
if (error != EEXIST) |
|
826 |
fatal(0, "spa_create(whatever) = %d", error); |
|
827 |
||
828 |
error = spa_open(za->za_pool, &spa, FTAG); |
|
829 |
if (error) |
|
830 |
fatal(0, "spa_open() = %d", error); |
|
831 |
||
832 |
error = spa_destroy(za->za_pool); |
|
833 |
if (error != EBUSY) |
|
834 |
fatal(0, "spa_destroy() = %d", error); |
|
835 |
||
836 |
spa_close(spa, FTAG); |
|
837 |
(void) rw_unlock(&ztest_shared->zs_name_lock); |
|
838 |
} |
|
839 |
||
840 |
/* |
|
841 |
* Verify that vdev_add() works as expected. |
|
842 |
*/ |
|
843 |
void |
|
844 |
ztest_vdev_add_remove(ztest_args_t *za) |
|
845 |
{ |
|
5530 | 846 |
spa_t *spa = za->za_spa; |
789 | 847 |
uint64_t leaves = MAX(zopt_mirrors, 1) * zopt_raidz; |
848 |
nvlist_t *nvroot; |
|
849 |
int error; |
|
850 |
||
851 |
if (zopt_verbose >= 6) |
|
852 |
(void) printf("adding vdev\n"); |
|
853 |
||
854 |
(void) mutex_lock(&ztest_shared->zs_vdev_lock); |
|
855 |
||
1544 | 856 |
spa_config_enter(spa, RW_READER, FTAG); |
789 | 857 |
|
858 |
ztest_shared->zs_vdev_primaries = |
|
859 |
spa->spa_root_vdev->vdev_children * leaves; |
|
860 |
||
1544 | 861 |
spa_config_exit(spa, FTAG); |
789 | 862 |
|
4527 | 863 |
/* |
864 |
* Make 1/4 of the devices be log devices. |
|
865 |
*/ |
|
866 |
nvroot = make_vdev_root(zopt_vdev_size, |
|
867 |
ztest_random(4) == 0, zopt_raidz, zopt_mirrors, 1); |
|
868 |
||
789 | 869 |
error = spa_vdev_add(spa, nvroot); |
870 |
nvlist_free(nvroot); |
|
871 |
||
872 |
(void) mutex_unlock(&ztest_shared->zs_vdev_lock); |
|
873 |
||
874 |
if (error == ENOSPC) |
|
875 |
ztest_record_enospc("spa_vdev_add"); |
|
876 |
else if (error != 0) |
|
877 |
fatal(0, "spa_vdev_add() = %d", error); |
|
878 |
||
879 |
if (zopt_verbose >= 6) |
|
880 |
(void) printf("spa_vdev_add = %d, as expected\n", error); |
|
881 |
} |
|
882 |
||
1544 | 883 |
static vdev_t * |
884 |
vdev_lookup_by_path(vdev_t *vd, const char *path) |
|
885 |
{ |
|
886 |
int c; |
|
887 |
vdev_t *mvd; |
|
888 |
||
889 |
if (vd->vdev_path != NULL) { |
|
890 |
if (vd->vdev_wholedisk == 1) { |
|
891 |
/* |
|
892 |
* For whole disks, the internal path has 's0', but the |
|
893 |
* path passed in by the user doesn't. |
|
894 |
*/ |
|
895 |
if (strlen(path) == strlen(vd->vdev_path) - 2 && |
|
896 |
strncmp(path, vd->vdev_path, strlen(path)) == 0) |
|
897 |
return (vd); |
|
898 |
} else if (strcmp(path, vd->vdev_path) == 0) { |
|
899 |
return (vd); |
|
900 |
} |
|
901 |
} |
|
902 |
||
903 |
for (c = 0; c < vd->vdev_children; c++) |
|
904 |
if ((mvd = vdev_lookup_by_path(vd->vdev_child[c], path)) != |
|
905 |
NULL) |
|
906 |
return (mvd); |
|
907 |
||
908 |
return (NULL); |
|
909 |
} |
|
910 |
||
789 | 911 |
/* |
912 |
* Verify that we can attach and detach devices. |
|
913 |
*/ |
|
914 |
void |
|
915 |
ztest_vdev_attach_detach(ztest_args_t *za) |
|
916 |
{ |
|
5530 | 917 |
spa_t *spa = za->za_spa; |
789 | 918 |
vdev_t *rvd = spa->spa_root_vdev; |
1544 | 919 |
vdev_t *oldvd, *newvd, *pvd; |
789 | 920 |
nvlist_t *root, *file; |
921 |
uint64_t leaves = MAX(zopt_mirrors, 1) * zopt_raidz; |
|
922 |
uint64_t leaf, top; |
|
1732 | 923 |
uint64_t ashift = ztest_get_ashift(); |
1544 | 924 |
size_t oldsize, newsize; |
925 |
char oldpath[MAXPATHLEN], newpath[MAXPATHLEN]; |
|
789 | 926 |
int replacing; |
927 |
int error, expected_error; |
|
928 |
int fd; |
|
929 |
||
930 |
(void) mutex_lock(&ztest_shared->zs_vdev_lock); |
|
931 |
||
1544 | 932 |
spa_config_enter(spa, RW_READER, FTAG); |
789 | 933 |
|
934 |
/* |
|
935 |
* Decide whether to do an attach or a replace. |
|
936 |
*/ |
|
937 |
replacing = ztest_random(2); |
|
938 |
||
939 |
/* |
|
940 |
* Pick a random top-level vdev. |
|
941 |
*/ |
|
942 |
top = ztest_random(rvd->vdev_children); |
|
943 |
||
944 |
/* |
|
945 |
* Pick a random leaf within it. |
|
946 |
*/ |
|
947 |
leaf = ztest_random(leaves); |
|
948 |
||
949 |
/* |
|
950 |
* Generate the path to this leaf. The filename will end with 'a'. |
|
951 |
* We'll alternate replacements with a filename that ends with 'b'. |
|
952 |
*/ |
|
1544 | 953 |
(void) snprintf(oldpath, sizeof (oldpath), |
789 | 954 |
ztest_dev_template, zopt_dir, zopt_pool, top * leaves + leaf); |
955 |
||
1544 | 956 |
bcopy(oldpath, newpath, MAXPATHLEN); |
789 | 957 |
|
958 |
/* |
|
959 |
* If the 'a' file isn't part of the pool, the 'b' file must be. |
|
960 |
*/ |
|
1544 | 961 |
if (vdev_lookup_by_path(rvd, oldpath) == NULL) |
962 |
oldpath[strlen(oldpath) - 1] = 'b'; |
|
789 | 963 |
else |
1544 | 964 |
newpath[strlen(newpath) - 1] = 'b'; |
789 | 965 |
|
966 |
/* |
|
1544 | 967 |
* Now oldpath represents something that's already in the pool, |
968 |
* and newpath is the thing we'll try to attach. |
|
789 | 969 |
*/ |
1544 | 970 |
oldvd = vdev_lookup_by_path(rvd, oldpath); |
971 |
newvd = vdev_lookup_by_path(rvd, newpath); |
|
972 |
ASSERT(oldvd != NULL); |
|
973 |
pvd = oldvd->vdev_parent; |
|
789 | 974 |
|
975 |
/* |
|
1544 | 976 |
* Make newsize a little bigger or smaller than oldsize. |
789 | 977 |
* If it's smaller, the attach should fail. |
978 |
* If it's larger, and we're doing a replace, |
|
979 |
* we should get dynamic LUN growth when we're done. |
|
980 |
*/ |
|
1544 | 981 |
oldsize = vdev_get_rsize(oldvd); |
982 |
newsize = 10 * oldsize / (9 + ztest_random(3)); |
|
789 | 983 |
|
984 |
/* |
|
985 |
* If pvd is not a mirror or root, the attach should fail with ENOTSUP, |
|
986 |
* unless it's a replace; in that case any non-replacing parent is OK. |
|
987 |
* |
|
1544 | 988 |
* If newvd is already part of the pool, it should fail with EBUSY. |
789 | 989 |
* |
1544 | 990 |
* If newvd is too small, it should fail with EOVERFLOW. |
789 | 991 |
*/ |
2174
73de7a781492
6433717 offline devices should not be marked persistently unavailble
eschrock
parents:
2113
diff
changeset
|
992 |
if (newvd != NULL) |
73de7a781492
6433717 offline devices should not be marked persistently unavailble
eschrock
parents:
2113
diff
changeset
|
993 |
expected_error = EBUSY; |
73de7a781492
6433717 offline devices should not be marked persistently unavailble
eschrock
parents:
2113
diff
changeset
|
994 |
else if (pvd->vdev_ops != &vdev_mirror_ops && |
789 | 995 |
pvd->vdev_ops != &vdev_root_ops && |
996 |
(!replacing || pvd->vdev_ops == &vdev_replacing_ops)) |
|
997 |
expected_error = ENOTSUP; |
|
1544 | 998 |
else if (newsize < oldsize) |
789 | 999 |
expected_error = EOVERFLOW; |
1732 | 1000 |
else if (ashift > oldvd->vdev_top->vdev_ashift) |
1001 |
expected_error = EDOM; |
|
789 | 1002 |
else |
1003 |
expected_error = 0; |
|
1004 |
||
1005 |
/* |
|
1544 | 1006 |
* If newvd isn't already part of the pool, create it. |
789 | 1007 |
*/ |
1544 | 1008 |
if (newvd == NULL) { |
1009 |
fd = open(newpath, O_RDWR | O_CREAT | O_TRUNC, 0666); |
|
789 | 1010 |
if (fd == -1) |
1544 | 1011 |
fatal(1, "can't open %s", newpath); |
1012 |
if (ftruncate(fd, newsize) != 0) |
|
1013 |
fatal(1, "can't ftruncate %s", newpath); |
|
789 | 1014 |
(void) close(fd); |
1015 |
} |
|
1016 |
||
1544 | 1017 |
spa_config_exit(spa, FTAG); |
789 | 1018 |
|
1019 |
/* |
|
1544 | 1020 |
* Build the nvlist describing newpath. |
789 | 1021 |
*/ |
1022 |
VERIFY(nvlist_alloc(&file, NV_UNIQUE_NAME, 0) == 0); |
|
1023 |
VERIFY(nvlist_add_string(file, ZPOOL_CONFIG_TYPE, VDEV_TYPE_FILE) == 0); |
|
1544 | 1024 |
VERIFY(nvlist_add_string(file, ZPOOL_CONFIG_PATH, newpath) == 0); |
1732 | 1025 |
VERIFY(nvlist_add_uint64(file, ZPOOL_CONFIG_ASHIFT, ashift) == 0); |
789 | 1026 |
|
1027 |
VERIFY(nvlist_alloc(&root, NV_UNIQUE_NAME, 0) == 0); |
|
1028 |
VERIFY(nvlist_add_string(root, ZPOOL_CONFIG_TYPE, VDEV_TYPE_ROOT) == 0); |
|
1029 |
VERIFY(nvlist_add_nvlist_array(root, ZPOOL_CONFIG_CHILDREN, |
|
1030 |
&file, 1) == 0); |
|
1031 |
||
1544 | 1032 |
error = spa_vdev_attach(spa, oldvd->vdev_guid, root, replacing); |
789 | 1033 |
|
1034 |
nvlist_free(file); |
|
1035 |
nvlist_free(root); |
|
1036 |
||
1037 |
/* |
|
1038 |
* If our parent was the replacing vdev, but the replace completed, |
|
1039 |
* then instead of failing with ENOTSUP we may either succeed, |
|
1040 |
* fail with ENODEV, or fail with EOVERFLOW. |
|
1041 |
*/ |
|
1042 |
if (expected_error == ENOTSUP && |
|
1043 |
(error == 0 || error == ENODEV || error == EOVERFLOW)) |
|
1044 |
expected_error = error; |
|
1045 |
||
797
af56ba8b7e41
6344108 snapshot create/delete interlock with scrub/resilver must sync txg
bonwick
parents:
789
diff
changeset
|
1046 |
/* |
af56ba8b7e41
6344108 snapshot create/delete interlock with scrub/resilver must sync txg
bonwick
parents:
789
diff
changeset
|
1047 |
* If someone grew the LUN, the replacement may be too small. |
af56ba8b7e41
6344108 snapshot create/delete interlock with scrub/resilver must sync txg
bonwick
parents:
789
diff
changeset
|
1048 |
*/ |
af56ba8b7e41
6344108 snapshot create/delete interlock with scrub/resilver must sync txg
bonwick
parents:
789
diff
changeset
|
1049 |
if (error == EOVERFLOW) |
af56ba8b7e41
6344108 snapshot create/delete interlock with scrub/resilver must sync txg
bonwick
parents:
789
diff
changeset
|
1050 |
expected_error = error; |
af56ba8b7e41
6344108 snapshot create/delete interlock with scrub/resilver must sync txg
bonwick
parents:
789
diff
changeset
|
1051 |
|
789 | 1052 |
if (error != expected_error) { |
1053 |
fatal(0, "attach (%s, %s, %d) returned %d, expected %d", |
|
1544 | 1054 |
oldpath, newpath, replacing, error, expected_error); |
789 | 1055 |
} |
1056 |
||
1057 |
(void) mutex_unlock(&ztest_shared->zs_vdev_lock); |
|
1058 |
} |
|
1059 |
||
1060 |
/* |
|
1061 |
* Verify that dynamic LUN growth works as expected. |
|
1062 |
*/ |
|
1063 |
/* ARGSUSED */ |
|
1064 |
void |
|
1065 |
ztest_vdev_LUN_growth(ztest_args_t *za) |
|
1066 |
{ |
|
5530 | 1067 |
spa_t *spa = za->za_spa; |
789 | 1068 |
char dev_name[MAXPATHLEN]; |
1069 |
uint64_t leaves = MAX(zopt_mirrors, 1) * zopt_raidz; |
|
1070 |
uint64_t vdev; |
|
1071 |
size_t fsize; |
|
1072 |
int fd; |
|
1073 |
||
1074 |
(void) mutex_lock(&ztest_shared->zs_vdev_lock); |
|
1075 |
||
1076 |
/* |
|
1077 |
* Pick a random leaf vdev. |
|
1078 |
*/ |
|
1544 | 1079 |
spa_config_enter(spa, RW_READER, FTAG); |
789 | 1080 |
vdev = ztest_random(spa->spa_root_vdev->vdev_children * leaves); |
1544 | 1081 |
spa_config_exit(spa, FTAG); |
789 | 1082 |
|
1083 |
(void) sprintf(dev_name, ztest_dev_template, zopt_dir, zopt_pool, vdev); |
|
1084 |
||
1085 |
if ((fd = open(dev_name, O_RDWR)) != -1) { |
|
1086 |
/* |
|
1087 |
* Determine the size. |
|
1088 |
*/ |
|
1089 |
fsize = lseek(fd, 0, SEEK_END); |
|
1090 |
||
1091 |
/* |
|
1092 |
* If it's less than 2x the original size, grow by around 3%. |
|
1093 |
*/ |
|
1094 |
if (fsize < 2 * zopt_vdev_size) { |
|
1095 |
size_t newsize = fsize + ztest_random(fsize / 32); |
|
1096 |
(void) ftruncate(fd, newsize); |
|
1097 |
if (zopt_verbose >= 6) { |
|
1098 |
(void) printf("%s grew from %lu to %lu bytes\n", |
|
1099 |
dev_name, (ulong_t)fsize, (ulong_t)newsize); |
|
1100 |
} |
|
1101 |
} |
|
1102 |
(void) close(fd); |
|
1103 |
} |
|
1104 |
||
1105 |
(void) mutex_unlock(&ztest_shared->zs_vdev_lock); |
|
1106 |
} |
|
1107 |
||
1108 |
/* ARGSUSED */ |
|
1109 |
static void |
|
4543 | 1110 |
ztest_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx) |
789 | 1111 |
{ |
1112 |
/* |
|
1113 |
* Create the directory object. |
|
1114 |
*/ |
|
1115 |
VERIFY(dmu_object_claim(os, ZTEST_DIROBJ, |
|
1116 |
DMU_OT_UINT64_OTHER, ZTEST_DIROBJ_BLOCKSIZE, |
|
5530 | 1117 |
DMU_OT_UINT64_OTHER, 5 * sizeof (ztest_block_tag_t), tx) == 0); |
789 | 1118 |
|
1119 |
VERIFY(zap_create_claim(os, ZTEST_MICROZAP_OBJ, |
|
1120 |
DMU_OT_ZAP_OTHER, DMU_OT_NONE, 0, tx) == 0); |
|
1121 |
||
1122 |
VERIFY(zap_create_claim(os, ZTEST_FATZAP_OBJ, |
|
1123 |
DMU_OT_ZAP_OTHER, DMU_OT_NONE, 0, tx) == 0); |
|
1124 |
} |
|
1125 |
||
2199 | 1126 |
static int |
789 | 1127 |
ztest_destroy_cb(char *name, void *arg) |
1128 |
{ |
|
5530 | 1129 |
ztest_args_t *za = arg; |
789 | 1130 |
objset_t *os; |
5530 | 1131 |
dmu_object_info_t *doi = &za->za_doi; |
789 | 1132 |
int error; |
1133 |
||
1134 |
/* |
|
1135 |
* Verify that the dataset contains a directory object. |
|
1136 |
*/ |
|
1137 |
error = dmu_objset_open(name, DMU_OST_OTHER, |
|
1138 |
DS_MODE_STANDARD | DS_MODE_READONLY, &os); |
|
1139 |
ASSERT3U(error, ==, 0); |
|
5530 | 1140 |
error = dmu_object_info(os, ZTEST_DIROBJ, doi); |
1731
1efa8b3d1296
6402598 'zfs destroy <fs>' can take a long time, stopping up the txg train
bonwick
parents:
1646
diff
changeset
|
1141 |
if (error != ENOENT) { |
1efa8b3d1296
6402598 'zfs destroy <fs>' can take a long time, stopping up the txg train
bonwick
parents:
1646
diff
changeset
|
1142 |
/* We could have crashed in the middle of destroying it */ |
1efa8b3d1296
6402598 'zfs destroy <fs>' can take a long time, stopping up the txg train
bonwick
parents:
1646
diff
changeset
|
1143 |
ASSERT3U(error, ==, 0); |
5530 | 1144 |
ASSERT3U(doi->doi_type, ==, DMU_OT_UINT64_OTHER); |
1145 |
ASSERT3S(doi->doi_physical_blks, >=, 0); |
|
1731
1efa8b3d1296
6402598 'zfs destroy <fs>' can take a long time, stopping up the txg train
bonwick
parents:
1646
diff
changeset
|
1146 |
} |
789 | 1147 |
dmu_objset_close(os); |
1148 |
||
1149 |
/* |
|
1150 |
* Destroy the dataset. |
|
1151 |
*/ |
|
1152 |
error = dmu_objset_destroy(name); |
|
1153 |
ASSERT3U(error, ==, 0); |
|
2199 | 1154 |
return (0); |
789 | 1155 |
} |
1156 |
||
1157 |
/* |
|
1158 |
* Verify that dmu_objset_{create,destroy,open,close} work as expected. |
|
1159 |
*/ |
|
1160 |
static uint64_t |
|
1161 |
ztest_log_create(zilog_t *zilog, dmu_tx_t *tx, uint64_t object, int mode) |
|
1162 |
{ |
|
1163 |
itx_t *itx; |
|
1164 |
lr_create_t *lr; |
|
1165 |
size_t namesize; |
|
1166 |
char name[24]; |
|
1167 |
||
1168 |
(void) sprintf(name, "ZOBJ_%llu", (u_longlong_t)object); |
|
1169 |
namesize = strlen(name) + 1; |
|
1170 |
||
1171 |
itx = zil_itx_create(TX_CREATE, sizeof (*lr) + namesize + |
|
1172 |
ztest_random(ZIL_MAX_BLKSZ)); |
|
1173 |
lr = (lr_create_t *)&itx->itx_lr; |
|
1174 |
bzero(lr + 1, lr->lr_common.lrc_reclen - sizeof (*lr)); |
|
1175 |
lr->lr_doid = object; |
|
1176 |
lr->lr_foid = 0; |
|
1177 |
lr->lr_mode = mode; |
|
1178 |
lr->lr_uid = 0; |
|
1179 |
lr->lr_gid = 0; |
|
1180 |
lr->lr_gen = dmu_tx_get_txg(tx); |
|
1181 |
lr->lr_crtime[0] = time(NULL); |
|
1182 |
lr->lr_crtime[1] = 0; |
|
1183 |
lr->lr_rdev = 0; |
|
1184 |
bcopy(name, (char *)(lr + 1), namesize); |
|
1185 |
||
1186 |
return (zil_itx_assign(zilog, itx, tx)); |
|
1187 |
} |
|
1188 |
||
1189 |
void |
|
1190 |
ztest_dmu_objset_create_destroy(ztest_args_t *za) |
|
1191 |
{ |
|
1192 |
int error; |
|
1193 |
objset_t *os; |
|
1194 |
char name[100]; |
|
1195 |
int mode, basemode, expected_error; |
|
1196 |
zilog_t *zilog; |
|
1197 |
uint64_t seq; |
|
1198 |
uint64_t objects; |
|
1199 |
ztest_replay_t zr; |
|
1200 |
||
1201 |
(void) rw_rdlock(&ztest_shared->zs_name_lock); |
|
1202 |
(void) snprintf(name, 100, "%s/%s_temp_%llu", za->za_pool, za->za_pool, |
|
1203 |
(u_longlong_t)za->za_instance); |
|
1204 |
||
1205 |
basemode = DS_MODE_LEVEL(za->za_instance); |
|
1206 |
if (basemode == DS_MODE_NONE) |
|
1207 |
basemode++; |
|
1208 |
||
1209 |
/* |
|
1210 |
* If this dataset exists from a previous run, process its replay log |
|
1211 |
* half of the time. If we don't replay it, then dmu_objset_destroy() |
|
1212 |
* (invoked from ztest_destroy_cb() below) should just throw it away. |
|
1213 |
*/ |
|
1214 |
if (ztest_random(2) == 0 && |
|
1215 |
dmu_objset_open(name, DMU_OST_OTHER, DS_MODE_PRIMARY, &os) == 0) { |
|
1216 |
zr.zr_os = os; |
|
3461 | 1217 |
zil_replay(os, &zr, &zr.zr_assign, ztest_replay_vector); |
789 | 1218 |
dmu_objset_close(os); |
1219 |
} |
|
1220 |
||
1221 |
/* |
|
1222 |
* There may be an old instance of the dataset we're about to |
|
1223 |
* create lying around from a previous run. If so, destroy it |
|
1224 |
* and all of its snapshots. |
|
1225 |
*/ |
|
5530 | 1226 |
(void) dmu_objset_find(name, ztest_destroy_cb, za, |
2417 | 1227 |
DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS); |
789 | 1228 |
|
1229 |
/* |
|
1230 |
* Verify that the destroyed dataset is no longer in the namespace. |
|
1231 |
*/ |
|
1232 |
error = dmu_objset_open(name, DMU_OST_OTHER, basemode, &os); |
|
1233 |
if (error != ENOENT) |
|
1234 |
fatal(1, "dmu_objset_open(%s) found destroyed dataset %p", |
|
1235 |
name, os); |
|
1236 |
||
1237 |
/* |
|
1238 |
* Verify that we can create a new dataset. |
|
1239 |
*/ |
|
6492
903545192033
6654808 FIGNORECASE lookups in a zfs xattr dir don't provide 'realname' data
timh
parents:
5994
diff
changeset
|
1240 |
error = dmu_objset_create(name, DMU_OST_OTHER, NULL, 0, |
903545192033
6654808 FIGNORECASE lookups in a zfs xattr dir don't provide 'realname' data
timh
parents:
5994
diff
changeset
|
1241 |
ztest_create_cb, NULL); |
789 | 1242 |
if (error) { |
1243 |
if (error == ENOSPC) { |
|
1244 |
ztest_record_enospc("dmu_objset_create"); |
|
1245 |
(void) rw_unlock(&ztest_shared->zs_name_lock); |
|
1246 |
return; |
|
1247 |
} |
|
1248 |
fatal(0, "dmu_objset_create(%s) = %d", name, error); |
|
1249 |
} |
|
1250 |
||
1251 |
error = dmu_objset_open(name, DMU_OST_OTHER, basemode, &os); |
|
1252 |
if (error) { |
|
1253 |
fatal(0, "dmu_objset_open(%s) = %d", name, error); |
|
1254 |
} |
|
1255 |
||
1256 |
/* |
|
1257 |
* Open the intent log for it. |
|
1258 |
*/ |
|
1259 |
zilog = zil_open(os, NULL); |
|
1260 |
||
1261 |
/* |
|
1262 |
* Put a random number of objects in there. |
|
1263 |
*/ |
|
1807
35c8b566d7af
6410711 intent log blocks don't get invited to pool parties
bonwick
parents:
1775
diff
changeset
|
1264 |
objects = ztest_random(20); |
789 | 1265 |
seq = 0; |
1266 |
while (objects-- != 0) { |
|
1267 |
uint64_t object; |
|
1268 |
dmu_tx_t *tx = dmu_tx_create(os); |
|
1269 |
dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, sizeof (name)); |
|
1270 |
error = dmu_tx_assign(tx, TXG_WAIT); |
|
1271 |
if (error) { |
|
1272 |
dmu_tx_abort(tx); |
|
1273 |
} else { |
|
1274 |
object = dmu_object_alloc(os, DMU_OT_UINT64_OTHER, 0, |
|
1275 |
DMU_OT_NONE, 0, tx); |
|
1276 |
ztest_set_random_blocksize(os, object, tx); |
|
1277 |
seq = ztest_log_create(zilog, tx, object, |
|
1278 |
DMU_OT_UINT64_OTHER); |
|
1279 |
dmu_write(os, object, 0, sizeof (name), name, tx); |
|
1280 |
dmu_tx_commit(tx); |
|
1281 |
} |
|
1282 |
if (ztest_random(5) == 0) { |
|
2638
4f583dfeae92
6413510 zfs: writing to ZFS filesystem slows down fsync() on other files in the same FS
perrin
parents:
2417
diff
changeset
|
1283 |
zil_commit(zilog, seq, object); |
789 | 1284 |
} |
1807
35c8b566d7af
6410711 intent log blocks don't get invited to pool parties
bonwick
parents:
1775
diff
changeset
|
1285 |
if (ztest_random(100) == 0) { |
789 | 1286 |
error = zil_suspend(zilog); |
1287 |
if (error == 0) { |
|
1288 |
zil_resume(zilog); |
|
1289 |
} |
|
1290 |
} |
|
1291 |
} |
|
1292 |
||
1293 |
/* |
|
1294 |
* Verify that we cannot create an existing dataset. |
|
1295 |
*/ |
|
6492
903545192033
6654808 FIGNORECASE lookups in a zfs xattr dir don't provide 'realname' data
timh
parents:
5994
diff
changeset
|
1296 |
error = dmu_objset_create(name, DMU_OST_OTHER, NULL, 0, NULL, NULL); |
789 | 1297 |
if (error != EEXIST) |
1298 |
fatal(0, "created existing dataset, error = %d", error); |
|
1299 |
||
1300 |
/* |
|
1301 |
* Verify that multiple dataset opens are allowed, but only when |
|
1302 |
* the new access mode is compatible with the base mode. |
|
1303 |
* We use a mixture of typed and typeless opens, and when the |
|
1304 |
* open succeeds, verify that the discovered type is correct. |
|
1305 |
*/ |
|
1306 |
for (mode = DS_MODE_STANDARD; mode < DS_MODE_LEVELS; mode++) { |
|
1307 |
objset_t *os2; |
|
1308 |
error = dmu_objset_open(name, DMU_OST_OTHER, mode, &os2); |
|
1309 |
expected_error = (basemode + mode < DS_MODE_LEVELS) ? 0 : EBUSY; |
|
1310 |
if (error != expected_error) |
|
1311 |
fatal(0, "dmu_objset_open('%s') = %d, expected %d", |
|
1312 |
name, error, expected_error); |
|
1313 |
if (error == 0) |
|
1314 |
dmu_objset_close(os2); |
|
1315 |
} |
|
1316 |
||
1317 |
zil_close(zilog); |
|
1318 |
dmu_objset_close(os); |
|
1319 |
||
1320 |
error = dmu_objset_destroy(name); |
|
1321 |
if (error) |
|
1322 |
fatal(0, "dmu_objset_destroy(%s) = %d", name, error); |
|
1323 |
||
1324 |
(void) rw_unlock(&ztest_shared->zs_name_lock); |
|
1325 |
} |
|
1326 |
||
1327 |
/* |
|
1328 |
* Verify that dmu_snapshot_{create,destroy,open,close} work as expected. |
|
1329 |
*/ |
|
1330 |
void |
|
1331 |
ztest_dmu_snapshot_create_destroy(ztest_args_t *za) |
|
1332 |
{ |
|
1333 |
int error; |
|
1334 |
objset_t *os = za->za_os; |
|
1335 |
char snapname[100]; |
|
1336 |
char osname[MAXNAMELEN]; |
|
1337 |
||
1338 |
(void) rw_rdlock(&ztest_shared->zs_name_lock); |
|
1339 |
dmu_objset_name(os, osname); |
|
1340 |
(void) snprintf(snapname, 100, "%s@%llu", osname, |
|
1341 |
(u_longlong_t)za->za_instance); |
|
1342 |
||
1343 |
error = dmu_objset_destroy(snapname); |
|
1344 |
if (error != 0 && error != ENOENT) |
|
1345 |
fatal(0, "dmu_objset_destroy() = %d", error); |
|
2199 | 1346 |
error = dmu_objset_snapshot(osname, strchr(snapname, '@')+1, FALSE); |
789 | 1347 |
if (error == ENOSPC) |
1348 |
ztest_record_enospc("dmu_take_snapshot"); |
|
1349 |
else if (error != 0 && error != EEXIST) |
|
1350 |
fatal(0, "dmu_take_snapshot() = %d", error); |
|
1351 |
(void) rw_unlock(&ztest_shared->zs_name_lock); |
|
1352 |
} |
|
1353 |
||
1354 |
#define ZTEST_TRAVERSE_BLOCKS 1000 |
|
1355 |
||
1356 |
static int |
|
1357 |
ztest_blk_cb(traverse_blk_cache_t *bc, spa_t *spa, void *arg) |
|
1358 |
{ |
|
1359 |
ztest_args_t *za = arg; |
|
1360 |
zbookmark_t *zb = &bc->bc_bookmark; |
|
1361 |
blkptr_t *bp = &bc->bc_blkptr; |
|
1362 |
dnode_phys_t *dnp = bc->bc_dnode; |
|
1363 |
traverse_handle_t *th = za->za_th; |
|
1364 |
uint64_t size = BP_GET_LSIZE(bp); |
|
1365 |
||
1544 | 1366 |
/* |
1367 |
* Level -1 indicates the objset_phys_t or something in its intent log. |
|
1368 |
*/ |
|
1369 |
if (zb->zb_level == -1) { |
|
1370 |
if (BP_GET_TYPE(bp) == DMU_OT_OBJSET) { |
|
1371 |
ASSERT3U(zb->zb_object, ==, 0); |
|
1372 |
ASSERT3U(zb->zb_blkid, ==, 0); |
|
1373 |
ASSERT3U(size, ==, sizeof (objset_phys_t)); |
|
1374 |
za->za_zil_seq = 0; |
|
1375 |
} else if (BP_GET_TYPE(bp) == DMU_OT_INTENT_LOG) { |
|
1376 |
ASSERT3U(zb->zb_object, ==, 0); |
|
1377 |
ASSERT3U(zb->zb_blkid, >, za->za_zil_seq); |
|
1378 |
za->za_zil_seq = zb->zb_blkid; |
|
1379 |
} else { |
|
1380 |
ASSERT3U(zb->zb_object, !=, 0); /* lr_write_t */ |
|
1381 |
} |
|
1382 |
||
1383 |
return (0); |
|
1384 |
} |
|
1385 |
||
789 | 1386 |
ASSERT(dnp != NULL); |
1387 |
||
1388 |
if (bc->bc_errno) |
|
1389 |
return (ERESTART); |
|
1390 |
||
1391 |
/* |
|
1392 |
* Once in a while, abort the traverse. We only do this to odd |
|
1393 |
* instance numbers to ensure that even ones can run to completion. |
|
1394 |
*/ |
|
1395 |
if ((za->za_instance & 1) && ztest_random(10000) == 0) |
|
1396 |
return (EINTR); |
|
1397 |
||
1398 |
if (bp->blk_birth == 0) { |
|
1399 |
ASSERT(th->th_advance & ADVANCE_HOLES); |
|
1400 |
return (0); |
|
1401 |
} |
|
1402 |
||
1403 |
if (zb->zb_level == 0 && !(th->th_advance & ADVANCE_DATA) && |
|
1404 |
bc == &th->th_cache[ZB_DN_CACHE][0]) { |
|
1405 |
ASSERT(bc->bc_data == NULL); |
|
1406 |
return (0); |
|
1407 |
} |
|
1408 |
||
1409 |
ASSERT(bc->bc_data != NULL); |
|
1410 |
||
1411 |
/* |
|
1412 |
* This is an expensive question, so don't ask it too often. |
|
1413 |
*/ |
|
1414 |
if (((za->za_random ^ th->th_callbacks) & 0xff) == 0) { |
|
1415 |
void *xbuf = umem_alloc(size, UMEM_NOFAIL); |
|
1416 |
if (arc_tryread(spa, bp, xbuf) == 0) { |
|
1417 |
ASSERT(bcmp(bc->bc_data, xbuf, size) == 0); |
|
1418 |
} |
|
1419 |
umem_free(xbuf, size); |
|
1420 |
} |
|
1421 |
||
1422 |
if (zb->zb_level > 0) { |
|
1423 |
ASSERT3U(size, ==, 1ULL << dnp->dn_indblkshift); |
|
1424 |
return (0); |
|
1425 |
} |
|
1426 |
||
1427 |
ASSERT(zb->zb_level == 0); |
|
1428 |
ASSERT3U(size, ==, dnp->dn_datablkszsec << DEV_BSHIFT); |
|
1429 |
||
1430 |
return (0); |
|
1431 |
} |
|
1432 |
||
1433 |
/* |
|
1434 |
* Verify that live pool traversal works. |
|
1435 |
*/ |
|
1436 |
void |
|
1437 |
ztest_traverse(ztest_args_t *za) |
|
1438 |
{ |
|
5530 | 1439 |
spa_t *spa = za->za_spa; |
789 | 1440 |
traverse_handle_t *th = za->za_th; |
1441 |
int rc, advance; |
|
1442 |
uint64_t cbstart, cblimit; |
|
1443 |
||
1444 |
if (th == NULL) { |
|
1445 |
advance = 0; |
|
1446 |
||
1447 |
if (ztest_random(2) == 0) |
|
1448 |
advance |= ADVANCE_PRE; |
|
1449 |
||
1450 |
if (ztest_random(2) == 0) |
|
1451 |
advance |= ADVANCE_PRUNE; |
|
1452 |
||
1453 |
if (ztest_random(2) == 0) |
|
1454 |
advance |= ADVANCE_DATA; |
|
1455 |
||
1456 |
if (ztest_random(2) == 0) |
|
1457 |
advance |= ADVANCE_HOLES; |
|
1458 |
||
1544 | 1459 |
if (ztest_random(2) == 0) |
1460 |
advance |= ADVANCE_ZIL; |
|
1461 |
||
789 | 1462 |
th = za->za_th = traverse_init(spa, ztest_blk_cb, za, advance, |
1463 |
ZIO_FLAG_CANFAIL); |
|
1464 |
||
1465 |
traverse_add_pool(th, 0, -1ULL); |
|
1466 |
} |
|
1467 |
||
1468 |
advance = th->th_advance; |
|
1469 |
cbstart = th->th_callbacks; |
|
1470 |
cblimit = cbstart + ((advance & ADVANCE_DATA) ? 100 : 1000); |
|
1471 |
||
1472 |
while ((rc = traverse_more(th)) == EAGAIN && th->th_callbacks < cblimit) |
|
1473 |
continue; |
|
1474 |
||
1475 |
if (zopt_verbose >= 5) |
|
1476 |
(void) printf("traverse %s%s%s%s %llu blocks to " |
|
1544 | 1477 |
"<%llu, %llu, %lld, %llx>%s\n", |
789 | 1478 |
(advance & ADVANCE_PRE) ? "pre" : "post", |
1479 |
(advance & ADVANCE_PRUNE) ? "|prune" : "", |
|
1480 |
(advance & ADVANCE_DATA) ? "|data" : "", |
|
1481 |
(advance & ADVANCE_HOLES) ? "|holes" : "", |
|
1482 |
(u_longlong_t)(th->th_callbacks - cbstart), |
|
1483 |
(u_longlong_t)th->th_lastcb.zb_objset, |
|
1484 |
(u_longlong_t)th->th_lastcb.zb_object, |
|
1544 | 1485 |
(u_longlong_t)th->th_lastcb.zb_level, |
789 | 1486 |
(u_longlong_t)th->th_lastcb.zb_blkid, |
1487 |
rc == 0 ? " [done]" : |
|
1488 |
rc == EINTR ? " [aborted]" : |
|
1489 |
rc == EAGAIN ? "" : |
|
1490 |
strerror(rc)); |
|
1491 |
||
1492 |
if (rc != EAGAIN) { |
|
1493 |
if (rc != 0 && rc != EINTR) |
|
1494 |
fatal(0, "traverse_more(%p) = %d", th, rc); |
|
1495 |
traverse_fini(th); |
|
1496 |
za->za_th = NULL; |
|
1497 |
} |
|
1498 |
} |
|
1499 |
||
1500 |
/* |
|
1501 |
* Verify that dmu_object_{alloc,free} work as expected. |
|
1502 |
*/ |
|
1503 |
void |
|
1504 |
ztest_dmu_object_alloc_free(ztest_args_t *za) |
|
1505 |
{ |
|
1506 |
objset_t *os = za->za_os; |
|
1507 |
dmu_buf_t *db; |
|
1508 |
dmu_tx_t *tx; |
|
1509 |
uint64_t batchobj, object, batchsize, endoff, temp; |
|
1510 |
int b, c, error, bonuslen; |
|
5530 | 1511 |
dmu_object_info_t *doi = &za->za_doi; |
789 | 1512 |
char osname[MAXNAMELEN]; |
1513 |
||
1514 |
dmu_objset_name(os, osname); |
|
1515 |
||
1516 |
endoff = -8ULL; |
|
1517 |
batchsize = 2; |
|
1518 |
||
1519 |
/* |
|
1520 |
* Create a batch object if necessary, and record it in the directory. |
|
1521 |
*/ |
|
1544 | 1522 |
VERIFY(0 == dmu_read(os, ZTEST_DIROBJ, za->za_diroff, |
1523 |
sizeof (uint64_t), &batchobj)); |
|
789 | 1524 |
if (batchobj == 0) { |
1525 |
tx = dmu_tx_create(os); |
|
1526 |
dmu_tx_hold_write(tx, ZTEST_DIROBJ, za->za_diroff, |
|
1527 |
sizeof (uint64_t)); |
|
1528 |
dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); |
|
1529 |
error = dmu_tx_assign(tx, TXG_WAIT); |
|
1530 |
if (error) { |
|
1531 |
ztest_record_enospc("create a batch object"); |
|
1532 |
dmu_tx_abort(tx); |
|
1533 |
return; |
|
1534 |
} |
|
1535 |
batchobj = dmu_object_alloc(os, DMU_OT_UINT64_OTHER, 0, |
|
1536 |
DMU_OT_NONE, 0, tx); |
|
1537 |
ztest_set_random_blocksize(os, batchobj, tx); |
|
1538 |
dmu_write(os, ZTEST_DIROBJ, za->za_diroff, |
|
1539 |
sizeof (uint64_t), &batchobj, tx); |
|
1540 |
dmu_tx_commit(tx); |
|
1541 |
} |
|
1542 |
||
1543 |
/* |
|
1544 |
* Destroy the previous batch of objects. |
|
1545 |
*/ |
|
1546 |
for (b = 0; b < batchsize; b++) { |
|
1544 | 1547 |
VERIFY(0 == dmu_read(os, batchobj, b * sizeof (uint64_t), |
1548 |
sizeof (uint64_t), &object)); |
|
789 | 1549 |
if (object == 0) |
1550 |
continue; |
|
1551 |
/* |
|
1552 |
* Read and validate contents. |
|
1553 |
* We expect the nth byte of the bonus buffer to be n. |
|
1554 |
*/ |
|
1544 | 1555 |
VERIFY(0 == dmu_bonus_hold(os, object, FTAG, &db)); |
5530 | 1556 |
za->za_dbuf = db; |
1557 |
||
1558 |
dmu_object_info_from_db(db, doi); |
|
1559 |
ASSERT(doi->doi_type == DMU_OT_UINT64_OTHER); |
|
1560 |
ASSERT(doi->doi_bonus_type == DMU_OT_PLAIN_OTHER); |
|
1561 |
ASSERT3S(doi->doi_physical_blks, >=, 0); |
|
1562 |
||
1563 |
bonuslen = doi->doi_bonus_size; |
|
789 | 1564 |
|
1565 |
for (c = 0; c < bonuslen; c++) { |
|
1566 |
if (((uint8_t *)db->db_data)[c] != |
|
1567 |
(uint8_t)(c + bonuslen)) { |
|
1568 |
fatal(0, |
|
1569 |
"bad bonus: %s, obj %llu, off %d: %u != %u", |
|
1570 |
osname, object, c, |
|
1571 |
((uint8_t *)db->db_data)[c], |
|
1572 |
(uint8_t)(c + bonuslen)); |
|
1573 |
} |
|
1574 |
} |
|
1575 |
||
1544 | 1576 |
dmu_buf_rele(db, FTAG); |
5530 | 1577 |
za->za_dbuf = NULL; |
789 | 1578 |
|
1579 |
/* |
|
1580 |
* We expect the word at endoff to be our object number. |
|
1581 |
*/ |
|
1544 | 1582 |
VERIFY(0 == dmu_read(os, object, endoff, |
1583 |
sizeof (uint64_t), &temp)); |
|
789 | 1584 |
|
1585 |
if (temp != object) { |
|
1586 |
fatal(0, "bad data in %s, got %llu, expected %llu", |
|
1587 |
osname, temp, object); |
|
1588 |
} |
|
1589 |
||
1590 |
/* |
|
1591 |
* Destroy old object and clear batch entry. |
|
1592 |
*/ |
|
1593 |
tx = dmu_tx_create(os); |
|
1594 |
dmu_tx_hold_write(tx, batchobj, |
|
1595 |
b * sizeof (uint64_t), sizeof (uint64_t)); |
|
1596 |
dmu_tx_hold_free(tx, object, 0, DMU_OBJECT_END); |
|
1597 |
error = dmu_tx_assign(tx, TXG_WAIT); |
|
1598 |
if (error) { |
|
1599 |
ztest_record_enospc("free object"); |
|
1600 |
dmu_tx_abort(tx); |
|
1601 |
return; |
|
1602 |
} |
|
1603 |
error = dmu_object_free(os, object, tx); |
|
1604 |
if (error) { |
|
1605 |
fatal(0, "dmu_object_free('%s', %llu) = %d", |
|
1606 |
osname, object, error); |
|
1607 |
} |
|
1608 |
object = 0; |
|
1609 |
||
1610 |
dmu_object_set_checksum(os, batchobj, |
|
1611 |
ztest_random_checksum(), tx); |
|
1612 |
dmu_object_set_compress(os, batchobj, |
|
1613 |
ztest_random_compress(), tx); |
|
1614 |
||
1615 |
dmu_write(os, batchobj, b * sizeof (uint64_t), |
|
1616 |
sizeof (uint64_t), &object, tx); |
|
1617 |
||
1618 |
dmu_tx_commit(tx); |
|
1619 |
} |
|
1620 |
||
1621 |
/* |
|
1622 |
* Before creating the new batch of objects, generate a bunch of churn. |
|
1623 |
*/ |
|
1624 |
for (b = ztest_random(100); b > 0; b--) { |
|
1625 |
tx = dmu_tx_create(os); |
|
1626 |
dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); |
|
1627 |
error = dmu_tx_assign(tx, TXG_WAIT); |
|
1628 |
if (error) { |
|
1629 |
ztest_record_enospc("churn objects"); |
|
1630 |
dmu_tx_abort(tx); |
|
1631 |
return; |
|
1632 |
} |
|
1633 |
object = dmu_object_alloc(os, DMU_OT_UINT64_OTHER, 0, |
|
1634 |
DMU_OT_NONE, 0, tx); |
|
1635 |
ztest_set_random_blocksize(os, object, tx); |
|
1636 |
error = dmu_object_free(os, object, tx); |
|
1637 |
if (error) { |
|
1638 |
fatal(0, "dmu_object_free('%s', %llu) = %d", |
|
1639 |
osname, object, error); |
|
1640 |
} |
|
1641 |
dmu_tx_commit(tx); |
|
1642 |
} |
|
1643 |
||
1644 |
/* |
|
1645 |
* Create a new batch of objects with randomly chosen |
|
1646 |
* blocksizes and record them in the batch directory. |
|
1647 |
*/ |
|
1648 |
for (b = 0; b < batchsize; b++) { |
|
1649 |
uint32_t va_blksize; |
|
1650 |
u_longlong_t va_nblocks; |
|
1651 |
||
1652 |
tx = dmu_tx_create(os); |
|
1653 |
dmu_tx_hold_write(tx, batchobj, b * sizeof (uint64_t), |
|
1654 |
sizeof (uint64_t)); |
|
1655 |
dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); |
|
1656 |
dmu_tx_hold_write(tx, DMU_NEW_OBJECT, endoff, |
|
1657 |
sizeof (uint64_t)); |
|
1658 |
error = dmu_tx_assign(tx, TXG_WAIT); |
|
1659 |
if (error) { |
|
1660 |
ztest_record_enospc("create batchobj"); |
|
1661 |
dmu_tx_abort(tx); |
|
1662 |
return; |
|
1663 |
} |
|
1664 |
bonuslen = (int)ztest_random(dmu_bonus_max()) + 1; |
|
1665 |
||
1666 |
object = dmu_object_alloc(os, DMU_OT_UINT64_OTHER, 0, |
|
1667 |
DMU_OT_PLAIN_OTHER, bonuslen, tx); |
|
1668 |
||
1669 |
ztest_set_random_blocksize(os, object, tx); |
|
1670 |
||
1671 |
dmu_object_set_checksum(os, object, |
|
1672 |
ztest_random_checksum(), tx); |
|
1673 |
dmu_object_set_compress(os, object, |
|
1674 |
ztest_random_compress(), tx); |
|
1675 |
||
1676 |
dmu_write(os, batchobj, b * sizeof (uint64_t), |
|
1677 |
sizeof (uint64_t), &object, tx); |
|
1678 |
||
1679 |
/* |
|
1680 |
* Write to both the bonus buffer and the regular data. |
|
1681 |
*/ |
|
5530 | 1682 |
VERIFY(dmu_bonus_hold(os, object, FTAG, &db) == 0); |
1683 |
za->za_dbuf = db; |
|
4944
96d96f8de974
6569719 panic dangling dbufs (dn=ffffffff28814d30, dbuf=ffffffff20756008)
maybee
parents:
4808
diff
changeset
|
1684 |
ASSERT3U(bonuslen, <=, db->db_size); |
789 | 1685 |
|
1686 |
dmu_object_size_from_db(db, &va_blksize, &va_nblocks); |
|
1687 |
ASSERT3S(va_nblocks, >=, 0); |
|
1688 |
||
1689 |
dmu_buf_will_dirty(db, tx); |
|
1690 |
||
1691 |
/* |
|
1692 |
* See comments above regarding the contents of |
|
1693 |
* the bonus buffer and the word at endoff. |
|
1694 |
*/ |
|
4944
96d96f8de974
6569719 panic dangling dbufs (dn=ffffffff28814d30, dbuf=ffffffff20756008)
maybee
parents:
4808
diff
changeset
|
1695 |
for (c = 0; c < bonuslen; c++) |
789 | 1696 |
((uint8_t *)db->db_data)[c] = (uint8_t)(c + bonuslen); |
1697 |
||
1544 | 1698 |
dmu_buf_rele(db, FTAG); |
5530 | 1699 |
za->za_dbuf = NULL; |
789 | 1700 |
|
1701 |
/* |
|
1702 |
* Write to a large offset to increase indirection. |
|
1703 |
*/ |
|
1704 |
dmu_write(os, object, endoff, sizeof (uint64_t), &object, tx); |
|
1705 |
||
1706 |
dmu_tx_commit(tx); |
|
1707 |
} |
|
1708 |
} |
|
1709 |
||
1710 |
/* |
|
1711 |
* Verify that dmu_{read,write} work as expected. |
|
1712 |
*/ |
|
1713 |
typedef struct bufwad { |
|
1714 |
uint64_t bw_index; |
|
1715 |
uint64_t bw_txg; |
|
1716 |
uint64_t bw_data; |
|
1717 |
} bufwad_t; |
|
1718 |
||
1719 |
typedef struct dmu_read_write_dir { |
|
1720 |
uint64_t dd_packobj; |
|
1721 |
uint64_t dd_bigobj; |
|
1722 |
uint64_t dd_chunk; |
|
1723 |
} dmu_read_write_dir_t; |
|
1724 |
||
1725 |
void |
|
1726 |
ztest_dmu_read_write(ztest_args_t *za) |
|
1727 |
{ |
|
1728 |
objset_t *os = za->za_os; |
|
1729 |
dmu_read_write_dir_t dd; |
|
1730 |
dmu_tx_t *tx; |
|
1731 |
int i, freeit, error; |
|
1732 |
uint64_t n, s, txg; |
|
1733 |
bufwad_t *packbuf, *bigbuf, *pack, *bigH, *bigT; |
|
1734 |
uint64_t packoff, packsize, bigoff, bigsize; |
|
1735 |
uint64_t regions = 997; |
|
1736 |
uint64_t stride = 123456789ULL; |
|
1737 |
uint64_t width = 40; |
|
1738 |
int free_percent = 5; |
|
1739 |
||
1740 |
/* |
|
1741 |
* This test uses two objects, packobj and bigobj, that are always |
|
1742 |
* updated together (i.e. in the same tx) so that their contents are |
|
1743 |
* in sync and can be compared. Their contents relate to each other |
|
1744 |
* in a simple way: packobj is a dense array of 'bufwad' structures, |
|
1745 |
* while bigobj is a sparse array of the same bufwads. Specifically, |
|
1746 |
* for any index n, there are three bufwads that should be identical: |
|
1747 |
* |
|
1748 |
* packobj, at offset n * sizeof (bufwad_t) |
|
1749 |
* bigobj, at the head of the nth chunk |
|
1750 |
* bigobj, at the tail of the nth chunk |
|
1751 |
* |
|
1752 |
* The chunk size is arbitrary. It doesn't have to be a power of two, |
|
1753 |
* and it doesn't have any relation to the object blocksize. |
|
1754 |
* The only requirement is that it can hold at least two bufwads. |
|
1755 |
* |
|
1756 |
* Normally, we write the bufwad to each of these locations. |
|
1757 |
* However, free_percent of the time we instead write zeroes to |
|
1758 |
* packobj and perform a dmu_free_range() on bigobj. By comparing |
|
1759 |
* bigobj to packobj, we can verify that the DMU is correctly |
|
1760 |
* tracking which parts of an object are allocated and free, |
|
1761 |
* and that the contents of the allocated blocks are correct. |
|
1762 |
*/ |
|
1763 |
||
1764 |
/* |
|
1765 |
* Read the directory info. If it's the first time, set things up. |
|
1766 |
*/ |
|
1544 | 1767 |
VERIFY(0 == dmu_read(os, ZTEST_DIROBJ, za->za_diroff, |
1768 |
sizeof (dd), &dd)); |
|
789 | 1769 |
if (dd.dd_chunk == 0) { |
1770 |
ASSERT(dd.dd_packobj == 0); |
|
1771 |
ASSERT(dd.dd_bigobj == 0); |
|
1772 |
tx = dmu_tx_create(os); |
|
1773 |
dmu_tx_hold_write(tx, ZTEST_DIROBJ, za->za_diroff, sizeof (dd)); |
|
1774 |
dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); |
|
1775 |
error = dmu_tx_assign(tx, TXG_WAIT); |
|
1776 |
if (error) { |
|
1777 |
ztest_record_enospc("create r/w directory"); |
|
1778 |
dmu_tx_abort(tx); |
|
1779 |
return; |
|
1780 |
} |
|
1781 |
||
1782 |
dd.dd_packobj = dmu_object_alloc(os, DMU_OT_UINT64_OTHER, 0, |
|
1783 |
DMU_OT_NONE, 0, tx); |
|
1784 |
dd.dd_bigobj = dmu_object_alloc(os, DMU_OT_UINT64_OTHER, 0, |
|
1785 |
DMU_OT_NONE, 0, tx); |
|
1786 |
dd.dd_chunk = (1000 + ztest_random(1000)) * sizeof (uint64_t); |
|
1787 |
||
1788 |
ztest_set_random_blocksize(os, dd.dd_packobj, tx); |
|
1789 |
ztest_set_random_blocksize(os, dd.dd_bigobj, tx); |
|
1790 |
||
1791 |
dmu_write(os, ZTEST_DIROBJ, za->za_diroff, sizeof (dd), &dd, |
|
1792 |
tx); |
|
1793 |
dmu_tx_commit(tx); |
|
1794 |
} |
|
1795 |
||
1796 |
/* |
|
1797 |
* Prefetch a random chunk of the big object. |
|
1798 |
* Our aim here is to get some async reads in flight |
|
1799 |
* for blocks that we may free below; the DMU should |
|
1800 |
* handle this race correctly. |
|
1801 |
*/ |
|
1802 |
n = ztest_random(regions) * stride + ztest_random(width); |
|
1803 |
s = 1 + ztest_random(2 * width - 1); |
|
1804 |
dmu_prefetch(os, dd.dd_bigobj, n * dd.dd_chunk, s * dd.dd_chunk); |
|
1805 |
||
1806 |
/* |
|
1807 |
* Pick a random index and compute the offsets into packobj and bigobj. |
|
1808 |
*/ |
|
1809 |
n = ztest_random(regions) * stride + ztest_random(width); |
|
1810 |
s = 1 + ztest_random(width - 1); |
|
1811 |
||
1812 |
packoff = n * sizeof (bufwad_t); |
|
1813 |
packsize = s * sizeof (bufwad_t); |
|
1814 |
||
1815 |
bigoff = n * dd.dd_chunk; |
|
1816 |
bigsize = s * dd.dd_chunk; |
|
1817 |
||
1818 |
packbuf = umem_alloc(packsize, UMEM_NOFAIL); |
|
1819 |
bigbuf = umem_alloc(bigsize, UMEM_NOFAIL); |
|
1820 |
||
1821 |
/* |
|
1822 |
* free_percent of the time, free a range of bigobj rather than |
|
1823 |
* overwriting it. |
|
1824 |
*/ |
|
1825 |
freeit = (ztest_random(100) < free_percent); |
|
1826 |
||
1827 |
/* |
|
1828 |
* Read the current contents of our objects. |
|
1829 |
*/ |
|
1544 | 1830 |
error = dmu_read(os, dd.dd_packobj, packoff, packsize, packbuf); |
1831 |
ASSERT3U(error, ==, 0); |
|
1832 |
error = dmu_read(os, dd.dd_bigobj, bigoff, bigsize, bigbuf); |
|
1833 |
ASSERT3U(error, ==, 0); |
|
789 | 1834 |
|
1835 |
/* |
|
1836 |
* Get a tx for the mods to both packobj and bigobj. |
|
1837 |
*/ |
|
1838 |
tx = dmu_tx_create(os); |
|
1839 |
||
1840 |
dmu_tx_hold_write(tx, dd.dd_packobj, packoff, packsize); |
|
1841 |
||
1842 |
if (freeit) |
|
1843 |
dmu_tx_hold_free(tx, dd.dd_bigobj, bigoff, bigsize); |
|
1844 |
else |
|
1845 |
dmu_tx_hold_write(tx, dd.dd_bigobj, bigoff, bigsize); |
|
1846 |
||
1847 |
error = dmu_tx_assign(tx, TXG_WAIT); |
|
1848 |
||
1849 |
if (error) { |
|
1850 |
ztest_record_enospc("dmu r/w range"); |
|
1851 |
dmu_tx_abort(tx); |
|
1852 |
umem_free(packbuf, packsize); |
|
1853 |
umem_free(bigbuf, bigsize); |
|
1854 |
return; |
|
1855 |
} |
|
1856 |
||
1857 |
txg = dmu_tx_get_txg(tx); |
|
1858 |
||
1859 |
/* |
|
1860 |
* For each index from n to n + s, verify that the existing bufwad |
|
1861 |
* in packobj matches the bufwads at the head and tail of the |
|
1862 |
* corresponding chunk in bigobj. Then update all three bufwads |
|
1863 |
* with the new values we want to write out. |
|
1864 |
*/ |
|
1865 |
for (i = 0; i < s; i++) { |
|
1866 |
/* LINTED */ |
|
1867 |
pack = (bufwad_t *)((char *)packbuf + i * sizeof (bufwad_t)); |
|
1868 |
/* LINTED */ |
|
1869 |
bigH = (bufwad_t *)((char *)bigbuf + i * dd.dd_chunk); |
|
1870 |
/* LINTED */ |
|
1871 |
bigT = (bufwad_t *)((char *)bigH + dd.dd_chunk) - 1; |
|
1872 |
||
1873 |
ASSERT((uintptr_t)bigH - (uintptr_t)bigbuf < bigsize); |
|
1874 |
ASSERT((uintptr_t)bigT - (uintptr_t)bigbuf < bigsize); |
|
1875 |
||
1876 |
if (pack->bw_txg > txg) |
|
1877 |
fatal(0, "future leak: got %llx, open txg is %llx", |
|
1878 |
pack->bw_txg, txg); |
|
1879 |
||
1880 |
if (pack->bw_data != 0 && pack->bw_index != n + i) |
|
1881 |
fatal(0, "wrong index: got %llx, wanted %llx+%llx", |
|
1882 |
pack->bw_index, n, i); |
|
1883 |
||
1884 |
if (bcmp(pack, bigH, sizeof (bufwad_t)) != 0) |
|
1885 |
fatal(0, "pack/bigH mismatch in %p/%p", pack, bigH); |
|
1886 |
||
1887 |
if (bcmp(pack, bigT, sizeof (bufwad_t)) != 0) |
|
1888 |
fatal(0, "pack/bigT mismatch in %p/%p", pack, bigT); |
|
1889 |
||
1890 |
if (freeit) { |
|
1891 |
bzero(pack, sizeof (bufwad_t)); |
|
1892 |
} else { |
|
1893 |
pack->bw_index = n + i; |
|
1894 |
pack->bw_txg = txg; |
|
1895 |
pack->bw_data = 1 + ztest_random(-2ULL); |
|
1896 |
} |
|
1897 |
*bigH = *pack; |
|
1898 |
*bigT = *pack; |
|
1899 |
} |
|
1900 |
||
1901 |
/* |
|
1902 |
* We've verified all the old bufwads, and made new ones. |
|
1903 |
* Now write them out. |
|
1904 |
*/ |
|
1905 |
dmu_write(os, dd.dd_packobj, packoff, packsize, packbuf, tx); |
|
1906 |
||
1907 |
if (freeit) { |
|
1908 |
if (zopt_verbose >= 6) { |
|
1909 |
(void) printf("freeing offset %llx size %llx" |
|
1910 |
" txg %llx\n", |
|
1911 |
(u_longlong_t)bigoff, |
|
1912 |
(u_longlong_t)bigsize, |
|
1913 |
(u_longlong_t)txg); |
|
1914 |
} |
|
1544 | 1915 |
VERIFY(0 == dmu_free_range(os, dd.dd_bigobj, bigoff, |
1916 |
bigsize, tx)); |
|
789 | 1917 |
} else { |
1918 |
if (zopt_verbose >= 6) { |
|
1919 |
(void) printf("writing offset %llx size %llx" |
|
1920 |
" txg %llx\n", |
|
1921 |
(u_longlong_t)bigoff, |
|
1922 |
(u_longlong_t)bigsize, |
|
1923 |
(u_longlong_t)txg); |
|
1924 |
} |
|
1925 |
dmu_write(os, dd.dd_bigobj, bigoff, bigsize, bigbuf, tx); |
|
1926 |
} |
|
1927 |
||
1928 |
dmu_tx_commit(tx); |
|
1929 |
||
1930 |
/* |
|
1931 |
* Sanity check the stuff we just wrote. |
|
1932 |
*/ |
|
1933 |
{ |
|
1934 |
void *packcheck = umem_alloc(packsize, UMEM_NOFAIL); |
|
1935 |
void *bigcheck = umem_alloc(bigsize, UMEM_NOFAIL); |
|
1936 |
||
1544 | 1937 |
VERIFY(0 == dmu_read(os, dd.dd_packobj, packoff, |
1938 |
packsize, packcheck)); |
|
1939 |
VERIFY(0 == dmu_read(os, dd.dd_bigobj, bigoff, |
|
1940 |
bigsize, bigcheck)); |
|
789 | 1941 |
|
1942 |
ASSERT(bcmp(packbuf, packcheck, packsize) == 0); |
|
1943 |
ASSERT(bcmp(bigbuf, bigcheck, bigsize) == 0); |
|
1944 |
||
1945 |
umem_free(packcheck, packsize); |
|
1946 |
umem_free(bigcheck, bigsize); |
|
1947 |
} |
|
1948 |
||
1949 |
umem_free(packbuf, packsize); |
|
1950 |
umem_free(bigbuf, bigsize); |
|
1951 |
} |
|
1952 |
||
1953 |
void |
|
5530 | 1954 |
ztest_dmu_check_future_leak(ztest_args_t *za) |
3711
2226ffbe7873
6526196 ZFS: assertion failed: zp->z_phys->zp_links > zp_is_dir
maybee
parents:
3668
diff
changeset
|
1955 |
{ |
5530 | 1956 |
objset_t *os = za->za_os; |
3711
2226ffbe7873
6526196 ZFS: assertion failed: zp->z_phys->zp_links > zp_is_dir
maybee
parents:
3668
diff
changeset
|
1957 |
dmu_buf_t *db; |
5530 | 1958 |
ztest_block_tag_t *bt; |
1959 |
dmu_object_info_t *doi = &za->za_doi; |
|
3711
2226ffbe7873
6526196 ZFS: assertion failed: zp->z_phys->zp_links > zp_is_dir
maybee
parents:
3668
diff
changeset
|
1960 |
|
2226ffbe7873
6526196 ZFS: assertion failed: zp->z_phys->zp_links > zp_is_dir
maybee
parents:
3668
diff
changeset
|
1961 |
/* |
2226ffbe7873
6526196 ZFS: assertion failed: zp->z_phys->zp_links > zp_is_dir
maybee
parents:
3668
diff
changeset
|
1962 |
* Make sure that, if there is a write record in the bonus buffer |
2226ffbe7873
6526196 ZFS: assertion failed: zp->z_phys->zp_links > zp_is_dir
maybee
parents:
3668
diff
changeset
|
1963 |
* of the ZTEST_DIROBJ, that the txg for this record is <= the |
2226ffbe7873
6526196 ZFS: assertion failed: zp->z_phys->zp_links > zp_is_dir
maybee
parents:
3668
diff
changeset
|
1964 |
* last synced txg of the pool. |
2226ffbe7873
6526196 ZFS: assertion failed: zp->z_phys->zp_links > zp_is_dir
maybee
parents:
3668
diff
changeset
|
1965 |
*/ |
5530 | 1966 |
VERIFY(dmu_bonus_hold(os, ZTEST_DIROBJ, FTAG, &db) == 0); |
1967 |
za->za_dbuf = db; |
|
1968 |
VERIFY(dmu_object_info(os, ZTEST_DIROBJ, doi) == 0); |
|
1969 |
ASSERT3U(doi->doi_bonus_size, >=, sizeof (*bt)); |
|
1970 |
ASSERT3U(doi->doi_bonus_size, <=, db->db_size); |
|
1971 |
ASSERT3U(doi->doi_bonus_size % sizeof (*bt), ==, 0); |
|
1972 |
bt = (void *)((char *)db->db_data + doi->doi_bonus_size - sizeof (*bt)); |
|
1973 |
if (bt->bt_objset != 0) { |
|
1974 |
ASSERT3U(bt->bt_objset, ==, dmu_objset_id(os)); |
|
1975 |
ASSERT3U(bt->bt_object, ==, ZTEST_DIROBJ); |
|
1976 |
ASSERT3U(bt->bt_offset, ==, -1ULL); |
|
1977 |
ASSERT3U(bt->bt_txg, <, spa_first_txg(za->za_spa)); |
|
3711
2226ffbe7873
6526196 ZFS: assertion failed: zp->z_phys->zp_links > zp_is_dir
maybee
parents:
3668
diff
changeset
|
1978 |
} |
2226ffbe7873
6526196 ZFS: assertion failed: zp->z_phys->zp_links > zp_is_dir
maybee
parents:
3668
diff
changeset
|
1979 |
dmu_buf_rele(db, FTAG); |
5530 | 1980 |
za->za_dbuf = NULL; |
3711
2226ffbe7873
6526196 ZFS: assertion failed: zp->z_phys->zp_links > zp_is_dir
maybee
parents:
3668
diff
changeset
|
1981 |
} |
2226ffbe7873
6526196 ZFS: assertion failed: zp->z_phys->zp_links > zp_is_dir
maybee
parents:
3668
diff
changeset
|
1982 |
|
2226ffbe7873
6526196 ZFS: assertion failed: zp->z_phys->zp_links > zp_is_dir
maybee
parents:
3668
diff
changeset
|
1983 |
void |
789 | 1984 |
ztest_dmu_write_parallel(ztest_args_t *za) |
1985 |
{ |
|
1986 |
objset_t *os = za->za_os; |
|
5530 | 1987 |
ztest_block_tag_t *rbt = &za->za_rbt; |
1988 |
ztest_block_tag_t *wbt = &za->za_wbt; |
|
1989 |
const size_t btsize = sizeof (ztest_block_tag_t); |
|
789 | 1990 |
dmu_buf_t *db; |
5530 | 1991 |
int b, error; |
1992 |
int bs = ZTEST_DIROBJ_BLOCKSIZE; |
|
1993 |
int do_free = 0; |
|
1994 |
uint64_t off, txg_how; |
|
789 | 1995 |
mutex_t *lp; |
1996 |
char osname[MAXNAMELEN]; |
|
1997 |
char iobuf[SPA_MAXBLOCKSIZE]; |
|
5530 | 1998 |
blkptr_t blk = { 0 }; |
1999 |
uint64_t blkoff; |
|
2000 |
zbookmark_t zb; |
|
2001 |
dmu_tx_t *tx = dmu_tx_create(os); |
|
789 | 2002 |
|
2003 |
dmu_objset_name(os, osname); |
|
2004 |
||
2005 |
/* |
|
2006 |
* Have multiple threads write to large offsets in ZTEST_DIROBJ |
|
2007 |
* to verify that having multiple threads writing to the same object |
|
2008 |
* in parallel doesn't cause any trouble. |
|
2009 |
*/ |
|
5530 | 2010 |
if (ztest_random(4) == 0) { |
2011 |
/* |
|
2012 |
* Do the bonus buffer instead of a regular block. |
|
2013 |
* We need a lock to serialize resize vs. others, |
|
2014 |
* so we hash on the objset ID. |
|
2015 |
*/ |
|
2016 |
b = dmu_objset_id(os) % ZTEST_SYNC_LOCKS; |
|
2017 |
off = -1ULL; |
|
2018 |
dmu_tx_hold_bonus(tx, ZTEST_DIROBJ); |
|
2019 |
} else { |
|
789 | 2020 |
b = ztest_random(ZTEST_SYNC_LOCKS); |
5530 | 2021 |
off = za->za_diroff_shared + (b << SPA_MAXBLOCKSHIFT); |
789 | 2022 |
if (ztest_random(4) == 0) { |
5530 | 2023 |
do_free = 1; |
789 | 2024 |
dmu_tx_hold_free(tx, ZTEST_DIROBJ, off, bs); |
5530 | 2025 |
} else { |
789 | 2026 |
dmu_tx_hold_write(tx, ZTEST_DIROBJ, off, bs); |
2027 |
} |
|
2028 |
} |
|
5530 | 2029 |
|
2030 |
txg_how = ztest_random(2) == 0 ? TXG_WAIT : TXG_NOWAIT; |
|
2031 |
error = dmu_tx_assign(tx, txg_how); |
|
2032 |
if (error) { |
|
2033 |
if (error == ERESTART) { |
|
2034 |
ASSERT(txg_how == TXG_NOWAIT); |
|
2035 |
dmu_tx_wait(tx); |
|
2036 |
} else { |
|
2037 |
ztest_record_enospc("dmu write parallel"); |
|
2038 |
} |
|
2039 |
dmu_tx_abort(tx); |
|
2040 |
return; |
|
2041 |
} |
|
2042 |
||
2043 |
lp = &ztest_shared->zs_sync_lock[b]; |
|
2044 |
(void) mutex_lock(lp); |
|
2045 |
||
2046 |
wbt->bt_objset = dmu_objset_id(os); |
|
2047 |
wbt->bt_object = ZTEST_DIROBJ; |
|
2048 |
wbt->bt_offset = off; |
|
2049 |
wbt->bt_txg = dmu_tx_get_txg(tx); |
|
2050 |
wbt->bt_thread = za->za_instance; |
|
2051 |
wbt->bt_seq = ztest_shared->zs_seq[b]++; /* protected by lp */ |
|
2052 |
||
2053 |
if (off == -1ULL) { |
|
2054 |
dmu_object_info_t *doi = &za->za_doi; |
|
2055 |
char *dboff; |
|
2056 |
||
2057 |
VERIFY(dmu_bonus_hold(os, ZTEST_DIROBJ, FTAG, &db) == 0); |
|
2058 |
za->za_dbuf = db; |
|
2059 |
dmu_object_info_from_db(db, doi); |
|
2060 |
ASSERT3U(doi->doi_bonus_size, <=, db->db_size); |
|
2061 |
ASSERT3U(doi->doi_bonus_size, >=, btsize); |
|
2062 |
ASSERT3U(doi->doi_bonus_size % btsize, ==, 0); |
|
2063 |
dboff = (char *)db->db_data + doi->doi_bonus_size - btsize; |
|
2064 |
bcopy(dboff, rbt, btsize); |
|
2065 |
if (rbt->bt_objset != 0) { |
|
2066 |
ASSERT3U(rbt->bt_objset, ==, wbt->bt_objset); |
|
2067 |
ASSERT3U(rbt->bt_object, ==, wbt->bt_object); |
|
2068 |
ASSERT3U(rbt->bt_offset, ==, wbt->bt_offset); |
|
2069 |
ASSERT3U(rbt->bt_txg, <=, wbt->bt_txg); |
|
2070 |
} |
|
2071 |
if (ztest_random(10) == 0) { |
|
2072 |
int newsize = (ztest_random(db->db_size / |
|
2073 |
btsize) + 1) * btsize; |
|
2074 |
||
2075 |
ASSERT3U(newsize, >=, btsize); |
|
2076 |
ASSERT3U(newsize, <=, db->db_size); |
|
2077 |
VERIFY3U(dmu_set_bonus(db, newsize, tx), ==, 0); |
|
2078 |
dboff = (char *)db->db_data + newsize - btsize; |
|
2079 |
} |
|
2080 |
dmu_buf_will_dirty(db, tx); |
|
2081 |
bcopy(wbt, dboff, btsize); |
|
2082 |
dmu_buf_rele(db, FTAG); |
|
2083 |
za->za_dbuf = NULL; |
|
2084 |
} else if (do_free) { |
|
2085 |
VERIFY(dmu_free_range(os, ZTEST_DIROBJ, off, bs, tx) == 0); |
|
2086 |
} else { |
|
2087 |
dmu_write(os, ZTEST_DIROBJ, off, btsize, wbt, tx); |
|
2088 |
} |
|
2089 |
||
2090 |
(void) mutex_unlock(lp); |
|
2091 |
||
2092 |
if (ztest_random(1000) == 0) |
|
2093 |
(void) poll(NULL, 0, 1); /* open dn_notxholds window */ |
|
2094 |
||
2095 |
dmu_tx_commit(tx); |
|
2096 |
||
2097 |
if (ztest_random(10000) == 0) |
|
2098 |
txg_wait_synced(dmu_objset_pool(os), wbt->bt_txg); |
|
2099 |
||
2100 |
if (off == -1 || do_free) |
|
2101 |
return; |
|
2102 |
||
2103 |
if (ztest_random(2) != 0) |
|
2104 |
return; |
|
2105 |
||
2106 |
/* |
|
2107 |
* dmu_sync() the block we just wrote. |
|
2108 |
*/ |
|
2109 |
(void) mutex_lock(lp); |
|
2110 |
||
2111 |
blkoff = P2ALIGN_TYPED(off, bs, uint64_t); |
|
2112 |
error = dmu_buf_hold(os, ZTEST_DIROBJ, blkoff, FTAG, &db); |
|
2113 |
za->za_dbuf = db; |
|
2114 |
if (error) { |
|
2115 |
dprintf("dmu_buf_hold(%s, %d, %llx) = %d\n", |
|
2116 |
osname, ZTEST_DIROBJ, blkoff, error); |
|
2117 |
(void) mutex_unlock(lp); |
|
2118 |
return; |
|
2119 |
} |
|
2120 |
blkoff = off - blkoff; |
|
2121 |
error = dmu_sync(NULL, db, &blk, wbt->bt_txg, NULL, NULL); |
|
2122 |
dmu_buf_rele(db, FTAG); |
|
2123 |
za->za_dbuf = NULL; |
|
2124 |
||
2125 |
(void) mutex_unlock(lp); |
|
2126 |
||
2127 |
if (error) { |
|
2128 |
dprintf("dmu_sync(%s, %d, %llx) = %d\n", |
|
2129 |
osname, ZTEST_DIROBJ, off, error); |
|
2130 |
return; |
|
2131 |
} |
|
2132 |
||
2133 |
if (blk.blk_birth == 0) /* concurrent free */ |
|
2134 |
return; |
|
2135 |
||
2136 |
txg_suspend(dmu_objset_pool(os)); |
|
2137 |
||
2138 |
ASSERT(blk.blk_fill == 1); |
|
2139 |
ASSERT3U(BP_GET_TYPE(&blk), ==, DMU_OT_UINT64_OTHER); |
|
2140 |
ASSERT3U(BP_GET_LEVEL(&blk), ==, 0); |
|
2141 |
ASSERT3U(BP_GET_LSIZE(&blk), ==, bs); |
|
2142 |
||
2143 |
/* |
|
2144 |
* Read the block that dmu_sync() returned to make sure its contents |
|
2145 |
* match what we wrote. We do this while still txg_suspend()ed |
|
2146 |
* to ensure that the block can't be reused before we read it. |
|
2147 |
*/ |
|
2148 |
zb.zb_objset = dmu_objset_id(os); |
|
2149 |
zb.zb_object = ZTEST_DIROBJ; |
|
2150 |
zb.zb_level = 0; |
|
2151 |
zb.zb_blkid = off / bs; |
|
2152 |
error = zio_wait(zio_read(NULL, za->za_spa, &blk, iobuf, bs, |
|
2153 |
NULL, NULL, ZIO_PRIORITY_SYNC_READ, ZIO_FLAG_MUSTSUCCEED, &zb)); |
|
2154 |
ASSERT3U(error, ==, 0); |
|
2155 |
||
2156 |
txg_resume(dmu_objset_pool(os)); |
|
2157 |
||
2158 |
bcopy(&iobuf[blkoff], rbt, btsize); |
|
2159 |
||
2160 |
if (rbt->bt_objset == 0) /* concurrent free */ |
|
2161 |
return; |
|
2162 |
||
2163 |
ASSERT3U(rbt->bt_objset, ==, wbt->bt_objset); |
|
2164 |
ASSERT3U(rbt->bt_object, ==, wbt->bt_object); |
|
2165 |
ASSERT3U(rbt->bt_offset, ==, wbt->bt_offset); |
|
2166 |
||
2167 |
/* |
|
2168 |
* The semantic of dmu_sync() is that we always push the most recent |
|
2169 |
* version of the data, so in the face of concurrent updates we may |
|
2170 |
* see a newer version of the block. That's OK. |
|
2171 |
*/ |
|
2172 |
ASSERT3U(rbt->bt_txg, >=, wbt->bt_txg); |
|
2173 |
if (rbt->bt_thread == wbt->bt_thread) |
|
2174 |
ASSERT3U(rbt->bt_seq, ==, wbt->bt_seq); |
|
2175 |
else |
|
2176 |
ASSERT3U(rbt->bt_seq, >, wbt->bt_seq); |
|
789 | 2177 |
} |
2178 |
||
2179 |
/* |
|
2180 |
* Verify that zap_{create,destroy,add,remove,update} work as expected. |
|
2181 |
*/ |
|
2182 |
#define ZTEST_ZAP_MIN_INTS 1 |
|
2183 |
#define ZTEST_ZAP_MAX_INTS 4 |
|
2184 |
#define ZTEST_ZAP_MAX_PROPS 1000 |
|
2185 |
||
2186 |
void |
|
2187 |
ztest_zap(ztest_args_t *za) |
|
2188 |
{ |
|
2189 |
objset_t *os = za->za_os; |
|
2190 |
uint64_t object; |
|
2191 |
uint64_t txg, last_txg; |
|
2192 |
uint64_t value[ZTEST_ZAP_MAX_INTS]; |
|
2193 |
uint64_t zl_ints, zl_intsize, prop; |
|
2194 |
int i, ints; |
|
2195 |
dmu_tx_t *tx; |
|
2196 |
char propname[100], txgname[100]; |
|
2197 |
int error; |
|
2198 |
char osname[MAXNAMELEN]; |
|
2199 |
char *hc[2] = { "s.acl.h", ".s.open.h.hyLZlg" }; |
|
2200 |
||
2201 |
dmu_objset_name(os, osname); |
|
2202 |
||
2203 |
/* |
|
2204 |
* Create a new object if necessary, and record it in the directory. |
|
2205 |
*/ |
|
1544 | 2206 |
VERIFY(0 == dmu_read(os, ZTEST_DIROBJ, za->za_diroff, |
2207 |
sizeof (uint64_t), &object)); |
|
789 | 2208 |
|
2209 |
if (object == 0) { |
|
2210 |
tx = dmu_tx_create(os); |
|
2211 |
dmu_tx_hold_write(tx, ZTEST_DIROBJ, za->za_diroff, |
|
2212 |
sizeof (uint64_t)); |
|
1544 | 2213 |
dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, TRUE, NULL); |
789 | 2214 |
error = dmu_tx_assign(tx, TXG_WAIT); |
2215 |
if (error) { |
|
2216 |
ztest_record_enospc("create zap test obj"); |
|
2217 |
dmu_tx_abort(tx); |
|
2218 |
return; |
|
2219 |
} |
|
2220 |
object = zap_create(os, DMU_OT_ZAP_OTHER, DMU_OT_NONE, 0, tx); |
|
2221 |
if (error) { |
|
2222 |
fatal(0, "zap_create('%s', %llu) = %d", |
|
2223 |
osname, object, error); |
|
2224 |
} |
|
2225 |
ASSERT(object != 0); |
|
2226 |
dmu_write(os, ZTEST_DIROBJ, za->za_diroff, |
|
2227 |
sizeof (uint64_t), &object, tx); |
|
2228 |
/* |
|
2229 |
* Generate a known hash collision, and verify that |
|
2230 |
* we can lookup and remove both entries. |
|
2231 |
*/ |
|
2232 |
for (i = 0; i < 2; i++) { |
|
2233 |
value[i] = i; |
|
2234 |
error = zap_add(os, object, hc[i], sizeof (uint64_t), |
|
2235 |
1, &value[i], tx); |
|
2236 |
ASSERT3U(error, ==, 0); |
|
2237 |
} |
|
2238 |
for (i = 0; i < 2; i++) { |
|
2239 |
error = zap_add(os, object, hc[i], sizeof (uint64_t), |
|
2240 |
1, &value[i], tx); |
|
2241 |
ASSERT3U(error, ==, EEXIST); |
|
2242 |
error = zap_length(os, object, hc[i], |
|
2243 |
&zl_intsize, &zl_ints); |
|
2244 |
ASSERT3U(error, ==, 0); |
|
2245 |
ASSERT3U(zl_intsize, ==, sizeof (uint64_t)); |
|
2246 |
ASSERT3U(zl_ints, ==, 1); |
|
2247 |
} |
|
2248 |
for (i = 0; i < 2; i++) { |
|
2249 |
error = zap_remove(os, object, hc[i], tx); |
|
2250 |
ASSERT3U(error, ==, 0); |
|
2251 |
} |
|
2252 |
||
2253 |
dmu_tx_commit(tx); |
|
2254 |
} |
|
2255 |
||
2256 |
ints = MAX(ZTEST_ZAP_MIN_INTS, object % ZTEST_ZAP_MAX_INTS); |
|
2257 |
||
5530 | 2258 |
prop = ztest_random(ZTEST_ZAP_MAX_PROPS); |
2259 |
(void) sprintf(propname, "prop_%llu", (u_longlong_t)prop); |
|
2260 |
(void) sprintf(txgname, "txg_%llu", (u_longlong_t)prop); |
|
2261 |
bzero(value, sizeof (value)); |
|
2262 |
last_txg = 0; |
|
2263 |
||
2264 |
/* |
|
2265 |
* If these zap entries already exist, validate their contents. |
|
2266 |
*/ |
|
2267 |
error = zap_length(os, object, txgname, &zl_intsize, &zl_ints); |
|
2268 |
if (error == 0) { |
|
2269 |
ASSERT3U(zl_intsize, ==, sizeof (uint64_t)); |
|
2270 |
ASSERT3U(zl_ints, ==, 1); |
|
2271 |
||
2272 |
VERIFY(zap_lookup(os, object, txgname, zl_intsize, |
|
2273 |
zl_ints, &last_txg) == 0); |
|
2274 |
||
2275 |
VERIFY(zap_length(os, object, propname, &zl_intsize, |
|
2276 |
&zl_ints) == 0); |
|
2277 |
||
2278 |
ASSERT3U(zl_intsize, ==, sizeof (uint64_t)); |
|
2279 |
ASSERT3U(zl_ints, ==, ints); |
|
2280 |
||
2281 |
VERIFY(zap_lookup(os, object, propname, zl_intsize, |
|
2282 |
zl_ints, value) == 0); |
|
2283 |
||
2284 |
for (i = 0; i < ints; i++) { |
|
2285 |
ASSERT3U(value[i], ==, last_txg + object + i); |
|
789 | 2286 |
} |
5530 | 2287 |
} else { |
2288 |
ASSERT3U(error, ==, ENOENT); |
|
2289 |
} |
|
2290 |
||
2291 |
/* |
|
2292 |
* Atomically update two entries in our zap object. |
|
2293 |
* The first is named txg_%llu, and contains the txg |
|
2294 |
* in which the property was last updated. The second |
|
2295 |
* is named prop_%llu, and the nth element of its value |
|
2296 |
* should be txg + object + n. |
|
2297 |
*/ |
|
2298 |
tx = dmu_tx_create(os); |
|
2299 |
dmu_tx_hold_zap(tx, object, TRUE, NULL); |
|
2300 |
error = dmu_tx_assign(tx, TXG_WAIT); |
|
2301 |
if (error) { |
|
2302 |
ztest_record_enospc("create zap entry"); |
|
2303 |
dmu_tx_abort(tx); |
|
2304 |
return; |
|
789 | 2305 |
} |
5530 | 2306 |
txg = dmu_tx_get_txg(tx); |
2307 |
||
2308 |
if (last_txg > txg) |
|
2309 |
fatal(0, "zap future leak: old %llu new %llu", last_txg, txg); |
|
2310 |
||
2311 |
for (i = 0; i < ints; i++) |
|
2312 |
value[i] = txg + object + i; |
|
2313 |
||
2314 |
error = zap_update(os, object, txgname, sizeof (uint64_t), 1, &txg, tx); |
|
2315 |
if (error) |
|
2316 |
fatal(0, "zap_update('%s', %llu, '%s') = %d", |
|
2317 |
osname, object, txgname, error); |
|
2318 |
||
2319 |
error = zap_update(os, object, propname, sizeof (uint64_t), |
|
2320 |
ints, value, tx); |
|
2321 |
if (error) |
|
2322 |
fatal(0, "zap_update('%s', %llu, '%s') = %d", |
|
2323 |
osname, object, propname, error); |
|
2324 |
||
2325 |
dmu_tx_commit(tx); |
|
2326 |
||
2327 |
/* |
|
2328 |
* Remove a random pair of entries. |
|
2329 |
*/ |
|
2330 |
prop = ztest_random(ZTEST_ZAP_MAX_PROPS); |
|
2331 |
(void) sprintf(propname, "prop_%llu", (u_longlong_t)prop); |
|
2332 |
(void) sprintf(txgname, "txg_%llu", (u_longlong_t)prop); |
|
2333 |
||
2334 |
error = zap_length(os, object, txgname, &zl_intsize, &zl_ints); |
|
2335 |
||
2336 |
if (error == ENOENT) |
|
2337 |
return; |
|
2338 |
||
2339 |
ASSERT3U(error, ==, 0); |
|
2340 |
||
2341 |
tx = dmu_tx_create(os); |
|
2342 |
dmu_tx_hold_zap(tx, object, TRUE, NULL); |
|
2343 |
error = dmu_tx_assign(tx, TXG_WAIT); |
|
2344 |
if (error) { |
|
2345 |
ztest_record_enospc("remove zap entry"); |
|
2346 |
dmu_tx_abort(tx); |
|
2347 |
return; |
|
2348 |
} |
|
2349 |
error = zap_remove(os, object, txgname, tx); |
|
2350 |
if (error) |
|
2351 |
fatal(0, "zap_remove('%s', %llu, '%s') = %d", |
|
2352 |
osname, object, txgname, error); |
|
2353 |
||
2354 |
error = zap_remove(os, object, propname, tx); |
|
2355 |
if (error) |
|
2356 |
fatal(0, "zap_remove('%s', %llu, '%s') = %d", |
|
2357 |
osname, object, propname, error); |
|
2358 |
||
2359 |
dmu_tx_commit(tx); |
|
789 | 2360 |
|
2361 |
/* |
|
2362 |
* Once in a while, destroy the object. |
|
2363 |
*/ |
|
5530 | 2364 |
if (ztest_random(1000) != 0) |
789 | 2365 |
return; |
2366 |
||
2367 |
tx = dmu_tx_create(os); |
|
2368 |
dmu_tx_hold_write(tx, ZTEST_DIROBJ, za->za_diroff, sizeof (uint64_t)); |
|
2369 |
dmu_tx_hold_free(tx, object, 0, DMU_OBJECT_END); |
|
2370 |
error = dmu_tx_assign(tx, TXG_WAIT); |
|
2371 |
if (error) { |
|
2372 |
ztest_record_enospc("destroy zap object"); |
|
2373 |
dmu_tx_abort(tx); |
|
2374 |
return; |
|
2375 |
} |
|
2376 |
error = zap_destroy(os, object, tx); |
|
2377 |
if (error) |
|
2378 |
fatal(0, "zap_destroy('%s', %llu) = %d", |
|
2379 |
osname, object, error); |
|
2380 |
object = 0; |
|
2381 |
dmu_write(os, ZTEST_DIROBJ, za->za_diroff, sizeof (uint64_t), |
|
2382 |
&object, tx); |
|
2383 |
dmu_tx_commit(tx); |
|
2384 |
} |
|
2385 |
||
2386 |
void |
|
2387 |
ztest_zap_parallel(ztest_args_t *za) |
|
2388 |
{ |
|
2389 |
objset_t *os = za->za_os; |
|
2390 |
uint64_t txg, object, count, wsize, wc, zl_wsize, zl_wc; |
|
2391 |
dmu_tx_t *tx; |
|
2392 |
int i, namelen, error; |
|
2393 |
char name[20], string_value[20]; |
|
2394 |
void *data; |
|
2395 |
||
5530 | 2396 |
/* |
2397 |
* Generate a random name of the form 'xxx.....' where each |
|
2398 |
* x is a random printable character and the dots are dots. |
|
2399 |
* There are 94 such characters, and the name length goes from |
|
2400 |
* 6 to 20, so there are 94^3 * 15 = 12,458,760 possible names. |
|
2401 |
*/ |
|
2402 |
namelen = ztest_random(sizeof (name) - 5) + 5 + 1; |
|
2403 |
||
2404 |
for (i = 0; i < 3; i++) |
|
2405 |
name[i] = '!' + ztest_random('~' - '!' + 1); |
|
2406 |
for (; i < namelen - 1; i++) |
|
2407 |
name[i] = '.'; |
|
2408 |
name[i] = '\0'; |
|
2409 |
||
2410 |
if (ztest_random(2) == 0) |
|
2411 |
object = ZTEST_MICROZAP_OBJ; |
|
2412 |
else |
|
2413 |
object = ZTEST_FATZAP_OBJ; |
|
2414 |
||
2415 |
if ((namelen & 1) || object == ZTEST_MICROZAP_OBJ) { |
|
2416 |
wsize = sizeof (txg); |
|
2417 |
wc = 1; |
|
2418 |
data = &txg; |
|
2419 |
} else { |
|
2420 |
wsize = 1; |
|
2421 |
wc = namelen; |
|
2422 |
data = string_value; |
|
2423 |
} |
|
2424 |
||
2425 |
count = -1ULL; |
|
2426 |
VERIFY(zap_count(os, object, &count) == 0); |
|
2427 |
ASSERT(count != -1ULL); |
|
2428 |
||
2429 |
/* |
|
2430 |
* Select an operation: length, lookup, add, update, remove. |
|
2431 |
*/ |
|
2432 |
i = ztest_random(5); |
|
2433 |
||
2434 |
if (i >= 2) { |
|
2435 |
tx = dmu_tx_create(os); |
|
2436 |
dmu_tx_hold_zap(tx, object, TRUE, NULL); |
|
2437 |
error = dmu_tx_assign(tx, TXG_WAIT); |
|
2438 |
if (error) { |
|
2439 |
ztest_record_enospc("zap parallel"); |
|
2440 |
dmu_tx_abort(tx); |
|
2441 |
return; |
|
789 | 2442 |
} |
5530 | 2443 |
txg = dmu_tx_get_txg(tx); |
2444 |
bcopy(name, string_value, namelen); |
|
2445 |
} else { |
|
2446 |
tx = NULL; |
|
2447 |
txg = 0; |
|
2448 |
bzero(string_value, namelen); |
|
2449 |
} |
|
2450 |
||
2451 |
switch (i) { |
|
2452 |
||
2453 |
case 0: |
|
2454 |
error = zap_length(os, object, name, &zl_wsize, &zl_wc); |
|
2455 |
if (error == 0) { |
|
2456 |
ASSERT3U(wsize, ==, zl_wsize); |
|
2457 |
ASSERT3U(wc, ==, zl_wc); |
|
789 | 2458 |
} else { |
5530 | 2459 |
ASSERT3U(error, ==, ENOENT); |
789 | 2460 |
} |
5530 | 2461 |
break; |
2462 |
||
2463 |
case 1: |
|
2464 |
error = zap_lookup(os, object, name, wsize, wc, data); |
|
2465 |
if (error == 0) { |
|
2466 |
if (data == string_value && |
|
2467 |
bcmp(name, data, namelen) != 0) |
|
2468 |
fatal(0, "name '%s' != val '%s' len %d", |
|
2469 |
name, data, namelen); |
|
2470 |
} else { |
|
2471 |
ASSERT3U(error, ==, ENOENT); |
|
789 | 2472 |
} |
5530 | 2473 |
break; |
2474 |
||
2475 |
case 2: |
|
2476 |
error = zap_add(os, object, name, wsize, wc, data, tx); |
|
2477 |
ASSERT(error == 0 || error == EEXIST); |
|
2478 |
break; |
|
2479 |
||
2480 |
case 3: |
|
2481 |
VERIFY(zap_update(os, object, name, wsize, wc, data, tx) == 0); |
|
2482 |
break; |
|
2483 |
||
2484 |
case 4: |
|
2485 |
error = zap_remove(os, object, name, tx); |
|
2486 |
ASSERT(error == 0 || error == ENOENT); |
|
2487 |
break; |
|
789 | 2488 |
} |
5530 | 2489 |
|
2490 |
if (tx != NULL) |
|
2491 |
dmu_tx_commit(tx); |
|
789 | 2492 |
} |
2493 |
||
2494 |
void |
|
2495 |
ztest_dsl_prop_get_set(ztest_args_t *za) |
|
2496 |
{ |
|
2497 |
objset_t *os = za->za_os; |
|
2498 |
int i, inherit; |
|
2499 |
uint64_t value; |
|
2500 |
const char *prop, *valname; |
|
2501 |
char setpoint[MAXPATHLEN]; |
|
2502 |
char osname[MAXNAMELEN]; |
|
1544 | 2503 |
int error; |
789 | 2504 |
|
2505 |
(void) rw_rdlock(&ztest_shared->zs_name_lock); |
|
2506 |
||
2507 |
dmu_objset_name(os, osname); |
|
2508 |
||
2509 |
for (i = 0; i < 2; i++) { |
|
2510 |
if (i == 0) { |
|
2511 |
prop = "checksum"; |
|
2512 |
value = ztest_random_checksum(); |
|
2513 |
inherit = (value == ZIO_CHECKSUM_INHERIT); |
|
2514 |
} else { |
|
2515 |
prop = "compression"; |
|
2516 |
value = ztest_random_compress(); |
|
2517 |
inherit = (value == ZIO_COMPRESS_INHERIT); |
|
2518 |
} |
|
2519 |
||
1544 | 2520 |
error = dsl_prop_set(osname, prop, sizeof (value), |
2521 |
!inherit, &value); |
|
2522 |
||
2523 |
if (error == ENOSPC) { |
|
2524 |
ztest_record_enospc("dsl_prop_set"); |
|
2525 |
break; |
|
2526 |
} |
|
2527 |
||
2528 |
ASSERT3U(error, ==, 0); |
|
789 | 2529 |
|
2530 |
VERIFY3U(dsl_prop_get(osname, prop, sizeof (value), |
|
2531 |
1, &value, setpoint), ==, 0); |
|
2532 |
||
2533 |
if (i == 0) |
|
2534 |
valname = zio_checksum_table[value].ci_name; |
|
2535 |
else |
|
2536 |
valname = zio_compress_table[value].ci_name; |
|
2537 |
||
2538 |
if (zopt_verbose >= 6) { |
|
2539 |
(void) printf("%s %s = %s for '%s'\n", |
|
2540 |
osname, prop, valname, setpoint); |
|
2541 |
} |
|
2542 |
} |
|
2543 |
||
2544 |
(void) rw_unlock(&ztest_shared->zs_name_lock); |
|
2545 |
} |
|
2546 |
||
1544 | 2547 |
static void |
2548 |
ztest_error_setup(vdev_t *vd, int mode, int mask, uint64_t arg) |
|
2549 |
{ |
|
2550 |
int c; |
|
2551 |
||
2552 |
for (c = 0; c < vd->vdev_children; c++) |
|
2553 |
ztest_error_setup(vd->vdev_child[c], mode, mask, arg); |
|
2554 |
||
2555 |
if (vd->vdev_path != NULL) { |
|
2556 |
vd->vdev_fault_mode = mode; |
|
2557 |
vd->vdev_fault_mask = mask; |
|
2558 |
vd->vdev_fault_arg = arg; |
|
2559 |
} |
|
2560 |
} |
|
2561 |
||
789 | 2562 |
/* |
2563 |
* Inject random faults into the on-disk data. |
|
2564 |
*/ |
|
2565 |
void |
|
2566 |
ztest_fault_inject(ztest_args_t *za) |
|
2567 |
{ |
|
2568 |
int fd; |
|
2569 |
uint64_t offset; |
|
2570 |
uint64_t leaves = MAX(zopt_mirrors, 1) * zopt_raidz; |
|
2571 |
uint64_t bad = 0x1990c0ffeedecade; |
|
2572 |
uint64_t top, leaf; |
|
2573 |
char path0[MAXPATHLEN]; |
|
2574 |
char pathrand[MAXPATHLEN]; |
|
2575 |
size_t fsize; |
|
5530 | 2576 |
spa_t *spa = za->za_spa; |
789 | 2577 |
int bshift = SPA_MAXBLOCKSHIFT + 2; /* don't scrog all labels */ |
2578 |
int iters = 1000; |
|
1544 | 2579 |
vdev_t *vd0; |
2580 |
uint64_t guid0 = 0; |
|
2581 |
||
2582 |
/* |
|
2583 |
* We can't inject faults when we have no fault tolerance. |
|
2584 |
*/ |
|
2585 |
if (zopt_maxfaults == 0) |
|
2586 |
return; |
|
2587 |
||
2588 |
ASSERT(leaves >= 2); |
|
789 | 2589 |
|
2590 |
/* |
|
2591 |
* Pick a random top-level vdev. |
|
2592 |
*/ |
|
1544 | 2593 |
spa_config_enter(spa, RW_READER, FTAG); |
789 | 2594 |
top = ztest_random(spa->spa_root_vdev->vdev_children); |
1544 | 2595 |
spa_config_exit(spa, FTAG); |
789 | 2596 |
|
2597 |
/* |
|
2598 |
* Pick a random leaf. |
|
2599 |
*/ |
|
2600 |
leaf = ztest_random(leaves); |
|
2601 |
||
2602 |
/* |
|
1544 | 2603 |
* Generate paths to the first two leaves in this top-level vdev, |
789 | 2604 |
* and to the random leaf we selected. We'll induce transient |
1544 | 2605 |
* I/O errors and random online/offline activity on leaf 0, |
789 | 2606 |
* and we'll write random garbage to the randomly chosen leaf. |
2607 |
*/ |
|
2608 |
(void) snprintf(path0, sizeof (path0), |
|
2609 |
ztest_dev_template, zopt_dir, zopt_pool, top * leaves + 0); |
|
2610 |
(void) snprintf(pathrand, sizeof (pathrand), |
|
2611 |
ztest_dev_template, zopt_dir, zopt_pool, top * leaves + leaf); |
|
2612 |
||
1544 | 2613 |
dprintf("damaging %s and %s\n", path0, pathrand); |
2614 |
||
2615 |
spa_config_enter(spa, RW_READER, FTAG); |
|
789 | 2616 |
|
2617 |
/* |
|
1544 | 2618 |
* If we can tolerate two or more faults, make vd0 fail randomly. |
789 | 2619 |
*/ |
1544 | 2620 |
vd0 = vdev_lookup_by_path(spa->spa_root_vdev, path0); |
2621 |
if (vd0 != NULL && zopt_maxfaults >= 2) { |
|
2622 |
guid0 = vd0->vdev_guid; |
|
2623 |
ztest_error_setup(vd0, VDEV_FAULT_COUNT, |
|
2624 |
(1U << ZIO_TYPE_READ) | (1U << ZIO_TYPE_WRITE), 100); |
|
2625 |
} |
|
2626 |
||
2627 |
spa_config_exit(spa, FTAG); |
|
2628 |
||
2629 |
/* |
|
2630 |
* If we can tolerate two or more faults, randomly online/offline vd0. |
|
2631 |
*/ |
|
2632 |
if (zopt_maxfaults >= 2 && guid0 != 0) { |
|
789 | 2633 |
if (ztest_random(10) < 6) |
1544 | 2634 |
(void) vdev_offline(spa, guid0, B_TRUE); |
789 | 2635 |
else |
4451 | 2636 |
(void) vdev_online(spa, guid0, B_FALSE, NULL); |
789 | 2637 |
} |
2638 |
||
2639 |
/* |
|
1544 | 2640 |
* We have at least single-fault tolerance, so inject data corruption. |
789 | 2641 |
*/ |
2642 |
fd = open(pathrand, O_RDWR); |
|
2643 |
||
2644 |
if (fd == -1) /* we hit a gap in the device namespace */ |
|
2645 |
return; |
|
2646 |
||
2647 |
fsize = lseek(fd, 0, SEEK_END); |
|
2648 |
||
2649 |
while (--iters != 0) { |
|
2650 |
offset = ztest_random(fsize / (leaves << bshift)) * |
|
2651 |
(leaves << bshift) + (leaf << bshift) + |
|
2652 |
(ztest_random(1ULL << (bshift - 1)) & -8ULL); |
|
2653 |
||
2654 |
if (offset >= fsize) |
|
2655 |
continue; |
|
2656 |
||
2657 |
if (zopt_verbose >= 6) |
|
2658 |
(void) printf("injecting bad word into %s," |
|
2659 |
" offset 0x%llx\n", pathrand, (u_longlong_t)offset); |
|
2660 |
||
2661 |
if (pwrite(fd, &bad, sizeof (bad), offset) != sizeof (bad)) |
|
2662 |
fatal(1, "can't inject bad word at 0x%llx in %s", |
|
2663 |
offset, pathrand); |
|
2664 |
} |
|
2665 |
||
2666 |
(void) close(fd); |
|
2667 |
} |
|
2668 |
||
2669 |
/* |
|
2670 |
* Scrub the pool. |
|
2671 |
*/ |
|
2672 |
void |
|
2673 |
ztest_scrub(ztest_args_t *za) |
|
2674 |
{ |
|
5530 | 2675 |
spa_t *spa = za->za_spa; |
789 | 2676 |
|
4808 | 2677 |
mutex_enter(&spa_namespace_lock); |
789 | 2678 |
(void) spa_scrub(spa, POOL_SCRUB_EVERYTHING, B_FALSE); |
4808 | 2679 |
mutex_exit(&spa_namespace_lock); |
789 | 2680 |
(void) poll(NULL, 0, 1000); /* wait a second, then force a restart */ |
4808 | 2681 |
mutex_enter(&spa_namespace_lock); |
789 | 2682 |
(void) spa_scrub(spa, POOL_SCRUB_EVERYTHING, B_FALSE); |
4808 | 2683 |
mutex_exit(&spa_namespace_lock); |
789 | 2684 |
} |
2685 |
||
2686 |
/* |
|
2687 |
* Rename the pool to a different name and then rename it back. |
|
2688 |
*/ |
|
2689 |
void |
|
2690 |
ztest_spa_rename(ztest_args_t *za) |
|
2691 |
{ |
|
2692 |
char *oldname, *newname; |
|
2693 |
int error; |
|
2694 |
spa_t *spa; |
|
2695 |
||
2696 |
(void) rw_wrlock(&ztest_shared->zs_name_lock); |
|
2697 |
||
2698 |
oldname = za->za_pool; |
|
2699 |
newname = umem_alloc(strlen(oldname) + 5, UMEM_NOFAIL); |
|
2700 |
(void) strcpy(newname, oldname); |
|
2701 |
(void) strcat(newname, "_tmp"); |
|
2702 |
||
2703 |
/* |
|
2704 |
* Do the rename |
|
2705 |
*/ |
|
2706 |
error = spa_rename(oldname, newname); |
|
2707 |
if (error) |
|
2708 |
fatal(0, "spa_rename('%s', '%s') = %d", oldname, |
|
2709 |
newname, error); |
|
2710 |
||
2711 |
/* |
|
2712 |
* Try to open it under the old name, which shouldn't exist |
|
2713 |
*/ |
|
2714 |
error = spa_open(oldname, &spa, FTAG); |
|
2715 |
if (error != ENOENT) |
|
2716 |
fatal(0, "spa_open('%s') = %d", oldname, error); |
|
2717 |
||
2718 |
/* |
|
2719 |
* Open it under the new name and make sure it's still the same spa_t. |
|
2720 |
*/ |
|
2721 |
error = spa_open(newname, &spa, FTAG); |
|
2722 |
if (error != 0) |
|
2723 |
fatal(0, "spa_open('%s') = %d", newname, error); |
|
2724 |
||
5530 | 2725 |
ASSERT(spa == za->za_spa); |
789 | 2726 |
spa_close(spa, FTAG); |
2727 |
||
2728 |
/* |
|
2729 |
* Rename it back to the original |
|
2730 |
*/ |
|
2731 |
error = spa_rename(newname, oldname); |
|
2732 |
if (error) |
|
2733 |
fatal(0, "spa_rename('%s', '%s') = %d", newname, |
|
2734 |
oldname, error); |
|
2735 |
||
2736 |
/* |
|
2737 |
* Make sure it can still be opened |
|
2738 |
*/ |
|
2739 |
error = spa_open(oldname, &spa, FTAG); |
|
2740 |
if (error != 0) |
|
2741 |
fatal(0, "spa_open('%s') = %d", oldname, error); |
|
2742 |
||
5530 | 2743 |
ASSERT(spa == za->za_spa); |
789 | 2744 |
spa_close(spa, FTAG); |
2745 |
||
2746 |
umem_free(newname, strlen(newname) + 1); |
|
2747 |
||
2748 |
(void) rw_unlock(&ztest_shared->zs_name_lock); |
|
2749 |
} |
|
2750 |
||
2751 |
||
2752 |
/* |
|
2753 |
* Completely obliterate one disk. |
|
2754 |
*/ |
|
2755 |
static void |
|
2756 |
ztest_obliterate_one_disk(uint64_t vdev) |
|
2757 |
{ |
|
2758 |
int fd; |
|
1807
35c8b566d7af
6410711 intent log blocks don't get invited to pool parties
bonwick
parents:
1775
diff
changeset
|
2759 |
char dev_name[MAXPATHLEN], copy_name[MAXPATHLEN]; |
789 | 2760 |
size_t fsize; |
2761 |
||
2762 |
if (zopt_maxfaults < 2) |
|
2763 |
return; |
|
2764 |
||
2765 |
(void) sprintf(dev_name, ztest_dev_template, zopt_dir, zopt_pool, vdev); |
|
1807
35c8b566d7af
6410711 intent log blocks don't get invited to pool parties
bonwick
parents:
1775
diff
changeset
|
2766 |
(void) snprintf(copy_name, MAXPATHLEN, "%s.old", dev_name); |
789 | 2767 |
|
2768 |
fd = open(dev_name, O_RDWR); |
|
2769 |
||
2770 |
if (fd == -1) |
|
2771 |
fatal(1, "can't open %s", dev_name); |
|
2772 |
||
2773 |
/* |
|
2774 |
* Determine the size. |
|
2775 |
*/ |
|
2776 |
fsize = lseek(fd, 0, SEEK_END); |
|
1807
35c8b566d7af
6410711 intent log blocks don't get invited to pool parties
bonwick
parents:
1775
diff
changeset
|
2777 |
|
789 | 2778 |
(void) close(fd); |
2779 |
||
2780 |
/* |
|
1807
35c8b566d7af
6410711 intent log blocks don't get invited to pool parties
bonwick
parents:
1775
diff
changeset
|
2781 |
* Rename the old device to dev_name.old (useful for debugging). |
789 | 2782 |
*/ |
1807
35c8b566d7af
6410711 intent log blocks don't get invited to pool parties
bonwick
parents:
1775
diff
changeset
|
2783 |
VERIFY(rename(dev_name, copy_name) == 0); |
789 | 2784 |
|
2785 |
/* |
|
2786 |
* Create a new one. |
|
2787 |
*/ |
|
2788 |
VERIFY((fd = open(dev_name, O_RDWR | O_CREAT | O_TRUNC, 0666)) >= 0); |
|
2789 |
VERIFY(ftruncate(fd, fsize) == 0); |
|
2790 |
(void) close(fd); |
|
2791 |
} |
|
2792 |
||
2793 |
static void |
|
2794 |
ztest_replace_one_disk(spa_t *spa, uint64_t vdev) |
|
2795 |
{ |
|
2796 |
char dev_name[MAXPATHLEN]; |
|
2797 |
nvlist_t *file, *root; |
|
2798 |
int error; |
|
1544 | 2799 |
uint64_t guid; |
1732 | 2800 |
uint64_t ashift = ztest_get_ashift(); |
1544 | 2801 |
vdev_t *vd; |
789 | 2802 |
|
2803 |
(void) sprintf(dev_name, ztest_dev_template, zopt_dir, zopt_pool, vdev); |
|
2804 |
||
2805 |
/* |
|
2806 |
* Build the nvlist describing dev_name. |
|
2807 |
*/ |
|
2808 |
VERIFY(nvlist_alloc(&file, NV_UNIQUE_NAME, 0) == 0); |
|
2809 |
VERIFY(nvlist_add_string(file, ZPOOL_CONFIG_TYPE, VDEV_TYPE_FILE) == 0); |
|
2810 |
VERIFY(nvlist_add_string(file, ZPOOL_CONFIG_PATH, dev_name) == 0); |
|
1732 | 2811 |
VERIFY(nvlist_add_uint64(file, ZPOOL_CONFIG_ASHIFT, ashift) == 0); |
789 | 2812 |
|
2813 |
VERIFY(nvlist_alloc(&root, NV_UNIQUE_NAME, 0) == 0); |
|
2814 |
VERIFY(nvlist_add_string(root, ZPOOL_CONFIG_TYPE, VDEV_TYPE_ROOT) == 0); |
|
2815 |
VERIFY(nvlist_add_nvlist_array(root, ZPOOL_CONFIG_CHILDREN, |
|
2816 |
&file, 1) == 0); |
|
2817 |
||
1544 | 2818 |
spa_config_enter(spa, RW_READER, FTAG); |
2819 |
if ((vd = vdev_lookup_by_path(spa->spa_root_vdev, dev_name)) == NULL) |
|
2820 |
guid = 0; |
|
2821 |
else |
|
2822 |
guid = vd->vdev_guid; |
|
2823 |
spa_config_exit(spa, FTAG); |
|
2824 |
error = spa_vdev_attach(spa, guid, root, B_TRUE); |
|
1732 | 2825 |
if (error != 0 && |
2826 |
error != EBUSY && |
|
2827 |
error != ENOTSUP && |
|
2828 |
error != ENODEV && |
|
2829 |
error != EDOM) |
|
789 | 2830 |
fatal(0, "spa_vdev_attach(in-place) = %d", error); |
2831 |
||
2832 |
nvlist_free(file); |
|
2833 |
nvlist_free(root); |
|
2834 |
} |
|
2835 |
||
2836 |
static void |
|
2837 |
ztest_verify_blocks(char *pool) |
|
2838 |
{ |
|
2839 |
int status; |
|
2840 |
char zdb[MAXPATHLEN + MAXNAMELEN + 20]; |
|
2841 |
char zbuf[1024]; |
|
2842 |
char *bin; |
|
4527 | 2843 |
char *ztest; |
2844 |
char *isa; |
|
2845 |
int isalen; |
|
789 | 2846 |
FILE *fp; |
2847 |
||
2848 |
(void) realpath(getexecname(), zdb); |
|
2849 |
||
2850 |
/* zdb lives in /usr/sbin, while ztest lives in /usr/bin */ |
|
2851 |
bin = strstr(zdb, "/usr/bin/"); |
|
4527 | 2852 |
ztest = strstr(bin, "/ztest"); |
2853 |
isa = bin + 8; |
|
2854 |
isalen = ztest - isa; |
|
2855 |
isa = strdup(isa); |
|
789 | 2856 |
/* LINTED */ |
5994
bedab011a2e5
6580270 'zdb [-C|-L] <pool'> can't open alternate root pools
ck153898
parents:
5530
diff
changeset
|
2857 |
(void) sprintf(bin, |
bedab011a2e5
6580270 'zdb [-C|-L] <pool'> can't open alternate root pools
ck153898
parents:
5530
diff
changeset
|
2858 |
"/usr/sbin%.*s/zdb -bc%s%s -U /tmp/zpool.cache -O %s %s", |
4527 | 2859 |
isalen, |
2860 |
isa, |
|
789 | 2861 |
zopt_verbose >= 3 ? "s" : "", |
2862 |
zopt_verbose >= 4 ? "v" : "", |
|
2863 |
ztest_random(2) == 0 ? "pre" : "post", pool); |
|
4527 | 2864 |
free(isa); |
789 | 2865 |
|
2866 |
if (zopt_verbose >= 5) |
|
2867 |
(void) printf("Executing %s\n", strstr(zdb, "zdb ")); |
|
2868 |
||
2869 |
fp = popen(zdb, "r"); |
|
2870 |
||
2871 |
while (fgets(zbuf, sizeof (zbuf), fp) != NULL) |
|
2872 |
if (zopt_verbose >= 3) |
|
2873 |
(void) printf("%s", zbuf); |
|
2874 |
||
2875 |
status = pclose(fp); |
|
2876 |
||
2877 |
if (status == 0) |
|
2878 |
return; |
|
2879 |
||
2880 |
ztest_dump_core = 0; |
|
2881 |
if (WIFEXITED(status)) |
|
2882 |
fatal(0, "'%s' exit code %d", zdb, WEXITSTATUS(status)); |
|
2883 |
else |
|
2884 |
fatal(0, "'%s' died with signal %d", zdb, WTERMSIG(status)); |
|
2885 |
} |
|
2886 |
||
2887 |
static void |
|
2888 |
ztest_walk_pool_directory(char *header) |
|
2889 |
{ |
|
2890 |
spa_t *spa = NULL; |
|
2891 |
||
2892 |
if (zopt_verbose >= 6) |
|
2893 |
(void) printf("%s\n", header); |
|
2894 |
||
2895 |
mutex_enter(&spa_namespace_lock); |
|
2896 |
while ((spa = spa_next(spa)) != NULL) |
|
2897 |
if (zopt_verbose >= 6) |
|
2898 |
(void) printf("\t%s\n", spa_name(spa)); |
|
2899 |
mutex_exit(&spa_namespace_lock); |
|
2900 |
} |
|
2901 |
||
2902 |
static void |
|
2903 |
ztest_spa_import_export(char *oldname, char *newname) |
|
2904 |
{ |
|
2905 |
nvlist_t *config; |
|
2906 |
uint64_t pool_guid; |
|
2907 |
spa_t *spa; |
|
2908 |
int error; |
|
2909 |
||
2910 |
if (zopt_verbose >= 4) { |
|
2911 |
(void) printf("import/export: old = %s, new = %s\n", |
|
2912 |
oldname, newname); |
|
2913 |
} |
|
2914 |
||
2915 |
/* |
|
2916 |
* Clean up from previous runs. |
|
2917 |
*/ |
|
2918 |
(void) spa_destroy(newname); |
|
2919 |
||
2920 |
/* |
|
2921 |
* Get the pool's configuration and guid. |
|
2922 |
*/ |
|
2923 |
error = spa_open(oldname, &spa, FTAG); |
|
2924 |
if (error) |
|
2925 |
fatal(0, "spa_open('%s') = %d", oldname, error); |
|
2926 |
||
2927 |
pool_guid = spa_guid(spa); |
|
2928 |
spa_close(spa, FTAG); |
|
2929 |
||
2930 |
ztest_walk_pool_directory("pools before export"); |
|
2931 |
||
2932 |
/* |
|
2933 |
* Export it. |
|
2934 |
*/ |
|
1775
e51e26b432c0
6410698 ZFS metadata needs to be more highly replicated (ditto blocks)
billm
parents:
1732
diff
changeset
|
2935 |
error = spa_export(oldname, &config); |
789 | 2936 |
if (error) |
2937 |
fatal(0, "spa_export('%s') = %d", oldname, error); |
|
2938 |
||
2939 |
ztest_walk_pool_directory("pools after export"); |
|
2940 |
||
2941 |
/* |
|
2942 |
* Import it under the new name. |
|
2943 |
*/ |
|
2944 |
error = spa_import(newname, config, NULL); |
|
2945 |
if (error) |
|
2946 |
fatal(0, "spa_import('%s') = %d", newname, error); |
|
2947 |
||
2948 |
ztest_walk_pool_directory("pools after import"); |
|
2949 |
||
2950 |
/* |
|
2951 |
* Try to import it again -- should fail with EEXIST. |
|
2952 |
*/ |
|
2953 |
error = spa_import(newname, config, NULL); |
|
2954 |
if (error != EEXIST) |
|
2955 |
fatal(0, "spa_import('%s') twice", newname); |
|
2956 |
||
2957 |
/* |
|
2958 |
* Try to import it under a different name -- should fail with EEXIST. |
|
2959 |
*/ |
|
2960 |
error = spa_import(oldname, config, NULL); |
|
2961 |
if (error != EEXIST) |
|
2962 |
fatal(0, "spa_import('%s') under multiple names", newname); |
|
2963 |
||
2964 |
/* |
|
2965 |
* Verify that the pool is no longer visible under the old name. |
|
2966 |
*/ |
|
2967 |
error = spa_open(oldname, &spa, FTAG); |
|
2968 |
if (error != ENOENT) |
|
2969 |
fatal(0, "spa_open('%s') = %d", newname, error); |
|
2970 |
||
2971 |
/* |
|
2972 |
* Verify that we can open and close the pool using the new name. |
|
2973 |
*/ |
|
2974 |
error = spa_open(newname, &spa, FTAG); |
|
2975 |
if (error) |
|
2976 |
fatal(0, "spa_open('%s') = %d", newname, error); |
|
2977 |
ASSERT(pool_guid == spa_guid(spa)); |
|
2978 |
spa_close(spa, FTAG); |
|
2979 |
||
2980 |
nvlist_free(config); |
|
2981 |
} |
|
2982 |
||
5329 | 2983 |
/* ARGSUSED */ |
2984 |
static void * |
|
2985 |
ztest_suspend_monitor(void *arg) |
|
2986 |
{ |
|
2987 |
spa_t *spa; |
|
2988 |
int error; |
|
2989 |
||
2990 |
error = spa_open(zopt_pool, &spa, FTAG); |
|
2991 |
if (error) { |
|
2992 |
(void) printf("Unable to monitor pool '%s'\n", zopt_pool); |
|
2993 |
return (NULL); |
|
2994 |
} |
|
2995 |
||
2996 |
while (!ztest_exiting) { |
|
2997 |
mutex_enter(&spa->spa_zio_lock); |
|
2998 |
while (!ztest_exiting && list_is_empty(&spa->spa_zio_list)) |
|
2999 |
cv_wait(&spa->spa_zio_cv, &spa->spa_zio_lock); |
|
3000 |
mutex_exit(&spa->spa_zio_lock); |
|
3001 |
||
3002 |
(void) sleep(3); |
|
3003 |
/* |
|
3004 |
* We don't hold the spa_config_lock since the pool is in |
|
3005 |
* complete failure mode and there is no way for us to |
|
3006 |
* change the vdev config when we're in this state. |
|
3007 |
*/ |
|
3008 |
while ((error = zio_vdev_resume_io(spa)) != 0) { |
|
3009 |
(void) printf("I/O could not be resumed, %d\n", error); |
|
3010 |
(void) sleep(1); |
|
3011 |
} |
|
3012 |
vdev_clear(spa, NULL, B_TRUE); |
|
3013 |
} |
|
3014 |
spa_close(spa, FTAG); |
|
3015 |
return (NULL); |
|
3016 |
} |
|
3017 |
||
789 | 3018 |
static void * |
3019 |
ztest_thread(void *arg) |
|
3020 |
{ |
|
3021 |
ztest_args_t *za = arg; |
|
3022 |
ztest_shared_t *zs = ztest_shared; |
|
3023 |
hrtime_t now, functime; |
|
3024 |
ztest_info_t *zi; |
|
5530 | 3025 |
int f, i; |
789 | 3026 |
|
3027 |
while ((now = gethrtime()) < za->za_stop) { |
|
3028 |
/* |
|
3029 |
* See if it's time to force a crash. |
|
3030 |
*/ |
|
3031 |
if (now > za->za_kill) { |
|
5530 | 3032 |
zs->zs_alloc = spa_get_alloc(za->za_spa); |
3033 |
zs->zs_space = spa_get_space(za->za_spa); |
|
789 | 3034 |
(void) kill(getpid(), SIGKILL); |
3035 |
} |
|
3036 |
||
3037 |
/* |
|
3038 |
* Pick a random function. |
|
3039 |
*/ |
|
3040 |
f = ztest_random(ZTEST_FUNCS); |
|
3041 |
zi = &zs->zs_info[f]; |
|
3042 |
||
3043 |
/* |
|
3044 |
* Decide whether to call it, based on the requested frequency. |
|
3045 |
*/ |
|
3046 |
if (zi->zi_call_target == 0 || |
|
3047 |
(double)zi->zi_call_total / zi->zi_call_target > |
|
3048 |
(double)(now - zs->zs_start_time) / (zopt_time * NANOSEC)) |
|
3049 |
continue; |
|
3050 |
||
3051 |
atomic_add_64(&zi->zi_calls, 1); |
|
3052 |
atomic_add_64(&zi->zi_call_total, 1); |
|
3053 |
||
3054 |
za->za_diroff = (za->za_instance * ZTEST_FUNCS + f) * |
|
3055 |
ZTEST_DIRSIZE; |
|
3056 |
za->za_diroff_shared = (1ULL << 63); |
|
3057 |
||
5530 | 3058 |
for (i = 0; i < zi->zi_iters; i++) |
3059 |
zi->zi_func(za); |
|
789 | 3060 |
|
3061 |
functime = gethrtime() - now; |
|
3062 |
||
3063 |
atomic_add_64(&zi->zi_call_time, functime); |
|
3064 |
||
3065 |
if (zopt_verbose >= 4) { |
|
3066 |
Dl_info dli; |
|
3067 |
(void) dladdr((void *)zi->zi_func, &dli); |
|
3068 |
(void) printf("%6.2f sec in %s\n", |
|
3069 |
(double)functime / NANOSEC, dli.dli_sname); |
|
3070 |
} |
|
3071 |
||
3072 |
/* |
|
3073 |
* If we're getting ENOSPC with some regularity, stop. |
|
3074 |
*/ |
|
3075 |
if (zs->zs_enospc_count > 10) |
|
3076 |
break; |
|
3077 |
} |
|
3078 |
||
3079 |
return (NULL); |
|
3080 |
} |
|
3081 |
||
3082 |
/* |
|
3083 |
* Kick off threads to run tests on all datasets in parallel. |
|
3084 |
*/ |
|
3085 |
static void |
|
3086 |
ztest_run(char *pool) |
|
3087 |
{ |
|
3088 |
int t, d, error; |
|
3089 |
ztest_shared_t *zs = ztest_shared; |
|
3090 |
ztest_args_t *za; |
|
3091 |
spa_t *spa; |
|
3092 |
char name[100]; |
|
5329 | 3093 |
thread_t tid; |
789 | 3094 |
|
3095 |
(void) _mutex_init(&zs->zs_vdev_lock, USYNC_THREAD, NULL); |
|
3096 |
(void) rwlock_init(&zs->zs_name_lock, USYNC_THREAD, NULL); |
|
3097 |
||
3098 |
for (t = 0; t < ZTEST_SYNC_LOCKS; t++) |
|
3099 |
(void) _mutex_init(&zs->zs_sync_lock[t], USYNC_THREAD, NULL); |
|
3100 |
||
3101 |
/* |
|
3102 |
* Destroy one disk before we even start. |
|
3103 |
* It's mirrored, so everything should work just fine. |
|
3104 |
* This makes us exercise fault handling very early in spa_load(). |
|
3105 |
*/ |
|
3106 |
ztest_obliterate_one_disk(0); |
|
3107 |
||
3108 |
/* |
|
3109 |
* Verify that the sum of the sizes of all blocks in the pool |
|
3110 |
* equals the SPA's allocated space total. |
|
3111 |
*/ |
|
3112 |
ztest_verify_blocks(pool); |
|
3113 |
||
3114 |
/* |
|
3115 |
* Kick off a replacement of the disk we just obliterated. |
|
3116 |
*/ |
|
3117 |
kernel_init(FREAD | FWRITE); |
|
3118 |
error = spa_open(pool, &spa, FTAG); |
|
3119 |
if (error) |
|
3120 |
fatal(0, "spa_open(%s) = %d", pool, error); |
|
3121 |
ztest_replace_one_disk(spa, 0); |
|
3122 |
if (zopt_verbose >= 5) |
|
3123 |
show_pool_stats(spa); |
|
3124 |
spa_close(spa, FTAG); |
|
3125 |
kernel_fini(); |
|
3126 |
||
3127 |
kernel_init(FREAD | FWRITE); |
|
3128 |
||
3129 |
/* |
|
3130 |
* Verify that we can export the pool and reimport it under a |
|
3131 |
* different name. |
|
3132 |
*/ |
|
1585
4ad213e858a9
6395480 ztest ASSERT: rbt.bt_objset == wbt.bt_objset, line 2041
bonwick
parents:
1544
diff
changeset
|
3133 |
if (ztest_random(2) == 0) { |
4ad213e858a9
6395480 ztest ASSERT: rbt.bt_objset == wbt.bt_objset, line 2041
bonwick
parents:
1544
diff
changeset
|
3134 |
(void) snprintf(name, 100, "%s_import", pool); |
4ad213e858a9
6395480 ztest ASSERT: rbt.bt_objset == wbt.bt_objset, line 2041
bonwick
parents:
1544
diff
changeset
|
3135 |
ztest_spa_import_export(pool, name); |
4ad213e858a9
6395480 ztest ASSERT: rbt.bt_objset == wbt.bt_objset, line 2041
bonwick
parents:
1544
diff
changeset
|
3136 |
ztest_spa_import_export(name, pool); |
4ad213e858a9
6395480 ztest ASSERT: rbt.bt_objset == wbt.bt_objset, line 2041
bonwick
parents:
1544
diff
changeset
|
3137 |
} |
789 | 3138 |
|
3139 |
/* |
|
3140 |
* Verify that we can loop over all pools. |
|
3141 |
*/ |
|
3142 |
mutex_enter(&spa_namespace_lock); |
|
3143 |
for (spa = spa_next(NULL); spa != NULL; spa = spa_next(spa)) { |
|
3144 |
if (zopt_verbose > 3) { |
|
3145 |
(void) printf("spa_next: found %s\n", spa_name(spa)); |
|
3146 |
} |
|
3147 |
} |
|
3148 |
mutex_exit(&spa_namespace_lock); |
|
3149 |
||
3150 |
/* |
|
5329 | 3151 |
* Create a thread to handling complete pool failures. This |
3152 |
* thread will kickstart the I/Os when they suspend. We must |
|
3153 |
* start the thread before setting the zio_io_fail_shift, which |
|
3154 |
* will indicate our failure rate. |
|
3155 |
*/ |
|
3156 |
error = thr_create(0, 0, ztest_suspend_monitor, NULL, THR_BOUND, &tid); |
|
3157 |
if (error) { |
|
3158 |
fatal(0, "can't create suspend monitor thread: error %d", |
|
3159 |
t, error); |
|
3160 |
} |
|
3161 |
||
3162 |
/* |
|
789 | 3163 |
* Open our pool. |
3164 |
*/ |
|
3165 |
error = spa_open(pool, &spa, FTAG); |
|
3166 |
if (error) |
|
3167 |
fatal(0, "spa_open() = %d", error); |
|
3168 |
||
3169 |
/* |
|
3170 |
* Verify that we can safely inquire about about any object, |
|
3171 |
* whether it's allocated or not. To make it interesting, |
|
3172 |
* we probe a 5-wide window around each power of two. |
|
3173 |
* This hits all edge cases, including zero and the max. |
|
3174 |
*/ |
|
3175 |
for (t = 0; t < 64; t++) { |
|
3176 |
for (d = -5; d <= 5; d++) { |
|
3177 |
error = dmu_object_info(spa->spa_meta_objset, |
|
3178 |
(1ULL << t) + d, NULL); |
|
1544 | 3179 |
ASSERT(error == 0 || error == ENOENT || |
3180 |
error == EINVAL); |
|
789 | 3181 |
} |
3182 |
} |
|
3183 |
||
3184 |
/* |
|
3185 |
* Now kick off all the tests that run in parallel. |
|
3186 |
*/ |
|
3187 |
zs->zs_enospc_count = 0; |
|
3188 |
||
3189 |
za = umem_zalloc(zopt_threads * sizeof (ztest_args_t), UMEM_NOFAIL); |
|
3190 |
||
3191 |
if (zopt_verbose >= 4) |
|
3192 |
(void) printf("starting main threads...\n"); |
|
3193 |
||
5329 | 3194 |
/* Let failures begin */ |
3195 |
zio_io_fail_shift = zopt_write_fail_shift; |
|
3196 |
||
789 | 3197 |
za[0].za_start = gethrtime(); |
3198 |
za[0].za_stop = za[0].za_start + zopt_passtime * NANOSEC; |
|
3199 |
za[0].za_stop = MIN(za[0].za_stop, zs->zs_stop_time); |
|
3200 |
za[0].za_kill = za[0].za_stop; |
|
3201 |
if (ztest_random(100) < zopt_killrate) |
|
3202 |
za[0].za_kill -= ztest_random(zopt_passtime * NANOSEC); |
|
3203 |
||
3204 |
for (t = 0; t < zopt_threads; t++) { |
|
1732 | 3205 |
d = t % zopt_datasets; |
5530 | 3206 |
|
3207 |
(void) strcpy(za[t].za_pool, pool); |
|
3208 |
za[t].za_os = za[d].za_os; |
|
3209 |
za[t].za_spa = spa; |
|
3210 |
za[t].za_zilog = za[d].za_zilog; |
|
3211 |
za[t].za_instance = t; |
|
3212 |
za[t].za_random = ztest_random(-1ULL); |
|
3213 |
za[t].za_start = za[0].za_start; |
|
3214 |
za[t].za_stop = za[0].za_stop; |
|
3215 |
za[t].za_kill = za[0].za_kill; |
|
3216 |
||
1732 | 3217 |
if (t < zopt_datasets) { |
789 | 3218 |
ztest_replay_t zr; |
3711
2226ffbe7873
6526196 ZFS: assertion failed: zp->z_phys->zp_links > zp_is_dir
maybee
parents:
3668
diff
changeset
|
3219 |
int test_future = FALSE; |
789 | 3220 |
(void) rw_rdlock(&ztest_shared->zs_name_lock); |
3221 |
(void) snprintf(name, 100, "%s/%s_%d", pool, pool, d); |
|
6492
903545192033
6654808 FIGNORECASE lookups in a zfs xattr dir don't provide 'realname' data
timh
parents:
5994
diff
changeset
|
3222 |
error = dmu_objset_create(name, DMU_OST_OTHER, NULL, 0, |
789 | 3223 |
ztest_create_cb, NULL); |
3711
2226ffbe7873
6526196 ZFS: assertion failed: zp->z_phys->zp_links > zp_is_dir
maybee
parents:
3668
diff
changeset
|
3224 |
if (error == EEXIST) { |
2226ffbe7873
6526196 ZFS: assertion failed: zp->z_phys->zp_links > zp_is_dir
maybee
parents:
3668
diff
changeset
|
3225 |
test_future = TRUE; |
5530 | 3226 |
} else if (error == ENOSPC) { |
3227 |
zs->zs_enospc_count++; |
|
3228 |
(void) rw_unlock(&ztest_shared->zs_name_lock); |
|
3229 |
break; |
|
3711
2226ffbe7873
6526196 ZFS: assertion failed: zp->z_phys->zp_links > zp_is_dir
maybee
parents:
3668
diff
changeset
|
3230 |
} else if (error != 0) { |
789 | 3231 |
fatal(0, "dmu_objset_create(%s) = %d", |
3232 |
name, error); |
|
3233 |
} |
|
3234 |
error = dmu_objset_open(name, DMU_OST_OTHER, |
|
3235 |
DS_MODE_STANDARD, &za[d].za_os); |
|
3236 |
if (error) |
|
3237 |
fatal(0, "dmu_objset_open('%s') = %d", |
|
3238 |
name, error); |
|
3239 |
(void) rw_unlock(&ztest_shared->zs_name_lock); |
|
5530 | 3240 |
if (test_future) |
3241 |
ztest_dmu_check_future_leak(&za[t]); |
|
789 | 3242 |
zr.zr_os = za[d].za_os; |
3243 |
zil_replay(zr.zr_os, &zr, &zr.zr_assign, |
|
3461 | 3244 |
ztest_replay_vector); |
789 | 3245 |
za[d].za_zilog = zil_open(za[d].za_os, NULL); |
3246 |
} |
|
3247 |
||
3248 |
error = thr_create(0, 0, ztest_thread, &za[t], THR_BOUND, |
|
3249 |
&za[t].za_thread); |
|
3250 |
if (error) |
|
3251 |
fatal(0, "can't create thread %d: error %d", |
|
3252 |
t, error); |
|
3253 |
} |
|
3254 |
||
3255 |
while (--t >= 0) { |
|
3256 |
error = thr_join(za[t].za_thread, NULL, NULL); |
|
3257 |
if (error) |
|
3258 |
fatal(0, "thr_join(%d) = %d", t, error); |
|
3259 |
if (za[t].za_th) |
|
3260 |
traverse_fini(za[t].za_th); |
|
1732 | 3261 |
if (t < zopt_datasets) { |
789 | 3262 |
zil_close(za[t].za_zilog); |
3263 |
dmu_objset_close(za[t].za_os); |
|
3264 |
} |
|
3265 |
} |
|
3266 |
||
3267 |
if (zopt_verbose >= 3) |
|
3268 |
show_pool_stats(spa); |
|
3269 |
||
3270 |
txg_wait_synced(spa_get_dsl(spa), 0); |
|
3271 |
||
3272 |
zs->zs_alloc = spa_get_alloc(spa); |
|
3273 |
zs->zs_space = spa_get_space(spa); |
|
3274 |
||
3275 |
/* |
|
5530 | 3276 |
* If we had out-of-space errors, destroy a random objset. |
789 | 3277 |
*/ |
3278 |
if (zs->zs_enospc_count != 0) { |
|
3279 |
(void) rw_rdlock(&ztest_shared->zs_name_lock); |
|
5530 | 3280 |
d = (int)ztest_random(zopt_datasets); |
3281 |
(void) snprintf(name, 100, "%s/%s_%d", pool, pool, d); |
|
789 | 3282 |
if (zopt_verbose >= 3) |
3283 |
(void) printf("Destroying %s to free up space\n", name); |
|
5530 | 3284 |
(void) dmu_objset_find(name, ztest_destroy_cb, &za[d], |
2417 | 3285 |
DS_FIND_SNAPSHOTS | DS_FIND_CHILDREN); |
789 | 3286 |
(void) rw_unlock(&ztest_shared->zs_name_lock); |
3287 |
} |
|
3288 |
||
1544 | 3289 |
txg_wait_synced(spa_get_dsl(spa), 0); |
789 | 3290 |
|
3291 |
/* |
|
3292 |
* Right before closing the pool, kick off a bunch of async I/O; |
|
3293 |
* spa_close() should wait for it to complete. |
|
3294 |
*/ |
|
3295 |
for (t = 1; t < 50; t++) |
|
3296 |
dmu_prefetch(spa->spa_meta_objset, t, 0, 1 << 15); |
|
3297 |
||
5329 | 3298 |
/* Shutdown the suspend monitor thread */ |
3299 |
zio_io_fail_shift = 0; |
|
3300 |
ztest_exiting = B_TRUE; |
|
3301 |
mutex_enter(&spa->spa_zio_lock); |
|
3302 |
cv_broadcast(&spa->spa_zio_cv); |
|
3303 |
mutex_exit(&spa->spa_zio_lock); |
|
3304 |
error = thr_join(tid, NULL, NULL); |
|
3305 |
if (error) |
|
3306 |
fatal(0, "thr_join(%d) = %d", tid, error); |
|
3307 |
||
5530 | 3308 |
umem_free(za, zopt_threads * sizeof (ztest_args_t)); |
3309 |
||
3310 |
spa_close(spa, FTAG); |
|
3311 |
||
789 | 3312 |
kernel_fini(); |
3313 |
} |
|
3314 |
||
3315 |
void |
|
3316 |
print_time(hrtime_t t, char *timebuf) |
|
3317 |
{ |
|
3318 |
hrtime_t s = t / NANOSEC; |
|
3319 |
hrtime_t m = s / 60; |
|
3320 |
hrtime_t h = m / 60; |
|
3321 |
hrtime_t d = h / 24; |
|
3322 |
||
3323 |
s -= m * 60; |
|
3324 |
m -= h * 60; |
|
3325 |
h -= d * 24; |
|
3326 |
||
3327 |
timebuf[0] = '\0'; |
|
3328 |
||
3329 |
if (d) |
|
3330 |
(void) sprintf(timebuf, |
|
3331 |
"%llud%02lluh%02llum%02llus", d, h, m, s); |
|
3332 |
else if (h) |
|
3333 |
(void) sprintf(timebuf, "%lluh%02llum%02llus", h, m, s); |
|
3334 |
else if (m) |
|
3335 |
(void) sprintf(timebuf, "%llum%02llus", m, s); |
|
3336 |
else |
|
3337 |
(void) sprintf(timebuf, "%llus", s); |
|
3338 |
} |
|
3339 |
||
3340 |
/* |
|
3341 |
* Create a storage pool with the given name and initial vdev size. |
|
3342 |
* Then create the specified number of datasets in the pool. |
|
3343 |
*/ |
|
3344 |
static void |
|
3345 |
ztest_init(char *pool) |
|
3346 |
{ |
|
3347 |
spa_t *spa; |
|
3348 |
int error; |
|
3349 |
nvlist_t *nvroot; |
|
3350 |
||
3351 |
kernel_init(FREAD | FWRITE); |
|
3352 |
||
3353 |
/* |
|
3354 |
* Create the storage pool. |
|
3355 |
*/ |
|
3356 |
(void) spa_destroy(pool); |
|
3357 |
ztest_shared->zs_vdev_primaries = 0; |
|
4527 | 3358 |
nvroot = make_vdev_root(zopt_vdev_size, 0, zopt_raidz, zopt_mirrors, 1); |
4715
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4543
diff
changeset
|
3359 |
error = spa_create(pool, nvroot, NULL, NULL); |
789 | 3360 |
nvlist_free(nvroot); |
3361 |
||
3362 |
if (error) |
|
3363 |
fatal(0, "spa_create() = %d", error); |
|
3364 |
error = spa_open(pool, &spa, FTAG); |
|
3365 |
if (error) |
|
3366 |
fatal(0, "spa_open() = %d", error); |
|
3367 |
||
3368 |
if (zopt_verbose >= 3) |
|
3369 |
show_pool_stats(spa); |
|
3370 |
||
3371 |
spa_close(spa, FTAG); |
|
3372 |
||
3373 |
kernel_fini(); |
|
3374 |
} |
|
3375 |
||
3376 |
int |
|
3377 |
main(int argc, char **argv) |
|
3378 |
{ |
|
3379 |
int kills = 0; |
|
3380 |
int iters = 0; |
|
3381 |
int i, f; |
|
3382 |
ztest_shared_t *zs; |
|
3383 |
ztest_info_t *zi; |
|
3384 |
char timebuf[100]; |
|
3385 |
char numbuf[6]; |
|
3386 |
||
3387 |
(void) setvbuf(stdout, NULL, _IOLBF, 0); |
|
3388 |
||
3389 |
/* Override location of zpool.cache */ |
|
3390 |
spa_config_dir = "/tmp"; |
|
3391 |
||
3392 |
ztest_random_fd = open("/dev/urandom", O_RDONLY); |
|
3393 |
||
3394 |
process_options(argc, argv); |
|
3395 |
||
3396 |
argc -= optind; |
|
3397 |
argv += optind; |
|
3398 |
||
3399 |
dprintf_setup(&argc, argv); |
|
3400 |
||
1544 | 3401 |
/* |
3402 |
* Blow away any existing copy of zpool.cache |
|
3403 |
*/ |
|
3404 |
if (zopt_init != 0) |
|
3405 |
(void) remove("/tmp/zpool.cache"); |
|
3406 |
||
789 | 3407 |
zs = ztest_shared = (void *)mmap(0, |
3408 |
P2ROUNDUP(sizeof (ztest_shared_t), getpagesize()), |
|
3409 |
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); |
|
3410 |
||
3411 |
if (zopt_verbose >= 1) { |
|
3412 |
(void) printf("%llu vdevs, %d datasets, %d threads," |
|
3413 |
" %llu seconds...\n", |
|
1732 | 3414 |
(u_longlong_t)zopt_vdevs, zopt_datasets, zopt_threads, |
789 | 3415 |
(u_longlong_t)zopt_time); |
3416 |
} |
|
3417 |
||
3418 |
/* |
|
3419 |
* Create and initialize our storage pool. |
|
3420 |
*/ |
|
3421 |
for (i = 1; i <= zopt_init; i++) { |
|
3422 |
bzero(zs, sizeof (ztest_shared_t)); |
|
3423 |
if (zopt_verbose >= 3 && zopt_init != 1) |
|
3424 |
(void) printf("ztest_init(), pass %d\n", i); |
|
3425 |
ztest_init(zopt_pool); |
|
3426 |
} |
|
3427 |
||
3428 |
/* |
|
3429 |
* Initialize the call targets for each function. |
|
3430 |
*/ |
|
3431 |
for (f = 0; f < ZTEST_FUNCS; f++) { |
|
3432 |
zi = &zs->zs_info[f]; |
|
3433 |
||
3434 |
*zi = ztest_info[f]; |
|
3435 |
||
3436 |
if (*zi->zi_interval == 0) |
|
3437 |
zi->zi_call_target = UINT64_MAX; |
|
3438 |
else |
|
3439 |
zi->zi_call_target = zopt_time / *zi->zi_interval; |
|
3440 |
} |
|
3441 |
||
3442 |
zs->zs_start_time = gethrtime(); |
|
3443 |
zs->zs_stop_time = zs->zs_start_time + zopt_time * NANOSEC; |
|
3444 |
||
3445 |
/* |
|
3446 |
* Run the tests in a loop. These tests include fault injection |
|
3447 |
* to verify that self-healing data works, and forced crashes |
|
3448 |
* to verify that we never lose on-disk consistency. |
|
3449 |
*/ |
|
3450 |
while (gethrtime() < zs->zs_stop_time) { |
|
3451 |
int status; |
|
3452 |
pid_t pid; |
|
3453 |
char *tmp; |
|
3454 |
||
3455 |
/* |
|
3456 |
* Initialize the workload counters for each function. |
|
3457 |
*/ |
|
3458 |
for (f = 0; f < ZTEST_FUNCS; f++) { |
|
3459 |
zi = &zs->zs_info[f]; |
|
3460 |
zi->zi_calls = 0; |
|
3461 |
zi->zi_call_time = 0; |
|
3462 |
} |
|
3463 |
||
3464 |
pid = fork(); |
|
3465 |
||
3466 |
if (pid == -1) |
|
3467 |
fatal(1, "fork failed"); |
|
3468 |
||
3469 |
if (pid == 0) { /* child */ |
|
3470 |
struct rlimit rl = { 1024, 1024 }; |
|
3471 |
(void) setrlimit(RLIMIT_NOFILE, &rl); |
|
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
1807
diff
changeset
|
3472 |
(void) enable_extended_FILE_stdio(-1, -1); |
789 | 3473 |
ztest_run(zopt_pool); |
3474 |
exit(0); |
|
3475 |
} |
|
3476 |
||
2856 | 3477 |
while (waitpid(pid, &status, 0) != pid) |
789 | 3478 |
continue; |
3479 |
||
3480 |
if (WIFEXITED(status)) { |
|
3481 |
if (WEXITSTATUS(status) != 0) { |
|
3482 |
(void) fprintf(stderr, |
|
3483 |
"child exited with code %d\n", |
|
3484 |
WEXITSTATUS(status)); |
|
3485 |
exit(2); |
|
3486 |
} |
|
2856 | 3487 |
} else if (WIFSIGNALED(status)) { |
789 | 3488 |
if (WTERMSIG(status) != SIGKILL) { |
3489 |
(void) fprintf(stderr, |
|
3490 |
"child died with signal %d\n", |
|
3491 |
WTERMSIG(status)); |
|
3492 |
exit(3); |
|
3493 |
} |
|
3494 |
kills++; |
|
2856 | 3495 |
} else { |
3496 |
(void) fprintf(stderr, "something strange happened " |
|
3497 |
"to child\n"); |
|
3498 |
exit(4); |
|
789 | 3499 |
} |
3500 |
||
3501 |
iters++; |
|
3502 |
||
3503 |
if (zopt_verbose >= 1) { |
|
3504 |
hrtime_t now = gethrtime(); |
|
3505 |
||
3506 |
now = MIN(now, zs->zs_stop_time); |
|
3507 |
print_time(zs->zs_stop_time - now, timebuf); |
|
3508 |
nicenum(zs->zs_space, numbuf); |
|
3509 |
||
3510 |
(void) printf("Pass %3d, %8s, %3llu ENOSPC, " |
|
3511 |
"%4.1f%% of %5s used, %3.0f%% done, %8s to go\n", |
|
3512 |
iters, |
|
3513 |
WIFEXITED(status) ? "Complete" : "SIGKILL", |
|
3514 |
(u_longlong_t)zs->zs_enospc_count, |
|
3515 |
100.0 * zs->zs_alloc / zs->zs_space, |
|
3516 |
numbuf, |
|
3517 |
100.0 * (now - zs->zs_start_time) / |
|
3518 |
(zopt_time * NANOSEC), timebuf); |
|
3519 |
} |
|
3520 |
||
3521 |
if (zopt_verbose >= 2) { |
|
3522 |
(void) printf("\nWorkload summary:\n\n"); |
|
3523 |
(void) printf("%7s %9s %s\n", |
|
3524 |
"Calls", "Time", "Function"); |
|
3525 |
(void) printf("%7s %9s %s\n", |
|
3526 |
"-----", "----", "--------"); |
|
3527 |
for (f = 0; f < ZTEST_FUNCS; f++) { |
|
3528 |
Dl_info dli; |
|
3529 |
||
3530 |
zi = &zs->zs_info[f]; |
|
3531 |
print_time(zi->zi_call_time, timebuf); |
|
3532 |
(void) dladdr((void *)zi->zi_func, &dli); |
|
3533 |
(void) printf("%7llu %9s %s\n", |
|
3534 |
(u_longlong_t)zi->zi_calls, timebuf, |
|
3535 |
dli.dli_sname); |
|
3536 |
} |
|
3537 |
(void) printf("\n"); |
|
3538 |
} |
|
3539 |
||
3540 |
/* |
|
3541 |
* It's possible that we killed a child during a rename test, in |
|
3542 |
* which case we'll have a 'ztest_tmp' pool lying around instead |
|
3543 |
* of 'ztest'. Do a blind rename in case this happened. |
|
3544 |
*/ |
|
3545 |
tmp = umem_alloc(strlen(zopt_pool) + 5, UMEM_NOFAIL); |
|
3546 |
(void) strcpy(tmp, zopt_pool); |
|
3547 |
(void) strcat(tmp, "_tmp"); |
|
3548 |
kernel_init(FREAD | FWRITE); |
|
3549 |
(void) spa_rename(tmp, zopt_pool); |
|
3550 |
kernel_fini(); |
|
3551 |
umem_free(tmp, strlen(tmp) + 1); |
|
3552 |
} |
|
3553 |
||
3554 |
ztest_verify_blocks(zopt_pool); |
|
3555 |
||
3556 |
if (zopt_verbose >= 1) { |
|
3557 |
(void) printf("%d killed, %d completed, %.0f%% kill rate\n", |
|
3558 |
kills, iters - kills, (100.0 * kills) / MAX(1, iters)); |
|
3559 |
} |
|
3560 |
||
3561 |
return (0); |
|
3562 |
} |