memory.c revision 0fab61babcfe4e703c15518d8ef8d07e1a545650
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <mdb/mdb_modapi.h>
#include <sys/balloon_impl.h>
#endif
/*
* Page walker.
* By default, this will walk all pages in the system. If given an
* address, it will walk all pages belonging to the vnode at that
* address.
*/
/*
* page_walk_data
*
* pw_hashleft is set to -1 when walking a vnode's pages, and holds the
* number of hash locations remaining in the page hash table when
* walking all pages.
*
* The astute reader will notice that pw_hashloc is only used when
* reading all pages (to hold a pointer to our location in the page
* hash table), and that pw_first is only used when reading the pages
* belonging to a particular vnode (to hold a pointer to the first
* page). While these could be combined to be a single pointer, they
* are left separate for clarity.
*/
typedef struct page_walk_data {
long pw_hashleft;
void **pw_hashloc;
int
{
void **ptr;
/*
* Walk all pages
*/
mdb_warn("page_hash, page_hashsz not found or invalid");
return (WALK_ERR);
}
/*
* Since we are walking all pages, initialize hashleft
* to be the remaining number of entries in the page
* hash. hashloc is set the start of the page hash
* table. Setting the walk address to 0 indicates that
* we aren't currently following a hash chain, and that
* we need to scan the page hash table for a page.
*/
} else {
/*
* Walk just this vnode
*/
mdb_warn("unable to read vnode_t at %#lx",
return (WALK_ERR);
}
/*
* We set hashleft to -1 to indicate that we are
* walking a vnode, and initialize first to 0 (it is
* used to terminate the walk, so it must not be set
* until after we have walked the first page). The
* walk address is set to the first page.
*/
}
return (WALK_NEXT);
}
int
{
if (pwd->pw_hashleft < 0) {
/* We're walking a vnode's pages */
/*
* If we don't have any pages to walk, we have come
* back around to the first one (we finished), or we
* can't read the page we're looking at, we are done.
*/
return (WALK_DONE);
return (WALK_ERR);
}
/*
* Set the walk address to the next page, and if the
* first page hasn't been set yet (i.e. we are on the
* first page), set it.
*/
} else if (pwd->pw_hashleft > 0) {
/* We're walking all pages */
/*
* If pp (the walk address) is NULL, we scan through
* the page hash table until we find a page.
*/
/*
* Iterate through the page hash table until we
* find a page or reach the end.
*/
do {
mdb_warn("unable to read from %#p",
pwd->pw_hashloc);
return (WALK_ERR);
}
pwd->pw_hashleft--;
pwd->pw_hashloc++;
/*
* We've reached the end; exit.
*/
return (WALK_DONE);
}
return (WALK_ERR);
}
/*
* Set the walk address to the next page.
*/
} else {
/* We've finished walking all pages. */
return (WALK_DONE);
}
}
void
{
}
/* Summary statistics of pages */
typedef struct memstat {
} memstat_t;
/*
* Summarize pages by type; called from page walker.
*/
/* ARGSUSED */
static int
{
/* read page's vnode pointer */
mdb_warn("unable to read vnode_t at %#lx",
ptr);
return (WALK_ERR);
}
} else
stats->ms_cachelist++;
stats->ms_zfs_data++;
else
return (WALK_NEXT);
}
/* ARGSUSED */
int
{
#endif
return (DCMD_USAGE);
/* Grab base page size */
mdb_warn("unable to read _pagesize");
return (DCMD_ERR);
}
/* Total physical memory */
mdb_warn("unable to read total_pages");
return (DCMD_ERR);
}
/* Artificially limited memory */
mdb_warn("unable to read physmem");
return (DCMD_ERR);
}
/* read kernel vnode pointer */
mdb_warn("unable to read kvp");
return (DCMD_ERR);
}
/*
* Read the zio vnode pointer. It may not exist on all kernels, so it
* it isn't found, it's not a fatal error.
*/
} else {
}
/* Walk page structures, summarizing usage */
&stats) == -1) {
mdb_warn("can't walk pages");
return (DCMD_ERR);
}
/* read unused pages vnode */
mdb_warn("unable to read unused_pages_vp");
return (DCMD_ERR);
}
/* Find unused pages */
&unused_stats) == -1) {
mdb_warn("can't walk pages");
return (DCMD_ERR);
}
/*
* If physmem != total_pages, then the administrator has limited the
* number of pages available in the system. In order to account for
* this, we reduce the amount normally attributed to the page cache.
*/
((physmem) * 10)))
mdb_printf("Page Summary Pages MB"
" %%Tot\n");
mdb_printf("------------ ---------------- ----------------"
" ----\n");
mdb_printf("Kernel %16llu %16llu %3lu%%\n",
if (stats.ms_zfs_data != 0)
mdb_printf("ZFS File Data %16llu %16llu %3lu%%\n",
mdb_printf("Anon %16llu %16llu %3lu%%\n",
mdb_printf("Exec and libs %16llu %16llu %3lu%%\n",
mdb_printf("Page cache %16llu %16llu %3lu%%\n",
mdb_printf("Free (cachelist) %16llu %16llu %3lu%%\n",
/*
* occasionally, we double count pages above. To avoid printing
* absurdly large values for freemem, we clamp it at zero.
*/
else
freemem = 0;
/* Are we running under Xen? If so, get balloon memory usage. */
else
freemem = 0;
}
#endif
if (bln_size != -1) {
mdb_printf("Balloon %16lu %16llu %3lu%%\n",
}
#endif
mdb_printf("\nTotal %16lu %16lu\n",
if (physmem != total_pages) {
mdb_printf("Physical %16lu %16lu\n",
}
return (DCMD_OK);
}
int
{
page_t p;
if (!(flags & DCMD_ADDRSPEC)) {
mdb_warn("can't walk pages");
return (DCMD_ERR);
}
return (DCMD_OK);
}
if (DCMD_HDRSPEC(flags)) {
mdb_printf("%<u>%?s %?s %16s %8s %3s %3s %2s %2s %2s%</u>\n",
"PAGE", "VNODE", "OFFSET", "SELOCK",
"LCT", "COW", "IO", "FS", "ST");
}
return (DCMD_ERR);
}
mdb_printf("%0?lx %?p %16llx %8x %3d %3d %2x %2x %2x\n",
return (DCMD_OK);
}
int
{
void *ptr;
mdb_warn("swapinfo not found or invalid");
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
return (WALK_DONE);
return (WALK_ERR);
}
}
int
{
char *name;
if (!(flags & DCMD_ADDRSPEC)) {
mdb_warn("can't walk swapinfo");
return (DCMD_ERR);
}
return (DCMD_OK);
}
if (DCMD_HDRSPEC(flags)) {
mdb_printf("%<u>%?s %?s %9s %9s %s%</u>\n",
"ADDR", "VNODE", "PAGES", "FREE", "NAME");
}
return (DCMD_ERR);
}
name = "*error*";
mdb_printf("%0?lx %?p %9d %9d %s\n",
return (DCMD_OK);
}
int
{
return (WALK_DONE);
return (WALK_ERR);
}
}
int
{
if (!(flags & DCMD_ADDRSPEC)) {
int i;
static const char *lists[] = {
"phys_install",
"phys_avail",
"virt_avail"
};
return (DCMD_USAGE);
if (!list)
list = 1;
if (!(list & 1))
continue;
return (DCMD_ERR);
}
ptr) == -1) {
mdb_warn("can't walk memlist");
return (DCMD_ERR);
}
}
return (DCMD_OK);
}
if (DCMD_HDRSPEC(flags))
return (DCMD_ERR);
}
return (DCMD_OK);
}