19f532d00SPekka Enberg #include "kvm/disk-image.h" 286835cedSPrasad Joshi #include "kvm/qcow.h" 3f41a132bSSasha Levin #include "kvm/virtio-blk.h" 4f41a132bSSasha Levin 5f41a132bSSasha Levin #include <sys/eventfd.h> 6f41a132bSSasha Levin #include <sys/poll.h> 7f41a132bSSasha Levin 8f41a132bSSasha Levin #define AIO_MAX 32 99f532d00SPekka Enberg 10aa400b00SPrasad Joshi int debug_iodelay; 11aa400b00SPrasad Joshi 12f41a132bSSasha Levin #ifdef CONFIG_HAS_AIO 13f41a132bSSasha Levin static void *disk_image__thread(void *param) 14f41a132bSSasha Levin { 15f41a132bSSasha Levin struct disk_image *disk = param; 16*618cbb7cSAsias He struct io_event event[AIO_MAX]; 17*618cbb7cSAsias He struct timespec notime = {0}; 18*618cbb7cSAsias He int nr, i; 19f41a132bSSasha Levin u64 dummy; 20f41a132bSSasha Levin 21f41a132bSSasha Levin while (read(disk->evt, &dummy, sizeof(dummy)) > 0) { 22*618cbb7cSAsias He nr = io_getevents(disk->ctx, 1, ARRAY_SIZE(event), event, ¬ime); 23*618cbb7cSAsias He for (i = 0; i < nr; i++) 24*618cbb7cSAsias He disk->disk_req_cb(event[i].data, event[i].res); 25f41a132bSSasha Levin } 26f41a132bSSasha Levin 27f41a132bSSasha Levin return NULL; 28f41a132bSSasha Levin } 29f41a132bSSasha Levin #endif 30f41a132bSSasha Levin 317d22135fSAsias He struct disk_image *disk_image__new(int fd, u64 size, struct disk_image_operations *ops, int use_mmap) 329f532d00SPekka Enberg { 3343835ac9SSasha Levin struct disk_image *disk; 349f532d00SPekka Enberg 3543835ac9SSasha Levin disk = malloc(sizeof *disk); 3643835ac9SSasha Levin if (!disk) 37fffb37a9SPekka Enberg return NULL; 389f532d00SPekka Enberg 3943835ac9SSasha Levin disk->fd = fd; 4043835ac9SSasha Levin disk->size = size; 4143835ac9SSasha Levin disk->ops = ops; 42f4ff38dfSPrasad Joshi 437d22135fSAsias He if (use_mmap == DISK_IMAGE_MMAP) { 447d22135fSAsias He /* 457d22135fSAsias He * The write to disk image will be discarded 467d22135fSAsias He */ 4737c34ca8SSasha Levin disk->priv = mmap(NULL, size, PROT_RW, MAP_PRIVATE | MAP_NORESERVE, fd, 0); 489d15c39aSSasha Levin if (disk->priv == MAP_FAILED) { 499d15c39aSSasha Levin free(disk); 509d15c39aSSasha Levin disk = NULL; 519d15c39aSSasha Levin } 527d22135fSAsias He } 537d22135fSAsias He 54f41a132bSSasha Levin #ifdef CONFIG_HAS_AIO 55f41a132bSSasha Levin if (disk) { 56f41a132bSSasha Levin pthread_t thread; 57f41a132bSSasha Levin 58f41a132bSSasha Levin disk->evt = eventfd(0, 0); 59f41a132bSSasha Levin io_setup(AIO_MAX, &disk->ctx); 60f41a132bSSasha Levin if (pthread_create(&thread, NULL, disk_image__thread, disk) != 0) 61f41a132bSSasha Levin die("Failed starting IO thread"); 62f41a132bSSasha Levin } 63f41a132bSSasha Levin #endif 6443835ac9SSasha Levin return disk; 659f532d00SPekka Enberg } 669f532d00SPekka Enberg 679ac38fe1SSasha Levin struct disk_image *disk_image__open(const char *filename, bool readonly) 68499f3bedSPekka Enberg { 6943835ac9SSasha Levin struct disk_image *disk; 706ec60cfdSPekka Enberg struct stat st; 71499f3bedSPekka Enberg int fd; 72499f3bedSPekka Enberg 736ec60cfdSPekka Enberg if (stat(filename, &st) < 0) 746ec60cfdSPekka Enberg return NULL; 756ec60cfdSPekka Enberg 76441767feSAsias He /* blk device ?*/ 77441767feSAsias He disk = blkdev__probe(filename, &st); 78441767feSAsias He if (disk) 79441767feSAsias He return disk; 806ec60cfdSPekka Enberg 819ac38fe1SSasha Levin fd = open(filename, readonly ? O_RDONLY : O_RDWR); 82499f3bedSPekka Enberg if (fd < 0) 83499f3bedSPekka Enberg return NULL; 84499f3bedSPekka Enberg 85441767feSAsias He /* qcow image ?*/ 8617f68274SPekka Enberg disk = qcow_probe(fd, true); 8717f68274SPekka Enberg if (disk) { 8817f68274SPekka Enberg pr_warning("Forcing read-only support for QCOW"); 8943835ac9SSasha Levin return disk; 9017f68274SPekka Enberg } 9186835cedSPrasad Joshi 92441767feSAsias He /* raw image ?*/ 9343835ac9SSasha Levin disk = raw_image__probe(fd, &st, readonly); 9443835ac9SSasha Levin if (disk) 9543835ac9SSasha Levin return disk; 96499f3bedSPekka Enberg 97d6c58e5bSPrasad Joshi if (close(fd) < 0) 984542f276SCyrill Gorcunov pr_warning("close() failed"); 99499f3bedSPekka Enberg 100499f3bedSPekka Enberg return NULL; 101499f3bedSPekka Enberg } 102499f3bedSPekka Enberg 103c1ed214eSPrasad Joshi struct disk_image **disk_image__open_all(const char **filenames, bool *readonly, int count) 104c1ed214eSPrasad Joshi { 105c1ed214eSPrasad Joshi struct disk_image **disks; 106c1ed214eSPrasad Joshi int i; 107c1ed214eSPrasad Joshi 108c1ed214eSPrasad Joshi if (!count || count > MAX_DISK_IMAGES) 109c1ed214eSPrasad Joshi return NULL; 110c1ed214eSPrasad Joshi 111c1ed214eSPrasad Joshi disks = calloc(count, sizeof(*disks)); 112c1ed214eSPrasad Joshi if (!disks) 113c1ed214eSPrasad Joshi return NULL; 114c1ed214eSPrasad Joshi 115c1ed214eSPrasad Joshi for (i = 0; i < count; i++) { 116c1ed214eSPrasad Joshi if (!filenames[i]) 117c1ed214eSPrasad Joshi continue; 118c1ed214eSPrasad Joshi 119c1ed214eSPrasad Joshi disks[i] = disk_image__open(filenames[i], readonly[i]); 120c1ed214eSPrasad Joshi if (!disks[i]) { 121c1ed214eSPrasad Joshi pr_error("Loading disk image '%s' failed", filenames[i]); 122c1ed214eSPrasad Joshi goto error; 123c1ed214eSPrasad Joshi } 124c1ed214eSPrasad Joshi } 125f41a132bSSasha Levin 126c1ed214eSPrasad Joshi return disks; 127c1ed214eSPrasad Joshi error: 128c1ed214eSPrasad Joshi for (i = 0; i < count; i++) 129c1ed214eSPrasad Joshi disk_image__close(disks[i]); 130c1ed214eSPrasad Joshi 131c1ed214eSPrasad Joshi free(disks); 132c1ed214eSPrasad Joshi return NULL; 133c1ed214eSPrasad Joshi } 134c1ed214eSPrasad Joshi 135fda63751SAsias He int disk_image__flush(struct disk_image *disk) 136fda63751SAsias He { 137fda63751SAsias He if (disk->ops->flush) 138fda63751SAsias He return disk->ops->flush(disk); 139fda63751SAsias He 140fda63751SAsias He return fsync(disk->fd); 141fda63751SAsias He } 142fda63751SAsias He 14372133dd2SAsias He int disk_image__close(struct disk_image *disk) 144499f3bedSPekka Enberg { 14582d94c50SIngo Molnar /* If there was no disk image then there's nothing to do: */ 14643835ac9SSasha Levin if (!disk) 14772133dd2SAsias He return 0; 14882d94c50SIngo Molnar 14943835ac9SSasha Levin if (disk->ops->close) 15072133dd2SAsias He return disk->ops->close(disk); 151499f3bedSPekka Enberg 15243835ac9SSasha Levin if (close(disk->fd) < 0) 1534542f276SCyrill Gorcunov pr_warning("close() failed"); 154499f3bedSPekka Enberg 15543835ac9SSasha Levin free(disk); 15672133dd2SAsias He 15772133dd2SAsias He return 0; 158499f3bedSPekka Enberg } 15970b0d7b0SSasha Levin 1609df47d00SPrasad Joshi void disk_image__close_all(struct disk_image **disks, int count) 1619df47d00SPrasad Joshi { 1629df47d00SPrasad Joshi while (count) 1639df47d00SPrasad Joshi disk_image__close(disks[--count]); 1649df47d00SPrasad Joshi 1659df47d00SPrasad Joshi free(disks); 1669df47d00SPrasad Joshi } 1679df47d00SPrasad Joshi 16897a90170SAsias He /* 16997a90170SAsias He * Fill iov with disk data, starting from sector 'sector'. 17097a90170SAsias He * Return amount of bytes read. 17197a90170SAsias He */ 1725af21162SSasha Levin ssize_t disk_image__read(struct disk_image *disk, u64 sector, const struct iovec *iov, 1735af21162SSasha Levin int iovcount, void *param) 17470b0d7b0SSasha Levin { 17597a90170SAsias He ssize_t total = 0; 17670b0d7b0SSasha Levin 177aa400b00SPrasad Joshi if (debug_iodelay) 178aa400b00SPrasad Joshi msleep(debug_iodelay); 179aa400b00SPrasad Joshi 1802534c9b6SSasha Levin if (disk->ops->read_sector) { 1815af21162SSasha Levin total = disk->ops->read_sector(disk, sector, iov, iovcount, param); 18297a90170SAsias He if (total < 0) { 1834542f276SCyrill Gorcunov pr_info("disk_image__read error: total=%ld\n", (long)total); 18470b0d7b0SSasha Levin return -1; 18597a90170SAsias He } 1862534c9b6SSasha Levin } else { 187b41ca15aSSasha Levin /* Do nothing */ 1882534c9b6SSasha Levin } 18997a90170SAsias He 190f41a132bSSasha Levin if (!disk->async && disk->disk_req_cb) 1918b52f877SSasha Levin disk->disk_req_cb(param, total); 1925af21162SSasha Levin 19397a90170SAsias He return total; 19470b0d7b0SSasha Levin } 19570b0d7b0SSasha Levin 19697a90170SAsias He /* 19797a90170SAsias He * Write iov to disk, starting from sector 'sector'. 19897a90170SAsias He * Return amount of bytes written. 19997a90170SAsias He */ 2005af21162SSasha Levin ssize_t disk_image__write(struct disk_image *disk, u64 sector, const struct iovec *iov, 2015af21162SSasha Levin int iovcount, void *param) 20270b0d7b0SSasha Levin { 20397a90170SAsias He ssize_t total = 0; 20470b0d7b0SSasha Levin 205aa400b00SPrasad Joshi if (debug_iodelay) 206aa400b00SPrasad Joshi msleep(debug_iodelay); 207aa400b00SPrasad Joshi 2082534c9b6SSasha Levin if (disk->ops->write_sector) { 20997a90170SAsias He /* 21097a90170SAsias He * Try writev based operation first 21197a90170SAsias He */ 2125af21162SSasha Levin 2135af21162SSasha Levin total = disk->ops->write_sector(disk, sector, iov, iovcount, param); 21497a90170SAsias He if (total < 0) { 2154542f276SCyrill Gorcunov pr_info("disk_image__write error: total=%ld\n", (long)total); 21670b0d7b0SSasha Levin return -1; 21797a90170SAsias He } 2182534c9b6SSasha Levin } else { 219b41ca15aSSasha Levin /* Do nothing */ 2202534c9b6SSasha Levin } 22170b0d7b0SSasha Levin 222f41a132bSSasha Levin if (!disk->async && disk->disk_req_cb) 2238b52f877SSasha Levin disk->disk_req_cb(param, total); 2245af21162SSasha Levin 22597a90170SAsias He return total; 22670b0d7b0SSasha Levin } 227ff6462e8SSasha Levin 228ff6462e8SSasha Levin ssize_t disk_image__get_serial(struct disk_image *disk, void *buffer, ssize_t *len) 229ff6462e8SSasha Levin { 230ff6462e8SSasha Levin struct stat st; 231ff6462e8SSasha Levin 232ff6462e8SSasha Levin if (fstat(disk->fd, &st) != 0) 233ff6462e8SSasha Levin return 0; 234ff6462e8SSasha Levin 235eab301d0SSasha Levin *len = snprintf(buffer, *len, "%llu%llu%llu", (u64)st.st_dev, (u64)st.st_rdev, (u64)st.st_ino); 236ff6462e8SSasha Levin return *len; 237ff6462e8SSasha Levin } 2385af21162SSasha Levin 2398b52f877SSasha Levin void disk_image__set_callback(struct disk_image *disk, void (*disk_req_cb)(void *param, long len)) 2405af21162SSasha Levin { 2415af21162SSasha Levin disk->disk_req_cb = disk_req_cb; 2425af21162SSasha Levin } 243