zdb -vvvvv on ztest pool dies with "out of memory"

ztest creates some extremely large files as part of its 
operation. When zdb tries to dump a large enough file, it 
can run out of memory or spend an extremely long time 
attempting to print millions or billions of uint64_ts.

We cap the amount of data from a uint64 object that we 
are willing to read and print.

Reviewed-by: Don Brady <don.brady@delphix.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Paul Dagnelie <pcd@delphix.com>
External-issue: DLPX-53814
Closes #8947
This commit is contained in:
Paul Dagnelie 2019-06-25 12:50:38 -07:00 committed by Brian Behlendorf
parent fc7546777b
commit 3fab4d9e08

View File

@ -424,23 +424,35 @@ static void
dump_uint64(objset_t *os, uint64_t object, void *data, size_t size) dump_uint64(objset_t *os, uint64_t object, void *data, size_t size)
{ {
uint64_t *arr; uint64_t *arr;
uint64_t oursize;
if (dump_opt['d'] < 6) if (dump_opt['d'] < 6)
return; return;
if (data == NULL) { if (data == NULL) {
dmu_object_info_t doi; dmu_object_info_t doi;
VERIFY0(dmu_object_info(os, object, &doi)); VERIFY0(dmu_object_info(os, object, &doi));
size = doi.doi_max_offset; size = doi.doi_max_offset;
arr = kmem_alloc(size, KM_SLEEP); /*
* We cap the size at 1 mebibyte here to prevent
* allocation failures and nigh-infinite printing if the
* object is extremely large.
*/
oursize = MIN(size, 1 << 20);
arr = kmem_alloc(oursize, KM_SLEEP);
int err = dmu_read(os, object, 0, size, arr, 0); int err = dmu_read(os, object, 0, oursize, arr, 0);
if (err != 0) { if (err != 0) {
(void) printf("got error %u from dmu_read\n", err); (void) printf("got error %u from dmu_read\n", err);
kmem_free(arr, size); kmem_free(arr, oursize);
return; return;
} }
} else { } else {
/*
* Even though the allocation is already done in this code path,
* we still cap the size to prevent excessive printing.
*/
oursize = MIN(size, 1 << 20);
arr = data; arr = data;
} }
@ -450,16 +462,18 @@ dump_uint64(objset_t *os, uint64_t object, void *data, size_t size)
} }
(void) printf("\t\t[%0llx", (u_longlong_t)arr[0]); (void) printf("\t\t[%0llx", (u_longlong_t)arr[0]);
for (size_t i = 1; i * sizeof (uint64_t) < size; i++) { for (size_t i = 1; i * sizeof (uint64_t) < oursize; i++) {
if (i % 4 != 0) if (i % 4 != 0)
(void) printf(", %0llx", (u_longlong_t)arr[i]); (void) printf(", %0llx", (u_longlong_t)arr[i]);
else else
(void) printf(",\n\t\t%0llx", (u_longlong_t)arr[i]); (void) printf(",\n\t\t%0llx", (u_longlong_t)arr[i]);
} }
if (oursize != size)
(void) printf(", ... ");
(void) printf("]\n"); (void) printf("]\n");
if (data == NULL) if (data == NULL)
kmem_free(arr, size); kmem_free(arr, oursize);
} }
/*ARGSUSED*/ /*ARGSUSED*/