Fix problem with zdb -d
zdb -d <pool>/<objset ID> does not work when other command line arguments are included i.e. zdb -U <cachefile> -d <pool>/<objset ID> This change fixes the command line parsing to handle this situation. Also fix issue where zdb -r <dataset> <file> does not handle the root <dataset> of the pool. Introduce -N option to force <objset ID> to be interpreted as a numeric objsetID. Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Rich Ercolani <rincebrain@gmail.com> Reviewed-by: Tony Nguyen <tony.nguyen@delphix.com> Signed-off-by: Paul Zuchowski <pzuchowski@datto.com> Closes #12845 Closes #12944
This commit is contained in:
parent
b06aff105c
commit
fcbddc7f7c
111
cmd/zdb/zdb.c
111
cmd/zdb/zdb.c
|
@ -8272,6 +8272,23 @@ zdb_embedded_block(char *thing)
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check for valid hex or decimal numeric string */
|
||||||
|
static boolean_t
|
||||||
|
zdb_numeric(char *str)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (strlen(str) == 0)
|
||||||
|
return (B_FALSE);
|
||||||
|
if (strncmp(str, "0x", 2) == 0 || strncmp(str, "0X", 2) == 0)
|
||||||
|
i = 2;
|
||||||
|
for (; i < strlen(str); i++) {
|
||||||
|
if (!isxdigit(str[i]))
|
||||||
|
return (B_FALSE);
|
||||||
|
}
|
||||||
|
return (B_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
@ -8317,7 +8334,7 @@ main(int argc, char **argv)
|
||||||
zfs_btree_verify_intensity = 3;
|
zfs_btree_verify_intensity = 3;
|
||||||
|
|
||||||
while ((c = getopt(argc, argv,
|
while ((c = getopt(argc, argv,
|
||||||
"AbcCdDeEFGhiI:klLmMo:Op:PqrRsSt:uU:vVx:XYyZ")) != -1) {
|
"AbcCdDeEFGhiI:klLmMNo:Op:PqrRsSt:uU:vVx:XYyZ")) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'b':
|
case 'b':
|
||||||
case 'c':
|
case 'c':
|
||||||
|
@ -8331,6 +8348,7 @@ main(int argc, char **argv)
|
||||||
case 'l':
|
case 'l':
|
||||||
case 'm':
|
case 'm':
|
||||||
case 'M':
|
case 'M':
|
||||||
|
case 'N':
|
||||||
case 'O':
|
case 'O':
|
||||||
case 'r':
|
case 'r':
|
||||||
case 'R':
|
case 'R':
|
||||||
|
@ -8422,31 +8440,6 @@ main(int argc, char **argv)
|
||||||
(void) fprintf(stderr, "-p option requires use of -e\n");
|
(void) fprintf(stderr, "-p option requires use of -e\n");
|
||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
if (dump_opt['d'] || dump_opt['r']) {
|
|
||||||
/* <pool>[/<dataset | objset id> is accepted */
|
|
||||||
if (argv[2] && (objset_str = strchr(argv[2], '/')) != NULL &&
|
|
||||||
objset_str++ != NULL) {
|
|
||||||
char *endptr;
|
|
||||||
errno = 0;
|
|
||||||
objset_id = strtoull(objset_str, &endptr, 0);
|
|
||||||
/* dataset 0 is the same as opening the pool */
|
|
||||||
if (errno == 0 && endptr != objset_str &&
|
|
||||||
objset_id != 0) {
|
|
||||||
target_is_spa = B_FALSE;
|
|
||||||
dataset_lookup = B_TRUE;
|
|
||||||
} else if (objset_id != 0) {
|
|
||||||
printf("failed to open objset %s "
|
|
||||||
"%llu %s", objset_str,
|
|
||||||
(u_longlong_t)objset_id,
|
|
||||||
strerror(errno));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
/* normal dataset name not an objset ID */
|
|
||||||
if (endptr == objset_str) {
|
|
||||||
objset_id = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(_LP64)
|
#if defined(_LP64)
|
||||||
/*
|
/*
|
||||||
|
@ -8486,7 +8479,7 @@ main(int argc, char **argv)
|
||||||
verbose = MAX(verbose, 1);
|
verbose = MAX(verbose, 1);
|
||||||
|
|
||||||
for (c = 0; c < 256; c++) {
|
for (c = 0; c < 256; c++) {
|
||||||
if (dump_all && strchr("AeEFklLOPrRSXy", c) == NULL)
|
if (dump_all && strchr("AeEFklLNOPrRSXy", c) == NULL)
|
||||||
dump_opt[c] = 1;
|
dump_opt[c] = 1;
|
||||||
if (dump_opt[c])
|
if (dump_opt[c])
|
||||||
dump_opt[c] += verbose;
|
dump_opt[c] += verbose;
|
||||||
|
@ -8525,6 +8518,7 @@ main(int argc, char **argv)
|
||||||
return (dump_path(argv[0], argv[1], NULL));
|
return (dump_path(argv[0], argv[1], NULL));
|
||||||
}
|
}
|
||||||
if (dump_opt['r']) {
|
if (dump_opt['r']) {
|
||||||
|
target_is_spa = B_FALSE;
|
||||||
if (argc != 3)
|
if (argc != 3)
|
||||||
usage();
|
usage();
|
||||||
dump_opt['v'] = verbose;
|
dump_opt['v'] = verbose;
|
||||||
|
@ -8535,6 +8529,10 @@ main(int argc, char **argv)
|
||||||
rewind = ZPOOL_DO_REWIND |
|
rewind = ZPOOL_DO_REWIND |
|
||||||
(dump_opt['X'] ? ZPOOL_EXTREME_REWIND : 0);
|
(dump_opt['X'] ? ZPOOL_EXTREME_REWIND : 0);
|
||||||
|
|
||||||
|
/* -N implies -d */
|
||||||
|
if (dump_opt['N'] && dump_opt['d'] == 0)
|
||||||
|
dump_opt['d'] = dump_opt['N'];
|
||||||
|
|
||||||
if (nvlist_alloc(&policy, NV_UNIQUE_NAME_TYPE, 0) != 0 ||
|
if (nvlist_alloc(&policy, NV_UNIQUE_NAME_TYPE, 0) != 0 ||
|
||||||
nvlist_add_uint64(policy, ZPOOL_LOAD_REQUEST_TXG, max_txg) != 0 ||
|
nvlist_add_uint64(policy, ZPOOL_LOAD_REQUEST_TXG, max_txg) != 0 ||
|
||||||
nvlist_add_uint32(policy, ZPOOL_LOAD_REWIND_POLICY, rewind) != 0)
|
nvlist_add_uint32(policy, ZPOOL_LOAD_REWIND_POLICY, rewind) != 0)
|
||||||
|
@ -8553,6 +8551,34 @@ main(int argc, char **argv)
|
||||||
targetlen = strlen(target);
|
targetlen = strlen(target);
|
||||||
if (targetlen && target[targetlen - 1] == '/')
|
if (targetlen && target[targetlen - 1] == '/')
|
||||||
target[targetlen - 1] = '\0';
|
target[targetlen - 1] = '\0';
|
||||||
|
/*
|
||||||
|
* See if an objset ID was supplied (-d <pool>/<objset ID>).
|
||||||
|
* To disambiguate tank/100, consider the 100 as objsetID
|
||||||
|
* if -N was given, otherwise 100 is an objsetID iff
|
||||||
|
* tank/100 as a named dataset fails on lookup.
|
||||||
|
*/
|
||||||
|
objset_str = strchr(target, '/');
|
||||||
|
if (objset_str && strlen(objset_str) > 1 &&
|
||||||
|
zdb_numeric(objset_str + 1)) {
|
||||||
|
char *endptr;
|
||||||
|
errno = 0;
|
||||||
|
objset_str++;
|
||||||
|
objset_id = strtoull(objset_str, &endptr, 0);
|
||||||
|
/* dataset 0 is the same as opening the pool */
|
||||||
|
if (errno == 0 && endptr != objset_str &&
|
||||||
|
objset_id != 0) {
|
||||||
|
if (dump_opt['N'])
|
||||||
|
dataset_lookup = B_TRUE;
|
||||||
|
}
|
||||||
|
/* normal dataset name not an objset ID */
|
||||||
|
if (endptr == objset_str) {
|
||||||
|
objset_id = -1;
|
||||||
|
}
|
||||||
|
} else if (objset_str && !zdb_numeric(objset_str + 1) &&
|
||||||
|
dump_opt['N']) {
|
||||||
|
printf("Supply a numeric objset ID with -N\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
target_pool = target;
|
target_pool = target;
|
||||||
}
|
}
|
||||||
|
@ -8670,13 +8696,27 @@ main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
return (error);
|
return (error);
|
||||||
} else {
|
} else {
|
||||||
|
target_pool = strdup(target);
|
||||||
|
if (strpbrk(target, "/@") != NULL)
|
||||||
|
*strpbrk(target_pool, "/@") = '\0';
|
||||||
|
|
||||||
zdb_set_skip_mmp(target);
|
zdb_set_skip_mmp(target);
|
||||||
|
/*
|
||||||
|
* If -N was supplied, the user has indicated that
|
||||||
|
* zdb -d <pool>/<objsetID> is in effect. Otherwise
|
||||||
|
* we first assume that the dataset string is the
|
||||||
|
* dataset name. If dmu_objset_hold fails with the
|
||||||
|
* dataset string, and we have an objset_id, retry the
|
||||||
|
* lookup with the objsetID.
|
||||||
|
*/
|
||||||
|
boolean_t retry = B_TRUE;
|
||||||
|
retry_lookup:
|
||||||
if (dataset_lookup == B_TRUE) {
|
if (dataset_lookup == B_TRUE) {
|
||||||
/*
|
/*
|
||||||
* Use the supplied id to get the name
|
* Use the supplied id to get the name
|
||||||
* for open_objset.
|
* for open_objset.
|
||||||
*/
|
*/
|
||||||
error = spa_open(target, &spa, FTAG);
|
error = spa_open(target_pool, &spa, FTAG);
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
error = name_from_objset_id(spa,
|
error = name_from_objset_id(spa,
|
||||||
objset_id, dsname);
|
objset_id, dsname);
|
||||||
|
@ -8685,10 +8725,23 @@ main(int argc, char **argv)
|
||||||
target = dsname;
|
target = dsname;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (error == 0)
|
if (error == 0) {
|
||||||
|
if (objset_id > 0 && retry) {
|
||||||
|
int err = dmu_objset_hold(target, FTAG,
|
||||||
|
&os);
|
||||||
|
if (err) {
|
||||||
|
dataset_lookup = B_TRUE;
|
||||||
|
retry = B_FALSE;
|
||||||
|
goto retry_lookup;
|
||||||
|
} else {
|
||||||
|
dmu_objset_rele(os, FTAG);
|
||||||
|
}
|
||||||
|
}
|
||||||
error = open_objset(target, FTAG, &os);
|
error = open_objset(target, FTAG, &os);
|
||||||
|
}
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
spa = dmu_objset_spa(os);
|
spa = dmu_objset_spa(os);
|
||||||
|
free(target_pool);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nvlist_free(policy);
|
nvlist_free(policy);
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
.Nd display ZFS storage pool debugging and consistency information
|
.Nd display ZFS storage pool debugging and consistency information
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm
|
.Nm
|
||||||
.Op Fl AbcdDFGhikLMPsvXYy
|
.Op Fl AbcdDFGhikLMNPsvXYy
|
||||||
.Op Fl e Oo Fl V Oc Oo Fl p Ar path Oc Ns …
|
.Op Fl e Oo Fl V Oc Oo Fl p Ar path Oc Ns …
|
||||||
.Op Fl I Ar inflight I/Os
|
.Op Fl I Ar inflight I/Os
|
||||||
.Oo Fl o Ar var Ns = Ns Ar value Oc Ns …
|
.Oo Fl o Ar var Ns = Ns Ar value Oc Ns …
|
||||||
|
@ -137,6 +137,14 @@ also display the configuration that would be used were the pool to be imported.
|
||||||
Display information about datasets.
|
Display information about datasets.
|
||||||
Specified once, displays basic dataset information: ID, create transaction,
|
Specified once, displays basic dataset information: ID, create transaction,
|
||||||
size, and object count.
|
size, and object count.
|
||||||
|
See
|
||||||
|
.Fl N
|
||||||
|
for determining if
|
||||||
|
.Op Ar poolname Ns Op / Ns Ar dataset | objset ID
|
||||||
|
is to use the specified
|
||||||
|
.Op Ar dataset | objset ID
|
||||||
|
as a string (dataset name) or a number (objset ID) when
|
||||||
|
datasets have numeric names.
|
||||||
.Pp
|
.Pp
|
||||||
If specified multiple times provides greater and greater verbosity.
|
If specified multiple times provides greater and greater verbosity.
|
||||||
.Pp
|
.Pp
|
||||||
|
@ -272,6 +280,14 @@ Also display information about the maximum contiguous free space and the
|
||||||
percentage of free space in each space map.
|
percentage of free space in each space map.
|
||||||
.It Fl MMM
|
.It Fl MMM
|
||||||
Display every spacemap record.
|
Display every spacemap record.
|
||||||
|
.It Fl N
|
||||||
|
Same as
|
||||||
|
.Fl d
|
||||||
|
but force zdb to interpret the
|
||||||
|
.Op Ar dataset | objset ID
|
||||||
|
in
|
||||||
|
.Op Ar poolname Ns Op / Ns Ar dataset | objset ID
|
||||||
|
as a numeric objset ID.
|
||||||
.It Fl O Ar dataset path
|
.It Fl O Ar dataset path
|
||||||
Look up the specified
|
Look up the specified
|
||||||
.Ar path
|
.Ar path
|
||||||
|
|
|
@ -58,7 +58,7 @@ set -A args "create" "add" "destroy" "import fakepool" \
|
||||||
"setvprop" "blah blah" "-%" "--?" "-*" "-=" \
|
"setvprop" "blah blah" "-%" "--?" "-*" "-=" \
|
||||||
"-a" "-f" "-g" "-j" "-n" "-o" "-p" "-p /tmp" \
|
"-a" "-f" "-g" "-j" "-n" "-o" "-p" "-p /tmp" \
|
||||||
"-t" "-w" "-z" "-E" "-H" "-I" "-J" "-K" \
|
"-t" "-w" "-z" "-E" "-H" "-I" "-J" "-K" \
|
||||||
"-N" "-Q" "-R" "-T" "-W"
|
"-Q" "-R" "-T" "-W"
|
||||||
|
|
||||||
log_assert "Execute zdb using invalid parameters."
|
log_assert "Execute zdb using invalid parameters."
|
||||||
|
|
||||||
|
|
|
@ -30,10 +30,16 @@
|
||||||
# 6. Confirm names
|
# 6. Confirm names
|
||||||
# 7. Run zdb -dddddd pool/objsetID objectID (hex)
|
# 7. Run zdb -dddddd pool/objsetID objectID (hex)
|
||||||
# 8. Confirm names
|
# 8. Confirm names
|
||||||
# 9. Obtain objsetID from /proc/spl/kstat/zfs/testpool/obset-0x<ID>
|
# 9. Repeat with zdb -NNNNNN pool/objsetID objectID
|
||||||
|
# 10. Obtain objsetID from /proc/spl/kstat/zfs/testpool/obset-0x<ID>
|
||||||
# (linux only)
|
# (linux only)
|
||||||
# 10. Run zdb -dddddd pool/objsetID (hex)
|
# 11. Run zdb -dddddd pool/objsetID (hex)
|
||||||
# 11. Match name from zdb against proc entry
|
# 12. Match name from zdb against proc entry
|
||||||
|
# 13. Create dataset with hex numeric name
|
||||||
|
# 14. Create dataset with decimal numeric name
|
||||||
|
# 15. zdb -d for numeric datasets succeeds
|
||||||
|
# 16. zdb -N for numeric datasets fails
|
||||||
|
# 17. zdb -dN for numeric datasets fails
|
||||||
#
|
#
|
||||||
|
|
||||||
function cleanup
|
function cleanup
|
||||||
|
@ -78,6 +84,17 @@ do
|
||||||
(( $? != 0 )) && log_fail \
|
(( $? != 0 )) && log_fail \
|
||||||
"zdb -dddddd $TESTPOOL/$id $obj failed $reason"
|
"zdb -dddddd $TESTPOOL/$id $obj failed $reason"
|
||||||
obj=$(printf "0x%X" $obj)
|
obj=$(printf "0x%X" $obj)
|
||||||
|
|
||||||
|
log_note "zdb -NNNNNN $TESTPOOL/$id $obj"
|
||||||
|
output=$(zdb -NNNNNN $TESTPOOL/$id $obj)
|
||||||
|
reason="($TESTPOOL/$TESTFS not in zdb output)"
|
||||||
|
echo $output |grep "$TESTPOOL/$TESTFS" > /dev/null
|
||||||
|
(( $? != 0 )) && log_fail \
|
||||||
|
"zdb -NNNNNN $TESTPOOL/$id $obj failed $reason"
|
||||||
|
reason="(file1 not in zdb output)"
|
||||||
|
echo $output |grep "file1" > /dev/null
|
||||||
|
(( $? != 0 )) && log_fail \
|
||||||
|
"zdb -NNNNNN $TESTPOOL/$id $obj failed $reason"
|
||||||
done
|
done
|
||||||
|
|
||||||
if is_linux; then
|
if is_linux; then
|
||||||
|
@ -94,4 +111,23 @@ if is_linux; then
|
||||||
"zdb -dddddd $TESTPOOL/$objset_hex failed $reason"
|
"zdb -dddddd $TESTPOOL/$objset_hex failed $reason"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
log_must zfs create $TESTPOOL/0x400
|
||||||
|
log_must zfs create $TESTPOOL/100
|
||||||
|
output=$(zdb -d $TESTPOOL/0x400)
|
||||||
|
reason="($TESTPOOL/0x400 not in zdb output)"
|
||||||
|
echo $output |grep "$TESTPOOL/0x400" > /dev/null
|
||||||
|
(( $? != 0 )) && log_fail \
|
||||||
|
"zdb -d $TESTPOOL/0x400 failed $reason"
|
||||||
|
output=$(zdb -d $TESTPOOL/100)
|
||||||
|
reason="($TESTPOOL/100 not in zdb output)"
|
||||||
|
echo $output |grep "$TESTPOOL/100" > /dev/null
|
||||||
|
(( $? != 0 )) && log_fail \
|
||||||
|
"zdb -d $TESTPOOL/100 failed $reason"
|
||||||
|
|
||||||
|
# force numeric interpretation, should fail
|
||||||
|
log_mustnot zdb -N $TESTPOOL/0x400
|
||||||
|
log_mustnot zdb -N $TESTPOOL/100
|
||||||
|
log_mustnot zdb -Nd $TESTPOOL/0x400
|
||||||
|
log_mustnot zdb -Nd $TESTPOOL/100
|
||||||
|
|
||||||
log_pass "zdb -d <pool>/<objset ID> generates the correct names."
|
log_pass "zdb -d <pool>/<objset ID> generates the correct names."
|
||||||
|
|
Loading…
Reference in New Issue