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 9fea74936SAsias He #define AIO_MAX 256 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 3254c84566SAsias He struct disk_image *disk_image__new(int fd, u64 size, 3354c84566SAsias He struct disk_image_operations *ops, 3454c84566SAsias 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 78*5236b505SAsias He struct disk_image *disk_image__open(const char *filename, bool readonly, bool direct) 79499f3bedSPekka Enberg { 8043835ac9SSasha Levin struct disk_image *disk; 816ec60cfdSPekka Enberg struct stat st; 82*5236b505SAsias He int fd, flags; 83*5236b505SAsias He 84*5236b505SAsias He if (readonly) 85*5236b505SAsias He flags = O_RDONLY; 86*5236b505SAsias He else 87*5236b505SAsias He flags = O_RDWR; 88*5236b505SAsias He if (direct) 89*5236b505SAsias He flags |= O_DIRECT; 90499f3bedSPekka Enberg 916ec60cfdSPekka Enberg if (stat(filename, &st) < 0) 929f9207c5SSasha Levin return ERR_PTR(-errno); 936ec60cfdSPekka Enberg 94441767feSAsias He /* blk device ?*/ 95*5236b505SAsias He disk = blkdev__probe(filename, flags, &st); 969f9207c5SSasha Levin if (!IS_ERR_OR_NULL(disk)) 97441767feSAsias He return disk; 986ec60cfdSPekka Enberg 99*5236b505SAsias He fd = open(filename, flags); 100499f3bedSPekka Enberg if (fd < 0) 1019f9207c5SSasha Levin return ERR_PTR(fd); 102499f3bedSPekka Enberg 103441767feSAsias He /* qcow image ?*/ 10417f68274SPekka Enberg disk = qcow_probe(fd, true); 1059f9207c5SSasha Levin if (!IS_ERR_OR_NULL(disk)) { 10617f68274SPekka Enberg pr_warning("Forcing read-only support for QCOW"); 10743835ac9SSasha Levin return disk; 10817f68274SPekka Enberg } 10986835cedSPrasad Joshi 110441767feSAsias He /* raw image ?*/ 11143835ac9SSasha Levin disk = raw_image__probe(fd, &st, readonly); 1129f9207c5SSasha Levin if (!IS_ERR_OR_NULL(disk)) 11343835ac9SSasha Levin return disk; 114499f3bedSPekka Enberg 115d6c58e5bSPrasad Joshi if (close(fd) < 0) 1164542f276SCyrill Gorcunov pr_warning("close() failed"); 117499f3bedSPekka Enberg 1189f9207c5SSasha Levin return ERR_PTR(-ENOSYS); 119499f3bedSPekka Enberg } 120499f3bedSPekka Enberg 12197f16d66SAsias He struct disk_image **disk_image__open_all(struct disk_image_params *params, int count) 122c1ed214eSPrasad Joshi { 123c1ed214eSPrasad Joshi struct disk_image **disks; 12497f16d66SAsias He const char *filename; 12597f16d66SAsias He bool readonly; 126*5236b505SAsias He bool direct; 1279f9207c5SSasha Levin void *err; 12897f16d66SAsias He int i; 129c1ed214eSPrasad Joshi 1309f9207c5SSasha Levin if (!count) 1319f9207c5SSasha Levin return ERR_PTR(-EINVAL); 1329f9207c5SSasha Levin if (count > MAX_DISK_IMAGES) 1339f9207c5SSasha Levin return ERR_PTR(-ENOSPC); 134c1ed214eSPrasad Joshi 135c1ed214eSPrasad Joshi disks = calloc(count, sizeof(*disks)); 136c1ed214eSPrasad Joshi if (!disks) 1379f9207c5SSasha Levin return ERR_PTR(-ENOMEM); 138c1ed214eSPrasad Joshi 139c1ed214eSPrasad Joshi for (i = 0; i < count; i++) { 14097f16d66SAsias He filename = params[i].filename; 14197f16d66SAsias He readonly = params[i].readonly; 142*5236b505SAsias He direct = params[i].direct; 14397f16d66SAsias He if (!filename) 144c1ed214eSPrasad Joshi continue; 145c1ed214eSPrasad Joshi 146*5236b505SAsias He disks[i] = disk_image__open(filename, readonly, direct); 1479f9207c5SSasha Levin if (IS_ERR_OR_NULL(disks[i])) { 14897f16d66SAsias He pr_err("Loading disk image '%s' failed", filename); 1499f9207c5SSasha Levin err = disks[i]; 150c1ed214eSPrasad Joshi goto error; 151c1ed214eSPrasad Joshi } 152c1ed214eSPrasad Joshi } 153f41a132bSSasha Levin 154c1ed214eSPrasad Joshi return disks; 155c1ed214eSPrasad Joshi error: 156c1ed214eSPrasad Joshi for (i = 0; i < count; i++) 1579f9207c5SSasha Levin if (!IS_ERR_OR_NULL(disks[i])) 158c1ed214eSPrasad Joshi disk_image__close(disks[i]); 159c1ed214eSPrasad Joshi 160c1ed214eSPrasad Joshi free(disks); 1619f9207c5SSasha Levin return err; 162c1ed214eSPrasad Joshi } 163c1ed214eSPrasad Joshi 164fda63751SAsias He int disk_image__flush(struct disk_image *disk) 165fda63751SAsias He { 166fda63751SAsias He if (disk->ops->flush) 167fda63751SAsias He return disk->ops->flush(disk); 168fda63751SAsias He 169fda63751SAsias He return fsync(disk->fd); 170fda63751SAsias He } 171fda63751SAsias He 17272133dd2SAsias He int disk_image__close(struct disk_image *disk) 173499f3bedSPekka Enberg { 17482d94c50SIngo Molnar /* If there was no disk image then there's nothing to do: */ 17543835ac9SSasha Levin if (!disk) 17672133dd2SAsias He return 0; 17782d94c50SIngo Molnar 17843835ac9SSasha Levin if (disk->ops->close) 17972133dd2SAsias He return disk->ops->close(disk); 180499f3bedSPekka Enberg 18143835ac9SSasha Levin if (close(disk->fd) < 0) 1824542f276SCyrill Gorcunov pr_warning("close() failed"); 183499f3bedSPekka Enberg 18443835ac9SSasha Levin free(disk); 18572133dd2SAsias He 18672133dd2SAsias He return 0; 187499f3bedSPekka Enberg } 18870b0d7b0SSasha Levin 1899f9207c5SSasha Levin int disk_image__close_all(struct disk_image **disks, int count) 1909df47d00SPrasad Joshi { 1919df47d00SPrasad Joshi while (count) 1929df47d00SPrasad Joshi disk_image__close(disks[--count]); 1939df47d00SPrasad Joshi 1949df47d00SPrasad Joshi free(disks); 1959f9207c5SSasha Levin 1969f9207c5SSasha Levin return 0; 1979df47d00SPrasad Joshi } 1989df47d00SPrasad Joshi 19997a90170SAsias He /* 20097a90170SAsias He * Fill iov with disk data, starting from sector 'sector'. 20197a90170SAsias He * Return amount of bytes read. 20297a90170SAsias He */ 20354c84566SAsias He ssize_t disk_image__read(struct disk_image *disk, u64 sector, 20454c84566SAsias He const struct iovec *iov, int iovcount, void *param) 20570b0d7b0SSasha Levin { 20697a90170SAsias He ssize_t total = 0; 20770b0d7b0SSasha Levin 208aa400b00SPrasad Joshi if (debug_iodelay) 209aa400b00SPrasad Joshi msleep(debug_iodelay); 210aa400b00SPrasad Joshi 211dcd3cd8eSAsias He if (disk->ops->read) { 212dcd3cd8eSAsias He total = disk->ops->read(disk, sector, iov, iovcount, param); 21397a90170SAsias He if (total < 0) { 2144542f276SCyrill Gorcunov pr_info("disk_image__read error: total=%ld\n", (long)total); 2159f9207c5SSasha Levin return total; 21697a90170SAsias He } 2172534c9b6SSasha Levin } 21897a90170SAsias He 219f41a132bSSasha Levin if (!disk->async && disk->disk_req_cb) 2208b52f877SSasha Levin disk->disk_req_cb(param, total); 2215af21162SSasha Levin 22297a90170SAsias He return total; 22370b0d7b0SSasha Levin } 22470b0d7b0SSasha Levin 22597a90170SAsias He /* 22697a90170SAsias He * Write iov to disk, starting from sector 'sector'. 22797a90170SAsias He * Return amount of bytes written. 22897a90170SAsias He */ 22954c84566SAsias He ssize_t disk_image__write(struct disk_image *disk, u64 sector, 23054c84566SAsias He const struct iovec *iov, int iovcount, void *param) 23170b0d7b0SSasha Levin { 23297a90170SAsias He ssize_t total = 0; 23370b0d7b0SSasha Levin 234aa400b00SPrasad Joshi if (debug_iodelay) 235aa400b00SPrasad Joshi msleep(debug_iodelay); 236aa400b00SPrasad Joshi 237dcd3cd8eSAsias He if (disk->ops->write) { 23897a90170SAsias He /* 23997a90170SAsias He * Try writev based operation first 24097a90170SAsias He */ 2415af21162SSasha Levin 242dcd3cd8eSAsias He total = disk->ops->write(disk, sector, iov, iovcount, param); 24397a90170SAsias He if (total < 0) { 2444542f276SCyrill Gorcunov pr_info("disk_image__write error: total=%ld\n", (long)total); 2459f9207c5SSasha Levin return total; 24697a90170SAsias He } 2472534c9b6SSasha Levin } else { 248b41ca15aSSasha Levin /* Do nothing */ 2492534c9b6SSasha Levin } 25070b0d7b0SSasha Levin 251f41a132bSSasha Levin if (!disk->async && disk->disk_req_cb) 2528b52f877SSasha Levin disk->disk_req_cb(param, total); 2535af21162SSasha Levin 25497a90170SAsias He return total; 25570b0d7b0SSasha Levin } 256ff6462e8SSasha Levin 257ff6462e8SSasha Levin ssize_t disk_image__get_serial(struct disk_image *disk, void *buffer, ssize_t *len) 258ff6462e8SSasha Levin { 259ff6462e8SSasha Levin struct stat st; 2609f9207c5SSasha Levin int r; 261ff6462e8SSasha Levin 2629f9207c5SSasha Levin r = fstat(disk->fd, &st); 2639f9207c5SSasha Levin if (r) 2649f9207c5SSasha Levin return r; 265ff6462e8SSasha Levin 26654c84566SAsias He *len = snprintf(buffer, *len, "%llu%llu%llu", 26754c84566SAsias He (u64)st.st_dev, (u64)st.st_rdev, (u64)st.st_ino); 268ff6462e8SSasha Levin return *len; 269ff6462e8SSasha Levin } 2705af21162SSasha Levin 27154c84566SAsias He void disk_image__set_callback(struct disk_image *disk, 27254c84566SAsias He void (*disk_req_cb)(void *param, long len)) 2735af21162SSasha Levin { 2745af21162SSasha Levin disk->disk_req_cb = disk_req_cb; 2755af21162SSasha Levin } 276