/* gcc -Wall -o logdirty -O -lxenctrl logdirty.c */ #include #include #include #include #include #include #include #define PAGE_SHIFT XC_PAGE_SHIFT #define ROUNDUP(_x,_w) (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1)) #define NRPAGES(x) (ROUNDUP(x, PAGE_SHIFT) >> PAGE_SHIFT) #define BITS_PER_LONG (sizeof(unsigned long) * 8) #define ORDER_LONG (sizeof(unsigned long) == 4 ? 5 : 6) static unsigned int domid = 0; static xc_interface *xch; static unsigned long xdmg(xc_interface *c, unsigned int d) { unsigned long r; #if XEN_DOMCTL_INTERFACE_VERSION < 0x0b r = xc_domain_maximum_gpfn(c, d); #else xen_pfn_t gpfns = 0; r = xc_domain_maximum_gpfn(c, d, &gpfns); #endif return r + 1; } static void sigint_handler(int sig) { int rc; fprintf(stderr, "User aborted\n"); rc = xc_shadow_control(xch, domid, XEN_DOMCTL_SHADOW_OP_OFF, NULL, 0, NULL, 0, NULL); if (rc < 0) perror("XEN_DOMCTL_SHADOW_OP_OFF hypercall failed\n"); exit(1); } static inline int bitmap_size(int nr_bits) { int nr_long, nr_bytes; nr_long = (nr_bits + BITS_PER_LONG - 1) >> ORDER_LONG; nr_bytes = nr_long * sizeof(unsigned long); return nr_bytes; } int main(int argc, char *argv[]) { int rc, ret = 1, i, runs = 42; unsigned int lflags; xentoollog_level lvl; xentoollog_logger *l; DECLARE_HYPERCALL_BUFFER(unsigned long, to_skip); unsigned long p2m_size; xc_shadow_op_stats_t stats; errno = EINVAL; if (argc > 1) domid = atoi(argv[1]); if (!domid) goto out; if (argc > 2) runs = atoi(argv[2]); if (!runs) goto out; errno = 0; lvl = XTL_DEBUG; lflags = XTL_STDIOSTREAM_SHOW_PID | XTL_STDIOSTREAM_HIDE_PROGRESS; l = (xentoollog_logger *) xtl_createlogger_stdiostream(stderr, lvl, lflags); if (!l) goto out; xch = xc_interface_open(l, 0, 0); if (!xch) goto out; p2m_size = xdmg(xch, domid); if (!p2m_size) goto out; to_skip = xc_hypercall_buffer_alloc_pages(xch, to_skip, NRPAGES(bitmap_size(p2m_size))); if (!to_skip) goto out; signal(SIGINT, sigint_handler); rc = xc_shadow_control(xch, domid, XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY, NULL, 0, NULL, 0, NULL); if (rc < 0) { rc = xc_shadow_control(xch, domid, XEN_DOMCTL_SHADOW_OP_OFF, NULL, 0, NULL, 0, NULL); if (rc < 0) goto out; rc = xc_shadow_control(xch, domid, XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY, NULL, 0, NULL, 0, NULL); if (rc < 0) goto out; } rc = xc_shadow_control(xch, domid, XEN_DOMCTL_SHADOW_OP_CLEAN, NULL, 0, NULL, 0, NULL); if (rc < 0) goto out; for (i = 0; i < runs; i++) { sleep(1); if (1) rc = xc_shadow_control(xch, domid, XEN_DOMCTL_SHADOW_OP_CLEAN, HYPERCALL_BUFFER(to_skip), p2m_size, NULL, 0, &stats); if (rc < 0) goto out; printf("%d: faults= %" PRIu32 " dirty= %" PRIu32 "\n", i, stats.fault_count, stats.dirty_count); } rc = xc_shadow_control(xch, domid, XEN_DOMCTL_SHADOW_OP_OFF, NULL, 0, NULL, 0, NULL); if (rc < 0) goto out; errno = ret = 0; out: perror(argv[0]); return ret; }