Print this page
9525 kmem_dump_size is a corrupting influence
*** 22,32 ****
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
! * Copyright 2011 Joyent, Inc. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
*/
#include <mdb/mdb_param.h>
#include <mdb/mdb_modapi.h>
--- 22,32 ----
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
! * Copyright 2018 Joyent, Inc. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
*/
#include <mdb/mdb_param.h>
#include <mdb/mdb_modapi.h>
*** 3010,3020 ****
typedef struct kmem_verify {
uint64_t *kmv_buf; /* buffer to read cache contents into */
size_t kmv_size; /* number of bytes in kmv_buf */
int kmv_corruption; /* > 0 if corruption found. */
! int kmv_besilent; /* report actual corruption sites */
struct kmem_cache kmv_cache; /* the cache we're operating on */
} kmem_verify_t;
/*
* verify_pattern()
--- 3010,3020 ----
typedef struct kmem_verify {
uint64_t *kmv_buf; /* buffer to read cache contents into */
size_t kmv_size; /* number of bytes in kmv_buf */
int kmv_corruption; /* > 0 if corruption found. */
! uint_t kmv_flags; /* dcmd flags */
struct kmem_cache kmv_cache; /* the cache we're operating on */
} kmem_verify_t;
/*
* verify_pattern()
*** 3055,3065 ****
kmem_verify_t *kmv = (kmem_verify_t *)private;
uint64_t *buf = kmv->kmv_buf; /* buf to validate */
int64_t corrupt; /* corruption offset */
kmem_buftag_t *buftagp; /* ptr to buftag */
kmem_cache_t *cp = &kmv->kmv_cache;
! int besilent = kmv->kmv_besilent;
/*LINTED*/
buftagp = KMEM_BUFTAG(cp, buf);
/*
--- 3055,3065 ----
kmem_verify_t *kmv = (kmem_verify_t *)private;
uint64_t *buf = kmv->kmv_buf; /* buf to validate */
int64_t corrupt; /* corruption offset */
kmem_buftag_t *buftagp; /* ptr to buftag */
kmem_cache_t *cp = &kmv->kmv_cache;
! boolean_t besilent = !!(kmv->kmv_flags & (DCMD_LOOP | DCMD_PIPE_OUT));
/*LINTED*/
buftagp = KMEM_BUFTAG(cp, buf);
/*
*** 3101,3110 ****
--- 3101,3112 ----
goto corrupt;
}
return (WALK_NEXT);
corrupt:
+ if (kmv->kmv_flags & DCMD_PIPE_OUT)
+ mdb_printf("%p\n", addr);
kmv->kmv_corruption++;
return (WALK_NEXT);
}
/*
*** 3122,3132 ****
/*LINTED*/
kmem_buftag_t *buftagp = KMEM_BUFTAG(cp, buf);
uint32_t *ip = (uint32_t *)buftagp;
uint8_t *bp = (uint8_t *)buf;
int looks_ok = 0, size_ok = 1; /* flags for finding corruption */
! int besilent = kmv->kmv_besilent;
/*
* Read the buffer to check.
*/
if (mdb_vread(buf, kmv->kmv_size, addr) == -1) {
--- 3124,3134 ----
/*LINTED*/
kmem_buftag_t *buftagp = KMEM_BUFTAG(cp, buf);
uint32_t *ip = (uint32_t *)buftagp;
uint8_t *bp = (uint8_t *)buf;
int looks_ok = 0, size_ok = 1; /* flags for finding corruption */
! boolean_t besilent = !!(kmv->kmv_flags & (DCMD_LOOP | DCMD_PIPE_OUT));
/*
* Read the buffer to check.
*/
if (mdb_vread(buf, kmv->kmv_size, addr) == -1) {
*** 3180,3189 ****
--- 3182,3194 ----
goto corrupt;
}
return (WALK_NEXT);
corrupt:
+ if (kmv->kmv_flags & DCMD_PIPE_OUT)
+ mdb_printf("%p\n", addr);
+
kmv->kmv_corruption++;
return (WALK_NEXT);
}
/*ARGSUSED2*/
*** 3198,3211 ****
--- 3203,3224 ----
addr) == -1) {
mdb_warn("couldn't read kmem_cache %p", addr);
return (DCMD_ERR);
}
+ if ((kmv.kmv_cache.cache_dump.kd_unsafe ||
+ kmv.kmv_cache.cache_dump.kd_alloc_fails) &&
+ !(flags & (DCMD_LOOP | DCMD_PIPE_OUT))) {
+ mdb_warn("WARNING: cache was used during dump: "
+ "corruption may be incorrectly reported\n");
+ }
+
kmv.kmv_size = kmv.kmv_cache.cache_buftag +
sizeof (kmem_buftag_t);
kmv.kmv_buf = mdb_alloc(kmv.kmv_size, UM_SLEEP | UM_GC);
kmv.kmv_corruption = 0;
+ kmv.kmv_flags = flags;
if ((kmv.kmv_cache.cache_flags & KMF_REDZONE)) {
check_alloc = 1;
if (kmv.kmv_cache.cache_flags & KMF_DEADBEEF)
check_free = 1;
*** 3216,3276 ****
kmv.kmv_cache.cache_name);
}
return (DCMD_ERR);
}
! if (flags & DCMD_LOOP) {
! /*
! * table mode, don't print out every corrupt buffer
! */
! kmv.kmv_besilent = 1;
! } else {
mdb_printf("Summary for cache '%s'\n",
kmv.kmv_cache.cache_name);
mdb_inc_indent(2);
- kmv.kmv_besilent = 0;
}
if (check_alloc)
(void) mdb_pwalk("kmem", verify_alloc, &kmv, addr);
if (check_free)
(void) mdb_pwalk("freemem", verify_free, &kmv, addr);
if (flags & DCMD_LOOP) {
if (kmv.kmv_corruption == 0) {
mdb_printf("%-*s %?p clean\n",
KMEM_CACHE_NAMELEN,
kmv.kmv_cache.cache_name, addr);
} else {
! char *s = ""; /* optional s in "buffer[s]" */
! if (kmv.kmv_corruption > 1)
! s = "s";
!
! mdb_printf("%-*s %?p %d corrupt buffer%s\n",
! KMEM_CACHE_NAMELEN,
kmv.kmv_cache.cache_name, addr,
! kmv.kmv_corruption, s);
}
} else {
/*
! * This is the more verbose mode, when the user has
! * type addr::kmem_verify. If the cache was clean,
! * nothing will have yet been printed. So say something.
*/
if (kmv.kmv_corruption == 0)
mdb_printf("clean\n");
mdb_dec_indent(2);
}
} else {
/*
* If the user didn't specify a cache to verify, we'll walk all
* kmem_cache's, specifying ourself as a callback for each...
* this is the equivalent of '::walk kmem_cache .::kmem_verify'
*/
! mdb_printf("%<u>%-*s %-?s %-20s%</b>\n", KMEM_CACHE_NAMELEN,
! "Cache Name", "Addr", "Cache Integrity");
(void) (mdb_walk_dcmd("kmem_cache", "kmem_verify", 0, NULL));
}
return (DCMD_OK);
}
--- 3229,3298 ----
kmv.kmv_cache.cache_name);
}
return (DCMD_ERR);
}
! if (!(flags & (DCMD_LOOP | DCMD_PIPE_OUT))) {
mdb_printf("Summary for cache '%s'\n",
kmv.kmv_cache.cache_name);
mdb_inc_indent(2);
}
if (check_alloc)
(void) mdb_pwalk("kmem", verify_alloc, &kmv, addr);
if (check_free)
(void) mdb_pwalk("freemem", verify_free, &kmv, addr);
+ if (!(flags & DCMD_PIPE_OUT)) {
if (flags & DCMD_LOOP) {
if (kmv.kmv_corruption == 0) {
mdb_printf("%-*s %?p clean\n",
KMEM_CACHE_NAMELEN,
kmv.kmv_cache.cache_name, addr);
} else {
! mdb_printf("%-*s %?p %d corrupt "
! "buffer%s\n", KMEM_CACHE_NAMELEN,
kmv.kmv_cache.cache_name, addr,
! kmv.kmv_corruption,
! kmv.kmv_corruption > 1 ? "s" : "");
}
} else {
/*
! * This is the more verbose mode, when the user
! * typed addr::kmem_verify. If the cache was
! * clean, nothing will have yet been printed. So
! * say something.
*/
if (kmv.kmv_corruption == 0)
mdb_printf("clean\n");
mdb_dec_indent(2);
}
+ }
} else {
/*
* If the user didn't specify a cache to verify, we'll walk all
* kmem_cache's, specifying ourself as a callback for each...
* this is the equivalent of '::walk kmem_cache .::kmem_verify'
*/
!
! if (!(flags & DCMD_PIPE_OUT)) {
! uintptr_t dump_curr;
! uintptr_t dump_end;
!
! if (mdb_readvar(&dump_curr, "kmem_dump_curr") != -1 &&
! mdb_readvar(&dump_end, "kmem_dump_end") != -1 &&
! dump_curr == dump_end) {
! mdb_warn("WARNING: exceeded kmem_dump_size; "
! "corruption may be incorrectly reported\n");
! }
!
! mdb_printf("%<u>%-*s %-?s %-20s%</b>\n",
! KMEM_CACHE_NAMELEN, "Cache Name", "Addr",
! "Cache Integrity");
! }
!
(void) (mdb_walk_dcmd("kmem_cache", "kmem_verify", 0, NULL));
}
return (DCMD_OK);
}