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 16*f4ff38dfSPrasad 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; 27*f4ff38dfSPrasad Joshi return self; 28*f4ff38dfSPrasad Joshi } 29*f4ff38dfSPrasad Joshi 30*f4ff38dfSPrasad Joshi struct disk_image *disk_image__new_readonly(int fd, uint64_t size, struct disk_image_operations *ops) 31*f4ff38dfSPrasad Joshi { 32*f4ff38dfSPrasad Joshi struct disk_image *self; 33*f4ff38dfSPrasad Joshi 34*f4ff38dfSPrasad Joshi self = disk_image__new(fd, size, ops); 35*f4ff38dfSPrasad Joshi if (!self) 36*f4ff38dfSPrasad Joshi return NULL; 37*f4ff38dfSPrasad 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 44*f4ff38dfSPrasad 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 95499f3bedSPekka Enberg static struct disk_image_operations raw_image_ops = { 96499f3bedSPekka Enberg .read_sector = raw_image__read_sector, 97499f3bedSPekka Enberg .write_sector = raw_image__write_sector, 98499f3bedSPekka Enberg }; 99499f3bedSPekka Enberg 1009ac38fe1SSasha Levin static struct disk_image_operations raw_image_ro_mmap_ops = { 1019ac38fe1SSasha Levin .read_sector = raw_image__read_sector_ro_mmap, 1029ac38fe1SSasha Levin .write_sector = raw_image__write_sector_ro_mmap, 1039ac38fe1SSasha Levin }; 1049ac38fe1SSasha Levin 1059ac38fe1SSasha Levin static struct disk_image *raw_image__probe(int fd, bool readonly) 106499f3bedSPekka Enberg { 107499f3bedSPekka Enberg struct stat st; 108499f3bedSPekka Enberg 109499f3bedSPekka Enberg if (fstat(fd, &st) < 0) 110499f3bedSPekka Enberg return NULL; 111499f3bedSPekka Enberg 112*f4ff38dfSPrasad Joshi if (readonly) 113*f4ff38dfSPrasad Joshi return disk_image__new_readonly(fd, st.st_size, &raw_image_ro_mmap_ops); 114*f4ff38dfSPrasad Joshi else 115*f4ff38dfSPrasad Joshi return disk_image__new(fd, st.st_size, &raw_image_ops); 116499f3bedSPekka Enberg } 117499f3bedSPekka Enberg 1189ac38fe1SSasha Levin struct disk_image *disk_image__open(const char *filename, bool readonly) 119499f3bedSPekka Enberg { 120499f3bedSPekka Enberg struct disk_image *self; 121499f3bedSPekka Enberg int fd; 122499f3bedSPekka Enberg 1239ac38fe1SSasha Levin fd = open(filename, readonly ? O_RDONLY : O_RDWR); 124499f3bedSPekka Enberg if (fd < 0) 125499f3bedSPekka Enberg return NULL; 126499f3bedSPekka Enberg 1279ac38fe1SSasha Levin self = raw_image__probe(fd, readonly); 128499f3bedSPekka Enberg if (self) 129499f3bedSPekka Enberg return self; 130499f3bedSPekka Enberg 131d6c58e5bSPrasad Joshi if (close(fd) < 0) 132499f3bedSPekka Enberg warning("close() failed"); 133499f3bedSPekka Enberg 134499f3bedSPekka Enberg return NULL; 135499f3bedSPekka Enberg } 136499f3bedSPekka Enberg 137499f3bedSPekka Enberg void disk_image__close(struct disk_image *self) 138499f3bedSPekka Enberg { 13982d94c50SIngo Molnar /* If there was no disk image then there's nothing to do: */ 14082d94c50SIngo Molnar if (!self) 14182d94c50SIngo Molnar return; 14282d94c50SIngo Molnar 1439ac38fe1SSasha Levin if (self->priv != MAP_FAILED) 1449ac38fe1SSasha Levin munmap(self->priv, self->size); 1459ac38fe1SSasha Levin 146499f3bedSPekka Enberg if (self->ops->close) 147499f3bedSPekka Enberg self->ops->close(self); 148499f3bedSPekka Enberg 149499f3bedSPekka Enberg if (close(self->fd) < 0) 150499f3bedSPekka Enberg warning("close() failed"); 151499f3bedSPekka Enberg 152499f3bedSPekka Enberg free(self); 153499f3bedSPekka Enberg } 154