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 327d22135fSAsias He struct disk_image *disk_image__new(int fd, u64 size, struct disk_image_operations *ops, int use_mmap) 339f532d00SPekka Enberg { 3443835ac9SSasha Levin struct disk_image *disk; 359f9207c5SSasha Levin int r; 369f532d00SPekka Enberg 3743835ac9SSasha Levin disk = malloc(sizeof *disk); 3843835ac9SSasha Levin if (!disk) 399f9207c5SSasha Levin return ERR_PTR(-ENOMEM); 409f532d00SPekka Enberg 419f9207c5SSasha Levin *disk = (struct disk_image) { 429f9207c5SSasha Levin .fd = fd, 439f9207c5SSasha Levin .size = size, 449f9207c5SSasha Levin .ops = ops, 459f9207c5SSasha Levin }; 46f4ff38dfSPrasad Joshi 477d22135fSAsias He if (use_mmap == DISK_IMAGE_MMAP) { 487d22135fSAsias He /* 497d22135fSAsias He * The write to disk image will be discarded 507d22135fSAsias He */ 5137c34ca8SSasha Levin disk->priv = mmap(NULL, size, PROT_RW, MAP_PRIVATE | MAP_NORESERVE, fd, 0); 529d15c39aSSasha Levin if (disk->priv == MAP_FAILED) { 539f9207c5SSasha Levin r = -errno; 549d15c39aSSasha Levin free(disk); 559f9207c5SSasha Levin return ERR_PTR(r); 569d15c39aSSasha Levin } 577d22135fSAsias He } 587d22135fSAsias He 59f41a132bSSasha Levin #ifdef CONFIG_HAS_AIO 60f41a132bSSasha Levin if (disk) { 61f41a132bSSasha Levin pthread_t thread; 62f41a132bSSasha Levin 63f41a132bSSasha Levin disk->evt = eventfd(0, 0); 64f41a132bSSasha Levin io_setup(AIO_MAX, &disk->ctx); 659f9207c5SSasha Levin r = pthread_create(&thread, NULL, disk_image__thread, disk); 669f9207c5SSasha Levin if (r) { 679f9207c5SSasha Levin r = -errno; 689f9207c5SSasha Levin free(disk); 699f9207c5SSasha Levin return ERR_PTR(r); 709f9207c5SSasha Levin } 71f41a132bSSasha Levin } 72f41a132bSSasha Levin #endif 7343835ac9SSasha Levin return disk; 749f532d00SPekka Enberg } 759f532d00SPekka Enberg 769ac38fe1SSasha Levin struct disk_image *disk_image__open(const char *filename, bool readonly) 77499f3bedSPekka Enberg { 7843835ac9SSasha Levin struct disk_image *disk; 796ec60cfdSPekka Enberg struct stat st; 80499f3bedSPekka Enberg int fd; 81499f3bedSPekka Enberg 826ec60cfdSPekka Enberg if (stat(filename, &st) < 0) 839f9207c5SSasha Levin return ERR_PTR(-errno); 846ec60cfdSPekka Enberg 85441767feSAsias He /* blk device ?*/ 86441767feSAsias He disk = blkdev__probe(filename, &st); 879f9207c5SSasha Levin if (!IS_ERR_OR_NULL(disk)) 88441767feSAsias He return disk; 896ec60cfdSPekka Enberg 909ac38fe1SSasha Levin fd = open(filename, readonly ? O_RDONLY : O_RDWR); 91499f3bedSPekka Enberg if (fd < 0) 929f9207c5SSasha Levin return ERR_PTR(fd); 93499f3bedSPekka Enberg 94441767feSAsias He /* qcow image ?*/ 9517f68274SPekka Enberg disk = qcow_probe(fd, true); 969f9207c5SSasha Levin if (!IS_ERR_OR_NULL(disk)) { 9717f68274SPekka Enberg pr_warning("Forcing read-only support for QCOW"); 9843835ac9SSasha Levin return disk; 9917f68274SPekka Enberg } 10086835cedSPrasad Joshi 101441767feSAsias He /* raw image ?*/ 10243835ac9SSasha Levin disk = raw_image__probe(fd, &st, readonly); 1039f9207c5SSasha Levin if (!IS_ERR_OR_NULL(disk)) 10443835ac9SSasha Levin return disk; 105499f3bedSPekka Enberg 106d6c58e5bSPrasad Joshi if (close(fd) < 0) 1074542f276SCyrill Gorcunov pr_warning("close() failed"); 108499f3bedSPekka Enberg 1099f9207c5SSasha Levin return ERR_PTR(-ENOSYS); 110499f3bedSPekka Enberg } 111499f3bedSPekka Enberg 112c1ed214eSPrasad Joshi struct disk_image **disk_image__open_all(const char **filenames, bool *readonly, int count) 113c1ed214eSPrasad Joshi { 114c1ed214eSPrasad Joshi struct disk_image **disks; 115c1ed214eSPrasad Joshi int i; 1169f9207c5SSasha Levin void *err; 117c1ed214eSPrasad Joshi 1189f9207c5SSasha Levin if (!count) 1199f9207c5SSasha Levin return ERR_PTR(-EINVAL); 1209f9207c5SSasha Levin if (count > MAX_DISK_IMAGES) 1219f9207c5SSasha Levin return ERR_PTR(-ENOSPC); 122c1ed214eSPrasad Joshi 123c1ed214eSPrasad Joshi disks = calloc(count, sizeof(*disks)); 124c1ed214eSPrasad Joshi if (!disks) 1259f9207c5SSasha Levin return ERR_PTR(-ENOMEM); 126c1ed214eSPrasad Joshi 127c1ed214eSPrasad Joshi for (i = 0; i < count; i++) { 128c1ed214eSPrasad Joshi if (!filenames[i]) 129c1ed214eSPrasad Joshi continue; 130c1ed214eSPrasad Joshi 131c1ed214eSPrasad Joshi disks[i] = disk_image__open(filenames[i], readonly[i]); 1329f9207c5SSasha Levin if (IS_ERR_OR_NULL(disks[i])) { 133599ed2a8SCyrill Gorcunov pr_err("Loading disk image '%s' failed", filenames[i]); 1349f9207c5SSasha Levin err = disks[i]; 135c1ed214eSPrasad Joshi goto error; 136c1ed214eSPrasad Joshi } 137c1ed214eSPrasad Joshi } 138f41a132bSSasha Levin 139c1ed214eSPrasad Joshi return disks; 140c1ed214eSPrasad Joshi error: 141c1ed214eSPrasad Joshi for (i = 0; i < count; i++) 1429f9207c5SSasha Levin if (!IS_ERR_OR_NULL(disks[i])) 143c1ed214eSPrasad Joshi disk_image__close(disks[i]); 144c1ed214eSPrasad Joshi 145c1ed214eSPrasad Joshi free(disks); 1469f9207c5SSasha Levin return err; 147c1ed214eSPrasad Joshi } 148c1ed214eSPrasad Joshi 149fda63751SAsias He int disk_image__flush(struct disk_image *disk) 150fda63751SAsias He { 151fda63751SAsias He if (disk->ops->flush) 152fda63751SAsias He return disk->ops->flush(disk); 153fda63751SAsias He 154fda63751SAsias He return fsync(disk->fd); 155fda63751SAsias He } 156fda63751SAsias He 15772133dd2SAsias He int disk_image__close(struct disk_image *disk) 158499f3bedSPekka Enberg { 15982d94c50SIngo Molnar /* If there was no disk image then there's nothing to do: */ 16043835ac9SSasha Levin if (!disk) 16172133dd2SAsias He return 0; 16282d94c50SIngo Molnar 16343835ac9SSasha Levin if (disk->ops->close) 16472133dd2SAsias He return disk->ops->close(disk); 165499f3bedSPekka Enberg 16643835ac9SSasha Levin if (close(disk->fd) < 0) 1674542f276SCyrill Gorcunov pr_warning("close() failed"); 168499f3bedSPekka Enberg 16943835ac9SSasha Levin free(disk); 17072133dd2SAsias He 17172133dd2SAsias He return 0; 172499f3bedSPekka Enberg } 17370b0d7b0SSasha Levin 1749f9207c5SSasha Levin int disk_image__close_all(struct disk_image **disks, int count) 1759df47d00SPrasad Joshi { 1769df47d00SPrasad Joshi while (count) 1779df47d00SPrasad Joshi disk_image__close(disks[--count]); 1789df47d00SPrasad Joshi 1799df47d00SPrasad Joshi free(disks); 1809f9207c5SSasha Levin 1819f9207c5SSasha Levin return 0; 1829df47d00SPrasad Joshi } 1839df47d00SPrasad Joshi 18497a90170SAsias He /* 18597a90170SAsias He * Fill iov with disk data, starting from sector 'sector'. 18697a90170SAsias He * Return amount of bytes read. 18797a90170SAsias He */ 1885af21162SSasha Levin ssize_t disk_image__read(struct disk_image *disk, u64 sector, const struct iovec *iov, 1895af21162SSasha Levin int iovcount, void *param) 19070b0d7b0SSasha Levin { 19197a90170SAsias He ssize_t total = 0; 19270b0d7b0SSasha Levin 193aa400b00SPrasad Joshi if (debug_iodelay) 194aa400b00SPrasad Joshi msleep(debug_iodelay); 195aa400b00SPrasad Joshi 196*dcd3cd8eSAsias He if (disk->ops->read) { 197*dcd3cd8eSAsias He total = disk->ops->read(disk, sector, iov, iovcount, param); 19897a90170SAsias He if (total < 0) { 1994542f276SCyrill Gorcunov pr_info("disk_image__read error: total=%ld\n", (long)total); 2009f9207c5SSasha Levin return total; 20197a90170SAsias He } 2022534c9b6SSasha Levin } else { 203b41ca15aSSasha Levin /* Do nothing */ 2042534c9b6SSasha Levin } 20597a90170SAsias He 206f41a132bSSasha Levin if (!disk->async && disk->disk_req_cb) 2078b52f877SSasha Levin disk->disk_req_cb(param, total); 2085af21162SSasha Levin 20997a90170SAsias He return total; 21070b0d7b0SSasha Levin } 21170b0d7b0SSasha Levin 21297a90170SAsias He /* 21397a90170SAsias He * Write iov to disk, starting from sector 'sector'. 21497a90170SAsias He * Return amount of bytes written. 21597a90170SAsias He */ 2165af21162SSasha Levin ssize_t disk_image__write(struct disk_image *disk, u64 sector, const struct iovec *iov, 2175af21162SSasha Levin int iovcount, void *param) 21870b0d7b0SSasha Levin { 21997a90170SAsias He ssize_t total = 0; 22070b0d7b0SSasha Levin 221aa400b00SPrasad Joshi if (debug_iodelay) 222aa400b00SPrasad Joshi msleep(debug_iodelay); 223aa400b00SPrasad Joshi 224*dcd3cd8eSAsias He if (disk->ops->write) { 22597a90170SAsias He /* 22697a90170SAsias He * Try writev based operation first 22797a90170SAsias He */ 2285af21162SSasha Levin 229*dcd3cd8eSAsias He total = disk->ops->write(disk, sector, iov, iovcount, param); 23097a90170SAsias He if (total < 0) { 2314542f276SCyrill Gorcunov pr_info("disk_image__write error: total=%ld\n", (long)total); 2329f9207c5SSasha Levin return total; 23397a90170SAsias He } 2342534c9b6SSasha Levin } else { 235b41ca15aSSasha Levin /* Do nothing */ 2362534c9b6SSasha Levin } 23770b0d7b0SSasha Levin 238f41a132bSSasha Levin if (!disk->async && disk->disk_req_cb) 2398b52f877SSasha Levin disk->disk_req_cb(param, total); 2405af21162SSasha Levin 24197a90170SAsias He return total; 24270b0d7b0SSasha Levin } 243ff6462e8SSasha Levin 244ff6462e8SSasha Levin ssize_t disk_image__get_serial(struct disk_image *disk, void *buffer, ssize_t *len) 245ff6462e8SSasha Levin { 246ff6462e8SSasha Levin struct stat st; 2479f9207c5SSasha Levin int r; 248ff6462e8SSasha Levin 2499f9207c5SSasha Levin r = fstat(disk->fd, &st); 2509f9207c5SSasha Levin if (r) 2519f9207c5SSasha Levin return r; 252ff6462e8SSasha Levin 253eab301d0SSasha Levin *len = snprintf(buffer, *len, "%llu%llu%llu", (u64)st.st_dev, (u64)st.st_rdev, (u64)st.st_ino); 254ff6462e8SSasha Levin return *len; 255ff6462e8SSasha Levin } 2565af21162SSasha Levin 2578b52f877SSasha Levin void disk_image__set_callback(struct disk_image *disk, void (*disk_req_cb)(void *param, long len)) 2585af21162SSasha Levin { 2595af21162SSasha Levin disk->disk_req_cb = disk_req_cb; 2605af21162SSasha Levin } 261