19f532d00SPekka Enberg #include "kvm/disk-image.h" 286835cedSPrasad Joshi #include "kvm/qcow.h" 3f41a132bSSasha Levin #include "kvm/virtio-blk.h" 43b55dcdeSSasha Levin #include "kvm/kvm.h" 5f41a132bSSasha Levin 69f9207c5SSasha Levin #include <linux/err.h> 7f41a132bSSasha Levin #include <sys/eventfd.h> 8*52c22e6eSAndre Przywara #include <poll.h> 9f41a132bSSasha Levin 10fea74936SAsias He #define AIO_MAX 256 119f532d00SPekka Enberg 12aa400b00SPrasad Joshi int debug_iodelay; 13aa400b00SPrasad Joshi 143b55dcdeSSasha Levin static int disk_image__close(struct disk_image *disk); 153b55dcdeSSasha Levin 163b55dcdeSSasha Levin int disk_img_name_parser(const struct option *opt, const char *arg, int unset) 173b55dcdeSSasha Levin { 183b55dcdeSSasha Levin const char *cur; 193b55dcdeSSasha Levin char *sep; 203b55dcdeSSasha Levin struct kvm *kvm = opt->ptr; 213b55dcdeSSasha Levin 223b55dcdeSSasha Levin if (kvm->cfg.image_count >= MAX_DISK_IMAGES) 233b55dcdeSSasha Levin die("Currently only 4 images are supported"); 243b55dcdeSSasha Levin 253b55dcdeSSasha Levin kvm->cfg.disk_image[kvm->cfg.image_count].filename = arg; 263b55dcdeSSasha Levin cur = arg; 273b55dcdeSSasha Levin 283b55dcdeSSasha Levin if (strncmp(arg, "scsi:", 5) == 0) { 293b55dcdeSSasha Levin sep = strstr(arg, ":"); 303b55dcdeSSasha Levin if (sep) 313b55dcdeSSasha Levin kvm->cfg.disk_image[kvm->cfg.image_count].wwpn = sep + 1; 323b55dcdeSSasha Levin sep = strstr(sep + 1, ":"); 333b55dcdeSSasha Levin if (sep) { 343b55dcdeSSasha Levin *sep = 0; 353b55dcdeSSasha Levin kvm->cfg.disk_image[kvm->cfg.image_count].tpgt = sep + 1; 363b55dcdeSSasha Levin } 373b55dcdeSSasha Levin cur = sep + 1; 383b55dcdeSSasha Levin } 393b55dcdeSSasha Levin 403b55dcdeSSasha Levin do { 413b55dcdeSSasha Levin sep = strstr(cur, ","); 423b55dcdeSSasha Levin if (sep) { 433b55dcdeSSasha Levin if (strncmp(sep + 1, "ro", 2) == 0) 443b55dcdeSSasha Levin kvm->cfg.disk_image[kvm->cfg.image_count].readonly = true; 453b55dcdeSSasha Levin else if (strncmp(sep + 1, "direct", 6) == 0) 463b55dcdeSSasha Levin kvm->cfg.disk_image[kvm->cfg.image_count].direct = true; 473b55dcdeSSasha Levin *sep = 0; 483b55dcdeSSasha Levin cur = sep + 1; 493b55dcdeSSasha Levin } 503b55dcdeSSasha Levin } while (sep); 513b55dcdeSSasha Levin 523b55dcdeSSasha Levin kvm->cfg.image_count++; 533b55dcdeSSasha Levin 543b55dcdeSSasha Levin return 0; 553b55dcdeSSasha Levin } 563b55dcdeSSasha Levin 57f41a132bSSasha Levin #ifdef CONFIG_HAS_AIO 58f41a132bSSasha Levin static void *disk_image__thread(void *param) 59f41a132bSSasha Levin { 60f41a132bSSasha Levin struct disk_image *disk = param; 61618cbb7cSAsias He struct io_event event[AIO_MAX]; 62618cbb7cSAsias He struct timespec notime = {0}; 63618cbb7cSAsias He int nr, i; 64f41a132bSSasha Levin u64 dummy; 65f41a132bSSasha Levin 66a4d8c55eSSasha Levin kvm__set_thread_name("disk-image-io"); 67a4d8c55eSSasha Levin 68f41a132bSSasha Levin while (read(disk->evt, &dummy, sizeof(dummy)) > 0) { 69618cbb7cSAsias He nr = io_getevents(disk->ctx, 1, ARRAY_SIZE(event), event, ¬ime); 70618cbb7cSAsias He for (i = 0; i < nr; i++) 71618cbb7cSAsias He disk->disk_req_cb(event[i].data, event[i].res); 72f41a132bSSasha Levin } 73f41a132bSSasha Levin 74f41a132bSSasha Levin return NULL; 75f41a132bSSasha Levin } 76f41a132bSSasha Levin #endif 77f41a132bSSasha Levin 7854c84566SAsias He struct disk_image *disk_image__new(int fd, u64 size, 7954c84566SAsias He struct disk_image_operations *ops, 8054c84566SAsias He int use_mmap) 819f532d00SPekka Enberg { 8243835ac9SSasha Levin struct disk_image *disk; 839f9207c5SSasha Levin int r; 849f532d00SPekka Enberg 8543835ac9SSasha Levin disk = malloc(sizeof *disk); 8643835ac9SSasha Levin if (!disk) 879f9207c5SSasha Levin return ERR_PTR(-ENOMEM); 889f532d00SPekka Enberg 899f9207c5SSasha Levin *disk = (struct disk_image) { 909f9207c5SSasha Levin .fd = fd, 919f9207c5SSasha Levin .size = size, 929f9207c5SSasha Levin .ops = ops, 939f9207c5SSasha Levin }; 94f4ff38dfSPrasad Joshi 957d22135fSAsias He if (use_mmap == DISK_IMAGE_MMAP) { 967d22135fSAsias He /* 977d22135fSAsias He * The write to disk image will be discarded 987d22135fSAsias He */ 9937c34ca8SSasha Levin disk->priv = mmap(NULL, size, PROT_RW, MAP_PRIVATE | MAP_NORESERVE, fd, 0); 1009d15c39aSSasha Levin if (disk->priv == MAP_FAILED) { 1019f9207c5SSasha Levin r = -errno; 1029d15c39aSSasha Levin free(disk); 1039f9207c5SSasha Levin return ERR_PTR(r); 1049d15c39aSSasha Levin } 1057d22135fSAsias He } 1067d22135fSAsias He 107f41a132bSSasha Levin #ifdef CONFIG_HAS_AIO 10871bf426aSSasha Levin { 109f41a132bSSasha Levin pthread_t thread; 110f41a132bSSasha Levin 111f41a132bSSasha Levin disk->evt = eventfd(0, 0); 112f41a132bSSasha Levin io_setup(AIO_MAX, &disk->ctx); 1139f9207c5SSasha Levin r = pthread_create(&thread, NULL, disk_image__thread, disk); 1149f9207c5SSasha Levin if (r) { 1159f9207c5SSasha Levin r = -errno; 1169f9207c5SSasha Levin free(disk); 1179f9207c5SSasha Levin return ERR_PTR(r); 1189f9207c5SSasha Levin } 119f41a132bSSasha Levin } 120f41a132bSSasha Levin #endif 12143835ac9SSasha Levin return disk; 1229f532d00SPekka Enberg } 1239f532d00SPekka Enberg 1243b55dcdeSSasha Levin static struct disk_image *disk_image__open(const char *filename, bool readonly, bool direct) 125499f3bedSPekka Enberg { 12643835ac9SSasha Levin struct disk_image *disk; 1276ec60cfdSPekka Enberg struct stat st; 1285236b505SAsias He int fd, flags; 1295236b505SAsias He 1305236b505SAsias He if (readonly) 1315236b505SAsias He flags = O_RDONLY; 1325236b505SAsias He else 1335236b505SAsias He flags = O_RDWR; 1345236b505SAsias He if (direct) 1355236b505SAsias He flags |= O_DIRECT; 136499f3bedSPekka Enberg 1376ec60cfdSPekka Enberg if (stat(filename, &st) < 0) 1389f9207c5SSasha Levin return ERR_PTR(-errno); 1396ec60cfdSPekka Enberg 140441767feSAsias He /* blk device ?*/ 1415236b505SAsias He disk = blkdev__probe(filename, flags, &st); 1429f9207c5SSasha Levin if (!IS_ERR_OR_NULL(disk)) 143441767feSAsias He return disk; 1446ec60cfdSPekka Enberg 1455236b505SAsias He fd = open(filename, flags); 146499f3bedSPekka Enberg if (fd < 0) 1479f9207c5SSasha Levin return ERR_PTR(fd); 148499f3bedSPekka Enberg 149441767feSAsias He /* qcow image ?*/ 15017f68274SPekka Enberg disk = qcow_probe(fd, true); 1519f9207c5SSasha Levin if (!IS_ERR_OR_NULL(disk)) { 15217f68274SPekka Enberg pr_warning("Forcing read-only support for QCOW"); 15343835ac9SSasha Levin return disk; 15417f68274SPekka Enberg } 15586835cedSPrasad Joshi 156441767feSAsias He /* raw image ?*/ 15743835ac9SSasha Levin disk = raw_image__probe(fd, &st, readonly); 1589f9207c5SSasha Levin if (!IS_ERR_OR_NULL(disk)) 15943835ac9SSasha Levin return disk; 160499f3bedSPekka Enberg 161d6c58e5bSPrasad Joshi if (close(fd) < 0) 1624542f276SCyrill Gorcunov pr_warning("close() failed"); 163499f3bedSPekka Enberg 1649f9207c5SSasha Levin return ERR_PTR(-ENOSYS); 165499f3bedSPekka Enberg } 166499f3bedSPekka Enberg 1673b55dcdeSSasha Levin static struct disk_image **disk_image__open_all(struct kvm *kvm) 168c1ed214eSPrasad Joshi { 169c1ed214eSPrasad Joshi struct disk_image **disks; 17097f16d66SAsias He const char *filename; 171a67da3beSAsias He const char *wwpn; 172a67da3beSAsias He const char *tpgt; 17397f16d66SAsias He bool readonly; 1745236b505SAsias He bool direct; 1759f9207c5SSasha Levin void *err; 17697f16d66SAsias He int i; 1773b55dcdeSSasha Levin struct disk_image_params *params = (struct disk_image_params *)&kvm->cfg.disk_image; 1783b55dcdeSSasha Levin int count = kvm->cfg.image_count; 179c1ed214eSPrasad Joshi 1809f9207c5SSasha Levin if (!count) 1819f9207c5SSasha Levin return ERR_PTR(-EINVAL); 1829f9207c5SSasha Levin if (count > MAX_DISK_IMAGES) 1839f9207c5SSasha Levin return ERR_PTR(-ENOSPC); 184c1ed214eSPrasad Joshi 185c1ed214eSPrasad Joshi disks = calloc(count, sizeof(*disks)); 186c1ed214eSPrasad Joshi if (!disks) 1879f9207c5SSasha Levin return ERR_PTR(-ENOMEM); 188c1ed214eSPrasad Joshi 189c1ed214eSPrasad Joshi for (i = 0; i < count; i++) { 19097f16d66SAsias He filename = params[i].filename; 19197f16d66SAsias He readonly = params[i].readonly; 1925236b505SAsias He direct = params[i].direct; 193a67da3beSAsias He wwpn = params[i].wwpn; 194a67da3beSAsias He tpgt = params[i].tpgt; 195a67da3beSAsias He 196a67da3beSAsias He if (wwpn) { 197a67da3beSAsias He disks[i] = malloc(sizeof(struct disk_image)); 198a67da3beSAsias He if (!disks[i]) 199a67da3beSAsias He return ERR_PTR(-ENOMEM); 200a67da3beSAsias He disks[i]->wwpn = wwpn; 201a67da3beSAsias He disks[i]->tpgt = tpgt; 202a67da3beSAsias He continue; 203a67da3beSAsias He } 204a67da3beSAsias He 20597f16d66SAsias He if (!filename) 206c1ed214eSPrasad Joshi continue; 207c1ed214eSPrasad Joshi 2085236b505SAsias He disks[i] = disk_image__open(filename, readonly, direct); 2099f9207c5SSasha Levin if (IS_ERR_OR_NULL(disks[i])) { 21097f16d66SAsias He pr_err("Loading disk image '%s' failed", filename); 2119f9207c5SSasha Levin err = disks[i]; 212c1ed214eSPrasad Joshi goto error; 213c1ed214eSPrasad Joshi } 2143b55dcdeSSasha Levin disks[i]->debug_iodelay = kvm->cfg.debug_iodelay; 215c1ed214eSPrasad Joshi } 216f41a132bSSasha Levin 217c1ed214eSPrasad Joshi return disks; 218c1ed214eSPrasad Joshi error: 219c1ed214eSPrasad Joshi for (i = 0; i < count; i++) 2209f9207c5SSasha Levin if (!IS_ERR_OR_NULL(disks[i])) 221c1ed214eSPrasad Joshi disk_image__close(disks[i]); 222c1ed214eSPrasad Joshi 223c1ed214eSPrasad Joshi free(disks); 2249f9207c5SSasha Levin return err; 225c1ed214eSPrasad Joshi } 226c1ed214eSPrasad Joshi 227fda63751SAsias He int disk_image__flush(struct disk_image *disk) 228fda63751SAsias He { 229fda63751SAsias He if (disk->ops->flush) 230fda63751SAsias He return disk->ops->flush(disk); 231fda63751SAsias He 232fda63751SAsias He return fsync(disk->fd); 233fda63751SAsias He } 234fda63751SAsias He 2353b55dcdeSSasha Levin static int disk_image__close(struct disk_image *disk) 236499f3bedSPekka Enberg { 23782d94c50SIngo Molnar /* If there was no disk image then there's nothing to do: */ 23843835ac9SSasha Levin if (!disk) 23972133dd2SAsias He return 0; 24082d94c50SIngo Molnar 24143835ac9SSasha Levin if (disk->ops->close) 24272133dd2SAsias He return disk->ops->close(disk); 243499f3bedSPekka Enberg 24443835ac9SSasha Levin if (close(disk->fd) < 0) 2454542f276SCyrill Gorcunov pr_warning("close() failed"); 246499f3bedSPekka Enberg 24743835ac9SSasha Levin free(disk); 24872133dd2SAsias He 24972133dd2SAsias He return 0; 250499f3bedSPekka Enberg } 25170b0d7b0SSasha Levin 2523b55dcdeSSasha Levin static int disk_image__close_all(struct disk_image **disks, int count) 2539df47d00SPrasad Joshi { 2549df47d00SPrasad Joshi while (count) 2559df47d00SPrasad Joshi disk_image__close(disks[--count]); 2569df47d00SPrasad Joshi 2579df47d00SPrasad Joshi free(disks); 2589f9207c5SSasha Levin 2599f9207c5SSasha Levin return 0; 2609df47d00SPrasad Joshi } 2619df47d00SPrasad Joshi 26297a90170SAsias He /* 26397a90170SAsias He * Fill iov with disk data, starting from sector 'sector'. 26497a90170SAsias He * Return amount of bytes read. 26597a90170SAsias He */ 26654c84566SAsias He ssize_t disk_image__read(struct disk_image *disk, u64 sector, 26754c84566SAsias He const struct iovec *iov, int iovcount, void *param) 26870b0d7b0SSasha Levin { 26997a90170SAsias He ssize_t total = 0; 27070b0d7b0SSasha Levin 271aa400b00SPrasad Joshi if (debug_iodelay) 272aa400b00SPrasad Joshi msleep(debug_iodelay); 273aa400b00SPrasad Joshi 274dcd3cd8eSAsias He if (disk->ops->read) { 275dcd3cd8eSAsias He total = disk->ops->read(disk, sector, iov, iovcount, param); 27697a90170SAsias He if (total < 0) { 2774542f276SCyrill Gorcunov pr_info("disk_image__read error: total=%ld\n", (long)total); 2789f9207c5SSasha Levin return total; 27997a90170SAsias He } 2802534c9b6SSasha Levin } 28197a90170SAsias He 282f41a132bSSasha Levin if (!disk->async && disk->disk_req_cb) 2838b52f877SSasha Levin disk->disk_req_cb(param, total); 2845af21162SSasha Levin 28597a90170SAsias He return total; 28670b0d7b0SSasha Levin } 28770b0d7b0SSasha Levin 28897a90170SAsias He /* 28997a90170SAsias He * Write iov to disk, starting from sector 'sector'. 29097a90170SAsias He * Return amount of bytes written. 29197a90170SAsias He */ 29254c84566SAsias He ssize_t disk_image__write(struct disk_image *disk, u64 sector, 29354c84566SAsias He const struct iovec *iov, int iovcount, void *param) 29470b0d7b0SSasha Levin { 29597a90170SAsias He ssize_t total = 0; 29670b0d7b0SSasha Levin 297aa400b00SPrasad Joshi if (debug_iodelay) 298aa400b00SPrasad Joshi msleep(debug_iodelay); 299aa400b00SPrasad Joshi 300dcd3cd8eSAsias He if (disk->ops->write) { 30197a90170SAsias He /* 30297a90170SAsias He * Try writev based operation first 30397a90170SAsias He */ 3045af21162SSasha Levin 305dcd3cd8eSAsias He total = disk->ops->write(disk, sector, iov, iovcount, param); 30697a90170SAsias He if (total < 0) { 3074542f276SCyrill Gorcunov pr_info("disk_image__write error: total=%ld\n", (long)total); 3089f9207c5SSasha Levin return total; 30997a90170SAsias He } 3102534c9b6SSasha Levin } else { 311b41ca15aSSasha Levin /* Do nothing */ 3122534c9b6SSasha Levin } 31370b0d7b0SSasha Levin 314f41a132bSSasha Levin if (!disk->async && disk->disk_req_cb) 3158b52f877SSasha Levin disk->disk_req_cb(param, total); 3165af21162SSasha Levin 31797a90170SAsias He return total; 31870b0d7b0SSasha Levin } 319ff6462e8SSasha Levin 320ff6462e8SSasha Levin ssize_t disk_image__get_serial(struct disk_image *disk, void *buffer, ssize_t *len) 321ff6462e8SSasha Levin { 322ff6462e8SSasha Levin struct stat st; 3239f9207c5SSasha Levin int r; 324ff6462e8SSasha Levin 3259f9207c5SSasha Levin r = fstat(disk->fd, &st); 3269f9207c5SSasha Levin if (r) 3279f9207c5SSasha Levin return r; 328ff6462e8SSasha Levin 32954c84566SAsias He *len = snprintf(buffer, *len, "%llu%llu%llu", 33069f50425SAndreas Herrmann (unsigned long long)st.st_dev, 33169f50425SAndreas Herrmann (unsigned long long)st.st_rdev, 33269f50425SAndreas Herrmann (unsigned long long)st.st_ino); 333ff6462e8SSasha Levin return *len; 334ff6462e8SSasha Levin } 3355af21162SSasha Levin 33654c84566SAsias He void disk_image__set_callback(struct disk_image *disk, 33754c84566SAsias He void (*disk_req_cb)(void *param, long len)) 3385af21162SSasha Levin { 3395af21162SSasha Levin disk->disk_req_cb = disk_req_cb; 3405af21162SSasha Levin } 3413b55dcdeSSasha Levin 3423b55dcdeSSasha Levin int disk_image__init(struct kvm *kvm) 3433b55dcdeSSasha Levin { 3443b55dcdeSSasha Levin if (kvm->cfg.image_count) { 3453b55dcdeSSasha Levin kvm->disks = disk_image__open_all(kvm); 3463b55dcdeSSasha Levin if (IS_ERR(kvm->disks)) 3473b55dcdeSSasha Levin return PTR_ERR(kvm->disks); 3483b55dcdeSSasha Levin } 3493b55dcdeSSasha Levin 3503b55dcdeSSasha Levin return 0; 3513b55dcdeSSasha Levin } 35249a8afd1SSasha Levin dev_base_init(disk_image__init); 3533b55dcdeSSasha Levin 3543b55dcdeSSasha Levin int disk_image__exit(struct kvm *kvm) 3553b55dcdeSSasha Levin { 3563b55dcdeSSasha Levin return disk_image__close_all(kvm->disks, kvm->nr_disks); 3573b55dcdeSSasha Levin } 35849a8afd1SSasha Levin dev_base_exit(disk_image__exit); 359