VM information interface

This commit is contained in:
David van Moolenbroek 2010-01-19 21:00:20 +00:00
parent 7d51b0cce1
commit 61bb82a44b
18 changed files with 412 additions and 64 deletions

View file

@ -200,7 +200,7 @@ service is
SYSCTL # 44
;
vm
CTL
INFO
;
uid 0;
};

View file

@ -974,13 +974,17 @@
# define VM_NOTIFY_SIG_ENDPOINT m1_i1
# define VM_NOTIFY_SIG_IPC m1_i2
#define VM_CTL (VM_RQ_BASE+40)
#define VCTL_WHAT m1_i1
#define VCTL_PARAM m1_i2
#define VM_INFO (VM_RQ_BASE+40)
# define VMI_WHAT m2_i1
# define VMI_EP m2_i2
# define VMI_COUNT m2_i3
# define VMI_PTR m2_p1
# define VMI_NEXT m2_l1
/* VCTL_PARAMs */
#define VCTLP_STATS_MEM 1
#define VCTLP_STATS_EP 2
/* VMI_WHAT values. */
#define VMIW_STATS 1
#define VMIW_USAGE 2
#define VMIW_REGION 3
/* Total. */
#define NR_VM_CALLS 41

View file

@ -27,5 +27,34 @@ _PROTOTYPE( int vm_ctl, (int what, int param));
_PROTOTYPE( int vm_set_priv, (int procnr, void *buf));
_PROTOTYPE( int vm_query_exit, (int *endpt));
struct vm_stats_info {
int vsi_pagesize; /* page size */
int vsi_total; /* total number of memory pages */
int vsi_free; /* number of free pages */
int vsi_largest; /* largest number of consecutive free pages */
};
struct vm_usage_info {
vir_bytes vui_total; /* total amount of process memory */
vir_bytes vui_common; /* part of memory mapped in more than once */
vir_bytes vui_shared; /* shared (non-COW) part of common memory */
};
struct vm_region_info {
int vri_seg; /* segment of virtual region (T or D) */
vir_bytes vri_addr; /* base address of region */
vir_bytes vri_length; /* length of region */
int vri_prot; /* protection flags (PROT_) */
int vri_flags; /* memory flags (subset of MAP_) */
};
#define MAX_VRI_COUNT 64 /* max. number of regions provided at once */
_PROTOTYPE( int vm_info_stats, (struct vm_stats_info *vfi) );
_PROTOTYPE( int vm_info_usage, (endpoint_t who,
struct vm_usage_info *vui) );
_PROTOTYPE( int vm_info_region, (endpoint_t who,
struct vm_region_info *vri, int count, vir_bytes *next) );
#endif /* _MINIX_VM_H */

View file

@ -80,11 +80,11 @@ libsys_FILES=" \
taskcall.c \
ds.c \
vm_brk.c \
vm_ctl.c \
vm_exec_newmem.c \
vm_exit.c \
vm_notify_sig.c \
vm_fork.c \
vm_info.c \
vm_map_phys.c \
vm_umap.c \
vm_push_sig.c"

View file

@ -1,18 +0,0 @@
#include "syslib.h"
#include <minix/vm.h>
/*===========================================================================*
* vm_umap *
*===========================================================================*/
PUBLIC int vm_ctl(int what, int param)
{
message m;
int result;
m.VCTL_WHAT = what;
m.VCTL_PARAM = param;
return _taskcall(VM_PROC_NR, VM_CTL, &m);
}

54
lib/syslib/vm_info.c Normal file
View file

@ -0,0 +1,54 @@
#include "syslib.h"
#include <minix/vm.h>
/*===========================================================================*
* vm_info_stats *
*===========================================================================*/
PUBLIC int vm_info_stats(struct vm_stats_info *vsi)
{
message m;
m.VMI_WHAT = VMIW_STATS;
m.VMI_PTR = (void *) vsi;
return _taskcall(VM_PROC_NR, VM_INFO, &m);
}
/*===========================================================================*
* vm_info_usage *
*===========================================================================*/
PUBLIC int vm_info_usage(endpoint_t who, struct vm_usage_info *vui)
{
message m;
m.VMI_WHAT = VMIW_USAGE;
m.VMI_EP = who;
m.VMI_PTR = (void *) vui;
return _taskcall(VM_PROC_NR, VM_INFO, &m);
}
/*===========================================================================*
* vm_info_region *
*===========================================================================*/
PUBLIC int vm_info_region(endpoint_t who, struct vm_region_info *vri,
int count, vir_bytes *next)
{
message m;
int result;
m.VMI_WHAT = VMIW_REGION;
m.VMI_EP = who;
m.VMI_COUNT = count;
m.VMI_PTR = (void *) vri;
m.VMI_NEXT = *next;
if ((result = _taskcall(VM_PROC_NR, VM_INFO, &m)) != OK)
return result;
*next = m.VMI_NEXT;
return m.VMI_COUNT;
}

