19f532d00SPekka Enberg #include "kvm/disk-image.h" 286835cedSPrasad Joshi #include "kvm/qcow.h" 3f41a132bSSasha Levin #include "kvm/virtio-blk.h" 4f41a132bSSasha Levin 59f9207c5SSasha Levin #include <linux/err.h> 6f41a132bSSasha Levin #include <sys/eventfd.h> 7f41a132bSSasha Levin #include <sys/poll.h> 8f41a132bSSasha Levin 9f41a132bSSasha Levin #define AIO_MAX 32 109f532d00SPekka Enberg 11aa400b00SPrasad Joshi int debug_iodelay; 12aa400b00SPrasad Joshi 13f41a132bSSasha Levin #ifdef CONFIG_HAS_AIO 14f41a132bSSasha Levin static void *disk_image__thread(void *param) 15f41a132bSSasha Levin { 16f41a132bSSasha Levin struct disk_image *disk = param; 17618cbb7cSAsias He struct io_event event[AIO_MAX]; 18618cbb7cSAsias He struct timespec notime = {0}; 19618cbb7cSAsias He int nr, i; 20f41a132bSSasha Levin u64 dummy; 21f41a132bSSasha Levin 22f41a132bSSasha Levin while (read(disk->evt, &dummy, sizeof(dummy)) > 0) { 23618cbb7cSAsias He nr = io_getevents(disk->ctx, 1, ARRAY_SIZE(event), event, ¬ime); 24618cbb7cSAsias He for (i = 0; i < nr; i++) 25618cbb7cSAsias He disk->disk_req_cb(event[i].data, event[i].res); 26f41a132bSSasha Levin } 27f41a132bSSasha Levin 28f41a132bSSasha Levin return NULL; 29f41a132bSSasha Levin } 30f41a132bSSasha Levin #endif 31f41a132bSSasha Levin 32*54c84566SAsias He struct disk_image *disk_image__new(int fd, u64 size, 33*54c84566SAsias He struct disk_image_operations *ops, 34*54c84566SAsias He int use_mmap) 359f532d00SPekka Enberg { 3643835ac9SSasha Levin struct disk_image *disk; 379f9207c5SSasha Levin int r; 389f532d00SPekka Enberg 3943835ac9SSasha Levin disk = malloc(sizeof *disk); 4043835ac9SSasha Levin if (!disk) 419f9207c5SSasha Levin return ERR_PTR(-ENOMEM); 429f532d00SPekka Enberg 439f9207c5SSasha Levin *disk = (struct disk_image) { 449f9207c5SSasha Levin .fd = fd, 459f9207c5SSasha Levin .size = size, 469f9207c5SSasha Levin .ops = ops, 479f9207c5SSasha Levin }; 48f4ff38dfSPrasad Joshi 497d22135fSAsias He if (use_mmap == DISK_IMAGE_MMAP) { 507d22135fSAsias He /* 517d22135fSAsias He * The write to disk image will be discarded 527d22135fSAsias He */ 5337c34ca8SSasha Levin disk->priv = mmap(NULL, size, PROT_RW, MAP_PRIVATE | MAP_NORESERVE, fd, 0); 549d15c39aSSasha Levin if (disk->priv == MAP_FAILED) { 559f9207c5SSasha Levin r = -errno; 569d15c39aSSasha Levin free(disk); 579f9207c5SSasha Levin return ERR_PTR(r); 589d15c39aSSasha Levin } 597d22135fSAsias He } 607d22135fSAsias He 61f41a132bSSasha Levin #ifdef CONFIG_HAS_AIO 62f41a132bSSasha Levin if (disk) { 63f41a132bSSasha Levin pthread_t thread; 64f41a132bSSasha Levin 65f41a132bSSasha Levin disk->evt = eventfd(0, 0); 66f41a132bSSasha Levin io_setup(AIO_MAX, &disk->ctx); 679f9207c5SSasha Levin r = pthread_create(&thread, NULL, disk_image__thread, disk); 689f9207c5SSasha Levin if (r) { 699f9207c5SSasha Levin r = -errno; 709f9207c5SSasha Levin free(disk); 719f9207c5SSasha Levin return ERR_PTR(r); 729f9207c5SSasha Levin } 73f41a132bSSasha Levin } 74f41a132bSSasha Levin #endif 7543835ac9SSasha Levin return disk; 769f532d00SPekka Enberg } 779f532d00SPekka Enberg 789ac38fe1SSasha Levin struct disk_image *disk_image__open(const char *filename, bool readonly) 79499f3bedSPekka Enberg { 8043835ac9SSasha Levin struct disk_image *disk; 816ec60cfdSPekka Enberg struct stat st; 82499f3bedSPekka Enberg int fd; 83499f3bedSPekka Enberg 846ec60cfdSPekka Enberg if (stat(filename, &st) < 0) 859f9207c5SSasha Levin return ERR_PTR(-errno); 866ec60cfdSPekka Enberg 87441767feSAsias He /* blk device ?*/ 88441767feSAsias He disk = blkdev__probe(filename, &st); 899f9207c5SSasha Levin if (!IS_ERR_OR_NULL(disk)) 90441767feSAsias He return disk; 916ec60cfdSPekka Enberg 929ac38fe1SSasha Levin fd = open(filename, readonly ? O_RDONLY : O_RDWR); 93499f3bedSPekka Enberg if (fd < 0) 949f9207c5SSasha Levin return ERR_PTR(fd); 95499f3bedSPekka Enberg 96441767feSAsias He /* qcow image ?*/ 9717f68274SPekka Enberg disk = qcow_probe(fd, true); 989f9207c5SSasha Levin if (!IS_ERR_OR_NULL(disk)) { 9917f68274SPekka Enberg pr_warning("Forcing read-only support for QCOW"); 10043835ac9SSasha Levin return disk; 10117f68274SPekka Enberg } 10286835cedSPrasad Joshi 103441767feSAsias He /* raw image ?*/ 10443835ac9SSasha Levin disk = raw_image__probe(fd, &st, readonly); 1059f9207c5SSasha Levin if (!IS_ERR_OR_NULL(disk)) 10643835ac9SSasha Levin return disk; 107499f3bedSPekka Enberg 108d6c58e5bSPrasad Joshi if (close(fd) < 0) 1094542f276SCyrill Gorcunov pr_warning("close() failed"); 110499f3bedSPekka Enberg 1119f9207c5SSasha Levin return ERR_PTR(-ENOSYS); 112499f3bedSPekka Enberg } 113499f3bedSPekka Enberg 114*54c84566SAsias He struct disk_image **disk_image__open_all(const char **filenames, 115*54c84566SAsias He bool *readonly, int count) 116c1ed214eSPrasad Joshi { 117c1ed214eSPrasad Joshi struct disk_image **disks; 118c1ed214eSPrasad Joshi int i; 1199f9207c5SSasha Levin void *err; 120c1ed214eSPrasad Joshi 1219f9207c5SSasha Levin if (!count) 1229f9207c5SSasha Levin return ERR_PTR(-EINVAL); 1239f9207c5SSasha Levin if (count > MAX_DISK_IMAGES) 1249f9207c5SSasha Levin return ERR_PTR(-ENOSPC); 125c1ed214eSPrasad Joshi 126c1ed214eSPrasad Joshi disks = calloc(count, sizeof(*disks)); 127c1ed214eSPrasad Joshi if (!disks) 1289f9207c5SSasha Levin return ERR_PTR(-ENOMEM); 129c1ed214eSPrasad Joshi 130c1ed214eSPrasad Joshi for (i = 0; i < count; i++) { 131c1ed214eSPrasad Joshi if (!filenames[i]) 132c1ed214eSPrasad Joshi continue; 133c1ed214eSPrasad Joshi 134c1ed214eSPrasad Joshi disks[i] = disk_image__open(filenames[i], readonly[i]); 1359f9207c5SSasha Levin if (IS_ERR_OR_NULL(disks[i])) { 136599ed2a8SCyrill Gorcunov pr_err("Loading disk image '%s' failed", filenames[i]); 1379f9207c5SSasha Levin err = disks[i]; 138c1ed214eSPrasad Joshi goto error; 139c1ed214eSPrasad Joshi } 140c1ed214eSPrasad Joshi } 141f41a132bSSasha Levin 142c1ed214eSPrasad Joshi return disks; 143c1ed214eSPrasad Joshi error: 144c1ed214eSPrasad Joshi for (i = 0; i < count; i++) 1459f9207c5SSasha Levin if (!IS_ERR_OR_NULL(disks[i])) 146c1ed214eSPrasad Joshi disk_image__close(disks[i]); 147c1ed214eSPrasad Joshi 148c1ed214eSPrasad Joshi free(disks); 1499f9207c5SSasha Levin return err; 150c1ed214eSPrasad Joshi } 151c1ed214eSPrasad Joshi 152fda63751SAsias He int disk_image__flush(struct disk_image *disk) 153fda63751SAsias He { 154fda63751SAsias He if (disk->ops->flush) 155fda63751SAsias He return disk->ops->flush(disk); 156fda63751SAsias He 157fda63751SAsias He return fsync(disk->fd); 158fda63751SAsias He } 159fda63751SAsias He 16072133dd2SAsias He int disk_image__close(struct disk_image *disk) 161499f3bedSPekka Enberg { 16282d94c50SIngo Molnar /* If there was no disk image then there's nothing to do: */ 16343835ac9SSasha Levin if (!disk) 16472133dd2SAsias He return 0; 16582d94c50SIngo Molnar 16643835ac9SSasha Levin if (disk->ops->close) 16772133dd2SAsias He return disk->ops->close(disk); 168499f3bedSPekka Enberg 16943835ac9SSasha Levin if (close(disk->fd) < 0) 1704542f276SCyrill Gorcunov pr_warning("close() failed"); 171499f3bedSPekka Enberg 17243835ac9SSasha Levin free(disk); 17372133dd2SAsias He 17472133dd2SAsias He return 0; 175499f3bedSPekka Enberg } 17670b0d7b0SSasha Levin 1779f9207c5SSasha Levin int disk_image__close_all(struct disk_image **disks, int count) 1789df47d00SPrasad Joshi { 1799df47d00SPrasad Joshi while (count) 1809df47d00SPrasad Joshi disk_image__close(disks[--count]); 1819df47d00SPrasad Joshi 1829df47d00SPrasad Joshi free(disks); 1839f9207c5SSasha Levin 1849f9207c5SSasha Levin return 0; 1859df47d00SPrasad Joshi } 1869df47d00SPrasad Joshi 18797a90170SAsias He /* 18897a90170SAsias He * Fill iov with disk data, starting from sector 'sector'. 18997a90170SAsias He * Return amount of bytes read. 19097a90170SAsias He */ 191*54c84566SAsias He ssize_t disk_image__read(struct disk_image *disk, u64 sector, 192*54c84566SAsias He const struct iovec *iov, int iovcount, void *param) 19370b0d7b0SSasha Levin { 19497a90170SAsias He ssize_t total = 0; 19570b0d7b0SSasha Levin 196aa400b00SPrasad Joshi if (debug_iodelay) 197aa400b00SPrasad Joshi msleep(debug_iodelay); 198aa400b00SPrasad Joshi 199dcd3cd8eSAsias He if (disk->ops->read) { 200dcd3cd8eSAsias He total = disk->ops->read(disk, sector, iov, iovcount, param); 20197a90170SAsias He if (total < 0) { 2024542f276SCyrill Gorcunov pr_info("disk_image__read error: total=%ld\n", (long)total); 2039f9207c5SSasha Levin return total; 20497a90170SAsias He } 2052534c9b6SSasha Levin } 20697a90170SAsias He 207f41a132bSSasha Levin if (!disk->async && disk->disk_req_cb) 2088b52f877SSasha Levin disk->disk_req_cb(param, total); 2095af21162SSasha Levin 21097a90170SAsias He return total; 21170b0d7b0SSasha Levin } 21270b0d7b0SSasha Levin 21397a90170SAsias He /* 21497a90170SAsias He * Write iov to disk, starting from sector 'sector'. 21597a90170SAsias He * Return amount of bytes written. 21697a90170SAsias He */ 217*54c84566SAsias He ssize_t disk_image__write(struct disk_image *disk, u64 sector, 218*54c84566SAsias He const struct iovec *iov, int iovcount, void *param) 21970b0d7b0SSasha Levin { 22097a90170SAsias He ssize_t total = 0; 22170b0d7b0SSasha Levin 222aa400b00SPrasad Joshi if (debug_iodelay) 223aa400b00SPrasad Joshi msleep(debug_iodelay); 224aa400b00SPrasad Joshi 225dcd3cd8eSAsias He if (disk->ops->write) { 22697a90170SAsias He /* 22797a90170SAsias He * Try writev based operation first 22897a90170SAsias He */ 2295af21162SSasha Levin 230dcd3cd8eSAsias He total = disk->ops->write(disk, sector, iov, iovcount, param); 23197a90170SAsias He if (total < 0) { 2324542f276SCyrill Gorcunov pr_info("disk_image__write error: total=%ld\n", (long)total); 2339f9207c5SSasha Levin return total; 23497a90170SAsias He } 2352534c9b6SSasha Levin } else { 236b41ca15aSSasha Levin /* Do nothing */ 2372534c9b6SSasha Levin } 23870b0d7b0SSasha Levin 239f41a132bSSasha Levin if (!disk->async && disk->disk_req_cb) 2408b52f877SSasha Levin disk->disk_req_cb(param, total); 2415af21162SSasha Levin 24297a90170SAsias He return total; 24370b0d7b0SSasha Levin } 244ff6462e8SSasha Levin 245ff6462e8SSasha Levin ssize_t disk_image__get_serial(struct disk_image *disk, void *buffer, ssize_t *len) 246ff6462e8SSasha Levin { 247ff6462e8SSasha Levin struct stat st; 2489f9207c5SSasha Levin int r; 249ff6462e8SSasha Levin 2509f9207c5SSasha Levin r = fstat(disk->fd, &st); 2519f9207c5SSasha Levin if (r) 2529f9207c5SSasha Levin return r; 253ff6462e8SSasha Levin 254*54c84566SAsias He *len = snprintf(buffer, *len, "%llu%llu%llu", 255*54c84566SAsias He (u64)st.st_dev, (u64)st.st_rdev, (u64)st.st_ino); 256ff6462e8SSasha Levin return *len; 257ff6462e8SSasha Levin } 2585af21162SSasha Levin 259*54c84566SAsias He void disk_image__set_callback(struct disk_image *disk, 260*54c84566SAsias He void (*disk_req_cb)(void *param, long len)) 2615af21162SSasha Levin { 2625af21162SSasha Levin disk->disk_req_cb = disk_req_cb; 2635af21162SSasha Levin } 264