19f532d00SPekka Enberg #include "kvm/disk-image.h" 286835cedSPrasad Joshi #include "kvm/qcow.h" 39f532d00SPekka Enberg 43fdf659dSSasha Levin struct disk_image *disk_image__new(int fd, u64 size, struct disk_image_operations *ops) 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; 1543835ac9SSasha Levin return disk; 16f4ff38dfSPrasad Joshi } 17f4ff38dfSPrasad Joshi 183fdf659dSSasha Levin struct disk_image *disk_image__new_readonly(int fd, u64 size, struct disk_image_operations *ops) 19f4ff38dfSPrasad Joshi { 2043835ac9SSasha Levin struct disk_image *disk; 21f4ff38dfSPrasad Joshi 2243835ac9SSasha Levin disk = disk_image__new(fd, size, ops); 2343835ac9SSasha Levin if (!disk) 24f4ff38dfSPrasad Joshi return NULL; 25f4ff38dfSPrasad Joshi 2637c34ca8SSasha Levin disk->priv = mmap(NULL, size, PROT_RW, MAP_PRIVATE | MAP_NORESERVE, fd, 0); 2743835ac9SSasha Levin if (disk->priv == MAP_FAILED) 289ac38fe1SSasha Levin die("mmap() failed"); 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 416ec60cfdSPekka Enberg if (S_ISBLK(st.st_mode)) 426ec60cfdSPekka Enberg return blkdev__probe(filename, &st); 436ec60cfdSPekka Enberg 449ac38fe1SSasha Levin fd = open(filename, readonly ? O_RDONLY : O_RDWR); 45499f3bedSPekka Enberg if (fd < 0) 46499f3bedSPekka Enberg return NULL; 47499f3bedSPekka Enberg 48f10860caSPekka Enberg disk = qcow_probe(fd, readonly); 4943835ac9SSasha Levin if (disk) 5043835ac9SSasha Levin return disk; 5186835cedSPrasad Joshi 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) 57499f3bedSPekka Enberg warning("close() failed"); 58499f3bedSPekka Enberg 59499f3bedSPekka Enberg return NULL; 60499f3bedSPekka Enberg } 61499f3bedSPekka Enberg 6243835ac9SSasha Levin void disk_image__close(struct disk_image *disk) 63499f3bedSPekka Enberg { 6482d94c50SIngo Molnar /* If there was no disk image then there's nothing to do: */ 6543835ac9SSasha Levin if (!disk) 6682d94c50SIngo Molnar return; 6782d94c50SIngo Molnar 6843835ac9SSasha Levin if (disk->ops->close) 6943835ac9SSasha Levin disk->ops->close(disk); 70499f3bedSPekka Enberg 7143835ac9SSasha Levin if (close(disk->fd) < 0) 72499f3bedSPekka Enberg warning("close() failed"); 73499f3bedSPekka Enberg 7443835ac9SSasha Levin free(disk); 75499f3bedSPekka Enberg } 7670b0d7b0SSasha Levin 7770b0d7b0SSasha Levin /* Fill iov with disk data, starting from sector 'sector'. Return amount of bytes read. */ 78*b8861977SAsias He ssize_t disk_image__read(struct disk_image *disk, u64 sector, const struct iovec *iov, int iovcount) 7970b0d7b0SSasha Levin { 8070b0d7b0SSasha Levin u64 first_sector = sector; 8170b0d7b0SSasha Levin 8270b0d7b0SSasha Levin if (disk->ops->read_sector_iov) 8370b0d7b0SSasha Levin return disk->ops->read_sector_iov(disk, sector, iov, iovcount); 8470b0d7b0SSasha Levin 8570b0d7b0SSasha Levin while (iovcount--) { 8670b0d7b0SSasha Levin if (disk->ops->read_sector(disk, sector, iov->iov_base, iov->iov_len) < 0) 8770b0d7b0SSasha Levin return -1; 8870b0d7b0SSasha Levin 8970b0d7b0SSasha Levin sector += iov->iov_len >> SECTOR_SHIFT; 9070b0d7b0SSasha Levin iov++; 9170b0d7b0SSasha Levin } 9270b0d7b0SSasha Levin 9370b0d7b0SSasha Levin return (sector - first_sector) << SECTOR_SHIFT; 9470b0d7b0SSasha Levin } 9570b0d7b0SSasha Levin 9670b0d7b0SSasha Levin /* Write iov to disk, starting from sector 'sector'. Return amount of bytes written. */ 97*b8861977SAsias He ssize_t disk_image__write(struct disk_image *disk, u64 sector, const struct iovec *iov, int iovcount) 9870b0d7b0SSasha Levin { 9970b0d7b0SSasha Levin u64 first_sector = sector; 10070b0d7b0SSasha Levin 10170b0d7b0SSasha Levin if (disk->ops->write_sector_iov) 10270b0d7b0SSasha Levin return disk->ops->write_sector_iov(disk, sector, iov, iovcount); 10370b0d7b0SSasha Levin 10470b0d7b0SSasha Levin while (iovcount--) { 10570b0d7b0SSasha Levin if (disk->ops->write_sector(disk, sector, iov->iov_base, iov->iov_len) < 0) 10670b0d7b0SSasha Levin return -1; 10770b0d7b0SSasha Levin 10870b0d7b0SSasha Levin sector += iov->iov_len >> SECTOR_SHIFT; 10970b0d7b0SSasha Levin iov++; 11070b0d7b0SSasha Levin } 11170b0d7b0SSasha Levin 11270b0d7b0SSasha Levin return (sector - first_sector) << SECTOR_SHIFT; 11370b0d7b0SSasha Levin } 114