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); 2343835ac9SSasha Levin if (disk->priv == MAP_FAILED) 249ac38fe1SSasha Levin die("mmap() failed"); 257d22135fSAsias He } 267d22135fSAsias He 2743835ac9SSasha Levin return disk; 289f532d00SPekka Enberg } 299f532d00SPekka Enberg 309ac38fe1SSasha Levin struct disk_image *disk_image__open(const char *filename, bool readonly) 31499f3bedSPekka Enberg { 3243835ac9SSasha Levin struct disk_image *disk; 336ec60cfdSPekka Enberg struct stat st; 34499f3bedSPekka Enberg int fd; 35499f3bedSPekka Enberg 366ec60cfdSPekka Enberg if (stat(filename, &st) < 0) 376ec60cfdSPekka Enberg return NULL; 386ec60cfdSPekka Enberg 39441767feSAsias He /* blk device ?*/ 40441767feSAsias He disk = blkdev__probe(filename, &st); 41441767feSAsias He if (disk) 42441767feSAsias He return disk; 436ec60cfdSPekka Enberg 449ac38fe1SSasha Levin fd = open(filename, readonly ? O_RDONLY : O_RDWR); 45499f3bedSPekka Enberg if (fd < 0) 46499f3bedSPekka Enberg return NULL; 47499f3bedSPekka Enberg 48441767feSAsias He /* qcow image ?*/ 49f10860caSPekka Enberg disk = qcow_probe(fd, readonly); 5043835ac9SSasha Levin if (disk) 5143835ac9SSasha Levin return disk; 5286835cedSPrasad Joshi 53441767feSAsias He /* raw image ?*/ 5443835ac9SSasha Levin disk = raw_image__probe(fd, &st, readonly); 5543835ac9SSasha Levin if (disk) 5643835ac9SSasha Levin return disk; 57499f3bedSPekka Enberg 58d6c58e5bSPrasad Joshi if (close(fd) < 0) 594542f276SCyrill Gorcunov pr_warning("close() failed"); 60499f3bedSPekka Enberg 61499f3bedSPekka Enberg return NULL; 62499f3bedSPekka Enberg } 63499f3bedSPekka Enberg 64c1ed214eSPrasad Joshi struct disk_image **disk_image__open_all(const char **filenames, bool *readonly, int count) 65c1ed214eSPrasad Joshi { 66c1ed214eSPrasad Joshi struct disk_image **disks; 67c1ed214eSPrasad Joshi int i; 68c1ed214eSPrasad Joshi 69c1ed214eSPrasad Joshi if (!count || count > MAX_DISK_IMAGES) 70c1ed214eSPrasad Joshi return NULL; 71c1ed214eSPrasad Joshi 72c1ed214eSPrasad Joshi disks = calloc(count, sizeof(*disks)); 73c1ed214eSPrasad Joshi if (!disks) 74c1ed214eSPrasad Joshi return NULL; 75c1ed214eSPrasad Joshi 76c1ed214eSPrasad Joshi for (i = 0; i < count; i++) { 77c1ed214eSPrasad Joshi if (!filenames[i]) 78c1ed214eSPrasad Joshi continue; 79c1ed214eSPrasad Joshi 80c1ed214eSPrasad Joshi disks[i] = disk_image__open(filenames[i], readonly[i]); 81c1ed214eSPrasad Joshi if (!disks[i]) { 82c1ed214eSPrasad Joshi pr_error("Loading disk image '%s' failed", filenames[i]); 83c1ed214eSPrasad Joshi goto error; 84c1ed214eSPrasad Joshi } 85c1ed214eSPrasad Joshi } 86c1ed214eSPrasad Joshi return disks; 87c1ed214eSPrasad Joshi error: 88c1ed214eSPrasad Joshi for (i = 0; i < count; i++) 89c1ed214eSPrasad Joshi disk_image__close(disks[i]); 90c1ed214eSPrasad Joshi 91c1ed214eSPrasad Joshi free(disks); 92c1ed214eSPrasad Joshi return NULL; 93c1ed214eSPrasad Joshi } 94c1ed214eSPrasad Joshi 95fda63751SAsias He int disk_image__flush(struct disk_image *disk) 96fda63751SAsias He { 97fda63751SAsias He if (disk->ops->flush) 98fda63751SAsias He return disk->ops->flush(disk); 99fda63751SAsias He 100fda63751SAsias He return fsync(disk->fd); 101fda63751SAsias He } 102fda63751SAsias He 10372133dd2SAsias He int disk_image__close(struct disk_image *disk) 104499f3bedSPekka Enberg { 10582d94c50SIngo Molnar /* If there was no disk image then there's nothing to do: */ 10643835ac9SSasha Levin if (!disk) 10772133dd2SAsias He return 0; 10882d94c50SIngo Molnar 10943835ac9SSasha Levin if (disk->ops->close) 11072133dd2SAsias He return disk->ops->close(disk); 111499f3bedSPekka Enberg 11243835ac9SSasha Levin if (close(disk->fd) < 0) 1134542f276SCyrill Gorcunov pr_warning("close() failed"); 114499f3bedSPekka Enberg 11543835ac9SSasha Levin free(disk); 11672133dd2SAsias He 11772133dd2SAsias He return 0; 118499f3bedSPekka Enberg } 11970b0d7b0SSasha Levin 1209df47d00SPrasad Joshi void disk_image__close_all(struct disk_image **disks, int count) 1219df47d00SPrasad Joshi { 1229df47d00SPrasad Joshi while (count) 1239df47d00SPrasad Joshi disk_image__close(disks[--count]); 1249df47d00SPrasad Joshi 1259df47d00SPrasad Joshi free(disks); 1269df47d00SPrasad Joshi } 1279df47d00SPrasad Joshi 12897a90170SAsias He /* 12997a90170SAsias He * Fill iov with disk data, starting from sector 'sector'. 13097a90170SAsias He * Return amount of bytes read. 13197a90170SAsias He */ 132b8861977SAsias He ssize_t disk_image__read(struct disk_image *disk, u64 sector, const struct iovec *iov, int iovcount) 13370b0d7b0SSasha Levin { 13497a90170SAsias He ssize_t total = 0; 13597a90170SAsias He ssize_t nr; 13670b0d7b0SSasha Levin 137aa400b00SPrasad Joshi if (debug_iodelay) 138aa400b00SPrasad Joshi msleep(debug_iodelay); 139aa400b00SPrasad Joshi 14097a90170SAsias He if (disk->ops->read_sector_iov) { 14197a90170SAsias He /* 14297a90170SAsias He * Try mulitple buffer based operation first 14397a90170SAsias He */ 14497a90170SAsias He total = disk->ops->read_sector_iov(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 } 14997a90170SAsias He } else if (disk->ops->read_sector) { 15097a90170SAsias He /* 15197a90170SAsias He * Fallback to single buffer based operation 15297a90170SAsias He */ 15397a90170SAsias He while (iovcount--) { 15497a90170SAsias He nr = disk->ops->read_sector(disk, sector, iov->iov_base, iov->iov_len); 15597a90170SAsias He if (nr != (ssize_t)iov->iov_len) { 1564542f276SCyrill Gorcunov pr_info("disk_image__read error: nr = %ld iov_len=%ld\n", (long)nr, (long)iov->iov_len); 15797a90170SAsias He return -1; 15897a90170SAsias He } 15970b0d7b0SSasha Levin sector += iov->iov_len >> SECTOR_SHIFT; 16070b0d7b0SSasha Levin iov++; 16197a90170SAsias He total += nr; 16297a90170SAsias He } 16397a90170SAsias He } else 16497a90170SAsias He die("No disk image operation for read\n"); 16597a90170SAsias He 16697a90170SAsias He return total; 16770b0d7b0SSasha Levin } 16870b0d7b0SSasha Levin 16997a90170SAsias He /* 17097a90170SAsias He * Write iov to disk, starting from sector 'sector'. 17197a90170SAsias He * Return amount of bytes written. 17297a90170SAsias He */ 173b8861977SAsias He ssize_t disk_image__write(struct disk_image *disk, u64 sector, const struct iovec *iov, int iovcount) 17470b0d7b0SSasha Levin { 17597a90170SAsias He ssize_t total = 0; 17697a90170SAsias He ssize_t nr; 17770b0d7b0SSasha Levin 178aa400b00SPrasad Joshi if (debug_iodelay) 179aa400b00SPrasad Joshi msleep(debug_iodelay); 180aa400b00SPrasad Joshi 18197a90170SAsias He if (disk->ops->write_sector_iov) { 18297a90170SAsias He /* 18397a90170SAsias He * Try writev based operation first 18497a90170SAsias He */ 18597a90170SAsias He total = disk->ops->write_sector_iov(disk, sector, iov, iovcount); 18697a90170SAsias He if (total < 0) { 1874542f276SCyrill Gorcunov pr_info("disk_image__write error: total=%ld\n", (long)total); 18870b0d7b0SSasha Levin return -1; 18997a90170SAsias He } 19097a90170SAsias He } else if (disk->ops->write_sector) { 19197a90170SAsias He /* 19297a90170SAsias He * Fallback to single buffer based operation 19397a90170SAsias He */ 19497a90170SAsias He while (iovcount--) { 19597a90170SAsias He nr = disk->ops->write_sector(disk, sector, iov->iov_base, iov->iov_len); 19697a90170SAsias He if (nr != (ssize_t)iov->iov_len) { 1974542f276SCyrill Gorcunov pr_info("disk_image__write error: nr=%ld iov_len=%ld\n", (long)nr, (long)iov->iov_len); 19897a90170SAsias He return -1; 19997a90170SAsias He } 20070b0d7b0SSasha Levin 20170b0d7b0SSasha Levin sector += iov->iov_len >> SECTOR_SHIFT; 20270b0d7b0SSasha Levin iov++; 20397a90170SAsias He total += nr; 20470b0d7b0SSasha Levin } 20597a90170SAsias He } else 20697a90170SAsias He die("No disk image operation for read\n"); 20770b0d7b0SSasha Levin 20897a90170SAsias He return total; 20970b0d7b0SSasha Levin } 210*ff6462e8SSasha Levin 211*ff6462e8SSasha Levin ssize_t disk_image__get_serial(struct disk_image *disk, void *buffer, ssize_t *len) 212*ff6462e8SSasha Levin { 213*ff6462e8SSasha Levin struct stat st; 214*ff6462e8SSasha Levin 215*ff6462e8SSasha Levin if (fstat(disk->fd, &st) != 0) 216*ff6462e8SSasha Levin return 0; 217*ff6462e8SSasha Levin 218*ff6462e8SSasha Levin *len = snprintf(buffer, *len, "%lu%lu%lu", st.st_dev, st.st_rdev, st.st_ino); 219*ff6462e8SSasha Levin return *len; 220*ff6462e8SSasha Levin }