19f532d00SPekka Enberg #include "kvm/disk-image.h" 286835cedSPrasad Joshi #include "kvm/qcow.h" 39f532d00SPekka Enberg 4aa400b00SPrasad Joshi int debug_iodelay; 5aa400b00SPrasad Joshi 67d22135fSAsias He struct disk_image *disk_image__new(int fd, u64 size, struct disk_image_operations *ops, int use_mmap) 79f532d00SPekka Enberg { 843835ac9SSasha Levin struct disk_image *disk; 99f532d00SPekka Enberg 1043835ac9SSasha Levin disk = malloc(sizeof *disk); 1143835ac9SSasha Levin if (!disk) 12fffb37a9SPekka Enberg return NULL; 139f532d00SPekka Enberg 1443835ac9SSasha Levin disk->fd = fd; 1543835ac9SSasha Levin disk->size = size; 1643835ac9SSasha Levin disk->ops = ops; 17f4ff38dfSPrasad Joshi 187d22135fSAsias He if (use_mmap == DISK_IMAGE_MMAP) { 197d22135fSAsias He /* 207d22135fSAsias He * The write to disk image will be discarded 217d22135fSAsias He */ 2237c34ca8SSasha Levin disk->priv = mmap(NULL, size, PROT_RW, MAP_PRIVATE | MAP_NORESERVE, fd, 0); 239d15c39aSSasha Levin if (disk->priv == MAP_FAILED) { 249d15c39aSSasha Levin free(disk); 259d15c39aSSasha Levin disk = NULL; 269d15c39aSSasha Levin } 277d22135fSAsias He } 287d22135fSAsias He 2943835ac9SSasha Levin return disk; 309f532d00SPekka Enberg } 319f532d00SPekka Enberg 329ac38fe1SSasha Levin struct disk_image *disk_image__open(const char *filename, bool readonly) 33499f3bedSPekka Enberg { 3443835ac9SSasha Levin struct disk_image *disk; 356ec60cfdSPekka Enberg struct stat st; 36499f3bedSPekka Enberg int fd; 37499f3bedSPekka Enberg 386ec60cfdSPekka Enberg if (stat(filename, &st) < 0) 396ec60cfdSPekka Enberg return NULL; 406ec60cfdSPekka Enberg 41441767feSAsias He /* blk device ?*/ 42441767feSAsias He disk = blkdev__probe(filename, &st); 43441767feSAsias He if (disk) 44441767feSAsias He return disk; 456ec60cfdSPekka Enberg 469ac38fe1SSasha Levin fd = open(filename, readonly ? O_RDONLY : O_RDWR); 47499f3bedSPekka Enberg if (fd < 0) 48499f3bedSPekka Enberg return NULL; 49499f3bedSPekka Enberg 50441767feSAsias He /* qcow image ?*/ 5117f68274SPekka Enberg disk = qcow_probe(fd, true); 5217f68274SPekka Enberg if (disk) { 5317f68274SPekka Enberg pr_warning("Forcing read-only support for QCOW"); 5443835ac9SSasha Levin return disk; 5517f68274SPekka Enberg } 5686835cedSPrasad Joshi 57441767feSAsias He /* raw image ?*/ 5843835ac9SSasha Levin disk = raw_image__probe(fd, &st, readonly); 5943835ac9SSasha Levin if (disk) 6043835ac9SSasha Levin return disk; 61499f3bedSPekka Enberg 62d6c58e5bSPrasad Joshi if (close(fd) < 0) 634542f276SCyrill Gorcunov pr_warning("close() failed"); 64499f3bedSPekka Enberg 65499f3bedSPekka Enberg return NULL; 66499f3bedSPekka Enberg } 67499f3bedSPekka Enberg 68c1ed214eSPrasad Joshi struct disk_image **disk_image__open_all(const char **filenames, bool *readonly, int count) 69c1ed214eSPrasad Joshi { 70c1ed214eSPrasad Joshi struct disk_image **disks; 71c1ed214eSPrasad Joshi int i; 72c1ed214eSPrasad Joshi 73c1ed214eSPrasad Joshi if (!count || count > MAX_DISK_IMAGES) 74c1ed214eSPrasad Joshi return NULL; 75c1ed214eSPrasad Joshi 76c1ed214eSPrasad Joshi disks = calloc(count, sizeof(*disks)); 77c1ed214eSPrasad Joshi if (!disks) 78c1ed214eSPrasad Joshi return NULL; 79c1ed214eSPrasad Joshi 80c1ed214eSPrasad Joshi for (i = 0; i < count; i++) { 81c1ed214eSPrasad Joshi if (!filenames[i]) 82c1ed214eSPrasad Joshi continue; 83c1ed214eSPrasad Joshi 84c1ed214eSPrasad Joshi disks[i] = disk_image__open(filenames[i], readonly[i]); 85c1ed214eSPrasad Joshi if (!disks[i]) { 86c1ed214eSPrasad Joshi pr_error("Loading disk image '%s' failed", filenames[i]); 87c1ed214eSPrasad Joshi goto error; 88c1ed214eSPrasad Joshi } 89c1ed214eSPrasad Joshi } 90c1ed214eSPrasad Joshi return disks; 91c1ed214eSPrasad Joshi error: 92c1ed214eSPrasad Joshi for (i = 0; i < count; i++) 93c1ed214eSPrasad Joshi disk_image__close(disks[i]); 94c1ed214eSPrasad Joshi 95c1ed214eSPrasad Joshi free(disks); 96c1ed214eSPrasad Joshi return NULL; 97c1ed214eSPrasad Joshi } 98c1ed214eSPrasad Joshi 99fda63751SAsias He int disk_image__flush(struct disk_image *disk) 100fda63751SAsias He { 101fda63751SAsias He if (disk->ops->flush) 102fda63751SAsias He return disk->ops->flush(disk); 103fda63751SAsias He 104fda63751SAsias He return fsync(disk->fd); 105fda63751SAsias He } 106fda63751SAsias He 10772133dd2SAsias He int disk_image__close(struct disk_image *disk) 108499f3bedSPekka Enberg { 10982d94c50SIngo Molnar /* If there was no disk image then there's nothing to do: */ 11043835ac9SSasha Levin if (!disk) 11172133dd2SAsias He return 0; 11282d94c50SIngo Molnar 11343835ac9SSasha Levin if (disk->ops->close) 11472133dd2SAsias He return disk->ops->close(disk); 115499f3bedSPekka Enberg 11643835ac9SSasha Levin if (close(disk->fd) < 0) 1174542f276SCyrill Gorcunov pr_warning("close() failed"); 118499f3bedSPekka Enberg 11943835ac9SSasha Levin free(disk); 12072133dd2SAsias He 12172133dd2SAsias He return 0; 122499f3bedSPekka Enberg } 12370b0d7b0SSasha Levin 1249df47d00SPrasad Joshi void disk_image__close_all(struct disk_image **disks, int count) 1259df47d00SPrasad Joshi { 1269df47d00SPrasad Joshi while (count) 1279df47d00SPrasad Joshi disk_image__close(disks[--count]); 1289df47d00SPrasad Joshi 1299df47d00SPrasad Joshi free(disks); 1309df47d00SPrasad Joshi } 1319df47d00SPrasad Joshi 13297a90170SAsias He /* 13397a90170SAsias He * Fill iov with disk data, starting from sector 'sector'. 13497a90170SAsias He * Return amount of bytes read. 13597a90170SAsias He */ 136b8861977SAsias He ssize_t disk_image__read(struct disk_image *disk, u64 sector, const struct iovec *iov, int iovcount) 13770b0d7b0SSasha Levin { 13897a90170SAsias He ssize_t total = 0; 13970b0d7b0SSasha Levin 140aa400b00SPrasad Joshi if (debug_iodelay) 141aa400b00SPrasad Joshi msleep(debug_iodelay); 142aa400b00SPrasad Joshi 1432534c9b6SSasha Levin if (disk->ops->read_sector) { 1442534c9b6SSasha Levin total = disk->ops->read_sector(disk, sector, iov, iovcount); 14597a90170SAsias He if (total < 0) { 1464542f276SCyrill Gorcunov pr_info("disk_image__read error: total=%ld\n", (long)total); 14770b0d7b0SSasha Levin return -1; 14897a90170SAsias He } 1492534c9b6SSasha Levin } else { 150*b41ca15aSSasha Levin /* Do nothing */ 1512534c9b6SSasha Levin } 15297a90170SAsias He 15397a90170SAsias He return total; 15470b0d7b0SSasha Levin } 15570b0d7b0SSasha Levin 15697a90170SAsias He /* 15797a90170SAsias He * Write iov to disk, starting from sector 'sector'. 15897a90170SAsias He * Return amount of bytes written. 15997a90170SAsias He */ 160b8861977SAsias He ssize_t disk_image__write(struct disk_image *disk, u64 sector, const struct iovec *iov, int iovcount) 16170b0d7b0SSasha Levin { 16297a90170SAsias He ssize_t total = 0; 16370b0d7b0SSasha Levin 164aa400b00SPrasad Joshi if (debug_iodelay) 165aa400b00SPrasad Joshi msleep(debug_iodelay); 166aa400b00SPrasad Joshi 1672534c9b6SSasha Levin if (disk->ops->write_sector) { 16897a90170SAsias He /* 16997a90170SAsias He * Try writev based operation first 17097a90170SAsias He */ 1712534c9b6SSasha Levin total = disk->ops->write_sector(disk, sector, iov, iovcount); 17297a90170SAsias He if (total < 0) { 1734542f276SCyrill Gorcunov pr_info("disk_image__write error: total=%ld\n", (long)total); 17470b0d7b0SSasha Levin return -1; 17597a90170SAsias He } 1762534c9b6SSasha Levin } else { 177*b41ca15aSSasha Levin /* Do nothing */ 1782534c9b6SSasha Levin } 17970b0d7b0SSasha Levin 18097a90170SAsias He return total; 18170b0d7b0SSasha Levin } 182ff6462e8SSasha Levin 183ff6462e8SSasha Levin ssize_t disk_image__get_serial(struct disk_image *disk, void *buffer, ssize_t *len) 184ff6462e8SSasha Levin { 185ff6462e8SSasha Levin struct stat st; 186ff6462e8SSasha Levin 187ff6462e8SSasha Levin if (fstat(disk->fd, &st) != 0) 188ff6462e8SSasha Levin return 0; 189ff6462e8SSasha Levin 190eab301d0SSasha Levin *len = snprintf(buffer, *len, "%llu%llu%llu", (u64)st.st_dev, (u64)st.st_rdev, (u64)st.st_ino); 191ff6462e8SSasha Levin return *len; 192ff6462e8SSasha Levin } 193