View file

@ -20,7 +20,7 @@ CFLAGS = $(CPROFILE) $(CPPFLAGS)
LDFLAGS = -i
LIBS = -lsys
OBJ = main.o dmp.o dmp_kernel.o dmp_pm.o dmp_fs.o dmp_rs.o dmp_ds.o
OBJ = main.o dmp.o dmp_kernel.o dmp_pm.o dmp_fs.o dmp_rs.o dmp_ds.o dmp_vm.o
# build local binary
all build: $(SERVER)

View file

@ -23,7 +23,7 @@ struct hook_entry {
{ F5, monparams_dmp, "Boot monitor parameters" },
{ F6, irqtab_dmp, "IRQ hooks and policies" },
{ F7, kmessages_dmp, "Kernel messages" },
{ F8, vm_dmp, "VM status" },
{ F8, vm_dmp, "VM status and process maps" },
{ F10, kenv_dmp, "Kernel parameters" },
{ F11, timing_dmp, "Timing details (if enabled)" },
{ SF1, mproc_dmp, "Process manager process table" },
@ -126,12 +126,3 @@ PUBLIC void mapping_dmp(void)
printf(" %10s. %s\n", key_name(hooks[h].key), hooks[h].name);
printf("\n");
}
/*===========================================================================*
* vm_dmp *
*===========================================================================*/
PUBLIC void vm_dmp(void)
{
vm_ctl(VCTLP_STATS_MEM, 0);
}

View file

@ -1,6 +1,8 @@
#include "inc.h"
#include "../ds/store.h"
#define LINES 22
PRIVATE struct data_store ds_store[NR_DS_KEYS];
PUBLIC void data_store_dmp()
@ -16,7 +18,7 @@ PUBLIC void data_store_dmp()
printf("Data store contents:\n");
printf("-slot- ------key------ -----owner----- ---type--- ----value---\n");
for(i = prev_i; i < NR_DS_KEYS; i++) {
for(i = prev_i; i < NR_DS_KEYS && n < LINES; i++) {
p = &ds_store[i];
if(!(p->flags & DSF_IN_USE))
continue;
@ -43,8 +45,7 @@ PUBLIC void data_store_dmp()
return;
}
if(n++ == 21)
break;
n++;
}
if (i >= NR_DS_KEYS) i = 0;

119
servers/is/dmp_vm.c Normal file
View file

