19f532d00SPekka Enberg #include "kvm/disk-image.h" 286835cedSPrasad Joshi #include "kvm/qcow.h" 39f532d00SPekka Enberg 47d22135fSAsias He struct disk_image *disk_image__new(int fd, u64 size, struct disk_image_operations *ops, int use_mmap) 59f532d00SPekka Enberg { 643835ac9SSasha Levin struct disk_image *disk; 79f532d00SPekka Enberg 843835ac9SSasha Levin disk = malloc(sizeof *disk); 943835ac9SSasha Levin if (!disk) 10fffb37a9SPekka Enberg return NULL; 119f532d00SPekka Enberg 1243835ac9SSasha Levin disk->fd = fd; 1343835ac9SSasha Levin disk->size = size; 1443835ac9SSasha Levin disk->ops = ops; 15f4ff38dfSPrasad Joshi 167d22135fSAsias He if (use_mmap == DISK_IMAGE_MMAP) { 177d22135fSAsias He /* 187d22135fSAsias He * The write to disk image will be discarded 197d22135fSAsias He */ 2037c34ca8SSasha Levin disk->priv = mmap(NULL, size, PROT_RW, MAP_PRIVATE | MAP_NORESERVE, fd, 0); 2143835ac9SSasha Levin if (disk->priv == MAP_FAILED) 229ac38fe1SSasha Levin die("mmap() failed"); 237d22135fSAsias He } 247d22135fSAsias He 2543835ac9SSasha Levin return disk; 269f532d00SPekka Enberg } 279f532d00SPekka Enberg 289ac38fe1SSasha Levin struct disk_image *disk_image__open(const char *filename, bool readonly) 29499f3bedSPekka Enberg { 3043835ac9SSasha Levin struct disk_image *disk; 316ec60cfdSPekka Enberg struct stat st; 32499f3bedSPekka Enberg int fd; 33499f3bedSPekka Enberg 346ec60cfdSPekka Enberg if (stat(filename, &st) < 0) 356ec60cfdSPekka Enberg return NULL; 366ec60cfdSPekka Enberg 37441767feSAsias He /* blk device ?*/ 38441767feSAsias He disk = blkdev__probe(filename, &st); 39441767feSAsias He if (disk) 40441767feSAsias He return disk; 416ec60cfdSPekka Enberg 429ac38fe1SSasha Levin fd = open(filename, readonly ? O_RDONLY : O_RDWR); 43499f3bedSPekka Enberg if (fd < 0) 44499f3bedSPekka Enberg return NULL; 45499f3bedSPekka Enberg 46441767feSAsias He /* qcow image ?*/ 47f10860caSPekka Enberg disk = qcow_probe(fd, readonly); 4843835ac9SSasha Levin if (disk) 4943835ac9SSasha Levin return disk; 5086835cedSPrasad Joshi 51441767feSAsias He /* raw image ?*/ 5243835ac9SSasha Levin disk = raw_image__probe(fd, &st, readonly); 5343835ac9SSasha Levin if (disk) 5443835ac9SSasha Levin return disk; 55499f3bedSPekka Enberg 56d6c58e5bSPrasad Joshi if (close(fd) < 0) 574542f276SCyrill Gorcunov pr_warning("close() failed"); 58499f3bedSPekka Enberg 59499f3bedSPekka Enberg return NULL; 60499f3bedSPekka Enberg } 61499f3bedSPekka Enberg 62c1ed214eSPrasad Joshi struct disk_image **disk_image__open_all(const char **filenames, bool *readonly, int count) 63c1ed214eSPrasad Joshi { 64c1ed214eSPrasad Joshi struct disk_image **disks; 65c1ed214eSPrasad Joshi int i; 66c1ed214eSPrasad Joshi 67c1ed214eSPrasad Joshi if (!count || count > MAX_DISK_IMAGES) 68c1ed214eSPrasad Joshi return NULL; 69c1ed214eSPrasad Joshi 70c1ed214eSPrasad Joshi disks = calloc(count, sizeof(*disks)); 71c1ed214eSPrasad Joshi if (!disks) 72c1ed214eSPrasad Joshi return NULL; 73c1ed214eSPrasad Joshi 74c1ed214eSPrasad Joshi for (i = 0; i < count; i++) { 75c1ed214eSPrasad Joshi if (!filenames[i]) 76c1ed214eSPrasad Joshi continue; 77c1ed214eSPrasad Joshi 78c1ed214eSPrasad Joshi disks[i] = disk_image__open(filenames[i], readonly[i]); 79c1ed214eSPrasad Joshi if (!disks[i]) { 80c1ed214eSPrasad Joshi pr_error("Loading disk image '%s' failed", filenames[i]); 81c1ed214eSPrasad Joshi goto error; 82c1ed214eSPrasad Joshi } 83c1ed214eSPrasad Joshi } 84c1ed214eSPrasad Joshi return disks; 85c1ed214eSPrasad Joshi error: 86c1ed214eSPrasad Joshi for (i = 0; i < count; i++) 87c1ed214eSPrasad Joshi disk_image__close(disks[i]); 88c1ed214eSPrasad Joshi 89c1ed214eSPrasad Joshi free(disks); 90c1ed214eSPrasad Joshi return NULL; 91c1ed214eSPrasad Joshi } 92c1ed214eSPrasad Joshi 93fda63751SAsias He int disk_image__flush(struct disk_image *disk) 94fda63751SAsias He { 95fda63751SAsias He if (disk->ops->flush) 96fda63751SAsias He return disk->ops->flush(disk); 97fda63751SAsias He 98fda63751SAsias He return fsync(disk->fd); 99fda63751SAsias He } 100fda63751SAsias He 10172133dd2SAsias He int disk_image__close(struct disk_image *disk) 102499f3bedSPekka Enberg { 10382d94c50SIngo Molnar /* If there was no disk image then there's nothing to do: */ 10443835ac9SSasha Levin if (!disk) 10572133dd2SAsias He return 0; 10682d94c50SIngo Molnar 10743835ac9SSasha Levin if (disk->ops->close) 10872133dd2SAsias He return disk->ops->close(disk); 109499f3bedSPekka Enberg 11043835ac9SSasha Levin if (close(disk->fd) < 0) 1114542f276SCyrill Gorcunov pr_warning("close() failed"); 112499f3bedSPekka Enberg 11343835ac9SSasha Levin free(disk); 11472133dd2SAsias He 11572133dd2SAsias He return 0; 116499f3bedSPekka Enberg } 11770b0d7b0SSasha Levin 118*9df47d00SPrasad Joshi void disk_image__close_all(struct disk_image **disks, int count) 119*9df47d00SPrasad Joshi { 120*9df47d00SPrasad Joshi while (count) 121*9df47d00SPrasad Joshi disk_image__close(disks[--count]); 122*9df47d00SPrasad Joshi 123*9df47d00SPrasad Joshi free(disks); 124*9df47d00SPrasad Joshi } 125*9df47d00SPrasad Joshi 12697a90170SAsias He /* 12797a90170SAsias He * Fill iov with disk data, starting from sector 'sector'. 12897a90170SAsias He * Return amount of bytes read. 12997a90170SAsias He */ 130b8861977SAsias He ssize_t disk_image__read(struct disk_image *disk, u64 sector, const struct iovec *iov, int iovcount) 13170b0d7b0SSasha Levin { 13297a90170SAsias He ssize_t total = 0; 13397a90170SAsias He ssize_t nr; 13470b0d7b0SSasha Levin 13597a90170SAsias He if (disk->ops->read_sector_iov) { 13697a90170SAsias He /* 13797a90170SAsias He * Try mulitple buffer based operation first 13897a90170SAsias He */ 13997a90170SAsias He total = disk->ops->read_sector_iov(disk, sector, iov, iovcount); 14097a90170SAsias He if (total < 0) { 1414542f276SCyrill Gorcunov pr_info("disk_image__read error: total=%ld\n", (long)total); 14270b0d7b0SSasha Levin return -1; 14397a90170SAsias He } 14497a90170SAsias He } else if (disk->ops->read_sector) { 14597a90170SAsias He /* 14697a90170SAsias He * Fallback to single buffer based operation 14797a90170SAsias He */ 14897a90170SAsias He while (iovcount--) { 14997a90170SAsias He nr = disk->ops->read_sector(disk, sector, iov->iov_base, iov->iov_len); 15097a90170SAsias He if (nr != (ssize_t)iov->iov_len) { 1514542f276SCyrill Gorcunov pr_info("disk_image__read error: nr = %ld iov_len=%ld\n", (long)nr, (long)iov->iov_len); 15297a90170SAsias He return -1; 15397a90170SAsias He } 15470b0d7b0SSasha Levin sector += iov->iov_len >> SECTOR_SHIFT; 15570b0d7b0SSasha Levin iov++; 15697a90170SAsias He total += nr; 15797a90170SAsias He } 15897a90170SAsias He } else 15997a90170SAsias He die("No disk image operation for read\n"); 16097a90170SAsias He 16197a90170SAsias He return total; 16270b0d7b0SSasha Levin } 16370b0d7b0SSasha Levin 16497a90170SAsias He /* 16597a90170SAsias He * Write iov to disk, starting from sector 'sector'. 16697a90170SAsias He * Return amount of bytes written. 16797a90170SAsias He */ 168b8861977SAsias He ssize_t disk_image__write(struct disk_image *disk, u64 sector, const struct iovec *iov, int iovcount) 16970b0d7b0SSasha Levin { 17097a90170SAsias He ssize_t total = 0; 17197a90170SAsias He ssize_t nr; 17270b0d7b0SSasha Levin 17397a90170SAsias He if (disk->ops->write_sector_iov) { 17497a90170SAsias He /* 17597a90170SAsias He * Try writev based operation first 17697a90170SAsias He */ 17797a90170SAsias He total = disk->ops->write_sector_iov(disk, sector, iov, iovcount); 17897a90170SAsias He if (total < 0) { 1794542f276SCyrill Gorcunov pr_info("disk_image__write error: total=%ld\n", (long)total); 18070b0d7b0SSasha Levin return -1; 18197a90170SAsias He } 18297a90170SAsias He } else if (disk->ops->write_sector) { 18397a90170SAsias He /* 18497a90170SAsias He * Fallback to single buffer based operation 18597a90170SAsias He */ 18697a90170SAsias He while (iovcount--) { 18797a90170SAsias He nr = disk->ops->write_sector(disk, sector, iov->iov_base, iov->iov_len); 18897a90170SAsias He if (nr != (ssize_t)iov->iov_len) { 1894542f276SCyrill Gorcunov pr_info("disk_image__write error: nr=%ld iov_len=%ld\n", (long)nr, (long)iov->iov_len); 19097a90170SAsias He return -1; 19197a90170SAsias He } 19270b0d7b0SSasha Levin 19370b0d7b0SSasha Levin sector += iov->iov_len >> SECTOR_SHIFT; 19470b0d7b0SSasha Levin iov++; 19597a90170SAsias He total += nr; 19670b0d7b0SSasha Levin } 19797a90170SAsias He } else 19897a90170SAsias He die("No disk image operation for read\n"); 19970b0d7b0SSasha Levin 20097a90170SAsias He return total; 20170b0d7b0SSasha Levin } 202