diff -r 3ea1c6118fc2 tools/libxc/xc_core.c --- a/tools/libxc/xc_core.c Fri Mar 10 01:08:59 2006 +0100 +++ b/tools/libxc/xc_core.c Fri Mar 10 16:58:15 2006 -0500 @@ -8,6 +8,14 @@ /* number of pages to write at a time */ #define DUMP_INCREMENT (4 * 1024) #define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK) + +/* Define the local structure for local_fd_dump. + * A structure is overkill, but someone may use this as an example + */ + +typedef struct dump_args_s { + int fd; +} dump_args_t; static int copy_from_domain_page(int xc_handle, @@ -26,24 +34,21 @@ copy_from_domain_page(int xc_handle, } int -xc_domain_dumpcore(int xc_handle, - uint32_t domid, - const char *corename) +xc_domain_dumpcore2(int xc_handle, + uint32_t domid, + void *args, dumpcore_rtn_t dump_rtn) { unsigned long nr_pages; unsigned long *page_array; xc_dominfo_t info; - int i, nr_vcpus = 0, dump_fd; + int i, nr_vcpus = 0; char *dump_mem, *dump_mem_start = NULL; struct xc_core_header header; vcpu_guest_context_t ctxt[MAX_VIRT_CPUS]; + unsigned char dummy[PAGE_SIZE]; + int dummy_len; + int sts; - - if ((dump_fd = open(corename, O_CREAT|O_RDWR, S_IWUSR|S_IRUSR)) < 0) { - PERROR("Could not open corefile %s: %s", corename, strerror(errno)); - goto error_out; - } - if ((dump_mem_start = malloc(DUMP_INCREMENT*PAGE_SIZE)) == NULL) { PERROR("Could not allocate dump_mem"); goto error_out; @@ -61,27 +66,29 @@ xc_domain_dumpcore(int xc_handle, for (i = 0; i <= info.max_vcpu_id; i++) if (xc_vcpu_getcontext(xc_handle, domid, - i, &ctxt[nr_vcpus]) == 0) + i, &ctxt[nr_vcpus]) == 0) nr_vcpus++; nr_pages = info.nr_pages; - header.xch_magic = XC_CORE_MAGIC; + header.xch_magic = XC_CORE_MAGIC; header.xch_nr_vcpus = nr_vcpus; header.xch_nr_pages = nr_pages; header.xch_ctxt_offset = sizeof(struct xc_core_header); header.xch_index_offset = sizeof(struct xc_core_header) + sizeof(vcpu_guest_context_t)*nr_vcpus; - header.xch_pages_offset = round_pgup(sizeof(struct xc_core_header) + - (sizeof(vcpu_guest_context_t) * nr_vcpus) + - (nr_pages * sizeof(unsigned long))); + dummy_len = (sizeof(struct xc_core_header) + + (sizeof(vcpu_guest_context_t) * nr_vcpus) + + (nr_pages * sizeof(unsigned long))); + header.xch_pages_offset = round_pgup(dummy_len); + + sts = dump_rtn(args, &header, sizeof(struct xc_core_header)); + if (sts != 0) + return sts; - if (write(dump_fd, &header, sizeof(struct xc_core_header)) < 0 || - write(dump_fd, &ctxt, sizeof(ctxt[0]) * nr_vcpus) < 0) - { - PERROR("write failed"); - goto error_out; - } + sts = dump_rtn(args, &ctxt, sizeof(ctxt[0]) * nr_vcpus); + if (sts != 0) + return sts; if ((page_array = malloc(nr_pages * sizeof(unsigned long))) == NULL) { printf("Could not allocate memory\n"); @@ -91,18 +98,21 @@ xc_domain_dumpcore(int xc_handle, printf("Could not get the page frame list\n"); goto error_out; } - if (write(dump_fd, page_array, nr_pages * sizeof(unsigned long)) < 0) - { - PERROR("write failed"); - goto error_out; - } - lseek(dump_fd, header.xch_pages_offset, SEEK_SET); + sts = dump_rtn(args, page_array, nr_pages * sizeof(unsigned long)); + if (sts != 0) + return sts; + + memset(dummy, 0, PAGE_SIZE); + sts = dump_rtn(args, dummy, header.xch_pages_offset - dummy_len); + if (sts != 0) + return sts; + for (dump_mem = dump_mem_start, i = 0; i < nr_pages; i++) { copy_from_domain_page(xc_handle, domid, page_array, i, dump_mem); dump_mem += PAGE_SIZE; if (((i + 1) % DUMP_INCREMENT == 0) || (i + 1) == nr_pages) { - if (write(dump_fd, dump_mem_start, dump_mem - dump_mem_start) < - dump_mem - dump_mem_start) { + sts = dump_rtn(args, dump_mem_start, dump_mem - dump_mem_start); + if (sts != 0) { PERROR("Partial write, file system full?"); goto error_out; } @@ -110,14 +120,59 @@ xc_domain_dumpcore(int xc_handle, } } - close(dump_fd); free(dump_mem_start); return 0; error_out: - if (dump_fd != -1) - close(dump_fd); free(dump_mem_start); return -1; +} + +/* Callback routine for writing to a local dump file */ + +static int local_file_dump(void *args, void *buffer, int length) +{ + dump_args_t *da = args; + int bytes; + int offset; + unsigned char *buf = buffer; + + + if ( (args == NULL) || (buffer == NULL) || (length < 0) ) + return -EINVAL; + + /* This is to a local disk, so in practice a simple single "write" */ + /* would also work just as well as this loop which probably only */ + /* executes for 1 iteration anyhow */ + + offset = 0; + while (offset < length) { + bytes = write(da->fd, &buf[offset], length-offset); + if (bytes <= 0) { + PERROR("Failed to write buffer: %s", strerror(errno)); + return -errno; + } + offset += bytes; + } + return 0; +} + +int +xc_domain_dumpcore(int xc_handle, + uint32_t domid, + const char *corename) +{ + dump_args_t da; + int sts; + + if ((da.fd = open(corename, O_CREAT|O_RDWR, S_IWUSR|S_IRUSR)) < 0) { + PERROR("Could not open corefile %s: %s", corename, strerror(errno)); + return -errno; + } + + sts = xc_domain_dumpcore2(xc_handle, domid, &da, &local_file_dump); + close(da.fd); + + return sts; } /* diff -r 3ea1c6118fc2 tools/libxc/xenctrl.h --- a/tools/libxc/xenctrl.h Fri Mar 10 01:08:59 2006 +0100 +++ b/tools/libxc/xenctrl.h Fri Mar 10 16:58:15 2006 -0500 @@ -139,9 +139,28 @@ int xc_domain_create(int xc_handle, uint32_t *pdomid); +/* Functions to produce a dump of a given domain + * xc_domain_dumpcore - produces a dump to a specified file + * xc_domain_dumpcore2 - produces a dump, using a specified callback + */ + int xc_domain_dumpcore(int xc_handle, uint32_t domid, const char *corename); + +/* Define the callback function type for xc_domain_dumpcore2 + * + * This function is called by the coredump code for every "write", + * and passes an opaque object for the use of the function and + * created by the caller of xc_domain_dumpcore2 + */ + +typedef int (dumpcore_rtn_t)(void *arg, void *buffer, int length); + +int xc_domain_dumpcore2(int xc_handle, + uint32_t domid, + void *arg, + dumpcore_rtn_t dump_rtn); /* * This function sets the maximum number of vcpus that a domain may create.