19f532d00SPekka Enberg #include "kvm/disk-image.h" 286835cedSPrasad Joshi #include "kvm/qcow.h" 3f41a132bSSasha Levin #include "kvm/virtio-blk.h" 4*3b55dcdeSSasha Levin #include "kvm/kvm.h" 5f41a132bSSasha Levin 69f9207c5SSasha Levin #include <linux/err.h> 7f41a132bSSasha Levin #include <sys/eventfd.h> 8f41a132bSSasha Levin #include <sys/poll.h> 9f41a132bSSasha Levin 10fea74936SAsias He #define AIO_MAX 256 119f532d00SPekka Enberg 12aa400b00SPrasad Joshi int debug_iodelay; 13aa400b00SPrasad Joshi 14*3b55dcdeSSasha Levin static int disk_image__close(struct disk_image *disk); 15*3b55dcdeSSasha Levin 16*3b55dcdeSSasha Levin int disk_img_name_parser(const struct option *opt, const char *arg, int unset) 17*3b55dcdeSSasha Levin { 18*3b55dcdeSSasha Levin const char *cur; 19*3b55dcdeSSasha Levin char *sep; 20*3b55dcdeSSasha Levin struct kvm *kvm = opt->ptr; 21*3b55dcdeSSasha Levin 22*3b55dcdeSSasha Levin if (kvm->cfg.image_count >= MAX_DISK_IMAGES) 23*3b55dcdeSSasha Levin die("Currently only 4 images are supported"); 24*3b55dcdeSSasha Levin 25*3b55dcdeSSasha Levin kvm->cfg.disk_image[kvm->cfg.image_count].filename = arg; 26*3b55dcdeSSasha Levin cur = arg; 27*3b55dcdeSSasha Levin 28*3b55dcdeSSasha Levin if (strncmp(arg, "scsi:", 5) == 0) { 29*3b55dcdeSSasha Levin sep = strstr(arg, ":"); 30*3b55dcdeSSasha Levin if (sep) 31*3b55dcdeSSasha Levin kvm->cfg.disk_image[kvm->cfg.image_count].wwpn = sep + 1; 32*3b55dcdeSSasha Levin sep = strstr(sep + 1, ":"); 33*3b55dcdeSSasha Levin if (sep) { 34*3b55dcdeSSasha Levin *sep = 0; 35*3b55dcdeSSasha Levin kvm->cfg.disk_image[kvm->cfg.image_count].tpgt = sep + 1; 36*3b55dcdeSSasha Levin } 37*3b55dcdeSSasha Levin cur = sep + 1; 38*3b55dcdeSSasha Levin } 39*3b55dcdeSSasha Levin 40*3b55dcdeSSasha Levin do { 41*3b55dcdeSSasha Levin sep = strstr(cur, ","); 42*3b55dcdeSSasha Levin if (sep) { 43*3b55dcdeSSasha Levin if (strncmp(sep + 1, "ro", 2) == 0) 44*3b55dcdeSSasha Levin kvm->cfg.disk_image[kvm->cfg.image_count].readonly = true; 45*3b55dcdeSSasha Levin else if (strncmp(sep + 1, "direct", 6) == 0) 46*3b55dcdeSSasha Levin kvm->cfg.disk_image[kvm->cfg.image_count].direct = true; 47*3b55dcdeSSasha Levin *sep = 0; 48*3b55dcdeSSasha Levin cur = sep + 1; 49*3b55dcdeSSasha Levin } 50*3b55dcdeSSasha Levin } while (sep); 51*3b55dcdeSSasha Levin 52*3b55dcdeSSasha Levin kvm->cfg.image_count++; 53*3b55dcdeSSasha Levin 54*3b55dcdeSSasha Levin return 0; 55*3b55dcdeSSasha Levin } 56*3b55dcdeSSasha 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 66f41a132bSSasha Levin while (read(disk->evt, &dummy, sizeof(dummy)) > 0) { 67618cbb7cSAsias He nr = io_getevents(disk->ctx, 1, ARRAY_SIZE(event), event, ¬ime); 68618cbb7cSAsias He for (i = 0; i < nr; i++) 69618cbb7cSAsias He disk->disk_req_cb(event[i].data, event[i].res); 70f41a132bSSasha Levin } 71f41a132bSSasha Levin 72f41a132bSSasha Levin return NULL; 73f41a132bSSasha Levin } 74f41a132bSSasha Levin #endif 75f41a132bSSasha Levin 7654c84566SAsias He struct disk_image *disk_image__new(int fd, u64 size, 7754c84566SAsias He struct disk_image_operations *ops, 7854c84566SAsias He int use_mmap) 799f532d00SPekka Enberg { 8043835ac9SSasha Levin struct disk_image *disk; 819f9207c5SSasha Levin int r; 829f532d00SPekka Enberg 8343835ac9SSasha Levin disk = malloc(sizeof *disk); 8443835ac9SSasha Levin if (!disk) 859f9207c5SSasha Levin return ERR_PTR(-ENOMEM); 869f532d00SPekka Enberg 879f9207c5SSasha Levin *disk = (struct disk_image) { 889f9207c5SSasha Levin .fd = fd, 899f9207c5SSasha Levin .size = size, 909f9207c5SSasha Levin .ops = ops, 919f9207c5SSasha Levin }; 92f4ff38dfSPrasad Joshi 937d22135fSAsias He if (use_mmap == DISK_IMAGE_MMAP) { 947d22135fSAsias He /* 957d22135fSAsias He * The write to disk image will be discarded 967d22135fSAsias He */ 9737c34ca8SSasha Levin disk->priv = mmap(NULL, size, PROT_RW, MAP_PRIVATE | MAP_NORESERVE, fd, 0); 989d15c39aSSasha Levin if (disk->priv == MAP_FAILED) { 999f9207c5SSasha Levin r = -errno; 1009d15c39aSSasha Levin free(disk); 1019f9207c5SSasha Levin return ERR_PTR(r); 1029d15c39aSSasha Levin } 1037d22135fSAsias He } 1047d22135fSAsias He 105f41a132bSSasha Levin #ifdef CONFIG_HAS_AIO 106f41a132bSSasha Levin if (disk) { 107f41a132bSSasha Levin pthread_t thread; 108f41a132bSSasha Levin 109f41a132bSSasha Levin disk->evt = eventfd(0, 0); 110f41a132bSSasha Levin io_setup(AIO_MAX, &disk->ctx); 1119f9207c5SSasha Levin r = pthread_create(&thread, NULL, disk_image__thread, disk); 1129f9207c5SSasha Levin if (r) { 1139f9207c5SSasha Levin r = -errno; 1149f9207c5SSasha Levin free(disk); 1159f9207c5SSasha Levin return ERR_PTR(r); 1169f9207c5SSasha Levin } 117f41a132bSSasha Levin } 118f41a132bSSasha Levin #endif 11943835ac9SSasha Levin return disk; 1209f532d00SPekka Enberg } 1219f532d00SPekka Enberg 122*3b55dcdeSSasha Levin static struct disk_image *disk_image__open(const char *filename, bool readonly, bool direct) 123499f3bedSPekka Enberg { 12443835ac9SSasha Levin struct disk_image *disk; 1256ec60cfdSPekka Enberg struct stat st; 1265236b505SAsias He int fd, flags; 1275236b505SAsias He 1285236b505SAsias He if (readonly) 1295236b505SAsias He flags = O_RDONLY; 1305236b505SAsias He else 1315236b505SAsias He flags = O_RDWR; 1325236b505SAsias He if (direct) 1335236b505SAsias He flags |= O_DIRECT; 134499f3bedSPekka Enberg 1356ec60cfdSPekka Enberg if (stat(filename, &st) < 0) 1369f9207c5SSasha Levin return ERR_PTR(-errno); 1376ec60cfdSPekka Enberg 138441767feSAsias He /* blk device ?*/ 1395236b505SAsias He disk = blkdev__probe(filename, flags, &st); 1409f9207c5SSasha Levin if (!IS_ERR_OR_NULL(disk)) 141441767feSAsias He return disk; 1426ec60cfdSPekka Enberg 1435236b505SAsias He fd = open(filename, flags); 144499f3bedSPekka Enberg if (fd < 0) 1459f9207c5SSasha Levin return ERR_PTR(fd); 146499f3bedSPekka Enberg 147441767feSAsias He /* qcow image ?*/ 14817f68274SPekka Enberg disk = qcow_probe(fd, true); 1499f9207c5SSasha Levin if (!IS_ERR_OR_NULL(disk)) { 15017f68274SPekka Enberg pr_warning("Forcing read-only support for QCOW"); 15143835ac9SSasha Levin return disk; 15217f68274SPekka Enberg } 15386835cedSPrasad Joshi 154441767feSAsias He /* raw image ?*/ 15543835ac9SSasha Levin disk = raw_image__probe(fd, &st, readonly); 1569f9207c5SSasha Levin if (!IS_ERR_OR_NULL(disk)) 15743835ac9SSasha Levin return disk; 158499f3bedSPekka Enberg 159d6c58e5bSPrasad Joshi if (close(fd) < 0) 1604542f276SCyrill Gorcunov pr_warning("close() failed"); 161499f3bedSPekka Enberg 1629f9207c5SSasha Levin return ERR_PTR(-ENOSYS); 163499f3bedSPekka Enberg } 164499f3bedSPekka Enberg 165*3b55dcdeSSasha Levin static struct disk_image **disk_image__open_all(struct kvm *kvm) 166c1ed214eSPrasad Joshi { 167c1ed214eSPrasad Joshi struct disk_image **disks; 16897f16d66SAsias He const char *filename; 169a67da3beSAsias He const char *wwpn; 170a67da3beSAsias He const char *tpgt; 17197f16d66SAsias He bool readonly; 1725236b505SAsias He bool direct; 1739f9207c5SSasha Levin void *err; 17497f16d66SAsias He int i; 175*3b55dcdeSSasha Levin struct disk_image_params *params = (struct disk_image_params *)&kvm->cfg.disk_image; 176*3b55dcdeSSasha Levin int count = kvm->cfg.image_count; 177c1ed214eSPrasad Joshi 1789f9207c5SSasha Levin if (!count) 1799f9207c5SSasha Levin return ERR_PTR(-EINVAL); 1809f9207c5SSasha Levin if (count > MAX_DISK_IMAGES) 1819f9207c5SSasha Levin return ERR_PTR(-ENOSPC); 182c1ed214eSPrasad Joshi 183c1ed214eSPrasad Joshi disks = calloc(count, sizeof(*disks)); 184c1ed214eSPrasad Joshi if (!disks) 1859f9207c5SSasha Levin return ERR_PTR(-ENOMEM); 186c1ed214eSPrasad Joshi 187c1ed214eSPrasad Joshi for (i = 0; i < count; i++) { 18897f16d66SAsias He filename = params[i].filename; 18997f16d66SAsias He readonly = params[i].readonly; 1905236b505SAsias He direct = params[i].direct; 191a67da3beSAsias He wwpn = params[i].wwpn; 192a67da3beSAsias He tpgt = params[i].tpgt; 193a67da3beSAsias He 194a67da3beSAsias He if (wwpn) { 195a67da3beSAsias He disks[i] = malloc(sizeof(struct disk_image)); 196a67da3beSAsias He if (!disks[i]) 197a67da3beSAsias He return ERR_PTR(-ENOMEM); 198a67da3beSAsias He disks[i]->wwpn = wwpn; 199a67da3beSAsias He disks[i]->tpgt = tpgt; 200a67da3beSAsias He continue; 201a67da3beSAsias He } 202a67da3beSAsias He 20397f16d66SAsias He if (!filename) 204c1ed214eSPrasad Joshi continue; 205c1ed214eSPrasad Joshi 2065236b505SAsias He disks[i] = disk_image__open(filename, readonly, direct); 2079f9207c5SSasha Levin if (IS_ERR_OR_NULL(disks[i])) { 20897f16d66SAsias He pr_err("Loading disk image '%s' failed", filename); 2099f9207c5SSasha Levin err = disks[i]; 210c1ed214eSPrasad Joshi goto error; 211c1ed214eSPrasad Joshi } 212*3b55dcdeSSasha Levin disks[i]->debug_iodelay = kvm->cfg.debug_iodelay; 213c1ed214eSPrasad Joshi } 214f41a132bSSasha Levin 215c1ed214eSPrasad Joshi return disks; 216c1ed214eSPrasad Joshi error: 217c1ed214eSPrasad Joshi for (i = 0; i < count; i++) 2189f9207c5SSasha Levin if (!IS_ERR_OR_NULL(disks[i])) 219c1ed214eSPrasad Joshi disk_image__close(disks[i]); 220c1ed214eSPrasad Joshi 221c1ed214eSPrasad Joshi free(disks); 2229f9207c5SSasha Levin return err; 223c1ed214eSPrasad Joshi } 224c1ed214eSPrasad Joshi 225fda63751SAsias He int disk_image__flush(struct disk_image *disk) 226fda63751SAsias He { 227fda63751SAsias He if (disk->ops->flush) 228fda63751SAsias He return disk->ops->flush(disk); 229fda63751SAsias He 230fda63751SAsias He return fsync(disk->fd); 231fda63751SAsias He } 232fda63751SAsias He 233*3b55dcdeSSasha Levin static int disk_image__close(struct disk_image *disk) 234499f3bedSPekka Enberg { 23582d94c50SIngo Molnar /* If there was no disk image then there's nothing to do: */ 23643835ac9SSasha Levin if (!disk) 23772133dd2SAsias He return 0; 23882d94c50SIngo Molnar 23943835ac9SSasha Levin if (disk->ops->close) 24072133dd2SAsias He return disk->ops->close(disk); 241499f3bedSPekka Enberg 24243835ac9SSasha Levin if (close(disk->fd) < 0) 2434542f276SCyrill Gorcunov pr_warning("close() failed"); 244499f3bedSPekka Enberg 24543835ac9SSasha Levin free(disk); 24672133dd2SAsias He 24772133dd2SAsias He return 0; 248499f3bedSPekka Enberg } 24970b0d7b0SSasha Levin 250*3b55dcdeSSasha Levin static int disk_image__close_all(struct disk_image **disks, int count) 2519df47d00SPrasad Joshi { 2529df47d00SPrasad Joshi while (count) 2539df47d00SPrasad Joshi disk_image__close(disks[--count]); 2549df47d00SPrasad Joshi 2559df47d00SPrasad Joshi free(disks); 2569f9207c5SSasha Levin 2579f9207c5SSasha Levin return 0; 2589df47d00SPrasad Joshi } 2599df47d00SPrasad Joshi 26097a90170SAsias He /* 26197a90170SAsias He * Fill iov with disk data, starting from sector 'sector'. 26297a90170SAsias He * Return amount of bytes read. 26397a90170SAsias He */ 26454c84566SAsias He ssize_t disk_image__read(struct disk_image *disk, u64 sector, 26554c84566SAsias He const struct iovec *iov, int iovcount, void *param) 26670b0d7b0SSasha Levin { 26797a90170SAsias He ssize_t total = 0; 26870b0d7b0SSasha Levin 269aa400b00SPrasad Joshi if (debug_iodelay) 270aa400b00SPrasad Joshi msleep(debug_iodelay); 271aa400b00SPrasad Joshi 272dcd3cd8eSAsias He if (disk->ops->read) { 273dcd3cd8eSAsias He total = disk->ops->read(disk, sector, iov, iovcount, param); 27497a90170SAsias He if (total < 0) { 2754542f276SCyrill Gorcunov pr_info("disk_image__read error: total=%ld\n", (long)total); 2769f9207c5SSasha Levin return total; 27797a90170SAsias He } 2782534c9b6SSasha Levin } 27997a90170SAsias He 280f41a132bSSasha Levin if (!disk->async && disk->disk_req_cb) 2818b52f877SSasha Levin disk->disk_req_cb(param, total); 2825af21162SSasha Levin 28397a90170SAsias He return total; 28470b0d7b0SSasha Levin } 28570b0d7b0SSasha Levin 28697a90170SAsias He /* 28797a90170SAsias He * Write iov to disk, starting from sector 'sector'. 28897a90170SAsias He * Return amount of bytes written. 28997a90170SAsias He */ 29054c84566SAsias He ssize_t disk_image__write(struct disk_image *disk, u64 sector, 29154c84566SAsias He const struct iovec *iov, int iovcount, void *param) 29270b0d7b0SSasha Levin { 29397a90170SAsias He ssize_t total = 0; 29470b0d7b0SSasha Levin 295aa400b00SPrasad Joshi if (debug_iodelay) 296aa400b00SPrasad Joshi msleep(debug_iodelay); 297aa400b00SPrasad Joshi 298dcd3cd8eSAsias He if (disk->ops->write) { 29997a90170SAsias He /* 30097a90170SAsias He * Try writev based operation first 30197a90170SAsias He */ 3025af21162SSasha Levin 303dcd3cd8eSAsias He total = disk->ops->write(disk, sector, iov, iovcount, param); 30497a90170SAsias He if (total < 0) { 3054542f276SCyrill Gorcunov pr_info("disk_image__write error: total=%ld\n", (long)total); 3069f9207c5SSasha Levin return total; 30797a90170SAsias He } 3082534c9b6SSasha Levin } else { 309b41ca15aSSasha Levin /* Do nothing */ 3102534c9b6SSasha Levin } 31170b0d7b0SSasha Levin 312f41a132bSSasha Levin if (!disk->async && disk->disk_req_cb) 3138b52f877SSasha Levin disk->disk_req_cb(param, total); 3145af21162SSasha Levin 31597a90170SAsias He return total; 31670b0d7b0SSasha Levin } 317ff6462e8SSasha Levin 318ff6462e8SSasha Levin ssize_t disk_image__get_serial(struct disk_image *disk, void *buffer, ssize_t *len) 319ff6462e8SSasha Levin { 320ff6462e8SSasha Levin struct stat st; 3219f9207c5SSasha Levin int r; 322ff6462e8SSasha Levin 3239f9207c5SSasha Levin r = fstat(disk->fd, &st); 3249f9207c5SSasha Levin if (r) 3259f9207c5SSasha Levin return r; 326ff6462e8SSasha Levin 32754c84566SAsias He *len = snprintf(buffer, *len, "%llu%llu%llu", 32854c84566SAsias He (u64)st.st_dev, (u64)st.st_rdev, (u64)st.st_ino); 329ff6462e8SSasha Levin return *len; 330ff6462e8SSasha Levin } 3315af21162SSasha Levin 33254c84566SAsias He void disk_image__set_callback(struct disk_image *disk, 33354c84566SAsias He void (*disk_req_cb)(void *param, long len)) 3345af21162SSasha Levin { 3355af21162SSasha Levin disk->disk_req_cb = disk_req_cb; 3365af21162SSasha Levin } 337*3b55dcdeSSasha Levin 338*3b55dcdeSSasha Levin int disk_image__init(struct kvm *kvm) 339*3b55dcdeSSasha Levin { 340*3b55dcdeSSasha Levin if (kvm->cfg.image_count) { 341*3b55dcdeSSasha Levin kvm->disks = disk_image__open_all(kvm); 342*3b55dcdeSSasha Levin if (IS_ERR(kvm->disks)) 343*3b55dcdeSSasha Levin return PTR_ERR(kvm->disks); 344*3b55dcdeSSasha Levin } 345*3b55dcdeSSasha Levin 346*3b55dcdeSSasha Levin return 0; 347*3b55dcdeSSasha Levin } 348*3b55dcdeSSasha Levin 349*3b55dcdeSSasha Levin int disk_image__exit(struct kvm *kvm) 350*3b55dcdeSSasha Levin { 351*3b55dcdeSSasha Levin return disk_image__close_all(kvm->disks, kvm->nr_disks); 352*3b55dcdeSSasha Levin } 353