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*9ac38fe1SSasha Levin struct disk_image *disk_image__new(int fd, uint64_t size, struct disk_image_operations *ops, bool readonly) 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*9ac38fe1SSasha Levin if (readonly) { 28*9ac38fe1SSasha Levin self->priv = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_NORESERVE, fd, 0); 29*9ac38fe1SSasha Levin if (self->priv == MAP_FAILED) 30*9ac38fe1SSasha Levin die("mmap() failed"); 31*9ac38fe1SSasha Levin } else 32*9ac38fe1SSasha Levin self->priv = MAP_FAILED; 339f532d00SPekka Enberg 34fffb37a9SPekka Enberg return self; 359f532d00SPekka Enberg } 369f532d00SPekka Enberg 37499f3bedSPekka Enberg static int raw_image__read_sector(struct disk_image *self, uint64_t sector, void *dst, uint32_t dst_len) 389f532d00SPekka Enberg { 399f532d00SPekka Enberg uint64_t offset = sector << SECTOR_SHIFT; 409f532d00SPekka Enberg 415a24a9f2SPekka Enberg if (offset + dst_len > self->size) 429f532d00SPekka Enberg return -1; 439f532d00SPekka Enberg 446b7deb02SPekka Enberg if (pread_in_full(self->fd, dst, dst_len, offset) < 0) 45c4d7847bSPekka Enberg return -1; 469f532d00SPekka Enberg 479f532d00SPekka Enberg return 0; 489f532d00SPekka Enberg } 49258dd093SPekka Enberg 50499f3bedSPekka Enberg static int raw_image__write_sector(struct disk_image *self, uint64_t sector, void *src, uint32_t src_len) 51258dd093SPekka Enberg { 52258dd093SPekka Enberg uint64_t offset = sector << SECTOR_SHIFT; 53258dd093SPekka Enberg 54258dd093SPekka Enberg if (offset + src_len > self->size) 55258dd093SPekka Enberg return -1; 56258dd093SPekka Enberg 576b7deb02SPekka Enberg if (pwrite_in_full(self->fd, src, src_len, offset) < 0) 58c4d7847bSPekka Enberg return -1; 59258dd093SPekka Enberg 60258dd093SPekka Enberg return 0; 61258dd093SPekka Enberg } 62499f3bedSPekka Enberg 63*9ac38fe1SSasha Levin static int raw_image__read_sector_ro_mmap(struct disk_image *self, uint64_t sector, void *dst, uint32_t dst_len) 64*9ac38fe1SSasha Levin { 65*9ac38fe1SSasha Levin uint64_t offset = sector << SECTOR_SHIFT; 66*9ac38fe1SSasha Levin 67*9ac38fe1SSasha Levin if (offset + dst_len > self->size) 68*9ac38fe1SSasha Levin return -1; 69*9ac38fe1SSasha Levin 70*9ac38fe1SSasha Levin memcpy(dst, self->priv + offset, dst_len); 71*9ac38fe1SSasha Levin 72*9ac38fe1SSasha Levin return 0; 73*9ac38fe1SSasha Levin } 74*9ac38fe1SSasha Levin 75*9ac38fe1SSasha Levin static int raw_image__write_sector_ro_mmap(struct disk_image *self, uint64_t sector, void *src, uint32_t src_len) 76*9ac38fe1SSasha Levin { 77*9ac38fe1SSasha Levin uint64_t offset = sector << SECTOR_SHIFT; 78*9ac38fe1SSasha Levin 79*9ac38fe1SSasha Levin if (offset + src_len > self->size) 80*9ac38fe1SSasha Levin return -1; 81*9ac38fe1SSasha Levin 82*9ac38fe1SSasha Levin memcpy(self->priv + offset, src, src_len); 83*9ac38fe1SSasha Levin 84*9ac38fe1SSasha Levin return 0; 85*9ac38fe1SSasha Levin } 86*9ac38fe1SSasha Levin 87499f3bedSPekka Enberg static struct disk_image_operations raw_image_ops = { 88499f3bedSPekka Enberg .read_sector = raw_image__read_sector, 89499f3bedSPekka Enberg .write_sector = raw_image__write_sector, 90499f3bedSPekka Enberg }; 91499f3bedSPekka Enberg 92*9ac38fe1SSasha Levin static struct disk_image_operations raw_image_ro_mmap_ops = { 93*9ac38fe1SSasha Levin .read_sector = raw_image__read_sector_ro_mmap, 94*9ac38fe1SSasha Levin .write_sector = raw_image__write_sector_ro_mmap, 95*9ac38fe1SSasha Levin }; 96*9ac38fe1SSasha Levin 97*9ac38fe1SSasha Levin static struct disk_image *raw_image__probe(int fd, bool readonly) 98499f3bedSPekka Enberg { 99499f3bedSPekka Enberg struct stat st; 100499f3bedSPekka Enberg 101499f3bedSPekka Enberg if (fstat(fd, &st) < 0) 102499f3bedSPekka Enberg return NULL; 103499f3bedSPekka Enberg 104*9ac38fe1SSasha Levin return disk_image__new(fd, st.st_size, readonly ? &raw_image_ro_mmap_ops : &raw_image_ops, readonly); 105499f3bedSPekka Enberg } 106499f3bedSPekka Enberg 107*9ac38fe1SSasha Levin struct disk_image *disk_image__open(const char *filename, bool readonly) 108499f3bedSPekka Enberg { 109499f3bedSPekka Enberg struct disk_image *self; 110499f3bedSPekka Enberg int fd; 111499f3bedSPekka Enberg 112*9ac38fe1SSasha Levin fd = open(filename, readonly ? O_RDONLY : O_RDWR); 113499f3bedSPekka Enberg if (fd < 0) 114499f3bedSPekka Enberg return NULL; 115499f3bedSPekka Enberg 116*9ac38fe1SSasha Levin self = raw_image__probe(fd, readonly); 117499f3bedSPekka Enberg if (self) 118499f3bedSPekka Enberg return self; 119499f3bedSPekka Enberg 120d6c58e5bSPrasad Joshi if (close(fd) < 0) 121499f3bedSPekka Enberg warning("close() failed"); 122499f3bedSPekka Enberg 123499f3bedSPekka Enberg return NULL; 124499f3bedSPekka Enberg } 125499f3bedSPekka Enberg 126499f3bedSPekka Enberg void disk_image__close(struct disk_image *self) 127499f3bedSPekka Enberg { 12882d94c50SIngo Molnar /* If there was no disk image then there's nothing to do: */ 12982d94c50SIngo Molnar if (!self) 13082d94c50SIngo Molnar return; 13182d94c50SIngo Molnar 132*9ac38fe1SSasha Levin if (self->priv != MAP_FAILED) 133*9ac38fe1SSasha Levin munmap(self->priv, self->size); 134*9ac38fe1SSasha Levin 135499f3bedSPekka Enberg if (self->ops->close) 136499f3bedSPekka Enberg self->ops->close(self); 137499f3bedSPekka Enberg 138499f3bedSPekka Enberg if (close(self->fd) < 0) 139499f3bedSPekka Enberg warning("close() failed"); 140499f3bedSPekka Enberg 141499f3bedSPekka Enberg free(self); 142499f3bedSPekka Enberg } 143