diff options
author | Paul Dagnelie <[email protected]> | 2019-06-25 12:50:38 -0700 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2019-06-25 12:50:37 -0700 |
commit | 3fab4d9e08aa1471c5c34bf7fdc2632bf4a7d494 (patch) | |
tree | 682288be0f0b010760ec8fd05c68ab62a3bd5a2d /cmd/zdb/zdb.c | |
parent | fc7546777ba15a7fff651cd803bf521f592d8379 (diff) |
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 <[email protected]>
Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: Paul Dagnelie <[email protected]>
External-issue: DLPX-53814
Closes #8947
Diffstat (limited to 'cmd/zdb/zdb.c')
-rw-r--r-- | cmd/zdb/zdb.c | 26 |
1 files changed, 20 insertions, 6 deletions
diff --git a/cmd/zdb/zdb.c b/cmd/zdb/zdb.c index 969c8f1b7..e0ea07280 100644 --- a/cmd/zdb/zdb.c +++ b/cmd/zdb/zdb.c @@ -424,23 +424,35 @@ static void dump_uint64(objset_t *os, uint64_t object, void *data, size_t size) { uint64_t *arr; - + uint64_t oursize; if (dump_opt['d'] < 6) return; + if (data == NULL) { dmu_object_info_t doi; VERIFY0(dmu_object_info(os, object, &doi)); 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) { (void) printf("got error %u from dmu_read\n", err); - kmem_free(arr, size); + kmem_free(arr, oursize); return; } } 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; } @@ -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]); - 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) (void) printf(", %0llx", (u_longlong_t)arr[i]); else (void) printf(",\n\t\t%0llx", (u_longlong_t)arr[i]); } + if (oursize != size) + (void) printf(", ... "); (void) printf("]\n"); if (data == NULL) - kmem_free(arr, size); + kmem_free(arr, oursize); } /*ARGSUSED*/ |