Take into account when zpool history block grows exceeding 128KB in zpool(8)
and zdb(8) by growing the buffer on demand with a cap of 1GB (specified in spa_history_create_obj()). PR: bin/186574 Submitted by: Andrew Childs <lorne cons org nz> (with changes) MFC after: 2 weeks
This commit is contained in:
parent
4fa056cdce
commit
8621ec029b
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=264467
@ -929,11 +929,16 @@ dump_dtl(vdev_t *vd, int indent)
|
||||
dump_dtl(vd->vdev_child[c], indent + 4);
|
||||
}
|
||||
|
||||
/* from spa_history.c: spa_history_create_obj() */
|
||||
#define HIS_BUF_LEN_DEF (128 << 10)
|
||||
#define HIS_BUF_LEN_MAX (1 << 30)
|
||||
|
||||
static void
|
||||
dump_history(spa_t *spa)
|
||||
{
|
||||
nvlist_t **events = NULL;
|
||||
char buf[SPA_MAXBLOCKSIZE];
|
||||
char *buf = NULL;
|
||||
uint64_t bufsize = HIS_BUF_LEN_DEF;
|
||||
uint64_t resid, len, off = 0;
|
||||
uint_t num = 0;
|
||||
int error;
|
||||
@ -942,8 +947,11 @@ dump_history(spa_t *spa)
|
||||
char tbuf[30];
|
||||
char internalstr[MAXPATHLEN];
|
||||
|
||||
if ((buf = malloc(bufsize)) == NULL)
|
||||
(void) fprintf(stderr, "Unable to read history: "
|
||||
"out of memory\n");
|
||||
do {
|
||||
len = sizeof (buf);
|
||||
len = bufsize;
|
||||
|
||||
if ((error = spa_history_get(spa, &off, &len, buf)) != 0) {
|
||||
(void) fprintf(stderr, "Unable to read history: "
|
||||
@ -953,9 +961,26 @@ dump_history(spa_t *spa)
|
||||
|
||||
if (zpool_history_unpack(buf, len, &resid, &events, &num) != 0)
|
||||
break;
|
||||
|
||||
off -= resid;
|
||||
|
||||
/*
|
||||
* If the history block is too big, double the buffer
|
||||
* size and try again.
|
||||
*/
|
||||
if (resid == len) {
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
|
||||
bufsize <<= 1;
|
||||
if ((bufsize >= HIS_BUF_LEN_MAX) ||
|
||||
((buf = malloc(bufsize)) == NULL)) {
|
||||
(void) fprintf(stderr, "Unable to read history: "
|
||||
"out of memory\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
} while (len != 0);
|
||||
free(buf);
|
||||
|
||||
(void) printf("\nHistory:\n");
|
||||
for (int i = 0; i < num; i++) {
|
||||
|
@ -3744,7 +3744,9 @@ zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover,
|
||||
return (0);
|
||||
}
|
||||
|
||||
#define HIS_BUF_LEN (128*1024)
|
||||
/* from spa_history.c: spa_history_create_obj() */
|
||||
#define HIS_BUF_LEN_DEF (128 << 10)
|
||||
#define HIS_BUF_LEN_MAX (1 << 30)
|
||||
|
||||
/*
|
||||
* Retrieve the command history of a pool.
|
||||
@ -3752,21 +3754,24 @@ zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover,
|
||||
int
|
||||
zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp)
|
||||
{
|
||||
char buf[HIS_BUF_LEN];
|
||||
char *buf = NULL;
|
||||
uint64_t bufsize = HIS_BUF_LEN_DEF;
|
||||
uint64_t off = 0;
|
||||
nvlist_t **records = NULL;
|
||||
uint_t numrecords = 0;
|
||||
int err, i;
|
||||
|
||||
if ((buf = malloc(bufsize)) == NULL)
|
||||
return (ENOMEM);
|
||||
do {
|
||||
uint64_t bytes_read = sizeof (buf);
|
||||
uint64_t bytes_read = bufsize;
|
||||
uint64_t leftover;
|
||||
|
||||
if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0)
|
||||
break;
|
||||
|
||||
/* if nothing else was read in, we're at EOF, just return */
|
||||
if (!bytes_read)
|
||||
if (bytes_read == 0)
|
||||
break;
|
||||
|
||||
if ((err = zpool_history_unpack(buf, bytes_read,
|
||||
@ -3774,8 +3779,25 @@ zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp)
|
||||
break;
|
||||
off -= leftover;
|
||||
|
||||
/*
|
||||
* If the history block is too big, double the buffer
|
||||
* size and try again.
|
||||
*/
|
||||
if (leftover == bytes_read) {
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
|
||||
bufsize <<= 1;
|
||||
if ((bufsize >= HIS_BUF_LEN_MAX) ||
|
||||
((buf = malloc(bufsize)) == NULL)) {
|
||||
err = ENOMEM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* CONSTCOND */
|
||||
} while (1);
|
||||
free(buf);
|
||||
|
||||
if (!err) {
|
||||
verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0);
|
||||
|
Loading…
Reference in New Issue
Block a user