mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-26 19:19:32 +03:00
Fix zdb -R with 'b' flag
zdb -R :b fails due to the indirect block being compressed, and the 'b' and 'd' flag not working in tandem when specified. Fix the flag parsing code and create a zfs test for zdb -R block display. Also fix the zio flags where the dotted notation for the vdev portion of DVA (i.e. 0.0:offset:length) fails. Reviewed-by: Ryan Moeller <ryan@iXsystems.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Paul Zuchowski <pzuchowski@datto.com> Closes #9640 Closes #9729
This commit is contained in:
parent
dda702fd16
commit
bc67cba7c0
387
cmd/zdb/zdb.c
387
cmd/zdb/zdb.c
@ -6410,6 +6410,18 @@ dump_zpool(spa_t *spa)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ZDB_FLAG_CHECKSUM 0x0001
|
||||||
|
#define ZDB_FLAG_DECOMPRESS 0x0002
|
||||||
|
#define ZDB_FLAG_BSWAP 0x0004
|
||||||
|
#define ZDB_FLAG_GBH 0x0008
|
||||||
|
#define ZDB_FLAG_INDIRECT 0x0010
|
||||||
|
#define ZDB_FLAG_RAW 0x0020
|
||||||
|
#define ZDB_FLAG_PRINT_BLKPTR 0x0040
|
||||||
|
#define ZDB_FLAG_VERBOSE 0x0080
|
||||||
|
|
||||||
|
static int flagbits[256];
|
||||||
|
static char flagbitstr[16];
|
||||||
|
|
||||||
static void
|
static void
|
||||||
zdb_print_blkptr(blkptr_t *bp, int flags)
|
zdb_print_blkptr(blkptr_t *bp, int flags)
|
||||||
{
|
{
|
||||||
@ -6576,162 +6588,11 @@ zdb_parse_block_sizes(char *sizes, uint64_t *lsize, uint64_t *psize)
|
|||||||
|
|
||||||
#define ZIO_COMPRESS_MASK(alg) (1ULL << (ZIO_COMPRESS_##alg))
|
#define ZIO_COMPRESS_MASK(alg) (1ULL << (ZIO_COMPRESS_##alg))
|
||||||
|
|
||||||
/*
|
static boolean_t
|
||||||
* Read a block from a pool and print it out. The syntax of the
|
zdb_decompress_block(abd_t *pabd, void *buf, void *lbuf, uint64_t lsize,
|
||||||
* block descriptor is:
|
uint64_t psize, int flags)
|
||||||
*
|
|
||||||
* pool:vdev_specifier:offset:[lsize/]psize[:flags]
|
|
||||||
*
|
|
||||||
* pool - The name of the pool you wish to read from
|
|
||||||
* vdev_specifier - Which vdev (see comment for zdb_vdev_lookup)
|
|
||||||
* offset - offset, in hex, in bytes
|
|
||||||
* size - Amount of data to read, in hex, in bytes
|
|
||||||
* flags - A string of characters specifying options
|
|
||||||
* b: Decode a blkptr at given offset within block
|
|
||||||
* c: Calculate and display checksums
|
|
||||||
* d: Decompress data before dumping
|
|
||||||
* e: Byteswap data before dumping
|
|
||||||
* g: Display data as a gang block header
|
|
||||||
* i: Display as an indirect block
|
|
||||||
* r: Dump raw data to stdout
|
|
||||||
* v: Verbose
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
zdb_read_block(char *thing, spa_t *spa)
|
|
||||||
{
|
{
|
||||||
blkptr_t blk, *bp = &blk;
|
boolean_t exceeded = B_FALSE;
|
||||||
dva_t *dva = bp->blk_dva;
|
|
||||||
int flags = 0;
|
|
||||||
uint64_t offset = 0, psize = 0, lsize = 0, blkptr_offset = 0;
|
|
||||||
zio_t *zio;
|
|
||||||
vdev_t *vd;
|
|
||||||
abd_t *pabd;
|
|
||||||
void *lbuf, *buf;
|
|
||||||
char *s, *p, *dup, *vdev, *flagstr, *sizes;
|
|
||||||
int i, error;
|
|
||||||
boolean_t borrowed = B_FALSE;
|
|
||||||
|
|
||||||
dup = strdup(thing);
|
|
||||||
s = strtok(dup, ":");
|
|
||||||
vdev = s ? s : "";
|
|
||||||
s = strtok(NULL, ":");
|
|
||||||
offset = strtoull(s ? s : "", NULL, 16);
|
|
||||||
sizes = strtok(NULL, ":");
|
|
||||||
s = strtok(NULL, ":");
|
|
||||||
flagstr = strdup(s ? s : "");
|
|
||||||
|
|
||||||
s = NULL;
|
|
||||||
if (!zdb_parse_block_sizes(sizes, &lsize, &psize))
|
|
||||||
s = "invalid size(s)";
|
|
||||||
if (!IS_P2ALIGNED(psize, DEV_BSIZE) || !IS_P2ALIGNED(lsize, DEV_BSIZE))
|
|
||||||
s = "size must be a multiple of sector size";
|
|
||||||
if (!IS_P2ALIGNED(offset, DEV_BSIZE))
|
|
||||||
s = "offset must be a multiple of sector size";
|
|
||||||
if (s) {
|
|
||||||
(void) printf("Invalid block specifier: %s - %s\n", thing, s);
|
|
||||||
free(flagstr);
|
|
||||||
free(dup);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (s = strtok(flagstr, ":"); s; s = strtok(NULL, ":")) {
|
|
||||||
for (i = 0; flagstr[i]; i++) {
|
|
||||||
int bit = flagbits[(uchar_t)flagstr[i]];
|
|
||||||
|
|
||||||
if (bit == 0) {
|
|
||||||
(void) printf("***Invalid flag: %c\n",
|
|
||||||
flagstr[i]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
flags |= bit;
|
|
||||||
|
|
||||||
/* If it's not something with an argument, keep going */
|
|
||||||
if ((bit & (ZDB_FLAG_CHECKSUM |
|
|
||||||
ZDB_FLAG_PRINT_BLKPTR)) == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
p = &flagstr[i + 1];
|
|
||||||
if (bit == ZDB_FLAG_PRINT_BLKPTR) {
|
|
||||||
blkptr_offset = strtoull(p, &p, 16);
|
|
||||||
i = p - &flagstr[i + 1];
|
|
||||||
}
|
|
||||||
if (*p != ':' && *p != '\0') {
|
|
||||||
(void) printf("***Invalid flag arg: '%s'\n", s);
|
|
||||||
free(flagstr);
|
|
||||||
free(dup);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(flagstr);
|
|
||||||
|
|
||||||
vd = zdb_vdev_lookup(spa->spa_root_vdev, vdev);
|
|
||||||
if (vd == NULL) {
|
|
||||||
(void) printf("***Invalid vdev: %s\n", vdev);
|
|
||||||
free(dup);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
if (vd->vdev_path)
|
|
||||||
(void) fprintf(stderr, "Found vdev: %s\n",
|
|
||||||
vd->vdev_path);
|
|
||||||
else
|
|
||||||
(void) fprintf(stderr, "Found vdev type: %s\n",
|
|
||||||
vd->vdev_ops->vdev_op_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
pabd = abd_alloc_for_io(SPA_MAXBLOCKSIZE, B_FALSE);
|
|
||||||
lbuf = umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL);
|
|
||||||
|
|
||||||
BP_ZERO(bp);
|
|
||||||
|
|
||||||
DVA_SET_VDEV(&dva[0], vd->vdev_id);
|
|
||||||
DVA_SET_OFFSET(&dva[0], offset);
|
|
||||||
DVA_SET_GANG(&dva[0], !!(flags & ZDB_FLAG_GBH));
|
|
||||||
DVA_SET_ASIZE(&dva[0], vdev_psize_to_asize(vd, psize));
|
|
||||||
|
|
||||||
BP_SET_BIRTH(bp, TXG_INITIAL, TXG_INITIAL);
|
|
||||||
|
|
||||||
BP_SET_LSIZE(bp, lsize);
|
|
||||||
BP_SET_PSIZE(bp, psize);
|
|
||||||
BP_SET_COMPRESS(bp, ZIO_COMPRESS_OFF);
|
|
||||||
BP_SET_CHECKSUM(bp, ZIO_CHECKSUM_OFF);
|
|
||||||
BP_SET_TYPE(bp, DMU_OT_NONE);
|
|
||||||
BP_SET_LEVEL(bp, 0);
|
|
||||||
BP_SET_DEDUP(bp, 0);
|
|
||||||
BP_SET_BYTEORDER(bp, ZFS_HOST_BYTEORDER);
|
|
||||||
|
|
||||||
spa_config_enter(spa, SCL_STATE, FTAG, RW_READER);
|
|
||||||
zio = zio_root(spa, NULL, NULL, 0);
|
|
||||||
|
|
||||||
if (vd == vd->vdev_top) {
|
|
||||||
/*
|
|
||||||
* Treat this as a normal block read.
|
|
||||||
*/
|
|
||||||
zio_nowait(zio_read(zio, spa, bp, pabd, psize, NULL, NULL,
|
|
||||||
ZIO_PRIORITY_SYNC_READ,
|
|
||||||
ZIO_FLAG_CANFAIL | ZIO_FLAG_RAW, NULL));
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Treat this as a vdev child I/O.
|
|
||||||
*/
|
|
||||||
zio_nowait(zio_vdev_child_io(zio, bp, vd, offset, pabd,
|
|
||||||
psize, ZIO_TYPE_READ, ZIO_PRIORITY_SYNC_READ,
|
|
||||||
ZIO_FLAG_DONT_CACHE | ZIO_FLAG_DONT_QUEUE |
|
|
||||||
ZIO_FLAG_DONT_PROPAGATE | ZIO_FLAG_DONT_RETRY |
|
|
||||||
ZIO_FLAG_CANFAIL | ZIO_FLAG_RAW | ZIO_FLAG_OPTIONAL,
|
|
||||||
NULL, NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
error = zio_wait(zio);
|
|
||||||
spa_config_exit(spa, SCL_STATE, FTAG);
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
(void) printf("Read of %s failed, error: %d\n", thing, error);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & ZDB_FLAG_DECOMPRESS) {
|
|
||||||
/*
|
/*
|
||||||
* We don't know how the data was compressed, so just try
|
* We don't know how the data was compressed, so just try
|
||||||
* every decompress function at every inflated blocksize.
|
* every decompress function at every inflated blocksize.
|
||||||
@ -6792,8 +6653,7 @@ zdb_read_block(char *thing, spa_t *spa)
|
|||||||
umem_free(lbuf2, SPA_MAXBLOCKSIZE);
|
umem_free(lbuf2, SPA_MAXBLOCKSIZE);
|
||||||
|
|
||||||
if (lsize > maxlsize) {
|
if (lsize > maxlsize) {
|
||||||
(void) printf("Decompress of %s failed\n", thing);
|
exceeded = B_TRUE;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
buf = lbuf;
|
buf = lbuf;
|
||||||
if (*cfuncp == ZIO_COMPRESS_ZLE) {
|
if (*cfuncp == ZIO_COMPRESS_ZLE) {
|
||||||
@ -6801,10 +6661,217 @@ zdb_read_block(char *thing, spa_t *spa)
|
|||||||
"suspect the results are wrong,\ntry avoiding ZLE "
|
"suspect the results are wrong,\ntry avoiding ZLE "
|
||||||
"by setting and exporting ZDB_NO_ZLE=\"true\"\n");
|
"by setting and exporting ZDB_NO_ZLE=\"true\"\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (exceeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read a block from a pool and print it out. The syntax of the
|
||||||
|
* block descriptor is:
|
||||||
|
*
|
||||||
|
* pool:vdev_specifier:offset:[lsize/]psize[:flags]
|
||||||
|
*
|
||||||
|
* pool - The name of the pool you wish to read from
|
||||||
|
* vdev_specifier - Which vdev (see comment for zdb_vdev_lookup)
|
||||||
|
* offset - offset, in hex, in bytes
|
||||||
|
* size - Amount of data to read, in hex, in bytes
|
||||||
|
* flags - A string of characters specifying options
|
||||||
|
* b: Decode a blkptr at given offset within block
|
||||||
|
* c: Calculate and display checksums
|
||||||
|
* d: Decompress data before dumping
|
||||||
|
* e: Byteswap data before dumping
|
||||||
|
* g: Display data as a gang block header
|
||||||
|
* i: Display as an indirect block
|
||||||
|
* r: Dump raw data to stdout
|
||||||
|
* v: Verbose
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
zdb_read_block(char *thing, spa_t *spa)
|
||||||
|
{
|
||||||
|
blkptr_t blk, *bp = &blk;
|
||||||
|
dva_t *dva = bp->blk_dva;
|
||||||
|
int flags = 0;
|
||||||
|
uint64_t offset = 0, psize = 0, lsize = 0, blkptr_offset = 0;
|
||||||
|
zio_t *zio;
|
||||||
|
vdev_t *vd;
|
||||||
|
abd_t *pabd;
|
||||||
|
void *lbuf, *buf;
|
||||||
|
char *s, *p, *dup, *vdev, *flagstr, *sizes;
|
||||||
|
int i, error;
|
||||||
|
boolean_t borrowed = B_FALSE, found = B_FALSE;
|
||||||
|
|
||||||
|
dup = strdup(thing);
|
||||||
|
s = strtok(dup, ":");
|
||||||
|
vdev = s ? s : "";
|
||||||
|
s = strtok(NULL, ":");
|
||||||
|
offset = strtoull(s ? s : "", NULL, 16);
|
||||||
|
sizes = strtok(NULL, ":");
|
||||||
|
s = strtok(NULL, ":");
|
||||||
|
flagstr = strdup(s ? s : "");
|
||||||
|
|
||||||
|
s = NULL;
|
||||||
|
if (!zdb_parse_block_sizes(sizes, &lsize, &psize))
|
||||||
|
s = "invalid size(s)";
|
||||||
|
if (!IS_P2ALIGNED(psize, DEV_BSIZE) || !IS_P2ALIGNED(lsize, DEV_BSIZE))
|
||||||
|
s = "size must be a multiple of sector size";
|
||||||
|
if (!IS_P2ALIGNED(offset, DEV_BSIZE))
|
||||||
|
s = "offset must be a multiple of sector size";
|
||||||
|
if (s) {
|
||||||
|
(void) printf("Invalid block specifier: %s - %s\n", thing, s);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (s = strtok(flagstr, ":"); s; s = strtok(NULL, ":")) {
|
||||||
|
for (i = 0; i < strlen(flagstr); i++) {
|
||||||
|
int bit = flagbits[(uchar_t)flagstr[i]];
|
||||||
|
|
||||||
|
if (bit == 0) {
|
||||||
|
(void) printf("***Ignoring flag: %c\n",
|
||||||
|
(uchar_t)flagstr[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
found = B_TRUE;
|
||||||
|
flags |= bit;
|
||||||
|
|
||||||
|
p = &flagstr[i + 1];
|
||||||
|
if (*p != ':' && *p != '\0') {
|
||||||
|
int j = 0, nextbit = flagbits[(uchar_t)*p];
|
||||||
|
char *end, offstr[8] = { 0 };
|
||||||
|
if ((bit == ZDB_FLAG_PRINT_BLKPTR) &&
|
||||||
|
(nextbit == 0)) {
|
||||||
|
/* look ahead to isolate the offset */
|
||||||
|
while (nextbit == 0 &&
|
||||||
|
strchr(flagbitstr, *p) == NULL) {
|
||||||
|
offstr[j] = *p;
|
||||||
|
j++;
|
||||||
|
if (i + j > strlen(flagstr))
|
||||||
|
break;
|
||||||
|
p++;
|
||||||
|
nextbit = flagbits[(uchar_t)*p];
|
||||||
|
}
|
||||||
|
blkptr_offset = strtoull(offstr, &end,
|
||||||
|
16);
|
||||||
|
i += j;
|
||||||
|
} else if (nextbit == 0) {
|
||||||
|
(void) printf("***Ignoring flag arg:"
|
||||||
|
" '%c'\n", (uchar_t)*p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (blkptr_offset % sizeof (blkptr_t)) {
|
||||||
|
printf("Block pointer offset 0x%llx "
|
||||||
|
"must be divisible by 0x%x\n",
|
||||||
|
(longlong_t)blkptr_offset, (int)sizeof (blkptr_t));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (found == B_FALSE && strlen(flagstr) > 0) {
|
||||||
|
printf("Invalid flag arg: '%s'\n", flagstr);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
vd = zdb_vdev_lookup(spa->spa_root_vdev, vdev);
|
||||||
|
if (vd == NULL) {
|
||||||
|
(void) printf("***Invalid vdev: %s\n", vdev);
|
||||||
|
free(dup);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (vd->vdev_path)
|
||||||
|
(void) fprintf(stderr, "Found vdev: %s\n",
|
||||||
|
vd->vdev_path);
|
||||||
|
else
|
||||||
|
(void) fprintf(stderr, "Found vdev type: %s\n",
|
||||||
|
vd->vdev_ops->vdev_op_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
pabd = abd_alloc_for_io(SPA_MAXBLOCKSIZE, B_FALSE);
|
||||||
|
lbuf = umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL);
|
||||||
|
|
||||||
|
BP_ZERO(bp);
|
||||||
|
|
||||||
|
DVA_SET_VDEV(&dva[0], vd->vdev_id);
|
||||||
|
DVA_SET_OFFSET(&dva[0], offset);
|
||||||
|
DVA_SET_GANG(&dva[0], !!(flags & ZDB_FLAG_GBH));
|
||||||
|
DVA_SET_ASIZE(&dva[0], vdev_psize_to_asize(vd, psize));
|
||||||
|
|
||||||
|
BP_SET_BIRTH(bp, TXG_INITIAL, TXG_INITIAL);
|
||||||
|
|
||||||
|
BP_SET_LSIZE(bp, lsize);
|
||||||
|
BP_SET_PSIZE(bp, psize);
|
||||||
|
BP_SET_COMPRESS(bp, ZIO_COMPRESS_OFF);
|
||||||
|
BP_SET_CHECKSUM(bp, ZIO_CHECKSUM_OFF);
|
||||||
|
BP_SET_TYPE(bp, DMU_OT_NONE);
|
||||||
|
BP_SET_LEVEL(bp, 0);
|
||||||
|
BP_SET_DEDUP(bp, 0);
|
||||||
|
BP_SET_BYTEORDER(bp, ZFS_HOST_BYTEORDER);
|
||||||
|
|
||||||
|
spa_config_enter(spa, SCL_STATE, FTAG, RW_READER);
|
||||||
|
zio = zio_root(spa, NULL, NULL, 0);
|
||||||
|
|
||||||
|
if (vd == vd->vdev_top) {
|
||||||
|
/*
|
||||||
|
* Treat this as a normal block read.
|
||||||
|
*/
|
||||||
|
zio_nowait(zio_read(zio, spa, bp, pabd, psize, NULL, NULL,
|
||||||
|
ZIO_PRIORITY_SYNC_READ,
|
||||||
|
ZIO_FLAG_CANFAIL | ZIO_FLAG_RAW, NULL));
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Treat this as a vdev child I/O.
|
||||||
|
*/
|
||||||
|
zio_nowait(zio_vdev_child_io(zio, bp, vd, offset, pabd,
|
||||||
|
psize, ZIO_TYPE_READ, ZIO_PRIORITY_SYNC_READ,
|
||||||
|
ZIO_FLAG_DONT_CACHE | ZIO_FLAG_DONT_PROPAGATE |
|
||||||
|
ZIO_FLAG_DONT_RETRY | ZIO_FLAG_CANFAIL | ZIO_FLAG_RAW |
|
||||||
|
ZIO_FLAG_OPTIONAL, NULL, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
error = zio_wait(zio);
|
||||||
|
spa_config_exit(spa, SCL_STATE, FTAG);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
(void) printf("Read of %s failed, error: %d\n", thing, error);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t orig_lsize = lsize;
|
||||||
|
buf = lbuf;
|
||||||
|
if (flags & ZDB_FLAG_DECOMPRESS) {
|
||||||
|
boolean_t failed = zdb_decompress_block(pabd, buf, lbuf,
|
||||||
|
lsize, psize, flags);
|
||||||
|
if (failed) {
|
||||||
|
(void) printf("Decompress of %s failed\n", thing);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
buf = abd_borrow_buf_copy(pabd, lsize);
|
buf = abd_borrow_buf_copy(pabd, lsize);
|
||||||
borrowed = B_TRUE;
|
borrowed = B_TRUE;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* Try to detect invalid block pointer. If invalid, try
|
||||||
|
* decompressing.
|
||||||
|
*/
|
||||||
|
if ((flags & ZDB_FLAG_PRINT_BLKPTR || flags & ZDB_FLAG_INDIRECT) &&
|
||||||
|
!(flags & ZDB_FLAG_DECOMPRESS)) {
|
||||||
|
const blkptr_t *b = (const blkptr_t *)(void *)
|
||||||
|
((uintptr_t)buf + (uintptr_t)blkptr_offset);
|
||||||
|
if (zfs_blkptr_verify(spa, b, B_FALSE, BLK_VERIFY_ONLY) ==
|
||||||
|
B_FALSE) {
|
||||||
|
abd_return_buf_copy(pabd, buf, lsize);
|
||||||
|
borrowed = B_FALSE;
|
||||||
|
buf = lbuf;
|
||||||
|
boolean_t failed = zdb_decompress_block(pabd, buf,
|
||||||
|
lbuf, lsize, psize, flags);
|
||||||
|
b = (const blkptr_t *)(void *)
|
||||||
|
((uintptr_t)buf + (uintptr_t)blkptr_offset);
|
||||||
|
if (failed || zfs_blkptr_verify(spa, b, B_FALSE,
|
||||||
|
BLK_VERIFY_LOG) == B_FALSE) {
|
||||||
|
printf("invalid block pointer at this DVA\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (flags & ZDB_FLAG_PRINT_BLKPTR)
|
if (flags & ZDB_FLAG_PRINT_BLKPTR)
|
||||||
zdb_print_blkptr((blkptr_t *)(void *)
|
zdb_print_blkptr((blkptr_t *)(void *)
|
||||||
@ -6812,8 +6879,8 @@ zdb_read_block(char *thing, spa_t *spa)
|
|||||||
else if (flags & ZDB_FLAG_RAW)
|
else if (flags & ZDB_FLAG_RAW)
|
||||||
zdb_dump_block_raw(buf, lsize, flags);
|
zdb_dump_block_raw(buf, lsize, flags);
|
||||||
else if (flags & ZDB_FLAG_INDIRECT)
|
else if (flags & ZDB_FLAG_INDIRECT)
|
||||||
zdb_dump_indirect((blkptr_t *)buf, lsize / sizeof (blkptr_t),
|
zdb_dump_indirect((blkptr_t *)buf,
|
||||||
flags);
|
orig_lsize / sizeof (blkptr_t), flags);
|
||||||
else if (flags & ZDB_FLAG_GBH)
|
else if (flags & ZDB_FLAG_GBH)
|
||||||
zdb_dump_gbh(buf, flags);
|
zdb_dump_gbh(buf, flags);
|
||||||
else
|
else
|
||||||
@ -6886,6 +6953,8 @@ zdb_read_block(char *thing, spa_t *spa)
|
|||||||
out:
|
out:
|
||||||
abd_free(pabd);
|
abd_free(pabd);
|
||||||
umem_free(lbuf, SPA_MAXBLOCKSIZE);
|
umem_free(lbuf, SPA_MAXBLOCKSIZE);
|
||||||
|
done:
|
||||||
|
free(flagstr);
|
||||||
free(dup);
|
free(dup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -516,6 +516,12 @@ struct zio {
|
|||||||
taskq_ent_t io_tqent;
|
taskq_ent_t io_tqent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum blk_verify_flag {
|
||||||
|
BLK_VERIFY_ONLY,
|
||||||
|
BLK_VERIFY_LOG,
|
||||||
|
BLK_VERIFY_HALT
|
||||||
|
};
|
||||||
|
|
||||||
extern int zio_bookmark_compare(const void *, const void *);
|
extern int zio_bookmark_compare(const void *, const void *);
|
||||||
|
|
||||||
extern zio_t *zio_null(zio_t *pio, spa_t *spa, vdev_t *vd,
|
extern zio_t *zio_null(zio_t *pio, spa_t *spa, vdev_t *vd,
|
||||||
@ -626,6 +632,9 @@ extern void zio_suspend(spa_t *spa, zio_t *zio, zio_suspend_reason_t);
|
|||||||
extern int zio_resume(spa_t *spa);
|
extern int zio_resume(spa_t *spa);
|
||||||
extern void zio_resume_wait(spa_t *spa);
|
extern void zio_resume_wait(spa_t *spa);
|
||||||
|
|
||||||
|
extern boolean_t zfs_blkptr_verify(spa_t *spa, const blkptr_t *bp,
|
||||||
|
boolean_t config_held, enum blk_verify_flag blk_verify);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initial setup and teardown.
|
* Initial setup and teardown.
|
||||||
*/
|
*/
|
||||||
|
@ -286,7 +286,7 @@ of the block to read and, optionally,
|
|||||||
.Pp
|
.Pp
|
||||||
.Bl -tag -compact -width "b offset"
|
.Bl -tag -compact -width "b offset"
|
||||||
.It Sy b Ar offset
|
.It Sy b Ar offset
|
||||||
Print block pointer
|
Print block pointer at hex offset
|
||||||
.It Sy c
|
.It Sy c
|
||||||
Calculate and display checksums
|
Calculate and display checksums
|
||||||
.It Sy d
|
.It Sy d
|
||||||
|
@ -890,35 +890,82 @@ zio_root(spa_t *spa, zio_done_func_t *done, void *private, enum zio_flag flags)
|
|||||||
return (zio_null(NULL, spa, NULL, done, private, flags));
|
return (zio_null(NULL, spa, NULL, done, private, flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int
|
||||||
zfs_blkptr_verify(spa_t *spa, const blkptr_t *bp, boolean_t config_held)
|
zfs_blkptr_verify_log(spa_t *spa, const blkptr_t *bp,
|
||||||
|
enum blk_verify_flag blk_verify, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
|
va_list adx;
|
||||||
|
char buf[256];
|
||||||
|
|
||||||
|
va_start(adx, fmt);
|
||||||
|
(void) vsnprintf(buf, sizeof (buf), fmt, adx);
|
||||||
|
va_end(adx);
|
||||||
|
|
||||||
|
switch (blk_verify) {
|
||||||
|
case BLK_VERIFY_HALT:
|
||||||
|
zfs_panic_recover("%s: %s", spa_name(spa), buf);
|
||||||
|
break;
|
||||||
|
case BLK_VERIFY_LOG:
|
||||||
|
zfs_dbgmsg("%s: %s", spa_name(spa), buf);
|
||||||
|
break;
|
||||||
|
case BLK_VERIFY_ONLY:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify the block pointer fields contain reasonable values. This means
|
||||||
|
* it only contains known object types, checksum/compression identifiers,
|
||||||
|
* block sizes within the maximum allowed limits, valid DVAs, etc.
|
||||||
|
*
|
||||||
|
* If everything checks out B_TRUE is returned. The zfs_blkptr_verify
|
||||||
|
* argument controls the behavior when an invalid field is detected.
|
||||||
|
*
|
||||||
|
* Modes for zfs_blkptr_verify:
|
||||||
|
* 1) BLK_VERIFY_ONLY (evaluate the block)
|
||||||
|
* 2) BLK_VERIFY_LOG (evaluate the block and log problems)
|
||||||
|
* 3) BLK_VERIFY_HALT (call zfs_panic_recover on error)
|
||||||
|
*/
|
||||||
|
boolean_t
|
||||||
|
zfs_blkptr_verify(spa_t *spa, const blkptr_t *bp, boolean_t config_held,
|
||||||
|
enum blk_verify_flag blk_verify)
|
||||||
|
{
|
||||||
|
int errors = 0;
|
||||||
|
|
||||||
if (!DMU_OT_IS_VALID(BP_GET_TYPE(bp))) {
|
if (!DMU_OT_IS_VALID(BP_GET_TYPE(bp))) {
|
||||||
zfs_panic_recover("blkptr at %p has invalid TYPE %llu",
|
errors += zfs_blkptr_verify_log(spa, bp, blk_verify,
|
||||||
|
"blkptr at %p has invalid TYPE %llu",
|
||||||
bp, (longlong_t)BP_GET_TYPE(bp));
|
bp, (longlong_t)BP_GET_TYPE(bp));
|
||||||
}
|
}
|
||||||
if (BP_GET_CHECKSUM(bp) >= ZIO_CHECKSUM_FUNCTIONS ||
|
if (BP_GET_CHECKSUM(bp) >= ZIO_CHECKSUM_FUNCTIONS ||
|
||||||
BP_GET_CHECKSUM(bp) <= ZIO_CHECKSUM_ON) {
|
BP_GET_CHECKSUM(bp) <= ZIO_CHECKSUM_ON) {
|
||||||
zfs_panic_recover("blkptr at %p has invalid CHECKSUM %llu",
|
errors += zfs_blkptr_verify_log(spa, bp, blk_verify,
|
||||||
|
"blkptr at %p has invalid CHECKSUM %llu",
|
||||||
bp, (longlong_t)BP_GET_CHECKSUM(bp));
|
bp, (longlong_t)BP_GET_CHECKSUM(bp));
|
||||||
}
|
}
|
||||||
if (BP_GET_COMPRESS(bp) >= ZIO_COMPRESS_FUNCTIONS ||
|
if (BP_GET_COMPRESS(bp) >= ZIO_COMPRESS_FUNCTIONS ||
|
||||||
BP_GET_COMPRESS(bp) <= ZIO_COMPRESS_ON) {
|
BP_GET_COMPRESS(bp) <= ZIO_COMPRESS_ON) {
|
||||||
zfs_panic_recover("blkptr at %p has invalid COMPRESS %llu",
|
errors += zfs_blkptr_verify_log(spa, bp, blk_verify,
|
||||||
|
"blkptr at %p has invalid COMPRESS %llu",
|
||||||
bp, (longlong_t)BP_GET_COMPRESS(bp));
|
bp, (longlong_t)BP_GET_COMPRESS(bp));
|
||||||
}
|
}
|
||||||
if (BP_GET_LSIZE(bp) > SPA_MAXBLOCKSIZE) {
|
if (BP_GET_LSIZE(bp) > SPA_MAXBLOCKSIZE) {
|
||||||
zfs_panic_recover("blkptr at %p has invalid LSIZE %llu",
|
errors += zfs_blkptr_verify_log(spa, bp, blk_verify,
|
||||||
|
"blkptr at %p has invalid LSIZE %llu",
|
||||||
bp, (longlong_t)BP_GET_LSIZE(bp));
|
bp, (longlong_t)BP_GET_LSIZE(bp));
|
||||||
}
|
}
|
||||||
if (BP_GET_PSIZE(bp) > SPA_MAXBLOCKSIZE) {
|
if (BP_GET_PSIZE(bp) > SPA_MAXBLOCKSIZE) {
|
||||||
zfs_panic_recover("blkptr at %p has invalid PSIZE %llu",
|
errors += zfs_blkptr_verify_log(spa, bp, blk_verify,
|
||||||
|
"blkptr at %p has invalid PSIZE %llu",
|
||||||
bp, (longlong_t)BP_GET_PSIZE(bp));
|
bp, (longlong_t)BP_GET_PSIZE(bp));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BP_IS_EMBEDDED(bp)) {
|
if (BP_IS_EMBEDDED(bp)) {
|
||||||
if (BPE_GET_ETYPE(bp) >= NUM_BP_EMBEDDED_TYPES) {
|
if (BPE_GET_ETYPE(bp) >= NUM_BP_EMBEDDED_TYPES) {
|
||||||
zfs_panic_recover("blkptr at %p has invalid ETYPE %llu",
|
errors += zfs_blkptr_verify_log(spa, bp, blk_verify,
|
||||||
|
"blkptr at %p has invalid ETYPE %llu",
|
||||||
bp, (longlong_t)BPE_GET_ETYPE(bp));
|
bp, (longlong_t)BPE_GET_ETYPE(bp));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -928,7 +975,7 @@ zfs_blkptr_verify(spa_t *spa, const blkptr_t *bp, boolean_t config_held)
|
|||||||
* will be done once the zio is executed in vdev_mirror_map_alloc.
|
* will be done once the zio is executed in vdev_mirror_map_alloc.
|
||||||
*/
|
*/
|
||||||
if (!spa->spa_trust_config)
|
if (!spa->spa_trust_config)
|
||||||
return;
|
return (B_TRUE);
|
||||||
|
|
||||||
if (!config_held)
|
if (!config_held)
|
||||||
spa_config_enter(spa, SCL_VDEV, bp, RW_READER);
|
spa_config_enter(spa, SCL_VDEV, bp, RW_READER);
|
||||||
@ -946,21 +993,21 @@ zfs_blkptr_verify(spa_t *spa, const blkptr_t *bp, boolean_t config_held)
|
|||||||
uint64_t vdevid = DVA_GET_VDEV(&bp->blk_dva[i]);
|
uint64_t vdevid = DVA_GET_VDEV(&bp->blk_dva[i]);
|
||||||
|
|
||||||
if (vdevid >= spa->spa_root_vdev->vdev_children) {
|
if (vdevid >= spa->spa_root_vdev->vdev_children) {
|
||||||
zfs_panic_recover("blkptr at %p DVA %u has invalid "
|
errors += zfs_blkptr_verify_log(spa, bp, blk_verify,
|
||||||
"VDEV %llu",
|
"blkptr at %p DVA %u has invalid VDEV %llu",
|
||||||
bp, i, (longlong_t)vdevid);
|
bp, i, (longlong_t)vdevid);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
vdev_t *vd = spa->spa_root_vdev->vdev_child[vdevid];
|
vdev_t *vd = spa->spa_root_vdev->vdev_child[vdevid];
|
||||||
if (vd == NULL) {
|
if (vd == NULL) {
|
||||||
zfs_panic_recover("blkptr at %p DVA %u has invalid "
|
errors += zfs_blkptr_verify_log(spa, bp, blk_verify,
|
||||||
"VDEV %llu",
|
"blkptr at %p DVA %u has invalid VDEV %llu",
|
||||||
bp, i, (longlong_t)vdevid);
|
bp, i, (longlong_t)vdevid);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (vd->vdev_ops == &vdev_hole_ops) {
|
if (vd->vdev_ops == &vdev_hole_ops) {
|
||||||
zfs_panic_recover("blkptr at %p DVA %u has hole "
|
errors += zfs_blkptr_verify_log(spa, bp, blk_verify,
|
||||||
"VDEV %llu",
|
"blkptr at %p DVA %u has hole VDEV %llu",
|
||||||
bp, i, (longlong_t)vdevid);
|
bp, i, (longlong_t)vdevid);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -977,13 +1024,15 @@ zfs_blkptr_verify(spa_t *spa, const blkptr_t *bp, boolean_t config_held)
|
|||||||
if (BP_IS_GANG(bp))
|
if (BP_IS_GANG(bp))
|
||||||
asize = vdev_psize_to_asize(vd, SPA_GANGBLOCKSIZE);
|
asize = vdev_psize_to_asize(vd, SPA_GANGBLOCKSIZE);
|
||||||
if (offset + asize > vd->vdev_asize) {
|
if (offset + asize > vd->vdev_asize) {
|
||||||
zfs_panic_recover("blkptr at %p DVA %u has invalid "
|
errors += zfs_blkptr_verify_log(spa, bp, blk_verify,
|
||||||
"OFFSET %llu",
|
"blkptr at %p DVA %u has invalid OFFSET %llu",
|
||||||
bp, i, (longlong_t)offset);
|
bp, i, (longlong_t)offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!config_held)
|
if (!config_held)
|
||||||
spa_config_exit(spa, SCL_VDEV, bp);
|
spa_config_exit(spa, SCL_VDEV, bp);
|
||||||
|
|
||||||
|
return (errors == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean_t
|
boolean_t
|
||||||
@ -1023,7 +1072,8 @@ zio_read(zio_t *pio, spa_t *spa, const blkptr_t *bp,
|
|||||||
{
|
{
|
||||||
zio_t *zio;
|
zio_t *zio;
|
||||||
|
|
||||||
zfs_blkptr_verify(spa, bp, flags & ZIO_FLAG_CONFIG_WRITER);
|
(void) zfs_blkptr_verify(spa, bp, flags & ZIO_FLAG_CONFIG_WRITER,
|
||||||
|
BLK_VERIFY_HALT);
|
||||||
|
|
||||||
zio = zio_create(pio, spa, BP_PHYSICAL_BIRTH(bp), bp,
|
zio = zio_create(pio, spa, BP_PHYSICAL_BIRTH(bp), bp,
|
||||||
data, size, size, done, private,
|
data, size, size, done, private,
|
||||||
@ -1116,7 +1166,7 @@ void
|
|||||||
zio_free(spa_t *spa, uint64_t txg, const blkptr_t *bp)
|
zio_free(spa_t *spa, uint64_t txg, const blkptr_t *bp)
|
||||||
{
|
{
|
||||||
|
|
||||||
zfs_blkptr_verify(spa, bp, B_FALSE);
|
(void) zfs_blkptr_verify(spa, bp, B_FALSE, BLK_VERIFY_HALT);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The check for EMBEDDED is a performance optimization. We
|
* The check for EMBEDDED is a performance optimization. We
|
||||||
@ -1186,7 +1236,8 @@ zio_claim(zio_t *pio, spa_t *spa, uint64_t txg, const blkptr_t *bp,
|
|||||||
{
|
{
|
||||||
zio_t *zio;
|
zio_t *zio;
|
||||||
|
|
||||||
zfs_blkptr_verify(spa, bp, flags & ZIO_FLAG_CONFIG_WRITER);
|
(void) zfs_blkptr_verify(spa, bp, flags & ZIO_FLAG_CONFIG_WRITER,
|
||||||
|
BLK_VERIFY_HALT);
|
||||||
|
|
||||||
if (BP_IS_EMBEDDED(bp))
|
if (BP_IS_EMBEDDED(bp))
|
||||||
return (zio_null(pio, spa, NULL, NULL, NULL, 0));
|
return (zio_null(pio, spa, NULL, NULL, NULL, 0));
|
||||||
|
@ -101,7 +101,8 @@ tags = ['functional', 'clean_mirror']
|
|||||||
[tests/functional/cli_root/zdb]
|
[tests/functional/cli_root/zdb]
|
||||||
tests = ['zdb_001_neg', 'zdb_002_pos', 'zdb_003_pos', 'zdb_004_pos',
|
tests = ['zdb_001_neg', 'zdb_002_pos', 'zdb_003_pos', 'zdb_004_pos',
|
||||||
'zdb_005_pos', 'zdb_006_pos', 'zdb_checksum', 'zdb_decompress',
|
'zdb_005_pos', 'zdb_006_pos', 'zdb_checksum', 'zdb_decompress',
|
||||||
'zdb_object_range_neg', 'zdb_object_range_pos', 'zdb_objset_id']
|
'zdb_object_range_neg', 'zdb_object_range_pos', 'zdb_display_block',
|
||||||
|
'zdb_objset_id']
|
||||||
pre =
|
pre =
|
||||||
post =
|
post =
|
||||||
tags = ['functional', 'cli_root', 'zdb']
|
tags = ['functional', 'cli_root', 'zdb']
|
||||||
|
@ -8,6 +8,7 @@ dist_pkgdata_SCRIPTS = \
|
|||||||
zdb_006_pos.ksh \
|
zdb_006_pos.ksh \
|
||||||
zdb_checksum.ksh \
|
zdb_checksum.ksh \
|
||||||
zdb_decompress.ksh \
|
zdb_decompress.ksh \
|
||||||
zdb_objset_id.ksh \
|
|
||||||
zdb_object_range_neg.ksh \
|
zdb_object_range_neg.ksh \
|
||||||
zdb_object_range_pos.ksh
|
zdb_object_range_pos.ksh \
|
||||||
|
zdb_display_block.ksh \
|
||||||
|
zdb_objset_id.ksh
|
||||||
|
128
tests/zfs-tests/tests/functional/cli_root/zdb/zdb_display_block.ksh
Executable file
128
tests/zfs-tests/tests/functional/cli_root/zdb/zdb_display_block.ksh
Executable file
@ -0,0 +1,128 @@
|
|||||||
|
#!/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) 2019 by Datto, Inc. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
|
||||||
|
#
|
||||||
|
# Description:
|
||||||
|
# zdb -R pool <DVA>:b will display the block
|
||||||
|
#
|
||||||
|
# Strategy:
|
||||||
|
# 1. Create a pool, set compression to lzjb
|
||||||
|
# 2. Write some identifiable data to a file
|
||||||
|
# 3. Run zdb -ddddddbbbbbb against the file
|
||||||
|
# 4. Record the DVA of the first L1 block;
|
||||||
|
# record the first L0 block display; and
|
||||||
|
# record the 2nd L0 block display.
|
||||||
|
# 5. Run zdb -R with :bd displays first L0
|
||||||
|
# 6. Run zdb -R with :b80d displays 2nd L0
|
||||||
|
# 7. Run zdb -R with :db80 displays 2nd L0
|
||||||
|
# 8. Run zdb -R with :id flag displays indirect block
|
||||||
|
# (similar to zdb -ddddddbbbbbb output)
|
||||||
|
# 9. Run zdb -R with :id flag and .0 vdev
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
function cleanup
|
||||||
|
{
|
||||||
|
datasetexists $TESTPOOL && destroy_pool $TESTPOOL
|
||||||
|
}
|
||||||
|
|
||||||
|
log_assert "Verify zdb -R :b flag (block display) works as expected"
|
||||||
|
log_onexit cleanup
|
||||||
|
init_data=$TESTDIR/file1
|
||||||
|
write_count=256
|
||||||
|
blksize=4096
|
||||||
|
|
||||||
|
# only read 256 128 byte block pointers in L1 (:i flag)
|
||||||
|
# 256 x 128 = 32k / 0x8000
|
||||||
|
l1_read_size="8000"
|
||||||
|
|
||||||
|
verify_runnable "global"
|
||||||
|
verify_disk_count "$DISKS" 2
|
||||||
|
|
||||||
|
default_mirror_setup_noexit $DISKS
|
||||||
|
log_must zfs set recordsize=$blksize $TESTPOOL/$TESTFS
|
||||||
|
log_must zfs set compression=lzjb $TESTPOOL/$TESTFS
|
||||||
|
|
||||||
|
file_write -d R -o create -w -f $init_data -b $blksize -c $write_count
|
||||||
|
sync_pool $TESTPOOL true
|
||||||
|
|
||||||
|
# get object number of file
|
||||||
|
listing=$(ls -i $init_data)
|
||||||
|
set -A array $listing
|
||||||
|
obj=${array[0]}
|
||||||
|
log_note "file $init_data has object number $obj"
|
||||||
|
|
||||||
|
output=$(zdb -ddddddbbbbbb $TESTPOOL/$TESTFS $obj 2> /dev/null \
|
||||||
|
|grep -m 1 "L1 DVA" |head -n1)
|
||||||
|
dva=$(sed -Ene 's/^.+DVA\[0\]=<([^>]+)>.*/\1/p' <<< "$output")
|
||||||
|
log_note "first L1 block $init_data has a DVA of $dva"
|
||||||
|
output=$(zdb -ddddddbbbbbb $TESTPOOL/$TESTFS $obj 2> /dev/null \
|
||||||
|
|grep -m 1 "L0 DVA" |head -n1)
|
||||||
|
blk_out0=${output##*>}
|
||||||
|
blk_out0=${blk_out0##+([[:space:]])}
|
||||||
|
|
||||||
|
output=$(zdb -ddddddbbbbbb $TESTPOOL/$TESTFS $obj 2> /dev/null \
|
||||||
|
|grep -m 1 "1000 L0 DVA" |head -n1)
|
||||||
|
blk_out1=${output##*>}
|
||||||
|
blk_out1=${blk_out1##+([[:space:]])}
|
||||||
|
|
||||||
|
output=$(export ZDB_NO_ZLE=\"true\"; zdb -R $TESTPOOL $dva:bd\
|
||||||
|
2> /dev/null)
|
||||||
|
output=${output##*>}
|
||||||
|
output=${output##+([[:space:]])}
|
||||||
|
if [ "$output" != "$blk_out0" ]; then
|
||||||
|
log_fail "zdb -R :bd (block 0 display/decompress) failed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
output=$(export ZDB_NO_ZLE=\"true\"; zdb -R $TESTPOOL $dva:db80\
|
||||||
|
2> /dev/null)
|
||||||
|
output=${output##*>}
|
||||||
|
output=${output##+([[:space:]])}
|
||||||
|
if [ "$output" != "$blk_out1" ]; then
|
||||||
|
log_fail "zdb -R :db80 (block 1 display/decompress) failed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
output=$(export ZDB_NO_ZLE=\"true\"; zdb -R $TESTPOOL $dva:b80d\
|
||||||
|
2> /dev/null)
|
||||||
|
output=${output##*>}
|
||||||
|
output=${output##+([[:space:]])}
|
||||||
|
if [ "$output" != "$blk_out1" ]; then
|
||||||
|
log_fail "zdb -R :b80d (block 1 display/decompress) failed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
vdev=$(echo "$dva" |awk '{split($0,array,":")} END{print array[1]}')
|
||||||
|
offset=$(echo "$dva" |awk '{split($0,array,":")} END{print array[2]}')
|
||||||
|
output=$(export ZDB_NO_ZLE=\"true\";\
|
||||||
|
zdb -R $TESTPOOL $vdev:$offset:$l1_read_size:id 2> /dev/null)
|
||||||
|
block_cnt=$(echo "$output" | grep 'L0' | wc -l)
|
||||||
|
if [ "$block_cnt" != "$write_count" ]; then
|
||||||
|
log_fail "zdb -R :id (indirect block display) failed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# read from specific half of mirror
|
||||||
|
vdev="$vdev.0"
|
||||||
|
log_note "Reading from DVA $vdev:$offset:$l1_read_size"
|
||||||
|
output=$(export ZDB_NO_ZLE=\"true\";\
|
||||||
|
zdb -R $TESTPOOL $vdev:$offset:$l1_read_size:id 2> /dev/null)
|
||||||
|
block_cnt=$(echo "$output" | grep 'L0' | wc -l)
|
||||||
|
if [ "$block_cnt" != "$write_count" ]; then
|
||||||
|
log_fail "zdb -R 0.0:offset:length:id (indirect block display) failed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_pass "zdb -R :b flag (block display) works as expected"
|
Loading…
Reference in New Issue
Block a user