-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix multiple zdb bugs #7099
Fix multiple zdb bugs #7099
Changes from all commits
6e5eb6d
5d95c95
9bafb76
a514714
14b919c
cdf8275
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3388,7 +3388,7 @@ dump_block_stats(spa_t *spa) | |
int flags = TRAVERSE_PRE | TRAVERSE_PREFETCH_METADATA | | ||
TRAVERSE_NO_DECRYPT | TRAVERSE_HARD; | ||
boolean_t leaks = B_FALSE; | ||
int e, c; | ||
int e, c, err; | ||
bp_embedded_type_t i; | ||
|
||
bzero(&zcb, sizeof (zcb)); | ||
|
@@ -3430,7 +3430,7 @@ dump_block_stats(spa_t *spa) | |
|
||
zcb.zcb_totalasize = metaslab_class_get_alloc(spa_normal_class(spa)); | ||
zcb.zcb_start = zcb.zcb_lastprint = gethrtime(); | ||
zcb.zcb_haderrors |= traverse_pool(spa, 0, flags, zdb_blkptr_cb, &zcb); | ||
err = traverse_pool(spa, 0, flags, zdb_blkptr_cb, &zcb); | ||
|
||
/* | ||
* If we've traversed the data blocks then we need to wait for those | ||
|
@@ -3446,6 +3446,12 @@ dump_block_stats(spa_t *spa) | |
} | ||
} | ||
|
||
/* | ||
* Done after zio_wait() since zcb_haderrors is modified in | ||
* zdb_blkptr_done() | ||
*/ | ||
zcb.zcb_haderrors |= err; | ||
|
||
if (zcb.zcb_haderrors) { | ||
(void) printf("\nError counts:\n\n"); | ||
(void) printf("\t%5s %s\n", "errno", "count"); | ||
|
@@ -3978,13 +3984,6 @@ zdb_vdev_lookup(vdev_t *vdev, const char *path) | |
return (NULL); | ||
} | ||
|
||
/* ARGSUSED */ | ||
static int | ||
random_get_pseudo_bytes_cb(void *buf, size_t len, void *unused) | ||
{ | ||
return (random_get_pseudo_bytes(buf, len)); | ||
} | ||
|
||
/* | ||
* Read a block from a pool and print it out. The syntax of the | ||
* block descriptor is: | ||
|
@@ -4154,17 +4153,8 @@ zdb_read_block(char *thing, spa_t *spa) | |
* every decompress function at every inflated blocksize. | ||
*/ | ||
enum zio_compress c; | ||
void *pbuf2 = umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL); | ||
void *lbuf2 = umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL); | ||
|
||
abd_copy_to_buf(pbuf2, pabd, psize); | ||
|
||
VERIFY0(abd_iterate_func(pabd, psize, SPA_MAXBLOCKSIZE - psize, | ||
random_get_pseudo_bytes_cb, NULL)); | ||
|
||
VERIFY0(random_get_pseudo_bytes((uint8_t *)pbuf2 + psize, | ||
SPA_MAXBLOCKSIZE - psize)); | ||
|
||
/* | ||
* XXX - On the one hand, with SPA_MAXBLOCKSIZE at 16MB, | ||
* this could take a while and we should let the user know | ||
|
@@ -4174,25 +4164,39 @@ zdb_read_block(char *thing, spa_t *spa) | |
for (lsize = psize + SPA_MINBLOCKSIZE; | ||
lsize <= SPA_MAXBLOCKSIZE; lsize += SPA_MINBLOCKSIZE) { | ||
for (c = 0; c < ZIO_COMPRESS_FUNCTIONS; c++) { | ||
/* | ||
* ZLE can easily decompress non zle stream. | ||
* So have an option to disable it. | ||
*/ | ||
if (c == ZIO_COMPRESS_ZLE && | ||
getenv("ZDB_NO_ZLE")) | ||
continue; | ||
|
||
(void) fprintf(stderr, | ||
"Trying %05llx -> %05llx (%s)\n", | ||
(u_longlong_t)psize, (u_longlong_t)lsize, | ||
zio_compress_table[c].ci_name); | ||
|
||
/* | ||
* We randomize lbuf2, and decompress to both | ||
* lbuf and lbuf2. This way, we will know if | ||
* decompression fill exactly to lsize. | ||
*/ | ||
VERIFY0(random_get_pseudo_bytes(lbuf2, lsize)); | ||
|
||
if (zio_decompress_data(c, pabd, | ||
lbuf, psize, lsize) == 0 && | ||
zio_decompress_data_buf(c, pbuf2, | ||
zio_decompress_data(c, pabd, | ||
lbuf2, psize, lsize) == 0 && | ||
bcmp(lbuf, lbuf2, lsize) == 0) | ||
break; | ||
} | ||
if (c != ZIO_COMPRESS_FUNCTIONS) | ||
break; | ||
} | ||
|
||
umem_free(pbuf2, SPA_MAXBLOCKSIZE); | ||
umem_free(lbuf2, SPA_MAXBLOCKSIZE); | ||
|
||
if (lsize <= psize) { | ||
if (lsize > SPA_MAXBLOCKSIZE) { | ||
(void) printf("Decompress of %s failed\n", thing); | ||
goto out; | ||
} | ||
|
@@ -4231,9 +4235,11 @@ zdb_embedded_block(char *thing) | |
{ | ||
blkptr_t bp; | ||
unsigned long long *words = (void *)&bp; | ||
char buf[SPA_MAXBLOCKSIZE]; | ||
char *buf; | ||
int err; | ||
|
||
buf = umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL); | ||
|
||
bzero(&bp, sizeof (bp)); | ||
err = sscanf(thing, "%llx:%llx:%llx:%llx:%llx:%llx:%llx:%llx:" | ||
"%llx:%llx:%llx:%llx:%llx:%llx:%llx:%llx", | ||
|
@@ -4252,6 +4258,7 @@ zdb_embedded_block(char *thing) | |
exit(1); | ||
} | ||
zdb_dump_block_raw(buf, BPE_GET_LSIZE(&bp), 0); | ||
umem_free(buf, SPA_MAXBLOCKSIZE); | ||
} | ||
|
||
int | ||
|
@@ -4266,7 +4273,7 @@ main(int argc, char **argv) | |
int error = 0; | ||
char **searchdirs = NULL; | ||
int nsearch = 0; | ||
char *target; | ||
char *target, *target_pool; | ||
nvlist_t *policy = NULL; | ||
uint64_t max_txg = UINT64_MAX; | ||
int flags = ZFS_IMPORT_MISSING_LOG; | ||
|
@@ -4469,6 +4476,20 @@ main(int argc, char **argv) | |
error = 0; | ||
target = argv[0]; | ||
|
||
if (strpbrk(target, "/@") != NULL) { | ||
size_t targetlen; | ||
|
||
target_pool = strdup(target); | ||
*strpbrk(target_pool, "/@") = '\0'; | ||
|
||
target_is_spa = B_FALSE; | ||
targetlen = strlen(target); | ||
if (targetlen && target[targetlen - 1] == '/') | ||
target[targetlen - 1] = '\0'; | ||
} else { | ||
target_pool = target; | ||
} | ||
|
||
if (dump_opt['e']) { | ||
importargs_t args = { 0 }; | ||
nvlist_t *cfg = NULL; | ||
|
@@ -4477,8 +4498,10 @@ main(int argc, char **argv) | |
args.path = searchdirs; | ||
args.can_be_active = B_TRUE; | ||
|
||
error = zpool_tryimport(g_zfs, target, &cfg, &args); | ||
error = zpool_tryimport(g_zfs, target_pool, &cfg, &args); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there any way we can use the error message set by 4568 if (error)
4569 fatal("can't open '%s': %s", target, strerror(error)); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's leave this for later. |
||
|
||
if (error == 0) { | ||
|
||
if (nvlist_add_nvlist(cfg, | ||
ZPOOL_REWIND_POLICY, policy) != 0) { | ||
fatal("can't open '%s': %s", | ||
|
@@ -4493,19 +4516,13 @@ main(int argc, char **argv) | |
(void) printf("\nConfiguration for import:\n"); | ||
dump_nvlist(cfg, 8); | ||
} | ||
error = spa_import(target, cfg, NULL, | ||
error = spa_import(target_pool, cfg, NULL, | ||
flags | ZFS_IMPORT_SKIP_MMP); | ||
} | ||
} | ||
|
||
if (strpbrk(target, "/@") != NULL) { | ||
size_t targetlen; | ||
|
||
target_is_spa = B_FALSE; | ||
targetlen = strlen(target); | ||
if (targetlen && target[targetlen - 1] == '/') | ||
target[targetlen - 1] = '\0'; | ||
} | ||
if (target_pool != target) | ||
free(target_pool); | ||
|
||
if (error == 0) { | ||
if (target_is_spa || dump_opt['R']) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -74,10 +74,14 @@ zle_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len, int n) | |
while (src < s_end && dst < d_end) { | ||
int len = 1 + *src++; | ||
if (len <= n) { | ||
if (src + len > s_end || dst + len > d_end) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Check my math on this, but shouldn't this be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Assuming |
||
return (-1); | ||
while (len-- != 0) | ||
*dst++ = *src++; | ||
} else { | ||
len -= n; | ||
if (dst + len > d_end) | ||
return (-1); | ||
while (len-- != 0) | ||
*dst++ = 0; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
#!/bin/ksh | ||
|
||
# | ||
# This file and its contents are supplied under the terms of the | ||
# Common Development and Distribution License ("CDDL"), version 1.0. | ||
# You may only use this file in accordance with the terms of version | ||
# 1.0 of the CDDL. | ||
# | ||
# A full copy of the text of the CDDL should have accompanied this | ||
# source. A copy of the CDDL is also available via the Internet at | ||
# http://www.illumos.org/license/CDDL. | ||
# | ||
|
||
# | ||
# Copyright (c) 2018 by Nutanix. All rights reserved. | ||
# | ||
|
||
. $STF_SUITE/include/libtest.shlib | ||
|
||
# | ||
# Description: | ||
# zdb -d will work on imported/exported pool with pool/dataset argument | ||
# | ||
# Strategy: | ||
# 1. Create a pool | ||
# 2. Run zdb -d with pool and dataset arguments. | ||
# 3. Export the pool | ||
# 4. Run zdb -ed with pool and dataset arguments. | ||
# | ||
|
||
function cleanup | ||
{ | ||
datasetexists $TESTPOOL && destroy_pool $TESTPOOL | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just copy this from other zdb tests for consistency. |
||
for DISK in $DISKS; do | ||
zpool labelclear -f $DEV_RDSKDIR/$DISK | ||
done | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: need to destroy There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why? The pool is already destroyed. |
||
|
||
log_assert "Verify zdb -d works on imported/exported pool with pool/dataset argument" | ||
log_onexit cleanup | ||
|
||
verify_runnable "global" | ||
verify_disk_count "$DISKS" 2 | ||
|
||
default_mirror_setup_noexit $DISKS | ||
log_must zfs snap $TESTPOOL/$TESTFS@snap | ||
|
||
log_must zdb -d $TESTPOOL | ||
log_must zdb -d $TESTPOOL/ | ||
log_must zdb -d $TESTPOOL/$TESTFS | ||
log_must zdb -d $TESTPOOL/$TESTFS@snap | ||
|
||
log_must zpool export $TESTPOOL | ||
|
||
log_must zdb -ed $TESTPOOL | ||
log_must zdb -ed $TESTPOOL/ | ||
log_must zdb -ed $TESTPOOL/$TESTFS | ||
log_must zdb -ed $TESTPOOL/$TESTFS@snap | ||
|
||
log_must zpool import $TESTPOOL | ||
|
||
cleanup | ||
|
||
log_pass "zdb -d works on imported/exported pool with pool/dataset argument" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a little concerning we didn't have any test coverage for this. What do you think about adding a very basic testcase to
tests/zfs-tests/tests/functional/cli_root/zdb/
which covers passing the pool/dataset for imported/exported pools.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do.