/*
* 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.
*/
/*
* The following routines implement the hat layer's
* recording of the referenced and modified bits.
*/
/*
* Note, usage of cmn_err requires you not hold any hat layer locks.
*/
int hrm_blist_num = 0;
int hrm_blist_total = 0;
int hrm_mlockinited = 0;
int hrm_allocfail = 0;
static struct hrmstat *hrm_balloc(void);
static void hrm_hashout(struct hrmstat *);
static void hrm_getblk(int);
(HRM_HASHMASK & \
/*
* Called when an address space maps in more pages while stats are being
* collected.
*/
/* ARGSUSED */
void
{
}
/*
* Start the statistics gathering for an address space.
* Return -1 if we can't do it, otherwise return an opaque
* identifier to be used when querying for the gathered statistics.
* The identifier is an unused bit in a_vbits.
* Bit 0 is reserved for swsmon.
*/
int
{
/*
* If the refmod saving memory allocator runs out, print
* a warning message about how to fix it, see comment at
* the beginning of hat_setstat.
*/
if (hrm_allocfailmsg) {
"hrm_balloc failures occured, increase hrm_blist_incr");
hrm_allocfailmsg = 0;
}
/*
* Verify that a buffer of statistics blocks exists
* and allocate more, if needed.
*/
if (chunk < HRM_BLIST_INCR)
chunk = 0;
hrm_getblk((int)chunk);
/*
* Find a unused id in the given address space.
*/
break;
return (-1);
}
return (id);
}
/*
* Record referenced and modified information for an address space.
* Rmbits is a word containing the referenced bit in bit position 1
* and the modified bit in bit position 0.
*
* For current informational uses, one can rerun any program using
* this facility after modifying the hrm_blist_incr to be a larger
* amount so that a larger buffer of blocks will be maintained.
*/
void
{
int h;
if (rmbits == 0)
return;
/*
* Search the hash list for the as and addr we are looking for
* and set the ref and mod bits in every block that matches.
*/
vbits = 0;
}
}
/*
* If we didn't find a block for all of the enabled
* vpages bits, then allocate and initialize a block
* for each bit that was not found.
*/
while (newbits) {
hrm_allocfailmsg = 1;
return;
}
}
}
}
/*
* Free the resources used to maintain the referenced and modified
* statistics for the virtual page view of an address space
* identified by id.
*/
void
{
if (id == 0)
else
return;
}
else
} else
}
/*
* If all statistics blocks are free,
* return the memory to the system.
*/
if (hrm_blist_num == hrm_blist_total) {
/* zero the block list since we are giving back its memory */
hrm_blist_num = 0;
hrm_blist_total = 0;
hrm_memlist = NULL;
} else {
hrm_tmplist = NULL;
}
/*
* If there are any hrmstat structures to be freed, this must only
* be done after we've released hat_statlock.
*/
while (hrm_tmplist != NULL) {
}
}
/*
* Grab memory for statistics gathering of the hat layer.
*/
static void
{
int i;
int hrm_incr;
/*
* XXX The whole private freelist management here really should be
* overhauled.
*
* The freelist should have some knowledge of how much memory is
* needed by a process and thus when hat_resvstat get's called, we can
* increment the freelist needs for that process within this subsystem.
* Thus there will be reservations for all processes which are being
* watched which should be accurate, and consume less memory overall.
*
* For now, just make sure there's enough entries on the freelist to
* handle the current chunk.
*/
(hrm_blist_num <= hrm_blist_lowater) ||
/*
* thread the allocated blocks onto a freelist
* using the first block to hold information for
* freeing them all later
*/
hrm_memlist = hrm;
for (i = 1; i < hrm_incr; i++) {
l = &hrm[i];
hrm_blist = l;
}
}
}
static void
{
int h;
hrm_hashtab[h] = hrm;
}
static void
{
int h;
list = hrm_hashtab[h];
prev_hrm = &hrm_hashtab[h];
while (list) {
return;
}
}
}
/*
* Link a statistic block into an address space and also put it
* on the hash list for future references.
*/
static void
{
}
/*
* Allocate a block for statistics keeping.
* Returns NULL if blocks are unavailable.
*/
static struct hrmstat *
hrm_balloc(void)
{
}
return (hrm);
}
/*
* Set the ref and mod bits for addr within statistics block hrm.
*/
static void
{
}
/*
* Return collected statistics about an address space.
* If clearflag is set, atomically read and zero the bits.
*
* Fill in the data array supplied with the referenced and
* modified bits collected for address range [addr ... addr + len]
* in address space, as, uniquely identified by id.
* The destination is a byte array. We fill in three bits per byte:
* referenced, modified, and hwmapped bits.
* Kernel only interface, can't fault on destination data array.
*
*/
void
{
caddr_t a;
char *dp;
/* allocate enough statistics blocks to cover the len passed in */
/* allocate more statistics blocks if needed */
hrm_getblk(0);
if (hrm_hashtab == NULL) {
/* can happen when victim process exits */
return;
}
size_t n; /* number of pages, temp */
int h; /* hash index */
n = (HRM_PAGES -
if (n > np)
n = np;
int i, nr;
/*
* Extract leading unaligned bits.
*/
i = 0;
while (i < n && (po & 3)) {
if (clearflag)
po++;
i++;
}
/*
* Extract aligned bits.
*/
while (i < nr) {
if (clearflag)
bo++;
po += 4;
i += 4;
}
/*
* Extract trailing unaligned bits.
*/
while (i < n) {
if (clearflag)
po++;
i++;
}
break;
}
}
dp += n;
np -= n;
a += n * MMU_PAGESIZE;
}
}