19f532d00SPekka Enberg #include "kvm/disk-image.h" 286835cedSPrasad Joshi #include "kvm/qcow.h" 3*f41a132bSSasha Levin #include "kvm/virtio-blk.h" 4*f41a132bSSasha Levin 5*f41a132bSSasha Levin #include <sys/eventfd.h> 6*f41a132bSSasha Levin #include <sys/poll.h> 7*f41a132bSSasha Levin 8*f41a132bSSasha Levin #define AIO_MAX 32 99f532d00SPekka Enberg 10aa400b00SPrasad Joshi int debug_iodelay; 11aa400b00SPrasad Joshi 12*f41a132bSSasha Levin #ifdef CONFIG_HAS_AIO 13*f41a132bSSasha Levin static void *disk_image__thread(void *param) 14*f41a132bSSasha Levin { 15*f41a132bSSasha Levin struct disk_image *disk = param; 16*f41a132bSSasha Levin u64 dummy; 17*f41a132bSSasha Levin 18*f41a132bSSasha Levin while (read(disk->evt, &dummy, sizeof(dummy)) > 0) { 19*f41a132bSSasha Levin struct io_event event; 20*f41a132bSSasha Levin struct timespec notime = {0}; 21*f41a132bSSasha Levin 22*f41a132bSSasha Levin while (io_getevents(disk->ctx, 1, 1, &event, ¬ime) > 0) 23*f41a132bSSasha Levin disk->disk_req_cb(event.data, event.res); 24*f41a132bSSasha Levin } 25*f41a132bSSasha Levin 26*f41a132bSSasha Levin return NULL; 27*f41a132bSSasha Levin } 28*f41a132bSSasha Levin #endif 29*f41a132bSSasha Levin 307d22135fSAsias He struct disk_image *disk_image__new(int fd, u64 size, struct disk_image_operations *ops, int use_mmap) 319f532d00SPekka Enberg { 3243835ac9SSasha Levin struct disk_image *disk; 339f532d00SPekka Enberg 3443835ac9SSasha Levin disk = malloc(sizeof *disk); 3543835ac9SSasha Levin if (!disk) 36fffb37a9SPekka Enberg return NULL; 379f532d00SPekka Enberg 3843835ac9SSasha Levin disk->fd = fd; 3943835ac9SSasha Levin disk->size = size; 4043835ac9SSasha Levin disk->ops = ops; 41f4ff38dfSPrasad Joshi 427d22135fSAsias He if (use_mmap == DISK_IMAGE_MMAP) { 437d22135fSAsias He /* 447d22135fSAsias He * The write to disk image will be discarded 457d22135fSAsias He */ 4637c34ca8SSasha Levin disk->priv = mmap(NULL, size, PROT_RW, MAP_PRIVATE | MAP_NORESERVE, fd, 0); 479d15c39aSSasha Levin if (disk->priv == MAP_FAILED) { 489d15c39aSSasha Levin free(disk); 499d15c39aSSasha Levin disk = NULL; 509d15c39aSSasha Levin } 517d22135fSAsias He } 527d22135fSAsias He 53*f41a132bSSasha Levin #ifdef CONFIG_HAS_AIO 54*f41a132bSSasha Levin if (disk) { 55*f41a132bSSasha Levin pthread_t thread; 56*f41a132bSSasha Levin 57*f41a132bSSasha Levin disk->evt = eventfd(0, 0); 58*f41a132bSSasha Levin io_setup(AIO_MAX, &disk->ctx); 59*f41a132bSSasha Levin if (pthread_create(&thread, NULL, disk_image__thread, disk) != 0) 60*f41a132bSSasha Levin die("Failed starting IO thread"); 61*f41a132bSSasha Levin } 62*f41a132bSSasha Levin #endif 6343835ac9SSasha Levin return disk; 649f532d00SPekka Enberg } 659f532d00SPekka Enberg 669ac38fe1SSasha Levin struct disk_image *disk_image__open(const char *filename, bool readonly) 67499f3bedSPekka Enberg { 6843835ac9SSasha Levin struct disk_image *disk; 696ec60cfdSPekka Enberg struct stat st; 70499f3bedSPekka Enberg int fd; 71499f3bedSPekka Enberg 726ec60cfdSPekka Enberg if (stat(filename, &st) < 0) 736ec60cfdSPekka Enberg return NULL; 746ec60cfdSPekka Enberg 75441767feSAsias He /* blk device ?*/ 76441767feSAsias He disk = blkdev__probe(filename, &st); 77441767feSAsias He if (disk) 78441767feSAsias He return disk; 796ec60cfdSPekka Enberg 809ac38fe1SSasha Levin fd = open(filename, readonly ? O_RDONLY : O_RDWR); 81499f3bedSPekka Enberg if (fd < 0) 82499f3bedSPekka Enberg return NULL; 83499f3bedSPekka Enberg 84441767feSAsias He /* qcow image ?*/ 8517f68274SPekka Enberg disk = qcow_probe(fd, true); 8617f68274SPekka Enberg if (disk) { 8717f68274SPekka Enberg pr_warning("Forcing read-only support for QCOW"); 8843835ac9SSasha Levin return disk; 8917f68274SPekka Enberg } 9086835cedSPrasad Joshi 91441767feSAsias He /* raw image ?*/ 9243835ac9SSasha Levin disk = raw_image__probe(fd, &st, readonly); 9343835ac9SSasha Levin if (disk) 9443835ac9SSasha Levin return disk; 95499f3bedSPekka Enberg 96d6c58e5bSPrasad Joshi if (close(fd) < 0) 974542f276SCyrill Gorcunov pr_warning("close() failed"); 98499f3bedSPekka Enberg 99499f3bedSPekka Enberg return NULL; 100499f3bedSPekka Enberg } 101499f3bedSPekka Enberg 102c1ed214eSPrasad Joshi struct disk_image **disk_image__open_all(const char **filenames, bool *readonly, int count) 103c1ed214eSPrasad Joshi { 104c1ed214eSPrasad Joshi struct disk_image **disks; 105c1ed214eSPrasad Joshi int i; 106c1ed214eSPrasad Joshi 107c1ed214eSPrasad Joshi if (!count || count > MAX_DISK_IMAGES) 108c1ed214eSPrasad Joshi return NULL; 109c1ed214eSPrasad Joshi 110c1ed214eSPrasad Joshi disks = calloc(count, sizeof(*disks)); 111c1ed214eSPrasad Joshi if (!disks) 112c1ed214eSPrasad Joshi return NULL; 113c1ed214eSPrasad Joshi 114c1ed214eSPrasad Joshi for (i = 0; i < count; i++) { 115c1ed214eSPrasad Joshi if (!filenames[i]) 116c1ed214eSPrasad Joshi continue; 117c1ed214eSPrasad Joshi 118c1ed214eSPrasad Joshi disks[i] = disk_image__open(filenames[i], readonly[i]); 119c1ed214eSPrasad Joshi if (!disks[i]) { 120c1ed214eSPrasad Joshi pr_error("Loading disk image '%s' failed", filenames[i]); 121c1ed214eSPrasad Joshi goto error; 122c1ed214eSPrasad Joshi } 123c1ed214eSPrasad Joshi } 124*f41a132bSSasha Levin 125c1ed214eSPrasad Joshi return disks; 126c1ed214eSPrasad Joshi error: 127c1ed214eSPrasad Joshi for (i = 0; i < count; i++) 128c1ed214eSPrasad Joshi disk_image__close(disks[i]); 129c1ed214eSPrasad Joshi 130c1ed214eSPrasad Joshi free(disks); 131c1ed214eSPrasad Joshi return NULL; 132c1ed214eSPrasad Joshi } 133c1ed214eSPrasad Joshi 134fda63751SAsias He int disk_image__flush(struct disk_image *disk) 135fda63751SAsias He { 136fda63751SAsias He if (disk->ops->flush) 137fda63751SAsias He return disk->ops->flush(disk); 138fda63751SAsias He 139fda63751SAsias He return fsync(disk->fd); 140fda63751SAsias He } 141fda63751SAsias He 14272133dd2SAsias He int disk_image__close(struct disk_image *disk) 143499f3bedSPekka Enberg { 14482d94c50SIngo Molnar /* If there was no disk image then there's nothing to do: */ 14543835ac9SSasha Levin if (!disk) 14672133dd2SAsias He return 0; 14782d94c50SIngo Molnar 14843835ac9SSasha Levin if (disk->ops->close) 14972133dd2SAsias He return disk->ops->close(disk); 150499f3bedSPekka Enberg 15143835ac9SSasha Levin if (close(disk->fd) < 0) 1524542f276SCyrill Gorcunov pr_warning("close() failed"); 153499f3bedSPekka Enberg 15443835ac9SSasha Levin free(disk); 15572133dd2SAsias He 15672133dd2SAsias He return 0; 157499f3bedSPekka Enberg } 15870b0d7b0SSasha Levin 1599df47d00SPrasad Joshi void disk_image__close_all(struct disk_image **disks, int count) 1609df47d00SPrasad Joshi { 1619df47d00SPrasad Joshi while (count) 1629df47d00SPrasad Joshi disk_image__close(disks[--count]); 1639df47d00SPrasad Joshi 1649df47d00SPrasad Joshi free(disks); 1659df47d00SPrasad Joshi } 1669df47d00SPrasad Joshi 16797a90170SAsias He /* 16897a90170SAsias He * Fill iov with disk data, starting from sector 'sector'. 16997a90170SAsias He * Return amount of bytes read. 17097a90170SAsias He */ 1715af21162SSasha Levin ssize_t disk_image__read(struct disk_image *disk, u64 sector, const struct iovec *iov, 1725af21162SSasha Levin int iovcount, void *param) 17370b0d7b0SSasha Levin { 17497a90170SAsias He ssize_t total = 0; 17570b0d7b0SSasha Levin 176aa400b00SPrasad Joshi if (debug_iodelay) 177aa400b00SPrasad Joshi msleep(debug_iodelay); 178aa400b00SPrasad Joshi 1792534c9b6SSasha Levin if (disk->ops->read_sector) { 1805af21162SSasha Levin total = disk->ops->read_sector(disk, sector, iov, iovcount, param); 18197a90170SAsias He if (total < 0) { 1824542f276SCyrill Gorcunov pr_info("disk_image__read error: total=%ld\n", (long)total); 18370b0d7b0SSasha Levin return -1; 18497a90170SAsias He } 1852534c9b6SSasha Levin } else { 186b41ca15aSSasha Levin /* Do nothing */ 1872534c9b6SSasha Levin } 18897a90170SAsias He 189*f41a132bSSasha Levin if (!disk->async && disk->disk_req_cb) 1908b52f877SSasha Levin disk->disk_req_cb(param, total); 1915af21162SSasha Levin 19297a90170SAsias He return total; 19370b0d7b0SSasha Levin } 19470b0d7b0SSasha Levin 19597a90170SAsias He /* 19697a90170SAsias He * Write iov to disk, starting from sector 'sector'. 19797a90170SAsias He * Return amount of bytes written. 19897a90170SAsias He */ 1995af21162SSasha Levin ssize_t disk_image__write(struct disk_image *disk, u64 sector, const struct iovec *iov, 2005af21162SSasha Levin int iovcount, void *param) 20170b0d7b0SSasha Levin { 20297a90170SAsias He ssize_t total = 0; 20370b0d7b0SSasha Levin 204aa400b00SPrasad Joshi if (debug_iodelay) 205aa400b00SPrasad Joshi msleep(debug_iodelay); 206aa400b00SPrasad Joshi 2072534c9b6SSasha Levin if (disk->ops->write_sector) { 20897a90170SAsias He /* 20997a90170SAsias He * Try writev based operation first 21097a90170SAsias He */ 2115af21162SSasha Levin 2125af21162SSasha Levin total = disk->ops->write_sector(disk, sector, iov, iovcount, param); 21397a90170SAsias He if (total < 0) { 2144542f276SCyrill Gorcunov pr_info("disk_image__write error: total=%ld\n", (long)total); 21570b0d7b0SSasha Levin return -1; 21697a90170SAsias He } 2172534c9b6SSasha Levin } else { 218b41ca15aSSasha Levin /* Do nothing */ 2192534c9b6SSasha Levin } 22070b0d7b0SSasha Levin 221*f41a132bSSasha Levin if (!disk->async && disk->disk_req_cb) 2228b52f877SSasha Levin disk->disk_req_cb(param, total); 2235af21162SSasha Levin 22497a90170SAsias He return total; 22570b0d7b0SSasha Levin } 226ff6462e8SSasha Levin 227ff6462e8SSasha Levin ssize_t disk_image__get_serial(struct disk_image *disk, void *buffer, ssize_t *len) 228ff6462e8SSasha Levin { 229ff6462e8SSasha Levin struct stat st; 230ff6462e8SSasha Levin 231ff6462e8SSasha Levin if (fstat(disk->fd, &st) != 0) 232ff6462e8SSasha Levin return 0; 233ff6462e8SSasha Levin 234eab301d0SSasha Levin *len = snprintf(buffer, *len, "%llu%llu%llu", (u64)st.st_dev, (u64)st.st_rdev, (u64)st.st_ino); 235ff6462e8SSasha Levin return *len; 236ff6462e8SSasha Levin } 2375af21162SSasha Levin 2388b52f877SSasha Levin void disk_image__set_callback(struct disk_image *disk, void (*disk_req_cb)(void *param, long len)) 2395af21162SSasha Levin { 2405af21162SSasha Levin disk->disk_req_cb = disk_req_cb; 2415af21162SSasha Levin } 242