@ -0,0 +1,119 @@
/* Debugging dump procedures for the VM server. */
#include "inc.h"
#include <sys/mman.h>
#include <minix/vm.h>
#include <timers.h>
#include "../../kernel/proc.h"
#define LINES 24
PRIVATE void print_region(struct vm_region_info *vri)
{
char c;
switch (vri->vri_seg) {
case T: c = 'T'; break;
case D: c = 'D'; break;
default: c = '?';
}
printf(" %c %08lx-%08lx %c%c%c %c (%lu kB)\n", c, vri->vri_addr,
vri->vri_addr + vri->vri_length,
(vri->vri_prot & PROT_READ) ? 'r' : '-',
(vri->vri_prot & PROT_WRITE) ? 'w' : '-',
(vri->vri_prot & PROT_EXEC) ? 'x' : '-',
(vri->vri_flags & MAP_SHARED) ? 's' : 'p',
vri->vri_length / 1024L);
}
PUBLIC void vm_dmp()
{
static struct proc proc[NR_TASKS + NR_PROCS];
static struct vm_region_info vri[LINES];
struct vm_stats_info vsi;
struct vm_usage_info vui;
static int prev_i = -1;
static vir_bytes prev_base = 0;
int r, r2, i, j, first, n = 0;
if (prev_i == -1) {
if ((r = vm_info_stats(&vsi)) != OK) {
report("IS", "warning: couldn't talk to VM", r);
return;
}
printf("Total %u kB, free %u kB, largest free area %u kB\n",
vsi.vsi_total * (vsi.vsi_pagesize / 1024),
vsi.vsi_free * (vsi.vsi_pagesize / 1024),
vsi.vsi_largest * (vsi.vsi_pagesize / 1024));
n++;
printf("\n");
n++;
prev_i++;
}
if ((r = sys_getproctab(proc)) != OK) {
report("IS", "warning: couldn't get copy of process table", r);
return;
}
for (i = prev_i; i < NR_TASKS + NR_PROCS && n < LINES; i++, prev_base = 0) {
if (i < NR_TASKS || isemptyp(&proc[i])) continue;
/* The first batch dump for each process contains a header line. */
first = prev_base == 0;
r = vm_info_region(proc[i].p_endpoint, vri, LINES - first, &prev_base);
if (r < 0) {
printf("Process %d (%s): error %d\n",
proc[i].p_endpoint, proc[i].p_name, r);
n++;
continue;
}
if (first) {
/* The entire batch should fit on the screen. */
if (n + 1 + r > LINES) {
prev_base = 0; /* restart on next page */
break;
}
if ((r2 = vm_info_usage(proc[i].p_endpoint, &vui)) != OK) {
printf("Process %d (%s): error %d\n",
proc[i].p_endpoint, proc[i].p_name, r2);
n++;
continue;
}
printf("Process %d (%s): total %lu kB, common %lu kB, "
"shared %lu kB\n",
proc[i].p_endpoint, proc[i].p_name,
vui.vui_total / 1024L, vui.vui_common / 1024L,
vui.vui_shared / 1024L);
n++;
}
for (j = 0; j < r; j++) {
print_region(&vri[j]);
n++;
}
if (n > LINES) printf("IS: internal error\n");
if (n == LINES) break;
/* This may have to wipe out the "--more--" from below. */
printf(" \n");
n++;
}
if (i >= NR_TASKS + NR_PROCS) {
i = -1;
prev_base = 0;
}
else printf("--more--\r");
prev_i = i;
}

View file

@ -803,7 +803,7 @@ struct
{ "GETPHYS", VM_GETPHYS },
{ "GETREFCNT", VM_GETREF },
{ "QUERYEXIT", VM_QUERY_EXIT },
{ "CTL", VM_CTL },
{ "INFO", VM_INFO },
{ NULL, 0 },
};

View file

@ -405,6 +405,8 @@ struct memory *chunks; /* list of free memory chunks */
addr_init(&addravl);
total_pages = 0;
/* Use the chunks of physical memory to allocate holes. */
for (i=NR_MEMS-1; i>=0; i--) {
if (chunks[i].size > 0) {
@ -413,6 +415,7 @@ struct memory *chunks; /* list of free memory chunks */
if(first || from < mem_low) mem_low = from;
if(first || to > mem_high) mem_high = to;
FREE_MEM(chunks[i].base, chunks[i].size);
total_pages += chunks[i].size;
first = 0;
}
}

View file

@ -24,6 +24,9 @@ EXTERN int incheck;
EXTERN long vm_sanitychecklevel;
#endif
/* total number of memory pages */
EXTERN int total_pages;
/* vm operation mode state and values */
EXTERN long vm_paged;

View file

@ -61,6 +61,36 @@ PUBLIC char *arch_map2str(struct vmproc *vmp, vir_bytes addr)
return bufstr;
}
/*===========================================================================*
* arch_map2info *
*===========================================================================*/
PUBLIC vir_bytes arch_map2info(struct vmproc *vmp, vir_bytes addr, int *seg,
int *prot)
{
vir_bytes textstart = CLICK2ABS(vmp->vm_arch.vm_seg[T].mem_phys);
vir_bytes textend = textstart +
CLICK2ABS(vmp->vm_arch.vm_seg[T].mem_len);
vir_bytes datastart = CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys);
/* The protection to be returned here is that of the segment. */
if(addr < textstart) {
*seg = D;
*prot = PROT_READ | PROT_WRITE | PROT_EXEC;
return addr;
} else if(addr < datastart) {
*seg = T;
*prot = PROT_READ | PROT_EXEC;
return addr - textstart;
} else {
*seg = D;
if (textstart == textend) /* common I&D? */
*prot = PROT_READ | PROT_WRITE | PROT_EXEC;
else
*prot = PROT_READ | PROT_WRITE;
return addr - datastart;
}
}
/*===========================================================================*
* arch_addrok *
*===========================================================================*/

