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 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*97f16d66SAsias He struct disk_image **disk_image__open_all(struct disk_image_params *params, int count) 115c1ed214eSPrasad Joshi { 116c1ed214eSPrasad Joshi struct disk_image **disks; 117*97f16d66SAsias He const char *filename; 118*97f16d66SAsias He bool readonly; 1199f9207c5SSasha Levin void *err; 120*97f16d66SAsias He int i; 121c1ed214eSPrasad Joshi 1229f9207c5SSasha Levin if (!count) 1239f9207c5SSasha Levin return ERR_PTR(-EINVAL); 1249f9207c5SSasha Levin if (count > MAX_DISK_IMAGES) 1259f9207c5SSasha Levin return ERR_PTR(-ENOSPC); 126c1ed214eSPrasad Joshi 127c1ed214eSPrasad Joshi disks = calloc(count, sizeof(*disks)); 128c1ed214eSPrasad Joshi if (!disks) 1299f9207c5SSasha Levin return ERR_PTR(-ENOMEM); 130c1ed214eSPrasad Joshi 131c1ed214eSPrasad Joshi for (i = 0; i < count; i++) { 132*97f16d66SAsias He filename = params[i].filename; 133*97f16d66SAsias He readonly = params[i].readonly; 134*97f16d66SAsias He if (!filename) 135c1ed214eSPrasad Joshi continue; 136c1ed214eSPrasad Joshi 137*97f16d66SAsias He disks[i] = disk_image__open(filename, readonly); 1389f9207c5SSasha Levin if (IS_ERR_OR_NULL(disks[i])) { 139*97f16d66SAsias He pr_err("Loading disk image '%s' failed", filename); 1409f9207c5SSasha Levin err = disks[i]; 141c1ed214eSPrasad Joshi goto error; 142c1ed214eSPrasad Joshi } 143c1ed214eSPrasad Joshi } 144f41a132bSSasha Levin 145c1ed214eSPrasad Joshi return disks; 146c1ed214eSPrasad Joshi error: 147c1ed214eSPrasad Joshi for (i = 0; i < count; i++) 1489f9207c5SSasha Levin if (!IS_ERR_OR_NULL(disks[i])) 149c1ed214eSPrasad Joshi disk_image__close(disks[i]); 150c1ed214eSPrasad Joshi 151c1ed214eSPrasad Joshi free(disks); 1529f9207c5SSasha Levin return err; 153c1ed214eSPrasad Joshi } 154c1ed214eSPrasad Joshi 155fda63751SAsias He int disk_image__flush(struct disk_image *disk) 156fda63751SAsias He { 157fda63751SAsias He if (disk->ops->flush) 158fda63751SAsias He return disk->ops->flush(disk); 159fda63751SAsias He 160fda63751SAsias He return fsync(disk->fd); 161fda63751SAsias He } 162fda63751SAsias He 16372133dd2SAsias He int disk_image__close(struct disk_image *disk) 164499f3bedSPekka Enberg { 16582d94c50SIngo Molnar /* If there was no disk image then there's nothing to do: */ 16643835ac9SSasha Levin if (!disk) 16772133dd2SAsias He return 0; 16882d94c50SIngo Molnar 16943835ac9SSasha Levin if (disk->ops->close) 17072133dd2SAsias He return disk->ops->close(disk); 171499f3bedSPekka Enberg 17243835ac9SSasha Levin if (close(disk->fd) < 0) 1734542f276SCyrill Gorcunov pr_warning("close() failed"); 174499f3bedSPekka Enberg 17543835ac9SSasha Levin free(disk); 17672133dd2SAsias He 17772133dd2SAsias He return 0; 178499f3bedSPekka Enberg } 17970b0d7b0SSasha Levin 1809f9207c5SSasha Levin int disk_image__close_all(struct disk_image **disks, int count) 1819df47d00SPrasad Joshi { 1829df47d00SPrasad Joshi while (count) 1839df47d00SPrasad Joshi disk_image__close(disks[--count]); 1849df47d00SPrasad Joshi 1859df47d00SPrasad Joshi free(disks); 1869f9207c5SSasha Levin 1879f9207c5SSasha Levin return 0; 1889df47d00SPrasad Joshi } 1899df47d00SPrasad Joshi 19097a90170SAsias He /* 19197a90170SAsias He * Fill iov with disk data, starting from sector 'sector'. 19297a90170SAsias He * Return amount of bytes read. 19397a90170SAsias He */ 19454c84566SAsias He ssize_t disk_image__read(struct disk_image *disk, u64 sector, 19554c84566SAsias He const struct iovec *iov, int iovcount, void *param) 19670b0d7b0SSasha Levin { 19797a90170SAsias He ssize_t total = 0; 19870b0d7b0SSasha Levin 199aa400b00SPrasad Joshi if (debug_iodelay) 200aa400b00SPrasad Joshi msleep(debug_iodelay); 201aa400b00SPrasad Joshi 202dcd3cd8eSAsias He if (disk->ops->read) { 203dcd3cd8eSAsias He total = disk->ops->read(disk, sector, iov, iovcount, param); 20497a90170SAsias He if (total < 0) { 2054542f276SCyrill Gorcunov pr_info("disk_image__read error: total=%ld\n", (long)total); 2069f9207c5SSasha Levin return total; 20797a90170SAsias He } 2082534c9b6SSasha Levin } 20997a90170SAsias He 210f41a132bSSasha Levin if (!disk->async && disk->disk_req_cb) 2118b52f877SSasha Levin disk->disk_req_cb(param, total); 2125af21162SSasha Levin 21397a90170SAsias He return total; 21470b0d7b0SSasha Levin } 21570b0d7b0SSasha Levin 21697a90170SAsias He /* 21797a90170SAsias He * Write iov to disk, starting from sector 'sector'. 21897a90170SAsias He * Return amount of bytes written. 21997a90170SAsias He */ 22054c84566SAsias He ssize_t disk_image__write(struct disk_image *disk, u64 sector, 22154c84566SAsias He const struct iovec *iov, int iovcount, void *param) 22270b0d7b0SSasha Levin { 22397a90170SAsias He ssize_t total = 0; 22470b0d7b0SSasha Levin 225aa400b00SPrasad Joshi if (debug_iodelay) 226aa400b00SPrasad Joshi msleep(debug_iodelay); 227aa400b00SPrasad Joshi 228dcd3cd8eSAsias He if (disk->ops->write) { 22997a90170SAsias He /* 23097a90170SAsias He * Try writev based operation first 23197a90170SAsias He */ 2325af21162SSasha Levin 233dcd3cd8eSAsias He total = disk->ops->write(disk, sector, iov, iovcount, param); 23497a90170SAsias He if (total < 0) { 2354542f276SCyrill Gorcunov pr_info("disk_image__write error: total=%ld\n", (long)total); 2369f9207c5SSasha Levin return total; 23797a90170SAsias He } 2382534c9b6SSasha Levin } else { 239b41ca15aSSasha Levin /* Do nothing */ 2402534c9b6SSasha Levin } 24170b0d7b0SSasha Levin 242f41a132bSSasha Levin if (!disk->async && disk->disk_req_cb) 2438b52f877SSasha Levin disk->disk_req_cb(param, total); 2445af21162SSasha Levin 24597a90170SAsias He return total; 24670b0d7b0SSasha Levin } 247ff6462e8SSasha Levin 248ff6462e8SSasha Levin ssize_t disk_image__get_serial(struct disk_image *disk, void *buffer, ssize_t *len) 249ff6462e8SSasha Levin { 250ff6462e8SSasha Levin struct stat st; 2519f9207c5SSasha Levin int r; 252ff6462e8SSasha Levin 2539f9207c5SSasha Levin r = fstat(disk->fd, &st); 2549f9207c5SSasha Levin if (r) 2559f9207c5SSasha Levin return r; 256ff6462e8SSasha Levin 25754c84566SAsias He *len = snprintf(buffer, *len, "%llu%llu%llu", 25854c84566SAsias He (u64)st.st_dev, (u64)st.st_rdev, (u64)st.st_ino); 259ff6462e8SSasha Levin return *len; 260ff6462e8SSasha Levin } 2615af21162SSasha Levin 26254c84566SAsias He void disk_image__set_callback(struct disk_image *disk, 26354c84566SAsias He void (*disk_req_cb)(void *param, long len)) 2645af21162SSasha Levin { 2655af21162SSasha Levin disk->disk_req_cb = disk_req_cb; 2665af21162SSasha Levin } 267