19f532d00SPekka Enberg #include "kvm/disk-image.h" 29f532d00SPekka Enberg 3c4d7847bSPekka Enberg #include "kvm/read-write.h" 49f532d00SPekka Enberg #include "kvm/util.h" 59f532d00SPekka Enberg 69f532d00SPekka Enberg #include <sys/types.h> 733d33901SPekka Enberg #include <inttypes.h> 89f532d00SPekka Enberg #include <sys/mman.h> 99f532d00SPekka Enberg #include <sys/stat.h> 105646450dSPekka Enberg #include <stdbool.h> 119f532d00SPekka Enberg #include <stddef.h> 129f532d00SPekka Enberg #include <stdlib.h> 139f532d00SPekka Enberg #include <unistd.h> 149f532d00SPekka Enberg #include <fcntl.h> 159f532d00SPekka Enberg 16f4ff38dfSPrasad Joshi struct disk_image *disk_image__new(int fd, uint64_t size, struct disk_image_operations *ops) 179f532d00SPekka Enberg { 18fffb37a9SPekka Enberg struct disk_image *self; 199f532d00SPekka Enberg 20fffb37a9SPekka Enberg self = malloc(sizeof *self); 21fffb37a9SPekka Enberg if (!self) 22fffb37a9SPekka Enberg return NULL; 239f532d00SPekka Enberg 24fffb37a9SPekka Enberg self->fd = fd; 25fffb37a9SPekka Enberg self->size = size; 26fffb37a9SPekka Enberg self->ops = ops; 27f4ff38dfSPrasad Joshi return self; 28f4ff38dfSPrasad Joshi } 29f4ff38dfSPrasad Joshi 30f4ff38dfSPrasad Joshi struct disk_image *disk_image__new_readonly(int fd, uint64_t size, struct disk_image_operations *ops) 31f4ff38dfSPrasad Joshi { 32f4ff38dfSPrasad Joshi struct disk_image *self; 33f4ff38dfSPrasad Joshi 34f4ff38dfSPrasad Joshi self = disk_image__new(fd, size, ops); 35f4ff38dfSPrasad Joshi if (!self) 36f4ff38dfSPrasad Joshi return NULL; 37f4ff38dfSPrasad Joshi 389ac38fe1SSasha Levin self->priv = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_NORESERVE, fd, 0); 399ac38fe1SSasha Levin if (self->priv == MAP_FAILED) 409ac38fe1SSasha Levin die("mmap() failed"); 41fffb37a9SPekka Enberg return self; 429f532d00SPekka Enberg } 439f532d00SPekka Enberg 44f4ff38dfSPrasad Joshi 45499f3bedSPekka Enberg static int raw_image__read_sector(struct disk_image *self, uint64_t sector, void *dst, uint32_t dst_len) 469f532d00SPekka Enberg { 479f532d00SPekka Enberg uint64_t offset = sector << SECTOR_SHIFT; 489f532d00SPekka Enberg 495a24a9f2SPekka Enberg if (offset + dst_len > self->size) 509f532d00SPekka Enberg return -1; 519f532d00SPekka Enberg 526b7deb02SPekka Enberg if (pread_in_full(self->fd, dst, dst_len, offset) < 0) 53c4d7847bSPekka Enberg return -1; 549f532d00SPekka Enberg 559f532d00SPekka Enberg return 0; 569f532d00SPekka Enberg } 57258dd093SPekka Enberg 58499f3bedSPekka Enberg static int raw_image__write_sector(struct disk_image *self, uint64_t sector, void *src, uint32_t src_len) 59258dd093SPekka Enberg { 60258dd093SPekka Enberg uint64_t offset = sector << SECTOR_SHIFT; 61258dd093SPekka Enberg 62258dd093SPekka Enberg if (offset + src_len > self->size) 63258dd093SPekka Enberg return -1; 64258dd093SPekka Enberg 656b7deb02SPekka Enberg if (pwrite_in_full(self->fd, src, src_len, offset) < 0) 66c4d7847bSPekka Enberg return -1; 67258dd093SPekka Enberg 68258dd093SPekka Enberg return 0; 69258dd093SPekka Enberg } 70499f3bedSPekka Enberg 719ac38fe1SSasha Levin static int raw_image__read_sector_ro_mmap(struct disk_image *self, uint64_t sector, void *dst, uint32_t dst_len) 729ac38fe1SSasha Levin { 739ac38fe1SSasha Levin uint64_t offset = sector << SECTOR_SHIFT; 749ac38fe1SSasha Levin 759ac38fe1SSasha Levin if (offset + dst_len > self->size) 769ac38fe1SSasha Levin return -1; 779ac38fe1SSasha Levin 789ac38fe1SSasha Levin memcpy(dst, self->priv + offset, dst_len); 799ac38fe1SSasha Levin 809ac38fe1SSasha Levin return 0; 819ac38fe1SSasha Levin } 829ac38fe1SSasha Levin 839ac38fe1SSasha Levin static int raw_image__write_sector_ro_mmap(struct disk_image *self, uint64_t sector, void *src, uint32_t src_len) 849ac38fe1SSasha Levin { 859ac38fe1SSasha Levin uint64_t offset = sector << SECTOR_SHIFT; 869ac38fe1SSasha Levin 879ac38fe1SSasha Levin if (offset + src_len > self->size) 889ac38fe1SSasha Levin return -1; 899ac38fe1SSasha Levin 909ac38fe1SSasha Levin memcpy(self->priv + offset, src, src_len); 919ac38fe1SSasha Levin 929ac38fe1SSasha Levin return 0; 939ac38fe1SSasha Levin } 949ac38fe1SSasha Levin 95*177a5815SPrasad Joshi static void raw_image__close_sector_ro_mmap(struct disk_image *self) 96*177a5815SPrasad Joshi { 97*177a5815SPrasad Joshi if (self->priv != MAP_FAILED) 98*177a5815SPrasad Joshi munmap(self->priv, self->size); 99*177a5815SPrasad Joshi } 100*177a5815SPrasad Joshi 101499f3bedSPekka Enberg static struct disk_image_operations raw_image_ops = { 102499f3bedSPekka Enberg .read_sector = raw_image__read_sector, 103499f3bedSPekka Enberg .write_sector = raw_image__write_sector, 104499f3bedSPekka Enberg }; 105499f3bedSPekka Enberg 1069ac38fe1SSasha Levin static struct disk_image_operations raw_image_ro_mmap_ops = { 1079ac38fe1SSasha Levin .read_sector = raw_image__read_sector_ro_mmap, 1089ac38fe1SSasha Levin .write_sector = raw_image__write_sector_ro_mmap, 109*177a5815SPrasad Joshi .close = raw_image__close_sector_ro_mmap, 1109ac38fe1SSasha Levin }; 1119ac38fe1SSasha Levin 1129ac38fe1SSasha Levin static struct disk_image *raw_image__probe(int fd, bool readonly) 113499f3bedSPekka Enberg { 114499f3bedSPekka Enberg struct stat st; 115499f3bedSPekka Enberg 116499f3bedSPekka Enberg if (fstat(fd, &st) < 0) 117499f3bedSPekka Enberg return NULL; 118499f3bedSPekka Enberg 119f4ff38dfSPrasad Joshi if (readonly) 120f4ff38dfSPrasad Joshi return disk_image__new_readonly(fd, st.st_size, &raw_image_ro_mmap_ops); 121f4ff38dfSPrasad Joshi else 122f4ff38dfSPrasad Joshi return disk_image__new(fd, st.st_size, &raw_image_ops); 123499f3bedSPekka Enberg } 124499f3bedSPekka Enberg 1259ac38fe1SSasha Levin struct disk_image *disk_image__open(const char *filename, bool readonly) 126499f3bedSPekka Enberg { 127499f3bedSPekka Enberg struct disk_image *self; 128499f3bedSPekka Enberg int fd; 129499f3bedSPekka Enberg 1309ac38fe1SSasha Levin fd = open(filename, readonly ? O_RDONLY : O_RDWR); 131499f3bedSPekka Enberg if (fd < 0) 132499f3bedSPekka Enberg return NULL; 133499f3bedSPekka Enberg 1349ac38fe1SSasha Levin self = raw_image__probe(fd, readonly); 135499f3bedSPekka Enberg if (self) 136499f3bedSPekka Enberg return self; 137499f3bedSPekka Enberg 138d6c58e5bSPrasad Joshi if (close(fd) < 0) 139499f3bedSPekka Enberg warning("close() failed"); 140499f3bedSPekka Enberg 141499f3bedSPekka Enberg return NULL; 142499f3bedSPekka Enberg } 143499f3bedSPekka Enberg 144499f3bedSPekka Enberg void disk_image__close(struct disk_image *self) 145499f3bedSPekka Enberg { 14682d94c50SIngo Molnar /* If there was no disk image then there's nothing to do: */ 14782d94c50SIngo Molnar if (!self) 14882d94c50SIngo Molnar return; 14982d94c50SIngo Molnar 150499f3bedSPekka Enberg if (self->ops->close) 151499f3bedSPekka Enberg self->ops->close(self); 152499f3bedSPekka Enberg 153499f3bedSPekka Enberg if (close(self->fd) < 0) 154499f3bedSPekka Enberg warning("close() failed"); 155499f3bedSPekka Enberg 156499f3bedSPekka Enberg free(self); 157499f3bedSPekka Enberg } 158