View file

@ -347,7 +347,7 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
CALLMAP(VM_GETPHYS, do_get_phys);
CALLMAP(VM_SHM_UNMAP, do_shared_unmap);
CALLMAP(VM_GETREF, do_get_refcount);
CALLMAP(VM_CTL, do_ctl);
CALLMAP(VM_INFO, do_info);
CALLMAP(VM_QUERY_EXIT, do_query_exit);
/* Sanity checks */

View file

@ -10,6 +10,7 @@ struct phys_region;
#include <minix/ipc.h>
#include <minix/endpoint.h>
#include <minix/safecopies.h>
#include <minix/vm.h>
#include <timers.h>
#include <stdio.h>
#include <pagetable.h>
@ -42,7 +43,7 @@ _PROTOTYPE( void reserve_proc_mem, (struct memory *mem_chunks,
struct mem_map *map_ptr));
_PROTOTYPE( int vm_isokendpt, (endpoint_t ep, int *proc) );
_PROTOTYPE( int get_stack_ptr, (int proc_nr, vir_bytes *sp) );
_PROTOTYPE( int do_ctl, (message *) );
_PROTOTYPE( int do_info, (message *) );
/* exit.c */
_PROTOTYPE( void clear_proc, (struct vmproc *vmp) );
@ -168,16 +169,22 @@ _PROTOTYPE(int map_copy_ph_block, (struct vmproc *vmp,
struct vir_region *region, struct phys_region *ph));
_PROTOTYPE(void pb_unreferenced, (struct vir_region *region,
struct phys_region *pr));
_PROTOTYPE(void get_usage_info, (struct vmproc *vmp,
struct vm_usage_info *vui));
_PROTOTYPE(int get_region_info, (struct vmproc *vmp,
struct vm_region_info *vri, int count, vir_bytes *nextp));
#if SANITYCHECKS
_PROTOTYPE(void map_sanitycheck,(char *file, int line));
#endif
/* $(ARCH)/vm.c */
_PROTOTYPE( vir_bytes, arch_map2vir(struct vmproc *vmp, vir_bytes addr));
_PROTOTYPE( char *, arch_map2str(struct vmproc *vmp, vir_bytes addr));
_PROTOTYPE( vir_bytes, arch_vir2map(struct vmproc *vmp, vir_bytes addr));
_PROTOTYPE( vir_bytes, arch_vir2map_text(struct vmproc *vmp, vir_bytes addr));
_PROTOTYPE( vir_bytes, arch_addrok(struct vmproc *vmp, vir_bytes addr));
_PROTOTYPE( vir_bytes arch_map2vir, (struct vmproc *vmp, vir_bytes addr));
_PROTOTYPE( char *arch_map2str, (struct vmproc *vmp, vir_bytes addr));
_PROTOTYPE( vir_bytes arch_map2info, (struct vmproc *vmp, vir_bytes addr,
int *space, int *prot));
_PROTOTYPE( vir_bytes arch_vir2map, (struct vmproc *vmp, vir_bytes addr));
_PROTOTYPE( vir_bytes arch_vir2map_text, (struct vmproc *vmp, vir_bytes addr));
_PROTOTYPE( vir_bytes arch_addrok, (struct vmproc *vmp, vir_bytes addr));
/* rs.c */
_PROTOTYPE(int do_rs_set_priv, (message *m));

View file

