Index: trunk/tools/libxc/xc_core.c =================================================================== --- trunk/tools/libxc/xc_core.c (revision 9948) +++ trunk/tools/libxc/xc_core.c (working copy) @@ -1,7 +1,13 @@ #include "xg_private.h" #include #include +#include +#ifndef O_DIRECT +#define O_DIRECT 040000 +#endif +#define SECTOR_SIZE 512 + /* number of pages to write at a time */ #define DUMP_INCREMENT (4 * 1024) #define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK) @@ -38,7 +44,10 @@ int dummy_len; int sts; - if ( (dump_mem_start = malloc(DUMP_INCREMENT*PAGE_SIZE)) == NULL ) + dump_mem_start = mmap(0, PAGE_SIZE*DUMP_INCREMENT, + PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); + if (dump_mem_start == NULL) { PERROR("Could not allocate dump_mem"); goto error_out; @@ -114,13 +123,15 @@ } } - free(dump_mem_start); + munmap(dump_mem_start, PAGE_SIZE*DUMP_INCREMENT); free(page_array); return 0; error_out: - free(dump_mem_start); - free(page_array); + if (dump_mem_start) + munmap(dump_mem_start, PAGE_SIZE*DUMP_INCREMENT); + if (page_array) + free(page_array); return -1; } @@ -130,14 +141,13 @@ }; /* Callback routine for writing to a local dump file. */ -static int local_file_dump(void *args, char *buffer, unsigned int length) +static int local_file_dump(int fd, char *buffer, unsigned int length) { - struct dump_args *da = args; int bytes, offset; for ( offset = 0; offset < length; offset += bytes ) { - bytes = write(da->fd, &buffer[offset], length-offset); + bytes = write(fd, &buffer[offset], length-offset); if ( bytes <= 0 ) { PERROR("Failed to write buffer"); @@ -148,6 +158,84 @@ return 0; } +// Callback routine that support O_DIRECT i/o to dump file by converting +// packed non-sector aligned output to sector aligned output. +static int +local_dumppacked_rtn(void *args, char *buffer, size_t length) +{ + static char *io_base = NULL; + static int io_len = 0; + + struct dump_args *da = args; + int sts; + int remaining; + void *p; + int i; + + if (io_base == NULL) { + // Initialize page aligned buffer to use to accumulate sector sized info + io_base = mmap(0, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); + + if (!io_base) { + fprintf(stderr, "Could not allocate sector buffer: %s\n", strerror(errno)); + return -errno; + } + } + + // Quick check to see if we can simply write from buffer passed in - this is + // OK if: + // 1. We dont have any pending writes buffered in our internal buffer + // 2. The buffer address is sector aligned + // 3. The length is an integral number of sectors + if (io_len == 0 && + !((unsigned long)buffer & (SECTOR_SIZE-1)) && + !(length & (SECTOR_SIZE-1))) { + // Yipee! no need to copy - just write + return local_file_dump(da->fd, buffer, length); + } + else { + remaining = PAGE_SIZE-io_len; + p = (char *)io_base + io_len; + + // Convert packed to sector aligned and write + while (length) { + // Add as much as possible to buffer + if (length < remaining) + i = length; + else + i = remaining; + + memcpy(p,buffer,i); + + buffer += + i; + io_len += i; + + // write if necessary + if (io_len == PAGE_SIZE) { + sts = local_file_dump(da->fd, io_base, io_len); + if ( sts != 0 ) + return sts; + + remaining = PAGE_SIZE; + p = io_base; + io_len = 0; + } + + length -= i; + } + + // Now, write any remainder if it is an integral number of sectors long + if (io_len && !(io_len % SECTOR_SIZE)) { + sts = local_file_dump(da->fd, io_base, io_len); + if (sts != 0) + return sts; + + io_len = 0; + } + } + return 0; +} + int xc_domain_dumpcore(int xc_handle, uint32_t domid, @@ -156,14 +244,14 @@ struct dump_args da; int sts; - if ( (da.fd = open(corename, O_CREAT|O_RDWR, S_IWUSR|S_IRUSR)) < 0 ) + if ( (da.fd = open(corename, O_CREAT|O_RDWR|O_DIRECT, S_IWUSR|S_IRUSR)) < 0 ) { PERROR("Could not open corefile %s", corename); return -errno; } sts = xc_domain_dumpcore_via_callback( - xc_handle, domid, &da, &local_file_dump); + xc_handle, domid, &da, &local_dumppacked_rtn); close(da.fd);