@ -1455,6 +1455,76 @@ PUBLIC int map_get_ref(struct vmproc *vmp, vir_bytes addr, u8_t *cnt)
return OK;
}
/*========================================================================*
* get_usage_info *
*========================================================================*/
PUBLIC void get_usage_info(struct vmproc *vmp, struct vm_usage_info *vui)
{
struct vir_region *vr;
physr_iter iter;
struct phys_region *ph;
vir_bytes len;
memset(vui, 0, sizeof(*vui));
for(vr = vmp->vm_regions; vr; vr = vr->next) {
physr_start_iter_least(vr->phys, &iter);
while((ph = physr_get_iter(&iter))) {
len = ph->ph->length;
/* All present pages are counted towards the total. */
vui->vui_total += len;
if (ph->ph->refcount > 1) {
/* Any page with a refcount > 1 is common. */
vui->vui_common += len;
/* Any common, non-COW page is shared. */
if (vr->flags & VR_SHARED ||
ph->ph->share_flag == PBSH_SMAP)
vui->vui_shared += len;
}
physr_incr_iter(&iter);
}
}
}
/*===========================================================================*
* get_region_info *
*===========================================================================*/
PUBLIC int get_region_info(struct vmproc *vmp, struct vm_region_info *vri,
int max, vir_bytes *nextp)
{
struct vir_region *vr;
vir_bytes next;
int count;
next = *nextp;
if (!max) return 0;
for(vr = vmp->vm_regions; vr; vr = vr->next)
if (vr->vaddr >= next) break;
if (!vr) return 0;
for(count = 0; vr && count < max; vr = vr->next, count++, vri++) {
vri->vri_addr = arch_map2info(vmp, vr->vaddr, &vri->vri_seg,
&vri->vri_prot);
vri->vri_length = vr->length;
/* "AND" the provided protection with per-page protection. */
if (!(vr->flags & VR_WRITABLE))
vri->vri_prot &= ~PROT_WRITE;
vri->vri_flags = (vr->flags & VR_SHARED) ? MAP_SHARED : 0;
next = vr->vaddr + vr->length;
}
*nextp = next;
return count;
}
/*========================================================================*
* regionprintstats *

View file

@ -122,7 +122,7 @@ PUBLIC int vm_isokendpt(endpoint_t endpoint, int *proc)
{
*proc = _ENDPOINT_P(endpoint);
if(*proc < 0 || *proc >= NR_PROCS)
vm_panic("crazy slot number", *proc);
return EINVAL;
if(*proc >= 0 && endpoint != vmproc[*proc].vm_endpoint)
return EDEADSRCDST;
if(*proc >= 0 && !(vmproc[*proc].vm_flags & VMF_INUSE))
@ -166,27 +166,82 @@ char *brk_addr;
}
/*===========================================================================*
* do_ctl *
* do_info *
*===========================================================================*/
PUBLIC int do_ctl(message *m)
PUBLIC int do_info(message *m)
{
int pages, nodes;
int pr;
struct vm_stats_info vsi;
struct vm_usage_info vui;
static struct vm_region_info vri[MAX_VRI_COUNT];
struct vmproc *vmp;
vir_bytes addr, size, next, ptr;
int r, pr, dummy, count;
switch(m->VCTL_WHAT) {
case VCTLP_STATS_MEM:
printmemstats();
break;
case VCTLP_STATS_EP:
if(vm_isokendpt(m->VCTL_PARAM, &pr) != OK)
return EINVAL;
printregionstats(&vmproc[pr]);
break;
default:
if (vm_isokendpt(m->m_source, &pr) != OK)
return EINVAL;
vmp = &vmproc[pr];
ptr = (vir_bytes) m->VMI_PTR;
switch(m->VMI_WHAT) {
case VMIW_STATS:
vsi.vsi_pagesize = VM_PAGE_SIZE;
vsi.vsi_total = total_pages;
memstats(&dummy, &vsi.vsi_free, &vsi.vsi_largest);
addr = (vir_bytes) &vsi;
size = sizeof(vsi);
break;
case VMIW_USAGE:
if (vm_isokendpt(m->VMI_EP, &pr) != OK)
return EINVAL;
get_usage_info(&vmproc[pr], &vui);
addr = (vir_bytes) &vui;
size = sizeof(vui);
break;
case VMIW_REGION:
if (vm_isokendpt(m->VMI_EP, &pr) != OK)
return EINVAL;
count = MIN(m->VMI_COUNT, MAX_VRI_COUNT);
next = m->VMI_NEXT;
count = get_region_info(&vmproc[pr], vri, count, &next);
m->VMI_COUNT = count;
m->VMI_NEXT = next;
addr = (vir_bytes) vri;
size = sizeof(vri[0]) * count;
break;
default:
return EINVAL;
}
return OK;
if (size == 0)
return OK;
/* Make sure that no page faults can occur while copying out. A page
* fault would cause the kernel to send a notify to us, while we would
* be waiting for the result of the copy system call, resulting in a
* deadlock. Note that no memory mapping can be undone without the
* involvement of VM, so we are safe until we're done.
*/
r = handle_memory(vmp, arch_vir2map(vmp, ptr), size, 1 /*wrflag*/);
if (r != OK) return r;
/* Now that we know the copy out will succeed, perform the actual copy
* operation.
*/
return sys_datacopy(SELF, addr,
(vir_bytes) vmp->vm_endpoint, ptr, size);
}